From 7605439efaf6754343e93f984b02f14572d1c391 Mon Sep 17 00:00:00 2001 From: Erik Date: Sun, 21 Jun 2026 17:38:47 +0200 Subject: [PATCH] =?UTF-8?q?test(physics=20#145):=20continuous-tracking=20t?= =?UTF-8?q?est=20=E2=80=94=20refutes=20the=20review=20staleness=20claim?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adversarial review flagged a possible CellPosition staleness on indoor->outdoor transition. Verified against source: false positive (SnapToCell isn't called on building entry; the body is world-space so the delta is frame-invariant; the anchor disengages indoors). Added a test proving CellPosition tracks the outdoor cell under the world position across a multi-cell, cross-landblock walk and stays canonical. Core cell-sync 6/6. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Physics/PhysicsBodyCellSyncTests.cs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/AcDream.Core.Tests/Physics/PhysicsBodyCellSyncTests.cs b/tests/AcDream.Core.Tests/Physics/PhysicsBodyCellSyncTests.cs index 3c1e22ed..fed0ca92 100644 --- a/tests/AcDream.Core.Tests/Physics/PhysicsBodyCellSyncTests.cs +++ b/tests/AcDream.Core.Tests/Physics/PhysicsBodyCellSyncTests.cs @@ -65,4 +65,38 @@ public class PhysicsBodyCellSyncTests body.Position += new Vector3(10f, 10f, 0f); Assert.Equal(0u, body.CellPosition.ObjCellId); } + + [Fact] + public void ContinuousTracking_LongWalkAcrossCellsAndBlock_NeverGoesStale() + { + // Refutes the "CellPosition goes stale" concern (incl. the indoor-transit case): + // because the Position setter re-derives the cell via AdjustToOutside on EVERY + // write, CellPosition continuously tracks the outdoor cell under the body's WORLD + // position. The body is always world-space, so the world delta is frame-invariant — + // there is no separate "interior" frame to desync. On any exit it is the correct + // cell, never stale. + var body = new PhysicsBody(); + body.SnapToCell(0xC95B0001u, new Vector3(1000f, 2000f, 12f), new Vector3(10f, 10f, 12f)); + + // A winding walk: east within the block, then north across the 192 m boundary. + foreach (var step in new[] + { + new Vector3(50f, 0f, 0f), + new Vector3(50f, 0f, 0f), + new Vector3(0f, 100f, 0f), + new Vector3(0f, 100f, 0f), // local Y 110 → 210, crosses north into 0xC95C + }) + body.Position += step; + + // local accum (10,10)+(100,200) = (110,210); Y 210 wraps to the north neighbour + // 0xC95C (lbY 0x5B → 0x5C), local Y = 210−192 = 18; cell (lx=4, ly=0) → low 0x21. + Assert.Equal(0xC95C0021u, body.CellPosition.ObjCellId); + Assert.Equal(new Vector3(110f, 18f, 12f), body.CellPosition.Frame.Origin); + + // And the carried (cell, local) is already canonical — re-deriving does not march. + uint cell = body.CellPosition.ObjCellId; + var local = body.CellPosition.Frame.Origin; + Assert.True(LandDefs.AdjustToOutside(ref cell, ref local)); + Assert.Equal(body.CellPosition.ObjCellId, cell); + } }