using System.Collections.Immutable; using System.Numerics; using AcDream.Core.Items; using AcDream.Core.Net; using AcDream.Core.Net.Messages; using AcDream.Core.Physics; using AcDream.Runtime.Gameplay; using AcDream.Runtime.Physics; namespace AcDream.Runtime.Entities; public readonly record struct RuntimeEntityRegistrationResult( InboundCreateResult Inbound, RuntimeEntityRecord? Canonical, bool LogicalRegistrationCreated, bool ReplacedExistingGeneration, Exception? PriorGenerationCleanupFailure = null, bool DeferredForParent = false); public readonly record struct RuntimeEntityObjectOwnershipSnapshot( int ActiveEntityCount, int TeardownEntityCount, int ClaimedLocalIdCount, int AcceptedSnapshotCount, int UnresolvedParentRelationCount, int DeferredParentCreateCount, int StagedParentRelationCount, int RecoveryParentRelationCount, int CommittedParentRelationCount, int ObjectCount, int ContainerCount, int ContainerProjectionCount, int EquipmentOwnerCount, int PendingMoveCount, int InitialCreateResidenceLeaseCount, int InitialCreateExecutorProgressCount, int StreamSubscriberCount, int PlacementStreamSubscriberCount, long StreamDispatchFailureCount, bool HasLastStreamDispatchFailure, int PendingDispatchCount, bool IsDispatching, bool IsSessionClearInProgress, bool IsDisposed, /// Round 5 R5-1: pending queue-by-parent-GUID accepted relations (see ). int DeferredAcceptedRelationCount = 0, /// Round 5 R5-3: mirrors StreamDispatchFailureCount/HasLastStreamDispatchFailure for the executor's contained-replay failure surface. Diagnostic only - like its stream precedent, NOT gated by . long ReplayFailureCount = 0, bool HasLastReplayFailure = false, /// /// F2: outstanding /// token-to-receipt correlation entries - one per completed drain whose /// ExecutorCompleted receipt a host has not yet acknowledged. Gated by /// , mirroring /// 's /// existing "unacknowledged receipt is outstanding debt" shape for the /// SAME underlying receipt stream - unlike ReplayFailureCount above, /// this is NOT a diagnostic-only counter. /// int PendingCompletionReceiptCount = 0, /// /// C3a/F2: outstanding AcDream.Runtime.Gameplay.RuntimeLocalPlayerFirstEntryState /// tracked keys - dormant (no production caller of its own /// Advance), but fully constructed/wired like every other owner /// here, so its own ownership must converge to zero the same way. /// int LocalPlayerFirstEntryActiveCount = 0, /// /// C3b: outstanding tracked /// keys - the remote/projectile Create-time body-construction conductor. /// Dormant like its C3a sibling; converges to zero the same way. /// int RemoteFirstEntryActiveCount = 0, /// /// C3c-R1 review F5: outstanding host first-entry drive entries /// (RuntimeFirstEntryDriveController pending keys, summed over /// every drive registered against this lifetime via /// ). /// Previously outside every ledger; gated by /// like the conductor counts it pumps. /// int FirstEntryDrivePendingCount = 0, /// /// C4 route 2: outstanding host RuntimeAcceptedPositionDriveController /// pending operations (a not-yet-committed or not-yet-acknowledged /// ForcePosition on the local player), summed over every drive /// registered against this lifetime via /// . /// Gated by — a leaked pending ack cannot hide. /// int AcceptedPositionDrivePendingCount = 0, /// /// C4 route 4b-1: outstanding /// AcDream.Runtime.Session.RuntimeRemotePlacementDriveController /// preparation-retry entries (a not-yet-resolved /// RetrySetupUnavailable/RetryWorldFrameUnavailable for a /// remote), summed over every drive registered against this lifetime via /// . /// Gated by , mirroring /// — steady-state /// remotes hold no operations, and this count proves it at every /// convergence checkpoint the same way. /// int RemotePlacementDrivePendingCount = 0) { public bool IsConverged => IsDisposed && ActiveEntityCount == 0 && TeardownEntityCount == 0 && ClaimedLocalIdCount == 0 && AcceptedSnapshotCount == 0 && UnresolvedParentRelationCount == 0 && DeferredParentCreateCount == 0 && DeferredAcceptedRelationCount == 0 && StagedParentRelationCount == 0 && RecoveryParentRelationCount == 0 && CommittedParentRelationCount == 0 && ObjectCount == 0 && ContainerCount == 0 && ContainerProjectionCount == 0 && EquipmentOwnerCount == 0 && PendingMoveCount == 0 && InitialCreateResidenceLeaseCount == 0 && InitialCreateExecutorProgressCount == 0 && PendingCompletionReceiptCount == 0 && LocalPlayerFirstEntryActiveCount == 0 && RemoteFirstEntryActiveCount == 0 && FirstEntryDrivePendingCount == 0 && AcceptedPositionDrivePendingCount == 0 && RemotePlacementDrivePendingCount == 0 && StreamSubscriberCount == 0 && PlacementStreamSubscriberCount == 0 && PendingDispatchCount == 0 && !IsDispatching && !IsSessionClearInProgress; } /// /// One exact DeleteObject acceptance issued by a /// . The graphical host retires the /// active identity before returning this token to the Runtime owner for the /// retained-object mutation, preserving retail callback order. /// public sealed class RuntimeEntityDeleteAcceptance { internal RuntimeEntityDeleteAcceptance( RuntimeEntityObjectLifetime owner, DeleteObject.Parsed delete, RuntimeEntityRecord? retiredCanonical, bool removeRetainedObject) { Owner = owner; Delete = delete; RetiredCanonical = retiredCanonical; RemoveRetainedObject = removeRetainedObject; } internal RuntimeEntityObjectLifetime Owner { get; } internal bool Completed { get; set; } public DeleteObject.Parsed Delete { get; } public RuntimeEntityRecord? RetiredCanonical { get; } public bool RemoveRetainedObject { get; } } /// /// Presentation-free ownership root for one session's canonical entity and /// retained object lifetimes. Graphical and direct hosts borrow these exact /// instances; they never allocate a second directory or object table. /// public sealed class RuntimeEntityObjectLifetime : IDisposable { private bool _sessionClearInProgress; private bool _disposed; /// C3c: see . private Action? _initialResidenceBegan; /// C3c-R1 review F5: see . private readonly List> _firstEntryDriveOwnership = []; /// C4 route 2: see . private readonly List> _acceptedPositionDriveOwnership = []; /// C4 route 4b-1: see . private readonly List> _remotePlacementDriveOwnership = []; /// /// C4 route 4a: captured by alongside the /// other generation-consuming children so /// can build a real /// RuntimeAuthoritativePositionAuthority from the SAME generation /// source every other accepted-position authority in this lifetime uses. /// Never exposed: a host must not be able to read a generation token out /// of this lifetime and assemble its own authority beside it. /// private Func? _generation; /// /// #297 (review round 2, preferred fix): keeps every canonical /// snapshot's ObjectDescriptionFlags live against /// ClientObjectTable.PublicWeenieBitfield — see /// for the full /// rationale. /// private readonly RuntimeEntityPvpBitfieldSnapshotSync _pvpBitfieldSync; public RuntimeEntityObjectLifetime( uint firstLocalEntityId = RuntimeEntityDirectory.FirstLocalEntityId, TimeProvider? timeProvider = null, IGameRuntimeClock? gameClock = null) { Entities = new RuntimeEntityDirectory(firstLocalEntityId); Physics = new RuntimePhysicsState( Entities, timeProvider: timeProvider, gameClock: gameClock); Objects = new ClientObjectTable(); _pvpBitfieldSync = new RuntimeEntityPvpBitfieldSnapshotSync(Entities, Objects); // AP-129 (Campaign P Slice P4 review fix, 2026-07-30): the physics // entry-restriction gate (ObjectInfo.CheckEntryRestrictions) resolves // a restricted cell's owner/guest list through the SAME live // ClientObjectTable every other subsystem borrows from this owner — // never a second table. Without this, every restricted cell fails // closed for everyone (see PhysicsEngine.Objects). Physics.Engine.Objects = Objects; var views = new RuntimeEntityObjectViews(Entities, Objects); EntityView = views.Entities; InventoryView = views.Inventory; Events = new RuntimeEntityObjectEventStream(Entities, Objects); Physics.SetPosition.BindEventStream(Events); InitialCreateResidences = new RuntimeInitialCreateResidenceState( Entities, Physics.SetPosition); InitialCreateExecution = new RuntimeInitialCreateContinuationExecutor( Entities, InitialCreateResidences, Physics, Events, (spawn, isLocalPlayer) => RegisterEntityWithInitialResidence(spawn, isLocalPlayer), (canonical, version, spawn, replaceGeneration) => ApplyAcceptedSpawn(canonical, version, spawn, replaceGeneration)); // C3a/F2: dormant - no production caller of its own Advance - but // constructed and wired exactly like the executor above so its // ownership converges the same way. RuntimeLocalPlayerPhysicsPublicationState // does not exist yet at this point (GameRuntime builds // RuntimeLocalPlayerMovementState, then attaches its publication, // only after this lifetime); BindPublication supplies it later. LocalPlayerFirstEntry = new RuntimeLocalPlayerFirstEntryState( InitialCreateResidences, InitialCreateExecution, Physics); // C3b: the remote/projectile analog of the conductor above — retail // body construction at Create time in place of the publication // chain. Dormant like its sibling (no production caller of Advance); // constructed and wired identically so its ownership converges the // same way. RemoteFirstEntry = new RuntimeRemoteFirstEntryState( InitialCreateResidences, InitialCreateExecution, Physics); // Round 3 B3: every residence retirement path - not only the // executor's own DiscardProgress calls - must converge the // executor's progress AND its separately-tracked pending // continuation placement token. This class owns both sides of the // relationship, so it binds the delegate here rather than the // residence state referencing the executor type directly. InitialCreateResidences.BindRetirementNotification( key => InitialCreateExecution.DiscardProgress(key)); // C3a/F2: the SAME multicast retirement notification also reaps the // first-entry conductor's tracked progress - see // RuntimeInitialCreateResidenceState.BindRetirementNotification's // updated doc comment for why this is now multicast. InitialCreateResidences.BindRetirementNotification( key => LocalPlayerFirstEntry.Forget(key)); // C3b: the remote conductor joins the SAME multicast retirement // fan-out, third in registration order. InitialCreateResidences.BindRetirementNotification( key => RemoteFirstEntry.Forget(key)); // F2: reaps the executor's completion-receipt correlation entry // exactly when a host acknowledges the ExecutorCompleted receipt it // correlates - mirrors the residence-retirement binding immediately // above. Physics.SetPosition.BindExecutorCompletionAcknowledgement( (key, sequence) => InitialCreateExecution.ForgetCompletionReceipt(key, sequence)); Placements = new RuntimePlacementProjectionChannel( Events, Physics.SetPosition, InitialCreateExecution); } internal RuntimeEntityObjectLifetime( PhysicsDataCache physicsDataCache, uint firstLocalEntityId = RuntimeEntityDirectory.FirstLocalEntityId, TimeProvider? timeProvider = null, IGameRuntimeClock? gameClock = null) { ArgumentNullException.ThrowIfNull(physicsDataCache); Entities = new RuntimeEntityDirectory(firstLocalEntityId); Physics = new RuntimePhysicsState( Entities, physicsDataCache, timeProvider, gameClock); Objects = new ClientObjectTable(); _pvpBitfieldSync = new RuntimeEntityPvpBitfieldSnapshotSync(Entities, Objects); Physics.Engine.Objects = Objects; var views = new RuntimeEntityObjectViews(Entities, Objects); EntityView = views.Entities; InventoryView = views.Inventory; Events = new RuntimeEntityObjectEventStream(Entities, Objects); Physics.SetPosition.BindEventStream(Events); InitialCreateResidences = new RuntimeInitialCreateResidenceState( Entities, Physics.SetPosition); InitialCreateExecution = new RuntimeInitialCreateContinuationExecutor( Entities, InitialCreateResidences, Physics, Events, (spawn, isLocalPlayer) => RegisterEntityWithInitialResidence(spawn, isLocalPlayer), (canonical, version, spawn, replaceGeneration) => ApplyAcceptedSpawn(canonical, version, spawn, replaceGeneration)); // C3a/F2: dormant - no production caller of its own Advance - but // constructed and wired exactly like the executor above so its // ownership converges the same way. RuntimeLocalPlayerPhysicsPublicationState // does not exist yet at this point (GameRuntime builds // RuntimeLocalPlayerMovementState, then attaches its publication, // only after this lifetime); BindPublication supplies it later. LocalPlayerFirstEntry = new RuntimeLocalPlayerFirstEntryState( InitialCreateResidences, InitialCreateExecution, Physics); // C3b: the remote/projectile analog of the conductor above — retail // body construction at Create time in place of the publication // chain. Dormant like its sibling (no production caller of Advance); // constructed and wired identically so its ownership converges the // same way. RemoteFirstEntry = new RuntimeRemoteFirstEntryState( InitialCreateResidences, InitialCreateExecution, Physics); // Round 3 B3: every residence retirement path - not only the // executor's own DiscardProgress calls - must converge the // executor's progress AND its separately-tracked pending // continuation placement token. This class owns both sides of the // relationship, so it binds the delegate here rather than the // residence state referencing the executor type directly. InitialCreateResidences.BindRetirementNotification( key => InitialCreateExecution.DiscardProgress(key)); // C3a/F2: the SAME multicast retirement notification also reaps the // first-entry conductor's tracked progress - see // RuntimeInitialCreateResidenceState.BindRetirementNotification's // updated doc comment for why this is now multicast. InitialCreateResidences.BindRetirementNotification( key => LocalPlayerFirstEntry.Forget(key)); // C3b: the remote conductor joins the SAME multicast retirement // fan-out, third in registration order. InitialCreateResidences.BindRetirementNotification( key => RemoteFirstEntry.Forget(key)); // F2: reaps the executor's completion-receipt correlation entry // exactly when a host acknowledges the ExecutorCompleted receipt it // correlates - mirrors the residence-retirement binding immediately // above. Physics.SetPosition.BindExecutorCompletionAcknowledgement( (key, sequence) => InitialCreateExecution.ForgetCompletionReceipt(key, sequence)); Placements = new RuntimePlacementProjectionChannel( Events, Physics.SetPosition, InitialCreateExecution); } internal RuntimeEntityObjectLifetime( PhysicsEngine physicsEngine, uint firstLocalEntityId = RuntimeEntityDirectory.FirstLocalEntityId, TimeProvider? timeProvider = null, IGameRuntimeClock? gameClock = null) { ArgumentNullException.ThrowIfNull(physicsEngine); Entities = new RuntimeEntityDirectory(firstLocalEntityId); Physics = new RuntimePhysicsState( Entities, physicsEngine, timeProvider, gameClock); Objects = new ClientObjectTable(); _pvpBitfieldSync = new RuntimeEntityPvpBitfieldSnapshotSync(Entities, Objects); Physics.Engine.Objects = Objects; var views = new RuntimeEntityObjectViews(Entities, Objects); EntityView = views.Entities; InventoryView = views.Inventory; Events = new RuntimeEntityObjectEventStream(Entities, Objects); Physics.SetPosition.BindEventStream(Events); InitialCreateResidences = new RuntimeInitialCreateResidenceState( Entities, Physics.SetPosition); InitialCreateExecution = new RuntimeInitialCreateContinuationExecutor( Entities, InitialCreateResidences, Physics, Events, (spawn, isLocalPlayer) => RegisterEntityWithInitialResidence(spawn, isLocalPlayer), (canonical, version, spawn, replaceGeneration) => ApplyAcceptedSpawn(canonical, version, spawn, replaceGeneration)); // C3a/F2: dormant - no production caller of its own Advance - but // constructed and wired exactly like the executor above so its // ownership converges the same way. RuntimeLocalPlayerPhysicsPublicationState // does not exist yet at this point (GameRuntime builds // RuntimeLocalPlayerMovementState, then attaches its publication, // only after this lifetime); BindPublication supplies it later. LocalPlayerFirstEntry = new RuntimeLocalPlayerFirstEntryState( InitialCreateResidences, InitialCreateExecution, Physics); // C3b: the remote/projectile analog of the conductor above — retail // body construction at Create time in place of the publication // chain. Dormant like its sibling (no production caller of Advance); // constructed and wired identically so its ownership converges the // same way. RemoteFirstEntry = new RuntimeRemoteFirstEntryState( InitialCreateResidences, InitialCreateExecution, Physics); // Round 3 B3: every residence retirement path - not only the // executor's own DiscardProgress calls - must converge the // executor's progress AND its separately-tracked pending // continuation placement token. This class owns both sides of the // relationship, so it binds the delegate here rather than the // residence state referencing the executor type directly. InitialCreateResidences.BindRetirementNotification( key => InitialCreateExecution.DiscardProgress(key)); // C3a/F2: the SAME multicast retirement notification also reaps the // first-entry conductor's tracked progress - see // RuntimeInitialCreateResidenceState.BindRetirementNotification's // updated doc comment for why this is now multicast. InitialCreateResidences.BindRetirementNotification( key => LocalPlayerFirstEntry.Forget(key)); // C3b: the remote conductor joins the SAME multicast retirement // fan-out, third in registration order. InitialCreateResidences.BindRetirementNotification( key => RemoteFirstEntry.Forget(key)); // F2: reaps the executor's completion-receipt correlation entry // exactly when a host acknowledges the ExecutorCompleted receipt it // correlates - mirrors the residence-retirement binding immediately // above. Physics.SetPosition.BindExecutorCompletionAcknowledgement( (key, sequence) => InitialCreateExecution.ForgetCompletionReceipt(key, sequence)); Placements = new RuntimePlacementProjectionChannel( Events, Physics.SetPosition, InitialCreateExecution); } public RuntimeEntityDirectory Entities { get; } public RuntimePhysicsState Physics { get; } public ClientObjectTable Objects { get; } public IRuntimeEntityView EntityView { get; } public IRuntimeInventoryView InventoryView { get; } public RuntimeEntityObjectEventStream Events { get; } public RuntimePlacementProjectionChannel Placements { get; } internal RuntimeInitialCreateResidenceState InitialCreateResidences { get; } internal RuntimeInitialCreateContinuationExecutor InitialCreateExecution { get; } internal RuntimeLocalPlayerFirstEntryState LocalPlayerFirstEntry { get; } internal RuntimeRemoteFirstEntryState RemoteFirstEntry { get; } public RuntimeEntityObjectOwnershipSnapshot CaptureOwnership() { ParentAttachmentState parents = Entities.ParentAttachments; RuntimeInitialCreateResidenceOwnershipSnapshot initialResidence = InitialCreateResidences.CaptureOwnership(); return new RuntimeEntityObjectOwnershipSnapshot( Entities.Count, Entities.PendingTeardownCount, Entities.ClaimedLocalIdCount, Entities.Snapshots.Count, parents.UnresolvedRelationCount, parents.DeferredCreateCount, parents.StagedRelationCount, parents.RecoveryRelationCount, parents.CommittedRelationCount, Objects.ObjectCount, Objects.ContainerCount, Objects.ContainerProjectionCount, Objects.EquipmentOwnerCount, Objects.PendingMoveCount, initialResidence.ActiveLeaseCount + initialResidence.PendingAdoptionCount, InitialCreateExecution.ProgressCount, Events.SubscriberCount, Events.PlacementSubscriberCount, Events.DispatchFailureCount, Events.LastDispatchFailure is not null, Events.PendingDispatchCount, Events.IsDispatching, _sessionClearInProgress, _disposed, parents.DeferredAcceptedRelationCount, InitialCreateExecution.ReplayFailureCount, InitialCreateExecution.LastReplayFailure is not null, InitialCreateExecution.PendingCompletionReceiptCount, LocalPlayerFirstEntry.CaptureOwnership().ActiveCount, RemoteFirstEntry.CaptureOwnership().ActiveCount, CaptureFirstEntryDrivePendingCount(), CaptureAcceptedPositionDrivePendingCount(), CaptureRemotePlacementDrivePendingCount()); } private int CaptureFirstEntryDrivePendingCount() { int total = 0; for (int i = 0; i < _firstEntryDriveOwnership.Count; i++) total = checked(total + _firstEntryDriveOwnership[i]()); return total; } private int CaptureAcceptedPositionDrivePendingCount() { int total = 0; for (int i = 0; i < _acceptedPositionDriveOwnership.Count; i++) total = checked(total + _acceptedPositionDriveOwnership[i]()); return total; } private int CaptureRemotePlacementDrivePendingCount() { int total = 0; for (int i = 0; i < _remotePlacementDriveOwnership.Count; i++) total = checked(total + _remotePlacementDriveOwnership[i]()); return total; } /// /// C3c-R1 review F5: registers one host first-entry drive controller's /// pending-count provider into this lifetime's ownership snapshot, so /// tracked-but-undriven entries can never sit outside every ledger. The /// drive controller registers itself at construction (it already binds /// there); multiple /// registrations sum, mirroring the multicast notification shape. /// public void RegisterFirstEntryDriveOwnership(Func pendingCount) { ArgumentNullException.ThrowIfNull(pendingCount); EnsureNotDisposed(); _firstEntryDriveOwnership.Add(pendingCount); } /// /// C4 route 2: registers one host RuntimeAcceptedPositionDriveController's /// pending-count provider into this lifetime's ownership snapshot, /// mirroring — a leaked /// pending ForcePosition ack must not sit outside every ledger. The /// drive controller registers itself at construction; multiple /// registrations sum (one per host route sharing this lifetime). /// public void RegisterAcceptedPositionDriveOwnership(Func pendingCount) { ArgumentNullException.ThrowIfNull(pendingCount); EnsureNotDisposed(); _acceptedPositionDriveOwnership.Add(pendingCount); } /// /// C4 route 4b-1: registers one host /// RuntimeRemotePlacementDriveController's pending-count provider /// into this lifetime's ownership snapshot, mirroring /// — a leaked /// remote preparation retry must not sit outside every ledger. The drive /// controller registers itself at construction; multiple registrations /// sum (one per host route sharing this lifetime). /// public void RegisterRemotePlacementDriveOwnership(Func pendingCount) { ArgumentNullException.ThrowIfNull(pendingCount); EnsureNotDisposed(); _remotePlacementDriveOwnership.Add(pendingCount); } public void BindEventContext( Func generation, Func frameNumber) { EnsureNotDisposed(); _generation = generation; Events.BindContext(generation, frameNumber); Placements.BindGeneration(generation); InitialCreateResidences.BindGeneration(generation); InitialCreateExecution.BindGeneration(generation); } /// /// C4 route 4a: classifies one REMOTE incarnation's accepted Position /// through , so /// the graphical host and any future no-window remote-motion host make /// the SAME airborne-no-op / near-interpolate decision from the same /// generation, the same authority shape, and the same request builder the /// deferred initial-create continuation uses. /// /// /// Returns when no classification can honestly be /// made: the lifetime has no bound generation yet, the canonical record /// has not claimed a local id, or there is no live local-player position /// to derive retail's player_distance from. A null here is /// "Runtime has no opinion", never "rejected". /// /// /// /// C4 route 4b-2 review fix — this used to add "In every one of those /// cases the caller's pre-existing legacy path runs completely /// unchanged". That path no longer exists: 4b-2 deleted the graphical /// caller's duplicated near/far blocks, and a null now takes the stated /// UnroutedCatchUp policy (AP-137; /// RuntimeRemoteFarSnapPosition.ResolveArm), which is AP-87's /// shared catch-up rather than a re-derived 96 m test. /// /// internal RuntimeAuthoritativePositionRoute? ClassifyRemoteAcceptedPosition( RuntimeEntityRecord canonical, in WorldSession.EntityPositionUpdate update, PositionTimestampDisposition disposition, in AcceptedPhysicsTimestamps timestamps, float? playerDistance) { ArgumentNullException.ThrowIfNull(canonical); if (_generation is not { } generation // C4 route 4b-3 (D1): a remote PositionEvent feeds the // classifier's cell-less predicate the PRE-merge committed cell // — the same value TryApplyPosition measured for THIS packet, // never re-read from the (already merged) canonical record. A // null here means the merge never observed a prior canonical // record for this entity, which "Runtime has no opinion" — the // same policy every other missing-input case in this method // already uses — covers honestly rather than fabricating 0. || timestamps.PreMergeCommittedCellId is not { } preMergeCommittedCellId) { return null; } if (!RuntimeAcceptedPositionRouteRequests.TryBuild( generation(), canonical, update, RuntimePositionEntityKind.Remote, RuntimeAcceptedPositionSource.PositionEvent, disposition, timestamps.PreviousTeleport, timestamps.Teleport, playerDistance, // Retail's UsePositionFromServer is consumed by the local // player branch only; the Remote branch never reads it. usePositionFromServer: false, preMergeCommittedCellId, out RuntimeAcceptedPositionRouteRequest request)) { return null; } return RuntimeAuthoritativePositionRouteClassifier .ClassifyAcceptedPosition(request); } /// /// C3c: registers one host callback fired for every FRESH initial-create /// residence begin (never for a same-generation FIFO append). Multicast, /// mirroring . /// The callback runs synchronously inside the registration transaction — /// subscribers must only record the entity for a later drive pump, never /// call a conductor's Advance re-entrantly from it. /// public void BindInitialResidenceBeginNotification( Action began) { ArgumentNullException.ThrowIfNull(began); EnsureNotDisposed(); _initialResidenceBegan += began; } /// /// C0-2: forwards to , /// the same fan-out shape already uses for /// generation binding. Separate from /// because GameRuntime constructs RuntimeCharacterState/ /// RuntimeLocalPlayerMovementState (the real source owners) AFTER /// this lifetime, so the live-input bind necessarily happens at a later /// point in GameRuntime's construction sequence than the /// generation bind. /// public void BindLiveInputs( Func usePositionFromServer, Func localPlayerPosition) { EnsureNotDisposed(); InitialCreateExecution.BindLiveInputs( usePositionFromServer, localPlayerPosition); } /// /// Owns the presentation-free half of retail's CreateObject lifetime /// transaction. An attached graphical host may synchronously retire the /// displaced projection through ; /// a direct host omits it and Runtime retires canonical-only state. /// public RuntimeEntityRegistrationResult RegisterEntity( WorldSession.EntitySpawn incoming, Func? retirePriorProjection = null) => RegisterEntityCore( incoming, beginInitialResidence: false, isLocalPlayer: false, retirePriorProjection); internal RuntimeEntityRegistrationResult RegisterEntityWithInitialResidence( WorldSession.EntitySpawn incoming, bool isLocalPlayer, Func? retirePriorProjection = null) => RegisterEntityCore( incoming, beginInitialResidence: true, isLocalPlayer, retirePriorProjection); private RuntimeEntityRegistrationResult RegisterEntityCore( WorldSession.EntitySpawn incoming, bool beginInitialResidence, bool isLocalPlayer, Func? retirePriorProjection) { EnsureNotDisposed(); if (beginInitialResidence && isLocalPlayer) { // The accepted local Create establishes the shared world frame // before any remote first-entry conductor converts its authored // landblock-local coordinates. #284: observe the Create itself // even when it carries no usable landblock - that is precisely // the case in which no frame is ever published, and every remote // placement would otherwise park forever without a diagnostic. Physics.ObserveLocalPlayerCreate( (incoming.Physics?.Position ?? incoming.Position) ?.LandblockId ?? 0u); } if (_sessionClearInProgress) { throw new InvalidOperationException( "A Runtime entity cannot register while its session lifetime is clearing."); } if (beginInitialResidence && !HasConsistentCreateIdentityAndParent(incoming)) { throw new InvalidOperationException( $"CreateObject 0x{incoming.Guid:X8} has inconsistent instance or parent projections."); } if (beginInitialResidence) incoming = RuntimeInitialCreateAdmissionFreezer.Freeze(incoming); uint parentGuid = incoming.ParentGuid ?? incoming.Physics?.Parent?.Guid ?? 0u; if (beginInitialResidence && parentGuid != 0u && !Entities.TryGetActive(parentGuid, out _)) { // SmartBox::HandleCreateObject resolves a nonzero parent before // object lookup or timestamp admission. Retain the complete raw // CreateObject so no child gate/canonical/projection state can // escape before the parent becomes addressable. Entities.ParentAttachments.EnqueueDeferredCreate( incoming, isLocalPlayer); return new RuntimeEntityRegistrationResult( SupersededCreateResult(), Canonical: null, LogicalRegistrationCreated: false, ReplacedExistingGeneration: false, DeferredForParent: true); } CreateObjectTimestampDisposition preview = Entities.PreviewCreateDisposition(incoming); bool requiresFreshResidenceAdmission = preview is CreateObjectTimestampDisposition.InitialGeneration or CreateObjectTimestampDisposition.NewGeneration; if (beginInitialResidence && requiresFreshResidenceAdmission && !InitialCreateResidences.CanAcceptCreate(incoming)) { throw new InvalidOperationException( $"CreateObject 0x{incoming.Guid:X8} cannot acquire a structurally valid initial residence lease."); } RuntimeEntityRecord? pendingResidenceRecord = null; RuntimeInitialCreateResidenceLease pendingResidence = default; bool admitIntoPendingResidence = beginInitialResidence && preview is CreateObjectTimestampDisposition.ExistingGeneration && Entities.TryGetActive( incoming.Guid, out pendingResidenceRecord) && InitialCreateResidences.TryGetTransaction( pendingResidenceRecord, out pendingResidence); if (admitIntoPendingResidence && !InitialCreateResidences.CanEnqueue( pendingResidenceRecord!, pendingResidence)) { throw new InvalidOperationException( $"CreateObject 0x{incoming.Guid:X8} cannot append to its pending initial residence FIFO."); } if (admitIntoPendingResidence && !IsStructurallyValidDeferredCreate(incoming)) { _ = Entities.TryGetAcceptedTimestamps( incoming.Guid, out AcceptedPhysicsTimestamps timestamps); return new RuntimeEntityRegistrationResult( new InboundCreateResult( CreateObjectTimestampDisposition.ExistingGeneration, pendingResidenceRecord!.Snapshot, SameGenerationEvents: null, timestamps), pendingResidenceRecord, LogicalRegistrationCreated: false, ReplacedExistingGeneration: false); } InboundCreateResult result = admitIntoPendingResidence ? Entities.AcceptCreateDeferredSameGeneration(incoming) : Entities.AcceptCreate(incoming); if (result.Disposition is CreateObjectTimestampDisposition.StaleGeneration) { return new RuntimeEntityRegistrationResult( result, Canonical: null, LogicalRegistrationCreated: false, ReplacedExistingGeneration: false); } ulong sessionVersion = Entities.SessionLifetimeVersion; ulong operationVersion = Entities.AdvanceLifetimeMutation(incoming.Guid); if (result.Disposition is CreateObjectTimestampDisposition.ExistingGeneration) { if (Entities.TryGetActive( incoming.Guid, out RuntimeEntityRecord retained)) { if (admitIntoPendingResidence) { if (!ReferenceEquals(retained, pendingResidenceRecord) || !AdmitSameGenerationCreate( retained, pendingResidence, incoming, result, isLocalPlayer)) { throw FailInitialResidenceRegistration( retained, publishDeleted: true); } InboundCreateResult dormant = result with { Snapshot = retained.Snapshot, SameGenerationEvents = null, }; return new RuntimeEntityRegistrationResult( dormant, retained, LogicalRegistrationCreated: false, ReplacedExistingGeneration: false); } // Existing-generation CreateObject contributes untimestamped // description fields here. Position/Parent/Pickup/State/etc. // remain separate freshness-gated events and must not churn a // pending initial placement or re-preclaim its wire cell. Entities.RefreshSnapshot( retained, result.Snapshot, refreshPosition: !beginInitialResidence); if (!beginInitialResidence) Entities.AdvanceCreateAuthority(retained); PublishEntity(RuntimeEntityChange.Updated, retained); if (!IsCurrentOperation( incoming.Guid, retained, sessionVersion, operationVersion)) { return SupersededRegistration( incoming.Guid, replacedExistingGeneration: false); } return new RuntimeEntityRegistrationResult( result, retained, LogicalRegistrationCreated: false, ReplacedExistingGeneration: false); } if (Entities.TryGetTeardown( incoming.Guid, result.Snapshot.InstanceSequence, out _)) { return new RuntimeEntityRegistrationResult( result, Canonical: null, LogicalRegistrationCreated: false, ReplacedExistingGeneration: false); } if (beginInitialResidence && !InitialCreateResidences.CanAcceptCreate(result.Snapshot)) { throw new InvalidOperationException( $"Recovered CreateObject 0x{incoming.Guid:X8} cannot acquire a structurally valid initial residence lease."); } RuntimeEntityRecord recovered = Entities.AddActive(result.Snapshot); if (!InitializeAcceptedCreateResidence( recovered, result, beginInitialResidence, isLocalPlayer)) { throw FailInitialResidenceRegistration( recovered, publishDeleted: false); } PublishEntity(RuntimeEntityChange.Registered, recovered); if (!IsCurrentOperation( incoming.Guid, recovered, sessionVersion, operationVersion)) { return SupersededRegistration( incoming.Guid, replacedExistingGeneration: false); } return new RuntimeEntityRegistrationResult( result, recovered, LogicalRegistrationCreated: true, ReplacedExistingGeneration: false); } bool replaced = Entities.RemoveActive( incoming.Guid, out RuntimeEntityRecord? prior); if (result.Disposition is CreateObjectTimestampDisposition.NewGeneration) { Entities.ParentAttachments.EndGeneration( incoming.Guid, result.Snapshot.InstanceSequence); } Exception? cleanupFailure = null; if (prior is not null) { // Removing the active GUID is an ownership transfer, not a gap. // Retain the exact incarnation before arbitrary synchronous // observers can re-enter registration, reset, or disposal. Entities.RetainTeardown(prior); try { PublishEntity(RuntimeEntityChange.Deleted, prior); } catch (Exception error) { cleanupFailure = error; } Exception? projectionFailure = retirePriorProjection is null ? RetireCanonicalOnly(prior) : retirePriorProjection(prior); cleanupFailure = Combine(cleanupFailure, projectionFailure); } if (Entities.SessionLifetimeVersion != sessionVersion || Entities.CurrentLifetimeMutation(incoming.Guid) != operationVersion) { if (cleanupFailure is not null) { throw new AggregateException( $"Prior incarnation of live entity 0x{incoming.Guid:X8} failed teardown while its incoming replacement was superseded.", cleanupFailure); } return new RuntimeEntityRegistrationResult( SupersededCreateResult(), Entities.TryGetActive( incoming.Guid, out RuntimeEntityRecord current) ? current : null, LogicalRegistrationCreated: false, ReplacedExistingGeneration: replaced); } RuntimeEntityRecord canonical = Entities.AddActive(result.Snapshot); if (!InitializeAcceptedCreateResidence( canonical, result, beginInitialResidence, isLocalPlayer)) { throw FailInitialResidenceRegistration( canonical, publishDeleted: false); } try { PublishEntity(RuntimeEntityChange.Registered, canonical); } catch (Exception error) { if (cleanupFailure is not null) { throw new AggregateException( $"Live entity 0x{incoming.Guid:X8} registered after prior cleanup and commit observers failed.", cleanupFailure, error); } throw; } if (!IsCurrentOperation( incoming.Guid, canonical, sessionVersion, operationVersion)) { if (cleanupFailure is not null) { throw new AggregateException( $"Prior incarnation of live entity 0x{incoming.Guid:X8} failed teardown while its committed replacement was superseded.", cleanupFailure); } return SupersededRegistration( incoming.Guid, replaced); } return new RuntimeEntityRegistrationResult( result, canonical, LogicalRegistrationCreated: true, ReplacedExistingGeneration: replaced, cleanupFailure); } /// /// Completes a displaced incarnation that never crossed the graphical /// projection acquisition edge. /// public Exception? RetireCanonicalOnly(RuntimeEntityRecord canonical) { EnsureNotDisposed(); ArgumentNullException.ThrowIfNull(canonical); try { Entities.RetainTeardown(canonical); try { CompleteProjectionRetirement(canonical); } finally { Entities.ReleaseTeardown(canonical); } return null; } catch (Exception error) { return error; } } /// /// Completes the presentation acknowledgement for one retained /// incarnation. Runtime retires every presentation-independent component /// and releases its local identity only after the graphical host has /// finished using those exact components for ExitWorld teardown. /// internal void CompleteProjectionRetirement( RuntimeEntityRecord canonical) { EnsureNotDisposed(); ArgumentNullException.ThrowIfNull(canonical); RuntimePlacementCancellationReceipt initialCancellation = ForgetInitialCreateResidence(canonical); RuntimePlacementCancellationReceipt ordinaryCancellation = Physics.SetPosition.Forget( canonical, releasePreparedMover: true); RuntimePlacementCancellationReceipt cancellation = PreferCancellation(initialCancellation, ordinaryCancellation); Physics.CollisionReports.Forget(canonical); Physics.RemoveSpatialProjection(canonical); Entities.SetRemoteMotion(canonical, null); Entities.SetRemoteMotionBindingInProgress(canonical, false); Entities.SetProjectile(canonical, null); Entities.SetProjectileBindingInProgress(canonical, false); Entities.SetRequiresRemotePlacementRuntime(canonical, false); Entities.SetPhysicsHost(canonical, null); Entities.SetPhysicsBody(canonical, null); Entities.SetPhysicsBodyAcquisitionInProgress(canonical, false); Entities.SetHasPartArray(canonical, false); Entities.ReleaseLocalId(canonical); Physics.SetPosition.PublishCancellation(cancellation); } /// /// Applies the retained-object half of an accepted CreateObject while the /// exact canonical incarnation and its integration version remain current. /// Object-table callbacks are synchronous and may re-enter entity lifetime, /// so the acceptance predicate is checked before, during, and after apply. /// public bool ApplyAcceptedSpawn( RuntimeEntityRecord canonical, ulong expectedCreateIntegrationVersion, WorldSession.EntitySpawn spawn, bool replaceGeneration) { EnsureNotDisposed(); ArgumentNullException.ThrowIfNull(canonical); if (canonical.ServerGuid != spawn.Guid || canonical.Incarnation != spawn.InstanceSequence) { return false; } bool IsCurrent() => Entities.IsCurrent(canonical) && canonical.CreateIntegrationVersion == expectedCreateIntegrationVersion; return IsCurrent() && ObjectTableWiring.ApplyEntitySpawn( Objects, spawn, replaceGeneration, IsCurrent) && IsCurrent(); } public bool TryApplyObjDesc( ObjDescEvent.Parsed update, Action? acknowledgeProjection, out WorldSession.EntitySpawn accepted) { EnsureNotDisposed(); if (TryGetPendingInitialResidence( update.Guid, out RuntimeEntityRecord pending, out RuntimeInitialCreateResidenceLease lease)) { if (!InitialCreateResidences.CanEnqueue(pending, lease)) { accepted = pending.Snapshot; return false; } bool acceptedByGate = Entities.TryAcceptDeferredObjDesc( update, out _); accepted = pending.Snapshot; if (!acceptedByGate) return false; EnqueueDormant( pending, lease, RuntimeInitialCreateContinuationKind.ObjDesc, RuntimeAcceptedPositionSource.Unknown, new RuntimeInitialCreateTailAction( RuntimeInitialCreateTailActionKind.ObjDesc, update.Guid, ObjDesc: update)); return true; } bool applied = Entities.TryApplyObjDesc(update, out accepted); if (!applied || !Entities.TryGetActive( update.Guid, out RuntimeEntityRecord canonical)) { return applied; } Entities.RefreshSnapshot(canonical, accepted); Entities.AdvanceObjDescAuthority(canonical); ulong authorityVersion = canonical.ObjDescAuthorityVersion; return AcknowledgeProjectionAndPublish( canonical, () => acknowledgeProjection?.Invoke(canonical), RuntimeEntityChange.Updated, () => canonical.ObjDescAuthorityVersion == authorityVersion); } public bool TryApplyPickup( PickupEvent.Parsed update, Action? acknowledgeProjection, out WorldSession.EntitySpawn accepted) { EnsureNotDisposed(); if (TryGetPendingInitialResidence( update.Guid, out RuntimeEntityRecord pending, out RuntimeInitialCreateResidenceLease lease)) { if (!InitialCreateResidences.CanEnqueue(pending, lease)) { accepted = pending.Snapshot; return false; } bool acceptedByGate = Entities.TryAcceptDeferredPickup( update, out _); accepted = pending.Snapshot; if (!acceptedByGate) return false; EnqueueDormant( pending, lease, RuntimeInitialCreateContinuationKind.Pickup, RuntimeAcceptedPositionSource.Unknown, new RuntimeInitialCreateTailAction( RuntimeInitialCreateTailActionKind.Pickup, update.Guid, Pickup: update)); return true; } bool applied = Entities.TryApplyPickup(update, out accepted); if (!applied || !Entities.TryGetActive( update.Guid, out RuntimeEntityRecord canonical)) { return applied; } Entities.RefreshSnapshot(canonical, accepted); RuntimePlacementCancellationReceipt initialCancellation = ForgetInitialCreateResidence(canonical); Entities.AdvancePositionAuthority(canonical); Physics.CollisionReports.LeaveWorld(canonical); RuntimePlacementCancellationReceipt ordinaryCancellation = Physics.SetPosition.Forget(canonical); RuntimePlacementCancellationReceipt cancellation = PreferCancellation(initialCancellation, ordinaryCancellation); Entities.SuspendObjectClock(canonical); Entities.SetFullCell(canonical, 0u, 0u); Entities.ParentAttachments.EndChildProjection(update.Guid); ulong positionVersion = canonical.PositionAuthorityVersion; ulong spatialVersion = canonical.SpatialAuthorityVersion; return AcknowledgeProjectionAndPublish( canonical, () => acknowledgeProjection?.Invoke(canonical), RuntimeEntityChange.Withdrawn, () => canonical.PositionAuthorityVersion == positionVersion && canonical.SpatialAuthorityVersion == spatialVersion, cancellation); } public bool TryApplyCreateParent( CreateParentUpdate update, Action? acknowledgeProjection, out WorldSession.EntitySpawn accepted) { EnsureNotDisposed(); if (TryGetPendingInitialResidence( update.ChildGuid, out _, out _)) { throw new InvalidOperationException( "A CreateObject parent relation must be admitted inside its atomic same-generation Create envelope."); } bool applied = Entities.TryApplyCreateParent(update, out accepted); return CommitPositionChannelUpdate( applied, update.ChildGuid, accepted, acknowledgeProjection); } public bool TryApplyParent( ParentEvent.Parsed update, Action? acknowledgeProjection, out WorldSession.EntitySpawn accepted) { EnsureNotDisposed(); if (TryGetPendingInitialResidence( update.ChildGuid, out RuntimeEntityRecord pending, out RuntimeInitialCreateResidenceLease lease)) { if (!InitialCreateResidences.CanEnqueue(pending, lease)) { accepted = pending.Snapshot; return false; } if (!Entities.TryGetActive( update.ParentGuid, out RuntimeEntityRecord parent) || parent.Incarnation != update.ParentInstanceSequence) { Entities.ParentAttachments.Enqueue(update); accepted = pending.Snapshot; return false; } bool acceptedByGate = Entities.TryAcceptDeferredParent( update, out AcceptedPhysicsTimestamps timestamps); accepted = pending.Snapshot; if (!acceptedByGate) return false; EnqueueDormant( pending, lease, RuntimeInitialCreateContinuationKind.Parent, RuntimeAcceptedPositionSource.Unknown, new RuntimeInitialCreateTailAction( RuntimeInitialCreateTailActionKind.Parent, update.ChildGuid, Parent: update, AcceptedTimestamps: timestamps)); return true; } bool applied = Entities.TryApplyParent(update, out accepted); return CommitPositionChannelUpdate( applied, update.ChildGuid, accepted, acknowledgeProjection); } public bool TryCommitParent( ParentAttachmentRelation relation, Action? acknowledgeProjection, out WorldSession.EntitySpawn accepted) { EnsureNotDisposed(); bool committed = Entities.TryCommitParent( relation.ChildGuid, relation.ParentGuid, relation.ParentLocation, relation.PlacementId, relation.ChildPositionSequence, out accepted); if (!committed || !Entities.TryGetActive( relation.ChildGuid, out RuntimeEntityRecord canonical)) { return committed; } Entities.RefreshSnapshot(canonical, accepted); // C0-4(a): this method had NO cancellation choke-point at all, // leaving a residence lease or ordinary SetPosition operation // dangling once ordinary placement traffic goes live - fixed with // the SAME exactly-once ForgetInitialCreateResidence -> // Physics.SetPosition.Forget -> PreferCancellation sequence every // other commit in this family (CommitPositionChannelUpdate, // TryApplyPickup, CommitAcceptedParentCellless, TryAcceptDelete) // uses for THIS part of the job. // F4 (deliberate, NOT an oversight): unlike CommitPositionChannelUpdate, // this method does NOT also call Physics.CollisionReports.LeaveWorld. // Retail set_parent (0x00515A90, lines 283832-283833) performs its // single leave_world call gated behind the SAME add_child branch this // method's staged/deferred-replay commit represents (App's // EquippedChildRenderController realize sequence, the executor's own // ParentRelationReplay) - a second LeaveWorld here would double-leave- // world with no retail counterpart. RuntimePlacementCancellationReceipt initialCancellation = ForgetInitialCreateResidence(canonical); RuntimePlacementCancellationReceipt ordinaryCancellation = Physics.SetPosition.Forget(canonical); RuntimePlacementCancellationReceipt cancellation = PreferCancellation(initialCancellation, ordinaryCancellation); Entities.AdvanceParentCommit(canonical); ulong parentCommitVersion = canonical.ParentCommitVersion; return AcknowledgeProjectionAndPublish( canonical, () => acknowledgeProjection?.Invoke(canonical), RuntimeEntityChange.Updated, () => canonical.ParentCommitVersion == parentCommitVersion, cancellation); } public bool CommitAcceptedParentCellless( RuntimeEntityRecord canonical, ulong positionAuthorityVersion, Action? acknowledgeProjection) { EnsureNotDisposed(); ArgumentNullException.ThrowIfNull(canonical); if (!Entities.IsCurrent(canonical) || canonical.PositionAuthorityVersion != positionAuthorityVersion) { return false; } RuntimePlacementCancellationReceipt initialCancellation = ForgetInitialCreateResidence(canonical); RuntimePlacementCancellationReceipt ordinaryCancellation = Physics.SetPosition.Forget(canonical); RuntimePlacementCancellationReceipt cancellation = PreferCancellation(initialCancellation, ordinaryCancellation); Physics.CollisionReports.LeaveWorld(canonical); Entities.SuspendObjectClock(canonical); Entities.SetFullCell(canonical, 0u, 0u); ulong spatialVersion = canonical.SpatialAuthorityVersion; return AcknowledgeProjectionAndPublish( canonical, () => acknowledgeProjection?.Invoke(canonical), RuntimeEntityChange.Withdrawn, () => canonical.PositionAuthorityVersion == positionAuthorityVersion && canonical.SpatialAuthorityVersion == spatialVersion, cancellation); } public bool TryApplyMotion( WorldSession.EntityMotionUpdate update, bool retainPayload, Action? acknowledgeProjection, out WorldSession.EntitySpawn accepted, out AcceptedPhysicsTimestamps timestamps) { EnsureNotDisposed(); if (TryGetPendingInitialResidence( update.Guid, out RuntimeEntityRecord pending, out RuntimeInitialCreateResidenceLease lease)) { if (!InitialCreateResidences.CanEnqueue(pending, lease)) { accepted = pending.Snapshot; timestamps = default; return false; } bool payloadApplied = Entities.TryAcceptDeferredMotion( update, out timestamps, out bool timestampMutation); accepted = pending.Snapshot; if (!payloadApplied && !timestampMutation) return false; EnqueueDormant( pending, lease, RuntimeInitialCreateContinuationKind.Movement, RuntimeAcceptedPositionSource.Unknown, new RuntimeInitialCreateTailAction( RuntimeInitialCreateTailActionKind.Movement, update.Guid, Movement: update, AcceptedTimestamps: timestamps, AppliesMovementPayload: payloadApplied, RetainMovementPayload: retainPayload, HasTimestampMutation: timestampMutation)); return payloadApplied; } bool applied = Entities.TryApplyMotion( update, retainPayload, out accepted, out timestamps); if (Entities.TryGetSnapshot( update.Guid, out WorldSession.EntitySpawn snapshot) && Entities.TryGetActive( update.Guid, out RuntimeEntityRecord canonical)) { Entities.RefreshSnapshot(canonical, snapshot); if (applied && retainPayload) Entities.AdvanceMovementAuthority(canonical); if (applied) { Entities.AdvanceMovementCommit(canonical); ulong movementCommitVersion = canonical.MovementCommitVersion; return AcknowledgeProjectionAndPublish( canonical, () => acknowledgeProjection?.Invoke(canonical), RuntimeEntityChange.Updated, () => canonical.MovementCommitVersion == movementCommitVersion); } acknowledgeProjection?.Invoke(canonical); } return applied; } public bool TryApplyVector( VectorUpdate.Parsed update, Action? acknowledgeProjection, out WorldSession.EntitySpawn accepted) { EnsureNotDisposed(); if (TryGetPendingInitialResidence( update.Guid, out RuntimeEntityRecord pending, out RuntimeInitialCreateResidenceLease lease)) { if (!IsFinite(update.Velocity) || !IsFinite(update.Omega) || !InitialCreateResidences.CanEnqueue(pending, lease)) { accepted = pending.Snapshot; return false; } bool acceptedByGate = Entities.TryAcceptDeferredVector( update, out _); accepted = pending.Snapshot; if (!acceptedByGate) return false; EnqueueDormant( pending, lease, RuntimeInitialCreateContinuationKind.Vector, RuntimeAcceptedPositionSource.Unknown, new RuntimeInitialCreateTailAction( RuntimeInitialCreateTailActionKind.Vector, update.Guid, Vector: update)); return true; } bool applied = Entities.TryApplyVector(update, out accepted); if (!applied || !Entities.TryGetActive( update.Guid, out RuntimeEntityRecord canonical)) { return applied; } Entities.RefreshSnapshot(canonical, accepted); Entities.AdvanceVectorAuthority(canonical); ulong authorityVersion = canonical.VectorAuthorityVersion; return AcknowledgeProjectionAndPublish( canonical, () => acknowledgeProjection?.Invoke(canonical), RuntimeEntityChange.Updated, () => canonical.VectorAuthorityVersion == authorityVersion); } public bool TryApplyState( SetState.Parsed update, Action? acknowledgeProjection, out WorldSession.EntitySpawn accepted, out RetailPhysicsStateTransition transition) { EnsureNotDisposed(); if (TryGetPendingInitialResidence( update.Guid, out RuntimeEntityRecord pending, out RuntimeInitialCreateResidenceLease lease)) { if (!InitialCreateResidences.CanEnqueue(pending, lease)) { accepted = pending.Snapshot; transition = default; return false; } bool acceptedByGate = Entities.TryAcceptDeferredState( update, out _); accepted = pending.Snapshot; transition = default; if (!acceptedByGate) return false; EnqueueDormant( pending, lease, RuntimeInitialCreateContinuationKind.State, RuntimeAcceptedPositionSource.Unknown, new RuntimeInitialCreateTailAction( RuntimeInitialCreateTailActionKind.State, update.Guid, State: update)); return true; } bool applied = Entities.TryApplyState(update, out accepted); transition = default; if (!applied || !Entities.TryGetActive( update.Guid, out RuntimeEntityRecord canonical)) { return applied; } Entities.RefreshSnapshot(canonical, accepted); RetailPhysicsStateTransition preview = RetailPhysicsStateTransitions.Apply( canonical.FinalPhysicsState, (PhysicsStateFlags)update.PhysicsState); ulong priorPhysicsMutation = canonical.PhysicsStateMutationVersion; if (preview.HiddenTransition is RetailHiddenTransition.BecameHidden) { Physics.CollisionReports.LeaveWorld(canonical); if (!Entities.IsCurrent(canonical) || canonical.PhysicsStateMutationVersion != priorPhysicsMutation) { transition = default; return false; } } transition = Entities.ApplyRawPhysicsState( canonical, update.PhysicsState); if (canonical.Key is { } key) { Physics.Engine.ShadowObjects.UpdatePhysicsState( key.LocalEntityId, (uint)canonical.FinalPhysicsState); } ulong stateVersion = canonical.StateAuthorityVersion; ulong physicsMutationVersion = canonical.PhysicsStateMutationVersion; RetailPhysicsStateTransition committedTransition = transition; return AcknowledgeProjectionAndPublish( canonical, () => acknowledgeProjection?.Invoke( canonical, committedTransition), committedTransition.HiddenTransition is RetailHiddenTransition.BecameHidden ? RuntimeEntityChange.Hidden : RuntimeEntityChange.Updated, () => canonical.StateAuthorityVersion == stateVersion && canonical.PhysicsStateMutationVersion == physicsMutationVersion); } public bool TryApplyPosition( WorldSession.EntityPositionUpdate update, bool isLocalPlayer, System.Numerics.Quaternion? forcePositionRotation, System.Numerics.Vector3? currentLocalVelocity, Action? acknowledgeProjection, out PositionTimestampDisposition disposition, out WorldSession.EntitySpawn accepted, out AcceptedPhysicsTimestamps timestamps) { EnsureNotDisposed(); if (TryGetPendingInitialResidence( update.Guid, out RuntimeEntityRecord pendingCanonical, out RuntimeInitialCreateResidenceLease pendingLease)) { if (!RuntimeAuthoritativePositionRouteClassifier .IsValidCreateWirePosition(update.Position) || update.Velocity is { } velocity && !IsFinite(velocity) || !InitialCreateResidences.CanEnqueue( pendingCanonical, pendingLease)) { disposition = PositionTimestampDisposition.Rejected; accepted = default; timestamps = default; return false; } bool deferredKnown = Entities.TryAcceptDeferredPosition( update, isLocalPlayer, out disposition, out timestamps, out bool timestampMutation); accepted = pendingCanonical.Snapshot; if (!deferredKnown) return false; if (isLocalPlayer && disposition is not PositionTimestampDisposition.Rejected) { Physics.ObserveLocalWorldFrame( update.Position.LandblockId, timestamps.TeleportAdvanced); } if (disposition is PositionTimestampDisposition.Rejected && !timestampMutation) { return true; } EnqueueDormant( pendingCanonical, pendingLease, RuntimeInitialCreateContinuationKind.Position, RuntimeAcceptedPositionSource.PositionEvent, new RuntimeInitialCreateTailAction( RuntimeInitialCreateTailActionKind.Position, update.Guid, Position: update, PositionSource: RuntimeAcceptedPositionSource.PositionEvent, PositionDisposition: disposition, PreviousTeleportSequence: timestamps.PreviousTeleport, AcceptedTimestamps: timestamps, HasTimestampMutation: timestampMutation)); return true; } bool hadCanonical = Entities.TryGetActive( update.Guid, out RuntimeEntityRecord beforeCanonical); uint beforeCell = beforeCanonical?.FullCellId ?? 0u; bool known = Entities.TryApplyPosition( update, isLocalPlayer, forcePositionRotation, currentLocalVelocity, out disposition, out accepted, out timestamps); if (!known || !Entities.TryGetSnapshot( update.Guid, out WorldSession.EntitySpawn snapshot) || !Entities.TryGetActive( update.Guid, out RuntimeEntityRecord canonical)) { return known; } if (isLocalPlayer && disposition is not PositionTimestampDisposition.Rejected) { Physics.ObserveLocalWorldFrame( update.Position.LandblockId, timestamps.TeleportAdvanced); } bool acceptedPosition = disposition is not PositionTimestampDisposition.Rejected; // C4 route 4b-3 (D1): the classifier's remote cell-less predicate // needs the PRE-merge committed cell — the value this method just // measured as `beforeCell`, before `RefreshSnapshot` // below stamps the accepted wire cell onto the canonical record via // `RefreshDerivedState` -> `SetFullCell`. Reading `canonical.FullCellId` // AFTER that merge (as the classifier's default builder overload // does for every other caller) always sees the wire cell, which is // why the predicate as fed to a remote PositionEvent was dead before // this fix. `hadCanonical` is what makes this an honest value rather // than a fabricated 0 — see the field's own doc. timestamps = timestamps with { PreMergeCommittedCellId = hadCanonical ? beforeCell : null, }; RuntimePlacementCancellationReceipt cancellation = default; if (acceptedPosition) { // A CANCELLATION, not a withdrawal: a newer accepted Position // supersedes the in-flight placement but the entity stays in the // world. If that placement was a DeferredCell park, cancelling it // without rolling the withdrawal back left the entity invisible // AND intangible with nothing able to wake it - see // RuntimeSetPositionState.Forget. Every OTHER Forget call in this // class is a withdrawal transaction and deliberately does not opt // in. cancellation = Physics.SetPosition.Forget( canonical, restoreCancelledPark: true); } Entities.RefreshSnapshot( canonical, snapshot, refreshPosition: acceptedPosition); if (acceptedPosition && ReferenceEquals(canonical, beforeCanonical)) { Entities.AdvancePositionAuthority(canonical); Entities.ParentAttachments.EndChildProjection(update.Guid); } ulong positionVersion = canonical.PositionAuthorityVersion; ulong spatialVersion = canonical.SpatialAuthorityVersion; if (!acceptedPosition) { acknowledgeProjection?.Invoke(canonical); return IsExpectedCanonical( canonical, () => canonical.PositionAuthorityVersion == positionVersion && canonical.SpatialAuthorityVersion == spatialVersion); } return AcknowledgeProjectionAndPublish( canonical, () => acknowledgeProjection?.Invoke(canonical), beforeCell != canonical.FullCellId ? RuntimeEntityChange.Rebucketed : RuntimeEntityChange.Updated, () => canonical.PositionAuthorityVersion == positionVersion && canonical.SpatialAuthorityVersion == spatialVersion, cancellation); } public bool CommitRebucket( RuntimeEntityRecord canonical, uint fullCellId, uint canonicalLandblockId, Action? acknowledgeProjection = null) { EnsureNotDisposed(); ArgumentNullException.ThrowIfNull(canonical); if (!Entities.IsCurrent(canonical)) return false; uint previous = canonical.FullCellId; Entities.SetFullCell( canonical, fullCellId, canonicalLandblockId); ulong spatialVersion = canonical.SpatialAuthorityVersion; if (previous == fullCellId) { acknowledgeProjection?.Invoke(canonical); return IsExpectedCanonical( canonical, () => canonical.SpatialAuthorityVersion == spatialVersion); } return AcknowledgeProjectionAndPublish( canonical, () => acknowledgeProjection?.Invoke(canonical), RuntimeEntityChange.Rebucketed, () => canonical.SpatialAuthorityVersion == spatialVersion); } public bool CommitWithdrawal( RuntimeEntityRecord canonical, Action? acknowledgeProjection = null) { EnsureNotDisposed(); ArgumentNullException.ThrowIfNull(canonical); if (!Entities.IsCurrent(canonical)) return false; // C0-4(b): this cancelled the initial-create residence but never the // ORDINARY placement family (Physics.SetPosition.Forget), unlike // TryApplyPickup/CommitAcceptedParentCellless/TryAcceptDelete, which // all cancel both. WithdrawLiveEntityProjectionToCellless routes // through here, so a live ordinary SetPosition/lost-cell watch could // dangle across a withdrawal-to-cellless once ordinary placement // traffic goes live. Fixed symmetrically with the same // Forget/PreferCancellation pair every sibling withdrawal uses. RuntimePlacementCancellationReceipt initialCancellation = ForgetInitialCreateResidence(canonical); Physics.CollisionReports.LeaveWorld(canonical); RuntimePlacementCancellationReceipt ordinaryCancellation = Physics.SetPosition.Forget(canonical); RuntimePlacementCancellationReceipt cancellation = PreferCancellation(initialCancellation, ordinaryCancellation); Entities.SuspendObjectClock(canonical); Entities.SetFullCell(canonical, 0u, 0u); ulong spatialVersion = canonical.SpatialAuthorityVersion; return AcknowledgeProjectionAndPublish( canonical, () => acknowledgeProjection?.Invoke(canonical), RuntimeEntityChange.Withdrawn, () => canonical.SpatialAuthorityVersion == spatialVersion, cancellation); } public bool CommitChildNoDraw( RuntimeEntityRecord canonical, bool noDraw, Action? acknowledgeProjection = null) { EnsureNotDisposed(); ArgumentNullException.ThrowIfNull(canonical); if (!Entities.IsCurrent(canonical)) return false; Entities.SetChildNoDraw(canonical, noDraw); ulong physicsMutationVersion = canonical.PhysicsStateMutationVersion; return AcknowledgeProjectionAndPublish( canonical, () => acknowledgeProjection?.Invoke(canonical), RuntimeEntityChange.Updated, () => canonical.PhysicsStateMutationVersion == physicsMutationVersion); } public bool RetireAfterProjectionAcquisitionFailure( RuntimeEntityRecord canonical) { EnsureNotDisposed(); ArgumentNullException.ThrowIfNull(canonical); if (!Entities.RemoveActive(canonical)) return false; Entities.AdvanceLifetimeMutation(canonical.ServerGuid); Entities.RetainTeardown(canonical); PublishEntity(RuntimeEntityChange.Deleted, canonical); return true; } /// /// Accepts and retires the exact canonical DeleteObject generation without /// yet publishing the retained-object removal. This split lets a graphical /// host tear down the exact retired projection before completing the /// retained-object mutation while Runtime remains the only freshness, /// identity, and canonical-lifetime authority. /// public bool TryAcceptDelete( DeleteObject.Parsed delete, bool isLocalPlayer, bool removeRetainedObject, out RuntimeEntityDeleteAcceptance acceptance) { EnsureNotDisposed(); if (!isLocalPlayer) { // A child whose complete raw CreateObject is waiting on a missing // parent has no timestamp gate yet. Cancel its exact/older raw // generation before the normal known-object delete gate returns. Entities.ParentAttachments.CancelDeferredChildGeneration( delete.Guid, delete.InstanceSequence); } if (!Entities.TryDelete(delete, isLocalPlayer)) { acceptance = null!; return false; } Entities.AdvanceLifetimeMutation(delete.Guid); Entities.ParentAttachments.DeleteGeneration( delete.Guid, delete.InstanceSequence); RuntimeEntityRecord? retiredCanonical = null; if (Entities.TryGetActive( delete.Guid, out RuntimeEntityRecord active) && active.Incarnation == delete.InstanceSequence && Entities.RemoveActive(active)) { RuntimePlacementCancellationReceipt initialCancellation = ForgetInitialCreateResidence(active); Physics.CollisionReports.Forget(active); RuntimePlacementCancellationReceipt ordinaryCancellation = Physics.SetPosition.Forget( active, releasePreparedMover: true); RuntimePlacementCancellationReceipt cancellation = PreferCancellation( initialCancellation, ordinaryCancellation); retiredCanonical = active; Entities.RetainTeardown(active); Physics.SetPosition.PublishCancellation(cancellation); PublishEntity( removeRetainedObject ? RuntimeEntityChange.Deleted : RuntimeEntityChange.Withdrawn, active); } acceptance = new RuntimeEntityDeleteAcceptance( this, delete, retiredCanonical, removeRetainedObject); return true; } /// /// Completes a previously accepted delete exactly once. Marking the token /// complete before synchronous callbacks preserves the current retry rule: /// a throwing observer does not replay an already-committed removal. /// public void CompleteAcceptedDelete( RuntimeEntityDeleteAcceptance acceptance) { EnsureNotDisposed(); ArgumentNullException.ThrowIfNull(acceptance); if (!ReferenceEquals(acceptance.Owner, this)) { throw new InvalidOperationException( "A delete acceptance belongs to a different Runtime lifetime."); } if (acceptance.Completed) { throw new InvalidOperationException( "A delete acceptance has already been completed."); } acceptance.Completed = true; if (acceptance.RemoveRetainedObject) ObjectTableWiring.ApplyEntityDelete(Objects, acceptance.Delete); } /// /// Applies a delete accepted by the dormant exact-incarnation owner after /// the active Runtime directory correctly reports no live record. /// public void ApplyAcceptedDormantDelete(DeleteObject.Parsed delete) { EnsureNotDisposed(); ObjectTableWiring.ApplyEntityDelete(Objects, delete); } /// /// Clears retained object state at the Runtime-owned reset stage. App /// projection teardown remains a later acknowledged stage. /// public void ClearObjects() { EnsureNotDisposed(); Objects.Clear(); } public IReadOnlyList BeginSessionClear() { EnsureNotDisposed(); if (_sessionClearInProgress) return Array.Empty(); _sessionClearInProgress = true; RuntimeEntityRecord[] active = Entities.ActiveRecords.ToArray(); InitialCreateResidences.Clear(); InitialCreateExecution.DiscardAll(); LocalPlayerFirstEntry.DiscardAll(); RemoteFirstEntry.DiscardAll(); Physics.CollisionReports.LeaveWorldBatch(active); Physics.ResetSessionPhysics(); Entities.BeginSessionClear(); foreach (RuntimeEntityRecord canonical in active) { Physics.SetPosition.Forget(canonical); if (!Entities.RemoveActive(canonical)) continue; Entities.RetainTeardown(canonical); PublishEntity(RuntimeEntityChange.Deleted, canonical); } return active; } public IReadOnlyList CaptureSessionClearRetirements() { EnsureNotDisposed(); if (!_sessionClearInProgress) { throw new InvalidOperationException( "Session-clear retirements are only available while the " + "canonical clear transaction is active."); } return Entities.TeardownRecords.ToArray(); } /// /// Completes one exact incarnation retained by /// after the borrowed host has retired its /// presentation projection. Failure keeps the tombstone and local /// identity intact so the same transaction cursor can retry this exact /// record without reconstructing the retirement set. /// public void CompleteSessionEntityRetirement( RuntimeEntityRecord canonical) { EnsureNotDisposed(); ArgumentNullException.ThrowIfNull(canonical); if (!_sessionClearInProgress || !Entities.TryGetTeardown( canonical.ServerGuid, canonical.Incarnation, out RuntimeEntityRecord retained) || !ReferenceEquals(retained, canonical)) { throw new InvalidOperationException( $"Live entity 0x{canonical.ServerGuid:X8}/{canonical.Incarnation} is not retained by the active session-clear transaction."); } CompleteProjectionRetirement(canonical); Entities.ReleaseTeardown(canonical); } public bool CompleteSessionClearIfConverged() { EnsureNotDisposed(); if (!_sessionClearInProgress || !Entities.CompleteSessionClearIfConverged()) { return false; } _sessionClearInProgress = false; return true; } public void Dispose() { if (_disposed) return; // Disposal is terminal, unlike a session reset. Quiesce borrowers // before committing internal cleanup so no observer can re-enter a // lifetime whose owner is being destroyed. Events.DetachObservers(); List? failures = null; try { if (!_sessionClearInProgress) _ = BeginSessionClear(); try { ClearObjects(); } catch (Exception error) { (failures ??= []).Add(error); } foreach (RuntimeEntityRecord canonical in Entities.TeardownRecords.ToArray()) { Exception? failure = RetireCanonicalOnly(canonical); if (failure is not null) (failures ??= []).Add(failure); } if (!CompleteSessionClearIfConverged()) { (failures ??= []).Add(new InvalidOperationException( "Runtime entity/object disposal did not converge every canonical owner.")); } } finally { _disposed = true; _generation = null; _pvpBitfieldSync.Dispose(); Events.Dispose(); Physics.Dispose(); } if (failures is not null) { throw new AggregateException( "Runtime entity/object disposal failed to converge.", failures); } } private bool CommitPositionChannelUpdate( bool applied, uint guid, WorldSession.EntitySpawn accepted, Action? acknowledgeProjection) { if (!applied || !Entities.TryGetActive( guid, out RuntimeEntityRecord canonical)) { return applied; } Entities.RefreshSnapshot(canonical, accepted); RuntimePlacementCancellationReceipt initialCancellation = ForgetInitialCreateResidence(canonical); Entities.AdvancePositionAuthority(canonical); Physics.CollisionReports.LeaveWorld(canonical); RuntimePlacementCancellationReceipt ordinaryCancellation = Physics.SetPosition.Forget(canonical); RuntimePlacementCancellationReceipt cancellation = PreferCancellation(initialCancellation, ordinaryCancellation); ulong positionVersion = canonical.PositionAuthorityVersion; ulong spatialVersion = canonical.SpatialAuthorityVersion; return AcknowledgeProjectionAndPublish( canonical, () => acknowledgeProjection?.Invoke(canonical), RuntimeEntityChange.Updated, () => canonical.PositionAuthorityVersion == positionVersion && canonical.SpatialAuthorityVersion == spatialVersion, cancellation); } private void PublishEntity( RuntimeEntityChange change, RuntimeEntityRecord canonical) => Events.PublishEntity(change, canonical); private bool AcknowledgeProjectionAndPublish( RuntimeEntityRecord canonical, Action acknowledgeProjection, RuntimeEntityChange change, Func matchesCommittedMutation, RuntimePlacementCancellationReceipt cancellation = default) { Physics.SetPosition.PublishCancellation(cancellation); if (!IsExpectedCanonical(canonical, matchesCommittedMutation)) return false; try { acknowledgeProjection(); } finally { if (IsExpectedCanonical( canonical, matchesCommittedMutation)) { PublishEntity(change, canonical); } } return IsExpectedCanonical( canonical, matchesCommittedMutation); } private bool IsExpectedCanonical( RuntimeEntityRecord canonical, Func matchesCommittedMutation) => Entities.IsCurrent(canonical) && matchesCommittedMutation(); private bool TryGetPendingInitialResidence( uint guid, out RuntimeEntityRecord canonical, out RuntimeInitialCreateResidenceLease lease) { if (Entities.TryGetActive(guid, out canonical) && InitialCreateResidences.TryGetTransaction( canonical, out lease)) { return true; } canonical = null!; lease = default; return false; } private void EnqueueDormant( RuntimeEntityRecord canonical, in RuntimeInitialCreateResidenceLease prior, RuntimeInitialCreateContinuationKind kind, RuntimeAcceptedPositionSource positionSource, in RuntimeInitialCreateTailAction action) { RuntimeInitialCreateResidenceLease retained = InitialCreateResidences .EnqueueAccepted( canonical, prior, kind, positionSource, ImmutableArray.Create(action)); if (!retained.IsValid) { throw new InvalidOperationException( $"Accepted {kind} for 0x{canonical.ServerGuid:X8}/{canonical.Incarnation} could not be retained by its initial-placement FIFO."); } } private static bool IsFinite(System.Numerics.Vector3 value) => float.IsFinite(value.X) && float.IsFinite(value.Y) && float.IsFinite(value.Z); private static bool HasConsistentCreateIdentityAndParent( in WorldSession.EntitySpawn incoming) { if (incoming.Guid == 0u) return false; bool hasTopParentGuid = incoming.ParentGuid is not null; bool hasTopParentLocation = incoming.ParentLocation is not null; if (hasTopParentGuid != hasTopParentLocation) return false; if (incoming.Physics is not { } physics) { // These flattened values are parser projections of PhysicsDesc. // Without that source block, accepting any of them would create // contradictory admission authority before the raw create is // either queued for a parent or assigned a residence lease. return incoming.Position is null && incoming.SetupTableId is null && incoming.MotionState is null && incoming.MotionTableId is null && incoming.PhysicsState is null && incoming.ObjScale is null && incoming.Friction is null && incoming.Elasticity is null && incoming.InstanceSequence == 0 && incoming.MovementSequence == 0 && incoming.ServerControlSequence == 0 && incoming.PositionSequence == 0 && !hasTopParentGuid && incoming.PlacementId is null; } if (physics.Timestamps.Instance != incoming.InstanceSequence || physics.Timestamps.Position != incoming.PositionSequence || physics.Timestamps.Movement != incoming.MovementSequence || physics.Timestamps.ServerControlledMove != incoming.ServerControlSequence || physics.Position != incoming.Position) return false; PhysicsAttachment? flattenedParent = incoming.ParentGuid is { } parentGuid && incoming.ParentLocation is { } parentLocation ? new PhysicsAttachment(parentGuid, parentLocation) : null; if (flattenedParent != physics.Parent || incoming.PlacementId != physics.AnimationFrame) { return false; } return true; } private static bool IsStructurallyValidDeferredCreate( in WorldSession.EntitySpawn incoming) { if (incoming.Guid == 0u) return false; if (incoming.Physics is not { } physics) return true; if (physics.Parent is null && physics.Position is { LandblockId: not 0u } position && !RuntimeAuthoritativePositionRouteClassifier .IsValidCreateWirePosition(position)) { return false; } if (physics.Velocity is { } velocity && !IsFinite(velocity) || physics.Acceleration is { } acceleration && !IsFinite(acceleration) || physics.AngularVelocity is { } angularVelocity && !IsFinite(angularVelocity) || physics.Scale is { } scale && !float.IsFinite(scale) || physics.Friction is { } friction && !float.IsFinite(friction) || physics.Elasticity is { } elasticity && !float.IsFinite(elasticity) || physics.Translucency is { } translucency && !float.IsFinite(translucency)) { return false; } return true; } private bool AdmitSameGenerationCreate( RuntimeEntityRecord canonical, in RuntimeInitialCreateResidenceLease prior, in WorldSession.EntitySpawn incoming, in InboundCreateResult admitted, bool isLocalPlayer) { if (!ReferenceEquals( canonical, Entities.TryGetActive( incoming.Guid, out RuntimeEntityRecord current) ? current : null) || canonical.Incarnation != incoming.InstanceSequence || admitted.Disposition is not CreateObjectTimestampDisposition.ExistingGeneration || !InitialCreateResidences.CanEnqueue(canonical, prior)) { return false; } var actions = ImmutableArray.CreateBuilder< RuntimeInitialCreateTailAction>(); RuntimeAcceptedPositionSource positionSource = RuntimeAcceptedPositionSource.Unknown; if (admitted.SameGenerationEvents is { } events) { actions.Add(new RuntimeInitialCreateTailAction( RuntimeInitialCreateTailActionKind .PreTailDescriptionAdaptation, incoming.Guid, Description: events.Description)); if (Entities.TryAcceptDeferredObjDesc( events.Appearance, out _)) { actions.Add(new RuntimeInitialCreateTailAction( RuntimeInitialCreateTailActionKind.ObjDesc, incoming.Guid, ObjDesc: events.Appearance)); } if (events.Parent is { } parent) { if (Entities.TryAcceptDeferredCreateParent( parent, out _)) { actions.Add(new RuntimeInitialCreateTailAction( RuntimeInitialCreateTailActionKind.CreateParent, incoming.Guid, CreateParent: parent)); } } else if (events.Position is { } position) { if (!RuntimeAuthoritativePositionRouteClassifier .IsValidCreateWirePosition(position.Position) || position.Velocity is { } velocity && !IsFinite(velocity)) { return false; } if (!Entities.TryAcceptDeferredPosition( position, isLocalPlayer, out PositionTimestampDisposition disposition, out AcceptedPhysicsTimestamps timestamps, out bool timestampMutation)) { return false; } if (disposition is not PositionTimestampDisposition.Rejected || timestampMutation) { positionSource = RuntimeAcceptedPositionSource .SameIncarnationCreate; actions.Add(new RuntimeInitialCreateTailAction( RuntimeInitialCreateTailActionKind.Position, incoming.Guid, Position: position, PositionSource: positionSource, PositionDisposition: disposition, PreviousTeleportSequence: timestamps.PreviousTeleport, AcceptedTimestamps: timestamps, HasTimestampMutation: timestampMutation)); } } else if (events.Pickup is { } pickup && Entities.TryAcceptDeferredPickup(pickup, out _)) { actions.Add(new RuntimeInitialCreateTailAction( RuntimeInitialCreateTailActionKind.Pickup, incoming.Guid, Pickup: pickup)); } if (events.Movement is { } movement) { bool payloadApplied = Entities.TryAcceptDeferredMotion( movement, out AcceptedPhysicsTimestamps timestamps, out bool timestampMutation); if (payloadApplied || timestampMutation) { actions.Add(new RuntimeInitialCreateTailAction( RuntimeInitialCreateTailActionKind.Movement, incoming.Guid, Movement: movement, AcceptedTimestamps: timestamps, AppliesMovementPayload: payloadApplied, RetainMovementPayload: true, HasTimestampMutation: timestampMutation)); } } if (Entities.TryAcceptDeferredState(events.State, out _)) { actions.Add(new RuntimeInitialCreateTailAction( RuntimeInitialCreateTailActionKind.State, incoming.Guid, State: events.State)); } if (Entities.TryAcceptDeferredVector(events.Vector, out _)) { actions.Add(new RuntimeInitialCreateTailAction( RuntimeInitialCreateTailActionKind.Vector, incoming.Guid, Vector: events.Vector)); } } actions.Add(new RuntimeInitialCreateTailAction( RuntimeInitialCreateTailActionKind.WeenieDescription, incoming.Guid, WeenieDescription: incoming)); actions.Add(new RuntimeInitialCreateTailAction( RuntimeInitialCreateTailActionKind.ResidentCellCleanup, incoming.Guid)); RuntimeInitialCreateResidenceLease retained = InitialCreateResidences .EnqueueAccepted( canonical, prior, RuntimeInitialCreateContinuationKind.SameIncarnationCreate, positionSource, actions.ToImmutable()); return retained.IsValid; } private void EnsureNotDisposed() => ObjectDisposedException.ThrowIf(_disposed, this); internal bool TryGetInitialCreateResidence( RuntimeEntityRecord canonical, out RuntimeInitialCreateResidenceLease lease) { EnsureNotDisposed(); return InitialCreateResidences.TryGetCurrent(canonical, out lease); } /// /// C3c-R1 review F7: host seam for a bounded-collision-neighborhood /// host to convert a remote/projectile Create's active residence to the /// celless completion route when its destination landblock will never /// be collision-published (a headless far remote). See /// . /// public bool TryConvertInitialResidenceToCellessRoute( RuntimeEntityRecord canonical) { EnsureNotDisposed(); return InitialCreateResidences.TryConvertToCellessRoute(canonical); } internal RuntimeInitialCreateResidenceCompletionStatus CompleteInitialCreateResidence( RuntimeEntityRecord canonical, in RuntimeInitialCreateResidenceToken token, out RuntimeInitialCreateResidenceReceipt receipt) { EnsureNotDisposed(); return InitialCreateResidences.Complete( canonical, token, out receipt); } internal bool AcknowledgeInitialCreateResidenceAdoption( RuntimeEntityRecord canonical, in RuntimeInitialCreateResidenceAdoptionToken token) { EnsureNotDisposed(); return InitialCreateResidences.AcknowledgeAdoption( canonical, token); } private RuntimePlacementCancellationReceipt ForgetInitialCreateResidence( RuntimeEntityRecord canonical) { bool forgotten = InitialCreateResidences.Forget( canonical, out _, out RuntimePlacementCancellationReceipt cancellation); // Round 3 B3: InitialCreateResidences.Forget's own retirement // notification already routes to InitialCreateExecution.DiscardProgress // for a successful Forget. This explicit call is defensive-in-depth // for the (record never held a residence) case where Forget returns // false without ever reaching the notification - DiscardProgress is // idempotent, so a redundant call after a successful Forget is a // guaranteed no-op, never a double-discard. if (canonical.Key is { } key) InitialCreateExecution.DiscardProgress(key); return forgotten ? cancellation : default; } private static RuntimePlacementCancellationReceipt PreferCancellation( in RuntimePlacementCancellationReceipt initial, in RuntimePlacementCancellationReceipt ordinary) => initial.IsValid ? initial : ordinary; private bool InitializeAcceptedCreateResidence( RuntimeEntityRecord canonical, in InboundCreateResult accepted, bool beginInitialResidence, bool isLocalPlayer) { if (!beginInitialResidence) return true; // The explicit cutover path separates accepted wire authority from // committed residence before any observer can hydrate it. Failure to // own the exact route is fail-closed; the caller removes the canonical // record before publishing Registered/Updated. if (canonical.PositionAuthorityVersion == 0UL) Entities.AdvancePositionAuthority(canonical); if (canonical.FullCellId != 0u) Entities.SetFullCell(canonical, 0u, 0u); RuntimeInitialCreateResidenceLease lease = InitialCreateResidences.Begin( canonical, accepted, isLocalPlayer); if (!lease.IsValid) return false; // C3c: host drive notification. Fires for EVERY fresh residence // begin through this single choke point — wire-dispatch Creates AND // the executor's deferred-child replays (which register through this // class's own bound delegate, never through a host runtime). The // subscriber must only RECORD the key for a later drive pump — this // fires mid-registration, before Registered publishes, and a // synchronous Advance here would interleave with the enclosing // transaction (and, for a replayed child, with the parent's own // in-flight Execute). _initialResidenceBegan?.Invoke(canonical); return true; } private Exception FailInitialResidenceRegistration( RuntimeEntityRecord canonical, bool publishDeleted) { if (!Entities.RemoveActive(canonical)) { return new InvalidOperationException( $"Initial residence for 0x{canonical.ServerGuid:X8} failed after its canonical incarnation was superseded."); } Exception? failure = null; if (publishDeleted) { try { PublishEntity(RuntimeEntityChange.Deleted, canonical); } catch (Exception error) { failure = error; } } failure = Combine(failure, RetireCanonicalOnly(canonical)); var cause = new InvalidOperationException( $"Initial residence for 0x{canonical.ServerGuid:X8} could not acquire its exact Runtime placement lease."); return failure is null ? cause : new AggregateException(cause, failure); } private static Exception? Combine( Exception? first, Exception? second) => first is null ? second : second is null ? first : new AggregateException(first, second); private static InboundCreateResult SupersededCreateResult() => new( CreateObjectTimestampDisposition.StaleGeneration, default, null, default); private bool IsCurrentOperation( uint guid, RuntimeEntityRecord canonical, ulong sessionVersion, ulong operationVersion) => Entities.SessionLifetimeVersion == sessionVersion && Entities.CurrentLifetimeMutation(guid) == operationVersion && Entities.IsCurrent(canonical); private RuntimeEntityRegistrationResult SupersededRegistration( uint guid, bool replacedExistingGeneration) => new( SupersededCreateResult(), Entities.TryGetActive(guid, out RuntimeEntityRecord current) ? current : null, LogicalRegistrationCreated: false, ReplacedExistingGeneration: replacedExistingGeneration); }