refactor: add ContentControl class

This commit is contained in:
MihailRis 2025-03-21 09:10:31 +03:00
parent 7262119f5b
commit 331734792d
21 changed files with 324 additions and 246 deletions

View File

@ -25,7 +25,7 @@ namespace fs = std::filesystem;
static debug::Logger logger("assets-loader");
AssetsLoader::AssetsLoader(Engine& engine, Assets& assets, const ResPaths* paths)
AssetsLoader::AssetsLoader(Engine& engine, Assets& assets, const ResPaths& paths)
: engine(engine), assets(assets), paths(paths) {
addLoader(AssetType::SHADER, assetload::shader);
addLoader(AssetType::TEXTURE, assetload::texture);
@ -200,7 +200,7 @@ void AssetsLoader::processPreloadConfig(const io::path& file) {
}
void AssetsLoader::processPreloadConfigs(const Content* content) {
auto preloadFile = paths->getMainRoot() / "preload.json";
io::path preloadFile = "res:preload.json";
if (io::exists(preloadFile)) {
processPreloadConfig(preloadFile);
}
@ -212,7 +212,7 @@ void AssetsLoader::processPreloadConfigs(const Content* content) {
continue;
}
const auto& pack = entry.second;
auto preloadFile = pack->getInfo().folder / "preload.json";
preloadFile = pack->getInfo().folder / "preload.json";
if (io::exists(preloadFile)) {
processPreloadConfig(preloadFile);
}
@ -301,7 +301,7 @@ Engine& AssetsLoader::getEngine() {
return engine;
}
const ResPaths* AssetsLoader::getPaths() const {
const ResPaths& AssetsLoader::getPaths() const {
return paths;
}

View File

@ -57,7 +57,7 @@ struct AtlasCfg : AssetCfg {
using aloader_func = std::function<
assetload::
postfunc(AssetsLoader*, const ResPaths*, const std::string&, const std::string&, std::shared_ptr<AssetCfg>)>;
postfunc(AssetsLoader*, const ResPaths&, const std::string&, const std::string&, std::shared_ptr<AssetCfg>)>;
struct aloader_entry {
AssetType tag;
@ -72,7 +72,7 @@ class AssetsLoader {
std::map<AssetType, aloader_func> loaders;
std::queue<aloader_entry> entries;
std::set<std::pair<AssetType, std::string>> enqueued;
const ResPaths* paths;
const ResPaths& paths;
void tryAddSound(const std::string& name);
@ -83,7 +83,7 @@ class AssetsLoader {
void processPreloadConfig(const io::path& file);
void processPreloadConfigs(const Content* content);
public:
AssetsLoader(Engine& engine, Assets& assets, const ResPaths* paths);
AssetsLoader(Engine& engine, Assets& assets, const ResPaths& paths);
void addLoader(AssetType tag, aloader_func func);
/// @brief Enqueue asset load
@ -105,7 +105,7 @@ public:
std::shared_ptr<Task> startTask(runnable onDone);
const ResPaths* getPaths() const;
const ResPaths& getPaths() const;
aloader_func getLoader(AssetType tag);
/// @brief Enqueue core and content assets

View File

@ -34,7 +34,7 @@ namespace fs = std::filesystem;
static bool load_animation(
Assets* assets,
const ResPaths* paths,
const ResPaths& paths,
const std::string& atlasName,
const std::string& directory,
const std::string& name,
@ -43,14 +43,14 @@ static bool load_animation(
assetload::postfunc assetload::texture(
AssetsLoader*,
const ResPaths* paths,
const ResPaths& paths,
const std::string& filename,
const std::string& name,
const std::shared_ptr<AssetCfg>&
) {
auto actualFile = paths->find(filename + ".png");
auto actualFile = paths.find(filename + ".png");
try {
std::shared_ptr<ImageData> image(imageio::read(actualFile).release());
std::shared_ptr<ImageData> image(imageio::read(actualFile));
return [name, image, actualFile](auto assets) {
assets->store(Texture::from(image.get()), name);
};
@ -62,13 +62,13 @@ assetload::postfunc assetload::texture(
assetload::postfunc assetload::shader(
AssetsLoader*,
const ResPaths* paths,
const ResPaths& paths,
const std::string& filename,
const std::string& name,
const std::shared_ptr<AssetCfg>&
) {
io::path vertexFile = paths->find(filename + ".glslv");
io::path fragmentFile = paths->find(filename + ".glslf");
io::path vertexFile = paths.find(filename + ".glslv");
io::path fragmentFile = paths.find(filename + ".glslf");
std::string vertexSource = io::read_string(vertexFile);
std::string fragmentSource = io::read_string(fragmentFile);
@ -104,14 +104,14 @@ static bool append_atlas(AtlasBuilder& atlas, const io::path& file) {
assetload::postfunc assetload::atlas(
AssetsLoader* loader,
const ResPaths* paths,
const ResPaths& paths,
const std::string& directory,
const std::string& name,
const std::shared_ptr<AssetCfg>& config
) {
auto atlasConfig = std::dynamic_pointer_cast<AtlasCfg>(config);
if (atlasConfig && atlasConfig->type == AtlasType::SEPARATE) {
for (const auto& file : paths->listdir(directory)) {
for (const auto& file : paths.listdir(directory)) {
if (!imageio::is_read_supported(file.extension()))
continue;
loader->add(
@ -123,7 +123,7 @@ assetload::postfunc assetload::atlas(
return [](auto){};
}
AtlasBuilder builder;
for (const auto& file : paths->listdir(directory)) {
for (const auto& file : paths.listdir(directory)) {
if (!imageio::is_read_supported(file.extension())) continue;
if (!append_atlas(builder, file)) continue;
}
@ -140,7 +140,7 @@ assetload::postfunc assetload::atlas(
assetload::postfunc assetload::font(
AssetsLoader*,
const ResPaths* paths,
const ResPaths& paths,
const std::string& filename,
const std::string& name,
const std::shared_ptr<AssetCfg>&
@ -148,7 +148,7 @@ assetload::postfunc assetload::font(
auto pages = std::make_shared<std::vector<std::unique_ptr<ImageData>>>();
for (size_t i = 0; i <= 1024; i++) {
std::string pagefile = filename + "_" + std::to_string(i) + ".png";
auto file = paths->find(pagefile);
auto file = paths.find(pagefile);
if (io::exists(file)) {
pages->push_back(imageio::read(file));
} else if (i == 0) {
@ -177,7 +177,7 @@ assetload::postfunc assetload::font(
assetload::postfunc assetload::layout(
AssetsLoader*,
const ResPaths* paths,
const ResPaths&,
const std::string& file,
const std::string& name,
const std::shared_ptr<AssetCfg>& config
@ -206,7 +206,7 @@ assetload::postfunc assetload::layout(
}
assetload::postfunc assetload::sound(
AssetsLoader*,
const ResPaths* paths,
const ResPaths& paths,
const std::string& file,
const std::string& name,
const std::shared_ptr<AssetCfg>& config
@ -220,13 +220,13 @@ assetload::postfunc assetload::sound(
for (size_t i = 0; i < extensions.size(); i++) {
extension = extensions[i];
// looking for 'sound_name' as base sound
auto soundFile = paths->find(file + extension);
auto soundFile = paths.find(file + extension);
if (io::exists(soundFile)) {
baseSound = audio::load_sound(soundFile, keepPCM);
break;
}
// looking for 'sound_name_0' as base sound
auto variantFile = paths->find(file + "_0" + extension);
auto variantFile = paths.find(file + "_0" + extension);
if (io::exists(variantFile)) {
baseSound = audio::load_sound(variantFile, keepPCM);
break;
@ -239,7 +239,7 @@ assetload::postfunc assetload::sound(
// loading sound variants
for (uint i = 1;; i++) {
auto variantFile =
paths->find(file + "_" + std::to_string(i) + extension);
paths.find(file + "_" + std::to_string(i) + extension);
if (!io::exists(variantFile)) {
break;
}
@ -265,12 +265,12 @@ static void request_textures(AssetsLoader* loader, const model::Model& model) {
assetload::postfunc assetload::model(
AssetsLoader* loader,
const ResPaths* paths,
const ResPaths& paths,
const std::string& file,
const std::string& name,
const std::shared_ptr<AssetCfg>&
) {
auto path = paths->find(file + ".vec3");
auto path = paths.find(file + ".vec3");
if (io::exists(path)) {
auto bytes = io::read_bytes_buffer(path);
auto modelVEC3 = std::make_shared<vec3::File>(vec3::load(path.string(), bytes));
@ -290,7 +290,7 @@ assetload::postfunc assetload::model(
}
};
}
path = paths->find(file + ".obj");
path = paths.find(file + ".obj");
auto text = io::read_string(path);
try {
auto model = obj::parse(path.string(), text).release();
@ -384,7 +384,7 @@ inline bool contains(
static bool load_animation(
Assets* assets,
const ResPaths* paths,
const ResPaths& paths,
const std::string& atlasName,
const std::string& directory,
const std::string& name,
@ -392,20 +392,20 @@ static bool load_animation(
) {
std::string animsDir = directory + "/animation";
for (const auto& folder : paths->listdir(animsDir)) {
for (const auto& folder : paths.listdir(animsDir)) {
if (!io::is_directory(folder)) continue;
if (folder.name() != name) continue;
//FIXME: if (fs::is_empty(folder)) continue;
AtlasBuilder builder;
append_atlas(builder, paths->find(directory + "/" + name + ".png"));
append_atlas(builder, paths.find(directory + "/" + name + ".png"));
std::vector<std::pair<std::string, int>> frameList;
std::string animFile = folder.string() + "/animation.json";
if (io::exists(animFile)) {
read_anim_file(animFile, frameList);
}
for (const auto& file : paths->listdir(animsDir + "/" + name)) {
for (const auto& file : paths.listdir(animsDir + "/" + name)) {
if (!frameList.empty() &&
!contains(frameList, file.stem())) {
continue;

View File

@ -15,49 +15,49 @@ struct AssetCfg;
namespace assetload {
postfunc texture(
AssetsLoader*,
const ResPaths* paths,
const ResPaths& paths,
const std::string& filename,
const std::string& name,
const std::shared_ptr<AssetCfg>& settings
);
postfunc shader(
AssetsLoader*,
const ResPaths* paths,
const ResPaths& paths,
const std::string& filename,
const std::string& name,
const std::shared_ptr<AssetCfg>& settings
);
postfunc atlas(
AssetsLoader*,
const ResPaths* paths,
const ResPaths& paths,
const std::string& directory,
const std::string& name,
const std::shared_ptr<AssetCfg>& settings
);
postfunc font(
AssetsLoader*,
const ResPaths* paths,
const ResPaths& paths,
const std::string& filename,
const std::string& name,
const std::shared_ptr<AssetCfg>& settings
);
postfunc layout(
AssetsLoader*,
const ResPaths* paths,
const ResPaths& paths,
const std::string& file,
const std::string& name,
const std::shared_ptr<AssetCfg>& settings
);
postfunc sound(
AssetsLoader*,
const ResPaths* paths,
const ResPaths& paths,
const std::string& file,
const std::string& name,
const std::shared_ptr<AssetCfg>& settings
);
postfunc model(
AssetsLoader*,
const ResPaths* paths,
const ResPaths& paths,
const std::string& file,
const std::string& name,
const std::shared_ptr<AssetCfg>& settings

View File

@ -0,0 +1,140 @@
#include "ContentControl.hpp"
#include "io/io.hpp"
#include "io/engine_paths.hpp"
#include "coders/toml.hpp"
#include "Content.hpp"
#include "ContentPack.hpp"
#include "ContentBuilder.hpp"
#include "ContentLoader.hpp"
#include "PacksManager.hpp"
#include "objects/rigging.hpp"
#include "logic/scripting/scripting.hpp"
#include "window/input.hpp"
#include "core_defs.hpp"
static void load_configs(Input& input, const io::path& root) {
auto configFolder = root / "config";
auto bindsFile = configFolder / "bindings.toml";
if (io::is_regular_file(bindsFile)) {
input.getBindings().read(
toml::parse(bindsFile.string(), io::read_string(bindsFile)),
BindType::BIND
);
}
}
ContentControl::ContentControl(std::function<void()> postContent)
: postContent(std::move(postContent)) {
basePacks = io::read_list("res:config/builtins.list");
}
ContentControl::~ContentControl() = default;
Content* ContentControl::get() {
return content.get();
}
std::vector<std::string>& ContentControl::getBasePacks() {
return basePacks;
}
void ContentControl::resetContent(
EnginePaths& paths, Input& input, std::vector<ContentPack>& contentPacks
) {
scripting::cleanup();
std::vector<PathsRoot> resRoots;
{
auto pack = ContentPack::createCore(paths);
resRoots.push_back({"core", pack.folder});
load_configs(input, pack.folder);
}
PacksManager manager;
manager.setSources({
"user:content",
"res:content",
});
manager.scan();
for (const auto& pack : manager.getAll(basePacks)) {
resRoots.push_back({pack.id, pack.folder});
}
paths.resPaths = ResPaths(resRoots);
content.reset();
contentPacks.clear();
contentPacks = manager.getAll(basePacks);
postContent();
}
void ContentControl::loadContent(
EnginePaths& paths,
Input& input,
std::vector<ContentPack>& packs,
const std::vector<std::string>& names
) {
PacksManager manager;
manager.setSources(getDefaultSources());
manager.scan();
packs = manager.getAll(manager.assemble(names));
loadContent(paths, input, packs);
}
void ContentControl::loadContent(
EnginePaths& paths,
Input& input,
std::vector<ContentPack>& contentPacks
) {
scripting::cleanup();
std::vector<std::string> names;
for (auto& pack : contentPacks) {
names.push_back(pack.id);
}
PacksManager manager;
manager.setSources(getDefaultSources());
manager.scan();
names = manager.assemble(names);
contentPacks = manager.getAll(names);
std::vector<PathsRoot> entryPoints;
for (auto& pack : contentPacks) {
entryPoints.emplace_back(pack.id, pack.folder);
}
paths.setEntryPoints(std::move(entryPoints));
ContentBuilder contentBuilder;
corecontent::setup(input, contentBuilder);
auto corePack = ContentPack::createCore(paths);
auto allPacks = contentPacks;
allPacks.insert(allPacks.begin(), corePack);
// Setup filesystem entry points
std::vector<PathsRoot> resRoots;
for (auto& pack : allPacks) {
resRoots.push_back({pack.id, pack.folder});
}
paths.resPaths = ResPaths(resRoots);
// Load content
for (auto& pack : allPacks) {
ContentLoader(&pack, contentBuilder, paths.resPaths).load();
load_configs(input, pack.folder);
}
content = contentBuilder.build();
scripting::on_content_load(content.get());
ContentLoader::loadScripts(*content);
postContent();
}
std::vector<io::path> ContentControl::getDefaultSources() {
return {
"world:content",
"user:content",
"res:content",
};
}

View File

@ -0,0 +1,48 @@
#pragma once
#include <memory>
#include <vector>
#include <string>
#include <functional>
class Content;
struct ContentPack;
class EnginePaths;
class Input;
namespace io {
class path;
}
class ContentControl {
public:
ContentControl(std::function<void()> postContent);
~ContentControl();
Content* get();
std::vector<std::string>& getBasePacks();
void resetContent(
EnginePaths& paths, Input& input, std::vector<ContentPack>& packs
);
void loadContent(
EnginePaths& paths,
Input& input,
std::vector<ContentPack>& packs,
const std::vector<std::string>& names
);
void loadContent(
EnginePaths& paths,
Input& input,
std::vector<ContentPack>& packs
);
std::vector<io::path> getDefaultSources();
private:
std::unique_ptr<Content> content;
std::vector<std::string> basePacks;
std::function<void()> postContent;
};

View File

@ -124,7 +124,7 @@ ContentPack ContentPack::read(const std::string& path, const io::path& folder) {
}
void ContentPack::scanFolder(
const std::string& path, const io::path& folder, std::vector<ContentPack>& packs
const io::path& folder, std::vector<ContentPack>& packs
) {
if (!io::is_directory(folder)) {
return;
@ -133,9 +133,7 @@ void ContentPack::scanFolder(
if (!io::is_directory(packFolder)) continue;
if (!is_pack(packFolder)) continue;
try {
packs.push_back(
read(path + "/" + packFolder.name(), packFolder)
);
packs.push_back(read(packFolder.string(), packFolder));
} catch (const contentpack_error& err) {
std::cerr << "package.json error at " << err.getFolder().string();
std::cerr << ": " << err.what() << std::endl;

View File

@ -58,14 +58,10 @@ struct ContentPack {
static const std::vector<std::string> RESERVED_NAMES;
static bool is_pack(const io::path& folder);
static ContentPack read(
const std::string& path, const io::path& folder
);
static ContentPack read(const std::string& path, const io::path& folder);
static void scanFolder(
const std::string& path,
const io::path& folder,
std::vector<ContentPack>& packs
const io::path& folder, std::vector<ContentPack>& packs
);
static std::vector<std::string> worldPacksList(

View File

@ -7,7 +7,7 @@
PacksManager::PacksManager() = default;
void PacksManager::setSources(std::vector<std::pair<std::string, io::path>> sources) {
void PacksManager::setSources(std::vector<io::path> sources) {
this->sources = std::move(sources);
}
@ -15,8 +15,8 @@ void PacksManager::scan() {
packs.clear();
std::vector<ContentPack> packsList;
for (auto& [path, folder] : sources) {
ContentPack::scanFolder(path, folder, packsList);
for (auto& folder : sources) {
ContentPack::scanFolder(folder, packsList);
for (auto& pack : packsList) {
packs.try_emplace(pack.id, pack);
}

View File

@ -8,12 +8,12 @@
class PacksManager {
std::unordered_map<std::string, ContentPack> packs;
std::vector<std::pair<std::string, io::path>> sources;
std::vector<io::path> sources;
public:
PacksManager();
/// @brief Set content packs sources (search folders)
void setSources(std::vector<std::pair<std::string, io::path>> sources);
void setSources(std::vector<io::path> sources);
/// @brief Scan sources and collect all found packs excluding duplication.
/// Scanning order depends on sources order

View File

@ -7,14 +7,14 @@
#include "debug/Logger.hpp"
#include "assets/AssetsLoader.hpp"
#include "audio/audio.hpp"
#include "voxels/Block.hpp"
#include "coders/GLSLExtension.hpp"
#include "coders/imageio.hpp"
#include "coders/json.hpp"
#include "coders/toml.hpp"
#include "coders/commons.hpp"
#include "content/Content.hpp"
#include "content/ContentBuilder.hpp"
#include "content/ContentLoader.hpp"
#include "content/ContentControl.hpp"
#include "core_defs.hpp"
#include "io/io.hpp"
#include "frontend/locale.hpp"
@ -146,7 +146,14 @@ void Engine::initialize(CoreParameters coreParameters) {
keepAlive(settings.ui.language.observe([this](auto lang) {
setLanguage(lang);
}, true));
basePacks = io::read_list("res:config/builtins.list");
content = std::make_unique<ContentControl>([this]() {
langs::setup("res:", langs::get_current(), paths.resPaths.collectRoots());
if (!isHeadless()) {
loadAssets();
onAssetsLoaded();
}
});
}
void Engine::loadSettings() {
@ -284,27 +291,19 @@ EngineController* Engine::getController() {
return controller.get();
}
PacksManager Engine::createPacksManager(const io::path& worldFolder) {
PacksManager manager;
manager.setSources({
{"world:content", worldFolder.empty() ? worldFolder : worldFolder / "content"},
{"user:content", "user:content"},
{"res:content", "res:content"}
});
return manager;
}
void Engine::setLevelConsumer(OnWorldOpen levelConsumer) {
this->levelConsumer = std::move(levelConsumer);
}
void Engine::loadAssets() {
logger.info() << "loading assets";
Shader::preprocessor->setPaths(resPaths.get());
Shader::preprocessor->setPaths(&paths.resPaths);
auto content = this->content->get();
auto new_assets = std::make_unique<Assets>();
AssetsLoader loader(*this, *new_assets, resPaths.get());
AssetsLoader::addDefaults(loader, content.get());
AssetsLoader loader(*this, *new_assets, paths.resPaths);
AssetsLoader::addDefaults(loader, content);
// no need
// correct log messages order is more useful
@ -345,118 +344,21 @@ void Engine::loadAssets() {
}
}
static void load_configs(Engine& engine, const io::path& root) {
auto& input = engine.getInput();
auto configFolder = root / "config";
auto bindsFile = configFolder / "bindings.toml";
if (io::is_regular_file(bindsFile)) {
input.getBindings().read(
toml::parse(bindsFile.string(), io::read_string(bindsFile)),
BindType::BIND
);
}
}
void Engine::loadContent() {
scripting::cleanup();
std::vector<std::string> names;
for (auto& pack : contentPacks) {
names.push_back(pack.id);
}
PacksManager manager = createPacksManager(paths.getCurrentWorldFolder());
manager.scan();
names = manager.assemble(names);
contentPacks = manager.getAll(names);
std::vector<PathsRoot> entryPoints;
for (auto& pack : contentPacks) {
entryPoints.emplace_back(pack.id, pack.folder);
}
paths.setEntryPoints(std::move(entryPoints));
ContentBuilder contentBuilder;
corecontent::setup(*input, contentBuilder);
auto corePack = ContentPack::createCore(paths);
// Setup filesystem entry points
std::vector<PathsRoot> resRoots {
{"core", corePack.folder}
};
for (auto& pack : contentPacks) {
resRoots.push_back({pack.id, pack.folder});
}
resPaths = std::make_unique<ResPaths>("res:", resRoots);
// Load content
{
ContentLoader(&corePack, contentBuilder, *resPaths).load();
load_configs(*this, corePack.folder);
}
for (auto& pack : contentPacks) {
ContentLoader(&pack, contentBuilder, *resPaths).load();
load_configs(*this, pack.folder);
}
content = contentBuilder.build();
scripting::on_content_load(content.get());
ContentLoader::loadScripts(*content);
langs::setup("res:", langs::get_current(), resPaths->collectRoots());
if (!isHeadless()) {
loadAssets();
onAssetsLoaded();
}
content->loadContent(paths, *input, contentPacks);
}
void Engine::resetContent() {
scripting::cleanup();
std::vector<PathsRoot> resRoots;
{
auto pack = ContentPack::createCore(paths);
resRoots.push_back({"core", pack.folder});
load_configs(*this, pack.folder);
}
auto manager = createPacksManager(io::path());
manager.scan();
for (const auto& pack : manager.getAll(basePacks)) {
resRoots.push_back({pack.id, pack.folder});
}
resPaths = std::make_unique<ResPaths>("res:", resRoots);
contentPacks.clear();
content.reset();
langs::setup("res:", langs::get_current(), resPaths->collectRoots());
if (!isHeadless()) {
loadAssets();
onAssetsLoaded();
}
contentPacks = manager.getAll(basePacks);
paths.setCurrentWorldFolder("");
content->resetContent(paths, *input, contentPacks);
}
void Engine::loadWorldContent(const io::path& folder) {
contentPacks.clear();
auto packNames = ContentPack::worldPacksList(folder);
PacksManager manager;
manager.setSources(
{{"world:content", folder.empty() ? folder : folder / "content"},
{"user:content", "user:content"},
{"res:content", "res:content"}}
);
manager.scan();
contentPacks = manager.getAll(manager.assemble(packNames));
paths.setCurrentWorldFolder(folder);
loadContent();
}
void Engine::loadAllPacks() {
PacksManager manager = createPacksManager(paths.getCurrentWorldFolder());
manager.scan();
auto allnames = manager.getAllNames();
contentPacks = manager.getAll(manager.assemble(allnames));
content->loadContent(
paths, *input, contentPacks, ContentPack::worldPacksList("world:")
);
}
void Engine::setScreen(std::shared_ptr<Screen> screen) {
@ -467,12 +369,7 @@ void Engine::setScreen(std::shared_ptr<Screen> screen) {
}
void Engine::setLanguage(std::string locale) {
langs::setup(
"res:",
std::move(locale),
resPaths ? resPaths->collectRoots()
: std::vector<io::path> {{"core", "res:"}}
);
langs::setup("res:", std::move(locale), paths.resPaths.collectRoots());
}
void Engine::onWorldOpen(std::unique_ptr<Level> level, int64_t localPlayer) {
@ -505,11 +402,11 @@ Assets* Engine::getAssets() {
}
const Content* Engine::getContent() const {
return content.get();
return content->get();
}
Content* Engine::getWriteableContent() {
return content.get();
return content->get();
}
std::vector<ContentPack> Engine::getAllContentPacks() {
@ -522,16 +419,12 @@ std::vector<ContentPack>& Engine::getContentPacks() {
return contentPacks;
}
std::vector<std::string>& Engine::getBasePacks() {
return basePacks;
}
EnginePaths& Engine::getPaths() {
return paths;
}
ResPaths* Engine::getResPaths() {
return resPaths.get();
ResPaths& Engine::getResPaths() {
return paths.resPaths;
}
std::shared_ptr<Screen> Engine::getScreen() {
@ -553,3 +446,7 @@ const CoreParameters& Engine::getCoreParameters() const {
bool Engine::isHeadless() const {
return params.headless;
}
ContentControl& Engine::getContentControl() {
return *content;
}

View File

@ -23,6 +23,7 @@ class Level;
class Screen;
class EnginePaths;
class ResPaths;
class ContentControl;
class EngineController;
class SettingsHandler;
struct EngineSettings;
@ -64,14 +65,12 @@ class Engine : public util::ObjectsKeeper {
std::unique_ptr<Assets> assets;
std::shared_ptr<Screen> screen;
std::vector<ContentPack> contentPacks;
std::unique_ptr<Content> content;
std::unique_ptr<ResPaths> resPaths;
std::unique_ptr<ContentControl> content;
std::unique_ptr<EngineController> controller;
std::unique_ptr<cmd::CommandsInterpreter> cmd;
std::unique_ptr<network::Network> network;
std::unique_ptr<Window> window;
std::unique_ptr<Input> input;
std::vector<std::string> basePacks;
std::unique_ptr<gui::GUI> gui;
PostRunnables postRunnables;
Time time;
@ -127,9 +126,6 @@ public:
/// @param folder world folder
void loadWorldContent(const io::path& folder);
/// @brief Collect all available content-packs from res/content
void loadAllPacks();
/// @brief Get active assets storage instance
Assets* getAssets();
@ -140,7 +136,7 @@ public:
EnginePaths& getPaths();
/// @brief Get engine resource paths controller
ResPaths* getResPaths();
ResPaths& getResPaths();
void onWorldOpen(std::unique_ptr<Level> level, int64_t localPlayer);
void onWorldClosed();
@ -159,8 +155,6 @@ public:
std::vector<ContentPack> getAllContentPacks();
std::vector<std::string>& getBasePacks();
/// @brief Get current screen
std::shared_ptr<Screen> getScreen();
@ -173,8 +167,6 @@ public:
EngineController* getController();
PacksManager createPacksManager(const io::path& worldFolder);
void setLevelConsumer(OnWorldOpen levelConsumer);
SettingsHandler& getSettingsHandler();
@ -185,6 +177,8 @@ public:
bool isHeadless() const;
ContentControl& getContentControl();
gui::GUI& getGUI() {
return *gui;
}

View File

@ -74,7 +74,7 @@ UiDocument* menus::show(
Engine& engine, const std::string& name, std::vector<dv::value> args
) {
auto menu = engine.getGUI().getMenu();
auto file = engine.getResPaths()->find("layouts/" + name + ".xml");
auto file = engine.getResPaths().find("layouts/" + name + ".xml");
auto fullname = "core:layouts/" + name;
auto documentPtr = UiDocument::read(

View File

@ -61,7 +61,7 @@ Decorator::Decorator(
player->getPosition()
));
}
playerNamePreset.deserialize(engine.getResPaths()->readCombinedObject(
playerNamePreset.deserialize(engine.getResPaths().readCombinedObject(
"presets/text3d/player_name.toml"
));
}

View File

@ -247,8 +247,8 @@ std::tuple<std::string, std::string> EnginePaths::parsePath(std::string_view pat
return {prefix, filename};
}
ResPaths::ResPaths(io::path mainRoot, std::vector<PathsRoot> roots)
: mainRoot(std::move(mainRoot)), roots(std::move(roots)) {
ResPaths::ResPaths(std::vector<PathsRoot> roots)
: roots(std::move(roots)) {
}
io::path ResPaths::find(const std::string& filename) const {
@ -259,7 +259,7 @@ io::path ResPaths::find(const std::string& filename) const {
return file;
}
}
return mainRoot / filename;
return io::path("res:") / filename;
}
std::string ResPaths::findRaw(const std::string& filename) const {
@ -356,7 +356,3 @@ std::vector<io::path> ResPaths::collectRoots() {
}
return collected;
}
const io::path& ResPaths::getMainRoot() const {
return mainRoot;
}

View File

@ -19,8 +19,33 @@ struct PathsRoot {
}
};
class ResPaths {
public:
ResPaths() = default;
ResPaths(std::vector<PathsRoot> roots);
io::path find(const std::string& filename) const;
std::string findRaw(const std::string& filename) const;
std::vector<io::path> listdir(const std::string& folder) const;
std::vector<std::string> listdirRaw(const std::string& folder) const;
/// @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) const;
dv::value readCombinedObject(const std::string& file, bool deep=false) const;
std::vector<io::path> collectRoots();
private:
std::vector<PathsRoot> roots;
};
class EnginePaths {
public:
ResPaths resPaths;
void prepare();
void setUserFilesFolder(std::filesystem::path folder);
@ -65,28 +90,3 @@ private:
void cleanup();
};
class ResPaths {
public:
ResPaths(io::path mainRoot, std::vector<PathsRoot> roots);
io::path find(const std::string& filename) const;
std::string findRaw(const std::string& filename) const;
std::vector<io::path> listdir(const std::string& folder) const;
std::vector<std::string> listdirRaw(const std::string& folder) const;
/// @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) const;
dv::value readCombinedObject(const std::string& file, bool deep=false) const;
std::vector<io::path> collectRoots();
const io::path& getMainRoot() const;
private:
io::path mainRoot;
std::vector<PathsRoot> roots;
};

View File

@ -9,6 +9,7 @@
#include "debug/Logger.hpp"
#include "coders/json.hpp"
#include "content/ContentReport.hpp"
#include "content/ContentControl.hpp"
#include "world/files/WorldConverter.hpp"
#include "world/files/WorldFiles.hpp"
#include "frontend/locale.hpp"
@ -318,7 +319,8 @@ void EngineController::reconfigPacks(
runnable removeFunc = [this, controller, packsToAdd, packsToRemove]() {
if (controller == nullptr) {
try {
auto manager = engine.createPacksManager("");
PacksManager manager;
manager.setSources(engine.getContentControl().getDefaultSources());
manager.scan();
auto names = PacksManager::getNames(engine.getContentPacks());
for (const auto& id : packsToAdd) {
@ -339,7 +341,9 @@ void EngineController::reconfigPacks(
auto world = controller->getLevel()->getWorld();
auto& wfile = *world->wfile;
controller->saveWorld();
auto manager = engine.createPacksManager(wfile.getFolder());
PacksManager manager;
manager.setSources(engine.getContentControl().getDefaultSources());
manager.scan();
auto names = PacksManager::getNames(world->getPacks());

View File

@ -71,8 +71,8 @@ inline audio::speakerid_t play_stream(
if (std::strchr(filename, ':')) {
file = std::string(filename);
} else {
auto paths = scripting::engine->getResPaths();
file = paths->find(filename);
const auto& paths = scripting::engine->getResPaths();
file = paths.find(filename);
}
return audio::play_stream(
file,

View File

@ -17,7 +17,7 @@ using namespace scripting;
static int l_find(lua::State* L) {
auto path = lua::require_string(L, 1);
try {
return lua::pushstring(L, engine->getResPaths()->findRaw(path));
return lua::pushstring(L, engine->getResPaths().findRaw(path));
} catch (const std::runtime_error& err) {
return 0;
}
@ -159,7 +159,7 @@ static int l_write_bytes(lua::State* L) {
}
static int l_list_all_res(lua::State* L, const std::string& path) {
auto files = engine->getResPaths()->listdirRaw(path);
auto files = engine->getResPaths().listdirRaw(path);
lua::createtable(L, files.size(), 0);
for (size_t i = 0; i < files.size(); i++) {
lua::pushstring(L, files[i]);
@ -222,7 +222,7 @@ static int l_read_combined_list(lua::State* L) {
if (path.find(':') != std::string::npos) {
throw std::runtime_error("entry point must not be specified");
}
return lua::pushvalue(L, engine->getResPaths()->readCombinedList(path));
return lua::pushvalue(L, engine->getResPaths().readCombinedList(path));
}
static int l_read_combined_object(lua::State* L) {
@ -230,7 +230,7 @@ static int l_read_combined_object(lua::State* L) {
if (path.find(':') != std::string::npos) {
throw std::runtime_error("entry point must not be specified");
}
return lua::pushvalue(L, engine->getResPaths()->readCombinedObject(path));
return lua::pushvalue(L, engine->getResPaths().readCombinedObject(path));
}
static int l_is_writeable(lua::State* L) {

View File

@ -68,7 +68,7 @@ static int l_get_generators(lua::State* L) {
/// @return The ID of the default world generator
static int l_get_default_generator(lua::State* L) {
// content is not initialized yet
auto combined = engine->getResPaths()->readCombinedObject(
auto combined = engine->getResPaths().readCombinedObject(
EnginePaths::CONFIG_DEFAULTS.string()
);
return lua::pushstring(L, combined["generator"].asString());

View File

@ -6,6 +6,7 @@
#include "assets/AssetsLoader.hpp"
#include "content/Content.hpp"
#include "content/ContentControl.hpp"
#include "engine/Engine.hpp"
#include "graphics/ui/gui_util.hpp"
#include "graphics/ui/elements/Menu.hpp"
@ -47,7 +48,8 @@ static int l_pack_get_available(lua::State* L) {
if (level) {
worldFolder = level->getWorld()->wfile->getFolder();
}
auto manager = engine->createPacksManager(worldFolder);
PacksManager manager;
manager.setSources(engine->getContentControl().getDefaultSources());
manager.scan();
const auto& installed = engine->getContentPacks();
@ -153,7 +155,8 @@ static int pack_get_infos(lua::State* L) {
if (level) {
worldFolder = level->getWorld()->wfile->getFolder();
}
auto manager = engine->createPacksManager(worldFolder);
PacksManager manager;
manager.setSources(engine->getContentControl().getDefaultSources());
manager.scan();
auto vec =
manager.getAll(std::vector<std::string>(ids.begin(), ids.end()));
@ -195,7 +198,8 @@ static int l_pack_get_info(lua::State* L) {
if (level) {
worldFolder = level->getWorld()->wfile->getFolder();
}
auto manager = engine->createPacksManager(worldFolder);
PacksManager manager;
manager.setSources(engine->getContentControl().getDefaultSources());
manager.scan();
auto vec = manager.getAll({packid});
if (!vec.empty()) {
@ -208,7 +212,7 @@ static int l_pack_get_info(lua::State* L) {
}
static int l_pack_get_base_packs(lua::State* L) {
auto& packs = engine->getBasePacks();
auto& packs = engine->getContentControl().getBasePacks();
lua::createtable(L, packs.size(), 0);
for (size_t i = 0; i < packs.size(); i++) {
lua::pushstring(L, packs[i]);
@ -232,7 +236,8 @@ static int l_pack_assemble(lua::State* L) {
if (level) {
worldFolder = level->getWorld()->wfile->getFolder();
}
auto manager = engine->createPacksManager(worldFolder);
PacksManager manager;
manager.setSources(engine->getContentControl().getDefaultSources());
manager.scan();
try {
ids = manager.assemble(ids);