Improve sound reloading

Also some minor refactoring.

Since realoding may take a lot of time, modman no longer reloads
the whole app on entering/leaving the screen.
pyro-refactor
MrSimbax 2020-07-27 15:59:33 +02:00
parent fd36ff3840
commit 9cb80daedf
9 changed files with 157 additions and 130 deletions

View File

@ -520,7 +520,9 @@ 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->Init(); m_modManager->FindMods();
m_modManager->SaveMods();
m_modManager->MountAllMods();
// Create the sound instance. // Create the sound instance.
#ifdef OPENAL_SOUND #ifdef OPENAL_SOUND
@ -1551,6 +1553,7 @@ void CApplication::StartLoadingMusic()
SystemTimeStamp* musicLoadStart = m_systemUtils->CreateTimeStamp(); SystemTimeStamp* musicLoadStart = m_systemUtils->CreateTimeStamp();
m_systemUtils->GetCurrentTimeStamp(musicLoadStart); m_systemUtils->GetCurrentTimeStamp(musicLoadStart);
m_sound->Reset();
m_sound->CacheAll(); m_sound->CacheAll();
SystemTimeStamp* musicLoadEnd = m_systemUtils->CreateTimeStamp(); SystemTimeStamp* musicLoadEnd = m_systemUtils->CreateTimeStamp();

View File

@ -44,8 +44,11 @@ CModManager::CModManager(CApplication* app, CPathManager* pathManager)
{ {
} }
void CModManager::Init() void CModManager::FindMods()
{ {
m_mods.clear();
m_userChanges = false;
// Load names from the config file // Load names from the config file
std::vector<std::string> savedModNames; std::vector<std::string> savedModNames;
GetConfigFile().GetArrayProperty("Mods", "Names", savedModNames); GetConfigFile().GetArrayProperty("Mods", "Names", savedModNames);
@ -103,9 +106,15 @@ void CModManager::Init()
m_mods.push_back(mod); m_mods.push_back(mod);
} }
SaveMods();
// Load the metadata for each mod // Load the metadata for each mod
// Unfortunately, the paths are distinguished by their real paths, not mount points
// So we must unmount mods temporarily
for (const auto& path : m_mountedModPaths)
{
UnmountMod(path);
}
for (auto& mod : m_mods) for (auto& mod : m_mods)
{ {
MountMod(mod, "/temp/mod"); MountMod(mod, "/temp/mod");
@ -113,28 +122,30 @@ void CModManager::Init()
UnmountMod(mod); UnmountMod(mod);
} }
UpdatePaths(); // Mount back
for (const auto& path : m_mountedModPaths)
{
MountMod(path);
}
} }
void CModManager::ReloadMods() void CModManager::ReloadMods()
{ {
UnmountAllMods(); UnmountAllMountedMods();
m_mods.clear(); MountAllMods();
Init();
// Apply the configuration
ReloadResources(); ReloadResources();
} }
void CModManager::EnableMod(size_t i) void CModManager::EnableMod(size_t i)
{ {
m_mods[i].enabled = true; m_mods[i].enabled = true;
m_userChanges = true;
} }
void CModManager::DisableMod(size_t i) void CModManager::DisableMod(size_t i)
{ {
m_mods[i].enabled = false; m_mods[i].enabled = false;
m_userChanges = true;
} }
size_t CModManager::MoveUp(size_t i) size_t CModManager::MoveUp(size_t i)
@ -142,6 +153,7 @@ size_t CModManager::MoveUp(size_t i)
if (i != 0) if (i != 0)
{ {
std::swap(m_mods[i - 1], m_mods[i]); std::swap(m_mods[i - 1], m_mods[i]);
m_userChanges = true;
return i - 1; return i - 1;
} }
else else
@ -155,6 +167,7 @@ size_t CModManager::MoveDown(size_t i)
if (i != m_mods.size() - 1) if (i != m_mods.size() - 1)
{ {
std::swap(m_mods[i], m_mods[i + 1]); std::swap(m_mods[i], m_mods[i + 1]);
m_userChanges = true;
return i + 1; return i + 1;
} }
else else
@ -163,13 +176,27 @@ size_t CModManager::MoveDown(size_t i)
} }
} }
void CModManager::UpdatePaths() bool CModManager::Changes()
{
std::vector<std::string> paths;
for (const auto& mod : m_mods)
{
if (mod.enabled)
{
paths.push_back(mod.path);
}
}
return paths != m_mountedModPaths || m_userChanges;
}
void CModManager::MountAllMods()
{ {
for (const auto& mod : m_mods) for (const auto& mod : m_mods)
{ {
if (mod.enabled) if (mod.enabled)
{ {
MountMod(mod); MountMod(mod);
m_mountedModPaths.push_back(mod.path);
} }
} }
} }
@ -192,6 +219,8 @@ void CModManager::SaveMods()
GetConfigFile().SetArrayProperty("Mods", "Enabled", savedEnabled); GetConfigFile().SetArrayProperty("Mods", "Enabled", savedEnabled);
GetConfigFile().Save(); GetConfigFile().Save();
m_userChanges = false;
} }
size_t CModManager::CountMods() const size_t CModManager::CountMods() const
@ -296,23 +325,34 @@ void CModManager::LoadModData(Mod& mod)
void CModManager::MountMod(const Mod& mod, const std::string& mountPoint) void CModManager::MountMod(const Mod& mod, const std::string& mountPoint)
{ {
GetLogger()->Debug("Mounting mod: '%s' at path %s\n", mod.path.c_str(), mountPoint.c_str()); MountMod(mod.path, mountPoint);
CResourceManager::AddLocation(mod.path, true, mountPoint); }
void CModManager::MountMod(const std::string& path, const std::string& mountPoint)
{
GetLogger()->Debug("Mounting mod: '%s' at path %s\n", path.c_str(), mountPoint.c_str());
CResourceManager::AddLocation(path, true, mountPoint);
} }
void CModManager::UnmountMod(const Mod& mod) void CModManager::UnmountMod(const Mod& mod)
{ {
if (CResourceManager::LocationExists(mod.path)) UnmountMod(mod.path);
}
void CModManager::UnmountMod(const std::string& path)
{
if (CResourceManager::LocationExists(path))
{ {
GetLogger()->Debug("Unmounting mod: '%s'\n", mod.path.c_str()); GetLogger()->Debug("Unmounting mod: '%s'\n", path.c_str());
CResourceManager::RemoveLocation(mod.path); CResourceManager::RemoveLocation(path);
} }
} }
void CModManager::UnmountAllMods() void CModManager::UnmountAllMountedMods()
{ {
for (const auto& mod : m_mods) for (const auto& path : m_mountedModPaths)
{ {
UnmountMod(mod); UnmountMod(path);
} }
m_mountedModPaths.clear();
} }

View File

@ -51,21 +51,17 @@ struct Mod
* The order matters since the order in which files are loaded matters, * The order matters since the order in which files are loaded matters,
* because some files can be overwritten. * because some files can be overwritten.
* *
* The changes in the list do not immediately apply * The changes in the list do not immediately apply.
* and will be lost after the \ref ReloadMods call if they were not
* saved beforehand with \ref SaveMods.
*
* The changes are also lost to mods which are no longer found in the search paths.
*/ */
class CModManager class CModManager
{ {
public: public:
CModManager(CApplication* app, CPathManager* pathManager); CModManager(CApplication* app, CPathManager* pathManager);
//! Loads mods without resource reloading; should be called only once after creation
void Init();
//! Finds all the mods along with their metadata //! Finds all the mods along with their metadata
void FindMods();
//! Applies the current configuration and reloads the application
void ReloadMods(); void ReloadMods();
//! Removes a mod from the list of loaded mods //! Removes a mod from the list of loaded mods
@ -80,6 +76,9 @@ public:
//! Moves the selected mod down in the list so that it's loaded later than others, returns the new index //! Moves the selected mod down in the list so that it's loaded later than others, returns the new index
size_t MoveDown(size_t i); size_t MoveDown(size_t i);
//! Checks if the list of currently used mods differs from the current configuration or there were changes made by the user
bool Changes();
//! Saves the current configuration of mods to the config file //! Saves the current configuration of mods to the config file
void SaveMods(); void SaveMods();
@ -93,8 +92,8 @@ public:
const std::vector<Mod>& GetMods() const; const std::vector<Mod>& GetMods() const;
private: private:
//! Updates the paths in Path Manager according to the current mod configuration // Allow access to MountAllMods() as CApplication doesn't want to reload itself during initialization
void UpdatePaths(); friend CApplication;
//! Reloads application resources so the enabled mods are applied //! Reloads application resources so the enabled mods are applied
void ReloadResources(); void ReloadResources();
@ -102,13 +101,24 @@ private:
//! Load mod data into mod //! Load mod data into mod
void LoadModData(Mod& mod); void LoadModData(Mod& mod);
//! Updates the paths in Path Manager according to the current mod configuration
void MountAllMods();
void MountMod(const Mod& mod, const std::string& mountPoint = ""); void MountMod(const Mod& mod, const std::string& mountPoint = "");
void MountMod(const std::string& path, const std::string& mountPoint = "");
void UnmountMod(const Mod& mod); void UnmountMod(const Mod& mod);
void UnmountAllMods(); void UnmountMod(const std::string& path);
void UnmountAllMountedMods();
private: private:
CApplication* m_app; CApplication* m_app;
CPathManager* m_pathManager; CPathManager* m_pathManager;
//! Paths to mods already in the virtual filesystem
std::vector<std::string> m_mountedModPaths;
//! List of mods
std::vector<Mod> m_mods; std::vector<Mod> m_mods;
bool m_userChanges = false;
}; };

View File

@ -47,22 +47,7 @@ void CALSound::CleanUp()
if (m_enabled) if (m_enabled)
{ {
GetLogger()->Info("Unloading files and closing device...\n"); GetLogger()->Info("Unloading files and closing device...\n");
StopAll(); Reset();
StopMusic();
m_channels.clear();
m_currentMusic.reset();
m_oldMusic.clear();
m_previousMusic.music.reset();
m_sounds.clear();
m_music.clear();
m_enabled = false;
alcDestroyContext(m_context); alcDestroyContext(m_context);
alcCloseDevice(m_device); alcCloseDevice(m_device);
@ -99,6 +84,24 @@ bool CALSound::Create()
return true; return true;
} }
void CALSound::Reset()
{
StopAll();
StopMusic();
m_channels.clear();
m_currentMusic.reset();
m_oldMusic.clear();
m_previousMusic.music.reset();
m_sounds.clear();
m_music.clear();
}
bool CALSound::GetEnable() bool CALSound::GetEnable()
{ {
return m_enabled; return m_enabled;

View File

@ -84,6 +84,7 @@ public:
~CALSound(); ~CALSound();
bool Create() override; bool Create() override;
void Reset() override;
bool Cache(SoundType, const std::string &) override; bool Cache(SoundType, const std::string &) override;
void CacheMusic(const std::string &) override; void CacheMusic(const std::string &) override;
bool IsCached(SoundType) override; bool IsCached(SoundType) override;

View File

@ -52,6 +52,10 @@ void CSoundInterface::CacheAll()
} }
} }
void CSoundInterface::Reset()
{
}
bool CSoundInterface::Cache(SoundType sound, const std::string &file) bool CSoundInterface::Cache(SoundType sound, const std::string &file)
{ {
return true; return true;

View File

@ -72,6 +72,10 @@ public:
*/ */
void CacheAll(); void CacheAll();
/** Stop all sounds and music and clean cache.
*/
virtual void Reset();
/** Function called to cache sound effect file. /** Function called to cache sound effect file.
* This function is called by plugin interface for each file. * This function is called by plugin interface for each file.
* \param sound - id of a file, will be used to identify sound files * \param sound - id of a file, will be used to identify sound files

View File

@ -36,6 +36,8 @@
#include "math/func.h" #include "math/func.h"
#include "sound/sound.h"
#include "ui/controls/button.h" #include "ui/controls/button.h"
#include "ui/controls/edit.h" #include "ui/controls/edit.h"
#include "ui/controls/interface.h" #include "ui/controls/interface.h"
@ -64,9 +66,6 @@ void CScreenModList::CreateInterface()
Math::Point pos, ddim; Math::Point pos, ddim;
std::string name; std::string name;
m_changes = false;
ApplyChanges();
// Display the window // Display the window
pos.x = 0.10f; pos.x = 0.10f;
pos.y = 0.10f; pos.y = 0.10f;
@ -104,8 +103,6 @@ void CScreenModList::CreateInterface()
pli->SetState(STATE_SHADOW); pli->SetState(STATE_SHADOW);
pli->SetState(STATE_EXTEND); pli->SetState(STATE_EXTEND);
UpdateModList();
// Displays the mod details // Displays the mod details
pos.x = ox+sx*9.5f; pos.x = ox+sx*9.5f;
pos.y = oy+sy*10.5f; pos.y = oy+sy*10.5f;
@ -124,8 +121,6 @@ void CScreenModList::CreateInterface()
pe->SetEditCap(false); // just to see pe->SetEditCap(false); // just to see
pe->SetHighlightCap(true); pe->SetHighlightCap(true);
UpdateModDetails();
pos = pli->GetPos(); pos = pli->GetPos();
ddim = pli->GetDim(); ddim = pli->GetDim();
@ -148,8 +143,6 @@ void CScreenModList::CreateInterface()
pe->SetEditCap(false); // just to see pe->SetEditCap(false); // just to see
pe->SetHighlightCap(true); pe->SetHighlightCap(true);
UpdateModSummary();
// Apply button // Apply button
pos.x = ox+sx*13.75f; pos.x = ox+sx*13.75f;
pos.y = oy+sy*2; pos.y = oy+sy*2;
@ -158,16 +151,12 @@ void CScreenModList::CreateInterface()
pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_MODS_APPLY); pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_MODS_APPLY);
pb->SetState(STATE_SHADOW); pb->SetState(STATE_SHADOW);
UpdateApplyButton();
// Display the enable/disable button // Display the enable/disable button
pos.x -= dim.x*2.3f; pos.x -= dim.x*2.3f;
ddim.x = dim.x*2.0f; ddim.x = dim.x*2.0f;
pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_MOD_ENABLE_OR_DISABLE); pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_MOD_ENABLE_OR_DISABLE);
pb->SetState(STATE_SHADOW); pb->SetState(STATE_SHADOW);
UpdateEnableDisableButton();
// Display the move up button // Display the move up button
pos.x -= dim.x*0.8f; pos.x -= dim.x*0.8f;
pos.y = oy+sy*2.48; pos.y = oy+sy*2.48;
@ -181,8 +170,6 @@ void CScreenModList::CreateInterface()
pb = pw->CreateButton(pos, ddim, 50, EVENT_INTERFACE_MOD_MOVE_DOWN); pb = pw->CreateButton(pos, ddim, 50, EVENT_INTERFACE_MOD_MOVE_DOWN);
pb->SetState(STATE_SHADOW); pb->SetState(STATE_SHADOW);
UpdateUpDownButtons();
// Display the refresh button // Display the refresh button
pos.x -= dim.x*1.3f; pos.x -= dim.x*1.3f;
pos.y = oy+sy*2; pos.y = oy+sy*2;
@ -207,6 +194,9 @@ void CScreenModList::CreateInterface()
pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_BACK); pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_BACK);
pb->SetState(STATE_SHADOW); pb->SetState(STATE_SHADOW);
FindMods();
UpdateAll();
// Background // Background
SetBackground("textures/interface/interface.png"); SetBackground("textures/interface/interface.png");
CreateVersionDisplay(); CreateVersionDisplay();
@ -231,7 +221,7 @@ bool CScreenModList::EventProcess(const Event &event)
event.type == EVENT_INTERFACE_BACK || event.type == EVENT_INTERFACE_BACK ||
(event.type == EVENT_KEY_DOWN && event.GetData<KeyEventData>()->key == KEY(ESCAPE))) (event.type == EVENT_KEY_DOWN && event.GetData<KeyEventData>()->key == KEY(ESCAPE)))
{ {
if (m_changes) if (m_modManager->Changes())
{ {
m_dialog->StartQuestion(RT_DIALOG_CHANGES_QUESTION, true, true, false, m_dialog->StartQuestion(RT_DIALOG_CHANGES_QUESTION, true, true, false,
[this]() [this]()
@ -241,14 +231,11 @@ bool CScreenModList::EventProcess(const Event &event)
}, },
[this]() [this]()
{ {
m_changes = false; // do not save changes on "No"
ApplyChanges();
CloseWindow(); CloseWindow();
}); });
} }
else else
{ {
ApplyChanges();
CloseWindow(); CloseWindow();
} }
return false; return false;
@ -278,7 +265,6 @@ bool CScreenModList::EventProcess(const Event &event)
} }
UpdateModList(); UpdateModList();
UpdateEnableDisableButton(); UpdateEnableDisableButton();
m_changes = true;
UpdateApplyButton(); UpdateApplyButton();
break; break;
@ -286,7 +272,6 @@ bool CScreenModList::EventProcess(const Event &event)
m_modSelectedIndex = m_modManager->MoveUp(m_modSelectedIndex); m_modSelectedIndex = m_modManager->MoveUp(m_modSelectedIndex);
UpdateModList(); UpdateModList();
UpdateUpDownButtons(); UpdateUpDownButtons();
m_changes = true;
UpdateApplyButton(); UpdateApplyButton();
break; break;
@ -294,20 +279,21 @@ bool CScreenModList::EventProcess(const Event &event)
m_modSelectedIndex = m_modManager->MoveDown(m_modSelectedIndex); m_modSelectedIndex = m_modManager->MoveDown(m_modSelectedIndex);
UpdateModList(); UpdateModList();
UpdateUpDownButtons(); UpdateUpDownButtons();
m_changes = true;
UpdateApplyButton(); UpdateApplyButton();
break; break;
case EVENT_INTERFACE_MODS_REFRESH: case EVENT_INTERFACE_MODS_REFRESH:
// Apply any changes before refresh so that the config file
// is better synchronized with the state of the game
case EVENT_INTERFACE_MODS_APPLY: case EVENT_INTERFACE_MODS_APPLY:
ApplyChanges(); ApplyChanges();
// Update the whole UI UpdateAll();
UpdateModList(); // Start playing the main menu music again
UpdateModSummary(); if (!m_app->GetSound()->IsPlayingMusic())
UpdateModDetails(); {
UpdateEnableDisableButton(); m_app->GetSound()->PlayMusic("music/Intro1.ogg", false);
UpdateApplyButton(); m_app->GetSound()->CacheMusic("music/Intro2.ogg");
UpdateUpDownButtons(); }
break; break;
case EVENT_INTERFACE_MODS_DIR: case EVENT_INTERFACE_MODS_DIR:
@ -341,19 +327,19 @@ bool CScreenModList::EventProcess(const Event &event)
return false; return false;
} }
void CScreenModList::FindMods()
{
m_modManager->FindMods();
if (m_modManager->CountMods() != 0)
{
m_modSelectedIndex = Math::Clamp(m_modSelectedIndex, static_cast<size_t>(0), m_modManager->CountMods() - 1);
}
}
void CScreenModList::ApplyChanges() void CScreenModList::ApplyChanges()
{ {
if (m_changes) m_modManager->SaveMods();
{
m_changes = false;
m_modManager->SaveMods();
}
m_modManager->ReloadMods(); m_modManager->ReloadMods();
m_empty = (m_modManager->CountMods() == 0);
m_modSelectedIndex = Math::Clamp(m_modSelectedIndex, static_cast<size_t>(0), m_modManager->CountMods() - 1);
} }
void CScreenModList::CloseWindow() void CScreenModList::CloseWindow()
@ -361,6 +347,16 @@ void CScreenModList::CloseWindow()
m_main->ChangePhase(PHASE_MAIN_MENU); m_main->ChangePhase(PHASE_MAIN_MENU);
} }
void CScreenModList::UpdateAll()
{
UpdateModList();
UpdateModDetails();
UpdateModSummary();
UpdateEnableDisableButton();
UpdateApplyButton();
UpdateUpDownButtons();
}
void CScreenModList::UpdateModList() void CScreenModList::UpdateModList()
{ {
CWindow* pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5)); CWindow* pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5));
@ -371,16 +367,16 @@ void CScreenModList::UpdateModList()
pl->Flush(); pl->Flush();
if (m_empty) if (m_modManager->CountMods() == 0)
{ {
return; return;
} }
auto mods = m_modManager->GetMods(); const auto& mods = m_modManager->GetMods();
for (size_t i = 0; i < mods.size(); ++i) for (size_t i = 0; i < mods.size(); ++i)
{ {
const auto& mod = mods[i]; const auto& mod = mods[i];
auto name = mod.data.displayName; const auto& name = mod.data.displayName;
pl->SetItemName(i, name); pl->SetItemName(i, name);
pl->SetCheck(i, mod.enabled); pl->SetCheck(i, mod.enabled);
pl->SetEnable(i, true); pl->SetEnable(i, true);
@ -398,7 +394,7 @@ void CScreenModList::UpdateModDetails()
CEdit* pe = static_cast<CEdit*>(pw->SearchControl(EVENT_INTERFACE_MOD_DETAILS)); CEdit* pe = static_cast<CEdit*>(pw->SearchControl(EVENT_INTERFACE_MOD_DETAILS));
if (pe == nullptr) return; if (pe == nullptr) return;
if (m_empty) if (m_modManager->CountMods() == 0)
{ {
pe->SetText("No information"); pe->SetText("No information");
return; return;
@ -475,7 +471,7 @@ void CScreenModList::UpdateModSummary()
std::string noSummary; std::string noSummary;
GetResource(RES_TEXT, RT_MOD_NO_SUMMARY, noSummary); GetResource(RES_TEXT, RT_MOD_NO_SUMMARY, noSummary);
if (m_empty) if (m_modManager->CountMods() == 0)
{ {
pe->SetText(noSummary); pe->SetText(noSummary);
return; return;
@ -503,7 +499,7 @@ void CScreenModList::UpdateEnableDisableButton()
std::string buttonName{}; std::string buttonName{};
if (m_empty) if (m_modManager->CountMods() == 0)
{ {
pb->ClearState(STATE_ENABLE); pb->ClearState(STATE_ENABLE);
@ -536,13 +532,7 @@ void CScreenModList::UpdateApplyButton()
CButton* pb = static_cast<CButton*>(pw->SearchControl(EVENT_INTERFACE_MODS_APPLY)); CButton* pb = static_cast<CButton*>(pw->SearchControl(EVENT_INTERFACE_MODS_APPLY));
if (pb == nullptr) return; if (pb == nullptr) return;
if (m_empty) if (m_modManager->Changes())
{
pb->ClearState(STATE_ENABLE);
return;
}
if (m_changes)
{ {
pb->SetState(STATE_ENABLE); pb->SetState(STATE_ENABLE);
} }
@ -563,7 +553,7 @@ void CScreenModList::UpdateUpDownButtons()
CButton* pb_down = static_cast<CButton*>(pw->SearchControl(EVENT_INTERFACE_MOD_MOVE_DOWN)); CButton* pb_down = static_cast<CButton*>(pw->SearchControl(EVENT_INTERFACE_MOD_MOVE_DOWN));
if (pb_down == nullptr) return; if (pb_down == nullptr) return;
if (m_empty) if (m_modManager->CountMods() == 0)
{ {
pb_up->ClearState(STATE_ENABLE); pb_up->ClearState(STATE_ENABLE);
pb_down->ClearState(STATE_ENABLE); pb_down->ClearState(STATE_ENABLE);

View File

@ -33,34 +33,6 @@ namespace Ui
/** /**
* \class CScreenModList * \class CScreenModList
* \brief This class is the front-end for the \ref CModManager. * \brief This class is the front-end for the \ref CModManager.
*
* \section Assumptions Assumptions
*
* It assumes the user is changing something in the mods folders while the screen is visible,
* e.g. removing them or adding more. For this reason, the mods are always reloaded after the user
* lefts the screen, possibly after asking the user if their changes should be saved. They are also reloaded
* when the user opens the screen to avoid weird situations like "the mod is no longer there but in theory
* it's still in the game's memory even if it's not visible on the list".
*
* Unsafe changes, like removing a mod which is still enabled, are a sole responsibility of the user and
* we basically can't guarantee the game will behave properly in such cases even when they happen while
* this screen is visible.
*
* \section Features UI Features
*
* The user can reorder mods with appropriate buttons and enable/disable them. To avoid reloading
* the resources after every change, the changes are not immediate. The resources are reloaded in the
* cases described above and also after using the Apply or Refresh buttons. The only technical
* difference between them is that the Refresh button is always enabled, but Apply is only enabled
* if the user made any changes in the list by using the UI. The reason is, again, to avoid dealing with
* weird situations like described above.
*
* The UI also shows the selected mod metadata like description, version, etc.
*
* There is also a button which will try to open the default web browser with the Workshop website,
* where the user can search for new mods.
*
* For convenience, also a button opening a saves/mods folder is provided.
*/ */
class CScreenModList : public CScreen class CScreenModList : public CScreen
{ {
@ -71,9 +43,11 @@ public:
bool EventProcess(const Event &event) override; bool EventProcess(const Event &event) override;
protected: protected:
void FindMods();
void ApplyChanges(); void ApplyChanges();
void CloseWindow(); void CloseWindow();
void UpdateAll();
void UpdateModList(); void UpdateModList();
void UpdateModDetails(); void UpdateModDetails();
void UpdateModSummary(); void UpdateModSummary();
@ -87,8 +61,6 @@ protected:
CModManager* m_modManager; CModManager* m_modManager;
size_t m_modSelectedIndex = 0; size_t m_modSelectedIndex = 0;
bool m_changes = false;
bool m_empty = true;
}; };
} // namespace Ui } // namespace Ui