using ProjectM.Simulation; using Unity.Burst; using Unity.Collections; using Unity.Entities; using Unity.Transforms; namespace ProjectM.Server { /// /// Server-only, one-shot spawner for the shared home-base storage container (mirrors /// UpgradePickupSpawnSystem). On its first update it reads the baked /// singleton and the , instantiates the container ghost at the cell center /// (), then destroys the spawner singleton so the system idles /// (spawned exactly once). Runs in the default SimulationSystemGroup (NOT the prediction loop); the /// container replicates to clients as an ownerless interpolated ghost. The container is intentionally /// NOT linked to any connection's LinkedEntityGroup, so it persists across player disconnects. /// [BurstCompile] [WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)] public partial struct SharedStorageSpawnSystem : ISystem { [BurstCompile] public void OnCreate(ref SystemState state) { state.RequireForUpdate(); state.RequireForUpdate(); } [BurstCompile] public void OnUpdate(ref SystemState state) { var spawnerEntity = SystemAPI.GetSingletonEntity(); var spawner = SystemAPI.GetComponent(spawnerEntity); var anchor = SystemAPI.GetSingleton(); var ecb = new EntityCommandBuffer(Allocator.Temp); if (spawner.Prefab != Entity.Null) { var container = ecb.Instantiate(spawner.Prefab); var position = BaseGridMath.CellToWorld(anchor, spawner.Cell); // Phase 0: the grid Y (GridOrigin.y=1) is the CC capsule-CENTER plane; center-pivot structure // meshes look grounded there, but the crate's pivot is at its base -> it floated 1 u. Sit it on // the terrain surface instead. position.y = 0f; // Preserve the prefab's baked scale/rotation (FromPosition would reset Scale to 1). var xform = SystemAPI.GetComponent(spawner.Prefab); xform.Position = position; ecb.SetComponent(container, xform); // M6: scope the shared storage to the base region for ghost relevancy. ecb.AddComponent(container, new RegionTag { Region = RegionId.Base }); } // One-shot: remove the spawner so RequireForUpdate fails and the system idles. ecb.DestroyEntity(spawnerEntity); ecb.Playback(state.EntityManager); ecb.Dispose(); } } }