Selaa lähdekoodia

Fix installation of multiple mods at once

Ivan Savenko 11 kuukautta sitten
vanhempi
sitoutus
fef19f4846

+ 10 - 10
launcher/modManager/cmodlistview_moc.cpp

@@ -451,8 +451,8 @@ void CModListView::selectMod(const QModelIndex & index)
 		//FIXME: ensure that this is also reflected correctly in "Notes" section of mod description
 		bool hasInvalidDeps = !findInvalidDependencies(modName).empty();
 
-		ui->disableButton->setVisible(modStateModel->isModEnabled(mod.getID()));
-		ui->enableButton->setVisible(!modStateModel->isModEnabled(mod.getID()));
+		ui->disableButton->setVisible(modStateModel->isModInstalled(mod.getID()) && modStateModel->isModEnabled(mod.getID()));
+		ui->enableButton->setVisible(modStateModel->isModInstalled(mod.getID()) && !modStateModel->isModEnabled(mod.getID()));
 		ui->installButton->setVisible(mod.isAvailable() && !mod.isSubmod());
 		ui->uninstallButton->setVisible(mod.isInstalled() && !mod.isSubmod());
 		ui->updateButton->setVisible(mod.isUpdateAvailable());
@@ -531,7 +531,7 @@ void CModListView::on_enableButton_clicked()
 
 void CModListView::enableModByName(QString modName)
 {
-	manager->enableMod(modName);
+	manager->enableMods({modName});
 	modModel->reloadRepositories();
 }
 
@@ -577,10 +577,11 @@ QStringList CModListView::getModsToInstall(QString mod)
 		QStringList dependencies = modStateModel->getMod(potentialToInstall).getDependencies();
 		for (const auto & dependency : dependencies)
 		{
-			if (!processed.contains(dependency))
+			if (!processed.contains(dependency) && !candidates.contains(dependency))
 				candidates.push_back(dependency);
 		}
 	}
+	assert(result.removeDuplicates() == 0);
 	return result;
 }
 
@@ -900,13 +901,15 @@ void CModListView::installMods(QStringList archives)
 	{
 		if(modStateModel->getMod(mod).isInstalled())
 		{
+			if (modStateModel->isModEnabled(mod))
+				modsToEnable.push_back(mod);
+
 			manager->uninstallMod(mod);
 		}
 		else
 		{
 			// installation of previously not present mod -> enable it
-			if (modStateModel->isModEnabled(mod))
-				modsToEnable.push_back(mod);
+			modsToEnable.push_back(mod);
 		}
 	}
 
@@ -916,10 +919,7 @@ void CModListView::installMods(QStringList archives)
 		manager->installMod(modNames[i], archives[i]);
 	}
 
-	for(QString mod : modsToEnable)
-	{
-		manager->enableMod(mod); // TODO: make it as a single action, so if mod 1 depends on mod 2 it would still activate
-	}
+	manager->enableMods(modsToEnable);
 
 	checkManagerErrors();
 

+ 11 - 13
launcher/modManager/modstatecontroller.cpp

@@ -99,14 +99,22 @@ bool ModStateController::uninstallMod(QString modname)
 	return canUninstallMod(modname) && doUninstallMod(modname);
 }
 
-bool ModStateController::enableMod(QString modname)
+bool ModStateController::enableMods(QStringList modlist)
 {
-	return canEnableMod(modname) && doEnableMod(modname, true);
+	for (const auto & modname : modlist)
+		if (!canEnableMod(modname))
+			return false;
+
+	modList->doEnableMods(modlist);
+	return true;
 }
 
 bool ModStateController::disableMod(QString modname)
 {
-	return canDisableMod(modname) && doEnableMod(modname, false);
+	if (!canDisableMod(modname))
+		return false;
+	modList->doDisableMod(modname);
+	return true;
 }
 
 bool ModStateController::canInstallMod(QString modname)
@@ -170,16 +178,6 @@ bool ModStateController::canDisableMod(QString modname)
 	return true;
 }
 
-bool ModStateController::doEnableMod(QString mod, bool on)
-{
-	if (on)
-		modList->doEnableMod(mod);
-	else
-		modList->doDisableMod(mod);
-
-	return true;
-}
-
 bool ModStateController::doInstallMod(QString modname, QString archivePath)
 {
 	const auto destDir = CLauncherDirs::modsPath() + QChar{'/'};

+ 1 - 2
launcher/modManager/modstatecontroller.h

@@ -24,7 +24,6 @@ class ModStateController : public QObject, public boost::noncopyable
 	std::shared_ptr<ModStateModel> modList;
 
 	// check-free version of public method
-	bool doEnableMod(QString mod, bool on);
 	bool doInstallMod(QString mod, QString archivePath);
 	bool doUninstallMod(QString mod);
 
@@ -47,7 +46,7 @@ public:
 	/// installs mod from zip archive located at archivePath
 	bool installMod(QString mod, QString archivePath);
 	bool uninstallMod(QString mod);
-	bool enableMod(QString mod);
+	bool enableMods(QStringList mod);
 	bool disableMod(QString mod);
 
 	bool canInstallMod(QString mod);

+ 7 - 2
launcher/modManager/modstatemodel.cpp

@@ -95,9 +95,14 @@ double ModStateModel::getInstalledModSizeMegabytes(QString modName) const
 	return modManager->getInstalledModSizeMegabytes(modName.toStdString());
 }
 
-void ModStateModel::doEnableMod(QString modname)
+void ModStateModel::doEnableMods(QStringList modList)
 {
-	modManager->tryEnableMod(modname.toStdString());
+	std::vector<std::string> stdList;
+
+	for (const auto & entry : modList)
+		stdList.push_back(entry.toStdString());
+
+	modManager->tryEnableMods(stdList);
 }
 
 void ModStateModel::doDisableMod(QString modname)

+ 1 - 1
launcher/modManager/modstatemodel.h

@@ -43,7 +43,7 @@ public:
 	bool isModUpdateAvailable(QString modName) const;
 	bool isModVisible(QString modName) const;
 
-	void doEnableMod(QString modname);
+	void doEnableMods(QStringList modList);
 	void doDisableMod(QString modname);
 
 	bool isSubmod(QString modname);

+ 19 - 9
lib/modding/ModManager.cpp

@@ -495,24 +495,34 @@ TModList ModManager::collectDependenciesRecursive(const TModID & modID) const
 	return result;
 }
 
-void ModManager::tryEnableMod(const TModID & modName)
+void ModManager::tryEnableMods(const TModList & modList)
 {
-	auto requiredActiveMods = collectDependenciesRecursive(modName);
-	auto additionalActiveMods = getActiveMods();
+	TModList requiredActiveMods;
+	TModList additionalActiveMods = getActiveMods();
 
-	assert(!vstd::contains(additionalActiveMods, modName));
-	assert(vstd::contains(requiredActiveMods, modName));// FIXME: fails on attempt to enable broken mod / translation to other language
+	for (const auto & modName : modList)
+	{
+		for (const auto & dependency : collectDependenciesRecursive(modName))
+			if (!vstd::contains(requiredActiveMods, dependency))
+				requiredActiveMods.push_back(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());
-	assert(vstd::contains(testResolver.getActiveMods(), modName));
 
 	testResolver.tryAddMods(additionalActiveMods, *modsStorage);
 
-	if (!vstd::contains(testResolver.getActiveMods(), modName))
+	for (const auto & modName : modList)
 	{
-		// FIXME: report?
-		return;
+		assert(vstd::contains(testResolver.getActiveMods(), modName));
+		if (!vstd::contains(testResolver.getActiveMods(), modName))
+		{
+			// FIXME: report?
+			return;
+		}
 	}
 
 	updatePreset(testResolver);

+ 3 - 1
lib/modding/ModManager.h

@@ -117,6 +117,8 @@ class DLL_LINKAGE ModManager : boost::noncopyable
 
 	TModList collectDependenciesRecursive(const TModID & modID) const;
 
+	void tryEnableMod(const TModID & modList);
+
 public:
 	ModManager(const JsonNode & repositoryList);
 	ModManager();
@@ -133,7 +135,7 @@ public:
 	void saveConfigurationState() const;
 	double getInstalledModSizeMegabytes(const TModID & modName) const;
 
-	void tryEnableMod(const TModID & modName);
+	void tryEnableMods(const TModList & modList);
 	void tryDisableMod(const TModID & modName);
 };