diff --git a/src/content/ContentPack.cpp b/src/content/ContentPack.cpp index f4890e8f..0a81970e 100644 --- a/src/content/ContentPack.cpp +++ b/src/content/ContentPack.cpp @@ -128,11 +128,11 @@ fs::path ContentPack::findPack( if (fs::is_directory(folder)) { return folder; } - folder = paths->getUserfiles() / fs::path("content") / fs::path(name); + folder = paths->getUserFilesFolder() / fs::path("content") / fs::path(name); if (fs::is_directory(folder)) { return folder; } - return paths->getResources() / fs::path("content") / fs::path(name); + return paths->getResourcesFolder() / fs::path("content") / fs::path(name); } ContentPackRuntime::ContentPackRuntime(ContentPack info, scriptenv env) diff --git a/src/core_defs.cpp b/src/core_defs.cpp index 0fd648b9..1c00d0c7 100644 --- a/src/core_defs.cpp +++ b/src/core_defs.cpp @@ -25,7 +25,7 @@ void corecontent::setup(EnginePaths* paths, ContentBuilder* builder) { ItemDef& item = builder->items.create("core:empty"); item.iconType = item_icon_type::none; - auto bindsFile = paths->getResources()/fs::path("bindings.toml"); + auto bindsFile = paths->getResourcesFolder()/fs::path("bindings.toml"); if (fs::is_regular_file(bindsFile)) { Events::loadBindings( bindsFile.u8string(), files::read_string(bindsFile) diff --git a/src/engine.cpp b/src/engine.cpp index 7bbff33b..b00294ed 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -83,7 +83,7 @@ Engine::Engine(EngineSettings& settings, SettingsHandler& settingsHandler, Engin paths->prepare(); loadSettings(); - auto resdir = paths->getResources(); + auto resdir = paths->getResourcesFolder(); controller = std::make_unique(this); if (Window::initialize(&this->settings.display)){ @@ -105,7 +105,7 @@ Engine::Engine(EngineSettings& settings, SettingsHandler& settingsHandler, Engin if (settings.ui.language.get() == "auto") { settings.ui.language.set(langs::locale_by_envlocale( platform::detect_locale(), - paths->getResources() + paths->getResourcesFolder() )); } if (ENGINE_DEBUG_BUILD) { @@ -162,7 +162,7 @@ void Engine::updateHotkeys() { void Engine::saveScreenshot() { auto image = Window::takeScreenshot(); image->flipY(); - fs::path filename = paths->getScreenshotFile("png"); + fs::path filename = paths->getNewScreenshotFile("png"); imageio::write(filename.string(), image.get()); logger.info() << "saved screenshot as " << filename.u8string(); } @@ -252,8 +252,8 @@ PacksManager Engine::createPacksManager(const fs::path& worldFolder) { PacksManager manager; manager.setSources({ worldFolder/fs::path("content"), - paths->getUserfiles()/fs::path("content"), - paths->getResources()/fs::path("content") + paths->getUserFilesFolder()/fs::path("content"), + paths->getResourcesFolder()/fs::path("content") }); return manager; } @@ -296,7 +296,7 @@ static void load_configs(const fs::path& root) { } void Engine::loadContent() { - auto resdir = paths->getResources(); + auto resdir = paths->getResourcesFolder(); std::vector names; for (auto& pack : contentPacks) { @@ -307,7 +307,7 @@ void Engine::loadContent() { corecontent::setup(paths, &contentBuilder); paths->setContentPacks(&contentPacks); - PacksManager manager = createPacksManager(paths->getWorldFolder()); + PacksManager manager = createPacksManager(paths->getCurrentWorldFolder()); manager.scan(); names = manager.assembly(names); contentPacks = manager.getAll(names); @@ -318,7 +318,7 @@ void Engine::loadContent() { ContentLoader(&pack, contentBuilder).load(); load_configs(pack.folder); } - load_configs(paths->getResources()); + load_configs(paths->getResourcesFolder()); content = contentBuilder.build(); resPaths = std::make_unique(resdir, resRoots); @@ -329,7 +329,7 @@ void Engine::loadContent() { } void Engine::resetContent() { - auto resdir = paths->getResources(); + auto resdir = paths->getResourcesFolder(); resPaths = std::make_unique(resdir, std::vector()); contentPacks.clear(); content.reset(); @@ -349,17 +349,17 @@ void Engine::loadWorldContent(const fs::path& folder) { PacksManager manager; manager.setSources({ folder/fs::path("content"), - paths->getUserfiles()/fs::path("content"), - paths->getResources()/fs::path("content") + paths->getUserFilesFolder()/fs::path("content"), + paths->getResourcesFolder()/fs::path("content") }); manager.scan(); contentPacks = manager.getAll(manager.assembly(packNames)); - paths->setWorldFolder(folder); + paths->setCurrentWorldFolder(folder); loadContent(); } void Engine::loadAllPacks() { - PacksManager manager = createPacksManager(paths->getWorldFolder()); + PacksManager manager = createPacksManager(paths->getCurrentWorldFolder()); manager.scan(); auto allnames = manager.getAllNames(); contentPacks = manager.getAll(manager.assembly(allnames)); @@ -376,7 +376,7 @@ void Engine::setScreen(std::shared_ptr screen) { } void Engine::setLanguage(std::string locale) { - langs::setup(paths->getResources(), std::move(locale), contentPacks); + langs::setup(paths->getResourcesFolder(), std::move(locale), contentPacks); gui->getMenu()->setPageLoader(menus::create_page_loader(this)); } diff --git a/src/files/engine_paths.cpp b/src/files/engine_paths.cpp index e4917e82..3fa66637 100644 --- a/src/files/engine_paths.cpp +++ b/src/files/engine_paths.cpp @@ -5,33 +5,80 @@ #include #include #include +#include #include #include #include "WorldFiles.hpp" -const fs::path SCREENSHOTS_FOLDER {"screenshots"}; -const fs::path CONTENT_FOLDER {"content"}; -const fs::path CONTROLS_FILE {"controls.toml"}; -const fs::path SETTINGS_FILE {"settings.toml"}; +/** + * @brief ENUM for accessing folder and file names + */ +enum F_F_NAME{ + SCREENSHOTS_FOLDER, + CONTENT_FOLDER, + CONTROLS_FILE, + SETTINGS_FILE, + + COUNT +}; + +/** + * @brief array for get file or folder name by enum `F_F_NAME` + * + * example: + * `std::filesystem::path settings = f_f_names[SETTINGS_FILE];` + */ +static std::array f_f_names{ + "screenshots", + "content", + "controls.toml", + "settings.toml" +}; + +static std::filesystem::path toCanonic(std::filesystem::path path) { + std::stack parts; + path = path.lexically_normal(); + do { + parts.push(path.filename().u8string()); + path = path.parent_path(); + } while (!path.empty()); + + path = fs::u8path(""); + + while (!parts.empty()) { + const std::string part = parts.top(); + parts.pop(); + if (part == ".") { + continue; + } + if (part == "..") { + throw files_access_error("entry point reached"); + } + + path = path / std::filesystem::path(part); + } + return path; +} + void EnginePaths::prepare() { - fs::path contentFolder = userfiles / fs::path(CONTENT_FOLDER); + std::filesystem::path contentFolder = userFilesFolder / std::filesystem::path(f_f_names[CONTENT_FOLDER]); if (!fs::is_directory(contentFolder)) { fs::create_directories(contentFolder); } } -fs::path EnginePaths::getUserfiles() const { - return userfiles; +std::filesystem::path EnginePaths::getUserFilesFolder() const { + return userFilesFolder; } -fs::path EnginePaths::getResources() const { - return resources; +std::filesystem::path EnginePaths::getResourcesFolder() const { + return resourcesFolder; } -fs::path EnginePaths::getScreenshotFile(const std::string& ext) { - fs::path folder = userfiles / fs::path(SCREENSHOTS_FOLDER); +std::filesystem::path EnginePaths::getNewScreenshotFile(const std::string& ext) { + std::filesystem::path folder = userFilesFolder / std::filesystem::path(f_f_names[SCREENSHOTS_FOLDER]); if (!fs::is_directory(folder)) { fs::create_directory(folder); } @@ -44,7 +91,7 @@ fs::path EnginePaths::getScreenshotFile(const std::string& ext) { ss << std::put_time(&tm, format); std::string datetimestr = ss.str(); - fs::path filename = + std::filesystem::path filename = folder / fs::u8path("screenshot-" + datetimestr + "." + ext); uint index = 0; while (fs::exists(filename)) { @@ -57,44 +104,44 @@ fs::path EnginePaths::getScreenshotFile(const std::string& ext) { return filename; } -fs::path EnginePaths::getWorldsFolder() { - return userfiles / fs::path("worlds"); +std::filesystem::path EnginePaths::getWorldsFolder() { + return userFilesFolder / std::filesystem::path("worlds"); } -fs::path EnginePaths::getWorldFolder() { - return worldFolder; +std::filesystem::path EnginePaths::getCurrentWorldFolder() { + return currentWorldFolder; } -fs::path EnginePaths::getWorldFolder(const std::string& name) { - return getWorldsFolder() / fs::path(name); +std::filesystem::path EnginePaths::getWorldFolderByName(const std::string& name) { + return getWorldsFolder() / std::filesystem::path(name); } -fs::path EnginePaths::getControlsFile() { - return userfiles / fs::path(CONTROLS_FILE); +std::filesystem::path EnginePaths::getControlsFile() { + return userFilesFolder / std::filesystem::path(f_f_names[CONTROLS_FILE]); } -fs::path EnginePaths::getSettingsFile() { - return userfiles / fs::path(SETTINGS_FILE); +std::filesystem::path EnginePaths::getSettingsFile() { + return userFilesFolder / std::filesystem::path(f_f_names[SETTINGS_FILE]); } -std::vector EnginePaths::scanForWorlds() { - std::vector folders; +std::vector EnginePaths::scanForWorlds() { + std::vector folders; - fs::path folder = getWorldsFolder(); + std::filesystem::path folder = getWorldsFolder(); if (!fs::is_directory(folder)) return folders; for (const auto& entry : fs::directory_iterator(folder)) { if (!entry.is_directory()) { continue; } - const fs::path& worldFolder = entry.path(); - fs::path worldFile = worldFolder / fs::u8path(WorldFiles::WORLD_FILE); + const std::filesystem::path& worldFolder = entry.path(); + std::filesystem::path worldFile = worldFolder / fs::u8path(WorldFiles::WORLD_FILE); if (!fs::is_regular_file(worldFile)) { continue; } folders.push_back(worldFolder); } - std::sort(folders.begin(), folders.end(), [](fs::path a, fs::path b) { + std::sort(folders.begin(), folders.end(), [](std::filesystem::path a, std::filesystem::path b) { a = a / fs::u8path(WorldFiles::WORLD_FILE); b = b / fs::u8path(WorldFiles::WORLD_FILE); return fs::last_write_time(a) > fs::last_write_time(b); @@ -102,51 +149,23 @@ std::vector EnginePaths::scanForWorlds() { return folders; } -bool EnginePaths::isWorldNameUsed(const std::string& name) { - return fs::exists(EnginePaths::getWorldsFolder() / fs::u8path(name)); +void EnginePaths::setUserFilesFolder(std::filesystem::path folder) { + this->userFilesFolder = std::move(folder); } -void EnginePaths::setUserfiles(fs::path folder) { - this->userfiles = std::move(folder); +void EnginePaths::setResourcesFolder(std::filesystem::path folder) { + this->resourcesFolder = std::move(folder); } -void EnginePaths::setResources(fs::path folder) { - this->resources = std::move(folder); -} - -void EnginePaths::setWorldFolder(fs::path folder) { - this->worldFolder = std::move(folder); +void EnginePaths::setCurrentWorldFolder(std::filesystem::path folder) { + this->currentWorldFolder = std::move(folder); } void EnginePaths::setContentPacks(std::vector* contentPacks) { this->contentPacks = contentPacks; } -static fs::path toCanonic(fs::path path) { - std::stack parts; - path = path.lexically_normal(); - while (true) { - parts.push(path.filename().u8string()); - path = path.parent_path(); - if (path.empty()) break; - } - path = fs::u8path(""); - while (!parts.empty()) { - const std::string part = parts.top(); - parts.pop(); - if (part == ".") { - continue; - } - if (part == "..") { - throw files_access_error("entry point reached"); - } - - path = path / fs::path(part); - } - return path; -} - -fs::path EnginePaths::resolve(const std::string& path, bool throwErr) { +std::filesystem::path EnginePaths::resolve(const std::string& path, bool throwErr) { size_t separator = path.find(':'); if (separator == std::string::npos) { throw files_access_error("no entry point specified"); @@ -156,13 +175,13 @@ fs::path EnginePaths::resolve(const std::string& path, bool throwErr) { filename = toCanonic(fs::u8path(filename)).u8string(); if (prefix == "res" || prefix == "core") { - return resources / fs::u8path(filename); + return resourcesFolder / fs::u8path(filename); } if (prefix == "user") { - return userfiles / fs::u8path(filename); + return userFilesFolder / fs::u8path(filename); } if (prefix == "world") { - return worldFolder / fs::u8path(filename); + return currentWorldFolder / fs::u8path(filename); } if (contentPacks) { @@ -175,17 +194,18 @@ fs::path EnginePaths::resolve(const std::string& path, bool throwErr) { if (throwErr) { throw files_access_error("unknown entry point '" + prefix + "'"); } - return fs::path(filename); + return std::filesystem::path(filename); } -ResPaths::ResPaths(fs::path mainRoot, std::vector roots) + +ResPaths::ResPaths(std::filesystem::path mainRoot, std::vector roots) : mainRoot(std::move(mainRoot)), roots(std::move(roots)) { } -fs::path ResPaths::find(const std::string& filename) const { +std::filesystem::path ResPaths::find(const std::string& filename) const { for (int i = roots.size() - 1; i >= 0; i--) { auto& root = roots[i]; - fs::path file = root.path / fs::u8path(filename); + std::filesystem::path file = root.path / fs::u8path(filename); if (fs::exists(file)) { return file; } @@ -196,12 +216,12 @@ fs::path ResPaths::find(const std::string& filename) const { std::string ResPaths::findRaw(const std::string& filename) const { for (int i = roots.size() - 1; i >= 0; i--) { auto& root = roots[i]; - if (fs::exists(root.path / fs::path(filename))) { + if (fs::exists(root.path / std::filesystem::path(filename))) { return root.name + ":" + filename; } } auto resDir = mainRoot; - if (fs::exists(resDir / fs::path(filename))) { + if (fs::exists(resDir / std::filesystem::path(filename))) { return "core:" + filename; } throw std::runtime_error("could not to find file " + util::quote(filename)); @@ -212,7 +232,7 @@ std::vector ResPaths::listdirRaw(const std::string& folderName std::vector entries; for (int i = roots.size() - 1; i >= 0; i--) { auto& root = roots[i]; - fs::path folder = root.path / fs::u8path(folderName); + std::filesystem::path folder = root.path / fs::u8path(folderName); if (!fs::is_directory(folder)) continue; for (const auto& entry : fs::directory_iterator(folder)) { auto name = entry.path().filename().u8string(); @@ -220,7 +240,7 @@ std::vector ResPaths::listdirRaw(const std::string& folderName } } { - fs::path folder = mainRoot / fs::u8path(folderName); + std::filesystem::path folder = mainRoot / fs::u8path(folderName); if (!fs::is_directory(folder)) return entries; for (const auto& entry : fs::directory_iterator(folder)) { auto name = entry.path().filename().u8string(); @@ -230,18 +250,18 @@ std::vector ResPaths::listdirRaw(const std::string& folderName return entries; } -std::vector ResPaths::listdir(const std::string& folderName) const { - std::vector entries; +std::vector ResPaths::listdir(const std::string& folderName) const { + std::vector entries; for (int i = roots.size() - 1; i >= 0; i--) { auto& root = roots[i]; - fs::path folder = root.path / fs::u8path(folderName); + std::filesystem::path folder = root.path / fs::u8path(folderName); if (!fs::is_directory(folder)) continue; for (const auto& entry : fs::directory_iterator(folder)) { entries.push_back(entry.path()); } } { - fs::path folder = mainRoot / fs::u8path(folderName); + std::filesystem::path folder = mainRoot / fs::u8path(folderName); if (!fs::is_directory(folder)) return entries; for (const auto& entry : fs::directory_iterator(folder)) { entries.push_back(entry.path()); @@ -250,6 +270,6 @@ std::vector ResPaths::listdir(const std::string& folderName) const { return entries; } -const fs::path& ResPaths::getMainRoot() const { +const std::filesystem::path& ResPaths::getMainRoot() const { return mainRoot; } diff --git a/src/files/engine_paths.hpp b/src/files/engine_paths.hpp index 56956d53..a32e7fad 100644 --- a/src/files/engine_paths.hpp +++ b/src/files/engine_paths.hpp @@ -8,7 +8,6 @@ #include -namespace fs = std::filesystem; class files_access_error : public std::runtime_error { public: @@ -17,51 +16,57 @@ public: }; class EnginePaths { - fs::path userfiles {"."}; - fs::path resources {"res"}; - fs::path worldFolder; - std::vector* contentPacks = nullptr; public: void prepare(); - fs::path getUserfiles() const; - fs::path getResources() const; + void setUserFilesFolder(std::filesystem::path folder); + std::filesystem::path getUserFilesFolder() const; - fs::path getScreenshotFile(const std::string& ext); - fs::path getWorldsFolder(); - fs::path getWorldFolder(); - fs::path getWorldFolder(const std::string& name); - fs::path getControlsFile(); - fs::path getSettingsFile(); - bool isWorldNameUsed(const std::string& name); + void setResourcesFolder(std::filesystem::path folder); + std::filesystem::path getResourcesFolder() const; + + std::filesystem::path getWorldsFolder(); + std::filesystem::path getWorldFolderByName(const std::string& name); + + void setCurrentWorldFolder(std::filesystem::path folder); + std::filesystem::path getCurrentWorldFolder(); + + std::filesystem::path getNewScreenshotFile(const std::string& ext); + std::filesystem::path getControlsFile(); + std::filesystem::path getSettingsFile(); - void setUserfiles(fs::path folder); - void setResources(fs::path folder); void setContentPacks(std::vector* contentPacks); - void setWorldFolder(fs::path folder); - std::vector scanForWorlds(); + std::vector scanForWorlds(); - fs::path resolve(const std::string& path, bool throwErr = true); + std::filesystem::path resolve(const std::string& path, bool throwErr = true); + +private: + std::filesystem::path userFilesFolder {"."}; + std::filesystem::path resourcesFolder {"res"}; + std::filesystem::path currentWorldFolder; + std::vector* contentPacks = nullptr; }; struct PathsRoot { std::string name; - fs::path path; + std::filesystem::path path; }; class ResPaths { - fs::path mainRoot; - std::vector roots; public: - ResPaths(fs::path mainRoot, std::vector roots); + ResPaths(std::filesystem::path mainRoot, std::vector roots); - fs::path find(const std::string& filename) const; + std::filesystem::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 listdir(const std::string& folder) const; std::vector listdirRaw(const std::string& folder) const; - const fs::path& getMainRoot() const; + const std::filesystem::path& getMainRoot() const; + +private: + std::filesystem::path mainRoot; + std::vector roots; }; #endif // FILES_ENGINE_PATHS_HPP_ diff --git a/src/frontend/screens/LevelScreen.cpp b/src/frontend/screens/LevelScreen.cpp index c6a20036..21eb8855 100644 --- a/src/frontend/screens/LevelScreen.cpp +++ b/src/frontend/screens/LevelScreen.cpp @@ -79,7 +79,7 @@ LevelScreen::~LevelScreen() { saveWorldPreview(); scripting::on_frontend_close(); controller->onWorldQuit(); - engine->getPaths()->setWorldFolder(fs::path()); + engine->getPaths()->setCurrentWorldFolder(fs::path()); } void LevelScreen::saveWorldPreview() { diff --git a/src/logic/EngineController.cpp b/src/logic/EngineController.cpp index 0017aa29..5d000a1e 100644 --- a/src/logic/EngineController.cpp +++ b/src/logic/EngineController.cpp @@ -30,7 +30,7 @@ EngineController::EngineController(Engine* engine) : engine(engine) { } void EngineController::deleteWorld(const std::string& name) { - fs::path folder = engine->getPaths()->getWorldFolder(name); + fs::path folder = engine->getPaths()->getWorldFolderByName(name); guiutil::confirm( engine->getGUI(), langs::get(L"delete-confirm", L"world") + L" (" + @@ -189,7 +189,7 @@ void EngineController::createWorld( if (!menus::call(engine, [this, paths, folder]() { engine->loadContent(); - paths->setWorldFolder(folder); + paths->setCurrentWorldFolder(folder); })) { return; } diff --git a/src/logic/scripting/lua/libpack.cpp b/src/logic/scripting/lua/libpack.cpp index 5c9d26c1..108ac196 100644 --- a/src/logic/scripting/lua/libpack.cpp +++ b/src/logic/scripting/lua/libpack.cpp @@ -17,7 +17,7 @@ using namespace scripting; static int l_pack_get_folder(lua::State* L) { std::string packName = lua::tostring(L, 1); if (packName == "core") { - auto folder = engine->getPaths()->getResources().u8string() + "/"; + auto folder = engine->getPaths()->getResourcesFolder().u8string() + "/"; return lua::pushstring(L, folder); } for (auto& pack : engine->getContentPacks()) { diff --git a/src/logic/scripting/lua/libworld.cpp b/src/logic/scripting/lua/libworld.cpp index 4300aec6..0581f71a 100644 --- a/src/logic/scripting/lua/libworld.cpp +++ b/src/logic/scripting/lua/libworld.cpp @@ -71,7 +71,7 @@ static int l_world_get_seed(lua::State* L) { static int l_world_exists(lua::State* L) { auto name = lua::require_string(L, 1); - auto worldsDir = engine->getPaths()->getWorldFolder(name); + auto worldsDir = engine->getPaths()->getWorldFolderByName(name); return lua::pushboolean(L, fs::is_directory(worldsDir)); } diff --git a/src/logic/scripting/scripting.cpp b/src/logic/scripting/scripting.cpp index 5d3b95c0..27c66535 100644 --- a/src/logic/scripting/scripting.cpp +++ b/src/logic/scripting/scripting.cpp @@ -38,7 +38,7 @@ LevelController* scripting::controller = nullptr; static void load_script(const fs::path& name, bool throwable) { auto paths = scripting::engine->getPaths(); - fs::path file = paths->getResources() / fs::path("scripts") / name; + fs::path file = paths->getResourcesFolder() / fs::path("scripts") / name; std::string src = files::read_string(file); auto L = lua::get_main_thread(); diff --git a/src/util/command_line.cpp b/src/util/command_line.cpp index 9485e6f8..f64789a4 100644 --- a/src/util/command_line.cpp +++ b/src/util/command_line.cpp @@ -48,14 +48,14 @@ bool perform_keyword( if (!fs::is_directory(fs::path(token))) { throw std::runtime_error(token + " is not a directory"); } - paths.setResources(fs::path(token)); + paths.setResourcesFolder(fs::path(token)); std::cout << "resources folder: " << token << std::endl; } else if (keyword == "--dir") { auto token = reader.next(); if (!fs::is_directory(fs::path(token))) { fs::create_directories(fs::path(token)); } - paths.setUserfiles(fs::path(token)); + paths.setUserFilesFolder(fs::path(token)); std::cout << "userfiles folder: " << token << std::endl; } else if (keyword == "--help" || keyword == "-h") { std::cout << "VoxelEngine command-line arguments:" << std::endl;