using Unity.Entities; using Unity.NetCode; namespace ProjectM.Simulation { /// /// Lifecycle states for a co-op expedition run (). A byte, never an enum /// (Burst/serialization safe), APPEND-ONLY. is appended after the original four so no /// value is re-meaned. The party is at the base hub in ; a discrete run spans /// (loop) → /// . /// public static class RunLifecycle { /// Party in the base hub; ready-check active; no expedition ghosts exist. public const byte Staging = 0; /// All-ready launch transient: seed chosen, party teleporting into room 0. public const byte Launching = 1; /// Active room populated; party fighting/looting. public const byte InRoom = 2; /// Room cleared; per-player boon offers pending; room torn down. public const byte RoomReward = 3; /// Run ended (boss cleared / party wiped / all left): teleport home, bank, → Staging. public const byte Returning = 4; /// Boons picked; party choosing the next branch (no room materialized — the teardown gap). public const byte RouteSelect = 5; /// DR-046: room cleared + boon picked, but the room + resource NODES persist and a portal is up. /// Party loots; interacting the portal (or a soft-timeout) tears the room down + advances (RouteSelect, or /// Returning if the boss fell). Append-only byte value — no ghost re-mean. public const byte RoomExplore = 6; } /// /// The REPLICATED run-lifecycle summary the whole party observes — a server-decided, client-observed FSM on the /// GLOBAL untagged CycleDirector ghost (so it is relevant cross-region for free, like / /// /). SOLE writer: RunDirectorSystem. Distinct from /// (that stays the BASE Calm↔Siege posture for retaliation/final sieges). /// /// Fields split three ways: the lifecycle/room readout (HUD "Room i/N", biome cross-fade), the branching-map /// wire ( so the client regenerates the map for DISPLAY, + and the /// authoritative reachable RouteOpt* the clickable options bind to), and a two-field mirror of the /// persisted meta counters for the HUD. All integers/bytes → replicate exact (no quantization). Adding this /// [GhostField] component re-hashes the runtime-spawned director ghost (server + client bake the same /// prefab → hash matches), exactly like /. /// public struct RunInfo : IComponentData { // ---- lifecycle + room readout ---- /// . [GhostField] public byte Lifecycle; /// 0-based depth of the active room (HUD "Room CurrentRoom+1 / RoomCount"). [GhostField] public int CurrentRoom; /// Total rooms this run (== map layer count, seed-varied in [6,10]). [GhostField] public int RoomCount; /// of the active room. [GhostField] public byte CurrentRoomType; /// of the active room (client atmosphere cross-fade). [GhostField] public byte CurrentBiome; /// Server tick the launch countdown elapses (0 = none). Via ; compared with IsNewerThan. [GhostField] public uint LaunchTick; // ---- branching map wire ---- /// The run seed — clients regenerate the map layout for DISPLAY via (no gameplay authority). [GhostField] public uint RunSeed; /// The party's current column in the active layer. [GhostField] public byte CurrentCol; /// Number of reachable next-room options (0 unless ). [GhostField] public byte RouteOptionCount; /// Reachable next-layer column for option 0 (authoritative — the clickable button binds to this, not the regen). [GhostField] public byte RouteOpt0Col; [GhostField] public byte RouteOpt1Col; [GhostField] public byte RouteOpt2Col; /// of option 0 (so the HUD labels the choice). [GhostField] public byte RouteOpt0Type; [GhostField] public byte RouteOpt1Type; [GhostField] public byte RouteOpt2Type; // ---- persisted-meta HUD mirror ---- /// Runs completed (boss-cleared), mirrored for the HUD from the persisted meta counters. [GhostField] public int RunsCompleted; /// Deepest room reached across runs, mirrored for the HUD. [GhostField] public int MaxDepthReached; } }