feat(runtime): own deferred set-position residence
This commit is contained in:
parent
e84a388e6f
commit
4c02ac4259
18 changed files with 5557 additions and 34 deletions
|
|
@ -9,6 +9,20 @@ public readonly record struct RuntimePhysicsOwnershipSnapshot(
|
|||
int SpatialRootCount,
|
||||
int SpatialRemoteCount,
|
||||
int SpatialProjectileCount,
|
||||
int SetPositionOperationCount,
|
||||
int AwaitingSetPositionPreparationCount,
|
||||
int DeferredSetPositionCount,
|
||||
int PendingSetPositionHostAcknowledgementCount,
|
||||
int LostCellDeadlineCount,
|
||||
int LostCellDeadlineNodeCount,
|
||||
int LostCellDeadlineIndexCount,
|
||||
int ExpiredLostCellCount,
|
||||
int ExpiredLostCellIndexCount,
|
||||
int DeferredSetPositionBucketCount,
|
||||
int DeferredSetPositionBucketOrderCount,
|
||||
int UnboundDeferredSetPositionCellCount,
|
||||
int UnboundDeferredSetPositionCellOrderCount,
|
||||
int PreparedSetPositionMoverCount,
|
||||
int CollisionAdmissionCount,
|
||||
int CollisionGenerationCount,
|
||||
bool OwnsProductionDataCache,
|
||||
|
|
@ -21,6 +35,20 @@ public readonly record struct RuntimePhysicsOwnershipSnapshot(
|
|||
&& SpatialRootCount == 0
|
||||
&& SpatialRemoteCount == 0
|
||||
&& SpatialProjectileCount == 0
|
||||
&& SetPositionOperationCount == 0
|
||||
&& AwaitingSetPositionPreparationCount == 0
|
||||
&& DeferredSetPositionCount == 0
|
||||
&& PendingSetPositionHostAcknowledgementCount == 0
|
||||
&& LostCellDeadlineCount == 0
|
||||
&& LostCellDeadlineNodeCount == 0
|
||||
&& LostCellDeadlineIndexCount == 0
|
||||
&& ExpiredLostCellCount == 0
|
||||
&& ExpiredLostCellIndexCount == 0
|
||||
&& DeferredSetPositionBucketCount == 0
|
||||
&& DeferredSetPositionBucketOrderCount == 0
|
||||
&& UnboundDeferredSetPositionCellCount == 0
|
||||
&& UnboundDeferredSetPositionCellOrderCount == 0
|
||||
&& PreparedSetPositionMoverCount == 0
|
||||
&& CollisionAdmissionCount == 0
|
||||
&& CollisionGenerationCount == 0
|
||||
&& OwnsProductionDataCache;
|
||||
|
|
@ -979,6 +1007,7 @@ internal readonly record struct RuntimeCollisionSealStep(
|
|||
public sealed class RuntimePhysicsState : IDisposable
|
||||
{
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly IGameRuntimeClock? _gameClock;
|
||||
private readonly Dictionary<RuntimeEntityKey, RuntimeEntityRecord>
|
||||
_spatialRoots = new();
|
||||
private readonly Dictionary<RuntimeEntityKey, IRuntimeRemoteMotion>
|
||||
|
|
@ -1020,10 +1049,12 @@ public sealed class RuntimePhysicsState : IDisposable
|
|||
internal RuntimePhysicsState(
|
||||
RuntimeEntityDirectory entities,
|
||||
PhysicsDataCache? dataCache = null,
|
||||
TimeProvider? timeProvider = null)
|
||||
TimeProvider? timeProvider = null,
|
||||
IGameRuntimeClock? gameClock = null)
|
||||
{
|
||||
Entities = entities ?? throw new ArgumentNullException(nameof(entities));
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
_gameClock = gameClock;
|
||||
DataCache = dataCache ?? PhysicsDataCache.CreateProduction();
|
||||
Engine = new PhysicsEngine
|
||||
{
|
||||
|
|
@ -1032,15 +1063,18 @@ public sealed class RuntimePhysicsState : IDisposable
|
|||
Engine.ShadowObjects.OwnerMutated += OnCollisionOwnerMutated;
|
||||
Engine.ShadowObjects.OwnerPrefixMembershipChanged +=
|
||||
OnCollisionOwnerPrefixMembershipChanged;
|
||||
SetPosition = new RuntimeSetPositionState(this, Entities);
|
||||
}
|
||||
|
||||
internal RuntimePhysicsState(
|
||||
RuntimeEntityDirectory entities,
|
||||
PhysicsEngine engine,
|
||||
TimeProvider? timeProvider = null)
|
||||
TimeProvider? timeProvider = null,
|
||||
IGameRuntimeClock? gameClock = null)
|
||||
{
|
||||
Entities = entities ?? throw new ArgumentNullException(nameof(entities));
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
_gameClock = gameClock;
|
||||
Engine = engine ?? throw new ArgumentNullException(nameof(engine));
|
||||
DataCache = engine.DataCache
|
||||
?? PhysicsDataCache.CreateProduction(engine.CollisionWorld);
|
||||
|
|
@ -1048,11 +1082,13 @@ public sealed class RuntimePhysicsState : IDisposable
|
|||
Engine.ShadowObjects.OwnerMutated += OnCollisionOwnerMutated;
|
||||
Engine.ShadowObjects.OwnerPrefixMembershipChanged +=
|
||||
OnCollisionOwnerPrefixMembershipChanged;
|
||||
SetPosition = new RuntimeSetPositionState(this, Entities);
|
||||
}
|
||||
|
||||
internal RuntimeEntityDirectory Entities { get; }
|
||||
public PhysicsEngine Engine { get; }
|
||||
public PhysicsDataCache DataCache { get; }
|
||||
internal RuntimeSetPositionState SetPosition { get; }
|
||||
public int SpatialRootCount => _spatialRoots.Count;
|
||||
public int SpatialRemoteCount => _spatialRemotes.Count;
|
||||
public int SpatialProjectileCount => _spatialProjectiles.Count;
|
||||
|
|
@ -1061,18 +1097,41 @@ public sealed class RuntimePhysicsState : IDisposable
|
|||
internal double UtcNowSeconds =>
|
||||
(_timeProvider.GetUtcNow() - DateTimeOffset.UnixEpoch)
|
||||
.TotalSeconds;
|
||||
internal double MonotonicNowSeconds =>
|
||||
_timeProvider.GetTimestamp()
|
||||
/ (double)_timeProvider.TimestampFrequency;
|
||||
internal double PlacementSimulationTime(double fallback) =>
|
||||
_gameClock?.SimulationTimeSeconds ?? fallback;
|
||||
|
||||
public RuntimePhysicsOwnershipSnapshot CaptureOwnership() =>
|
||||
new(
|
||||
public RuntimePhysicsOwnershipSnapshot CaptureOwnership()
|
||||
{
|
||||
RuntimeSetPositionOwnershipSnapshot setPosition =
|
||||
SetPosition.CaptureOwnership();
|
||||
return new(
|
||||
Engine.LandblockCount,
|
||||
Engine.ShadowObjects.RetainedRegistrationCount,
|
||||
_spatialRoots.Count,
|
||||
_spatialRemotes.Count,
|
||||
_spatialProjectiles.Count,
|
||||
setPosition.ActiveOperationCount,
|
||||
setPosition.AwaitingPreparationCount,
|
||||
setPosition.DeferredCellCount,
|
||||
setPosition.PendingProjectionAcknowledgementCount,
|
||||
setPosition.LostDeadlineCount,
|
||||
setPosition.LostDeadlineNodeCount,
|
||||
setPosition.LostDeadlineIndexCount,
|
||||
setPosition.ExpiredLostCellCount,
|
||||
setPosition.ExpiredLostCellIndexCount,
|
||||
setPosition.DeferredBucketCount,
|
||||
setPosition.DeferredBucketOrderCount,
|
||||
setPosition.UnboundDeferredCellCount,
|
||||
setPosition.UnboundDeferredCellOrderCount,
|
||||
setPosition.PreparedMoverCount,
|
||||
_collisionAdmissions.Count,
|
||||
_collisionGenerations.Count,
|
||||
ReferenceEquals(Engine.DataCache, DataCache),
|
||||
_disposed);
|
||||
}
|
||||
|
||||
public void AcknowledgeSpatialProjection(
|
||||
RuntimeEntityRecord record,
|
||||
|
|
@ -1806,6 +1865,20 @@ public sealed class RuntimePhysicsState : IDisposable
|
|||
EnsureNotDisposed();
|
||||
EnsureCollisionMutationThread();
|
||||
uint canonical = CanonicalLandblock(landblockId);
|
||||
if (_collisionAdmissions.Remove(
|
||||
canonical,
|
||||
out RuntimeCollisionAdmission? superseded))
|
||||
{
|
||||
SetPosition.CancelCollisionGeneration(
|
||||
canonical,
|
||||
superseded.Generation);
|
||||
if (_preparedCollisionGenerations.Remove(
|
||||
canonical,
|
||||
out PreparedLandblockCollisionGeneration? prepared))
|
||||
{
|
||||
prepared.Dispose();
|
||||
}
|
||||
}
|
||||
ulong generation = _collisionGenerations.TryGetValue(
|
||||
canonical,
|
||||
out ulong current)
|
||||
|
|
@ -1817,6 +1890,7 @@ public sealed class RuntimePhysicsState : IDisposable
|
|||
canonical,
|
||||
generation);
|
||||
_collisionAdmissions[canonical] = admission;
|
||||
SetPosition.BeginCollisionGeneration(canonical, generation);
|
||||
return admission;
|
||||
}
|
||||
|
||||
|
|
@ -1901,6 +1975,9 @@ public sealed class RuntimePhysicsState : IDisposable
|
|||
&& ReferenceEquals(current, admission))
|
||||
{
|
||||
_collisionAdmissions.Remove(admission.LandblockId);
|
||||
SetPosition.CancelCollisionGeneration(
|
||||
admission.LandblockId,
|
||||
admission.Generation);
|
||||
_collisionGenerations[admission.LandblockId] = checked(
|
||||
admission.Generation + 1UL);
|
||||
}
|
||||
|
|
@ -2137,6 +2214,10 @@ public sealed class RuntimePhysicsState : IDisposable
|
|||
admission.Generation,
|
||||
Engine.IsLandblockTerrainResident(admission.LandblockId),
|
||||
Ready: Engine.IsLandblockTerrainResident(admission.LandblockId));
|
||||
SetPosition.CommitCollisionGeneration(
|
||||
acknowledgement.LandblockId,
|
||||
acknowledgement.Generation,
|
||||
acknowledgement.Ready);
|
||||
PublishCollisionGenerationCommitted(
|
||||
new RuntimeCollisionGenerationCommitted(
|
||||
acknowledgement.LandblockId,
|
||||
|
|
@ -2221,6 +2302,7 @@ public sealed class RuntimePhysicsState : IDisposable
|
|||
prepared.Dispose();
|
||||
}
|
||||
_preparedCollisionGenerations.Clear();
|
||||
SetPosition.Dispose();
|
||||
_collisionOwnerJournal.Clear();
|
||||
_collisionOwnerSubscribers.Clear();
|
||||
Engine.Clear();
|
||||
|
|
@ -2380,12 +2462,22 @@ public sealed class RuntimePhysicsState : IDisposable
|
|||
|
||||
private void InvalidateCollisionAdmission(uint landblockId)
|
||||
{
|
||||
ulong generation = _collisionGenerations.TryGetValue(
|
||||
ulong currentGeneration = _collisionGenerations.TryGetValue(
|
||||
landblockId,
|
||||
out ulong current)
|
||||
? checked(current + 1UL)
|
||||
: 1UL;
|
||||
? current
|
||||
: 0UL;
|
||||
ulong invalidatedGeneration = _collisionAdmissions.TryGetValue(
|
||||
landblockId,
|
||||
out RuntimeCollisionAdmission? admission)
|
||||
? admission.Generation
|
||||
: checked(currentGeneration + 1UL);
|
||||
ulong generation = checked(
|
||||
Math.Max(currentGeneration, invalidatedGeneration) + 1UL);
|
||||
_collisionGenerations[landblockId] = generation;
|
||||
SetPosition.CancelCollisionGeneration(
|
||||
landblockId,
|
||||
invalidatedGeneration);
|
||||
_collisionAdmissions.Remove(landblockId);
|
||||
if (_preparedCollisionGenerations.Remove(
|
||||
landblockId,
|
||||
|
|
@ -2396,6 +2488,70 @@ public sealed class RuntimePhysicsState : IDisposable
|
|||
TrimCollisionOwnerJournal();
|
||||
}
|
||||
|
||||
internal ulong ExpectedCollisionGeneration(uint exactCellId)
|
||||
{
|
||||
uint landblockId = CanonicalLandblock(exactCellId);
|
||||
if (landblockId == 0u)
|
||||
return 0UL;
|
||||
if (_collisionAdmissions.TryGetValue(
|
||||
landblockId,
|
||||
out RuntimeCollisionAdmission? admission))
|
||||
{
|
||||
return admission.Generation;
|
||||
}
|
||||
return _collisionGenerations.TryGetValue(
|
||||
landblockId,
|
||||
out ulong generation)
|
||||
? checked(generation + 1UL)
|
||||
: 1UL;
|
||||
}
|
||||
|
||||
internal bool HandleSetPositionCollisions(
|
||||
RuntimeEntityRecord record,
|
||||
ulong positionAuthorityVersion,
|
||||
ulong spatialAuthorityVersion,
|
||||
ulong velocityAuthorityVersion,
|
||||
bool previousContact,
|
||||
bool previousOnWalkable,
|
||||
in PhysicsSetPositionCollisionReport report)
|
||||
{
|
||||
if (!Entities.IsCurrent(record)
|
||||
|| record.PositionAuthorityVersion != positionAuthorityVersion
|
||||
|| record.SpatialAuthorityVersion != spatialAuthorityVersion
|
||||
|| (velocityAuthorityVersion != 0UL
|
||||
&& record.VelocityAuthorityVersion
|
||||
!= velocityAuthorityVersion)
|
||||
|| record.PhysicsBody is not { } body)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
body.FramesStationaryFall = report.FramesStationaryFall;
|
||||
PhysicsObjUpdate.HandleAllCollisions(
|
||||
body,
|
||||
report.CollisionNormalValid,
|
||||
report.CollisionNormal,
|
||||
previousContact,
|
||||
previousOnWalkable,
|
||||
body.OnWalkable);
|
||||
body.TransientState &= ~(TransientStateFlags.StationaryFall
|
||||
| TransientStateFlags.StationaryStop
|
||||
| TransientStateFlags.StationaryStuck);
|
||||
body.TransientState |= report.FramesStationaryFall switch
|
||||
{
|
||||
1 => TransientStateFlags.StationaryFall,
|
||||
2 => TransientStateFlags.StationaryStop,
|
||||
3 => TransientStateFlags.StationaryStuck,
|
||||
_ => TransientStateFlags.None,
|
||||
};
|
||||
// Retail returns the result of collision reporting, not a collision-
|
||||
// presence guess. Runtime does not yet own the per-object report/
|
||||
// tracking table required to reproduce that return value, so fail
|
||||
// closed. This preserves ordinary placement rejection and leaves the
|
||||
// already-registered reporting seam explicit for the 4B2 cutover.
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnCollisionOwnerMutated(uint ownerId, ulong version)
|
||||
{
|
||||
_ = version;
|
||||
|
|
|
|||
2014
src/AcDream.Runtime/Physics/RuntimeSetPositionState.cs
Normal file
2014
src/AcDream.Runtime/Physics/RuntimeSetPositionState.cs
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue