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
|
|
@ -20,6 +20,7 @@ public sealed class AnimationHookFrameQueue
|
|||
{
|
||||
private readonly AnimationHookRouter _router;
|
||||
private readonly IEntityEffectPoseSource _poses;
|
||||
private readonly IEntityEffectPoseLifetimeSource? _poseLifetimes;
|
||||
private readonly List<Entry> _entries = new();
|
||||
|
||||
public AnimationHookFrameQueue(
|
||||
|
|
@ -28,6 +29,7 @@ public sealed class AnimationHookFrameQueue
|
|||
{
|
||||
_router = router ?? throw new ArgumentNullException(nameof(router));
|
||||
_poses = poses ?? throw new ArgumentNullException(nameof(poses));
|
||||
_poseLifetimes = poses as IEntityEffectPoseLifetimeSource;
|
||||
}
|
||||
|
||||
public int Count => _entries.Count;
|
||||
|
|
@ -45,6 +47,12 @@ public sealed class AnimationHookFrameQueue
|
|||
{
|
||||
ArgumentNullException.ThrowIfNull(sequencer);
|
||||
ArgumentNullException.ThrowIfNull(hooks);
|
||||
// Capture incarnation identity before AnimationDone: its semantic
|
||||
// callback can synchronously delete this owner and reuse the local ID.
|
||||
// Reading the version afterwards would mislabel the old hook batch as
|
||||
// belonging to the replacement.
|
||||
ulong ownerLifetimeVersion =
|
||||
_poseLifetimes?.GetPoseOwnerLifetimeVersion(ownerLocalId) ?? 0UL;
|
||||
|
||||
// Retail CPhysicsObj::process_hooks (0x00511550) executes AnimDone
|
||||
// inside UpdatePositionInternal, before the transition and every
|
||||
|
|
@ -55,12 +63,25 @@ public sealed class AnimationHookFrameQueue
|
|||
// authored hook stream after the final part poses are published.
|
||||
for (int i = 0; i < hooks.Count; i++)
|
||||
{
|
||||
// MotionDone can synchronously delete this owner and reuse the
|
||||
// local ID. Do not advance the displaced sequencer for later
|
||||
// AnimDone hooks from the old catch-up batch.
|
||||
if (_poseLifetimes is not null
|
||||
&& _poseLifetimes.GetPoseOwnerLifetimeVersion(
|
||||
ownerLocalId) != ownerLifetimeVersion)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (hooks[i] is AnimationDoneHook)
|
||||
sequencer.Manager.AnimationDone(success: true);
|
||||
}
|
||||
|
||||
if (hooks.Count == 0)
|
||||
return;
|
||||
|
||||
_entries.Add(new Entry(
|
||||
ownerLocalId,
|
||||
ownerLifetimeVersion,
|
||||
hooks));
|
||||
}
|
||||
|
||||
|
|
@ -69,19 +90,35 @@ public sealed class AnimationHookFrameQueue
|
|||
for (int i = 0; i < _entries.Count; i++)
|
||||
{
|
||||
Entry entry = _entries[i];
|
||||
bool hasRootPose = _poses.TryGetRootPose(
|
||||
entry.OwnerLocalId,
|
||||
out Matrix4x4 rootWorld);
|
||||
Vector3 worldPosition = hasRootPose
|
||||
? rootWorld.Translation
|
||||
: Vector3.Zero;
|
||||
if (_poseLifetimes is not null
|
||||
&& _poseLifetimes.GetPoseOwnerLifetimeVersion(
|
||||
entry.OwnerLocalId) != entry.OwnerLifetimeVersion)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (int hi = 0; hi < entry.Hooks.Count; hi++)
|
||||
{
|
||||
// A prior hook sink can tear down and replace this local ID.
|
||||
// Revalidate per hook so the remainder of the old PES/animation
|
||||
// batch can never spill into the replacement incarnation.
|
||||
if (_poseLifetimes is not null
|
||||
&& _poseLifetimes.GetPoseOwnerLifetimeVersion(
|
||||
entry.OwnerLocalId) != entry.OwnerLifetimeVersion)
|
||||
{
|
||||
break;
|
||||
}
|
||||
AnimationHook? hook = entry.Hooks[hi];
|
||||
if (hook is null)
|
||||
continue;
|
||||
if (hasRootPose)
|
||||
_router.OnHook(entry.OwnerLocalId, worldPosition, hook);
|
||||
if (_poses.TryGetRootPose(
|
||||
entry.OwnerLocalId,
|
||||
out Matrix4x4 rootWorld))
|
||||
{
|
||||
_router.OnHook(
|
||||
entry.OwnerLocalId,
|
||||
rootWorld.Translation,
|
||||
hook);
|
||||
}
|
||||
}
|
||||
}
|
||||
_entries.Clear();
|
||||
|
|
@ -91,5 +128,6 @@ public sealed class AnimationHookFrameQueue
|
|||
|
||||
private readonly record struct Entry(
|
||||
uint OwnerLocalId,
|
||||
ulong OwnerLifetimeVersion,
|
||||
IReadOnlyList<AnimationHook> Hooks);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue