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

@ -1,5 +1,7 @@
namespace AcDream.App.Update;
using AcDream.App.Streaming;
/// <summary>
/// The host-supplied input for one update callback.
/// </summary>
@ -28,10 +30,13 @@ internal sealed class UpdateFrameClock : IPhysicsScriptTimeSource
{
public double CurrentScriptTime { get; private set; }
public UpdateFrameTiming Advance(UpdateFrameInput input)
public UpdateFrameTiming Advance(
UpdateFrameInput input,
bool advanceScriptClock = true)
{
double deltaSeconds = NormalizeDeltaSeconds(input.HostDeltaSeconds);
CurrentScriptTime += deltaSeconds;
if (advanceScriptClock)
CurrentScriptTime += deltaSeconds;
return new UpdateFrameTiming(
deltaSeconds,
(float)deltaSeconds,
@ -122,6 +127,7 @@ internal sealed class UpdateFrameOrchestrator : AcDream.App.Rendering.IGameUpdat
private readonly ILocalPlayerTeleportFramePhase _teleport;
private readonly IPlayerModeAutoEntryFramePhase _playerModeAutoEntry;
private readonly ICameraFramePhase _camera;
private readonly IWorldGenerationAvailability _availability;
public UpdateFrameOrchestrator(
IUpdateFrameTeardownPhase teardown,
@ -134,7 +140,8 @@ internal sealed class UpdateFrameOrchestrator : AcDream.App.Rendering.IGameUpdat
ILiveEntityLivenessFramePhase liveness,
ILocalPlayerTeleportFramePhase teleport,
IPlayerModeAutoEntryFramePhase playerModeAutoEntry,
ICameraFramePhase camera)
ICameraFramePhase camera,
IWorldGenerationAvailability? availability = null)
{
_teardown = teardown ?? throw new ArgumentNullException(nameof(teardown));
_failureSink = failureSink ?? throw new ArgumentNullException(nameof(failureSink));
@ -149,6 +156,7 @@ internal sealed class UpdateFrameOrchestrator : AcDream.App.Rendering.IGameUpdat
_playerModeAutoEntry = playerModeAutoEntry
?? throw new ArgumentNullException(nameof(playerModeAutoEntry));
_camera = camera ?? throw new ArgumentNullException(nameof(camera));
_availability = availability ?? AlwaysAvailableWorldGeneration.Instance;
}
public void Tick(UpdateFrameInput input)
@ -165,12 +173,15 @@ internal sealed class UpdateFrameOrchestrator : AcDream.App.Rendering.IGameUpdat
_failureSink.ReportTeardownFailure(error);
}
UpdateFrameTiming timing = _clock.Advance(input);
UpdateFrameTiming timing = _clock.Advance(
input,
advanceScriptClock: _availability.IsWorldAvailable);
_scriptClockPublisher.PublishTime(timing.ScriptTime);
_streaming.Tick();
_input.Tick(timing);
_liveFrame.Tick(timing.SimulationDeltaSecondsSingle);
_liveness.Tick();
if (_availability.IsWorldAvailable)
_liveness.Tick();
_teleport.Tick(timing.SimulationDeltaSecondsSingle);
_playerModeAutoEntry.TryEnter();
_camera.Tick(timing);