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:
Erik 2026-07-19 21:40:14 +02:00
parent 0f996db747
commit c5ab99081c
17 changed files with 493 additions and 98 deletions

View file

@ -84,7 +84,11 @@ internal sealed class RemotePhysicsUpdater
|| record.WorldEntity is not { } entity)
continue;
TickHidden(remote, entity, dt);
System.Action? handlePartArray = record.AnimationRuntime is AnimatedEntity
{ Sequencer: { } sequencer }
? sequencer.Manager.UseTime
: null;
TickHidden(remote, entity, dt, handlePartArray);
// PositionManager callbacks can rebucket, delete, or replace this
// GUID. Publish only while the captured record/runtime pair still
// owns a loaded spatial projection.
@ -116,16 +120,6 @@ internal sealed class RemotePhysicsUpdater
int liveCenterY)
{
uint serverGuid = ae.Entity.ServerGuid;
// R5-V2: retail UpdateObjectInternal ticks TargetManager::
// HandleTargetting UNCONDITIONALLY per entity, BEFORE the
// movement managers' UseTime. This is where this entity, as a
// watched target, pushes its position to its voyeurs (any entity
// moving-to it), and where its own target-info staleness times
// out. Runs for every remote regardless of the grounded/airborne
// branch below (which drive MoveToManager.UseTime via
// TickRemoteMoveTo). No-op for entities with no target + no voyeurs.
rm.Host?.HandleTargetting();
// #184 Slice 2b — the UNIFIED per-remote tick. The former Path A
// (grounded PLAYER remotes: interp catch-up with the ResolveWithTransition
// sweep OMITTED, per the now-retired issue-#40 "collision is the sender's
@ -221,7 +215,6 @@ internal sealed class RemotePhysicsUpdater
// the sink (the LEGS). Position comes from the catch-up; legs from
// this per-node dispatch + the funnel. The #170-deleted per-frame
// apply_current_movement is NOT reintroduced.
TickRemoteMoveTo(rm);
}
else
{
@ -609,7 +602,21 @@ internal sealed class RemotePhysicsUpdater
// sticky 1 s lease watchdog (StickyManager::UseTime
// 0x00555610 — a stick not re-issued by a fresh server arm
// within 1 s tears itself down). No-op while nothing is stuck.
rm.Host?.PositionManager.UseTime();
System.Action? handleTargeting = rm.Host is { } targetHost
? targetHost.HandleTargetting
: null;
System.Action? partArrayHandleMovement = ae.Sequencer is { } sequencer
? sequencer.Manager.UseTime
: null;
System.Action? positionUseTime = rm.Host is { } positionHost
? positionHost.PositionManager.UseTime
: null;
AcDream.Core.Physics.RetailObjectManagerTail.Run(
checkDetection: null,
handleTargeting,
movementUseTime: rm.Movement.UseTime,
partArrayHandleMovement,
positionUseTime);
}
/// <summary>
@ -624,7 +631,8 @@ internal sealed class RemotePhysicsUpdater
public void TickHidden(
RemoteMotion rm,
AcDream.Core.World.WorldEntity entity,
float dt)
float dt,
System.Action? partArrayHandleMovement = null)
{
ArgumentNullException.ThrowIfNull(rm);
ArgumentNullException.ThrowIfNull(entity);
@ -700,20 +708,18 @@ internal sealed class RemotePhysicsUpdater
entity.ParentCellId = rm.CellId;
entity.Rotation = rm.Body.Orientation;
rm.Host?.HandleTargetting();
TickRemoteMoveTo(rm);
rm.Host?.PositionManager.UseTime();
}
/// <summary>
/// R4-V5 / R5-V2: the per-tick <see cref="AcDream.Core.Physics.Motion.MovementManager"/>
/// drive (retail <c>MovementManager::UseTime</c> 0x005242f0 — the moveto
/// side's steering, arrival, fail-distance; R5-V5 facade relay). Moved from
/// GameWindow (#184 Slice 2a); the DR tick is its only caller.
/// </summary>
private static void TickRemoteMoveTo(RemoteMotion rm)
{
rm.Movement.UseTime();
System.Action? handleTargeting = rm.Host is { } targetHost
? targetHost.HandleTargetting
: null;
System.Action? positionUseTime = rm.Host is { } positionHost
? positionHost.PositionManager.UseTime
: null;
AcDream.Core.Physics.RetailObjectManagerTail.Run(
checkDetection: null,
handleTargeting,
movementUseTime: rm.Movement.UseTime,
partArrayHandleMovement,
positionUseTime);
}
/// <summary>