using ProjectM.Simulation;
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.NetCode;
namespace ProjectM.Server
{
///
/// Server receiver for — a participant interacting the room-exit portal during
/// RoomExplore. Honored ONLY when RunInfo.Lifecycle==RoomExplore and the sender is an EXPEDITION player
/// (region gate, the RouteSelect idiom). Sets the server-only latch IN-PLACE; it does
/// NOT write RunInfo or tear the room down — RunDirectorSystem (the sole FSM/teardown owner) consumes the latch and
/// advances. Plain server group, before RunDirectorSystem; requests ALWAYS destroyed; NO CyclePhase edge.
///
[BurstCompile]
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
[UpdateInGroup(typeof(SimulationSystemGroup))]
[UpdateBefore(typeof(RunDirectorSystem))]
public partial struct PortalInteractReceiveSystem : ISystem
{
[BurstCompile]
public void OnCreate(ref SystemState state)
{
var b = new EntityQueryBuilder(Allocator.Temp).WithAll();
state.RequireForUpdate(state.GetEntityQuery(b));
state.RequireForUpdate();
state.RequireForUpdate();
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
var dirEntity = SystemAPI.GetSingletonEntity();
bool gateOpen = SystemAPI.GetComponent(dirEntity).Lifecycle == RunLifecycle.RoomExplore;
// Sender region lookup (N3 idiom): a base-bound joiner cannot pull the party out of the room.
var regionByConn = new NativeHashMap(8, Allocator.Temp);
foreach (var (owner, region) in
SystemAPI.Query, RefRO>().WithAll())
regionByConn[owner.ValueRO.NetworkId] = region.ValueRO.Region;
bool interacted = SystemAPI.GetComponent(dirEntity).HasInteract != 0;
var ecb = new EntityCommandBuffer(Allocator.Temp);
foreach (var (receive, requestEntity) in
SystemAPI.Query>().WithAll().WithEntityAccess())
{
var conn = receive.ValueRO.SourceConnection;
bool valid = gateOpen && !interacted
&& SystemAPI.HasComponent(conn)
&& regionByConn.TryGetValue(SystemAPI.GetComponent(conn).Value, out byte senderRegion)
&& senderRegion == RegionId.Expedition;
if (valid)
{
SystemAPI.SetComponent(dirEntity, new PortalCommand { HasInteract = 1 });
interacted = true;
}
ecb.DestroyEntity(requestEntity);
}
ecb.Playback(state.EntityManager);
ecb.Dispose();
regionByConn.Dispose();
}
}
}