diff --git a/src/assets/AssetsLoader.cpp b/src/assets/AssetsLoader.cpp index 42fe4a0b..10f3f7ea 100644 --- a/src/assets/AssetsLoader.cpp +++ b/src/assets/AssetsLoader.cpp @@ -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; } diff --git a/src/assets/AssetsLoader.hpp b/src/assets/AssetsLoader.hpp index 20dc50a3..e3c137ba 100644 --- a/src/assets/AssetsLoader.hpp +++ b/src/assets/AssetsLoader.hpp @@ -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)>; + postfunc(AssetsLoader*, const ResPaths&, const std::string&, const std::string&, std::shared_ptr)>; struct aloader_entry { AssetType tag; @@ -72,7 +72,7 @@ class AssetsLoader { std::map loaders; std::queue entries; std::set> 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 startTask(runnable onDone); - const ResPaths* getPaths() const; + const ResPaths& getPaths() const; aloader_func getLoader(AssetType tag); /// @brief Enqueue core and content assets diff --git a/src/assets/assetload_funcs.cpp b/src/assets/assetload_funcs.cpp index f6582333..01c251b4 100644 --- a/src/assets/assetload_funcs.cpp +++ b/src/assets/assetload_funcs.cpp @@ -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& ) { - auto actualFile = paths->find(filename + ".png"); + auto actualFile = paths.find(filename + ".png"); try { - std::shared_ptr image(imageio::read(actualFile).release()); + std::shared_ptr 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& ) { - 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& config ) { auto atlasConfig = std::dynamic_pointer_cast(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& @@ -148,7 +148,7 @@ assetload::postfunc assetload::font( auto pages = std::make_shared>>(); 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& 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& 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& ) { - 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::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> 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; diff --git a/src/assets/assetload_funcs.hpp b/src/assets/assetload_funcs.hpp index 3348edaa..eb26dc62 100644 --- a/src/assets/assetload_funcs.hpp +++ b/src/assets/assetload_funcs.hpp @@ -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& settings ); postfunc shader( AssetsLoader*, - const ResPaths* paths, + const ResPaths& paths, const std::string& filename, const std::string& name, const std::shared_ptr& settings ); postfunc atlas( AssetsLoader*, - const ResPaths* paths, + const ResPaths& paths, const std::string& directory, const std::string& name, const std::shared_ptr& settings ); postfunc font( AssetsLoader*, - const ResPaths* paths, + const ResPaths& paths, const std::string& filename, const std::string& name, const std::shared_ptr& settings ); postfunc layout( AssetsLoader*, - const ResPaths* paths, + const ResPaths& paths, const std::string& file, const std::string& name, const std::shared_ptr& settings ); postfunc sound( AssetsLoader*, - const ResPaths* paths, + const ResPaths& paths, const std::string& file, const std::string& name, const std::shared_ptr& settings ); postfunc model( AssetsLoader*, - const ResPaths* paths, + const ResPaths& paths, const std::string& file, const std::string& name, const std::shared_ptr& settings diff --git a/src/content/ContentControl.cpp b/src/content/ContentControl.cpp new file mode 100644 index 00000000..ef9a09d1 --- /dev/null +++ b/src/content/ContentControl.cpp @@ -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 postContent) + : postContent(std::move(postContent)) { + basePacks = io::read_list("res:config/builtins.list"); +} + +ContentControl::~ContentControl() = default; + +Content* ContentControl::get() { + return content.get(); +} + +std::vector& ContentControl::getBasePacks() { + return basePacks; +} + +void ContentControl::resetContent( + EnginePaths& paths, Input& input, std::vector& contentPacks +) { + scripting::cleanup(); + std::vector 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& packs, + const std::vector& 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& contentPacks +) { + scripting::cleanup(); + + std::vector 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 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 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 ContentControl::getDefaultSources() { + return { + "world:content", + "user:content", + "res:content", + }; +} diff --git a/src/content/ContentControl.hpp b/src/content/ContentControl.hpp new file mode 100644 index 00000000..7a9b7bbb --- /dev/null +++ b/src/content/ContentControl.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include +#include + +class Content; +struct ContentPack; +class EnginePaths; +class Input; + +namespace io { + class path; +} + +class ContentControl { +public: + ContentControl(std::function postContent); + ~ContentControl(); + + Content* get(); + + std::vector& getBasePacks(); + + void resetContent( + EnginePaths& paths, Input& input, std::vector& packs + ); + + void loadContent( + EnginePaths& paths, + Input& input, + std::vector& packs, + const std::vector& names + ); + + void loadContent( + EnginePaths& paths, + Input& input, + std::vector& packs + ); + + std::vector getDefaultSources(); +private: + std::unique_ptr content; + std::vector basePacks; + std::function postContent; +}; diff --git a/src/content/ContentPack.cpp b/src/content/ContentPack.cpp index 73a9503e..b261c47e 100644 --- a/src/content/ContentPack.cpp +++ b/src/content/ContentPack.cpp @@ -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& packs + const io::path& folder, std::vector& 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; diff --git a/src/content/ContentPack.hpp b/src/content/ContentPack.hpp index ed7c3eb8..c8dd7f26 100644 --- a/src/content/ContentPack.hpp +++ b/src/content/ContentPack.hpp @@ -58,14 +58,10 @@ struct ContentPack { static const std::vector 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& packs + const io::path& folder, std::vector& packs ); static std::vector worldPacksList( diff --git a/src/content/PacksManager.cpp b/src/content/PacksManager.cpp index 49c3014c..0e9925c8 100644 --- a/src/content/PacksManager.cpp +++ b/src/content/PacksManager.cpp @@ -7,7 +7,7 @@ PacksManager::PacksManager() = default; -void PacksManager::setSources(std::vector> sources) { +void PacksManager::setSources(std::vector sources) { this->sources = std::move(sources); } @@ -15,8 +15,8 @@ void PacksManager::scan() { packs.clear(); std::vector 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); } diff --git a/src/content/PacksManager.hpp b/src/content/PacksManager.hpp index 32ac43d6..94ce7bdc 100644 --- a/src/content/PacksManager.hpp +++ b/src/content/PacksManager.hpp @@ -8,12 +8,12 @@ class PacksManager { std::unordered_map packs; - std::vector> sources; + std::vector sources; public: PacksManager(); /// @brief Set content packs sources (search folders) - void setSources(std::vector> sources); + void setSources(std::vector sources); /// @brief Scan sources and collect all found packs excluding duplication. /// Scanning order depends on sources order diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index b6db2d21..05e26abc 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -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([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(); - 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 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 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 resRoots { - {"core", corePack.folder} - }; - for (auto& pack : contentPacks) { - resRoots.push_back({pack.id, pack.folder}); - } - resPaths = std::make_unique("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 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("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) { @@ -467,12 +369,7 @@ void Engine::setScreen(std::shared_ptr screen) { } void Engine::setLanguage(std::string locale) { - langs::setup( - "res:", - std::move(locale), - resPaths ? resPaths->collectRoots() - : std::vector {{"core", "res:"}} - ); + langs::setup("res:", std::move(locale), paths.resPaths.collectRoots()); } void Engine::onWorldOpen(std::unique_ptr 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 Engine::getAllContentPacks() { @@ -522,16 +419,12 @@ std::vector& Engine::getContentPacks() { return contentPacks; } -std::vector& Engine::getBasePacks() { - return basePacks; -} - EnginePaths& Engine::getPaths() { return paths; } -ResPaths* Engine::getResPaths() { - return resPaths.get(); +ResPaths& Engine::getResPaths() { + return paths.resPaths; } std::shared_ptr Engine::getScreen() { @@ -553,3 +446,7 @@ const CoreParameters& Engine::getCoreParameters() const { bool Engine::isHeadless() const { return params.headless; } + +ContentControl& Engine::getContentControl() { + return *content; +} diff --git a/src/engine/Engine.hpp b/src/engine/Engine.hpp index 8c046b66..9730336e 100644 --- a/src/engine/Engine.hpp +++ b/src/engine/Engine.hpp @@ -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; std::shared_ptr screen; std::vector contentPacks; - std::unique_ptr content; - std::unique_ptr resPaths; + std::unique_ptr content; std::unique_ptr controller; std::unique_ptr cmd; std::unique_ptr network; std::unique_ptr window; std::unique_ptr input; - std::vector basePacks; std::unique_ptr 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, int64_t localPlayer); void onWorldClosed(); @@ -159,8 +155,6 @@ public: std::vector getAllContentPacks(); - std::vector& getBasePacks(); - /// @brief Get current screen std::shared_ptr 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; } diff --git a/src/frontend/menu.cpp b/src/frontend/menu.cpp index bc5409a3..020e1fbd 100644 --- a/src/frontend/menu.cpp +++ b/src/frontend/menu.cpp @@ -74,7 +74,7 @@ UiDocument* menus::show( Engine& engine, const std::string& name, std::vector 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( diff --git a/src/graphics/render/Decorator.cpp b/src/graphics/render/Decorator.cpp index 1fd69dfc..dc928b4d 100644 --- a/src/graphics/render/Decorator.cpp +++ b/src/graphics/render/Decorator.cpp @@ -61,7 +61,7 @@ Decorator::Decorator( player->getPosition() )); } - playerNamePreset.deserialize(engine.getResPaths()->readCombinedObject( + playerNamePreset.deserialize(engine.getResPaths().readCombinedObject( "presets/text3d/player_name.toml" )); } diff --git a/src/io/engine_paths.cpp b/src/io/engine_paths.cpp index cccdf934..31f55d33 100644 --- a/src/io/engine_paths.cpp +++ b/src/io/engine_paths.cpp @@ -247,8 +247,8 @@ std::tuple EnginePaths::parsePath(std::string_view pat return {prefix, filename}; } -ResPaths::ResPaths(io::path mainRoot, std::vector roots) - : mainRoot(std::move(mainRoot)), roots(std::move(roots)) { +ResPaths::ResPaths(std::vector 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 ResPaths::collectRoots() { } return collected; } - -const io::path& ResPaths::getMainRoot() const { - return mainRoot; -} diff --git a/src/io/engine_paths.hpp b/src/io/engine_paths.hpp index a883fb98..70292923 100644 --- a/src/io/engine_paths.hpp +++ b/src/io/engine_paths.hpp @@ -19,8 +19,33 @@ struct PathsRoot { } }; +class ResPaths { +public: + ResPaths() = default; + + ResPaths(std::vector roots); + + io::path find(const std::string& filename) const; + std::string findRaw(const std::string& filename) const; + std::vector listdir(const std::string& folder) const; + std::vector 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 collectRoots(); +private: + std::vector 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 roots); - - io::path find(const std::string& filename) const; - std::string findRaw(const std::string& filename) const; - std::vector listdir(const std::string& folder) const; - std::vector 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 collectRoots(); - - const io::path& getMainRoot() const; - -private: - io::path mainRoot; - std::vector roots; -}; diff --git a/src/logic/EngineController.cpp b/src/logic/EngineController.cpp index ebd73cac..d09cd4b8 100644 --- a/src/logic/EngineController.cpp +++ b/src/logic/EngineController.cpp @@ -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()); diff --git a/src/logic/scripting/lua/libs/libaudio.cpp b/src/logic/scripting/lua/libs/libaudio.cpp index 2559f7ac..41362fe7 100644 --- a/src/logic/scripting/lua/libs/libaudio.cpp +++ b/src/logic/scripting/lua/libs/libaudio.cpp @@ -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, diff --git a/src/logic/scripting/lua/libs/libfile.cpp b/src/logic/scripting/lua/libs/libfile.cpp index 495ec1f8..546fe4d7 100644 --- a/src/logic/scripting/lua/libs/libfile.cpp +++ b/src/logic/scripting/lua/libs/libfile.cpp @@ -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) { diff --git a/src/logic/scripting/lua/libs/libgeneration.cpp b/src/logic/scripting/lua/libs/libgeneration.cpp index 3062e079..6829951d 100644 --- a/src/logic/scripting/lua/libs/libgeneration.cpp +++ b/src/logic/scripting/lua/libs/libgeneration.cpp @@ -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()); diff --git a/src/logic/scripting/lua/libs/libpack.cpp b/src/logic/scripting/lua/libs/libpack.cpp index 1e37a8c8..6ac07e22 100644 --- a/src/logic/scripting/lua/libs/libpack.cpp +++ b/src/logic/scripting/lua/libs/libpack.cpp @@ -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(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);