#include "Generator.hpp" #include "../Math/Noise.hpp" namespace MC::World { Chunk Generator::generate(int64_t chunk_x, int64_t chunk_y) { Chunk chunk(chunk_x, chunk_y); auto ocean_weights = ocean_weights_pass(chunk_x, chunk_y); auto biome_weights = biome_weights_pass(chunk_x, chunk_y, ocean_weights); auto heights = height_pass(chunk_x, chunk_y, biome_weights); auto biomes = flat_biome_pass(biome_weights); float extent = 60.0f; float base = 4.0f; for (int x = 0; x < Chunk::Width; x++) { for (int z = 0; z < Chunk::Width; z++) { uint32_t height = std::round(heights(x, z) * extent + base); auto biome = biomes(x, z); BlockType top_block{}; BlockType fill_block{}; switch (biome) { case BiomeType::Forest: case BiomeType::Plains: top_block = BlockType::Grass; fill_block = BlockType::Dirt; break; case BiomeType::Desert: top_block = BlockType::Sand; fill_block = BlockType::Sand; break; case BiomeType::Ocean: top_block = BlockType::Water; fill_block = BlockType::Dirt; break; } for (int y = 0; y < Chunk::Height; y++) { BlockType type = BlockType::Air; if (y < (int32_t)height - 10) { type = BlockType::Stone; } else if (y < height) { type = fill_block; } else if (y == height) { type = top_block; } chunk.set(x, y, z, type); } } } return chunk; } Matrix Generator::ocean_weights_pass(int64_t chunk_x, int64_t chunk_y) { auto ocean_offset = 1125.0f; auto ocean_scale = 0.05f; Matrix ocean_weights{}; for (int x = 0; x < Chunk::Width; x++) { for (int y = 0; y < Chunk::Width; y++) { float ocean_weight = Math::noise2d({ (chunk_x * Chunk::Width + x) * ocean_scale + ocean_offset, (chunk_y * Chunk::Width + y) * ocean_scale + ocean_offset }); ocean_weights(x, y) = ocean_weight; } } return ocean_weights; } Matrix> Generator::biome_weights_pass( int64_t chunk_x, int64_t chunk_y, Matrix ocean_weights ) { auto ocean_threshold = 0.4f; std::vector biome_offsets = {110.0f, 2450.0f, 5042.0f}; auto biome_scale = 0.15f; Matrix> biome_weights{}; for (int x = 0; x < Chunk::Width; x++) { for (int y = 0; y < Chunk::Width; y++) { Vector weights{}; for (auto biome : MC::World::BiomeType::all_ground()) { float biome_noise = Math::noise2d({ (chunk_x * Chunk::Width + x) * biome_scale + biome_offsets[biome], (chunk_y * Chunk::Width + y) * biome_scale + biome_offsets[biome] }); weights[biome] = biome_noise; } bool ocean_weight = ocean_weights(x, y) < ocean_threshold; weights[MC::World::BiomeType::Ocean] = ocean_weight; biome_weights(x,y) = weights; } } return biome_weights; } Matrix Generator::height_pass( int64_t chunk_x, int64_t chunk_y, Matrix> biome_weights ) { auto height_offset = 6050.0f; auto height_scale = 0.7f; Matrix heights{}; for (int x = 0; x < Chunk::Width; x++) { for (int y = 0; y < Chunk::Width; y++) { auto weights = biome_weights(x, y); auto total_weight = 0.0f; for (auto biome : MC::World::BiomeType::all()) { total_weight += weights[biome]; } std::pair total_effect{}; for (auto biome : MC::World::BiomeType::all()) { auto weight = weights[biome]; std::pair effect{}; switch (biome) { case MC::World::BiomeType::Forest: effect = {0.5f, 0.45f}; break; case MC::World::BiomeType::Plains: effect = {0.4f, 0.4f}; break; case MC::World::BiomeType::Desert: effect = {0.6f, 0.35f}; break; case MC::World::BiomeType::Ocean: effect = {0.0f, 0.0f}; break; } total_effect = { total_effect.first + effect.first * (weight / total_weight), total_effect.second + effect.second * (weight / total_weight), }; } float height = Math::noise2d({ (chunk_x * Chunk::Width + x) * height_scale + height_offset, (chunk_y * Chunk::Width + y) * height_scale + height_offset }) * total_effect.first + total_effect.second; heights(x, y) = height; } } return heights; } Matrix Generator::flat_biome_pass( Matrix> biome_weights ) { Matrix biomes{}; for (int x = 0; x < Chunk::Width; x++) { for (int y = 0; y < Chunk::Width; y++) { auto weights = biome_weights(x, y); std::pair max_biome{MC::World::BiomeType::Plains, 0.0f}; for (auto biome : MC::World::BiomeType::all()) { auto weight = weights[biome]; if (weight > max_biome.second) { max_biome = {biome, weight}; } } biomes(x, y) = max_biome.first; } } return biomes; } }