fix(motion): close #45 — scale local sidestep speedMod by ACE's wire factor

User observed (during fix #5 visual verify of #39): "our own Acdream
client renders sidestep walking too slow". Filed as #45.

Root cause: PlayerMovementController.cs:871 computes localAnimSpeed as
the raw `runRate || 1.0`, while ACE's BroadcastMovement converts
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.

Fix: in UpdatePlayerAnimation, when animCommand is SideStepLeft / Right
(low byte 0x0F or 0x10), multiply animSpeed by
    WalkAnimSpeed / SidestepAnimSpeed × 0.5 = 3.12 / 1.25 × 0.5 = 1.248
before calling SetCycle. Same factor as ACE; no clamp on the local
side (sequencer handles MultiplyCyclicFramerate naturally).

Forward / backward / turn cycles unchanged — those use WalkAnimSpeed
or RunAnimSpeed as base, where localAnimSpeed = wire ForwardSpeed
already produces the right cadence.

Build clean. Visual verify pending: user reports slow-strafe cadence
should match retail / our own observed-remote rendering after this.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-06 08:58:41 +02:00
parent 898d7cd2cf
commit e9e080db8c

View file

@ -7244,6 +7244,27 @@ public sealed class GameWindow : IDisposable
// For everything else (Walk → Run, Run → Ready, etc.) we
// keep the link so transitions stay smooth.
bool skipLink = animCommand == AcDream.Core.Physics.MotionCommand.Falling;
// #45 (2026-05-06): scale sidestep speedMod to match ACE's
// wire formula. PlayerMovementController hands us a raw
// localAnimSpeed (1.0 slow / runRate fast), but ACE's
// BroadcastMovement converts SidestepSpeed via
// `speed × 3.12 / 1.25 × 0.5`
// (Network/Motion/MovementData.cs:124-131). Without the
// matching multiplier here, the local sidestep cycle plays
// at speedMod = 1.0 while the observer-side cycle plays at
// ~1.248 — local strafe visibly slower than retail (user
// report at #45 close-out of #39).
// Factor = WalkAnimSpeed / SidestepAnimSpeed × 0.5
// = 3.12 / 1.25 × 0.5 = 1.248.
uint cmdLow = animCommand & 0xFFu;
if (cmdLow == 0x0Fu /* SideStepRight */ || cmdLow == 0x10u /* SideStepLeft */)
{
animSpeed *= AcDream.Core.Physics.MotionInterpreter.WalkAnimSpeed
/ AcDream.Core.Physics.MotionInterpreter.SidestepAnimSpeed
* 0.5f;
}
ae.Sequencer.SetCycle(fullStyle, animCommand, animSpeed * animScale,
skipTransitionLink: skipLink);
}