diff --git a/tests/AcDream.Core.Tests/Terrain/TerrainModernConformanceTests.cs b/tests/AcDream.Core.Tests/Terrain/TerrainModernConformanceTests.cs index 3bc403b..c02f7cc 100644 --- a/tests/AcDream.Core.Tests/Terrain/TerrainModernConformanceTests.cs +++ b/tests/AcDream.Core.Tests/Terrain/TerrainModernConformanceTests.cs @@ -41,7 +41,7 @@ public class TerrainModernConformanceTests ("Mid-map 0x7F7F", 0x7F, 0x7F), ("MapCorner 0xFEFE", 0xFE, 0xFE), ("Subway outdoor 0x0185", 0x01, 0x85), - ("North continent 0x4D96", 0x4D, 0x96), + ("North continent 0x4D96", 0x4D, 0x96), // worst-case landblock from SplitFormulaDivergenceTest }; [Fact] @@ -102,14 +102,19 @@ public class TerrainModernConformanceTests var surfaceCache = new Dictionary(); var meshData = LandblockMesh.Build(landblock, lbX, lbY, heightTable, ctx, surfaceCache); - // Sample 100 (localX, localY) points uniformly in [0, 192). - // We avoid the exact upper bound (192) because that maps to - // cell index 8 which the physics path clamps; the pure mesh - // sampler doesn't have triangles past 192 anyway. + // Sample 100 (localX, localY) points uniformly in [0, 191.975]. + // The physics path clamps fx = localX/24 to (CellsPerSide - 0.001f) + // = 7.999, which corresponds to localX <= 7.999 * 24 = 191.976. + // Sampling beyond that boundary makes physics compute Z at the + // clamped position while the mesh sampler uses the actual + // position — a difference of up to 23 mm at the upper edge, + // which on a steep slope would falsely trip the 1 mm sentinel. + // Stay strictly below the clamp boundary so both oracles + // compute Z at the same (cellX, tx). for (int s = 0; s < 100; s++) { - float lx = (float)rng.NextDouble() * 191.999f; - float ly = (float)rng.NextDouble() * 191.999f; + float lx = (float)rng.NextDouble() * 191.975f; + float ly = (float)rng.NextDouble() * 191.975f; float meshZ = SampleMeshZ(meshData, lx, ly); float physicsZ = TerrainSurface.SampleZFromHeightmap(