acdream/docs/research/2026-07-03-r4-moveto/ghidra-confirmations.md
Erik 386b1ce550 docs(R4-V0): pins P1-P7 resolved — the autonomous-byte gate IS retail's echo discriminator; heading_diff mirror Ghidra-confirmed
P1 (BLOCKER -> RESOLVED, no adaptation needed): retail's
CPhysics::SetObjectMovement (0x00509690) drops any movement event whose
wire AUTONOMOUS byte is set when the addressed object IsThePlayer -
BEFORE unpack_movement's unconditional head-interrupt ever runs. ACE's
mt-0 MoveToState echo is IsAutonomous=1 HARDCODED (MovementData.cs:162)
and only exists when the client itself sends a MoveToState (the
2026-05-14 'echo kills auto-walk' trace was the pre-#75 build whose
overlay leaked outbound packets - post-#75 there is no echo at moveto
start). acdream parses isAutonomous (UpdateMotion.cs:129) and consumes
it NOWHERE; MotionSequenceGate cites 0x00509690 in its own doc but
omitted this final branch. V-commits port the missing gate tail and the
verbatim head-cancel lands cleanly; the informal GameWindow
no-cancel-on-non-MoveTo note retires.

P3 (Ghidra-confirmed live, textual verdict independently identical):
heading_diff 0x00528fb0 HAS the TurnLeft mirror - 360-diff whenever the
turn command != TurnRight; the extraction's 'arg unused' was a BN
x87-setcc artifact (the W6b class). P2 Ghidra-confirmed:
get_desired_heading = fwd-towards 0 / fwd-away 180 / back-towards
180 / back-away 0. ghidra-confirmations.md holds both raw decompiles.
P4-P7 pinned per V0-pins.md. RemoteMoveToDriver's stale chase/flee
class-doc claim corrected (retail and ACE AGREE on the predicates).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 11:02:13 +02:00

1.9 KiB
Raw Blame History

R4-V0 — Ghidra ground-truth decompiles (patchmem.gpr, fetched live 2026-07-03)

Authoritative resolutions for the two pins the BN pseudo-C garbled. Fetched via the Ghidra MCP while the V0 pin workflow ran; these OVERRIDE any textual adjudication that disagrees.

P3 — heading_diff 0x00528fb0: the TurnLeft mirror EXISTS

float __cdecl heading_diff(float param_1, float param_2, ulong param_3)
{
  float fVar1;

  fVar1 = param_1 - param_2;
  if (ABS(param_1 - param_2) < F_EPSILON) {
    fVar1 = 0.0f;
  }
  if (fVar1 < -F_EPSILON) {
    fVar1 = fVar1 + 360.0f;            // ___real_43b40000
  }
  if ((F_EPSILON < fVar1) && (param_3 != 0x6500000d)) {
    fVar1 = 360.0f - fVar1;            // the mirror — NOT-TurnRight only
  }
  return fVar1;
}

Adjudication of the research contradiction:

  • r4-moveto-decomp.md §5g ("turn-command arg UNUSED") is WRONG — the arg gates the mirror.
  • r4-ace-moveto.md's suspicion (an x87-garbled 360diff TurnLeft branch) is CONFIRMED: the mirror applies whenever the turn command is not TurnRight (0x6500000d), i.e. the TurnLeft direction measures the complementary angle. Port verbatim with the epsilon literal 0.000199999995f (F_EPSILON).

P2 — MovementParameters::get_desired_heading 0x0052aad0: ACE-shaped constants CONFIRMED

float __thiscall MovementParameters::get_desired_heading(
    MovementParameters* this, ulong command, int movingAway)
{
  if ((command == 0x44000007) || (command == 0x45000005)) {   // Run/WalkForward
    if (movingAway == 0)
      return 0.0f;
  }
  else {
    if (command != 0x45000006)                                 // not WalkBackward
      return 0.0f;
    if (movingAway != 0)
      return 0.0f;
  }
  return 180.0f;                                               // ___real_43340000
}

Truth table: forward+towards → 0°; forward+away → 180°; backward+towards → 180°; backward+away → 0°; any other command → 0°.