fix(physics): P5 commit 3 - retire TS-35, close #167 (ConstraintManager leash)
PhysicsBody.IsFullyConstrained now reflects real ConstraintManager state (pushed every tick by the same per-tick pumps commit 2 wired), so jump_is_allowed's already-ported gate (WeenieError 0x47) actually fires while an object is rubber-banding hard against a server position correction, closing the last piece of #167. Housekeeping: - Delete register row TS-35 (retired: the write side is no longer stubbed). - Rewrite the stale doc comments on PhysicsBody.IsFullyConstrained, ConstraintManager (class + IsFullyConstrained), PositionManager.ConstrainTo, EntityPhysicsHost.PositionManager, and PlayerMovementController.PositionManager that described the leash as permanently unarmed/stubbed. - Close #167 in ISSUES.md citing the research doc and commitse0629145/7719d25b. - Add an "as-ported" addendum to docs/research/2026-07-30-constraint-leash-constants.md naming the actual current seam owners (the doc's own open question flagged this as implementer-verify-required post-J-slices). - Update docs/plans/2026-07-29-physics-parity-campaign.md's P5 status and CLAUDE.md's Campaign P summary to reflect #167's closure (items #153/#72 remain open in P5). Verification: complete solution suite green - 9,978 tests, 5 skips, 0 failures across all 9 test projects (Core.Tests, Runtime.Tests, App.Tests, Headless.Tests, Core.Net.Tests, Content.Tests, UI.Abstractions.Tests, Bake.Tests, Cli.Tests).
This commit is contained in:
parent
7719d25bc5
commit
9e17554ed4
10 changed files with 159 additions and 48 deletions
|
|
@ -13,16 +13,18 @@ namespace AcDream.Core.Physics.Motion;
|
|||
/// <c>CMotionInterp::jump_is_allowed</c> (block jump while
|
||||
/// <see cref="IsFullyConstrained"/>).
|
||||
///
|
||||
/// <para><b>Arming is UNPORTED in acdream (R5).</b> Retail arms the leash ONLY
|
||||
/// from <c>SmartBox::HandleReceivedPosition</c> (on every inbound server
|
||||
/// position packet) with two constants from
|
||||
/// <c>CPhysicsObj::GetStart/MaxConstraintDistance</c> whose values BN elided
|
||||
/// (x87 returns — unknown, need a cdb read). acdream's position reconciliation
|
||||
/// is not SmartBox, so nothing calls <see cref="ConstrainTo"/> — the leash
|
||||
/// stays disarmed and <see cref="IsFullyConstrained"/> stays false, matching
|
||||
/// register TS-35's current stub behavior. The class is ported for structural
|
||||
/// completeness of <see cref="PositionManager"/>; the leash-arming port + the
|
||||
/// two unknown constants are a deferred issue (port-plan §Constraint scope).</para>
|
||||
/// <para><b>Armed as of Campaign P P5 (2026-07-30, #167, closed
|
||||
/// register row TS-35).</b> Retail arms the leash ONLY from
|
||||
/// <c>SmartBox::HandleReceivedPosition</c> (0x00453fd0, on every inbound
|
||||
/// server position packet) with the start/max band from
|
||||
/// <c>CPhysicsObj::GetStart/MaxConstraintDistance</c> — byte-decoded (the x87
|
||||
/// returns BN elided) in <see cref="ConstraintDistance"/>. acdream's
|
||||
/// equivalents call <see cref="ConstrainTo"/> at every accepted-position
|
||||
/// seam: <c>LiveEntityNetworkUpdateController</c> for remotes (anchored to
|
||||
/// the object's own position, right after the hard-teleport branch returns)
|
||||
/// and <c>PlayerMovementController.SetPosition</c>/<c>BlipPosition</c> for
|
||||
/// the local player (anchored to the received position). See
|
||||
/// <c>docs/research/2026-07-30-constraint-leash-constants.md</c>.</para>
|
||||
/// </summary>
|
||||
public sealed class ConstraintManager
|
||||
{
|
||||
|
|
@ -77,8 +79,11 @@ public sealed class ConstraintManager
|
|||
/// Retail <c>ConstraintManager::IsFullyConstrained</c> (0x005560d0):
|
||||
/// <c>constraint_distance_max * 0.9 < constraint_pos_offset</c> — the
|
||||
/// object counts as fully constrained once it has strained past 90 % of the
|
||||
/// max leash. Read by <c>jump_is_allowed</c> to block jumps. Always false
|
||||
/// while the leash is disarmed (acdream never arms it — see class note).
|
||||
/// max leash. Read by <c>jump_is_allowed</c> to block jumps. False while
|
||||
/// unconstrained (no prior <see cref="ConstrainTo"/> or after
|
||||
/// <see cref="UnConstrain"/>) since <see cref="ConstraintDistanceMax"/> and
|
||||
/// <see cref="ConstraintPosOffset"/> both default to zero (<c>0*0.9 < 0</c>
|
||||
/// is false).
|
||||
/// </summary>
|
||||
public bool IsFullyConstrained()
|
||||
=> ConstraintDistanceMax * 0.9f < ConstraintPosOffset;
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ public sealed class PositionManager
|
|||
|
||||
/// <summary>Retail <c>PositionManager::ConstrainTo</c> (0x00555280) —
|
||||
/// lazily create the <see cref="ConstraintManager"/> and arm the leash.
|
||||
/// (Unused in acdream — no arming call site; see
|
||||
/// <see cref="ConstraintManager"/>.)</summary>
|
||||
/// Armed as of Campaign P P5 (#167) at every accepted-position seam — see
|
||||
/// <see cref="ConstraintManager"/>'s class doc for the call sites.</summary>
|
||||
public void ConstrainTo(Position anchor, float startDistance, float maxDistance)
|
||||
{
|
||||
_constraint ??= new ConstraintManager(_host);
|
||||
|
|
|
|||
|
|
@ -408,16 +408,33 @@ public sealed class PhysicsBody
|
|||
public double LastUpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// R3-W3 stub for retail <c>CPhysicsObj::IsFullyConstrained</c>
|
||||
/// (0x0050f730), read by <c>CMotionInterp::jump_is_allowed</c> (raw
|
||||
/// 305524-305525: <c>if (IsFullyConstrained(physics_obj) != 0) return
|
||||
/// 0x47;</c>). Retail's body walks per-cell contact-plane constraints
|
||||
/// (a mover pinned between opposing walkable surfaces / doorway
|
||||
/// jamming); acdream has no equivalent constraint-tracking yet.
|
||||
/// Register row: stubbed false (never fires) — a real port needs the
|
||||
/// per-cell shadow-list contact accounting the physics digest tracks.
|
||||
/// See docs/architecture/retail-divergence-register.md (added same
|
||||
/// commit as this field).
|
||||
/// Retail <c>CPhysicsObj::IsFullyConstrained</c> (0x0050f730), read by
|
||||
/// <c>CMotionInterp::jump_is_allowed</c> (raw 305524-305525:
|
||||
/// <c>if (IsFullyConstrained(physics_obj) != 0) return 0x47;</c>) to block
|
||||
/// a jump while the object is rubber-banding hard against a server
|
||||
/// position correction.
|
||||
///
|
||||
/// <para>R3-W3 originally stubbed this as an always-false property under
|
||||
/// a WRONG mechanism guess (per-cell contact-plane / doorway-jamming).
|
||||
/// R5-V1 corrected the mechanism: the real retail source is
|
||||
/// <c>ConstraintManager::IsFullyConstrained</c> (0x005560d0,
|
||||
/// <c>constraint_distance_max * 0.9 < constraint_pos_offset</c>) —
|
||||
/// <see cref="Motion.PositionManager"/>'s constraint sub-manager. R5-V1
|
||||
/// ported <see cref="Motion.ConstraintManager"/> but did not arm it (#167,
|
||||
/// former register row TS-35).</para>
|
||||
///
|
||||
/// <para>Campaign P P5 (2026-07-30) armed the leash at every current
|
||||
/// inbound-position acceptance seam
|
||||
/// (<c>LiveEntityNetworkUpdateController</c> for remotes,
|
||||
/// <c>PlayerMovementController.SetPosition</c>/<c>BlipPosition</c> for the
|
||||
/// local player — see <c>docs/research/2026-07-30-constraint-leash-constants.md</c>
|
||||
/// §2/§3). <see cref="MotionInterpreter"/> only holds a
|
||||
/// <see cref="PhysicsBody"/> reference (no host), so this property stays a
|
||||
/// plain settable bool; the per-tick pump that already runs
|
||||
/// <c>PositionManager.AdjustOffset</c> (<c>PlayerMovementController.Update</c>,
|
||||
/// <c>RuntimeRemotePhysicsUpdater.Tick</c>/<c>TickHidden</c>) is the single
|
||||
/// owner that pushes <c>PositionManager.IsFullyConstrained()</c> here every
|
||||
/// tick, so this read is now live, not stubbed.</para>
|
||||
/// </summary>
|
||||
public bool IsFullyConstrained { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -503,7 +503,11 @@ public sealed class PlayerMovementController
|
|||
/// motion) and <c>UseTime</c> after the completed-motions sweep (retail
|
||||
/// <c>UpdateObjectInternal</c> tail @0x005159b3 — the sticky 1 s lease
|
||||
/// watchdog). <see cref="SetPosition(Vector3, uint, Vector3)"/> tears any
|
||||
/// stick down (retail <c>teleport_hook</c> @0x00514eee).
|
||||
/// stick down (retail <c>teleport_hook</c> @0x00514eee) and, as of
|
||||
/// Campaign P P5 (#167), also tears down and immediately re-arms the
|
||||
/// constraint leash (<c>UnConstrain</c> then <c>ConstrainTo</c>);
|
||||
/// <see cref="BlipPosition"/> arms the leash without tearing it down first
|
||||
/// (retail <c>SmartBox::BlipPlayer</c> survives motion/velocity/stick).
|
||||
/// </summary>
|
||||
public AcDream.Core.Physics.Motion.PositionManager? PositionManager { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -170,10 +170,13 @@ public sealed class EntityPhysicsHost : IPhysicsObjHost
|
|||
public TargetManager TargetManager => _targetManager;
|
||||
|
||||
/// <summary>R5-V3 — the owned <see cref="PositionManager"/> facade (retail
|
||||
/// <c>CPhysicsObj::position_manager</c>): sticky follow + (unarmed)
|
||||
/// constraint leash. Seam targets: <c>MoveToManager.StickTo/Unstick</c>,
|
||||
/// <c>CPhysicsObj::position_manager</c>): sticky follow + the
|
||||
/// server-position constraint leash (armed as of Campaign P P5, #167).
|
||||
/// Seam targets: <c>MoveToManager.StickTo/Unstick</c>,
|
||||
/// <c>MotionInterpreter.UnstickFromObject</c>, the per-tick
|
||||
/// <c>AdjustOffset</c>/<c>UseTime</c> drivers.</summary>
|
||||
/// <c>AdjustOffset</c>/<c>UseTime</c> drivers, and
|
||||
/// <c>LiveEntityNetworkUpdateController</c>'s remote-position
|
||||
/// <c>ConstrainTo</c> arm.</summary>
|
||||
public PositionManager PositionManager { get; }
|
||||
|
||||
// ── IPhysicsObjHost fan-out / target-tracking seams ────────────────────
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue