diff --git a/SVSim.BattleNode/Lifecycle/ScriptedLifecycle.cs b/SVSim.BattleNode/Lifecycle/ScriptedLifecycle.cs index 0dfaa9c..a1389f6 100644 --- a/SVSim.BattleNode/Lifecycle/ScriptedLifecycle.cs +++ b/SVSim.BattleNode/Lifecycle/ScriptedLifecycle.cs @@ -6,13 +6,11 @@ using SVSim.BattleNode.Protocol.Bodies; namespace SVSim.BattleNode.Lifecycle; /// -/// v1 hand-rolled scripted opponent. Static frame builders for the five lifecycle uris -/// (Matched / BattleStart / Deal / Swap response / Ready) plus a trivial opponent TurnStart -/// the dispatch pushes after the player's TurnEnd. The values are templated from the TK2 -/// captures at data_dumps/captures/battle-traffic_tk2_regular.ndjson — anything -/// hardcoded here came from a real prod frame, with names + provenance in -/// . The player-half of Matched/BattleStart now reads from -/// instead of . +/// Server-authored battle frames pushed to the client during match setup and teardown +/// (Matched / BattleStart / Deal / Swap response / Ready) plus the post-mulligan hand +/// computation. Used by every battle mode's handshake/mulligan dispatch arms. Hardcoded +/// values are templated from the TK2 prod captures (battle-traffic_tk2_*.ndjson); see +/// for provenance. /// public static class ScriptedLifecycle { @@ -127,66 +125,6 @@ public static class ScriptedLifecycle IdxChangeSeed: ScriptedProfiles.ReadyIdxChangeSeed, Spin: ScriptedProfiles.ReadySpin)); - // --- Client-shaped emissions (legacy scripted-bot scaffolding, pending removal) so the - // session brokers the bot through the same handshake arms as a human. Bodies for the parameterless - // handshake frames are ignored by the session (it reads from.Context / phase); only - // Swap's idxList is consumed (empty = keep the dealt hand). - - public static MsgEnvelope BuildClientInitNetwork() => ClientFrame(NetworkBattleUri.InitNetwork, EmitCategory.General); - public static MsgEnvelope BuildClientInitBattle() => ClientFrame(NetworkBattleUri.InitBattle, EmitCategory.General); - public static MsgEnvelope BuildClientLoaded() => ClientFrame(NetworkBattleUri.Loaded, EmitCategory.General); - - public static MsgEnvelope BuildClientSwap() => - new(NetworkBattleUri.Swap, - ViewerId: FakeOpponentViewerId, - Uuid: WireConstants.ServerUuid, - Bid: null, - Try: 0, - Cat: EmitCategory.Battle, - PubSeq: null, - PlaySeq: null, - Body: new RawBody(new Dictionary { ["idxList"] = new List() })); - - private static MsgEnvelope ClientFrame(NetworkBattleUri uri, EmitCategory cat) => - new(uri, - ViewerId: FakeOpponentViewerId, - Uuid: WireConstants.ServerUuid, - Bid: null, - Try: 0, - Cat: cat, - PubSeq: null, - PlaySeq: null, - Body: new ResultCodeOnlyBody()); - - /// - /// First half of the v1.1 scripted opponent turn cycle: pushed after the player's - /// TurnEnd, transitions the client into "Opponent's turn…" state. Paired with - /// , which immediately follows and hands control - /// back to the player. - /// - public static MsgEnvelope BuildOpponentTurnStart() => - EnvelopeForPush(NetworkBattleUri.TurnStart, - new OpponentTurnStartBody(Spin: ScriptedProfiles.OpponentTurnStartSpin)); - - /// - /// Server-pushed TurnEnd transition that closes the opponent's turn and hands control - /// back to the player. Paired with in the v1.1 loop. - /// Wire shape from prod capture battle-traffic_tk2_regular.ndjson L18: - /// {"uri":"TurnEnd","turnState":0,"resultCode":1,"playSeq":N}. - /// - public static MsgEnvelope BuildOpponentTurnEnd() => - EnvelopeForPush(NetworkBattleUri.TurnEnd, new TurnEndBody(TurnState: 0)); - - /// - /// Server-pushed Judge frame that follows the opponent's TurnEnd and unblocks the - /// client's JudgeOperationControlTurnStartPlayer, transitioning to the - /// player's next turn. Without this frame the client hangs on "Opponent's turn…" — - /// see data_dumps/captures/battle-traffic.ndjson line 14 (client emits its own - /// Judge then waits forever). - /// - public static MsgEnvelope BuildOpponentJudge() => - EnvelopeForPush(NetworkBattleUri.Judge, new JudgeBody(Spin: ScriptedProfiles.OpponentJudgeSpin)); - private static IReadOnlyList BuildPosIdxList(IReadOnlyList hand) { var list = new List(hand.Count); diff --git a/SVSim.BattleNode/Lifecycle/ScriptedProfiles.cs b/SVSim.BattleNode/Lifecycle/ScriptedProfiles.cs index b41c100..3f4b419 100644 --- a/SVSim.BattleNode/Lifecycle/ScriptedProfiles.cs +++ b/SVSim.BattleNode/Lifecycle/ScriptedProfiles.cs @@ -24,11 +24,6 @@ internal static class ScriptedProfiles public const int ReadyIdxChangeSeed = 771_335_280; public const int ReadySpin = 243; - // Generic non-zero spin that lands the client in "Opponent's turn..." - // display state. v1 doesn't simulate the opponent — once this lands, - // the client sits there indefinitely. - public const int OpponentTurnStartSpin = 100; - /// /// Server-pushed Judge frame spin value. Prod varies per push (55, 175, 73, ...) — it's /// an animation seed, not a stateful value. Fixed at 100 here for test stability; diff --git a/SVSim.BattleNode/Sessions/BattleType.cs b/SVSim.BattleNode/Sessions/BattleType.cs index 2a4e5fb..ea6fd83 100644 --- a/SVSim.BattleNode/Sessions/BattleType.cs +++ b/SVSim.BattleNode/Sessions/BattleType.cs @@ -14,9 +14,4 @@ public enum BattleType /// path; matched only in rank rotation / rank unlimited per prod). Server is /// ack-only. p2 must be null. Bot, - - /// One real player; server scripts the opponent (today's v1.2 - /// behaviour, preserved as a solo testing harness). p2 currently null; - /// future server-driven bot config can ride on p2. - Scripted, } diff --git a/SVSim.UnitTests/BattleNode/Sessions/BattleSessionDispatchTests.cs b/SVSim.UnitTests/BattleNode/Sessions/BattleSessionDispatchTests.cs index 97d38f1..bfd1b3b 100644 --- a/SVSim.UnitTests/BattleNode/Sessions/BattleSessionDispatchTests.cs +++ b/SVSim.UnitTests/BattleNode/Sessions/BattleSessionDispatchTests.cs @@ -340,7 +340,7 @@ public class BattleSessionDispatchTests [Test] public void Pvp_TurnEndFinal_from_A_forwards_envelope_to_B_and_pushes_paired_BattleFinish() { - // Same unified handling as Scripted — A is the winner, B is the loser. + // Unified TurnEndFinal handling — A is the winner, B is the loser. var (s, a, b) = NewPvpSession(); DriveToAfterReady(s, a); DriveToAfterReady(s, b); @@ -539,7 +539,7 @@ public class BattleSessionDispatchTests [Test] public void Bot_Retire_pushes_paired_BattleFinish_RetireLose_to_player_RetireWin_to_bot() { - // Unified Retire/Kill dispatch — same paired push as Scripted and PvP. + // Unified Retire/Kill dispatch — same paired push as PvP. // NoOpBotParticipant swallows its push. var (s, a, b) = NewBotSession(); s.ComputeFrames(a, NewEnvelope(NetworkBattleUri.InitNetwork));