feat(core): Phase W Stage 1 — return swept sp.CurCellId from ResolveWithTransition (retail SetPositionInternal)

Replace ResolveCellId(sp.GlobalSphere[0].Origin, ...) with SetCurrAndReturn(sp.CurCellId)
in both the OK and partial paths of ResolveWithTransition. Retail's
SetPositionInternal reads sphere_path.curr_cell which ValidateTransition
advances only on accepted moves and reverts on blocks — so a push-back or
standing-still tick cannot flip the cell. The static re-derive from the
resting origin strobes between outdoor 0031 and indoor 0170 at doorway
boundaries because the origin lands just outside the indoor BSP volume
after push-back; the swept cell doesn't.

SetCurrAndReturn is kept in both paths so the W2a CellGraph.CurrCell write
that the render root consumes still fires. ResolveCellId is NOT deleted —
it still has one caller at TransitionTypes.cs:1947 (AddAllOutsideCells).
partialCellId is kept as the degenerate fallback when sp.CurCellId==0
(teleport / physics reset before any transition has run).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-02 14:09:35 +02:00
parent 851cecc757
commit 3e1d502101

View file

@ -915,7 +915,12 @@ public sealed class PhysicsEngine
resolveResult = new ResolveResult(
sp.CheckPos,
ResolveCellId(sp.GlobalSphere[0].Origin, sphereRadius, sp.CheckCellId),
// Phase W Stage 1: return the transition's SWEPT cell (retail SetPositionInternal
// reads sphere_path.curr_cell), not a static re-derive from the resting origin.
// ValidateTransition advances sp.CurCellId only on accepted moves / reverts on
// blocks, so push-back or standing still cannot flip it. SetCurrAndReturn keeps the
// W2a CellGraph.CurrCell write the render root consumes.
SetCurrAndReturn(sp.CurCellId),
onGround,
collisionNormalValid,
collisionNormal);
@ -934,7 +939,9 @@ public sealed class PhysicsEngine
uint partialCellId = sp.CheckCellId != 0 ? sp.CheckCellId : cellId;
resolveResult = new ResolveResult(
sp.CheckPos,
ResolveCellId(sp.GlobalSphere[0].Origin, sphereRadius, partialCellId),
// Phase W Stage 1: prefer the swept cell; fall back to partialCellId only when
// sp.CurCellId is zero (transition never advanced — teleport or physics reset).
SetCurrAndReturn(sp.CurCellId != 0 ? sp.CurCellId : partialCellId),
partialOnGround,
collisionNormalValid,
collisionNormal);