using ProjectM.Simulation; using Unity.Burst; using Unity.Collections; using Unity.Entities; using Unity.NetCode; using Unity.Transforms; namespace ProjectM.Server { /// /// Server-only, one-shot spawner for the GLOBAL cycle-director ghost (mirrors SharedStorageSpawnSystem, /// but MINUS the RegionTag — the director must stay global so GhostRelevancy keeps it relevant to every /// region). On its first update it reads the baked + NetworkTime, /// instantiates the ghost, initializes (Expedition, cycle 1, PhaseEndTick = /// now + ), adds the server-only , and /// places it at the base center (preserving the prefab's baked LocalTransform scale — FromPosition would /// reset the replicated Scale GhostField), then destroys the spawner so it idles. /// [BurstCompile] [WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)] public partial struct CycleDirectorSpawnSystem : ISystem { [BurstCompile] public void OnCreate(ref SystemState state) { state.RequireForUpdate(); state.RequireForUpdate(); } [BurstCompile] public void OnUpdate(ref SystemState state) { var serverTick = SystemAPI.GetSingleton().ServerTick; if (!serverTick.IsValid) return; var spawnerEntity = SystemAPI.GetSingletonEntity(); var spawner = SystemAPI.GetComponent(spawnerEntity); var ecb = new EntityCommandBuffer(Allocator.Temp); if (spawner.Prefab != Entity.Null) { var director = ecb.Instantiate(spawner.Prefab); // Place at the base center, preserving the prefab's baked scale/rotation. var xform = SystemAPI.GetComponent(spawner.Prefab); if (SystemAPI.TryGetSingleton(out var anchor)) xform.Position = BaseGridMath.PlotCenter(anchor); ecb.SetComponent(director, xform); // Boot the run-state in Calm (the persistent default) — no timer; ThreatDirector arms sieges. ecb.SetComponent(director, new CycleState { Phase = CyclePhase.Calm, CycleNumber = 1, PhaseEndTick = 0u, }); ecb.AddComponent(director, new CycleRuntime { DefendStartWave = 0 }); ecb.AddComponent(director, new ThreatState()); } // One-shot: remove the spawner so RequireForUpdate fails and the system idles. ecb.DestroyEntity(spawnerEntity); ecb.Playback(state.EntityManager); } } }