refactor(battle-node): remove scripted-bot test-stub arms from dispatch handlers

The IsScriptedBot(ctx.From) forwards in JudgeHandler/TurnStartHandler/TurnEndHandler
and the 'if Type==Scripted' raw-forward only ever fired for ScriptedBotParticipant
emissions; NoOpBot (Bot mode) never emits, so they are dead. Routing is now purely
PvP-vs-Bot. Drops the IsScriptedBot helper.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-03 20:00:41 -04:00
parent 963adbbd1b
commit ca9ad5db8f
4 changed files with 2 additions and 23 deletions

View File

@@ -32,10 +32,4 @@ internal sealed class FrameDispatchContext
internal bool BothAfterReady() =>
(A as IHasHandshakePhase)?.Phase == BattleSessionPhase.AfterReady &&
(B as IHasHandshakePhase)?.Phase == BattleSessionPhase.AfterReady;
/// <summary>True for any participant carrying the synthetic opponent viewer id — i.e. a
/// <c>ScriptedBotParticipant</c> OR a <c>NoOpBotParticipant</c>. Callers that must exclude Bot
/// mode rely on a preceding <c>Type == BattleType.Bot</c> guard. Mirrors the legacy
/// IsRealForwardableFromScripted guard.</summary>
internal bool IsScriptedBot(IBattleParticipant p) => p.ViewerId == ScriptedLifecycle.FakeOpponentViewerId;
}

View File

@@ -7,10 +7,6 @@ internal sealed class JudgeHandler : IFrameHandler
{
public IReadOnlyList<DispatchRoute> Handle(FrameDispatchContext ctx)
{
// Scripted-bot Judge (test stub): forward verbatim (carries the {spin} shape already).
if (ctx.IsScriptedBot(ctx.From))
return new[] { new DispatchRoute(ctx.Other, ctx.Env, false) };
// PvP: Judge is the handover gate. The player who sends Judge is the one TAKING OVER the
// turn (the client rule is: receive opponent TurnEnd -> SendJudge). Receiving Judge{spin}
// fires ControlTurnStartPlayer ("start MY turn"), so the {spin} must REFLECT BACK to the

View File

@@ -11,8 +11,8 @@ internal sealed class TurnEndHandler : IFrameHandler
if (ctx.Type == BattleType.Bot && ctx.SenderPhase == BattleSessionPhase.AfterReady)
return new[] { new DispatchRoute(ctx.From, BattleFrames.BuildJudgeBroadcast(), false) };
// case 8: general AfterReady arm — matches (and consumes) for any non-Bot type once the
// sender is AfterReady, even if it yields no routes (legacy `break;`).
// case 8: general AfterReady arm — PvP forwards a {turnState} TurnEnd to the opponent
// (handover gate). Any non-Pvp non-Bot type that reaches AfterReady consumes the frame.
if (ctx.SenderPhase == BattleSessionPhase.AfterReady)
{
if (ctx.Type == BattleType.Pvp && ctx.BothAfterReady())
@@ -23,16 +23,9 @@ internal sealed class TurnEndHandler : IFrameHandler
var te = ctx.Env with { Body = new TurnEndBody(TurnState: 0) };
return new[] { new DispatchRoute(ctx.Other, te, false) };
}
if (ctx.Type == BattleType.Scripted)
return new[] { new DispatchRoute(ctx.Other, ctx.Env, false) };
return Array.Empty<DispatchRoute>(); // Pvp-not-both-ready → drop (Bot already returned above)
}
// case 11: scripted-bot TurnEnd whose sender has no handshake phase (test stub) → forward.
if (ctx.IsScriptedBot(ctx.From))
return new[] { new DispatchRoute(ctx.Other, ctx.Env, false) };
return Array.Empty<DispatchRoute>();
}
}

View File

@@ -15,10 +15,6 @@ internal sealed class TurnStartHandler : IFrameHandler
return new[] { new DispatchRoute(ctx.Other, frame, false) };
}
// Scripted-bot emission (test stub path): the bot already emits the {spin} shape — forward.
if (ctx.IsScriptedBot(ctx.From))
return new[] { new DispatchRoute(ctx.Other, ctx.Env, false) };
return Array.Empty<DispatchRoute>();
}
}