From 84d5b5d1a8e015a5e9b6b10a846336dfd4633438 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 20 Feb 2025 22:08:09 +0300 Subject: [PATCH] add dv::merge & update EnginePaths::readCombinedObject --- src/content/loading/GeneratorLoader.cpp | 2 +- src/data/dv.cpp | 46 +++++++++++++++++++++++++ src/data/dv.hpp | 2 ++ src/io/engine_paths.cpp | 6 ++-- src/io/engine_paths.hpp | 2 +- 5 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/content/loading/GeneratorLoader.cpp b/src/content/loading/GeneratorLoader.cpp index b14b0b2f..99ffde50 100644 --- a/src/content/loading/GeneratorLoader.cpp +++ b/src/content/loading/GeneratorLoader.cpp @@ -241,7 +241,7 @@ void ContentLoader::loadGenerator( load_structures(def, structuresMap, structuresFile.parent(), paths); auto biomesFile = GENERATORS_DIR / (name + ".files") / BIOMES_FILE; - auto biomesMap = paths.readCombinedObject(biomesFile.string()); + auto biomesMap = paths.readCombinedObject(biomesFile.string(), true); if (biomesMap.empty()) { throw std::runtime_error( "generator " + util::quote(def.name) + diff --git a/src/data/dv.cpp b/src/data/dv.cpp index cccf348e..ee5c16fa 100644 --- a/src/data/dv.cpp +++ b/src/data/dv.cpp @@ -14,6 +14,52 @@ namespace dv { return (*val.object)[key]; } + static void apply_method(value& dst, value&& val, std::string_view method, bool deep) { + if (!val.isList()) { + return; + } + if (dst == nullptr) { + dst = dv::list(); + } else if (!dst.isList()) { + return; + } + if (method == "append") { + if (dst == nullptr) { + dst = std::forward(val); + return; + } + for (auto& elem : val) { + dst.add(std::move(elem)); + } + } + } + + static void merge_elem(value& self, const key_t& key, value&& val, bool deep) { + auto& dst = self[key]; + size_t pos = key.rfind('@'); + if (pos != std::string::npos) { + auto method = std::string_view(key).substr(pos + 1); + auto& field = self[key.substr(0, pos)]; + apply_method(field, std::forward(val), method, deep); + return; + } + if (val.isObject() && dst == nullptr) { + dst = dv::object(); + } + if (dst.isObject() && deep) { + dst.merge(std::forward(val), true); + } else { + dst = std::forward(val); + } + } + + void value::merge(dv::value&& other, bool deep) { + check_type(other.type, value_type::object); + for (auto& [key, val] : *other.val.object) { + merge_elem(*this, key, std::forward(val), deep); + } + } + value& value::operator=(const objects::Bytes& bytes) { return setBytes(std::make_shared(bytes)); } diff --git a/src/data/dv.hpp b/src/data/dv.hpp index 447d6fe9..3c3f4a71 100644 --- a/src/data/dv.hpp +++ b/src/data/dv.hpp @@ -374,6 +374,8 @@ namespace dv { const value& operator[](const key_t& key) const; + void merge(dv::value&& other, bool deep); + value& operator[](size_t index); const value& operator[](size_t index) const; diff --git a/src/io/engine_paths.cpp b/src/io/engine_paths.cpp index 76485031..d8c7e91e 100644 --- a/src/io/engine_paths.cpp +++ b/src/io/engine_paths.cpp @@ -253,7 +253,7 @@ dv::value ResPaths::readCombinedList(const std::string& filename) const { return list; } -dv::value ResPaths::readCombinedObject(const std::string& filename) const { +dv::value ResPaths::readCombinedObject(const std::string& filename, bool deep) const { dv::value object = dv::object(); for (const auto& root : roots) { auto path = root.path / filename; @@ -267,9 +267,7 @@ dv::value ResPaths::readCombinedObject(const std::string& filename) const { << "reading combined object " << root.name << ": " << filename << " is not an object (skipped)"; } - for (const auto& [key, element] : value.asObject()) { - object[key] = element; - } + object.merge(std::move(value), deep); } catch (const std::runtime_error& err) { logger.warning() << "reading combined object " << root.name << ":" << filename << ": " << err.what(); diff --git a/src/io/engine_paths.hpp b/src/io/engine_paths.hpp index 6bf62010..f06c6aa6 100644 --- a/src/io/engine_paths.hpp +++ b/src/io/engine_paths.hpp @@ -68,7 +68,7 @@ public: /// @param file *.json file path relative to entry point dv::value readCombinedList(const std::string& file) const; - dv::value readCombinedObject(const std::string& file) const; + dv::value readCombinedObject(const std::string& file, bool deep=false) const; const io::path& getMainRoot() const;