feat(physics): port retail complete object frame pipeline

Restore the named-retail object update order across local, remote, static, projectile, animation, shadow, teleport, and effect lifetimes. Separate authoritative root commits from spatial rebucketing, preserve per-owner hook/FIFO ordering, and remove update-path allocations with exact lifecycle and residency gates.

Add deterministic conformance, adversarial lifetime, GUID-reuse, pending-cell, quaternion, timestamp, and allocation coverage. Release build is warning-free and all 6,446 tests pass with five intentional skips; retail, architecture, and adversarial reviews are clean.

Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-20 09:10:31 +02:00
parent 31a0889f08
commit f961d70023
77 changed files with 12513 additions and 1871 deletions

View file

@ -119,6 +119,143 @@ public sealed class EntityEffectPoseRegistryTests
Assert.Equal(0, queue.Count);
}
[Fact]
public void AnimationHookQueue_DeleteAndLocalIdReuse_DropsOldIncarnationHooks()
{
var poses = new EntityEffectPoseRegistry();
WorldEntity first = Entity(9u, Vector3.Zero);
poses.Publish(first, Array.Empty<Matrix4x4>());
var router = new AnimationHookRouter();
var sink = new RecordingSink();
router.Register(sink);
var queue = new AnimationHookFrameQueue(router, poses);
var sequencer = new AnimationSequencer(
new Setup(),
new MotionTable(),
new NullAnimationLoader());
queue.Capture(9u, sequencer, new AnimationHook[] { new SoundHook() });
Assert.True(poses.Remove(9u));
WorldEntity replacement = Entity(9u, new Vector3(40f, 50f, 60f));
poses.Publish(replacement, Array.Empty<Matrix4x4>());
queue.Drain();
Assert.Empty(sink.Calls);
Assert.Equal(0, queue.Count);
}
[Fact]
public void AnimationDoneReuseDuringCapture_DropsOldIncarnationHooks()
{
var poses = new EntityEffectPoseRegistry();
poses.Publish(Entity(9u, Vector3.Zero), Array.Empty<Matrix4x4>());
var router = new AnimationHookRouter();
var sink = new RecordingSink();
router.Register(sink);
var queue = new AnimationHookFrameQueue(router, poses);
var sequencer = new AnimationSequencer(
new Setup(),
new MotionTable(),
new NullAnimationLoader());
sequencer.Manager.AddToQueue(0x10000001u, ticks: 1u);
sequencer.MotionDoneTarget = (_, success) =>
{
Assert.True(success);
Assert.True(poses.Remove(9u));
poses.Publish(
Entity(9u, new Vector3(40f, 50f, 60f)),
Array.Empty<Matrix4x4>());
};
queue.Capture(
9u,
sequencer,
new AnimationHook[]
{
new AnimationDoneHook(),
new SoundHook(),
});
queue.Drain();
Assert.Empty(sink.Calls);
Assert.Equal(0, queue.Count);
}
[Fact]
public void MultipleAnimationDoneHooks_StopAdvancingDisplacedSequencerAfterReuse()
{
var poses = new EntityEffectPoseRegistry();
poses.Publish(Entity(9u, Vector3.Zero), Array.Empty<Matrix4x4>());
var queue = new AnimationHookFrameQueue(
new AnimationHookRouter(),
poses);
var sequencer = new AnimationSequencer(
new Setup(),
new MotionTable(),
new NullAnimationLoader());
sequencer.Manager.AddToQueue(0x10000001u, ticks: 1u);
sequencer.Manager.AddToQueue(0x10000002u, ticks: 1u);
int completions = 0;
sequencer.MotionDoneTarget = (_, success) =>
{
Assert.True(success);
completions++;
Assert.True(poses.Remove(9u));
poses.Publish(
Entity(9u, new Vector3(40f, 50f, 60f)),
Array.Empty<Matrix4x4>());
};
queue.Capture(
9u,
sequencer,
new AnimationHook[]
{
new AnimationDoneHook(),
new AnimationDoneHook(),
});
Assert.Equal(1, completions);
Assert.Single(sequencer.Manager.PendingAnimations);
queue.Drain();
Assert.Equal(0, queue.Count);
}
[Fact]
public void HookSinkReuseDuringDrain_StopsRemainingOldIncarnationHooks()
{
var poses = new EntityEffectPoseRegistry();
poses.Publish(Entity(9u, Vector3.Zero), Array.Empty<Matrix4x4>());
var router = new AnimationHookRouter();
bool replaced = false;
var sink = new CallbackSink(() =>
{
if (replaced)
return;
replaced = true;
Assert.True(poses.Remove(9u));
poses.Publish(
Entity(9u, new Vector3(40f, 50f, 60f)),
Array.Empty<Matrix4x4>());
});
router.Register(sink);
var queue = new AnimationHookFrameQueue(router, poses);
var sequencer = new AnimationSequencer(
new Setup(),
new MotionTable(),
new NullAnimationLoader());
queue.Capture(
9u,
sequencer,
new AnimationHook[] { new SoundHook(), new SoundHook() });
queue.Drain();
Assert.Equal(1, sink.Calls);
Assert.Equal(0, queue.Count);
}
[Fact]
public void AnimationHookQueue_CompletesMotionStateAtCaptureEvenWhenPoseWasRemoved()
{
@ -217,6 +354,17 @@ public sealed class EntityEffectPoseRegistryTests
Calls.Add((entityId, entityWorldPosition));
}
private sealed class CallbackSink(Action callback) : IAnimationHookSink
{
public int Calls { get; private set; }
public void OnHook(uint entityId, Vector3 entityWorldPosition, AnimationHook hook)
{
Calls++;
callback();
}
}
private sealed class NullAnimationLoader : IAnimationLoader
{
public Animation? LoadAnimation(uint animationId) => null;