acdream/docs/plans/2026-07-02-retail-motion-animation-rewrite.md
Erik b87726dc2c docs(R4-V6): register sweep + roadmap + plan trail - R4 SHIPPED
Register:
- Verified retired: AD-8/AD-9/AP-8/AP-9 (V4), TS-36/AD-26 (V5) - all gone.
- AD-34 widened: MoveToManager.pending_actions joins the managed-LinkedList
  row, with the MoveToNode rename note (retail MoveToManager::MovementNode,
  renamed to avoid colliding with R2's MotionNode) - V2 owed this note.
- NEW TS-39: MoveToManager.StickTo/Unstick are unbound no-op seams - a
  sticky MoveTo (wire bit 0x80) completes-and-stops instead of sticking;
  PositionManager/StickyManager bodies are R5 scope (call shapes only in
  the R4 extraction). Retires with R5.
- Re-anchored after the V5 controller deletion shifted lines: AD-25
  (:1212->:874), AP-24 (:170->:176), AP-30 (:1503->:1110), TS-21
  (:362->:311, stale-comment clause updated - V5 fixed the comment).
- AP-79 (widened in V5's commit) and the PlanFromVelocity row (V4)
  verified present.

Roadmap: Phase R entry - R4 SHIPPED 2026-07-03 (V0-V6 trail), R2+R3+R4
share the ONE pending user visual pass; next code stage R5 (MovementManager
facade + Sticky/Constraint/TargetManager).

Plan of record: R4 stage entry filled in with the full V0-V6 commit trail
+ expected-diffs for the visual pass (retail cylinder-distance stop, real
turn cycles during corrections, CanCharge walk/run legs).

Handoff doc: postscript - R4 complete, V4 smoke log analyzed clean and
deleted; memory index updated (animation deep-dive map: MoveToManager gap
CLOSED, the "three approximations" pattern retired).

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

174 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Phase R — retail motion & animation stack, ground-up reconstruction
Date: 2026-07-02. **Mandate (user, verbatim intent):** a complete new
movement + animation system, verbatim retail equivalent — all movement,
inbound and outbound, all animation, for players, NPCs, and monsters. No
frozen code, no bandaids, no guessing, no approximation. Total overhaul.
**Execution shape:** a staged verbatim RECONSTRUCTION, not a big-bang
cutover — each stage builds a retail class 1:1 with a conformance harness,
cuts consumers over, and DELETES the legacy path in the same stage. "New
system" is the destination; the client keeps running between stages. The
cdb-golden technique is proven (183/183 live-retail dispatch conformance in
S2a) and is the acceptance mechanism for every stage: the user's eyes are a
final sanity pass only.
Supersedes the L.2g S3S6 slice plan (S1/S2/S5 landed and are absorbed as
components). This doc is the plan of record; the deviation map
(`docs/research/2026-07-02-inbound-motion-deviation-map.md`), the funnel
pseudocode (`…-s2-inbound-funnel-pseudocode.md`), and the 2026-06-04
sequencer deep-dive are its research base.
## The retail module map to reconstruct (per physics object, ALL classes)
```
CPhysicsObj (local player, remote player, NPC, monster — ONE pipeline)
├─ MovementManager unpack_movement 0x00524440 (10-way dispatch),
│ │ PerformMovement, MotionDone relay
│ ├─ CMotionInterp raw_state + interpreted_state + pending_motions,
│ │ DoMotion / DoInterpretedMotion / StopInterpretedMotion,
│ │ apply_raw/interpreted/current_movement, my_run_rate,
│ │ HitGround / LeaveGround / ReportExhaustion, jump family
│ └─ MoveToManager movement types 6/7/8/9 (MoveToObject/Position,
│ TurnToObject/Heading), node stepping, arrival radii,
│ fail distance, CanCharge walk/run selection
├─ CPartArray → MotionTableManager pending_animations, add_to_queue 0x0051bfe0,
│ │ remove_redundant_links 0x0051bf20,
│ │ CheckForCompletedMotions 0x0051be00 → AnimationDone
│ └─ CMotionTable::GetObjectSequence 0x00522860
│ │ same-substate fast path (change_cycle_speed +
│ │ subtract/combine_motion), link path (get_link +
│ │ style-default double-hop), re_modify, is_allowed
│ └─ CSequence anim-node DLList, append_animation 0x00525510,
│ remove_cyclic_anims, clear_physics, velocity/omega
│ accumulators, update/update_internal + apply_physics
│ (root motion), placement frames, hook dispatch
├─ PositionManager InterpolationManager [PORTED ✓ L.3] + StickyManager
│ + ConstraintManager
└─ per-tick UpdateObjectInternal 0x005156b0 order:
CPartArray.Update (CSequence root motion) → PositionManager.adjust_offset
(chase REPLACES) → Frame.combine → UpdatePhysicsInternal → FULL transition
sweep (ALL entities — retires the remote no-sweep fork) → MovementManager.UseTime
/ CPartArray.HandleMovement / PositionManager.UseTime → process_hooks
```
## Already-verbatim components (absorbed, not rewritten)
- `MotionSequenceGate` (S1) — is_newer 3-stamp gate, live-validated.
- Inbound funnel: `MoveToInterpretedState` / `ApplyInterpretedMovement` /
`DispatchInterpretedMotion` / verbatim `contact_allows_move` (S2a) +
183-case live-trace conformance suite.
- `InterpolationManager` (L.3) — chase constants re-verified 2026-07-02.
- Outbound: `RawMotionState::Pack` default-difference, MoveToStatePack
trailer, JumpPack (L.2b/D6.2b, golden-byte tests); dual command catalogs
(L.1b); `adjust_motion`/`apply_run_to_command`/`apply_raw_movement`/
`get_state_velocity` (D6).
Everything else is reconstruction scope — especially: `AnimationSequencer`
internals (becomes the CSequence port's host or is replaced by it), the
three per-tick drive paths in `GameWindow.TickAnimations`, `RemoteMotionSink`
(temporary S2b seam — dissolves into GetObjectSequence), `RemoteMoveToDriver`,
`ServerControlledLocomotion`, the motion half of `PlayerMovementController`,
the 300 ms stop-detection window, NPC UP hard-snaps.
## Stage plan (each: pseudocode → harness → port → cutover → DELETE legacy → register sweep)
- **R1 — CSequence verbatim. SHIPPED 2026-07-02** (commits 1371c2a1 P0/P1, 778744bf P2, 5138b8fb P3, 658b91d8 P4, 9147344a P5, +P6): the verbatim core (AnimSequenceNode/CSequence/FrameOps, 56 conformance tests) + the AnimationSequencer adapter rehost deleting the legacy epsilon/stale-head/safety-cap/per-node-flag mechanisms; root motion flows through Advance(dt, Frame) = retail update(Frame*). Registers AD-33/AD-34. Node list, framerate/rate math, velocity+
omega accumulators (set/combine/subtract), update/update_internal root
motion, apply_physics, placement frames, hook dispatch. Goldens: dat
MotionData fixtures + a cdb trace of append_animation/remove_cyclic_anims
args (script pattern: tools/cdb/l2g-observer.cdb). Cutover: becomes the
sequencer core behind the existing AnimationSequencer API, then the API
narrows to retail's.
- **R2 — GetObjectSequence + MotionTableManager. SHIPPED 2026-07-02 (pending
the stage visual pass).** Fast path,
link path (restores the walk↔run link pose — old S4), re_modify (modifier
blend — retires AP-73), pending_animations + remove_redundant_links +
CheckForCompletedMotions → AnimationDone→MotionDone chain (old S3).
RemoteMotionSink's single-cycle pick DELETED — GetObjectSequence decides.
Progress: Q0 pins (dc54a3e4) + Q1 MotionState (2345da30), Q2 CMotionTable all-4-branch
GetObjectSequence + statics (98f58db9, 44 tests), Q3 MotionTableManager+
pending_animations (aa65990a, 47 tests), Q4 adapter cutover (3b9d9bb6 —
SetCycle/PlayAction → PerformMovement; Fix B / fast-path / stop-anim
fallback / G17 gate DELETED; 11-scenario trace conformance a6235a36).
Q5 RemoteMotionSink DELETED (d82f07d4 — funnel → MotionTableDispatchSink →
PerformMovement; AP-73 retired; spawn/despawn run initialize_state/
HandleExitWorld; live smoke green: MOTIONDONE chain firing in-world).
Q6 sweep done with Q5. OUTSTANDING: the ONE user visual pass (walk↔run
stride continuity, turn-while-running legs, emote overlay, stop settle).
R3 prep done in parallel: research base 8eff3978 + W0 pins cd0289be (all
10 ambiguities resolved, adversarially verified).
- **R3 — CMotionInterp completion. SHIPPED 2026-07-03 (pending the stage
visual pass).** pending_motions/MotionDone, DoMotion, jump family
(jump_charge_is_allowed/motion_allows_jump verbatim — the misattribution
found in S2a), HitGround/LeaveGround/ReportExhaustion, enter_default_state.
LOCAL PLAYER unified (edge-driven CommandInterpreter altitude; the
synthesis layer + UpdatePlayerAnimation deleted).
Trail: W-1 research 8eff3978, W0 pins cd0289be (A1-A10 adversarially
verified), W1 state completion 86649591, W2 pending_motions 37167991,
W3 jump family af476444, W4 ground transitions + K-fix18 DELETED
e214acdf, W5 one-DoInterpretedMotion + zero-tick flush df7b096d
(discovery: the dispatch RESULT gates queue+state writes — sink returns
bool), W6 local-player unification fb7beb70 (map fc5a2cda; discoveries:
ChargeJump never wired, CurrentHoldKey shadow-field staleness, the
autonomous-flag clobber). Registers through the arc: retired AP-73/
AP-74/AP-78/TS-34/IA-4 + the Fix-B-class inventions; added AD-36
(narrowed), AP-75/76/77, TS-35/36/37/38. EXPECTED-DIFFS for the visual
pass: #45 sidestep factor + ANIM_SPEED_SCALE retired (local now matches
remotes), auto-walk-at-run walk-pace legs (R4), ApplyServerRunRate echo
live through fast re-speed. R3+R2 share ONE visual pass.
- **R4 — MoveToManager verbatim. SHIPPED 2026-07-03 (pending the stage
visual pass).** Types 6/7/8/9 (TurnToObject/TurnToHeading — the dropped
D9/DEV-5 commands), node stepping, arrival, fail distance, CanCharge.
RemoteMoveToDriver + ServerControlledLocomotion.PlanMoveToStart + B.6
auto-walk all DELETED.
Trail: research base 988304e1, V0 pins 386b1ce5 (P1-P7 resolved; P1
autonomous-echo gate + P3 heading_diff mirror adversarially sealed, P3
down to instruction bytes), V1 command-selection family e0d2492c
(GetCommand + CanCharge fast-path + MoveToMath), V2 the verbatim manager
addc8e97 (all 33 members, 101 tests, seam-injected harness), V3 wire
completion a144e873 (mt 8/9 parse + full params exposure + sticky
trailer), V4 remote cutover 7016b26c (per-remote manager, P4
TargetTracker adapter, retail unpack dispatch; retired AD-8/AD-9/AP-8/
AP-9; smoke log verified clean), V5 local-player cutover b3decdfa (P1
gate ported verbatim — ACE's autonomous echo dropped before unpack;
B.6 deleted; TS-36 bound — input/jump/teleport cancel through the retail
interrupt chain; run-rate re-anchored to PD skills + mt-6/7 my_run_rate,
echo tap deleted with NO AD row; MoveToComplete client seam widened to
natural completion for AD-27; adversarial-review fixes: remote HitGround
relay, mt-8 wire_heading degrade, remote curTime clock), V6 register/
docs sweep (AD-34 widened with the MoveToNode rename, NEW TS-39 StickTo/
Unstick no-op seams → R5, TS-33 extended with the orientation-diff gap,
TS-21/AD-25/AP-24/AP-30 re-anchored). EXPECTED-DIFFS for the visual
pass: melee-range stop distance (retail cylinder distance — the AD-8
max() class is gone), auto-walk legs now walk/run per CanCharge with
real turn cycles during corrections, walk-pace close-in demote.
OUTSTANDING: the stage visual pass (folds into the pending R2+R3 pass).
- **R5 — MovementManager + MovementSystem facade.** One per-object pipeline
for every entity class; StickyManager (stick_to_object — the motionFlags
0x100 bit) + ConstraintManager ports; GameWindow's OnLiveMotionUpdated
shrinks to parse→MovementSystem.HandleMovementEvent.
- **R6 — per-tick UpdateObjectInternal order.** Retail tick order for ALL
entities incl. the transition sweep for remotes (retires the L.3-M2
no-sweep fork + the path A/B split + the 300 ms stop window + NPC UP
hard-snap special cases). GameWindow.TickAnimations sheds its motion
logic entirely (Code Structure Rule 1).
- **R7 — outbound autonomy cadence.** ShouldSendPositionEvent (0x006b45e0)
+ the MTS/AP stamp split — retires TS-33. Outbound becomes 100% verbatim.
- **R8 — cutover audit.** grep-sweep for legacy motion code, register
reconciliation (every AD/AP/TS motion row retired or re-justified), full
live protocol (walk/run/toggle/turn/circle/stop/jump/MoveTo/TurnTo,
player+NPC+monster), ONE final user visual pass.
## Standing rules for every stage
1. Decomp is the oracle; ACE the interpretation aid; cdb/TTD the runtime
arbiter when they disagree (the S0/S2 pattern).
2. No stage ships without its conformance fixtures. Golden sources: dat
tables, cdb traces (both observer + actor side), captured wire logs.
3. Every commit: build + full suite green; register rows added/retired in
the same commit; roadmap stage table updated on stage completion.
4. New code lives in `src/AcDream.Core/Physics/Motion/` (pure logic; GL-free)
with App seams only for rendering handoff (Structure Rule 2).
5. Delete, don't gate: when a stage cuts over, the legacy path is REMOVED in
that stage (mandate: no frozen code, no bandaids).