Browse Source

Allow mod operations such as install when possible

Ivan Savenko 11 tháng trước cách đây
mục cha
commit
00f97fb8cd

+ 68 - 54
launcher/modManager/cmodlistview_moc.cpp

@@ -266,41 +266,34 @@ QStringList CModListView::getModNames(QString queryingModID, QStringList input)
 
 	for(const auto & modID : input)
 	{
-		// Missing mod - use mod ID
-		// TODO: for submods show parent ID instead
-		if (!modStateModel->isModExists(modID))
-		{
-			result += modID;
+		if (modStateModel->isModExists(modID) && modStateModel->getMod(modID).isHidden())
 			continue;
-		}
 
-		auto mod = modStateModel->getMod(modID);
+		QString parentModID = modStateModel->getTopParent(modID);
+		QString displayName;
 
-		if (queryingMod.getParentID() == modID)
-			continue;
+		if (modStateModel->isSubmod(modID) && queryingMod.getParentID() != parentModID )
+		{
+			// show in form "parent mod (submod)"
 
-		if (mod.isHidden())
-			continue;
+			QString parentDisplayName = parentModID;
+			QString submodDisplayName = modID;
 
-		QString displayName = mod.getName();
-		if (displayName.isEmpty())
-			displayName = modID.toLower();
+			if (modStateModel->isModExists(parentModID))
+				parentDisplayName = modStateModel->getMod(parentModID).getName();
 
-		if (mod.isSubmod() && queryingMod.getParentID() != mod.getParentID() ) // FIXME: recheck this block
+			if (modStateModel->isModExists(modID))
+				submodDisplayName = modStateModel->getMod(modID).getName();
+
+			displayName = QString("%1 (%2)").arg(submodDisplayName, parentDisplayName);
+		}
+		else
 		{
-			auto parentModID = mod.getTopParentID();
-			auto parentMod = modStateModel->getMod(parentModID);
-			QString parentDisplayName = parentMod.getName();
-			if (parentDisplayName.isEmpty())
-				parentDisplayName = parentModID.toLower();
-			
-			if (modStateModel->isModInstalled(modID))
-				displayName = QString("%1 (%2)").arg(displayName, parentDisplayName);
-			else
-				displayName = parentDisplayName;
+			// show simply as mod name
+			displayName = modID;
+			if (modStateModel->isModExists(modID))
+				displayName = modStateModel->getMod(modID).getName();
 		}
-
-		// TODO: show active mods in bold?
 		result += displayName;
 	}
 	return result;
@@ -457,7 +450,6 @@ void CModListView::selectMod(const QModelIndex & index)
 		//FIXME: this function should be recursive
 		//FIXME: ensure that this is also reflected correctly in "Notes" section of mod description
 		bool hasInvalidDeps = !findInvalidDependencies(modName).empty();
-		bool hasDependentMods = !findDependentMods(modName, true).empty();
 
 		ui->disableButton->setVisible(modStateModel->isModEnabled(mod.getID()));
 		ui->enableButton->setVisible(!modStateModel->isModEnabled(mod.getID()));
@@ -466,13 +458,11 @@ void CModListView::selectMod(const QModelIndex & index)
 		ui->updateButton->setVisible(mod.isUpdateAvailable());
 
 		// Block buttons if action is not allowed at this time
-		// TODO: automate handling of some of these cases instead of forcing player
-		// to resolve all conflicts manually.
 		ui->disableButton->setEnabled(true);
 		ui->enableButton->setEnabled(!hasInvalidDeps);
 		ui->installButton->setEnabled(!hasInvalidDeps);
 		ui->uninstallButton->setEnabled(true);
-		ui->updateButton->setEnabled(!hasInvalidDeps && !hasDependentMods);
+		ui->updateButton->setEnabled(!hasInvalidDeps);
 
 		loadScreenshots();
 	}
@@ -514,27 +504,18 @@ QStringList CModListView::findInvalidDependencies(QString mod)
 	QStringList ret;
 	for(QString requirement : modStateModel->getMod(mod).getDependencies())
 	{
-		if(!modStateModel->isModExists(requirement))
-			ret += requirement;
-	}
-	return ret;
-}
-
-QStringList CModListView::findDependentMods(QString mod, bool excludeDisabled)
-{
-	QStringList ret;
-	for(QString modName : modStateModel->getAllMods())
-	{
-		auto current = modStateModel->getMod(modName);
-
-		if(!current.isInstalled() || !current.isVisible())
+		if(modStateModel->isModExists(requirement))
 			continue;
 
-		if(current.getDependencies().contains(mod, Qt::CaseInsensitive))
+		if(modStateModel->isSubmod(requirement))
 		{
-			if(!(modStateModel->isModEnabled(modName) && excludeDisabled))
-				ret += modName;
+			QString parentModID = modStateModel->getTopParent(requirement);
+
+			if (modStateModel->isModExists(parentModID) && !modStateModel->isModInstalled(parentModID))
+				continue;
 		}
+
+		ret += requirement;
 	}
 	return ret;
 }
@@ -569,13 +550,47 @@ void CModListView::disableModByName(QString modName)
 	modModel->reloadRepositories();
 }
 
+QStringList CModListView::getModsToInstall(QString mod)
+{
+	QStringList result;
+	QStringList candidates;
+	QStringList processed;
+
+	candidates.push_back(mod);
+	while (!candidates.empty())
+	{
+		QString potentialToInstall = candidates.back();
+		candidates.pop_back();
+		processed.push_back(potentialToInstall);
+
+		if (modStateModel->isSubmod(potentialToInstall))
+			potentialToInstall = modStateModel->getTopParent(potentialToInstall);
+
+		if (!modStateModel->isModExists(potentialToInstall))
+			throw std::runtime_error("Attempt to install non-existing mod! Mod name:" + potentialToInstall.toStdString());
+
+		if (modStateModel->isModInstalled(potentialToInstall))
+			continue;
+
+		result.push_back(potentialToInstall);
+
+		QStringList dependencies = modStateModel->getMod(potentialToInstall).getDependencies();
+		for (const auto & dependency : dependencies)
+		{
+			if (!processed.contains(dependency))
+				candidates.push_back(dependency);
+		}
+	}
+	return result;
+}
+
 void CModListView::on_updateButton_clicked()
 {
 	QString modName = ui->allModsView->currentIndex().data(ModRoles::ModNameRole).toString();
 
 	assert(findInvalidDependencies(modName).empty());
 
-	for(const auto & name : modStateModel->getMod(modName).getDependencies())
+	for(const auto & name : getModsToInstall(modName))
 	{
 		auto mod = modStateModel->getMod(name);
 		// update required mod, install missing (can be new dependency)
@@ -604,8 +619,8 @@ void CModListView::on_installButton_clicked()
 	QString modName = ui->allModsView->currentIndex().data(ModRoles::ModNameRole).toString();
 
 	assert(findInvalidDependencies(modName).empty());
-	
-	for(const auto & name : modStateModel->getMod(modName).getDependencies())
+
+	for(const auto & name : getModsToInstall(modName))
 	{
 		auto mod = modStateModel->getMod(name);
 		if(mod.isAvailable())
@@ -1058,7 +1073,6 @@ void CModListView::on_allModsView_doubleClicked(const QModelIndex &index)
 	auto mod = modStateModel->getMod(modName);
 	
 	bool hasInvalidDeps = !findInvalidDependencies(modName).empty();
-	bool hasDependentMods = !findDependentMods(modName, true).empty();
 	
 	if(!hasInvalidDeps && mod.isAvailable() && !mod.isSubmod())
 	{
@@ -1066,7 +1080,7 @@ void CModListView::on_allModsView_doubleClicked(const QModelIndex &index)
 		return;
 	}
 
-	if(!hasInvalidDeps && !hasDependentMods && mod.isUpdateAvailable() && index.column() == ModFields::STATUS_UPDATE)
+	if(!hasInvalidDeps && mod.isUpdateAvailable() && index.column() == ModFields::STATUS_UPDATE)
 	{
 		on_updateButton_clicked();
 		return;
@@ -1088,7 +1102,7 @@ void CModListView::on_allModsView_doubleClicked(const QModelIndex &index)
 		return;
 	}
 
-	if(!hasDependentMods && !mod.isVisible() && modStateModel->isModEnabled(modName))
+	if(modStateModel->isModEnabled(modName))
 	{
 		on_disableButton_clicked();
 		return;

+ 3 - 2
launcher/modManager/cmodlistview_moc.h

@@ -46,10 +46,11 @@ class CModListView : public QWidget
 	/// replace mod ID's with proper human-readable mod names
 	QStringList getModNames(QString queryingMod, QStringList input);
 
+	/// returns list of mods that are needed for install of this mod (potentially including this mod itself)
+	QStringList getModsToInstall(QString mod);
+
 	// find mods unknown to mod list (not present in repo and not installed)
 	QStringList findInvalidDependencies(QString mod);
-	// find mods that depend on this one
-	QStringList findDependentMods(QString mod, bool excludeDisabled);
 
 	void manualInstallFile(QString filePath);
 	void downloadFile(QString file, QString url, QString description, qint64 size = 0);

+ 14 - 0
launcher/modManager/modstatemodel.cpp

@@ -104,3 +104,17 @@ void ModStateModel::doDisableMod(QString modname)
 {
 	modManager->tryDisableMod(modname.toStdString());
 }
+
+bool ModStateModel::isSubmod(QString modname)
+{
+	return modname.contains('.');
+}
+
+QString ModStateModel::getTopParent(QString modname) const
+{
+	QStringList components = modname.split('.');
+	if (components.size() > 1)
+		return components.front();
+	else
+		return "";
+}

+ 3 - 0
launcher/modManager/modstatemodel.h

@@ -45,4 +45,7 @@ public:
 
 	void doEnableMod(QString modname);
 	void doDisableMod(QString modname);
+
+	bool isSubmod(QString modname);
+	QString getTopParent(QString modname) const;
 };

+ 2 - 1
lib/modding/CModHandler.cpp

@@ -93,7 +93,8 @@ void CModHandler::loadModFilesystems()
 		modFilesystems[modName] = genModFilesystem(modName, getModInfo(modName).getFilesystemConfig());
 
 	for(const TModID & modName : activeMods)
-		CResourceHandler::addFilesystem("data", modName, modFilesystems[modName]);
+		if (modName != "core") // FIXME: remove
+			CResourceHandler::addFilesystem("data", modName, modFilesystems[modName]);
 
 	if (settings["mods"]["validation"].String() == "full")
 		checkModFilesystemsConflicts(modFilesystems);