It's better to use '= default;' syntax instead of empty constructor and destructor body. Using '= default;' can help the compiler generate more optimal code. Reported by: PVS-Studio Signed-off-by: Vyacheslav Ivanov <islavaivanov76@gmail.com>
146 lines
4.5 KiB
C++
146 lines
4.5 KiB
C++
#include "ContentPack.hpp"
|
|
|
|
#include <iostream>
|
|
#include <algorithm>
|
|
#include <utility>
|
|
|
|
#include "../coders/json.hpp"
|
|
#include "../files/files.hpp"
|
|
#include "../files/engine_paths.hpp"
|
|
#include "../data/dynamic.hpp"
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
const std::vector<std::string> ContentPack::RESERVED_NAMES = {
|
|
"res", "abs", "local", "core", "user", "world", "none", "null"
|
|
};
|
|
|
|
contentpack_error::contentpack_error(
|
|
std::string packId,
|
|
fs::path folder,
|
|
const std::string& message)
|
|
: std::runtime_error(message), packId(std::move(packId)), folder(std::move(folder)) {
|
|
}
|
|
|
|
std::string contentpack_error::getPackId() const {
|
|
return packId;
|
|
}
|
|
fs::path contentpack_error::getFolder() const {
|
|
return folder;
|
|
}
|
|
|
|
fs::path ContentPack::getContentFile() const {
|
|
return folder/fs::path(CONTENT_FILENAME);
|
|
}
|
|
|
|
bool ContentPack::is_pack(const fs::path& folder) {
|
|
return fs::is_regular_file(folder/fs::path(PACKAGE_FILENAME));
|
|
}
|
|
|
|
static void checkContentPackId(const std::string& id, const fs::path& folder) {
|
|
if (id.length() < 2 || id.length() > 24)
|
|
throw contentpack_error(id, folder,
|
|
"content-pack id length is out of range [2, 24]");
|
|
if (isdigit(id[0]))
|
|
throw contentpack_error(id, folder,
|
|
"content-pack id must not start with a digit");
|
|
for (char c : id) {
|
|
if (!isalnum(c) && c != '_') {
|
|
throw contentpack_error(id, folder,
|
|
"illegal character in content-pack id");
|
|
}
|
|
}
|
|
if (std::find(ContentPack::RESERVED_NAMES.begin(),
|
|
ContentPack::RESERVED_NAMES.end(), id)
|
|
!= ContentPack::RESERVED_NAMES.end()) {
|
|
throw contentpack_error(id, folder,
|
|
"this content-pack id is reserved");
|
|
}
|
|
}
|
|
|
|
ContentPack ContentPack::read(const fs::path& folder) {
|
|
auto root = files::read_json(folder/fs::path(PACKAGE_FILENAME));
|
|
ContentPack pack;
|
|
root->str("id", pack.id);
|
|
root->str("title", pack.title);
|
|
root->str("version", pack.version);
|
|
root->str("creator", pack.creator);
|
|
root->str("description", pack.description);
|
|
pack.folder = folder;
|
|
|
|
auto dependencies = root->list("dependencies");
|
|
if (dependencies) {
|
|
for (size_t i = 0; i < dependencies->size(); i++) {
|
|
pack.dependencies.push_back(
|
|
{DependencyLevel::required, dependencies->str(i)}
|
|
);
|
|
}
|
|
}
|
|
|
|
if (pack.id == "none")
|
|
throw contentpack_error(pack.id, folder,
|
|
"content-pack id is not specified");
|
|
checkContentPackId(pack.id, folder);
|
|
|
|
return pack;
|
|
}
|
|
|
|
void ContentPack::scanFolder(
|
|
const fs::path& folder,
|
|
std::vector<ContentPack>& packs
|
|
) {
|
|
if (!fs::is_directory(folder)) {
|
|
return;
|
|
}
|
|
for (const auto& entry : fs::directory_iterator(folder)) {
|
|
const fs::path& folder = entry.path();
|
|
if (!fs::is_directory(folder))
|
|
continue;
|
|
if (!is_pack(folder))
|
|
continue;
|
|
try {
|
|
packs.push_back(read(folder));
|
|
} catch (const contentpack_error& err) {
|
|
std::cerr << "package.json error at " << err.getFolder().u8string();
|
|
std::cerr << ": " << err.what() << std::endl;
|
|
} catch (const std::runtime_error& err) {
|
|
std::cerr << err.what() << std::endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::vector<std::string> ContentPack::worldPacksList(const fs::path& folder) {
|
|
fs::path listfile = folder / fs::path("packs.list");
|
|
if (!fs::is_regular_file(listfile)) {
|
|
std::cerr << "warning: packs.list not found (will be created)";
|
|
std::cerr << std::endl;
|
|
files::write_string(listfile, "# autogenerated, do not modify\nbase\n");
|
|
}
|
|
return files::read_list(listfile);
|
|
}
|
|
|
|
fs::path ContentPack::findPack(const EnginePaths* paths, const fs::path& worldDir, const std::string& name) {
|
|
fs::path folder = worldDir / fs::path("content") / fs::path(name);
|
|
if (fs::is_directory(folder)) {
|
|
return folder;
|
|
}
|
|
folder = paths->getUserfiles() / fs::path("content") / fs::path(name);
|
|
if (fs::is_directory(folder)) {
|
|
return folder;
|
|
}
|
|
folder = paths->getResources() / fs::path("content") / fs::path(name);
|
|
if (fs::is_directory(folder)) {
|
|
return folder;
|
|
}
|
|
return folder;
|
|
}
|
|
|
|
ContentPackRuntime::ContentPackRuntime(
|
|
ContentPack info,
|
|
scriptenv env
|
|
) : info(std::move(info)), env(std::move(env))
|
|
{
|
|
}
|
|
|
|
ContentPackRuntime::~ContentPackRuntime() = default;
|