From 78ce09944039499135670a5b51629b62d0fe58d3 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 10 Apr 2026 20:18:09 +0200 Subject: [PATCH] fix(core): LandblockMesh keys atlas lookup on TerrainInfo.Type Task 1's subagent used the raw ushort as the map key because the test used raw ushort 7 as the value. But the atlas map is built from Region.TerrainInfo.LandSurfaces.TexMerge.TerrainDesc which keys on TerrainTextureType enum values, extracted from bits 2-6 of the TerrainInfo ushort per DatReaderWriter's Types/TerrainInfo.cs. Reverts to using block.Terrain[hi].Type so the Task 2 TerrainAtlas can actually find matching keys against real dat terrain. The test is updated to encode Type=7 correctly as (7 << 2) in the raw ushort. --- src/AcDream.Core/Terrain/LandblockMesh.cs | 9 +++++---- .../Terrain/LandblockMeshTests.cs | 14 ++++++++------ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/AcDream.Core/Terrain/LandblockMesh.cs b/src/AcDream.Core/Terrain/LandblockMesh.cs index 934e754..860353e 100644 --- a/src/AcDream.Core/Terrain/LandblockMesh.cs +++ b/src/AcDream.Core/Terrain/LandblockMesh.cs @@ -34,10 +34,11 @@ public static class LandblockMesh float height = heightTable[block.Height[hi]]; - // TerrainInfo raw ushort value used as the atlas-layer map key. - // The map is keyed on the raw terrain ushort (which encodes Road, - // Type, and Scenery fields), matching what the test and caller supply. - uint terrainType = (ushort)block.Terrain[hi]; + // TerrainInfo is bit-packed: bits 0-1 Road, bits 2-6 Type (5-bit + // TerrainTextureType enum), bits 11-15 Scenery. The atlas keys on + // Type only, matching Region.TerrainInfo.LandSurfaces.TexMerge.TerrainDesc + // which lists SurfaceTexture ids per TerrainTextureType. + uint terrainType = (uint)block.Terrain[hi].Type; if (!terrainTypeToLayer.TryGetValue(terrainType, out var layer)) layer = 0; diff --git a/tests/AcDream.Core.Tests/Terrain/LandblockMeshTests.cs b/tests/AcDream.Core.Tests/Terrain/LandblockMeshTests.cs index d106fa2..0d91e6e 100644 --- a/tests/AcDream.Core.Tests/Terrain/LandblockMeshTests.cs +++ b/tests/AcDream.Core.Tests/Terrain/LandblockMeshTests.cs @@ -89,15 +89,17 @@ public class LandblockMeshTests public void Build_PerVertexTerrainLayer_UsesMappedLayerIndex() { var block = BuildFlatLandBlock(); - // TerrainInfo is a struct with implicit conversion from ushort. The low 5 bits - // of the ushort encode TerrainTextureType via TerrainInfo.Type. - // Set vertex at x-major index (x=2, y=3) to terrain type 7. - block.Terrain[2 * 9 + 3] = (ushort)7; // low 5 bits = 7 + // TerrainInfo is bit-packed: bits 0-1 Road, bits 2-6 Type, bits 11-15 Scenery. + // Raw ushort 0x001C = binary 0011100 → Type field = 7 (bits 2-6). + // This is what a terrain sample with TerrainTextureType=7 looks like in the + // underlying byte stream. LandblockMesh uses TerrainInfo.Type (not raw) as + // the atlas lookup key. + block.Terrain[2 * 9 + 3] = (ushort)(7 << 2); // Type=7, Road=0, Scenery=0 var map = new Dictionary { [0] = 0u, // default type → atlas layer 0 - [7] = 4u, // type 7 → atlas layer 4 + [7] = 4u, // TerrainTextureType 7 → atlas layer 4 }; var mesh = LandblockMesh.Build(block, IdentityHeightTable, map); @@ -105,7 +107,7 @@ public class LandblockMeshTests // Vertex buffer internal order is y*9+x, so vertex at world (x=2, y=3) is at // index 3*9+2 = 29. Assert.Equal(4u, mesh.Vertices[3 * 9 + 2].TerrainLayer); - // An untouched vertex still has type 0, maps to layer 0. + // An untouched vertex still has Type 0, maps to layer 0. Assert.Equal(0u, mesh.Vertices[0].TerrainLayer); }