fix(animation): harden presentation phase handoffs

Own every borrowed PartArray frame across callbacks, version presentation state across appearance rebinding, reject recursive phase consumption, and preserve static MotionDone when only a stale visual pose is discarded.
This commit is contained in:
Erik 2026-07-21 10:01:25 +02:00
parent a2fd61684a
commit 833520253a
10 changed files with 657 additions and 140 deletions

View file

@ -671,23 +671,7 @@ public sealed class GameWindow : IDisposable, ILiveAnimationPresentationContext
public System.Numerics.Vector3 PrevServerPos;
public double PrevServerPosTime;
public double LastOmegaDiagLogTime;
/// <summary>
/// Diagnostic-only (gated on <c>ACDREAM_REMOTE_VEL_DIAG=1</c>): own
/// throttle clock for the SEQSTATE log line in TickAnimations.
/// Previously SEQSTATE shared <see cref="LastOmegaDiagLogTime"/> with
/// the OMEGA_DIAG block, which fires at 0.5s and resets the clock —
/// any remote that turned during a transition silently swallowed
/// SEQSTATE for 0.51.5s, masking the bug we're trying to diagnose
/// (walk↔run leg-cycle sticking on observed retail chars). Split
/// 2026-05-03 (Commit A).
/// </summary>
public double LastSeqStateLogTime;
/// <summary>
/// Diagnostic-only (gated on <c>ACDREAM_REMOTE_VEL_DIAG=1</c>): own
/// throttle clock for the PARTSDIAG log line in TickAnimations
/// (D5). One log per remote per ~1s.
/// </summary>
public double LastPartsDiagLogTime;
/// <summary>
/// Diagnostic-only: maximum scaled CSequence root-motion speed
/// observed since the last UpdatePosition arrival. The next UP
@ -4539,7 +4523,7 @@ public sealed class GameWindow : IDisposable, ILiveAnimationPresentationContext
});
_staticAnimationScheduler?.BindLiveOwner(
entity,
staticSequencer,
registeredAnimation,
staticBody);
}
}
@ -11540,7 +11524,8 @@ public sealed class GameWindow : IDisposable, ILiveAnimationPresentationContext
DatReaderWriter.Types.Frame rootFrame = ae.RootMotionScratch;
rootFrame.Origin = System.Numerics.Vector3.Zero;
rootFrame.Orientation = System.Numerics.Quaternion.Identity;
ae.PreparedSequenceFrames = sequencer.Advance(dt, rootFrame);
ae.PreparedSequenceFrames = ae.CaptureSequenceFrames(
sequencer.Advance(dt, rootFrame));
ae.SequenceAdvancedBeforeAnimationPass = true;
output.Origin = rootFrame.Origin;