From 3e1d502101ab1b7a89a3439add315c6226bdb45c Mon Sep 17 00:00:00 2001 From: Erik Date: Tue, 2 Jun 2026 14:09:35 +0200 Subject: [PATCH] =?UTF-8?q?feat(core):=20Phase=20W=20Stage=201=20=E2=80=94?= =?UTF-8?q?=20return=20swept=20sp.CurCellId=20from=20ResolveWithTransition?= =?UTF-8?q?=20(retail=20SetPositionInternal)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- src/AcDream.Core/Physics/PhysicsEngine.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/AcDream.Core/Physics/PhysicsEngine.cs b/src/AcDream.Core/Physics/PhysicsEngine.cs index 33d03db..08f062a 100644 --- a/src/AcDream.Core/Physics/PhysicsEngine.cs +++ b/src/AcDream.Core/Physics/PhysicsEngine.cs @@ -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);