From f54b46b61d5f4897289a87f0cacc170d1f38caca Mon Sep 17 00:00:00 2001 From: krzys-h Date: Sun, 8 Mar 2015 15:22:21 +0100 Subject: [PATCH] CPathManager * Moved path management from CApplication to CPathManager * Moved %lvl% replacements from CParserParam to CPathManager * Added %lvl% support in produce(), closes #426 --- src/CMakeLists.txt | 1 + src/app/app.cpp | 69 +++--------- src/app/app.h | 15 +-- src/common/pathman.cpp | 173 +++++++++++++++++++++++++++++++ src/common/pathman.h | 69 ++++++++++++ src/object/level/parserparam.cpp | 31 +----- src/object/level/parserparam.h | 2 - src/script/scriptfunc.cpp | 4 +- src/ui/edit.cpp | 13 ++- 9 files changed, 270 insertions(+), 107 deletions(-) create mode 100644 src/common/pathman.cpp create mode 100644 src/common/pathman.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a1e1c66a..a17df8f8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -72,6 +72,7 @@ set(BASE_SOURCES common/iman.cpp common/logger.cpp common/misc.cpp + common/pathman.cpp common/profile.cpp common/restext.cpp common/stringutils.cpp diff --git a/src/app/app.cpp b/src/app/app.cpp index d598c0e5..a5d17431 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -29,6 +29,7 @@ #include "common/iman.h" #include "common/image.h" #include "common/key.h" +#include "common/pathman.h" #include "common/stringutils.h" #include "common/resources/resourcemanager.h" @@ -104,6 +105,7 @@ CApplication::CApplication() { m_private = new ApplicationPrivate(); m_iMan = new CInstanceManager(); + m_pathManager = new CPathManager(); m_objMan = new CObjectManager(); m_eventQueue = new CEventQueue(); m_profile = new CProfile(); @@ -151,20 +153,6 @@ CApplication::CApplication() m_mouseMode = MOUSE_SYSTEM; - #ifdef PORTABLE - m_dataPath = "./data"; - m_langPath = "./lang"; - #else - m_dataPath = GetSystemUtils()->GetDataPath(); - m_langPath = GetSystemUtils()->GetLangPath(); - #endif - - #ifdef DEV_BUILD - m_savePath = "./saves"; - #else - m_savePath = GetSystemUtils()->GetSaveDir(); - #endif - m_runSceneName = ""; m_runSceneRank = 0; @@ -194,6 +182,9 @@ CApplication::~CApplication() delete m_profile; m_profile = nullptr; + delete m_pathManager; + m_pathManager = nullptr; + delete m_iMan; m_iMan = nullptr; @@ -376,26 +367,25 @@ ParseArgsStatus CApplication::ParseArguments(int argc, char *argv[]) } case OPT_DATADIR: { - m_dataPath = optarg; + m_pathManager->SetDataPath(optarg); GetLogger()->Info("Using data dir: '%s'\n", optarg); break; } case OPT_LANGDIR: { - m_langPath = optarg; + m_pathManager->SetLangPath(optarg); GetLogger()->Info("Using language dir: '%s'\n", optarg); break; } case OPT_SAVEDIR: { - m_savePath = optarg; + m_pathManager->SetSavePath(optarg); GetLogger()->Info("Using save dir: '%s'\n", optarg); break; } case OPT_MOD: { - GetLogger()->Info("Loading mod: '%s'\n", optarg); - CResourceManager::AddLocation(optarg, true); + m_pathManager->AddMod(optarg); break; } case OPT_RESOLUTION: @@ -430,28 +420,12 @@ bool CApplication::Create() GetLogger()->Info("Creating CApplication\n"); - boost::filesystem::path dataPath(m_dataPath); - if (! (boost::filesystem::exists(dataPath) && boost::filesystem::is_directory(dataPath)) ) - { - GetLogger()->Error("Data directory '%s' doesn't exist or is not a directory\n", m_dataPath.c_str()); - m_errorMessage = 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."); + m_errorMessage = m_pathManager->VerifyPaths(); + if(!m_errorMessage.empty()) { m_exitCode = 1; return false; } - - boost::filesystem::create_directories(m_savePath); - boost::filesystem::create_directories(m_savePath+"/mods"); - - 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); - CResourceManager::SetSaveLocation(m_savePath); - CResourceManager::AddLocation(m_savePath, true); + m_pathManager->InitPaths(); if (!GetProfile().Init()) { @@ -653,23 +627,6 @@ bool CApplication::CreateVideoSurface() return true; } -void CApplication::LoadModsFromDir(const std::string &dir) -{ - try { - boost::filesystem::directory_iterator iterator(dir); - for(; iterator != boost::filesystem::directory_iterator(); ++iterator) - { - std::string fn = iterator->path().string(); - CLogger::GetInstancePointer()->Info("Loading mod: '%s'\n", fn.c_str()); - CResourceManager::AddLocation(fn, false); - } - } - catch(std::exception &e) - { - CLogger::GetInstancePointer()->Warn("Unable to load mods from directory '%s': %s\n", dir.c_str(), e.what()); - } -} - void CApplication::Destroy() { m_joystickEnabled = false; @@ -1712,7 +1669,7 @@ void CApplication::SetLanguage(Language language) std::locale::global(std::locale(std::locale(""), "C", std::locale::numeric)); - bindtextdomain("colobot", m_langPath.c_str()); + bindtextdomain("colobot", m_pathManager->GetLangPath().c_str()); bind_textdomain_codeset("colobot", "UTF-8"); textdomain("colobot"); diff --git a/src/app/app.h b/src/app/app.h index 818eaf46..d8a1e1d9 100644 --- a/src/app/app.h +++ b/src/app/app.h @@ -44,6 +44,7 @@ class CController; class CSoundInterface; class CInput; class CObjectManager; +class CPathManager; namespace Gfx { class CModelManager; @@ -327,9 +328,6 @@ public: protected: //! Creates the window's SDL_Surface bool CreateVideoSurface(); - - //! Loads all mods from given directory - void LoadModsFromDir(const std::string &dir); //! Processes the captured SDL event to Event struct Event ProcessSystemEvent(); @@ -379,6 +377,8 @@ protected: CProfile* m_profile; //! Input manager CInput* m_input; + //! Path manager + CPathManager* m_pathManager; //! Code to return at exit int m_exitCode; @@ -435,15 +435,6 @@ protected: std::vector m_joyAxeState; //! Current state of joystick buttons; may be updated from another thread std::vector m_joyButtonState; - - //! Path to directory with data files - std::string m_dataPath; - - //! Path to directory with language files - std::string m_langPath; - - //! Path to directory with save files - std::string m_savePath; //@{ //! Scene to run on startup diff --git a/src/common/pathman.cpp b/src/common/pathman.cpp new file mode 100644 index 00000000..ccf61ab5 --- /dev/null +++ b/src/common/pathman.cpp @@ -0,0 +1,173 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2014, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsiteс.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + + +#include "common/pathman.h" + + +#include "app/app.h" +#include "app/system.h" + +#include "common/config.h" +#include "common/logger.h" +#include "common/resources/resourcemanager.h" + +#include "object/robotmain.h" + +#include "object/level/parser.h" + +#include +#include + +template<> CPathManager* CSingleton::m_instance = nullptr; + +CPathManager::CPathManager() +{ + #ifdef PORTABLE + m_dataPath = "./data"; + m_langPath = "./lang"; + m_savePath = "./saves"; + #else + m_dataPath = GetSystemUtils()->GetDataPath(); + m_langPath = GetSystemUtils()->GetLangPath(); + #ifdef DEV_BUILD + m_savePath = "./saves"; + #else + m_savePath = GetSystemUtils()->GetSaveDir(); + #endif + #endif +} + +CPathManager::~CPathManager() +{ +} + +void CPathManager::SetDataPath(std::string dataPath) +{ + m_dataPath = dataPath; +} + +void CPathManager::SetLangPath(std::string langPath) +{ + m_langPath = langPath; +} + +void CPathManager::SetSavePath(std::string savePath) +{ + m_savePath = savePath; +} + +void CPathManager::AddMod(std::string modPath) +{ + CLogger::GetInstancePointer()->Info("Loading mod: '%s'\n", modPath.c_str()); + CResourceManager::AddLocation(modPath, true); +} + +const std::string& CPathManager::GetDataPath() +{ + return m_dataPath; +} + +const std::string& CPathManager::GetLangPath() +{ + return m_langPath; +} + +const std::string& CPathManager::GetSavePath() +{ + return m_savePath; +} + +std::string CPathManager::VerifyPaths() +{ + boost::filesystem::path dataPath(m_dataPath); + if (! (boost::filesystem::exists(dataPath) && boost::filesystem::is_directory(dataPath)) ) + { + CLogger::GetInstancePointer()->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."); + } + + boost::filesystem::path langPath(m_langPath); + if (! (boost::filesystem::exists(langPath) && boost::filesystem::is_directory(langPath)) ) + { + CLogger::GetInstancePointer()->Warn("Language path '%s' is invalid, assuming translation files not installed\n", m_langPath.c_str()); + } + + boost::filesystem::create_directories(m_savePath); + boost::filesystem::create_directories(m_savePath+"/mods"); + + return ""; +} + +void CPathManager::InitPaths() +{ + LoadModsFromDir(m_dataPath+"/mods"); + LoadModsFromDir(m_savePath+"/mods"); + + CLogger::GetInstancePointer()->Info("Data path: %s\n", m_dataPath.c_str()); + CLogger::GetInstancePointer()->Info("Save path: %s\n", m_savePath.c_str()); + CResourceManager::AddLocation(m_dataPath, false); + CResourceManager::SetSaveLocation(m_savePath); + CResourceManager::AddLocation(m_savePath, true); +} + +void CPathManager::LoadModsFromDir(const std::string &dir) +{ + try { + boost::filesystem::directory_iterator iterator(dir); + for(; iterator != boost::filesystem::directory_iterator(); ++iterator) + { + AddMod(iterator->path().string()); + } + } + catch(std::exception &e) + { + CLogger::GetInstancePointer()->Warn("Unable to load mods from directory '%s': %s\n", dir.c_str(), e.what()); + } +} + +std::string CPathManager::InjectLevelDir(std::string path, const std::string& defaultDir) +{ + std::string newPath = path; + std::string lvlDir = CLevelParser::BuildSceneName(CRobotMain::GetInstancePointer()->GetSceneName(), CRobotMain::GetInstancePointer()->GetSceneRank()/100, CRobotMain::GetInstancePointer()->GetSceneRank()%100, false); + boost::replace_all(newPath, "%lvl%", lvlDir); + std::string chapDir = CLevelParser::BuildSceneName(CRobotMain::GetInstancePointer()->GetSceneName(), CRobotMain::GetInstancePointer()->GetSceneRank()/100, 0, false); + boost::replace_all(newPath, "%chap%", chapDir); + if(newPath == path && !path.empty()) + { + newPath = defaultDir + (!defaultDir.empty() ? "/" : "") + newPath; + } + + //TODO: %cat% + + std::string langPath = newPath; + std::string langStr(1, CApplication::GetInstancePointer()->GetLanguageChar()); + boost::replace_all(langPath, "%lng%", langStr); + if(CResourceManager::Exists(langPath)) + return langPath; + + // Fallback to English if file doesn't exist + boost::replace_all(newPath, "%lng%", "E"); + if(CResourceManager::Exists(newPath)) + return newPath; + + return langPath; // Return current language file if none of the files exist +} \ No newline at end of file diff --git a/src/common/pathman.h b/src/common/pathman.h new file mode 100644 index 00000000..6ddeda0d --- /dev/null +++ b/src/common/pathman.h @@ -0,0 +1,69 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2014, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsiteс.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +/** + * \file common/pathman.h + * \brief Class for managing data/lang/save paths, and %something% replacements + */ + +#pragma once + +#include "common/singleton.h" + +#include + +/** + * \class CPathManager + * \brief Class for managing data/lang/save paths, and %something% replacements + */ +class CPathManager : public CSingleton +{ +public: + CPathManager(); + ~CPathManager(); + + void SetDataPath(std::string dataPath); + void SetLangPath(std::string langPath); + void SetSavePath(std::string savePath); + void AddMod(std::string modPath); + + const std::string& GetDataPath(); + const std::string& GetLangPath(); + const std::string& GetSavePath(); + + //! Checks if paths are configured correctly + std::string VerifyPaths(); + //! Loads configured paths + void InitPaths(); + + //! Does the %lvl%, %chap%, %cat% and %lng% replacements (with fallback to English when translations are not available) + static std::string InjectLevelDir(std::string path, const std::string& defaultDir = ""); + +private: + //! Loads all mods from given directory + void LoadModsFromDir(const std::string &dir); + +private: + //! Data path + std::string m_dataPath; + //! Lang path + std::string m_langPath; + //! Save path + std::string m_savePath; +}; \ No newline at end of file diff --git a/src/object/level/parserparam.cpp b/src/object/level/parserparam.cpp index a6393623..8d4adfc5 100644 --- a/src/object/level/parserparam.cpp +++ b/src/object/level/parserparam.cpp @@ -22,6 +22,7 @@ #include "app/app.h" #include "common/logger.h" +#include "common/pathman.h" #include "common/resources/resourcemanager.h" #include "object/level/parser.h" #include "object/robotmain.h" @@ -164,38 +165,12 @@ bool CLevelParserParam::AsBool(bool def) } -std::string CLevelParserParam::InjectLevelDir(std::string path, const std::string defaultDir) -{ - std::string newPath = path; - std::string lvlDir = CLevelParser::BuildSceneName(CRobotMain::GetInstancePointer()->GetSceneName(), CRobotMain::GetInstancePointer()->GetSceneRank()/100, CRobotMain::GetInstancePointer()->GetSceneRank()%100, false); - boost::replace_all(newPath, "%lvl%", lvlDir); - std::string chapDir = CLevelParser::BuildSceneName(CRobotMain::GetInstancePointer()->GetSceneName(), CRobotMain::GetInstancePointer()->GetSceneRank()/100, 0, false); - boost::replace_all(newPath, "%chap%", chapDir); - if(newPath == path && !path.empty()) - { - newPath = defaultDir + (!defaultDir.empty() ? "/" : "") + newPath; - } - - std::string langPath = newPath; - std::string langStr(1, CApplication::GetInstancePointer()->GetLanguageChar()); - boost::replace_all(langPath, "%lng%", langStr); - if(CResourceManager::Exists(langPath)) - return langPath; - - // Fallback to English if file doesn't exist - boost::replace_all(newPath, "%lng%", "E"); - if(CResourceManager::Exists(newPath)) - return newPath; - - return langPath; // Return current language file if none of the files exist -} - std::string CLevelParserParam::ToPath(std::string path, const std::string defaultDir) { if(defaultDir == "" && path.find("%lvl%") != std::string::npos) throw CLevelParserException("TODO: Param "+m_name+" does not yet support %lvl%! :("); - return InjectLevelDir(path, defaultDir); + return CPathManager::InjectLevelDir(path, defaultDir); } std::string CLevelParserParam::AsPath(const std::string defaultDir) @@ -209,7 +184,7 @@ std::string CLevelParserParam::AsPath(const std::string defaultDir) std::string CLevelParserParam::AsPath(const std::string defaultDir, std::string def) { if(m_empty) - return InjectLevelDir(def, defaultDir); + return CPathManager::InjectLevelDir(def, defaultDir); return ToPath(AsString(def), defaultDir); } diff --git a/src/object/level/parserparam.h b/src/object/level/parserparam.h index 0ef350fb..9421f291 100644 --- a/src/object/level/parserparam.h +++ b/src/object/level/parserparam.h @@ -107,8 +107,6 @@ public: std::string GetValue(); bool IsDefined(); - static std::string InjectLevelDir(std::string path, const std::string defaultDir); - private: void ParseArray(); void LoadArray(); diff --git a/src/script/scriptfunc.cpp b/src/script/scriptfunc.cpp index 666539be..23996506 100644 --- a/src/script/scriptfunc.cpp +++ b/src/script/scriptfunc.cpp @@ -22,6 +22,7 @@ #include "app/app.h" +#include "common/pathman.h" #include "common/resources/inputstream.h" #include "common/resources/resourcemanager.h" @@ -1702,8 +1703,7 @@ bool CScriptFunctions::rProduce(CBotVar* var, CBotVar* result, int& exception, v if (name[0] != 0) { - //TODO: Add %lvl% support - std::string name2 = std::string("ai/")+name; + std::string name2 = CPathManager::InjectLevelDir(name, "ai"); object->ReadProgram(0, name2.c_str()); object->RunProgram(0); } diff --git a/src/ui/edit.cpp b/src/ui/edit.cpp index 1b745610..59ddef9b 100644 --- a/src/ui/edit.cpp +++ b/src/ui/edit.cpp @@ -25,13 +25,12 @@ #include "clipboard/clipboard.h" -#include "object/robotmain.h" - -#include "object/level/parserparam.h" - +#include "common/pathman.h" #include "common/resources/inputstream.h" #include "common/resources/outputstream.h" +#include "object/robotmain.h" + #include #include @@ -788,7 +787,7 @@ void CEdit::HyperJump(std::string name, std::string marker) sMarker = marker; filename = name + std::string(".txt"); - filename = CLevelParserParam::InjectLevelDir(filename, "help/%lng%"); + filename = CPathManager::InjectLevelDir(filename, "help/%lng%"); boost::replace_all(filename, "\\", "/"); //TODO: Fix this in files if ( ReadText(filename) ) @@ -1144,7 +1143,7 @@ void CEdit::DrawImage(Math::Point pos, std::string name, float width, std::string filename; filename = name + ".png"; - filename = CLevelParserParam::InjectLevelDir(filename, "icons"); + filename = CPathManager::InjectLevelDir(filename, "icons"); boost::replace_all(filename, "\\", "/"); //TODO: Fix this in files m_engine->SetTexture(filename); @@ -1434,7 +1433,7 @@ void CEdit::LoadImage(std::string name) { std::string filename; filename = name + ".png"; - filename = CLevelParserParam::InjectLevelDir(filename, "icons"); + filename = CPathManager::InjectLevelDir(filename, "icons"); boost::replace_all(filename, "\\", "/"); //TODO: Fix this in files m_engine->LoadTexture(filename); }