using ProjectM.Simulation; using Unity.Burst; using Unity.Collections; using Unity.Entities; using Unity.NetCode; namespace ProjectM.Server { /// /// Server receiver for : resolves the sender (SourceConnection → NetworkId → /// GhostOwner → player entity, the AbilityUpgradeSystem idiom) and SETS . /// Honored ONLY while the run FSM is in Staging or Launching — an un-ready during the Launching countdown is the /// launch-abort escape hatch (RunDirectorSystem reverts to Staging); toggles arriving mid-run are dropped (the /// Returning edge clears every flag anyway). Ordered BEFORE RunDirectorSystem so a toggle lands the same tick the /// ready-count is derived. Plain server group (one-off RPC effects never run in the predicted loop); the request /// entity is ALWAYS destroyed. /// [BurstCompile] [WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)] [UpdateInGroup(typeof(SimulationSystemGroup))] [UpdateBefore(typeof(RunDirectorSystem))] public partial struct ReadyToggleSystem : ISystem { [BurstCompile] public void OnCreate(ref SystemState state) { var builder = new EntityQueryBuilder(Allocator.Temp) .WithAll(); state.RequireForUpdate(state.GetEntityQuery(builder)); state.RequireForUpdate(); } [BurstCompile] public void OnUpdate(ref SystemState state) { byte lifecycle = SystemAPI.GetSingleton().Lifecycle; bool accept = lifecycle == RunLifecycle.Staging || lifecycle == RunLifecycle.Launching; var playerByConn = new NativeHashMap(8, Allocator.Temp); foreach (var (owner, entity) in SystemAPI.Query>().WithAll().WithEntityAccess()) playerByConn[owner.ValueRO.NetworkId] = entity; var ecb = new EntityCommandBuffer(Allocator.Temp); foreach (var (receive, req, requestEntity) in SystemAPI.Query, RefRO>().WithEntityAccess()) { var conn = receive.ValueRO.SourceConnection; if (accept && SystemAPI.HasComponent(conn) && playerByConn.TryGetValue(SystemAPI.GetComponent(conn).Value, out var player)) { SystemAPI.SetComponent(player, new PlayerReady { Value = (byte)(req.ValueRO.Ready != 0 ? 1 : 0) }); } ecb.DestroyEntity(requestEntity); } ecb.Playback(state.EntityManager); playerByConn.Dispose(); } } }