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

@ -0,0 +1,112 @@
using AcDream.App.World;
namespace AcDream.App.Tests.World;
public sealed class RetailInboundEventDispatcherTests
{
private sealed class Counter
{
public int Value;
}
[Fact]
public void NestedEvents_DrainAfterCompleteOuterTail_InArrivalOrder()
{
var dispatcher = new RetailInboundEventDispatcher();
var calls = new List<string>();
dispatcher.Run(() =>
{
calls.Add("position-head");
dispatcher.Run(() => calls.Add("state"));
dispatcher.Run(() => calls.Add("vector"));
calls.Add("position-tail");
});
Assert.Equal(
["position-head", "position-tail", "state", "vector"],
calls);
Assert.False(dispatcher.IsDraining);
Assert.Equal(0, dispatcher.PendingCount);
}
[Fact]
public void FrameOperation_DefersInboundMutationUntilQuantumTail()
{
var dispatcher = new RetailInboundEventDispatcher();
var calls = new List<string>();
dispatcher.Run(() =>
{
calls.Add("physics");
dispatcher.Run(() => calls.Add("position"));
calls.Add("shadow-and-hooks");
});
Assert.Equal(["physics", "shadow-and-hooks", "position"], calls);
}
[Fact]
public void NestedStateOperations_DrainAfterOuterTail_InArrivalOrder()
{
var dispatcher = new RetailInboundEventDispatcher();
var calls = new List<string>();
dispatcher.Run(
dispatcher,
calls,
static (active, output) =>
{
output.Add("position-head");
active.Run(
output,
"state",
static (target, value) => target.Add(value));
output.Add("position-tail");
});
Assert.Equal(["position-head", "position-tail", "state"], calls);
Assert.False(dispatcher.IsDraining);
Assert.Equal(0, dispatcher.PendingCount);
}
[Fact]
public void Failure_DiscardsQueuedTailAndLeavesDispatcherReusable()
{
var dispatcher = new RetailInboundEventDispatcher();
bool queuedRan = false;
Assert.Throws<InvalidOperationException>(() => dispatcher.Run(() =>
{
dispatcher.Run(() => queuedRan = true);
throw new InvalidOperationException("packet failed");
}));
Assert.False(queuedRan);
Assert.False(dispatcher.IsDraining);
Assert.Equal(0, dispatcher.PendingCount);
dispatcher.Run(() => queuedRan = true);
Assert.True(queuedRan);
}
[Fact]
public void StateFastPath_DoesNotAllocateAfterWarmup()
{
var dispatcher = new RetailInboundEventDispatcher();
var counter = new Counter();
Action<Counter, int> increment =
static (target, amount) => target.Value += amount;
dispatcher.Run(counter, 1, increment);
long before = GC.GetAllocatedBytesForCurrentThread();
for (int i = 0; i < 1_000; i++)
{
dispatcher.Run(counter, 1, increment);
}
long allocated = GC.GetAllocatedBytesForCurrentThread() - before;
Assert.Equal(0, allocated);
Assert.Equal(1_001, counter.Value);
}
}