fix #270: run retail spawn placement at remote-body creation - standing monsters' attack animations restored
The [MT-FAIL] probe caught combat-stance monsters constantly failing to dispatch 0x40000015 (Falling): their bodies were airborne-flagged while standing. contact_allows_move (0x00528dd0) requires Contact+OnWalkable and silently refuses every action animation for an airborne mover - a spawned-standing monster's swings never played until it first moved. Retail never has this state: CreateObject spawns run the placement transition (CPhysicsObj::SetPosition -> SetPositionInternal 0x00515330), which establishes CONTACT/ON_WALKABLE from the floor at spawn. Our remote creation seeded a raw position with no placement. SeedRemoteSpawnPlacement mirrors RemoteTeleportPlacement: engine placement resolve (Setup-derived cylinder, TS-46) + the verbatim CommitSetPositionTransition, wired at BOTH RemoteMotion creation sites (UM-triggered creation - so a first-ever-UM attack animates in the same packet - and ordinary first-UP creation). Unplaceable results leave the body airborne exactly like a failed retail placement. Also adds the [UM-ACT] (wire action items + stamp-gate verdict) and [MT-FAIL] (refused animation dispatches) probes, riding ACDREAM_DUMP_MOTION=1, which are what convicted the body state. Complete Release suite: 10,032 passed / 5 skips / 0 failures. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
1390add140
commit
4da25a442b
4 changed files with 257 additions and 17 deletions
|
|
@ -2772,6 +2772,17 @@ public sealed class MotionInterpreter : IMotionDoneSink
|
|||
int stored = ServerActionStamp & 0x7FFF;
|
||||
int diff = incoming >= stored ? incoming - stored : stored - incoming;
|
||||
bool newer = diff <= 0x3FFF ? stored < incoming : incoming < stored;
|
||||
|
||||
// #270 missing-attack investigation (2026-07-30): one line per
|
||||
// wire action item with the gate verdict — rides
|
||||
// ACDREAM_DUMP_MOTION=1. Strip when #270 closes.
|
||||
if (PhysicsDiagnostics.DumpMotionEnabled)
|
||||
{
|
||||
Console.WriteLine(
|
||||
$"[UM-ACT] cmd=0x{a.Command:X8} stamp={incoming} stored={stored} "
|
||||
+ $"newer={newer} auton={a.Autonomous} localSkip={IsLocalPlayer && a.Autonomous}");
|
||||
}
|
||||
|
||||
if (!newer) continue;
|
||||
|
||||
// Local player skips its own autonomous echoes (305977).
|
||||
|
|
@ -3020,6 +3031,17 @@ public sealed class MotionInterpreter : IMotionDoneSink
|
|||
// non-action" apply-only path below — but WITHOUT writing state.
|
||||
bool dispatchOk = sink?.ApplyMotion(motion, p.Speed) ?? true;
|
||||
|
||||
// #270 missing-attack investigation (2026-07-30): surface FAILED
|
||||
// animation dispatches — a silently-failing sink is the "monster
|
||||
// attacks but the animation never fires" candidate. Rides
|
||||
// ACDREAM_DUMP_MOTION=1. Strip when #270 closes.
|
||||
if (!dispatchOk && PhysicsDiagnostics.DumpMotionEnabled)
|
||||
{
|
||||
Console.WriteLine(
|
||||
$"[MT-FAIL] motion=0x{motion:X8} speed={p.Speed:F2} "
|
||||
+ $"style=0x{InterpretedState.CurrentStyle:X8} substate=0x{InterpretedState.ForwardCommand:X8}");
|
||||
}
|
||||
|
||||
if (!dispatchOk)
|
||||
{
|
||||
// Retail: `result = CPhysicsObj::DoInterpretedMotion(...)` is
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue