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

@ -94,3 +94,52 @@ None for the constants/flow. Remaining implementation risk is only
where acdream's position-acceptance seams sit today (J6.3 moved
teleport correlation into Runtime — the implementer must find the
current owner rather than trusting older file cites).
## As-ported (Campaign P Slice P5, 2026-07-30)
The implementation risk flagged above resolved to these CURRENT seam owners
(post-J-slices) — recorded here so the next reader doesn't have to re-derive
them:
- **Constants**`src/AcDream.Core/Physics/Motion/ConstraintDistance.cs`.
Keyed purely on the object's own full cell id's low 16 bits (`>= 0x0100` =
indoor); the vestigial player/remote branch from §1 is deliberately not
represented as an API parameter.
- **Remote arm**`src/AcDream.App/Physics/LiveEntityNetworkUpdateController.cs`,
the inbound `UpdatePosition` handler's remote branch (`update.Guid !=
_playerServerGuid`), immediately after the `remotePlacementRequired`
hard-teleport block returns (that block already covers retail's
`MoveOrTeleport` Branch A / hard-place case; everything reached past it is
"did not hard-place"). One call site covers BOTH player-remote and NPC
remotes — retail's `SmartBox::HandleReceivedPosition` doesn't distinguish
them either, only `GetStart/MaxConstraintDistance`'s now-omitted vestigial
branch did. Anchored to the live `IPhysicsObjHost.Position` (which reads
`RemoteMotion.Body.Position` + the tracked cell id), matching retail's
"anchored to the object's own current position" — since the anchor and
`_host.Position` read are the same value at call time,
`ConstraintManager.ConstrainTo`'s initial offset is always 0 regardless of
whether the routing above just far-snapped or left a near-correction
queued.
- **Remote per-tick taper + `IsFullyConstrained` push** — already wired
pre-P5 for the taper (`RuntimeRemotePhysicsUpdater.Tick`/`TickHidden` call
`PositionManager.AdjustOffset` every tick via the pre-existing R5-V3
sticky/constraint chain); P5 added the `PhysicsBody.IsFullyConstrained =
host.PositionManager.IsFullyConstrained()` push at the same two call
sites, since `MotionInterpreter` only holds a `PhysicsBody` (no host
reference) and needs a live value to read.
- **Local player arm**`src/AcDream.Runtime/Gameplay/PlayerMovementController.cs`:
`SetPositionCore` (teleport: `UnConstrain` then re-`ConstrainTo` after the
existing `StopCompletelyAtPhysicsObjectBoundary` velocity zero — composed,
not duplicated) and `CommitPreparedPosition` (mirrors the same pair for
the deferred player-mode-entry commit path); `BlipPosition` (ForcePosition:
`ConstrainTo` only, no teardown — matches `SmartBox::BlipPlayer` surviving
motion/velocity/stick). Anchored to `_body.CellPosition` (the just-applied
received position).
- **Local player per-tick taper + push**`PlayerMovementController.Update`
already called `PositionManager.AdjustOffset` every physics tick pre-P5;
P5 added the `_body.IsFullyConstrained = PositionManager?.IsFullyConstrained()
?? false` push immediately after, at the same chokepoint.
- **TS-35 retirement**`PhysicsBody.IsFullyConstrained` stayed a plain
settable bool (not a computed property) so the ~40 pre-existing direct-set
unit tests keep working; the per-tick pumps above are its single writers
now, matching the project's per-entity single-owner-write pattern.