M7 Automation: deterministic Harvester to Conveyor to Fabricator chains

Server-only production chains (never predicted): components + server systems + pure byte-only math (ProductionMath/ConveyorMath/MachineSlotMath), authoring + 3 machine prefabs wired into the Gameplay subscene, StructureCatalog rows, BuildPlace Direction/RuntimePlacedTag, Tuning, and 35 EditMode tests (catch-up gating, conveyor shuffle-invariance, SaveData v2 round-trip).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-06 15:05:15 -07:00
parent 31c4ab16d6
commit f3f65bccbf
49 changed files with 2599 additions and 1 deletions
@@ -23,11 +23,13 @@ namespace ProjectM.Server
public partial struct BuildPlaceSystem : ISystem
{
ComponentLookup<LocalTransform> m_TransformLookup;
ComponentLookup<Conveyor> m_ConveyorLookup;
[BurstCompile]
public void OnCreate(ref SystemState state)
{
m_TransformLookup = state.GetComponentLookup<LocalTransform>(isReadOnly: true);
m_ConveyorLookup = state.GetComponentLookup<Conveyor>(isReadOnly: true);
state.RequireForUpdate<StructureCatalog>();
state.RequireForUpdate<BaseAnchor>();
state.RequireForUpdate<ResourceLedger>();
@@ -41,6 +43,7 @@ namespace ProjectM.Server
public void OnUpdate(ref SystemState state)
{
m_TransformLookup.Update(ref state);
m_ConveyorLookup.Update(ref state);
uint now = SystemAPI.GetSingleton<NetworkTime>().ServerTick.TickIndexForValidTick;
var anchor = SystemAPI.GetSingleton<BaseAnchor>();
@@ -88,9 +91,16 @@ namespace ProjectM.Server
Type = req.StructureType,
Cell = cell,
NextTick = 0u,
LastProcessedTick = TickUtil.NonZero(now),
LastProcessedTick = 0u, // 0 = uninitialized; the production systems set the baseline on first encounter (turret ignores it)
});
ecb.AddComponent(structure, new RegionTag { Region = RegionId.Base });
ecb.AddComponent<RuntimePlacedTag>(structure); // player-built -> persisted by SaveStructureScan
if (req.StructureType == StructureType.Conveyor && m_ConveyorLookup.HasComponent(entry.Prefab))
{
var conv = m_ConveyorLookup[entry.Prefab];
conv.Direction = req.Direction;
ecb.SetComponent(structure, conv);
}
}
}