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:
@@ -15,11 +15,11 @@ public class MatchedBodyTests
|
||||
SelfInfo: new MatchedSelfInfo(
|
||||
CountryCode: "KOR", UserName: "Player", SleeveId: "3000011",
|
||||
EmblemId: "701441011", DegreeId: "300003", FieldId: 43,
|
||||
IsOfficial: false, OppoId: 847666884L, Seed: 17_548_138L),
|
||||
IsOfficial: false, OppoId: 847666884, Seed: 17_548_138),
|
||||
OppoInfo: new MatchedOppoInfo(
|
||||
CountryCode: "JPN", UserName: "Opponent", SleeveId: "704141010",
|
||||
EmblemId: "400001100", DegreeId: "120027", FieldId: 5,
|
||||
IsOfficial: false, OppoId: 906243102L, Seed: 17_548_138L, OppoDeckCount: 30),
|
||||
IsOfficial: false, OppoId: 906243102, Seed: 17_548_138, OppoDeckCount: 30),
|
||||
SelfDeck: new[] { new DeckCardRef(Idx: 1, CardId: 100011010L) });
|
||||
|
||||
var node = (JsonObject)JsonSerializer.SerializeToNode(body)!;
|
||||
@@ -32,16 +32,16 @@ public class MatchedBodyTests
|
||||
Assert.That(selfInfo["degreeId"]!.GetValue<string>(), Is.EqualTo("300003"));
|
||||
Assert.That(selfInfo["fieldId"]!.GetValue<int>(), Is.EqualTo(43));
|
||||
Assert.That(selfInfo["isOfficial"]!.GetValue<int>(), Is.EqualTo(0));
|
||||
Assert.That(selfInfo["oppoId"]!.GetValue<long>(), Is.EqualTo(847666884L));
|
||||
Assert.That(selfInfo["seed"]!.GetValue<long>(), Is.EqualTo(17_548_138L));
|
||||
Assert.That(selfInfo["oppoId"]!.GetValue<int>(), Is.EqualTo(847666884));
|
||||
Assert.That(selfInfo["seed"]!.GetValue<int>(), Is.EqualTo(17_548_138));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OppoInfo_HasOppoDeckCount_OnTheWire()
|
||||
{
|
||||
var body = new MatchedBody(
|
||||
SelfInfo: new MatchedSelfInfo("KOR","P","s","e","d",0,false,1L,1L),
|
||||
OppoInfo: new MatchedOppoInfo("JPN","O","s","e","d",0,false,1L,1L, OppoDeckCount: 30),
|
||||
SelfInfo: new MatchedSelfInfo("KOR","P","s","e","d",0,false,1,1),
|
||||
OppoInfo: new MatchedOppoInfo("JPN","O","s","e","d",0,false,1,1, OppoDeckCount: 30),
|
||||
SelfDeck: System.Array.Empty<DeckCardRef>());
|
||||
|
||||
var node = (JsonObject)JsonSerializer.SerializeToNode(body)!;
|
||||
@@ -54,8 +54,8 @@ public class MatchedBodyTests
|
||||
public void SelfInfo_DoesNotHaveOppoDeckCount_OnTheWire()
|
||||
{
|
||||
var body = new MatchedBody(
|
||||
SelfInfo: new MatchedSelfInfo("KOR","P","s","e","d",0,false,1L,1L),
|
||||
OppoInfo: new MatchedOppoInfo("JPN","O","s","e","d",0,false,1L,1L,30),
|
||||
SelfInfo: new MatchedSelfInfo("KOR","P","s","e","d",0,false,1,1),
|
||||
OppoInfo: new MatchedOppoInfo("JPN","O","s","e","d",0,false,1,1,30),
|
||||
SelfDeck: System.Array.Empty<DeckCardRef>());
|
||||
|
||||
var node = (JsonObject)JsonSerializer.SerializeToNode(body)!;
|
||||
@@ -68,8 +68,8 @@ public class MatchedBodyTests
|
||||
public void ResultCode_DefaultsToOne_OnConstruction()
|
||||
{
|
||||
var body = new MatchedBody(
|
||||
SelfInfo: new MatchedSelfInfo("KOR","P","s","e","d",0,false,1L,1L),
|
||||
OppoInfo: new MatchedOppoInfo("JPN","O","s","e","d",0,false,1L,1L,30),
|
||||
SelfInfo: new MatchedSelfInfo("KOR","P","s","e","d",0,false,1,1),
|
||||
OppoInfo: new MatchedOppoInfo("JPN","O","s","e","d",0,false,1,1,30),
|
||||
SelfDeck: System.Array.Empty<DeckCardRef>());
|
||||
|
||||
Assert.That(body.ResultCode, Is.EqualTo(1));
|
||||
@@ -81,8 +81,8 @@ public class MatchedBodyTests
|
||||
public void SelfDeck_SerializesAsArray_WithIdxAndCardIdKeys()
|
||||
{
|
||||
var body = new MatchedBody(
|
||||
SelfInfo: new MatchedSelfInfo("KOR","P","s","e","d",0,false,1L,1L),
|
||||
OppoInfo: new MatchedOppoInfo("JPN","O","s","e","d",0,false,1L,1L,30),
|
||||
SelfInfo: new MatchedSelfInfo("KOR","P","s","e","d",0,false,1,1),
|
||||
OppoInfo: new MatchedOppoInfo("JPN","O","s","e","d",0,false,1,1,30),
|
||||
SelfDeck: new[]
|
||||
{
|
||||
new DeckCardRef(Idx: 1, CardId: 100011010L),
|
||||
|
||||
Reference in New Issue
Block a user