From 486f72f4a03d6a2d0a4e7562271cbac1977bb26c Mon Sep 17 00:00:00 2001 From: gamer147 Date: Wed, 3 Jun 2026 17:51:02 -0400 Subject: [PATCH] feat(battle-node): typed PlayActionsBroadcastBody + KnownCardEntry/OppoTargetEntry Co-Authored-By: Claude Opus 4.8 --- .../Bodies/PlayActionsBroadcastBody.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 SVSim.BattleNode/Protocol/Bodies/PlayActionsBroadcastBody.cs diff --git a/SVSim.BattleNode/Protocol/Bodies/PlayActionsBroadcastBody.cs b/SVSim.BattleNode/Protocol/Bodies/PlayActionsBroadcastBody.cs new file mode 100644 index 0000000..b93f9ac --- /dev/null +++ b/SVSim.BattleNode/Protocol/Bodies/PlayActionsBroadcastBody.cs @@ -0,0 +1,30 @@ +using System.Text.Json.Serialization; + +namespace SVSim.BattleNode.Protocol.Bodies; + +/// Opponent-facing PlayActions frame the node synthesizes from the active player's +/// send. KnownList reveals the played card's identity (null = token reveal deferred, see +/// the deterministic-turn slice). OppoTargetList is the renamed targetList +/// (independent of KnownList — a targeted hand play carries both). Both omitted when null via the +/// envelope's WhenWritingNull policy. +public sealed record PlayActionsBroadcastBody( + [property: JsonPropertyName("playIdx")] int PlayIdx, + [property: JsonPropertyName("type")] int Type, + [property: JsonPropertyName("knownList")] IReadOnlyList? KnownList, + [property: JsonPropertyName("oppoTargetList")] IReadOnlyList? OppoTargetList) : IMsgBody; + +/// One revealed card in a knownList. Vanilla slice fills cardId from the sender's +/// deck map and leaves spellboost 0 / attachTarget "" (cost/clan/tribe deferred to the card-master +/// port — the receiver re-derives them from cardId). +public sealed record KnownCardEntry( + [property: JsonPropertyName("idx")] int Idx, + [property: JsonPropertyName("cardId")] long CardId, + [property: JsonPropertyName("to")] int To, + [property: JsonPropertyName("spellboost")] int Spellboost, + [property: JsonPropertyName("attachTarget")] string AttachTarget); + +/// Renamed targetList entry. isSelf is actor-relative and passes through +/// verbatim — no perspective flip (bullet-3 audit F2). +public sealed record OppoTargetEntry( + [property: JsonPropertyName("targetIdx")] int TargetIdx, + [property: JsonPropertyName("isSelf")] int IsSelf);