Commit Graph

8 Commits

Author SHA1 Message Date
gamer147
7d4da69f22 refactor(battlenode): low-churn §B/§D/§E/§F quality cleanups
Behavior-preserving; 231 BattleNode tests green.

- §D: MsgEnvelope.Try -> RetryAttempt (drops keyword-escape; wire key stays "try");
  SocketIoFrame.AckResponse arg -> pubSeqEcho.
- §B: Gungnir.EmitInterval -> BattleNodeOptions.AliveEmitInterval (unused literal
  moved to its config home); deck-idx 4L -> InitialHand.Length + 1.
- §E: shared Wire.WireJsonOptions.CamelCase replaces the duplicated camelCase
  JsonSerializerOptions in EngineIoHandshake and MsgEnvelope.
- §F: do-NOT-consistency-fix polarity notes on TurnEndFinalHandler (From wins)
  and RetireKillHandler (From loses).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 23:06:44 -04:00
gamer147
e70f32db79 refactor(battlenode): close §A boolean-blindness items (MinedToken, Stock, KeyActionType)
Behavior-preserving; 231 BattleNode tests green.

- MinedToken record struct replaces the transpose-prone (int Idx, long CardId,
  CardOwner IsSelf) tuple returned by KnownListBuilder.Mine*. Positional deconstruct
  keeps the Record*From call sites unchanged.
- enum Stock { Normal, Bypass } replaces the negative `bool noStock` on
  IBattleParticipant.PushAsync and DispatchRoute, threaded through both participants,
  BattleSession, and all handler construction sites.
- enum KeyActionType mirrors the client's SendKeyActionDataManager.KeyActionType;
  the StripKeyActionForOpponent guard compares named values, KeyActionEntry.Type is
  the enum (wire-identical via JsonNumberEnumConverter).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 22:53:32 -04:00
gamer147
f21ab7a38c refactor(battle-node): remove ScriptedBotParticipant and dev-affordance wiring
Deletes the scripted opponent and every entry point that created a
BattleType.Scripted session (the ?scripted=1 query opt-in, the
SoloDefaultsToScripted toggle, the resolver short-circuit, the WS handler case,
the bridge validation arm). Real two-client PvP and the Bot matchmaking-timeout
fallback are untouched. ResolveAsync drops its scriptedOptIn parameter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 20:15:48 -04:00
gamer147
8f270a87f0 refactor(battle-node): gate WS diagnostic logging behind config flag
The temporary [sio-in] / [sio-out] / [ws-rx-text] / [ws-rx-bin] /
[ws-recv-exit] / [ws-loop-exit] logs added during the hand-ack
investigation are useful enough to keep around (PvP testing, future WS
debugging) but too chatty to leave on by default. Promote them from
"strip before merge" to a permanent opt-in.

New BattleNodeOptions.DiagnosticLogging (bool, default false). Wired
through BattleNodeWebSocketHandler to RealParticipant via a new optional
ctor parameter (default false — existing test sites pick up the silent
default with no changes). Every Information/Warning log added during the
investigation is now if-gated; non-diagnostic logs (the decode-failure
warnings, the dispatch-drop debug) stay as-is.

Toggle via appsettings*.json:
  "BattleNode": { "DiagnosticLogging": true }

Or live via the singleton:
  factory.Services.GetRequiredService<BattleNodeOptions>().DiagnosticLogging = true

175 battle-node tests still passing — existing tests use the constructor
default and emit nothing, so no test changes were required.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 16:49:17 -04:00
gamer147
0095bdf0cf feat(arena-tk2): SoloDefaultsToScripted config flag for dev convenience
Adds BattleNodeOptions.SoloDefaultsToScripted (default false). When true,
the TK2 do_matching controller treats every solo poll as if ?scripted=1
were passed and returns a Scripted 3004 match immediately — useful for
the live client (which can't append query params) to drive the scripted
bot without needing a second player.

Toggle via "BattleNode:SoloDefaultsToScripted" in appsettings*.json
(Program.cs now binds the BattleNode section over the AddBattleNode
defaults). Turn off to test real PvP with two clients.

Trade-off documented on the option: while on, two simultaneous pollers
each get their own Scripted match instead of pairing, so PvP is
effectively disabled until the flag is flipped.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 23:48:14 -04:00
gamer147
2789dc08cb feat(battle-node): WaitingRoom for PvP WS rendezvous
Per-BattleId slot keyed dict. Pair returns the first arriver to the
second; ParkAsync awaits a TCS and returns the second arriver. Timeout
defaults to BattleNodeOptions.WaitingRoomTimeout (60s); evict on timeout
keeps the dict clean. Singleton in DI; consumed by the handler in the
next task.
2026-06-01 21:55:11 -04:00
gamer147
5525dbee24 fix(battle-node): node_server_url matches prod wire format (no scheme, with path)
Prod do_matching captures (data_dumps/captures/traffic_prod_tk2_*) send
the node URL as host:port/socket.io/ with no scheme prefix —
e.g. "node06.shadowverse.jp:13560/socket.io/". BestHTTP's SocketManager
expects this exact shape; the leading ws:// we were sending plus the
missing /socket.io/ path was preventing the client from completing the
post-do_matching connect (eventually times out with "connection timed
out").

Update BattleNodeOptions default, Program.cs override, and both
controller and bridge tests to use "localhost:5148/socket.io/".

Discovered during v1 smoke walkthrough.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 01:06:40 -04:00
gamer147
d3c4b3083e feat(battle-node): IMatchingBridge + MatchingBridge mint battle id + node url 2026-05-31 22:31:04 -04:00