fix #270: retry spawn placement until first success (lost-cell recovery analog) + attributed probes

The creation-only spawn placement could no-op or fail during the login
flood (cell id not yet hydrated / streaming collision not resident) with
nothing retrying - monsters created in that window stayed
airborne-flagged forever and their action animations remained refused.
Retail's answer to 'object addressed before its cell exists' is the
CObjectMaint lost-cell list (GotoLostCell): park, re-place when the cell
is available. The UM dispatch path now retries SeedRemoteSpawnPlacement
while the body has never been successfully placed (no contact AND no
stored plane); one success ends the retries.

Probes: [SPAWN-PLACE] logs each placement outcome (guid/cell/ok/
contact/walkable); [UM-ACT]/[MT-FAIL] now carry the owning guid via
MotionInterpreter.DiagnosticGuid (probe-identity-attribution lesson)
plus the body's live contact/walkable flags.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-30 23:57:38 +02:00
parent 4da25a442b
commit 807fdb5f7f
3 changed files with 35 additions and 8 deletions

View file

@ -678,6 +678,14 @@ public sealed class MotionInterpreter : IMotionDoneSink
/// </summary>
public Action? RemoveLinkAnimations { get; set; }
/// <summary>
/// #270 diagnostic identity (2026-07-30): the owning entity's server
/// guid, stamped by the binding layer so [UM-ACT]/[MT-FAIL] probe lines
/// are attributable (probe-identity-attribution lesson). 0 = unset.
/// Strip with the #270 probes.
/// </summary>
public uint DiagnosticGuid { get; set; }
/// <summary>
/// R3-W4 no-op seam standing in for retail
/// <c>CPhysicsObj::InitializeMotionTables</c>, called from
@ -2779,7 +2787,7 @@ public sealed class MotionInterpreter : IMotionDoneSink
if (PhysicsDiagnostics.DumpMotionEnabled)
{
Console.WriteLine(
$"[UM-ACT] cmd=0x{a.Command:X8} stamp={incoming} stored={stored} "
$"[UM-ACT] guid={DiagnosticGuid:X8} cmd=0x{a.Command:X8} stamp={incoming} stored={stored} "
+ $"newer={newer} auton={a.Autonomous} localSkip={IsLocalPlayer && a.Autonomous}");
}
@ -3038,8 +3046,10 @@ public sealed class MotionInterpreter : IMotionDoneSink
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}");
$"[MT-FAIL] guid={DiagnosticGuid:X8} motion=0x{motion:X8} speed={p.Speed:F2} "
+ $"style=0x{InterpretedState.CurrentStyle:X8} substate=0x{InterpretedState.ForwardCommand:X8} "
+ $"contact={PhysicsObj.TransientState.HasFlag(TransientStateFlags.Contact)} "
+ $"walkable={PhysicsObj.TransientState.HasFlag(TransientStateFlags.OnWalkable)}");
}
if (!dispatchOk)