feat(physics): port retail complete object frame pipeline
Restore the named-retail object update order across local, remote, static, projectile, animation, shadow, teleport, and effect lifetimes. Separate authoritative root commits from spatial rebucketing, preserve per-owner hook/FIFO ordering, and remove update-path allocations with exact lifecycle and residency gates. Add deterministic conformance, adversarial lifetime, GUID-reuse, pending-cell, quaternion, timestamp, and allocation coverage. Release build is warning-free and all 6,446 tests pass with five intentional skips; retail, architecture, and adversarial reviews are clean. Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
parent
31a0889f08
commit
f961d70023
77 changed files with 12513 additions and 1871 deletions
90
src/AcDream.App/Rendering/StaticLiveRootCommitter.cs
Normal file
90
src/AcDream.App/Rendering/StaticLiveRootCommitter.cs
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
using AcDream.App.Physics;
|
||||
using AcDream.App.World;
|
||||
using AcDream.Core.Physics;
|
||||
using AcDream.Core.World;
|
||||
|
||||
namespace AcDream.App.Rendering;
|
||||
|
||||
/// <summary>
|
||||
/// Commits a changed root produced by retail's
|
||||
/// <c>CPhysicsObj::animate_static_object</c> to the retained effect pose and
|
||||
/// collision-shadow projections of the same live object incarnation.
|
||||
/// </summary>
|
||||
internal sealed class StaticLiveRootCommitter
|
||||
{
|
||||
private readonly Func<LiveEntityRuntime?> _runtime;
|
||||
private readonly ShadowObjectRegistry _shadows;
|
||||
private readonly Func<(int X, int Y)> _liveCenter;
|
||||
private readonly Action<WorldEntity> _updateEffectRoot;
|
||||
|
||||
public StaticLiveRootCommitter(
|
||||
Func<LiveEntityRuntime?> runtime,
|
||||
ShadowObjectRegistry shadows,
|
||||
Func<(int X, int Y)> liveCenter,
|
||||
Action<WorldEntity> updateEffectRoot)
|
||||
{
|
||||
_runtime = runtime ?? throw new ArgumentNullException(nameof(runtime));
|
||||
_shadows = shadows ?? throw new ArgumentNullException(nameof(shadows));
|
||||
_liveCenter = liveCenter
|
||||
?? throw new ArgumentNullException(nameof(liveCenter));
|
||||
_updateEffectRoot = updateEffectRoot
|
||||
?? throw new ArgumentNullException(nameof(updateEffectRoot));
|
||||
}
|
||||
|
||||
public bool Commit(WorldEntity entity, PhysicsBody body)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(entity);
|
||||
ArgumentNullException.ThrowIfNull(body);
|
||||
LiveEntityRuntime? runtime = _runtime();
|
||||
if (runtime is null
|
||||
|| !runtime.TryGetRecord(entity.ServerGuid, out LiveEntityRecord record)
|
||||
|| !ReferenceEquals(record.WorldEntity, entity)
|
||||
|| !ReferenceEquals(record.PhysicsBody, body))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// The retained pose owner follows the CPhysicsObj root even while its
|
||||
// mesh is hidden. Hidden is presentation state, not logical teardown.
|
||||
_updateEffectRoot(entity);
|
||||
|
||||
// EffectPoseChanged observers run synchronously and may delete this
|
||||
// incarnation (or replace the GUID) before returning. Do not let the
|
||||
// stale root restore collision shadows for an owner which no longer
|
||||
// exists. This is the same callback-boundary lifetime rule used by the
|
||||
// live schedulers and movement controllers.
|
||||
if (!ReferenceEquals(_runtime(), runtime)
|
||||
|| !runtime.TryGetRecord(entity.ServerGuid, out LiveEntityRecord current)
|
||||
|| !ReferenceEquals(current, record)
|
||||
|| !ReferenceEquals(current.WorldEntity, entity)
|
||||
|| !ReferenceEquals(current.PhysicsBody, body))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// CObjCell::hide_object removes shadows. Never let a later static
|
||||
// animation tick re-register collision for a hidden, withdrawn, or
|
||||
// pending projection; UnHide/re-entry owns restoration.
|
||||
if (record.ProjectionKind is not LiveEntityProjectionKind.World
|
||||
|| !record.IsSpatiallyProjected
|
||||
|| !record.IsSpatiallyVisible
|
||||
|| runtime.IsHidden(entity.ServerGuid))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
uint cellId = body.CellPosition.ObjCellId != 0
|
||||
? body.CellPosition.ObjCellId
|
||||
: record.FullCellId;
|
||||
(int centerX, int centerY) = _liveCenter();
|
||||
ShadowPositionSynchronizer.Sync(
|
||||
_shadows,
|
||||
entity.Id,
|
||||
body.Position,
|
||||
body.Orientation,
|
||||
cellId,
|
||||
centerX,
|
||||
centerY);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue