refactor(battle-node): move handshake phase reads to per-participant
ComputeFrames now reads (from as IHasHandshakePhase)?.Phase for the four handshake arms (InitNetwork, InitBattle, Loaded, Swap) and the TurnEnd gate, transitioning the participant's Phase instead of the session's. RealParticipant implements IHasHandshakePhase via the new Phase property; the session-level BattleSession.Phase stays for the Terminal short-circuit. Scripted dispatch + wire shape unchanged (single-Real-participant case collapses to Phase 1 semantics). Test fixture migrates FakeParticipant to FakeRealParticipant for the side that drives handshake states. The bot's TurnEnd previously rode the session-level AfterReady arm; with that arm now gated on the sender's per-participant Phase (which the bot lacks), TurnEnd joins TurnStart/Judge in the scripted-bot forwarder arm so the v1.2 burst still reaches the real participant.
This commit is contained in:
@@ -10,6 +10,18 @@ using SVSim.BattleNode.Wire;
|
||||
|
||||
namespace SVSim.BattleNode.Sessions.Participants;
|
||||
|
||||
/// <summary>
|
||||
/// Marker interface implemented by participants that own a handshake-phase cursor.
|
||||
/// <see cref="BattleSession.ComputeFrames"/> reads the sender's <see cref="Phase"/>
|
||||
/// when gating the handshake-phase arms (InitNetwork / InitBattle / Loaded / Swap)
|
||||
/// and the TurnEnd-AfterReady forwarder. Bots don't implement this — they never
|
||||
/// send the gating URIs.
|
||||
/// </summary>
|
||||
internal interface IHasHandshakePhase
|
||||
{
|
||||
BattleSessionPhase Phase { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WS-backed participant. Owns the WS read loop, SIO encoding/decoding, per-WS
|
||||
/// <see cref="OutboundSequencer"/> + <see cref="InboundTracker"/>. Fires
|
||||
@@ -17,7 +29,7 @@ namespace SVSim.BattleNode.Sessions.Participants;
|
||||
/// PushAsync encodes + sends; ordered pushes get a playSeq from the sequencer,
|
||||
/// no-stock control pushes bypass it.
|
||||
/// </summary>
|
||||
public sealed class RealParticipant : IBattleParticipant
|
||||
public sealed class RealParticipant : IBattleParticipant, IHasHandshakePhase
|
||||
{
|
||||
private readonly WebSocket _ws;
|
||||
private readonly ILogger<RealParticipant> _log;
|
||||
@@ -32,9 +44,17 @@ public sealed class RealParticipant : IBattleParticipant
|
||||
/// handshake-phase synthesis (Matched / BattleStart / Deal / Swap response /
|
||||
/// Ready). Session transitions via the setter after dispatch. Defaults to
|
||||
/// AwaitingInitNetwork; only RealParticipant tracks this — bots have no phase
|
||||
/// because they never send the gating URIs.</summary>
|
||||
/// because they never send the gating URIs. Also satisfies
|
||||
/// <see cref="IHasHandshakePhase"/> (the interface BattleSession uses to gate
|
||||
/// handshake dispatch without depending on the concrete RealParticipant type).</summary>
|
||||
internal BattleSessionPhase Phase { get; set; } = BattleSessionPhase.AwaitingInitNetwork;
|
||||
|
||||
BattleSessionPhase IHasHandshakePhase.Phase
|
||||
{
|
||||
get => Phase;
|
||||
set => Phase = value;
|
||||
}
|
||||
|
||||
public event Func<MsgEnvelope, CancellationToken, Task>? FrameEmitted;
|
||||
|
||||
public RealParticipant(WebSocket ws, long viewerId, MatchContext context,
|
||||
|
||||
Reference in New Issue
Block a user