using Unity.Entities;
using Unity.NetCode;
namespace ProjectM.Simulation
{
///
/// Macro-loop state for "The Aether Cycle": which phase the run is in, the cycle number, and the server
/// tick the current (timed) phase ends. Server-authoritative, maintained by CyclePhaseSystem. Currently a
/// server-side singleton; the [GhostField]s below are inert until it is moved onto the runtime-spawned
/// CycleDirector ghost (when the client HUD is wired), at which point the same struct replicates unchanged.
/// The Defend phase is NOT timed — it ends when the base-defense wave is cleared — so PhaseEndTick is only
/// meaningful in Expedition/Build (0 during Defend).
///
public struct CycleState : IComponentData
{
/// Current phase (see ).
[GhostField] public byte Phase;
/// 1-based cycle counter (increments when a new Expedition begins).
[GhostField] public int CycleNumber;
/// Server tick the current timed phase ends (Expedition/Build only; 0 in Defend).
[GhostField] public uint PhaseEndTick;
/// Live Husk wave number during Defend, synced from the server-only WaveState by CyclePhaseSystem so the replicated-state-only HUD can show it (holds the last wave number outside Defend; the HUD gates the display to the Defend phase).
[GhostField] public int WaveNumber;
}
/// Phase constants for (a byte, not an enum, for trivial Burst/serialization).
public static class CyclePhase
{
/// Out in the procedural field gathering resources (timed).
public const byte Expedition = 0;
/// The base is under assault by a Husk wave (ends when the wave is cleared).
public const byte Defend = 1;
/// Calm at base: spend resources to build/upgrade (timed).
public const byte Build = 2;
/// Expedition phase duration in server ticks (SimulationTickRate = 60). Tunable; short for the M6 slice.
public const uint ExpeditionTicks = 3600; // ~60s cap (early return via the gate ends it sooner)
/// Build phase duration in server ticks.
public const uint BuildTicks = 1200; // ~20s
}
///
/// Server-only bookkeeping for the cycle state machine that must NOT replicate (kept separate from the
/// replicated ). Records the wave number captured when the Defend phase began so
/// the director can detect "this Defend's wave has now been spawned and cleared".
///
public struct CycleRuntime : IComponentData
{
/// WaveState.WaveNumber captured at the moment the current Defend phase started.
public int DefendStartWave;
/// Cycle phase from the previous tick — lets ExpeditionFieldSystem edge-detect entering/leaving Expedition.
public byte PrevPhase;
/// CycleNumber the expedition field was last seeded for (compared by int equality, never tick math).
public int LastSpawnedCycle;
}
}