using System.Collections.Generic; using Unity.Collections; using Unity.Entities; namespace ProjectM.Simulation { /// /// Scans a server world for PLAYER-built structures ( + ) /// into the flat SaveData v2 arrays — the SINGLE shared scan used by BOTH the autosave (SaveWriteSystem) and the /// quit-to-menu save (WorldLauncher), so the two paths can never drift (only RuntimePlacedTag structures are saved; /// anything baked into the subscene is the subscene's source of truth, not the save's). Cooldowns are stored as /// REMAINING ticks (epoch-independent). Managed (List/array) — runs only on a save, never in the hot loop. /// public static class SaveStructureScan { public static void Collect(EntityManager em, uint nowTick, out StructureSave[] structures, out StructureIoRow[] io) { var structs = new List(); var ioRows = new List(); using var q = em.CreateEntityQuery( ComponentType.ReadOnly(), ComponentType.ReadOnly()); using var entities = q.ToEntityArray(Allocator.Temp); for (int k = 0; k < entities.Length; k++) { var e = entities[k]; var ps = em.GetComponentData(e); int idx = structs.Count; var row = new StructureSave { Type = ps.Type, CellX = ps.Cell.x, CellZ = ps.Cell.y, RemainingTicks = ProductionMath.RemainingTicks(ps.NextTick, nowTick), }; if (em.HasComponent(e)) row.Direction = em.GetComponentData(e).Direction; if (em.HasComponent(e) && em.IsComponentEnabled(e)) { var item = em.GetComponentData(e); row.ConveyorResId = item.ResourceId; row.ConveyorCount = item.Count; } structs.Add(row); if (em.HasBuffer(e)) { var buf = em.GetBuffer(e, true); for (int i = 0; i < buf.Length; i++) ioRows.Add(new StructureIoRow { StructureIndex = idx, Slot = 0, ResourceId = buf[i].ResourceId, Count = buf[i].Count }); } if (em.HasBuffer(e)) { var buf = em.GetBuffer(e, true); for (int i = 0; i < buf.Length; i++) ioRows.Add(new StructureIoRow { StructureIndex = idx, Slot = 1, ResourceId = buf[i].ResourceId, Count = buf[i].Count }); } } structures = structs.ToArray(); io = ioRows.ToArray(); } } }