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:
parent
e18df84437
commit
420e5eea70
73 changed files with 2939 additions and 1715 deletions
|
|
@ -1,6 +1,7 @@
|
|||
using AcDream.App.World;
|
||||
using AcDream.Core.Lighting;
|
||||
using AcDream.Core.Physics;
|
||||
using AcDream.Runtime.Entities;
|
||||
using DatReaderWriter.DBObjs;
|
||||
|
||||
namespace AcDream.App.Rendering.Vfx;
|
||||
|
|
@ -22,8 +23,8 @@ public sealed class LiveEntityLightController : IDisposable
|
|||
private readonly EntityEffectPoseRegistry _poses;
|
||||
private readonly LightingHookSink _lighting;
|
||||
private readonly Func<uint, Setup?> _loadSetup;
|
||||
private readonly Dictionary<uint, uint> _serverGuidByOwner = new();
|
||||
private readonly HashSet<uint> _presentOwners = new();
|
||||
private readonly HashSet<RuntimeEntityKey> _trackedOwners = [];
|
||||
private readonly HashSet<RuntimeEntityKey> _presentOwners = [];
|
||||
|
||||
public LiveEntityLightController(
|
||||
LiveEntityRuntime liveEntities,
|
||||
|
|
@ -49,8 +50,9 @@ public sealed class LiveEntityLightController : IDisposable
|
|||
return false;
|
||||
}
|
||||
|
||||
_serverGuidByOwner[entity.Id] = serverGuid;
|
||||
_presentOwners.Add(entity.Id);
|
||||
RuntimeEntityKey key = RequireProjectionKey(record);
|
||||
_trackedOwners.Add(key);
|
||||
_presentOwners.Add(key);
|
||||
_lighting.UnregisterOwner(entity.Id, forgetState: false);
|
||||
_lighting.InitializeOwnerLighting(
|
||||
entity.Id,
|
||||
|
|
@ -87,7 +89,13 @@ public sealed class LiveEntityLightController : IDisposable
|
|||
/// <summary>Withdraw cell-scoped presentation but retain logical light state.</summary>
|
||||
public void Unregister(uint ownerLocalId)
|
||||
{
|
||||
_presentOwners.Remove(ownerLocalId);
|
||||
if (_liveEntities.TryGetRecordByLocalEntityId(
|
||||
ownerLocalId,
|
||||
out LiveEntityRecord record)
|
||||
&& record.ProjectionKey is { } key)
|
||||
{
|
||||
_presentOwners.Remove(key);
|
||||
}
|
||||
_lighting.UnregisterOwner(ownerLocalId, forgetState: false);
|
||||
}
|
||||
|
||||
|
|
@ -105,16 +113,20 @@ public sealed class LiveEntityLightController : IDisposable
|
|||
}
|
||||
|
||||
/// <summary>End logical ownership after leave-world presentation teardown.</summary>
|
||||
public void Forget(uint ownerLocalId)
|
||||
public void Forget(LiveEntityRecord record)
|
||||
{
|
||||
_presentOwners.Remove(ownerLocalId);
|
||||
_serverGuidByOwner.Remove(ownerLocalId);
|
||||
_lighting.UnregisterOwner(ownerLocalId);
|
||||
ArgumentNullException.ThrowIfNull(record);
|
||||
if (record.ProjectionKey is not { } key)
|
||||
return;
|
||||
|
||||
_presentOwners.Remove(key);
|
||||
_trackedOwners.Remove(key);
|
||||
_lighting.UnregisterOwner(key.LocalEntityId);
|
||||
}
|
||||
|
||||
public void Refresh() => _lighting.RefreshAttachedLights();
|
||||
|
||||
internal int TrackedOwnerCount => _serverGuidByOwner.Count;
|
||||
internal int TrackedOwnerCount => _trackedOwners.Count;
|
||||
internal int PresentedOwnerCount => _presentOwners.Count;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -127,7 +139,8 @@ public sealed class LiveEntityLightController : IDisposable
|
|||
if (!_liveEntities.TryGetRecord(serverGuid, out LiveEntityRecord record)
|
||||
|| record.ProjectionKind is not LiveEntityProjectionKind.Attached
|
||||
|| record.WorldEntity is not { } entity
|
||||
|| _presentOwners.Contains(entity.Id))
|
||||
|| record.ProjectionKey is not { } key
|
||||
|| _presentOwners.Contains(key))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -136,8 +149,11 @@ public sealed class LiveEntityLightController : IDisposable
|
|||
|
||||
private void OnOwnerLightingChanged(uint ownerLocalId, bool enabled)
|
||||
{
|
||||
if (!_presentOwners.Contains(ownerLocalId)
|
||||
|| !_serverGuidByOwner.TryGetValue(ownerLocalId, out uint serverGuid))
|
||||
if (!_liveEntities.TryGetRecordByLocalEntityId(
|
||||
ownerLocalId,
|
||||
out LiveEntityRecord record)
|
||||
|| record.ProjectionKey is not { } key
|
||||
|| !_presentOwners.Contains(key))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -148,15 +164,17 @@ public sealed class LiveEntityLightController : IDisposable
|
|||
return;
|
||||
}
|
||||
|
||||
Register(serverGuid);
|
||||
Register(record.ServerGuid);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_lighting.OwnerLightingChanged -= OnOwnerLightingChanged;
|
||||
_liveEntities.ProjectionVisibilityChanged -= OnProjectionVisibilityChanged;
|
||||
foreach (uint ownerId in _serverGuidByOwner.Keys.ToArray())
|
||||
Forget(ownerId);
|
||||
foreach (RuntimeEntityKey key in _trackedOwners)
|
||||
_lighting.UnregisterOwner(key.LocalEntityId);
|
||||
_trackedOwners.Clear();
|
||||
_presentOwners.Clear();
|
||||
}
|
||||
|
||||
private void OnProjectionVisibilityChanged(LiveEntityRecord record, bool visible)
|
||||
|
|
@ -176,4 +194,11 @@ public sealed class LiveEntityLightController : IDisposable
|
|||
else
|
||||
Unregister(entity.Id);
|
||||
}
|
||||
|
||||
private static RuntimeEntityKey RequireProjectionKey(
|
||||
LiveEntityRecord record) =>
|
||||
record.ProjectionKey
|
||||
?? throw new InvalidOperationException(
|
||||
$"Live entity 0x{record.ServerGuid:X8}/{record.Generation} " +
|
||||
"has no exact projection key.");
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue