feat(battle-node): cross-side gift + Echo-frame token mining

Close the two generated-token gaps that desynced PvP live test #3 (the
Forestcraft Fairy), both sourced from the 2026-06-03 decomp-validation table.

- MineAddOps now returns (idx, cardId, isSelf) and no longer drops isSelf:0.
  isSelf is the sender's perspective tag on CardObj.IsPlayer (RegisterToken.cs:22)
  and a card has one CardObj.Index, so an isSelf:0 add is the opponent's card.
- New shared BattleSessionState.RecordTokensFrom routes isSelf:1 -> sender,
  isSelf:0 -> opponent (the gift lives in the recipient's map, consulted when
  they play it). PlayActionsHandler delegates to it.
- EchoHandler now mines via the same helper but still returns no routes. An
  Echo's orderList carries the same add-op shape as a send (MakeEchoData ->
  MakeCommonSendAndEchoCardData), so MineAddOps applies verbatim; mining != relaying.

Choice/copy/private-group adds stay skipped (no concrete cardId). Full solution
963/963 green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-04 07:59:46 -04:00
parent 155ccf0a48
commit 62251482e4
7 changed files with 133 additions and 25 deletions

View File

@@ -21,10 +21,10 @@ internal sealed class PlayActionsHandler : IFrameHandler
var orderList = entries.GetValueOrDefault("orderList");
// Mine generated-token identities from this frame's add ops into the sender's idx->cardId
// map, so a token played in a LATER frame resolves its cardId (bullet-3 audit F1).
foreach (var (idx, cardId) in KnownListBuilder.MineAddOps(orderList))
ctx.State.RecordToken(ctx.From, idx, cardId);
// Mine generated-token identities from this frame's add ops into the right side's idx->cardId
// map (isSelf:1 → sender; isSelf:0 → opponent, a cross-side gift), so a token played in a LATER
// frame resolves its cardId — by whichever side ends up playing it (bullet-3 audit F1).
ctx.State.RecordTokensFrom(ctx.From, ctx.Other, orderList);
var deckMap = ctx.State.GetOrSeedDeckMap(ctx.From);
var played = KnownListBuilder.BuildPlayedCard(deckMap, playIdx, orderList);