feat(runtime): atomically replace collision generations

This commit is contained in:
Erik 2026-08-01 17:33:34 +02:00
parent 99bf1751bb
commit 9b0f59bd1b
21 changed files with 2435 additions and 408 deletions

View file

@ -336,7 +336,8 @@ public sealed class RuntimePhysicsStateTests
CommitPrepared(first.Physics, newer, prepared));
RuntimeCollisionAcknowledgement withdrawn =
first.Physics.WithdrawCollision(0xA9B4FFFFu);
CompleteWithdrawal(first.Physics, 0xA9B4FFFFu)
.Acknowledgement;
Assert.True(withdrawn.WasResident);
Assert.True(withdrawn.Generation > completed.Generation);
Assert.Equal(0, first.Physics.Engine.LandblockCount);
@ -465,7 +466,8 @@ public sealed class RuntimePhysicsStateTests
uint owner = Assert.Single(SealPrepared(physics, admission, prepared));
physics.Engine.ShadowObjects.UpdatePhysicsState(owner, 0x14u);
Assert.True(physics.CommitCollisionGeneration(
Assert.True(CompleteSealedCommit(
physics,
admission,
prepared).Committed);
Assert.Equal(15f, physics.Engine.SampleTerrainZ(1f, 1f));
@ -561,6 +563,11 @@ public sealed class RuntimePhysicsStateTests
Assert.True(sealSteps > ownerCount);
Assert.True(workUnits > ownerCount);
Assert.False(physics.CommitCollisionGeneration(
admission,
prepared).Committed);
_ = SealPrepared(physics, admission, prepared);
_ = GC.GetAllocatedBytesForCurrentThread();
long before = GC.GetAllocatedBytesForCurrentThread();
RuntimeCollisionGenerationCommit commit =
@ -662,7 +669,8 @@ public sealed class RuntimePhysicsStateTests
}
while (!seal.Completed);
Assert.True(physics.CommitCollisionGeneration(
Assert.True(CompleteSealedCommit(
physics,
admission,
prepared).Committed);
Assert.Equal(15f, physics.Engine.SampleTerrainZ(1f, 1f));
@ -742,7 +750,8 @@ public sealed class RuntimePhysicsStateTests
break;
}
Assert.True(physics.CommitCollisionGeneration(
Assert.True(CompleteSealedCommit(
physics,
admission,
prepared).Committed);
ShadowEntry[] entries = physics.Engine.ShadowObjects
@ -841,7 +850,8 @@ public sealed class RuntimePhysicsStateTests
}
while (!seal.Completed);
Assert.True(physics.CommitCollisionGeneration(
Assert.True(CompleteSealedCommit(
physics,
admission,
prepared).Committed);
ShadowEntry[] entries = physics.Engine.ShadowObjects
@ -885,6 +895,10 @@ public sealed class RuntimePhysicsStateTests
ShadowObjectRegistry shadowFacade = physics.Engine.ShadowObjects;
int notifications = 0;
physics.CollisionGenerationCommitted += _ => notifications++;
Assert.False(physics.CommitCollisionGeneration(
admission,
prepared).Committed);
_ = SealPrepared(physics, admission, prepared);
_ = GC.GetAllocatedBytesForCurrentThread();
long before = GC.GetAllocatedBytesForCurrentThread();
RuntimeCollisionGenerationCommit commit =
@ -1049,6 +1063,10 @@ public sealed class RuntimePhysicsStateTests
PhysicsDataCache cacheFacade = physics.DataCache;
CellGraph graphFacade = physics.DataCache.CellGraph;
ShadowObjectRegistry shadowFacade = physics.Engine.ShadowObjects;
Assert.False(physics.CommitCollisionGeneration(
admission,
prepared).Committed);
_ = SealPrepared(physics, admission, prepared);
_ = GC.GetAllocatedBytesForCurrentThread();
long before = GC.GetAllocatedBytesForCurrentThread();
RuntimeCollisionGenerationCommit commit =
@ -1106,9 +1124,15 @@ public sealed class RuntimePhysicsStateTests
_ = SealPrepared(physics, firstAdmission, first);
_ = SealPrepared(physics, secondAdmission, second);
Assert.False(physics.CommitCollisionGeneration(
firstAdmission,
first).Committed);
_ = SealPrepared(physics, firstAdmission, first);
_ = GC.GetAllocatedBytesForCurrentThread();
long firstBefore = GC.GetAllocatedBytesForCurrentThread();
Assert.True(physics.CommitCollisionGeneration(
Assert.True(CompleteSealedCommit(
physics,
firstAdmission,
first).Committed);
long firstAllocated =
@ -1118,10 +1142,15 @@ public sealed class RuntimePhysicsStateTests
Assert.True(physics.Engine.IsLandblockTerrainResident(firstLandblock));
Assert.False(physics.Engine.IsLandblockTerrainResident(secondLandblock));
_ = SealPrepared(physics, secondAdmission, second);
Assert.False(physics.CommitCollisionGeneration(
secondAdmission,
second).Committed);
_ = SealPrepared(physics, secondAdmission, second);
_ = GC.GetAllocatedBytesForCurrentThread();
long secondBefore = GC.GetAllocatedBytesForCurrentThread();
Assert.True(physics.CommitCollisionGeneration(
Assert.True(CompleteSealedCommit(
physics,
secondAdmission,
second).Committed);
long secondAllocated =
@ -1172,7 +1201,8 @@ public sealed class RuntimePhysicsStateTests
_ = SealPrepared(physics, firstAdmission, first);
_ = SealPrepared(physics, secondAdmission, second);
Assert.True(physics.CommitCollisionGeneration(
Assert.True(CompleteSealedCommit(
physics,
firstAdmission,
first).Committed);
physics.Engine.ShadowObjects.UpdatePosition(
@ -1185,7 +1215,8 @@ public sealed class RuntimePhysicsStateTests
seedCellId: 0x01010001u);
_ = SealPrepared(physics, secondAdmission, second);
Assert.True(physics.CommitCollisionGeneration(
Assert.True(CompleteSealedCommit(
physics,
secondAdmission,
second).Committed);
Assert.Equal(12f, Assert.Single(
@ -1256,11 +1287,13 @@ public sealed class RuntimePhysicsStateTests
_ = SealPrepared(physics, northAdmission, northPrepared);
_ = SealPrepared(physics, southAdmission, southPrepared);
Assert.True(physics.CommitCollisionGeneration(
Assert.True(CompleteSealedCommit(
physics,
northAdmission,
northPrepared).Committed);
_ = SealPrepared(physics, southAdmission, southPrepared);
Assert.True(physics.CommitCollisionGeneration(
Assert.True(CompleteSealedCommit(
physics,
southAdmission,
southPrepared).Committed);
Assert.True(physics.Engine.ShadowObjects.HasOwnerRowsInLandblock(
@ -1394,7 +1427,8 @@ public sealed class RuntimePhysicsStateTests
physics.Engine.UpdatePlayerCurrCell(secondCell);
ObjCell oldRootCell = physics.DataCache.CellGraph.CurrCell!;
Assert.True(physics.CommitCollisionGeneration(
Assert.True(CompleteSealedCommit(
physics,
admission,
prepared).Committed);
@ -1454,7 +1488,8 @@ public sealed class RuntimePhysicsStateTests
destination,
seedCellId: 0x02020001u);
Assert.True(physics.CommitCollisionGeneration(
Assert.True(CompleteSealedCommit(
physics,
admission,
prepared).Committed);
Assert.False(physics.Engine.ShadowObjects.HasOwnerRowsInLandblock(
@ -1521,7 +1556,8 @@ public sealed class RuntimePhysicsStateTests
seedCellId: 0x02020001u,
isStatic: false);
Assert.True(physics.CommitCollisionGeneration(
Assert.True(CompleteSealedCommit(
physics,
admission,
prepared).Committed);
ShadowEntry entry = Assert.Single(
@ -1692,8 +1728,8 @@ public sealed class RuntimePhysicsStateTests
preparedThird,
CollisionAssets(replacement));
Assert.True(physics.DemoteCollisionToTerrain(demoted).WasResident);
Assert.True(physics.WithdrawCollision(withdrawn).WasResident);
Assert.True(CompleteDemotion(physics, demoted).WasResident);
Assert.True(CompleteWithdrawal(physics, withdrawn).WasResident);
Assert.True(CommitPrepared(
physics,
third,
@ -1745,7 +1781,8 @@ public sealed class RuntimePhysicsStateTests
}
_ = SealPrepared(physics, retiredAdmission, retiredPrepared);
Assert.True(physics.CommitCollisionGeneration(
Assert.True(CompleteSealedCommit(
physics,
retiredAdmission,
retiredPrepared).Committed);
if (beginRebase)
@ -1762,9 +1799,9 @@ public sealed class RuntimePhysicsStateTests
}
if (withdraw)
Assert.True(physics.WithdrawCollision(retired).WasResident);
Assert.True(CompleteWithdrawal(physics, retired).WasResident);
else
Assert.True(physics.DemoteCollisionToTerrain(retired).WasResident);
Assert.True(CompleteDemotion(physics, retired).WasResident);
Assert.True(CommitPrepared(
physics,
@ -1986,6 +2023,11 @@ public sealed class RuntimePhysicsStateTests
while (!seal.Completed);
Assert.Equal(ownerCount, worked);
Assert.False(physics.CommitCollisionGeneration(
admission,
prepared).Committed);
_ = SealPrepared(physics, admission, prepared);
_ = GC.GetAllocatedBytesForCurrentThread();
long before = GC.GetAllocatedBytesForCurrentThread();
RuntimeCollisionGenerationCommit commit =
@ -2050,7 +2092,8 @@ public sealed class RuntimePhysicsStateTests
survivingTarget,
seedCellId: 0x02020001u,
isStatic: false);
Assert.True(physics.CommitCollisionGeneration(
Assert.True(CompleteSealedCommit(
physics,
survivingAdmission,
surviving).Committed);
Assert.Contains(
@ -2097,7 +2140,8 @@ public sealed class RuntimePhysicsStateTests
0f,
target,
seedCellId: 0x01010001u);
Assert.True(physics.CommitCollisionGeneration(
Assert.True(CompleteSealedCommit(
physics,
admission,
prepared).Committed);
Assert.True(physics.Engine.ShadowObjects.HasOwnerRowsInLandblock(
@ -2146,7 +2190,8 @@ public sealed class RuntimePhysicsStateTests
outside,
seedCellId: 0x02020001u);
physics.Engine.ShadowObjects.UpdatePhysicsState(ownerId, 0x55u);
Assert.True(physics.CommitCollisionGeneration(
Assert.True(CompleteSealedCommit(
physics,
admission,
prepared).Committed);
ShadowEntry entry = Assert.Single(
@ -2217,7 +2262,7 @@ public sealed class RuntimePhysicsStateTests
replacementAdmission,
replacementPrepared);
Assert.True(physics.WithdrawCollision(retired).WasResident);
Assert.True(CompleteWithdrawal(physics, retired).WasResident);
Assert.False(physics.CommitCollisionGeneration(
replacementAdmission,
replacementPrepared).Committed);
@ -2226,7 +2271,8 @@ public sealed class RuntimePhysicsStateTests
physics,
replacementAdmission,
replacementPrepared);
Assert.True(physics.CommitCollisionGeneration(
Assert.True(CompleteSealedCommit(
physics,
replacementAdmission,
replacementPrepared).Committed);
Assert.False(physics.Engine.IsLandblockTerrainResident(retired));
@ -2254,7 +2300,8 @@ public sealed class RuntimePhysicsStateTests
uint ordinal = index + 0x1000u;
uint x = ordinal & 0xFFu;
uint y = (ordinal >> 8) & 0xFFu;
_ = physics.WithdrawCollision(
_ = CompleteWithdrawal(
physics,
(x << 24) | (y << 16) | 0xFFFFu);
}
Assert.False(physics.CommitCollisionGeneration(
@ -2272,7 +2319,8 @@ public sealed class RuntimePhysicsStateTests
Assert.True(++steps < 100_000);
}
while (!seal.Completed);
Assert.True(physics.CommitCollisionGeneration(
Assert.True(CompleteSealedCommit(
physics,
admission,
prepared).Committed);
}
@ -2380,7 +2428,8 @@ public sealed class RuntimePhysicsStateTests
Assert.InRange(seal.WorkUnits, 0, 1);
}
while (!seal.Completed);
Assert.True(physics.CommitCollisionGeneration(
Assert.True(CompleteSealedCommit(
physics,
admission,
prepared).Committed);
Assert.Empty(physics.Engine.ShadowObjects.AllEntriesForDebug());
@ -2448,7 +2497,8 @@ public sealed class RuntimePhysicsStateTests
seedCellId: 0x01010001u,
isStatic: false);
physics.Engine.ShadowObjects.Deregister(77u);
Assert.True(physics.CommitCollisionGeneration(
Assert.True(CompleteSealedCommit(
physics,
admission,
prepared).Committed);
Assert.Empty(physics.Engine.ShadowObjects.AllEntriesForDebug());
@ -2484,7 +2534,8 @@ public sealed class RuntimePhysicsStateTests
seedCellId: 0x01010001u,
isStatic: false);
}
Assert.True(physics.CommitCollisionGeneration(
Assert.True(CompleteSealedCommit(
physics,
admission,
prepared).Committed);
Assert.Equal(
@ -2903,7 +2954,55 @@ public sealed class RuntimePhysicsStateTests
PreparedLandblockCollisionGeneration prepared)
{
_ = SealPrepared(physics, admission, prepared);
return physics.CommitCollisionGeneration(admission, prepared);
return CompleteSealedCommit(physics, admission, prepared);
}
private static RuntimeCollisionGenerationCommit CompleteSealedCommit(
RuntimePhysicsState physics,
RuntimeCollisionAdmission admission,
PreparedLandblockCollisionGeneration prepared)
{
for (int poll = 0; poll < 10_000; poll++)
{
RuntimeCollisionGenerationCommit commit =
physics.CommitCollisionGeneration(admission, prepared);
if (commit.Committed)
return commit;
if (!commit.EngineCommitted)
_ = SealPrepared(physics, admission, prepared);
}
throw new InvalidOperationException(
"Collision generation did not complete its Runtime mutation transaction.");
}
private static RuntimeCollisionMutationResult CompleteDemotion(
RuntimePhysicsState physics,
uint landblockId)
{
for (int poll = 0; poll < 10_000; poll++)
{
RuntimeCollisionMutationResult result =
physics.DemoteCollisionToTerrain(landblockId);
if (result.Completed)
return result;
}
throw new InvalidOperationException(
"Collision demotion did not complete its Runtime mutation transaction.");
}
private static RuntimeCollisionMutationResult CompleteWithdrawal(
RuntimePhysicsState physics,
uint landblockId)
{
for (int poll = 0; poll < 10_000; poll++)
{
RuntimeCollisionMutationResult result =
physics.WithdrawCollision(landblockId);
if (result.Completed)
return result;
}
throw new InvalidOperationException(
"Collision withdrawal did not complete its Runtime mutation transaction.");
}
private static uint[] SealPrepared(