fix(#170): refresh remote body velocity from get_state_velocity (kill the attack glide)
Root cause (confirmed by a live ACDREAM_DUMP_MOTION capture of Mite Scamp
0x80000244 + the retail decomp): a chasing+attacking creature's attacks arrive
as the ForwardCommand of frequent mt-0 InterpretedMotionState UMs (66 attack UMs
0x62/63/64 vs 2 mt-6 chase MoveTos in the capture). Retail's get_state_velocity
(0x00527d50) computes the body's translation velocity from the current forward
command: WalkForward→3.12×spd, RunForward→4.0×spd, and 0 for everything else
(an attack) — so the creature plants its feet. acdream ALREADY has a faithful
get_state_velocity (returns 0 for a non-locomotion command; cross-checked vs
holtburger grounded_local_velocity's `_ => zero`), but it was never WIRED to the
remote body for entities with an animation sink: apply_current_movement's sink
path (all remotes have a DefaultSink) dispatches the animation and early-returns
BEFORE the set_local_velocity(get_state_velocity()) write, which lives only in
the no-sink fallback (MotionInterpreter ~1702). So a remote NPC's body.Velocity
was never recomputed from its motion state and kept the STALE run velocity from
the last chase — the body dead-reckoned forward at ~4 m/s while playing an
idle+attack pose ("glides after me").
Fix: after apply_current_movement in the grounded remote-NPC dead-reckon path
(GameWindow ~9992, restricted to remotes by serverGuid != player and to grounded
by OnWalkable), refresh rm.Body via set_local_velocity(get_state_velocity()) —
the exact write retail's apply_current_movement performs, reusing the verbatim
ported get_state_velocity. An attack forward command now resolves to 0, so the
creature stops and swings in place; RunForward still yields the run velocity.
Narrowest safe seam: the local player (which also has a sink) is excluded by the
loop's player guard, so its PlayerMovementController velocity path is untouched.
The earlier suspicion (#159 combat-command numbering) was a red herring — the
scamp's 0x62/63/64 were always in the correct block and the planner is unwired;
the wire even carries full attack variety, so "uniform" was the visual artifact
of rapid attacks over a gliding idle base, not a classification bug.
Tests: MotionVelocityPipelineTests.AttackForwardCommand_ZeroVelocity (4 cases)
pins get_state_velocity → 0 for the attack forward commands the fix depends on.
Core suite 2503 green. Visual gate pending (retail side-by-side: creature should
plant + step, not glide).
Ref: docs/research/named-retail get_state_velocity 0x00527d50; ISSUES #170.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
fe24289ac5
commit
d2ccc80e59
2 changed files with 59 additions and 0 deletions
|
|
@ -184,4 +184,34 @@ public sealed class MotionVelocityPipelineTests
|
|||
Assert.Equal(0f, v.X, 5);
|
||||
Assert.Equal(0f, v.Y, 5);
|
||||
}
|
||||
|
||||
// ── attack / non-locomotion forward command (#170) ───────────────────────
|
||||
|
||||
[Theory]
|
||||
[InlineData(0x10000062u)] // AttackHigh1
|
||||
[InlineData(0x10000063u)] // AttackMed1
|
||||
[InlineData(0x10000064u)] // AttackLow1
|
||||
[InlineData(0x10000186u)] // AttackHigh4 (shifted late block)
|
||||
public void AttackForwardCommand_ZeroVelocity(uint attackCommand)
|
||||
{
|
||||
// #170: an ATTACK forward command (action-class 0x1000006x/0x100001xx)
|
||||
// is neither WalkForward (0x45000005) nor RunForward (0x44000007), so
|
||||
// retail's get_state_velocity (0x00527d50) hits its `else → 0` branch —
|
||||
// the creature plants its feet instead of coasting at the last run
|
||||
// velocity. Cross-checked against holtburger grounded_local_velocity
|
||||
// (`_ => Vector3::zero()`) and the retail decomp. This is the invariant
|
||||
// the #170 glide fix relies on: GameWindow's remote dead-reckon now
|
||||
// refreshes the body velocity from get_state_velocity each tick, so a
|
||||
// creature that switches from a run-chase (ForwardCommand=RunForward)
|
||||
// to an attack (ForwardCommand=0x1000006x) resolves to zero velocity
|
||||
// and stops gliding.
|
||||
var interp = MakeInterp(RunRate);
|
||||
interp.InterpretedState.ForwardCommand = attackCommand;
|
||||
interp.InterpretedState.ForwardSpeed = 0.97f;
|
||||
|
||||
var v = interp.get_state_velocity();
|
||||
Assert.Equal(0f, v.X, 5);
|
||||
Assert.Equal(0f, v.Y, 5);
|
||||
Assert.Equal(0f, v.Z, 5);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue