using System.Collections.Immutable; using System.Numerics; using AcDream.Content; using AcDream.Content.Pak; using AcDream.Core.Net; using AcDream.Core.Net.Messages; using AcDream.Core.Physics; using AcDream.Runtime.Entities; using AcDream.Runtime.Physics; using AcDream.Runtime; namespace AcDream.Runtime.Tests.Entities; public sealed class RuntimeRemoteFirstEntryStateTests { private const uint Landblock = 0xA9B60000u; private const uint Cell = Landblock | 0x0001u; private const uint SetupId = 0x02000001u; private static readonly RuntimeInitialCreateExecutionInputs NoContact = new(UsePositionFromServer: false, PlayerDistance: 0f); // --------------------------------------------------------------- // Happy path // --------------------------------------------------------------- [Fact] public void FullSequenceRemoteEntryConstructsGatedBodyPlacesAndCompletes() { using var fixture = new Fixture(residentWorld: true); RuntimeRemoteFirstEntryStatus status = fixture.Advance( out RuntimeInitialCreateExecutionReceipt receipt, out RuntimeRemoteBodyConstructionReceipt construction); Assert.Equal(RuntimeRemoteFirstEntryStatus.Completed, status); Assert.Equal(Cell, receipt.FullCellId); // Remote Creates carry NO teleport hook (classifier: AfterEnterWorld // is local-player-only). Assert.Equal(RuntimeTeleportHookPhase.None, receipt.TeleportHookPhase); // M1: the terminal Advance delivers the construction receipt in the // same call that reaps its retained storage — the C3c host's one // natural consumption point. Assert.True(construction.MotionTableGatePassed); Assert.Equal(0x09000001u, construction.MotionTableId); Assert.False(construction.MovementBranch); Assert.True(construction.PlacementFrameStaged); Assert.True(construction.FrictionApplied); Assert.Equal(0.5f, construction.Friction); Assert.False(construction.TranslucencyApplied); Assert.Equal(0f, construction.TranslucencyOriginal); Assert.True(construction.VelocityApplied); Assert.True(construction.OmegaApplied); PhysicsBody body = Assert.IsType(fixture.Record.PhysicsBody); Assert.True(body.InWorld); Assert.Equal(Cell, fixture.Record.FullCellId); // set_description field application from the frozen wire desc: // friction 0.5 passed gates 1+2; elasticity 0.05 inside the // set_elasticity clamp; state is the record's retail-transitioned // view; omega was the raw step-11 write. Assert.Equal(0.5f, body.Friction); Assert.Equal(0.05f, body.Elasticity); Assert.Equal(fixture.Record.FinalPhysicsState, body.State); Assert.Equal(new Vector3(0f, 0f, 0.25f), body.Omega); Assert.True(fixture.Lifetime.Physics.IsSpatialRoot(fixture.Record)); Assert.Equal(0, fixture.Conductor.CaptureOwnership().ActiveCount); Assert.False(fixture.Conductor.TryGetConstruction( fixture.Key, out _)); Assert.False(fixture.Lifetime.TryGetInitialCreateResidence( fixture.Record, out _)); Assert.Equal(0, fixture.Lifetime.CaptureOwnership() .InitialCreateResidenceLeaseCount); Assert.Equal(0, fixture.Lifetime.CaptureOwnership() .InitialCreateExecutorProgressCount); Assert.Equal(0, fixture.Lifetime.CaptureOwnership() .RemoteFirstEntryActiveCount); // Retrying with the now-stale residence token is a distinct, safe // no-op — nothing left to resume. Assert.Equal( RuntimeRemoteFirstEntryStatus.RejectedToken, fixture.Advance(out _)); } [Fact] public void ProjectileFlavorFullSequenceCompletesWithMissileState() { using var fixture = new Fixture( residentWorld: true, rawState: (uint)(PhysicsStateFlags.Gravity | PhysicsStateFlags.ReportCollisions | PhysicsStateFlags.Missile | PhysicsStateFlags.Inelastic | PhysicsStateFlags.PathClipped | PhysicsStateFlags.AlignPath)); // The Missile flag classified the Create to ProjectileAuthoritative // (RuntimeInitialCreateResidenceState.Begin) — the conductor accepts // that flavor through the identical stages. Assert.True(fixture.Lifetime.TryGetInitialCreateResidence( fixture.Record, out RuntimeInitialCreateResidenceLease lease)); Assert.Equal( RuntimeSetPositionOperationKind.ProjectileAuthoritative, lease.Route.OperationKind); RuntimeRemoteFirstEntryStatus status = fixture.Advance( out RuntimeInitialCreateExecutionReceipt receipt); Assert.Equal(RuntimeRemoteFirstEntryStatus.Completed, status); Assert.Equal(Cell, receipt.FullCellId); PhysicsBody body = Assert.IsType(fixture.Record.PhysicsBody); Assert.True(body.InWorld); Assert.True(body.State.HasFlag(PhysicsStateFlags.Missile)); Assert.Equal(fixture.Record.FinalPhysicsState, body.State); Assert.Equal(0, fixture.Conductor.CaptureOwnership().ActiveCount); } // --------------------------------------------------------------- // The three float gates, proven both ways on the pure construction // (docs/research/2026-08-02-set-description-float-gates.md is law) // --------------------------------------------------------------- [Theory] [InlineData(-1f, false, 0.95f)] [InlineData(0f, true, 0f)] [InlineData(0.5f, true, 0.5f)] [InlineData(1f, true, 1f)] [InlineData(1.5f, false, 0.95f)] // R2b: NaN is SKIPPED (body keeps its default) — the gates doc's // sanctioned deviation from retail's unordered-goes-to-apply codegen // quirk; see the friction comment in RuntimeRemoteBodyDescription. [InlineData(float.NaN, false, 0.95f)] public void FrictionGateAppliesOnlyInsideClosedUnitInterval( float wireFriction, bool expectedApplied, float expectedBodyFriction) { (PhysicsBody body, RuntimeRemoteBodyConstructionReceipt receipt) = ConstructDirect(friction: wireFriction); Assert.Equal(expectedApplied, receipt.FrictionApplied); Assert.Equal(expectedBodyFriction, body.Friction); Assert.Equal(body.Friction, receipt.Friction); } [Fact] public void FrictionAbsentOnWireTakesTheDescConstructorDefault() { // PhysicsDesc ctor 0x0051D4D0 seeds friction 0.95f; it passes the // gate, so an absent wire friction still records an APPLIED write. (PhysicsBody body, RuntimeRemoteBodyConstructionReceipt receipt) = ConstructDirect(friction: null); Assert.True(receipt.FrictionApplied); Assert.Equal(0.95f, body.Friction); } [Theory] [InlineData(0f, false)] [InlineData(0.5f, true)] [InlineData(-0.25f, true)] // R2: NaN lands in the apply bucket — matching retail's unordered case // exactly (gates doc conditional 3: JNP fires ONLY on exact equality // with 0.0f). [InlineData(float.NaN, true)] public void TranslucencyGateAppliesOnlyWhenNonZeroAndOriginalIsAlwaysRecorded( float wireTranslucency, bool expectedApplied) { (_, RuntimeRemoteBodyConstructionReceipt receipt) = ConstructDirect(translucency: wireTranslucency); // translucencyOriginal is written UNCONDITIONALLY (0x00515097, // before the gate); the live apply fires for every value except // exact 0.0f (gate 3's JNP fires only on equality). Assert.Equal(wireTranslucency, receipt.TranslucencyOriginal); Assert.Equal(expectedApplied, receipt.TranslucencyApplied); } [Fact] public void TranslucencyAbsentOnWireIsZeroOriginalAndNoLiveApply() { (_, RuntimeRemoteBodyConstructionReceipt receipt) = ConstructDirect(translucency: null); Assert.Equal(0f, receipt.TranslucencyOriginal); Assert.False(receipt.TranslucencyApplied); } [Theory] [InlineData(-0.5f, 0f)] [InlineData(0f, 0f)] [InlineData(0.05f, 0.05f)] [InlineData(0.1f, 0.1f)] [InlineData(0.2f, 0.1f)] // R2a: retail's FIRST x87 compare sends unordered to the zeroing arm // (0x0050FD51) — NaN -> 0f, NOT ACE's divergent NaN -> 0.1f. [InlineData(float.NaN, 0f)] public void ElasticityClampMatchesRetailSetter( float wireElasticity, float expectedBodyElasticity) { // CPhysicsObj::set_elasticity 0x0050FD40: < 0 -> 0; <= 0.1 -> value; // > 0.1 -> 0.1 (ACE PhysicsGlobals.MaxElasticity = 0.1f agrees). (PhysicsBody body, RuntimeRemoteBodyConstructionReceipt receipt) = ConstructDirect(elasticity: wireElasticity); Assert.Equal(expectedBodyElasticity, body.Elasticity); Assert.Equal(body.Elasticity, receipt.Elasticity); } // --------------------------------------------------------------- // Placement-frame-vs-movement branch (set_description step 4) // --------------------------------------------------------------- [Fact] public void MovementPayloadSuppressesPlacementFrameAndWritesAutonomy() { (PhysicsBody body, RuntimeRemoteBodyConstructionReceipt receipt) = ConstructDirect(movement: new PhysicsMovementData( RawData: new byte[] { 0x01 }, MotionState: null, IsAutonomous: true)); Assert.True(receipt.MovementBranch); Assert.True(receipt.LastMoveWasAutonomous); Assert.True(body.LastMoveWasAutonomous); Assert.False(receipt.PlacementFrameStaged); // No frame staged: the body's cell identity stays default-detached. Assert.Equal(0u, body.CellPosition.ObjCellId); Assert.False(body.InWorld); } [Fact] public void MovementFlagWithEmptyBufferTakesThePlacementBranch() { // R1: retail's branch discriminator is `movement_buffer != 0` — // PhysicsDesc::UnPack (0x0051DDD0) assigns the buffer only inside // `if (buff_length != 0)` (0051DE1F-0051DE2A), so a movement flag // with a ZERO-LENGTH buffer reaches set_description with a null // buffer and takes the PLACEMENT branch; the autonomy write (in the // movement else-branch only) never runs. Our parser materializes // exactly this wrapper shape (CreateObject.cs: non-null // PhysicsMovementData with empty RawData). IsAutonomous is set true // here deliberately — the BRANCH, never the wrapper's value, must // decide. (PhysicsBody body, RuntimeRemoteBodyConstructionReceipt receipt) = ConstructDirect(movement: new PhysicsMovementData( RawData: ReadOnlyMemory.Empty, MotionState: null, IsAutonomous: true)); Assert.False(receipt.MovementBranch); Assert.True(receipt.PlacementFrameStaged); Assert.Equal(Cell, body.CellPosition.ObjCellId); Assert.False(body.InWorld); Assert.False(receipt.LastMoveWasAutonomous); Assert.False(body.LastMoveWasAutonomous); } [Fact] public void NoMovementPayloadStagesTheDormantPlacementFrame() { (PhysicsBody body, RuntimeRemoteBodyConstructionReceipt receipt) = ConstructDirect(movement: null); Assert.False(receipt.MovementBranch); Assert.True(receipt.PlacementFrameStaged); Assert.Equal(Cell, body.CellPosition.ObjCellId); // SetPlacementFrameInternal is NOT enter_world — the submission owns // world residence. Assert.False(body.InWorld); Assert.False(body.LastMoveWasAutonomous); } // --------------------------------------------------------------- // Yield flavors + retry idempotency per stage // --------------------------------------------------------------- [Fact] public void AwaitingCollisionSourceRetriesThenResumesOnceSetupLands() { using var fixture = new Fixture(residentWorld: true, setupTableId: SetupId); fixture.CollisionSource.Status = PreparedAssetReadStatus.Missing; RuntimeRemoteFirstEntryStatus first = fixture.Advance(out _); Assert.Equal(RuntimeRemoteFirstEntryStatus.AwaitingCollisionSource, first); // No progress entry, no body, nothing mutated while the Setup is // outstanding. Assert.Equal(0, fixture.Conductor.CaptureOwnership().ActiveCount); Assert.Null(fixture.Record.PhysicsBody); RuntimeRemoteFirstEntryStatus second = fixture.Advance(out _); Assert.Equal(RuntimeRemoteFirstEntryStatus.AwaitingCollisionSource, second); Assert.True(fixture.CollisionSource.ReadCount >= 2); Assert.Equal(0, fixture.Conductor.CaptureOwnership().ActiveCount); Assert.Null(fixture.Record.PhysicsBody); fixture.CollisionSource.Status = PreparedAssetReadStatus.Loaded; Assert.Equal(RuntimeRemoteFirstEntryStatus.Completed, fixture.Advance(out RuntimeInitialCreateExecutionReceipt receipt)); Assert.Equal(Cell, receipt.FullCellId); Assert.NotNull(fixture.Record.PhysicsBody); } [Fact] public void DeferredPlacementRetainsOneBodyIdentityAcrossRetriesThenWakesAndCompletes() { // Non-resident world: the ordinary submission defers (the // destination landblock's collision world was never added), parking // the operation behind a Withdraw the conductor drains itself. using var fixture = new Fixture(residentWorld: false); RuntimeRemoteFirstEntryStatus first = fixture.Advance(out _); Assert.Equal(RuntimeRemoteFirstEntryStatus.AwaitingPlacement, first); PhysicsBody body = Assert.IsType(fixture.Record.PhysicsBody); Assert.False(body.InWorld); Assert.Equal(0u, fixture.Record.FullCellId); // The construction is still inspectable mid-flight, and the // set_description writes are already on the body. Assert.True(fixture.Conductor.TryGetConstruction( fixture.Key, out RuntimeRemoteBodyConstructionReceipt construction)); Assert.True(construction.FrictionApplied); Assert.Equal(0.5f, body.Friction); Assert.True(construction.VelocityApplied); Assert.Equal(new Vector3(1f, 2f, 0.5f), body.Velocity); Assert.True(construction.OmegaApplied); Assert.Equal(1, fixture.Conductor.CaptureOwnership().ActiveCount); // Retry idempotency: the SAME body identity survives every retry — // no duplicate construction, no re-submission churn. for (int i = 0; i < 3; i++) { Assert.Equal(RuntimeRemoteFirstEntryStatus.AwaitingPlacement, fixture.Advance(out _)); Assert.Same(body, fixture.Record.PhysicsBody); Assert.Equal(1, fixture.Conductor.CaptureOwnership().ActiveCount); } const ulong generation = 1UL; fixture.Lifetime.Physics.SetPosition.BeginCollisionGeneration( Landblock, generation); fixture.Lifetime.Physics.Engine.AddLandblock( Landblock, new TerrainSurface(new byte[81], new float[256]), Array.Empty(), Array.Empty(), worldOffsetX: 0f, worldOffsetY: 0f); fixture.Lifetime.Physics.SetPosition.CommitCollisionGeneration( Landblock, generation, ready: true); Assert.Equal(RuntimeRemoteFirstEntryStatus.Completed, fixture.Advance(out RuntimeInitialCreateExecutionReceipt receipt)); Assert.Same(body, fixture.Record.PhysicsBody); Assert.True(body.InWorld); Assert.Equal(Cell, receipt.FullCellId); Assert.Equal(Cell, fixture.Record.FullCellId); Assert.Equal(0, fixture.Conductor.CaptureOwnership().ActiveCount); } [Fact] public void ReentrantAdvanceDuringCollisionCallbackFailsClosedWithContentionAndOuterCallStillCompletes() { using var fixture = new Fixture(residentWorld: true); bool reentered = false; RuntimeRemoteFirstEntryStatus? innerStatus = null; fixture.Lifetime.Physics.Engine.TransitionCellCollisionTestHook = (_, phase, _, observed) => { if (!reentered && phase is TransitionCellCollisionPhase.Environment) { reentered = true; innerStatus = fixture.Advance(out _); } return observed; }; RuntimeRemoteFirstEntryStatus outerStatus = fixture.Advance( out RuntimeInitialCreateExecutionReceipt receipt); Assert.True(reentered); Assert.Equal(RuntimeRemoteFirstEntryStatus.Contention, innerStatus); Assert.Equal(RuntimeRemoteFirstEntryStatus.Completed, outerStatus); Assert.Equal(Cell, receipt.FullCellId); Assert.Equal(0, fixture.Conductor.CaptureOwnership().ActiveCount); } [Fact] public void AwaitingReceiptAcknowledgementWhileAnotherEntityHoldsTheFifoHeadThenResumes() { using var fixture = new Fixture(residentWorld: true); (RuntimeEntityRecord other, RuntimePlacementProjectionToken otherToken) = BeginPendingOrdinaryPlacement(fixture, 0x70099001u); // Our submission commits, but its Place sits BEHIND the other // entity's unacknowledged receipt in the one ordered FIFO. RuntimeRemoteFirstEntryStatus first = fixture.Advance(out _); Assert.Equal( RuntimeRemoteFirstEntryStatus.AwaitingReceiptAcknowledgement, first); Assert.True(fixture.Record.PhysicsBody!.InWorld); RuntimeRemoteFirstEntryStatus second = fixture.Advance(out _); Assert.Equal( RuntimeRemoteFirstEntryStatus.AwaitingReceiptAcknowledgement, second); Assert.True(fixture.Lifetime.Physics.SetPosition .AcknowledgeProjection(otherToken)); Assert.Equal(RuntimeRemoteFirstEntryStatus.Completed, fixture.Advance(out RuntimeInitialCreateExecutionReceipt receipt)); Assert.Equal(Cell, receipt.FullCellId); _ = other; } [Fact] public void DeleteWhileAwaitingReceiptAcknowledgementAbandonsInsteadOfRetryingForeverAndConverges() { // M2a — the exact C3a-shaped scenario: the placement has ALREADY // committed (body in world) but acknowledgement is blocked behind // another entity's unacknowledged Place. The delete-path mechanism // (Physics.SetPosition.Forget with releasePreparedMover — the exact // inner call TryAcceptDelete makes) rewrites our still-pending Place // slot to Discard with a bumped revision, so the cached // progress.Projection can never match the FIFO head again. Without // the shared IsAcknowledgementStillPending re-check, Advance would // report AwaitingReceiptAcknowledgement forever and ownership would // never converge. using var fixture = new Fixture(residentWorld: true); (RuntimeEntityRecord other, RuntimePlacementProjectionToken otherToken) = BeginPendingOrdinaryPlacement(fixture, 0x70099002u); Assert.Equal( RuntimeRemoteFirstEntryStatus.AwaitingReceiptAcknowledgement, fixture.Advance(out _)); Assert.Equal(1, fixture.Conductor.CaptureOwnership().ActiveCount); Assert.True(fixture.Record.PhysicsBody!.InWorld); Assert.True(fixture.Lifetime.TryGetInitialCreateResidence( fixture.Record, out _)); RuntimePlacementCancellationReceipt cancellation = fixture.Lifetime .Physics.SetPosition.Forget( fixture.Record, releasePreparedMover: true); fixture.Lifetime.Physics.SetPosition.PublishCancellation(cancellation); Assert.Equal(RuntimeRemoteFirstEntryStatus.RejectedAuthority, fixture.Advance(out _)); Assert.Equal(0, fixture.Conductor.CaptureOwnership().ActiveCount); // The unrelated entity's own placement is untouched and still // acknowledgeable — the abandonment never reached past our own // entity's projection. Assert.True(fixture.Lifetime.Physics.SetPosition .AcknowledgeProjection(otherToken)); _ = other; } [Fact] public void AwaitingContinuationPlacementPropagatesExecutorYieldThenResumes() { using var fixture = new Fixture(residentWorld: true); // A fresh Position arrives while the initial residence is still // pending — enqueued as a continuation, classified only at drain. WorldSession.EntityPositionUpdate update = new( fixture.Record.ServerGuid, new CreateObject.ServerPosition(Cell, 40f, 20f, 7f, 1f, 0f, 0f, 0f), Velocity: null, PlacementId: 2, IsGrounded: true, InstanceSequence: 1, PositionSequence: 2, TeleportSequence: 1, ForcePositionSequence: 0); Assert.True(fixture.Lifetime.TryApplyPosition( update, isLocalPlayer: false, forcePositionRotation: null, currentLocalVelocity: null, projectionRequiresTeleportHook: false, acknowledgeProjection: null, out PositionTimestampDisposition disposition, out _, out _)); Assert.Equal(PositionTimestampDisposition.Apply, disposition); RuntimeRemoteFirstEntryStatus status = fixture.Advance(out _); Assert.Equal( RuntimeRemoteFirstEntryStatus.AwaitingContinuationPlacement, status); // The conductor's own sequence reached its terminal Acknowledged // stage; the retained progress entry lets a retry skip straight to // re-calling Execute. Assert.Equal(1, fixture.Conductor.CaptureOwnership().ActiveCount); RuntimeEntityKey key = fixture.Key; Assert.True(fixture.Lifetime.InitialCreateExecution .TryGetPendingContinuationPlacement( key, out RuntimeEntityPlacementToken placement)); Assert.True(fixture.Lifetime.InitialCreateExecution .TryGetPendingContinuationRoute( key, out RuntimeAuthoritativePositionRoute route)); CompleteOrdinaryPlacement(fixture, placement, route); RuntimeRemoteFirstEntryStatus resumed = fixture.Advance( out RuntimeInitialCreateExecutionReceipt receipt); Assert.Equal(RuntimeRemoteFirstEntryStatus.Completed, resumed); Assert.Contains(receipt.Trace, a => a.Kind is RuntimeInitialCreateExecutedActionKind.Position); Assert.Equal(0, fixture.Conductor.CaptureOwnership().ActiveCount); } // --------------------------------------------------------------- // Domain refusal + never-clobber // --------------------------------------------------------------- [Fact] public void LocalPlayerLeaseIsRefusedWithoutTrackingAnything() { using var fixture = new Fixture(residentWorld: true, isLocalPlayer: true); Assert.Equal(RuntimeRemoteFirstEntryStatus.RejectedToken, fixture.Advance(out _)); Assert.Equal(0, fixture.Conductor.CaptureOwnership().ActiveCount); Assert.Null(fixture.Record.PhysicsBody); // The lease itself is untouched — the C3a conductor still owns it. Assert.True(fixture.Lifetime.TryGetInitialCreateResidence( fixture.Record, out RuntimeInitialCreateResidenceLease lease)); Assert.Equal(fixture.Lease.Token, lease.Token); } [Fact] public void ForeignBodyBoundOutOfBandAbandonsWithoutClobbering() { using var fixture = new Fixture(residentWorld: true); var foreign = new PhysicsBody { Position = new Vector3(1f, 2f, 3f), State = fixture.Record.FinalPhysicsState, }; fixture.Lifetime.Entities.SetPhysicsBody(fixture.Record, foreign); Assert.Equal(RuntimeRemoteFirstEntryStatus.RejectedAuthority, fixture.Advance(out _)); // The foreign body was never replaced or mutated toward ours. Assert.Same(foreign, fixture.Record.PhysicsBody); Assert.Equal(0, fixture.Conductor.CaptureOwnership().ActiveCount); } // --------------------------------------------------------------- // Delete / reset mid-flight convergence // --------------------------------------------------------------- [Fact] public void DeleteWhileAwaitingPlacementConvergesAutomaticallyThroughTheRetirementFanOut() { using var fixture = new Fixture(residentWorld: false); Assert.Equal(RuntimeRemoteFirstEntryStatus.AwaitingPlacement, fixture.Advance(out _)); Assert.Equal(1, fixture.Conductor.CaptureOwnership().ActiveCount); DeleteEntity(fixture); Assert.Null(fixture.Record.Key); // TryAcceptDelete's ForgetInitialCreateResidence fired the multicast // retirement notification synchronously — this conductor's Forget is // bound into that same fan-out, so convergence is complete before // delete returns. Assert.Equal(0, fixture.Conductor.CaptureOwnership().ActiveCount); // Retrying Advance afterward is a safe, distinct no-op. Assert.Equal(RuntimeRemoteFirstEntryStatus.RejectedToken, fixture.Advance(out _)); } [Fact] public void SessionClearMidFlightConvergesOwnership() { using var fixture = new Fixture(residentWorld: false); Assert.Equal(RuntimeRemoteFirstEntryStatus.AwaitingPlacement, fixture.Advance(out _)); Assert.Equal(1, fixture.Conductor.CaptureOwnership().ActiveCount); _ = fixture.Lifetime.BeginSessionClear(); Assert.Equal(0, fixture.Conductor.CaptureOwnership().ActiveCount); Assert.Equal(0, fixture.Lifetime.CaptureOwnership() .RemoteFirstEntryActiveCount); } [Fact] public void DeleteAndSameGuidReincarnationStartsAFreshSequence() { using var fixture = new Fixture(residentWorld: false); Assert.Equal(RuntimeRemoteFirstEntryStatus.AwaitingPlacement, fixture.Advance(out _)); RuntimeEntityKey staleKey = fixture.Key; uint guid = fixture.Record.ServerGuid; DeleteEntity(fixture); Assert.Equal(0, fixture.Conductor.CaptureOwnership().ActiveCount); RuntimeEntityRecord reincarnated = fixture.Lifetime .RegisterEntityWithInitialResidence( Spawn(guid, incarnation: 2), isLocalPlayer: false) .Canonical!; Assert.NotEqual(staleKey, reincarnated.Key!.Value); Assert.True(fixture.Lifetime.TryGetInitialCreateResidence( reincarnated, out RuntimeInitialCreateResidenceLease freshLease)); fixture.Record = reincarnated; fixture.Lease = freshLease; Assert.Equal(RuntimeRemoteFirstEntryStatus.AwaitingPlacement, fixture.Advance(out _)); const ulong generation = 1UL; fixture.Lifetime.Physics.SetPosition.BeginCollisionGeneration( Landblock, generation); fixture.Lifetime.Physics.Engine.AddLandblock( Landblock, new TerrainSurface(new byte[81], new float[256]), Array.Empty(), Array.Empty(), worldOffsetX: 0f, worldOffsetY: 0f); fixture.Lifetime.Physics.SetPosition.CommitCollisionGeneration( Landblock, generation, ready: true); RuntimeRemoteFirstEntryStatus status = fixture.Advance( out RuntimeInitialCreateExecutionReceipt receipt); Assert.Equal(RuntimeRemoteFirstEntryStatus.Completed, status); Assert.Equal(Cell, receipt.FullCellId); Assert.NotNull(reincarnated.PhysicsBody); Assert.True(reincarnated.PhysicsBody!.InWorld); Assert.Equal(0, fixture.Conductor.CaptureOwnership().ActiveCount); } // --------------------------------------------------------------- // Helpers // --------------------------------------------------------------- private static (PhysicsBody Body, RuntimeRemoteBodyConstructionReceipt Receipt) ConstructDirect( float? friction = 0.5f, float? elasticity = 0.05f, float? translucency = null, PhysicsMovementData? movement = null) { var record = new RuntimeEntityRecordFactory(); RuntimeEntityRecord canonical = record.Lifetime .RegisterEntity( Spawn( 0x70090077u, incarnation: 1, friction: friction, elasticity: elasticity, translucency: translucency, movement: movement)) .Canonical!; var command = new RuntimeSetPositionCommand( new PhysicsSetPositionRequest( new Vector3(1f, 2f, 3f), Quaternion.Identity, Cell, new Vector3(1f, 2f, 3f), ImmutableArray.Empty, Scale: 1f, StepUpHeight: 0f, StepDownHeight: 0f, canonical.FinalPhysicsState, ObjectInfoState.None, canonical.Key?.LocalEntityId ?? 0u, PhysicsPlacementClass.Ordinary, PhysicsSetPositionFlags.Placement | PhysicsSetPositionFlags.Slide), RuntimeSetPositionOperationKind.RemoteAuthoritative, GameTime: 1d, ExpectedVelocityAuthorityVersion: 0UL); PhysicsBody body = RuntimeRemoteBodyDescription.Construct( canonical, canonical.Snapshot.Physics, command, out RuntimeRemoteBodyConstructionReceipt receipt); record.Dispose(); return (body, receipt); } private sealed class RuntimeEntityRecordFactory : IDisposable { internal RuntimeEntityObjectLifetime Lifetime { get; } = new(); internal RuntimeEntityRecordFactory() { var generation = new RuntimeGenerationToken(1UL); Lifetime.BindEventContext(() => generation, static () => 1UL); } public void Dispose() => Lifetime.Dispose(); } private static (RuntimeEntityRecord Record, RuntimePlacementProjectionToken Token) BeginPendingOrdinaryPlacement(Fixture fixture, uint guid) { RuntimeEntityRecord record = fixture.Lifetime.RegisterEntity( Spawn(guid, incarnation: 1)).Canonical!; var body = new PhysicsBody { Position = new Vector3(50f, 50f, 3f), Orientation = Quaternion.Identity, State = record.FinalPhysicsState, }; body.SnapToCell(Cell, body.Position, body.Position); fixture.Lifetime.Entities.SetPhysicsBody(record, body); RuntimeEntityPlacementToken placement = fixture.Lifetime.Physics .SetPosition.BeginAuthoredPlacement( record, record.PositionAuthorityVersion, RuntimeSetPositionOperationKind.RemoteAuthoritative); Assert.True(placement.IsValid); var preparation = new RuntimeSetPositionMoverPreparation( RuntimeSetPositionMoverSetup.ResolvedAbsent, RuntimeSetPositionOperationKind.RemoteAuthoritative, GameTime: 1d, PhysicsPlacementClass.Ordinary, PhysicsSetPositionFlags.Placement | PhysicsSetPositionFlags.Slide); Assert.Equal(RuntimeSetPositionMoverPreparationStatus.Prepared, fixture.Lifetime.Physics.SetPosition.PrepareMover( placement, preparation, out RuntimeSetPositionCommand command)); RuntimeSetPositionOutcome outcome = fixture.Lifetime.Physics.SetPosition .SubmitPreparedPlacement(placement, command); Assert.Equal(RuntimeSetPositionStatus.CommittedHostAcknowledgementPending, outcome.Status); return (record, outcome.Projection); } private static void CompleteOrdinaryPlacement( Fixture fixture, in RuntimeEntityPlacementToken placement, in RuntimeAuthoritativePositionRoute route) { var preparation = new RuntimeSetPositionMoverPreparation( RuntimeSetPositionMoverSetup.ResolvedAbsent, route.OperationKind, GameTime: 1d, PhysicsPlacementClass.Ordinary, route.SetPositionFlags); Assert.Equal(RuntimeSetPositionMoverPreparationStatus.Prepared, fixture.Lifetime.Physics.SetPosition.PrepareMover( placement, preparation, out RuntimeSetPositionCommand command)); RuntimeSetPositionOutcome outcome = fixture.Lifetime.Physics.SetPosition .SubmitPreparedPlacement(placement, command); Assert.Equal(RuntimeSetPositionStatus.CommittedHostAcknowledgementPending, outcome.Status); Assert.True(fixture.Lifetime.Physics.SetPosition .AcknowledgeProjection(outcome.Projection)); } private static void DeleteEntity(Fixture fixture) { Assert.True(fixture.Lifetime.TryAcceptDelete( new DeleteObject.Parsed( fixture.Record.ServerGuid, fixture.Record.Incarnation), isLocalPlayer: false, removeRetainedObject: false, out RuntimeEntityDeleteAcceptance acceptance)); fixture.Lifetime.CompleteAcceptedDelete(acceptance); Assert.Null(fixture.Lifetime.RetireCanonicalOnly(fixture.Record)); } private static WorldSession.EntitySpawn Spawn( uint guid, ushort incarnation, bool includePosition = true, uint setupTableId = 0u, uint rawState = (uint)(PhysicsStateFlags.Gravity | PhysicsStateFlags.ReportCollisions), float? friction = 0.5f, float? elasticity = 0.05f, float? translucency = null, PhysicsMovementData? movement = null) { CreateObject.ServerPosition? position = includePosition ? new CreateObject.ServerPosition(Cell, 1f, 2f, 3f, 1f, 0f, 0f, 0f) : null; var timestamps = new PhysicsTimestamps( Position: 1, Movement: 1, State: 1, Vector: 1, Teleport: 0, ServerControlledMove: 1, ForcePosition: 0, ObjDesc: 1, Instance: incarnation); var physics = new PhysicsSpawnData( RawState: rawState, Position: position, Movement: movement, AnimationFrame: null, SetupTableId: setupTableId == 0u ? null : setupTableId, MotionTableId: 0x09000001u, SoundTableId: null, PhysicsScriptTableId: null, Parent: null, Children: null, Scale: 1f, Friction: friction, Elasticity: elasticity, Translucency: translucency, Velocity: new Vector3(1f, 2f, 0.5f), Acceleration: null, AngularVelocity: new Vector3(0f, 0f, 0.25f), DefaultScriptType: null, DefaultScriptIntensity: null, Timestamps: timestamps); return new WorldSession.EntitySpawn( Guid: guid, Position: position, SetupTableId: setupTableId == 0u ? null : setupTableId, AnimPartChanges: Array.Empty(), TextureChanges: Array.Empty(), SubPalettes: Array.Empty(), BasePaletteId: null, ObjScale: 1f, Name: "remote-entry-fixture", ItemType: null, MotionState: null, MotionTableId: 0x09000001u, PhysicsState: physics.RawState, ObjectDescriptionFlags: 0x8u, Friction: friction, Elasticity: elasticity, InstanceSequence: incarnation, MovementSequence: 1, ServerControlSequence: 1, PositionSequence: 1, Physics: physics); } private sealed class FakeCollisionSource( uint expectedSetupTableId, FlatSetupCollision setup) : IPreparedCollisionSource { internal int ReadCount { get; private set; } internal PreparedAssetReadStatus Status { get; set; } = PreparedAssetReadStatus.Loaded; public PreparedAssetPresence ProbeCollision( PakAssetType type, uint sourceFileId) => PreparedAssetPresence.Available; public PreparedCollisionReadResult ReadSetupCollision( uint sourceFileId, CancellationToken cancellationToken = default) { ReadCount++; Assert.Equal(expectedSetupTableId, sourceFileId); return Status switch { PreparedAssetReadStatus.Loaded => PreparedCollisionReadResult.Loaded(setup), PreparedAssetReadStatus.Corrupt => PreparedCollisionReadResult.Corrupt, _ => PreparedCollisionReadResult.Missing, }; } public PreparedCollisionReadResult ReadGfxObjCollision( uint sourceFileId, CancellationToken cancellationToken = default) => throw new NotSupportedException( "Only ReadSetupCollision is exercised by these tests."); public PreparedCollisionReadResult ReadCellStructureCollision( uint sourceFileId, CancellationToken cancellationToken = default) => throw new NotSupportedException( "Only ReadSetupCollision is exercised by these tests."); public PreparedCollisionReadResult ReadEnvCellTopology( uint sourceFileId, CancellationToken cancellationToken = default) => throw new NotSupportedException( "Only ReadSetupCollision is exercised by these tests."); public PreparedCollisionSourceStats CollisionStats => default; public void Dispose() { } } private sealed class Fixture : IDisposable { internal Fixture( bool residentWorld, uint setupTableId = 0u, uint rawState = (uint)(PhysicsStateFlags.Gravity | PhysicsStateFlags.ReportCollisions), bool isLocalPlayer = false) { if (residentWorld) { 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); Lifetime = new RuntimeEntityObjectLifetime(engine); } else { Lifetime = new RuntimeEntityObjectLifetime(); } var generation = new RuntimeGenerationToken(1UL); Lifetime.BindEventContext(() => generation, static () => 1UL); // 670f307c: CreateObject frames are landblock-local, so a remote // conductor's PrepareMover resolves them through Runtime's world // frame (RuntimeSetPositionState.PrepareMover:1526-1544) and // returns RetrySetupUnavailable until that frame exists. Only the // accepted local-player Create publishes it // (RuntimeEntityObjectLifetime.RegisterEntityCore:558-570 -> // RuntimePhysicsState.ObserveLocalWorldFrame) — production always // registers the player before any broadcast Create is driven. // Model that ambient world fact here, alongside the resident // terrain above, rather than registering a second entity that // would perturb every ownership-ledger assertion in this class. Lifetime.Physics.ObserveLocalWorldFrame( Cell, teleportAdvanced: false); // The SAME conductor instance RuntimeEntityObjectLifetime itself // constructs and wires into the residence's multicast retirement // fan-out and BeginSessionClear — never a standalone copy — so // these tests exercise the real production wiring. Conductor = Lifetime.RemoteFirstEntry; Record = Lifetime.RegisterEntityWithInitialResidence( Spawn( 0x70090002u, incarnation: 1, setupTableId: setupTableId, rawState: rawState), isLocalPlayer).Canonical!; Assert.True(Lifetime.TryGetInitialCreateResidence( Record, out RuntimeInitialCreateResidenceLease lease)); Lease = lease; CollisionSource = new FakeCollisionSource( setupTableId, new FlatSetupCollision( ImmutableArray.Empty, [new FlatCollisionSphere(Vector3.Zero, 0.48f)], height: 0f, radius: 0f, stepUpHeight: 0.4f, stepDownHeight: 0.4f)); } internal RuntimeEntityObjectLifetime Lifetime { get; } internal RuntimeRemoteFirstEntryState Conductor { get; } internal RuntimeEntityRecord Record { get; set; } internal RuntimeInitialCreateResidenceLease Lease { get; set; } internal FakeCollisionSource CollisionSource { get; } internal RuntimeEntityKey Key => Record.Key!.Value; internal RuntimeRemoteFirstEntryStatus Advance( out RuntimeInitialCreateExecutionReceipt receipt) => Advance(out receipt, out _); internal RuntimeRemoteFirstEntryStatus Advance( out RuntimeInitialCreateExecutionReceipt receipt, out RuntimeRemoteBodyConstructionReceipt construction) => Conductor.Advance( Record, Lease.Token, CollisionSource, gameTime: 10d, NoContact, out receipt, out construction); public void Dispose() => Lifetime.Dispose(); } }