Files
VoxelEngine/VoxelEngine.Tests/WorldGen/WorldGeneratorTests.cs
MDietermann e034d10339 feat(world-gen): larger biomes, smooth height blending, capped mountains; centralize tunables in Configuration
Terrain feel: biome regions ~10x larger (Voronoi cell size 96->960); terrain height now eases across biome borders via a Voronoi distance blend (smooth, and ~25x cheaper than the old 169-sample box blur); mountains capped to ~2/3 world height and gentled (ridged amplitude/frequency lowered), snow line lowered to match.

Centralization: ~27 world-gen/render tuning constants (biome amplitudes & frequencies, climate-noise frequencies/octaves, biome-selection thresholds, blend width, cell size, filler depth, snow line, camera near plane, spawn offset, overlay scale) hoisted from scattered literals into a region-organized, fully-commented Configuration. Configuration is threaded into NoiseSource, the biomes, BiomeRegistry, BiomeMap (+Classify), TerrainSampler, WorldGenerator (+BlockAt filler depth), and Camera via Player. Defaults equal the prior values, so generation is unchanged; worldgen tests updated for the new constructor signatures.
2026-06-03 16:27:06 +02:00

100 lines
3.5 KiB
C#

using OpenTK.Mathematics;
using VoxelEngine.Core;
using VoxelEngine.World.Blocks;
using VoxelEngine.World.Chunk;
using VoxelEngine.World.WorldGen;
using Xunit;
namespace VoxelEngine.Tests.WorldGen;
public class WorldGeneratorTests
{
private static BlockRegistry Blocks => new();
[Fact]
public void BlockAt_AboveTerrainAndSea_IsAir()
{
var blocks = Blocks;
var biomes = new BiomeRegistry(1, blocks, new Configuration());
ushort id = WorldGenerator.BlockAt(300, surfaceHeight: 290, biomes.Plains, blocks, fillerDepth: 3);
Assert.Equal(blocks.Air.Id, id); // 300 > 290 (above surface) and 300 > SeaLevel(256)
}
[Fact]
public void BlockAt_AboveTerrainBelowSea_IsWater()
{
var blocks = Blocks;
var biomes = new BiomeRegistry(1, blocks, new Configuration());
ushort id = WorldGenerator.BlockAt(60, surfaceHeight: 50, biomes.Plains, blocks, fillerDepth: 3);
Assert.Equal(blocks.Water.Id, id); // 60 > 50 but 60 <= SeaLevel(64)
}
[Fact]
public void BlockAt_Surface_IsBiomeTop()
{
var blocks = Blocks;
var biomes = new BiomeRegistry(1, blocks, new Configuration());
ushort id = WorldGenerator.BlockAt(70, surfaceHeight: 70, biomes.Desert, blocks, fillerDepth: 3);
Assert.Equal(blocks.Sand.Id, id);
}
[Fact]
public void BlockAt_FillerBand_IsBiomeFiller()
{
var blocks = Blocks;
var biomes = new BiomeRegistry(1, blocks, new Configuration());
ushort id = WorldGenerator.BlockAt(68, surfaceHeight: 70, biomes.Plains, blocks, fillerDepth: 3);
Assert.Equal(blocks.Dirt.Id, id); // within 3 of surface
}
[Fact]
public void BlockAt_Deep_IsStone()
{
var blocks = Blocks;
var biomes = new BiomeRegistry(1, blocks, new Configuration());
ushort id = WorldGenerator.BlockAt(40, surfaceHeight: 70, biomes.Plains, blocks, fillerDepth: 3);
Assert.Equal(blocks.Stone.Id, id);
}
[Fact]
public void Generate_IsDeterministic()
{
var gen1 = new WorldGenerator(99, Blocks, new Configuration());
var gen2 = new WorldGenerator(99, Blocks, new Configuration());
Chunk a = gen1.Generate(new Vector3i(0, 4, 0));
Chunk b = gen2.Generate(new Vector3i(0, 4, 0));
for (int x = 0; x < Chunk.Size; x++)
for (int y = 0; y < Chunk.Size; y++)
for (int z = 0; z < Chunk.Size; z++)
Assert.Equal(a[x, y, z], b[x, y, z]);
}
[Fact]
public void Generate_AppliesCaves_ProducesAirVoxelsBelowSurface()
{
var gen = new WorldGenerator(seed: 12345, Blocks, new Configuration());
// A chunk well below typical surface height — guaranteed mostly stone before carving.
Chunk c = gen.Generate(new Vector3i(0, 1, 0)); // worldY = 16..31
int airCount = 0;
for (int x = 0; x < Chunk.Size; x++)
for (int y = 0; y < Chunk.Size; y++)
for (int z = 0; z < Chunk.Size; z++)
if (c[x, y, z] == Blocks.Air.Id) airCount++;
Assert.True(airCount > 0,
"Deep chunk had zero air voxels after generation — caves not running?");
}
[Fact]
public void Generate_PreservesBedrockFloor_Y0_IsStone()
{
var gen = new WorldGenerator(seed: 12345, Blocks, new Configuration());
Chunk c = gen.Generate(new Vector3i(0, 0, 0)); // worldY = 0..15
for (int x = 0; x < Chunk.Size; x++)
for (int z = 0; z < Chunk.Size; z++)
Assert.Equal(Blocks.Stone.Id, c[x, 0, z]);
}
}