mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-25 22:42:04 +02:00
Implement remaining todo's, fix handling of mods with invalid
dependencies
This commit is contained in:
@@ -395,12 +395,19 @@ QString CModListView::genModInfoText(const ModState & mod)
|
|||||||
|
|
||||||
result += "<p></p>"; // to get some empty space
|
result += "<p></p>"; // to get some empty space
|
||||||
|
|
||||||
QString unknownDeps = tr("This mod can not be installed or enabled because the following dependencies are not present");
|
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");
|
QString thisIsSubmod = tr("This is a submod and it cannot be installed or uninstalled separately from its parent mod");
|
||||||
|
|
||||||
QString notes;
|
QString notes;
|
||||||
|
|
||||||
notes += replaceIfNotEmpty(getModNames(mod.getID(), findInvalidDependencies(mod.getID())), listTemplate.arg(unknownDeps));
|
QStringList notInstalledDependencies = this->getModsToInstall(mod.getID());
|
||||||
|
QStringList unavailableDependencies = this->findUnavailableMods(notInstalledDependencies);
|
||||||
|
|
||||||
|
if (mod.isInstalled())
|
||||||
|
notes += replaceIfNotEmpty(getModNames(mod.getID(), notInstalledDependencies), listTemplate.arg(notInstalledDeps));
|
||||||
|
else
|
||||||
|
notes += replaceIfNotEmpty(getModNames(mod.getID(), unavailableDependencies), listTemplate.arg(unavailableDeps));
|
||||||
|
|
||||||
if(mod.isSubmod())
|
if(mod.isSubmod())
|
||||||
notes += noteTemplate.arg(thisIsSubmod);
|
notes += noteTemplate.arg(thisIsSubmod);
|
||||||
@@ -447,9 +454,8 @@ void CModListView::selectMod(const QModelIndex & index)
|
|||||||
Helper::enableScrollBySwiping(ui->modInfoBrowser);
|
Helper::enableScrollBySwiping(ui->modInfoBrowser);
|
||||||
Helper::enableScrollBySwiping(ui->changelogBrowser);
|
Helper::enableScrollBySwiping(ui->changelogBrowser);
|
||||||
|
|
||||||
//FIXME: this function should be recursive
|
QStringList notInstalledDependencies = this->getModsToInstall(modName);
|
||||||
//FIXME: ensure that this is also reflected correctly in "Notes" section of mod description
|
QStringList unavailableDependencies = this->findUnavailableMods(notInstalledDependencies);
|
||||||
bool hasInvalidDeps = !findInvalidDependencies(modName).empty();
|
|
||||||
|
|
||||||
ui->disableButton->setVisible(modStateModel->isModInstalled(mod.getID()) && 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->enableButton->setVisible(modStateModel->isModInstalled(mod.getID()) && !modStateModel->isModEnabled(mod.getID()));
|
||||||
@@ -459,10 +465,10 @@ void CModListView::selectMod(const QModelIndex & index)
|
|||||||
|
|
||||||
// Block buttons if action is not allowed at this time
|
// Block buttons if action is not allowed at this time
|
||||||
ui->disableButton->setEnabled(true);
|
ui->disableButton->setEnabled(true);
|
||||||
ui->enableButton->setEnabled(!hasInvalidDeps);
|
ui->enableButton->setEnabled(notInstalledDependencies.empty());
|
||||||
ui->installButton->setEnabled(!hasInvalidDeps);
|
ui->installButton->setEnabled(unavailableDependencies.empty());
|
||||||
ui->uninstallButton->setEnabled(true);
|
ui->uninstallButton->setEnabled(true);
|
||||||
ui->updateButton->setEnabled(!hasInvalidDeps);
|
ui->updateButton->setEnabled(unavailableDependencies.empty());
|
||||||
|
|
||||||
loadScreenshots();
|
loadScreenshots();
|
||||||
}
|
}
|
||||||
@@ -499,25 +505,16 @@ void CModListView::on_comboBox_currentIndexChanged(int index)
|
|||||||
filterModel->setTypeFilter(enumIndex);
|
filterModel->setTypeFilter(enumIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList CModListView::findInvalidDependencies(QString mod)
|
QStringList CModListView::findUnavailableMods(QStringList candidates)
|
||||||
{
|
{
|
||||||
QStringList ret;
|
QStringList invalidMods;
|
||||||
for(QString requirement : modStateModel->getMod(mod).getDependencies())
|
|
||||||
|
for(QString modName : candidates)
|
||||||
{
|
{
|
||||||
if(modStateModel->isModExists(requirement))
|
if(!modStateModel->isModExists(modName))
|
||||||
continue;
|
invalidMods.push_back(modName);
|
||||||
|
|
||||||
if(modStateModel->isSubmod(requirement))
|
|
||||||
{
|
|
||||||
QString parentModID = modStateModel->getTopParent(requirement);
|
|
||||||
|
|
||||||
if (modStateModel->isModExists(parentModID) && !modStateModel->isModInstalled(parentModID))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret += requirement;
|
|
||||||
}
|
}
|
||||||
return ret;
|
return invalidMods;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CModListView::on_enableButton_clicked()
|
void CModListView::on_enableButton_clicked()
|
||||||
@@ -563,22 +560,32 @@ QStringList CModListView::getModsToInstall(QString mod)
|
|||||||
candidates.pop_back();
|
candidates.pop_back();
|
||||||
processed.push_back(potentialToInstall);
|
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))
|
if (modStateModel->isModInstalled(potentialToInstall))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (modStateModel->isSubmod(potentialToInstall))
|
||||||
|
{
|
||||||
|
QString topParent = modStateModel->getTopParent(potentialToInstall);
|
||||||
|
if (modStateModel->isModInstalled(topParent))
|
||||||
|
{
|
||||||
|
if (modStateModel->isModUpdateAvailable(topParent))
|
||||||
|
potentialToInstall = modStateModel->getTopParent(potentialToInstall);
|
||||||
|
// else - potentially broken mod that depends on non-existing submod
|
||||||
|
}
|
||||||
|
else
|
||||||
|
potentialToInstall = modStateModel->getTopParent(potentialToInstall);
|
||||||
|
}
|
||||||
|
|
||||||
result.push_back(potentialToInstall);
|
result.push_back(potentialToInstall);
|
||||||
|
|
||||||
QStringList dependencies = modStateModel->getMod(potentialToInstall).getDependencies();
|
if (modStateModel->isModExists(potentialToInstall))
|
||||||
for (const auto & dependency : dependencies)
|
|
||||||
{
|
{
|
||||||
if (!processed.contains(dependency) && !candidates.contains(dependency))
|
QStringList dependencies = modStateModel->getMod(potentialToInstall).getDependencies();
|
||||||
candidates.push_back(dependency);
|
for (const auto & dependency : dependencies)
|
||||||
|
{
|
||||||
|
if (!processed.contains(dependency) && !candidates.contains(dependency))
|
||||||
|
candidates.push_back(dependency);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(result.removeDuplicates() == 0);
|
assert(result.removeDuplicates() == 0);
|
||||||
@@ -589,8 +596,6 @@ void CModListView::on_updateButton_clicked()
|
|||||||
{
|
{
|
||||||
QString modName = ui->allModsView->currentIndex().data(ModRoles::ModNameRole).toString();
|
QString modName = ui->allModsView->currentIndex().data(ModRoles::ModNameRole).toString();
|
||||||
|
|
||||||
assert(findInvalidDependencies(modName).empty());
|
|
||||||
|
|
||||||
for(const auto & name : getModsToInstall(modName))
|
for(const auto & name : getModsToInstall(modName))
|
||||||
{
|
{
|
||||||
auto mod = modStateModel->getMod(name);
|
auto mod = modStateModel->getMod(name);
|
||||||
@@ -619,8 +624,6 @@ void CModListView::on_installButton_clicked()
|
|||||||
{
|
{
|
||||||
QString modName = ui->allModsView->currentIndex().data(ModRoles::ModNameRole).toString();
|
QString modName = ui->allModsView->currentIndex().data(ModRoles::ModNameRole).toString();
|
||||||
|
|
||||||
assert(findInvalidDependencies(modName).empty());
|
|
||||||
|
|
||||||
for(const auto & name : getModsToInstall(modName))
|
for(const auto & name : getModsToInstall(modName))
|
||||||
{
|
{
|
||||||
auto mod = modStateModel->getMod(name);
|
auto mod = modStateModel->getMod(name);
|
||||||
@@ -1020,8 +1023,6 @@ void CModListView::on_screenshotsList_clicked(const QModelIndex & index)
|
|||||||
|
|
||||||
void CModListView::doInstallMod(const QString & modName)
|
void CModListView::doInstallMod(const QString & modName)
|
||||||
{
|
{
|
||||||
assert(findInvalidDependencies(modName).empty());
|
|
||||||
|
|
||||||
for(const auto & name : modStateModel->getMod(modName).getDependencies())
|
for(const auto & name : modStateModel->getMod(modName).getDependencies())
|
||||||
{
|
{
|
||||||
auto mod = modStateModel->getMod(name);
|
auto mod = modStateModel->getMod(name);
|
||||||
@@ -1072,15 +1073,16 @@ void CModListView::on_allModsView_doubleClicked(const QModelIndex &index)
|
|||||||
auto modName = index.data(ModRoles::ModNameRole).toString();
|
auto modName = index.data(ModRoles::ModNameRole).toString();
|
||||||
auto mod = modStateModel->getMod(modName);
|
auto mod = modStateModel->getMod(modName);
|
||||||
|
|
||||||
bool hasInvalidDeps = !findInvalidDependencies(modName).empty();
|
QStringList notInstalledDependencies = this->getModsToInstall(mod.getID());
|
||||||
|
QStringList unavailableDependencies = this->findUnavailableMods(notInstalledDependencies);
|
||||||
|
|
||||||
if(!hasInvalidDeps && mod.isAvailable() && !mod.isSubmod())
|
if(unavailableDependencies.empty() && mod.isAvailable() && !mod.isSubmod())
|
||||||
{
|
{
|
||||||
on_installButton_clicked();
|
on_installButton_clicked();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!hasInvalidDeps && mod.isUpdateAvailable() && index.column() == ModFields::STATUS_UPDATE)
|
if(unavailableDependencies.empty() && mod.isUpdateAvailable() && index.column() == ModFields::STATUS_UPDATE)
|
||||||
{
|
{
|
||||||
on_updateButton_clicked();
|
on_updateButton_clicked();
|
||||||
return;
|
return;
|
||||||
@@ -1096,7 +1098,7 @@ void CModListView::on_allModsView_doubleClicked(const QModelIndex &index)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!hasInvalidDeps && !modStateModel->isModEnabled(modName))
|
if(notInstalledDependencies.empty() && !modStateModel->isModEnabled(modName))
|
||||||
{
|
{
|
||||||
on_enableButton_clicked();
|
on_enableButton_clicked();
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class CModListView : public QWidget
|
|||||||
QStringList getModsToInstall(QString mod);
|
QStringList getModsToInstall(QString mod);
|
||||||
|
|
||||||
// find mods unknown to mod list (not present in repo and not installed)
|
// find mods unknown to mod list (not present in repo and not installed)
|
||||||
QStringList findInvalidDependencies(QString mod);
|
QStringList findUnavailableMods(QStringList candidates);
|
||||||
|
|
||||||
void manualInstallFile(QString filePath);
|
void manualInstallFile(QString filePath);
|
||||||
void downloadFile(QString file, QString url, QString description, qint64 size = 0);
|
void downloadFile(QString file, QString url, QString description, qint64 size = 0);
|
||||||
|
|||||||
@@ -110,15 +110,12 @@ QVariant ModStateItemModel::getIcon(const ModState & mod, int field) const
|
|||||||
if (!model->isModInstalled(mod.getID()))
|
if (!model->isModInstalled(mod.getID()))
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
if(mod.isSubmod())
|
if(mod.isSubmod() && !model->isModEnabled(mod.getTopParentID()))
|
||||||
{
|
{
|
||||||
if (!model->isModEnabled(mod.getTopParentID()))
|
if (model->isModEnabled(mod.getID()))
|
||||||
{
|
return QIcon(iconEnabledSubmod);
|
||||||
if (model->isModEnabled(mod.getID()))
|
else
|
||||||
return QIcon(iconEnabledSubmod);
|
return QIcon(iconDisabledSubmod);
|
||||||
else
|
|
||||||
return QIcon(iconDisabledSubmod);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model->isModEnabled(mod.getID()))
|
if (model->isModEnabled(mod.getID()))
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ void CModHandler::loadModFilesystems()
|
|||||||
modFilesystems[modName] = genModFilesystem(modName, getModInfo(modName).getFilesystemConfig());
|
modFilesystems[modName] = genModFilesystem(modName, getModInfo(modName).getFilesystemConfig());
|
||||||
|
|
||||||
for(const TModID & modName : activeMods)
|
for(const TModID & modName : activeMods)
|
||||||
if (modName != "core") // FIXME: remove
|
if (modName != "core") // virtual mod 'core' has no filesystem on its own - shared with base install
|
||||||
CResourceHandler::addFilesystem("data", modName, modFilesystems[modName]);
|
CResourceHandler::addFilesystem("data", modName, modFilesystems[modName]);
|
||||||
|
|
||||||
if (settings["mods"]["validation"].String() == "full")
|
if (settings["mods"]["validation"].String() == "full")
|
||||||
|
|||||||
@@ -67,7 +67,6 @@ uint32_t ModsState::computeChecksum(const TModID & modName) const
|
|||||||
modChecksum.process_bytes(static_cast<const void*>(GameConstants::VCMI_VERSION.data()), GameConstants::VCMI_VERSION.size());
|
modChecksum.process_bytes(static_cast<const void*>(GameConstants::VCMI_VERSION.data()), GameConstants::VCMI_VERSION.size());
|
||||||
|
|
||||||
// second - add mod.json into checksum because filesystem does not contains this file
|
// second - add mod.json into checksum because filesystem does not contains this file
|
||||||
// FIXME: remove workaround for core mod
|
|
||||||
if (modName != ModScope::scopeBuiltin())
|
if (modName != ModScope::scopeBuiltin())
|
||||||
{
|
{
|
||||||
auto modConfFile = getModDescriptionFile(modName);
|
auto modConfFile = getModDescriptionFile(modName);
|
||||||
@@ -483,7 +482,7 @@ TModList ModManager::collectDependenciesRecursive(const TModID & modID) const
|
|||||||
result.push_back(currentModID);
|
result.push_back(currentModID);
|
||||||
|
|
||||||
if (!currentMod.isInstalled())
|
if (!currentMod.isInstalled())
|
||||||
return {}; // failure. TODO: better handling?
|
throw std::runtime_error("Unable to enable mod " + modID + "! Dependency " + currentModID + " is not installed!");
|
||||||
|
|
||||||
for (const auto & dependency : currentMod.getDependencies())
|
for (const auto & dependency : currentMod.getDependencies())
|
||||||
{
|
{
|
||||||
@@ -519,10 +518,7 @@ void ModManager::tryEnableMods(const TModList & modList)
|
|||||||
{
|
{
|
||||||
assert(vstd::contains(testResolver.getActiveMods(), modName));
|
assert(vstd::contains(testResolver.getActiveMods(), modName));
|
||||||
if (!vstd::contains(testResolver.getActiveMods(), modName))
|
if (!vstd::contains(testResolver.getActiveMods(), modName))
|
||||||
{
|
throw std::runtime_error("Failed to enable mod! Mod " + modName + " remains disabled!");
|
||||||
// FIXME: report?
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePreset(testResolver);
|
updatePreset(testResolver);
|
||||||
@@ -538,10 +534,7 @@ void ModManager::tryDisableMod(const TModID & modName)
|
|||||||
ModDependenciesResolver testResolver(desiredActiveMods, *modsStorage);
|
ModDependenciesResolver testResolver(desiredActiveMods, *modsStorage);
|
||||||
|
|
||||||
if (vstd::contains(testResolver.getActiveMods(), modName))
|
if (vstd::contains(testResolver.getActiveMods(), modName))
|
||||||
{
|
throw std::runtime_error("Failed to disable mod! Mod " + modName + " remains enabled!");
|
||||||
// FIXME: report?
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
updatePreset(testResolver);
|
updatePreset(testResolver);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user