refactor(app): key live projections by runtime identity

Move materialized live-object sidecars and presentation worksets to exact RuntimeEntityKey ownership. Runtime remains the only GUID/incarnation/local-ID authority while hydration, animation, effects, lights, equipped children, renderer resources, visibility, liveness, and teardown resolve exact projection identities. Preserve synchronous callbacks, local-ID allocation order, and current rendering behavior.
This commit is contained in:
Erik 2026-07-25 21:50:58 +02:00
parent e18df84437
commit 420e5eea70
73 changed files with 2939 additions and 1715 deletions

View file

@ -20,8 +20,7 @@ public sealed class RadarSnapshotProvider
private static readonly Vector2 ProductionCenter = new(60f, 60f);
private readonly ClientObjectTable _objects;
private readonly Func<IReadOnlyDictionary<uint, WorldEntity>> _worldEntities;
private readonly Func<IReadOnlyDictionary<uint, WorldEntity>> _playerEntities;
private readonly ILiveEntityRadarSource _liveEntities;
private readonly Func<IReadOnlyDictionary<uint, WorldSession.EntitySpawn>> _spawns;
private readonly Func<uint> _playerGuid;
private readonly Func<float> _playerYawRadians;
@ -35,7 +34,7 @@ public sealed class RadarSnapshotProvider
public RadarSnapshotProvider(
ClientObjectTable objects,
Func<IReadOnlyDictionary<uint, WorldEntity>> worldEntities,
ILiveEntityRadarSource liveEntities,
Func<IReadOnlyDictionary<uint, WorldSession.EntitySpawn>> spawns,
Func<uint> playerGuid,
Func<float> playerYawRadians,
@ -44,12 +43,10 @@ public sealed class RadarSnapshotProvider
Func<bool> coordinatesOnRadar,
Func<bool> uiLocked,
Func<uint, RadarRelationshipTraits>? relationshipFor = null,
Func<IReadOnlyDictionary<uint, WorldEntity>>? playerEntities = null,
Func<ILiveEntitySpatialQuery?>? spatialQuery = null)
{
_objects = objects ?? throw new ArgumentNullException(nameof(objects));
_worldEntities = worldEntities ?? throw new ArgumentNullException(nameof(worldEntities));
_playerEntities = playerEntities ?? worldEntities;
_liveEntities = liveEntities ?? throw new ArgumentNullException(nameof(liveEntities));
_spawns = spawns ?? throw new ArgumentNullException(nameof(spawns));
_playerGuid = playerGuid ?? throw new ArgumentNullException(nameof(playerGuid));
_playerYawRadians = playerYawRadians ?? throw new ArgumentNullException(nameof(playerYawRadians));
@ -67,13 +64,14 @@ public sealed class RadarSnapshotProvider
// startup. Resolve these canonical projections per snapshot so the
// provider observes that runtime once it is installed, rather than
// retaining the bootstrap empty-map sentinels forever.
IReadOnlyDictionary<uint, WorldEntity> worldEntities = _worldEntities();
IReadOnlyDictionary<uint, WorldEntity> playerEntities = _playerEntities();
IReadOnlyDictionary<uint, WorldSession.EntitySpawn> spawns = _spawns();
bool uiLocked = _uiLocked();
uint playerGuid = _playerGuid();
if (playerGuid == 0u || !playerEntities.TryGetValue(playerGuid, out var playerEntity))
if (playerGuid == 0u
|| !_liveEntities.TryGetMaterialized(
playerGuid,
out WorldEntity playerEntity))
return UiRadarSnapshot.Empty with { UiLocked = uiLocked };
float heading = MoveToMath.HeadingFromYaw(_playerYawRadians());
@ -104,8 +102,7 @@ public sealed class RadarSnapshotProvider
}
else
{
foreach (var pair in worldEntities)
_candidateScratch.Add(pair);
_liveEntities.CopyVisibleTo(_candidateScratch);
}
var blips = new List<UiRadarBlip>(Math.Min(_candidateScratch.Count, 64));
@ -116,7 +113,7 @@ public sealed class RadarSnapshotProvider
continue;
var entity = pair.Value;
if (!worldEntities.TryGetValue(guid, out WorldEntity? visibleEntity)
if (!_liveEntities.TryGetVisible(guid, out WorldEntity? visibleEntity)
|| !ReferenceEquals(entity, visibleEntity))
{
continue;