feat(phys L.2g slice 1): WorldSession dispatches SetState (0xF74B) + hex probe

Three changes folded into one commit:

1. New public StateUpdated event on WorldSession + dispatcher branch
   for op == SetState.Opcode. Mirrors the VectorUpdated /
   MotionUpdated event pattern. GameWindow will subscribe in the next
   commit and feed the parsed (guid, newState) pair to
   ShadowObjectRegistry.UpdatePhysicsState.

2. One-shot probe-gated hex-dump (ACDREAM_PROBE_BUILDING) emits the
   first inbound SetState message's body bytes. Originally planned
   as a separate slice 1.5 confidence-check on holtburger's claimed
   12-byte payload vs ACE's GameMessageSetState.cs. Folded into the
   dispatcher to avoid re-touching the same branch. The new
   _setStateHexDumped guard keeps the log clean — auto-close every
   30s would otherwise produce noise.

3. Doc-comment polish on SetState.cs requested by Task 1's code
   review: remove false uncertainty about ACE's sequence-field width
   (ACE's UShortSequence.CurrentBytes provably writes 2 bytes via
   BitConverter), and align the 'total body size' phrasing with
   VectorUpdate.cs's convention. Folded here to avoid churning the
   file twice this slice.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-12 22:28:04 +02:00
parent d53891557d
commit 536a608093
2 changed files with 49 additions and 8 deletions

View file

@ -24,16 +24,18 @@ namespace AcDream.Core.Net.Messages;
/// </list>
///
/// <para>
/// Total body size: 16 bytes from start (opcode + 12-byte payload).
/// Total body size: 16 bytes (4-byte opcode + 12-byte payload).
/// </para>
///
/// <para>
/// Server-side reference:
/// <c>references/ACE/Source/ACE.Server/Network/GameMessages/Messages/GameMessageSetState.cs:8-15</c>
/// (ACE writes the same field order but appears to use <c>uint</c> for the
/// sequence fields; verified against retail format by hex-dump probe in
/// Task 5). Holtburger has been validated against a retail-format server,
/// so its 12-byte payload is the trusted spec.
/// — ACE writes the same field order using its <c>UShortSequence.CurrentBytes</c>
/// helper (which calls <c>BitConverter.GetBytes((ushort)value)</c> = 2 bytes per
/// sequence field), so its wire output matches holtburger's 12-byte payload.
/// A one-shot <c>ACDREAM_PROBE_BUILDING</c> hex-dump in
/// <see cref="WorldSession"/>'s dispatcher (added in the same commit) emits
/// the first SetState body bytes for runtime confirmation.
/// </para>
///
/// <para>
@ -69,9 +71,9 @@ public static class SetState
uint opcode = BinaryPrimitives.ReadUInt32LittleEndian(body.Slice(0, 4));
if (opcode != Opcode) return null;
uint guid = BinaryPrimitives.ReadUInt32LittleEndian(body.Slice(4, 4));
uint state = BinaryPrimitives.ReadUInt32LittleEndian(body.Slice(8, 4));
ushort instSeq = BinaryPrimitives.ReadUInt16LittleEndian(body.Slice(12, 2));
uint guid = BinaryPrimitives.ReadUInt32LittleEndian(body.Slice(4, 4));
uint state = BinaryPrimitives.ReadUInt32LittleEndian(body.Slice(8, 4));
ushort instSeq = BinaryPrimitives.ReadUInt16LittleEndian(body.Slice(12, 2));
ushort stateSeq = BinaryPrimitives.ReadUInt16LittleEndian(body.Slice(14, 2));
return new Parsed(guid, state, instSeq, stateSeq);