From 03ba7c9539dc20c92dac0dfc4ad851c681fa64f1 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 21 Sep 2024 17:21:47 +0300 Subject: [PATCH] test voxel structures generation --- res/generators/default.files/tree0.vox | Bin 16479 -> 16479 bytes res/generators/default.lua | 16 ++- .../scripting/scripting_world_generation.cpp | 35 +++++++ src/world/generator/GeneratorDef.hpp | 5 + src/world/generator/StructurePlacement.hpp | 12 +++ src/world/generator/VoxelStructure.cpp | 8 +- src/world/generator/VoxelStructure.hpp | 1 + src/world/generator/WorldGenerator.cpp | 97 ++++++++++++++---- src/world/generator/WorldGenerator.hpp | 30 ++---- 9 files changed, 164 insertions(+), 40 deletions(-) create mode 100644 src/world/generator/StructurePlacement.hpp diff --git a/res/generators/default.files/tree0.vox b/res/generators/default.files/tree0.vox index 3bcff6939b0f4c9ff3aefcdf1375869974caf324..c01219d8ee27132f1431e07cbc1f80617f9d88be 100644 GIT binary patch delta 59 zcmccLz<9rbal;2jMwZPV8UHhbC{_r?388o)l;D46Ru*PPX6DHo1#LGQiRo$q0K3E# A-2eap delta 59 zcmccLz<9rbal;43%}jFtm>C%-3fgbhV>`q=QOIhu7S}OmMuyEFdH;hc!T-$649tv^ M*8`OpiRo$q0DwgksQ>@~ diff --git a/res/generators/default.lua b/res/generators/default.lua index 89b03707..d6058b4b 100644 --- a/res/generators/default.lua +++ b/res/generators/default.lua @@ -57,10 +57,24 @@ biomes = { function load_structures() local structures = {} - table.insert(structures, generation.load_structure("core:default.files/tree0")) + local names = {"tree0"} + for i, name in ipairs(names) do + local filename = "core:default.files/"..name + debug.log("loading structure "..filename) + table.insert(structures, generation.load_structure(filename)) + end return structures end +function place_structures(x, z, w, d, seed) + local placements = {} + local px = math.random() * w + local py = 200; + local pz = math.random() * d + table.insert(placements, {0, {px, py, pz}}) + return placements +end + local function _generate_heightmap(x, y, w, h, seed, s) local umap = Heightmap(w, h) local vmap = Heightmap(w, h) diff --git a/src/logic/scripting/scripting_world_generation.cpp b/src/logic/scripting/scripting_world_generation.cpp index b291d600..4551a0c9 100644 --- a/src/logic/scripting/scripting_world_generation.cpp +++ b/src/logic/scripting/scripting_world_generation.cpp @@ -43,6 +43,7 @@ public: lua::touserdata(L, -1)) { structures.push_back(lstruct->getStructure()); } + lua::pop(L); } } } @@ -97,6 +98,40 @@ public: return maps; } + std::vector placeStructures( + const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed + ) override { + std::vector placements; + + auto L = lua::get_main_thread(); + lua::stackguard _(L); + lua::pushenv(L, *env); + if (lua::getfield(L, "place_structures")) { + lua::pushivec_stack(L, offset); + lua::pushivec_stack(L, size); + lua::pushinteger(L, seed); + if (lua::call_nothrow(L, 5, 1)) { + int len = lua::objlen(L, -1); + for (int i = 1; i <= len; i++) { + lua::rawgeti(L, i); + + lua::rawgeti(L, 1); + int structIndex = lua::tointeger(L, -1); + lua::pop(L); + + lua::rawgeti(L, 2); + glm::ivec3 pos = lua::tovec3(L, -1); + + lua::pop(L); + + placements.emplace_back(structIndex, pos); + } + lua::pop(L); + } + } + return placements; + } + void prepare(const Content* content) override { for (auto& biome : biomes) { for (auto& layer : biome.groundLayers.layers) { diff --git a/src/world/generator/GeneratorDef.hpp b/src/world/generator/GeneratorDef.hpp index f219e6d4..d038c986 100644 --- a/src/world/generator/GeneratorDef.hpp +++ b/src/world/generator/GeneratorDef.hpp @@ -5,6 +5,7 @@ #include "typedefs.hpp" #include "maths/Heightmap.hpp" +#include "StructurePlacement.hpp" class Content; class VoxelStructure; @@ -114,6 +115,10 @@ public: virtual std::vector> generateParameterMaps( const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed) = 0; + virtual std::vector placeStructures( + const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed) = 0; + + /// @brief Get generator biomes virtual const std::vector& getBiomes() const = 0; /// @return Number of biome parameters, that biome choosing depending on diff --git a/src/world/generator/StructurePlacement.hpp b/src/world/generator/StructurePlacement.hpp new file mode 100644 index 00000000..584ec1dd --- /dev/null +++ b/src/world/generator/StructurePlacement.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include + +struct StructurePlacement { + int structure; + + glm::ivec3 position; + + StructurePlacement(int structure, glm::ivec3 position) + : structure(structure), position(std::move(position)) {} +}; diff --git a/src/world/generator/VoxelStructure.cpp b/src/world/generator/VoxelStructure.cpp index b7595064..6e27e086 100644 --- a/src/world/generator/VoxelStructure.cpp +++ b/src/world/generator/VoxelStructure.cpp @@ -40,6 +40,7 @@ std::unique_ptr VoxelStructure::create( index = found->second; } voxels[i].id = index; + voxels[i].state = volVoxels[i].state; } return std::make_unique( @@ -67,6 +68,11 @@ void VoxelStructure::deserialize(const dv::value& src) { size = glm::ivec3(); dv::get_vec(src, "size", size); + const auto& namesArr = src["block-names"]; + for (const auto& elem : namesArr) { + blockNames.push_back(elem.asString()); + } + auto volume = size.x*size.y*size.z; voxels.resize(volume); @@ -81,7 +87,7 @@ void VoxelStructure::prepare(const Content& content) { auto volume = size.x*size.y*size.z; voxelsRuntime.resize(volume); for (size_t i = 0; i < volume; i++) { - const auto& name = blockNames[voxels[i].id]; + const auto& name = blockNames.at(voxels[i].id); voxelsRuntime[i].id = content.blocks.require(name).rt.id; voxelsRuntime[i].state = voxels[i].state; } diff --git a/src/world/generator/VoxelStructure.hpp b/src/world/generator/VoxelStructure.hpp index 444a1f1a..938df3cd 100644 --- a/src/world/generator/VoxelStructure.hpp +++ b/src/world/generator/VoxelStructure.hpp @@ -48,6 +48,7 @@ public: } const std::vector& getRuntimeVoxels() { + assert(!voxelsRuntime.empty()); return voxelsRuntime; } }; diff --git a/src/world/generator/WorldGenerator.cpp b/src/world/generator/WorldGenerator.cpp index 5991a699..2e6462e8 100644 --- a/src/world/generator/WorldGenerator.cpp +++ b/src/world/generator/WorldGenerator.cpp @@ -15,7 +15,7 @@ static debug::Logger logger("world-generator"); static inline constexpr uint MAX_PARAMETERS = 4; -static inline constexpr uint MAX_CHUNK_PROTOTYPE_LEVELS = 3; +static inline constexpr uint MAX_CHUNK_PROTOTYPE_LEVELS = 5; WorldGenerator::WorldGenerator( const GeneratorDef& def, const Content* content, uint64_t seed @@ -44,14 +44,31 @@ WorldGenerator::WorldGenerator( if (found == prototypes.end()) { throw std::runtime_error("prototype not found"); } - generateHeightmap(found->second.get(), x, z); + generateStructures(requirePrototype(x, z), x, z); + }); + surroundMap.setLevelCallback(3, [this](int const x, int const z) { + generateBiomes(requirePrototype(x, z), x, z); + }); + surroundMap.setLevelCallback(4, [this](int const x, int const z) { + generateHeightmap(requirePrototype(x, z), x, z); }); structures = def.script->loadStructures(); + for (auto& structure : structures) { + structure->prepare(*content); + } } WorldGenerator::~WorldGenerator() {} +ChunkPrototype& WorldGenerator::requirePrototype(int x, int z) { + const auto& found = prototypes.find({x, z}); + if (found == prototypes.end()) { + throw std::runtime_error("prototype not found"); + } + return *found->second; +} + static inline void generate_pole( const BlocksLayers& layers, int top, int bottom, @@ -112,6 +129,27 @@ static inline const Biome* choose_biome( std::unique_ptr WorldGenerator::generatePrototype( int chunkX, int chunkZ ) { + return std::make_unique(); +} + +void WorldGenerator::generateStructures( + ChunkPrototype& prototype, int chunkX, int chunkZ +) { + if (prototype.level >= ChunkPrototypeLevel::STRUCTURES) { + return; + } + prototype.structures = def.script->placeStructures( + {chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, seed + ); + prototype.level = ChunkPrototypeLevel::STRUCTURES; +} + +void WorldGenerator::generateBiomes( + ChunkPrototype& prototype, int chunkX, int chunkZ +) { + if (prototype.level >= ChunkPrototypeLevel::BIOMES) { + return; + } auto biomeParams = def.script->generateParameterMaps( {chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, seed); const auto& biomes = def.script->getBiomes(); @@ -123,21 +161,19 @@ std::unique_ptr WorldGenerator::generatePrototype( choose_biome(biomes, biomeParams, x, z); } } - return std::make_unique( - ChunkPrototypeLevel::BIOMES, - std::move(chunkBiomes), - nullptr); + prototype.biomes = std::move(chunkBiomes); + prototype.level = ChunkPrototypeLevel::BIOMES; } void WorldGenerator::generateHeightmap( - ChunkPrototype* prototype, int chunkX, int chunkZ + ChunkPrototype& prototype, int chunkX, int chunkZ ) { - if (prototype->level >= ChunkPrototypeLevel::HEIGHTMAP) { + if (prototype.level >= ChunkPrototypeLevel::HEIGHTMAP) { return; } - prototype->heightmap = def.script->generateHeightmap( + prototype.heightmap = def.script->generateHeightmap( {chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, seed); - prototype->level = ChunkPrototypeLevel::HEIGHTMAP; + prototype.level = ChunkPrototypeLevel::HEIGHTMAP; } void WorldGenerator::update(int centerX, int centerY, int loadDistance) { @@ -150,13 +186,8 @@ void WorldGenerator::update(int centerX, int centerY, int loadDistance) { void WorldGenerator::generate(voxel* voxels, int chunkX, int chunkZ) { surroundMap.completeAt(chunkX, chunkZ); - const auto& found = prototypes.find({chunkX, chunkZ}); - if (found == prototypes.end()) { - throw std::runtime_error("no prototype found"); - } - - auto prototype = found->second.get(); - const auto values = prototype->heightmap->getValues(); + const auto& prototype = requirePrototype(chunkX, chunkZ); + const auto values = prototype.heightmap->getValues(); uint seaLevel = def.script->getSeaLevel(); @@ -165,7 +196,7 @@ void WorldGenerator::generate(voxel* voxels, int chunkX, int chunkZ) { PseudoRandom plantsRand; plantsRand.setSeed(chunkX, chunkZ); - const auto& biomes = prototype->biomes.get(); + const auto& biomes = prototype.biomes.get(); for (uint z = 0; z < CHUNK_D; z++) { for (uint x = 0; x < CHUNK_W; x++) { const Biome* biome = biomes[z * CHUNK_W + x]; @@ -189,4 +220,34 @@ void WorldGenerator::generate(voxel* voxels, int chunkX, int chunkZ) { } } } + + for (const auto& placement : prototype.structures) { + if (placement.structure < 0 || placement.structure >= structures.size()) { + logger.error() << "invalid structure index " << placement.structure; + } + auto& structure = *structures[placement.structure]; + auto& structVoxels = structure.getRuntimeVoxels(); + const auto& offset = placement.position; + const auto& size = structure.getSize(); + for (int y = 0; y < size.y; y++) { + int sy = y + offset.y; + if (sy < 0 || sy >= CHUNK_H) { + continue; + } + for (int z = 0; z < size.z; z++) { + int sz = z + offset.z; + if (sz < 0 || sz >= CHUNK_D) { + continue; + } + for (int x = 0; x < size.x; x++) { + int sx = x + offset.x; + if (sx < 0 || sx >= CHUNK_W) { + continue; + } + voxels[vox_index(sx, sy, sz)] = + structVoxels[vox_index(x, y, z, size.x, size.z)]; + } + } + } + } } diff --git a/src/world/generator/WorldGenerator.hpp b/src/world/generator/WorldGenerator.hpp index 8d6306c9..3b3fc12e 100644 --- a/src/world/generator/WorldGenerator.hpp +++ b/src/world/generator/WorldGenerator.hpp @@ -9,6 +9,7 @@ #include "typedefs.hpp" #include "voxels/voxel.hpp" #include "SurroundMap.hpp" +#include "StructurePlacement.hpp" class Content; struct GeneratorDef; @@ -17,20 +18,11 @@ struct Biome; class VoxelStructure; enum class ChunkPrototypeLevel { - BIOMES, HEIGHTMAP -}; - -struct StructurePlacement { - VoxelStructure& structure; - - glm::ivec3 position; - - StructurePlacement(VoxelStructure& structure, glm::ivec3 position) - : structure(structure), position(std::move(position)) {} + VOID=0, STRUCTURES, BIOMES, HEIGHTMAP }; struct ChunkPrototype { - ChunkPrototypeLevel level; + ChunkPrototypeLevel level = ChunkPrototypeLevel::VOID; /// @brief chunk biomes matrix std::unique_ptr biomes; @@ -39,14 +31,6 @@ struct ChunkPrototype { std::shared_ptr heightmap; std::vector structures; - - ChunkPrototype( - ChunkPrototypeLevel level, - std::unique_ptr biomes, - std::shared_ptr heightmap - ) : level(level), - biomes(std::move(biomes)), - heightmap(std::move(heightmap)) {}; }; /// @brief High-level world generation controller @@ -69,7 +53,13 @@ class WorldGenerator { /// @param z chunk position Y divided by CHUNK_D std::unique_ptr generatePrototype(int x, int z); - void generateHeightmap(ChunkPrototype* prototype, int x, int z); + ChunkPrototype& requirePrototype(int x, int z); + + void generateStructures(ChunkPrototype& prototype, int x, int z); + + void generateBiomes(ChunkPrototype& prototype, int x, int z); + + void generateHeightmap(ChunkPrototype& prototype, int x, int z); public: WorldGenerator( const GeneratorDef& def,