refactor(battle-node): replace int IsSelf with CardOwner enum on mined-token tuples
MineAddOps/MineChoicePicks/MineCopyTokens return types and all extraction casts changed from int to CardOwner. The 4 routing comparisons in BattleSessionState now read isSelf == CardOwner.Self instead of isSelf == 1. No wire or behavioral change — CardOwner was already in use on the wire-facing side (OppoTargetEntry, UnapprovedCardEntry); this extends it to the internal mining path so the bare-int transpose risk is gone. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using SVSim.BattleNode.Lifecycle;
|
||||
using SVSim.BattleNode.Protocol;
|
||||
using SVSim.BattleNode.Sessions;
|
||||
|
||||
namespace SVSim.BattleNode.Sessions.Dispatch;
|
||||
@@ -84,7 +85,7 @@ internal sealed class BattleSessionState
|
||||
public void RecordTokensFrom(IBattleParticipant from, IBattleParticipant other, object? orderList)
|
||||
{
|
||||
foreach (var (idx, cardId, isSelf) in KnownListBuilder.MineAddOps(orderList))
|
||||
RecordToken(isSelf == 1 ? from : other, idx, cardId);
|
||||
RecordToken(isSelf == CardOwner.Self ? from : other, idx, cardId);
|
||||
}
|
||||
|
||||
/// <summary>Mine + record choice/Discover-token picks (<see cref="KnownListBuilder.MineChoicePicks"/>)
|
||||
@@ -95,7 +96,7 @@ internal sealed class BattleSessionState
|
||||
public void RecordChoicePicksFrom(IBattleParticipant from, IBattleParticipant other, object? orderList, object? keyAction)
|
||||
{
|
||||
foreach (var (idx, cardId, isSelf) in KnownListBuilder.MineChoicePicks(orderList, keyAction))
|
||||
RecordToken(isSelf == 1 ? from : other, idx, cardId);
|
||||
RecordToken(isSelf == CardOwner.Self ? from : other, idx, cardId);
|
||||
}
|
||||
|
||||
/// <summary>Mine + record copy/clone-token identities (<see cref="KnownListBuilder.MineCopyTokens"/>)
|
||||
@@ -112,6 +113,6 @@ internal sealed class BattleSessionState
|
||||
var selfMap = GetOrSeedDeckMap(from);
|
||||
var otherMap = GetOrSeedDeckMap(other);
|
||||
foreach (var (idx, cardId, isSelf) in KnownListBuilder.MineCopyTokens(orderList, selfMap, otherMap))
|
||||
RecordToken(isSelf == 1 ? from : other, idx, cardId);
|
||||
RecordToken(isSelf == CardOwner.Self ? from : other, idx, cardId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ internal static class KnownListBuilder
|
||||
/// <c>idx</c>-is-list guards. This is the only place a freshly-generated card's identity exists on
|
||||
/// the wire (bullet-3 audit F1; producing code <c>RegisterToken</c>/<c>RegisterActionBase</c>) —
|
||||
/// the played-card op itself never carries a <c>cardId</c>.</summary>
|
||||
public static IEnumerable<(int Idx, long CardId, int IsSelf)> MineAddOps(object? orderList)
|
||||
public static IEnumerable<(int Idx, long CardId, CardOwner IsSelf)> MineAddOps(object? orderList)
|
||||
{
|
||||
if (orderList is not IEnumerable<object?> ops) yield break;
|
||||
foreach (var op in ops)
|
||||
@@ -64,7 +64,7 @@ internal static class KnownListBuilder
|
||||
if (!opDict.TryGetValue("add", out var addRaw) || addRaw is not IDictionary<string, object?> add) continue;
|
||||
|
||||
add.TryGetValue("isSelf", out var isSelfRaw);
|
||||
var isSelf = (int)AsLong(isSelfRaw);
|
||||
var isSelf = (CardOwner)(int)AsLong(isSelfRaw);
|
||||
|
||||
if (!add.TryGetValue("card", out var cardRaw) || cardRaw is not IDictionary<string, object?> card) continue;
|
||||
if (!card.TryGetValue("cardId", out var cardIdRaw)) continue; // candidates/isChoice → no identity yet
|
||||
@@ -87,7 +87,7 @@ internal static class KnownListBuilder
|
||||
/// only gates the strip (<see cref="StripKeyActionForOpponent"/>), not the recording. An add whose
|
||||
/// candidates contain none of the picks is skipped (defensive — no record, no desync); Echo (no
|
||||
/// keyAction) yields nothing, leaving it mining-only via <see cref="MineAddOps"/>.</summary>
|
||||
public static IEnumerable<(int Idx, long CardId, int IsSelf)> MineChoicePicks(object? orderList, object? keyAction)
|
||||
public static IEnumerable<(int Idx, long CardId, CardOwner IsSelf)> MineChoicePicks(object? orderList, object? keyAction)
|
||||
{
|
||||
if (orderList is not IEnumerable<object?> ops) yield break;
|
||||
|
||||
@@ -123,7 +123,7 @@ internal static class KnownListBuilder
|
||||
if (chosen is null) continue; // no pick in this op's pool — skip (no desync, just no record)
|
||||
|
||||
add.TryGetValue("isSelf", out var isSelfRaw);
|
||||
var isSelf = (int)AsLong(isSelfRaw);
|
||||
var isSelf = (CardOwner)(int)AsLong(isSelfRaw);
|
||||
|
||||
if (!add.TryGetValue("idx", out var idxRaw) || idxRaw is not IEnumerable<object?> idxList) continue;
|
||||
foreach (var i in idxList)
|
||||
@@ -144,7 +144,7 @@ internal static class KnownListBuilder
|
||||
/// <c>candidates</c> (→ MineChoicePicks), a <c>string</c> <c>baseIdx</c> (private-group copy,
|
||||
/// <c>RegisterCopyToken.cs:19-22</c>), and a <c>baseIdx</c> absent from the chosen map (unknown source
|
||||
/// → degrade, no desync). <c>isPremium</c> (IsFoil) is cosmetic and ignored.</summary>
|
||||
public static IEnumerable<(int Idx, long CardId, int IsSelf)> MineCopyTokens(
|
||||
public static IEnumerable<(int Idx, long CardId, CardOwner IsSelf)> MineCopyTokens(
|
||||
object? orderList,
|
||||
IReadOnlyDictionary<int, long> selfMap,
|
||||
IReadOnlyDictionary<int, long> otherMap)
|
||||
@@ -162,8 +162,8 @@ internal static class KnownListBuilder
|
||||
var baseIdx = (int)AsLong(baseRaw);
|
||||
|
||||
add.TryGetValue("isSelf", out var isSelfRaw);
|
||||
var isSelf = (int)AsLong(isSelfRaw);
|
||||
var map = isSelf == 1 ? selfMap : otherMap;
|
||||
var isSelf = (CardOwner)(int)AsLong(isSelfRaw);
|
||||
var map = isSelf == CardOwner.Self ? selfMap : otherMap;
|
||||
if (!map.TryGetValue(baseIdx, out var cardId)) continue; // unknown source → degrade
|
||||
|
||||
if (!add.TryGetValue("idx", out var idxRaw) || idxRaw is not IEnumerable<object?> idxList) continue;
|
||||
|
||||
@@ -414,7 +414,7 @@ public class CaptureConformanceTests
|
||||
.MineCopyTokens(orderList, new Dictionary<int, long>(), otherMap)
|
||||
.ToList();
|
||||
|
||||
Assert.That(mined, Is.EquivalentTo(new[] { (49, 123_456_789L, 0) }));
|
||||
Assert.That(mined, Is.EquivalentTo(new[] { (49, 123_456_789L, CardOwner.Opponent) }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -131,7 +131,7 @@ public class KnownListBuilderTests
|
||||
var orderList = new List<object?> { AddOp(new[] { 31L, 32L }, 900111010L) };
|
||||
var mined = KnownListBuilder.MineAddOps(orderList).ToList();
|
||||
|
||||
Assert.That(mined, Is.EquivalentTo(new[] { (31, 900111010L, 1), (32, 900111010L, 1) }));
|
||||
Assert.That(mined, Is.EquivalentTo(new[] { (31, 900111010L, CardOwner.Self), (32, 900111010L, CardOwner.Self) }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -142,7 +142,7 @@ public class KnownListBuilderTests
|
||||
// it; the caller routes it into the OTHER side's map.
|
||||
var orderList = new List<object?> { AddOp(new[] { 31L }, 900111010L, isSelf: 0) };
|
||||
Assert.That(KnownListBuilder.MineAddOps(orderList),
|
||||
Is.EquivalentTo(new[] { (31, 900111010L, 0) }));
|
||||
Is.EquivalentTo(new[] { (31, 900111010L, CardOwner.Opponent) }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -205,7 +205,7 @@ public class KnownListBuilderTests
|
||||
AddOp(new[] { 32L }, 900811090L),
|
||||
};
|
||||
var mined = KnownListBuilder.MineAddOps(orderList).ToList();
|
||||
Assert.That(mined, Is.EquivalentTo(new[] { (31, 900111010L, 1), (32, 900811090L, 1) }));
|
||||
Assert.That(mined, Is.EquivalentTo(new[] { (31, 900111010L, CardOwner.Self), (32, 900811090L, CardOwner.Self) }));
|
||||
}
|
||||
|
||||
// A choice/Discover add op as it arrives in a RawBody: candidates-only (no concrete cardId —
|
||||
@@ -248,7 +248,7 @@ public class KnownListBuilderTests
|
||||
var keyAction = KeyActionChoice(generatingCardId: 810014030L, chosen: new[] { 810041260L }, open: 0);
|
||||
|
||||
Assert.That(KnownListBuilder.MineChoicePicks(orderList, keyAction),
|
||||
Is.EquivalentTo(new[] { (46, 810041260L, 1) }));
|
||||
Is.EquivalentTo(new[] { (46, 810041260L, CardOwner.Self) }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -260,7 +260,7 @@ public class KnownListBuilderTests
|
||||
var keyAction = KeyActionChoice(810014030L, new[] { 101041020L }, open: 0);
|
||||
|
||||
Assert.That(KnownListBuilder.MineChoicePicks(orderList, keyAction),
|
||||
Is.EquivalentTo(new[] { (46, 101041020L, 0) }));
|
||||
Is.EquivalentTo(new[] { (46, 101041020L, CardOwner.Opponent) }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -357,7 +357,7 @@ public class KnownListBuilderTests
|
||||
var selfMap = new Dictionary<int, long> { [5] = 100_011_010L };
|
||||
var otherMap = new Dictionary<int, long>();
|
||||
var mined = KnownListBuilder.MineCopyTokens(orderList, selfMap, otherMap).ToList();
|
||||
Assert.That(mined, Is.EquivalentTo(new[] { (31, 100_011_010L, 1) }));
|
||||
Assert.That(mined, Is.EquivalentTo(new[] { (31, 100_011_010L, CardOwner.Self) }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -369,7 +369,7 @@ public class KnownListBuilderTests
|
||||
var selfMap = new Dictionary<int, long>();
|
||||
var otherMap = new Dictionary<int, long> { [21] = 900_841_330L };
|
||||
var mined = KnownListBuilder.MineCopyTokens(orderList, selfMap, otherMap).ToList();
|
||||
Assert.That(mined, Is.EquivalentTo(new[] { (49, 900_841_330L, 0) }));
|
||||
Assert.That(mined, Is.EquivalentTo(new[] { (49, 900_841_330L, CardOwner.Opponent) }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -422,7 +422,7 @@ public class KnownListBuilderTests
|
||||
var orderList = new List<object?> { CopyOp(new[] { 31L, 32L }, baseIdx: 5L, isSelf: 1) };
|
||||
var selfMap = new Dictionary<int, long> { [5] = 700L };
|
||||
var mined = KnownListBuilder.MineCopyTokens(orderList, selfMap, new Dictionary<int, long>()).ToList();
|
||||
Assert.That(mined, Is.EquivalentTo(new[] { (31, 700L, 1), (32, 700L, 1) }));
|
||||
Assert.That(mined, Is.EquivalentTo(new[] { (31, 700L, CardOwner.Self), (32, 700L, CardOwner.Self) }));
|
||||
}
|
||||
|
||||
// A uList entry as it arrives in a RawBody. Minimal = the 5 always-present fields
|
||||
|
||||
Reference in New Issue
Block a user