fix(net): VectorUpdate parser was reading guid from opcode bytes — remote jumps invisible
User report: "in ACdream client, when other client is jumping,
nothing happens at all".
Diagnostic [VU.recv] revealed the parser was reading
guid = 0x0000F74E (= the opcode itself) and velocity values in
the billions:
[VU.recv] guid=0x0000F74E vel=(8589944832.00,0.00,0.00)
isLocal=False hasRemote=False
WorldSession.ProcessDatagram passes the FULL reassembled body
including the 4-byte opcode at offset 0 — every other parser
in src/AcDream.Core.Net/Messages/ verifies the opcode word
before reading payload (UpdateMotion.TryParse:77,
UpdatePosition.TryParse, etc.). VectorUpdate.TryParse skipped
that step and read every field shifted four bytes early,
making the guid the opcode bytes and the velocities random
floats from later in the buffer. With guid=0xF74E never
matching any tracked entity, OnLiveVectorUpdated returned
early and remote jumps rendered nothing.
Fix: read + verify opcode at offset 0 in TryParse, then read
guid at offset 4, velocity at 8/12/16, omega at 20/24/28,
sequences at 32/34. Body length now 4 (opcode) + 32 (payload).
Tests stay 1222 green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
68d521df4f
commit
0ebf0cad09
1 changed files with 24 additions and 13 deletions
|
|
@ -39,27 +39,38 @@ public static class VectorUpdate
|
|||
ushort VectorSequence);
|
||||
|
||||
/// <summary>
|
||||
/// Parse a 0xF74E body. Returns null if the buffer is truncated or
|
||||
/// malformed (sequence-number mismatch is not checked here — the
|
||||
/// session-level handler decides what to do).
|
||||
/// Parse a 0xF74E body. <paramref name="body"/> must start with the
|
||||
/// 4-byte opcode (matches the convention used by UpdateMotion /
|
||||
/// UpdatePosition / etc.). Returns null on truncation or opcode
|
||||
/// mismatch.
|
||||
/// </summary>
|
||||
public static Parsed? TryParse(ReadOnlySpan<byte> body)
|
||||
{
|
||||
if (body.Length < 32) return null;
|
||||
// K-fix16 (2026-04-26): body convention includes the opcode at
|
||||
// offset 0 — every other parser in this folder verifies the
|
||||
// opcode word before reading payload fields. The previous
|
||||
// version of this method skipped that, reading guid from the
|
||||
// opcode bytes (and shifting every subsequent field by 4),
|
||||
// which is why VU.recv lines showed guid=0xF74E and gigantic
|
||||
// garbage velocity values.
|
||||
if (body.Length < 4 + 32) return null;
|
||||
try
|
||||
{
|
||||
uint guid = BinaryPrimitives.ReadUInt32LittleEndian(body[..4]);
|
||||
uint opcode = BinaryPrimitives.ReadUInt32LittleEndian(body.Slice(0, 4));
|
||||
if (opcode != Opcode) return null;
|
||||
|
||||
float vx = BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(body.Slice(4, 4)));
|
||||
float vy = BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(body.Slice(8, 4)));
|
||||
float vz = BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(body.Slice(12, 4)));
|
||||
uint guid = BinaryPrimitives.ReadUInt32LittleEndian(body.Slice(4, 4));
|
||||
|
||||
float ox = BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(body.Slice(16, 4)));
|
||||
float oy = BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(body.Slice(20, 4)));
|
||||
float oz = BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(body.Slice(24, 4)));
|
||||
float vx = BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(body.Slice(8, 4)));
|
||||
float vy = BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(body.Slice(12, 4)));
|
||||
float vz = BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(body.Slice(16, 4)));
|
||||
|
||||
ushort instSeq = BinaryPrimitives.ReadUInt16LittleEndian(body.Slice(28, 2));
|
||||
ushort vecSeq = BinaryPrimitives.ReadUInt16LittleEndian(body.Slice(30, 2));
|
||||
float ox = BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(body.Slice(20, 4)));
|
||||
float oy = BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(body.Slice(24, 4)));
|
||||
float oz = BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(body.Slice(28, 4)));
|
||||
|
||||
ushort instSeq = BinaryPrimitives.ReadUInt16LittleEndian(body.Slice(32, 2));
|
||||
ushort vecSeq = BinaryPrimitives.ReadUInt16LittleEndian(body.Slice(34, 2));
|
||||
|
||||
return new Parsed(guid, new Vector3(vx, vy, vz), new Vector3(ox, oy, oz), instSeq, vecSeq);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue