feat(vfx): port retail hidden and teleport presentation
Preserve canonical live-object ownership across Hidden transitions and remote teleport placement so effects, collision, streaming, and targeting remain synchronized.
This commit is contained in:
parent
a51ebc66e9
commit
1e98d81448
46 changed files with 4883 additions and 127 deletions
|
|
@ -88,6 +88,8 @@ public sealed class GpuWorldState
|
|||
// list, so rebuilding it replaces the reference atomically.
|
||||
private IReadOnlyList<WorldEntity> _flatEntities = System.Array.Empty<WorldEntity>();
|
||||
private readonly HashSet<uint> _visibleLiveGuids = new();
|
||||
private readonly Queue<(uint ServerGuid, bool Visible)> _visibilityTransitions = new();
|
||||
private bool _dispatchingVisibilityTransitions;
|
||||
|
||||
public IReadOnlyList<WorldEntity> Entities => _flatEntities;
|
||||
public IReadOnlyCollection<uint> LoadedLandblockIds => _loaded.Keys;
|
||||
|
|
@ -282,6 +284,10 @@ public sealed class GpuWorldState
|
|||
// and it couldn't reach a pending entity). Re-appending routes the entity
|
||||
// to _loaded (drawn) when its landblock is loaded, or back to pending to
|
||||
// await AddLandblock otherwise.
|
||||
// Remove + place is one spatial transaction. Rebuilding between the
|
||||
// two operations exposes a false/true implementation pulse for a
|
||||
// loaded-to-loaded move and lets reentrant visibility callbacks observe
|
||||
// a state that never exists at the LiveEntityRuntime boundary.
|
||||
RemoveEntityFromAllBuckets(entity);
|
||||
PlaceLiveEntityProjection(canonical, entity);
|
||||
}
|
||||
|
|
@ -307,7 +313,6 @@ public sealed class GpuWorldState
|
|||
if (j != i) newList.Add(entities[j]);
|
||||
_loaded[kvp.Key] = new LoadedLandblock(
|
||||
kvp.Value.LandblockId, kvp.Value.Heightmap, newList);
|
||||
RebuildFlatView();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -510,6 +515,7 @@ public sealed class GpuWorldState
|
|||
bucket.Add(entity);
|
||||
if (probePersistent)
|
||||
EntityVanishProbe.Log($"[ent] APPEND guid=0x{entity.ServerGuid:X8} lb=0x{canonicalLandblockId:X8} -> PENDING(hidden)");
|
||||
RebuildFlatView();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -624,21 +630,48 @@ public sealed class GpuWorldState
|
|||
_flatEntities
|
||||
.Where(entity => entity.ServerGuid != 0)
|
||||
.Select(entity => entity.ServerGuid));
|
||||
foreach (uint guid in _visibleLiveGuids)
|
||||
{
|
||||
if (!nowVisible.Contains(guid))
|
||||
LiveProjectionVisibilityChanged?.Invoke(guid, false);
|
||||
}
|
||||
foreach (uint guid in nowVisible)
|
||||
{
|
||||
if (!_visibleLiveGuids.Contains(guid))
|
||||
LiveProjectionVisibilityChanged?.Invoke(guid, true);
|
||||
}
|
||||
uint[] becameHidden = _visibleLiveGuids
|
||||
.Where(guid => !nowVisible.Contains(guid))
|
||||
.ToArray();
|
||||
uint[] becameVisible = nowVisible
|
||||
.Where(guid => !_visibleLiveGuids.Contains(guid))
|
||||
.ToArray();
|
||||
|
||||
// Commit the new spatial truth before notifying observers. A
|
||||
// visibility callback may synchronously rebucket/withdraw the same
|
||||
// object (deferred teleport rollback); those nested transitions must
|
||||
// compare against this committed state rather than the stale prior set.
|
||||
_visibleLiveGuids.Clear();
|
||||
_visibleLiveGuids.UnionWith(nowVisible);
|
||||
foreach (uint guid in becameHidden)
|
||||
_visibilityTransitions.Enqueue((guid, false));
|
||||
foreach (uint guid in becameVisible)
|
||||
_visibilityTransitions.Enqueue((guid, true));
|
||||
DrainVisibilityTransitions();
|
||||
if (EntityVanishProbe.Enabled) ProbeFlatViewTransitions();
|
||||
}
|
||||
|
||||
private void DrainVisibilityTransitions()
|
||||
{
|
||||
if (_dispatchingVisibilityTransitions)
|
||||
return;
|
||||
|
||||
_dispatchingVisibilityTransitions = true;
|
||||
try
|
||||
{
|
||||
while (_visibilityTransitions.TryDequeue(out var transition))
|
||||
{
|
||||
LiveProjectionVisibilityChanged?.Invoke(
|
||||
transition.ServerGuid,
|
||||
transition.Visible);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_dispatchingVisibilityTransitions = false;
|
||||
}
|
||||
}
|
||||
|
||||
// TEMP (#138-B): persistent guids currently present in the drawn flat
|
||||
// view, for EntityVanishProbe transition logging. Strip with the probe.
|
||||
private readonly HashSet<uint> _persistentInFlatProbe = new();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue