Campaign P Slice P3 item 2. CPhysicsObj::handle_all_collisions
(0x00514780, pc:282647) is one uniform function retail calls
unconditionally after every SetPositionInternal, player or remote. The
gate is shouldReflect = !(prevOnWalkable && nowOnWalkable && !sledding).
RuntimeRemotePhysicsUpdater.Tick's post-resolve reflect was still the
2026-07-05 (#173) hand-inlined block, gated on
resolveResult.CollisionNormalValid and using two ad-hoc branches that
diverge from retail in exactly the cases the register row named:
- non-sledding: old = "!prevOnWalkable && !nowOnWalkable" (reflects
ONLY airborne-before-AND-after); retail reflects on every transition
except grounded-before-AND-after.
- sledding: old = "!(prevOnWalkable && nowOnWalkable)" (suppresses the
bounce exactly when both grounded); retail's "!sledding" term forces
shouldReflect = true unconditionally when sledding, the opposite
polarity.
Both gaps meant a remote's post-landing reflect never ran on a
grounded-transition tick at all -- the "acdream lands clean and dead"
half of #166's slope-landing composite.
Replace the hand-inlined block with a direct call to
PhysicsObjUpdate.HandleAllCollisions -- the same verbatim port the
local player and every ordinary body already use via
CommitSetPositionTransition -- passing the same
prevContact/prevOnWalkable/nowOnWalkable values the old code already
computed. Narrower swap per the research's explicit recommendation:
does not fold in CommitSetPositionTransition's HitGround/LeaveGround
dispatch, leaving the remote's bespoke landing-detection block
(interp-queue-clear, animation-hook-specific logic) untouched. The call
is now unconditional (matching retail's own unconditional call site)
rather than gated behind CollisionNormalValid, since HandleAllCollisions
already no-ops the reflect step internally when no normal was found but
still runs the frames-stationary-fall bleed regardless.
PhysicsObjUpdate.HandleAllCollisionsTests already exhaustively pins the
retail formula in isolation; this change is a mechanical wiring swap to
the already-tested function using values the removed block already
computed. Full regression suites (Core.Tests 3991/2 skip, Runtime.Tests
425/0, App.Tests 3968/3 skip) pass unchanged -- no existing test pinned
the old broken formula.
Register: AD-25 retired (both the local-player and remote halves are now
the ported HandleAllCollisions); #166's reattribution note updated to
reflect the closure, leaving only TS-4 as the remaining blocker on that
issue's downhill-jump-glide acceptance.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>