acdream/tests/AcDream.Core.Tests/World/SceneryGeneratorTests.cs
Erik 768a9a0619 fix(app+core): Phase B.3 — Setup.StepUpHeight + scenery road exclusion
StepUpHeight: when Tab enters player mode, read Setup.StepUpHeight from the
player entity's dat and apply it to the controller (fallback 2f for non-Setup
entities or when the dat value is zero). Previously hardcoded to 5.0 which
made step-up too permissive.

Road exclusion: SceneryGenerator now skips terrain vertices where bits 0-1 of
the raw terrain word are non-zero. These bits encode the road type (GetRoad()
in ACViewer's Landblock.cs). Trees, rocks and bushes will no longer be placed
on road surfaces.

Added SceneryGenerator.IsRoadVertex(ushort) public helper + 9 unit tests
(theory + fact) verifying the road-bit convention matches TerrainInfo.Road.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 18:27:36 +02:00

53 lines
2 KiB
C#

using AcDream.Core.World;
using DatReaderWriter.Types;
namespace AcDream.Core.Tests.World;
/// <summary>
/// Tests for SceneryGenerator road-exclusion logic.
/// The full Generate() pipeline requires real dat files (Region, Scene, etc.)
/// so road-check behavior is tested via the internal IsRoadVertex helper,
/// which is the single gate that guards against placing trees on roads.
/// </summary>
public class SceneryGeneratorTests
{
// Terrain word layout (ushort):
// bits 0-1 = Road (non-zero → on a road)
// bits 2-6 = TerrainType
// bits 11-15 = SceneType
[Theory]
[InlineData(0x0000, false)] // no road bits
[InlineData(0x0001, true)] // road bit 0 set
[InlineData(0x0002, true)] // road bit 1 set
[InlineData(0x0003, true)] // both road bits set
[InlineData(0x007C, false)] // terrain type bits only, no road
[InlineData(0xF800, false)] // scenery bits only, no road
[InlineData(0xF803, true)] // road + scenery bits
public void IsRoadVertex_CorrectlyIdentifiesRoadBits(ushort raw, bool expectedIsRoad)
{
Assert.Equal(expectedIsRoad, SceneryGenerator.IsRoadVertex(raw));
}
[Fact]
public void IsRoadVertex_ZeroTerrain_IsNotRoad()
{
// A fully blank terrain entry (no type, no road, no scene) is not a road.
Assert.False(SceneryGenerator.IsRoadVertex(0));
}
[Fact]
public void IsRoadVertex_MatchesTerrainInfoRoadProperty()
{
// Verify that IsRoadVertex agrees with the typed TerrainInfo.Road property
// for a sample of raw values, ensuring the bit convention is consistent.
for (ushort raw = 0; raw < 4; raw++)
{
TerrainInfo ti = raw;
bool expectedFromStruct = ti.Road != 0;
bool actual = SceneryGenerator.IsRoadVertex(raw);
Assert.True(actual == expectedFromStruct,
$"raw=0x{raw:X4}: IsRoadVertex={actual} but TerrainInfo.Road={ti.Road}");
}
}
}