feat(L.2b): outbound movement wire parity — RawMotionState default-difference, JumpPack, contact byte
Ports the three retail outbound-movement packers verbatim (decomp-derived golden bytes, confirmed via the Ghidra bridge, cross-checked vs holtburger): - D1 — RawMotionState::Pack (0x0051ed10): new AcDream.Core.Physics.RawMotionState data type (11 fields + actions, retail defaults) + RawMotionStatePacker that sets a flag bit only when the field DIFFERS from its default. MoveToState.Build now takes a RawMotionState instead of presence-based nullable params, so the over-sent forwardSpeed=1.0 / currentHoldKey=None / default per-axis holdkeys are no longer emitted. num_actions packs into bits 11-15 (not "bits 11-31"). - D3 — MoveToStatePack::Pack (0x005168f0) trailing byte = (standingLongjump ? 0x02 : 0) | (contact ? 0x01 : 0); explicit contact/ standingLongjump params (standingLongjump=false honestly until the feature lands). - D4 — JumpAction rewritten to retail JumpPack::Pack (0x00516d10): extent, velocity, full Position, four u16 timestamps, align. Removed the spurious objectGuid/spellId u32s; Position is now packed (it was absent). Body 56 bytes. - Position::Pack (0x005a9640) / Frame::Pack (0x00535130) verified already-correct (cellId, origin xyz, quaternion wxyz); locked with a golden test, no change. GameWindow callers adapted minimally: build the RawMotionState from the existing MovementResult values (behavior preserved except the intended D1 omissions) and pass cellId/position/rotation to the Jump send. Pre-existing MotionInterpreter placeholder struct RawMotionState renamed LegacyRawMotionState (D6/Phase-2 scope, pure rename) to free the name for the retail-faithful type. D5 audit: confirmed a real divergence — retail SendMovementEvent (0x006b4680) stamps only last_sent_position_time after an MTS while SendPositionEvent (0x006b4770) stamps all three; acdream's NotePositionSent stamps all three on both paths. Left unchanged (comments added at both call sites), recorded as register TS-33, deferred to a dedicated cadence-port slice. Tests: RawMotionStatePackTests / MoveToStateGoldenTests / JumpActionTests / PositionPackTests + updated MoveToStateTests / AutonomousPositionTests. Full suite green (Core.Net.Tests 372, full solution 3228 passed / 4 pre-existing skips). Register: TS-24/TS-25 refreshed (packer now supports actions/style; runtime emission still deferred), TS-33 added. Roadmap L.2b shipped note added. Spec: docs/superpowers/specs/2026-06-30-movement-wire-parity-design.md (2-6) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
2c8620ea94
commit
78e163a41e
15 changed files with 1173 additions and 212 deletions
|
|
@ -9,18 +9,27 @@ namespace AcDream.Core.Net.Messages;
|
|||
/// the extent + velocity to validate the jump and replicate it to nearby
|
||||
/// clients.
|
||||
///
|
||||
/// Wire layout (from holtburger JumpActionData::pack):
|
||||
/// u32 0xF7B1 (GameAction envelope)
|
||||
/// u32 sequence
|
||||
/// u32 0xF61B (Jump sub-opcode)
|
||||
/// f32 extent (0.0–1.0 charge power)
|
||||
/// f32 velocity.x, f32 velocity.y, f32 velocity.z
|
||||
/// u16 instanceSequence
|
||||
/// u16 serverControlSequence
|
||||
/// u16 teleportSequence
|
||||
/// u16 forcePositionSequence
|
||||
/// u32 objectGuid (0 for normal jump)
|
||||
/// u32 spellId (0 for normal jump)
|
||||
/// <para>
|
||||
/// Wire layout — ports retail's <c>JumpPack::Pack</c> verbatim
|
||||
/// (<c>0x00516d10</c>, decomp lines ~284934-284963). Confirmed against the
|
||||
/// Ghidra decompile-by-address bridge during this slice (2026-06-30):
|
||||
/// </para>
|
||||
/// <list type="bullet">
|
||||
/// <item><b>GameAction envelope</b>: u32 0xF7B1, u32 sequence, u32 0xF61B</item>
|
||||
/// <item><b>f32 extent</b> (0.0-1.0 charge power)</item>
|
||||
/// <item><b>f32 velocity.x, velocity.y, velocity.z</b></item>
|
||||
/// <item><b>Position::Pack</b>: u32 cellId, f32 x, f32 y, f32 z,
|
||||
/// f32 qw, f32 qx, f32 qy, f32 qz (32 bytes)</item>
|
||||
/// <item><b>Sequences</b>: u16 instance, u16 serverControl,
|
||||
/// u16 teleport, u16 forcePosition</item>
|
||||
/// <item><b>Align to 4 bytes</b></item>
|
||||
/// </list>
|
||||
///
|
||||
/// <para>
|
||||
/// <b>D4 fix.</b> Retail's <c>JumpPack</c> does NOT pack an objectGuid or a
|
||||
/// spellId, and DOES pack the full <c>Position</c> — the pre-slice code had
|
||||
/// it backwards (two spurious trailing zero u32s, no Position at all).
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public static class JumpAction
|
||||
{
|
||||
|
|
@ -28,29 +37,45 @@ public static class JumpAction
|
|||
public const uint JumpOpcode = 0xF61Bu;
|
||||
|
||||
public static byte[] Build(
|
||||
uint gameActionSequence,
|
||||
float extent,
|
||||
Vector3 velocity,
|
||||
ushort instanceSequence,
|
||||
ushort serverControlSequence,
|
||||
ushort teleportSequence,
|
||||
ushort forcePositionSequence)
|
||||
uint gameActionSequence,
|
||||
float extent,
|
||||
Vector3 velocity,
|
||||
uint cellId,
|
||||
Vector3 position,
|
||||
Quaternion rotation,
|
||||
ushort instanceSequence,
|
||||
ushort serverControlSequence,
|
||||
ushort teleportSequence,
|
||||
ushort forcePositionSequence)
|
||||
{
|
||||
var w = new PacketWriter(48);
|
||||
var w = new PacketWriter(80);
|
||||
|
||||
w.WriteUInt32(GameActionOpcode);
|
||||
w.WriteUInt32(gameActionSequence);
|
||||
w.WriteUInt32(JumpOpcode);
|
||||
|
||||
w.WriteFloat(extent);
|
||||
w.WriteFloat(velocity.X);
|
||||
w.WriteFloat(velocity.Y);
|
||||
w.WriteFloat(velocity.Z);
|
||||
|
||||
// --- Position::Pack (0x005a9640): cellId + Frame::Pack (32 bytes) ---
|
||||
w.WriteUInt32(cellId);
|
||||
w.WriteFloat(position.X);
|
||||
w.WriteFloat(position.Y);
|
||||
w.WriteFloat(position.Z);
|
||||
// Quaternion wire order: W, X, Y, Z
|
||||
w.WriteFloat(rotation.W);
|
||||
w.WriteFloat(rotation.X);
|
||||
w.WriteFloat(rotation.Y);
|
||||
w.WriteFloat(rotation.Z);
|
||||
|
||||
w.WriteUInt16(instanceSequence);
|
||||
w.WriteUInt16(serverControlSequence);
|
||||
w.WriteUInt16(teleportSequence);
|
||||
w.WriteUInt16(forcePositionSequence);
|
||||
w.WriteUInt32(0); // objectGuid — 0 for normal jump
|
||||
w.WriteUInt32(0); // spellId — 0 for normal jump
|
||||
|
||||
w.AlignTo4();
|
||||
|
||||
return w.ToArray();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue