using OpenTK.Mathematics; using VoxelEngine.Core; using VoxelEngine.World.Blocks; using VoxelChunk = VoxelEngine.World.Chunk.Chunk; namespace VoxelEngine.World.WorldGen; public sealed class WorldGenerator { private readonly Configuration _cfg; private readonly BlockRegistry _blocks; private readonly BiomeMap _biomeMap; private readonly TerrainSampler _terrain; private readonly CaveCarver _caves; public WorldGenerator(int seed, BlockRegistry blocks, Configuration cfg) { this._cfg = cfg; this._blocks = blocks; NoiseSource noise = new(seed, cfg); VoronoiCells cells = new(seed, cfg.BiomeCellSize); BiomeRegistry biomes = new(seed, blocks, cfg); this._biomeMap = new BiomeMap(noise, cells, biomes, cfg); this._terrain = new TerrainSampler(noise, this._biomeMap, cfg); this._caves = new CaveCarver(seed, blocks, cfg); } public int SurfaceHeightAt(int worldX, int worldZ) => this._terrain.HeightAt(worldX, worldZ); public string BiomeNameAt(int worldX, int worldZ) => this._biomeMap.BiomeAt(worldX, worldZ).Name; public VoxelChunk Generate(Vector3i chunkPos) { VoxelChunk chunk = new(); int baseX = chunkPos.X * VoxelChunk.Size; int baseY = chunkPos.Y * VoxelChunk.Size; int baseZ = chunkPos.Z * VoxelChunk.Size; for (int x = 0; x < VoxelChunk.Size; x++) for (int z = 0; z < VoxelChunk.Size; z++) { int worldX = baseX + x; int worldZ = baseZ + z; int height = this._terrain.HeightAt(worldX, worldZ); IBiome biome = this._biomeMap.BiomeAt(worldX, worldZ); for (int y = 0; y < VoxelChunk.Size; y++) { int worldY = baseY + y; chunk[x, y, z] = BlockAt(worldY, height, biome, this._blocks, this._cfg.SurfaceFillerDepth); } } this._caves.Carve(chunk, chunkPos); return chunk; } public static ushort BlockAt(int worldY, int surfaceHeight, IBiome biome, BlockRegistry blocks, int fillerDepth) { if (worldY > surfaceHeight) return worldY <= WorldConstants.SeaLevel ? blocks.Water.Id : blocks.Air.Id; if (worldY == surfaceHeight) return biome.TopBlock(worldY).Id; if (worldY >= surfaceHeight - fillerDepth) return biome.Surface.Filler.Id; return biome.Surface.Under.Id; } }