fix(motion): restore retail object manager order
Process animation completion at the retail process_hooks boundary, then run targeting, movement, PartArray completion, and PositionManager in the named UpdateObjectInternal order for local, remote, hidden, and position-less animated objects. Retire TS-42 with deterministic conformance coverage.\n\nCo-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
parent
0f996db747
commit
c5ab99081c
17 changed files with 493 additions and 98 deletions
|
|
@ -11113,6 +11113,7 @@ public sealed class GameWindow : IDisposable
|
|||
var ae = kv.Value;
|
||||
bool sequenceAdvancedBeforeAnimationPass =
|
||||
ae.SequenceAdvancedBeforeAnimationPass;
|
||||
bool managerTailHandledForObject = ae.Entity.ServerGuid == _playerServerGuid;
|
||||
IReadOnlyList<AcDream.Core.Physics.PartTransform>? preparedSequenceFrames =
|
||||
ae.PreparedSequenceFrames;
|
||||
ae.SequenceAdvancedBeforeAnimationPass = false;
|
||||
|
|
@ -11208,6 +11209,7 @@ public sealed class GameWindow : IDisposable
|
|||
remoteRootMotionFrame.Origin,
|
||||
_liveCenterX,
|
||||
_liveCenterY);
|
||||
managerTailHandledForObject = true;
|
||||
}
|
||||
|
||||
// ── Get per-part (origin, orientation) from either sequencer or legacy ──
|
||||
|
|
@ -11264,7 +11266,9 @@ public sealed class GameWindow : IDisposable
|
|||
// This matches CPhysicsObj::UpdateObjectInternal followed by
|
||||
// CPhysicsObj::UpdateChild (0x00512D50): a hand/weapon effect
|
||||
// reads this frame's pose, never the previous frame's pose.
|
||||
// AnimationDone/UseTime remain paired with the deferred drain.
|
||||
// AnimationDone is processed semantically by Capture at
|
||||
// retail's process_hooks slot. Pose-dependent delivery is
|
||||
// deferred; the later manager-tail block owns UseTime.
|
||||
if (!hidden)
|
||||
_animationHookFrames?.Capture(ae.Entity.Id, ae.Sequencer);
|
||||
}
|
||||
|
|
@ -11287,6 +11291,41 @@ public sealed class GameWindow : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
// R6: objects which did not enter the local or moving-remote
|
||||
// physics owner still need their CPartArray manager tail. Doors
|
||||
// and levers commonly receive UpdateMotion without ever receiving
|
||||
// UpdatePosition; classifying the tail by LastServerPosTime made
|
||||
// their zero-tick completions depend on the old global hook drain.
|
||||
// Hidden remotes were already handled by TickHiddenEntities above.
|
||||
bool hiddenRemoteManagerTailHandled = hidden
|
||||
&& _remoteDeadReckon.TryGetValue(serverGuid, out _);
|
||||
AcDream.Core.Physics.AnimationSequencer? tailSequencer = ae.Sequencer;
|
||||
if (!managerTailHandledForObject
|
||||
&& !hiddenRemoteManagerTailHandled
|
||||
&& tailSequencer is not null)
|
||||
{
|
||||
if (_remoteDeadReckon.TryGetValue(serverGuid, out var tailRemote)
|
||||
&& _projectileController?.HandlesMovement(serverGuid) != true)
|
||||
{
|
||||
System.Action? handleTargeting = tailRemote.Host is { } targetHost
|
||||
? targetHost.HandleTargetting
|
||||
: null;
|
||||
System.Action? positionUseTime = tailRemote.Host is { } positionHost
|
||||
? positionHost.PositionManager.UseTime
|
||||
: null;
|
||||
AcDream.Core.Physics.RetailObjectManagerTail.Run(
|
||||
checkDetection: null,
|
||||
handleTargeting,
|
||||
movementUseTime: tailRemote.Movement.UseTime,
|
||||
partArrayHandleMovement: tailSequencer.Manager.UseTime,
|
||||
positionUseTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
tailSequencer.Manager.UseTime();
|
||||
}
|
||||
}
|
||||
|
||||
int partCount = ae.PartTemplate.Count;
|
||||
|
||||
// D5 (Commit A 2026-05-03): PARTSDIAG — proves whether
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue