fix #270: fire ReportExhaustion on the stamina-exhaustion edge only, not every stats tick

Retail calls CPhysicsObj::report_exhaustion from exactly one site -
CommandInterpreter::HandleExhaustion (0x006b3c70), a notification handler
for the stamina-exhaustion EVENT. Campaign P P1 wired it to every
movement-stats application instead (every stamina regen/drain tick), and
each call re-dispatches the current movement state through the animation
sink - truncating any in-flight action animation. The diagnostic session
log shows 490 spurious casting-stance re-queues in one short session:
'sometimes stuck in spell animations' was every stamina tick that
collided with a cast gesture's play window.

The re-apply now fires only when the exhausted state (stamina == 0)
transitions, matching retail's event semantics. Stats still reach
PlayerWeenie immediately via RuntimeMovementSkillProjection.ApplyTo.

Also adds the [remote-edge] probe (rides ACDREAM_DUMP_MOTION=1): one
line per remote HitGround/LeaveGround - each such edge drains the
mover's pending action animations (retail HandleEnterWorld), the
working theory for intermittently missing monster attack swings.

Complete Release suite: 10,026 passed / 5 skips / 0 failures.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-30 22:11:20 +02:00
parent 5788fdaa02
commit a46c8e65b2
4 changed files with 101 additions and 10 deletions

View file

@ -61,6 +61,18 @@ public static class PhysicsDiagnostics
public static bool ProbeCellEnabled { get; set; } =
Environment.GetEnvironmentVariable("ACDREAM_PROBE_CELL") == "1";
/// <summary>
/// Stuck-cast/missing-attack investigation (2026-07-30). When true,
/// every REMOTE ground-contact edge (HitGround / LeaveGround — each of
/// which drains the mover's pending action animations via retail's
/// <c>HandleEnterWorld</c>) emits one <c>[remote-edge]</c> line with the
/// server guid. Correlates eaten attack animations with spurious
/// contact flickers. Rides <c>ACDREAM_DUMP_MOTION=1</c> so one flag
/// captures the whole animation story.
/// </summary>
public static bool DumpMotionEnabled { get; set; } =
Environment.GetEnvironmentVariable("ACDREAM_DUMP_MOTION") == "1";
/// <summary>
/// L.2d slice 1 (2026-05-13). When true, every BSP-shadow-entry hit
/// attributed by <c>TransitionTypes.FindObjCollisions</c> emits a