refactor(streaming): compose landblock presentation transaction

Own render, physics, DAT-static presentation, and retained static-resource rebinds behind retryable receipts so a failed publication resumes its exact unfinished suffix without replaying retail create-time defaults.

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Erik 2026-07-21 21:45:16 +02:00
parent e1110f7e54
commit ea0da8c8ae
15 changed files with 1744 additions and 89 deletions

View file

@ -670,6 +670,13 @@ public sealed class GpuWorldState : ILiveEntitySpatialQuery
RequiresActivation: false);
}
// Reconcile the only fallible logical-owner edge before consuming any
// pending live/render/tier maps. A retry then sees the exact pending
// suffix even when a resolver or owner callback fails partway through.
landblock = NormalizeLoadedLandblock(landblock);
if (_loaded.TryGetValue(landblock.LandblockId, out LoadedLandblock? displaced))
ReconcileRetainedStaticEntityScripts(displaced, landblock);
// If pending live entities have been waiting for this landblock,
// merge them into the render-thread-owned mutable entity bucket before
// storing. Subsequent live spawns append to that bucket in O(1).
@ -681,11 +688,6 @@ public sealed class GpuWorldState : ILiveEntitySpatialQuery
landblock = NormalizeLoadedLandblock(landblock, merged);
_pendingByLandblock.Remove(landblock.LandblockId);
}
else
{
landblock = NormalizeLoadedLandblock(landblock);
}
HashSet<ulong>? mergedRenderIds = additionalRenderIds is null
? null
: new HashSet<ulong>(additionalRenderIds);
@ -703,7 +705,7 @@ public sealed class GpuWorldState : ILiveEntitySpatialQuery
tier = LandblockStreamTier.Near;
}
if (_loaded.Remove(landblock.LandblockId, out LoadedLandblock? displaced))
if (_loaded.Remove(landblock.LandblockId, out displaced))
{
RemoveLoadedLandblockFromFlatView(displaced);
_animatedIndexByLandblock.Remove(landblock.LandblockId);
@ -717,6 +719,39 @@ public sealed class GpuWorldState : ILiveEntitySpatialQuery
(IEnumerable<ulong>?)mergedRenderIds ?? Array.Empty<ulong>());
}
/// <summary>
/// A same-landblock rehydrate is an acdream streaming replacement, not a
/// retail logical create/delete edge. Retained static IDs rebind their
/// Setup-owned resources without replaying defaults; omitted IDs perform
/// the same exact teardown used by ordinary retirement.
/// </summary>
private void ReconcileRetainedStaticEntityScripts(
LoadedLandblock displaced,
LoadedLandblock replacement)
{
if (_entityScriptActivator is null)
return;
var replacementsById = new Dictionary<uint, WorldEntity>();
for (int i = 0; i < replacement.Entities.Count; i++)
{
WorldEntity entity = replacement.Entities[i];
if (entity.ServerGuid == 0)
replacementsById.Add(entity.Id, entity);
}
for (int i = 0; i < displaced.Entities.Count; i++)
{
WorldEntity prior = displaced.Entities[i];
if (prior.ServerGuid != 0)
continue;
if (replacementsById.TryGetValue(prior.Id, out WorldEntity? retained))
_entityScriptActivator.OnRebindStatic(prior, retained);
else
_entityScriptActivator.OnRemove(prior);
}
}
internal void ActivateLandblockPresentation(
GpuLandblockSpatialPublication publication)
{