acdream/docs/research/2026-07-26-slice-j5-4-local-movement-ownership.md
Erik aa3f4a60f8 refactor(runtime): own local movement and outbound cadence
Move the canonical local movement controller, body/motion managers, object clock, movement wire data, and MTS/jump/AP sender into AcDream.Runtime. Replace process skill defaults with typed Runtime character options, make graphical and direct commands borrow one autorun owner, retain the construction-time PartArray seam, and include movement in terminal ownership convergence.

Preserve the accepted pre-inbound movement/jump and post-inbound autonomous-position order while moving the exact packet/cadence fixtures into Runtime tests. Add graphical/direct parity, two-instance isolation, teardown, allocation, architecture, and divergence-path coverage.

Co-authored-by: Codex <noreply@openai.com>
2026-07-26 12:33:53 +02:00

6.2 KiB
Raw Blame History

Slice J5.4 — canonical local movement ownership

Date: 2026-07-26 Parent: docs/plans/2026-07-26-modern-runtime-slice-j5.md Scope: ownership relocation only; no movement, collision, animation, or wire behavior changes

Retail oracle

The named September 2013 client remains the oracle:

Mechanism Named symbol Address / named pseudo-C
take local control CommandInterpreter::TakeControlFromServer 0x006B32D0, lines 699046699145
apply current raw movement CommandInterpreter::ApplyCurrentMovement 0x006B3430, lines 699146699530
stop decision CommandInterpreter::MaybeStopCompletely 0x006B3B90, lines 699531699563
post-inbound position slot CommandInterpreter::UseTime 0x006B3BF0, lines 699564699645
input command boundary CommandInterpreter::MovePlayer 0x006B3F40, lines 699803700232
AP predicate CommandInterpreter::ShouldSendPositionEvent 0x006B45E0, lines 700233700273
MTS serialization CommandInterpreter::SendMovementEvent 0x006B4680, lines 700274700315
AP serialization CommandInterpreter::SendPositionEvent 0x006B4770, lines 700316 onward
object/root-motion step CPhysicsObj::UpdatePositionInternal 0x00512C30, lines 280817 onward
object update envelope CPhysicsObj::update_object 0x00515D10, lines 283950 onward

The detailed wire unpack/pack interpretation and prior ACE/Holtburger cross-checks are retained in:

  • docs/research/2026-05-04-l3-port/02-um-handling.md;
  • docs/research/2026-05-04-l3-port/14-local-player-audit.md;
  • docs/research/2026-05-01-retail-motion-trace/findings.md;
  • docs/research/2026-07-26-slice-j5-owner-and-retail-order-inventory.md.

The reference source trees are not present in this worktree, so J5.4 reuses those already-recorded cross-checks rather than inventing a new interpretation. No behavioral algorithm is changed by this slice.

Consolidated retail pseudocode

Input / object phase

MovePlayer(command, speed, hold, ...)
    if server currently controls movement
        TakeControlFromServer()

    mutate the player's one RawMotionState / MotionInterpreter
    apply the current movement to the same CPhysicsObj
    if the movement boundary requires a report
        SendMovementEvent()

SendMovementEvent()
    require player + SmartBox + raw motion state + autonomous movement
    snapshot complete raw motion state
    snapshot the player's canonical cell-local Position and contact
    snapshot instance/server-control/teleport/force-position sequences
    serialize and send MoveToState
    stamp only last_sent_position_time after successful send

Jump uses the same pre-inbound input/object phase. The charged extent and body-local launch velocity are read from the canonical local controller and serialized exactly once on release.

Object simulation

UpdatePositionInternal(dt, rootFrame)
    apply the animation-authored root frame to the canonical physics body
    integrate/transition through the existing retail physics pipeline
    commit complete Position, velocity, contact, and cell membership

update_object()
    advance the retail object clock in fixed quanta
    update movement and physics in retail order
    leave one committed canonical body for every later borrower

App animation may supply the authored root frame and consume the committed pose. It does not own a second body, movement state, or object clock.

Post-inbound autonomous position phase

UseTime()
    after inbound messages may have corrected the canonical body:
        if ShouldSendPositionEvent()
            SendPositionEvent()

ShouldSendPositionEvent()
    compare current cell/contact against the last AP baseline
    after the retail interval, compare the complete current Frame

SendPositionEvent()
    snapshot canonical cell-local Position, orientation, contact, timestamps
    serialize and send AutonomousPosition
    after successful send:
        stamp last_sent_position_time
        copy complete Position and contact plane into the AP baseline

This preserves the accepted acdream frame order:

  1. graphical or no-window input becomes a typed MovementInput;
  2. Runtime mutates the canonical controller/body;
  3. Runtime emits MTS/jump before inbound dispatch;
  4. inbound corrections mutate that same body;
  5. Runtime evaluates/emits AP after inbound dispatch;
  6. App projects the final committed body to animation, camera, and UI.

Ownership result

  • PlayerMovementController, its movement data types, and LocalPlayerOutboundController now live in AcDream.Runtime.Gameplay.
  • RuntimeLocalPlayerMovementState is the sole controller, construction motion seam, autorun latch, typed view, and terminal ownership ledger.
  • DispatcherMovementInputSource samples physical held state only and maps configured edges onto the Runtime owner.
  • direct Runtime movement commands and graphical input mutate that same autorun state.
  • PlayerMovementConstructionOptions replaces process environment reads and is populated from RuntimeMovementSkillState.
  • the App diagnostic implementation crosses only IMovementTruthDiagnosticSink.
  • shutdown retires graphical/session borrowers before disposing the Runtime movement owner.

Preserved boundaries

  • Silk input, mouse filtering, camera, CSequence/PartArray presentation, retained jump bar, sounds, and effects remain in App.
  • PhysicsEngine remains App-owned until J5.5.
  • remote movement and projectiles remain App-owned until J5.5/J5.6.
  • TS-33's already-recorded possible same-update MTS/AP ordering difference is preserved; this ownership move neither widens nor hides it.

Automated evidence required before closeout

  • Runtime state/view identity, two-instance isolation, construction lease, terminal convergence, typed movement skills, and zero-allocation snapshots;
  • graphical/direct autorun parity and one-production-owner source guards;
  • existing bit-exact RawMotionState, MTS, jump, AP, quaternion, contact, and strict cadence tests;
  • existing run/walk/back/strafe/turn/mouse-look/jump/land, short-tap, portal/reset, target-facing, and repeat-abort tests;
  • Release build, complete solution tests, exact-binary connected lifecycle, and canonical movement route.