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

@ -56,6 +56,7 @@ public sealed class GpuWorldState : ILiveEntitySpatialQuery
{
private readonly LandblockSpawnAdapter? _wbSpawnAdapter;
private readonly EntityScriptActivator? _entityScriptActivator;
private readonly IWorldGenerationAvailability _availability;
/// <summary>
/// Phase Post-A.5 #53 (Task 12): optional callback fired before
@ -72,11 +73,13 @@ public sealed class GpuWorldState : ILiveEntitySpatialQuery
public GpuWorldState(
LandblockSpawnAdapter? wbSpawnAdapter = null,
System.Action<uint>? onLandblockUnloaded = null,
EntityScriptActivator? entityScriptActivator = null)
EntityScriptActivator? entityScriptActivator = null,
IWorldGenerationAvailability? availability = null)
{
_wbSpawnAdapter = wbSpawnAdapter;
_onLandblockUnloaded = onLandblockUnloaded;
_entityScriptActivator = entityScriptActivator;
_availability = availability ?? AlwaysAvailableWorldGeneration.Instance;
}
private readonly Dictionary<uint, LoadedLandblock> _loaded = new();
@ -151,7 +154,9 @@ public sealed class GpuWorldState : ILiveEntitySpatialQuery
_loaded.ContainsKey(landblockId)
&& (_wbSpawnAdapter?.IsLandblockRenderReady(landblockId) ?? true);
public bool IsLiveEntityVisible(uint serverGuid) =>
serverGuid != 0 && _visibleLiveProjectionCounts.ContainsKey(serverGuid);
_availability.IsWorldAvailable
&& serverGuid != 0
&& _visibleLiveProjectionCounts.ContainsKey(serverGuid);
/// <summary>
/// Try to grab the loaded record for a landblock — useful for callers
@ -217,6 +222,9 @@ public sealed class GpuWorldState : ILiveEntitySpatialQuery
{
get
{
if (!_availability.IsWorldAvailable)
yield break;
foreach (var kvp in _loaded)
{
if (_aabbs.TryGetValue(kvp.Key, out var aabb))
@ -232,6 +240,9 @@ public sealed class GpuWorldState : ILiveEntitySpatialQuery
IReadOnlyDictionary<uint, WorldEntity>? AnimatedById)> EnumerateLandblockEntries(
bool includeAnimatedIndex)
{
if (!_availability.IsWorldAvailable)
yield break;
foreach (var kvp in _loaded)
{
IReadOnlyDictionary<uint, WorldEntity>? byId = null;
@ -299,6 +310,8 @@ public sealed class GpuWorldState : ILiveEntitySpatialQuery
ArgumentNullException.ThrowIfNull(destination);
ArgumentOutOfRangeException.ThrowIfNegative(landblockRadius);
destination.Clear();
if (!_availability.IsWorldAvailable)
return;
int centerX = (int)((centerCellOrLandblockId >> 24) & 0xFFu);
int centerY = (int)((centerCellOrLandblockId >> 16) & 0xFFu);