refactor(world): canonicalize live physics host ownership

This commit is contained in:
Erik 2026-07-21 14:05:34 +02:00
parent 5882b308c1
commit fcb66198fc
21 changed files with 1546 additions and 323 deletions

View file

@ -16,9 +16,9 @@ namespace AcDream.Core.Physics.Motion;
/// <c>RemoteMotion</c> or the local player), wiring the accessors to the live
/// <see cref="PhysicsBody"/> and the <see cref="MoveToManager"/> /
/// <see cref="PositionManager"/> / <see cref="TargetManager"/> it owns.
/// <see cref="GetObjectA"/> is backed by the App's live entity table
/// (<c>_entitiesByServerGuid</c>), giving the voyeur round-trip its
/// cross-entity delivery path.</para>
/// <see cref="GetObjectA"/> is backed by the App's canonical
/// <c>LiveEntityRuntime</c> records, giving the voyeur round-trip its
/// cross-entity delivery path without a second GUID index.</para>
/// </summary>
public interface IPhysicsObjHost
{
@ -57,11 +57,21 @@ public interface IPhysicsObjHost
double PhysicsTimerTime { get; }
/// <summary>Retail <c>CObjectMaint::GetObjectA(id)</c> — resolve another
/// physics object by guid, or <c>null</c> if not currently known/visible.
/// The cross-entity seam for the voyeur round-trip and sticky live-target
/// physics object by guid from the object table. The App additionally
/// withholds Hidden objects from ordinary relationship creation through
/// its registered TS-49 DetectionManager adaptation. This is the
/// cross-entity seam for the voyeur round-trip and sticky live-target
/// resolve.</summary>
IPhysicsObjHost? GetObjectA(uint id);
/// <summary>
/// Returns the exact target incarnation captured by this host's current
/// TargetManager relationship. App teardown can overlap a newer
/// INSTANCE_TS with the same GUID, so StickyManager must not re-resolve the
/// relationship through the active GUID table.
/// </summary>
IPhysicsObjHost? GetRelationshipTarget(uint objectId);
/// <summary>Retail <c>CPhysicsObj::HandleUpdateTarget</c> — fans a
/// <see cref="TargetInfo"/> to this host's <see cref="MoveToManager"/>
/// (move-to steering) AND <see cref="PositionManager"/> (sticky follow).
@ -86,15 +96,19 @@ public interface IPhysicsObjHost
/// <summary>Retail <c>CPhysicsObj::receive_target_update</c> →
/// <see cref="TargetManager.ReceiveUpdate"/>. The inbound side a SENDER's
/// <c>SendVoyeurUpdate</c> tail-calls on the watcher.</summary>
void ReceiveTargetUpdate(TargetInfo info);
void ReceiveTargetUpdate(TargetInfo info, IPhysicsObjHost sender);
/// <summary>Retail <c>CPhysicsObj::add_voyeur(id, radius, quantum)</c> →
/// <see cref="TargetManager.AddVoyeur"/> (lazily creating the
/// TargetManager). Called on the TARGET when a watcher subscribes.</summary>
void AddVoyeur(uint watcherId, float radius, double quantum);
/// TargetManager). Called on the TARGET when a watcher subscribes. The
/// exact watcher host preserves retail's unique object-table identity
/// while App teardown overlaps a newer same-GUID generation.</summary>
void AddVoyeur(IPhysicsObjHost watcher, float radius, double quantum);
/// <summary>Retail <c>CPhysicsObj::remove_voyeur(id)</c> →
/// <see cref="TargetManager.RemoveVoyeur"/>. Called on the TARGET when a
/// watcher unsubscribes.</summary>
void RemoveVoyeur(uint watcherId);
/// watcher unsubscribes. The expected watcher identity prevents a retiring
/// same-GUID incarnation from removing a newer incarnation's subscription
/// while App teardown callbacks converge.</summary>
void RemoveVoyeur(uint watcherId, IPhysicsObjHost expectedWatcher);
}