fix(battle-node): harden SIO parse + narrow Matched OppoId/Seed to int

#3: SocketIoFrame.Parse now range-checks the packet type char (was
unchecked cast — any char outside 0-6 produced an undefined enum
value) and uses int.TryParse for ack-id (was int.Parse — a >10-digit
ack-id threw OverflowException, tearing down the WS mid-game). Both
now throw ArgumentException consistently. The read loop in
RealParticipant wraps both EIO and SIO parse calls with try-catch so
a malformed frame is logged and skipped instead of killing the battle.

#4: MatchedSelfInfo/MatchedOppoInfo OppoId and Seed narrowed from
long to int. The client reads both with Convert.ToInt32 inside a
swallowing try/catch — any value > int.MaxValue silently dropped the
Matched event, preventing the battle from starting. Seed was already
int-range (BattleSeeds.Stable returns int); OppoId (viewer ID) is
~847M in captures, well under int.MaxValue. The narrowing cast now
happens explicitly in ServerBattleFrames.BuildMatched at the wire
boundary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-04 21:57:29 -04:00
parent e9af7af1b8
commit 99129c786c
9 changed files with 65 additions and 33 deletions

View File

@@ -14,19 +14,19 @@ public class ServerBattleFramesTests
{
var env = ServerBattleFrames.BuildMatched(FixtureCtx(), FakeOpponentCtx(),
selfViewerId: 906243102, oppoViewerId: 847666884,
battleId: "b", seed: 17_548_138L, selfDeckOrder: FixtureCtx().SelfDeckCardIds);
battleId: "b", seed: 17_548_138, selfDeckOrder: FixtureCtx().SelfDeckCardIds);
Assert.That(env.Uri, Is.EqualTo(NetworkBattleUri.Matched));
var body = (MatchedBody)env.Body;
Assert.That(body.SelfInfo.OppoId, Is.EqualTo(847666884L));
Assert.That(body.OppoInfo.OppoId, Is.EqualTo(906243102L));
Assert.That(body.SelfInfo.OppoId, Is.EqualTo(847666884));
Assert.That(body.OppoInfo.OppoId, Is.EqualTo(906243102));
Assert.That(env.Bid, Is.EqualTo("b"));
}
[Test]
public void BuildMatched_ContainsThirtyCardSelfDeck()
{
var env = ServerBattleFrames.BuildMatched(FixtureCtx(), FakeOpponentCtx(), 1, 2, "b", 17_548_138L, FixtureCtx().SelfDeckCardIds);
var env = ServerBattleFrames.BuildMatched(FixtureCtx(), FakeOpponentCtx(), 1, 2, "b", 17_548_138, FixtureCtx().SelfDeckCardIds);
var body = (MatchedBody)env.Body;
Assert.That(body.SelfDeck.Count, Is.EqualTo(30));
}
@@ -35,7 +35,7 @@ public class ServerBattleFramesTests
public void BuildMatched_deck_idxs_pair_1to30_with_context_card_ids()
{
var draftedDeck = Enumerable.Range(1, 30).Select(i => 200_000_000L + i).ToList();
var env = ServerBattleFrames.BuildMatched(FixtureCtx(draftedDeck), FakeOpponentCtx(), 1, 2, "b", 17_548_138L, draftedDeck);
var env = ServerBattleFrames.BuildMatched(FixtureCtx(draftedDeck), FakeOpponentCtx(), 1, 2, "b", 17_548_138, draftedDeck);
var body = (MatchedBody)env.Body;
for (int i = 0; i < 30; i++)
@@ -56,7 +56,7 @@ public class ServerBattleFramesTests
EmblemId = "888", DegreeId = "777", FieldId = 42, IsOfficial = 1,
};
var env = ServerBattleFrames.BuildMatched(ctx, FakeOpponentCtx(), 1, 2, "b", 17_548_138L, ctx.SelfDeckCardIds);
var env = ServerBattleFrames.BuildMatched(ctx, FakeOpponentCtx(), 1, 2, "b", 17_548_138, ctx.SelfDeckCardIds);
var body = (MatchedBody)env.Body;
Assert.That(body.SelfInfo.CountryCode, Is.EqualTo("JPN"));

View File

@@ -28,7 +28,7 @@ public class TypedBodyWireShapeTests
// with "Value cannot be null. Parameter name: source". The prod wire format
// emits envelope keys (uri first) before body keys; we must too.
var env = ServerBattleFrames.BuildMatched(FixtureCtx(), FakeOpponentCtx(),
selfViewerId: 1, oppoViewerId: 2, battleId: "b", seed: 17_548_138L,
selfViewerId: 1, oppoViewerId: 2, battleId: "b", seed: 17_548_138,
selfDeckOrder: FixtureCtx().SelfDeckCardIds);
var json = MsgEnvelope.ToJson(env);
@@ -48,7 +48,7 @@ public class TypedBodyWireShapeTests
{
var env = ServerBattleFrames.BuildMatched(FixtureCtx(), FakeOpponentCtx(),
selfViewerId: 906243102, oppoViewerId: 847666884, battleId: "597830888107",
seed: 17_548_138L, selfDeckOrder: FixtureCtx().SelfDeckCardIds);
seed: 17_548_138, selfDeckOrder: FixtureCtx().SelfDeckCardIds);
var json = MsgEnvelope.ToJson(env);
var node = JsonNode.Parse(json)!.AsObject();