phase(N.1): add LandBlock → TerrainEntry[] adapter
Phase N.1 step 1: WbSceneryAdapter.BuildTerrainEntries converts our LandBlock dat type into the TerrainEntry[81] shape WorldBuilder's TerrainUtils / SceneryRenderManager consume. Field mapping (TerrainInfo → TerrainEntry): TerrainInfo.Road (bits 0-1) → TerrainEntry.Road TerrainInfo.Type (bits 2-6) → TerrainEntry.Type TerrainInfo.Scenery (bits 11-15) → TerrainEntry.Scenery LandBlock.Height[i] → TerrainEntry.Height The spec listed the texture property as 'Texture' but TerrainEntry's actual property is named 'Type' (confirmed from source). The spec also described LandBlock.Terrain as ushort[81] but it is TerrainInfo[81] — DatReaderWriter already decodes the bit fields so the adapter uses TerrainInfo's named properties rather than raw bit-shift expressions. Spec: docs/superpowers/specs/2026-05-08-phase-n1-scenery-via-wb-helpers-design.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
21425ffb22
commit
26cf2b84e7
2 changed files with 119 additions and 0 deletions
74
tests/AcDream.Core.Tests/World/WbSceneryAdapterTests.cs
Normal file
74
tests/AcDream.Core.Tests/World/WbSceneryAdapterTests.cs
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
using AcDream.Core.World;
|
||||
using DatReaderWriter.DBObjs;
|
||||
using DatReaderWriter.Types;
|
||||
|
||||
namespace AcDream.Core.Tests.World;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for <see cref="WbSceneryAdapter"/>. The adapter converts our
|
||||
/// LandBlock dat type (Terrain TerrainInfo[81] + Height byte[81]) into
|
||||
/// WorldBuilder's <see cref="WorldBuilder.Shared.Models.TerrainEntry"/>[81]
|
||||
/// shape, which WB's TerrainUtils / SceneryRenderManager consume.
|
||||
///
|
||||
/// Bit layout in LandBlock.Terrain[i] (TerrainInfo / ushort):
|
||||
/// bits 0-1 : Road (2 bits) → WB TerrainEntry.Road
|
||||
/// bits 2-6 : TerrainType (5 bits) → WB TerrainEntry.Type
|
||||
/// bits 11-15 : SceneType (5 bits) → WB TerrainEntry.Scenery
|
||||
/// Height comes from LandBlock.Height[i] (byte) → WB TerrainEntry.Height.
|
||||
/// </summary>
|
||||
public class WbSceneryAdapterTests
|
||||
{
|
||||
[Fact]
|
||||
public void BuildTerrainEntries_PreservesRoadTextureSceneryHeight()
|
||||
{
|
||||
var block = new LandBlock();
|
||||
|
||||
// Vertex 0: road=0x3, type=0x00, scenery=0x1F, height=42
|
||||
// raw layout: bits 0-1=11, bits 2-6=00000, bits 7-10=0000, bits 11-15=11111
|
||||
// = 0xF803
|
||||
block.Terrain[0] = (TerrainInfo)0xF803;
|
||||
block.Height[0] = 42;
|
||||
|
||||
// Vertex 80: road=0x0, type=0x1F, scenery=0x00, height=200
|
||||
// raw layout: bits 0-1=00, bits 2-6=11111, bits 11-15=00000
|
||||
// = 0x007C
|
||||
block.Terrain[80] = (TerrainInfo)0x007C;
|
||||
block.Height[80] = 200;
|
||||
|
||||
var entries = WbSceneryAdapter.BuildTerrainEntries(block);
|
||||
|
||||
Assert.Equal(81, entries.Length);
|
||||
|
||||
Assert.Equal((byte)42, entries[0].Height);
|
||||
Assert.Equal((byte)0x3, entries[0].Road);
|
||||
Assert.Equal((byte)0x00, entries[0].Type);
|
||||
Assert.Equal((byte)0x1F, entries[0].Scenery);
|
||||
|
||||
Assert.Equal((byte)200, entries[80].Height);
|
||||
Assert.Equal((byte)0x0, entries[80].Road);
|
||||
Assert.Equal((byte)0x1F, entries[80].Type);
|
||||
Assert.Equal((byte)0x00, entries[80].Scenery);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildTerrainEntries_AllZeros_ProducesEmptyEntries()
|
||||
{
|
||||
var block = new LandBlock();
|
||||
// Terrain and Height are already zero-initialized by LandBlock constructor.
|
||||
var entries = WbSceneryAdapter.BuildTerrainEntries(block);
|
||||
Assert.All(entries, e =>
|
||||
{
|
||||
Assert.Equal((byte)0, e.Height);
|
||||
Assert.Equal((byte)0, e.Road);
|
||||
Assert.Equal((byte)0, e.Type);
|
||||
Assert.Equal((byte)0, e.Scenery);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildTerrainEntries_NullBlock_Throws()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() =>
|
||||
WbSceneryAdapter.BuildTerrainEntries(null!));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue