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,82 @@
using System.Numerics;
using AcDream.App.World;
using AcDream.Core.Physics;
using AcDream.Core.Physics.Motion;
using AcDream.Runtime.Physics;
namespace AcDream.App.Physics;
/// <summary>
/// Graphical configuration factory for Runtime's presentation-free
/// <see cref="EntityPhysicsHost"/>. Runtime owns exact-incarnation
/// installation, stable identity, manager lifetime, and lookup.
/// </summary>
internal static class EntityPhysicsHostComposition
{
internal static EntityPhysicsHost InstallOrRebind(
LiveEntityRuntime runtime,
LiveEntityRecord expectedRecord,
EntityPhysicsHost configuration)
{
ArgumentNullException.ThrowIfNull(runtime);
ArgumentNullException.ThrowIfNull(expectedRecord);
ArgumentNullException.ThrowIfNull(configuration);
bool ProjectionIsCurrent() =>
runtime.TryGetRecord(
expectedRecord.ServerGuid,
out LiveEntityRecord current)
&& ReferenceEquals(current, expectedRecord);
return runtime.Physics.InstallOrRebindPhysicsHost(
expectedRecord.Canonical,
configuration,
ProjectionIsCurrent);
}
internal static EntityPhysicsHost SelectStableHostWithoutRebind(
LiveEntityRuntime runtime,
LiveEntityRecord expectedRecord,
EntityPhysicsHost configuration)
{
ArgumentNullException.ThrowIfNull(runtime);
ArgumentNullException.ThrowIfNull(expectedRecord);
ArgumentNullException.ThrowIfNull(configuration);
bool ProjectionIsCurrent() =>
runtime.TryGetRecord(
expectedRecord.ServerGuid,
out LiveEntityRecord current)
&& ReferenceEquals(current, expectedRecord);
return runtime.Physics.SelectStablePhysicsHostWithoutRebind(
expectedRecord.Canonical,
configuration,
ProjectionIsCurrent);
}
internal static EntityPhysicsHost CreateMinimal(
LiveEntityRecord record,
Func<uint, IPhysicsObjHost?> resolve,
Func<double> now)
{
ArgumentNullException.ThrowIfNull(record);
ArgumentNullException.ThrowIfNull(resolve);
ArgumentNullException.ThrowIfNull(now);
return new EntityPhysicsHost(
record.ServerGuid,
getPosition: () => new Position(
record.FullCellId,
record.WorldEntity?.Position
?? record.PhysicsBody?.Position
?? Vector3.Zero,
record.WorldEntity?.Rotation
?? record.PhysicsBody?.Orientation
?? Quaternion.Identity),
getVelocity: () => record.PhysicsBody?.Velocity ?? Vector3.Zero,
getRadius: () => 0f,
inContact: () => record.PhysicsBody?.InContact ?? true,
minterpMaxSpeed: () => null,
curTime: now,
physicsTimerTime: now,
getObjectA: resolve,
handleUpdateTarget: _ => { },
interruptCurrentMovement: () => { });
}
}