refactor(runtime): own per-session physics simulation

Move the sole PhysicsEngine, production cache, collision admissions, canonical bodies and hosts, remote components, ordinary/remote worksets, simulation, cell commits, and shadow synchronization under RuntimeEntityObjectLifetime. Keep App as the prepared-asset, animation-input, and render-projection adapter while preserving the named-retail update and collision order.

Add exact-incarnation, object-clock, callback-reentrancy, GUID-reuse, two-runtime isolation, source ownership, collision publication, and graphical projection coverage. Release build and the complete 8,588-test solution pass.

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Erik 2026-07-26 13:39:57 +02:00
parent 0dc3bfdeff
commit 7e6033d0ad
39 changed files with 3685 additions and 1722 deletions

View file

@ -0,0 +1,787 @@
using AcDream.Core.Physics;
using AcDream.Runtime.Entities;
namespace AcDream.Runtime.Physics;
public readonly record struct RuntimePhysicsOwnershipSnapshot(
int LandblockCount,
int RetainedShadowRegistrationCount,
int SpatialRootCount,
int SpatialRemoteCount,
int CollisionAdmissionCount,
int CollisionGenerationCount,
bool OwnsProductionDataCache,
bool IsDisposed);
public readonly record struct RuntimePhysicsCellCommit(
RuntimeEntityRecord Record,
uint PreviousFullCellId,
uint FullCellId,
ulong SpatialAuthorityVersion);
public sealed record RuntimeLandblockCollisionAssets(
uint LandblockId,
TerrainSurface Terrain,
IReadOnlyList<CellSurface> CellSurfaces,
IReadOnlyList<PortalPlane> PortalPlanes,
float WorldOffsetX,
float WorldOffsetY,
uint CurrentCellId);
public sealed class RuntimeCollisionAdmission
{
internal RuntimeCollisionAdmission(
RuntimePhysicsState owner,
uint landblockId,
ulong generation)
{
Owner = owner;
LandblockId = landblockId;
Generation = generation;
}
internal RuntimePhysicsState Owner { get; }
internal bool AssetsAdmitted { get; set; }
internal bool Completed { get; set; }
public uint LandblockId { get; }
public ulong Generation { get; }
}
public readonly record struct RuntimeCollisionAcknowledgement(
uint LandblockId,
ulong Generation,
bool WasResident);
/// <summary>
/// Presentation-free mutable physics world for one Runtime/session owner.
/// Immutable prepared collision inputs may be supplied by a graphical or
/// no-window host, but the engine, transition scratch, cell graph, and shadow
/// registry are never shared between Runtime instances.
/// </summary>
public sealed class RuntimePhysicsState : IDisposable
{
private readonly Dictionary<RuntimeEntityKey, RuntimeEntityRecord>
_spatialRoots = new();
private readonly Dictionary<RuntimeEntityKey, IRuntimeRemoteMotion>
_spatialRemotes = new();
private readonly Dictionary<uint, ulong> _collisionGenerations = new();
private readonly Dictionary<uint, RuntimeCollisionAdmission>
_collisionAdmissions = new();
private bool _disposed;
public event Action<RuntimePhysicsCellCommit>? CellCommitted;
internal RuntimePhysicsState(
RuntimeEntityDirectory entities,
PhysicsDataCache? dataCache = null)
{
Entities = entities ?? throw new ArgumentNullException(nameof(entities));
DataCache = dataCache ?? PhysicsDataCache.CreateProduction();
Engine = new PhysicsEngine
{
DataCache = DataCache,
};
}
internal RuntimeEntityDirectory Entities { get; }
public PhysicsEngine Engine { get; }
public PhysicsDataCache DataCache { get; }
public int SpatialRootCount => _spatialRoots.Count;
public int SpatialRemoteCount => _spatialRemotes.Count;
public RuntimePhysicsOwnershipSnapshot CaptureOwnership() =>
new(
Engine.LandblockCount,
Engine.ShadowObjects.RetainedRegistrationCount,
_spatialRoots.Count,
_spatialRemotes.Count,
_collisionAdmissions.Count,
_collisionGenerations.Count,
ReferenceEquals(Engine.DataCache, DataCache),
_disposed);
public void AcknowledgeSpatialProjection(
RuntimeEntityRecord record,
bool spatial)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(record);
if (record.Key is not { } key)
{
if (spatial)
{
throw new InvalidOperationException(
$"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} cannot enter the physics workset without a local identity.");
}
return;
}
if (spatial && Entities.IsCurrent(record))
{
_spatialRoots[key] = record;
if (record.RemoteMotion is { } remote)
_spatialRemotes[key] = remote;
else
_spatialRemotes.Remove(key);
return;
}
RemoveSpatialProjection(record);
}
public void RefreshRemoteComponent(RuntimeEntityRecord record)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(record);
if (record.Key is not { } key
|| !_spatialRoots.TryGetValue(key, out RuntimeEntityRecord? root)
|| !ReferenceEquals(root, record)
|| !Entities.IsCurrent(record))
{
RemoveSpatialRemote(record);
return;
}
if (record.RemoteMotion is { } remote)
_spatialRemotes[key] = remote;
else
_spatialRemotes.Remove(key);
}
public void SetRemoteMotion(
RuntimeEntityRecord record,
IRuntimeRemoteMotion runtime,
Func<bool>? externalOwnerValid = null)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(record);
ArgumentNullException.ThrowIfNull(runtime);
EnsureCurrent(record);
if (!(externalOwnerValid?.Invoke() ?? true))
{
throw new InvalidOperationException(
$"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} changed external ownership before remote-motion binding.");
}
if (record.RemoteMotionBindingInProgress)
{
throw new InvalidOperationException(
$"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} remote-motion binding is already in progress.");
}
PhysicsBody candidateBody = runtime.Body
?? throw new InvalidOperationException(
"A remote-motion runtime returned no physics body.");
if (ReferenceEquals(record.RemoteMotion, runtime))
{
if (!ReferenceEquals(record.PhysicsBody, candidateBody))
{
throw new InvalidOperationException(
$"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} remote motion changed its canonical physics body.");
}
candidateBody.State = record.FinalPhysicsState;
SynchronizeBodyActiveState(record);
RefreshRemoteComponent(record);
return;
}
if (record.PhysicsBodyAcquisitionInProgress
&& record.PhysicsBody is null)
{
throw new InvalidOperationException(
$"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} cannot bind remote motion during physics-body acquisition.");
}
if (record.PhysicsBody is { } canonicalBody
&& !ReferenceEquals(canonicalBody, candidateBody))
{
throw new InvalidOperationException(
$"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} cannot replace its canonical physics body.");
}
if (record.RequiresRemotePlacementRuntime
&& runtime is not IRuntimeRemotePlacement)
{
throw new InvalidOperationException(
$"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} cannot discard its remote-placement contract.");
}
ulong sessionVersion = Entities.SessionLifetimeVersion;
PhysicsBody? expectedBody = record.PhysicsBody;
IRuntimeRemoteMotion? expectedRuntime = record.RemoteMotion;
bool expectedPlacementContract =
record.RequiresRemotePlacementRuntime;
Func<AcDream.Core.Physics.Motion.IPhysicsObjHost?> readPhysicsHost =
() => Entities.IsCurrent(record)
&& ReferenceEquals(record.RemoteMotion, runtime)
? record.PhysicsHost
: null;
Func<uint> readCell = () => record.FullCellId;
Action<uint> writeCell = cellId =>
CommitCanonicalCell(record, runtime, cellId);
Entities.SetRemoteMotionBindingInProgress(record, true);
try
{
if (runtime is IRuntimeCanonicalPhysicsConsumer canonicalConsumer)
{
canonicalConsumer.BindCanonicalRuntime(
readPhysicsHost,
readCell,
writeCell);
}
else
{
bool consumesHost = runtime is IRuntimePhysicsHostConsumer;
bool consumesCell = runtime is IRuntimeCanonicalCellConsumer;
if (consumesHost && consumesCell)
{
throw new InvalidOperationException(
"A remote runtime that consumes both canonical host and cell identity must bind them atomically.");
}
if (runtime is IRuntimePhysicsHostConsumer hostConsumer)
hostConsumer.BindPhysicsHost(readPhysicsHost);
if (runtime is IRuntimeCanonicalCellConsumer cellConsumer)
cellConsumer.BindCanonicalCell(readCell, writeCell);
}
if (Entities.SessionLifetimeVersion != sessionVersion
|| !Entities.IsCurrent(record)
|| !ReferenceEquals(record.PhysicsBody, expectedBody)
|| !ReferenceEquals(record.RemoteMotion, expectedRuntime)
|| record.RequiresRemotePlacementRuntime
!= expectedPlacementContract
|| !(externalOwnerValid?.Invoke() ?? true))
{
throw new InvalidOperationException(
$"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} changed ownership during remote-motion binding.");
}
Entities.SetRequiresRemotePlacementRuntime(
record,
expectedPlacementContract
|| runtime is IRuntimeRemotePlacement);
Entities.SetRemoteMotion(record, runtime);
Entities.SetPhysicsBody(record, candidateBody);
candidateBody.State = record.FinalPhysicsState;
SynchronizeBodyActiveState(record);
RefreshRemoteComponent(record);
}
finally
{
if (Entities.IsCurrent(record))
{
Entities.SetRemoteMotionBindingInProgress(record, false);
}
}
}
/// <summary>
/// Acquires the one retail <c>CPhysicsObj</c> body for an exact accepted
/// object incarnation. Factories may cross a host boundary, so ownership
/// is revalidated after the callback before the body becomes canonical.
/// </summary>
public PhysicsBody GetOrCreatePhysicsBody(
RuntimeEntityRecord record,
Func<RuntimeEntityRecord, PhysicsBody> factory,
Func<bool>? externalOwnerValid = null)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(record);
ArgumentNullException.ThrowIfNull(factory);
EnsureCurrent(record);
if (!(externalOwnerValid?.Invoke() ?? true))
{
throw new InvalidOperationException(
$"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} changed external ownership before physics-body acquisition.");
}
if (record.PhysicsBody is { } retained)
return retained;
if (record.PhysicsBodyAcquisitionInProgress)
{
throw new InvalidOperationException(
$"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} physics-body acquisition is already in progress.");
}
Entities.SetPhysicsBodyAcquisitionInProgress(record, true);
try
{
PhysicsBody candidate = factory(record)
?? throw new InvalidOperationException(
"Physics-body factory returned null.");
if (!Entities.IsCurrent(record)
|| !(externalOwnerValid?.Invoke() ?? true))
{
throw new InvalidOperationException(
$"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} changed ownership during physics-body acquisition.");
}
if (record.PhysicsBody is { } concurrentlyBound)
{
if (ReferenceEquals(concurrentlyBound, candidate))
return concurrentlyBound;
throw new InvalidOperationException(
$"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} acquired two physics bodies within one incarnation.");
}
Entities.SetPhysicsBody(record, candidate);
candidate.State = record.FinalPhysicsState;
SynchronizeBodyActiveState(record);
return candidate;
}
finally
{
// A callback can retire this incarnation. The in-progress bit
// belongs to the record itself and must not strand its teardown.
if (Entities.IsCurrent(record))
Entities.SetPhysicsBodyAcquisitionInProgress(record, false);
else
record.PhysicsBodyAcquisitionInProgress = false;
}
}
public void InstallPhysicsHost(
RuntimeEntityRecord record,
AcDream.Core.Physics.Motion.IPhysicsObjHost host,
Func<bool>? externalOwnerValid = null)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(record);
ArgumentNullException.ThrowIfNull(host);
EnsureCurrent(record);
if (host.Id != record.ServerGuid)
{
throw new ArgumentException(
"A physics host must match its runtime entity GUID.",
nameof(host));
}
if (!(externalOwnerValid?.Invoke() ?? true))
{
throw new InvalidOperationException(
$"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} changed external ownership before physics-host installation.");
}
if (record.PhysicsHost is not null)
{
throw new InvalidOperationException(
$"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} already owns its incarnation-stable physics host.");
}
Entities.SetPhysicsHost(record, host);
if (!Entities.IsCurrent(record)
|| !(externalOwnerValid?.Invoke() ?? true))
{
if (ReferenceEquals(record.PhysicsHost, host))
record.PhysicsHost = null;
throw new InvalidOperationException(
$"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} changed ownership during physics-host installation.");
}
}
public EntityPhysicsHost InstallOrRebindPhysicsHost(
RuntimeEntityRecord record,
EntityPhysicsHost configuration,
Func<bool>? externalOwnerValid = null)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(record);
ArgumentNullException.ThrowIfNull(configuration);
EnsureCurrent(record);
if (!(externalOwnerValid?.Invoke() ?? true))
{
throw new InvalidOperationException(
$"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} changed external ownership before physics-host composition.");
}
if (record.PhysicsHost is null)
{
InstallPhysicsHost(record, configuration, externalOwnerValid);
return configuration;
}
if (record.PhysicsHost is not EntityPhysicsHost existing)
{
throw new InvalidOperationException(
$"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} owns an incompatible physics-host implementation.");
}
existing.RebindFrom(configuration);
if (!Entities.IsCurrent(record)
|| !(externalOwnerValid?.Invoke() ?? true))
{
throw new InvalidOperationException(
$"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} changed ownership during physics-host composition.");
}
return existing;
}
public EntityPhysicsHost SelectStablePhysicsHostWithoutRebind(
RuntimeEntityRecord record,
EntityPhysicsHost configuration,
Func<bool>? externalOwnerValid = null)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(record);
ArgumentNullException.ThrowIfNull(configuration);
EnsureCurrent(record);
if (!(externalOwnerValid?.Invoke() ?? true))
{
throw new InvalidOperationException(
$"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} changed external ownership during physics-host preparation.");
}
return record.PhysicsHost switch
{
null => configuration,
EntityPhysicsHost existing => existing,
_ => throw new InvalidOperationException(
$"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} owns an incompatible physics-host implementation."),
};
}
public bool TryGetPhysicsHost(
uint serverGuid,
out AcDream.Core.Physics.Motion.IPhysicsObjHost host)
{
EnsureNotDisposed();
if (Entities.TryGetActive(serverGuid, out RuntimeEntityRecord record)
&& record.PhysicsHost is { } existing)
{
host = existing;
return true;
}
host = null!;
return false;
}
public bool ClearRemoteMotion(RuntimeEntityRecord record)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(record);
if (!Entities.IsCurrent(record)
|| record.RemoteMotion is null)
{
return false;
}
Entities.SetRemoteMotion(record, null);
RefreshRemoteComponent(record);
return true;
}
public void RemoveSpatialProjection(RuntimeEntityRecord record)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(record);
if (record.Key is not { } key)
return;
if (_spatialRoots.TryGetValue(key, out RuntimeEntityRecord? root)
&& ReferenceEquals(root, record))
{
_spatialRoots.Remove(key);
}
RemoveSpatialRemote(record);
}
public bool IsSpatialRoot(RuntimeEntityRecord record) =>
record.Key is { } key
&& Entities.IsCurrent(record)
&& _spatialRoots.TryGetValue(key, out RuntimeEntityRecord? indexed)
&& ReferenceEquals(indexed, record);
public bool IsSpatialRemote(
RuntimeEntityRecord record,
IRuntimeRemoteMotion remote) =>
IsSpatialRoot(record)
&& ReferenceEquals(record.RemoteMotion, remote)
&& record.Key is { } key
&& _spatialRemotes.TryGetValue(key, out IRuntimeRemoteMotion? indexed)
&& ReferenceEquals(indexed, remote);
public void CopySpatialRootsTo(List<RuntimeEntityRecord> destination)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(destination);
destination.Clear();
foreach ((RuntimeEntityKey key, RuntimeEntityRecord record)
in _spatialRoots)
{
if (record.Key == key
&& Entities.IsCurrent(record))
{
destination.Add(record);
}
}
}
public void CopySpatialRemotesTo(List<RuntimeEntityRecord> destination)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(destination);
destination.Clear();
foreach ((RuntimeEntityKey key, IRuntimeRemoteMotion remote)
in _spatialRemotes)
{
if (Entities.TryGetByLocalId(
key.LocalEntityId,
out RuntimeEntityRecord record)
&& record.Key == key
&& ReferenceEquals(record.RemoteMotion, remote)
&& IsSpatialRoot(record))
{
destination.Add(record);
}
}
}
internal bool CommitOrdinaryCell(
RuntimeEntityRecord record,
PhysicsBody body,
ulong objectClockEpoch,
uint fullCellId,
Func<bool>? externalOwnerValid)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(record);
ArgumentNullException.ThrowIfNull(body);
bool IsExactOwner() =>
IsSpatialRoot(record)
&& record.ObjectClockEpoch == objectClockEpoch
&& ReferenceEquals(record.PhysicsBody, body)
&& record.RemoteMotion is null
&& (externalOwnerValid?.Invoke() ?? true);
return CommitCanonicalCell(
record,
fullCellId,
IsExactOwner);
}
public void ClearSpatialWorksets()
{
EnsureNotDisposed();
_spatialRemotes.Clear();
_spatialRoots.Clear();
}
public RuntimeCollisionAdmission BeginCollisionAdmission(
uint landblockId)
{
EnsureNotDisposed();
uint canonical = CanonicalLandblock(landblockId);
ulong generation = _collisionGenerations.TryGetValue(
canonical,
out ulong current)
? checked(current + 1UL)
: 1UL;
_collisionGenerations[canonical] = generation;
var admission = new RuntimeCollisionAdmission(
this,
canonical,
generation);
_collisionAdmissions[canonical] = admission;
return admission;
}
public void AdmitCollisionAssets(
RuntimeCollisionAdmission admission,
RuntimeLandblockCollisionAssets assets)
{
ValidateAdmission(admission);
ArgumentNullException.ThrowIfNull(assets);
if (CanonicalLandblock(assets.LandblockId)
!= admission.LandblockId)
{
throw new ArgumentException(
"Collision assets do not match their admission landblock.",
nameof(assets));
}
if (admission.Completed)
{
throw new InvalidOperationException(
"A completed collision admission cannot publish more assets.");
}
if (admission.AssetsAdmitted)
{
throw new InvalidOperationException(
"Collision assets were already admitted by this receipt.");
}
Engine.AddLandblock(
admission.LandblockId,
assets.Terrain,
assets.CellSurfaces,
assets.PortalPlanes,
assets.WorldOffsetX,
assets.WorldOffsetY);
if ((assets.CurrentCellId & 0xFFFF0000u)
== (admission.LandblockId & 0xFFFF0000u))
{
Engine.UpdatePlayerCurrCell(assets.CurrentCellId);
}
admission.AssetsAdmitted = true;
}
public RuntimeCollisionAcknowledgement CompleteCollisionAdmission(
RuntimeCollisionAdmission admission)
{
ValidateAdmission(admission);
if (!admission.AssetsAdmitted)
{
throw new InvalidOperationException(
"Collision admission cannot complete before its assets publish.");
}
if (admission.Completed)
{
throw new InvalidOperationException(
"Collision admission has already completed.");
}
admission.Completed = true;
_collisionAdmissions.Remove(admission.LandblockId);
return new RuntimeCollisionAcknowledgement(
admission.LandblockId,
admission.Generation,
Engine.IsLandblockTerrainResident(admission.LandblockId));
}
public RuntimeCollisionAcknowledgement DemoteCollisionToTerrain(
uint landblockId)
{
EnsureNotDisposed();
uint canonical = CanonicalLandblock(landblockId);
bool resident = Engine.IsLandblockTerrainResident(canonical);
InvalidateCollisionAdmission(canonical);
Engine.DemoteLandblockToTerrain(canonical);
return new RuntimeCollisionAcknowledgement(
canonical,
_collisionGenerations[canonical],
resident);
}
public RuntimeCollisionAcknowledgement WithdrawCollision(
uint landblockId)
{
EnsureNotDisposed();
uint canonical = CanonicalLandblock(landblockId);
bool resident = Engine.IsLandblockTerrainResident(canonical);
InvalidateCollisionAdmission(canonical);
Engine.RemoveLandblock(canonical);
return new RuntimeCollisionAcknowledgement(
canonical,
_collisionGenerations[canonical],
resident);
}
public void Dispose()
{
if (_disposed)
return;
_spatialRemotes.Clear();
_spatialRoots.Clear();
_collisionAdmissions.Clear();
_collisionGenerations.Clear();
CellCommitted = null;
_disposed = true;
}
private void CommitCanonicalCell(
RuntimeEntityRecord record,
IRuntimeRemoteMotion expectedRuntime,
uint fullCellId)
{
_ = CommitCanonicalCell(
record,
fullCellId,
() => Entities.IsCurrent(record)
&& ReferenceEquals(record.RemoteMotion, expectedRuntime));
}
private bool CommitCanonicalCell(
RuntimeEntityRecord record,
uint fullCellId,
Func<bool> exactOwnerValid)
{
if (fullCellId == 0 || !exactOwnerValid())
return false;
if (fullCellId == record.FullCellId)
return true;
uint previousCellId = record.FullCellId;
Entities.SetFullCell(
record,
fullCellId,
(fullCellId & 0xFFFF0000u) | 0xFFFFu);
CellCommitted?.Invoke(
new RuntimePhysicsCellCommit(
record,
previousCellId,
fullCellId,
record.SpatialAuthorityVersion));
return exactOwnerValid()
&& record.FullCellId == fullCellId;
}
private void RemoveSpatialRemote(RuntimeEntityRecord record)
{
if (record.Key is not { } key)
return;
if (_spatialRemotes.TryGetValue(
key,
out IRuntimeRemoteMotion? remote)
&& (record.RemoteMotion is null
|| ReferenceEquals(remote, record.RemoteMotion)
|| !Entities.IsCurrent(record)))
{
_spatialRemotes.Remove(key);
}
}
private void EnsureNotDisposed() =>
ObjectDisposedException.ThrowIf(_disposed, this);
private void EnsureCurrent(RuntimeEntityRecord record)
{
if (!Entities.IsCurrent(record))
{
throw new InvalidOperationException(
$"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} is not current.");
}
}
private void ValidateAdmission(RuntimeCollisionAdmission admission)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(admission);
if (!ReferenceEquals(admission.Owner, this)
|| !_collisionAdmissions.TryGetValue(
admission.LandblockId,
out RuntimeCollisionAdmission? current)
|| !ReferenceEquals(current, admission)
|| !_collisionGenerations.TryGetValue(
admission.LandblockId,
out ulong generation)
|| generation != admission.Generation)
{
throw new InvalidOperationException(
"Collision admission is stale or belongs to another Runtime.");
}
}
private void InvalidateCollisionAdmission(uint landblockId)
{
ulong generation = _collisionGenerations.TryGetValue(
landblockId,
out ulong current)
? checked(current + 1UL)
: 1UL;
_collisionGenerations[landblockId] = generation;
_collisionAdmissions.Remove(landblockId);
}
private static uint CanonicalLandblock(uint value) =>
(value & 0xFFFF0000u) | 0xFFFFu;
private static void SynchronizeBodyActiveState(RuntimeEntityRecord record)
{
if (record.PhysicsBody is not { } body)
return;
if (record.ObjectClock.IsActive)
body.TransientState |= TransientStateFlags.Active;
else
body.TransientState &= ~TransientStateFlags.Active;
}
}