feat(physics): C4 route 2 — ForcePosition through the canonical placement
A local-player ForcePosition had TWO independent writers for one accepted
packet: LocalForcePositionTransaction snapped the physics body
(PlayerMovementController.BlipPosition, a raw SnapToCell with no collision
resolve), while LiveEntityNetworkUpdateController's generic tail separately
wrote position/cell/rotation to the render WorldEntity from the raw wire and
rebucketed it. Two stores, one packet — the divergence class 670f307c fixed on
the remote path. The outbound AutonomousPosition ack also fired BEFORE any
canonical commit existed: we told ACE "got it, I'm here" before deciding where
"here" was, and the trailing isCurrent() could only suppress the continuation,
never recall the packet.
RuntimeAcceptedPositionDriveController is now the one Runtime-owned seam. Both
hosts call the identical TryExecuteAcceptedLocalPosition; App and headless
project the committed result through the existing placement projection sink
(LiveEntityRuntime.TryApplyRuntimePlacementPlace already performed the same
four writes, from committed state rather than a wire guess).
Retail: SmartBox::HandleReceivedPosition @0x00453FD0's FORCE_POSITION branch is
get_heading -> Frame::set_heading -> SmartBox::BlipPlayer @0x00453940 -> stamp
POSITION_TS -> SendPositionEvent @0x00454091 -> return @0x0045409D. BlipPlayer
is CPhysicsObj::SetPositionSimple @0x005162B0 with flags 0x1012
(Teleport|Slide|SendPositionEvent) — a real collision-resolving SetPosition,
not a snap. The pinned classifier already encoded this exactly.
Named behaviour changes:
* The ack is now an OUTPUT of the committed route, fired strictly after the
canonical commit and exactly once per accepted force packet.
* The ForcePosition route no longer re-arms the constraint leash. The force
branch returns at 0x0045409D, ahead of all three ConstrainTo sites
(0x00454272, 0x0045418A, 0x004541EC); the old re-arm cited retail's "Player,
normal" branch, which BlipPlayer is not on. The teleport, CommitPreparedPosition
and first-entry callers legitimately still constrain and are untouched.
* A force correction that terminates WITHOUT committing still sends its
position event and is not retried — retail's BlipPlayer discards
SetPositionSimple's SetPositionError return and acks unconditionally.
A single _pending funnel owns the in-flight placement, deciding on the token's
PositionAuthorityVersion against the record's: equal -> clear; advanced with the
newest accepted event still a force -> re-issue, re-classified; advanced to an
ordinary Apply -> clear, since newer server truth owns that pose. This closes a
double-apply/double-ack and a silently-dropped correction that two earlier
iterations of this slice each introduced.
AD-62 records the residual: a ForcePosition our async collision publication
cannot carry to a committed placement is not re-applied. Retail has no park —
its world is fully resident and its placement synchronous — so the state is
unreachable there. AP-131 is NOT retired; its legacy Position caller is route 4.
Deleted: LocalForcePositionTransaction, PlayerMovementController.BlipPosition,
HeadlessSessionWorldProjection.BlipLocalPlayer.
Gates: complete Release solution 10,858 passed / 4 skipped / 0 failed (baseline
10,844/4/0). Two independent Opus reviews (retail-conformance and
architecture/adversarial) PASS on the final diff after three FAIL rounds; every
intermediate state was fully green, so the suite caught none of the four real
defects. Connected acceptance is NOT run: nothing a user can do makes ACE emit
a ForcePosition without retail's @pklite, which acdream does not implement — see
docs/research/2026-08-03-c4-route-2-visual-gate.md.
Known gap, recorded not claimed: the plan's acceptance item 2 is unmet. The App
double-write check is a source pin, and "the committed projection moves the
render entity" is uncovered at any layer (#292). Filed alongside: #286-#291,
#293-#296.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
22a5c95400
commit
9966b53174
25 changed files with 4292 additions and 195 deletions
|
|
@ -629,8 +629,13 @@ public sealed class PlayerMovementController
|
|||
/// 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).
|
||||
/// <see cref="CommitCanonicalForcePositionFrame"/>'s ForcePosition route
|
||||
/// does NOT touch the leash at all — retail's FORCE_POSITION branch of
|
||||
/// <c>SmartBox::HandleReceivedPosition</c> (@0x00453FD0) returns at
|
||||
/// 0x0045409D, before every <c>ConstrainTo</c> call (C4 route 2 review
|
||||
/// fix, 2026-08-03 — the deleted <c>BlipPosition</c>'s unconditional
|
||||
/// leash re-arm here was an unbacked deviation for that exact branch;
|
||||
/// see docs/research/2026-08-03-c4-route-2-implementation-plan.md §1b).
|
||||
/// </summary>
|
||||
public AcDream.Core.Physics.Motion.PositionManager? PositionManager
|
||||
{
|
||||
|
|
@ -1915,25 +1920,33 @@ public sealed class PlayerMovementController
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retail <c>SmartBox::BlipPlayer</c> (0x00453940): apply a server
|
||||
/// FORCE_POSITION correction through <c>CPhysicsObj::SetPositionSimple</c>
|
||||
/// without the teleport hook. Active motion, velocity, contact state, and
|
||||
/// PositionManager stick relationships deliberately survive the blip.
|
||||
/// C4 route 2: the controller-local half of a ForcePosition commit whose
|
||||
/// body write already happened inside Runtime's canonical
|
||||
/// <c>RuntimeSetPositionState.CommitCanonical</c> (retail
|
||||
/// <c>CPhysicsObj::SetPositionSimple</c> @0x005162B0 with flags
|
||||
/// <c>0x1012</c>, called from <c>SmartBox::BlipPlayer</c> @0x00453940,
|
||||
/// acclient_2013_pseudo_c.txt:284276/92528). Resets the render-lerp
|
||||
/// anchors and republishes the render-root cell — the same two
|
||||
/// controller-local jobs the deleted <c>BlipPosition</c> performed after
|
||||
/// its own (now-Runtime-owned) body snap.
|
||||
///
|
||||
/// Deliberately does NOT call <see cref="RearmConstraintLeashAtCurrentPosition"/>:
|
||||
/// retail's FORCE_POSITION branch of <c>SmartBox::HandleReceivedPosition</c>
|
||||
/// (@0x00453FD0) returns at 0x0045409D, before every
|
||||
/// <c>CPhysicsObj::ConstrainTo</c> call (0x00454272/0x0045418A/
|
||||
/// 0x004541EC) — the deleted <c>BlipPosition</c>'s re-arm here was an
|
||||
/// unbacked deviation (docs/research/2026-08-03-c4-route-2-implementation-plan.md
|
||||
/// §1b); this route retires it. Active motion, velocity, contact state,
|
||||
/// and PositionManager stick relationships are untouched, matching
|
||||
/// retail's BlipPlayer path exactly (Runtime's canonical commit — not
|
||||
/// this method — is what already wrote the body).
|
||||
/// </summary>
|
||||
public void BlipPosition(Vector3 pos, uint cellId, Vector3 cellLocal)
|
||||
internal void CommitCanonicalForcePositionFrame()
|
||||
{
|
||||
EnsurePublishedForRuntimeOperation();
|
||||
_body.SnapToCell(cellId, pos, cellLocal);
|
||||
_prevPhysicsPos = pos;
|
||||
_currPhysicsPos = pos;
|
||||
_prevPhysicsPos = _body.Position;
|
||||
_currPhysicsPos = _body.Position;
|
||||
UpdateCellId(_body.CellPosition.ObjCellId, "force-position");
|
||||
// #167 (Campaign P P5): retail "Player, normal" branch of
|
||||
// SmartBox::HandleReceivedPosition (0x00453fd0) — ConstrainTo anchored
|
||||
// to the received position, with NO teardown call (this is the
|
||||
// BlipPlayer path: motion, velocity, and PositionManager stick
|
||||
// relationships all deliberately survive the blip per the class
|
||||
// comment above, and the leash is no different).
|
||||
RearmConstraintLeashAtCurrentPosition();
|
||||
}
|
||||
|
||||
private Vector3 ComputeRenderPosition()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue