feat: make dependencies auto disable/enable

Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
This commit is contained in:
Trial97 2025-05-05 00:35:35 +03:00
parent 2b62b4281f
commit 8277fd41ae
No known key found for this signature in database
GPG Key ID: 55EF5DA53DB36318
4 changed files with 104 additions and 18 deletions

View File

@ -52,6 +52,9 @@
#include "Application.h"
#include "minecraft/Component.h"
#include "minecraft/mod/Resource.h"
#include "minecraft/mod/ResourceFolderModel.h"
#include "minecraft/mod/tasks/LocalModParseTask.h"
#include "modplatform/ModIndex.h"
@ -260,6 +263,12 @@ void ModFolderModel::onParseSucceeded(int ticket, QString mod_id)
emit dataChanged(index(row), index(row, columnCount(QModelIndex()) - 1));
}
Mod* findById(QList<Mod*> mods, QString modId)
{
auto found = std::find_if(mods.begin(), mods.end(), [modId](Mod* m) { return m->mod_id() == modId; });
return found != mods.end() ? *found : nullptr;
}
void ModFolderModel::onParseFinished()
{
if (hasPendingParseTasks()) {
@ -267,37 +276,37 @@ void ModFolderModel::onParseFinished()
}
auto mods = allMods();
auto findById = [mods](QString modId) -> Mod* {
auto found = std::find_if(mods.begin(), mods.end(), [modId](Mod* m) { return m->mod_id() == modId; });
return found != mods.end() ? *found : nullptr;
};
auto findByProjectID = [mods](QVariant modId, ModPlatform::ResourceProvider provider) -> Mod* {
auto found = std::find_if(mods.begin(), mods.end(), [modId, provider](Mod* m) {
return m->metadata()->provider == provider && m->metadata()->project_id == modId;
return m->metadata() && m->metadata()->provider == provider && m->metadata()->project_id == modId;
});
return found != mods.end() ? *found : nullptr;
};
for (auto mod : mods) {
auto id = mod->internal_id();
auto id = mod->mod_id();
for (auto dep : mod->dependencies()) {
auto d = findById(dep);
auto d = findById(mods, dep);
if (d) {
m_requires[id] << d;
m_requiredBy[d->internal_id()] << mod;
m_requiredBy[d->mod_id()] << mod;
}
}
for (auto dep : mod->metadata()->dependencies) {
auto d = findByProjectID(dep.addonId, mod->metadata()->provider);
if (d) {
m_requires[id] << d;
m_requiredBy[d->internal_id()] << mod;
if (mod->metadata()) {
for (auto dep : mod->metadata()->dependencies) {
if (dep.type == ModPlatform::DependencyType::REQUIRED) {
auto d = findByProjectID(dep.addonId, mod->metadata()->provider);
if (d) {
m_requires[id] << d;
m_requiredBy[d->mod_id()] << mod;
}
}
}
}
}
auto removeDuplicates = [](QList<Mod*>& list) {
std::set<QString> seen;
auto it = std::remove_if(list.begin(), list.end(), [&seen](Mod* m) {
auto id = m->internal_id();
auto id = m->mod_id();
if (seen.count(id) > 0) {
return true;
}
@ -313,10 +322,66 @@ void ModFolderModel::onParseFinished()
removeDuplicates(m_requires[key]);
}
for (auto mod : mods) {
auto id = mod->internal_id();
auto id = mod->mod_id();
mod->setRequiredByCount(m_requiredBy[id].count());
mod->setRequiresCount(m_requires[id].count());
int row = m_resources_index[id];
int row = m_resources_index[mod->internal_id()];
emit dataChanged(index(row), index(row, columnCount(QModelIndex()) - 1));
}
}
QModelIndexList ModFolderModel::getAffectedMods(const QModelIndexList& indexes, EnableAction action)
{
if (indexes.isEmpty())
return {};
QModelIndexList affectedList = {};
auto indexedMods = selectedMods(indexes);
if (action == EnableAction::TOGGLE) {
if (indexedMods.length() != 1) {
return {}; // not sure how to handle a bunch of rows that are toggled(not even sure it is posible)
}
action = indexedMods.first()->enabled() ? EnableAction::DISABLE : EnableAction::ENABLE;
}
std::set<QString> seen;
bool shouldBeEnabled = action == EnableAction::ENABLE;
for (auto mod : indexedMods) {
auto id = mod->mod_id();
QList<Mod*> mods;
switch (action) {
case EnableAction::DISABLE: {
mods = m_requiredBy[id];
break;
}
case EnableAction::ENABLE: {
mods = m_requires[id];
break;
}
case EnableAction::TOGGLE:
break;
}
for (auto affected : mods) {
auto affectedId = affected->mod_id();
if (findById(indexedMods, affectedId) == nullptr && seen.count(affectedId) == 0) {
seen.insert(affectedId);
if (shouldBeEnabled != affected->enabled()) {
auto row = m_resources_index[affected->internal_id()];
affectedList << index(row, 0);
}
}
}
}
// collect the affected mods until all of them are included in the list
if (!affectedList.isEmpty()) {
affectedList += getAffectedMods(indexes + affectedList, action);
}
return affectedList;
}
bool ModFolderModel::setResourceEnabled(const QModelIndexList& indexes, EnableAction action)
{
auto affected = getAffectedMods(indexes, action);
return ResourceFolderModel::setResourceEnabled(indexes + affected, action);
}

View File

@ -47,6 +47,7 @@
#include "Mod.h"
#include "ResourceFolderModel.h"
#include "minecraft/Component.h"
#include "minecraft/mod/Resource.h"
class BaseInstance;
@ -89,6 +90,9 @@ class ModFolderModel : public ResourceFolderModel {
bool isValid();
bool setResourceEnabled(const QModelIndexList& indexes, EnableAction action) override;
QModelIndexList getAffectedMods(const QModelIndexList& indexes, EnableAction action);
RESOURCE_HELPERS(Mod)
private slots:

View File

@ -882,6 +882,7 @@ QList<Resource*> ResourceFolderModel::allResources()
result.append((resource.get()));
return result;
}
QList<Resource*> ResourceFolderModel::selectedResources(const QModelIndexList& indexes)
{
QList<Resource*> result;

View File

@ -37,6 +37,7 @@
*/
#include "ModFolderPage.h"
#include "minecraft/mod/Resource.h"
#include "ui/dialogs/ExportToModListDialog.h"
#include "ui_ExternalResourcesPage.h"
@ -90,7 +91,7 @@ ModFolderPage::ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel>
auto depsDisabled = APPLICATION->settings()->getSetting("ModDependenciesDisabled");
ui->actionVerifyItemDependencies->setVisible(!depsDisabled->get().toBool());
connect(depsDisabled.get(), &Setting::SettingChanged, this,
[this](const Setting& setting, const QVariant& value) { ui->actionVerifyItemDependencies->setVisible(!value.toBool()); });
[this](const Setting&, const QVariant& value) { ui->actionVerifyItemDependencies->setVisible(!value.toBool()); });
updateMenu->addAction(ui->actionResetItemMetadata);
connect(ui->actionResetItemMetadata, &QAction::triggered, this, &ModFolderPage::deleteModMetadata);
@ -133,7 +134,22 @@ void ModFolderPage::removeItems(const QItemSelection& selection)
if (response != QMessageBox::Yes)
return;
}
m_model->deleteResources(selection.indexes());
auto indexes = selection.indexes();
auto affected = m_model->getAffectedMods(indexes, EnableAction::DISABLE);
if (!affected.isEmpty()) {
auto response = CustomMessageBox::selectable(this, tr("Confirm Disable"),
tr("The mods you are tring to disable are required by %1 mods.\n"
"Do you want to disable them?")
.arg(affected.length()),
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
->exec();
if (response != QMessageBox::Yes) {
m_model->setResourceEnabled(affected, EnableAction::DISABLE);
}
}
m_model->deleteResources(indexes);
}
void ModFolderPage::downloadMods()