CPathManager

* Moved path management from CApplication to CPathManager
* Moved %lvl% replacements from CParserParam to CPathManager
* Added %lvl% support in produce(), closes #426
master
krzys-h 2015-03-08 15:22:21 +01:00
parent d99432e955
commit f54b46b61d
9 changed files with 270 additions and 107 deletions

View File

@ -72,6 +72,7 @@ set(BASE_SOURCES
common/iman.cpp common/iman.cpp
common/logger.cpp common/logger.cpp
common/misc.cpp common/misc.cpp
common/pathman.cpp
common/profile.cpp common/profile.cpp
common/restext.cpp common/restext.cpp
common/stringutils.cpp common/stringutils.cpp

View File

@ -29,6 +29,7 @@
#include "common/iman.h" #include "common/iman.h"
#include "common/image.h" #include "common/image.h"
#include "common/key.h" #include "common/key.h"
#include "common/pathman.h"
#include "common/stringutils.h" #include "common/stringutils.h"
#include "common/resources/resourcemanager.h" #include "common/resources/resourcemanager.h"
@ -104,6 +105,7 @@ CApplication::CApplication()
{ {
m_private = new ApplicationPrivate(); m_private = new ApplicationPrivate();
m_iMan = new CInstanceManager(); m_iMan = new CInstanceManager();
m_pathManager = new CPathManager();
m_objMan = new CObjectManager(); m_objMan = new CObjectManager();
m_eventQueue = new CEventQueue(); m_eventQueue = new CEventQueue();
m_profile = new CProfile(); m_profile = new CProfile();
@ -151,20 +153,6 @@ CApplication::CApplication()
m_mouseMode = MOUSE_SYSTEM; 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_runSceneName = "";
m_runSceneRank = 0; m_runSceneRank = 0;
@ -194,6 +182,9 @@ CApplication::~CApplication()
delete m_profile; delete m_profile;
m_profile = nullptr; m_profile = nullptr;
delete m_pathManager;
m_pathManager = nullptr;
delete m_iMan; delete m_iMan;
m_iMan = nullptr; m_iMan = nullptr;
@ -376,26 +367,25 @@ ParseArgsStatus CApplication::ParseArguments(int argc, char *argv[])
} }
case OPT_DATADIR: case OPT_DATADIR:
{ {
m_dataPath = optarg; m_pathManager->SetDataPath(optarg);
GetLogger()->Info("Using data dir: '%s'\n", optarg); GetLogger()->Info("Using data dir: '%s'\n", optarg);
break; break;
} }
case OPT_LANGDIR: case OPT_LANGDIR:
{ {
m_langPath = optarg; m_pathManager->SetLangPath(optarg);
GetLogger()->Info("Using language dir: '%s'\n", optarg); GetLogger()->Info("Using language dir: '%s'\n", optarg);
break; break;
} }
case OPT_SAVEDIR: case OPT_SAVEDIR:
{ {
m_savePath = optarg; m_pathManager->SetSavePath(optarg);
GetLogger()->Info("Using save dir: '%s'\n", optarg); GetLogger()->Info("Using save dir: '%s'\n", optarg);
break; break;
} }
case OPT_MOD: case OPT_MOD:
{ {
GetLogger()->Info("Loading mod: '%s'\n", optarg); m_pathManager->AddMod(optarg);
CResourceManager::AddLocation(optarg, true);
break; break;
} }
case OPT_RESOLUTION: case OPT_RESOLUTION:
@ -430,28 +420,12 @@ bool CApplication::Create()
GetLogger()->Info("Creating CApplication\n"); GetLogger()->Info("Creating CApplication\n");
boost::filesystem::path dataPath(m_dataPath); m_errorMessage = m_pathManager->VerifyPaths();
if (! (boost::filesystem::exists(dataPath) && boost::filesystem::is_directory(dataPath)) ) if(!m_errorMessage.empty()) {
{
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_exitCode = 1; m_exitCode = 1;
return false; return false;
} }
m_pathManager->InitPaths();
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);
if (!GetProfile().Init()) if (!GetProfile().Init())
{ {
@ -653,23 +627,6 @@ bool CApplication::CreateVideoSurface()
return true; 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() void CApplication::Destroy()
{ {
m_joystickEnabled = false; m_joystickEnabled = false;
@ -1712,7 +1669,7 @@ void CApplication::SetLanguage(Language language)
std::locale::global(std::locale(std::locale(""), "C", std::locale::numeric)); 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"); bind_textdomain_codeset("colobot", "UTF-8");
textdomain("colobot"); textdomain("colobot");

View File

@ -44,6 +44,7 @@ class CController;
class CSoundInterface; class CSoundInterface;
class CInput; class CInput;
class CObjectManager; class CObjectManager;
class CPathManager;
namespace Gfx { namespace Gfx {
class CModelManager; class CModelManager;
@ -328,9 +329,6 @@ protected:
//! Creates the window's SDL_Surface //! Creates the window's SDL_Surface
bool CreateVideoSurface(); bool CreateVideoSurface();
//! Loads all mods from given directory
void LoadModsFromDir(const std::string &dir);
//! Processes the captured SDL event to Event struct //! Processes the captured SDL event to Event struct
Event ProcessSystemEvent(); Event ProcessSystemEvent();
//! If applicable, creates a virtual event to match the changed state as of new event //! If applicable, creates a virtual event to match the changed state as of new event
@ -379,6 +377,8 @@ protected:
CProfile* m_profile; CProfile* m_profile;
//! Input manager //! Input manager
CInput* m_input; CInput* m_input;
//! Path manager
CPathManager* m_pathManager;
//! Code to return at exit //! Code to return at exit
int m_exitCode; int m_exitCode;
@ -436,15 +436,6 @@ protected:
//! Current state of joystick buttons; may be updated from another thread //! Current state of joystick buttons; may be updated from another thread
std::vector<bool> m_joyButtonState; std::vector<bool> 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 //! Scene to run on startup
std::string m_runSceneName; std::string m_runSceneName;

173
src/common/pathman.cpp Normal file
View File

@ -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 <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
template<> CPathManager* CSingleton<CPathManager>::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
}

69
src/common/pathman.h Normal file
View File

@ -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 <string>
/**
* \class CPathManager
* \brief Class for managing data/lang/save paths, and %something% replacements
*/
class CPathManager : public CSingleton<CPathManager>
{
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;
};

View File

@ -22,6 +22,7 @@
#include "app/app.h" #include "app/app.h"
#include "common/logger.h" #include "common/logger.h"
#include "common/pathman.h"
#include "common/resources/resourcemanager.h" #include "common/resources/resourcemanager.h"
#include "object/level/parser.h" #include "object/level/parser.h"
#include "object/robotmain.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) std::string CLevelParserParam::ToPath(std::string path, const std::string defaultDir)
{ {
if(defaultDir == "" && path.find("%lvl%") != std::string::npos) if(defaultDir == "" && path.find("%lvl%") != std::string::npos)
throw CLevelParserException("TODO: Param "+m_name+" does not yet support %lvl%! :("); 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) 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) std::string CLevelParserParam::AsPath(const std::string defaultDir, std::string def)
{ {
if(m_empty) if(m_empty)
return InjectLevelDir(def, defaultDir); return CPathManager::InjectLevelDir(def, defaultDir);
return ToPath(AsString(def), defaultDir); return ToPath(AsString(def), defaultDir);
} }

View File

@ -107,8 +107,6 @@ public:
std::string GetValue(); std::string GetValue();
bool IsDefined(); bool IsDefined();
static std::string InjectLevelDir(std::string path, const std::string defaultDir);
private: private:
void ParseArray(); void ParseArray();
void LoadArray(); void LoadArray();

View File

@ -22,6 +22,7 @@
#include "app/app.h" #include "app/app.h"
#include "common/pathman.h"
#include "common/resources/inputstream.h" #include "common/resources/inputstream.h"
#include "common/resources/resourcemanager.h" #include "common/resources/resourcemanager.h"
@ -1702,8 +1703,7 @@ bool CScriptFunctions::rProduce(CBotVar* var, CBotVar* result, int& exception, v
if (name[0] != 0) if (name[0] != 0)
{ {
//TODO: Add %lvl% support std::string name2 = CPathManager::InjectLevelDir(name, "ai");
std::string name2 = std::string("ai/")+name;
object->ReadProgram(0, name2.c_str()); object->ReadProgram(0, name2.c_str());
object->RunProgram(0); object->RunProgram(0);
} }

View File

@ -25,13 +25,12 @@
#include "clipboard/clipboard.h" #include "clipboard/clipboard.h"
#include "object/robotmain.h" #include "common/pathman.h"
#include "object/level/parserparam.h"
#include "common/resources/inputstream.h" #include "common/resources/inputstream.h"
#include "common/resources/outputstream.h" #include "common/resources/outputstream.h"
#include "object/robotmain.h"
#include <string.h> #include <string.h>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
@ -788,7 +787,7 @@ void CEdit::HyperJump(std::string name, std::string marker)
sMarker = marker; sMarker = marker;
filename = name + std::string(".txt"); 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 boost::replace_all(filename, "\\", "/"); //TODO: Fix this in files
if ( ReadText(filename) ) if ( ReadText(filename) )
@ -1144,7 +1143,7 @@ void CEdit::DrawImage(Math::Point pos, std::string name, float width,
std::string filename; std::string filename;
filename = name + ".png"; filename = name + ".png";
filename = CLevelParserParam::InjectLevelDir(filename, "icons"); filename = CPathManager::InjectLevelDir(filename, "icons");
boost::replace_all(filename, "\\", "/"); //TODO: Fix this in files boost::replace_all(filename, "\\", "/"); //TODO: Fix this in files
m_engine->SetTexture(filename); m_engine->SetTexture(filename);
@ -1434,7 +1433,7 @@ void CEdit::LoadImage(std::string name)
{ {
std::string filename; std::string filename;
filename = name + ".png"; filename = name + ".png";
filename = CLevelParserParam::InjectLevelDir(filename, "icons"); filename = CPathManager::InjectLevelDir(filename, "icons");
boost::replace_all(filename, "\\", "/"); //TODO: Fix this in files boost::replace_all(filename, "\\", "/"); //TODO: Fix this in files
m_engine->LoadTexture(filename); m_engine->LoadTexture(filename);
} }