fix(motion): #39 candidate — un-gate UP velocity-cycle for player remotes (forward only)

Adds a player-remote velocity-fallback path to ApplyServerControlledVelocityCycle
so that when retail (the actor) toggles Shift while holding W and acdream is
the observer, the visible leg cycle switches Run↔Walk within ~200–500 ms even
though no fresh UM arrives. Static analysis (ACE GameActionMoveToState +
MovementData.cs auto-upgrade + acdream's prior diag traces) suggests retail
does NOT broadcast a fresh MoveToState on HoldKey-only changes — acdream's
UMs handle direction-key changes and our local +Acdream's transitions, but
retail-driven actors leave the cycle stuck.

Changes (all in src/AcDream.App/Rendering/GameWindow.cs):
- New RemoteMotion.LastUMTime field, stamped in OnLiveMotionUpdated
- ApplyServerControlledVelocityCycle: removed inner IsPlayerGuid gate;
  routes player remotes to new ApplyPlayerLocomotionRefinement
- ApplyPlayerLocomotionRefinement (forward-direction only):
  - 500 ms UM grace window (UMs win when fresh)
  - Forward-direction-only (low byte 0x05 / 0x07)
  - Hysteresis: Run → Walk demote at < 4.5 m/s; Walk → Run promote > 5.5 m/s
  - Skip SetCycle when neither motion ID nor speedMod changed meaningfully
  - [UPCYCLE_PLAYER] diag gated on ACDREAM_REMOTE_VEL_DIAG=1
- Outer call site in OnLivePositionUpdated un-gated (!IsPlayerGuid removed);
  per-remote routing now lives inside the function

Scope: case #1 (Run↔Walk forward) only. Cases #2–#7 (backward, sidestep
speed-buckets, direction-flips) remain deferred — PlanFromVelocity is
forward-only and its NPC-tuned thresholds (RunThreshold=1.25) do not
separate player Walk (~2.5 m/s) from player Run (~9 m/s); a TTD trace
of retail's per-direction algorithm should ground the wider fix.

ISSUES.md #39 updated with progress; investigation-prompt.md and a new
findings-static.md committed under
docs/research/2026-05-06-locomotion-cycle-transitions/ (the prompt was
authored on a parallel branch in commit 7a38da3 and is brought into this
worktree here so the next session can find it without branch-hopping).

Build clean. The 8 pre-existing test failures on this branch
(BSPStepUpTests.C3_Path6_AirborneMoverHitsSteepSlope, MotionInterpreter
WalkBackward GetMaxSpeed, etc.) are unrelated to this change — verified
by running them with the diff stashed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-06 06:34:20 +02:00
parent 5f2e2e28ff
commit 8fa04af4c7
4 changed files with 679 additions and 8 deletions

View file

@ -111,6 +111,12 @@ the same direction. Add a `LastUMUpdateTime` grace window (e.g.
- `docs/research/2026-05-03-remote-anim-cycle/investigation-prompt.md`
full background of the four-agent investigation
- `docs/research/2026-05-06-locomotion-cycle-transitions/investigation-prompt.md`
expansion to the full 7-transition matrix (Run↔Walk forward + backward,
Fast↔Slow strafe L+R, direction-flip cases) with TTD-driven workflow
- `docs/research/2026-05-06-locomotion-cycle-transitions/findings-static.md`
static-analysis findings + scope of the 2026-05-06 candidate fix
(case #1, Run↔Walk forward only)
- This session's diagnostic logs at `tools/diag-logs/walkrun-A1b-*.log`
(UM_RAW, FWD_WIRE, SETCYCLE traces) confirming ACE's wire pattern
@ -124,6 +130,23 @@ the same direction. Add a `LastUMUpdateTime` grace window (e.g.
- No spurious cycle thrashing during turning while running (ObservedOmega
doesn't trigger velocity-bucket changes).
**Progress 2026-05-06 (candidate fix shipped, awaiting visual verify):**
- `RemoteMotion.LastUMTime` added, stamped in `OnLiveMotionUpdated`.
- `ApplyServerControlledVelocityCycle` un-gated for player remotes;
player path routed through new `ApplyPlayerLocomotionRefinement`:
- 500 ms UM grace window
- Forward-direction-only refinement (low byte 0x05 / 0x07)
- Hysteresis: Run → Walk demote < 4.5 m/s; Walk Run promote > 5.5 m/s
- Skip SetCycle when neither motion ID nor speedMod changed meaningfully
- Outer call site at `OnLivePositionUpdated` un-gated (`!IsPlayerGuid`
removed); function-internal route handles player vs NPC.
- Diagnostic `[UPCYCLE_PLAYER]` line gated on `ACDREAM_REMOTE_VEL_DIAG=1`.
Scope of this fix is **case #1 (Run↔Walk forward) only**. Cases #2#7
(backward, sidestep, direction-flips) remain deferred until TTD trace
grounds retail's exact algorithm — see findings-static.md §"Does NOT".
## #42 — [DONE 2026-05-05 · ec59a08] Airborne XY drift on observed player remote jumps (~1 m horizontal offset over arc)
**Status:** DONE