feat(runtime): seal dormant SetPosition evaluations

This commit is contained in:
Erik 2026-08-01 11:31:58 +02:00
parent 22651c823d
commit 99f867f053
16 changed files with 2298 additions and 62 deletions

View file

@ -1,3 +1,5 @@
using System.Collections.Immutable;
using AcDream.Core.Items;
using AcDream.Core.Physics;
using AcDream.Runtime.Entities;
@ -1042,6 +1044,7 @@ public sealed class RuntimePhysicsState : IDisposable
private bool _suppressCollisionOwnerJournal;
private long _nextCollisionPreparationSequence;
private long _latestCollisionPreparationStartSequence;
private ulong _collisionWorldAuthority = 1UL;
private readonly List<Action<RuntimeCollisionGenerationCommitted>>
_collisionGenerationCommittedObservers = new();
private bool _disposed;
@ -1898,6 +1901,7 @@ public sealed class RuntimePhysicsState : IDisposable
EnsureNotDisposed();
EnsureCollisionMutationThread();
uint canonical = CanonicalLandblock(landblockId);
AdvanceCollisionWorldAuthority();
if (_collisionAdmissions.Remove(
canonical,
out RuntimeCollisionAdmission? superseded))
@ -2013,6 +2017,7 @@ public sealed class RuntimePhysicsState : IDisposable
admission.Generation);
_collisionGenerations[admission.LandblockId] = checked(
admission.Generation + 1UL);
AdvanceCollisionWorldAuthority();
}
TrimCollisionOwnerJournal();
}
@ -2226,6 +2231,7 @@ public sealed class RuntimePhysicsState : IDisposable
try
{
Engine.CommitLandblockReplacement(replacement);
AdvanceCollisionWorldAuthority();
}
finally
{
@ -2496,6 +2502,7 @@ public sealed class RuntimePhysicsState : IDisposable
private void InvalidateCollisionAdmission(uint landblockId)
{
AdvanceCollisionWorldAuthority();
ulong currentGeneration = _collisionGenerations.TryGetValue(
landblockId,
out ulong current)
@ -2540,6 +2547,130 @@ public sealed class RuntimePhysicsState : IDisposable
: 1UL;
}
/// <summary>
/// Exact collision-prefix generation authority used by private
/// SetPosition evaluations. Beginning a replacement generation advances
/// this authority immediately, so a receipt cannot survive a prepared
/// world replacement and later observe different collision rows.
/// </summary>
internal ulong CollisionGenerationAuthority(uint exactCellId)
{
uint landblockId = CanonicalLandblock(exactCellId);
return landblockId != 0u
&& _collisionGenerations.TryGetValue(
landblockId,
out ulong generation)
? generation
: 0UL;
}
internal ulong CollisionWorldAuthority => _collisionWorldAuthority;
internal ulong ShadowWorldAuthority =>
Engine.ShadowObjects.MutationRevision;
internal ClientObjectTable? ObjectTable => Engine.Objects;
internal ulong ObjectTableBindingAuthority =>
Engine.ObjectsBindingRevision;
internal ulong ObjectTableAuthority =>
ObjectTable?.MutationRevision ?? 0UL;
private void AdvanceCollisionWorldAuthority() =>
_collisionWorldAuthority = checked(_collisionWorldAuthority + 1UL);
internal bool TrySealCollisionEvaluationAuthority(
in PhysicsSetPositionResult result,
ulong expectedCollisionWorldAuthority,
ulong expectedShadowWorldAuthority,
ClientObjectTable? expectedObjectTable,
ulong expectedObjectTableBindingAuthority,
ulong expectedObjectTableAuthority,
out RuntimeCollisionEvaluationAuthority authority)
{
authority = default;
if (_collisionWorldAuthority != expectedCollisionWorldAuthority
|| ShadowWorldAuthority != expectedShadowWorldAuthority
|| !ReferenceEquals(ObjectTable, expectedObjectTable)
|| ObjectTableBindingAuthority
!= expectedObjectTableBindingAuthority
|| ObjectTableAuthority != expectedObjectTableAuthority)
{
return false;
}
var prefixes = new HashSet<uint>();
var authorities = ImmutableArray.CreateBuilder<
RuntimeCollisionGenerationAuthority>();
void Add(uint cellId)
{
uint landblock = CanonicalLandblock(cellId);
if (landblock == 0u || !prefixes.Add(landblock))
return;
authorities.Add(new RuntimeCollisionGenerationAuthority(
landblock,
CollisionGenerationAuthority(landblock)));
}
Add(result.CellId);
if (!result.QueriedCellIds.IsDefaultOrEmpty)
{
foreach (uint cellId in result.QueriedCellIds)
Add(cellId);
}
foreach (uint prefix in prefixes)
{
if (_collisionAdmissions.ContainsKey(prefix))
return false;
}
if (_collisionWorldAuthority != expectedCollisionWorldAuthority
|| ShadowWorldAuthority != expectedShadowWorldAuthority
|| !ReferenceEquals(ObjectTable, expectedObjectTable)
|| ObjectTableBindingAuthority
!= expectedObjectTableBindingAuthority
|| ObjectTableAuthority != expectedObjectTableAuthority)
{
return false;
}
authority = new RuntimeCollisionEvaluationAuthority(
expectedCollisionWorldAuthority,
expectedShadowWorldAuthority,
expectedObjectTable,
expectedObjectTableBindingAuthority,
expectedObjectTableAuthority,
authorities.ToImmutable());
return true;
}
internal bool IsCollisionEvaluationAuthorityCurrent(
in RuntimeCollisionEvaluationAuthority authority)
{
if (!authority.IsValid
|| _collisionWorldAuthority != authority.CollisionWorldAuthority
|| ShadowWorldAuthority != authority.ShadowWorldAuthority
|| !ReferenceEquals(ObjectTable, authority.ObjectTable)
|| ObjectTableBindingAuthority
!= authority.ObjectTableBindingAuthority
|| ObjectTableAuthority != authority.ObjectTableAuthority)
{
return false;
}
foreach (RuntimeCollisionGenerationAuthority generation
in authority.Generations)
{
if (generation.LandblockId == 0u
|| _collisionAdmissions.ContainsKey(generation.LandblockId)
|| CollisionGenerationAuthority(generation.LandblockId)
!= generation.Generation)
{
return false;
}
}
return true;
}
internal bool HandleSetPositionCollisions(
RuntimeEntityRecord record,
ulong positionAuthorityVersion,