using System.Collections.Immutable; using System.Numerics; using AcDream.Core.Net; using AcDream.Core.Net.Messages; using AcDream.Core.Physics; using AcDream.Runtime.Entities; using AcDream.Runtime.Physics; namespace AcDream.Runtime.Tests.Entities; public sealed class RuntimeInitialCreateResidenceStateTests { private const uint Landblock = 0xA9B40000u; private const uint Cell = Landblock | 0x0001u; [Theory] [InlineData(true, false, RuntimeSetPositionOperationKind.InitialLogin, RuntimeTeleportHookPhase.AfterEnterWorld)] [InlineData(false, false, RuntimeSetPositionOperationKind.RemoteAuthoritative, RuntimeTeleportHookPhase.None)] [InlineData(false, true, RuntimeSetPositionOperationKind.ProjectileAuthoritative, RuntimeTeleportHookPhase.None)] internal void TopLevelRegistrationOwnsExactCelllessLeaseBeforeObservers( bool isLocalPlayer, bool missile, RuntimeSetPositionOperationKind expectedOperation, RuntimeTeleportHookPhase expectedHook) { using var lifetime = new RuntimeEntityObjectLifetime(); Bind(lifetime, 7UL); RuntimeInitialCreateResidenceLease observed = default; uint observedCell = uint.MaxValue; using IDisposable subscription = lifetime.Events.Subscribe( new EntityObserver(delta => { if (delta.Change is not RuntimeEntityChange.Registered) return; Assert.True(lifetime.Entities.TryGetByLocalId( delta.Entity.Identity.LocalEntityId, out RuntimeEntityRecord record)); observedCell = record.FullCellId; Assert.True(lifetime.TryGetInitialCreateResidence( record, out observed)); })); RuntimeEntityRegistrationResult registration = lifetime .RegisterEntityWithInitialResidence( Spawn(0x70003001u, 1, missile: missile), isLocalPlayer); RuntimeEntityRecord canonical = registration.Canonical!; Assert.Equal(0u, observedCell); Assert.Equal(0u, canonical.FullCellId); Assert.Equal(Cell, canonical.Snapshot.Position!.Value.LandblockId); Assert.True(observed.IsValid); Assert.Equal(observed.Token.Entity, observed.Route.Authority.Entity); Assert.Equal(expectedOperation, observed.Route.OperationKind); Assert.Equal(expectedHook, observed.Route.TeleportHookPhase); Assert.Equal(0x11u, (uint)observed.Route.SetPositionFlags); Assert.True(observed.Placement.IsValid); Assert.Equal(1, lifetime.CaptureOwnership() .InitialCreateResidenceLeaseCount); } [Theory] [InlineData(true)] [InlineData(false)] public void FreshParentedAndPickedCreateRemainCelllessWithoutWithdrawal( bool parented) { using var lifetime = new RuntimeEntityObjectLifetime(); Bind(lifetime, 8UL); RuntimeEntityRecord canonical = lifetime .RegisterEntityWithInitialResidence( Spawn( 0x70003002u, 1, includePosition: false, parentGuid: parented ? 0x70004000u : null), isLocalPlayer: false) .Canonical!; Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease lease)); Assert.Equal(0u, canonical.FullCellId); Assert.False(lease.Placement.IsValid); Assert.Equal(RuntimeAuthoritativePositionDisposition.AwaitFreshPosition, lease.Route.Disposition); Assert.False(lease.Route.LeaveWorld); Assert.Equal( RuntimeInitialCreateResidenceCompletionStatus.Completed, lifetime.CompleteInitialCreateResidence( canonical, lease.Token, out RuntimeInitialCreateResidenceReceipt receipt)); Assert.Equal(0u, receipt.FullCellId); Assert.Equal(RuntimeTeleportHookPhase.None, receipt.TeleportHookPhase); Assert.True(lifetime.AcknowledgeInitialCreateResidenceAdoption( canonical, receipt.Adoption)); Assert.Equal(0, lifetime.CaptureOwnership() .InitialCreateResidenceLeaseCount); Assert.Equal(0, lifetime.Physics.SetPosition.CaptureOwnership() .ActiveOperationCount); } [Fact] public void MissingCellDefersExactLeaseWithoutCommittingWireResidence() { using var lifetime = new RuntimeEntityObjectLifetime(); Bind(lifetime, 9UL); RuntimeEntityRecord canonical = lifetime .RegisterEntityWithInitialResidence( Spawn(0x70003003u, 1, setupId: null), isLocalPlayer: false) .Canonical!; Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease lease)); AttachDormantBody(lifetime, canonical); RuntimeSetPositionCommand command = Prepare( lifetime, lease, RuntimeSetPositionMoverSetup.ResolvedAbsent); RuntimeSetPositionOutcome outcome = lifetime.Physics.SetPosition .SubmitPreparedPlacement(lease.Placement, command); Assert.Equal(RuntimeSetPositionStatus.DeferredCell, outcome.Status); Assert.Equal(0u, canonical.FullCellId); Assert.Equal(Cell, canonical.Snapshot.Position!.Value.LandblockId); Assert.Equal( RuntimeInitialCreateResidenceCompletionStatus.PendingPlacement, lifetime.CompleteInitialCreateResidence( canonical, lease.Token, out _)); Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease retained)); Assert.Equal(lease, retained); } [Theory] [InlineData(true, RuntimeTeleportHookPhase.AfterEnterWorld)] [InlineData(false, RuntimeTeleportHookPhase.None)] internal void CommittedAndAcknowledgedCreateYieldsExactEnterWorldReceipt( bool isLocalPlayer, RuntimeTeleportHookPhase expectedHook) { var engine = new PhysicsEngine { DataCache = new PhysicsDataCache() }; engine.AddLandblock( Landblock, new TerrainSurface(new byte[81], new float[256]), Array.Empty(), Array.Empty(), worldOffsetX: 0f, worldOffsetY: 0f); using var lifetime = new RuntimeEntityObjectLifetime(engine); Bind(lifetime, 10UL); RuntimeEntityRecord canonical = lifetime .RegisterEntityWithInitialResidence( Spawn(0x70003004u, 1, setupId: null), isLocalPlayer) .Canonical!; Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease lease)); AttachDormantBody(lifetime, canonical); RuntimeSetPositionCommand command = Prepare( lifetime, lease, RuntimeSetPositionMoverSetup.ResolvedAbsent); RuntimeSetPositionOutcome outcome = lifetime.Physics.SetPosition .SubmitPreparedPlacement(lease.Placement, command); Assert.Equal( RuntimeSetPositionStatus.CommittedHostAcknowledgementPending, outcome.Status); Assert.Equal(Cell, canonical.FullCellId); Assert.Equal( RuntimeInitialCreateResidenceCompletionStatus.PendingPlacement, lifetime.CompleteInitialCreateResidence( canonical, lease.Token, out _)); Assert.True(lifetime.Physics.SetPosition.AcknowledgeProjection( outcome.Projection)); Assert.Equal( RuntimeInitialCreateResidenceCompletionStatus.Completed, lifetime.CompleteInitialCreateResidence( canonical, lease.Token, out RuntimeInitialCreateResidenceReceipt receipt)); Assert.Equal(expectedHook, receipt.TeleportHookPhase); Assert.Equal(Cell, receipt.FullCellId); Assert.Equal(canonical.PlacementCommitVersion, receipt.PlacementCommitVersion); Assert.True(receipt.Adoption.IsValid); Assert.Empty(receipt.Continuations); Assert.Equal( RuntimeInitialCreateResidenceCompletionStatus.Completed, lifetime.CompleteInitialCreateResidence( canonical, lease.Token, out RuntimeInitialCreateResidenceReceipt repeated)); Assert.Equal(receipt, repeated); Assert.False(lifetime.Physics.SetPosition .TryBeginExclusiveAuthoredPlacement( canonical, canonical.PositionAuthorityVersion, RuntimeSetPositionOperationKind.RemoteAuthoritative) .IsValid); Assert.True(lifetime.AcknowledgeInitialCreateResidenceAdoption( canonical, receipt.Adoption)); RuntimeEntityPlacementToken afterAdoption = lifetime.Physics.SetPosition .TryBeginExclusiveAuthoredPlacement( canonical, canonical.PositionAuthorityVersion, RuntimeSetPositionOperationKind.RemoteAuthoritative); Assert.True(afterAdoption.IsValid); _ = lifetime.Physics.SetPosition.ForgetExactPlacement(afterAdoption); Assert.False(lifetime.TryGetInitialCreateResidence( canonical, out _)); } [Fact] public void GenerationReplacementForgetsOldLeaseAndOwnsOnlySuccessor() { using var lifetime = new RuntimeEntityObjectLifetime(); Bind(lifetime, 11UL); RuntimeEntityRecord first = lifetime .RegisterEntityWithInitialResidence( Spawn(0x70003005u, 1), isLocalPlayer: false) .Canonical!; Assert.True(lifetime.TryGetInitialCreateResidence( first, out RuntimeInitialCreateResidenceLease oldLease)); RuntimeEntityRecord second = lifetime .RegisterEntityWithInitialResidence( Spawn(0x70003005u, 2), isLocalPlayer: false) .Canonical!; Assert.False(lifetime.TryGetInitialCreateResidence(first, out _)); Assert.Equal( RuntimeInitialCreateResidenceCompletionStatus.RejectedToken, lifetime.CompleteInitialCreateResidence( first, oldLease.Token, out _)); Assert.True(lifetime.TryGetInitialCreateResidence( second, out RuntimeInitialCreateResidenceLease successor)); Assert.NotEqual(oldLease.Token, successor.Token); Assert.Equal(1, lifetime.CaptureOwnership() .InitialCreateResidenceLeaseCount); } [Fact] public void RegistrationObserverReentryCannotResurrectOuterLease() { using var lifetime = new RuntimeEntityObjectLifetime(); Bind(lifetime, 12UL); RuntimeEntityRegistrationResult nested = default; bool reentered = false; using IDisposable subscription = lifetime.Events.Subscribe( new EntityObserver(delta => { if (reentered || delta.Change is not RuntimeEntityChange.Registered) return; reentered = true; nested = lifetime.RegisterEntityWithInitialResidence( Spawn(0x70003006u, 2), isLocalPlayer: false); })); RuntimeEntityRegistrationResult outer = lifetime .RegisterEntityWithInitialResidence( Spawn(0x70003006u, 1), isLocalPlayer: false); Assert.Equal(CreateObjectTimestampDisposition.StaleGeneration, outer.Inbound.Disposition); RuntimeEntityRecord current = nested.Canonical!; Assert.True(lifetime.Entities.IsCurrent(current)); Assert.Equal((ushort)2, current.Incarnation); Assert.True(lifetime.TryGetInitialCreateResidence( current, out RuntimeInitialCreateResidenceLease lease)); Assert.Equal(current.Key, lease.Token.Entity); Assert.Equal(1, lifetime.CaptureOwnership() .InitialCreateResidenceLeaseCount); } [Fact] public void DeleteResetAndDisposeConvergeEveryInitialResidenceOwner() { var lifetime = new RuntimeEntityObjectLifetime(); Bind(lifetime, 13UL); RuntimeEntityRecord deleted = lifetime .RegisterEntityWithInitialResidence( Spawn(0x70003007u, 1), isLocalPlayer: false) .Canonical!; Assert.True(lifetime.TryAcceptDelete( new DeleteObject.Parsed(deleted.ServerGuid, deleted.Incarnation), isLocalPlayer: false, removeRetainedObject: true, out RuntimeEntityDeleteAcceptance acceptance)); Assert.Equal(0, lifetime.CaptureOwnership() .InitialCreateResidenceLeaseCount); lifetime.CompleteAcceptedDelete(acceptance); Assert.Null(lifetime.RetireCanonicalOnly(deleted)); _ = lifetime.RegisterEntityWithInitialResidence( Spawn(0x70003008u, 1), isLocalPlayer: false); IReadOnlyList retirements = lifetime.BeginSessionClear(); Assert.Equal(0, lifetime.CaptureOwnership() .InitialCreateResidenceLeaseCount); foreach (RuntimeEntityRecord record in retirements) lifetime.CompleteSessionEntityRetirement(record); Assert.True(lifetime.CompleteSessionClearIfConverged()); lifetime.Dispose(); Assert.True(lifetime.CaptureOwnership().IsConverged); } [Fact] public void ResetCancelsCompletedUnadoptedContinuationBatch() { var engine = new PhysicsEngine { DataCache = new PhysicsDataCache() }; engine.AddLandblock( Landblock, new TerrainSurface(new byte[81], new float[256]), Array.Empty(), Array.Empty(), worldOffsetX: 0f, worldOffsetY: 0f); using var lifetime = new RuntimeEntityObjectLifetime(engine); Bind(lifetime, 32UL); RuntimeEntityRecord canonical = lifetime .RegisterEntityWithInitialResidence( Spawn(0x7000301Eu, 1, setupId: null), isLocalPlayer: true) .Canonical!; Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease lease)); AttachDormantBody(lifetime, canonical); RuntimeSetPositionOutcome outcome = lifetime.Physics.SetPosition .SubmitPreparedPlacement( lease.Placement, Prepare( lifetime, lease, RuntimeSetPositionMoverSetup.ResolvedAbsent)); Assert.True(lifetime.Physics.SetPosition.AcknowledgeProjection( outcome.Projection)); Assert.Equal( RuntimeInitialCreateResidenceCompletionStatus.Completed, lifetime.CompleteInitialCreateResidence( canonical, lease.Token, out RuntimeInitialCreateResidenceReceipt receipt)); Assert.Equal(1, lifetime.CaptureOwnership() .InitialCreateResidenceLeaseCount); IReadOnlyList retirements = lifetime.BeginSessionClear(); Assert.False(lifetime.AcknowledgeInitialCreateResidenceAdoption( canonical, receipt.Adoption)); Assert.Equal(0, lifetime.CaptureOwnership() .InitialCreateResidenceLeaseCount); RuntimeSetPositionOwnershipSnapshot ownership = lifetime.Physics.SetPosition.CaptureOwnership(); Assert.Equal(0, ownership.ActiveOperationCount); Assert.Equal(0, ownership.PlacementCompletionWatchCount); Assert.Equal(0, ownership.AcknowledgedPlacementCompletionCount); foreach (RuntimeEntityRecord record in retirements) lifetime.CompleteSessionEntityRetirement(record); Assert.True(lifetime.CompleteSessionClearIfConverged()); } [Fact] public void PostCompletionRebucketRejectsTopLevelAdoptionAndConverges() { var engine = new PhysicsEngine { DataCache = new PhysicsDataCache() }; engine.AddLandblock( Landblock, new TerrainSurface(new byte[81], new float[256]), Array.Empty(), Array.Empty(), worldOffsetX: 0f, worldOffsetY: 0f); using var lifetime = new RuntimeEntityObjectLifetime(engine); Bind(lifetime, 33UL); RuntimeEntityRecord canonical = lifetime .RegisterEntityWithInitialResidence( Spawn(0x7000301Fu, 1, setupId: null), isLocalPlayer: false) .Canonical!; Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease lease)); AttachDormantBody(lifetime, canonical); RuntimeSetPositionOutcome outcome = lifetime.Physics.SetPosition .SubmitPreparedPlacement( lease.Placement, Prepare( lifetime, lease, RuntimeSetPositionMoverSetup.ResolvedAbsent)); Assert.True(lifetime.Physics.SetPosition.AcknowledgeProjection( outcome.Projection)); Assert.Equal( RuntimeInitialCreateResidenceCompletionStatus.Completed, lifetime.CompleteInitialCreateResidence( canonical, lease.Token, out RuntimeInitialCreateResidenceReceipt receipt)); lifetime.Entities.SetFullCell( canonical, Landblock | 0x0002u, Landblock); Assert.False(lifetime.AcknowledgeInitialCreateResidenceAdoption( canonical, receipt.Adoption)); Assert.Equal(0, lifetime.CaptureOwnership() .InitialCreateResidenceLeaseCount); RuntimeSetPositionOwnershipSnapshot ownership = lifetime.Physics.SetPosition.CaptureOwnership(); Assert.Equal(0, ownership.ActiveOperationCount); Assert.Equal(0, ownership.PlacementCompletionWatchCount); Assert.Equal(0, ownership.AcknowledgedPlacementCompletionCount); } [Fact] public void PostCompletionAuthorityChangeRejectsCelllessAdoption() { using var lifetime = new RuntimeEntityObjectLifetime(); Bind(lifetime, 34UL); RuntimeEntityRecord canonical = lifetime .RegisterEntityWithInitialResidence( Spawn( 0x70003020u, 1, includePosition: false, parentGuid: 0x70004020u), isLocalPlayer: false) .Canonical!; Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease lease)); Assert.Equal( RuntimeInitialCreateResidenceCompletionStatus.Completed, lifetime.CompleteInitialCreateResidence( canonical, lease.Token, out RuntimeInitialCreateResidenceReceipt receipt)); lifetime.Entities.AdvancePositionAuthority(canonical); Assert.False(lifetime.AcknowledgeInitialCreateResidenceAdoption( canonical, receipt.Adoption)); Assert.Equal(0, lifetime.CaptureOwnership() .InitialCreateResidenceLeaseCount); Assert.True(lifetime.Physics.SetPosition.CaptureOwnership() .IsConverged); } [Fact] public void CelllessPendingAdoptionRevisionsForFreshPositionWithoutLeak() { using var lifetime = new RuntimeEntityObjectLifetime(); Bind(lifetime, 36UL); const uint guid = 0x70003024u; RuntimeEntityRecord canonical = lifetime .RegisterEntityWithInitialResidence( Spawn( guid, 1, includePosition: false, parentGuid: 0x70004024u), isLocalPlayer: false) .Canonical!; Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease lease)); ulong positionAuthority = canonical.PositionAuthorityVersion; Assert.Equal( RuntimeInitialCreateResidenceCompletionStatus.Completed, lifetime.CompleteInitialCreateResidence( canonical, lease.Token, out RuntimeInitialCreateResidenceReceipt original)); int callbacks = 0; WorldSession.EntityPositionUpdate update = PositionUpdate( guid, positionSequence: 2, teleportSequence: 1, forcePositionSequence: 0, positionX: 25f); Assert.True(lifetime.TryApplyPosition( update, isLocalPlayer: false, forcePositionRotation: null, currentLocalVelocity: null, projectionRequiresTeleportHook: false, acknowledgeProjection: _ => callbacks++, out PositionTimestampDisposition disposition, out _, out _)); Assert.Equal(PositionTimestampDisposition.Apply, disposition); Assert.Equal(0, callbacks); Assert.Equal(positionAuthority, canonical.PositionAuthorityVersion); Assert.Null(canonical.Snapshot.Position); Assert.Equal(0u, canonical.FullCellId); Assert.Equal( RuntimeInitialCreateResidenceCompletionStatus.Completed, lifetime.CompleteInitialCreateResidence( canonical, lease.Token, out RuntimeInitialCreateResidenceReceipt revised)); Assert.Equal(original.Adoption.Revision + 1UL, revised.Adoption.Revision); RuntimeInitialCreateResidenceContinuation continuation = Assert.Single(revised.Continuations); Assert.Equal(25f, continuation.AcceptedWirePosition.PositionX); Assert.Equal((ushort)1, continuation.AcceptedTeleportSequence); Assert.False(lifetime.AcknowledgeInitialCreateResidenceAdoption( canonical, original.Adoption)); Assert.True(lifetime.AcknowledgeInitialCreateResidenceAdoption( canonical, revised.Adoption)); Assert.Equal(0, lifetime.CaptureOwnership() .InitialCreateResidenceLeaseCount); Assert.True(lifetime.Physics.SetPosition.CaptureOwnership() .IsConverged); } [Fact] public void ResetSnapshotsAllResidenceOwnersBeforeReentrantDiscardObserver() { var engine = new PhysicsEngine { DataCache = new PhysicsDataCache() }; engine.AddLandblock( Landblock, new TerrainSurface(new byte[81], new float[256]), Array.Empty(), Array.Empty(), worldOffsetX: 0f, worldOffsetY: 0f); using var lifetime = new RuntimeEntityObjectLifetime(engine); Bind(lifetime, 35UL); RuntimeEntityRecord completedRecord = lifetime .RegisterEntityWithInitialResidence( Spawn( 0x70003023u, 1, setupId: null, positionX: 70f), isLocalPlayer: false) .Canonical!; Assert.True(lifetime.TryGetInitialCreateResidence( completedRecord, out RuntimeInitialCreateResidenceLease completedLease)); AttachDormantBody(lifetime, completedRecord); RuntimeSetPositionOutcome completedOutcome = lifetime.Physics.SetPosition .SubmitPreparedPlacement( completedLease.Placement, Prepare( lifetime, completedLease, RuntimeSetPositionMoverSetup.ResolvedAbsent)); Assert.True(lifetime.Physics.SetPosition.AcknowledgeProjection( completedOutcome.Projection)); Assert.Equal( RuntimeInitialCreateResidenceCompletionStatus.Completed, lifetime.CompleteInitialCreateResidence( completedRecord, completedLease.Token, out _)); var pending = new List(); uint[] pendingGuids = [0x70003021u, 0x70003022u]; for (int index = 0; index < pendingGuids.Length; index++) { uint guid = pendingGuids[index]; RuntimeEntityRecord record = lifetime .RegisterEntityWithInitialResidence( Spawn( guid, 1, setupId: null, positionX: 10f + index * 30f), isLocalPlayer: false) .Canonical!; Assert.True(lifetime.TryGetInitialCreateResidence( record, out RuntimeInitialCreateResidenceLease lease)); AttachDormantBody(lifetime, record); pending.Add(lifetime.Physics.SetPosition.SubmitPreparedPlacement( lease.Placement, Prepare( lifetime, lease, RuntimeSetPositionMoverSetup.ResolvedAbsent))); } var discards = new List(); int nestedRetirementCount = -1; using IDisposable subscription = lifetime.Events.SubscribePlacement( new PlacementObserver(delta => { if (delta.Placement.Kind is not RuntimePlacementProjectionKind.Discard) { return; } discards.Add(delta.Placement.Token.Sequence); if (nestedRetirementCount < 0) { nestedRetirementCount = lifetime.BeginSessionClear().Count; } })); IReadOnlyList retirements = lifetime.BeginSessionClear(); Assert.Equal(0, nestedRetirementCount); Assert.Equal( pending.Select(static item => item.Projection.Sequence) .Order(), discards.Order()); Assert.Equal(0, lifetime.Events.DispatchFailureCount); Assert.Equal(0, lifetime.CaptureOwnership() .InitialCreateResidenceLeaseCount); foreach (RuntimeEntityRecord record in retirements) lifetime.CompleteSessionEntityRetirement(record); Assert.True(lifetime.CompleteSessionClearIfConverged()); } [Fact] public void InvalidGenerationFailsBeforeInboundOrCanonicalAcceptance() { using var lifetime = new RuntimeEntityObjectLifetime(); ulong generation = 0UL; lifetime.BindEventContext( () => new RuntimeGenerationToken(generation), static () => 1UL); WorldSession.EntitySpawn spawn = Spawn(0x70003009u, 1); Assert.Throws(() => lifetime .RegisterEntityWithInitialResidence(spawn, isLocalPlayer: false)); Assert.Equal(0, lifetime.Entities.Count); Assert.Equal(0, lifetime.Entities.ClaimedLocalIdCount); Assert.Empty(lifetime.Entities.Snapshots); Assert.Equal(0, lifetime.CaptureOwnership() .InitialCreateResidenceLeaseCount); Assert.True(lifetime.Physics.SetPosition.CaptureOwnership() .IsConverged); generation = 14UL; RuntimeEntityRegistrationResult recovered = lifetime .RegisterEntityWithInitialResidence(spawn, isLocalPlayer: false); Assert.Equal(CreateObjectTimestampDisposition.InitialGeneration, recovered.Inbound.Disposition); Assert.NotNull(recovered.Canonical); } [Fact] public void UnboundGenerationFailsWithoutFabricatingSessionAuthority() { using var lifetime = new RuntimeEntityObjectLifetime(); Assert.Throws(() => lifetime .RegisterEntityWithInitialResidence( Spawn(0x70003014u, 1), isLocalPlayer: false)); Assert.Empty(lifetime.Entities.Snapshots); Assert.Equal(0, lifetime.Entities.Count); Assert.Equal(0, lifetime.Entities.ClaimedLocalIdCount); } [Theory] [InlineData((ushort)1)] [InlineData((ushort)2)] public void EqualOrStaleMalformedCreateDoesNotDisplaceCurrentAdmission( ushort currentIncarnation) { using var lifetime = new RuntimeEntityObjectLifetime(); Bind(lifetime, 24UL); RuntimeEntityRecord canonical = lifetime .RegisterEntityWithInitialResidence( Spawn(0x70003015u, currentIncarnation), isLocalPlayer: false) .Canonical!; Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease initial)); ushort incomingIncarnation = 1; RuntimeEntityRegistrationResult result = lifetime .RegisterEntityWithInitialResidence( Spawn( 0x70003015u, incomingIncarnation, positionX: float.NaN), isLocalPlayer: false); Assert.Equal( currentIncarnation == incomingIncarnation ? CreateObjectTimestampDisposition.ExistingGeneration : CreateObjectTimestampDisposition.StaleGeneration, result.Inbound.Disposition); Assert.True(lifetime.Entities.IsCurrent(canonical)); Assert.Equal(10f, canonical.Snapshot.Position!.Value.PositionX); Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease retained)); Assert.Equal(initial, retained); } [Fact] public void MalformedInitialPositionDoesNotPoisonSameInstanceRecovery() { using var lifetime = new RuntimeEntityObjectLifetime(); Bind(lifetime, 15UL); WorldSession.EntitySpawn malformed = Spawn( 0x7000300Au, 1, positionX: float.NaN); Assert.Throws(() => lifetime .RegisterEntityWithInitialResidence( malformed, isLocalPlayer: false)); Assert.Empty(lifetime.Entities.Snapshots); Assert.Equal(0, lifetime.Entities.Count); WorldSession.EntitySpawn corrected = Spawn(0x7000300Au, 1); RuntimeEntityRegistrationResult recovered = lifetime .RegisterEntityWithInitialResidence( corrected, isLocalPlayer: false); Assert.Equal(CreateObjectTimestampDisposition.InitialGeneration, recovered.Inbound.Disposition); Assert.Equal(corrected.Position, recovered.Canonical!.Snapshot.Position); Assert.Equal(0u, recovered.Canonical.FullCellId); } [Fact] public void ExistingPlacementCollisionCannotStealOrPartiallyOwnLease() { using var lifetime = new RuntimeEntityObjectLifetime(); Bind(lifetime, 16UL); RuntimeEntityRegistrationResult registration = lifetime.RegisterEntity( Spawn(0x7000300Bu, 1)); RuntimeEntityRecord canonical = registration.Canonical!; lifetime.Entities.SetFullCell(canonical, 0u, 0u); lifetime.Entities.AdvancePositionAuthority(canonical); RuntimeEntityPlacementToken conflict = lifetime.Physics.SetPosition .BeginAuthoredPlacement( canonical, canonical.PositionAuthorityVersion, RuntimeSetPositionOperationKind.RemoteAuthoritative); Assert.True(conflict.IsValid); RuntimeInitialCreateResidenceLease rejected = lifetime.InitialCreateResidences.Begin( canonical, registration.Inbound, isLocalPlayer: false); Assert.False(rejected.IsValid); Assert.True(lifetime.Physics.SetPosition.IsPlacementCurrent(conflict)); Assert.Equal(0, lifetime.CaptureOwnership() .InitialCreateResidenceLeaseCount); Assert.Equal(0, lifetime.Physics.SetPosition.CaptureOwnership() .PlacementCompletionWatchCount); } [Fact] public void ParentPrecedesCombinedWirePositionAndCreatesNoWorldPlacement() { using var lifetime = new RuntimeEntityObjectLifetime(); Bind(lifetime, 17UL); RuntimeEntityRecord canonical = lifetime .RegisterEntityWithInitialResidence( Spawn( 0x7000300Cu, 1, includePosition: true, parentGuid: 0x70004001u), isLocalPlayer: false) .Canonical!; Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease lease)); Assert.Equal(RuntimeAuthoritativePositionDisposition.AwaitFreshPosition, lease.Route.Disposition); Assert.False(lease.Placement.IsValid); Assert.Equal(0u, canonical.FullCellId); Assert.Equal(0, lifetime.Physics.SetPosition.CaptureOwnership() .ActiveOperationCount); } [Theory] [InlineData(false)] [InlineData(true)] public void AbsentAndPresentZeroCellCreateAwaitFreshPosition( bool presentZeroCell) { using var lifetime = new RuntimeEntityObjectLifetime(); Bind(lifetime, 25UL); RuntimeEntityRecord canonical = lifetime .RegisterEntityWithInitialResidence( Spawn( presentZeroCell ? 0x70003016u : 0x70003017u, 1, includePosition: presentZeroCell, positionCell: 0u), isLocalPlayer: false) .Canonical!; Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease lease)); Assert.Equal(RuntimeAuthoritativePositionDisposition.AwaitFreshPosition, lease.Route.Disposition); Assert.False(lease.Placement.IsValid); Assert.Equal(0u, canonical.FullCellId); Assert.Equal(0, lifetime.Physics.SetPosition.CaptureOwnership() .ActiveOperationCount); } [Fact] public void EqualAndNewerSameGenerationCreateDoNotChurnPendingPlacement() { using var lifetime = new RuntimeEntityObjectLifetime(); Bind(lifetime, 18UL); RuntimeEntityRecord canonical = lifetime .RegisterEntityWithInitialResidence( Spawn(0x7000300Du, 1), isLocalPlayer: false) .Canonical!; Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease initial)); ulong positionAuthority = canonical.PositionAuthorityVersion; ulong spatialAuthority = canonical.SpatialAuthorityVersion; RuntimeEntityRegistrationResult duplicate = lifetime .RegisterEntityWithInitialResidence( Spawn(0x7000300Du, 1), isLocalPlayer: false); Assert.Equal(CreateObjectTimestampDisposition.ExistingGeneration, duplicate.Inbound.Disposition); Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease afterDuplicate)); Assert.Equal(initial, afterDuplicate); Assert.Equal(positionAuthority, canonical.PositionAuthorityVersion); Assert.Equal(spatialAuthority, canonical.SpatialAuthorityVersion); RuntimeEntityRegistrationResult newer = lifetime .RegisterEntityWithInitialResidence( Spawn( 0x7000300Du, 1, positionSequence: 2, positionX: 30f), isLocalPlayer: false); Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease beforeFreshRoute)); Assert.Equal(initial, beforeFreshRoute); Assert.Equal(10f, canonical.Snapshot.Position!.Value.PositionX); Assert.NotNull(newer.Inbound.SameGenerationEvents); WorldSession.EntityPositionUpdate update = newer.Inbound.SameGenerationEvents!.Value.Position!.Value; Assert.True(lifetime.TryApplyPosition( update, isLocalPlayer: false, forcePositionRotation: null, currentLocalVelocity: null, projectionRequiresTeleportHook: false, acknowledgeProjection: null, out PositionTimestampDisposition disposition, out _, out _)); Assert.Equal(PositionTimestampDisposition.Apply, disposition); Assert.Equal(0u, canonical.FullCellId); Assert.Equal(10f, canonical.Snapshot.Position!.Value.PositionX); Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease successor)); Assert.Equal(initial.Token, successor.Token); Assert.Equal(RuntimeSetPositionOperationKind.RemoteAuthoritative, successor.Route.OperationKind); RuntimeInitialCreateResidenceContinuation continuation = Assert.Single(successor.Continuations); Assert.Equal(30f, continuation.AcceptedWirePosition.PositionX); Assert.Equal((ushort)2, continuation.PositionSequence); Assert.Equal(PositionTimestampDisposition.Apply, continuation.TimestampDisposition); Assert.True(successor.Placement.IsValid); Assert.Equal(1, lifetime.Physics.SetPosition.CaptureOwnership() .ActiveOperationCount); } [Fact] public void AlreadyPlacedSameGenerationCreateCannotReclaimWireCell() { var engine = new PhysicsEngine { DataCache = new PhysicsDataCache() }; engine.AddLandblock( Landblock, new TerrainSurface(new byte[81], new float[256]), Array.Empty(), Array.Empty(), worldOffsetX: 0f, worldOffsetY: 0f); using var lifetime = new RuntimeEntityObjectLifetime(engine); Bind(lifetime, 19UL); RuntimeEntityRecord canonical = lifetime .RegisterEntityWithInitialResidence( Spawn(0x7000300Eu, 1, setupId: null), isLocalPlayer: false) .Canonical!; Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease lease)); AttachDormantBody(lifetime, canonical); RuntimeSetPositionOutcome outcome = lifetime.Physics.SetPosition .SubmitPreparedPlacement( lease.Placement, Prepare( lifetime, lease, RuntimeSetPositionMoverSetup.ResolvedAbsent)); Assert.True(lifetime.Physics.SetPosition.AcknowledgeProjection( outcome.Projection)); Assert.Equal( RuntimeInitialCreateResidenceCompletionStatus.Completed, lifetime.CompleteInitialCreateResidence( canonical, lease.Token, out _)); ulong spatialAuthority = canonical.SpatialAuthorityVersion; _ = lifetime.RegisterEntityWithInitialResidence( Spawn(0x7000300Eu, 1, setupId: null), isLocalPlayer: false); Assert.Equal(Cell, canonical.FullCellId); Assert.Equal(spatialAuthority, canonical.SpatialAuthorityVersion); Assert.False(lifetime.TryGetInitialCreateResidence(canonical, out _)); } [Fact] public void LocalNoTeleportFreshPositionRemainsInitialWorldAdmission() { using var lifetime = new RuntimeEntityObjectLifetime(); Bind(lifetime, 22UL); RuntimeEntityRecord canonical = lifetime .RegisterEntityWithInitialResidence( Spawn(0x70003012u, 1), isLocalPlayer: true) .Canonical!; Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease initial)); RuntimeEntityRegistrationResult newer = lifetime .RegisterEntityWithInitialResidence( Spawn( 0x70003012u, 1, positionSequence: 2, positionX: 40f), isLocalPlayer: true); WorldSession.EntityPositionUpdate update = newer.Inbound.SameGenerationEvents!.Value.Position!.Value; Assert.True(lifetime.TryApplyPosition( update, isLocalPlayer: true, forcePositionRotation: null, currentLocalVelocity: null, projectionRequiresTeleportHook: false, acknowledgeProjection: null, out PositionTimestampDisposition disposition, out _, out AcceptedPhysicsTimestamps timestamps)); Assert.Equal(PositionTimestampDisposition.Apply, disposition); Assert.False(timestamps.TeleportAdvanced); Assert.Equal(0u, canonical.FullCellId); Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease successor)); Assert.Equal(initial.Token, successor.Token); Assert.Equal(RuntimeAuthoritativePositionDisposition.SetPosition, successor.Route.Disposition); Assert.Equal(RuntimeSetPositionOperationKind.InitialLogin, successor.Route.OperationKind); Assert.Equal(RuntimeTeleportHookPhase.AfterEnterWorld, successor.Route.TeleportHookPhase); Assert.True(successor.Placement.IsValid); RuntimeInitialCreateResidenceContinuation continuation = Assert.Single(successor.Continuations); Assert.Equal(PositionTimestampDisposition.Apply, continuation.TimestampDisposition); Assert.Equal((ushort)0, continuation.PreviousTeleportSequence); Assert.Equal((ushort)0, continuation.TeleportSequence); } [Fact] public void LocalForcePositionSuffixIsQueuedBehindInitialAdmission() { using var lifetime = new RuntimeEntityObjectLifetime(); Bind(lifetime, 26UL); RuntimeInitialCreateResidenceLease successor = ApplyFreshSuccessor( lifetime, guid: 0x70003018u, isLocalPlayer: true, teleportSequence: 0, forcePositionSequence: 1, out PositionTimestampDisposition disposition); Assert.Equal(PositionTimestampDisposition.ForcePosition, disposition); Assert.Equal(RuntimeSetPositionOperationKind.InitialLogin, successor.Route.OperationKind); RuntimeInitialCreateResidenceContinuation continuation = Assert.Single(successor.Continuations); Assert.Equal(RuntimePositionEntityKind.LocalPlayer, continuation.EntityKind); Assert.Equal((ushort)1, continuation.ForcePositionSequence); Assert.Equal((ushort)0, continuation.PreviousTeleportSequence); Assert.Equal((ushort)0, continuation.TeleportSequence); Assert.NotNull(continuation.ForcePositionRotation); } [Fact] public void LocalTeleportSuffixIsQueuedBehindInitialAdmission() { using var lifetime = new RuntimeEntityObjectLifetime(); Bind(lifetime, 27UL); RuntimeInitialCreateResidenceLease successor = ApplyFreshSuccessor( lifetime, guid: 0x70003019u, isLocalPlayer: true, teleportSequence: 1, forcePositionSequence: 0, out PositionTimestampDisposition disposition); Assert.Equal(PositionTimestampDisposition.Apply, disposition); RuntimeInitialCreateResidenceContinuation continuation = Assert.Single(successor.Continuations); Assert.Equal(RuntimePositionEntityKind.LocalPlayer, continuation.EntityKind); Assert.Equal((ushort)0, continuation.PreviousTeleportSequence); Assert.Equal((ushort)1, continuation.TeleportSequence); Assert.Equal(Vector3.Zero, continuation.AcceptedVelocity); } [Fact] public void RemoteTeleportSuffixIsQueuedBehindInitialAdmission() { using var lifetime = new RuntimeEntityObjectLifetime(); Bind(lifetime, 28UL); RuntimeInitialCreateResidenceLease successor = ApplyFreshSuccessor( lifetime, guid: 0x7000301Au, isLocalPlayer: false, teleportSequence: 1, forcePositionSequence: 0, out PositionTimestampDisposition disposition); Assert.Equal(PositionTimestampDisposition.Apply, disposition); RuntimeInitialCreateResidenceContinuation continuation = Assert.Single(successor.Continuations); Assert.Equal(RuntimePositionEntityKind.Remote, continuation.EntityKind); Assert.Equal((ushort)0, continuation.PreviousTeleportSequence); Assert.Equal((ushort)1, continuation.TeleportSequence); } [Fact] public void AcceptedPositionsRemainMonotonicRawFifoWithoutMutatingInitialAdmission() { using var lifetime = new RuntimeEntityObjectLifetime(); Bind(lifetime, 29UL); const uint guid = 0x7000301Bu; RuntimeEntityRecord canonical = lifetime .RegisterEntityWithInitialResidence( Spawn(guid, 1), isLocalPlayer: true) .Canonical!; Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease initial)); ulong positionAuthority = canonical.PositionAuthorityVersion; int callbacks = 0; ApplyQueuedPosition( lifetime, guid, positionSequence: 2, teleportSequence: 0, forcePositionSequence: 0, positionX: 20f, projectionRequiresTeleportHook: false, () => callbacks++); ApplyQueuedPosition( lifetime, guid, positionSequence: 3, teleportSequence: 1, forcePositionSequence: 0, positionX: 30f, projectionRequiresTeleportHook: true, () => callbacks++); ApplyQueuedPosition( lifetime, guid, positionSequence: 4, teleportSequence: 2, forcePositionSequence: 0, positionX: 40f, projectionRequiresTeleportHook: false, () => callbacks++); Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease retained)); Assert.Equal(initial.Token, retained.Token); Assert.Equal(initial.Route, retained.Route); Assert.Equal(initial.Placement, retained.Placement); Assert.Equal(10f, canonical.Snapshot.Position!.Value.PositionX); Assert.Equal(positionAuthority, canonical.PositionAuthorityVersion); Assert.Equal(0, callbacks); Assert.Equal([1UL, 2UL, 3UL], retained.Continuations.Select(static item => item.Sequence)); Assert.Equal([20f, 30f, 40f], retained.Continuations.Select( static item => item.AcceptedWirePosition.PositionX)); Assert.Equal([(ushort)0, (ushort)0, (ushort)1], retained.Continuations.Select( static item => item.PreviousTeleportSequence)); Assert.Equal([(ushort)0, (ushort)1, (ushort)2], retained.Continuations.Select( static item => item.TeleportSequence)); Assert.False(retained.Continuations[0] .ProjectionRequiresTeleportHook); Assert.True(retained.Continuations[1] .ProjectionRequiresTeleportHook); } [Fact] public void MalformedQueuedPositionIsRejectedBeforeTimestampConsumption() { using var lifetime = new RuntimeEntityObjectLifetime(); Bind(lifetime, 30UL); const uint guid = 0x7000301Cu; RuntimeEntityRecord canonical = lifetime .RegisterEntityWithInitialResidence( Spawn(guid, 1), isLocalPlayer: false) .Canonical!; Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease initial)); WorldSession.EntityPositionUpdate malformed = PositionUpdate( guid, positionSequence: 2, teleportSequence: 0, forcePositionSequence: 0, positionX: float.NaN); Assert.False(lifetime.TryApplyPosition( malformed, isLocalPlayer: false, forcePositionRotation: null, currentLocalVelocity: null, projectionRequiresTeleportHook: false, acknowledgeProjection: null, out PositionTimestampDisposition disposition, out _, out _)); Assert.Equal(PositionTimestampDisposition.Rejected, disposition); Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease retained)); Assert.Equal(initial, retained); Assert.Equal(10f, canonical.Snapshot.Position!.Value.PositionX); ApplyQueuedPosition( lifetime, guid, positionSequence: 2, teleportSequence: 0, forcePositionSequence: 0, positionX: 25f, projectionRequiresTeleportHook: false, callback: null, isLocalPlayer: false); Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out retained)); Assert.Equal((ushort)2, Assert.Single(retained.Continuations).PositionSequence); } [Fact] public void CompletionRequiresExactAcknowledgedOriginalPlacement() { var engine = new PhysicsEngine { DataCache = new PhysicsDataCache() }; engine.AddLandblock( Landblock, new TerrainSurface(new byte[81], new float[256]), Array.Empty(), Array.Empty(), worldOffsetX: 0f, worldOffsetY: 0f); using var lifetime = new RuntimeEntityObjectLifetime(engine); Bind(lifetime, 20UL); RuntimeEntityRecord canonical = lifetime .RegisterEntityWithInitialResidence( Spawn(0x7000300Fu, 1, setupId: null), isLocalPlayer: false) .Canonical!; Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease original)); AttachDormantBody(lifetime, canonical); RuntimeEntityPlacementToken replacement = lifetime.Physics.SetPosition .BeginAuthoredPlacement( canonical, canonical.PositionAuthorityVersion, RuntimeSetPositionOperationKind.RemoteAuthoritative); var preparation = new RuntimeSetPositionMoverPreparation( RuntimeSetPositionMoverSetup.ResolvedAbsent, RuntimeSetPositionOperationKind.RemoteAuthoritative, GameTime: 1d, PhysicsPlacementClass.Ordinary, original.Route.SetPositionFlags); Assert.Equal( RuntimeSetPositionMoverPreparationStatus.Prepared, lifetime.Physics.SetPosition.PrepareMover( replacement, preparation, out RuntimeSetPositionCommand command)); RuntimeSetPositionOutcome outcome = lifetime.Physics.SetPosition .SubmitPreparedPlacement(replacement, command); Assert.True(lifetime.Physics.SetPosition.AcknowledgeProjection( outcome.Projection)); Assert.Equal( RuntimeInitialCreateResidenceCompletionStatus.RejectedAuthority, lifetime.CompleteInitialCreateResidence( canonical, original.Token, out _)); Assert.Equal(0, lifetime.CaptureOwnership() .InitialCreateResidenceLeaseCount); Assert.Equal(0, lifetime.Physics.SetPosition.CaptureOwnership() .AcknowledgedPlacementCompletionCount); } [Fact] public void FreshPositionQueuesBehindCommittedUnacknowledgedInitialAdmission() { var engine = new PhysicsEngine { DataCache = new PhysicsDataCache() }; engine.AddLandblock( Landblock, new TerrainSurface(new byte[81], new float[256]), Array.Empty(), Array.Empty(), worldOffsetX: 0f, worldOffsetY: 0f); using var lifetime = new RuntimeEntityObjectLifetime(engine); Bind(lifetime, 23UL); int deleted = 0; using IDisposable subscription = lifetime.Events.Subscribe( new EntityObserver(delta => { if (delta.Change is RuntimeEntityChange.Deleted) deleted++; })); RuntimeEntityRecord canonical = lifetime .RegisterEntityWithInitialResidence( Spawn(0x70003013u, 1, setupId: null), isLocalPlayer: true) .Canonical!; Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease initial)); AttachDormantBody(lifetime, canonical); RuntimeSetPositionOutcome first = lifetime.Physics.SetPosition .SubmitPreparedPlacement( initial.Placement, Prepare( lifetime, initial, RuntimeSetPositionMoverSetup.ResolvedAbsent)); Assert.Equal( RuntimeSetPositionStatus.CommittedHostAcknowledgementPending, first.Status); Assert.Equal(Cell, canonical.FullCellId); RuntimeEntityRegistrationResult newer = lifetime .RegisterEntityWithInitialResidence( Spawn( 0x70003013u, 1, setupId: null, positionSequence: 2, positionX: 45f), isLocalPlayer: true); WorldSession.EntityPositionUpdate update = newer.Inbound.SameGenerationEvents!.Value.Position!.Value; Assert.True(lifetime.TryApplyPosition( update, isLocalPlayer: true, forcePositionRotation: null, currentLocalVelocity: null, projectionRequiresTeleportHook: false, acknowledgeProjection: null, out PositionTimestampDisposition disposition, out _, out _)); Assert.Equal(PositionTimestampDisposition.Apply, disposition); Assert.Equal(0, deleted); Assert.True(lifetime.Physics.SetPosition.TryPeekProjection( out RuntimePlacementProjectionSnapshot place)); Assert.Equal(RuntimePlacementProjectionKind.Place, place.Kind); Assert.Equal(first.Projection.Sequence, place.Token.Sequence); Assert.True(lifetime.Physics.SetPosition.AcknowledgeProjection( place.Token)); Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease successor)); Assert.Equal(initial.Token, successor.Token); Assert.Equal(initial.Route, successor.Route); Assert.Equal(initial.Placement, successor.Placement); Assert.Equal(RuntimeTeleportHookPhase.AfterEnterWorld, successor.Route.TeleportHookPhase); RuntimeInitialCreateResidenceContinuation continuation = Assert.Single(successor.Continuations); Assert.Equal(45f, continuation.AcceptedWirePosition.PositionX); Assert.Equal( RuntimeInitialCreateResidenceCompletionStatus.Completed, lifetime.CompleteInitialCreateResidence( canonical, successor.Token, out RuntimeInitialCreateResidenceReceipt receipt)); Assert.Equal(RuntimeTeleportHookPhase.AfterEnterWorld, receipt.TeleportHookPhase); Assert.Equal(first.Projection, receipt.Projection); Assert.Equal(successor.Continuations, receipt.Continuations); ApplyQueuedPosition( lifetime, canonical.ServerGuid, positionSequence: 3, teleportSequence: 1, forcePositionSequence: 0, positionX: 55f, projectionRequiresTeleportHook: true, callback: null); Assert.Equal( RuntimeInitialCreateResidenceCompletionStatus.Completed, lifetime.CompleteInitialCreateResidence( canonical, successor.Token, out RuntimeInitialCreateResidenceReceipt repeated)); Assert.Equal(receipt.Adoption.Revision + 1UL, repeated.Adoption.Revision); Assert.Equal(2, repeated.Continuations.Length); Assert.Equal(55f, repeated.Continuations[1].AcceptedWirePosition.PositionX); Assert.False(lifetime.AcknowledgeInitialCreateResidenceAdoption( canonical, receipt.Adoption)); Assert.True(lifetime.AcknowledgeInitialCreateResidenceAdoption( canonical, repeated.Adoption)); Assert.Equal( RuntimeInitialCreateResidenceCompletionStatus.RejectedToken, lifetime.CompleteInitialCreateResidence( canonical, successor.Token, out _)); Assert.Equal(0, deleted); } [Fact] public void PreAcknowledgementSpatialCorruptionRetiresOperationAsDiscard() { var engine = new PhysicsEngine { DataCache = new PhysicsDataCache() }; engine.AddLandblock( Landblock, new TerrainSurface(new byte[81], new float[256]), Array.Empty(), Array.Empty(), worldOffsetX: 0f, worldOffsetY: 0f); using var lifetime = new RuntimeEntityObjectLifetime(engine); Bind(lifetime, 31UL); RuntimeEntityRecord canonical = lifetime .RegisterEntityWithInitialResidence( Spawn(0x7000301Du, 1, setupId: null), isLocalPlayer: false) .Canonical!; Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease lease)); AttachDormantBody(lifetime, canonical); RuntimeSetPositionOutcome outcome = lifetime.Physics.SetPosition .SubmitPreparedPlacement( lease.Placement, Prepare( lifetime, lease, RuntimeSetPositionMoverSetup.ResolvedAbsent)); Assert.Equal( RuntimeSetPositionStatus.CommittedHostAcknowledgementPending, outcome.Status); lifetime.Entities.SetFullCell( canonical, Landblock | 0x0002u, Landblock); Assert.Equal( RuntimeInitialCreateResidenceCompletionStatus.RejectedAuthority, lifetime.CompleteInitialCreateResidence( canonical, lease.Token, out _)); Assert.True(lifetime.Physics.SetPosition.TryPeekProjection( out RuntimePlacementProjectionSnapshot discard)); Assert.Equal(RuntimePlacementProjectionKind.Discard, discard.Kind); Assert.Equal(outcome.Projection.Sequence, discard.Token.Sequence); Assert.True(lifetime.Physics.SetPosition.AcknowledgeProjection( discard.Token)); RuntimeSetPositionOwnershipSnapshot ownership = lifetime.Physics.SetPosition.CaptureOwnership(); Assert.Equal(0, ownership.ActiveOperationCount); Assert.Equal(0, ownership.PlacementCompletionWatchCount); Assert.Equal(0, ownership.AcknowledgedPlacementCompletionCount); Assert.Equal(0, lifetime.CaptureOwnership() .InitialCreateResidenceLeaseCount); } [Fact] public void CorruptedPostAcknowledgementAuthorityRetiresProofAndLease() { var engine = new PhysicsEngine { DataCache = new PhysicsDataCache() }; engine.AddLandblock( Landblock, new TerrainSurface(new byte[81], new float[256]), Array.Empty(), Array.Empty(), worldOffsetX: 0f, worldOffsetY: 0f); using var lifetime = new RuntimeEntityObjectLifetime(engine); Bind(lifetime, 21UL); RuntimeEntityRecord canonical = lifetime .RegisterEntityWithInitialResidence( Spawn(0x70003010u, 1, setupId: null), isLocalPlayer: false) .Canonical!; Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease lease)); AttachDormantBody(lifetime, canonical); RuntimeSetPositionOutcome outcome = lifetime.Physics.SetPosition .SubmitPreparedPlacement( lease.Placement, Prepare( lifetime, lease, RuntimeSetPositionMoverSetup.ResolvedAbsent)); Assert.True(lifetime.Physics.SetPosition.AcknowledgeProjection( outcome.Projection)); lifetime.Entities.AdvancePlacementCommit(canonical); Assert.Equal( RuntimeInitialCreateResidenceCompletionStatus.RejectedAuthority, lifetime.CompleteInitialCreateResidence( canonical, lease.Token, out _)); Assert.Equal(0, lifetime.CaptureOwnership() .InitialCreateResidenceLeaseCount); RuntimeSetPositionOwnershipSnapshot ownership = lifetime.Physics.SetPosition.CaptureOwnership(); Assert.Equal(0, ownership.PlacementCompletionWatchCount); Assert.Equal(0, ownership.AcknowledgedPlacementCompletionCount); } [Fact] public void LegacyRegistrationAdvancesSpatialAuthorityOnlyOnce() { using var lifetime = new RuntimeEntityObjectLifetime(); RuntimeEntityRecord canonical = lifetime.RegisterEntity( Spawn(0x70003011u, 1)).Canonical!; Assert.Equal(Cell, canonical.FullCellId); Assert.Equal(1UL, canonical.SpatialAuthorityVersion); } private static RuntimeSetPositionCommand Prepare( RuntimeEntityObjectLifetime lifetime, in RuntimeInitialCreateResidenceLease lease, in RuntimeSetPositionMoverSetup setup) { var preparation = new RuntimeSetPositionMoverPreparation( setup, lease.Route.OperationKind, GameTime: 1d, PhysicsPlacementClass.Ordinary, lease.Route.SetPositionFlags); Assert.Equal( RuntimeSetPositionMoverPreparationStatus.Prepared, lifetime.Physics.SetPosition.PrepareMover( lease.Placement, preparation, out RuntimeSetPositionCommand command)); return command; } private static RuntimeInitialCreateResidenceLease ApplyFreshSuccessor( RuntimeEntityObjectLifetime lifetime, uint guid, bool isLocalPlayer, ushort teleportSequence, ushort forcePositionSequence, out PositionTimestampDisposition disposition) { RuntimeEntityRecord canonical = lifetime .RegisterEntityWithInitialResidence( Spawn(guid, 1), isLocalPlayer) .Canonical!; Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease initial)); RuntimeEntityRegistrationResult newer = lifetime .RegisterEntityWithInitialResidence( Spawn( guid, 1, positionSequence: 2, positionX: 40f, teleportSequence: teleportSequence, forcePositionSequence: forcePositionSequence), isLocalPlayer); WorldSession.EntityPositionUpdate update = newer.Inbound.SameGenerationEvents!.Value.Position!.Value; var preservedRotation = Quaternion.CreateFromYawPitchRoll( 0.5f, 0.25f, 0.125f); var currentVelocity = new Vector3(1f, 2f, 3f); Assert.True(lifetime.TryApplyPosition( update, isLocalPlayer, forcePositionRotation: preservedRotation, currentLocalVelocity: currentVelocity, projectionRequiresTeleportHook: true, acknowledgeProjection: null, out disposition, out _, out _)); Assert.True(lifetime.TryGetInitialCreateResidence( canonical, out RuntimeInitialCreateResidenceLease retained)); Assert.Equal(initial.Token, retained.Token); Assert.Equal(initial.Route, retained.Route); Assert.Equal(initial.Placement, retained.Placement); return retained; } private static void ApplyQueuedPosition( RuntimeEntityObjectLifetime lifetime, uint guid, ushort positionSequence, ushort teleportSequence, ushort forcePositionSequence, float positionX, bool projectionRequiresTeleportHook, Action? callback, bool isLocalPlayer = true) { WorldSession.EntityPositionUpdate update = PositionUpdate( guid, positionSequence, teleportSequence, forcePositionSequence, positionX); Assert.True(lifetime.TryApplyPosition( update, isLocalPlayer, forcePositionRotation: Quaternion.Identity, currentLocalVelocity: new Vector3(1f, 2f, 3f), projectionRequiresTeleportHook, acknowledgeProjection: callback is null ? null : _ => callback(), out PositionTimestampDisposition disposition, out _, out _)); Assert.True(disposition is PositionTimestampDisposition.Apply or PositionTimestampDisposition.ForcePosition); } private static WorldSession.EntityPositionUpdate PositionUpdate( uint guid, ushort positionSequence, ushort teleportSequence, ushort forcePositionSequence, float positionX) { return new WorldSession.EntityPositionUpdate( guid, new CreateObject.ServerPosition( Cell, positionX, 20f, 7f, 1f, 0f, 0f, 0f), new Vector3(positionSequence, 2f, 3f), PlacementId: positionSequence, IsGrounded: true, InstanceSequence: 1, PositionSequence: positionSequence, TeleportSequence: teleportSequence, ForcePositionSequence: forcePositionSequence); } private static void AttachDormantBody( RuntimeEntityObjectLifetime lifetime, RuntimeEntityRecord canonical) { var body = new PhysicsBody { State = canonical.FinalPhysicsState, Orientation = Quaternion.Identity, InWorld = false, }; lifetime.Entities.SetPhysicsBody(canonical, body); } private static void Bind( RuntimeEntityObjectLifetime lifetime, ulong generation) { var token = new RuntimeGenerationToken(generation); lifetime.BindEventContext(() => token, static () => 1UL); } private static WorldSession.EntitySpawn Spawn( uint guid, ushort incarnation, bool missile = false, bool includePosition = true, uint? parentGuid = null, uint? setupId = 0x02000001u, ushort positionSequence = 1, float positionX = 10f, uint positionCell = Cell, ushort teleportSequence = 0, ushort forcePositionSequence = 0) { CreateObject.ServerPosition? position = includePosition ? new CreateObject.ServerPosition( positionCell, positionX, 20f, 7f, 1f, 0f, 0f, 0f) : null; uint rawState = (uint)(PhysicsStateFlags.Gravity | (missile ? PhysicsStateFlags.Missile : 0)); var timestamps = new PhysicsTimestamps( Position: positionSequence, Movement: 1, State: 1, Vector: 1, Teleport: teleportSequence, ServerControlledMove: 1, ForcePosition: forcePositionSequence, ObjDesc: 1, Instance: incarnation); var physics = new PhysicsSpawnData( rawState, position, Movement: null, AnimationFrame: null, setupId, MotionTableId: null, SoundTableId: null, PhysicsScriptTableId: null, Parent: parentGuid is { } parent ? new PhysicsAttachment(parent, 1u) : null, Children: null, Scale: null, Friction: null, Elasticity: null, Translucency: null, Velocity: null, Acceleration: null, AngularVelocity: null, DefaultScriptType: null, DefaultScriptIntensity: null, timestamps); return new WorldSession.EntitySpawn( guid, position, setupId, Array.Empty(), Array.Empty(), Array.Empty(), BasePaletteId: null, ObjScale: null, Name: "initial-create", ItemType: null, MotionState: null, MotionTableId: null, PhysicsState: rawState, InstanceSequence: incarnation, PositionSequence: positionSequence, ParentGuid: parentGuid, ParentLocation: parentGuid is null ? null : 1u, Physics: physics); } private sealed class EntityObserver(Action onEntity) : IRuntimeEntityObjectObserver { public void OnEntity(in RuntimeEntityDelta delta) => onEntity(delta); public void OnInventory(in RuntimeInventoryDelta delta) { } } private sealed class PlacementObserver( Action onPlacement) : IRuntimePlacementObserver { public void OnPlacement(in RuntimePlacementDelta delta) => onPlacement(delta); } }