60e1e21dd3
Adds CoreIntegrity{[GhostField] Current,Max,OverrunTick} on the GLOBAL
CycleDirector ghost (no new ghost/relevancy). CoreDamageSystem (server,
after EnemyAISystem): a Husk within ~3u of PlotCenter drains + is consumed;
CoreRestoreSystem regenerates only in Calm. The SOFT-loss edge lives inside
CyclePhaseSystem (sole Phase writer): Current<=0 in Siege flips to Calm with
NO goal reward, StorageMath.DrainFraction drains the shared ledger, all Husks
despawn, and OverrunTick is stamped (a transient HUD-flash pulse, not a
latching outcome - the Victory latch is END-2's). EnemyAISystem treats the
Core as a FALLBACK target so an undefended base is overrun instead of idling.
SaveData -> v4 persists CoreCurrent (0 -> born full, the EB-1 HP sentinel);
3 live TuningConfig knobs + a red HUD Core bar. Soft-loss + targeting +
breach-resolution forks operator-locked.
See DR-034.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
70 lines
2.9 KiB
C#
70 lines
2.9 KiB
C#
using System;
|
|
|
|
namespace ProjectM.Simulation
|
|
{
|
|
/// <summary>One serialized ledger row (item id + count). An array FIELD of <see cref="SaveData"/>.</summary>
|
|
[Serializable]
|
|
public struct LedgerRow
|
|
{
|
|
public int ItemId;
|
|
public int Count;
|
|
}
|
|
/// <summary>
|
|
/// One serialized player-built structure (M7). Flat scalars (JsonUtility has no int2). The production
|
|
/// cooldown is stored as REMAINING ticks (epoch-independent) so it survives the server-tick origin reset on a
|
|
/// fresh session; the in-flight conveyor item (if any) rides here, while variable-length machine I/O buffers
|
|
/// live in the flat <see cref="SaveData.StructureIo"/> table keyed by index.
|
|
/// </summary>
|
|
[Serializable]
|
|
public struct StructureSave
|
|
{
|
|
public byte Type;
|
|
public int CellX;
|
|
public int CellZ;
|
|
public byte Direction; // conveyor facing (0 for non-conveyors)
|
|
public uint RemainingTicks; // production/cooldown ticks left at save time
|
|
public byte ConveyorResId; // in-flight conveyor item resource (0 = none)
|
|
public int ConveyorCount;
|
|
public float HP; // EB-1: hit points at save time (0 from a pre-v3 save -> restored to baked Max)
|
|
}
|
|
|
|
/// <summary>
|
|
/// One serialized machine I/O buffer row, joined to <see cref="SaveData.Structures"/> by
|
|
/// <see cref="StructureIndex"/>. A flat top-level array (JsonUtility can't nest arrays-of-arrays); Slot 0 =
|
|
/// MachineInput, Slot 1 = MachineOutput.
|
|
/// </summary>
|
|
[Serializable]
|
|
public struct StructureIoRow
|
|
{
|
|
public int StructureIndex;
|
|
public byte Slot;
|
|
public byte ResourceId;
|
|
public int Count;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Versioned, host-authoritative save slice (the FOUNDATION): the long-arc goal charge/target + the shared
|
|
/// resource ledger. JsonUtility-friendly — a class with flat fields and an array FIELD (never a root array).
|
|
/// The schema is intentionally ADDITIVE: future fields (placed structures, threat, storage) append without
|
|
/// breaking old saves, gated by <see cref="Version"/> migration.
|
|
/// </summary>
|
|
[Serializable]
|
|
public class SaveData
|
|
{
|
|
public const int CurrentVersion = 4; // END-1: v4 adds CoreCurrent (a wounded base persists)
|
|
|
|
/// <summary>Oldest save schema the loader accepts (additive); a v2 save loads with structures at full HP.</summary>
|
|
public const int MinLoadableVersion = 2;
|
|
|
|
public int Version = CurrentVersion;
|
|
public int GoalCharge;
|
|
public int GoalTarget;
|
|
public int CoreCurrent; // END-1: Engine Core integrity at save time (0 from a pre-v4 save -> restored to baked Max)
|
|
|
|
public LedgerRow[] Ledger = Array.Empty<LedgerRow>();
|
|
public StructureSave[] Structures = Array.Empty<StructureSave>();
|
|
public StructureIoRow[] StructureIo = Array.Empty<StructureIoRow>();
|
|
public long SavedAtMs;
|
|
}
|
|
}
|