feat(physics): R5-V1 — port PositionManager/Sticky/Constraint + TargetManager (Core, unwired)
The retail movement-manager family the R4 MoveToManager port left as do-not-invent seams (decomp §9f/§9g). Faithful C# ports of retail's PositionManager facade + StickyManager + ConstraintManager + the TargetManager voyeur system, with full conformance tests. NO wiring yet — purely additive, no behavior change. Wiring (retiring TS-39 sticky + AP-79 target adapter) is R5-V2/V3. New Core classes (src/AcDream.Core/Physics/Motion/): - StickyManager (0x00555400): follow-a-target steering. adjust_offset's dense x87 mush decoded via ACE (StickyRadius 0.3, StickyTime 1.0, follow speed ×5 / fallback 15) — speed-clamped signed-distance steer + bounded turn-to-face; 1 s watchdog; Ok→initialized / non-Ok→teardown. - ConstraintManager (0x00556090): the server-position rubber-band leash. 90% IsFullyConstrained jump gate + grounded linear brake taper. Structural only — acdream never ARMS it (retail arms from SmartBox::HandleReceivedPosition, which acdream lacks, with two x87 constants BN elided). IsFullyConstrained stays false = TS-35 behavior; leash-arming + the unknown constants are a deferred issue. - PositionManager facade (0x00555160): lazy Sticky/Constraint + fan-out. - TargetManager (0x0051a370) + TargettedVoyeurInfo: the peer-to-peer voyeur subscription system (0.5 s throttle, 10 s staleness, send-on-drift-past-radius, dead-reckon GetInterpolatedPosition). A faithful superset of the AP-79 adapter — SetTarget subscribes ON the target; the target's HandleTargetting pushes updates back. - IPhysicsObjHost: the CPhysicsObj back-pointer seam (position/velocity/ radius/contact/GetObjectA + target-tracking fan-out) the App wires per entity in V2/V3. MotionDeltaFrame: mutable retail-Frame delta accumulator. Supporting: - TargetInfo extended to the full retail 10-field struct (additive defaults keep the R4 4-arg call sites compiling). - MoveToMath: signed CylinderDistanceNoZ, NormalizeCheckSmall, GlobalToLocalVec. - Rename: the misnamed AcDream.Core.Physics.PositionManager (a remote anim+interp per-frame combiner, NOT the retail facade) → RemoteMotion Combiner, freeing the name and removing the ambiguity that breaks every file importing both Physics + Physics.Motion (GameWindow will in V2/V3). Tests: 42 new conformance cases (Sticky/Constraint/Position facade + TargetManager incl. the full cross-entity voyeur round-trip). Full suite 4006 green (+2 skipped), no regressions. Decomp + ACE cross-ref + port plan: docs/research/2026-07-03-r5-managers/. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
517bbfdae4
commit
3d89446d98
25 changed files with 7279 additions and 12 deletions
100
src/AcDream.Core/Physics/Motion/IPhysicsObjHost.cs
Normal file
100
src/AcDream.Core/Physics/Motion/IPhysicsObjHost.cs
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
using System.Numerics;
|
||||
|
||||
namespace AcDream.Core.Physics.Motion;
|
||||
|
||||
/// <summary>
|
||||
/// R5 seam — the acdream stand-in for retail's <c>CPhysicsObj</c> as seen BY
|
||||
/// its owned managers. Retail's <c>StickyManager</c> / <c>ConstraintManager</c>
|
||||
/// / <c>TargetManager</c> each hold a raw <c>physics_obj</c> pointer and call
|
||||
/// back through it (position/velocity/radius accessors, target-tracking
|
||||
/// registration, the <c>HandleUpdateTarget</c> fan-out) and — for the voyeur
|
||||
/// system — resolve OTHER physics objects via <c>CObjectMaint::GetObjectA</c>
|
||||
/// and drive their <c>add_voyeur</c> / <c>receive_target_update</c> /
|
||||
/// <c>remove_voyeur</c> entry points. This interface is that back-pointer.
|
||||
///
|
||||
/// <para>The App layer implements one host per entity (a remote
|
||||
/// <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>
|
||||
/// </summary>
|
||||
public interface IPhysicsObjHost
|
||||
{
|
||||
/// <summary>Retail <c>physics_obj->id</c> — this object's guid.</summary>
|
||||
uint Id { get; }
|
||||
|
||||
/// <summary>Retail <c>physics_obj->m_position</c> — world-space cell +
|
||||
/// frame (acdream seams carry WORLD space; see the MoveToManager binding
|
||||
/// note).</summary>
|
||||
Position Position { get; }
|
||||
|
||||
/// <summary>Retail <c>CPhysicsObj::get_velocity</c>.</summary>
|
||||
Vector3 Velocity { get; }
|
||||
|
||||
/// <summary>Retail <c>CPhysicsObj::GetRadius</c> — the mover's cylinder
|
||||
/// radius.</summary>
|
||||
float Radius { get; }
|
||||
|
||||
/// <summary>Retail <c>physics_obj->transient_state & 1</c> — the
|
||||
/// CONTACT bit (ConstraintManager's grounded gate).</summary>
|
||||
bool InContact { get; }
|
||||
|
||||
/// <summary>Retail <c>CPhysicsObj::get_minterp()->get_max_speed()</c> —
|
||||
/// the mover's max locomotion speed, or <c>null</c> if it has no motion
|
||||
/// interpreter yet (StickyManager falls back to a 15.0 constant).</summary>
|
||||
float? MinterpMaxSpeed { get; }
|
||||
|
||||
/// <summary>Retail <c>Timer::cur_time</c> — the wall/game clock (seconds).
|
||||
/// Drives the sticky 1 s timeout and target 10 s staleness deadlines.</summary>
|
||||
double CurTime { get; }
|
||||
|
||||
/// <summary>Retail <c>PhysicsTimer::curr_time</c> — the physics-tick clock
|
||||
/// (seconds). Drives <c>TargetManager::HandleTargetting</c>'s 0.5 s
|
||||
/// throttle. Retail uses a DIFFERENT clock here than <see cref="CurTime"/>;
|
||||
/// acdream may bind both to the same source.</summary>
|
||||
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
|
||||
/// resolve.</summary>
|
||||
IPhysicsObjHost? GetObjectA(uint id);
|
||||
|
||||
/// <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).
|
||||
/// Called from <see cref="TargetManager.ReceiveUpdate"/> and the timeout
|
||||
/// path.</summary>
|
||||
void HandleUpdateTarget(TargetInfo info);
|
||||
|
||||
/// <summary>Retail <c>CPhysicsObj::interrupt_current_movement</c> →
|
||||
/// <c>MovementManager::CancelMoveTo(0x36)</c>.</summary>
|
||||
void InterruptCurrentMovement();
|
||||
|
||||
/// <summary>Retail <c>CPhysicsObj::set_target(ctx, objId, radius,
|
||||
/// quantum)</c> → <see cref="TargetManager.SetTarget"/> (lazily creating
|
||||
/// the TargetManager). Called by <c>StickyManager::StickTo</c> and
|
||||
/// <c>MoveToManager</c>'s object-move entry points.</summary>
|
||||
void SetTarget(uint contextId, uint objectId, float radius, double quantum);
|
||||
|
||||
/// <summary>Retail <c>CPhysicsObj::clear_target</c> →
|
||||
/// <see cref="TargetManager.ClearTarget"/>.</summary>
|
||||
void ClearTarget();
|
||||
|
||||
/// <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);
|
||||
|
||||
/// <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);
|
||||
|
||||
/// <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);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue