From faca68e6c33b5cce4a3ea545d35adedd17fa078e Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 16 Oct 2024 08:46:32 +0300 Subject: [PATCH] replace argument 'seed' with global constant 'SEED' --- doc/ru/world-generator.md | 27 ++++--- .../base/generators/demo.files/script.lua | 24 +++--- .../scripting/scripting_world_generation.cpp | 80 ++++++++++--------- src/world/generator/GeneratorDef.hpp | 20 +++-- src/world/generator/WorldGenerator.cpp | 8 +- 5 files changed, 85 insertions(+), 74 deletions(-) diff --git a/doc/ru/world-generator.md b/doc/ru/world-generator.md index eb8d6d60..aa9228c3 100644 --- a/doc/ru/world-generator.md +++ b/doc/ru/world-generator.md @@ -3,6 +3,7 @@ ## Содержание - [Основные понятия](#основные-понятия) +- [Глобальные переменные](#глобальные-переменные) - [Файл конфигурации](#файл-конфигурации) - [Фрагменты](#фрагменты) - [Структуры](#структуры) @@ -52,6 +53,14 @@ - **heights-bpd** - количество блоков на точку карты высот. По-умолчанию: 4. - **wide-structs-chunks-radius** - масимальный радиус размещения 'широких' структур, измеряемый в чанках. +## Глобальные переменные + +В скрипте генератора доступны следующие переменные: + +- `SEED` - зерно генерации мира +- `__DIR__` - директория генератора (`пак:generators/имя_генератора.files/`) +- `__FILE__` - файл скрипта (`пак:generators/имя_генератора.files/script.lua`) + ## Фрагменты Фрагмент является сохраненной для дальнейшего использования, областью мира, как и чанк, ограниченную некоторой шириной, высотой и длиной. Фрагмент может содержать данные не только о блоках, попадающих в область, но и о инвентарях блоков области, а так же сущностях. В отличие от чанка, размер фрагмента произволен. @@ -75,6 +84,7 @@ ``` На данный момент, имя структуры должно совпадать с именем использованного фрагмента. + ## Биомы Биом определяет то, из каких блоков и какими слоями генерируется ландшафт, а так же набор растений, структур. @@ -139,22 +149,22 @@ structures = [ -- x, y - позиция начала карты (в точках) -- w, h - ширина и высота карты (в точках) -- bpd - (blocks per dot) число блоков на точку (масштаб) -function generate_biome_parameters(x, y, w, h, seed, bpd) +function generate_biome_parameters(x, y, w, h, bpd) -- создание карт высот (Heightmap) для каждого параметра биомов -- ... return карты_через_запятую end -- пример -function generate_biome_parameters(x, y, w, h, seed, s) +function generate_biome_parameters(x, y, w, h, s) -- карта температур local tempmap = Heightmap(w, h) - tempmap.noiseSeed = seed + 5324 + tempmap.noiseSeed = SEED + 5324 tempmap:noise({x, y}, 0.04*s, 6) tempmap:pow(3) -- карта влажности local hummap = Heightmap(w, h) - hummap.noiseSeed = seed + 953 + hummap.noiseSeed = SEED + 953 hummap:noise({x, y}, 0.04*s, 6) hummap:pow(3) @@ -356,7 +366,6 @@ generation.save_fragment( function generate_heightmap( x, y, -- смещение карты высот w, h, -- размер карты высот, ожидаемый движком - seed, -- зерно мира bpd, -- число блоков на точку карты (blocks per dot) - масштаб [опционально] inputs -- массив входных карт параметров биомов -- (см. свойство heightmap-inputs генератора) @@ -367,11 +376,11 @@ function generate_heightmap( к нужному диапазону: ```lua -function generate_heightmap(x, y, w, h, seed, bpd) +function generate_heightmap(x, y, w, h, bpd) -- создаем карту высот с заданным размером local map = Heightmap(w, h) -- настраиваем зерно шума - map.noiseSeed = seed + map.noiseSeed = SEED -- шум с масштабом 1/10 на 4 октавы с амплитудой 0.5 map:noise({x, y}, 0.1*bpd, 4, 0.5) -- сдвигаем высоты к положительному диапазону @@ -415,7 +424,6 @@ end function place_structures( x, z, -- позиция начала области в блоках w, d, -- размер области в блоках - seed, -- зерно мира heights, -- карта высот чанка chunk_height, -- высота чанка ) --> массив размещений структур @@ -426,7 +434,7 @@ function place_structures( Пример: ```lua -function place_structures(x, z, w, d, seed, hmap, chunk_height) +function place_structures(x, z, w, d, hmap, chunk_height) local placements = {} local height = hmap:at(w/2, h/2) * chunk_height @@ -449,7 +457,6 @@ end function place_structures_wide( x, z, -- позиция начала области в блоках w, d, -- размер области в блоках - seed, -- зерно мира chunk_height, -- высота чанка ) --> массив размещений структур / тоннелей ``` diff --git a/res/content/base/generators/demo.files/script.lua b/res/content/base/generators/demo.files/script.lua index ffec458d..756da50e 100644 --- a/res/content/base/generators/demo.files/script.lua +++ b/res/content/base/generators/demo.files/script.lua @@ -2,13 +2,13 @@ local _, dir = parse_path(__DIR__) local ores = require "base:generation/ores" ores.load(dir) -function place_structures(x, z, w, d, seed, hmap, chunk_height) +function place_structures(x, z, w, d, hmap, chunk_height) local placements = {} - ores.place(placements, x, z, w, d, seed, hmap, chunk_height) + ores.place(placements, x, z, w, d, SEED, hmap, chunk_height) return placements end -function place_structures_wide(x, z, w, d, seed, chunk_height) +function place_structures_wide(x, z, w, d, chunk_height) local placements = {} if math.random() < 0.05 then -- generate caves local sx = x + math.random() * 10 - 5 @@ -43,22 +43,22 @@ function place_structures_wide(x, z, w, d, seed, chunk_height) return placements end -function generate_heightmap(x, y, w, h, seed, s, inputs) +function generate_heightmap(x, y, w, h, s, inputs) local umap = Heightmap(w, h) local vmap = Heightmap(w, h) - umap.noiseSeed = seed - vmap.noiseSeed = seed + umap.noiseSeed = SEED + vmap.noiseSeed = SEED vmap:noise({x+521, y+70}, 0.1*s, 3, 25.8) vmap:noise({x+95, y+246}, 0.15*s, 3, 25.8) local map = Heightmap(w, h) - map.noiseSeed = seed + map.noiseSeed = SEED map:noise({x, y}, 0.8*s, 4, 0.02) map:cellnoise({x, y}, 0.1*s, 3, 0.3, umap, vmap) map:add(0.7) local rivermap = Heightmap(w, h) - rivermap.noiseSeed = seed + rivermap.noiseSeed = SEED rivermap:noise({x+21, y+12}, 0.1*s, 4) rivermap:abs() rivermap:mul(2.0) @@ -67,21 +67,21 @@ function generate_heightmap(x, y, w, h, seed, s, inputs) map:mul(rivermap) local desertmap = Heightmap(w, h) - desertmap.noiseSeed = seed + desertmap.noiseSeed = SEED desertmap:cellnoise({x+52, y+326}, 0.3*s, 2, 0.2) desertmap:add(0.4) map:mixin(desertmap, inputs[1]) return map end -function generate_biome_parameters(x, y, w, h, seed, s) +function generate_biome_parameters(x, y, w, h, s) local tempmap = Heightmap(w, h) - tempmap.noiseSeed = seed + 5324 + tempmap.noiseSeed = SEED + 5324 tempmap:noise({x, y}, 0.04*s, 6) tempmap:mul(0.5) tempmap:add(0.5) local hummap = Heightmap(w, h) - hummap.noiseSeed = seed + 953 + hummap.noiseSeed = SEED + 953 hummap:noise({x, y}, 0.04*s, 6) tempmap:pow(3) hummap:pow(3) diff --git a/src/logic/scripting/scripting_world_generation.cpp b/src/logic/scripting/scripting_world_generation.cpp index caa08d6c..32479888 100644 --- a/src/logic/scripting/scripting_world_generation.cpp +++ b/src/logic/scripting/scripting_world_generation.cpp @@ -24,10 +24,13 @@ static debug::Logger logger("generator-scripting"); class LuaGeneratorScript : public GeneratorScript { State* L; const GeneratorDef& def; - scriptenv env; + scriptenv env = nullptr; + + fs::path file; + std::string dirPath; public: - LuaGeneratorScript(State* L, const GeneratorDef& def, scriptenv env) - : L(L), def(def), env(std::move(env)) { + LuaGeneratorScript(State* L, const GeneratorDef& def, const fs::path& file, const std::string& dirPath) + : L(L), def(def), file(file), dirPath(dirPath) { } virtual ~LuaGeneratorScript() { @@ -37,10 +40,33 @@ public: } } + void initialize(uint64_t seed) override { + env = create_environment(L); + stackguard _(L); + + pushenv(L, *env); + pushstring(L, dirPath); + setfield(L, "__DIR__"); + pushstring(L, dirPath + "/script.lua"); + setfield(L, "__FILE__"); + pushinteger(L, seed); + setfield(L, "SEED"); + + pop(L); + + if (fs::exists(file)) { + std::string src = files::read_string(file); + logger.info() << "script (generator) " << file.u8string(); + pop(L, execute(L, *env, src, file.u8string())); + } else { + // Use default (empty) script + pop(L, execute(L, *env, "", "")); + } + } + std::shared_ptr generateHeightmap( const glm::ivec2& offset, const glm::ivec2& size, - uint64_t seed, uint bpd, const std::vector>& inputs ) override { @@ -48,7 +74,6 @@ public: if (getfield(L, "generate_heightmap")) { pushivec_stack(L, offset); pushivec_stack(L, size); - pushinteger(L, seed); pushinteger(L, bpd); if (!inputs.empty()) { size_t inputsNum = def.heightmapInputs.size(); @@ -58,7 +83,7 @@ public: rawseti(L, i+1); } } - if (call_nothrow(L, 6 + (!inputs.empty()))) { + if (call_nothrow(L, 5 + (!inputs.empty()))) { auto map = touserdata(L, -1)->getHeightmap(); pop(L, 2); return map; @@ -69,7 +94,7 @@ public: } std::vector> generateParameterMaps( - const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed, uint bpd + const glm::ivec2& offset, const glm::ivec2& size, uint bpd ) override { std::vector> maps; @@ -78,9 +103,8 @@ public: if (getfield(L, "generate_biome_parameters")) { pushivec_stack(L, offset); pushivec_stack(L, size); - pushinteger(L, seed); pushinteger(L, bpd); - if (call_nothrow(L, 6, biomeParameters)) { + if (call_nothrow(L, 5, biomeParameters)) { for (int i = biomeParameters-1; i >= 0; i--) { maps.push_back( touserdata(L, -1-i)->getHeightmap()); @@ -166,7 +190,6 @@ public: std::vector placeStructuresWide( const glm::ivec2& offset, const glm::ivec2& size, - uint64_t seed, uint chunkHeight ) override { std::vector placements {}; @@ -176,9 +199,8 @@ public: if (getfield(L, "place_structures_wide")) { pushivec_stack(L, offset); pushivec_stack(L, size); - pushinteger(L, seed); pushinteger(L, chunkHeight); - if (call_nothrow(L, 6, 1)) { + if (call_nothrow(L, 5, 1)) { int len = objlen(L, -1); for (int i = 1; i <= len; i++) { rawgeti(L, i); @@ -194,8 +216,10 @@ public: } std::vector placeStructures( - const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed, - const std::shared_ptr& heightmap, uint chunkHeight + const glm::ivec2& offset, + const glm::ivec2& size, + const std::shared_ptr& heightmap, + uint chunkHeight ) override { std::vector placements {}; @@ -204,10 +228,9 @@ public: if (getfield(L, "place_structures")) { pushivec_stack(L, offset); pushivec_stack(L, size); - pushinteger(L, seed); newuserdata(L, heightmap); pushinteger(L, chunkHeight); - if (call_nothrow(L, 7, 1)) { + if (call_nothrow(L, 6, 1)) { int len = objlen(L, -1); for (int i = 1; i <= len; i++) { rawgeti(L, i); @@ -224,28 +247,11 @@ public: }; std::unique_ptr scripting::load_generator( - const GeneratorDef& def, const fs::path& file, const std::string& dirPath + const GeneratorDef& def, + const fs::path& file, + const std::string& dirPath ) { auto L = create_state(*engine->getPaths(), StateType::GENERATOR); - auto env = create_environment(L); - stackguard _(L); - pushenv(L, *env); - pushstring(L, dirPath); - setfield(L, "__DIR__"); - pushstring(L, dirPath + "/script.lua"); - setfield(L, "__FILE__"); - - pop(L); - - if (fs::exists(file)) { - std::string src = files::read_string(file); - logger.info() << "script (generator) " << file.u8string(); - pop(L, execute(L, *env, src, file.u8string())); - } else { - // Use default (empty) script - pop(L, execute(L, *env, "", "")); - } - - return std::make_unique(L, def, std::move(env)); + return std::make_unique(L, def, file, dirPath); } diff --git a/src/world/generator/GeneratorDef.hpp b/src/world/generator/GeneratorDef.hpp index 3a1e110b..b48d69de 100644 --- a/src/world/generator/GeneratorDef.hpp +++ b/src/world/generator/GeneratorDef.hpp @@ -123,17 +123,17 @@ class GeneratorScript { public: virtual ~GeneratorScript() = default; + virtual void initialize(uint64_t seed) = 0; + /// @brief Generate a heightmap with values in range 0..1 /// @param offset position of the heightmap in the world /// @param size size of the heightmap - /// @param seed world seed /// @param bpd blocks per dot /// @param inputs biome parameter maps passed to generate_heightmap /// @return generated heightmap (can't be nullptr) virtual std::shared_ptr generateHeightmap( const glm::ivec2& offset, const glm::ivec2& size, - uint64_t seed, uint bpd, const std::vector>& inputs ) = 0; @@ -141,13 +141,11 @@ public: /// @brief Generate a biomes parameters maps /// @param offset position of maps in the world /// @param size maps size - /// @param seed world seed /// @param bpd blocks per dot /// @return generated maps (can't be nullptr) virtual std::vector> generateParameterMaps( const glm::ivec2& offset, const glm::ivec2& size, - uint64_t seed, uint bpd ) = 0; @@ -156,12 +154,10 @@ public: /// wide-structs-chunks-radius /// @param offset position of the area /// @param size size of the area (blocks) - /// @param seed world seed /// @param chunkHeight chunk height to use as heights multiplier virtual std::vector placeStructuresWide( - const glm::ivec2& offset, - const glm::ivec2& size, - uint64_t seed, + const glm::ivec2& offset, + const glm::ivec2& size, uint chunkHeight ) = 0; @@ -169,13 +165,15 @@ public: /// placed to nearest chunks also (position of out area). /// @param offset position of the area /// @param size size of the area (blocks) - /// @param seed world seed /// @param heightmap area heightmap /// @param chunkHeight chunk height to use as heights multiplier /// @return structure & line placements virtual std::vector placeStructures( - const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed, - const std::shared_ptr& heightmap, uint chunkHeight) = 0; + const glm::ivec2& offset, + const glm::ivec2& size, + const std::shared_ptr& heightmap, + uint chunkHeight + ) = 0; }; /// @brief Structure voxel fragments and metadata diff --git a/src/world/generator/WorldGenerator.cpp b/src/world/generator/WorldGenerator.cpp index 7fb699f6..08b0b7f2 100644 --- a/src/world/generator/WorldGenerator.cpp +++ b/src/world/generator/WorldGenerator.cpp @@ -31,6 +31,8 @@ WorldGenerator::WorldGenerator( seed(seed), surroundMap(0, BASIC_PROTOTYPE_LAYERS + def.wideStructsChunksRadius * 2) { + def.script->initialize(seed); + uint levels = BASIC_PROTOTYPE_LAYERS + def.wideStructsChunksRadius * 2; surroundMap = SurroundMap(0, levels); @@ -228,7 +230,7 @@ void WorldGenerator::generateStructuresWide( return; } auto placements = def.script->placeStructuresWide( - {chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, seed, CHUNK_H + {chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, CHUNK_H ); placeStructures(placements, prototype, chunkX, chunkZ); @@ -245,7 +247,7 @@ void WorldGenerator::generateStructures( const auto& heightmap = prototype.heightmap; auto placements = def.script->placeStructures( - {chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, seed, + {chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, heightmap, CHUNK_H ); placeStructures(placements, prototype, chunkX, chunkZ); @@ -297,7 +299,6 @@ void WorldGenerator::generateBiomes( auto biomeParams = def.script->generateParameterMaps( {floordiv(chunkX * CHUNK_W, bpd), floordiv(chunkZ * CHUNK_D, bpd)}, {floordiv(CHUNK_W, bpd)+1, floordiv(CHUNK_D, bpd)+1}, - seed, bpd ); for (auto index : def.heightmapInputs) { @@ -339,7 +340,6 @@ void WorldGenerator::generateHeightmap( prototype.heightmap = def.script->generateHeightmap( {floordiv(chunkX * CHUNK_W, bpd), floordiv(chunkZ * CHUNK_D, bpd)}, {floordiv(CHUNK_W, bpd)+1, floordiv(CHUNK_D, bpd)+1}, - seed, bpd, prototype.heightmapInputs );