From b4578cfb87ace34ea61e4d2a82ec3c15a9ced66a Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 8 Oct 2024 22:37:41 +0300 Subject: [PATCH] fix caves issues & add block 'surface-replacement' property --- res/content/base/blocks/dirt.json | 5 +- src/content/ContentBuilder.cpp | 1 + src/content/ContentLoader.cpp | 1 + src/maths/util.hpp | 4 +- src/voxels/Block.hpp | 5 ++ src/world/generator/WorldGenerator.cpp | 101 +++++++++++++++++++++---- src/world/generator/WorldGenerator.hpp | 16 ++++ 7 files changed, 115 insertions(+), 18 deletions(-) diff --git a/res/content/base/blocks/dirt.json b/res/content/base/blocks/dirt.json index 1495377a..81453c4b 100644 --- a/res/content/base/blocks/dirt.json +++ b/res/content/base/blocks/dirt.json @@ -1,4 +1,5 @@ { "texture": "dirt", - "material": "base:ground" -} \ No newline at end of file + "material": "base:ground", + "surface-replacement": "base:grass_block" +} diff --git a/src/content/ContentBuilder.cpp b/src/content/ContentBuilder.cpp index 60dbf36e..30e65911 100644 --- a/src/content/ContentBuilder.cpp +++ b/src/content/ContentBuilder.cpp @@ -82,6 +82,7 @@ std::unique_ptr ContentBuilder::build() { // Now, it's time to resolve foreign keys for (Block* def : blockDefsIndices) { def->rt.pickingItem = content->items.require(def->pickingItem).rt.id; + def->rt.surfaceReplacement = content->blocks.require(def->surfaceReplacement).rt.id; } for (ItemDef* def : itemDefsIndices) { diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index ff0e371f..151ed19f 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -286,6 +286,7 @@ void ContentLoader::loadBlock( root.at("hidden").get(def.hidden); root.at("draw-group").get(def.drawGroup); root.at("picking-item").get(def.pickingItem); + root.at("surface-replacement").get(def.surfaceReplacement); root.at("script-name").get(def.scriptName); root.at("ui-layout").get(def.uiLayout); root.at("inventory-size").get(def.inventorySize); diff --git a/src/maths/util.hpp b/src/maths/util.hpp index 5f08253f..7500bf2a 100644 --- a/src/maths/util.hpp +++ b/src/maths/util.hpp @@ -74,8 +74,8 @@ namespace util { /// @note glm::distance2 does not support integer vectors inline int distance2(const glm::ivec3& a, const glm::ivec3& b) { return (b.x - a.x) * (b.x - a.x) + - (b.y - a.y) * (b.y - a.y) + - (b.z - a.z) * (b.z - a.z); + (b.y - a.y) * (b.y - a.y) + + (b.z - a.z) * (b.z - a.z); } /// @return integer square of distance between two points diff --git a/src/voxels/Block.hpp b/src/voxels/Block.hpp index 3ba6785a..e9b91664 100644 --- a/src/voxels/Block.hpp +++ b/src/voxels/Block.hpp @@ -181,6 +181,9 @@ public: /// @brief Block script name in blocks/ without extension std::string scriptName = name.substr(name.find(':') + 1); + /// @brief Block will be used instead of this if generated on surface + std::string surfaceReplacement = name; + /// @brief Default block layout will be used by hud.open_block(...) std::string uiLayout = name; @@ -214,6 +217,8 @@ public: /// @brief picking item integer id itemid_t pickingItem = 0; + + blockid_t surfaceReplacement = 0; } rt {}; Block(const std::string& name); diff --git a/src/world/generator/WorldGenerator.cpp b/src/world/generator/WorldGenerator.cpp index daf22ece..46009ec5 100644 --- a/src/world/generator/WorldGenerator.cpp +++ b/src/world/generator/WorldGenerator.cpp @@ -305,6 +305,65 @@ void WorldGenerator::update(int centerX, int centerY, int loadDistance) { surroundMap.setCenter(centerX, centerY); } +void WorldGenerator::generatePlants( + const ChunkPrototype& prototype, + float* heights, + voxel* voxels, + int chunkX, + int chunkZ, + const Biome** biomes +) { + const auto& indices = content->getIndices()->blocks; + util::PseudoRandom plantsRand; + plantsRand.setSeed(chunkX, chunkZ); + + for (uint z = 0; z < CHUNK_D; z++) { + for (uint x = 0; x < CHUNK_W; x++) { + const Biome* biome = biomes[z * CHUNK_W + x]; + + int height = heights[z * CHUNK_W + x] * CHUNK_H; + height = std::max(0, height); + + if (height+1 > def.seaLevel) { + float rand = plantsRand.randFloat(); + blockid_t plant = biome->plants.choose(rand); + if (plant) { + auto& voxel = voxels[vox_index(x, height+1, z)]; + auto& groundVoxel = voxels[vox_index(x, height, z)]; + if (indices.get(groundVoxel.id)->rt.solid) { + voxel = {plant, {}}; + } + } + } + } + } +} + +void WorldGenerator::generateLand( + const ChunkPrototype& prototype, + float* values, + voxel* voxels, + int chunkX, + int chunkZ, + const Biome** biomes +) { + uint seaLevel = def.seaLevel; + for (uint z = 0; z < CHUNK_D; z++) { + for (uint x = 0; x < CHUNK_W; x++) { + const Biome* biome = biomes[z * CHUNK_W + x]; + + int height = values[z * CHUNK_W + x] * CHUNK_H; + height = std::max(0, height); + + const auto& groundLayers = biome->groundLayers; + const auto& seaLayers = biome->seaLayers; + + generate_pole(seaLayers, seaLevel, height, seaLevel, voxels, x, z); + generate_pole(groundLayers, height, 0, seaLevel, voxels, x, z); + } + } +} + void WorldGenerator::generate(voxel* voxels, int chunkX, int chunkZ) { surroundMap.completeAt(chunkX, chunkZ); @@ -315,9 +374,7 @@ void WorldGenerator::generate(voxel* voxels, int chunkX, int chunkZ) { std::memset(voxels, 0, sizeof(voxel) * CHUNK_VOL); - util::PseudoRandom plantsRand; - plantsRand.setSeed(chunkX, chunkZ); - + const auto& indices = content->getIndices()->blocks; const auto& biomes = prototype.biomes.get(); for (uint z = 0; z < CHUNK_D; z++) { for (uint x = 0; x < CHUNK_W; x++) { @@ -331,18 +388,20 @@ void WorldGenerator::generate(voxel* voxels, int chunkX, int chunkZ) { generate_pole(seaLayers, seaLevel, height, seaLevel, voxels, x, z); generate_pole(groundLayers, height, 0, seaLevel, voxels, x, z); - - if (height+1 > seaLevel) { - float rand = plantsRand.randFloat(); - blockid_t plant = biome->plants.choose(rand); - if (plant) { - voxels[vox_index(x, height+1, z)].id = plant; - } - } } } generateLines(prototype, voxels, chunkX, chunkZ); + generatePlants(prototype, values, voxels, chunkX, chunkZ, biomes); generateStructures(prototype, voxels, chunkX, chunkZ); + +#ifndef NDEBUG + for (uint i = 0; i < CHUNK_VOL; i++) { + blockid_t id = voxels[i].id; + if (indices.get(id) == nullptr) { + abort(); + } + } +#endif } void WorldGenerator::generateStructures( @@ -391,11 +450,12 @@ void WorldGenerator::generateStructures( void WorldGenerator::generateLines( const ChunkPrototype& prototype, voxel* voxels, int chunkX, int chunkZ ) { + const auto& indices = content->getIndices()->blocks; for (const auto& line : prototype.lines) { int cgx = chunkX * CHUNK_W; int cgz = chunkZ * CHUNK_D; - int radius = line.radius; + int const radius = line.radius; auto a = line.a; auto b = line.b; @@ -418,8 +478,21 @@ void WorldGenerator::generateLines( glm::ivec3 closest = util::closest_point_on_segment( a, b, point ); - if (util::distance2(closest, point) <= radius*radius) { - voxels[vox_index(x, y, z)] = {line.block, {}}; + if (y > 0 && util::distance2(closest, point) <= radius*radius && line.block == BLOCK_AIR) { + auto& voxel = voxels[vox_index(x, y, z)]; + if (!indices.require(voxel.id).replaceable) { + voxel = {line.block, {}}; + } + auto& below = voxels[vox_index(x, y-1, z)]; + glm::ivec3 closest2 = util::closest_point_on_segment( + a, b, {gx, y-1, gz} + ); + if (util::distance2(closest2, {gx, y-1, gz}) > radius*radius) { + const auto& def = indices.require(below.id); + if (def.rt.surfaceReplacement != below.id) { + below = {def.rt.surfaceReplacement, {}}; + } + } } } } diff --git a/src/world/generator/WorldGenerator.hpp b/src/world/generator/WorldGenerator.hpp index e40ce92f..0e3f580b 100644 --- a/src/world/generator/WorldGenerator.hpp +++ b/src/world/generator/WorldGenerator.hpp @@ -83,6 +83,22 @@ class WorldGenerator { void generateStructures( const ChunkPrototype& prototype, voxel* voxels, int x, int z ); + void generatePlants( + const ChunkPrototype& prototype, + float* values, + voxel* voxels, + int x, + int z, + const Biome** biomes + ); + void generateLand( + const ChunkPrototype& prototype, + float* values, + voxel* voxels, + int x, + int z, + const Biome** biomes + ); public: WorldGenerator( const GeneratorDef& def,