Files
Project-M/Assets/_Project/Scripts/Simulation/World/RunRuntime.cs
T
2026-07-02 20:41:43 -07:00

56 lines
3.6 KiB
C#

namespace ProjectM.Simulation
{
/// <summary>
/// Server-only working state for the run FSM — lives on the CycleDirector beside <see cref="RunInfo"/> but is
/// NOT replicated (adding fields here never re-bakes the ghost). Owned/written by <c>RunDirectorSystem</c>.
/// Determinism: <see cref="RunSeed"/> = max(1, Hash(<see cref="RunEpoch"/>, <see cref="HostSalt"/>)) — monotonic
/// int, never a tick, equality-compared. Tick sentinels (<see cref="RewardGraceTick"/>/<see cref="RouteGraceTick"/>)
/// route through <see cref="TickUtil.NonZero"/> and compare via NetworkTick.IsNewerThan (never raw uint).
/// </summary>
public struct RunRuntime : Unity.Entities.IComponentData
{
// ---- run identity / seed ----
/// <summary>Working copy of the run seed (mirrored to the replicated <see cref="RunInfo.RunSeed"/>).</summary>
public uint RunSeed;
/// <summary>Monotonic run counter; bumped on the Staging→Launching edge so each run reseeds. Equality-compared.</summary>
public int RunEpoch;
/// <summary>Per-playthrough salt folded into <see cref="RunSeed"/> for cross-session map variety (seeded at spawn, non-tick).</summary>
public uint HostSalt;
// ---- room traversal ----
/// <summary>Monotonic room-seed counter; bumped per room advance so the field/enemy directors reseed. Equality-compared.</summary>
public int RoomEpoch;
/// <summary>Which of the two ping-pong sub-arena slots the active room occupies (CurrentRoom &amp; 1).</summary>
public byte ActiveSubSlot;
/// <summary>The active room's stable map node id (single plan authority — field/enemy directors read this, never re-derive).</summary>
public int CurrentNodeId;
/// <summary>The active room's column (mirrors <see cref="RunInfo.CurrentCol"/>).</summary>
public byte CurrentCol;
/// <summary>The active room's <see cref="RoomTypeId"/> (single plan authority).</summary>
public byte CurrentRoomType;
// ---- scarcity / banking latches ----
/// <summary>Run-wide remaining resource-node allotment (floors each room's scatter; decrements per node) → true scarcity.</summary>
public int NodeBudgetRemaining;
/// <summary>The <see cref="RunEpoch"/> the terminal bank last fired for — equality latch so a multi-tick Returning banks once.</summary>
public int LastBankedRunEpoch;
/// <summary>1 iff the run ended by a genuine BOSS clear (gates the win-meter/RunsCompleted credit; 0 on abort/wipe).</summary>
public byte LastTerminalCleared;
/// <summary>Rooms actually CLEARED this run (bumped on each InRoom→RoomReward edge; reset at launch) — the
/// honest depth the terminal bank records into MaxDepthReached (never the planned RoomCount — D-F3).</summary>
public int RoomsClearedThisRun;
// ---- ready / grace ----
/// <summary>Previous-tick all-ready state (rising-edge latch for the Staging→Launching launch).</summary>
public byte WasAllReady;
/// <summary>Server tick the RoomReward boon-pick grace elapses (NonZero; IsNewerThan-compared).</summary>
public uint RewardGraceTick;
/// <summary>Server tick the RouteSelect grace elapses → auto-pick lowest-index reachable (NonZero; IsNewerThan-compared).</summary>
public uint RouteGraceTick;
// ---- boons ----
/// <summary>Monotonic per-run boon-pick counter → distinct SourceIds in the run-scoped boon band; reset each run.</summary>
public uint BoonPickCounter;
}
}