f31ffe910b
Netcode frontend pattern: UITK main menu / pause / settings (MenuUi + controllers), on-demand world lifecycle (WorldLauncher/SessionRunner), GameBootstrap menu branch; Graphics/Audio settings (SettingsService/GameVolume); single-slot save foundation (SaveData/SaveService, born-correct load at director spawn, autosave on Siege->Calm + quit); RuntimePanelSettings + theme; BuildTool menu; 10 EditMode tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
71 lines
3.0 KiB
C#
71 lines
3.0 KiB
C#
using System.Collections.Generic;
|
|
using Unity.Collections;
|
|
using Unity.Entities;
|
|
|
|
namespace ProjectM.Simulation
|
|
{
|
|
/// <summary>
|
|
/// Scans a server world for PLAYER-built structures (<see cref="PlacedStructure"/> + <see cref="RuntimePlacedTag"/>)
|
|
/// 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.
|
|
/// </summary>
|
|
public static class SaveStructureScan
|
|
{
|
|
public static void Collect(EntityManager em, uint nowTick, out StructureSave[] structures, out StructureIoRow[] io)
|
|
{
|
|
var structs = new List<StructureSave>();
|
|
var ioRows = new List<StructureIoRow>();
|
|
|
|
using var q = em.CreateEntityQuery(
|
|
ComponentType.ReadOnly<PlacedStructure>(),
|
|
ComponentType.ReadOnly<RuntimePlacedTag>());
|
|
using var entities = q.ToEntityArray(Allocator.Temp);
|
|
|
|
for (int k = 0; k < entities.Length; k++)
|
|
{
|
|
var e = entities[k];
|
|
var ps = em.GetComponentData<PlacedStructure>(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<Conveyor>(e))
|
|
row.Direction = em.GetComponentData<Conveyor>(e).Direction;
|
|
|
|
if (em.HasComponent<ConveyorItem>(e) && em.IsComponentEnabled<ConveyorItem>(e))
|
|
{
|
|
var item = em.GetComponentData<ConveyorItem>(e);
|
|
row.ConveyorResId = item.ResourceId;
|
|
row.ConveyorCount = item.Count;
|
|
}
|
|
|
|
structs.Add(row);
|
|
|
|
if (em.HasBuffer<MachineInput>(e))
|
|
{
|
|
var buf = em.GetBuffer<MachineInput>(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<MachineOutput>(e))
|
|
{
|
|
var buf = em.GetBuffer<MachineOutput>(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();
|
|
}
|
|
}
|
|
}
|