From 538099ff4b986b4705fce422b20b68dd6aa5c8fc Mon Sep 17 00:00:00 2001 From: gamer147 Date: Wed, 3 Jun 2026 14:17:20 -0400 Subject: [PATCH] refactor(battle-node): extract TurnEndHandler --- SVSim.BattleNode/Sessions/BattleSession.cs | 1 + .../Dispatch/Handlers/TurnEndHandler.cs | 41 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 SVSim.BattleNode/Sessions/Dispatch/Handlers/TurnEndHandler.cs diff --git a/SVSim.BattleNode/Sessions/BattleSession.cs b/SVSim.BattleNode/Sessions/BattleSession.cs index ece7532..33e90b1 100644 --- a/SVSim.BattleNode/Sessions/BattleSession.cs +++ b/SVSim.BattleNode/Sessions/BattleSession.cs @@ -40,6 +40,7 @@ public sealed class BattleSession [NetworkBattleUri.InitBattle] = new InitBattleHandler(), [NetworkBattleUri.Loaded] = new LoadedHandler(), [NetworkBattleUri.Swap] = new SwapHandler(), + [NetworkBattleUri.TurnEnd] = new TurnEndHandler(), }; private FrameDispatchContext BuildContext(IBattleParticipant from, MsgEnvelope env) => diff --git a/SVSim.BattleNode/Sessions/Dispatch/Handlers/TurnEndHandler.cs b/SVSim.BattleNode/Sessions/Dispatch/Handlers/TurnEndHandler.cs new file mode 100644 index 0000000..9f29501 --- /dev/null +++ b/SVSim.BattleNode/Sessions/Dispatch/Handlers/TurnEndHandler.cs @@ -0,0 +1,41 @@ +using SVSim.BattleNode.Protocol; + +namespace SVSim.BattleNode.Sessions.Dispatch.Handlers; + +internal sealed class TurnEndHandler : IFrameHandler +{ + public IReadOnlyList Handle(FrameDispatchContext ctx) + { + // case 4: Bot — Judge to sender only (no real opponent; client flips back to its local AI). + 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;`). + if (ctx.SenderPhase == BattleSessionPhase.AfterReady) + { + if (ctx.Type == BattleType.Pvp && ctx.BothAfterReady()) + { + var te = BattleFrames.BuildTurnEndBroadcast(); + var jg = BattleFrames.BuildJudgeBroadcast(); + return new[] + { + new DispatchRoute(ctx.From, te, false), + new DispatchRoute(ctx.Other, te, false), + new DispatchRoute(ctx.From, jg, false), + new DispatchRoute(ctx.Other, jg, false), + }; + } + if (ctx.Type == BattleType.Scripted) + return new[] { new DispatchRoute(ctx.Other, ctx.Env, false) }; + + return Array.Empty(); // 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(); + } +}