acdream/docs/research/2026-07-03-phase-r-session-handoff.md
2026-07-03 12:19:16 +02:00

8.6 KiB
Raw Blame History

Phase R handoff — fresh-session entry point (2026-07-03)

Read this first, then the plan of record (docs/plans/2026-07-02-retail-motion-animation-rewrite.md). This session ran the R2→R4 arc of the Phase R mandate; the fresh session picks up at R4-V4 smoke verification → R4-V5.

The mandate (user, standing)

Total overhaul of movement + animation as a VERBATIM retail port — all movement, inbound and outbound, all animation, for players/NPCs/monsters. No guessing, no approximations, no bandaids. The user cancelled the /loop self-scheduling near the end of this session — work continues on user prompts, not self-scheduled wakeups, but the drive-autonomously rules in CLAUDE.md still apply within a turn.

State at handoff (worktree vigorous-joliot-f0c3ad, branch claude/vigorous-joliot-f0c3ad)

  • Tree: CLEAN at 7016b26c (only v4-smoke.log untracked — session scratch, delete freely). Full suite green: 3,948 tests (385 Net + 425 UI + 713 App + 2,425 Core, +4 pre-existing skips).
  • R1 R2 R3 shipped (trail + commit SHAs recorded in the plan doc's stage entries). R4: V0V4 shipped, V5+V6 remain.
  • A smoke client was launched with the V4 build (ACDREAM_DUMP_MOTION=1, log v4-smoke.log in the worktree root, UTF-16) — the user had NOT yet reported an NPC-behavior verdict at handoff time. First order of business: get that verdict (or relaunch and ask). Watch items: NPC chase/wander legs, turn-to-face, melee-range stop distance (arrival is now retail cylinder distance — the old max() gate is gone).

What just landed (this session, newest first)

Commit What
7016b26c R4-V4 remote cutover: per-remote MoveToManager; RemoteMoveToDriver + PlanMoveToStart DELETED; P4 TargetTracker adapter; retail unpack_movement dispatch (head-interrupt every UM; mt 69 never touch the interpreted funnel)
a144e873 R4-V3 wire: mt 8/9 parsing (TurnToPathData), raw bitfield surfaced, mt-0 sticky trailer
addc8e97 R4-V2 the verbatim MoveToManager (33 members, 101 tests; seams listed in its final report — ctor takes the interp + 14 providers; the identity-quaternion TDD catch)
e0d2492c R4-V1 command-selection family (GetCommand + CanCharge fast-path; MoveToMath incl. the Ghidra-confirmed heading_diff mirror)
386b1ce5 R4-V0 pins P1P7 (see below)
988304e1 R4 research base (docs/research/2026-07-03-r4-moveto/ — decomp, ACE cross-ref, port plan)
30115d96 W6b fix — the "press W and stop instantly" live regression (see gotchas)
fb7beb708eff3978 R3 W0W7 + R2 Q0Q6 (see the plan doc's stage trails)

NEXT: R4-V5 — LOCAL PLAYER cutover (the delicate one)

Spec: docs/research/2026-07-03-r4-moveto/r4-port-plan.md §3 V5. ONE commit, GameWindow + PlayerMovementController, do NOT fan out (feedback_dont_parallelize_coupled_plan_slices). Shape:

  • The player gets a MoveToManager bound like remotes (the EnsureRemoteMotionBindings block at GameWindow is the reference wiring; the player's Motion/seams already exist from R3 — DefaultSink is bound, _playerController.Motion exposed).
  • B.6 auto-walk DELETED: DriveServerAutoWalk + BeginServerAutoWalk
    • the _autoWalk* fields + the local mt-6 branch in GameWindow (BeginServerAutoWalk call site) + the two relocated constants (AutoWalkArrivalEpsilon, AutoWalkTurnRateFor — marked V5-scope in the controller).
  • P1 pin applies here: port the missing tail of retail's CPhysics::SetObjectMovement gate — DROP any 0xF74C event whose wire IsAutonomous byte is set when guid == local player (parsed at UpdateMotion.cs isAutonomous, relayed by WorldSession, consumed NOWHERE yet). That's what makes retail's unconditional head-interrupt safe against ACE's mt-0 echo. V0-pins.md P1 has the full adjudication + the LoseControlToServer note. This RETIRES the informal "don't cancel on non-MoveTo" comment block in the local UM branch.
  • TS-36 retires (InterruptCurrentMovement bound for the player); AD-26 retires; AD-27/AP-23 re-anchor.
  • Movement keys auto-cancel a server MoveTo (retail: the CommandInterpreter DoMotion's cancel bit → interrupt → CancelMoveTo — the edge-driven W6 input already calls DoMotion with ctor-default params whose CancelMoveTo is TRUE, so this may fall out for free — verify, don't assume).
  • Tests: the V2 harness pattern for the player-side bind; the W6 edge-driven regression suite (W6EdgeDrivenMovementTests.cs) is the template for controller-level tests with a real sink.
  • Then V6: register/roadmap/plan/memory sweep (V6 spec in the plan). After V6, R4 is done → R5 (MovementSystem facade + StickyManager + ConstraintManager + TargetManager full port), R6 (per-tick UpdateObjectInternal order — retires the 300ms stop window, PlanFromVelocity AP-80, ObservedOmega AP-76, AP-75/AP-77 velocity adaptations), R7 (outbound cadence TS-33), R8 (audit + final visual pass).

Pending user verifications (visual passes)

  1. V4 smoke verdict (see above — NPC movement).
  2. R2+R3 combined visual pass (task #9): jump instant-Falling engage, walk-off-ledge momentum (NEW behavior), running-in-circles blend, stop settle, strafe pacing (EXPECTED-DIFF: #45's 1.248× factor retired — local now matches remotes), retail-observer view (no rubber-band). Partially confirmed ("works a lot better now") after the W6b fix.

Load-bearing gotchas from this session (do not relearn these)

  1. BN hoisted-register artifact class (caused the W6b live bug): the pseudo-C renders pre-call register caches as post-call field reads. ApplyInterpretedMovement must ENTRY-CACHE the axis values — the style dispatch's ApplyMotion(style) resets forward to Ready (verbatim, raw 0051ea6c) and retail self-heals via the cached fwd re-apply. The 183-case suite can NOT catch sink-result-dependent bugs: its RecordingSink's bool return doesn't mirror the real MotionTableDispatchSink (style dispatches return TRUE → the resetting state-write runs). Regression suite: W6EdgeDrivenMovementTests.cs.
  2. The dispatch RESULT gates queue+state writes (W5 discovery): IInterpretedMotionSink.ApplyMotion/StopMotion return bool for this reason — documented on the interface.
  3. Retail's echo discriminator is the wire autonomous byte (V0 P1): not a workaround — CPhysics::SetObjectMovement 0x00509690's final branch. Port it in V5, don't invent gating.
  4. MoveToManager entry points never drain pending_actions — re-issues MUST route through PerformMovement (V2 finding, tested).
  5. default(Quaternion) is zero, not identity — heading math reads 90° off a zero quat (V2 TDD catch; IdentityPosition constant).
  6. fail_progress_count is WRITE-ONLY in retail — there is no MoveTo give-up threshold; do not invent one.
  7. Delegation pattern that works: sonnet implementers against committed pinned specs (research → pins with adversarial verify → implement → orchestrator independently verifies scope + suite + spot-checks against the raw decomp → commit). GameWindow/controller coupled surgery stays with the orchestrator. Workflow tool for research fan-outs (r3/r4 extraction + pin workflows are the templates).
  8. py (not python) exists on this box; logs from Tee-Object are UTF-16; heredocs with quotes inside python strings break — write scripts to the scratchpad with the Write tool and run py file.py.
  9. Ghidra MCP (port 8080/8081, needs the user to open patchmem.gpr): used live this session for heading_diff/get_desired_heading (ghidra-confirmations.md). Ask the user to open it when a BN garble blocks a pin.
  10. ACE session care: graceful client close (CloseMainWindow) or ACE holds the session ~3 min (exit 29 on relaunch). Don't kill clients the user launched — ask.

Key file map (R4 additions)

  • src/AcDream.Core/Physics/Motion/MoveToManager.cs + MoveToNode.cs — the V2 port (seams doc'd on the ctor).
  • src/AcDream.Core/Physics/Motion/MoveToMath.cs — heading/cylinder math
    • OriginToWorld (relocated from the deleted RemoteMoveToDriver).
  • src/AcDream.Core/Physics/Motion/MovementParameters.csGetCommand / FromWire / FromWireTurnTo / GetDesiredHeading / TowardsAndAway.
  • docs/research/2026-07-03-r4-moveto/ — decomp + ACE cross-ref + port plan + V0-pins.md + ghidra-confirmations.md.
  • GameWindow: EnsureRemoteMotionBindings (the full per-remote wiring reference), the remote UM dispatch (mt 69 vs mt-0 funnel), the per-tick tracker+UseTime block.