using Unity.Entities; using Unity.NetCode; namespace ProjectM.Simulation { /// /// MC-4 — predicted, owner-replicated melee combo state on the player (the PRIMARY offense verb). UNLIKE the dash /// (DashState is non-replicated because a dash is a STATELESS-per-tick decision), the combo is /// PATH-DEPENDENT — which chain link you are on depends on the sequence + timing of prior presses — and the bounded /// input command buffer cannot reconstruct it across a reconnect / long rollback (MC-4 review PRED-1 / ROLLBACK-1). /// So the minimal anchor is replicated as owner-predicted [GhostField]s: a rollback restores the /// authoritative combo position, then MeleeComboSystem re-simulates forward with ABSOLUTE-WRITE windows (never an /// in-place prev+1 of a non-restored field — the DashSystem idempotency idiom). The derived chain deadline /// (LockUntilTick + grace) is NOT stored. All ticks routed through TickUtil.NonZero; compared via /// only. Baked all-zero (idle). This is the player ghost's only net-new replicated melee /// state (one re-bake; in-family with DashCooldown/AbilityCooldown). /// public struct MeleeCombo : IComponentData { /// Current/last swing index: 0 = idle, 1..N = chain link. Owner-predicted so a rollback restores the /// authoritative combo position (the only legitimately path-dependent value). [GhostField] public byte Step; /// Raw ServerTick the current swing started (NonZero). Inclusive lower bound of the movement-commit /// window; also the juice edge signal and the (instant) damage frame. [GhostField] public uint SwingStartTick; /// Raw ServerTick the swing's movement-commit / recovery lock ends (NonZero). Gates the next press /// (locked while now < this) and anchors the chain window [LockUntilTick, LockUntilTick + grace). [GhostField] public uint LockUntilTick; } }