diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index dcbfe8fde6..830f718aae 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -59,6 +59,10 @@ set(CORE_SOURCES Json.h Json.cpp + # Toml parsing helpers + Toml.h + Toml.cpp + FileSystem.h FileSystem.cpp @@ -323,6 +327,7 @@ set(MINECRAFT_SOURCES minecraft/mod/Mod.h minecraft/mod/Mod.cpp minecraft/mod/ModDetails.h + minecraft/mod/ModDetails.cpp minecraft/mod/ModFolderModel.h minecraft/mod/ModFolderModel.cpp minecraft/mod/Resource.h @@ -419,6 +424,9 @@ set(SETTINGS_SOURCES settings/Setting.h settings/SettingsObject.cpp settings/SettingsObject.h + settings/TomlFile.cpp + settings/TomlFile.h + settings/SettingsFile.h ) set(JAVA_SOURCES diff --git a/launcher/InstanceList.h b/launcher/InstanceList.h index c85fe55c7b..846d8542d3 100644 --- a/launcher/InstanceList.h +++ b/launcher/InstanceList.h @@ -52,10 +52,6 @@ using InstanceId = QString; using GroupId = QString; using InstanceLocator = std::pair; -enum class InstCreateError { NoCreateError = 0, NoSuchVersion, UnknownCreateError, InstExists, CantCreateDir }; - -enum class GroupsState { NotLoaded, Steady, Dirty }; - struct TrashHistoryItem { QString id; QString path; diff --git a/launcher/Toml.cpp b/launcher/Toml.cpp new file mode 100644 index 0000000000..49ae86e3d2 --- /dev/null +++ b/launcher/Toml.cpp @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2024 Trial97 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "Toml.h" + +namespace Toml { +QString getString(toml::table table, QString key, QString def) +{ + return QString::fromStdString(table[key.toStdString()].value_or(def.toStdString())); +} + +QStringList toStringList(toml::array* arr) +{ + QStringList list; + if (arr) { + for (auto&& v : *arr) { + list.push_back(QString::fromStdString(v.value_or(""))); + } + } + return list; +} + +toml::array fromStringList(QStringList list) +{ + toml::array arr; + for (auto v : list) { + arr.push_back(v.toStdString()); + } + return arr; +} +} // namespace Toml \ No newline at end of file diff --git a/launcher/Toml.h b/launcher/Toml.h new file mode 100644 index 0000000000..2dfa72ddef --- /dev/null +++ b/launcher/Toml.h @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2024 Trial97 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include + +#include + +namespace Toml { + +QString getString(toml::table table, QString key, QString def = {}); + +QStringList toStringList(toml::array* arr); + +toml::array fromStringList(QStringList list); + +} // namespace Toml \ No newline at end of file diff --git a/launcher/minecraft/mod/Mod.h b/launcher/minecraft/mod/Mod.h index a0d9797ed7..ee35e67e29 100644 --- a/launcher/minecraft/mod/Mod.h +++ b/launcher/minecraft/mod/Mod.h @@ -78,7 +78,7 @@ class Mod : public Resource { auto releaseType() const -> ModPlatform::IndexedVersionType; /** Get the intneral path to the mod's icon file*/ - QString iconPath() const { return m_local_details.icon_file; } + QString iconPath() const { return m_local_details.icon_path; } /** Gets the icon of the mod, converted to a QPixmap for drawing, and scaled to size. */ [[nodiscard]] QPixmap icon(QSize size, Qt::AspectRatioMode mode = Qt::AspectRatioMode::IgnoreAspectRatio) const; /** Thread-safe. */ diff --git a/launcher/minecraft/mod/ModDetails.cpp b/launcher/minecraft/mod/ModDetails.cpp new file mode 100644 index 0000000000..85e803b241 --- /dev/null +++ b/launcher/minecraft/mod/ModDetails.cpp @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2024 Trial97 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ModDetails.h" +#include "Toml.h" +#include "modplatform/ModIndex.h" +#include "modplatform/helpers/HashUtils.h" + +ModLicense::ModLicense(QString license) +{ + // FIXME: come up with a better license parsing. + // handle SPDX identifiers? https://spdx.org/licenses/ + auto parts = license.split(' '); + QStringList notNameParts = {}; + for (auto part : parts) { + auto _url = QUrl(part); + if (part.startsWith("(") && part.endsWith(")")) + _url = QUrl(part.mid(1, part.size() - 2)); + + if (_url.isValid() && !_url.scheme().isEmpty() && !_url.host().isEmpty()) { + this->url = _url.toString(); + notNameParts.append(part); + continue; + } + } + + for (auto part : notNameParts) { + parts.removeOne(part); + } + + auto licensePart = parts.join(' '); + this->name = licensePart; + this->description = licensePart; + + if (parts.size() == 1) { + this->id = parts.first(); + } +} +ModLicense::ModLicense(const QString& name_, const QString& id_, const QString& url_, const QString& description_) + : name(name_), id(id_), url(url_), description(description_) +{} +ModLicense::ModLicense(const ModLicense& other) : name(other.name), id(other.id), url(other.url), description(other.description) {} +ModLicense& ModLicense::operator=(const ModLicense& other) +{ + this->name = other.name; + this->id = other.id; + this->url = other.url; + this->description = other.description; + + return *this; +} +ModLicense& ModLicense::operator=(const ModLicense&& other) +{ + this->name = other.name; + this->id = other.id; + this->url = other.url; + this->description = other.description; + + return *this; +} +bool ModLicense::isEmpty() +{ + return this->name.isEmpty() && this->id.isEmpty() && this->url.isEmpty() && this->description.isEmpty(); +} + +ModLicense::ModLicense(toml::table table) +{ + name = Toml::getString(table, "name"); + id = Toml::getString(table, "id"); + url = Toml::getString(table, "url"); + description = Toml::getString(table, "description"); +} + +toml::table ModLicense::toToml() +{ + return toml::table{ + { "name", name.toStdString() }, + { "id", id.toStdString() }, + { "url", url.toStdString() }, + { "description", description.toStdString() }, + }; +} + +ModDetails::ModDetails(const ModDetails& other) + : mod_id(other.mod_id) + , name(other.name) + , version(other.version) + , mcversion(other.mcversion) + , homeurl(other.homeurl) + , description(other.description) + , authors(other.authors) + , issue_tracker(other.issue_tracker) + , licenses(other.licenses) + , icon_path(other.icon_path) + , status(other.status) + , new_format_id(other.new_format_id) +{} + +ModDetails& ModDetails::operator=(const ModDetails& other) +{ + this->mod_id = other.mod_id; + this->name = other.name; + this->version = other.version; + this->mcversion = other.mcversion; + this->homeurl = other.homeurl; + this->description = other.description; + this->authors = other.authors; + this->issue_tracker = other.issue_tracker; + this->licenses = other.licenses; + this->icon_path = other.icon_path; + this->status = other.status; + this->new_format_id = other.new_format_id; + + return *this; +} + +ModDetails& ModDetails::operator=(const ModDetails&& other) +{ + this->mod_id = other.mod_id; + this->name = other.name; + this->version = other.version; + this->mcversion = other.mcversion; + this->homeurl = other.homeurl; + this->description = other.description; + this->authors = other.authors; + this->issue_tracker = other.issue_tracker; + this->licenses = other.licenses; + this->icon_path = other.icon_path; + this->status = other.status; + this->new_format_id = other.new_format_id; + + return *this; +} + +ModDetails::ModDetails(toml::table table) +{ + mod_id = Toml::getString(table, "mod_id"); + name = Toml::getString(table, "name"); + version = Toml::getString(table, "version"); + mcversion = Toml::getString(table, "mcversion"); + homeurl = Toml::getString(table, "homeurl"); + description = Toml::getString(table, "description"); + issue_tracker = Toml::getString(table, "issue_tracker"); + icon_path = Toml::getString(table, "icon_path"); + new_format_id = table["format_id"].value_or(0); + + authors = Toml::toStringList(table["authors"].as_array()); + if (auto licenseArr = table["licenses"].as_array()) { + for (auto&& l : *licenseArr) { + if (auto table = l.as_table()) { + licenses.push_back({ *table }); + } + } + } +} + +toml::table ModDetails::toToml() +{ + toml::array licenseArr; + for (auto l : licenses) { + if (!l.isEmpty()) { + licenseArr.push_back(l.toToml()); + } + } + return toml::table{ + { "mod_id", mod_id.toStdString() }, + { "name", name.toStdString() }, + { "version", version.toStdString() }, + { "mcversion", mcversion.toStdString() }, + { "homeurl", homeurl.toStdString() }, + { "description", description.toStdString() }, + { "issue_tracker", issue_tracker.toStdString() }, + { "icon_path", icon_path.toStdString() }, + { "format_id", new_format_id }, + { "authors", Toml::fromStringList(authors) }, + { "licenses", licenseArr }, + }; +} + +ResourceHash::ResourceHash(toml::table table) +{ + alg = Hashing::algorithmFromString(Toml::getString(table, "alg")); + hash = Toml::getString(table, "hash"); +} + +toml::table ResourceHash::toToml() +{ + return toml::table{ + { "alg", Hashing::algorithmToString(alg).toStdString() }, + { "hash", hash.toStdString() }, + }; +} + +ProviderInfo::ProviderInfo(toml::table table) +{ + name = ModPlatform::ProviderCapabilities::fromString(Toml::getString(table, "name")); + id = Toml::getString(table, "id"); + version = Toml::getString(table, "version"); + url = Toml::getString(table, "url"); + side = stringToSide(Toml::getString(table, "side")); + if (auto lds = table["loaders"]; lds && lds.is_array()) { + for (auto&& loader : *lds.as_array()) { + if (loader.is_string()) { + loaders |= ModPlatform::getModLoaderFromString(QString::fromStdString(loader.as_string()->value_or(""))); + } + } + } + mcVersions = Toml::toStringList(table.get_as("mcVersions")); + releaseType = Toml::getString(table, "releaseType"); + if (auto deps = table.get_as("dependencies")) { + for (auto&& d : *deps) { + if (auto t = d.as_table()) { + dependencies.push_back(ModPlatform::Dependency(*t)); + } + } + } +} + +toml::table ProviderInfo::toToml() +{ + toml::array deps; + for (auto dep : dependencies) { + if (dep.type == ModPlatform::DependencyType::REQUIRED) { + deps.push_back(dep.toToml()); + } + } + toml::array lds; + for (auto loader : { ModPlatform::NeoForge, ModPlatform::Forge, ModPlatform::Cauldron, ModPlatform::LiteLoader, ModPlatform::Fabric, + ModPlatform::Quilt }) { + if (loaders & loader) { + lds.push_back(getModLoaderAsString(loader).toStdString()); + } + } + return toml::table{ + { "name", ModPlatform::ProviderCapabilities::name(name) }, + { "id", id.toStdString() }, + { "version", version.toStdString() }, + { "url", url.toStdString() }, + { "side", sideToString(side).toStdString() }, + { "loaders", lds }, + { "mcVersions", Toml::fromStringList(mcVersions) }, + { "releaseType", releaseType.toString().toStdString() }, + { "dependencies", deps }, + }; +} +QString sideToString(Side side) +{ + switch (side) { + case Side::ClientSide: + return "client"; + case Side::ServerSide: + return "server"; + case Side::UniversalSide: + return "both"; + } + return {}; +} +Side stringToSide(QString side) +{ + if (side == "client") + return Side::ClientSide; + if (side == "server") + return Side::ServerSide; + if (side == "both") + return Side::UniversalSide; + return Side::UniversalSide; +} diff --git a/launcher/minecraft/mod/ModDetails.h b/launcher/minecraft/mod/ModDetails.h index a00d5a24b2..053d5fcb14 100644 --- a/launcher/minecraft/mod/ModDetails.h +++ b/launcher/minecraft/mod/ModDetails.h @@ -41,7 +41,11 @@ #include #include +#include + #include "minecraft/mod/MetadataHandler.h" +#include "modplatform/ModIndex.h" +#include "modplatform/helpers/HashUtils.h" enum class ModStatus { Installed, // Both JAR and Metadata are present @@ -56,66 +60,17 @@ struct ModLicense { QString url = {}; QString description = {}; - ModLicense() {} - - ModLicense(const QString license) - { - // FIXME: come up with a better license parsing. - // handle SPDX identifiers? https://spdx.org/licenses/ - auto parts = license.split(' '); - QStringList notNameParts = {}; - for (auto part : parts) { - auto _url = QUrl(part); - if (part.startsWith("(") && part.endsWith(")")) - _url = QUrl(part.mid(1, part.size() - 2)); - - if (_url.isValid() && !_url.scheme().isEmpty() && !_url.host().isEmpty()) { - this->url = _url.toString(); - notNameParts.append(part); - continue; - } - } - - for (auto part : notNameParts) { - parts.removeOne(part); - } - - auto licensePart = parts.join(' '); - this->name = licensePart; - this->description = licensePart; - - if (parts.size() == 1) { - this->id = parts.first(); - } - } - - ModLicense(const QString& name_, const QString& id_, const QString& url_, const QString& description_) - : name(name_), id(id_), url(url_), description(description_) - {} - - ModLicense(const ModLicense& other) : name(other.name), id(other.id), url(other.url), description(other.description) {} - - ModLicense& operator=(const ModLicense& other) - { - this->name = other.name; - this->id = other.id; - this->url = other.url; - this->description = other.description; - - return *this; - } - - ModLicense& operator=(const ModLicense&& other) - { - this->name = other.name; - this->id = other.id; - this->url = other.url; - this->description = other.description; - - return *this; - } - - bool isEmpty() { return this->name.isEmpty() && this->id.isEmpty() && this->url.isEmpty() && this->description.isEmpty(); } + ModLicense() = default; + ModLicense(QString license); + ModLicense(const QString& name_, const QString& id_, const QString& url_, const QString& description_); + ModLicense(const ModLicense& other); + ModLicense(toml::table table); + + ModLicense& operator=(const ModLicense& other); + ModLicense& operator=(const ModLicense&& other); + + bool isEmpty(); + toml::table toToml(); }; struct ModDetails { @@ -147,7 +102,7 @@ struct ModDetails { QList licenses = {}; /* Path of mod logo */ - QString icon_file = {}; + QString icon_path = {}; /* Installation status of the mod */ ModStatus status = ModStatus::Unknown; @@ -155,54 +110,55 @@ struct ModDetails { /* Metadata information, if any */ std::shared_ptr metadata = nullptr; + int new_format_id; // for resourcepacks + ModDetails() = default; + ModDetails(const ModDetails& other); + ModDetails& operator=(const ModDetails& other); + ModDetails& operator=(const ModDetails&& other); + ModDetails(toml::table table); + + toml::table toToml(); +}; + +struct ResourceHash { + Hashing::Algorithm alg = Hashing::Algorithm::Sha1; + QString hash = {}; - /** Metadata should be handled manually to properly set the mod status. */ - ModDetails(const ModDetails& other) - : mod_id(other.mod_id) - , name(other.name) - , version(other.version) - , mcversion(other.mcversion) - , homeurl(other.homeurl) - , description(other.description) - , authors(other.authors) - , issue_tracker(other.issue_tracker) - , licenses(other.licenses) - , icon_file(other.icon_file) - , status(other.status) - {} - - ModDetails& operator=(const ModDetails& other) - { - this->mod_id = other.mod_id; - this->name = other.name; - this->version = other.version; - this->mcversion = other.mcversion; - this->homeurl = other.homeurl; - this->description = other.description; - this->authors = other.authors; - this->issue_tracker = other.issue_tracker; - this->licenses = other.licenses; - this->icon_file = other.icon_file; - this->status = other.status; - - return *this; - } - - ModDetails& operator=(const ModDetails&& other) - { - this->mod_id = other.mod_id; - this->name = other.name; - this->version = other.version; - this->mcversion = other.mcversion; - this->homeurl = other.homeurl; - this->description = other.description; - this->authors = other.authors; - this->issue_tracker = other.issue_tracker; - this->licenses = other.licenses; - this->icon_file = other.icon_file; - this->status = other.status; - - return *this; - } + ResourceHash(toml::table table); + toml::table toToml(); }; + +enum class Side { ClientSide = 1 << 0, ServerSide = 1 << 1, UniversalSide = ClientSide | ServerSide }; +QString sideToString(Side side); +Side stringToSide(QString side); + +struct ProviderInfo { + ModPlatform::ResourceProvider name; + QString id = {}; + QString version = {}; + QString url = {}; + Side side = Side::UniversalSide; + ModPlatform::ModLoaderTypes loaders; + QStringList mcVersions = {}; + ModPlatform::IndexedVersionType releaseType; + QList dependencies = {}; + + ProviderInfo(toml::table table); + toml::table toToml(); +}; + +enum class ResourceInfoType { Mod, Coremod, Resourcepack, Shaderpack, Datapack, Worlds, Screenshots, Extra }; +struct ResourceInfo { + QString path; + ResourceInfoType type; + ResourceInfoType fileType; + bool enabled; + bool managedByPack; + Side side; + bool lockVersion = true; + QStringList categories; + ModDetails info; + QList hashes; + QList providers; +}; \ No newline at end of file diff --git a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp index d456211f8e..938eba9362 100644 --- a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp @@ -53,7 +53,7 @@ ModDetails ReadMCModInfo(QByteArray contents) } if (firstObj.contains("logoFile")) { - details.icon_file = firstObj.value("logoFile").toString(); + details.icon_path = firstObj.value("logoFile").toString(); } for (auto author : authors) { @@ -194,7 +194,7 @@ ModDetails ReadMCModTOML(QByteArray contents) } else if (auto logoFileDatumMods = (*modsTable)["logoFile"].as_string()) { logoFile = QString::fromStdString(logoFileDatumMods->get()); } - details.icon_file = logoFile; + details.icon_path = logoFile; return details; } @@ -271,16 +271,16 @@ ModDetails ReadFabricModInfo(QByteArray contents) } if (largest > 0) { auto key = QString::number(largest) + "x" + QString::number(largest); - details.icon_file = obj.value(key).toString(); + details.icon_path = obj.value(key).toString(); } else { // parsing the sizes failed // take the first for (auto i : obj) { - details.icon_file = i.toString(); + details.icon_path = i.toString(); break; } } } else if (icon.isString()) { - details.icon_file = icon.toString(); + details.icon_path = icon.toString(); } } } @@ -358,16 +358,16 @@ ModDetails ReadQuiltModInfo(QByteArray contents) } if (largest > 0) { auto key = QString::number(largest) + "x" + QString::number(largest); - details.icon_file = obj.value(key).toString(); + details.icon_path = obj.value(key).toString(); } else { // parsing the sizes failed // take the first for (auto i : obj) { - details.icon_file = i.toString(); + details.icon_path = i.toString(); break; } } } else if (icon.isString()) { - details.icon_file = icon.toString(); + details.icon_path = icon.toString(); } } } diff --git a/launcher/modplatform/EnsureMetadataTask.cpp b/launcher/modplatform/EnsureMetadataTask.cpp index f6f49f38d2..d81545aab1 100644 --- a/launcher/modplatform/EnsureMetadataTask.cpp +++ b/launcher/modplatform/EnsureMetadataTask.cpp @@ -216,7 +216,8 @@ void EnsureMetadataTask::emitFail(Mod* m, QString key, RemoveFromList remove) Task::Ptr EnsureMetadataTask::modrinthVersionsTask() { - auto hash_type = ModPlatform::ProviderCapabilities::hashType(ModPlatform::ResourceProvider::MODRINTH).first(); + auto hash_type = + Hashing::algorithmToString(ModPlatform::ProviderCapabilities::hashType(ModPlatform::ResourceProvider::MODRINTH).first()); auto response = std::make_shared(); auto ver_task = modrinth_api.currentVersions(m_mods.keys(), hash_type, response); diff --git a/launcher/modplatform/ModIndex.cpp b/launcher/modplatform/ModIndex.cpp index 8c85ae122d..75c3f0d04a 100644 --- a/launcher/modplatform/ModIndex.cpp +++ b/launcher/modplatform/ModIndex.cpp @@ -22,6 +22,7 @@ #include #include #include +#include "Toml.h" namespace ModPlatform { @@ -81,15 +82,12 @@ QString ProviderCapabilities::readableName(ResourceProvider p) return {}; } -QStringList ProviderCapabilities::hashType(ResourceProvider p) +ResourceProvider ProviderCapabilities::fromString(QString p) { - switch (p) { - case ResourceProvider::MODRINTH: - return { "sha512", "sha1" }; - case ResourceProvider::FLAME: - // Try newer formats first, fall back to old format - return { "sha1", "md5", "murmur2" }; - } + if (p == "modrinth") + return ResourceProvider::MODRINTH; + if (p == "curseforge") + return ResourceProvider::FLAME; return {}; } @@ -120,6 +118,20 @@ auto getModLoaderAsString(ModLoaderType type) -> const QString return ""; } +Dependency::Dependency(toml::table table) +{ + type = DependencyType::REQUIRED; + addonId = Toml::getString(table, "id"); + version = Toml::getString(table, "version"); +} + +toml::table Dependency::toToml() +{ + return toml::table{ { "id", addonId.toString().toStdString() }, { "version", version.toStdString() } }; +} + +Dependency::Dependency(QVariant addonId_, DependencyType type_, QString version_) : addonId(addonId_), type(type_), version(version_){}; + auto getModLoaderFromString(QString type) -> ModLoaderType { if (type == "neoforge") diff --git a/launcher/modplatform/ModIndex.h b/launcher/modplatform/ModIndex.h index d5ee12473a..3fae02d1da 100644 --- a/launcher/modplatform/ModIndex.h +++ b/launcher/modplatform/ModIndex.h @@ -25,6 +25,7 @@ #include #include #include +#include class QIODevice; @@ -42,6 +43,7 @@ enum class DependencyType { REQUIRED, OPTIONAL, INCOMPATIBLE, EMBEDDED, TOOL, IN namespace ProviderCapabilities { const char* name(ResourceProvider); QString readableName(ResourceProvider); +ResourceProvider fromString(QString); QStringList hashType(ResourceProvider); } // namespace ProviderCapabilities @@ -85,9 +87,14 @@ struct IndexedVersionType { }; struct Dependency { - QVariant addonId; - DependencyType type; - QString version; + QVariant addonId = {}; + DependencyType type = {}; + QString version = {}; + + Dependency() = default; + Dependency(QVariant addonId_, DependencyType type_ = DependencyType::REQUIRED, QString version_ = {}); + Dependency(toml::table table); + toml::table toToml(); }; struct IndexedVersion { diff --git a/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp b/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp index abe7d01773..e26ce35bf0 100644 --- a/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp +++ b/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp @@ -824,7 +824,7 @@ void PackInstallTask::downloadMods() BlockedModsDialog message_dialog(nullptr, tr("Blocked mods found"), tr("The following files are not available for download in third party launchers.
" "You will need to manually download them and add them to the instance."), - mods, "md5"); + mods, Hashing::Algorithm::Md5); message_dialog.setModal(true); diff --git a/launcher/modplatform/flame/FlameModIndex.cpp b/launcher/modplatform/flame/FlameModIndex.cpp index 7de05f1779..80ed5a3729 100644 --- a/launcher/modplatform/flame/FlameModIndex.cpp +++ b/launcher/modplatform/flame/FlameModIndex.cpp @@ -5,6 +5,7 @@ #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" #include "modplatform/flame/FlameAPI.h" +#include "modplatform/helpers/HashUtils.h" static FlameAPI api; @@ -65,14 +66,14 @@ void FlameMod::loadBody(ModPlatform::IndexedPack& pack, [[maybe_unused]] QJsonOb pack.extraDataLoaded = true; } -static QString enumToString(int hash_algorithm) +static Hashing::Algorithm enumToHash(int hash_algorithm) { switch (hash_algorithm) { default: case 1: - return "sha1"; + return Hashing::Algorithm::Sha1; case 2: - return "md5"; + return Hashing::Algorithm::Md5; } } @@ -164,10 +165,10 @@ auto FlameMod::loadIndexedPackVersion(QJsonObject& obj, bool load_changelog) -> for (auto h : hash_list) { auto hash_entry = Json::ensureObject(h); auto hash_types = ModPlatform::ProviderCapabilities::hashType(ModPlatform::ResourceProvider::FLAME); - auto hash_algo = enumToString(Json::ensureInteger(hash_entry, "algo", 1, "algorithm")); + auto hash_algo = enumToHash(Json::ensureInteger(hash_entry, "algo", 1, "algorithm")); if (hash_types.contains(hash_algo)) { file.hash = Json::requireString(hash_entry, "value"); - file.hash_type = hash_algo; + file.hash_type = Hashing::algorithmToString(hash_algo); break; } } diff --git a/launcher/modplatform/helpers/HashUtils.cpp b/launcher/modplatform/helpers/HashUtils.cpp index a3b8d904cb..d62b62eaaf 100644 --- a/launcher/modplatform/helpers/HashUtils.cpp +++ b/launcher/modplatform/helpers/HashUtils.cpp @@ -23,11 +23,6 @@ Hasher::Ptr createHasher(QString file_path, ModPlatform::ResourceProvider provid } } -Hasher::Ptr createHasher(QString file_path, QString type) -{ - return makeShared(file_path, type); -} - class QIODeviceReader : public Murmur2::Reader { public: QIODeviceReader(QIODevice* device) : m_device(device) {} @@ -162,4 +157,25 @@ bool Hasher::abort() } return false; } + +QString Hasher::getResult() const +{ + return m_result; +} + +QString Hasher::getPath() const +{ + return m_path; +} + } // namespace Hashing +QList ModPlatform::ProviderCapabilities::hashType(ModPlatform::ResourceProvider p) +{ + switch (p) { + case ModPlatform::ResourceProvider::MODRINTH: + return { Hashing::Algorithm::Sha512, Hashing::Algorithm::Sha1 }; + case ModPlatform::ResourceProvider::FLAME: + return { Hashing::Algorithm::Sha1, Hashing::Algorithm::Md5, Hashing::Algorithm::Murmur2 }; + } + return {}; +} \ No newline at end of file diff --git a/launcher/modplatform/helpers/HashUtils.h b/launcher/modplatform/helpers/HashUtils.h index 5d8b7d1320..a176320a16 100644 --- a/launcher/modplatform/helpers/HashUtils.h +++ b/launcher/modplatform/helpers/HashUtils.h @@ -30,8 +30,8 @@ class Hasher : public Task { void executeTask() override; - QString getResult() const { return m_result; }; - QString getPath() const { return m_path; }; + QString getResult() const; + QString getPath() const; signals: void resultsReady(QString hash); @@ -46,6 +46,8 @@ class Hasher : public Task { }; Hasher::Ptr createHasher(QString file_path, ModPlatform::ResourceProvider provider); -Hasher::Ptr createHasher(QString file_path, QString type); - } // namespace Hashing + +namespace ModPlatform::ProviderCapabilities { +QList hashType(ModPlatform::ResourceProvider); +}; \ No newline at end of file diff --git a/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp b/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp index 70bf138a80..d319a31b50 100644 --- a/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp +++ b/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp @@ -8,6 +8,7 @@ #include "QObjectPtr.h" #include "ResourceDownloadTask.h" +#include "modplatform/ModIndex.h" #include "modplatform/helpers/HashUtils.h" #include "tasks/ConcurrentTask.h" diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp index 48b27a597b..50442646a8 100644 --- a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp @@ -25,6 +25,7 @@ #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" #include "modplatform/ModIndex.h" +#include "modplatform/helpers/HashUtils.h" static ModrinthAPI api; @@ -232,7 +233,8 @@ auto Modrinth::loadIndexedPackVersion(QJsonObject& obj, file.hash_type = preferred_hash_type; } else { auto hash_types = ModPlatform::ProviderCapabilities::hashType(ModPlatform::ResourceProvider::MODRINTH); - for (auto& hash_type : hash_types) { + for (auto& alg : hash_types) { + auto hash_type = Hashing::algorithmToString(alg); if (hash_list.contains(hash_type)) { file.hash = Json::requireString(hash_list, hash_type); file.hash_type = hash_type; diff --git a/launcher/settings/INIFile.cpp b/launcher/settings/INIFile.cpp index e97741f20f..73bff54bb0 100644 --- a/launcher/settings/INIFile.cpp +++ b/launcher/settings/INIFile.cpp @@ -46,17 +46,15 @@ #include -INIFile::INIFile() {} - bool INIFile::saveFile(QString fileName) { if (!contains("ConfigVersion")) - insert("ConfigVersion", "1.2"); + m_values.insert("ConfigVersion", "1.2"); QSettings _settings_obj{ fileName, QSettings::Format::IniFormat }; _settings_obj.setFallbacksEnabled(false); _settings_obj.clear(); - for (Iterator iter = begin(); iter != end(); iter++) + for (auto iter = m_values.begin(); iter != m_values.end(); iter++) _settings_obj.setValue(iter.key(), iter.value()); _settings_obj.sync(); @@ -170,21 +168,21 @@ bool INIFile::loadFile(QString fileName) parseOldFileFormat(file, map); file.close(); for (auto&& key : map.keys()) - insert(key, map.value(key)); - insert("ConfigVersion", "1.2"); + m_values.insert(key, map.value(key)); + m_values.insert("ConfigVersion", "1.2"); } else if (_settings_obj.value("ConfigVersion").toString() == "1.1") { for (auto&& key : _settings_obj.allKeys()) { if (auto valueStr = _settings_obj.value(key).toString(); (valueStr.contains(QChar(';')) || valueStr.contains(QChar('=')) || valueStr.contains(QChar(','))) && valueStr.endsWith("\"") && valueStr.startsWith("\"")) { - insert(key, unquote(valueStr)); + m_values.insert(key, unquote(valueStr)); } else - insert(key, _settings_obj.value(key)); + m_values.insert(key, _settings_obj.value(key)); } - insert("ConfigVersion", "1.2"); + m_values.insert("ConfigVersion", "1.2"); } else for (auto&& key : _settings_obj.allKeys()) - insert(key, _settings_obj.value(key)); + m_values.insert(key, _settings_obj.value(key)); return true; } @@ -205,11 +203,29 @@ QVariant INIFile::get(QString key, QVariant def) const { if (!this->contains(key)) return def; - else - return this->operator[](key); + return m_values[key]; } void INIFile::set(QString key, QVariant val) { - this->operator[](key) = val; + m_values[key] = val; +} + +void INIFile::remove(QString key) +{ + m_values.remove(key); +} + +bool INIFile::contains(QString key) const +{ + return m_values.contains(key); +} + +QVariant INIFile::operator[](const QString& key) const +{ + return m_values[key]; +} +QStringList INIFile::keys() +{ + return m_values.keys(); } diff --git a/launcher/settings/INIFile.h b/launcher/settings/INIFile.h index c15578f6d4..33c1d1ba11 100644 --- a/launcher/settings/INIFile.h +++ b/launcher/settings/INIFile.h @@ -36,22 +36,27 @@ #pragma once -#include #include #include -#include -#include +#include "settings/SettingsFile.h" // Sectionless INI parser (for instance config files) -class INIFile : public QMap { +class INIFile : public SettingsFile { public: - explicit INIFile(); + explicit INIFile() = default; bool loadFile(QString fileName); bool loadFile(QByteArray data); bool saveFile(QString fileName); - QVariant get(QString key, QVariant def) const; + QVariant get(QString key, QVariant def = {}) const; void set(QString key, QVariant val); + void remove(QString key); + bool contains(QString key) const; + QVariant operator[](const QString& key) const; + QStringList keys(); + + private: + QMap m_values; }; diff --git a/launcher/settings/INISettingsObject.cpp b/launcher/settings/INISettingsObject.cpp index 519b8193e8..a37ea577a1 100644 --- a/launcher/settings/INISettingsObject.cpp +++ b/launcher/settings/INISettingsObject.cpp @@ -35,13 +35,13 @@ INISettingsObject::INISettingsObject(QStringList paths, QObject* parent) : Setti } m_filePath = first_path; - m_ini.loadFile(first_path); + m_ini->loadFile(first_path); } INISettingsObject::INISettingsObject(QString path, QObject* parent) : SettingsObject(parent) { m_filePath = path; - m_ini.loadFile(path); + m_ini->loadFile(path); } void INISettingsObject::setFilePath(const QString& filePath) @@ -51,7 +51,7 @@ void INISettingsObject::setFilePath(const QString& filePath) bool INISettingsObject::reload() { - return m_ini.loadFile(m_filePath) && SettingsObject::reload(); + return m_ini->loadFile(m_filePath) && SettingsObject::reload(); } void INISettingsObject::suspendSave() @@ -63,7 +63,7 @@ void INISettingsObject::resumeSave() { m_suspendSave = false; if (m_doSave) { - m_ini.saveFile(m_filePath); + m_ini->saveFile(m_filePath); } } @@ -73,14 +73,14 @@ void INISettingsObject::changeSetting(const Setting& setting, QVariant value) // valid value -> set the main config, remove all the sysnonyms if (value.isValid()) { auto list = setting.configKeys(); - m_ini.set(list.takeFirst(), value); + m_ini->set(list.takeFirst(), value); for (auto iter : list) - m_ini.remove(iter); + m_ini->remove(iter); } // invalid -> remove all (just like resetSetting) else { for (auto iter : setting.configKeys()) - m_ini.remove(iter); + m_ini->remove(iter); } doSave(); } @@ -91,7 +91,7 @@ void INISettingsObject::doSave() if (m_suspendSave) { m_doSave = true; } else { - m_ini.saveFile(m_filePath); + m_ini->saveFile(m_filePath); } } @@ -100,7 +100,7 @@ void INISettingsObject::resetSetting(const Setting& setting) // if we have the setting, remove all the synonyms. ALL OF THEM if (contains(setting.id())) { for (auto iter : setting.configKeys()) - m_ini.remove(iter); + m_ini->remove(iter); doSave(); } } @@ -110,8 +110,8 @@ QVariant INISettingsObject::retrieveValue(const Setting& setting) // if we have the setting, return value of the first matching synonym if (contains(setting.id())) { for (auto iter : setting.configKeys()) { - if (m_ini.contains(iter)) - return m_ini[iter]; + if (m_ini->contains(iter)) + return (*m_ini)[iter]; } } return QVariant(); diff --git a/launcher/settings/INISettingsObject.h b/launcher/settings/INISettingsObject.h index 4cc8085807..e3fc448a46 100644 --- a/launcher/settings/INISettingsObject.h +++ b/launcher/settings/INISettingsObject.h @@ -16,10 +16,10 @@ #pragma once #include - -#include "settings/INIFile.h" +#include #include "settings/SettingsObject.h" +#include "settings/TomlFile.h" /*! * \brief A settings object that stores its settings in an INIFile. @@ -58,6 +58,6 @@ class INISettingsObject : public SettingsObject { void doSave(); protected: - INIFile m_ini; + std::unique_ptr m_ini = std::unique_ptr(new TomlFile()); QString m_filePath; }; diff --git a/launcher/settings/SettingsFile.h b/launcher/settings/SettingsFile.h new file mode 100644 index 0000000000..dd58c0b4c8 --- /dev/null +++ b/launcher/settings/SettingsFile.h @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2024 Trial97 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include + +class SettingsFile { + public: + virtual ~SettingsFile() = default; + virtual bool loadFile(QString fileName) = 0; + virtual bool loadFile(QByteArray data) = 0; + virtual bool saveFile(QString fileName) = 0; + + virtual QVariant get(QString key, QVariant def = {}) const = 0; + virtual void set(QString key, QVariant val) = 0; + virtual void remove(QString key) = 0; + virtual bool contains(QString key) const = 0; + virtual QVariant operator[](const QString& key) const = 0; + virtual QStringList keys() = 0; +}; diff --git a/launcher/settings/TomlFile.cpp b/launcher/settings/TomlFile.cpp new file mode 100644 index 0000000000..d3fed1628b --- /dev/null +++ b/launcher/settings/TomlFile.cpp @@ -0,0 +1,308 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2024 Trial97 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "TomlFile.h" + +#include "settings/INIFile.h" + +#include + +#include +#include + +bool TomlFile::loadFile(QString fileName) +{ +#if TOML_EXCEPTIONS + try { + m_data = toml::parse_file(fileName.toStdString()); + } catch (const toml::parse_error& err) { + qWarning() << QString("Could not open file %1!").arg(fileName); + qWarning() << "Reason: " << QString(err.what()); + return migrate(fileName); + } +#else + auto result = toml::parse_file(fileName.toStdString()); + if (!result) { + qWarning() << QString("Could not open file %1!").arg(fileName); + qWarning() << "Reason: " << result.error().description(); + return migrate(fileName); + } + m_data = result.table(); +#endif + + /*migration*/ + if (!m_data.empty() && (!m_data.contains("ConfigVersion") || !m_data.get("ConfigVersion")->is_string() || + m_data.get("ConfigVersion")->value().value() != "1.3")) { + m_loaded = migrate(fileName); + } else { + m_loaded = true; + } + return m_loaded; +} + +bool TomlFile::loadFile(QByteArray data) +{ +#if TOML_EXCEPTIONS + try { + m_data = toml::parse(data.toStdString()); + } catch (const toml::parse_error& err) { + return false; + } +#else + auto result = toml::parse(data.toStdString()); + if (!result) { + return false; + } + m_data = result.table(); +#endif + return true; +} + +toml::table merge_tables(const toml::table& table1, const toml::table& table2) +{ + toml::table merged = table1; + + for (const auto& [key, value] : table2) { + if (merged.contains(key)) { + if (merged[key].is_table() && value.is_table()) { + merged.insert_or_assign(key, merge_tables(*merged[key].as_table(), *value.as_table())); + } else { + merged.insert_or_assign(key, value); + } + } else { + merged.insert_or_assign(key, value); + } + } + + return merged; +} + +bool TomlFile::saveFile(QString fileName) +{ + if (!m_loaded) { + auto tmp = m_data; + m_data = {}; + loadFile(fileName); + m_data = merge_tables(m_data, tmp); + } + if (!contains("ConfigVersion")) + set("ConfigVersion", "1.3"); + std::ofstream outFile; + outFile.open(fileName.toStdString()); + if (!outFile.is_open()) { + qCritical() << QString("Could not open file %1!").arg(fileName); + return false; + } + outFile << m_data; + outFile.flush(); + outFile.close(); + return true; +} + +QVariant TomlFile::get(QString key, QVariant def) const +{ + auto stdKey = key.toStdString(); + if (!m_data.contains(stdKey)) + return def; + auto node = m_data.get(stdKey); + switch (node->type()) { + case toml::node_type::none: + return def; + case toml::node_type::table: + if (auto table = node->as_table(); // we may want in the future to support multiple QT types + table->contains("type") && table->contains("value") && table->get("type")->value() == "QByteArray") + return QByteArray::fromBase64(QByteArray::fromStdString(table->get("value")->value().value())); + return QVariant::fromValue(node); + case toml::node_type::array: + return QVariant::fromValue(node); + case toml::node_type::string: { + auto value = node->value().value(); + return QString::fromStdString(value); + } + case toml::node_type::integer: { + auto value = node->value().value(); + return value; + } + case toml::node_type::floating_point: { + auto value = node->value().value(); + return value; + } + case toml::node_type::boolean: { + auto value = node->value().value(); + return value; + } + case toml::node_type::date: + /* fallthrough */ + case toml::node_type::time: + /* fallthrough */ + case toml::node_type::date_time: + /* fallthrough */ + default: + return {}; + } +} + +bool isEmptyNode(const toml::node& node) +{ + return (node.is_string() && node.as_string()->get().empty()) || (node.is_integer() && node.as_integer()->get() == 0) || + (node.is_floating_point() && node.as_floating_point()->get() == 0.0) || + (node.is_boolean() && node.as_boolean()->get() == false) || (node.is_array() && node.as_array()->empty()) || + (node.is_table() && node.as_table()->empty()); +} + +// Function to filter out empty fields from a TOML table +void filterEmptyFields(toml::table& table) +{ + for (auto it = table.begin(); it != table.end();) { + auto& value = it->second; + if (value.is_table()) { + filterEmptyFields(*value.as_table()); + } + if (isEmptyNode(value)) { + it = table.erase(it); + } else { + ++it; + } + } +} + +void TomlFile::set(QString key, QVariant val) +{ + auto stdKey = key.toStdString(); + + switch (val.type()) { + case QVariant::Bool: + m_data.insert_or_assign(stdKey, val.toBool()); + break; + case QVariant::Int: + m_data.insert_or_assign(stdKey, val.toInt()); + break; + case QVariant::UInt: + m_data.insert_or_assign(stdKey, val.toUInt()); + break; + case QVariant::LongLong: + m_data.insert_or_assign(stdKey, val.toLongLong()); + break; + case QVariant::ULongLong: + m_data.insert_or_assign(stdKey, val.toLongLong()); + break; + case QVariant::Double: + m_data.insert_or_assign(stdKey, val.toDouble()); + break; + case QVariant::Char: + /* fallthrough */ + case QVariant::Url: + /* fallthrough */ + case QVariant::String: + m_data.insert_or_assign(stdKey, val.toString().toStdString()); + break; + case QVariant::StringList: { + toml::array array; + for (auto s : val.toStringList()) + array.push_back(s.toStdString()); + m_data.insert_or_assign(stdKey, array); + break; + } + case QVariant::ByteArray: + m_data.insert_or_assign(stdKey, + toml::table{ { "type", "QByteArray" }, { "value", val.toByteArray().toBase64().toStdString() } }); + break; + case QVariant::Invalid: + break; + // case QVariant::BitArray: + // case QVariant::Date: + // case QVariant::Time: + // case QVariant::DateTime: + // case QVariant::Map: + // case QVariant::List: + default: + // minimize the content by removing empty fields + if (val.canConvert()) { + auto table = val.value(); + filterEmptyFields(table); + m_data.insert_or_assign(stdKey, table); + } else if (val.canConvert()) { + auto array = val.value(); + if (array.is_array_of_tables()) { + for (auto& element : array) { + if (element.is_table()) { + filterEmptyFields(*element.as_table()); + } + } + } + m_data.insert_or_assign(stdKey, array); + } + break; + } +} + +void TomlFile::remove(QString key) +{ + m_data.erase(key.toStdString()); +} + +bool TomlFile::contains(QString key) const +{ + return m_data.contains(key.toStdString()); +} + +QVariant TomlFile::operator[](const QString& key) const +{ + return get(key); +} + +void collect_keys(const toml::node* node, QStringList& keys, const QString& prefix = "") +{ + if (node->is_table()) { + const auto& table = node->as_table(); + for (const auto& [key, val] : *table) { + auto keyStr = QString::fromStdString(std::string(key.str())); + auto new_prefix = prefix.isEmpty() ? keyStr : prefix + "." + keyStr; + keys.append(new_prefix); + collect_keys(&val, keys, new_prefix); + } + } else if (node->is_array()) { + const auto& array = node->as_array(); + for (size_t i = 0; i < array->size(); ++i) { + auto new_prefix = prefix + "[" + QString::number(i) + "]"; + keys.append(new_prefix); + collect_keys(array->get(i), keys, new_prefix); + } + } +} + +QStringList TomlFile::keys() +{ + QStringList v; + collect_keys(&m_data, v); + return v; +} + +bool TomlFile::migrate(QString fileName) +{ + m_data = {}; + INIFile f; + if (!f.loadFile(fileName)) + return false; + + for (auto key : f.keys()) + set(key, f.get(key)); + + set("ConfigVersion", "1.3"); + m_loaded = true; + return saveFile(fileName); +} diff --git a/launcher/settings/TomlFile.h b/launcher/settings/TomlFile.h new file mode 100644 index 0000000000..341a7bdcf4 --- /dev/null +++ b/launcher/settings/TomlFile.h @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2024 Trial97 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +#include "settings/SettingsFile.h" + +#include + +Q_DECLARE_METATYPE(toml::table) +Q_DECLARE_METATYPE(toml::array) + +class TomlFile : public SettingsFile { + public: + explicit TomlFile() = default; + + bool loadFile(QString fileName); + bool loadFile(QByteArray data); + bool saveFile(QString fileName); + + QVariant get(QString key, QVariant def = {}) const; + void set(QString key, QVariant val); + void remove(QString key); + bool contains(QString key) const; + QVariant operator[](const QString& key) const; + virtual QStringList keys(); + + private: + bool migrate(QString fileName); + + private: + toml::table m_data; + bool m_loaded; +}; diff --git a/launcher/ui/dialogs/BlockedModsDialog.cpp b/launcher/ui/dialogs/BlockedModsDialog.cpp index 5c93053d1c..6540fb66ed 100644 --- a/launcher/ui/dialogs/BlockedModsDialog.cpp +++ b/launcher/ui/dialogs/BlockedModsDialog.cpp @@ -24,6 +24,7 @@ */ #include "BlockedModsDialog.h" +#include "QObjectPtr.h" #include "ui_BlockedModsDialog.h" #include "Application.h" @@ -42,7 +43,11 @@ #include #include -BlockedModsDialog::BlockedModsDialog(QWidget* parent, const QString& title, const QString& text, QList& mods, QString hash_type) +BlockedModsDialog::BlockedModsDialog(QWidget* parent, + const QString& title, + const QString& text, + QList& mods, + Hashing::Algorithm hash_type) : QDialog(parent), ui(new Ui::BlockedModsDialog), m_mods(mods), m_hash_type(hash_type) { m_hashing_task = shared_qobject_ptr( @@ -266,7 +271,7 @@ void BlockedModsDialog::addHashTask(QString path) /// @param path the path to the local file being hashed void BlockedModsDialog::buildHashTask(QString path) { - auto hash_task = Hashing::createHasher(path, m_hash_type); + auto hash_task = makeShared(path, m_hash_type); qDebug() << "[Blocked Mods Dialog] Creating Hash task for path: " << path; diff --git a/launcher/ui/dialogs/BlockedModsDialog.h b/launcher/ui/dialogs/BlockedModsDialog.h index 09722bce98..cebb6227e9 100644 --- a/launcher/ui/dialogs/BlockedModsDialog.h +++ b/launcher/ui/dialogs/BlockedModsDialog.h @@ -31,6 +31,7 @@ #include +#include "modplatform/helpers/HashUtils.h" #include "tasks/ConcurrentTask.h" class QPushButton; @@ -54,7 +55,11 @@ class BlockedModsDialog : public QDialog { Q_OBJECT public: - BlockedModsDialog(QWidget* parent, const QString& title, const QString& text, QList& mods, QString hash_type = "sha1"); + BlockedModsDialog(QWidget* parent, + const QString& title, + const QString& text, + QList& mods, + Hashing::Algorithm hash_type = Hashing::Algorithm::Sha1); ~BlockedModsDialog() override; @@ -73,7 +78,7 @@ class BlockedModsDialog : public QDialog { QSet m_pending_hash_paths; bool m_rehash_pending; QPushButton* m_openMissingButton; - QString m_hash_type; + Hashing::Algorithm m_hash_type; void openAll(bool missingOnly); void addDownloadFolder();