From 24407fec3c3c616873e6935738cfc0990c503607 Mon Sep 17 00:00:00 2001 From: Erik Date: Wed, 6 May 2026 09:03:35 +0200 Subject: [PATCH] docs(issues): close #45 (sidestep slow); file #46 (retail observer of acdream blippy) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #45 — closed by commit e9e080d. PlayerMovementController hands a raw localAnimSpeed (1.0 slow / runRate fast); UpdatePlayerAnimation now scales sidestep cycles by WalkAnimSpeed/SidestepAnimSpeed × 0.5 to match ACE's BroadcastMovement formula. User-verified. #46 — filed. Retail clients observing acdream's local +Acdream character see visibly blippy / laggy movement. Local acdream view of the same character is fine; acdream observing retail-driven characters is also fine (after #39 / #45). The degradation is specifically on the OUTBOUND path. Likely culprits ranked: AutoPos heartbeat cadence (acdream's fixed 200 ms is suspect per project_retail_motion_outbound memory), MoveToState send conditions, sequence counters, or absent HasVelocity on UPs. Verification approach documented (two retail clients + one acdream side-by-side; cdb breakpoint count of MovementManager::unpack_movement on retail observer). Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/ISSUES.md | 56 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/docs/ISSUES.md b/docs/ISSUES.md index f5c59cf..6577750 100644 --- a/docs/ISSUES.md +++ b/docs/ISSUES.md @@ -1258,37 +1258,61 @@ If hypothesis (a) is correct, this issue effectively rolls into **#28** — the --- -## #45 — Local +Acdream sidestep walking renders too slow +## #46 — Retail observer of acdream sees blippy / laggy movement **Status:** OPEN -**Severity:** LOW (visible animation cadence; not a correctness/wire bug) +**Severity:** MEDIUM (degrades external perception of acdream-driven characters) **Filed:** 2026-05-06 -**Component:** physics / animation (local player path: `PlayerMovementController` → `UpdatePlayerAnimation` → `AnimationSequencer.SetCycle`) +**Component:** net / motion (acdream's outbound path: `PlayerMovementController` → `MoveToState` (0xF61C) / `AutonomousPosition` heartbeat → ACE → retail observer) -**Description:** When the local +Acdream character strafes (A or D held) at slow pace (no Shift), the visible leg cycle for the local player plays slower than retail's equivalent. Fast strafe (with Shift held) appears correct. Observed by user 2026-05-06 immediately after fix #5 (commit `349ba65`) landed the matching fix on the *observer-side* `ApplyPlayerLocomotionRefinement` for retail-driven remotes. +**Description:** When viewing acdream's local +Acdream character through a parallel retail acclient.exe, the retail observer sees the character's movement as visibly blippy and laggy — position appears to step in discrete jumps rather than translating smoothly. The local acdream view of the same character looks fine, and acdream observing a retail-driven character (after #39 / #45) also looks fine. The degradation is specifically on the **outbound** side: what acdream sends to ACE for relay to other clients. **Root cause / status:** -Likely the same constant mismatch as fix #5: the local player's sidestep speedMod was being computed off `WalkAnimSpeed` (3.12 m/s) where it should use `SidestepAnimSpeed` (1.25 m/s). Because the wire-emitted `SideStepSpeed` already encodes a 0.5× multiplier (per ACE `MovementData.cs:124-131`), dividing the wrong base on either send or render side compresses the slow strafe to a sub-walk cadence. +Unverified. The likely culprits, ranked by suspected probability: -To confirm: look at `UpdatePlayerAnimation` in `src/AcDream.App/Rendering/GameWindow.cs` (~line 7000) and trace where the strafe speedMod is sourced from. Either the speedMod passed to `SetCycle` is too small, or the framerate computation downstream applies an extra 0.5×. +1. **AutonomousPosition heartbeat cadence.** `memory/project_retail_motion_outbound.md` notes acdream's fixed 200 ms heartbeat is a probable retail mismatch. Retail's `CommandInterpreter::SendPositionEvent` gates on transient_state (Contact + OnWalkable + valid Position) and may broadcast at a different cadence — fewer / more / variable. If acdream sends too rarely, observer dead-reckons too long between updates and visibly stutters when each AutoPos arrives. +2. **MoveToState send conditions.** `PlayerMovementController.cs:813-840` decides when a fresh MoveToState fires (state-change detection). If important transitions are missed (e.g., direction changes that don't flip ForwardCommand/SidestepCommand), the observer's last-known motion stays stale and AutoPos updates blip the body to the new authoritative position. +3. **InstanceSequence / ObjectMovement sequence counters.** ACE rejects out-of-order packets. If acdream's sequence stamping is off, ACE silently drops some packets; observer dead-reckons through the gap. +4. **Velocity field absent on AutoPos.** ACE relays UPs without HasVelocity for player characters (per `OnLivePositionUpdated` comment). Observer's dead-reckoning between UPs may extrapolate using stale velocity, producing visible position drift that snaps back on the next UP — exactly the blippy pattern. -Cross-reference: -- `MotionInterpreter.SidestepAnimSpeed = 1.25f` -- `MotionInterpreter.WalkAnimSpeed = 3.12f` -- ACE `MovementData(MoveToState)`: `interpState.SidestepSpeed = speed * 3.12f / 1.25f * 0.5f` +**Verification approach:** + +- Run two retail clients + one acdream client. Drive acdream; observe acdream's character on retail #1 and on retail #2 (both retail observers see the same wire). Compare to a retail-driven character observed from the same retail clients — does it look smooth there? If yes, the issue is acdream-outbound-specific. If both look blippy, it's something on the ACE side (less likely). +- cdb-attach a retail observer client and breakpoint `MovementManager::unpack_movement` to count UPs and UMs received per second from the acdream-driven character vs from another retail character. The cadence delta will identify which packet stream is misbehaving. +- Compare acdream's outbound packet timing against holtburger's `client/movement/system.rs` heartbeat logic — that's the closest known-working reference for how a non-retail client should pace its outbound. **Files:** -- `src/AcDream.App/Rendering/GameWindow.cs` — `UpdatePlayerAnimation` (~line 7000) -- `src/AcDream.App/Input/PlayerMovementController.cs` — wire-builder for outbound MoveToState (sidestep path) -- `src/AcDream.Core/Physics/MotionInterpreter.cs:243-247` — anim-speed constants +- `src/AcDream.App/Input/PlayerMovementController.cs` — outbound state-change detection + heartbeat +- `src/AcDream.Core.Net/WorldSession.cs` — sequence counters + send path +- `src/AcDream.Core.Net/Net/Outbound/...MoveToState.cs` / `AutonomousPosition.cs` — wire builders +- `references/holtburger/crates/holtburger-core/src/client/movement/system.rs` — reference cadence **Acceptance:** -- Local +Acdream slow strafe (A or D, no Shift) plays at the same visible cadence as retail's slow strafe in a side-by-side comparison. -- Local fast strafe (A or D + Shift) does not regress. -- Forward / backward / run cycles do not regress. +- Side-by-side comparison: retail observer of acdream-driven character and retail observer of retail-driven character look equally smooth during running, walking, sidestepping, turning, and stopping. +- No visible "step" pattern when acdream-driven character translates between AutoPos updates. + +**Cross-reference:** + +- `memory/project_retail_motion_outbound.md` — 2026-05-01 cdb live trace of retail's outbound (`CommandInterpreter::SendMovementEvent` for WASD, `Event_Jump` per-frame while charging). +- CLAUDE.md "Outbound motion wire format" — the `WalkForward + HoldKey.Run` ↔ `RunForward` auto-upgrade ACE applies on broadcast. + +--- + +## #45 — [DONE 2026-05-06 · e9e080d] Local +Acdream sidestep walking renders too slow + +**Status:** DONE +**Closed:** 2026-05-06 +**Commit:** `e9e080d` +**Component:** physics / animation (local player path: `UpdatePlayerAnimation`) + +**Resolution:** `PlayerMovementController.cs:871` computes `localAnimSpeed` as raw `runRate || 1.0`, but ACE's `BroadcastMovement` converts the inbound `MoveToState.SidestepSpeed` via `speed × 3.12 / 1.25 × 0.5` (`Network/Motion/MovementData.cs:124-131`). Observer-side cycles play at the ACE-scaled value (~1.248 slow / ~3.0 fast clamped); the local cycle was playing at the raw 1.0 / runRate — about 80% of retail cadence for slow strafe. + +`UpdatePlayerAnimation` now multiplies `animSpeed` by `WalkAnimSpeed / SidestepAnimSpeed × 0.5 = 1.248` when `animCommand` is `SideStepLeft / Right` (low byte 0x0F or 0x10). User-verified: local strafe cadence matches retail / observer-side rendering. + +**Original investigation note (preserved):** Same constant mismatch pattern as #39 fix #5 (commit `349ba65`) but on the local-player render path instead of the observer-side `ApplyPlayerLocomotionRefinement` — both fixed by aligning the speedMod base to ACE's wire formula. ---