From abec40af7f484873f640c94c235e3c54ba474979 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 29 Dec 2024 14:36:07 +0200 Subject: [PATCH] add update lock Signed-off-by: Trial97 --- launcher/minecraft/mod/ModFolderModel.cpp | 25 ++++++--- launcher/minecraft/mod/ModFolderModel.h | 1 + launcher/minecraft/mod/Resource.cpp | 8 +++ launcher/minecraft/mod/Resource.h | 1 + .../minecraft/mod/ResourceFolderModel.cpp | 54 +++++++++++++++++++ launcher/minecraft/mod/ResourceFolderModel.h | 21 ++++++-- .../minecraft/mod/ResourcePackFolderModel.cpp | 27 +++++++--- .../minecraft/mod/ResourcePackFolderModel.h | 1 + .../minecraft/mod/TexturePackFolderModel.cpp | 25 ++++++--- .../minecraft/mod/TexturePackFolderModel.h | 1 + .../mod/tasks/LocalResourceUpdateTask.cpp | 8 ++- .../mod/tasks/LocalResourceUpdateTask.h | 6 ++- launcher/modplatform/EnsureMetadataTask.cpp | 2 +- launcher/modplatform/EnsureMetadataTask.h | 2 + .../flame/FlameInstanceCreationTask.cpp | 2 +- .../modrinth/ModrinthInstanceCreationTask.cpp | 1 + launcher/modplatform/packwiz/Packwiz.cpp | 2 + launcher/modplatform/packwiz/Packwiz.h | 1 + launcher/ui/dialogs/ResourceUpdateDialog.cpp | 2 +- .../pages/instance/ExternalResourcesPage.cpp | 20 +++++++ .../ui/pages/instance/ExternalResourcesPage.h | 3 ++ .../pages/instance/ExternalResourcesPage.ui | 16 ++++++ launcher/ui/pages/instance/ModFolderPage.cpp | 2 + .../ui/pages/instance/ResourcePackPage.cpp | 3 ++ launcher/ui/pages/instance/ShaderPackPage.cpp | 3 ++ .../ui/pages/instance/TexturePackPage.cpp | 3 ++ 26 files changed, 208 insertions(+), 32 deletions(-) diff --git a/launcher/minecraft/mod/ModFolderModel.cpp b/launcher/minecraft/mod/ModFolderModel.cpp index d5f609df3..bc1e32406 100644 --- a/launcher/minecraft/mod/ModFolderModel.cpp +++ b/launcher/minecraft/mod/ModFolderModel.cpp @@ -63,17 +63,17 @@ ModFolderModel::ModFolderModel(const QDir& dir, BaseInstance* instance, bool isI : ResourceFolderModel(QDir(dir), instance, isIndexed, createDir, parent) { m_columnNames = QStringList({ "Enable", "Image", "Name", "Version", "Last Modified", "Provider", "Size", "Side", "Loaders", - "Minecraft Versions", "Release Type", "Requires", "Required By", "File Name" }); - m_columnNamesTranslated = - QStringList({ tr("Enable"), tr("Image"), tr("Name"), tr("Version"), tr("Last Modified"), tr("Provider"), tr("Size"), tr("Side"), - tr("Loaders"), tr("Minecraft Versions"), tr("Release Type"), tr("Requires"), tr("Required By"), tr("File Name") }); - m_columnSortKeys = { SortType::Enabled, SortType::Name, SortType::Name, SortType::Version, SortType::Date, - SortType::Provider, SortType::Size, SortType::Side, SortType::Loaders, SortType::McVersions, - SortType::ReleaseType, SortType::Requires, SortType::RequiredBy, SortType::Filename }; + "Minecraft Versions", "Release Type", "Requires", "Required By", "File Name", "Update" }); + m_columnNamesTranslated = QStringList({ tr("Enable"), tr("Image"), tr("Name"), tr("Version"), tr("Last Modified"), tr("Provider"), + tr("Size"), tr("Side"), tr("Loaders"), tr("Minecraft Versions"), tr("Release Type"), + tr("Requires"), tr("Required By"), tr("File Name"), tr("Update") }); + m_columnSortKeys = { SortType::Enabled, SortType::Name, SortType::Name, SortType::Version, SortType::Date, + SortType::Provider, SortType::Size, SortType::Side, SortType::Loaders, SortType::McVersions, + SortType::ReleaseType, SortType::Requires, SortType::RequiredBy, SortType::Filename, SortType::LOCK_UPDATE }; m_columnResizeModes = { QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Stretch, QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive, - QHeaderView::Interactive, QHeaderView::Interactive }; + QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive }; m_columnsHideable = { false, true, false, true, true, true, true, true, true, true, true, true, true, true }; connect(this, &ModFolderModel::parseFinished, this, &ModFolderModel::onParseFinished); @@ -136,6 +136,12 @@ QVariant ModFolderModel::data(const QModelIndex& index, int role) const return QSize(32, 32); } break; + case Qt::CheckStateRole: + if (column == ActiveColumn) + return at(row).enabled() ? Qt::Checked : Qt::Unchecked; + else if (column == LockUpdateCoumn) + return !at(row).lockUpdate() ? Qt::Checked : Qt::Unchecked; + return QVariant(); default: break; } @@ -191,6 +197,7 @@ QVariant ModFolderModel::headerData(int section, [[maybe_unused]] Qt::Orientatio case RequiredByColumn: case RequiresColumn: case FileNameColumn: + case LockUpdateCoumn: return columnNames().at(section); default: return QVariant(); @@ -224,6 +231,8 @@ QVariant ModFolderModel::headerData(int section, [[maybe_unused]] Qt::Orientatio return tr("For each mod, the number of other mods it depends on."); case FileNameColumn: return tr("The file name of the mod."); + case LockUpdateCoumn: + return tr("Should this mod be updated?"); default: return QVariant(); } diff --git a/launcher/minecraft/mod/ModFolderModel.h b/launcher/minecraft/mod/ModFolderModel.h index a5c6ba483..1542e0aa9 100644 --- a/launcher/minecraft/mod/ModFolderModel.h +++ b/launcher/minecraft/mod/ModFolderModel.h @@ -73,6 +73,7 @@ class ModFolderModel : public ResourceFolderModel { RequiresColumn, RequiredByColumn, FileNameColumn, + LockUpdateCoumn, NumColumns }; ModFolderModel(const QDir& dir, BaseInstance* instance, bool isIndexed, bool createDir, QObject* parent = nullptr); diff --git a/launcher/minecraft/mod/Resource.cpp b/launcher/minecraft/mod/Resource.cpp index 06d9a0af7..464fecf62 100644 --- a/launcher/minecraft/mod/Resource.cpp +++ b/launcher/minecraft/mod/Resource.cpp @@ -114,6 +114,14 @@ auto Resource::homepage() const -> QString return {}; } +bool Resource::lockUpdate() const +{ + if (metadata()) + return metadata()->lockUpdate; + + return false; +} + void Resource::setMetadata(std::shared_ptr&& metadata) { if (status() == ResourceStatus::NoMetadata) { diff --git a/launcher/minecraft/mod/Resource.h b/launcher/minecraft/mod/Resource.h index 694d74ec0..dc9605d25 100644 --- a/launcher/minecraft/mod/Resource.h +++ b/launcher/minecraft/mod/Resource.h @@ -79,6 +79,7 @@ enum class SortType : std::uint8_t { Requires, RequiredBy, Filename, + LOCK_UPDATE }; enum class EnableAction : std::uint8_t { ENABLE, DISABLE, TOGGLE }; diff --git a/launcher/minecraft/mod/ResourceFolderModel.cpp b/launcher/minecraft/mod/ResourceFolderModel.cpp index ddc132089..9577a223a 100644 --- a/launcher/minecraft/mod/ResourceFolderModel.cpp +++ b/launcher/minecraft/mod/ResourceFolderModel.cpp @@ -596,6 +596,8 @@ QVariant ResourceFolderModel::data(const QModelIndex& index, int role) const case Qt::CheckStateRole: if (column == ActiveColumn) { return m_resources[row]->enabled() ? Qt::Checked : Qt::Unchecked; + } else if (column == LockUpdateCoumn) { + return !at(row).lockUpdate() ? Qt::Checked : Qt::Unchecked; } return {}; default: @@ -611,6 +613,9 @@ bool ResourceFolderModel::setData(const QModelIndex& index, [[maybe_unused]] con } if (role == Qt::CheckStateRole) { + if (columnNames(false).at(index.column()) == "Update") { + return setModUpdate({ index }, EnableAction::TOGGLE); + } return setResourceEnabled({ index }, EnableAction::TOGGLE); } @@ -628,10 +633,12 @@ QVariant ResourceFolderModel::headerData(int section, [[maybe_unused]] Qt::Orien case ProviderColumn: case SizeColumn: case FileNameColumn: + case LockUpdateCoumn: return columnNames().at(section); default: return {}; } + case Qt::ToolTipRole: { //: Here, resource is a generic term for external resources, like Mods, Resource Packs, Shader Packs, etc. switch (section) { @@ -647,6 +654,8 @@ QVariant ResourceFolderModel::headerData(int section, [[maybe_unused]] Qt::Orien return tr("The size of the resource."); case FileNameColumn: return tr("The file name of the resource."); + case LockUpdateCoumn: + return tr("Should this mod be updated?"); default: return {}; } @@ -990,3 +999,48 @@ QList ResourceFolderModel::selectedResources(const QModelIndexList& i } return result; } + +bool ResourceFolderModel::setModUpdate(const QModelIndexList& indexes, EnableAction action) +{ + if (indexes.isEmpty()) + return true; + + bool succeeded = true; + auto updateColumn = columnNames(false).indexOf("Update"); + for (const auto& idx : indexes) { + if (!validateIndex(idx) || idx.column() != updateColumn) + continue; + + int row = idx.row(); + auto& resource = m_resources[row]; + + bool update = true; + switch (action) { + case EnableAction::ENABLE: + update = false; + break; + case EnableAction::DISABLE: + update = true; + break; + case EnableAction::TOGGLE: + default: + update = !resource->lockUpdate(); + break; + } + + if (resource->lockUpdate() == update) { + succeeded = false; + continue; + } + + auto meta = resource->metadata(); + if (meta) { + meta->lockUpdate = update; + Metadata::update(indexDir(), *meta.get()); + resource->setMetadata(*meta.get()); + emit dataChanged(index(row, updateColumn), index(row, columnCount(QModelIndex()) - 1)); + } + } + + return succeeded; +} \ No newline at end of file diff --git a/launcher/minecraft/mod/ResourceFolderModel.h b/launcher/minecraft/mod/ResourceFolderModel.h index 7699394ab..5a77c070a 100644 --- a/launcher/minecraft/mod/ResourceFolderModel.h +++ b/launcher/minecraft/mod/ResourceFolderModel.h @@ -137,7 +137,16 @@ class ResourceFolderModel : public QAbstractListModel { /* Qt behavior */ /* Basic columns */ - enum Columns : std::uint8_t { ActiveColumn = 0, NameColumn, DateColumn, ProviderColumn, SizeColumn, FileNameColumn, NumColumns }; + enum Columns : std::uint8_t { + ActiveColumn = 0, + NameColumn, + DateColumn, + ProviderColumn, + SizeColumn, + FileNameColumn, + LockUpdateCoumn, + NumColumns + }; QStringList columnNames(bool translated = true) const { return translated ? m_columnNamesTranslated : m_columnNames; } @@ -185,6 +194,8 @@ class ResourceFolderModel : public QAbstractListModel { QString instDirPath() const; BaseInstance* instance() const { return m_instance; } + bool setModUpdate(const QModelIndexList& indexes, EnableAction action); + signals: void updateFinished(); void parseFinished(); @@ -242,10 +253,12 @@ class ResourceFolderModel : public QAbstractListModel { // As such, the order in with they appear is very important! QList m_columnSortKeys = { SortType::Enabled, SortType::Name, SortType::Date, SortType::Provider, SortType::Size, SortType::Filename }; - QStringList m_columnNames = { "Enable", "Name", "Last Modified", "Provider", "Size", "File Name" }; - QStringList m_columnNamesTranslated = { tr("Enable"), tr("Name"), tr("Last Modified"), tr("Provider"), tr("Size"), tr("File Name") }; + QStringList m_columnNames = { "Enable", "Name", "Last Modified", "Provider", "Size", "File Name", "Update" }; + QStringList m_columnNamesTranslated = { tr("Enable"), tr("Name"), tr("Last Modified"), tr("Provider"), + tr("Size"), tr("File Name"), tr("Update") }; QList m_columnResizeModes = { QHeaderView::Interactive, QHeaderView::Stretch, QHeaderView::Interactive, - QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive }; + QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive, + QHeaderView::Interactive }; QList m_columnsHideable = { false, false, true, true, true, true }; QDir m_dir; diff --git a/launcher/minecraft/mod/ResourcePackFolderModel.cpp b/launcher/minecraft/mod/ResourcePackFolderModel.cpp index 4dd8e314c..08e8d2b90 100644 --- a/launcher/minecraft/mod/ResourcePackFolderModel.cpp +++ b/launcher/minecraft/mod/ResourcePackFolderModel.cpp @@ -39,18 +39,21 @@ #include #include +#include "minecraft/mod/Resource.h" +#include "minecraft/mod/ResourceFolderModel.h" #include "minecraft/mod/tasks/LocalDataPackParseTask.h" ResourcePackFolderModel::ResourcePackFolderModel(const QDir& dir, BaseInstance* instance, bool isIndexed, bool createDir, QObject* parent) : ResourceFolderModel(dir, instance, isIndexed, createDir, parent) { - m_columnNames = QStringList({ "Enable", "Image", "Name", "Pack Format", "Last Modified", "Provider", "Size", "File Name" }); - m_columnNamesTranslated = QStringList( - { tr("Enable"), tr("Image"), tr("Name"), tr("Pack Format"), tr("Last Modified"), tr("Provider"), tr("Size"), tr("File Name") }); - m_columnSortKeys = { SortType::Enabled, SortType::Name, SortType::Name, SortType::PackFormat, - SortType::Date, SortType::Provider, SortType::Size, SortType::Filename }; - m_columnResizeModes = { QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Stretch, QHeaderView::Interactive, - QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive }; + m_columnNames = QStringList({ "Enable", "Image", "Name", "Pack Format", "Last Modified", "Provider", "Size", "File Name", "Update" }); + m_columnNamesTranslated = QStringList({ tr("Enable"), tr("Image"), tr("Name"), tr("Pack Format"), tr("Last Modified"), tr("Provider"), + tr("Size"), tr("File Name"), tr("Update") }); + m_columnSortKeys = { SortType::Enabled, SortType::Name, SortType::Name, SortType::PackFormat, SortType::Date, + SortType::Provider, SortType::Size, SortType::Filename, SortType::LOCK_UPDATE }; + m_columnResizeModes = { QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Stretch, + QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive, + QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive }; m_columnsHideable = { false, true, false, true, true, true, true, true }; } @@ -91,6 +94,13 @@ QVariant ResourcePackFolderModel::data(const QModelIndex& index, int role) const return QSize(32, 32); } break; + case Qt::CheckStateRole: + if (column == ActiveColumn) { + return at(row).enabled() ? Qt::Checked : Qt::Unchecked; + } else if (column == LockUpdateCoumn) { + return !at(row).lockUpdate() ? Qt::Checked : Qt::Unchecked; + } + return {}; default: break; } @@ -140,6 +150,7 @@ QVariant ResourcePackFolderModel::headerData(int section, [[maybe_unused]] Qt::O case ProviderColumn: case SizeColumn: case FileNameColumn: + case LockUpdateCoumn: return columnNames().at(section); default: return {}; @@ -162,6 +173,8 @@ QVariant ResourcePackFolderModel::headerData(int section, [[maybe_unused]] Qt::O return tr("The size of the resource pack."); case FileNameColumn: return tr("The file name of the resource pack."); + case LockUpdateCoumn: + return tr("Should this mod be updated?"); default: return {}; } diff --git a/launcher/minecraft/mod/ResourcePackFolderModel.h b/launcher/minecraft/mod/ResourcePackFolderModel.h index 186bbb75d..cf25448db 100644 --- a/launcher/minecraft/mod/ResourcePackFolderModel.h +++ b/launcher/minecraft/mod/ResourcePackFolderModel.h @@ -16,6 +16,7 @@ class ResourcePackFolderModel : public ResourceFolderModel { ProviderColumn, SizeColumn, FileNameColumn, + LockUpdateCoumn, NumColumns }; diff --git a/launcher/minecraft/mod/TexturePackFolderModel.cpp b/launcher/minecraft/mod/TexturePackFolderModel.cpp index 976bf3854..79a803d1d 100644 --- a/launcher/minecraft/mod/TexturePackFolderModel.cpp +++ b/launcher/minecraft/mod/TexturePackFolderModel.cpp @@ -35,18 +35,19 @@ */ #include "TexturePackFolderModel.h" +#include "minecraft/mod/Resource.h" #include "minecraft/mod/tasks/LocalTexturePackParseTask.h" TexturePackFolderModel::TexturePackFolderModel(const QDir& dir, BaseInstance* instance, bool isIndexed, bool createDir, QObject* parent) : ResourceFolderModel(QDir(dir), instance, isIndexed, createDir, parent) { - m_columnNames = QStringList({ "Enable", "Image", "Name", "Last Modified", "Provider", "Size", "File Name" }); - m_columnNamesTranslated = - QStringList({ tr("Enable"), tr("Image"), tr("Name"), tr("Last Modified"), tr("Provider"), tr("Size"), tr("File Name") }); - m_columnSortKeys = { SortType::Enabled, SortType::Name, SortType::Name, SortType::Date, - SortType::Provider, SortType::Size, SortType::Filename }; - m_columnResizeModes = { QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Stretch, QHeaderView::Interactive, - QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive }; + m_columnNames = QStringList({ "Enable", "Image", "Name", "Last Modified", "Provider", "Size", "File Name", "Update" }); + m_columnNamesTranslated = QStringList( + { tr("Enable"), tr("Image"), tr("Name"), tr("Last Modified"), tr("Provider"), tr("Size"), tr("File Name"), tr("Update") }); + m_columnSortKeys = { SortType::Enabled, SortType::Name, SortType::Name, SortType::Date, + SortType::Provider, SortType::Size, SortType::Filename, SortType::LOCK_UPDATE }; + m_columnResizeModes = { QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Stretch, QHeaderView::Interactive, + QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive }; m_columnsHideable = { false, true, false, true, true, true, true }; } @@ -78,6 +79,13 @@ QVariant TexturePackFolderModel::data(const QModelIndex& index, int role) const return QSize(32, 32); } break; + case Qt::CheckStateRole: + if (column == ActiveColumn) { + return m_resources[row]->enabled() ? Qt::Checked : Qt::Unchecked; + } else if (column == LockUpdateCoumn) { + return !m_resources[row]->lockUpdate() ? Qt::Checked : Qt::Unchecked; + } + return {}; default: break; } @@ -126,6 +134,7 @@ QVariant TexturePackFolderModel::headerData(int section, [[maybe_unused]] Qt::Or case ProviderColumn: case SizeColumn: case FileNameColumn: + case LockUpdateCoumn: return columnNames().at(section); default: return {}; @@ -144,6 +153,8 @@ QVariant TexturePackFolderModel::headerData(int section, [[maybe_unused]] Qt::Or return tr("The size of the texture pack."); case FileNameColumn: return tr("The file name of the texture pack."); + case LockUpdateCoumn: + return tr("Should this mod be updated?"); default: return {}; } diff --git a/launcher/minecraft/mod/TexturePackFolderModel.h b/launcher/minecraft/mod/TexturePackFolderModel.h index 3e7343092..d47883c28 100644 --- a/launcher/minecraft/mod/TexturePackFolderModel.h +++ b/launcher/minecraft/mod/TexturePackFolderModel.h @@ -52,6 +52,7 @@ class TexturePackFolderModel : public ResourceFolderModel { ProviderColumn, SizeColumn, FileNameColumn, + LockUpdateCoumn, NumColumns }; diff --git a/launcher/minecraft/mod/tasks/LocalResourceUpdateTask.cpp b/launcher/minecraft/mod/tasks/LocalResourceUpdateTask.cpp index 8c2d6f0e1..2f56dc8db 100644 --- a/launcher/minecraft/mod/tasks/LocalResourceUpdateTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalResourceUpdateTask.cpp @@ -26,8 +26,11 @@ #include #endif -LocalResourceUpdateTask::LocalResourceUpdateTask(QDir index_dir, ModPlatform::IndexedPack& project, ModPlatform::IndexedVersion& version) - : m_index_dir(index_dir), m_project(project), m_version(version) +LocalResourceUpdateTask::LocalResourceUpdateTask(QDir index_dir, + ModPlatform::IndexedPack& project, + ModPlatform::IndexedVersion& version, + bool lockUpdate) + : m_index_dir(index_dir), m_project(project), m_version(version), m_lockUpdate(lockUpdate) { // Ensure a '.index' folder exists in the mods folder, and create it if it does not if (!FS::ensureFolderPathExists(index_dir.path())) { @@ -59,6 +62,7 @@ void LocalResourceUpdateTask::executeTask() auto pw_mod = Metadata::create(m_index_dir, m_project, m_version); if (pw_mod.isValid()) { + pw_mod.lockUpdate = m_lockUpdate; Metadata::update(m_index_dir, pw_mod); emitSucceeded(); } else { diff --git a/launcher/minecraft/mod/tasks/LocalResourceUpdateTask.h b/launcher/minecraft/mod/tasks/LocalResourceUpdateTask.h index f8869258e..1f5d16d62 100644 --- a/launcher/minecraft/mod/tasks/LocalResourceUpdateTask.h +++ b/launcher/minecraft/mod/tasks/LocalResourceUpdateTask.h @@ -28,7 +28,10 @@ class LocalResourceUpdateTask : public Task { public: using Ptr = shared_qobject_ptr; - explicit LocalResourceUpdateTask(QDir index_dir, ModPlatform::IndexedPack& project, ModPlatform::IndexedVersion& version); + explicit LocalResourceUpdateTask(QDir index_dir, + ModPlatform::IndexedPack& project, + ModPlatform::IndexedVersion& version, + bool lockUpdate = false); auto canAbort() const -> bool override { return true; } auto abort() -> bool override; @@ -44,4 +47,5 @@ class LocalResourceUpdateTask : public Task { QDir m_index_dir; ModPlatform::IndexedPack m_project; ModPlatform::IndexedVersion m_version; + bool m_lockUpdate = false; }; diff --git a/launcher/modplatform/EnsureMetadataTask.cpp b/launcher/modplatform/EnsureMetadataTask.cpp index 2c7e485e5..ce7a556fc 100644 --- a/launcher/modplatform/EnsureMetadataTask.cpp +++ b/launcher/modplatform/EnsureMetadataTask.cpp @@ -484,7 +484,7 @@ void EnsureMetadataTask::updateMetadata(ModPlatform::IndexedPack& pack, ModPlatf if (ver.fileName.endsWith(".disabled")) ver.fileName.chop(9); - auto task = makeShared(m_indexDir, pack, ver); + auto task = makeShared(m_indexDir, pack, ver, m_lockUpdate); connect(task.get(), &Task::finished, this, [this, &pack, resource] { updateMetadataCallback(pack, resource); }); diff --git a/launcher/modplatform/EnsureMetadataTask.h b/launcher/modplatform/EnsureMetadataTask.h index 3d8a8ba53..fbdc4b65e 100644 --- a/launcher/modplatform/EnsureMetadataTask.h +++ b/launcher/modplatform/EnsureMetadataTask.h @@ -22,6 +22,7 @@ class EnsureMetadataTask : public Task { ~EnsureMetadataTask() = default; Task::Ptr getHashingTask() { return m_hashingTask; } + void setLockUpdate(bool lockUpdate) { m_lockUpdate = lockUpdate; } public slots: bool abort() override; @@ -62,4 +63,5 @@ class EnsureMetadataTask : public Task { Task::Ptr m_hashingTask; Task::Ptr m_currentTask; QHash m_updateMetadataTasks; + bool m_lockUpdate = false; }; diff --git a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp index 534132a6e..06d91341e 100644 --- a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp +++ b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp @@ -718,7 +718,7 @@ void FlameCreationTask::validateOtherResources(QEventLoop& loop) if (file.targetFolder != "mods" || (file.version.fileName.endsWith(".zip") && !zipMods.contains(file.version.fileName))) { continue; } - task->addTask(makeShared(folder, file.pack, file.version)); + task->addTask(makeShared(folder, file.pack, file.version, true)); } connect(task.get(), &Task::finished, &loop, &QEventLoop::quit); m_processUpdateFileInfoJob = task; diff --git a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp index 0cb2c547d..e4b5d2b43 100644 --- a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp +++ b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp @@ -332,6 +332,7 @@ std::unique_ptr ModrinthCreationTask::createInstance() QEventLoop ensureMetaLoop; QDir folder = FS::PathCombine(instance->modsRoot(), ".index"); auto ensureMetadataTask = makeShared(resources, folder, ModPlatform::ResourceProvider::MODRINTH); + ensureMetadataTask->setLockUpdate(true); connect(ensureMetadataTask.get(), &Task::succeeded, this, [&endedWell]() { endedWell = true; }); connect(ensureMetadataTask.get(), &Task::finished, &ensureMetaLoop, &QEventLoop::quit); connect(ensureMetadataTask.get(), &Task::progress, [this](qint64 current, qint64 total) { diff --git a/launcher/modplatform/packwiz/Packwiz.cpp b/launcher/modplatform/packwiz/Packwiz.cpp index 4d162a90d..8ffbcab9a 100644 --- a/launcher/modplatform/packwiz/Packwiz.cpp +++ b/launcher/modplatform/packwiz/Packwiz.cpp @@ -229,6 +229,7 @@ void V1::updateModIndex(const QDir& index_dir, Mod& mod) { "x-prismlauncher-release-type", mod.releaseType.toString().toStdString() }, { "x-prismlauncher-version-number", mod.version_number.toStdString() }, { "x-prismlauncher-dependencies", deps }, + { "x-prismlauncher-lock-update", mod.lockUpdate }, { "download", toml::table{ { "mode", mod.mode.toStdString() }, @@ -302,6 +303,7 @@ auto V1::getIndexForMod(const QDir& index_dir, QString slug) -> Mod mod.filename = stringEntry(table, "filename"); mod.side = ModPlatform::SideUtils::fromString(stringEntry(table, "side")); mod.releaseType = ModPlatform::IndexedVersionType::fromString(table["x-prismlauncher-release-type"].value_or("")); + mod.lockUpdate = table["x-prismlauncher-lock-update"].value_or(false); if (auto loaders = table["x-prismlauncher-loaders"]; loaders && loaders.is_array()) { for (auto&& loader : *loaders.as_array()) { if (loader.is_string()) { diff --git a/launcher/modplatform/packwiz/Packwiz.h b/launcher/modplatform/packwiz/Packwiz.h index b5b817755..78addea53 100644 --- a/launcher/modplatform/packwiz/Packwiz.h +++ b/launcher/modplatform/packwiz/Packwiz.h @@ -54,6 +54,7 @@ class V1 { QString version_number{}; QList dependencies; + bool lockUpdate; public: // This is a totally heuristic, but should work for now. diff --git a/launcher/ui/dialogs/ResourceUpdateDialog.cpp b/launcher/ui/dialogs/ResourceUpdateDialog.cpp index e9776c660..0c6225db6 100644 --- a/launcher/ui/dialogs/ResourceUpdateDialog.cpp +++ b/launcher/ui/dialogs/ResourceUpdateDialog.cpp @@ -398,7 +398,7 @@ auto ResourceUpdateDialog::ensureMetadata() -> bool void ResourceUpdateDialog::onMetadataEnsured(Resource* resource) { // When the mod is a folder, for instance - if (!resource->metadata()) { + if (!resource->metadata() || resource->lockUpdate()) { return; } diff --git a/launcher/ui/pages/instance/ExternalResourcesPage.cpp b/launcher/ui/pages/instance/ExternalResourcesPage.cpp index da7fa3ee0..138a0cfdd 100644 --- a/launcher/ui/pages/instance/ExternalResourcesPage.cpp +++ b/launcher/ui/pages/instance/ExternalResourcesPage.cpp @@ -81,6 +81,9 @@ ExternalResourcesPage::ExternalResourcesPage(BaseInstance* instance, ResourceFol connect(ui->treeView, &ModListView::customContextMenuRequested, this, &ExternalResourcesPage::ShowContextMenu); connect(ui->treeView, &ModListView::activated, this, &ExternalResourcesPage::itemActivated); + connect(ui->actionEnableUpdates, &QAction::triggered, this, &ExternalResourcesPage::enableUpdates); + connect(ui->actionDisableUpdates, &QAction::triggered, this, &ExternalResourcesPage::disableUpdates); + auto selection_model = ui->treeView->selectionModel(); connect(selection_model, &QItemSelectionModel::currentChanged, this, [this](const QModelIndex& current, const QModelIndex& previous) { @@ -316,6 +319,8 @@ void ExternalResourcesPage::updateActions() const bool hasSelection = ui->treeView->selectionModel()->hasSelection(); const QModelIndexList selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()).indexes(); const QList selectedResources = m_model->selectedResources(selection); + const bool hasMeta = hasSelection && std::any_of(selectedResources.begin(), selectedResources.end(), + [](Resource* resource) { return resource->metadata(); }); ui->actionUpdateItem->setEnabled(!m_model->empty()); ui->actionResetItemMetadata->setEnabled(hasSelection); @@ -328,6 +333,9 @@ void ExternalResourcesPage::updateActions() ui->actionViewHomepage->setEnabled(hasSelection && std::any_of(selectedResources.begin(), selectedResources.end(), [](Resource* resource) { return !resource->homepage().isEmpty(); })); + + ui->actionEnableUpdates->setEnabled(hasMeta); + ui->actionDisableUpdates->setEnabled(hasMeta); ui->actionExportMetadata->setEnabled(!m_model->empty()); } @@ -348,3 +356,15 @@ QString ExternalResourcesPage::extraHeaderInfoString() } return tr(" (%1 installed)").arg(m_model->size()); } + +void ExternalResourcesPage::enableUpdates() +{ + auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()); + m_model->setModUpdate(selection.indexes(), EnableAction::ENABLE); +} + +void ExternalResourcesPage::disableUpdates() +{ + auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()); + m_model->setModUpdate(selection.indexes(), EnableAction::DISABLE); +} \ No newline at end of file diff --git a/launcher/ui/pages/instance/ExternalResourcesPage.h b/launcher/ui/pages/instance/ExternalResourcesPage.h index 7f4320648..4cac99e49 100644 --- a/launcher/ui/pages/instance/ExternalResourcesPage.h +++ b/launcher/ui/pages/instance/ExternalResourcesPage.h @@ -64,6 +64,9 @@ class ExternalResourcesPage : public QMainWindow, public BasePage { void ShowContextMenu(const QPoint& pos); void ShowHeaderContextMenu(const QPoint& pos); + void enableUpdates(); + void disableUpdates(); + protected: BaseInstance* m_instance = nullptr; diff --git a/launcher/ui/pages/instance/ExternalResourcesPage.ui b/launcher/ui/pages/instance/ExternalResourcesPage.ui index c6955d0ce..58f3e4d9c 100644 --- a/launcher/ui/pages/instance/ExternalResourcesPage.ui +++ b/launcher/ui/pages/instance/ExternalResourcesPage.ui @@ -218,6 +218,22 @@ View the homepages of all selected items. + + + Ena&ble Updates + + + Mark resource to be updated + + + + + Disable U&pdates + + + Mark resource to prevent it from being updated + + diff --git a/launcher/ui/pages/instance/ModFolderPage.cpp b/launcher/ui/pages/instance/ModFolderPage.cpp index 99c78647c..672ae48a5 100644 --- a/launcher/ui/pages/instance/ModFolderPage.cpp +++ b/launcher/ui/pages/instance/ModFolderPage.cpp @@ -110,6 +110,8 @@ ModFolderPage::ModFolderPage(BaseInstance* inst, ModFolderModel* model, QWidget* ui->actionsToolbar->insertActionAfter(ui->actionViewHomepage, ui->actionExportMetadata); ui->actionsToolbar->insertActionAfter(ui->actionViewFolder, ui->actionViewConfigs); + ui->actionsToolbar->insertActionAfter(ui->actionUpdateItem, ui->actionEnableUpdates); + ui->actionsToolbar->insertActionAfter(ui->actionEnableUpdates, ui->actionDisableUpdates); } bool ModFolderPage::shouldDisplay() const diff --git a/launcher/ui/pages/instance/ResourcePackPage.cpp b/launcher/ui/pages/instance/ResourcePackPage.cpp index e4709ab2b..e500ce934 100644 --- a/launcher/ui/pages/instance/ResourcePackPage.cpp +++ b/launcher/ui/pages/instance/ResourcePackPage.cpp @@ -69,6 +69,9 @@ ResourcePackPage::ResourcePackPage(MinecraftInstance* instance, ResourcePackFold ui->actionChangeVersion->setToolTip(tr("Change a mod's version.")); connect(ui->actionChangeVersion, &QAction::triggered, this, &ResourcePackPage::changeResourcePackVersion); ui->actionsToolbar->insertActionAfter(ui->actionUpdateItem, ui->actionChangeVersion); + + ui->actionsToolbar->insertActionAfter(ui->actionUpdateItem, ui->actionEnableUpdates); + ui->actionsToolbar->insertActionAfter(ui->actionEnableUpdates, ui->actionDisableUpdates); } void ResourcePackPage::updateFrame(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous) diff --git a/launcher/ui/pages/instance/ShaderPackPage.cpp b/launcher/ui/pages/instance/ShaderPackPage.cpp index a29564abc..b4f89d7ad 100644 --- a/launcher/ui/pages/instance/ShaderPackPage.cpp +++ b/launcher/ui/pages/instance/ShaderPackPage.cpp @@ -74,6 +74,9 @@ ShaderPackPage::ShaderPackPage(MinecraftInstance* instance, ShaderPackFolderMode ui->actionChangeVersion->setToolTip(tr("Change a shader pack's version.")); connect(ui->actionChangeVersion, &QAction::triggered, this, &ShaderPackPage::changeShaderPackVersion); ui->actionsToolbar->insertActionAfter(ui->actionUpdateItem, ui->actionChangeVersion); + + ui->actionsToolbar->insertActionAfter(ui->actionUpdateItem, ui->actionEnableUpdates); + ui->actionsToolbar->insertActionAfter(ui->actionEnableUpdates, ui->actionDisableUpdates); } void ShaderPackPage::downloadShaderPack() diff --git a/launcher/ui/pages/instance/TexturePackPage.cpp b/launcher/ui/pages/instance/TexturePackPage.cpp index 01325e3f6..d2157af55 100644 --- a/launcher/ui/pages/instance/TexturePackPage.cpp +++ b/launcher/ui/pages/instance/TexturePackPage.cpp @@ -75,6 +75,9 @@ TexturePackPage::TexturePackPage(MinecraftInstance* instance, TexturePackFolderM ui->actionsToolbar->insertActionAfter(ui->actionUpdateItem, ui->actionChangeVersion); ui->actionViewHomepage->setToolTip(tr("View the homepages of all selected texture packs.")); + + ui->actionsToolbar->insertActionAfter(ui->actionUpdateItem, ui->actionEnableUpdates); + ui->actionsToolbar->insertActionAfter(ui->actionEnableUpdates, ui->actionDisableUpdates); } void TexturePackPage::updateFrame(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous)