using System.Numerics; using AcDream.Core.Physics; using AcDream.Runtime.Entities; using AcDream.Runtime.Physics; namespace AcDream.Runtime.Tests.Physics; public sealed partial class RuntimeCollisionPrefixQuiescenceTests { [Fact] public void ActivationWaitsForExactWithdrawAndPlaceReceipts() { using var fixture = new Fixture(bindGeneration: true); RuntimeEntityRecord record = fixture.Add( 0x70003101u, 1, CellP, new Vector3(11f, 40f, 0f)); RuntimeSetPositionOutcome seeded = fixture.Place( record, CellP, new Vector3(11.5f, 40f, 0f)); Assert.True(fixture.Lifetime.Physics.SetPosition .AcknowledgeProjection(seeded.Projection)); RuntimePhysicsState physics = fixture.Lifetime.Physics; RuntimeCollisionAdmission admission = physics.BeginCollisionAdmission(PrefixP); using PreparedLandblockCollisionGeneration prepared = PrepareSealedMutation(physics, admission, PrefixP); int committedNotifications = 0; physics.CollisionGenerationCommitted += _ => committedNotifications++; RuntimeCollisionGenerationCommit first = physics.CommitCollisionGeneration(admission, prepared); Assert.False(first.EngineCommitted); Assert.False(first.Completed); Assert.False(physics.IsSpatialRoot(record)); Assert.True(physics.SetPosition.TryPeekProjection( out RuntimePlacementProjectionSnapshot withdrawn)); Assert.Equal(RuntimePlacementProjectionKind.Withdraw, withdrawn.Kind); Assert.True(physics.SetPosition.AcknowledgeProjection(withdrawn.Token)); _ = SealMutation(physics, admission, prepared); RuntimeCollisionGenerationCommit transferred = physics.CommitCollisionGeneration(admission, prepared); Assert.True(transferred.EngineCommitted); Assert.False(transferred.Completed); Assert.True(physics.SetPosition.TryPeekProjection( out RuntimePlacementProjectionSnapshot restored)); Assert.Equal(RuntimePlacementProjectionKind.Place, restored.Kind); Assert.True(physics.SetPosition.AcknowledgeProjection(restored.Token)); RuntimeCollisionGenerationCommit completed = physics.CommitCollisionGeneration(admission, prepared); Assert.True(completed.EngineCommitted); Assert.True(completed.Completed); Assert.True(physics.IsSpatialRoot(record)); Assert.Equal(1, committedNotifications); Assert.Equal(0, physics.CaptureOwnership().CollisionPrefixMutationCount); Assert.Equal(0, physics.CaptureOwnership().CollisionPrefixQuiescenceCount); } [Fact] public void DemotionParksOnlyIndoorResidentsAndLeavesOutdoorPresentationLive() { using var fixture = new Fixture(bindGeneration: true); RuntimeEntityRecord outdoor = fixture.Add( 0x70003102u, 1, CellP, new Vector3(12f, 41f, 0f)); RuntimeEntityRecord indoor = fixture.Add( 0x70003103u, 1, PrefixP | 0x0100u, new Vector3(13f, 41f, 0f)); RuntimeCollisionMutationResult first = fixture.Lifetime.Physics.DemoteCollisionToTerrain(PrefixP); Assert.False(first.Completed); Assert.True(fixture.Lifetime.Physics.IsSpatialRoot(outdoor)); Assert.False(fixture.Lifetime.Physics.IsSpatialRoot(indoor)); Assert.True(fixture.Lifetime.Physics.SetPosition.TryPeekProjection( out RuntimePlacementProjectionSnapshot withdrawal)); Assert.Equal(indoor.Key, withdrawal.Token.Entity); Assert.True(fixture.Lifetime.Physics.SetPosition .AcknowledgeProjection(withdrawal.Token)); RuntimeCollisionMutationResult completed = fixture.Lifetime.Physics.DemoteCollisionToTerrain(PrefixP); Assert.True(completed.Completed); Assert.True(completed.Ready); Assert.True(fixture.Lifetime.Physics.IsSpatialRoot(outdoor)); Assert.False(fixture.Lifetime.Physics.IsSpatialRoot(indoor)); Assert.False(fixture.Lifetime.Physics.SetPosition.TryPeekProjection(out _)); } [Fact] public void WithdrawalLeavesResidentUnboundUntilLaterGenerationWakesIt() { using var fixture = new Fixture(bindGeneration: true); RuntimeEntityRecord record = fixture.Add( 0x70003104u, 1, CellP, new Vector3(14f, 42f, 0f)); RuntimeSetPositionOutcome seeded = fixture.Place( record, CellP, new Vector3(14.5f, 42f, 0f)); Assert.True(fixture.Lifetime.Physics.SetPosition .AcknowledgeProjection(seeded.Projection)); RuntimePhysicsState physics = fixture.Lifetime.Physics; RuntimeCollisionMutationResult withdrawal = physics.WithdrawCollision(PrefixP); Assert.False(withdrawal.Completed); Assert.True(physics.SetPosition.TryPeekProjection( out RuntimePlacementProjectionSnapshot removed)); Assert.True(physics.SetPosition.AcknowledgeProjection(removed.Token)); withdrawal = physics.WithdrawCollision(PrefixP); Assert.True(withdrawal.Completed); Assert.False(withdrawal.Ready); Assert.False(physics.IsSpatialRoot(record)); RuntimeCollisionAdmission admission = physics.BeginCollisionAdmission(PrefixP); using PreparedLandblockCollisionGeneration prepared = PrepareSealedMutation(physics, admission, PrefixP); RuntimeCollisionGenerationCommit pending = physics.CommitCollisionGeneration(admission, prepared); Assert.False(pending.Completed); _ = SealMutation(physics, admission, prepared); RuntimeCollisionGenerationCommit completed = physics.CommitCollisionGeneration(admission, prepared); Assert.True(completed.EngineCommitted); Assert.False(completed.Completed); Assert.True(physics.SetPosition.TryPeekProjection( out RuntimePlacementProjectionSnapshot restored)); Assert.Equal(RuntimePlacementProjectionKind.Place, restored.Kind); Assert.True(physics.SetPosition.AcknowledgeProjection(restored.Token)); completed = physics.CommitCollisionGeneration(admission, prepared); Assert.True(completed.Completed); Assert.True(physics.IsSpatialRoot(record)); } [Theory] [InlineData(false)] [InlineData(true)] public void SessionResetClearsPreAndPostEngineMutationDebt(bool postEngine) { using var fixture = new Fixture(bindGeneration: true); RuntimeEntityRecord record = fixture.Add( 0x70003105u, 1, CellP, new Vector3(15f, 43f, 0f)); RuntimeSetPositionOutcome seeded = fixture.Place( record, CellP, new Vector3(15.5f, 43f, 0f)); Assert.True(fixture.Lifetime.Physics.SetPosition .AcknowledgeProjection(seeded.Projection)); RuntimePhysicsState physics = fixture.Lifetime.Physics; RuntimeCollisionAdmission admission = physics.BeginCollisionAdmission(PrefixP); using PreparedLandblockCollisionGeneration prepared = PrepareSealedMutation(physics, admission, PrefixP); Assert.False(physics.CommitCollisionGeneration( admission, prepared).Completed); if (postEngine) { Assert.True(physics.SetPosition.TryPeekProjection( out RuntimePlacementProjectionSnapshot withdrawal)); Assert.True(physics.SetPosition.AcknowledgeProjection( withdrawal.Token)); _ = SealMutation(physics, admission, prepared); RuntimeCollisionGenerationCommit transferred = physics.CommitCollisionGeneration(admission, prepared); Assert.True(transferred.EngineCommitted); Assert.False(transferred.Completed); } _ = fixture.Lifetime.BeginSessionClear(); RuntimePhysicsOwnershipSnapshot ownership = physics.CaptureOwnership(); Assert.Equal(0, ownership.CollisionPrefixMutationCount); Assert.Equal(0, ownership.CommittedCollisionPrefixMutationCount); Assert.Equal(0, ownership.CollisionPrefixQuiescenceCount); Assert.Equal(0, ownership.PendingCollisionPrefixProjectionCount); Assert.Equal(0, ownership.CollisionAdmissionCount); } [Fact] public void CancelledActivationCannotCommitWhileRestoreAckIsPending() { using var fixture = new Fixture(bindGeneration: true); RuntimePhysicsState physics = fixture.Lifetime.Physics; RuntimeCollisionAdmission baselineAdmission = physics.BeginCollisionAdmission(PrefixP); using (PreparedLandblockCollisionGeneration baseline = PrepareSealedMutation(physics, baselineAdmission, PrefixP)) { Assert.False(physics.CommitCollisionGeneration( baselineAdmission, baseline).Completed); _ = SealMutation(physics, baselineAdmission, baseline); Assert.True(physics.CommitCollisionGeneration( baselineAdmission, baseline).Completed); } RuntimeEntityRecord record = fixture.Add( 0x70003106u, 1, CellP, new Vector3(16f, 44f, 0f)); RuntimeSetPositionOutcome seeded = fixture.Place( record, CellP, new Vector3(16.5f, 44f, 0f)); Assert.True(physics.SetPosition.AcknowledgeProjection( seeded.Projection)); RuntimeCollisionAdmission admission = physics.BeginCollisionAdmission(PrefixP); using PreparedLandblockCollisionGeneration prepared = PrepareSealedMutation(physics, admission, PrefixP); RuntimeCollisionGenerationCommit parked = physics.CommitCollisionGeneration(admission, prepared); Assert.False(parked.EngineCommitted); Assert.True(physics.SetPosition.TryPeekProjection( out RuntimePlacementProjectionSnapshot withdrawal)); Assert.True(physics.SetPosition.AcknowledgeProjection(withdrawal.Token)); Assert.False(physics.CancelCollisionGeneration(admission, prepared)); RuntimeCollisionGenerationCommit forbidden = physics.CommitCollisionGeneration(admission, prepared); Assert.False(forbidden.EngineCommitted); Assert.False(forbidden.Completed); Assert.True(physics.SetPosition.TryPeekProjection( out RuntimePlacementProjectionSnapshot restored)); Assert.Equal(RuntimePlacementProjectionKind.Place, restored.Kind); Assert.True(physics.SetPosition.AcknowledgeProjection(restored.Token)); Assert.True(physics.CancelCollisionGeneration(admission, prepared)); Assert.True(physics.IsSpatialRoot(record)); Assert.True(physics.Engine.IsLandblockTerrainResident(PrefixP)); Assert.Equal(0, physics.CaptureOwnership().CollisionPrefixMutationCount); Assert.Equal(0, physics.CaptureOwnership().CollisionPrefixQuiescenceCount); Assert.Equal(0, physics.CaptureOwnership().CollisionAdmissionCount); } [Fact] public void SupersededAdmissionCancellationRestoresExactBaselineGeneration() { using var fixture = new Fixture(bindGeneration: true); RuntimePhysicsState physics = fixture.Lifetime.Physics; RuntimeCollisionAdmission baseline = physics.BeginCollisionAdmission(PrefixP); using (PreparedLandblockCollisionGeneration preparedBaseline = PrepareSealedMutation(physics, baseline, PrefixP)) { Assert.False(physics.CommitCollisionGeneration( baseline, preparedBaseline).Completed); Assert.True(physics.CommitCollisionGeneration( baseline, preparedBaseline).Completed); } RuntimeEntityRecord record = fixture.Add( 0x70003107u, 1, CellP, new Vector3(17f, 45f, 0f)); RuntimeSetPositionOutcome seeded = fixture.Place( record, CellP, new Vector3(17.5f, 45f, 0f)); Assert.True(physics.SetPosition.AcknowledgeProjection( seeded.Projection)); RuntimeCollisionAdmission admissionA = physics.BeginCollisionAdmission(PrefixP); using PreparedLandblockCollisionGeneration preparedA = PrepareSealedMutation(physics, admissionA, PrefixP); RuntimeCollisionAdmission admissionB = physics.BeginCollisionAdmission(PrefixP); Assert.Equal(baseline.Generation, admissionB.PreviousGeneration); using PreparedLandblockCollisionGeneration preparedB = PrepareSealedMutation(physics, admissionB, PrefixP); RuntimeCollisionGenerationCommit parked = physics.CommitCollisionGeneration(admissionB, preparedB); Assert.False(parked.EngineCommitted); Assert.True(physics.SetPosition.TryPeekProjection( out RuntimePlacementProjectionSnapshot withdrawal)); Assert.False(physics.CancelCollisionGeneration(admissionB, preparedB)); Assert.True(physics.SetPosition.AcknowledgeProjection(withdrawal.Token)); Assert.False(physics.CancelCollisionGeneration(admissionB, preparedB)); Assert.True(physics.SetPosition.TryPeekProjection( out RuntimePlacementProjectionSnapshot restored)); Assert.Equal(RuntimePlacementProjectionKind.Place, restored.Kind); Assert.True(physics.SetPosition.AcknowledgeProjection(restored.Token)); Assert.True(physics.CancelCollisionGeneration(admissionB, preparedB)); Assert.True(physics.IsSpatialRoot(record)); Assert.Equal(restored.Token.ExactCellId, record.FullCellId); Assert.True(physics.Engine.IsLandblockTerrainResident(PrefixP)); RuntimePhysicsOwnershipSnapshot ownership = physics.CaptureOwnership(); Assert.Equal(0, ownership.CollisionPrefixMutationCount); Assert.Equal(0, ownership.CollisionPrefixQuiescenceCount); Assert.Equal(0, ownership.CollisionAdmissionCount); } [Fact] public void CancellationAfterEngineCommitFinishesExactPlaceAckWithoutRollback() { using var fixture = new Fixture(bindGeneration: true); RuntimePhysicsState physics = fixture.Lifetime.Physics; RuntimeCollisionAdmission baseline = physics.BeginCollisionAdmission(PrefixP); using (PreparedLandblockCollisionGeneration preparedBaseline = PrepareSealedMutation(physics, baseline, PrefixP)) { Assert.False(physics.CommitCollisionGeneration( baseline, preparedBaseline).Completed); Assert.True(physics.CommitCollisionGeneration( baseline, preparedBaseline).Completed); } RuntimeEntityRecord record = fixture.Add( 0x70003108u, 1, CellP, new Vector3(18f, 46f, 0f)); RuntimeSetPositionOutcome seeded = fixture.Place( record, CellP, new Vector3(18.5f, 46f, 0f)); Assert.True(physics.SetPosition.AcknowledgeProjection( seeded.Projection)); RuntimeCollisionAdmission admission = physics.BeginCollisionAdmission(PrefixP); using PreparedLandblockCollisionGeneration prepared = PrepareSealedMutation(physics, admission, PrefixP); int committedNotifications = 0; physics.CollisionGenerationCommitted += _ => committedNotifications++; Assert.False(physics.CommitCollisionGeneration( admission, prepared).Completed); Assert.True(physics.SetPosition.TryPeekProjection( out RuntimePlacementProjectionSnapshot withdrawal)); Assert.True(physics.SetPosition.AcknowledgeProjection(withdrawal.Token)); _ = SealMutation(physics, admission, prepared); RuntimeCollisionGenerationCommit transferred = physics.CommitCollisionGeneration(admission, prepared); Assert.True(transferred.EngineCommitted); Assert.False(transferred.Completed); Assert.True(physics.SetPosition.TryPeekProjection( out RuntimePlacementProjectionSnapshot restored)); Assert.False(physics.CancelCollisionGeneration(admission, prepared)); Assert.True(physics.Engine.IsLandblockTerrainResident(PrefixP)); Assert.Equal(0, committedNotifications); Assert.True(physics.SetPosition.AcknowledgeProjection(restored.Token)); Assert.True(physics.CancelCollisionGeneration(admission, prepared)); Assert.True(physics.IsSpatialRoot(record)); Assert.True(physics.Engine.IsLandblockTerrainResident(PrefixP)); Assert.Equal(1, committedNotifications); RuntimePhysicsOwnershipSnapshot ownership = physics.CaptureOwnership(); Assert.Equal(0, ownership.CollisionPrefixMutationCount); Assert.Equal(0, ownership.CollisionPrefixQuiescenceCount); Assert.Equal(0, ownership.CollisionAdmissionCount); } [Fact] public void ColdFirstGenerationCancellationReleasesToUnavailableWithoutDebt() { // The injected-engine constructor is an internal fixture seam. It can // begin with collision resident before Runtime has assigned generation // one; production Runtime constructs an empty PhysicsEngine. using var fixture = new Fixture(bindGeneration: true); RuntimePhysicsState physics = fixture.Lifetime.Physics; RuntimeEntityRecord record = fixture.Add( 0x70003109u, 1, CellP, new Vector3(19f, 47f, 0f)); RuntimeSetPositionOutcome seeded = fixture.Place( record, CellP, new Vector3(19.5f, 47f, 0f)); Assert.True(physics.SetPosition.AcknowledgeProjection( seeded.Projection)); RuntimeCollisionAdmission admission = physics.BeginCollisionAdmission(PrefixP); Assert.Equal(0UL, admission.PreviousGeneration); using PreparedLandblockCollisionGeneration prepared = PrepareSealedMutation(physics, admission, PrefixP); RuntimeCollisionGenerationCommit parked = physics.CommitCollisionGeneration(admission, prepared); Assert.False(parked.EngineCommitted); Assert.True(physics.SetPosition.TryPeekProjection( out RuntimePlacementProjectionSnapshot withdrawal)); Assert.True(physics.SetPosition.AcknowledgeProjection(withdrawal.Token)); Assert.True(physics.CancelCollisionGeneration(admission, prepared)); Assert.True(physics.Engine.IsLandblockTerrainResident(PrefixP)); Assert.False(physics.IsSpatialRoot(record)); RuntimePhysicsOwnershipSnapshot ownership = physics.CaptureOwnership(); Assert.Equal(0, ownership.CollisionPrefixMutationCount); Assert.Equal(0, ownership.CollisionPrefixQuiescenceCount); Assert.Equal(0, ownership.PendingCollisionPrefixProjectionCount); Assert.Equal(0, ownership.CollisionAdmissionCount); RuntimeSetPositionOwnershipSnapshot placement = physics.SetPosition.CaptureOwnership(); Assert.Equal(1, placement.UnboundDeferredCellCount); Assert.Equal(0, placement.DeferredBucketCount); } private static PreparedLandblockCollisionGeneration PrepareSealedMutation( RuntimePhysicsState physics, RuntimeCollisionAdmission admission, uint landblock) { PreparedLandblockCollisionGeneration prepared = physics.PrepareCollisionGeneration(admission); physics.StageCollisionAssets( admission, prepared, new RuntimeLandblockCollisionAssets( landblock, new TerrainSurface(new byte[81], new float[256]), Array.Empty(), Array.Empty(), 0f, 0f, 0u)); _ = SealMutation(physics, admission, prepared); return prepared; } private static uint[] SealMutation( RuntimePhysicsState physics, RuntimeCollisionAdmission admission, PreparedLandblockCollisionGeneration prepared) { while (true) { while (!physics.AdvanceCollisionRetainedOwnerCapture( admission, prepared).Completed) { } foreach (uint ownerId in prepared.RetainedOwnerIds) physics.RefreshCollisionRetainedOwner(admission, prepared, ownerId); RuntimeCollisionSealStep seal; do { seal = physics.AdvanceCollisionGenerationSeal( admission, prepared); } while (!seal.Completed && !seal.Restarted); if (seal.Completed) return [.. prepared.RetainedOwnerIds]; } } }