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:
parent
d9bf4c4960
commit
5ef8b5371d
40 changed files with 712 additions and 170 deletions
|
|
@ -1,7 +1,7 @@
|
|||
using AcDream.App.Input;
|
||||
using AcDream.Core.Items;
|
||||
using AcDream.Core.Net;
|
||||
using AcDream.Core.Net.Messages;
|
||||
using AcDream.Runtime.Entities;
|
||||
|
||||
namespace AcDream.App.World;
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ internal interface ILiveEntityPruneSink
|
|||
internal sealed class LiveEntityDeletionController : ILiveEntityPruneSink
|
||||
{
|
||||
private readonly LiveEntityRuntime _runtime;
|
||||
private readonly ClientObjectTable _objects;
|
||||
private readonly RuntimeEntityObjectLifetime _entityObjects;
|
||||
private readonly ILiveEntityTeardownCoordinator _teardown;
|
||||
private readonly ILocalPlayerIdentitySource _identity;
|
||||
private readonly DormantLiveEntityStore _dormant;
|
||||
|
|
@ -25,14 +25,15 @@ internal sealed class LiveEntityDeletionController : ILiveEntityPruneSink
|
|||
|
||||
public LiveEntityDeletionController(
|
||||
LiveEntityRuntime runtime,
|
||||
ClientObjectTable objects,
|
||||
RuntimeEntityObjectLifetime entityObjects,
|
||||
ILiveEntityTeardownCoordinator teardown,
|
||||
ILocalPlayerIdentitySource identity,
|
||||
DormantLiveEntityStore? dormant = null,
|
||||
Action<string>? diagnostic = null)
|
||||
{
|
||||
_runtime = runtime ?? throw new ArgumentNullException(nameof(runtime));
|
||||
_objects = objects ?? throw new ArgumentNullException(nameof(objects));
|
||||
_entityObjects = entityObjects
|
||||
?? throw new ArgumentNullException(nameof(entityObjects));
|
||||
_teardown = teardown ?? throw new ArgumentNullException(nameof(teardown));
|
||||
_identity = identity ?? throw new ArgumentNullException(nameof(identity));
|
||||
_dormant = dormant ?? new DormantLiveEntityStore();
|
||||
|
|
@ -56,11 +57,10 @@ internal sealed class LiveEntityDeletionController : ILiveEntityPruneSink
|
|||
bool removed = _runtime.UnregisterLiveEntity(
|
||||
delete,
|
||||
isLocalPlayer: false,
|
||||
beforeTeardown: () =>
|
||||
ObjectTableWiring.ApplyEntityDelete(_objects, delete));
|
||||
removeRetainedObject: true);
|
||||
bool removedDormant = _dormant.RemoveExact(delete);
|
||||
if (!removed && removedDormant)
|
||||
ObjectTableWiring.ApplyEntityDelete(_objects, delete);
|
||||
_entityObjects.ApplyAcceptedDormantDelete(delete);
|
||||
if (removed)
|
||||
{
|
||||
_dormant.RemoveExact(delete);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using AcDream.App.Rendering;
|
||||
using AcDream.App.Input;
|
||||
using AcDream.Core.Items;
|
||||
using AcDream.Core.Net;
|
||||
using AcDream.Core.Net.Messages;
|
||||
using AcDream.Core.World;
|
||||
|
|
@ -169,7 +168,7 @@ internal interface ILiveEntityWorldOriginCoordinator
|
|||
internal sealed class LiveEntityHydrationController : ILiveEntityLandblockLoadedSink
|
||||
{
|
||||
private readonly LiveEntityRuntime _runtime;
|
||||
private readonly ClientObjectTable _objects;
|
||||
private readonly RuntimeEntityObjectLifetime _entityObjects;
|
||||
private readonly object _datLock;
|
||||
private readonly ILiveEntityProjectionMaterializer _materializer;
|
||||
private readonly ILiveEntityRelationshipProjection _relationships;
|
||||
|
|
@ -193,7 +192,7 @@ internal sealed class LiveEntityHydrationController : ILiveEntityLandblockLoaded
|
|||
|
||||
public LiveEntityHydrationController(
|
||||
LiveEntityRuntime runtime,
|
||||
ClientObjectTable objects,
|
||||
RuntimeEntityObjectLifetime entityObjects,
|
||||
object datLock,
|
||||
ILiveEntityProjectionMaterializer materializer,
|
||||
ILiveEntityRelationshipProjection relationships,
|
||||
|
|
@ -207,7 +206,8 @@ internal sealed class LiveEntityHydrationController : ILiveEntityLandblockLoaded
|
|||
Action<string>? diagnostic = null)
|
||||
{
|
||||
_runtime = runtime ?? throw new ArgumentNullException(nameof(runtime));
|
||||
_objects = objects ?? throw new ArgumentNullException(nameof(objects));
|
||||
_entityObjects = entityObjects
|
||||
?? throw new ArgumentNullException(nameof(entityObjects));
|
||||
_datLock = datLock ?? throw new ArgumentNullException(nameof(datLock));
|
||||
_materializer = materializer ?? throw new ArgumentNullException(nameof(materializer));
|
||||
_relationships = relationships ?? throw new ArgumentNullException(nameof(relationships));
|
||||
|
|
@ -285,15 +285,13 @@ internal sealed class LiveEntityHydrationController : ILiveEntityLandblockLoaded
|
|||
if (_runtime.IsCurrentCreateIntegration(
|
||||
canonical,
|
||||
createIntegrationVersion)
|
||||
&& ObjectTableWiring.ApplyEntitySpawn(
|
||||
_objects,
|
||||
&& _entityObjects.ApplyAcceptedSpawn(
|
||||
canonical,
|
||||
createIntegrationVersion,
|
||||
spawn,
|
||||
replaceGeneration: result.Disposition is
|
||||
AcDream.Core.Physics.CreateObjectTimestampDisposition.NewGeneration
|
||||
|| dormantDisposition is DormantCreateDisposition.NewGeneration,
|
||||
accepting: () => _runtime.IsCurrentCreateIntegration(
|
||||
canonical,
|
||||
createIntegrationVersion))
|
||||
|| dormantDisposition is DormantCreateDisposition.NewGeneration)
|
||||
&& _runtime.IsCurrentCreateIntegration(
|
||||
canonical,
|
||||
createIntegrationVersion))
|
||||
|
|
|
|||
|
|
@ -448,6 +448,7 @@ public sealed class LiveEntityRuntime : ILiveEntityRadarSource
|
|||
private readonly GpuWorldState _spatial;
|
||||
private readonly ILiveEntityResourceLifecycle _resources;
|
||||
private readonly ILiveEntityRuntimeComponentLifecycle _runtimeComponentLifecycle;
|
||||
private readonly RuntimeEntityObjectLifetime _entityObjects;
|
||||
private readonly RuntimeEntityDirectory _directory;
|
||||
private readonly LiveEntityProjectionStore _projections;
|
||||
// Logical components survive retail's 25-second leave-visibility lifetime.
|
||||
|
|
@ -471,12 +472,12 @@ public sealed class LiveEntityRuntime : ILiveEntityRadarSource
|
|||
public LiveEntityRuntime(
|
||||
GpuWorldState spatial,
|
||||
ILiveEntityResourceLifecycle resources,
|
||||
uint firstLocalEntityId = FirstLiveEntityId)
|
||||
RuntimeEntityObjectLifetime entityObjects)
|
||||
: this(
|
||||
spatial,
|
||||
resources,
|
||||
NullLiveEntityRuntimeComponentLifecycle.Instance,
|
||||
firstLocalEntityId)
|
||||
entityObjects)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -484,12 +485,12 @@ public sealed class LiveEntityRuntime : ILiveEntityRadarSource
|
|||
GpuWorldState spatial,
|
||||
ILiveEntityResourceLifecycle resources,
|
||||
Action<LiveEntityRecord> tearDownRuntimeComponents,
|
||||
uint firstLocalEntityId = FirstLiveEntityId)
|
||||
RuntimeEntityObjectLifetime entityObjects)
|
||||
: this(
|
||||
spatial,
|
||||
resources,
|
||||
new DelegateLiveEntityRuntimeComponentLifecycle(tearDownRuntimeComponents),
|
||||
firstLocalEntityId)
|
||||
entityObjects)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -497,13 +498,15 @@ public sealed class LiveEntityRuntime : ILiveEntityRadarSource
|
|||
GpuWorldState spatial,
|
||||
ILiveEntityResourceLifecycle resources,
|
||||
ILiveEntityRuntimeComponentLifecycle? runtimeComponentLifecycle,
|
||||
uint firstLocalEntityId = FirstLiveEntityId)
|
||||
RuntimeEntityObjectLifetime entityObjects)
|
||||
{
|
||||
_spatial = spatial ?? throw new ArgumentNullException(nameof(spatial));
|
||||
_resources = resources ?? throw new ArgumentNullException(nameof(resources));
|
||||
_runtimeComponentLifecycle = runtimeComponentLifecycle
|
||||
?? throw new ArgumentNullException(nameof(runtimeComponentLifecycle));
|
||||
_directory = new RuntimeEntityDirectory(firstLocalEntityId);
|
||||
_entityObjects = entityObjects
|
||||
?? throw new ArgumentNullException(nameof(entityObjects));
|
||||
_directory = _entityObjects.Entities;
|
||||
_projections = new LiveEntityProjectionStore(_directory);
|
||||
_spatial.LiveProjectionVisibilityChanged += OnSpatialVisibilityChanged;
|
||||
}
|
||||
|
|
@ -1187,6 +1190,7 @@ public sealed class LiveEntityRuntime : ILiveEntityRadarSource
|
|||
public bool UnregisterLiveEntity(
|
||||
DeleteObject.Parsed delete,
|
||||
bool isLocalPlayer,
|
||||
bool removeRetainedObject = false,
|
||||
Action? beforeTeardown = null)
|
||||
{
|
||||
if (_isRegisteringResources)
|
||||
|
|
@ -1208,9 +1212,13 @@ public sealed class LiveEntityRuntime : ILiveEntityRadarSource
|
|||
&& (record.DeleteAcceptedForTeardown
|
||||
|| _isClearing
|
||||
|| _sessionClearPendingFinalization);
|
||||
RuntimeEntityDeleteAcceptance? acceptedDelete = null;
|
||||
if (!retryingAcceptedDelete)
|
||||
{
|
||||
if (!_directory.TryDelete(delete, isLocalPlayer))
|
||||
if (!_entityObjects.TryAcceptDelete(
|
||||
delete,
|
||||
isLocalPlayer,
|
||||
out acceptedDelete))
|
||||
return false;
|
||||
AdvanceLifetimeMutation(delete.Guid);
|
||||
ParentAttachments.DeleteGeneration(delete.Guid, delete.InstanceSequence);
|
||||
|
|
@ -1258,6 +1266,18 @@ public sealed class LiveEntityRuntime : ILiveEntityRadarSource
|
|||
{
|
||||
if (!retryingAcceptedDelete)
|
||||
{
|
||||
if (removeRetainedObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
_entityObjects.CompleteAcceptedDelete(acceptedDelete!);
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
(failures ??= new List<Exception>()).Add(error);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
beforeTeardown?.Invoke();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue