using AcDream.Core.Net; using AcDream.Core.Net.Messages; using AcDream.Core.Physics; using AcDream.Runtime.Physics; namespace AcDream.Runtime.Entities; /// /// The single update-thread authority for live server GUIDs, incarnations, /// accepted wire snapshots, teardown tombstones, and runtime-local identity. /// It owns no graphical state and can run without loading App or a backend. /// public sealed class RuntimeEntityDirectory { public const uint FirstLocalEntityId = 1_000_000u; public const uint LastLocalEntityId = 0x3FFF_FFFFu; private readonly InboundPhysicsStateController _inbound = new(); private readonly Dictionary _activeByGuid = new(); private readonly Dictionary<(uint Guid, ushort Incarnation), RuntimeEntityRecord> _teardownByIncarnation = new(); private readonly Dictionary _byLocalId = new(); private readonly Dictionary _lifetimeMutationByGuid = new(); private uint _nextLocalEntityId; public RuntimeEntityDirectory(uint firstLocalEntityId = FirstLocalEntityId) { if (firstLocalEntityId is < FirstLocalEntityId or > LastLocalEntityId) { throw new ArgumentOutOfRangeException( nameof(firstLocalEntityId), $"Live entity ids must stay in 0x{FirstLocalEntityId:X8}..0x{LastLocalEntityId:X8}."); } _nextLocalEntityId = firstLocalEntityId; } public int Count => _activeByGuid.Count; public int PendingTeardownCount => _teardownByIncarnation.Count; public int ClaimedLocalIdCount => _byLocalId.Count; public ulong SessionLifetimeVersion { get; private set; } public IReadOnlyCollection ActiveRecords => _activeByGuid.Values; public IReadOnlyCollection TeardownRecords => _teardownByIncarnation.Values; public IReadOnlyDictionary Snapshots => _inbound.Snapshots; public ParentAttachmentState ParentAttachments { get; } = new(); public InboundCreateResult AcceptCreate(WorldSession.EntitySpawn incoming) => _inbound.AcceptCreate(incoming); internal InboundCreateResult AcceptCreateDeferredSameGeneration( WorldSession.EntitySpawn incoming) => _inbound.AcceptCreateDeferredSameGeneration(incoming); public CreateObjectTimestampDisposition PreviewCreateDisposition( WorldSession.EntitySpawn incoming) => _inbound.PreviewCreateDisposition(incoming); public bool TryDelete( AcDream.Core.Net.Messages.DeleteObject.Parsed delete, bool isLocalPlayer) => _inbound.TryDelete(delete, isLocalPlayer); public bool TryGetSnapshot(uint guid, out WorldSession.EntitySpawn spawn) => _inbound.TryGetSnapshot(guid, out spawn); internal bool TryGetAcceptedTimestamps( uint guid, out AcceptedPhysicsTimestamps timestamps) => _inbound.TryGetAcceptedTimestamps(guid, out timestamps); public bool TryGetActive(uint guid, out RuntimeEntityRecord record) => _activeByGuid.TryGetValue(guid, out record!); public bool IsCurrent(RuntimeEntityRecord record) => _activeByGuid.TryGetValue(record.ServerGuid, out RuntimeEntityRecord? current) && ReferenceEquals(current, record); public bool TryGetByLocalId(uint localEntityId, out RuntimeEntityRecord record) => _byLocalId.TryGetValue(localEntityId, out record!); public bool TryGetTeardown( uint guid, ushort incarnation, out RuntimeEntityRecord record) => _teardownByIncarnation.TryGetValue((guid, incarnation), out record!); public RuntimeEntityRecord AddActive(WorldSession.EntitySpawn snapshot) { if (_activeByGuid.ContainsKey(snapshot.Guid)) { throw new InvalidOperationException( $"Live entity 0x{snapshot.Guid:X8} already has an active incarnation."); } var record = new RuntimeEntityRecord(snapshot); _activeByGuid.Add(snapshot.Guid, record); try { ClaimLocalId(record); return record; } catch { _activeByGuid.Remove(snapshot.Guid); throw; } } public bool RemoveActive(uint guid, out RuntimeEntityRecord? record) => _activeByGuid.Remove(guid, out record); public bool RemoveActive(RuntimeEntityRecord expected) { if (!IsCurrent(expected)) return false; return _activeByGuid.Remove(expected.ServerGuid); } public void RetainTeardown(RuntimeEntityRecord record) { var key = (record.ServerGuid, record.Incarnation); if (_teardownByIncarnation.TryGetValue( key, out RuntimeEntityRecord? retained) && !ReferenceEquals(retained, record)) { throw new InvalidOperationException( $"Live entity teardown tombstone collision for 0x{record.ServerGuid:X8} generation {record.Incarnation}."); } _teardownByIncarnation[key] = record; } public void ReleaseTeardown(RuntimeEntityRecord record) { var key = (record.ServerGuid, record.Incarnation); if (_teardownByIncarnation.TryGetValue( key, out RuntimeEntityRecord? retained) && ReferenceEquals(retained, record)) { _teardownByIncarnation.Remove(key); } } public bool HasPendingTeardown(uint serverGuid) { foreach ((uint Guid, ushort Incarnation) key in _teardownByIncarnation.Keys) { if (key.Guid == serverGuid) return true; } return false; } public uint ClaimLocalId(RuntimeEntityRecord record) { if (!IsKnown(record)) { throw new InvalidOperationException( "A local id can only be claimed for an active or retained incarnation."); } if (record.LocalEntityId is { } existing) return existing; uint start = _nextLocalEntityId; do { uint candidate = _nextLocalEntityId; _nextLocalEntityId = candidate == LastLocalEntityId ? FirstLocalEntityId : candidate + 1u; if (_byLocalId.ContainsKey(candidate)) continue; _byLocalId.Add(candidate, record); record.LocalEntityId = candidate; return candidate; } while (_nextLocalEntityId != start); throw new InvalidOperationException("The live entity id namespace is exhausted."); } public bool ReleaseLocalId(RuntimeEntityRecord record) { if (record.LocalEntityId is not { } localId) return false; if (_byLocalId.TryGetValue(localId, out RuntimeEntityRecord? retained) && ReferenceEquals(retained, record)) { _byLocalId.Remove(localId); } record.LocalEntityId = null; return true; } public ulong AdvanceLifetimeMutation(uint serverGuid) { ulong next = _lifetimeMutationByGuid.GetValueOrDefault(serverGuid) + 1UL; _lifetimeMutationByGuid[serverGuid] = next; return next; } public ulong CurrentLifetimeMutation(uint serverGuid) => _lifetimeMutationByGuid.GetValueOrDefault(serverGuid); public void BeginSessionClear() { SessionLifetimeVersion++; _lifetimeMutationByGuid.Clear(); ParentAttachments.Clear(); _inbound.Clear(); } public bool CompleteSessionClearIfConverged() { if (_activeByGuid.Count != 0 || _teardownByIncarnation.Count != 0) return false; _byLocalId.Clear(); ParentAttachments.Clear(); _inbound.Clear(); return true; } public void RefreshSnapshot( RuntimeEntityRecord record, WorldSession.EntitySpawn accepted, bool refreshPosition = false) { EnsureKnown(record); uint previousCell = record.FullCellId; record.Snapshot = accepted; record.RefreshDerivedState(refreshPosition); if (record.FullCellId != previousCell) { PropagateFullCellToChildren( record, record.FullCellId, record.CanonicalLandblockId); } } public void AdvanceCreateAuthority(RuntimeEntityRecord record) { EnsureKnown(record); record.AdvanceCreateAuthority(); } public void AdvancePositionAuthority(RuntimeEntityRecord record) { EnsureKnown(record); record.AdvancePositionAuthority(); } public void AdvanceVectorAuthority(RuntimeEntityRecord record) { EnsureKnown(record); record.AdvanceVectorAuthority(); } public void AdvanceMovementAuthority(RuntimeEntityRecord record) { EnsureKnown(record); record.AdvanceMovementAuthority(); } public void AdvanceMovementCommit(RuntimeEntityRecord record) { EnsureKnown(record); record.AdvanceMovementCommit(); } public void AdvancePlacementCommit(RuntimeEntityRecord record) { EnsureKnown(record); record.AdvancePlacementCommit(); } public void AdvanceParentCommit(RuntimeEntityRecord record) { EnsureKnown(record); record.AdvanceParentCommit(); } public void AdvanceObjDescAuthority(RuntimeEntityRecord record) { EnsureKnown(record); record.AdvanceObjDescAuthority(); } public RetailPhysicsStateTransition ApplyRawPhysicsState( RuntimeEntityRecord record, uint rawState) { EnsureKnown(record); return record.ApplyRawPhysicsState(rawState); } public bool TryDequeueStateTransition( RuntimeEntityRecord record, out RetailPhysicsStateTransition transition) { EnsureKnown(record); return record.TryDequeueStateTransition(out transition); } public void SetChildNoDraw(RuntimeEntityRecord record, bool noDraw) { EnsureKnown(record); record.SetChildNoDraw(noDraw); } public void SuspendObjectClock(RuntimeEntityRecord record) { EnsureKnown(record); record.SuspendObjectClock(); } /// /// Re-activates a clock suspended by , for /// rolling back a withdrawal that is being cancelled rather than /// completed. NOT an exact inverse — the retained sub-quantum time is /// discarded, which is retail's set_active(1) rebase semantic; see /// . Distinct from /// , which is the /// entering-the-world edge and additionally rebases the static/dynamic /// quantum shape; a rollback re-activates a clock that never conceptually /// left. /// public void ResumeObjectClock(RuntimeEntityRecord record) { EnsureKnown(record); record.ResumeObjectClock(); } public void ResetObjectClockForEnterWorld(RuntimeEntityRecord record, bool isStatic) { EnsureKnown(record); record.ResetObjectClockForEnterWorld(isStatic); } public void SetFullCell( RuntimeEntityRecord record, uint fullCellId, uint canonicalLandblockId) { EnsureKnown(record); record.SetFullCell(fullCellId, canonicalLandblockId); PropagateFullCellToChildren(record, fullCellId, canonicalLandblockId); } /// /// Reused across every call. /// Always empty on entry and on exit (the loop drains it unconditionally /// before returning) — see that method's remarks for why sharing it is /// safe rather than a repeat of the round-3 A6/B4 scratch-buffer /// reentrancy lesson: this stack never escapes the method, and nothing /// on the write path can trigger a nested call while it holds state. /// private readonly Stack _propagationWorklist = new(); /// /// C4 route 7 D2 — the sole propagation hook. Retail's parent-cell- /// crossing propagation (CPhysicsObj::SetPositionInternal /// @0x00515330's changed-cell branch @0x00515372 -> change_cell /// @0x00513390 -> the self-recursive enter_cell/leave_cell /// @0x00510ed0/@0x00510f50) has exactly one acdream analogue: every /// canonical cell write already funnels through this method or /// 's derived-state write (see /// docs/research/2026-08-04-retail-parent-cell-propagation.md and the /// route-7 contract's D2). /// /// /// ITERATIVE, not recursive (round-3 remediation — both the retail and /// architecture reviews independently converged on the same finding, /// N4/B3: a depth-capped RECURSIVE version left a subtree beyond the cap /// at a STALE NONZERO cell permanently — on the withdraw path that is /// the #184 shape verbatim, the exact defect AP-142 clause (a) exists to /// reject, shipped fresh inside the slice whose headline is fixing it. /// A reused stack removes the depth /// concept entirely rather than mitigating it: there is no C# call-stack /// growth to bound, so the only limit is the number of committed /// relations actually in the system (which cannot exceed the live /// entity count) — matching retail's own genuinely unbounded recursion /// exactly, with no acdream-only cap and no register row for one. This /// also retires B5 in the sense that there is no longer a RECURSIVE call /// to reason about — but the bypass itself is NOT retired: the loop /// below still calls a child's own SetFullCell directly rather /// than the public , and that bypass is /// DELIBERATE and LOAD-BEARING, not incidental. The public /// calls this method, and this method opens /// with _propagationWorklist.Clear() — routing a child through /// the public method would re-enter this method mid-drain, clear the /// shared worklist out from under the OUTER loop, and silently drop /// every sibling still waiting on the stack, with no error and no /// exception. Any side effect added to the public /// in the future MUST be mirrored by hand at /// this call site, because this call site cannot route through it. /// /// /// /// Skipping a child whose /// (and , A7) /// already equals the target is BOTH the cycle guard (an A→B→A wire- /// induced relation cycle writes A, pushes B, writes B, pops B, finds A /// already at the target value, and does not re-push it — no visited /// set needed) and the retail-behavioral subsumption of retail's /// separate same-cell depth-1 id refresh (@0x0051539c-@0x005153d8) /// under this project's single-field cell model (AP-142). Zero /// allocation after warmup: /// returns /// the stored list or , and the worklist /// stack is a reused field, never a fresh collection per call. Field /// writes only — no clock, workset, shadow, or placement work — so this /// is safe to run re-entrantly inside whatever transaction is mid-commit /// on the parent's own cell; the worklist field itself is safe to share /// across calls because the loop below unconditionally drains it to /// empty before this method returns, and nothing on the write path /// (a field assignment and an optional diagnostic log line) can call /// back into a nested . NOT gated on retail's /// part_array != 0 guard (@0x00510ed8) — see AP-142 clause (d) /// for why that guard has no reproducible analogue at acdream's /// canonical layer. /// /// /// P8 (contract proof obligation, corrected at the architecture review /// round — A3): this step deliberately publishes NO per-child /// RuntimeEntityChange.Rebucketed delta, matching /// RuntimePhysicsState.CommitCanonicalCell's precedent. The /// correct basis for that decision is BOTH observer interfaces, not /// just IRuntimeEntityObjectObserver's direct implementations: /// GameRuntimeEventHub itself implements /// IRuntimeEntityObjectObserver and fans every entity delta out /// to IRuntimeEventObserver, and RuntimeTraceRecorder.OnEntity /// (GameRuntimeEvents.cs) is a non-stub shipped consumer that /// records (delta.Change, delta.Entity.CellId) for every entity /// delta — it is diagnostic tracing, not gameplay logic, and the /// entries it would lose are graphical-only equipped-child /// Rebucketed deltas that TickChild's demoted rebucket used to /// produce, so silence here is acceptable, but "no consumer at all" is /// false and must not be restated that way. /// /// /// /// P4 (contract proof obligation — the child broadphase story, stated): /// this step writes canonical cell FIELDS only. At attach, the /// preceding cell-less edge already force-ends collision reporting /// (Physics.CollisionReports.LeaveWorld) and no child broadphase /// registration exists to rebuild — retail's own /// recalc_cross_cells @0x00515A30 runs at attach only, never /// per-crossing (the §0 trap this hook deliberately does not port). At /// every crossing thereafter, a committed child never becomes a spatial /// root (LiveEntityRuntime.HasSpatialRuntimeProjection keys off /// ProjectionKind is World, and an attached child is always /// ProjectionKind.AttachedAcknowledgeSpatialProjection /// is never called on this path, headless or graphical), so it never /// joins any physics workset or shadow/cross-cell list this step would /// need to maintain. Confirmed, not assumed: zero shadow work is /// performed anywhere in this method. /// /// private void PropagateFullCellToChildren( RuntimeEntityRecord root, uint fullCellId, uint canonicalLandblockId) { _propagationWorklist.Clear(); _propagationWorklist.Push(root); while (_propagationWorklist.Count > 0) { RuntimeEntityRecord current = _propagationWorklist.Pop(); IReadOnlyList children = ParentAttachments.ChildrenAttachedToParent( current.ServerGuid, current.Incarnation); for (int i = 0; i < children.Count; i++) { // A7 (architecture review, LOW): key the idempotence/cycle // skip on the PAIR, not FullCellId alone. Every production // writer derives canonicalLandblockId from fullCellId, so // the two are coupled today, but the coupling is not // enforced anywhere (LiveEntityRuntime.CanonicalLandblockId's // setter can write a same-cell, different-landblock pair) — // testing the pair is the version that is correct // independent of that coupling. if (!TryGetActive(children[i], out RuntimeEntityRecord child) || (child.FullCellId == fullCellId && child.CanonicalLandblockId == canonicalLandblockId)) { continue; } if (PhysicsDiagnostics.ProbeChildCellEnabled) { Console.WriteLine(FormattableString.Invariant( $"[child-cell] parent=0x{current.ServerGuid:X8} child=0x{child.ServerGuid:X8} old=0x{child.FullCellId:X8} new=0x{fullCellId:X8} cause={(fullCellId == 0u ? "withdraw" : "propagate")}")); } child.SetFullCell(fullCellId, canonicalLandblockId); _propagationWorklist.Push(child); } } } public void SetFinalPhysicsState( RuntimeEntityRecord record, PhysicsStateFlags state) { EnsureKnown(record); record.SetFinalPhysicsState(state); } internal bool StopMissileAfterCollision( RuntimeEntityRecord record, bool requireCurrentMissile) { EnsureKnown(record); return record.StopMissileAfterCollision(requireCurrentMissile); } public void SetHasPartArray(RuntimeEntityRecord record, bool value) { EnsureKnown(record); record.HasPartArray = value; } public void SetPhysicsBody( RuntimeEntityRecord record, AcDream.Core.Physics.PhysicsBody? body) { EnsureKnown(record); record.SetPhysicsBody(body); } public void SetPhysicsBodyAcquisitionInProgress( RuntimeEntityRecord record, bool value) { EnsureKnown(record); record.PhysicsBodyAcquisitionInProgress = value; } public void SetRemoteMotion( RuntimeEntityRecord record, IRuntimeRemoteMotion? remote) { EnsureKnown(record); record.RemoteMotion = remote; } public void SetRemoteMotionBindingInProgress( RuntimeEntityRecord record, bool value) { EnsureKnown(record); record.RemoteMotionBindingInProgress = value; } public void SetProjectile( RuntimeEntityRecord record, IRuntimeProjectile? projectile) { EnsureKnown(record); record.Projectile = projectile; } public void SetProjectileBindingInProgress( RuntimeEntityRecord record, bool value) { EnsureKnown(record); record.ProjectileBindingInProgress = value; } public void SetRequiresRemotePlacementRuntime( RuntimeEntityRecord record, bool value) { EnsureKnown(record); record.RequiresRemotePlacementRuntime = value; } public void SetPhysicsHost( RuntimeEntityRecord record, AcDream.Core.Physics.Motion.IPhysicsObjHost? host) { EnsureKnown(record); record.PhysicsHost = host; } public void SetDeleteAcceptedForTeardown( RuntimeEntityRecord record, bool value) { EnsureKnown(record); record.DeleteAcceptedForTeardown = value; } public bool TryApplyObjDesc( AcDream.Core.Net.Messages.ObjDescEvent.Parsed update, out WorldSession.EntitySpawn accepted) => _inbound.TryApplyObjDesc(update, out accepted); public bool TryApplyPickup( AcDream.Core.Net.Messages.PickupEvent.Parsed update, out WorldSession.EntitySpawn accepted) => _inbound.TryApplyPickup(update, out accepted); public bool TryApplyCreateParent( CreateParentUpdate update, out WorldSession.EntitySpawn accepted) => _inbound.TryApplyCreateParent(update, out accepted); public bool TryApplyParent( AcDream.Core.Net.Messages.ParentEvent.Parsed update, out WorldSession.EntitySpawn accepted) => _inbound.TryApplyParent(update, out accepted); public bool TryCommitParent( uint childGuid, uint parentGuid, uint parentLocation, uint placementId, ushort positionSequence, out WorldSession.EntitySpawn accepted) => _inbound.TryCommitParent( childGuid, parentGuid, parentLocation, placementId, positionSequence, out accepted); public bool TryApplyMotion( WorldSession.EntityMotionUpdate update, bool retainPayload, out WorldSession.EntitySpawn accepted, out AcceptedPhysicsTimestamps timestamps) => _inbound.TryApplyMotion(update, retainPayload, out accepted, out timestamps); public bool TryApplyVector( AcDream.Core.Net.Messages.VectorUpdate.Parsed update, out WorldSession.EntitySpawn accepted) => _inbound.TryApplyVector(update, out accepted); public bool TryApplyState( AcDream.Core.Net.Messages.SetState.Parsed update, out WorldSession.EntitySpawn accepted) => _inbound.TryApplyState(update, out accepted); public bool TryApplyPosition( WorldSession.EntityPositionUpdate update, bool isLocalPlayer, System.Numerics.Quaternion? forcePositionRotation, System.Numerics.Vector3? currentLocalVelocity, out PositionTimestampDisposition disposition, out WorldSession.EntitySpawn accepted, out AcceptedPhysicsTimestamps timestamps) => _inbound.TryApplyPosition( update, isLocalPlayer, forcePositionRotation, currentLocalVelocity, out disposition, out accepted, out timestamps); internal bool TryAcceptDeferredPosition( WorldSession.EntityPositionUpdate update, bool isLocalPlayer, out PositionTimestampDisposition disposition, out AcceptedPhysicsTimestamps timestamps, out bool hasTimestampMutation) => _inbound.TryAcceptDeferredPosition( update, isLocalPlayer, out disposition, out timestamps, out hasTimestampMutation); internal bool TryAcceptDeferredObjDesc( ObjDescEvent.Parsed update, out AcceptedPhysicsTimestamps timestamps) => _inbound.TryAcceptDeferredObjDesc(update, out timestamps); internal bool TryAcceptDeferredPickup( PickupEvent.Parsed update, out AcceptedPhysicsTimestamps timestamps) => _inbound.TryAcceptDeferredPickup(update, out timestamps); internal bool TryAcceptDeferredCreateParent( CreateParentUpdate update, out AcceptedPhysicsTimestamps timestamps) => _inbound.TryAcceptDeferredCreateParent(update, out timestamps); internal bool TryAcceptDeferredParent( ParentEvent.Parsed update, out AcceptedPhysicsTimestamps timestamps) => _inbound.TryAcceptDeferredParent(update, out timestamps); internal bool TryAcceptDeferredMotion( WorldSession.EntityMotionUpdate update, out AcceptedPhysicsTimestamps timestamps, out bool hasTimestampMutation) => _inbound.TryAcceptDeferredMotion( update, out timestamps, out hasTimestampMutation); internal bool TryAcceptDeferredState( SetState.Parsed update, out AcceptedPhysicsTimestamps timestamps) => _inbound.TryAcceptDeferredState(update, out timestamps); internal bool TryAcceptDeferredVector( VectorUpdate.Parsed update, out AcceptedPhysicsTimestamps timestamps) => _inbound.TryAcceptDeferredVector(update, out timestamps); public bool IsFreshTeleportStart(uint guid, ushort teleportSequence) => _inbound.IsFreshTeleportStart(guid, teleportSequence); // Round 3 A1: gate-less instance seams for the initial-Create // continuation executor. Each merges against _inbound's OWN // _snapshots[guid] (never a caller-supplied base) and writes the result // back, keeping this store and RuntimeEntityRecord.Snapshot in lockstep. internal bool ApplyAcceptedObjDescSnapshot( uint guid, ObjDescEvent.Parsed update, out WorldSession.EntitySpawn accepted) => _inbound.ApplyAcceptedObjDescSnapshot(guid, update, out accepted); internal bool ApplyAcceptedPickupSnapshot( uint guid, PickupEvent.Parsed update, out WorldSession.EntitySpawn accepted) => _inbound.ApplyAcceptedPickupSnapshot(guid, update, out accepted); internal bool ApplyAcceptedCreateParentSnapshot( uint guid, CreateParentUpdate update, out WorldSession.EntitySpawn accepted) => _inbound.ApplyAcceptedCreateParentSnapshot(guid, update, out accepted); internal bool ApplyAcceptedParentSnapshot( uint guid, ParentEvent.Parsed update, out WorldSession.EntitySpawn accepted) => _inbound.ApplyAcceptedParentSnapshot(guid, update, out accepted); internal bool ApplyAcceptedMotionSnapshot( uint guid, ushort movementSequence, ushort acceptedServerControlledMove, WorldSession.EntityMotionUpdate update, bool retainPayload, out WorldSession.EntitySpawn accepted) => _inbound.ApplyAcceptedMotionSnapshot( guid, movementSequence, acceptedServerControlledMove, update, retainPayload, out accepted); internal bool ApplyAcceptedStateSnapshot( uint guid, SetState.Parsed update, out WorldSession.EntitySpawn accepted) => _inbound.ApplyAcceptedStateSnapshot(guid, update, out accepted); internal bool ApplyAcceptedVectorSnapshot( uint guid, VectorUpdate.Parsed update, out WorldSession.EntitySpawn accepted) => _inbound.ApplyAcceptedVectorSnapshot(guid, update, out accepted); internal bool ApplyAcceptedPositionSnapshot( uint guid, WorldSession.EntityPositionUpdate update, PositionTimestampDisposition disposition, AcceptedPhysicsTimestamps timestamps, bool isLocalPlayer, System.Numerics.Quaternion? forcePositionRotation, System.Numerics.Vector3? currentLocalVelocity, bool installPlacementFrame, bool clearParent, out WorldSession.EntitySpawn accepted) => _inbound.ApplyAcceptedPositionSnapshot( guid, update, disposition, timestamps, isLocalPlayer, forcePositionRotation, currentLocalVelocity, installPlacementFrame, clearParent, out accepted); internal bool ApplyAcceptedPositionExecutionRejectedSnapshot( uint guid, ushort acceptedPositionSequence, AcceptedPhysicsTimestamps timestamps, out WorldSession.EntitySpawn accepted) => _inbound.ApplyAcceptedPositionExecutionRejectedSnapshot( guid, acceptedPositionSequence, timestamps, out accepted); internal bool ApplyAcceptedWeenieDescriptionSnapshot( uint guid, WorldSession.EntitySpawn incoming, out WorldSession.EntitySpawn merged) => _inbound.ApplyAcceptedWeenieDescriptionSnapshot(guid, incoming, out merged); /// /// #297 review round 2: see /// . /// internal bool TryRefreshObjectDescriptionFlags( uint guid, uint bitfield, out WorldSession.EntitySpawn merged) => _inbound.TryRefreshObjectDescriptionFlags(guid, bitfield, out merged); private bool IsKnown(RuntimeEntityRecord record) { if (IsCurrent(record)) return true; return _teardownByIncarnation.TryGetValue( (record.ServerGuid, record.Incarnation), out RuntimeEntityRecord? retained) && ReferenceEquals(retained, record); } private void EnsureKnown(RuntimeEntityRecord record) { ArgumentNullException.ThrowIfNull(record); if (!IsKnown(record)) { throw new InvalidOperationException( $"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} is no longer owned by the directory."); } } }