fix(physics): activate collision generations atomically
This commit is contained in:
parent
3e0f3b6206
commit
be94bc9b06
18 changed files with 1402 additions and 80 deletions
|
|
@ -311,27 +311,28 @@ public sealed class RuntimePhysicsStateTests
|
|||
first.Physics.BeginCollisionAdmission(0xA9B4FFFFu);
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
first.Physics.AdmitCollisionAssets(
|
||||
admission,
|
||||
CollisionAssets(0xA9B4FFFFu)));
|
||||
first.Physics.PrepareCollisionGeneration(admission));
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
second.Physics.AdmitCollisionAssets(
|
||||
newer,
|
||||
CollisionAssets(0xA9B4FFFFu)));
|
||||
second.Physics.PrepareCollisionGeneration(newer));
|
||||
|
||||
first.Physics.AdmitCollisionAssets(
|
||||
using PreparedLandblockCollisionGeneration prepared =
|
||||
first.Physics.PrepareCollisionGeneration(newer);
|
||||
first.Physics.StageCollisionAssets(
|
||||
newer,
|
||||
prepared,
|
||||
CollisionAssets(0xA9B4FFFFu));
|
||||
RuntimeCollisionAcknowledgement completed =
|
||||
first.Physics.CompleteCollisionAdmission(newer);
|
||||
RuntimeCollisionGenerationCommit commit =
|
||||
first.Physics.CommitCollisionGeneration(newer, prepared);
|
||||
RuntimeCollisionAcknowledgement completed = commit.Acknowledgement;
|
||||
|
||||
Assert.True(commit.Committed);
|
||||
Assert.True(completed.WasResident);
|
||||
Assert.Equal(1, first.Physics.Engine.LandblockCount);
|
||||
Assert.Equal(
|
||||
0,
|
||||
first.Physics.CaptureOwnership().CollisionAdmissionCount);
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
first.Physics.CompleteCollisionAdmission(newer));
|
||||
first.Physics.CommitCollisionGeneration(newer, prepared));
|
||||
|
||||
RuntimeCollisionAcknowledgement withdrawn =
|
||||
first.Physics.WithdrawCollision(0xA9B4FFFFu);
|
||||
|
|
@ -340,6 +341,193 @@ public sealed class RuntimePhysicsStateTests
|
|||
Assert.Equal(0, first.Physics.Engine.LandblockCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CollisionGenerationKeepsPreviousWorldVisibleUntilOneCommitNotification()
|
||||
{
|
||||
using var lifetime = new RuntimeEntityObjectLifetime();
|
||||
RuntimePhysicsState physics = lifetime.Physics;
|
||||
RuntimeCollisionAdmission firstAdmission =
|
||||
physics.BeginCollisionAdmission(0xA9B4FFFFu);
|
||||
using (PreparedLandblockCollisionGeneration first =
|
||||
physics.PrepareCollisionGeneration(firstAdmission))
|
||||
{
|
||||
physics.StageCollisionAssets(
|
||||
firstAdmission,
|
||||
first,
|
||||
CollisionAssets(0xA9B4FFFFu, terrainHeight: 10f));
|
||||
Assert.True(physics.CommitCollisionGeneration(
|
||||
firstAdmission,
|
||||
first).Committed);
|
||||
}
|
||||
|
||||
int notifications = 0;
|
||||
physics.CollisionGenerationCommitted += _ => notifications++;
|
||||
RuntimeCollisionAdmission replacementAdmission =
|
||||
physics.BeginCollisionAdmission(0xA9B4FFFFu);
|
||||
using PreparedLandblockCollisionGeneration replacement =
|
||||
physics.PrepareCollisionGeneration(replacementAdmission);
|
||||
physics.StageCollisionAssets(
|
||||
replacementAdmission,
|
||||
replacement,
|
||||
CollisionAssets(0xA9B4FFFFu, terrainHeight: 25f));
|
||||
|
||||
Assert.Equal(10f, physics.Engine.SampleTerrainZ(1f, 1f));
|
||||
Assert.Equal(0, notifications);
|
||||
|
||||
RuntimeCollisionGenerationCommit committed =
|
||||
physics.CommitCollisionGeneration(
|
||||
replacementAdmission,
|
||||
replacement);
|
||||
|
||||
Assert.True(committed.Committed);
|
||||
Assert.Equal(25f, physics.Engine.SampleTerrainZ(1f, 1f));
|
||||
Assert.Equal(1, notifications);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CollisionGenerationRejectsStaleReplacementWithoutMutatingActiveWorld()
|
||||
{
|
||||
using var lifetime = new RuntimeEntityObjectLifetime();
|
||||
RuntimePhysicsState physics = lifetime.Physics;
|
||||
RuntimeCollisionAdmission stale =
|
||||
physics.BeginCollisionAdmission(0xA9B4FFFFu);
|
||||
using PreparedLandblockCollisionGeneration preparedStale =
|
||||
physics.PrepareCollisionGeneration(stale);
|
||||
physics.StageCollisionAssets(
|
||||
stale,
|
||||
preparedStale,
|
||||
CollisionAssets(0xA9B4FFFFu, terrainHeight: 10f));
|
||||
|
||||
RuntimeCollisionAdmission current =
|
||||
physics.BeginCollisionAdmission(0xA9B4FFFFu);
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
physics.CommitCollisionGeneration(stale, preparedStale));
|
||||
Assert.False(physics.Engine.IsLandblockTerrainResident(0xA9B4FFFFu));
|
||||
|
||||
using PreparedLandblockCollisionGeneration preparedCurrent =
|
||||
physics.PrepareCollisionGeneration(current);
|
||||
physics.StageCollisionAssets(
|
||||
current,
|
||||
preparedCurrent,
|
||||
CollisionAssets(0xA9B4FFFFu, terrainHeight: 20f));
|
||||
Assert.True(physics.CommitCollisionGeneration(
|
||||
current,
|
||||
preparedCurrent).Committed);
|
||||
Assert.Equal(20f, physics.Engine.SampleTerrainZ(1f, 1f));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MovingDynamicOwnerDuringStagingMustRefreshBeforeCommit()
|
||||
{
|
||||
using var lifetime = new RuntimeEntityObjectLifetime();
|
||||
RuntimePhysicsState physics = lifetime.Physics;
|
||||
RuntimeCollisionAdmission initialAdmission =
|
||||
physics.BeginCollisionAdmission(0x0101FFFFu);
|
||||
using (PreparedLandblockCollisionGeneration initial =
|
||||
physics.PrepareCollisionGeneration(initialAdmission))
|
||||
{
|
||||
physics.StageCollisionAssets(
|
||||
initialAdmission,
|
||||
initial,
|
||||
CollisionAssets(0x0101FFFFu, terrainHeight: 5f));
|
||||
Assert.True(physics.CommitCollisionGeneration(
|
||||
initialAdmission,
|
||||
initial).Committed);
|
||||
}
|
||||
physics.Engine.ShadowObjects.Register(
|
||||
42u,
|
||||
0x01000001u,
|
||||
new Vector3(10f, 10f, 0f),
|
||||
Quaternion.Identity,
|
||||
0.5f,
|
||||
0f,
|
||||
0f,
|
||||
0x0101FFFFu,
|
||||
seedCellId: 0x01010001u,
|
||||
isStatic: false);
|
||||
|
||||
RuntimeCollisionAdmission admission =
|
||||
physics.BeginCollisionAdmission(0x0101FFFFu);
|
||||
using PreparedLandblockCollisionGeneration prepared =
|
||||
physics.PrepareCollisionGeneration(admission);
|
||||
physics.StageCollisionAssets(
|
||||
admission,
|
||||
prepared,
|
||||
CollisionAssets(0x0101FFFFu, terrainHeight: 15f));
|
||||
uint owner = Assert.Single(physics.CaptureCollisionDynamicOwners(
|
||||
admission,
|
||||
prepared));
|
||||
physics.RefreshCollisionDynamicOwner(admission, prepared, owner);
|
||||
physics.Engine.ShadowObjects.UpdatePosition(
|
||||
owner,
|
||||
new Vector3(30f, 10f, 0f),
|
||||
Quaternion.Identity,
|
||||
0f,
|
||||
0f,
|
||||
0x0101FFFFu,
|
||||
seedCellId: 0x01010009u);
|
||||
|
||||
RuntimeCollisionGenerationCommit rejected =
|
||||
physics.CommitCollisionGeneration(admission, prepared);
|
||||
Assert.False(rejected.Committed);
|
||||
Assert.Equal(owner, Assert.Single(rejected.DirtyDynamicOwnerIds));
|
||||
Assert.Equal(5f, physics.Engine.SampleTerrainZ(1f, 1f));
|
||||
|
||||
physics.RefreshCollisionDynamicOwner(admission, prepared, owner);
|
||||
Assert.True(physics.CommitCollisionGeneration(
|
||||
admission,
|
||||
prepared).Committed);
|
||||
Assert.Equal(15f, physics.Engine.SampleTerrainZ(1f, 1f));
|
||||
Assert.Contains(
|
||||
physics.Engine.ShadowObjects.GetObjectsInCell(0x01010009u),
|
||||
entry => entry.EntityId == owner);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SpawnAndDeleteDuringStagingAreBothGenerationGated()
|
||||
{
|
||||
using var lifetime = new RuntimeEntityObjectLifetime();
|
||||
RuntimePhysicsState physics = lifetime.Physics;
|
||||
RuntimeCollisionAdmission admission =
|
||||
physics.BeginCollisionAdmission(0x0101FFFFu);
|
||||
using PreparedLandblockCollisionGeneration prepared =
|
||||
physics.PrepareCollisionGeneration(admission);
|
||||
physics.StageCollisionAssets(
|
||||
admission,
|
||||
prepared,
|
||||
CollisionAssets(0x0101FFFFu, terrainHeight: 12f));
|
||||
Assert.Empty(physics.CaptureCollisionDynamicOwners(admission, prepared));
|
||||
|
||||
physics.Engine.ShadowObjects.Register(
|
||||
77u,
|
||||
0x01000001u,
|
||||
new Vector3(10f, 10f, 0f),
|
||||
Quaternion.Identity,
|
||||
0.5f,
|
||||
0f,
|
||||
0f,
|
||||
0x0101FFFFu,
|
||||
seedCellId: 0x01010001u,
|
||||
isStatic: false);
|
||||
RuntimeCollisionGenerationCommit spawned =
|
||||
physics.CommitCollisionGeneration(admission, prepared);
|
||||
Assert.False(spawned.Committed);
|
||||
Assert.Equal(77u, Assert.Single(spawned.DirtyDynamicOwnerIds));
|
||||
|
||||
physics.RefreshCollisionDynamicOwner(admission, prepared, 77u);
|
||||
physics.Engine.ShadowObjects.Deregister(77u);
|
||||
RuntimeCollisionGenerationCommit deleted =
|
||||
physics.CommitCollisionGeneration(admission, prepared);
|
||||
Assert.False(deleted.Committed);
|
||||
Assert.Equal(77u, Assert.Single(deleted.DirtyDynamicOwnerIds));
|
||||
|
||||
physics.RefreshCollisionDynamicOwner(admission, prepared, 77u);
|
||||
Assert.True(physics.CommitCollisionGeneration(
|
||||
admission,
|
||||
prepared).Committed);
|
||||
Assert.Empty(physics.Engine.ShadowObjects.AllEntriesForDebug());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TerminalDisposalClearsLandblocksShadowsAndWorksets()
|
||||
{
|
||||
|
|
@ -352,10 +540,13 @@ public sealed class RuntimePhysicsStateTests
|
|||
|
||||
RuntimeCollisionAdmission admission =
|
||||
lifetime.Physics.BeginCollisionAdmission(0x0101FFFFu);
|
||||
lifetime.Physics.AdmitCollisionAssets(
|
||||
using PreparedLandblockCollisionGeneration prepared =
|
||||
lifetime.Physics.PrepareCollisionGeneration(admission);
|
||||
lifetime.Physics.StageCollisionAssets(
|
||||
admission,
|
||||
prepared,
|
||||
CollisionAssets(0x0101FFFFu));
|
||||
_ = lifetime.Physics.CompleteCollisionAdmission(admission);
|
||||
_ = lifetime.Physics.CommitCollisionGeneration(admission, prepared);
|
||||
lifetime.Physics.Engine.ShadowObjects.Register(
|
||||
entityId: record.LocalEntityId!.Value,
|
||||
gfxObjId: 0x01000001u,
|
||||
|
|
@ -740,10 +931,12 @@ public sealed class RuntimePhysicsStateTests
|
|||
}
|
||||
|
||||
private static RuntimeLandblockCollisionAssets CollisionAssets(
|
||||
uint landblockId)
|
||||
uint landblockId,
|
||||
float terrainHeight = 0f)
|
||||
{
|
||||
var heights = new byte[81];
|
||||
var table = new float[256];
|
||||
table[0] = terrainHeight;
|
||||
return new RuntimeLandblockCollisionAssets(
|
||||
landblockId,
|
||||
new TerrainSurface(heights, table),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue