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 commits e0629145 /
  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:
Erik 2026-07-30 12:12:29 +02:00
parent 7719d25bc5
commit 9e17554ed4
10 changed files with 159 additions and 48 deletions

View file

@ -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 &lt; 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 &lt; 0</c>
/// is false).
/// </summary>
public bool IsFullyConstrained()
=> ConstraintDistanceMax * 0.9f < ConstraintPosOffset;