refactor(runtime): own canonical entity and object lifetime

Introduce one presentation-free RuntimeEntityObjectLifetime for the exact entity directory and ClientObjectTable. Make GameWindow, graphical projections, retained UI, interaction, session routing, create/delete integration, and reset borrow that owner while preserving synchronous retail ordering, dormant retention, and retry semantics.

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-26 05:54:46 +02:00
parent d9bf4c4960
commit 5ef8b5371d
40 changed files with 712 additions and 170 deletions

View file

@ -25,6 +25,7 @@ using AcDream.Core.Rendering;
using AcDream.Core.Selection;
using AcDream.Core.Vfx;
using AcDream.Core.World;
using AcDream.Runtime.Entities;
using DatReaderWriter;
using DatReaderWriter.DBObjs;
using Silk.NET.OpenGL;
@ -44,7 +45,7 @@ internal sealed record LivePresentationDependencies(
WorldGameState WorldGameState,
WorldEvents WorldEvents,
SelectionState Selection,
ClientObjectTable Objects,
RuntimeEntityObjectLifetime EntityObjects,
LiveEntityRuntimeSlot RuntimeSlot,
DeferredLiveEntityMotionRuntimeBindings MotionBindings,
DeferredEntityEffectAdvanceSource EffectAdvance,
@ -377,7 +378,8 @@ internal sealed class LivePresentationCompositionPhase
worldState,
new CompositeLiveEntityResourceLifecycle(
[.. resourceOwners]),
componentLifecycle);
componentLifecycle,
d.EntityObjects);
var liveRuntimeLease = scope.Own(
"canonical live-entity runtime",
liveEntities,
@ -487,7 +489,7 @@ internal sealed class LivePresentationCompositionPhase
() => new EquippedChildRenderController(
content.Dats,
d.DatLock,
d.Objects,
d.EntityObjects.Objects,
liveEntities,
d.EffectPoses,
parentAcceptance.TryAccept,
@ -675,7 +677,7 @@ internal sealed class LivePresentationCompositionPhase
static value => value.Dispose());
var selectionQuery = new WorldSelectionQuery(
liveEntities,
d.Objects,
d.EntityObjects.Objects,
selectionScene,
() => d.PlayerIdentity.ServerGuid,
interaction.LateBindings.SelectionCamera.Snapshot,
@ -699,7 +701,7 @@ internal sealed class LivePresentationCompositionPhase
}
});
var radarSnapshotProvider = new RadarSnapshotProvider(
d.Objects,
d.EntityObjects.Objects,
liveEntities,
() => liveEntities.Snapshots,
playerGuid: () => d.PlayerIdentity.ServerGuid,

View file

@ -26,6 +26,7 @@ using AcDream.Core.Player;
using AcDream.Core.Social;
using AcDream.Core.Spells;
using AcDream.Core.World;
using AcDream.Runtime.Entities;
using AcDream.Runtime.Session;
using Silk.NET.Windowing;
@ -47,7 +48,7 @@ internal sealed record SessionPlayerDependencies(
WorldGameState WorldGameState,
WorldEvents WorldEvents,
SelectionState Selection,
ClientObjectTable Objects,
RuntimeEntityObjectLifetime EntityObjects,
EntityClassificationCache ClassificationCache,
LiveEntityRuntimeSlot RuntimeSlot,
LiveEntityAnimationRuntimeView<LiveEntityAnimationState> AnimatedEntities,
@ -475,14 +476,14 @@ internal sealed class SessionPlayerCompositionPhase
var dormantLiveEntities = new DormantLiveEntityStore();
var deletion = new LiveEntityDeletionController(
live.LiveEntities,
d.Objects,
d.EntityObjects,
teardown,
d.PlayerIdentity,
dormantLiveEntities,
d.Options.DumpLiveSpawns ? d.Log : null);
var hydration = new LiveEntityHydrationController(
live.LiveEntities,
d.Objects,
d.EntityObjects,
d.DatLock,
projectionMaterializer,
new LiveEntityRelationshipProjection(live.EquippedChildren),
@ -505,7 +506,7 @@ internal sealed class SessionPlayerCompositionPhase
var networkUpdates = new LiveEntityNetworkUpdateController(
live.LiveEntities,
d.Objects,
d.EntityObjects.Objects,
hydration,
live.EntityEffects,
live.Presentation,
@ -574,7 +575,7 @@ internal sealed class SessionPlayerCompositionPhase
new CombatAttackTargetSource(
d.Selection,
live.LiveEntities,
d.Objects,
d.EntityObjects.Objects,
d.PlayerIdentity),
d.Settings,
d.PlayerController,
@ -809,7 +810,7 @@ internal sealed class SessionPlayerCompositionPhase
d.Shortcuts,
d.DesiredComponents),
new LiveSessionDomainRuntime(
d.Objects,
d.EntityObjects,
d.LocalPlayer,
d.Spellbook,
d.Combat,
@ -873,7 +874,7 @@ internal sealed class SessionPlayerCompositionPhase
var combatCommand = new LiveCombatModeCommandController(
new LiveSessionCombatModeAuthority(sessionHost),
new LocalPlayerCombatEquipmentSource(
d.Objects,
d.EntityObjects.Objects,
d.PlayerIdentity),
d.Combat,
new ItemInteractionCombatModeIntentSink(
@ -890,7 +891,7 @@ internal sealed class SessionPlayerCompositionPhase
liveSessionCommands,
d.PlayerIdentity,
live.LiveEntities,
d.Objects,
d.EntityObjects.Objects,
d.Chat,
d.PlayerController,
worldReveal,