Explorar el Código

Fix enabling and disabling of mods

Ivan Savenko hace 11 meses
padre
commit
4aaa6c1eb4

+ 7 - 1
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 <future>
 
@@ -395,6 +396,7 @@ QString CModListView::genModInfoText(const ModState & mod)
 
 	result += "<p></p>"; // 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());

+ 4 - 0
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

+ 21 - 7
lib/modding/ModManager.cpp

@@ -205,7 +205,8 @@ TModList ModsPresetState::getActiveRootMods() const
 {
 	const JsonNode & modsToActivateJson = getActivePresetConfig()["mods"];
 	auto modsToActivate = modsToActivateJson.convertTo<std::vector<TModID>>();
-	modsToActivate.push_back(ModScope::scopeBuiltin());
+	if (!vstd::contains(modsToActivate, ModScope::scopeBuiltin()))
+		modsToActivate.push_back(ModScope::scopeBuiltin());
 	return modsToActivate;
 }
 
@@ -282,11 +283,17 @@ std::vector<TModID> 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<TModID> desiredModList = modsPreset->getActiveMods();
 	depedencyResolver = std::make_unique<ModDependenciesResolver>(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;