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

@ -147,8 +147,8 @@ public sealed class LiveRenderProjectionJournalTests
incarnation,
harness.Journal.Pending[0].Record.OwnerIncarnation);
Assert.True(harness.Runtime.WithdrawLiveEntityProjection(Guid));
harness.Projections.OnProjectionRemoved(record.WorldEntity.Id);
harness.Projections.OnProjectionRemoved(record.WorldEntity.Id);
harness.Projections.OnProjectionRemoved(record);
harness.Projections.OnProjectionRemoved(record);
Assert.Equal(2, harness.Journal.Count);
Assert.Equal(
RenderProjectionDeltaKind.UpdateFlags,
@ -166,13 +166,10 @@ public sealed class LiveRenderProjectionJournalTests
uint firstLocalId = first.WorldEntity!.Id;
harness.Journal.DrainTo(harness.Scene);
LiveEntityRegistrationResult replacement =
harness.Runtime.RegisterLiveEntity(Spawn(Guid, instance: 5));
LiveEntityRecord second = replacement.Record!;
WorldEntity secondEntity = harness.Runtime.MaterializeLiveEntity(
Guid,
CellId,
localId => Entity(localId, Guid))!;
LiveEntityRecord second = harness.Runtime.RegisterAndMaterializeProjection(
Spawn(Guid, instance: 5),
localId => Entity(localId, Guid));
WorldEntity secondEntity = Assert.IsType<WorldEntity>(second.WorldEntity);
second.InitialHydrationCompleted = true;
LiveEntityReadyCandidate current = LiveEntityReadyCandidate.Capture(second);
Assert.True(harness.Projections.OnEntityReady(current));
@ -209,7 +206,7 @@ public sealed class LiveRenderProjectionJournalTests
LiveEntityRegistrationResult duplicate =
harness.Runtime.RegisterLiveEntity(Spawn(Guid, instance: 5));
Assert.Same(record, duplicate.Record);
Assert.Same(record, duplicate.Projection);
Assert.True(harness.Projections.OnEntityReady(
LiveEntityReadyCandidate.Capture(record)));
@ -285,7 +282,7 @@ public sealed class LiveRenderProjectionJournalTests
LiveEntityReadyCandidate.Capture(record)));
harness.Journal.DrainTo(harness.Scene);
Assert.True(harness.Runtime.WithdrawLiveEntityProjection(Guid));
harness.Projections.OnProjectionRemoved(record.WorldEntity!.Id);
harness.Projections.OnProjectionRemoved(record);
harness.Journal.DrainTo(harness.Scene);
harness.Projections.SynchronizeActiveSources();
@ -311,7 +308,7 @@ public sealed class LiveRenderProjectionJournalTests
LiveEntityReadyCandidate.Capture(record)));
harness.Journal.DrainTo(harness.Scene);
Assert.True(harness.Runtime.WithdrawLiveEntityProjection(Guid));
harness.Projections.OnProjectionRemoved(record.WorldEntity!.Id);
harness.Projections.OnProjectionRemoved(record);
harness.Journal.DrainTo(harness.Scene);
Assert.True(harness.Runtime.RebucketLiveEntity(Guid, CellId));
@ -337,7 +334,7 @@ public sealed class LiveRenderProjectionJournalTests
LiveEntityReadyCandidate.Capture(record)));
harness.Journal.DrainTo(harness.Scene);
Assert.True(harness.Runtime.WithdrawLiveEntityProjection(Guid));
harness.Projections.OnProjectionRemoved(record.WorldEntity!.Id);
harness.Projections.OnProjectionRemoved(record);
harness.Journal.DrainTo(harness.Scene);
Assert.True(harness.Runtime.UnregisterLiveEntity(
@ -383,14 +380,11 @@ public sealed class LiveRenderProjectionJournalTests
LiveEntityProjectionKind projectionKind =
LiveEntityProjectionKind.World)
{
LiveEntityRecord record =
harness.Runtime.RegisterLiveEntity(Spawn(guid, instance)).Record!;
WorldEntity? entity = harness.Runtime.MaterializeLiveEntity(
guid,
CellId,
LiveEntityRecord record = harness.Runtime.RegisterAndMaterializeProjection(
Spawn(guid, instance),
localId => Entity(localId, guid),
projectionKind);
Assert.NotNull(entity);
Assert.NotNull(record.WorldEntity);
record.InitialHydrationCompleted = true;
return record;
}