diff --git a/res/content/base/generators/demo.files/biomes.json b/res/content/base/generators/demo.files/biomes.json deleted file mode 100644 index 52bb9598..00000000 --- a/res/content/base/generators/demo.files/biomes.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "forest": { - "parameters": [ - {"weight": 1, "value": 1}, - {"weight": 0.5, "value": 0.2} - ], - "layers": [ - {"below_sea_level": false, "height": 1, "block": "base:grass_block"}, - {"below_sea_level": false, "height": 7, "block": "base:dirt"}, - {"height": -1, "block": "base:stone"}, - {"height": 1, "block": "base:bazalt"} - ], - "sea_layers": [ - {"height": -1, "block": "base:water"} - ], - "plant_chance": 0.4, - "plants": [ - {"weight": 1, "block": "base:grass"}, - {"weight": 0.03, "block": "base:flower"} - ], - "structure_chance": 0.032, - "structures": [ - {"name": "tree0", "weight": 1}, - {"name": "tree1", "weight": 1}, - {"name": "tree2", "weight": 1}, - {"name": "tower", "weight": 0.002} - ] - }, - "desert": { - "parameters": [ - {"weight": 0.3, "value": 0}, - {"weight": 0.1, "value": 0} - ], - "layers": [ - {"height": 6, "block": "base:sand"}, - {"height": -1, "block": "base:stone"}, - {"height": 1, "block": "base:bazalt"} - ], - "sea_layers": [ - {"height": -1, "block": "base:water"} - ] - }, - "plains": { - "parameters": [ - {"weight": 0.6, "value": 0.5}, - {"weight": 0.6, "value": 0.5} - ], - "layers": [ - {"below_sea_level": false, "height": 1, "block": "base:grass_block"}, - {"below_sea_level": false, "height": 5, "block": "base:dirt"}, - {"height": -1, "block": "base:stone"}, - {"height": 1, "block": "base:bazalt"} - ], - "sea_layers": [ - {"height": -1, "block": "base:water"} - ], - "plant_chance": 0.3, - "plants": [ - {"weight": 1, "block": "base:grass"}, - {"weight": 0.03, "block": "base:flower"} - ], - "structure_chance": 0.0001, - "structures": [ - {"name": "tree0", "weight": 1}, - {"name": "tree1", "weight": 1} - ] - } -} diff --git a/res/content/base/generators/demo.files/biomes.toml b/res/content/base/generators/demo.files/biomes.toml new file mode 100644 index 00000000..d782d991 --- /dev/null +++ b/res/content/base/generators/demo.files/biomes.toml @@ -0,0 +1,67 @@ +[forest] +parameters = [ + {weight=1, value=1}, + {weight=0.5, value=0.2} +] +layers = [ + {below_sea_level=false, height=1, block="base:grass_block"}, + {below_sea_level=false, height=7, block="base:dirt"}, + {height=-1, block="base:stone"}, + {height=1, block="base:bazalt"} +] +sea_layers = [ + {height=-1, block="base:water"} +] +plant_chance = 0.4 +plants = [ + {weight=1, block="base:grass"}, + {weight=0.03, block="base:flower"} +] +structure_chance = 0.032 +structures = [ + {name="tree0", weight=1}, + {name="tree1", weight=1}, + {name="tree2", weight=1}, + {name="tower", weight=0.002} +] + + +[desert] +parameters = [ + {weight=0.3, value=0}, + {weight=0.1, value=0} +] +layers = [ + {height=6, block="base:sand"}, + {height=-1, block="base:stone"}, + {height=1, block="base:bazalt"} +] +sea_layers = [ + {height=-1, block="base:water"} +] + + +[plains] +parameters = [ + {weight=0.6, value=0.5}, + {weight=0.6, value=0.5} +] +layers = [ + {below_sea_level=false, height=1, block="base:grass_block"}, + {below_sea_level=false, height=5, block="base:dirt"}, + {height=-1, block="base:stone"}, + {height=1, block="base:bazalt"} +] +sea_layers = [ + {height=-1, block="base:water"} +] +plant_chance = 0.3 +plants = [ + {weight=1, block="base:grass"}, + {weight=0.03, block="base:flower"} +] +structure_chance=0.0001 +structures = [ + {name="tree0", weight=1}, + {name="tree1", weight=1} +] diff --git a/res/generators/default.files/biomes.json b/res/generators/default.files/biomes.json deleted file mode 100644 index baf0bf9b..00000000 --- a/res/generators/default.files/biomes.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "flat": { - "parameters": [], - "layers": [ - {"height": -1, "block": "core:obstacle"} - ], - "sea_layers": [ - {"height": -1, "block": "core:obstacle"} - ] - } -} diff --git a/res/generators/default.files/biomes.toml b/res/generators/default.files/biomes.toml new file mode 100644 index 00000000..94d6e7cd --- /dev/null +++ b/res/generators/default.files/biomes.toml @@ -0,0 +1,8 @@ +[flat] +parameters = [] +layers = [ + {height=-1, block="core:obstacle"} +] +sea_layers = [ + {height=-1, block="core:obstacle"} +] diff --git a/src/coders/json.cpp b/src/coders/json.cpp index 9c189998..05db4e13 100644 --- a/src/coders/json.cpp +++ b/src/coders/json.cpp @@ -242,7 +242,7 @@ dv::value Parser::parseValue() { } else if (literal == "nan") { return NAN; } - throw error("invalid literal "); + throw error("invalid keyword " + literal); } if (next == '{') { return parseObject(); diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index 151ed19f..bc03b810 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -28,8 +28,10 @@ using namespace data; static debug::Logger logger("content-loader"); -ContentLoader::ContentLoader(ContentPack* pack, ContentBuilder& builder) - : pack(pack), builder(builder) { +ContentLoader::ContentLoader( + ContentPack* pack, ContentBuilder& builder, const ResPaths& paths +) + : pack(pack), builder(builder), paths(paths) { auto runtime = std::make_unique( *pack, scripting::create_pack_environment(*pack) ); diff --git a/src/content/ContentLoader.hpp b/src/content/ContentLoader.hpp index 762b3fbe..efd54efd 100644 --- a/src/content/ContentLoader.hpp +++ b/src/content/ContentLoader.hpp @@ -16,6 +16,7 @@ struct EntityDef; struct ContentPack; struct GeneratorDef; +class ResPaths; class ContentBuilder; class ContentPackRuntime; struct ContentPackStats; @@ -26,6 +27,7 @@ class ContentLoader { scriptenv env; ContentBuilder& builder; ContentPackStats* stats; + const ResPaths& paths; void loadBlock( Block& def, const std::string& full, const std::string& name @@ -55,7 +57,11 @@ class ContentLoader { void loadContent(const dv::value& map); public: - ContentLoader(ContentPack* pack, ContentBuilder& builder); + ContentLoader( + ContentPack* pack, + ContentBuilder& builder, + const ResPaths& paths + ); // Refresh pack content.json static bool fixPackIndices( diff --git a/src/content/loading/GeneratorLoader.cpp b/src/content/loading/GeneratorLoader.cpp index eef4fb1c..72cd330c 100644 --- a/src/content/loading/GeneratorLoader.cpp +++ b/src/content/loading/GeneratorLoader.cpp @@ -3,10 +3,12 @@ #include "../ContentPack.hpp" #include "files/files.hpp" +#include "files/engine_paths.hpp" #include "logic/scripting/scripting.hpp" #include "world/generator/GeneratorDef.hpp" #include "world/generator/VoxelFragment.hpp" #include "debug/Logger.hpp" +#include "util/stringutil.hpp" static BlocksLayer load_layer( const dv::value& map, uint& lastLayersHeight, bool& hasResizeableLayer @@ -167,11 +169,10 @@ static void load_structures(GeneratorDef& def, const fs::path& structuresFile) { } static inline const auto STRUCTURES_FILE = fs::u8path("structures.json"); -static inline const auto BIOMES_FILE = fs::u8path("biomes.json"); +static inline const auto BIOMES_FILE = fs::u8path("biomes.toml"); static inline const auto GENERATORS_DIR = fs::u8path("generators"); -static void load_biomes(GeneratorDef& def, const fs::path& file) { - auto root = files::read_json(file); +static void load_biomes(GeneratorDef& def, const dv::value& root) { for (const auto& [biomeName, biomeMap] : root.asObject()) { try { def.biomes.push_back( @@ -205,14 +206,16 @@ void ContentLoader::loadGenerator( if (fs::exists(structuresFile)) { load_structures(def, structuresFile); } - auto biomesFiles = folder / BIOMES_FILE; - if (!fs::exists(biomesFiles)) { + + auto biomesFile = GENERATORS_DIR / fs::u8path(name + ".files") / BIOMES_FILE; + auto biomesMap = paths.readCombinedObject(biomesFile.u8string()); + if (biomesMap.empty()) { throw std::runtime_error( - BIOMES_FILE.u8string() + - ": file not found (at least one biome required)" + "generator " + util::quote(def.name) + + ": at least one biome required" ); } - load_biomes(def, biomesFiles); + load_biomes(def, biomesMap); def.script = scripting::load_generator( def, scriptFile, pack->id+":generators/"+name+".files"); } diff --git a/src/engine.cpp b/src/engine.cpp index a7b94bbb..b32128f7 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -322,11 +322,11 @@ void Engine::loadContent() { // Load content { - ContentLoader(&corePack, contentBuilder).load(); + ContentLoader(&corePack, contentBuilder, *resPaths).load(); load_configs(corePack.folder); } for (auto& pack : contentPacks) { - ContentLoader(&pack, contentBuilder).load(); + ContentLoader(&pack, contentBuilder, *resPaths).load(); load_configs(pack.folder); } diff --git a/src/files/engine_paths.cpp b/src/files/engine_paths.cpp index c826457f..6bc42cc1 100644 --- a/src/files/engine_paths.cpp +++ b/src/files/engine_paths.cpp @@ -255,7 +255,7 @@ std::vector ResPaths::listdir( return entries; } -dv::value ResPaths::readCombinedList(const std::string& filename) { +dv::value ResPaths::readCombinedList(const std::string& filename) const { dv::value list = dv::list(); for (const auto& root : roots) { auto path = root.path / fs::u8path(filename); @@ -280,6 +280,31 @@ dv::value ResPaths::readCombinedList(const std::string& filename) { return list; } +dv::value ResPaths::readCombinedObject(const std::string& filename) const { + dv::value object = dv::object(); + for (const auto& root : roots) { + auto path = root.path / fs::u8path(filename); + if (!fs::exists(path)) { + continue; + } + try { + auto value = files::read_object(path); + if (!value.isObject()) { + logger.warning() + << "reading combined object " << root.name << ": " + << filename << " is not an object (skipped)"; + } + for (const auto& [key, element] : value.asObject()) { + object[key] = element; + } + } catch (const std::runtime_error& err) { + logger.warning() << "reading combined object " << root.name << ":" + << filename << ": " << err.what(); + } + } + return object; +} + const std::filesystem::path& ResPaths::getMainRoot() const { return mainRoot; } diff --git a/src/files/engine_paths.hpp b/src/files/engine_paths.hpp index ec0c38d5..3abcb4ea 100644 --- a/src/files/engine_paths.hpp +++ b/src/files/engine_paths.hpp @@ -68,7 +68,9 @@ public: /// @brief Read all found list versions from all packs and combine into a /// single list. Invalid versions will be skipped with logging a warning /// @param file *.json file path relative to entry point - dv::value readCombinedList(const std::string& file); + dv::value readCombinedList(const std::string& file) const; + + dv::value readCombinedObject(const std::string& file) const; const std::filesystem::path& getMainRoot() const; diff --git a/src/world/generator/WorldGenerator.cpp b/src/world/generator/WorldGenerator.cpp index db3d157d..14c0c5aa 100644 --- a/src/world/generator/WorldGenerator.cpp +++ b/src/world/generator/WorldGenerator.cpp @@ -251,6 +251,7 @@ void WorldGenerator::generateStructures( util::PseudoRandom structsRand; structsRand.setSeed(chunkX, chunkZ); + // Place structures defined in biome auto heights = heightmap->getValues(); for (uint z = 0; z < CHUNK_D; z++) { for (uint x = 0; x < CHUNK_W; x++) {