From 073191d1eaaa0a82923ebf936e7ce2b388ebdf9c Mon Sep 17 00:00:00 2001 From: krzys-h Date: Wed, 16 May 2018 13:28:06 +0200 Subject: [PATCH] Small CPathManager refactoring --- CMakeLists.txt | 31 ++++---- src/app/pathman.cpp | 90 ++++++++++++++++-------- src/app/pathman.h | 26 ++++--- src/common/config.h.cmake | 2 +- src/common/resources/resourcemanager.cpp | 10 +++ src/common/resources/resourcemanager.h | 4 ++ src/common/system/system.cpp | 2 +- src/common/system/system_linux.cpp | 7 +- src/common/system/system_macosx.cpp | 5 ++ src/common/system/system_windows.cpp | 7 +- 10 files changed, 120 insertions(+), 64 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ab7f22a..9b96d6b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -201,6 +201,9 @@ option(OFFICIAL_BUILD "Official build (changes crash screen text)" OFF) # Portable build - load all data from current directory option(PORTABLE "Portable build" OFF) +# Portable saves - suitable for e.g. putting the whole game on external storage and moving your saves with it +option(PORTABLE_SAVES "Portable saves" OFF) + # Building tests can be enabled/disabled option(TESTS "Build tests" OFF) @@ -350,21 +353,19 @@ endif() ## # Installation paths defined before compiling sources -if(PLATFORM_WINDOWS) - if(MXE) - # We need to use STRING because PATH doesn't accept relative paths - set(COLOBOT_INSTALL_BIN_DIR ./ CACHE STRING "Colobot binary directory") - set(COLOBOT_INSTALL_LIB_DIR ./ CACHE STRING "Colobot libraries directory") - set(COLOBOT_INSTALL_DATA_DIR ./data CACHE STRING "Colobot shared data directory") - set(COLOBOT_INSTALL_I18N_DIR ./lang CACHE STRING "Colobot translations directory") - set(COLOBOT_INSTALL_DOC_DIR ./doc CACHE STRING "Colobot documentation directory") - else() - set(COLOBOT_INSTALL_BIN_DIR ${CMAKE_INSTALL_PREFIX}/ CACHE PATH "Colobot binary directory") - set(COLOBOT_INSTALL_LIB_DIR ${CMAKE_INSTALL_PREFIX}/ CACHE PATH "Colobot libraries directory") - set(COLOBOT_INSTALL_DATA_DIR ${CMAKE_INSTALL_PREFIX}/data CACHE PATH "Colobot shared data directory") - set(COLOBOT_INSTALL_I18N_DIR ${CMAKE_INSTALL_PREFIX}/lang CACHE PATH "Colobot translations directory") - set(COLOBOT_INSTALL_DOC_DIR ${CMAKE_INSTALL_PREFIX}/doc CACHE PATH "Colobot documentation directory") - endif() +if(PORTABLE OR (PLATFORM_WINDOWS AND MXE)) + # We need to use STRING because PATH doesn't accept relative paths + set(COLOBOT_INSTALL_BIN_DIR ./ CACHE STRING "Colobot binary directory") + set(COLOBOT_INSTALL_LIB_DIR ./ CACHE STRING "Colobot libraries directory") + set(COLOBOT_INSTALL_DATA_DIR ./data CACHE STRING "Colobot shared data directory") + set(COLOBOT_INSTALL_I18N_DIR ./lang CACHE STRING "Colobot translations directory") + set(COLOBOT_INSTALL_DOC_DIR ./doc CACHE STRING "Colobot documentation directory") +elseif(PLATFORM_WINDOWS) + set(COLOBOT_INSTALL_BIN_DIR ${CMAKE_INSTALL_PREFIX}/ CACHE PATH "Colobot binary directory") + set(COLOBOT_INSTALL_LIB_DIR ${CMAKE_INSTALL_PREFIX}/ CACHE PATH "Colobot libraries directory") + set(COLOBOT_INSTALL_DATA_DIR ${CMAKE_INSTALL_PREFIX}/data CACHE PATH "Colobot shared data directory") + set(COLOBOT_INSTALL_I18N_DIR ${CMAKE_INSTALL_PREFIX}/lang CACHE PATH "Colobot translations directory") + set(COLOBOT_INSTALL_DOC_DIR ${CMAKE_INSTALL_PREFIX}/doc CACHE PATH "Colobot documentation directory") elseif(PLATFORM_MACOSX) set(COLOBOT_INSTALL_BIN_DIR ../MacOS CACHE STRING "Colobot binary directory") set(COLOBOT_INSTALL_LIB_DIR ../MacOS CACHE STRING "Colobot libraries directory") diff --git a/src/app/pathman.cpp b/src/app/pathman.cpp index e86780e5..60715ac1 100644 --- a/src/app/pathman.cpp +++ b/src/app/pathman.cpp @@ -38,46 +38,41 @@ #include CPathManager::CPathManager(CSystemUtils* systemUtils) - : m_systemUtils(systemUtils) + : m_dataPath(systemUtils->GetDataPath()) + , m_langPath(systemUtils->GetLangPath()) + , m_savePath(systemUtils->GetSaveDir()) + , m_modAutoloadDir{ m_dataPath + "/mods", m_savePath + "/mods" } + , m_mods{} { - #ifdef PORTABLE - m_dataPath = "./data"; - m_langPath = "./lang"; - m_savePath = "./saves"; - #else - m_dataPath = m_systemUtils->GetDataPath(); - m_langPath = m_systemUtils->GetLangPath(); - #ifdef DEV_BUILD - m_savePath = "./saves"; - #else - m_savePath = m_systemUtils->GetSaveDir(); - #endif - #endif } CPathManager::~CPathManager() { } -void CPathManager::SetDataPath(std::string dataPath) +void CPathManager::SetDataPath(const std::string &dataPath) { m_dataPath = dataPath; } -void CPathManager::SetLangPath(std::string langPath) +void CPathManager::SetLangPath(const std::string &langPath) { m_langPath = langPath; } -void CPathManager::SetSavePath(std::string savePath) +void CPathManager::SetSavePath(const std::string &savePath) { m_savePath = savePath; } -void CPathManager::AddMod(std::string modPath) +void CPathManager::AddModAutoloadDir(const std::string &modAutoloadDirPath) { - GetLogger()->Info("Loading mod: '%s'\n", modPath.c_str()); - CResourceManager::AddLocation(modPath, true); + m_modAutoloadDir.push_back(modAutoloadDirPath); +} + +void CPathManager::AddMod(const std::string &modPath) +{ + m_mods.push_back(modPath); } const std::string& CPathManager::GetDataPath() @@ -106,8 +101,8 @@ std::string CPathManager::VerifyPaths() { GetLogger()->Error("Data directory '%s' doesn't exist or is not a directory\n", m_dataPath.c_str()); return std::string("Could not read from data directory:\n") + - std::string("'") + m_dataPath + std::string("'\n") + - std::string("Please check your installation, or supply a valid data directory by -datadir option."); + std::string("'") + m_dataPath + std::string("'\n") + + std::string("Please check your installation, or supply a valid data directory by -datadir option."); } #if PLATFORM_WINDOWS @@ -133,19 +128,51 @@ std::string CPathManager::VerifyPaths() void CPathManager::InitPaths() { - LoadModsFromDir(m_dataPath+"/mods"); - LoadModsFromDir(m_savePath+"/mods"); - GetLogger()->Info("Data path: %s\n", m_dataPath.c_str()); GetLogger()->Info("Save path: %s\n", m_savePath.c_str()); - CResourceManager::AddLocation(m_dataPath, false); + if (!m_modAutoloadDir.empty()) + { + GetLogger()->Info("Mod autoload dirs:\n"); + for(const std::string& modAutoloadDir : m_modAutoloadDir) + GetLogger()->Info(" * %s\n", modAutoloadDir.c_str()); + } + if (!m_mods.empty()) + { + GetLogger()->Info("Mods:\n"); + for(const std::string& modPath : m_mods) + GetLogger()->Info(" * %s\n", modPath.c_str()); + } + + CResourceManager::AddLocation(m_dataPath); + + for (const std::string& modAutoloadDir : m_modAutoloadDir) + { + GetLogger()->Trace("Searching for mods in '%s'...\n", modAutoloadDir.c_str()); + for (const std::string& modPath : FindModsInDir(modAutoloadDir)) + { + GetLogger()->Info("Autoloading mod: '%s'\n", modPath.c_str()); + CResourceManager::AddLocation(modPath); + } + } + + for (const std::string& modPath : m_mods) + { + GetLogger()->Info("Loading mod: '%s'\n", modPath.c_str()); + CResourceManager::AddLocation(modPath); + } + CResourceManager::SetSaveLocation(m_savePath); - CResourceManager::AddLocation(m_savePath, true); + CResourceManager::AddLocation(m_savePath); + + GetLogger()->Debug("Finished initalizing data paths\n"); + GetLogger()->Debug("PHYSFS search path is:\n"); + for (const std::string& path : CResourceManager::GetLocations()) + GetLogger()->Debug(" * %s\n", path.c_str()); } -void CPathManager::LoadModsFromDir(const std::string &dir) +std::vector CPathManager::FindModsInDir(const std::string &dir) { - GetLogger()->Trace("Looking for mods in '%s' ...\n", dir.c_str()); + std::vector ret; try { #if PLATFORM_WINDOWS @@ -156,9 +183,9 @@ void CPathManager::LoadModsFromDir(const std::string &dir) for(; iterator != boost::filesystem::directory_iterator(); ++iterator) { #if PLATFORM_WINDOWS - AddMod(CSystemUtilsWindows::UTF8_Encode(iterator->path().wstring())); + ret.push_back(CSystemUtilsWindows::UTF8_Encode(iterator->path().wstring())); #else - AddMod(iterator->path().string()); + ret.push_back(iterator->path().string()); #endif } } @@ -166,4 +193,5 @@ void CPathManager::LoadModsFromDir(const std::string &dir) { GetLogger()->Warn("Unable to load mods from directory '%s': %s\n", dir.c_str(), e.what()); } + return ret; } diff --git a/src/app/pathman.h b/src/app/pathman.h index 39c780df..dd18d66e 100644 --- a/src/app/pathman.h +++ b/src/app/pathman.h @@ -17,16 +17,10 @@ * along with this program. If not, see http://gnu.org/licenses */ -/** - * \file app/pathman.h - * \brief Class for managing data/lang/save paths - */ - #pragma once -#include "common/singleton.h" - #include +#include class CSystemUtils; @@ -34,16 +28,17 @@ class CSystemUtils; * \class CPathManager * \brief Class for managing data/lang/save paths */ -class CPathManager : public CSingleton +class CPathManager { public: CPathManager(CSystemUtils* systemUtils); ~CPathManager(); - void SetDataPath(std::string dataPath); - void SetLangPath(std::string langPath); - void SetSavePath(std::string savePath); - void AddMod(std::string modPath); + void SetDataPath(const std::string &dataPath); + void SetLangPath(const std::string &langPath); + void SetSavePath(const std::string &savePath); + void AddModAutoloadDir(const std::string &modAutoloadDirPath); + void AddMod(const std::string &modPath); const std::string& GetDataPath(); const std::string& GetLangPath(); @@ -56,14 +51,17 @@ public: private: //! Loads all mods from given directory - void LoadModsFromDir(const std::string &dir); + std::vector FindModsInDir(const std::string &dir); private: - CSystemUtils* m_systemUtils; //! Data path std::string m_dataPath; //! Lang path std::string m_langPath; //! Save path std::string m_savePath; + //! Mod autoload paths + std::vector m_modAutoloadDir; + //! Mod paths + std::vector m_mods; }; diff --git a/src/common/config.h.cmake b/src/common/config.h.cmake index b4767724..f6d0bcae 100644 --- a/src/common/config.h.cmake +++ b/src/common/config.h.cmake @@ -16,7 +16,7 @@ #cmakedefine OPENAL_SOUND -#cmakedefine PORTABLE @PORTABLE@ +#cmakedefine PORTABLE_SAVES @PORTABLE_SAVES@ #define COLOBOT_DEFAULT_DATADIR "@COLOBOT_INSTALL_DATA_DIR@" #define COLOBOT_I18N_DIR "@COLOBOT_INSTALL_I18N_DIR@" diff --git a/src/common/resources/resourcemanager.cpp b/src/common/resources/resourcemanager.cpp index 820495b8..0ad82816 100644 --- a/src/common/resources/resourcemanager.cpp +++ b/src/common/resources/resourcemanager.cpp @@ -85,6 +85,16 @@ bool CResourceManager::RemoveLocation(const std::string &location) return true; } +std::vector CResourceManager::GetLocations() +{ + std::vector ret; + char **list = PHYSFS_getSearchPath(); + for (char **it = list; *it != nullptr; ++it) + ret.push_back(*it); + PHYSFS_freeList(list); + return ret; +} + bool CResourceManager::SetSaveLocation(const std::string &location) { diff --git a/src/common/resources/resourcemanager.h b/src/common/resources/resourcemanager.h index d0b4ab24..95661a4f 100644 --- a/src/common/resources/resourcemanager.h +++ b/src/common/resources/resourcemanager.h @@ -35,8 +35,12 @@ public: static std::string CleanPath(const std::string &path); + //! Add a location to the search path static bool AddLocation(const std::string &location, bool prepend = true); + //! Remove a location from the search path static bool RemoveLocation(const std::string &location); + //! List all locations in the search path + static std::vector GetLocations(); static bool SetSaveLocation(const std::string &location); static std::string GetSaveLocation(); diff --git a/src/common/system/system.cpp b/src/common/system/system.cpp index 01b633cc..44064556 100644 --- a/src/common/system/system.cpp +++ b/src/common/system/system.cpp @@ -190,5 +190,5 @@ std::string CSystemUtils::GetLangPath() std::string CSystemUtils::GetSaveDir() { - return std::string("saves"); + return "./saves"; } diff --git a/src/common/system/system_linux.cpp b/src/common/system/system_linux.cpp index 3cd25ed2..6578830d 100644 --- a/src/common/system/system_linux.cpp +++ b/src/common/system/system_linux.cpp @@ -96,6 +96,9 @@ long long CSystemUtilsLinux::TimeStampExactDiff(SystemTimeStamp *before, SystemT std::string CSystemUtilsLinux::GetSaveDir() { +#if PORTABLE_SAVES || DEV_BUILD + return CSystemUtils::GetSaveDir(); +#else std::string savegameDir; // Determine savegame dir according to XDG Base Directory Specification @@ -105,7 +108,8 @@ std::string CSystemUtilsLinux::GetSaveDir() char *envHOME = getenv("HOME"); if (envHOME == nullptr) { - savegameDir = "/tmp/colobot-save"; + GetLogger()->Warn("Unable to find directory for saves - using current directory"); + savegameDir = "./saves"; } else { @@ -119,6 +123,7 @@ std::string CSystemUtilsLinux::GetSaveDir() GetLogger()->Trace("Saved game files are going to %s\n", savegameDir.c_str()); return savegameDir; +#endif } void CSystemUtilsLinux::Usleep(int usec) diff --git a/src/common/system/system_macosx.cpp b/src/common/system/system_macosx.cpp index ede5b481..9ef7ce1d 100644 --- a/src/common/system/system_macosx.cpp +++ b/src/common/system/system_macosx.cpp @@ -102,10 +102,15 @@ std::string CSystemUtilsMacOSX::GetLangPath() std::string CSystemUtilsMacOSX::GetSaveDir() { +#if PORTABLE_SAVES || DEV_BUILD + // TODO: I have no idea if this actually works on Mac OS + return "./saves"; +#else std::string savegameDir = m_ASPath; GetLogger()->Trace("Saved game files are going to %s\n", savegameDir.c_str()); return savegameDir; +#endif } void CSystemUtilsMacOSX::Usleep(int usec) diff --git a/src/common/system/system_windows.cpp b/src/common/system/system_windows.cpp index f51959b4..e459cf00 100644 --- a/src/common/system/system_windows.cpp +++ b/src/common/system/system_windows.cpp @@ -110,12 +110,16 @@ std::wstring CSystemUtilsWindows::UTF8_Decode(const std::string& str) std::string CSystemUtilsWindows::GetSaveDir() { +#if PORTABLE_SAVES || DEV_BUILD + return "./saves"; +#else std::string savegameDir; wchar_t* envUSERPROFILE = _wgetenv(L"USERPROFILE"); if (envUSERPROFILE == nullptr) { - savegameDir = "./saves"; + GetLogger()->Warn("Unable to find directory for saves - using current directory"); + savegameDir = CSystemUtils::GetSaveDir(false); } else { @@ -124,6 +128,7 @@ std::string CSystemUtilsWindows::GetSaveDir() GetLogger()->Trace("Saved game files are going to %s\n", savegameDir.c_str()); return savegameDir; +#endif } void CSystemUtilsWindows::Usleep(int usec)