perf(streaming): quiesce retired generations and budget teardown

Publish the retail blocking-for-cells edge before deferred recenter work, freeze old-world presentation/simulation/audio, and advance full-window retirement from exact metered entity and owner cursors. This removes synchronous portal teardown without allowing retained owners to remain observable.
This commit is contained in:
Erik 2026-07-24 18:29:52 +02:00
parent b8f6317fe1
commit bb16f74fd4
38 changed files with 1691 additions and 170 deletions

View file

@ -38,6 +38,25 @@ public sealed class RecallTeleportAnimationTests
Assert.Equal(["objects", "network", "commands", "spatial"], calls);
}
[Fact]
public void LiveFrame_WhileCellsAreBlocked_DrainsNetworkAndCommandsWithoutWorldTicks()
{
var calls = new List<string>();
var availability = new WorldGenerationAvailabilityState();
availability.Begin(1);
var frame = new RetailLiveFrameCoordinator(
new TestLiveObjectFramePhase(_ => calls.Add("objects")),
new GpuWorldState(availability: availability),
new TestLiveSessionFramePhase(() => calls.Add("network")),
new TestPostNetworkCommandFramePhase(() => calls.Add("commands")),
new TestLiveSpatialReconcilePhase(() => calls.Add("spatial")),
availability);
frame.Tick(1f / 60f);
Assert.Equal(["network", "commands"], calls);
}
[Fact]
public void LiveFrame_InvalidHostDeltaCannotBlockNetworkDispatch()
{

View file

@ -1,5 +1,6 @@
using System.Reflection;
using AcDream.App.Rendering;
using AcDream.App.Streaming;
using AcDream.App.Update;
using AcDream.App.World;
@ -129,6 +130,33 @@ public sealed class UpdateFrameOrchestratorTests
observed.Camera.Select(value => value.SimulationDeltaSeconds));
}
[Fact]
public void QuiescedWorld_FreezesScriptClockAndLivenessWhilePortalPhasesContinue()
{
var calls = new List<string>();
var observed = new FrameObservations();
var availability = new WorldGenerationAvailabilityState();
availability.Begin(7);
UpdateFrameOrchestrator frame = Create(
calls,
observed: observed,
availability: availability);
frame.Tick(new UpdateFrameInput(0.25));
frame.Tick(new UpdateFrameInput(0.25));
availability.End(7);
frame.Tick(new UpdateFrameInput(0.25));
Assert.Equal([0.0, 0.0, 0.25], observed.PublishedTimes);
Assert.Equal(1, calls.Count(call => call == "liveness"));
Assert.Equal(3, calls.Count(call => call == "streaming"));
Assert.Equal(3, calls.Count(call => call == "network"));
Assert.Equal(3, calls.Count(call => call == "teleport"));
Assert.Equal(3, calls.Count(call => call == "camera"));
Assert.Equal([0.25f, 0.25f, 0.25f], observed.LiveDeltas);
Assert.Equal([0.25f, 0.25f, 0.25f], observed.TeleportDeltas);
}
[Fact]
public void Clock_RejectsFiniteDeltaAboveTheSinglePrecisionConsumerRange()
{
@ -200,6 +228,7 @@ public sealed class UpdateFrameOrchestratorTests
typeof(ILocalPlayerTeleportFramePhase),
typeof(IPlayerModeAutoEntryFramePhase),
typeof(ICameraFramePhase),
typeof(IWorldGenerationAvailability),
];
FieldInfo[] fields = typeof(UpdateFrameOrchestrator).GetFields(
@ -534,7 +563,8 @@ public sealed class UpdateFrameOrchestratorTests
"new LiveEntityLivenessFramePhase(",
"session.LocalTeleport,",
"new PlayerModeAutoEntryFramePhase(",
"cameraFrame);");
"cameraFrame,",
"live.WorldAvailability);");
}
[Fact]
@ -860,7 +890,8 @@ public sealed class UpdateFrameOrchestratorTests
RecordingFailureSink? failureSink = null,
FrameObservations? observed = null,
bool teleportPlace = false,
bool inboundCreatedPlayer = false)
bool inboundCreatedPlayer = false,
IWorldGenerationAvailability? availability = null)
{
teardown ??= new RecordingTeardown(calls);
failureSink ??= new RecordingFailureSink();
@ -875,7 +906,8 @@ public sealed class UpdateFrameOrchestratorTests
new RecordingLiveness(calls),
new RecordingTeleport(calls, observed, teleportPlace),
new RecordingAutoEntry(calls),
new RecordingCamera(calls, observed, inboundCreatedPlayer));
new RecordingCamera(calls, observed, inboundCreatedPlayer),
availability);
}
private sealed class RecordingTeardown(List<string> calls)