fix(streaming): #138 — re-hydrate server objects from the retained spawn table on reload
Doors/NPCs/portals vanished after a portal OUT of the 0x0007 dungeon back to Holtburg. Root cause confirmed via ACE + holtburger cross-reference: the dungeon collapse drops a landblock's render entities for FPS, and ACE will NOT re-broadcast objects whose guid is still in its per-player KnownObjects set (never cleared on a normal teleport — ACE relies on the client retaining its object table and culling stale objects itself). So nothing restored them on the way back. Retail-faithful fix: a real client keeps its weenie_object_table and re-renders the world from it (holtburger keeps the table across a teleport; only suspends physics bodies). acdream's _lastSpawnByGuid (the parsed CreateObject records — position + Setup + appearance) IS that table and survives the collapse (the collapse path never calls RemoveLiveEntityByServerGuid, the only thing that prunes it). On landblock (re)load, replay OnLiveEntitySpawnedLocked for retained spawns whose render entity is absent — independent of any ACE re-send. - LandblockEntityRehydrator: pure selection (landblock match; skip already-present, the player, and mesh-less spawns), unit-tested (7). - StreamingController: onLandblockLoaded callback after AddLandblock (Loaded = dungeon-exit expand) and AddEntitiesToExistingLandblock (Promoted = Far->Near). - GameWindow.RehydrateServerEntitiesForLandblock: present-gate keys on GpuWorldState (NOT _entitiesByServerGuid, which holds collapse orphans), replay under _datLock; the replay's own RemoveLiveEntityByServerGuid de-dup scrubs the orphan state. Corrects the handoff: ClientObjectTable is inventory-only (no world position/Setup) and cannot rebuild a render entity; _lastSpawnByGuid is the world-object table. Register row AP-48 (no retail 25s visibility cull). dotnet build + 1518 Core tests green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b9445f53fe
commit
bf66fb4123
5 changed files with 311 additions and 3 deletions
|
|
@ -23,6 +23,17 @@ public sealed class StreamingController
|
|||
private readonly Action<LoadedLandblock, LandblockMeshData> _applyTerrain;
|
||||
private readonly Action<uint>? _removeTerrain;
|
||||
private readonly Action? _clearPendingLoads;
|
||||
|
||||
/// <summary>
|
||||
/// #138: fired after a landblock's entity layer (re)loads — both the full
|
||||
/// <see cref="LandblockStreamResult.Loaded"/> path (initial / dungeon-exit
|
||||
/// expand) and the <see cref="LandblockStreamResult.Promoted"/> path
|
||||
/// (Far→Near). <c>GameWindow</c> wires it to re-hydrate server objects whose
|
||||
/// render entities were dropped by the collapse/demote but whose parsed
|
||||
/// spawns it still retains. Receives the canonical landblock id. Null in
|
||||
/// tests that don't exercise re-hydration.
|
||||
/// </summary>
|
||||
private readonly Action<uint>? _onLandblockLoaded;
|
||||
private readonly GpuWorldState _state;
|
||||
private StreamingRegion? _region;
|
||||
|
||||
|
|
@ -87,7 +98,8 @@ public sealed class StreamingController
|
|||
int nearRadius,
|
||||
int farRadius,
|
||||
Action<uint>? removeTerrain = null,
|
||||
Action? clearPendingLoads = null)
|
||||
Action? clearPendingLoads = null,
|
||||
Action<uint>? onLandblockLoaded = null)
|
||||
{
|
||||
_enqueueLoad = enqueueLoad;
|
||||
_enqueueUnload = enqueueUnload;
|
||||
|
|
@ -95,6 +107,7 @@ public sealed class StreamingController
|
|||
_applyTerrain = applyTerrain;
|
||||
_removeTerrain = removeTerrain;
|
||||
_clearPendingLoads = clearPendingLoads;
|
||||
_onLandblockLoaded = onLandblockLoaded;
|
||||
_state = state;
|
||||
NearRadius = nearRadius;
|
||||
FarRadius = farRadius;
|
||||
|
|
@ -297,10 +310,15 @@ public sealed class StreamingController
|
|||
case LandblockStreamResult.Loaded loaded:
|
||||
_applyTerrain(loaded.Landblock, loaded.MeshData);
|
||||
_state.AddLandblock(loaded.Landblock);
|
||||
// #138: after the landblock is in _loaded (so AppendLiveEntity
|
||||
// hot-paths), restore any retained server objects ACE won't
|
||||
// re-send. Fired AFTER AddLandblock, never before.
|
||||
_onLandblockLoaded?.Invoke(loaded.Landblock.LandblockId);
|
||||
break;
|
||||
case LandblockStreamResult.Promoted promoted:
|
||||
_applyTerrain(promoted.Landblock, promoted.MeshData);
|
||||
_state.AddEntitiesToExistingLandblock(promoted.LandblockId, promoted.Entities);
|
||||
_onLandblockLoaded?.Invoke(promoted.LandblockId);
|
||||
break;
|
||||
case LandblockStreamResult.Unloaded unloaded:
|
||||
_state.RemoveLandblock(unloaded.LandblockId);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue