From b5c1050f431fb020b5a0175c830ada4c115b4de5 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 11 Oct 2024 18:37:03 +0300 Subject: [PATCH] add placements priority --- .../base/generators/demo.files/ores.json | 2 +- .../base/generators/demo.files/script.lua | 4 +- .../scripting/scripting_world_generation.cpp | 34 ++- src/world/generator/GeneratorDef.hpp | 9 +- src/world/generator/StructurePlacement.hpp | 11 + src/world/generator/WorldGenerator.cpp | 227 ++++++++++-------- src/world/generator/WorldGenerator.hpp | 29 ++- 7 files changed, 190 insertions(+), 126 deletions(-) diff --git a/res/content/base/generators/demo.files/ores.json b/res/content/base/generators/demo.files/ores.json index 682bb23a..9ccf696c 100644 --- a/res/content/base/generators/demo.files/ores.json +++ b/res/content/base/generators/demo.files/ores.json @@ -1,3 +1,3 @@ [ - {"struct": "coal_ore0", "rarity": 22000} + {"struct": "coal_ore0", "rarity": 4400} ] diff --git a/res/content/base/generators/demo.files/script.lua b/res/content/base/generators/demo.files/script.lua index 63445863..8e138fd2 100644 --- a/res/content/base/generators/demo.files/script.lua +++ b/res/content/base/generators/demo.files/script.lua @@ -17,7 +17,7 @@ local function place_ores(placements, x, z, w, d, seed, hmap, chunk_height) local sz = math.random() * d local sy = math.random() * (chunk_height * 0.5) if sy < hmap:at(sx, sz) * chunk_height - 6 then - table.insert(placements, {ore.struct, {sx, sy, sz}, math.random()*4}) + table.insert(placements, {ore.struct, {sx, sy, sz}, math.random()*4, -1}) end end end @@ -33,7 +33,7 @@ function place_structures_wide(x, z, w, d, seed, chunk_height) local placements = {} if math.random() < 0.05 then -- generate caves local sx = x + math.random() * 10 - 5 - local sy = math.random() * (chunk_height / 4) + 27 + local sy = math.random() * (chunk_height / 4) + 10 local sz = z + math.random() * 10 - 5 local dir = math.random() * math.pi * 2 diff --git a/src/logic/scripting/scripting_world_generation.cpp b/src/logic/scripting/scripting_world_generation.cpp index 7a339adf..a1865e48 100644 --- a/src/logic/scripting/scripting_world_generation.cpp +++ b/src/logic/scripting/scripting_world_generation.cpp @@ -84,7 +84,7 @@ public: return maps; } - void perform_line(lua::State* L, PrototypePlacements& placements) { + void perform_line(lua::State* L, std::vector& placements) { rawgeti(L, 2); blockid_t block = touinteger(L, -1); pop(L); @@ -101,10 +101,17 @@ public: int radius = touinteger(L, -1); pop(L); - placements.lines.emplace_back(block, a, b, radius); + int priority = 0; + if (objlen(L, -1) >= 6) { + rawgeti(L, 6); + priority = tointeger(L, -1); + pop(L); + } + + placements.emplace_back(priority, LinePlacement {block, a, b, radius}); } - void perform_placement(lua::State* L, PrototypePlacements& placements) { + void perform_placement(lua::State* L, std::vector& placements) { rawgeti(L, 1); int structIndex = 0; if (isstring(L, -1)) { @@ -129,19 +136,28 @@ public: pop(L); rawgeti(L, 3); - int rotation = tointeger(L, -1) & 0b11; + uint8_t rotation = tointeger(L, -1) & 0b11; pop(L); - placements.structs.emplace_back(structIndex, pos, rotation); + int priority = 1; + if (objlen(L, -1) >= 4) { + rawgeti(L, 4); + priority = tointeger(L, -1); + pop(L); + } + + placements.emplace_back( + priority, StructurePlacement {structIndex, pos, rotation} + ); } - PrototypePlacements placeStructuresWide( + std::vector placeStructuresWide( const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed, uint chunkHeight ) override { - PrototypePlacements placements {}; + std::vector placements {}; stackguard _(L); pushenv(L, *env); @@ -165,11 +181,11 @@ public: return placements; } - PrototypePlacements placeStructures( + std::vector placeStructures( const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed, const std::shared_ptr& heightmap, uint chunkHeight ) override { - PrototypePlacements placements {}; + std::vector placements {}; stackguard _(L); pushenv(L, *env); diff --git a/src/world/generator/GeneratorDef.hpp b/src/world/generator/GeneratorDef.hpp index 2247b3a8..f23bea57 100644 --- a/src/world/generator/GeneratorDef.hpp +++ b/src/world/generator/GeneratorDef.hpp @@ -118,11 +118,6 @@ struct Biome { BlocksLayers seaLayers; }; -struct PrototypePlacements { - std::vector structs {}; - std::vector lines {}; -}; - /// @brief Generator behaviour and settings interface class GeneratorScript { public: @@ -154,7 +149,7 @@ public: uint bpd ) = 0; - virtual PrototypePlacements placeStructuresWide( + virtual std::vector placeStructuresWide( const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed, @@ -169,7 +164,7 @@ public: /// @param heightmap area heightmap /// @param chunkHeight chunk height to use as heights multiplier /// @return structure & line placements - virtual PrototypePlacements placeStructures( + virtual std::vector placeStructures( const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed, const std::shared_ptr& heightmap, uint chunkHeight) = 0; }; diff --git a/src/world/generator/StructurePlacement.hpp b/src/world/generator/StructurePlacement.hpp index 58f90c78..2ec7185e 100644 --- a/src/world/generator/StructurePlacement.hpp +++ b/src/world/generator/StructurePlacement.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -25,3 +26,13 @@ struct LinePlacement { : block(block), a(std::move(a)), b(std::move(b)), radius(radius) { } }; + +struct Placement { + int priority; + std::variant placement; + + Placement( + int priority, + std::variant placement + ) : priority(priority), placement(std::move(placement)) {} +}; diff --git a/src/world/generator/WorldGenerator.cpp b/src/world/generator/WorldGenerator.cpp index 9fa1ea76..6c1fdca7 100644 --- a/src/world/generator/WorldGenerator.cpp +++ b/src/world/generator/WorldGenerator.cpp @@ -1,6 +1,7 @@ #include "WorldGenerator.hpp" #include +#include #include "maths/util.hpp" #include "content/Content.hpp" @@ -147,34 +148,36 @@ inline AABB gen_chunk_aabb(int chunkX, int chunkZ) { } void WorldGenerator::placeStructure( - const glm::ivec3& offset, size_t structureId, uint8_t rotation, + const StructurePlacement& placement, int priority, int chunkX, int chunkZ ) { - auto& structure = *def.structures[structureId]->fragments[rotation]; - auto position = glm::ivec3(chunkX * CHUNK_W, 0, chunkZ * CHUNK_D)+offset; + auto& structure = + *def.structures[placement.structure]->fragments[placement.rotation]; + auto position = + glm::ivec3(chunkX * CHUNK_W, 0, chunkZ * CHUNK_D) + placement.position; auto size = structure.getSize() + glm::ivec3(0, CHUNK_H, 0); AABB aabb(position, position + size); for (int lcz = -1; lcz <= 1; lcz++) { for (int lcx = -1; lcx <= 1; lcx++) { - if (lcx == 0 && lcz == 0) { - continue; - } auto& otherPrototype = requirePrototype( chunkX + lcx, chunkZ + lcz ); auto chunkAABB = gen_chunk_aabb(chunkX + lcx, chunkZ + lcz); if (chunkAABB.intersect(aabb)) { - otherPrototype.structures.emplace_back( - structureId, - offset - glm::ivec3(lcx * CHUNK_W, 0, lcz * CHUNK_D), - rotation + otherPrototype.placements.emplace_back( + priority, + StructurePlacement { + placement.structure, + placement.position - + glm::ivec3(lcx * CHUNK_W, 0, lcz * CHUNK_D), + placement.rotation} ); } } } } -void WorldGenerator::placeLine(const LinePlacement& line) { +void WorldGenerator::placeLine(const LinePlacement& line, int priority) { AABB aabb(line.a, line.b); aabb.fix(); aabb.a -= line.radius; @@ -187,30 +190,29 @@ void WorldGenerator::placeLine(const LinePlacement& line) { for (int cx = cxa; cx <= cxb; cx++) { const auto& found = prototypes.find({cx, cz}); if (found != prototypes.end()) { - found->second->lines.push_back(line); + found->second->placements.emplace_back(priority, line); } } } } void WorldGenerator::placeStructures( - const PrototypePlacements& placements, + const std::vector& placements, ChunkPrototype& prototype, int chunkX, int chunkZ ) { - util::concat(prototype.structures, placements.structs); - for (const auto& placement : prototype.structures) { - const auto& offset = placement.position; - if (placement.structure < 0 || placement.structure >= def.structures.size()) { - logger.error() << "invalid structure index " << placement.structure; - continue; + for (const auto& placement : placements) { + if (auto sp = std::get_if(&placement.placement)) { + if (sp->structure < 0 || sp->structure >= def.structures.size()) { + logger.error() << "invalid structure index " << sp->structure; + continue; + } + placeStructure(*sp, placement.priority, chunkX, chunkZ); + } else { + const auto& line = std::get(placement.placement); + placeLine(line, placement.priority); } - placeStructure( - offset, placement.structure, placement.rotation, chunkX, chunkZ); - } - for (const auto& line : placements.lines) { - placeLine(line); } } @@ -251,7 +253,7 @@ void WorldGenerator::generateStructures( for (uint x = 0; x < CHUNK_W; x++) { float rand = structsRand.randFloat(); const Biome* biome = biomes[z * CHUNK_W + x]; - size_t structureId = biome->structures.choose(rand, -1); + int structureId = biome->structures.choose(rand, -1); if (structureId == -1) { continue; } @@ -264,12 +266,16 @@ void WorldGenerator::generateStructures( glm::ivec3 position {x, height, z}; position.x -= structure.getSize().x / 2; position.z -= structure.getSize().z / 2; - prototype.structures.push_back({ - static_cast(structureId), position, rotation}); + prototype.placements.emplace_back( + 1, StructurePlacement {structureId, position, rotation} + ); placeStructure( - position, - structureId, - rotation, + StructurePlacement { + structureId, + position, + rotation + }, + 1, chunkX, chunkZ ); @@ -361,6 +367,9 @@ void WorldGenerator::generatePlants( blockid_t plant = biome->plants.choose(rand); if (plant) { auto& voxel = voxels[vox_index(x, height+1, z)]; + if (voxel.id) { + continue; + } auto& groundVoxel = voxels[vox_index(x, height, z)]; if (indices.get(groundVoxel.id)->rt.solid) { voxel = {plant, {}}; @@ -422,9 +431,8 @@ void WorldGenerator::generate(voxel* voxels, int chunkX, int chunkZ) { generate_pole(groundLayers, height, 0, seaLevel, voxels, x, z); } } - generateLines(prototype, voxels, chunkX, chunkZ); + generatePlacements(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++) { @@ -436,42 +444,64 @@ void WorldGenerator::generate(voxel* voxels, int chunkX, int chunkZ) { #endif } -void WorldGenerator::generateStructures( +void WorldGenerator::generatePlacements( const ChunkPrototype& prototype, voxel* voxels, int chunkX, int chunkZ ) { - for (const auto& placement : prototype.structures) { - if (placement.structure < 0 || placement.structure >= def.structures.size()) { - logger.error() << "invalid structure index " << placement.structure; + auto placements = prototype.placements; + std::stable_sort( + placements.begin(), + placements.end(), + [](const auto& a, const auto& b) { + return a.priority < b.priority; + } + ); + for (const auto& placement : placements) { + if (auto structure = std::get_if(&placement.placement)) { + generateStructure(prototype, *structure, voxels, chunkX, chunkZ); + } else { + const auto& line = std::get(placement.placement); + generateLine(prototype, line, voxels, chunkX, chunkZ); + } + } +} + +void WorldGenerator::generateStructure( + const ChunkPrototype& prototype, + const StructurePlacement& placement, + voxel* voxels, + int chunkX, int chunkZ +) { + if (placement.structure < 0 || placement.structure >= def.structures.size()) { + logger.error() << "invalid structure index " << placement.structure; + return; + } + auto& generatingStructure = def.structures[placement.structure]; + auto& structure = *generatingStructure->fragments[placement.rotation]; + 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; } - auto& generatingStructure = def.structures[placement.structure]; - auto& structure = *generatingStructure->fragments[placement.rotation]; - 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) { + for (int z = 0; z < size.z; z++) { + int sz = z + offset.z; + if (sz < 0 || sz >= CHUNK_D) { continue; } - for (int z = 0; z < size.z; z++) { - int sz = z + offset.z; - if (sz < 0 || sz >= CHUNK_D) { + for (int x = 0; x < size.x; x++) { + int sx = x + offset.x; + if (sx < 0 || sx >= CHUNK_W) { continue; } - for (int x = 0; x < size.x; x++) { - int sx = x + offset.x; - if (sx < 0 || sx >= CHUNK_W) { - continue; - } - const auto& structVoxel = - structVoxels[vox_index(x, y, z, size.x, size.z)]; - if (structVoxel.id) { - if (structVoxel.id == BLOCK_STRUCT_AIR) { - voxels[vox_index(sx, sy, sz)] = {0, {}}; - } else { - voxels[vox_index(sx, sy, sz)] = structVoxel; - } + const auto& structVoxel = + structVoxels[vox_index(x, y, z, size.x, size.z)]; + if (structVoxel.id) { + if (structVoxel.id == BLOCK_STRUCT_AIR) { + voxels[vox_index(sx, sy, sz)] = {0, {}}; + } else { + voxels[vox_index(sx, sy, sz)] = structVoxel; } } } @@ -479,51 +509,56 @@ void WorldGenerator::generateStructures( } } -void WorldGenerator::generateLines( - const ChunkPrototype& prototype, voxel* voxels, int chunkX, int chunkZ +void WorldGenerator::generateLine( + const ChunkPrototype& prototype, + const LinePlacement& line, + 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 const radius = line.radius; + int cgx = chunkX * CHUNK_W; + int cgz = chunkZ * CHUNK_D; - auto a = line.a; - auto b = line.b; + int const radius = line.radius; - int minX = std::max(0, std::min(a.x-radius-cgx, b.x-radius-cgx)); - int maxX = std::min(CHUNK_W, std::max(a.x+radius-cgx, b.x+radius-cgx)); + auto a = line.a; + auto b = line.b; - int minZ = std::max(0, std::min(a.z-radius-cgz, b.z-radius-cgz)); - int maxZ = std::min(CHUNK_D, std::max(a.z+radius-cgz, b.z+radius-cgz)); + int minX = std::max(0, std::min(a.x-radius-cgx, b.x-radius-cgx)); + int maxX = std::min(CHUNK_W, std::max(a.x+radius-cgx, b.x+radius-cgx)); - int minY = std::max(0, std::min(a.y-radius, b.y-radius)); - int maxY = std::min(CHUNK_H, std::max(a.y+radius, b.y+radius)); + int minZ = std::max(0, std::min(a.z-radius-cgz, b.z-radius-cgz)); + int maxZ = std::min(CHUNK_D, std::max(a.z+radius-cgz, b.z+radius-cgz)); - for (int y = minY; y < maxY; y++) { - for (int z = minZ; z < maxZ; z++) { - for (int x = minX; x < maxX; x++) { - int gx = x + cgx; - int gz = z + cgz; - glm::ivec3 point {gx, y, gz}; - glm::ivec3 closest = util::closest_point_on_segment( - a, b, point + int minY = std::max(0, std::min(a.y-radius, b.y-radius)); + int maxY = std::min(CHUNK_H, std::max(a.y+radius, b.y+radius)); + + for (int y = minY; y < maxY; y++) { + for (int z = minZ; z < maxZ; z++) { + for (int x = minX; x < maxX; x++) { + int gx = x + cgx; + int gz = z + cgz; + glm::ivec3 point {gx, y, gz}; + glm::ivec3 closest = util::closest_point_on_segment( + a, b, point + ); + 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 (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, {}}; - } + 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 59a43e1c..c3943e47 100644 --- a/src/world/generator/WorldGenerator.hpp +++ b/src/world/generator/WorldGenerator.hpp @@ -17,7 +17,6 @@ struct GeneratorDef; class Heightmap; struct Biome; class VoxelFragment; -struct PrototypePlacements; enum class ChunkPrototypeLevel { VOID=0, WIDE_STRUCTS, BIOMES, HEIGHTMAP, STRUCTURES @@ -32,9 +31,7 @@ struct ChunkPrototype { /// @brief chunk heightmap std::shared_ptr heightmap; - std::vector structures; - - std::vector lines; + std::vector placements; }; struct WorldGenDebugInfo { @@ -69,22 +66,32 @@ class WorldGenerator { void generateStructures(ChunkPrototype& prototype, int x, int z); + void generatePlacements( + const ChunkPrototype& prototype, voxel* voxels, int x, int z + ); + void generateBiomes(ChunkPrototype& prototype, int x, int z); void generateHeightmap(ChunkPrototype& prototype, int x, int z); void placeStructure( - const glm::ivec3& offset, size_t structure, uint8_t rotation, + const StructurePlacement& placement, int priority, int chunkX, int chunkZ ); - void placeLine(const LinePlacement& line); + void placeLine(const LinePlacement& line, int priority); - void generateLines( - const ChunkPrototype& prototype, voxel* voxels, int x, int z + void generateLine( + const ChunkPrototype& prototype, + const LinePlacement& placement, + voxel* voxels, + int x, int z ); - void generateStructures( - const ChunkPrototype& prototype, voxel* voxels, int x, int z + void generateStructure( + const ChunkPrototype& prototype, + const StructurePlacement& placement, + voxel* voxels, + int x, int z ); void generatePlants( const ChunkPrototype& prototype, @@ -104,7 +111,7 @@ class WorldGenerator { ); void placeStructures( - const PrototypePlacements& placements, + const std::vector& placements, ChunkPrototype& prototype, int x, int z); public: