Refactor the mod manager

Moved list of mods logic to a new CModManager class.

The list of enabled mods is now managed by a flag instead of directory
names of mods.

Mods are now disabled by default.

Also general cleanup, fixing issues from the code review in
https://github.com/colobot/colobot/pull/1191 and fixing linter issues.

Regression: the state of enabled/disabled mods is now not persistent.
The plan is to use some kind of config file for this.
pyro-refactor
MrSimbax 2020-07-18 14:30:50 +02:00
parent 5f76722ecb
commit 8390d85e46
13 changed files with 320 additions and 177 deletions

View File

@ -145,6 +145,8 @@ set(BASE_SOURCES
app/controller.h app/controller.h
app/input.cpp app/input.cpp
app/input.h app/input.h
app/modman.cpp
app/modman.h
app/pathman.cpp app/pathman.cpp
app/pathman.h app/pathman.h
app/pausemanager.cpp app/pausemanager.cpp

View File

@ -21,6 +21,7 @@
#include "app/controller.h" #include "app/controller.h"
#include "app/input.h" #include "app/input.h"
#include "app/modman.h"
#include "app/pathman.h" #include "app/pathman.h"
#include "common/config_file.h" #include "common/config_file.h"
@ -113,7 +114,8 @@ CApplication::CApplication(CSystemUtils* systemUtils)
m_private(MakeUnique<ApplicationPrivate>()), m_private(MakeUnique<ApplicationPrivate>()),
m_configFile(MakeUnique<CConfigFile>()), m_configFile(MakeUnique<CConfigFile>()),
m_input(MakeUnique<CInput>()), m_input(MakeUnique<CInput>()),
m_pathManager(MakeUnique<CPathManager>(systemUtils)) m_pathManager(MakeUnique<CPathManager>(systemUtils)),
m_modManager(MakeUnique<CModManager>(this, m_pathManager.get()))
{ {
m_exitCode = 0; m_exitCode = 0;
m_active = false; m_active = false;
@ -220,6 +222,11 @@ CSoundInterface* CApplication::GetSound()
return m_sound.get(); return m_sound.get();
} }
CModManager* CApplication::GetModManager()
{
return m_modManager.get();
}
void CApplication::LoadEnvironmentVariables() void CApplication::LoadEnvironmentVariables()
{ {
auto dataDir = m_systemUtils->GetEnvVar("COLOBOT_DATA_DIR"); auto dataDir = m_systemUtils->GetEnvVar("COLOBOT_DATA_DIR");
@ -513,6 +520,8 @@ bool CApplication::Create()
GetLogger()->Warn("Config could not be loaded. Default values will be used!\n"); GetLogger()->Warn("Config could not be loaded. Default values will be used!\n");
} }
m_modManager->ReinitMods();
// Create the sound instance. // Create the sound instance.
#ifdef OPENAL_SOUND #ifdef OPENAL_SOUND
if (!m_headless) if (!m_headless)
@ -698,21 +707,7 @@ bool CApplication::Create()
// Create the robot application. // Create the robot application.
m_controller = MakeUnique<CController>(); m_controller = MakeUnique<CController>();
CThread musicLoadThread([this]() StartLoadingMusic();
{
GetLogger()->Debug("Cache sounds...\n");
SystemTimeStamp* musicLoadStart = m_systemUtils->CreateTimeStamp();
m_systemUtils->GetCurrentTimeStamp(musicLoadStart);
m_sound->CacheAll();
SystemTimeStamp* musicLoadEnd = m_systemUtils->CreateTimeStamp();
m_systemUtils->GetCurrentTimeStamp(musicLoadEnd);
float musicLoadTime = m_systemUtils->TimeStampDiff(musicLoadStart, musicLoadEnd, STU_MSEC);
GetLogger()->Debug("Sound loading took %.2f ms\n", musicLoadTime);
},
"Sound loading thread");
musicLoadThread.Start();
if (m_runSceneCategory == LevelCategory::Max) if (m_runSceneCategory == LevelCategory::Max)
m_controller->StartApp(); m_controller->StartApp();
@ -726,22 +721,11 @@ bool CApplication::Create()
return true; return true;
} }
void CApplication::Reload() void CApplication::ReloadResources()
{ {
m_sound->Create(); GetLogger()->Info("Reloading resources\n");
m_engine->ReloadAllTextures(); m_engine->ReloadAllTextures();
CThread musicLoadThread([this]() StartLoadingMusic();
{
SystemTimeStamp* musicLoadStart = m_systemUtils->CreateTimeStamp();
m_systemUtils->GetCurrentTimeStamp(musicLoadStart);
m_sound->CacheAll();
SystemTimeStamp* musicLoadEnd = m_systemUtils->CreateTimeStamp();
m_systemUtils->GetCurrentTimeStamp(musicLoadEnd);
float musicLoadTime = m_systemUtils->TimeStampDiff(musicLoadStart, musicLoadEnd, STU_MSEC);
GetLogger()->Debug("Sound loading took %.2f ms\n", musicLoadTime);
},
"Sound loading thread");
musicLoadThread.Start();
m_controller->GetRobotMain()->UpdateCustomLevelList(); m_controller->GetRobotMain()->UpdateCustomLevelList();
} }
@ -1559,6 +1543,24 @@ void CApplication::InternalResumeSimulation()
m_absTimeBase = m_exactAbsTime; m_absTimeBase = m_exactAbsTime;
} }
void CApplication::StartLoadingMusic()
{
CThread musicLoadThread([this]()
{
GetLogger()->Debug("Cache sounds...\n");
SystemTimeStamp* musicLoadStart = m_systemUtils->CreateTimeStamp();
m_systemUtils->GetCurrentTimeStamp(musicLoadStart);
m_sound->CacheAll();
SystemTimeStamp* musicLoadEnd = m_systemUtils->CreateTimeStamp();
m_systemUtils->GetCurrentTimeStamp(musicLoadEnd);
float musicLoadTime = m_systemUtils->TimeStampDiff(musicLoadStart, musicLoadEnd, STU_MSEC);
GetLogger()->Debug("Sound loading took %.2f ms\n", musicLoadTime);
}, "Sound loading thread");
musicLoadThread.Start();
}
bool CApplication::GetSimulationSuspended() const bool CApplication::GetSimulationSuspended() const
{ {
return m_simulationSuspended; return m_simulationSuspended;

View File

@ -42,6 +42,7 @@ class CEventQueue;
class CController; class CController;
class CSoundInterface; class CSoundInterface;
class CInput; class CInput;
class CModManager;
class CPathManager; class CPathManager;
class CConfigFile; class CConfigFile;
class CSystemUtils; class CSystemUtils;
@ -162,6 +163,8 @@ public:
CEventQueue* GetEventQueue(); CEventQueue* GetEventQueue();
//! Returns the sound subsystem //! Returns the sound subsystem
CSoundInterface* GetSound(); CSoundInterface* GetSound();
//! Returns the mod manager
CModManager* GetModManager();
public: public:
//! Loads some data from environment variables //! Loads some data from environment variables
@ -170,8 +173,8 @@ public:
ParseArgsStatus ParseArguments(int argc, char *argv[]); ParseArgsStatus ParseArguments(int argc, char *argv[]);
//! Initializes the application //! Initializes the application
bool Create(); bool Create();
//! Reloads the application //! Reloads the application resources, e.g. mods
void Reload(); void ReloadResources();
//! Main event loop //! Main event loop
int Run(); int Run();
//! Returns the code to be returned at main() exit //! Returns the code to be returned at main() exit
@ -303,6 +306,9 @@ protected:
//! Internal procedure to reset time counters //! Internal procedure to reset time counters
void InternalResumeSimulation(); void InternalResumeSimulation();
//! Loads music in a new thread
void StartLoadingMusic();
protected: protected:
//! System utils instance //! System utils instance
CSystemUtils* m_systemUtils; CSystemUtils* m_systemUtils;
@ -324,6 +330,8 @@ protected:
std::unique_ptr<CInput> m_input; std::unique_ptr<CInput> m_input;
//! Path manager //! Path manager
std::unique_ptr<CPathManager> m_pathManager; std::unique_ptr<CPathManager> m_pathManager;
//! Mod manager
std::unique_ptr<CModManager> m_modManager;
//! Code to return at exit //! Code to return at exit
int m_exitCode; int m_exitCode;

117
src/app/modman.cpp Normal file
View File

@ -0,0 +1,117 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.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 "modman.h"
//TODO: clean up includes
#include "common/config.h"
#include "app/app.h"
#include "app/pathman.h"
#include "common/restext.h"
#include "common/logger.h"
#include "common/settings.h"
#include "common/stringutils.h"
#include "common/resources/resourcemanager.h"
#include "common/system/system.h"
#include <algorithm>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
using namespace boost::filesystem;
CModManager::CModManager(CApplication* app, CPathManager* pathManager)
: m_app{app},
m_pathManager{pathManager}
{
}
void CModManager::ReinitMods()
{
m_mods.clear();
const auto foundMods = m_pathManager->FindMods();
for (const auto& modPath : foundMods)
{
Mod mod;
mod.name = boost::filesystem::path(modPath).stem().string();
mod.path = modPath;
mod.enabled = m_pathManager->ModLoaded(mod.path); //TODO: load from some config file
m_mods.push_back(mod);
}
}
void CModManager::EnableMod(const std::string& modName)
{
Mod* mod = FindMod(modName);
if (!mod)
{
GetLogger()->Error("Could not enable mod: %s not found\n", modName.c_str());
return;
}
mod->enabled = true;
}
void CModManager::DisableMod(const std::string& modName)
{
Mod* mod = FindMod(modName);
if (!mod)
{
GetLogger()->Error("Could not disable mod: %s not found\n", modName.c_str());
return;
}
mod->enabled = false;
}
void CModManager::ReloadMods()
{
for (const auto& mod : m_mods)
{
bool loaded = m_pathManager->ModLoaded(mod.path);
if (mod.enabled && !loaded)
{
m_pathManager->AddMod(mod.path);
}
else if (!mod.enabled && loaded)
{
m_pathManager->RemoveMod(mod.path);
}
}
m_app->ReloadResources();
}
boost::optional<Mod> CModManager::GetMod(const std::string& modName)
{
Mod* mod = FindMod(modName);
return mod != nullptr ? *mod : boost::optional<Mod>();
}
const std::vector<Mod>& CModManager::GetMods() const
{
return m_mods;
}
Mod* CModManager::FindMod(const std::string& modName)
{
auto it = std::find_if(m_mods.begin(), m_mods.end(), [&](Mod& mod) { return mod.name == modName; });
return it != m_mods.end() ? &(*it) : nullptr;
}

75
src/app/modman.h Normal file
View File

@ -0,0 +1,75 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.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
*/
#pragma once
#include "ui/maindialog.h"
#include "ui/screen/screen_setup.h"
#include <unordered_map>
#include <boost/optional.hpp>
class CPathManager;
struct Mod
{
std::string name;
std::string path;
bool enabled = false;
//TODO: add metadata for UI
};
/**
* \class CApplication
* \brief Main application
*
* This class handles the list of currently loaded mods.
*
*/
class CModManager
{
public:
CModManager(CApplication* app, CPathManager* pathManager);
//! Finds all the mods along with their metadata
void ReinitMods();
//! Removes a mod from the list of loaded mods
void EnableMod(const std::string& modName);
//! Adds a mod to the list of loaded mods
void DisableMod(const std::string& modName);
//! Reloads application resources so the enabled mods are applied
void ReloadMods();
boost::optional<Mod> GetMod(const std::string& modName);
const std::vector<Mod>& GetMods() const;
private:
Mod* FindMod(const std::string& modName);
private:
CApplication* m_app;
CPathManager* m_pathManager;
//TODO: better data structure?
std::vector<Mod> m_mods;
};

View File

@ -41,8 +41,7 @@ CPathManager::CPathManager(CSystemUtils* systemUtils)
: m_dataPath(systemUtils->GetDataPath()) : m_dataPath(systemUtils->GetDataPath())
, m_langPath(systemUtils->GetLangPath()) , m_langPath(systemUtils->GetLangPath())
, m_savePath(systemUtils->GetSaveDir()) , m_savePath(systemUtils->GetSaveDir())
, m_modAutoloadDir{} , m_modSearchDirs{}
, m_mods{}
{ {
} }
@ -65,35 +64,41 @@ void CPathManager::SetSavePath(const std::string &savePath)
m_savePath = savePath; m_savePath = savePath;
} }
void CPathManager::AddModAutoloadDir(const std::string &modAutoloadDirPath) void CPathManager::AddModSearchDir(const std::string &modSearchDirPath)
{ {
m_modAutoloadDir.push_back(modAutoloadDirPath); m_modSearchDirs.push_back(modSearchDirPath);
} }
void CPathManager::AddMod(const std::string &modPath) void CPathManager::AddMod(const std::string &modPath)
{ {
std::string::size_type enabled; GetLogger()->Info("Loading mod: '%s'\n", modPath.c_str());
enabled = modPath.find('~'); CResourceManager::AddLocation(modPath, true);
if (enabled == std::string::npos)
{
GetLogger()->Info("Loading mod: '%s'\n", modPath.c_str());
CResourceManager::AddLocation(modPath, true);
}
else
{
GetLogger()->Info("Found excluded mod: '%s'\n", modPath.c_str());
}
} }
void CPathManager::RemoveMod(const std::string &modPath) void CPathManager::RemoveMod(const std::string &modPath)
{ {
std::string::size_type enabled; GetLogger()->Info("Unloading mod: '%s'\n", modPath.c_str());
enabled = modPath.find('~'); CResourceManager::RemoveLocation(modPath);
if (enabled == std::string::npos) }
bool CPathManager::ModLoaded(const std::string& modPath)
{
return CResourceManager::LocationExists(modPath);
}
std::vector<std::string> CPathManager::FindMods() const
{
std::vector<std::string> mods;
GetLogger()->Info("Found mods:\n");
for (const auto &searchPath : m_modSearchDirs)
{ {
GetLogger()->Info("Unloading mod: '%s'\n", modPath.c_str()); for (const auto &modPath : FindModsInDir(searchPath))
CResourceManager::RemoveLocation(modPath); {
GetLogger()->Info(" * %s\n", modPath.c_str());
mods.push_back(modPath);
}
} }
return mods;
} }
const std::string& CPathManager::GetDataPath() const std::string& CPathManager::GetDataPath()
@ -152,58 +157,18 @@ void CPathManager::InitPaths()
GetLogger()->Info("Data path: %s\n", m_dataPath.c_str()); GetLogger()->Info("Data path: %s\n", m_dataPath.c_str());
GetLogger()->Info("Save path: %s\n", m_savePath.c_str()); GetLogger()->Info("Save path: %s\n", m_savePath.c_str());
m_modAutoloadDir.push_back(m_dataPath + "/mods"); m_modSearchDirs.push_back(m_dataPath + "/mods");
m_modAutoloadDir.push_back(m_savePath + "/mods"); m_modSearchDirs.push_back(m_savePath + "/mods");
if (!m_modAutoloadDir.empty()) if (!m_modSearchDirs.empty())
{ {
GetLogger()->Info("Mod autoload dirs:\n"); GetLogger()->Info("Mod search dirs:\n");
for(const std::string& modAutoloadDir : m_modAutoloadDir) for(const std::string& modSearchDir : m_modSearchDirs)
GetLogger()->Info(" * %s\n", modAutoloadDir.c_str()); GetLogger()->Info(" * %s\n", modSearchDir.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); 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))
{
std::string::size_type enabled;
enabled = modPath.find('~');
if (enabled == std::string::npos)
{
GetLogger()->Info("Autoloading mod: '%s'\n", modPath.c_str());
CResourceManager::AddLocation(modPath);
}
else
{
GetLogger()->Info("Found excluded mod: '%s'\n", modPath.c_str());
}
}
}
for (const std::string& modPath : m_mods)
{
std::string::size_type enabled;
enabled = modPath.find('~');
if (enabled == std::string::npos)
{
GetLogger()->Info("Loading mod: '%s'\n", modPath.c_str());
CResourceManager::AddLocation(modPath);
}
else
{
GetLogger()->Info("Found excluded mod: '%s'\n", modPath.c_str());
}
}
CResourceManager::SetSaveLocation(m_savePath); CResourceManager::SetSaveLocation(m_savePath);
CResourceManager::AddLocation(m_savePath); CResourceManager::AddLocation(m_savePath);
@ -213,7 +178,7 @@ void CPathManager::InitPaths()
GetLogger()->Debug(" * %s\n", path.c_str()); GetLogger()->Debug(" * %s\n", path.c_str());
} }
std::vector<std::string> CPathManager::FindModsInDir(const std::string &dir) std::vector<std::string> CPathManager::FindModsInDir(const std::string &dir) const
{ {
std::vector<std::string> ret; std::vector<std::string> ret;
try try

View File

@ -37,9 +37,11 @@ public:
void SetDataPath(const std::string &dataPath); void SetDataPath(const std::string &dataPath);
void SetLangPath(const std::string &langPath); void SetLangPath(const std::string &langPath);
void SetSavePath(const std::string &savePath); void SetSavePath(const std::string &savePath);
void AddModAutoloadDir(const std::string &modAutoloadDirPath); void AddModSearchDir(const std::string &modAutoloadDirPath);
void AddMod(const std::string &modPath); void AddMod(const std::string &modPath);
void RemoveMod(const std::string &modPath); void RemoveMod(const std::string &modPath);
bool ModLoaded(const std::string& modPath);
std::vector<std::string> FindMods() const;
const std::string& GetDataPath(); const std::string& GetDataPath();
const std::string& GetLangPath(); const std::string& GetLangPath();
@ -52,7 +54,7 @@ public:
private: private:
//! Loads all mods from given directory //! Loads all mods from given directory
std::vector<std::string> FindModsInDir(const std::string &dir); std::vector<std::string> FindModsInDir(const std::string &dir) const;
private: private:
//! Data path //! Data path
@ -61,8 +63,6 @@ private:
std::string m_langPath; std::string m_langPath;
//! Save path //! Save path
std::string m_savePath; std::string m_savePath;
//! Mod autoload paths //! Mod search paths
std::vector<std::string> m_modAutoloadDir; std::vector<std::string> m_modSearchDirs;
//! Mod paths
std::vector<std::string> m_mods;
}; };

View File

@ -95,6 +95,12 @@ std::vector<std::string> CResourceManager::GetLocations()
return ret; return ret;
} }
bool CResourceManager::LocationExists(const std::string& location)
{
auto locations = GetLocations();
auto it = std::find(locations.cbegin(), locations.cend(), location);
return it != locations.cend();
}
bool CResourceManager::SetSaveLocation(const std::string &location) bool CResourceManager::SetSaveLocation(const std::string &location)
{ {

View File

@ -41,6 +41,8 @@ public:
static bool RemoveLocation(const std::string &location); static bool RemoveLocation(const std::string &location);
//! List all locations in the search path //! List all locations in the search path
static std::vector<std::string> GetLocations(); static std::vector<std::string> GetLocations();
//! Check if given location is in the search path
static bool LocationExists(const std::string &location);
static bool SetSaveLocation(const std::string &location); static bool SetSaveLocation(const std::string &location);
static std::string GetSaveLocation(); static std::string GetSaveLocation();

View File

@ -259,10 +259,8 @@ void CText::FlushCache()
} }
} }
m_lastCachedFont = nullptr; //TODO: fix this
m_lastFontType = FONT_COMMON; Destroy();
m_lastFontSize = 0;
Create(); Create();
} }

View File

@ -85,7 +85,7 @@ CMainUserInterface::CMainUserInterface()
m_screenSetupDisplay = MakeUnique<CScreenSetupDisplay>(); m_screenSetupDisplay = MakeUnique<CScreenSetupDisplay>();
m_screenSetupGame = MakeUnique<CScreenSetupGame>(); m_screenSetupGame = MakeUnique<CScreenSetupGame>();
m_screenSetupGraphics = MakeUnique<CScreenSetupGraphics>(); m_screenSetupGraphics = MakeUnique<CScreenSetupGraphics>();
m_screenSetupMods = MakeUnique<CScreenSetupMods>(m_dialog.get()); m_screenSetupMods = MakeUnique<CScreenSetupMods>(m_dialog.get(), m_app->GetModManager());
m_screenSetupSound = MakeUnique<CScreenSetupSound>(); m_screenSetupSound = MakeUnique<CScreenSetupSound>();
m_screenMainMenu = MakeUnique<CScreenMainMenu>(); m_screenMainMenu = MakeUnique<CScreenMainMenu>();
m_screenPlayerSelect = MakeUnique<CScreenPlayerSelect>(m_dialog.get()); m_screenPlayerSelect = MakeUnique<CScreenPlayerSelect>(m_dialog.get());

View File

@ -1,6 +1,6 @@
/* /*
* This file is part of the Colobot: Gold Edition source code * This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2019, Daniel Roux, EPSITEC SA & TerranovaTeam * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot * http://epsitec.ch; http://colobot.info; http://github.com/colobot
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -19,18 +19,20 @@
#include "ui/screen/screen_setup_mods.h" #include "ui/screen/screen_setup_mods.h"
#include "app/app.h" #include "common/config.h"
#include "app/pathman.h"
#include "common/system/system.h" #include "app/app.h"
#include "app/modman.h"
#include "common/restext.h" #include "common/restext.h"
#include "common/config.h"
#include "common/logger.h" #include "common/logger.h"
#include "common/settings.h" #include "common/settings.h"
#include "common/stringutils.h" #include "common/stringutils.h"
#include "common/resources/resourcemanager.h" #include "common/resources/resourcemanager.h"
#include "common/system/system.h"
#include "level/parser/parser.h" #include "level/parser/parser.h"
#include "ui/controls/button.h" #include "ui/controls/button.h"
@ -49,8 +51,9 @@ using namespace boost::filesystem;
namespace Ui namespace Ui
{ {
CScreenSetupMods::CScreenSetupMods(CMainDialog* mainDialog) CScreenSetupMods::CScreenSetupMods(CMainDialog* dialog, CModManager* modManager)
: m_dialog(mainDialog) : m_dialog(dialog),
m_modManager(modManager)
{ {
} }
@ -128,6 +131,7 @@ void CScreenSetupMods::CreateInterface()
pb->SetState(STATE_SHADOW); pb->SetState(STATE_SHADOW);
pb->ClearState(STATE_ENABLE); pb->ClearState(STATE_ENABLE);
} }
bool CScreenSetupMods::EventProcess(const Event &event) bool CScreenSetupMods::EventProcess(const Event &event)
{ {
CWindow* pw; CWindow* pw;
@ -135,7 +139,7 @@ bool CScreenSetupMods::EventProcess(const Event &event)
CList* pl; CList* pl;
std::string modName; std::string modName;
const std::string website = "https://www.moddb.com/games/colobot-gold-edition"; const std::string website = "https://www.moddb.com/games/colobot-gold-edition";
const std::string modDir = CResourceManager::GetSaveLocation() + "/" + "mods"; const std::string modDir = CResourceManager::GetSaveLocation() + "/mods";
auto systemUtils = CSystemUtils::Create(); // platform-specific utils auto systemUtils = CSystemUtils::Create(); // platform-specific utils
if (!CScreenSetup::EventProcess(event)) return false; if (!CScreenSetup::EventProcess(event)) return false;
@ -149,9 +153,10 @@ bool CScreenSetupMods::EventProcess(const Event &event)
pl = static_cast<CList*>(pw->SearchControl(EVENT_INTERFACE_MODS_UNLOADED)); pl = static_cast<CList*>(pw->SearchControl(EVENT_INTERFACE_MODS_UNLOADED));
if (pl == nullptr) return false; if (pl == nullptr) return false;
modName = pl->GetItemName(pl->GetSelect()); modName = pl->GetItemName(pl->GetSelect());
LoadMod(modName);
m_app->Reload(); m_modManager->EnableMod(modName);
m_modManager->ReloadMods();
m_main->ChangePhase(PHASE_SETUPm); m_main->ChangePhase(PHASE_SETUPm);
break; break;
@ -159,9 +164,10 @@ bool CScreenSetupMods::EventProcess(const Event &event)
pl = static_cast<CList*>(pw->SearchControl(EVENT_INTERFACE_MODS_LOADED)); pl = static_cast<CList*>(pw->SearchControl(EVENT_INTERFACE_MODS_LOADED));
if (pl == nullptr) return false; if (pl == nullptr) return false;
modName = pl->GetItemName(pl->GetSelect()); modName = pl->GetItemName(pl->GetSelect());
UnloadMod(modName);
m_app->Reload(); m_modManager->DisableMod(modName);
m_modManager->ReloadMods();
m_main->ChangePhase(PHASE_SETUPm); m_main->ChangePhase(PHASE_SETUPm);
break; break;
@ -200,7 +206,7 @@ bool CScreenSetupMods::EventProcess(const Event &event)
GetResource(RES_TEXT, RT_DIALOG_OPEN_PATH_FAILED_TITLE, title); GetResource(RES_TEXT, RT_DIALOG_OPEN_PATH_FAILED_TITLE, title);
GetResource(RES_TEXT, RT_DIALOG_OPEN_PATH_FAILED_TEXT, text); GetResource(RES_TEXT, RT_DIALOG_OPEN_PATH_FAILED_TEXT, text);
// Workaround for how labels treat the \\ character on Windows // Workaround for Windows: the label skips everything after the first \\ character
std::string modDirWithoutBackSlashes = modDir; std::string modDirWithoutBackSlashes = modDir;
std::replace(modDirWithoutBackSlashes.begin(), modDirWithoutBackSlashes.end(), '\\', '/'); std::replace(modDirWithoutBackSlashes.begin(), modDirWithoutBackSlashes.end(), '\\', '/');
@ -224,34 +230,11 @@ bool CScreenSetupMods::EventProcess(const Event &event)
return false; return false;
} }
void CScreenSetupMods::UnloadMod(std::string modName)
{
std::string modPath, modPathRaw, disabled = "~";
modPathRaw = CResourceManager::GetSaveLocation() + "/" + "mods" + "/";
modPath = modPathRaw.c_str();
m_pathManager->RemoveMod(modPath+modName);
boost::filesystem::rename(modPath+modName, modPath+disabled+modName);
}
void CScreenSetupMods::LoadMod(std::string modName)
{
std::string modPath, modPathRaw, disabled = "~";
modPathRaw = CResourceManager::GetSaveLocation() + "/" + "mods" + "/";
modPath = modPathRaw.c_str();
boost::filesystem::rename(modPath+disabled+modName, modPath+modName);
m_pathManager->AddMod(modPath+modName);
}
void CScreenSetupMods::UpdateUnloadedModList() void CScreenSetupMods::UpdateUnloadedModList()
{ {
CWindow* pw; CWindow* pw;
CList* pl; CList* pl;
int i = 0; int i = 0;
std::string modPath, modPathRaw;
directory_iterator end_itr; directory_iterator end_itr;
pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5)); pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
@ -261,30 +244,22 @@ void CScreenSetupMods::UpdateUnloadedModList()
if ( pl == nullptr ) return; if ( pl == nullptr ) return;
pl->Flush(); pl->Flush();
modPathRaw = CResourceManager::GetSaveLocation() + "/" + "mods" + "/"; for (const auto& mod : m_modManager->GetMods())
modPath = modPathRaw.c_str();
for (directory_iterator itr(modPath); itr != end_itr; ++itr)
{ {
std::string modName = itr->path().string(); if (!mod.enabled)
boost::erase_all(modName, modPath);
std::string::size_type enabled;
enabled = modName.find('~');
if (enabled != std::string::npos)
{ {
modName.erase(0,1); pl->SetItemName(i++, mod.name);
pl->SetItemName(i++, modName);
} }
} }
pl->ShowSelect(false); // shows the selected columns pl->ShowSelect(false); // shows the selected columns
} }
void CScreenSetupMods::UpdateLoadedModList() void CScreenSetupMods::UpdateLoadedModList()
{ {
CWindow* pw; CWindow* pw;
CList* pl; CList* pl;
int i = 0; int i = 0;
std::string modPath, modPathRaw;
directory_iterator end_itr; directory_iterator end_itr;
pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5)); pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
@ -294,19 +269,15 @@ void CScreenSetupMods::UpdateLoadedModList()
if ( pl == nullptr ) return; if ( pl == nullptr ) return;
pl->Flush(); pl->Flush();
modPathRaw = CResourceManager::GetSaveLocation() + "/" + "mods" + "/"; for (const auto& mod : m_modManager->GetMods())
modPath = modPathRaw.c_str();
for (directory_iterator itr(modPath); itr != end_itr; ++itr)
{ {
std::string modName = itr->path().string(); if (mod.enabled)
boost::erase_all(modName, modPath); {
std::string::size_type enabled; pl->SetItemName(i++, mod.name);
enabled = modName.find('~'); }
if (enabled == std::string::npos)
pl->SetItemName(i++, modName);
} }
pl->ShowSelect(false); // shows the selected columns pl->ShowSelect(false); // shows the selected columns
} }
} // namespace Ui } // namespace Ui

View File

@ -1,6 +1,6 @@
/* /*
* This file is part of the Colobot: Gold Edition source code * This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2019, Daniel Roux, EPSITEC SA & TerranovaTeam * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot * http://epsitec.ch; http://colobot.info; http://github.com/colobot
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -20,11 +20,12 @@
#pragma once #pragma once
#include "ui/maindialog.h" #include "ui/maindialog.h"
#include "ui/screen/screen_setup.h" #include "ui/screen/screen_setup.h"
#include <vector> #include <vector>
class CPathManager; class CModManager;
namespace Ui namespace Ui
{ {
@ -32,24 +33,20 @@ namespace Ui
class CScreenSetupMods : public CScreenSetup class CScreenSetupMods : public CScreenSetup
{ {
public: public:
CScreenSetupMods(CMainDialog* mainDialog); CScreenSetupMods(CMainDialog* dialog, CModManager* modManager);
void SetActive() override; void SetActive() override;
void CreateInterface() override; void CreateInterface() override;
bool EventProcess(const Event &event) override; bool EventProcess(const Event &event) override;
protected: protected:
void UnloadMod(std::string ModName);
void LoadMod(std::string ModName);
void UpdateUnloadedModList(); void UpdateUnloadedModList();
void UpdateLoadedModList(); void UpdateLoadedModList();
protected: protected:
CMainDialog* m_dialog; CModManager* m_modManager;
CPathManager* m_pathManager; CMainDialog* m_dialog;
std::vector<std::string> m_unloadedModList;
std::vector<std::string> m_loadedModList;
}; };
} // namespace Ui } // namespace Ui