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:
parent
e1110f7e54
commit
ea0da8c8ae
15 changed files with 1744 additions and 89 deletions
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue