feat(runtime): commit dormant SetPosition activation
This commit is contained in:
parent
99f867f053
commit
5785a07b3e
13 changed files with 4674 additions and 111 deletions
|
|
@ -13,6 +13,604 @@ public sealed class RuntimeCollisionReportingStateTests
|
|||
private const uint Landblock = 0xA9B40000u;
|
||||
private const uint Cell = Landblock | 0x0001u;
|
||||
|
||||
[Fact]
|
||||
public void PreparedBatchDefersTrackingUntilOrderedDispatchAndDispatchesOnce()
|
||||
{
|
||||
using var lifetime = Lifetime();
|
||||
RuntimeEntityRecord owner = Entity(
|
||||
lifetime,
|
||||
0x70001F01u,
|
||||
1,
|
||||
PhysicsStateFlags.ReportCollisions);
|
||||
RuntimeEntityRecord target = Entity(
|
||||
lifetime,
|
||||
0x70001F02u,
|
||||
1,
|
||||
PhysicsStateFlags.ReportCollisions);
|
||||
target.PhysicsBody!.TransientState |= TransientStateFlags.Contact;
|
||||
RegisterDynamicShadow(lifetime, target);
|
||||
var observer = new CollisionObserver();
|
||||
using IDisposable subscription = lifetime.Physics.CollisionReports
|
||||
.Subscribe(observer);
|
||||
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryPrepareSetPositionBatch(
|
||||
owner,
|
||||
owner.PhysicsBody!,
|
||||
physicsTime: 10d,
|
||||
previousContact: false,
|
||||
previousOnWalkable: false,
|
||||
finalOnWalkable: false,
|
||||
collidedWithEnvironment: false,
|
||||
[target.Key!.Value.LocalEntityId],
|
||||
out var prepared));
|
||||
Assert.NotNull(prepared);
|
||||
Assert.Empty(observer.Reports);
|
||||
Assert.Equal(0, lifetime.Physics.CollisionReports.CaptureOwnership()
|
||||
.TrackedObjectCount);
|
||||
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryInstallSetPositionBatch(
|
||||
prepared!,
|
||||
out var receipt));
|
||||
Assert.Empty(observer.Reports);
|
||||
Assert.Equal(0, lifetime.Physics.CollisionReports.CaptureOwnership()
|
||||
.TrackedObjectCount);
|
||||
Assert.Equal(1, lifetime.Physics.CaptureOwnership()
|
||||
.PendingCollisionSetPositionDispatchCount);
|
||||
|
||||
lifetime.Physics.CollisionReports.DispatchSetPositionBatch(receipt);
|
||||
Assert.Equal(2, observer.Reports.Count);
|
||||
Assert.Equal(1, lifetime.Physics.CollisionReports.CaptureOwnership()
|
||||
.TrackedObjectCount);
|
||||
Assert.False(observer.Reports[0].RecipientWasInContact);
|
||||
Assert.True(observer.Reports[0].OtherWasInContact);
|
||||
Assert.True(observer.Reports[1].RecipientWasInContact);
|
||||
Assert.False(observer.Reports[1].OtherWasInContact);
|
||||
Assert.Equal(0, lifetime.Physics.CaptureOwnership()
|
||||
.PendingCollisionSetPositionDispatchCount);
|
||||
lifetime.Physics.CollisionReports.DispatchSetPositionBatch(receipt);
|
||||
Assert.Equal(2, observer.Reports.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CombinedPhysicsLedgerIncludesPendingShadowSetPositionReceipt()
|
||||
{
|
||||
using var lifetime = Lifetime();
|
||||
RuntimeEntityRecord owner = Entity(
|
||||
lifetime, 0x70001F03u, 1, PhysicsStateFlags.None);
|
||||
RegisterDynamicShadow(lifetime, owner);
|
||||
ShadowObjectRegistry shadows = lifetime.Physics.Engine.ShadowObjects;
|
||||
Assert.True(shadows.TryPrepareSetPosition(
|
||||
owner.Key!.Value.LocalEntityId,
|
||||
new Vector3(13f, 12f, 7f),
|
||||
Quaternion.Identity,
|
||||
Cell,
|
||||
0f,
|
||||
0f,
|
||||
PhysicsShadowCommitAction.Replace,
|
||||
[Cell],
|
||||
provenShapeless: false,
|
||||
suspendOwner: false,
|
||||
out var prepared));
|
||||
Assert.True(shadows.TryApplySetPosition(prepared!, out var receipt));
|
||||
|
||||
Assert.Equal(1, lifetime.Physics.CaptureOwnership()
|
||||
.PendingShadowSetPositionDispatchCount);
|
||||
|
||||
Assert.True(shadows.DiscardSetPositionCommit(receipt));
|
||||
Assert.Equal(0, lifetime.Physics.CaptureOwnership()
|
||||
.PendingShadowSetPositionDispatchCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TwoOwnerPreparedBatchesDispatchExactlyOnceInReverseOrder()
|
||||
{
|
||||
using var lifetime = Lifetime();
|
||||
RuntimeEntityRecord first = Entity(
|
||||
lifetime, 0x70001E01u, 1, PhysicsStateFlags.ReportCollisions);
|
||||
RuntimeEntityRecord second = Entity(
|
||||
lifetime, 0x70001E02u, 1, PhysicsStateFlags.ReportCollisions);
|
||||
const uint staticId = 0x00F01E01u;
|
||||
RegisterShadow(lifetime, staticId, PhysicsStateFlags.Static,
|
||||
isStatic: true);
|
||||
var observer = new CollisionObserver();
|
||||
using IDisposable subscription = lifetime.Physics.CollisionReports
|
||||
.Subscribe(observer);
|
||||
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryPrepareSetPositionBatch(
|
||||
first, first.PhysicsBody!, 10d, false, false, false, false,
|
||||
[staticId], out var firstPrepared));
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryInstallSetPositionBatch(
|
||||
firstPrepared!, out var firstReceipt));
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryPrepareSetPositionBatch(
|
||||
second, second.PhysicsBody!, 10d, false, false, false, false,
|
||||
[staticId], out var secondPrepared));
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryInstallSetPositionBatch(
|
||||
secondPrepared!, out var secondReceipt));
|
||||
|
||||
Assert.True(lifetime.Physics.CollisionReports.DispatchSetPositionBatch(
|
||||
secondReceipt));
|
||||
Assert.True(lifetime.Physics.CollisionReports.DispatchSetPositionBatch(
|
||||
firstReceipt));
|
||||
Assert.False(lifetime.Physics.CollisionReports.DispatchSetPositionBatch(
|
||||
secondReceipt));
|
||||
Assert.False(lifetime.Physics.CollisionReports.DispatchSetPositionBatch(
|
||||
firstReceipt));
|
||||
|
||||
Assert.Equal(2, observer.Reports.Count);
|
||||
Assert.Equal(0, lifetime.Physics.CollisionReports.CaptureOwnership()
|
||||
.PendingSetPositionDispatchCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OldBatchRetirementCannotRemoveBatchInstalledByItsCallback()
|
||||
{
|
||||
using var lifetime = Lifetime();
|
||||
RuntimeEntityRecord owner = Entity(
|
||||
lifetime, 0x70001E03u, 1, PhysicsStateFlags.ReportCollisions);
|
||||
const uint staticId = 0x00F01E03u;
|
||||
RegisterShadow(lifetime, staticId, PhysicsStateFlags.Static,
|
||||
isStatic: true);
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryPrepareSetPositionBatch(
|
||||
owner, owner.PhysicsBody!, 10d, false, false, false, false,
|
||||
[staticId], out var oldPrepared));
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryInstallSetPositionBatch(
|
||||
oldPrepared!, out var oldReceipt));
|
||||
RuntimeCollisionReportingState.SetPositionCollisionBatchReceipt
|
||||
newerReceipt = default;
|
||||
bool installedNewer = false;
|
||||
var observer = new CollisionObserver(ignoredReport =>
|
||||
{
|
||||
if (installedNewer)
|
||||
return;
|
||||
installedNewer = true;
|
||||
Assert.True(lifetime.Physics.CollisionReports
|
||||
.TryPrepareSetPositionBatch(
|
||||
owner, owner.PhysicsBody!, 11d, false, false, false, true,
|
||||
ImmutableArray<uint>.Empty, out var newerPrepared));
|
||||
Assert.True(lifetime.Physics.CollisionReports
|
||||
.TryInstallSetPositionBatch(newerPrepared!, out newerReceipt));
|
||||
_ = lifetime.Physics.CollisionReports.DispatchSetPositionBatch(
|
||||
newerReceipt);
|
||||
_ = ignoredReport;
|
||||
});
|
||||
using IDisposable subscription = lifetime.Physics.CollisionReports
|
||||
.Subscribe(observer);
|
||||
|
||||
Assert.True(lifetime.Physics.CollisionReports.DispatchSetPositionBatch(
|
||||
oldReceipt));
|
||||
Assert.True(installedNewer);
|
||||
Assert.True(newerReceipt.IsValid);
|
||||
Assert.Equal(1, lifetime.Physics.CollisionReports.CaptureOwnership()
|
||||
.OwnerCount);
|
||||
|
||||
lifetime.Physics.CollisionReports.RetireSetPositionBatchOwner(
|
||||
oldReceipt);
|
||||
Assert.Equal(1, lifetime.Physics.CollisionReports.CaptureOwnership()
|
||||
.OwnerCount);
|
||||
|
||||
lifetime.Physics.CollisionReports.RetireSetPositionBatchOwner(
|
||||
newerReceipt);
|
||||
Assert.Equal(0, lifetime.Physics.CollisionReports.CaptureOwnership()
|
||||
.OwnerCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PreparedBatchTracksHiddenIgnoredPeerButSuppressesCallbacks()
|
||||
{
|
||||
using var lifetime = Lifetime();
|
||||
RuntimeEntityRecord owner = Entity(
|
||||
lifetime,
|
||||
0x70001F11u,
|
||||
1,
|
||||
PhysicsStateFlags.ReportCollisions);
|
||||
RuntimeEntityRecord target = Entity(
|
||||
lifetime,
|
||||
0x70001F12u,
|
||||
1,
|
||||
PhysicsStateFlags.ReportCollisions);
|
||||
RegisterDynamicShadow(lifetime, target);
|
||||
var observer = new CollisionObserver();
|
||||
using IDisposable subscription = lifetime.Physics.CollisionReports
|
||||
.Subscribe(observer);
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryPrepareSetPositionBatch(
|
||||
owner,
|
||||
owner.PhysicsBody!,
|
||||
10d,
|
||||
previousContact: false,
|
||||
previousOnWalkable: false,
|
||||
finalOnWalkable: false,
|
||||
collidedWithEnvironment: false,
|
||||
[target.Key!.Value.LocalEntityId],
|
||||
out var prepared));
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryInstallSetPositionBatch(
|
||||
prepared!,
|
||||
out var receipt));
|
||||
|
||||
PhysicsStateFlags hidden = PhysicsStateFlags.Hidden
|
||||
| PhysicsStateFlags.IgnoreCollisions;
|
||||
lifetime.Entities.SetFinalPhysicsState(target, hidden);
|
||||
target.PhysicsBody!.State = hidden;
|
||||
lifetime.Physics.CollisionReports.DispatchSetPositionBatch(receipt);
|
||||
|
||||
Assert.Empty(observer.Reports);
|
||||
Assert.Equal(1, lifetime.Physics.CollisionReports.CaptureOwnership()
|
||||
.TrackedObjectCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PreparedBatchConvertsLiveReportAsEnvironmentAfterGroundEdge()
|
||||
{
|
||||
using var lifetime = Lifetime();
|
||||
RuntimeEntityRecord owner = Entity(
|
||||
lifetime,
|
||||
0x70001F21u,
|
||||
1,
|
||||
PhysicsStateFlags.ReportCollisions);
|
||||
RuntimeEntityRecord target = Entity(
|
||||
lifetime,
|
||||
0x70001F22u,
|
||||
1,
|
||||
PhysicsStateFlags.ReportCollisions);
|
||||
RegisterDynamicShadow(lifetime, target);
|
||||
var observer = new CollisionObserver();
|
||||
using IDisposable subscription = lifetime.Physics.CollisionReports
|
||||
.Subscribe(observer);
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryPrepareSetPositionBatch(
|
||||
owner,
|
||||
owner.PhysicsBody!,
|
||||
10d,
|
||||
previousContact: false,
|
||||
previousOnWalkable: false,
|
||||
finalOnWalkable: false,
|
||||
collidedWithEnvironment: false,
|
||||
[target.Key!.Value.LocalEntityId],
|
||||
out var prepared));
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryInstallSetPositionBatch(
|
||||
prepared!,
|
||||
out var receipt));
|
||||
|
||||
lifetime.Entities.SetFinalPhysicsState(
|
||||
target,
|
||||
PhysicsStateFlags.ReportAsEnvironment);
|
||||
target.PhysicsBody!.State = PhysicsStateFlags.ReportAsEnvironment;
|
||||
lifetime.Physics.CollisionReports.DispatchSetPositionBatch(receipt);
|
||||
|
||||
Assert.Single(observer.Reports);
|
||||
Assert.Equal(RuntimeCollisionReportKind.EnvironmentCollision,
|
||||
observer.Reports[0].Kind);
|
||||
Assert.Equal(1, lifetime.Physics.CollisionReports.CaptureOwnership()
|
||||
.TrackedObjectCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PreparedEnvironmentBatchClearsCapturedMissileWithoutReport()
|
||||
{
|
||||
using var lifetime = Lifetime();
|
||||
RuntimeEntityRecord owner = Entity(
|
||||
lifetime,
|
||||
0x70001F31u,
|
||||
1,
|
||||
PhysicsStateFlags.Missile | PhysicsStateFlags.AlignPath);
|
||||
RegisterDynamicShadow(lifetime, owner);
|
||||
const uint staticId = 0x00F01F31u;
|
||||
RegisterShadow(
|
||||
lifetime,
|
||||
staticId,
|
||||
PhysicsStateFlags.Static,
|
||||
isStatic: true);
|
||||
var observer = new CollisionObserver();
|
||||
using IDisposable subscription = lifetime.Physics.CollisionReports
|
||||
.Subscribe(observer);
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryPrepareSetPositionBatch(
|
||||
owner,
|
||||
owner.PhysicsBody!,
|
||||
10d,
|
||||
previousContact: false,
|
||||
previousOnWalkable: false,
|
||||
finalOnWalkable: false,
|
||||
collidedWithEnvironment: false,
|
||||
[staticId],
|
||||
out var prepared));
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryInstallSetPositionBatch(
|
||||
prepared!,
|
||||
out var receipt));
|
||||
|
||||
lifetime.Physics.CollisionReports.DispatchSetPositionBatch(receipt);
|
||||
|
||||
Assert.Empty(observer.Reports);
|
||||
Assert.False(owner.FinalPhysicsState.HasFlag(PhysicsStateFlags.Missile));
|
||||
Assert.False(owner.PhysicsBody!.State.HasFlag(PhysicsStateFlags.Missile));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PreparedExpiredEndDegradesToMissingTargetAfterInstall()
|
||||
{
|
||||
using var lifetime = Lifetime();
|
||||
RuntimeEntityRecord owner = Entity(
|
||||
lifetime,
|
||||
0x70001F41u,
|
||||
1,
|
||||
PhysicsStateFlags.ReportCollisions);
|
||||
RuntimeEntityRecord target = Entity(
|
||||
lifetime,
|
||||
0x70001F42u,
|
||||
1,
|
||||
PhysicsStateFlags.ReportCollisions);
|
||||
target.PhysicsBody!.TransientState |= TransientStateFlags.Contact;
|
||||
RegisterDynamicShadow(lifetime, target);
|
||||
var observer = new CollisionObserver();
|
||||
using IDisposable subscription = lifetime.Physics.CollisionReports
|
||||
.Subscribe(observer);
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryPrepareSetPositionBatch(
|
||||
owner,
|
||||
owner.PhysicsBody!,
|
||||
10d,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
[target.Key!.Value.LocalEntityId],
|
||||
out var start));
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryInstallSetPositionBatch(
|
||||
start!,
|
||||
out var startReceipt));
|
||||
lifetime.Physics.CollisionReports.DispatchSetPositionBatch(startReceipt);
|
||||
observer.Reports.Clear();
|
||||
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryPrepareSetPositionBatch(
|
||||
owner,
|
||||
owner.PhysicsBody!,
|
||||
11.0001d,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
ImmutableArray<uint>.Empty,
|
||||
out var end));
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryInstallSetPositionBatch(
|
||||
end!,
|
||||
out var endReceipt));
|
||||
Assert.True(lifetime.TryAcceptDelete(
|
||||
new DeleteObject.Parsed(target.ServerGuid, target.Incarnation),
|
||||
isLocalPlayer: false,
|
||||
removeRetainedObject: false,
|
||||
out RuntimeEntityDeleteAcceptance acceptance));
|
||||
lifetime.CompleteAcceptedDelete(acceptance);
|
||||
Assert.Null(lifetime.RetireCanonicalOnly(target));
|
||||
|
||||
lifetime.Physics.CollisionReports.DispatchSetPositionBatch(endReceipt);
|
||||
|
||||
RuntimeCollisionReport report = Assert.Single(observer.Reports);
|
||||
Assert.Equal(RuntimeCollisionReportKind.ObjectCollisionEnd, report.Kind);
|
||||
Assert.Equal(owner.Key, report.Recipient);
|
||||
Assert.Equal(target.ServerGuid, report.OtherServerGuid);
|
||||
Assert.False(report.OtherWasInContact);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PreparedBatchPreservesPreLoopEnvironmentLatchUntilFinalSuffix()
|
||||
{
|
||||
using var lifetime = Lifetime();
|
||||
RuntimeEntityRecord owner = Entity(
|
||||
lifetime,
|
||||
0x70001F51u,
|
||||
1,
|
||||
PhysicsStateFlags.ReportCollisions);
|
||||
RuntimeEntityRecord target = Entity(
|
||||
lifetime,
|
||||
0x70001F52u,
|
||||
1,
|
||||
PhysicsStateFlags.ReportCollisions);
|
||||
RegisterDynamicShadow(lifetime, target);
|
||||
var observer = new CollisionObserver();
|
||||
using IDisposable subscription = lifetime.Physics.CollisionReports
|
||||
.Subscribe(observer);
|
||||
|
||||
Assert.True(lifetime.Physics.CollisionReports.HandleReports(
|
||||
owner,
|
||||
owner.PhysicsBody!,
|
||||
9d,
|
||||
previousContact: false,
|
||||
previousOnWalkable: false,
|
||||
collidedWithEnvironment: true,
|
||||
ImmutableArray<uint>.Empty));
|
||||
observer.Reports.Clear();
|
||||
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryPrepareSetPositionBatch(
|
||||
owner,
|
||||
owner.PhysicsBody!,
|
||||
10d,
|
||||
previousContact: false,
|
||||
previousOnWalkable: false,
|
||||
finalOnWalkable: false,
|
||||
collidedWithEnvironment: false,
|
||||
[target.Key!.Value.LocalEntityId],
|
||||
out var prepared));
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryInstallSetPositionBatch(
|
||||
prepared!,
|
||||
out var receipt));
|
||||
lifetime.Entities.SetFinalPhysicsState(
|
||||
target,
|
||||
PhysicsStateFlags.ReportAsEnvironment);
|
||||
target.PhysicsBody!.State = PhysicsStateFlags.ReportAsEnvironment;
|
||||
|
||||
lifetime.Physics.CollisionReports.DispatchSetPositionBatch(receipt);
|
||||
|
||||
Assert.Empty(observer.Reports);
|
||||
Assert.Equal(1, lifetime.Physics.CollisionReports.CaptureOwnership()
|
||||
.TrackedObjectCount);
|
||||
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryPrepareSetPositionBatch(
|
||||
owner,
|
||||
owner.PhysicsBody!,
|
||||
11d,
|
||||
previousContact: false,
|
||||
previousOnWalkable: false,
|
||||
finalOnWalkable: false,
|
||||
collidedWithEnvironment: true,
|
||||
ImmutableArray<uint>.Empty,
|
||||
out var next));
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryInstallSetPositionBatch(
|
||||
next!,
|
||||
out var nextReceipt));
|
||||
lifetime.Physics.CollisionReports.DispatchSetPositionBatch(nextReceipt);
|
||||
|
||||
RuntimeCollisionReport report = Assert.Single(observer.Reports);
|
||||
Assert.Equal(RuntimeCollisionReportKind.EnvironmentCollision,
|
||||
report.Kind);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PreparedEnvironmentBatchStopsMissileAddedByCallback()
|
||||
{
|
||||
using var lifetime = Lifetime();
|
||||
RuntimeEntityRecord owner = Entity(
|
||||
lifetime,
|
||||
0x70001F61u,
|
||||
1,
|
||||
PhysicsStateFlags.ReportCollisions);
|
||||
RegisterDynamicShadow(lifetime, owner);
|
||||
const uint staticId = 0x00F01F61u;
|
||||
RegisterShadow(
|
||||
lifetime,
|
||||
staticId,
|
||||
PhysicsStateFlags.Static,
|
||||
isStatic: true);
|
||||
var observer = new CollisionObserver(_ =>
|
||||
{
|
||||
PhysicsStateFlags callbackState = owner.PhysicsBody!.State
|
||||
| PhysicsStateFlags.Missile
|
||||
| PhysicsStateFlags.AlignPath;
|
||||
lifetime.Entities.SetFinalPhysicsState(owner, callbackState);
|
||||
owner.PhysicsBody.State = callbackState;
|
||||
});
|
||||
using IDisposable subscription = lifetime.Physics.CollisionReports
|
||||
.Subscribe(observer);
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryPrepareSetPositionBatch(
|
||||
owner,
|
||||
owner.PhysicsBody!,
|
||||
10d,
|
||||
previousContact: false,
|
||||
previousOnWalkable: false,
|
||||
finalOnWalkable: false,
|
||||
collidedWithEnvironment: false,
|
||||
[staticId],
|
||||
out var prepared));
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryInstallSetPositionBatch(
|
||||
prepared!,
|
||||
out var receipt));
|
||||
|
||||
lifetime.Physics.CollisionReports.DispatchSetPositionBatch(receipt);
|
||||
|
||||
Assert.Single(observer.Reports);
|
||||
Assert.False(owner.FinalPhysicsState.HasFlag(PhysicsStateFlags.Missile));
|
||||
Assert.False(owner.PhysicsBody!.State.HasFlag(PhysicsStateFlags.Missile));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PreparedExistingCollisionRefreshesLiveEtherealBeforeExpiry()
|
||||
{
|
||||
using var lifetime = Lifetime();
|
||||
RuntimeEntityRecord owner = Entity(
|
||||
lifetime,
|
||||
0x70001F71u,
|
||||
1,
|
||||
PhysicsStateFlags.ReportCollisions);
|
||||
RuntimeEntityRecord target = Entity(
|
||||
lifetime,
|
||||
0x70001F72u,
|
||||
1,
|
||||
PhysicsStateFlags.ReportCollisions);
|
||||
RegisterDynamicShadow(lifetime, target);
|
||||
var observer = new CollisionObserver();
|
||||
using IDisposable subscription = lifetime.Physics.CollisionReports
|
||||
.Subscribe(observer);
|
||||
|
||||
DispatchPrepared(
|
||||
lifetime,
|
||||
owner,
|
||||
physicsTime: 10d,
|
||||
[target.Key!.Value.LocalEntityId]);
|
||||
observer.Reports.Clear();
|
||||
PhysicsStateFlags ethereal = PhysicsStateFlags.ReportCollisions
|
||||
| PhysicsStateFlags.Ethereal;
|
||||
lifetime.Entities.SetFinalPhysicsState(target, ethereal);
|
||||
target.PhysicsBody!.State = ethereal;
|
||||
|
||||
DispatchPrepared(
|
||||
lifetime,
|
||||
owner,
|
||||
physicsTime: 10.5d,
|
||||
[target.Key!.Value.LocalEntityId]);
|
||||
Assert.Empty(observer.Reports);
|
||||
DispatchPrepared(
|
||||
lifetime,
|
||||
owner,
|
||||
physicsTime: 10.5001d,
|
||||
ImmutableArray<uint>.Empty);
|
||||
|
||||
Assert.Equal(2, observer.Reports.Count);
|
||||
Assert.All(observer.Reports, report => Assert.Equal(
|
||||
RuntimeCollisionReportKind.ObjectCollisionEnd,
|
||||
report.Kind));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PreparedExistingCollisionBecomingStaticKeepsOldAgeForSamePassEnd()
|
||||
{
|
||||
using var lifetime = Lifetime();
|
||||
RuntimeEntityRecord owner = Entity(
|
||||
lifetime,
|
||||
0x70001F81u,
|
||||
1,
|
||||
PhysicsStateFlags.ReportCollisions);
|
||||
RuntimeEntityRecord target = Entity(
|
||||
lifetime,
|
||||
0x70001F82u,
|
||||
1,
|
||||
PhysicsStateFlags.ReportCollisions);
|
||||
RegisterDynamicShadow(lifetime, target);
|
||||
var observer = new CollisionObserver();
|
||||
using IDisposable subscription = lifetime.Physics.CollisionReports
|
||||
.Subscribe(observer);
|
||||
DispatchPrepared(
|
||||
lifetime,
|
||||
owner,
|
||||
physicsTime: 10d,
|
||||
[target.Key!.Value.LocalEntityId]);
|
||||
observer.Reports.Clear();
|
||||
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryPrepareSetPositionBatch(
|
||||
owner,
|
||||
owner.PhysicsBody!,
|
||||
11.0001d,
|
||||
previousContact: false,
|
||||
previousOnWalkable: false,
|
||||
finalOnWalkable: false,
|
||||
collidedWithEnvironment: false,
|
||||
[target.Key!.Value.LocalEntityId],
|
||||
out var prepared));
|
||||
Assert.True(lifetime.Physics.CollisionReports.TryInstallSetPositionBatch(
|
||||
prepared!,
|
||||
out var receipt));
|
||||
PhysicsStateFlags becameStatic = PhysicsStateFlags.ReportCollisions
|
||||
| PhysicsStateFlags.Static;
|
||||
lifetime.Entities.SetFinalPhysicsState(target, becameStatic);
|
||||
target.PhysicsBody!.State = becameStatic;
|
||||
|
||||
lifetime.Physics.CollisionReports.DispatchSetPositionBatch(receipt);
|
||||
|
||||
Assert.Equal(3, observer.Reports.Count);
|
||||
Assert.Equal(RuntimeCollisionReportKind.EnvironmentCollision,
|
||||
observer.Reports[0].Kind);
|
||||
Assert.Equal(RuntimeCollisionReportKind.ObjectCollisionEnd,
|
||||
observer.Reports[1].Kind);
|
||||
Assert.Equal(RuntimeCollisionReportKind.ObjectCollisionEnd,
|
||||
observer.Reports[2].Kind);
|
||||
Assert.Equal(0, lifetime.Physics.CollisionReports.CaptureOwnership()
|
||||
.TrackedObjectCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExactObjectReportsAreOrderedDeduplicatedAndExpireAtRetailThreshold()
|
||||
{
|
||||
|
|
@ -1656,6 +2254,28 @@ public sealed class RuntimeCollisionReportingStateTests
|
|||
owner.PhysicsBody.OnWalkable,
|
||||
collision);
|
||||
|
||||
private static void DispatchPrepared(
|
||||
RuntimeEntityObjectLifetime lifetime,
|
||||
RuntimeEntityRecord owner,
|
||||
double physicsTime,
|
||||
ImmutableArray<uint> collidedObjectIds)
|
||||
{
|
||||
Assert.True(lifetime.Physics.CollisionReports
|
||||
.TryPrepareSetPositionBatch(
|
||||
owner,
|
||||
owner.PhysicsBody!,
|
||||
physicsTime,
|
||||
previousContact: owner.PhysicsBody!.InContact,
|
||||
previousOnWalkable: owner.PhysicsBody.OnWalkable,
|
||||
finalOnWalkable: owner.PhysicsBody.OnWalkable,
|
||||
collidedWithEnvironment: false,
|
||||
collidedObjectIds,
|
||||
out var prepared));
|
||||
Assert.True(lifetime.Physics.CollisionReports
|
||||
.TryInstallSetPositionBatch(prepared!, out var receipt));
|
||||
lifetime.Physics.CollisionReports.DispatchSetPositionBatch(receipt);
|
||||
}
|
||||
|
||||
private static RuntimeSetPositionCommand PlacementCommand(
|
||||
RuntimeEntityRecord owner,
|
||||
Vector3 position)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue