From 4aaa6c1eb4ce91aacf266113ab3a437c42b3260f Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 20 Nov 2024 20:44:24 +0000 Subject: [PATCH] Fix enabling and disabling of mods --- launcher/modManager/cmodlistview_moc.cpp | 8 ++++++- launcher/modManager/modstatecontroller.cpp | 4 ++++ lib/modding/ModManager.cpp | 28 ++++++++++++++++------ 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/launcher/modManager/cmodlistview_moc.cpp b/launcher/modManager/cmodlistview_moc.cpp index 40198eebd..c6f7aa67b 100644 --- a/launcher/modManager/cmodlistview_moc.cpp +++ b/launcher/modManager/cmodlistview_moc.cpp @@ -32,6 +32,7 @@ #include "../../lib/texts/Languages.h" #include "../../lib/modding/CModVersion.h" #include "../../lib/filesystem/Filesystem.h" +#include "../../lib/texts/CGeneralTextHandler.h" #include @@ -395,6 +396,7 @@ QString CModListView::genModInfoText(const ModState & mod) result += "

"; // to get some empty space + QString translationMismatch = tr("This mod cannot be enabled because it translates into a different language."); QString notInstalledDeps = tr("This mod can not be enabled because the following dependencies are not present"); QString unavailableDeps = tr("This mod can not be installed because the following dependencies are not present"); QString thisIsSubmod = tr("This is a submod and it cannot be installed or uninstalled separately from its parent mod"); @@ -412,6 +414,9 @@ QString CModListView::genModInfoText(const ModState & mod) if(mod.isSubmod()) notes += noteTemplate.arg(thisIsSubmod); + if (mod.isTranslation() && CGeneralTextHandler::getPreferredLanguage() != mod.getBaseLanguage().toStdString()) + notes += noteTemplate.arg(translationMismatch); + if(notes.size()) result += textTemplate.arg(tr("Notes")).arg(notes); @@ -456,6 +461,7 @@ void CModListView::selectMod(const QModelIndex & index) QStringList notInstalledDependencies = this->getModsToInstall(modName); QStringList unavailableDependencies = this->findUnavailableMods(notInstalledDependencies); + bool translationMismatch = mod.isTranslation() && CGeneralTextHandler::getPreferredLanguage() != mod.getBaseLanguage().toStdString(); ui->disableButton->setVisible(modStateModel->isModInstalled(mod.getID()) && modStateModel->isModEnabled(mod.getID())); ui->enableButton->setVisible(modStateModel->isModInstalled(mod.getID()) && !modStateModel->isModEnabled(mod.getID())); @@ -465,7 +471,7 @@ void CModListView::selectMod(const QModelIndex & index) // Block buttons if action is not allowed at this time ui->disableButton->setEnabled(true); - ui->enableButton->setEnabled(notInstalledDependencies.empty()); + ui->enableButton->setEnabled(notInstalledDependencies.empty() && !translationMismatch); ui->installButton->setEnabled(unavailableDependencies.empty()); ui->uninstallButton->setEnabled(true); ui->updateButton->setEnabled(unavailableDependencies.empty()); diff --git a/launcher/modManager/modstatecontroller.cpp b/launcher/modManager/modstatecontroller.cpp index 0d2a05279..fa243f0b8 100644 --- a/launcher/modManager/modstatecontroller.cpp +++ b/launcher/modManager/modstatecontroller.cpp @@ -18,6 +18,7 @@ #include "../../lib/modding/CModHandler.h" #include "../../lib/modding/IdentifierStorage.h" #include "../../lib/json/JsonNode.h" +#include "../../lib/texts/CGeneralTextHandler.h" #include "../vcmiqt/jsonutils.h" #include "../vcmiqt/launcherdirs.h" @@ -156,6 +157,9 @@ bool ModStateController::canEnableMod(QString modname) if(!mod.isCompatible()) return addError(modname, tr("Mod is not compatible, please update VCMI and checkout latest mod revisions")); + if (mod.isTranslation() && CGeneralTextHandler::getPreferredLanguage() != mod.getBaseLanguage().toStdString()) + return addError(modname, tr("Can not enable translation mod for a different language!")); + for(const auto & modEntry : mod.getDependencies()) { if(!modList->isModExists(modEntry)) // required mod is not available diff --git a/lib/modding/ModManager.cpp b/lib/modding/ModManager.cpp index 529f1bd9a..13217cbc7 100644 --- a/lib/modding/ModManager.cpp +++ b/lib/modding/ModManager.cpp @@ -205,7 +205,8 @@ TModList ModsPresetState::getActiveRootMods() const { const JsonNode & modsToActivateJson = getActivePresetConfig()["mods"]; auto modsToActivate = modsToActivateJson.convertTo>(); - modsToActivate.push_back(ModScope::scopeBuiltin()); + if (!vstd::contains(modsToActivate, ModScope::scopeBuiltin())) + modsToActivate.push_back(ModScope::scopeBuiltin()); return modsToActivate; } @@ -282,11 +283,17 @@ std::vector ModsPresetState::getActiveMods() const for(const auto & activeMod : activeRootMods) { + assert(!vstd::contains(allActiveMods, activeMod)); allActiveMods.push_back(activeMod); for(const auto & submod : getModSettings(activeMod)) + { if(submod.second) + { + assert(!vstd::contains(allActiveMods, activeMod + '.' + submod.first)); allActiveMods.push_back(activeMod + '.' + submod.first); + } + } } return allActiveMods; } @@ -464,7 +471,7 @@ void ModManager::addNewModsToPreset() const auto & modSettings = modsPreset->getModSettings(rootMod); if (!modSettings.count(settingID)) - modsPreset->setSettingActive(rootMod, settingID, modsStorage->getMod(modID).keepDisabled()); + modsPreset->setSettingActive(rootMod, settingID, !modsStorage->getMod(modID).keepDisabled()); } } @@ -502,24 +509,25 @@ void ModManager::tryEnableMods(const TModList & modList) for (const auto & modName : modList) { for (const auto & dependency : collectDependenciesRecursive(modName)) + { if (!vstd::contains(requiredActiveMods, dependency)) + { requiredActiveMods.push_back(dependency); + vstd::erase(additionalActiveMods, dependency); + } + } assert(!vstd::contains(additionalActiveMods, modName)); assert(vstd::contains(requiredActiveMods, modName));// FIXME: fails on attempt to enable broken mod / translation to other language } ModDependenciesResolver testResolver(requiredActiveMods, *modsStorage); - assert(testResolver.getBrokenMods().empty()); testResolver.tryAddMods(additionalActiveMods, *modsStorage); for (const auto & modName : modList) - { - assert(vstd::contains(testResolver.getActiveMods(), modName)); if (!vstd::contains(testResolver.getActiveMods(), modName)) throw std::runtime_error("Failed to enable mod! Mod " + modName + " remains disabled!"); - } updatePreset(testResolver); } @@ -536,6 +544,7 @@ void ModManager::tryDisableMod(const TModID & modName) if (vstd::contains(testResolver.getActiveMods(), modName)) throw std::runtime_error("Failed to disable mod! Mod " + modName + " remains enabled!"); + modsPreset->setModActive(modName, false); updatePreset(testResolver); } @@ -551,7 +560,11 @@ void ModManager::updatePreset(const ModDependenciesResolver & testResolver) } for (const auto & modID : newBrokenMods) - modsPreset->setModActive(modID, false); + { + const auto & mod = getModDescription(modID); + if (vstd::contains(newActiveMods, mod.getTopParentID())) + modsPreset->setModActive(modID, false); + } std::vector desiredModList = modsPreset->getActiveMods(); depedencyResolver = std::make_unique(desiredModList, *modsStorage); @@ -620,6 +633,7 @@ void ModDependenciesResolver::tryAddMods(TModList modsToResolve, const ModsStora if(isResolved(storage.getMod(*it))) { resolvedOnCurrentTreeLevel.insert(*it); // Not to the resolvedModIDs, so current node children will be resolved on the next iteration + assert(!vstd::contains(sortedValidMods, *it)); sortedValidMods.push_back(*it); it = modsToResolve.erase(it); continue;