diff --git a/res/content/base/generators/demo.toml b/res/content/base/generators/demo.toml new file mode 100644 index 00000000..a5cad573 --- /dev/null +++ b/res/content/base/generators/demo.toml @@ -0,0 +1,4 @@ +# 1 - temperature +# 2 - humidity +biome_parameters = 2 +sea_level = 64 diff --git a/res/content/base/generators/demo.lua b/res/content/base/generators/demo/script.lua similarity index 97% rename from res/content/base/generators/demo.lua rename to res/content/base/generators/demo/script.lua index a8e0a365..7744882f 100644 --- a/res/content/base/generators/demo.lua +++ b/res/content/base/generators/demo/script.lua @@ -1,9 +1,3 @@ -sea_level = 64 - --- 1 - temperature --- 2 - humidity -biome_parameters = 2 - biomes = json.parse(file.read("base:generators/demo/biomes.json")) function place_structures(x, z, w, d, seed, hmap) diff --git a/res/generators/default.toml b/res/generators/default.toml new file mode 100644 index 00000000..b5e19313 --- /dev/null +++ b/res/generators/default.toml @@ -0,0 +1 @@ +biome_parameters = 0 diff --git a/res/generators/default.lua b/res/generators/default/script.lua similarity index 63% rename from res/generators/default.lua rename to res/generators/default/script.lua index c88a6135..e949a610 100644 --- a/res/generators/default.lua +++ b/res/generators/default/script.lua @@ -1,5 +1,3 @@ -biome_parameters = 0 - biomes = {flat = { parameters = {}, layers = { @@ -9,7 +7,3 @@ biomes = {flat = { {height=-1, block="core:obstacle"} } }} - -function generate_heightmap(x, y, w, h, seed) - return Heightmap(w, h) -end diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index 907e8388..7cdb3a96 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -49,7 +49,7 @@ static void detect_defs( if (name[0] == '_') { continue; } - if (fs::is_regular_file(file) && file.extension() == ".json") { + if (fs::is_regular_file(file) && files::is_data_file(file)) { detected.push_back(prefix.empty() ? name : prefix + ":" + name); } else if (fs::is_directory(file)) { detect_defs(file, name, detected); diff --git a/src/content/loading/GeneratorLoader.cpp b/src/content/loading/GeneratorLoader.cpp index fd6fdf38..5342c081 100644 --- a/src/content/loading/GeneratorLoader.cpp +++ b/src/content/loading/GeneratorLoader.cpp @@ -66,14 +66,20 @@ void ContentLoader::loadGenerator( ) { auto packDir = pack->folder; auto generatorsDir = packDir / GENERATORS_DIR; - auto folder = generatorsDir / fs::u8path(name); - auto generatorFile = generatorsDir / fs::u8path(name + ".lua"); + auto generatorFile = generatorsDir / fs::u8path(name + ".toml"); if (!fs::exists(generatorFile)) { return; } + auto map = files::read_toml(generatorsDir / fs::u8path(name + ".toml")); + map.at("biome_parameters").get(def.biomeParameters); + map.at("sea_level").get(def.seaLevel); + + auto folder = generatorsDir / fs::u8path(name); + auto scriptFile = folder / fs::u8path("script.lua"); + auto structuresFile = folder / STRUCTURES_FILE; if (fs::exists(structuresFile)) { load_structures(def, structuresFile); } - def.script = scripting::load_generator(generatorFile); + def.script = scripting::load_generator(def, scriptFile); } diff --git a/src/files/files.cpp b/src/files/files.cpp index c1f74c63..31eff94e 100644 --- a/src/files/files.cpp +++ b/src/files/files.cpp @@ -159,3 +159,36 @@ std::vector files::read_list(const fs::path& filename) { } return lines; } + +#include + +#include "coders/json.hpp" +#include "coders/toml.hpp" + +using DecodeFunc = dv::value(*)(std::string_view, std::string_view); + +static std::map data_decoders { + {fs::u8path(".json"), json::parse}, + {fs::u8path(".toml"), toml::parse}, +}; + +bool files::is_data_file(const fs::path& file) { + return is_data_interchange_format(file.extension()); +} + +bool files::is_data_interchange_format(const fs::path& ext) { + return data_decoders.find(ext) != data_decoders.end(); +} + +dv::value files::read_object(const fs::path& file) { + const auto& found = data_decoders.find(file.extension()); + if (found == data_decoders.end()) { + throw std::runtime_error("unknown file format"); + } + auto text = read_string(file); + try { + return found->second(file.u8string(), text); + } catch (const parsing_error& err) { + throw std::runtime_error(err.errorLog()); + } +} diff --git a/src/files/files.hpp b/src/files/files.hpp index d6827dae..3c602b66 100644 --- a/src/files/files.hpp +++ b/src/files/files.hpp @@ -66,4 +66,8 @@ namespace files { dv::value read_binary_json(const fs::path& file); dv::value read_toml(const fs::path& file); std::vector read_list(const fs::path& file); + + bool is_data_file(const fs::path& file); + bool is_data_interchange_format(const fs::path& ext); + dv::value read_object(const fs::path& file); } diff --git a/src/logic/scripting/scripting.hpp b/src/logic/scripting/scripting.hpp index 3f4ada53..aad1bd9e 100644 --- a/src/logic/scripting/scripting.hpp +++ b/src/logic/scripting/scripting.hpp @@ -33,6 +33,7 @@ class LevelController; class Entity; struct EntityDef; class GeneratorScript; +struct GeneratorDef; namespace scripting { extern Engine* engine; @@ -147,6 +148,7 @@ namespace scripting { void load_entity_component(const std::string& name, const fs::path& file); std::unique_ptr load_generator( + const GeneratorDef& def, const fs::path& file ); diff --git a/src/logic/scripting/scripting_world_generation.cpp b/src/logic/scripting/scripting_world_generation.cpp index da6e63a4..fe0bd8de 100644 --- a/src/logic/scripting/scripting_world_generation.cpp +++ b/src/logic/scripting/scripting_world_generation.cpp @@ -16,20 +16,17 @@ #include "util/timeutil.hpp" class LuaGeneratorScript : public GeneratorScript { + const GeneratorDef& def; scriptenv env; std::vector biomes; - uint biomeParameters; - uint seaLevel; public: LuaGeneratorScript( - scriptenv env, - std::vector biomes, - uint biomeParameters, - uint seaLevel) - : env(std::move(env)), - biomes(std::move(biomes)), - biomeParameters(biomeParameters), - seaLevel(seaLevel) + const GeneratorDef& def, + scriptenv env, + std::vector biomes) + : def(def), + env(std::move(env)), + biomes(std::move(biomes)) {} std::shared_ptr generateHeightmap( @@ -56,6 +53,7 @@ public: ) override { std::vector> maps; + uint biomeParameters = def.biomeParameters; auto L = lua::get_main_thread(); lua::pushenv(L, *env); if (lua::getfield(L, "generate_biome_parameters")) { @@ -79,7 +77,6 @@ public: } std::vector placeStructures( - const GeneratorDef& def, const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed, const std::shared_ptr& heightmap ) override { @@ -153,14 +150,6 @@ public: const std::vector& getBiomes() const override { return biomes; } - - uint getBiomeParameters() const override { - return biomeParameters; - } - - uint getSeaLevel() const override { - return seaLevel; - } }; static BlocksLayer load_layer( @@ -273,7 +262,7 @@ static inline Biome load_biome( } std::unique_ptr scripting::load_generator( - const fs::path& file + const GeneratorDef& def, const fs::path& file ) { auto env = create_environment(); auto L = lua::get_main_thread(); @@ -285,24 +274,20 @@ std::unique_ptr scripting::load_generator( auto root = lua::tovalue(L, -1); lua::pop(L); - uint biomeParameters = root["biome_parameters"].asInteger(); - uint seaLevel = 0; - root.at("sea_level").get(seaLevel); - std::vector biomes; const auto& biomesMap = root["biomes"]; for (const auto& [biomeName, biomeMap] : biomesMap.asObject()) { try { biomes.push_back( - load_biome(biomeMap, biomeName, biomeParameters, -2)); + load_biome(biomeMap, biomeName, def.biomeParameters, -2)); } catch (const std::runtime_error& err) { throw std::runtime_error("biome "+biomeName+": "+err.what()); } } return std::make_unique( + def, std::move(env), - std::move(biomes), - biomeParameters, - seaLevel); + std::move(biomes) + ); } diff --git a/src/world/generator/GeneratorDef.hpp b/src/world/generator/GeneratorDef.hpp index bf6934b0..8311e15f 100644 --- a/src/world/generator/GeneratorDef.hpp +++ b/src/world/generator/GeneratorDef.hpp @@ -135,19 +135,12 @@ public: const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed) = 0; virtual std::vector placeStructures( - const GeneratorDef& def, const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed, const std::shared_ptr& heightmap) = 0; /// @brief Get generator biomes virtual const std::vector& getBiomes() const = 0; - /// @return Number of biome parameters, that biome choosing depending on - virtual uint getBiomeParameters() const = 0; - - /// @return Sea level (top of seaLayers) - virtual uint getSeaLevel() const = 0; - /// @brief Build the runtime cache /// @param content built content virtual void prepare(const GeneratorDef& def, const Content* content) = 0; @@ -169,6 +162,12 @@ struct GeneratorDef { std::string name; std::unique_ptr script; + /// @brief Sea level (top of seaLayers) + uint seaLevel = 0; + + /// @brief Number of biome parameters, that biome choosing depending on + uint biomeParameters = 0; + std::unordered_map structuresIndices; std::vector> structures; diff --git a/src/world/generator/WorldGenerator.cpp b/src/world/generator/WorldGenerator.cpp index 596a66fc..e1c32c65 100644 --- a/src/world/generator/WorldGenerator.cpp +++ b/src/world/generator/WorldGenerator.cpp @@ -175,7 +175,7 @@ void WorldGenerator::generateStructures( const auto& heightmap = prototype.heightmap; util::concat(prototype.structures, def.script->placeStructures( - def, {chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, seed, + {chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, seed, heightmap )); for (const auto& placement : prototype.structures) { @@ -202,7 +202,7 @@ void WorldGenerator::generateStructures( } uint8_t rotation = structsRand.randU32() % 4; int height = heights[z * CHUNK_W + x] * CHUNK_H; - if (height < def.script->getSeaLevel()) { + if (height < def.seaLevel) { continue; } auto& structure = *def.structures[structureId]->fragments[rotation]; @@ -268,7 +268,7 @@ void WorldGenerator::generate(voxel* voxels, int chunkX, int chunkZ) { const auto& prototype = requirePrototype(chunkX, chunkZ); const auto values = prototype.heightmap->getValues(); - uint seaLevel = def.script->getSeaLevel(); + uint seaLevel = def.seaLevel; std::memset(voxels, 0, sizeof(voxel) * CHUNK_VOL);