adding/removing packs update

This commit is contained in:
MihailRis 2024-04-13 23:26:21 +03:00
parent 657b09da9e
commit 7c4c511826
5 changed files with 61 additions and 95 deletions

View File

@ -24,6 +24,10 @@ void PacksManager::scan() {
}
}
void PacksManager::exclude(const std::string& id) {
packs.erase(id);
}
std::vector<std::string> PacksManager::getAllNames() const {
std::vector<std::string> 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<std::string> PacksManager::assembly(const std::vector<std::string>&
}
return added;
}
std::vector<std::string> PacksManager::getNames(const std::vector<ContentPack>& packs) {
std::vector<std::string> result;
for (const auto& pack : packs) {
result.push_back(pack.id);
}
return result;
}

View File

@ -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<std::string> getAllNames() const;
@ -36,6 +39,9 @@ public:
/// @throws contentpack_error if required dependency not found or
/// circular dependency detected
std::vector<std::string> assembly(const std::vector<std::string>& names) const;
/// @brief Collect all pack names (identifiers) into a new vector
static std::vector<std::string> getNames(const std::vector<ContentPack>& packs);
};
#endif // CONTENT_PACKS_MANAGER_H_

View File

@ -21,6 +21,7 @@
#include "../items/Inventory.h"
#include "../data/dynamic.h"
#include "../core_defs.h"
#include <cassert>
#include <iostream>
@ -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<ContentPack>& 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<std::string>& packs) {
auto root = files::read_json(getIndicesFile());
for (const auto& id : packs) {
erase_pack_indices(root.get(), id);
}
files::write_json(getIndicesFile(), root.get());
}

View File

@ -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 <map>
#include <vector>
#include <string>
#include <memory>
#include <unordered_map>
@ -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<ContentPack>& 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<std::string>& packs);
static const inline std::string WORLD_FILE = "world.json";
};

View File

@ -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);