From d9fbb67f0cac0e17cb282000735df03737fbd4ba Mon Sep 17 00:00:00 2001 From: gamer147 Date: Mon, 1 Jun 2026 10:33:34 -0400 Subject: [PATCH] feat(battle-node): typed MatchedBody + Self/Oppo info records --- .../Protocol/Bodies/MatchedBody.cs | 36 +++++++ .../Protocol/Bodies/MatchedBodyTests.cs | 99 +++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 SVSim.BattleNode/Protocol/Bodies/MatchedBody.cs create mode 100644 SVSim.UnitTests/BattleNode/Protocol/Bodies/MatchedBodyTests.cs diff --git a/SVSim.BattleNode/Protocol/Bodies/MatchedBody.cs b/SVSim.BattleNode/Protocol/Bodies/MatchedBody.cs new file mode 100644 index 0000000..a5e9e80 --- /dev/null +++ b/SVSim.BattleNode/Protocol/Bodies/MatchedBody.cs @@ -0,0 +1,36 @@ +using System.Text.Json.Serialization; + +namespace SVSim.BattleNode.Protocol.Bodies; + +public sealed record MatchedBody( + [property: JsonPropertyName("selfInfo")] MatchedSelfInfo SelfInfo, + [property: JsonPropertyName("oppoInfo")] MatchedOppoInfo OppoInfo, + [property: JsonPropertyName("selfDeck")] IReadOnlyList SelfDeck, + [property: JsonPropertyName("resultCode")] int ResultCode = 1) : IMsgBody; + +public sealed record MatchedSelfInfo( + [property: JsonPropertyName("country_code")] string CountryCode, + [property: JsonPropertyName("userName")] string UserName, + [property: JsonPropertyName("sleeveId")] string SleeveId, + [property: JsonPropertyName("emblemId")] string EmblemId, + [property: JsonPropertyName("degreeId")] string DegreeId, + [property: JsonPropertyName("fieldId")] int FieldId, + [property: JsonPropertyName("isOfficial")] int IsOfficial, + [property: JsonPropertyName("oppoId")] long OppoId, + [property: JsonPropertyName("seed")] long Seed); + +public sealed record MatchedOppoInfo( + [property: JsonPropertyName("country_code")] string CountryCode, + [property: JsonPropertyName("userName")] string UserName, + [property: JsonPropertyName("sleeveId")] string SleeveId, + [property: JsonPropertyName("emblemId")] string EmblemId, + [property: JsonPropertyName("degreeId")] string DegreeId, + [property: JsonPropertyName("fieldId")] int FieldId, + [property: JsonPropertyName("isOfficial")] int IsOfficial, + [property: JsonPropertyName("oppoId")] long OppoId, + [property: JsonPropertyName("seed")] long Seed, + [property: JsonPropertyName("oppoDeckCount")] int OppoDeckCount); + +public sealed record DeckCardRef( + [property: JsonPropertyName("idx")] int Idx, + [property: JsonPropertyName("cardId")] long CardId); diff --git a/SVSim.UnitTests/BattleNode/Protocol/Bodies/MatchedBodyTests.cs b/SVSim.UnitTests/BattleNode/Protocol/Bodies/MatchedBodyTests.cs new file mode 100644 index 0000000..5dc6afc --- /dev/null +++ b/SVSim.UnitTests/BattleNode/Protocol/Bodies/MatchedBodyTests.cs @@ -0,0 +1,99 @@ +using System.Text.Json; +using System.Text.Json.Nodes; +using NUnit.Framework; +using SVSim.BattleNode.Protocol.Bodies; + +namespace SVSim.UnitTests.BattleNode.Protocol.Bodies; + +[TestFixture] +public class MatchedBodyTests +{ + [Test] + public void Serializes_AllSelfInfoFields_WithCorrectWireKeys() + { + var body = new MatchedBody( + SelfInfo: new MatchedSelfInfo( + CountryCode: "KOR", UserName: "Player", SleeveId: "3000011", + EmblemId: "701441011", DegreeId: "300003", FieldId: 43, + IsOfficial: 0, OppoId: 847666884L, Seed: 17_548_138L), + OppoInfo: new MatchedOppoInfo( + CountryCode: "JPN", UserName: "Opponent", SleeveId: "704141010", + EmblemId: "400001100", DegreeId: "120027", FieldId: 5, + IsOfficial: 0, OppoId: 906243102L, Seed: 17_548_138L, OppoDeckCount: 30), + SelfDeck: new[] { new DeckCardRef(Idx: 1, CardId: 100011010L) }); + + var node = (JsonObject)JsonSerializer.SerializeToNode(body)!; + var selfInfo = (JsonObject)node["selfInfo"]!; + + Assert.That(selfInfo["country_code"]!.GetValue(), Is.EqualTo("KOR")); + Assert.That(selfInfo["userName"]!.GetValue(), Is.EqualTo("Player")); + Assert.That(selfInfo["sleeveId"]!.GetValue(), Is.EqualTo("3000011")); + Assert.That(selfInfo["emblemId"]!.GetValue(), Is.EqualTo("701441011")); + Assert.That(selfInfo["degreeId"]!.GetValue(), Is.EqualTo("300003")); + Assert.That(selfInfo["fieldId"]!.GetValue(), Is.EqualTo(43)); + Assert.That(selfInfo["isOfficial"]!.GetValue(), Is.EqualTo(0)); + Assert.That(selfInfo["oppoId"]!.GetValue(), Is.EqualTo(847666884L)); + Assert.That(selfInfo["seed"]!.GetValue(), Is.EqualTo(17_548_138L)); + } + + [Test] + public void OppoInfo_HasOppoDeckCount_OnTheWire() + { + var body = new MatchedBody( + SelfInfo: new MatchedSelfInfo("KOR","P","s","e","d",0,0,1L,1L), + OppoInfo: new MatchedOppoInfo("JPN","O","s","e","d",0,0,1L,1L, OppoDeckCount: 30), + SelfDeck: System.Array.Empty()); + + var node = (JsonObject)JsonSerializer.SerializeToNode(body)!; + var oppoInfo = (JsonObject)node["oppoInfo"]!; + + Assert.That(oppoInfo["oppoDeckCount"]!.GetValue(), Is.EqualTo(30)); + } + + [Test] + public void SelfInfo_DoesNotHaveOppoDeckCount_OnTheWire() + { + var body = new MatchedBody( + SelfInfo: new MatchedSelfInfo("KOR","P","s","e","d",0,0,1L,1L), + OppoInfo: new MatchedOppoInfo("JPN","O","s","e","d",0,0,1L,1L,30), + SelfDeck: System.Array.Empty()); + + var node = (JsonObject)JsonSerializer.SerializeToNode(body)!; + var selfInfo = (JsonObject)node["selfInfo"]!; + + Assert.That(selfInfo.ContainsKey("oppoDeckCount"), Is.False); + } + + [Test] + public void ResultCode_DefaultsToOne_OnConstruction() + { + var body = new MatchedBody( + SelfInfo: new MatchedSelfInfo("KOR","P","s","e","d",0,0,1L,1L), + OppoInfo: new MatchedOppoInfo("JPN","O","s","e","d",0,0,1L,1L,30), + SelfDeck: System.Array.Empty()); + + Assert.That(body.ResultCode, Is.EqualTo(1)); + var node = (JsonObject)JsonSerializer.SerializeToNode(body)!; + Assert.That(node["resultCode"]!.GetValue(), Is.EqualTo(1)); + } + + [Test] + public void SelfDeck_SerializesAsArray_WithIdxAndCardIdKeys() + { + var body = new MatchedBody( + SelfInfo: new MatchedSelfInfo("KOR","P","s","e","d",0,0,1L,1L), + OppoInfo: new MatchedOppoInfo("JPN","O","s","e","d",0,0,1L,1L,30), + SelfDeck: new[] + { + new DeckCardRef(Idx: 1, CardId: 100011010L), + new DeckCardRef(Idx: 2, CardId: 100011010L), + }); + + var node = (JsonObject)JsonSerializer.SerializeToNode(body)!; + var deck = (JsonArray)node["selfDeck"]!; + + Assert.That(deck.Count, Is.EqualTo(2)); + Assert.That(((JsonObject)deck[0]!)["idx"]!.GetValue(), Is.EqualTo(1)); + Assert.That(((JsonObject)deck[0]!)["cardId"]!.GetValue(), Is.EqualTo(100011010L)); + } +}