diff --git a/src/content/PacksManager.cpp b/src/content/PacksManager.cpp index a72451f5..2a83d612 100644 --- a/src/content/PacksManager.cpp +++ b/src/content/PacksManager.cpp @@ -24,6 +24,10 @@ void PacksManager::scan() { } } +void PacksManager::exclude(const std::string& id) { + packs.erase(id); +} + std::vector PacksManager::getAllNames() const { std::vector names; for (auto& entry : packs) { @@ -82,7 +86,7 @@ static bool resolve_dependencies ( auto found = packs.find(dep.id); bool exists = found != packs.end(); if (!exists && dep.level == DependencyLevel::required) { - throw contentpack_error(pack->id, pack->folder, "missing dependency '"+dep.id+"'"); + throw contentpack_error(dep.id, fs::path(), "dependency of '"+pack->id+"'"); } if (!exists) { // ignored for optional or weak dependencies @@ -144,3 +148,11 @@ std::vector PacksManager::assembly(const std::vector& } return added; } + +std::vector PacksManager::getNames(const std::vector& packs) { + std::vector result; + for (const auto& pack : packs) { + result.push_back(pack.id); + } + return result; +} diff --git a/src/content/PacksManager.h b/src/content/PacksManager.h index 575feb20..24c6d239 100644 --- a/src/content/PacksManager.h +++ b/src/content/PacksManager.h @@ -22,6 +22,9 @@ public: /// Scanning order depends on sources order void scan(); + /// @brief Remove pack from manager to make it invisible for assembly(...) + void exclude(const std::string& id); + /// @brief Get all found packs std::vector getAllNames() const; @@ -36,6 +39,9 @@ public: /// @throws contentpack_error if required dependency not found or /// circular dependency detected std::vector assembly(const std::vector& names) const; + + /// @brief Collect all pack names (identifiers) into a new vector + static std::vector getNames(const std::vector& packs); }; #endif // CONTENT_PACKS_MANAGER_H_ diff --git a/src/files/WorldFiles.cpp b/src/files/WorldFiles.cpp index 2db9b695..0c68e8b9 100644 --- a/src/files/WorldFiles.cpp +++ b/src/files/WorldFiles.cpp @@ -21,6 +21,7 @@ #include "../items/Inventory.h" #include "../data/dynamic.h" +#include "../core_defs.h" #include #include @@ -496,7 +497,9 @@ void WorldFiles::write(const World* world, const Content* content) { if (world) { writeWorldInfo(world); - writePacks(world); + if (!fs::exists(getPacksFile())) { + writePacks(world->getPacks()); + } } if (generatorTestMode) { return; @@ -508,13 +511,8 @@ void WorldFiles::write(const World* world, const Content* content) { writeRegions(storages, inventoriesFolder, REGION_LAYER_INVENTORIES); } -void WorldFiles::writePacks(const World* world) { +void WorldFiles::writePacks(const std::vector& packs) { auto packsFile = getPacksFile(); - if (fs::is_regular_file(packsFile)) { - return; - } - - const auto& packs = world->getPacks(); std::stringstream ss; ss << "# autogenerated; do not modify\n"; for (const auto& pack : packs) { @@ -559,56 +557,15 @@ bool WorldFiles::readWorldInfo(World* world) { return true; } -void WorldFiles::addPack(const World* world, const std::string& id) { - fs::path file = getPacksFile(); - if (!fs::is_regular_file(file)) { - if (!fs::is_directory(directory)) { - fs::create_directories(directory); - } - writePacks(world); - } - auto packs = files::read_list(file); - packs.push_back(id); - - std::stringstream ss; - ss << "# autogenerated; do not modify\n"; - for (const auto& pack : packs) { - ss << pack << "\n"; - } - files::write_string(file, ss.str()); -} - -void WorldFiles::removePack(const World* world, const std::string& id) { - fs::path file = getPacksFile(); - if (!fs::is_regular_file(file)) { - if (!fs::is_directory(directory)) { - fs::create_directories(directory); - } - writePacks(world); - } - auto packs = files::read_list(file); - auto found = std::find(packs.begin(), packs.end(), id); - if (found != packs.end()) { - packs.erase(found); - } - - std::stringstream ss; - ss << "# autogenerated; do not modify\n"; - for (const auto& pack : packs) { - ss << pack << "\n"; - } - files::write_string(file, ss.str()); - - // erase invalid indices +static void erase_pack_indices(dynamic::Map* root, const std::string& id) { auto prefix = id+":"; - auto root = files::read_json(getIndicesFile()); auto blocks = root->list("blocks"); for (uint i = 0; i < blocks->size(); i++) { auto name = blocks->str(i); if (name.find(prefix) != 0) continue; auto value = blocks->getValueWriteable(i); - value->value = "core:air"; + value->value = CORE_AIR; } auto items = root->list("items"); @@ -617,7 +574,14 @@ void WorldFiles::removePack(const World* world, const std::string& id) { if (name.find(prefix) != 0) continue; auto value = items->getValueWriteable(i); - value->value = "core:empty"; + value->value = CORE_EMPTY; + } +} + +void WorldFiles::removeIndices(const std::vector& packs) { + auto root = files::read_json(getIndicesFile()); + for (const auto& id : packs) { + erase_pack_indices(root.get(), id); } files::write_json(getIndicesFile(), root.get()); } diff --git a/src/files/WorldFiles.h b/src/files/WorldFiles.h index 1f66852d..b2ab9fb9 100644 --- a/src/files/WorldFiles.h +++ b/src/files/WorldFiles.h @@ -1,7 +1,14 @@ #ifndef FILES_WORLDFILES_H_ #define FILES_WORLDFILES_H_ +#include "files.h" +#include "../typedefs.h" +#include "../settings.h" +#include "../content/ContentPack.h" +#include "../voxels/Chunk.h" + #include +#include #include #include #include @@ -11,12 +18,6 @@ #define GLM_ENABLE_EXPERIMENTAL #include "glm/gtx/hash.hpp" -#include "files.h" -#include "../typedefs.h" -#include "../settings.h" - -#include "../voxels/Chunk.h" - inline constexpr uint REGION_HEADER_SIZE = 10; inline constexpr uint REGION_LAYER_VOXELS = 0; @@ -146,19 +147,10 @@ public: /// @param content world content void write(const World* world, const Content* content); - void writePacks(const World* world); + void writePacks(const std::vector& packs); void writeIndices(const ContentIndices* indices); - /// @brief Append pack to the packs list without duplicate check and - /// dependencies resolve - /// @param world target world - /// @param id pack id - void addPack(const World* world, const std::string& id); - - /// @brief Remove pack from the list (does not remove indices) - /// @param world target world - /// @param id pack id - void removePack(const World* world, const std::string& id); + void removeIndices(const std::vector& packs); static const inline std::string WORLD_FILE = "world.json"; }; diff --git a/src/frontend/menu/menu_pause.cpp b/src/frontend/menu/menu_pause.cpp index 93a2f95b..f31fec0c 100644 --- a/src/frontend/menu/menu_pause.cpp +++ b/src/frontend/menu/menu_pause.cpp @@ -118,27 +118,6 @@ static void reopen_world(Engine* engine, World* world) { menus::open_world(wname, engine, true); } -// FIXME: dependency levels -static bool try_add_dependency(Engine* engine, World* world, const ContentPack& pack, std::string& missing) { - auto paths = engine->getPaths(); - for (const auto& dependency : pack.dependencies) { - fs::path folder = ContentPack::findPack( - paths, - world->wfile->directory, - dependency.id - ); - if (!fs::is_directory(folder)) { - missing = dependency.id; - return true; - } - if (!world->hasPack(dependency.id)) { - world->wfile->addPack(world, dependency.id); - } - } - world->wfile->addPack(world, pack.id); - return false; -} - void menus::remove_packs( Engine* engine, LevelController* controller, @@ -161,9 +140,16 @@ void menus::remove_packs( runnable removeFunc = [=]() { controller->saveWorld(); + auto manager = engine->createPacksManager(world->wfile->directory);; + manager.scan(); + + auto names = PacksManager::getNames(world->getPacks()); for (const auto& id : packsToRemove) { - world->wfile->removePack(world, id); + manager.exclude(id); + names.erase(std::find(names.begin(), names.end(), id)); } + world->wfile->removeIndices(packsToRemove); + world->wfile->writePacks(manager.getAll(names)); reopen_world(engine, world); }; @@ -210,15 +196,21 @@ void create_content_panel(Engine* engine, LevelController* controller) { auto panel = menus::create_packs_panel(scanned, engine, true, [=](const ContentPack& pack) { auto world = level->getWorld(); - std::string missing; - if (try_add_dependency(engine, world, pack, missing)) { + auto new_packs = PacksManager::getNames(world->getPacks()); + new_packs.push_back(pack.id); + + auto manager = engine->createPacksManager(world->wfile->directory); + manager.scan(); + try { + new_packs = manager.assembly(new_packs); + } catch (const contentpack_error& err) { guiutil::alert( gui, langs::get(L"error.dependency-not-found")+ - L": "+util::str2wstr_utf8(missing) + L": "+util::str2wstr_utf8(err.getPackId()) ); return; } - world->wfile->addPack(world, pack.id); + world->wfile->writePacks(manager.getAll(new_packs)); controller->saveWorld(); reopen_world(engine, world); }, nullptr);