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

@ -6,6 +6,7 @@ using AcDream.App.World;
using AcDream.Core.Physics;
using AcDream.Core.Physics.Motion;
using AcDream.Core.World;
using AcDream.Runtime.Entities;
using DatReaderWriter.Types;
using RemoteMotion = AcDream.App.Physics.RemoteMotion;
@ -27,7 +28,8 @@ internal sealed class LiveEntityAnimationScheduler
private readonly IEntityRootPosePublisher _rootPoses;
private readonly IAnimationHookCaptureSink _animationHooks;
private readonly List<LiveEntityRecord> _rootSnapshot = new();
private readonly Dictionary<uint, LiveEntityAnimationSchedule> _schedules = new();
private readonly Dictionary<RuntimeEntityKey, LiveEntityAnimationSchedule>
_schedules = [];
private readonly Frame _rootFrameScratch = new();
private readonly MotionDeltaFrame _rootDeltaScratch = new();
@ -59,7 +61,7 @@ internal sealed class LiveEntityAnimationScheduler
/// callback. The returned dictionary is reused and valid until the next
/// call.
/// </summary>
public IReadOnlyDictionary<uint, LiveEntityAnimationSchedule> Tick(
public IReadOnlyDictionary<RuntimeEntityKey, LiveEntityAnimationSchedule> Tick(
float elapsedSeconds,
Vector3? playerPosition,
bool localHiddenPartPoseDirty,
@ -139,7 +141,11 @@ internal sealed class LiveEntityAnimationScheduler
IReadOnlyList<PartTransform>? ownedFrames = schedule.SequenceFrames is { } produced
? animation.CaptureScheduleFrames(produced)
: null;
_schedules[entity.Id] = schedule with
RuntimeEntityKey key = record.ProjectionKey
?? throw new InvalidOperationException(
$"Live entity 0x{record.ServerGuid:X8}/" +
$"{record.Generation} has no exact projection key.");
_schedules[key] = schedule with
{
SequenceFrames = ownedFrames,
Record = record,