fix(#170): stop per-frame interpreted re-dispatch flooding pending_motions (partial — flood fixed, run install not yet sustained)
Live retail cdb tracing + acdream probes root-caused the creature chase "slide"
end-to-end, SUPERSEDING the earlier MovementManager-coexistence hypothesis
(eb423fb7):
Chase run cycle is manufactured client-side from mt-6 MoveToObject:
HandleUpdateTarget -> MoveToObject_Internal -> (TurnToHeading node completes
via UseTime) -> BeginMoveForward -> _DoMotion(RunForward) sets substate.
BeginTurnToHeading (MoveToManager 0x00529b90) bails while
CMotionInterp.motions_pending is non-empty (retail-faithful).
acdream's pending_motions EXPLODED to ~1.3M entries (live: add=1.37M vs
done=5.7K) because the NPC per-tick called rm.Motion.apply_current_movement
EVERY FRAME, which for a remote (has a DefaultSink) re-ran
ApplyInterpretedMovement and re-dispatched the WHOLE interpreted state (stance
0x8000003C + forward=attack + sidestep/turn stops), each appending a
pending_motions node that barely drains. => MotionsPending() permanently true
=> the chase turn never started => BeginMoveForward/RunForward ~never fired =>
the creature slid in an idle+attack pose. Retail dispatches per MOTION EVENT
(per UM), never per frame — cdb drain trace: retail add_to_queue == MotionDone.
FIX: delete the per-frame apply_current_movement call in the grounded remote-NPC
dead-reckon path (GameWindow ~9992). The motion is already dispatched per UM by
the funnel (MoveToInterpretedState) + by the MoveToManager per node; body
velocity is refreshed directly by the existing get_state_velocity line.
RESULT (verified live): pending_motions depth 1.3M -> ~1 (add~=done); "stuck in
attack animation" GONE (user-confirmed); run cycle now installs (BeginMoveForward
1->10, RunForward held 0->7). PARTIAL: still not fully sustained — BeginTurnToHeading
still blocked motionsPending=True 256/272 (94%) because a residual Ready
(0x41000003) stop-node backlog keeps the queue from fully emptying between swings
(retail hits add==done exactly). acdream gets ~10 run-starts vs retail's ~21, so
it now twitches+glides instead of a clean run-then-stop. Residual = the R2/R3
Ready-stop drain (next session; see docs/research/2026-07-04-*-handoff.md).
Also includes the env-gated #170 diagnostic probes used to find this
(ACDREAM_MVTO_DIAG=1: [mvto]/[npc-tick]/[drain]/[drainq]) — TEMPORARY, strip when
#170 closes. No effect on normal runs. Core suite green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
d2ccc80e59
commit
427332acaa
3 changed files with 96 additions and 34 deletions
|
|
@ -738,6 +738,12 @@ public sealed class MoveToManager
|
|||
/// (<see cref="PreviousDistance"/>/<see cref="OriginalDistance"/> = dist,
|
||||
/// both times = now).
|
||||
/// </summary>
|
||||
// #170 temp diag (ACDREAM_MVTO_DIAG): trace the MoveTo dispatch/re-drive/cancel
|
||||
// events to compare acdream's run-cycle install cadence against a live retail
|
||||
// cdb count. Strip once #170 is understood.
|
||||
private static readonly bool s_mvtoDiag =
|
||||
System.Environment.GetEnvironmentVariable("ACDREAM_MVTO_DIAG") == "1";
|
||||
|
||||
public void BeginMoveForward()
|
||||
{
|
||||
if (!HasPhysicsObj)
|
||||
|
|
@ -756,6 +762,10 @@ public sealed class MoveToManager
|
|||
|
||||
Params.GetCommand(dist, heading, out uint cmd, out HoldKey holdKey, out bool movingAway);
|
||||
|
||||
if (s_mvtoDiag)
|
||||
System.Console.WriteLine(System.FormattableString.Invariant(
|
||||
$"[mvto] BeginMoveForward dist={dist:F2} cmd=0x{cmd:X8} hold={holdKey} movingAway={movingAway}"));
|
||||
|
||||
if (cmd == 0)
|
||||
{
|
||||
RemovePendingActionsHead();
|
||||
|
|
@ -816,6 +826,10 @@ public sealed class MoveToManager
|
|||
return;
|
||||
}
|
||||
|
||||
if (s_mvtoDiag)
|
||||
System.Console.WriteLine(System.FormattableString.Invariant(
|
||||
$"[mvto] BeginTurnToHeading motionsPending={_interp.MotionsPending()} curCmd=0x{CurrentCommand:X8}"));
|
||||
|
||||
if (_interp.MotionsPending())
|
||||
{
|
||||
return;
|
||||
|
|
@ -952,6 +966,10 @@ public sealed class MoveToManager
|
|||
/// </summary>
|
||||
public void UseTime()
|
||||
{
|
||||
if (s_mvtoDiag && (MovementTypeState != MovementType.Invalid || _pendingActions.First is not null))
|
||||
System.Console.WriteLine(System.FormattableString.Invariant(
|
||||
$"[mvto] UseTime enter contact={_contact()} pending={_pendingActions.Count} mtState={MovementTypeState} init={Initialized} hasPhys={HasPhysicsObj}"));
|
||||
|
||||
if (!HasPhysicsObj || !_contact()) return;
|
||||
|
||||
if (_pendingActions.First is null) return;
|
||||
|
|
@ -960,6 +978,9 @@ public sealed class MoveToManager
|
|||
if (!objectMoveGate) return;
|
||||
|
||||
MovementType type = _pendingActions.First.Value.Type;
|
||||
if (s_mvtoDiag)
|
||||
System.Console.WriteLine(System.FormattableString.Invariant(
|
||||
$"[mvto] UseTime dispatch node={type} mtState={MovementTypeState}"));
|
||||
if (type == MovementType.MoveToPosition)
|
||||
{
|
||||
HandleMoveToPosition();
|
||||
|
|
@ -1228,6 +1249,10 @@ public sealed class MoveToManager
|
|||
/// </summary>
|
||||
public void HandleUpdateTarget(TargetInfo info)
|
||||
{
|
||||
if (s_mvtoDiag)
|
||||
System.Console.WriteLine(System.FormattableString.Invariant(
|
||||
$"[mvto] HandleUpdateTarget objId=0x{info.ObjectId:X8} myTgt=0x{TopLevelObjectId:X8} match={(TopLevelObjectId == info.ObjectId)} init={Initialized} mtState={MovementTypeState} status={info.Status}"));
|
||||
|
||||
if (!HasPhysicsObj)
|
||||
{
|
||||
CancelMoveTo(WeenieError.NoPhysicsObject);
|
||||
|
|
@ -1460,6 +1485,9 @@ public sealed class MoveToManager
|
|||
/// </summary>
|
||||
public void CancelMoveTo(WeenieError error)
|
||||
{
|
||||
if (s_mvtoDiag && MovementTypeState != MovementType.Invalid)
|
||||
System.Console.WriteLine($"[mvto] CancelMoveTo (real) wasType={MovementTypeState} err={error}");
|
||||
|
||||
_ = error; // retail: never read in the body (decomp §7c) — kept for parity/logging.
|
||||
|
||||
if (MovementTypeState == MovementType.Invalid) return;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue