refactor(runtime): close simulation ownership
Move remote-motion construction, CreateObject vector initialization, final simulation-component retirement, and the combined J5 ownership ledger into Runtime. Delete App compatibility views and moved-state reconstruction while preserving the existing graphical projection and retail update order.
This commit is contained in:
parent
c30a3efeb0
commit
cdee7a4b49
57 changed files with 1013 additions and 410 deletions
|
|
@ -12,7 +12,19 @@ public readonly record struct RuntimePhysicsOwnershipSnapshot(
|
|||
int CollisionAdmissionCount,
|
||||
int CollisionGenerationCount,
|
||||
bool OwnsProductionDataCache,
|
||||
bool IsDisposed);
|
||||
bool IsDisposed)
|
||||
{
|
||||
public bool IsConverged =>
|
||||
IsDisposed
|
||||
&& LandblockCount == 0
|
||||
&& RetainedShadowRegistrationCount == 0
|
||||
&& SpatialRootCount == 0
|
||||
&& SpatialRemoteCount == 0
|
||||
&& SpatialProjectileCount == 0
|
||||
&& CollisionAdmissionCount == 0
|
||||
&& CollisionGenerationCount == 0
|
||||
&& OwnsProductionDataCache;
|
||||
}
|
||||
|
||||
public readonly record struct RuntimePhysicsCellCommit(
|
||||
RuntimeEntityRecord Record,
|
||||
|
|
@ -437,6 +449,8 @@ public sealed class RuntimePhysicsState : IDisposable
|
|||
record,
|
||||
expectedPlacementContract
|
||||
|| runtime is IRuntimeRemotePlacement);
|
||||
if (expectedBody is null)
|
||||
InitializeNewPhysicsBody(record, candidateBody);
|
||||
Entities.SetRemoteMotion(record, runtime);
|
||||
Entities.SetPhysicsBody(record, candidateBody);
|
||||
candidateBody.State = record.FinalPhysicsState;
|
||||
|
|
@ -452,6 +466,52 @@ public sealed class RuntimePhysicsState : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs the one built-in remote-motion component for an exact
|
||||
/// canonical incarnation. A graphical host may attach animation and pose
|
||||
/// sinks afterward, but cannot construct or replace simulation state.
|
||||
/// </summary>
|
||||
internal RemoteMotion GetOrCreateRemoteMotion(
|
||||
RuntimeEntityRecord record,
|
||||
Func<bool>? externalOwnerValid = null)
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
ArgumentNullException.ThrowIfNull(record);
|
||||
EnsureCurrent(record);
|
||||
if (record.RemoteMotion is { } retained)
|
||||
{
|
||||
return retained as RemoteMotion
|
||||
?? throw new InvalidOperationException(
|
||||
$"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} owns a non-production remote-motion component.");
|
||||
}
|
||||
|
||||
var created = new RemoteMotion(record.PhysicsBody);
|
||||
created.Movement.ActivatePhysicsObject = () =>
|
||||
TryActivateOrdinaryObject(record, created);
|
||||
SetRemoteMotion(record, created, externalOwnerValid);
|
||||
return created;
|
||||
}
|
||||
|
||||
internal bool TryActivateOrdinaryObject(
|
||||
RuntimeEntityRecord record,
|
||||
IRuntimeRemoteMotion runtime,
|
||||
Func<bool>? externalOwnerValid = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(record);
|
||||
ArgumentNullException.ThrowIfNull(runtime);
|
||||
if (!Entities.IsCurrent(record)
|
||||
|| !ReferenceEquals(record.RemoteMotion, runtime)
|
||||
|| (record.FinalPhysicsState & PhysicsStateFlags.Static) != 0
|
||||
|| !(externalOwnerValid?.Invoke() ?? true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
record.ObjectClock.Activate();
|
||||
runtime.Body.TransientState |= TransientStateFlags.Active;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Acquires the one retail <c>CPhysicsObj</c> body for an exact accepted
|
||||
/// object incarnation. Factories may cross a host boundary, so ownership
|
||||
|
|
@ -499,6 +559,7 @@ public sealed class RuntimePhysicsState : IDisposable
|
|||
$"Runtime entity 0x{record.ServerGuid:X8}/{record.Incarnation} acquired two physics bodies within one incarnation.");
|
||||
}
|
||||
|
||||
InitializeNewPhysicsBody(record, candidate);
|
||||
Entities.SetPhysicsBody(record, candidate);
|
||||
candidate.State = record.FinalPhysicsState;
|
||||
SynchronizeBodyActiveState(record);
|
||||
|
|
@ -905,6 +966,7 @@ public sealed class RuntimePhysicsState : IDisposable
|
|||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
Engine.Clear();
|
||||
_spatialRemotes.Clear();
|
||||
_spatialProjectiles.Clear();
|
||||
_spatialRoots.Clear();
|
||||
|
|
@ -1039,4 +1101,22 @@ public sealed class RuntimePhysicsState : IDisposable
|
|||
else
|
||||
body.TransientState &= ~TransientStateFlags.Active;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retail <c>CPhysicsObj::set_description</c> (0x00514F40) installs the
|
||||
/// accepted CreateObject velocity and omega once, when the incarnation's
|
||||
/// CPhysicsObj is first acquired. Later SetState never replays them.
|
||||
/// </summary>
|
||||
private static void InitializeNewPhysicsBody(
|
||||
RuntimeEntityRecord record,
|
||||
PhysicsBody body)
|
||||
{
|
||||
body.State = record.FinalPhysicsState;
|
||||
if (record.Snapshot.Physics is not { } physics)
|
||||
return;
|
||||
if (physics.Velocity is { } velocity && IsFinite(velocity))
|
||||
body.set_velocity(velocity);
|
||||
if (physics.AngularVelocity is { } omega && IsFinite(omega))
|
||||
body.Omega = omega;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue