7.7 KiB
7.7 KiB
date, type, tags, permalink
| date | type | tags | permalink | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| 2026-06-05 | session |
|
gamevault/07-sessions/2026/2026-06-05-m7-automation |
Session 2026-06-05 — M7 Automation: self-running production chains (Harvester → Conveyor → Fabricator)
Goal
Operator: "Let us start the automation milestone." → M7 — Automation: self-running, tick-based production chains with deterministic offline catch-up, building on the DR-014 locked structure model.
Intake decisions (AskUserQuestion):
- Scope: the FULL chain (Harvester → Conveyor → Fabricator), not a reduced harvester-only slice.
- What it makes: AUTO-GATHER EXISTING resources (no new resource ids) — the chain refines existing resources (default 2 Ore → 1 Aether) into the global ledger so setup compounds.
- Persistence: FOLDED IN now (SaveData → v2; player-built structures survive quit→Continue).
- (Informed re-confirm after the adversarial review:) keep the full chain with a deterministic conveyor; "offline catch-up" = within-session tick math + preserved stockpile across quit (NO wall-clock minting — honors the determinism pillar).
Process (ultracode: workflows + adversarial verification)
- Phases 1–4 (research + design): code-graph scan + context7 API verification (NetworkTick/NetworkTime accessors, ECB singleton, server-only
IBufferElementDatastays off the wire); a 3-lens design swarm — code architect · persistence/authoring architect · adversarial netcode/determinism/reuse critic. The critic earned its keep: flagged the conveyor as the dominant complexity/risk, a catch-upperiod=0div-by-zero + per-tick/catch-up double-count footgun, the restore tick-rebase blocker, and theStorageEntrysingleton-collision; all folded into the plan. - Phase 5: plan approved; the two informed forks resolved (keep full chain; within-session catch-up + preserved stockpile).
- Phase 6 (source workflow → controlled MCP apply): a draft→critique Workflow produced the source bundle. Incident: the Workflow's general-purpose draft agents ignored the "return source only" instruction and raw-
Write-wrote the 3 systems + 5 tests intoAssets/— which compile but get no.meta/test-discovery untilrefresh_unity scope=all mode=force(logged as native memory raw-written-cs-needs-full-refresh). Recovered: kept the (high-quality, internally-consistent) agent systems + tests, authored the foundation to satisfy them, and applied everything via MCP with reconciliations — the key one:CyclesDuelower-bound 0, not 1 (prevents a premature mint on a restoredremaining==0machine), andBuildPlaceSystemstampsLastProcessedTick=0so runtime-placed machines hitNeedsInit.
Done — code (compiles clean; EditMode 187→190)
- Components (
Simulation/Automation/AutomationComponents.cs):Harvester{byte ResourceId;int Yield;int PeriodTicks},Fabricator{byte In/OutResourceId;int In/OutAmount;int PeriodTicks},Conveyor{byte Direction;int PeriodTicks}, server-only buffersMachineInput/MachineOutput,ConveyorItem(enableable, baked DISABLED),RuntimePlacedTag. The DR-014 "recipe column onStructureCatalogEntry" was deliberately dropped — dead weight; the recipe is baked on each machine component (server-only, not needed client-side). - Pure math (unit-tested, byte-only):
ProductionMath(NeedsInit/CyclesDue/RemainingTicks/RestoreNextTick— the single gated catch-up path),ConveyorMath(DirOffset/CellKey/ResolveMoves— deterministic + order-independent: snapshot → stable-sort by CellKey → at-most-one destination claim → stall losers no-loss),MachineSlotMath(byte-id deposit/withdraw/total, the non-replicated twin ofStorageMath). - Systems (
Server/Automation/, server-only, ordered[UpdateAfter(PredictedSimulationSystemGroup)]chain Harvester→Conveyor→Fabricator):HarvesterProductionSystem(fixed-yield → itsMachineOutput),ConveyorTransportSystem(pull from adjacent upstreamMachineOutput→ResolveMoves→ settleConveyorItemenable-bit / deposit to sinkMachineInput),FabricatorProductionSystem(input-limited recipe → GLOBAL ledger).Tuning.MaxProductionCatchup = 600. - Persistence (SaveData v2):
StructureSave[]+ flatStructureIoRow[](cooldown as epoch-independent REMAINING ticks; in-flight conveyor item inline);SaveComponentsPendingStructure/PendingStructureIostaging buffers; sharedSaveStructureScan.Collect(both autosave + quit-save scan ONLYRuntimePlacedTagstructures → kills the two-path drift the critic flagged);SaveWriteSystem+WorldLauncher(StagePendingSave + TrySaveFromServer) extended; new one-shotBaseRestoreSystem(gates onStructureCatalog+BaseAnchor+NetworkTime, replays each saved structure CHARGE-FREE, refills buffers + conveyor item, re-tags, self-destructs). - Build wiring:
BuildPlaceRequest+byte Direction(additive scalar; RPC wire-hash shifts → single-build);BuildPlaceSystemstamps conveyorDirection(via aComponentLookup<Conveyor>on the prefab) +RuntimePlacedTag+LastProcessedTick=0;BuildSendSystemH/F/C keys +[/]conveyor-rotate + editor staticsPlaceHarvester/Fabricator/Conveyor. - Authoring + prefabs: 3 MonoBehaviours + bakers;
StructureCatalogAuthoring+3 rows (Harvester 20 / Fabricator 30 / Conveyor 2 Ore);Harvester/Fabricator/Conveyor.prefab(duplicated fromTurret.prefab→ swapped authoring; ownerless-interpolatedGhostAuthoringComponent+ mesh free) wired into the catalog in the Gameplay subscene.
Validation
- EditMode 190/190 (35 new automation tests): catch-up gating/clamp/no-mint/period-0-guard; conveyor Y-junction tie-break + 4-cell line + shuffle-invariance + blocked-stall; fabricator input-limit (no mint-from-nothing); SaveData v2 round-trip + epoch-independent cooldown.
- Runtime (real netcode ServerWorld+ClientWorld, focused editor, via
execute_code): catalog bakes all 6 entries (T1/T5/T6 + T2/T3/T4 machine prefabs valid); placed a live H(18,18)→C(19,18 +X)→F(20,18) chain (RPC → cost Ore 200→148); the chain ran end-to-end (Harvester output flowed → Conveyor transported → Fabricator2 Ore → 1 Aether→ ledger), SERVER Aether == CLIENT Aether (22, then 52 — replicated). Quit autosaved v2 (3 structures + rebasedRemainingTicks); Continue restored all 3 at the exact cells, charge-free (Ore unchanged at 148), born-correct ledger, and the restored chain resumed producing. Console clean of errors throughout.
Decisions
DR-020_M7_Automation_Production_Chains. Resolves the open Backlog "production replication (predicted vs server-only)" question: server-only — production runs in the plain server SimulationSystemGroup; results replicate via the existing global ledger + PlacedStructure ghosts, never predicted.
Next-session intent
- Throughput visuals (item-on-belt): server-only machine buffers don't reach the client (clients see only
PlacedStructure.Type); add ONE small replicated byte if live belt visuals are wanted. - Build-palette HUD + ghost preview + a conveyor-facing indicator (dev
[/]rotate + H/F/C keys only today). - Relevancy ceiling:
RegionRelevancySystem's O(structures×connections)/tick scan becomes load-bearing at higher conveyor counts (DR-014 ceiling note) — batch it when counts grow. - Recipe depth: multi-input fabricator recipes; fabricator→conveyor output chaining (additive — give the fabricator a
MachineOutput); per-machine distinct meshes (machines reuse the Turret mesh as a placeholder). - Operator live play-through + a real 2-build LAN run to exercise the chain under latency (single-client validated).