From 85e28d7c39bf7e0b26f272dd3007a13100bdf642 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 4 Jun 2024 23:14:57 +0300 Subject: [PATCH 1/6] changed the default config format Signed-off-by: Trial97 --- launcher/CMakeLists.txt | 3 + launcher/InstanceList.h | 4 - launcher/MMCZip.h | 2 +- launcher/settings/INIFile.cpp | 42 ++-- launcher/settings/INIFile.h | 30 ++- launcher/settings/INISettingsObject.cpp | 22 +- launcher/settings/INISettingsObject.h | 4 +- launcher/settings/TomlFile.cpp | 269 ++++++++++++++++++++++++ launcher/settings/TomlFile.h | 53 +++++ 9 files changed, 393 insertions(+), 36 deletions(-) create mode 100644 launcher/settings/TomlFile.cpp create mode 100644 launcher/settings/TomlFile.h diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 5c89f1fe06..d538ded1b8 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -407,6 +407,9 @@ set(SETTINGS_SOURCES settings/Setting.h settings/SettingsObject.cpp settings/SettingsObject.h + + settings/TomlFile.cpp + settings/TomlFile.h ) set(JAVA_SOURCES diff --git a/launcher/InstanceList.h b/launcher/InstanceList.h index 5ddddee95d..ec83aa39f2 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 polyPath; diff --git a/launcher/MMCZip.h b/launcher/MMCZip.h index a872411fa8..eb0ea8f6a2 100644 --- a/launcher/MMCZip.h +++ b/launcher/MMCZip.h @@ -213,7 +213,7 @@ class ExtractZipTask : public Task { {} virtual ~ExtractZipTask() = default; - typedef std::optional ZipResult; + using ZipResult = std::optional; protected: virtual void executeTask() override; 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..13147196f0 100644 --- a/launcher/settings/INIFile.h +++ b/launcher/settings/INIFile.h @@ -36,22 +36,40 @@ #pragma once -#include #include #include -#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; +}; // 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..3380c286dc 100644 --- a/launcher/settings/INISettingsObject.h +++ b/launcher/settings/INISettingsObject.h @@ -16,10 +16,12 @@ #pragma once #include +#include #include "settings/INIFile.h" #include "settings/SettingsObject.h" +#include "settings/TomlFile.h" /*! * \brief A settings object that stores its settings in an INIFile. @@ -58,6 +60,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/TomlFile.cpp b/launcher/settings/TomlFile.cpp new file mode 100644 index 0000000000..d47d4ce72e --- /dev/null +++ b/launcher/settings/TomlFile.cpp @@ -0,0 +1,269 @@ +// 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 + +#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 = {}; + if (!loadFile(fileName)) + return false; + m_data = merge_tables(m_data, tmp); + } + if (!contains("ConfigVersion")) + set("ConfigVersion", "1.3"); + std::ofstream outFile(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 {}; + } +} + +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: + if (val.canConvert()) + m_data.insert_or_assign(stdKey, val.value()); + else if (val.canConvert()) + m_data.insert_or_assign(stdKey, val.value()); + 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"); + return true; +} diff --git a/launcher/settings/TomlFile.h b/launcher/settings/TomlFile.h new file mode 100644 index 0000000000..81abf2e513 --- /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/INIFile.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; +}; From 1baf6f1c23b5e81ef1f9c2615d1177913c5edb96 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 6 Jun 2024 00:08:31 +0300 Subject: [PATCH 2/6] move settings file Signed-off-by: Trial97 --- launcher/CMakeLists.txt | 2 +- launcher/settings/INIFile.h | 15 +---------- launcher/settings/INISettingsObject.h | 2 -- launcher/settings/SettingsFile.h | 37 +++++++++++++++++++++++++++ launcher/settings/TomlFile.cpp | 2 ++ launcher/settings/TomlFile.h | 2 +- 6 files changed, 42 insertions(+), 18 deletions(-) create mode 100644 launcher/settings/SettingsFile.h diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index d538ded1b8..3e0337ab1b 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -407,9 +407,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/settings/INIFile.h b/launcher/settings/INIFile.h index 13147196f0..33c1d1ba11 100644 --- a/launcher/settings/INIFile.h +++ b/launcher/settings/INIFile.h @@ -39,20 +39,7 @@ #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; -}; +#include "settings/SettingsFile.h" // Sectionless INI parser (for instance config files) class INIFile : public SettingsFile { diff --git a/launcher/settings/INISettingsObject.h b/launcher/settings/INISettingsObject.h index 3380c286dc..e3fc448a46 100644 --- a/launcher/settings/INISettingsObject.h +++ b/launcher/settings/INISettingsObject.h @@ -18,8 +18,6 @@ #include #include -#include "settings/INIFile.h" - #include "settings/SettingsObject.h" #include "settings/TomlFile.h" 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 index d47d4ce72e..d79e44ee9f 100644 --- a/launcher/settings/TomlFile.cpp +++ b/launcher/settings/TomlFile.cpp @@ -17,6 +17,8 @@ */ #include "TomlFile.h" +#include "settings/INIFile.h" + #include #include diff --git a/launcher/settings/TomlFile.h b/launcher/settings/TomlFile.h index 81abf2e513..341a7bdcf4 100644 --- a/launcher/settings/TomlFile.h +++ b/launcher/settings/TomlFile.h @@ -22,7 +22,7 @@ #include #include -#include "settings/INIFile.h" +#include "settings/SettingsFile.h" #include From 2e6a0467a3478c7ec92d8398af0c2885679d49c4 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 6 Jun 2024 14:11:46 +0300 Subject: [PATCH 3/6] refactored hassing task Signed-off-by: Trial97 --- launcher/CMakeLists.txt | 1 + launcher/minecraft/mod/Mod.h | 2 +- launcher/minecraft/mod/ModDetails.cpp | 217 ++++++++++++++++++ launcher/minecraft/mod/ModDetails.h | 130 ++--------- .../minecraft/mod/tasks/LocalModParseTask.cpp | 16 +- launcher/modplatform/EnsureMetadataTask.cpp | 2 +- launcher/modplatform/ModIndex.cpp | 32 --- launcher/modplatform/ModIndex.h | 2 - .../atlauncher/ATLPackInstallTask.cpp | 2 +- launcher/modplatform/flame/FlameModIndex.cpp | 14 +- .../modplatform/flame/FlamePackExportTask.cpp | 4 +- launcher/modplatform/helpers/HashUtils.cpp | 160 +++++-------- launcher/modplatform/helpers/HashUtils.h | 51 ++-- .../modrinth/ModrinthCheckUpdate.cpp | 6 +- .../modrinth/ModrinthPackIndex.cpp | 7 +- launcher/settings/TomlFile.cpp | 44 +++- launcher/ui/dialogs/BlockedModsDialog.cpp | 9 +- launcher/ui/dialogs/BlockedModsDialog.h | 9 +- 18 files changed, 394 insertions(+), 314 deletions(-) create mode 100644 launcher/minecraft/mod/ModDetails.cpp diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 3e0337ab1b..639152d49d 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -315,6 +315,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 diff --git a/launcher/minecraft/mod/Mod.h b/launcher/minecraft/mod/Mod.h index e97ee9d3b3..5966c86f10 100644 --- a/launcher/minecraft/mod/Mod.h +++ b/launcher/minecraft/mod/Mod.h @@ -72,7 +72,7 @@ class Mod : public Resource { auto metaurl() const -> QString; /** 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..93f3b97493 --- /dev/null +++ b/launcher/minecraft/mod/ModDetails.cpp @@ -0,0 +1,217 @@ +// 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 +#include + +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(); +} + +QString getTomlString(toml::table table, QString key, QString def = {}) +{ + return QString::fromStdString(table[key.toStdString()].value_or(def.toStdString())); +} + +QStringList getTomlStringList(toml::array* arr) +{ + QStringList list; + if (arr) { + for (auto&& v : *arr) { + list.push_back(QString::fromStdString(v.value_or(""))); + } + } + return list; +} + +toml::array stringListToToml(QStringList list) +{ + toml::array arr; + for (auto v : list) { + arr.push_back(v.toStdString()); + } + return arr; +} + +ModLicense::ModLicense(toml::table table) +{ + name = getTomlString(table, "name"); + id = getTomlString(table, "id"); + url = getTomlString(table, "url"); + description = getTomlString(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 = getTomlString(table, "mod_id"); + name = getTomlString(table, "name"); + version = getTomlString(table, "version"); + mcversion = getTomlString(table, "mcversion"); + homeurl = getTomlString(table, "homeurl"); + description = getTomlString(table, "description"); + issue_tracker = getTomlString(table, "issue_tracker"); + icon_path = getTomlString(table, "icon_path"); + new_format_id = table["format_id"].value_or(0); + + authors = getTomlStringList(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", stringListToToml(authors) }, + { "licenses", licenseArr }, + }; +} diff --git a/launcher/minecraft/mod/ModDetails.h b/launcher/minecraft/mod/ModDetails.h index a00d5a24b2..2f2c9dd47f 100644 --- a/launcher/minecraft/mod/ModDetails.h +++ b/launcher/minecraft/mod/ModDetails.h @@ -41,6 +41,8 @@ #include #include +#include + #include "minecraft/mod/MetadataHandler.h" enum class ModStatus { @@ -56,66 +58,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 +100,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 +108,13 @@ 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); - /** 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; - } + toml::table toToml(); }; diff --git a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp index 60257ce0cd..c5b3b50aaa 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 ce53ee62dd..05ce218d51 100644 --- a/launcher/modplatform/EnsureMetadataTask.cpp +++ b/launcher/modplatform/EnsureMetadataTask.cpp @@ -215,7 +215,7 @@ void EnsureMetadataTask::emitFail(Mod* m, QString key, RemoveFromList remove) Task::Ptr EnsureMetadataTask::modrinthVersionsTask() { - auto hash_type = ProviderCaps.hashType(ModPlatform::ResourceProvider::MODRINTH).first(); + auto hash_type = Hashing::algorithmToString(Hashing::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 fc79dff152..0ef2b0ab3f 100644 --- a/launcher/modplatform/ModIndex.cpp +++ b/launcher/modplatform/ModIndex.cpp @@ -78,38 +78,6 @@ auto ProviderCapabilities::readableName(ResourceProvider p) -> QString } return {}; } -auto ProviderCapabilities::hashType(ResourceProvider p) -> QStringList -{ - switch (p) { - case ResourceProvider::MODRINTH: - return { "sha512", "sha1" }; - case ResourceProvider::FLAME: - // Try newer formats first, fall back to old format - return { "sha1", "md5", "murmur2" }; - } - return {}; -} - -auto ProviderCapabilities::hash(ResourceProvider p, QIODevice* device, QString type) -> QString -{ - QCryptographicHash::Algorithm algo = QCryptographicHash::Sha1; - switch (p) { - case ResourceProvider::MODRINTH: { - algo = (type == "sha1") ? QCryptographicHash::Sha1 : QCryptographicHash::Sha512; - break; - } - case ResourceProvider::FLAME: - algo = (type == "sha1") ? QCryptographicHash::Sha1 : QCryptographicHash::Md5; - break; - } - - QCryptographicHash hash(algo); - if (!hash.addData(device)) - qCritical() << "Failed to read JAR to create hash!"; - - Q_ASSERT(hash.result().length() == hash.hashLength(algo)); - return { hash.result().toHex() }; -} QString getMetaURL(ResourceProvider provider, QVariant projectID) { diff --git a/launcher/modplatform/ModIndex.h b/launcher/modplatform/ModIndex.h index eff7e7f9f9..dae53d3220 100644 --- a/launcher/modplatform/ModIndex.h +++ b/launcher/modplatform/ModIndex.h @@ -44,8 +44,6 @@ class ProviderCapabilities { public: auto name(ResourceProvider) -> const char*; auto readableName(ResourceProvider) -> QString; - auto hashType(ResourceProvider) -> QStringList; - auto hash(ResourceProvider, QIODevice*, QString type = "") -> QString; }; struct ModpackAuthor { diff --git a/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp b/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp index a7721673e2..d961a43041 100644 --- a/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp +++ b/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp @@ -830,7 +830,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 83a28fa2b2..f0473e782c 100644 --- a/launcher/modplatform/flame/FlameModIndex.cpp +++ b/launcher/modplatform/flame/FlameModIndex.cpp @@ -5,9 +5,9 @@ #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" #include "modplatform/flame/FlameAPI.h" +#include "modplatform/helpers/HashUtils.h" static FlameAPI api; -static ModPlatform::ProviderCapabilities ProviderCaps; void FlameMod::loadIndexedPack(ModPlatform::IndexedPack& pack, QJsonObject& obj) { @@ -63,14 +63,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; } } @@ -162,11 +162,11 @@ auto FlameMod::loadIndexedPackVersion(QJsonObject& obj, bool load_changelog) -> auto hash_list = Json::ensureArray(obj, "hashes"); for (auto h : hash_list) { auto hash_entry = Json::ensureObject(h); - auto hash_types = ProviderCaps.hashType(ModPlatform::ResourceProvider::FLAME); - auto hash_algo = enumToString(Json::ensureInteger(hash_entry, "algo", 1, "algorithm")); + auto hash_types = Hashing::hashType(ModPlatform::ResourceProvider::FLAME); + 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/flame/FlamePackExportTask.cpp b/launcher/modplatform/flame/FlamePackExportTask.cpp index 5691817325..11bc3553be 100644 --- a/launcher/modplatform/flame/FlamePackExportTask.cpp +++ b/launcher/modplatform/flame/FlamePackExportTask.cpp @@ -116,7 +116,7 @@ void FlamePackExportTask::collectHashes() if (relative.startsWith("resourcepacks/") && (relative.endsWith(".zip") || relative.endsWith(".zip.disabled"))) { // is resourcepack - auto hashTask = Hashing::createFlameHasher(file.absoluteFilePath()); + auto hashTask = Hashing::createHasher(file.absoluteFilePath(), ModPlatform::ResourceProvider::FLAME); connect(hashTask.get(), &Hashing::Hasher::resultsReady, [this, relative, file](QString hash) { if (m_state == Task::State::Running) { pendingHashes.insert(hash, { relative, file.absoluteFilePath(), relative.endsWith(".zip") }); @@ -140,7 +140,7 @@ void FlamePackExportTask::collectHashes() continue; } - auto hashTask = Hashing::createFlameHasher(mod->fileinfo().absoluteFilePath()); + auto hashTask = Hashing::createHasher(mod->fileinfo().absoluteFilePath(), ModPlatform::ResourceProvider::FLAME); connect(hashTask.get(), &Hashing::Hasher::resultsReady, [this, mod](QString hash) { if (m_state == Task::State::Running) { pendingHashes.insert(hash, { mod->name(), mod->fileinfo().absoluteFilePath(), mod->enabled(), true }); diff --git a/launcher/modplatform/helpers/HashUtils.cpp b/launcher/modplatform/helpers/HashUtils.cpp index 6ff1d17106..6adf690ee8 100644 --- a/launcher/modplatform/helpers/HashUtils.cpp +++ b/launcher/modplatform/helpers/HashUtils.cpp @@ -1,122 +1,81 @@ #include "HashUtils.h" +#include #include #include -#include "FileSystem.h" -#include "StringUtils.h" - #include namespace Hashing { -static ModPlatform::ProviderCapabilities ProviderCaps; - Hasher::Ptr createHasher(QString file_path, ModPlatform::ResourceProvider provider) { - switch (provider) { - case ModPlatform::ResourceProvider::MODRINTH: - return createModrinthHasher(file_path); - case ModPlatform::ResourceProvider::FLAME: - return createFlameHasher(file_path); - default: - qCritical() << "[Hashing]" - << "Unrecognized mod platform!"; - return nullptr; - } -} - -Hasher::Ptr createModrinthHasher(QString file_path) -{ - return makeShared(file_path); -} - -Hasher::Ptr createFlameHasher(QString file_path) -{ - return makeShared(file_path); + return makeShared(file_path, hashType(provider).first()); } -Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::ResourceProvider provider) +QString hash(QString file_path, Algorithm alg) { - return makeShared(file_path, provider); -} - -Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::ResourceProvider provider, QString type) -{ - auto hasher = makeShared(file_path, provider); - hasher->useHashType(type); - return hasher; -} - -void ModrinthHasher::executeTask() -{ - QFile file(m_path); - - try { - file.open(QFile::ReadOnly); - } catch (FS::FileSystemException& e) { - qCritical() << QString("Failed to open JAR file in %1").arg(m_path); - qCritical() << QString("Reason: ") << e.cause(); - - emitFailed("Failed to open file for hashing."); - return; + QCryptographicHash::Algorithm algo = QCryptographicHash::Sha1; + switch (alg) { + case Algorithm::Sha512: + algo = QCryptographicHash::Sha512; + break; + case Algorithm::Sha1: + algo = QCryptographicHash::Sha1; + break; + case Algorithm::Md5: + algo = QCryptographicHash::Md5; + break; + case Algorithm::Murmur2: { + auto should_filter_out = [](char c) { return (c == 9 || c == 10 || c == 13 || c == 32); }; + + std::ifstream file_stream(file_path.toStdString(), std::ifstream::binary); + // TODO: This is very heavy work, but apparently QtConcurrent can't use move semantics, so we can't boop this to another thread. + // How do we make this non-blocking then? + return QString::number(MurmurHash2(std::move(file_stream), 4 * MiB, should_filter_out)); + } } - auto hash_type = ProviderCaps.hashType(ModPlatform::ResourceProvider::MODRINTH).first(); - m_hash = ProviderCaps.hash(ModPlatform::ResourceProvider::MODRINTH, &file, hash_type); + QFile file(file_path); + if (!file.open(QFile::ReadOnly)) + return {}; + QCryptographicHash hash(algo); + if (!hash.addData(&file)) + qCritical() << "Failed to read JAR to create hash!"; file.close(); - if (m_hash.isEmpty()) { - emitFailed("Empty hash!"); - } else { - emitSucceeded(); - emit resultsReady(m_hash); - } + Q_ASSERT(hash.result().length() == hash.hashLength(algo)); + return { hash.result().toHex() }; } -void FlameHasher::executeTask() +QString algorithmToString(Algorithm alg) { - // CF-specific - auto should_filter_out = [](char c) { return (c == 9 || c == 10 || c == 13 || c == 32); }; - - std::ifstream file_stream(StringUtils::toStdString(m_path).c_str(), std::ifstream::binary); - // TODO: This is very heavy work, but apparently QtConcurrent can't use move semantics, so we can't boop this to another thread. - // How do we make this non-blocking then? - m_hash = QString::number(MurmurHash2(std::move(file_stream), 4 * MiB, should_filter_out)); - - if (m_hash.isEmpty()) { - emitFailed("Empty hash!"); - } else { - emitSucceeded(); - emit resultsReady(m_hash); + switch (alg) { + case Algorithm::Sha512: + return "sha512"; + case Algorithm::Sha1: + return "sha1"; + case Algorithm::Md5: + return "md5"; + case Algorithm::Murmur2: + return "murmur2"; } } -BlockedModHasher::BlockedModHasher(QString file_path, ModPlatform::ResourceProvider provider) : Hasher(file_path), provider(provider) +Hasher::Hasher(QString file_path, Algorithm algorithm) : m_file_path(file_path), m_algorithm(algorithm) { - setObjectName(QString("BlockedModHasher: %1").arg(file_path)); - hash_type = ProviderCaps.hashType(provider).first(); + setObjectName(QString("%1 Hasher: %2").arg(algorithmToString(m_algorithm), file_path)); } -void BlockedModHasher::executeTask() +bool Hasher::abort() { - QFile file(m_path); - - try { - file.open(QFile::ReadOnly); - } catch (FS::FileSystemException& e) { - qCritical() << QString("Failed to open JAR file in %1").arg(m_path); - qCritical() << QString("Reason: ") << e.cause(); - - emitFailed("Failed to open file for hashing."); - return; - } - - m_hash = ProviderCaps.hash(provider, &file, hash_type); - - file.close(); + return true; +} +void Hasher::executeTask() +{ + m_hash = hash(m_file_path, m_algorithm); if (m_hash.isEmpty()) { emitFailed("Empty hash!"); } else { @@ -125,20 +84,23 @@ void BlockedModHasher::executeTask() } } -QStringList BlockedModHasher::getHashTypes() +QString Hasher::getResult() const { - return ProviderCaps.hashType(provider); + return m_hash; } -bool BlockedModHasher::useHashType(QString type) +QString Hasher::getPath() const { - auto types = ProviderCaps.hashType(provider); - if (types.contains(type)) { - hash_type = type; - return true; - } - qDebug() << "Bad hash type " << type << " for provider"; - return false; + return m_file_path; } +QList hashType(ModPlatform::ResourceProvider p) +{ + switch (p) { + case ModPlatform::ResourceProvider::MODRINTH: + return { Algorithm::Sha512, Algorithm::Sha1 }; + case ModPlatform::ResourceProvider::FLAME: + return { Algorithm::Sha1, Algorithm::Md5, Algorithm::Murmur2 }; + } +} } // namespace Hashing diff --git a/launcher/modplatform/helpers/HashUtils.h b/launcher/modplatform/helpers/HashUtils.h index 73a2435a2c..d1091c465f 100644 --- a/launcher/modplatform/helpers/HashUtils.h +++ b/launcher/modplatform/helpers/HashUtils.h @@ -7,61 +7,36 @@ namespace Hashing { +enum class Algorithm { Sha512, Sha1, Md5, Murmur2 }; + +QList hashType(ModPlatform::ResourceProvider); +QString hash(QString file_path, Algorithm alg); +QString algorithmToString(Algorithm alg); + class Hasher : public Task { Q_OBJECT public: using Ptr = shared_qobject_ptr; - Hasher(QString file_path) : m_path(std::move(file_path)) {} + Hasher(QString file_path, Algorithm algorithm = Algorithm::Sha1); /* We can't really abort this task, but we can say we aborted and finish our thing quickly :) */ - bool abort() override { return true; } + bool abort() override; - void executeTask() override = 0; + void executeTask() override; - QString getResult() const { return m_hash; }; - QString getPath() const { return m_path; }; + QString getResult() const; + QString getPath() const; signals: void resultsReady(QString hash); protected: QString m_hash; - QString m_path; -}; - -class FlameHasher : public Hasher { - public: - FlameHasher(QString file_path) : Hasher(file_path) { setObjectName(QString("FlameHasher: %1").arg(file_path)); } - - void executeTask() override; -}; - -class ModrinthHasher : public Hasher { - public: - ModrinthHasher(QString file_path) : Hasher(file_path) { setObjectName(QString("ModrinthHasher: %1").arg(file_path)); } - - void executeTask() override; -}; - -class BlockedModHasher : public Hasher { - public: - BlockedModHasher(QString file_path, ModPlatform::ResourceProvider provider); - - void executeTask() override; - - QStringList getHashTypes(); - bool useHashType(QString type); - - private: - ModPlatform::ResourceProvider provider; - QString hash_type; + QString m_file_path; + Algorithm m_algorithm = Algorithm::Sha1; }; Hasher::Ptr createHasher(QString file_path, ModPlatform::ResourceProvider provider); -Hasher::Ptr createFlameHasher(QString file_path); -Hasher::Ptr createModrinthHasher(QString file_path); -Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::ResourceProvider provider); -Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::ResourceProvider provider, QString type); } // namespace Hashing diff --git a/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp b/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp index e78061f27b..341de89c98 100644 --- a/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp +++ b/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp @@ -6,6 +6,7 @@ #include "ResourceDownloadTask.h" +#include "modplatform/ModIndex.h" #include "modplatform/helpers/HashUtils.h" #include "tasks/ConcurrentTask.h" @@ -13,7 +14,6 @@ #include "minecraft/mod/ModFolderModel.h" static ModrinthAPI api; -static ModPlatform::ProviderCapabilities ProviderCaps; bool ModrinthCheckUpdate::abort() { @@ -36,7 +36,7 @@ void ModrinthCheckUpdate::executeTask() // Create all hashes QStringList hashes; - auto best_hash_type = ProviderCaps.hashType(ModPlatform::ResourceProvider::MODRINTH).first(); + auto best_hash_type = Hashing::algorithmToString(Hashing::hashType(ModPlatform::ResourceProvider::MODRINTH).first()); ConcurrentTask hashing_task(this, "MakeModrinthHashesTask", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt()); for (auto* mod : m_mods) { @@ -51,7 +51,7 @@ void ModrinthCheckUpdate::executeTask() // need to generate a new hash if the current one is innadequate // (though it will rarely happen, if at all) if (mod->metadata()->hash_format != best_hash_type) { - auto hash_task = Hashing::createModrinthHasher(mod->fileinfo().absoluteFilePath()); + auto hash_task = Hashing::createHasher(mod->fileinfo().absoluteFilePath(), ModPlatform::ResourceProvider::MODRINTH); connect(hash_task.get(), &Hashing::Hasher::resultsReady, [&hashes, &mappings, mod](QString hash) { hashes.append(hash); mappings.insert(hash, mod); diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp index 4671a330d5..40cd2c3893 100644 --- a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp @@ -24,9 +24,9 @@ #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" #include "modplatform/ModIndex.h" +#include "modplatform/helpers/HashUtils.h" static ModrinthAPI api; -static ModPlatform::ProviderCapabilities ProviderCaps; bool shouldDownloadOnSide(QString side) { @@ -237,8 +237,9 @@ auto Modrinth::loadIndexedPackVersion(QJsonObject& obj, QString preferred_hash_t file.hash = Json::requireString(hash_list, preferred_hash_type); file.hash_type = preferred_hash_type; } else { - auto hash_types = ProviderCaps.hashType(ModPlatform::ResourceProvider::MODRINTH); - for (auto& hash_type : hash_types) { + auto hash_types = Hashing::hashType(ModPlatform::ResourceProvider::MODRINTH); + 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/TomlFile.cpp b/launcher/settings/TomlFile.cpp index d79e44ee9f..41371e469b 100644 --- a/launcher/settings/TomlFile.cpp +++ b/launcher/settings/TomlFile.cpp @@ -156,6 +156,30 @@ QVariant TomlFile::get(QString key, QVariant def) const } } +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(); @@ -206,10 +230,22 @@ void TomlFile::set(QString key, QVariant val) // case QVariant::Map: // case QVariant::List: default: - if (val.canConvert()) - m_data.insert_or_assign(stdKey, val.value()); - else if (val.canConvert()) - m_data.insert_or_assign(stdKey, val.value()); + // 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; } } diff --git a/launcher/ui/dialogs/BlockedModsDialog.cpp b/launcher/ui/dialogs/BlockedModsDialog.cpp index 2b415c2d98..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::createBlockedModHasher(path, ModPlatform::ResourceProvider::FLAME, 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(); From 4c6e9c766292e62be44fbcfa05bd904b36dd8d0a Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 6 Jun 2024 21:42:21 +0300 Subject: [PATCH 4/6] update toml parsers Signed-off-by: Trial97 --- launcher/CMakeLists.txt | 4 ++ launcher/Toml.cpp | 46 +++++++++++++++ launcher/Toml.h | 34 +++++++++++ launcher/minecraft/mod/ModDetails.cpp | 68 +++++++++------------- launcher/minecraft/mod/ModDetails.h | 20 +++++++ launcher/modplatform/ModIndex.cpp | 12 ++++ launcher/modplatform/ModIndex.h | 6 +- launcher/modplatform/helpers/HashUtils.cpp | 13 +++++ launcher/modplatform/helpers/HashUtils.h | 1 + 9 files changed, 162 insertions(+), 42 deletions(-) create mode 100644 launcher/Toml.cpp create mode 100644 launcher/Toml.h diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 639152d49d..e4b3337be4 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -57,6 +57,10 @@ set(CORE_SOURCES Json.h Json.cpp + # Toml parsing helpers + Toml.h + Toml.cpp + FileSystem.h FileSystem.cpp 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/ModDetails.cpp b/launcher/minecraft/mod/ModDetails.cpp index 93f3b97493..fbed04fd48 100644 --- a/launcher/minecraft/mod/ModDetails.cpp +++ b/launcher/minecraft/mod/ModDetails.cpp @@ -17,8 +17,8 @@ */ #include "ModDetails.h" -#include -#include +#include "Toml.h" +#include "modplatform/helpers/HashUtils.h" ModLicense::ModLicense(QString license) { @@ -77,37 +77,12 @@ bool ModLicense::isEmpty() return this->name.isEmpty() && this->id.isEmpty() && this->url.isEmpty() && this->description.isEmpty(); } -QString getTomlString(toml::table table, QString key, QString def = {}) -{ - return QString::fromStdString(table[key.toStdString()].value_or(def.toStdString())); -} - -QStringList getTomlStringList(toml::array* arr) -{ - QStringList list; - if (arr) { - for (auto&& v : *arr) { - list.push_back(QString::fromStdString(v.value_or(""))); - } - } - return list; -} - -toml::array stringListToToml(QStringList list) -{ - toml::array arr; - for (auto v : list) { - arr.push_back(v.toStdString()); - } - return arr; -} - ModLicense::ModLicense(toml::table table) { - name = getTomlString(table, "name"); - id = getTomlString(table, "id"); - url = getTomlString(table, "url"); - description = getTomlString(table, "description"); + name = Toml::getString(table, "name"); + id = Toml::getString(table, "id"); + url = Toml::getString(table, "url"); + description = Toml::getString(table, "description"); } toml::table ModLicense::toToml() @@ -173,17 +148,17 @@ ModDetails& ModDetails::operator=(const ModDetails&& other) ModDetails::ModDetails(toml::table table) { - mod_id = getTomlString(table, "mod_id"); - name = getTomlString(table, "name"); - version = getTomlString(table, "version"); - mcversion = getTomlString(table, "mcversion"); - homeurl = getTomlString(table, "homeurl"); - description = getTomlString(table, "description"); - issue_tracker = getTomlString(table, "issue_tracker"); - icon_path = getTomlString(table, "icon_path"); + 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 = getTomlStringList(table["authors"].as_array()); + authors = Toml::toStringList(table["authors"].as_array()); if (auto licenseArr = table["licenses"].as_array()) { for (auto&& l : *licenseArr) { if (auto table = l.as_table()) { @@ -211,7 +186,18 @@ toml::table ModDetails::toToml() { "issue_tracker", issue_tracker.toStdString() }, { "icon_path", icon_path.toStdString() }, { "format_id", new_format_id }, - { "authors", stringListToToml(authors) }, + { "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() } }; +} diff --git a/launcher/minecraft/mod/ModDetails.h b/launcher/minecraft/mod/ModDetails.h index 2f2c9dd47f..9543610866 100644 --- a/launcher/minecraft/mod/ModDetails.h +++ b/launcher/minecraft/mod/ModDetails.h @@ -44,6 +44,8 @@ #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 @@ -118,3 +120,21 @@ struct ModDetails { toml::table toToml(); }; + +struct ResourceHash { + Hashing::Algorithm alg = Hashing::Algorithm::Sha1; + QString hash = {}; + + ResourceHash(toml::table table); + toml::table toToml(); +}; + +// enum class Side { ClientSide = 1 << 0, ServerSide = 1 << 1, UniversalSide = ClientSide | ServerSide }; +// struct ProviderInfo { +// ModPlatform::ResourceProvider name; +// QString id = {}; +// QString version = {}; +// QString url = {}; +// Side side = Side::UniversalSide; +// loaders = [""] mcVersions = [""] releaseType = "" +// }; \ No newline at end of file diff --git a/launcher/modplatform/ModIndex.cpp b/launcher/modplatform/ModIndex.cpp index 0ef2b0ab3f..709afd7339 100644 --- a/launcher/modplatform/ModIndex.cpp +++ b/launcher/modplatform/ModIndex.cpp @@ -21,6 +21,7 @@ #include #include #include +#include "Toml.h" namespace ModPlatform { @@ -106,4 +107,15 @@ auto getModLoaderString(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() } }; +} } // namespace ModPlatform diff --git a/launcher/modplatform/ModIndex.h b/launcher/modplatform/ModIndex.h index dae53d3220..ace66ced5d 100644 --- a/launcher/modplatform/ModIndex.h +++ b/launcher/modplatform/ModIndex.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include class QIODevice; @@ -89,6 +89,10 @@ struct Dependency { QVariant addonId; DependencyType type; QString version; + + Dependency() = default; + Dependency(toml::table table); + toml::table toToml(); }; struct IndexedVersion { diff --git a/launcher/modplatform/helpers/HashUtils.cpp b/launcher/modplatform/helpers/HashUtils.cpp index 6adf690ee8..585c6d45cf 100644 --- a/launcher/modplatform/helpers/HashUtils.cpp +++ b/launcher/modplatform/helpers/HashUtils.cpp @@ -63,6 +63,19 @@ QString algorithmToString(Algorithm alg) } } +Algorithm algorithmFromString(QString alg) +{ + if (alg == "sha512") + return Algorithm::Sha512; + if (alg == "sha1") + return Algorithm::Sha1; + if (alg == "md5") + return Algorithm::Md5; + if (alg == "murmur2") + return Algorithm::Murmur2; + return Algorithm::Sha1; +} + Hasher::Hasher(QString file_path, Algorithm algorithm) : m_file_path(file_path), m_algorithm(algorithm) { setObjectName(QString("%1 Hasher: %2").arg(algorithmToString(m_algorithm), file_path)); diff --git a/launcher/modplatform/helpers/HashUtils.h b/launcher/modplatform/helpers/HashUtils.h index d1091c465f..f61ef04637 100644 --- a/launcher/modplatform/helpers/HashUtils.h +++ b/launcher/modplatform/helpers/HashUtils.h @@ -12,6 +12,7 @@ enum class Algorithm { Sha512, Sha1, Md5, Murmur2 }; QList hashType(ModPlatform::ResourceProvider); QString hash(QString file_path, Algorithm alg); QString algorithmToString(Algorithm alg); +Algorithm algorithmFromString(QString alg); class Hasher : public Task { Q_OBJECT From 3c25232ad27dfeb9b96c94c9a115a8e761f39ad6 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 6 Jun 2024 23:34:52 +0300 Subject: [PATCH 5/6] more toml types Signed-off-by: Trial97 --- launcher/minecraft/mod/Mod.cpp | 4 +- launcher/minecraft/mod/ModDetails.cpp | 81 ++++++++++++++++++- launcher/minecraft/mod/ModDetails.h | 27 ++++--- launcher/modplatform/EnsureMetadataTask.cpp | 9 +-- launcher/modplatform/ModIndex.cpp | 11 +++ launcher/modplatform/ModIndex.h | 17 ++-- launcher/modplatform/flame/FlameModIndex.cpp | 2 +- launcher/modplatform/helpers/HashUtils.cpp | 14 ++-- launcher/modplatform/helpers/HashUtils.h | 5 +- .../modrinth/ModrinthCheckUpdate.cpp | 3 +- .../modrinth/ModrinthPackIndex.cpp | 2 +- launcher/modplatform/packwiz/Packwiz.cpp | 8 +- launcher/settings/TomlFile.cpp | 9 ++- launcher/ui/dialogs/ChooseProviderDialog.cpp | 4 +- launcher/ui/dialogs/ModUpdateDialog.cpp | 4 +- .../ui/dialogs/ResourceDownloadDialog.cpp | 4 +- 16 files changed, 150 insertions(+), 54 deletions(-) diff --git a/launcher/minecraft/mod/Mod.cpp b/launcher/minecraft/mod/Mod.cpp index 75ad8cfa39..8610fc4743 100644 --- a/launcher/minecraft/mod/Mod.cpp +++ b/launcher/minecraft/mod/Mod.cpp @@ -50,8 +50,6 @@ #include "minecraft/mod/tasks/LocalModParseTask.h" #include "modplatform/ModIndex.h" -static ModPlatform::ProviderCapabilities ProviderCaps; - Mod::Mod(const QFileInfo& file) : Resource(file), m_local_details() { m_enabled = (file.suffix() != "disabled"); @@ -260,7 +258,7 @@ void Mod::finishResolvingWithDetails(ModDetails&& details) auto Mod::provider() const -> std::optional { if (metadata()) - return ProviderCaps.readableName(metadata()->provider); + return ModPlatform::ProviderCapabilities::readableName(metadata()->provider); return {}; } diff --git a/launcher/minecraft/mod/ModDetails.cpp b/launcher/minecraft/mod/ModDetails.cpp index fbed04fd48..85e803b241 100644 --- a/launcher/minecraft/mod/ModDetails.cpp +++ b/launcher/minecraft/mod/ModDetails.cpp @@ -18,6 +18,7 @@ #include "ModDetails.h" #include "Toml.h" +#include "modplatform/ModIndex.h" #include "modplatform/helpers/HashUtils.h" ModLicense::ModLicense(QString license) @@ -199,5 +200,83 @@ ResourceHash::ResourceHash(toml::table table) toml::table ResourceHash::toToml() { - return toml::table{ { "alg", Hashing::algorithmToString(alg).toStdString() }, { "hash", hash.toStdString() } }; + 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 9543610866..161ae99d25 100644 --- a/launcher/minecraft/mod/ModDetails.h +++ b/launcher/minecraft/mod/ModDetails.h @@ -129,12 +129,21 @@ struct ResourceHash { toml::table toToml(); }; -// enum class Side { ClientSide = 1 << 0, ServerSide = 1 << 1, UniversalSide = ClientSide | ServerSide }; -// struct ProviderInfo { -// ModPlatform::ResourceProvider name; -// QString id = {}; -// QString version = {}; -// QString url = {}; -// Side side = Side::UniversalSide; -// loaders = [""] mcVersions = [""] releaseType = "" -// }; \ No newline at end of file +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(); +}; \ No newline at end of file diff --git a/launcher/modplatform/EnsureMetadataTask.cpp b/launcher/modplatform/EnsureMetadataTask.cpp index 05ce218d51..87a064673f 100644 --- a/launcher/modplatform/EnsureMetadataTask.cpp +++ b/launcher/modplatform/EnsureMetadataTask.cpp @@ -15,8 +15,6 @@ #include "modplatform/modrinth/ModrinthAPI.h" #include "modplatform/modrinth/ModrinthPackIndex.h" -static ModPlatform::ProviderCapabilities ProviderCaps; - static ModrinthAPI modrinth_api; static FlameAPI flame_api; @@ -162,10 +160,10 @@ void EnsureMetadataTask::executeTask() }); if (m_mods.size() > 1) - setStatus(tr("Requesting metadata information from %1...").arg(ProviderCaps.readableName(m_provider))); + setStatus(tr("Requesting metadata information from %1...").arg(ModPlatform::ProviderCapabilities::readableName(m_provider))); else if (!m_mods.empty()) setStatus(tr("Requesting metadata information from %1 for '%2'...") - .arg(ProviderCaps.readableName(m_provider), m_mods.begin().value()->name())); + .arg(ModPlatform::ProviderCapabilities::readableName(m_provider), m_mods.begin().value()->name())); m_current_task = version_task; version_task->start(); @@ -215,7 +213,8 @@ void EnsureMetadataTask::emitFail(Mod* m, QString key, RemoveFromList remove) Task::Ptr EnsureMetadataTask::modrinthVersionsTask() { - auto hash_type = Hashing::algorithmToString(Hashing::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 01f4cd04f5..e80447c633 100644 --- a/launcher/modplatform/ModIndex.cpp +++ b/launcher/modplatform/ModIndex.cpp @@ -81,6 +81,15 @@ auto ProviderCapabilities::readableName(ResourceProvider p) -> QString return {}; } +ResourceProvider ProviderCapabilities::fromString(QString p) +{ + if (p == "modrinth") + return ResourceProvider::MODRINTH; + if (p == "curseforge") + return ResourceProvider::FLAME; + return {}; +} + QString getMetaURL(ResourceProvider provider, QVariant projectID) { return ((provider == ModPlatform::ResourceProvider::FLAME) ? "https://www.curseforge.com/projects/" : "https://modrinth.com/mod/") + @@ -120,6 +129,8 @@ 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 8a4cb604b2..7103c93b97 100644 --- a/launcher/modplatform/ModIndex.h +++ b/launcher/modplatform/ModIndex.h @@ -40,11 +40,11 @@ enum class ResourceType { MOD, RESOURCE_PACK, SHADER_PACK }; enum class DependencyType { REQUIRED, OPTIONAL, INCOMPATIBLE, EMBEDDED, TOOL, INCLUDE, UNKNOWN }; -class ProviderCapabilities { - public: - auto name(ResourceProvider) -> const char*; - auto readableName(ResourceProvider) -> QString; -}; +namespace ProviderCapabilities { +const char* name(ResourceProvider); +QString readableName(ResourceProvider); +ResourceProvider fromString(QString); +}; // namespace ProviderCapabilities struct ModpackAuthor { QString name; @@ -86,11 +86,12 @@ 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(); }; diff --git a/launcher/modplatform/flame/FlameModIndex.cpp b/launcher/modplatform/flame/FlameModIndex.cpp index bd89bfa55d..0b89ee6785 100644 --- a/launcher/modplatform/flame/FlameModIndex.cpp +++ b/launcher/modplatform/flame/FlameModIndex.cpp @@ -163,7 +163,7 @@ auto FlameMod::loadIndexedPackVersion(QJsonObject& obj, bool load_changelog) -> auto hash_list = Json::ensureArray(obj, "hashes"); for (auto h : hash_list) { auto hash_entry = Json::ensureObject(h); - auto hash_types = Hashing::hashType(ModPlatform::ResourceProvider::FLAME); + auto hash_types = ModPlatform::ProviderCapabilities::hashType(ModPlatform::ResourceProvider::FLAME); auto hash_algo = enumToHash(Json::ensureInteger(hash_entry, "algo", 1, "algorithm")); if (hash_types.contains(hash_algo)) { file.hash = Json::requireString(hash_entry, "value"); diff --git a/launcher/modplatform/helpers/HashUtils.cpp b/launcher/modplatform/helpers/HashUtils.cpp index 585c6d45cf..73a685faca 100644 --- a/launcher/modplatform/helpers/HashUtils.cpp +++ b/launcher/modplatform/helpers/HashUtils.cpp @@ -10,7 +10,7 @@ namespace Hashing { Hasher::Ptr createHasher(QString file_path, ModPlatform::ResourceProvider provider) { - return makeShared(file_path, hashType(provider).first()); + return makeShared(file_path, ModPlatform::ProviderCapabilities::hashType(provider).first()); } QString hash(QString file_path, Algorithm alg) @@ -61,6 +61,7 @@ QString algorithmToString(Algorithm alg) case Algorithm::Murmur2: return "murmur2"; } + return {}; } Algorithm algorithmFromString(QString alg) @@ -107,13 +108,14 @@ QString Hasher::getPath() const return m_file_path; } -QList hashType(ModPlatform::ResourceProvider p) +} // namespace Hashing +QList ModPlatform::ProviderCapabilities::hashType(ModPlatform::ResourceProvider p) { switch (p) { case ModPlatform::ResourceProvider::MODRINTH: - return { Algorithm::Sha512, Algorithm::Sha1 }; + return { Hashing::Algorithm::Sha512, Hashing::Algorithm::Sha1 }; case ModPlatform::ResourceProvider::FLAME: - return { Algorithm::Sha1, Algorithm::Md5, Algorithm::Murmur2 }; + return { Hashing::Algorithm::Sha1, Hashing::Algorithm::Md5, Hashing::Algorithm::Murmur2 }; } -} -} // namespace Hashing + return {}; +} \ No newline at end of file diff --git a/launcher/modplatform/helpers/HashUtils.h b/launcher/modplatform/helpers/HashUtils.h index f61ef04637..dd32bdac57 100644 --- a/launcher/modplatform/helpers/HashUtils.h +++ b/launcher/modplatform/helpers/HashUtils.h @@ -9,7 +9,6 @@ namespace Hashing { enum class Algorithm { Sha512, Sha1, Md5, Murmur2 }; -QList hashType(ModPlatform::ResourceProvider); QString hash(QString file_path, Algorithm alg); QString algorithmToString(Algorithm alg); Algorithm algorithmFromString(QString alg); @@ -41,3 +40,7 @@ class Hasher : public Task { Hasher::Ptr createHasher(QString file_path, ModPlatform::ResourceProvider provider); } // 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 b66522b7ef..51fc7b74d7 100644 --- a/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp +++ b/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp @@ -36,7 +36,8 @@ void ModrinthCheckUpdate::executeTask() // Create all hashes QStringList hashes; - auto best_hash_type = Hashing::algorithmToString(Hashing::hashType(ModPlatform::ResourceProvider::MODRINTH).first()); + auto best_hash_type = + Hashing::algorithmToString(ModPlatform::ProviderCapabilities::hashType(ModPlatform::ResourceProvider::MODRINTH).first()); ConcurrentTask hashing_task(this, "MakeModrinthHashesTask", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt()); for (auto* mod : m_mods) { diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp index 102178cc62..1226fd1240 100644 --- a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp @@ -233,7 +233,7 @@ auto Modrinth::loadIndexedPackVersion(QJsonObject& obj, QString preferred_hash_t file.hash = Json::requireString(hash_list, preferred_hash_type); file.hash_type = preferred_hash_type; } else { - auto hash_types = Hashing::hashType(ModPlatform::ResourceProvider::MODRINTH); + auto hash_types = ModPlatform::ProviderCapabilities::hashType(ModPlatform::ResourceProvider::MODRINTH); for (auto& alg : hash_types) { auto hash_type = Hashing::algorithmToString(alg); if (hash_list.contains(hash_type)) { diff --git a/launcher/modplatform/packwiz/Packwiz.cpp b/launcher/modplatform/packwiz/Packwiz.cpp index c8899345ee..626f1c9df5 100644 --- a/launcher/modplatform/packwiz/Packwiz.cpp +++ b/launcher/modplatform/packwiz/Packwiz.cpp @@ -67,8 +67,6 @@ static inline auto indexFileName(QString const& mod_slug) -> QString return QString("%1.pw.toml").arg(mod_slug); } -static ModPlatform::ProviderCapabilities ProviderCaps; - // Helper functions for extracting data from the TOML file auto stringEntry(toml::table table, QString entry_name) -> QString { @@ -219,7 +217,7 @@ void V1::updateModIndex(QDir& index_dir, Mod& mod) { "hash-format", mod.hash_format.toStdString() }, { "hash", mod.hash.toStdString() }, } }, - { "update", toml::table{ { ProviderCaps.name(mod.provider), update } } } }; + { "update", toml::table{ { ModPlatform::ProviderCapabilities::name(mod.provider), update } } } }; std::stringstream ss; ss << tbl; in_stream << QString::fromStdString(ss.str()); @@ -340,11 +338,11 @@ auto V1::getIndexForMod(QDir& index_dir, QString slug) -> Mod } toml::table* mod_provider_table = nullptr; - if ((mod_provider_table = update_table[ProviderCaps.name(Provider::FLAME)].as_table())) { + if ((mod_provider_table = update_table[ModPlatform::ProviderCapabilities::name(Provider::FLAME)].as_table())) { mod.provider = Provider::FLAME; mod.file_id = intEntry(*mod_provider_table, "file-id"); mod.project_id = intEntry(*mod_provider_table, "project-id"); - } else if ((mod_provider_table = update_table[ProviderCaps.name(Provider::MODRINTH)].as_table())) { + } else if ((mod_provider_table = update_table[ModPlatform::ProviderCapabilities::name(Provider::MODRINTH)].as_table())) { mod.provider = Provider::MODRINTH; mod.mod_id() = stringEntry(*mod_provider_table, "mod-id"); mod.version() = stringEntry(*mod_provider_table, "version"); diff --git a/launcher/settings/TomlFile.cpp b/launcher/settings/TomlFile.cpp index 41371e469b..d3fed1628b 100644 --- a/launcher/settings/TomlFile.cpp +++ b/launcher/settings/TomlFile.cpp @@ -96,13 +96,13 @@ bool TomlFile::saveFile(QString fileName) if (!m_loaded) { auto tmp = m_data; m_data = {}; - if (!loadFile(fileName)) - return false; + loadFile(fileName); m_data = merge_tables(m_data, tmp); } if (!contains("ConfigVersion")) set("ConfigVersion", "1.3"); - std::ofstream outFile(fileName.toStdString()); + std::ofstream outFile; + outFile.open(fileName.toStdString()); if (!outFile.is_open()) { qCritical() << QString("Could not open file %1!").arg(fileName); return false; @@ -303,5 +303,6 @@ bool TomlFile::migrate(QString fileName) set(key, f.get(key)); set("ConfigVersion", "1.3"); - return true; + m_loaded = true; + return saveFile(fileName); } diff --git a/launcher/ui/dialogs/ChooseProviderDialog.cpp b/launcher/ui/dialogs/ChooseProviderDialog.cpp index 83748e1e29..68457802d0 100644 --- a/launcher/ui/dialogs/ChooseProviderDialog.cpp +++ b/launcher/ui/dialogs/ChooseProviderDialog.cpp @@ -6,8 +6,6 @@ #include "modplatform/ModIndex.h" -static ModPlatform::ProviderCapabilities ProviderCaps; - ChooseProviderDialog::ChooseProviderDialog(QWidget* parent, bool single_choice, bool allow_skipping) : QDialog(parent), ui(new Ui::ChooseProviderDialog) { @@ -78,7 +76,7 @@ void ChooseProviderDialog::addProviders() QRadioButton* btn; for (auto& provider : { ModPlatform::ResourceProvider::MODRINTH, ModPlatform::ResourceProvider::FLAME }) { - btn = new QRadioButton(ProviderCaps.readableName(provider), this); + btn = new QRadioButton(ModPlatform::ProviderCapabilities::readableName(provider), this); m_providers.addButton(btn, btn_index++); ui->providersLayout->addWidget(btn); } diff --git a/launcher/ui/dialogs/ModUpdateDialog.cpp b/launcher/ui/dialogs/ModUpdateDialog.cpp index 6649bee4e0..1583b4f463 100644 --- a/launcher/ui/dialogs/ModUpdateDialog.cpp +++ b/launcher/ui/dialogs/ModUpdateDialog.cpp @@ -25,8 +25,6 @@ #include -static ModPlatform::ProviderCapabilities ProviderCaps; - static std::list mcVersions(BaseInstance* inst) { return { static_cast(inst)->getPackProfile()->getComponent("net.minecraft")->getVersion() }; @@ -427,7 +425,7 @@ void ModUpdateDialog::appendMod(CheckUpdateTask::UpdatableMod const& info, QStri item_top->setExpanded(true); auto provider_item = new QTreeWidgetItem(item_top); - provider_item->setText(0, tr("Provider: %1").arg(ProviderCaps.readableName(info.provider))); + provider_item->setText(0, tr("Provider: %1").arg(ModPlatform::ProviderCapabilities::readableName(info.provider))); auto old_version_item = new QTreeWidgetItem(item_top); old_version_item->setText(0, tr("Old version: %1").arg(info.old_version.isEmpty() ? tr("Not installed") : info.old_version)); diff --git a/launcher/ui/dialogs/ResourceDownloadDialog.cpp b/launcher/ui/dialogs/ResourceDownloadDialog.cpp index c5dfe4915c..ef36edb32b 100644 --- a/launcher/ui/dialogs/ResourceDownloadDialog.cpp +++ b/launcher/ui/dialogs/ResourceDownloadDialog.cpp @@ -126,8 +126,6 @@ void ResourceDownloadDialog::connectButtons() connect(HelpButton, &QPushButton::clicked, m_container, &PageContainer::help); } -static ModPlatform::ProviderCapabilities ProviderCaps; - void ResourceDownloadDialog::confirm() { auto confirm_dialog = ReviewMessageBox::create(this, tr("Confirm %1 to download").arg(resourcesString())); @@ -169,7 +167,7 @@ void ResourceDownloadDialog::confirm() for (auto& task : selected) { auto extraInfo = dependencyExtraInfo.value(task->getPack()->addonId.toString()); confirm_dialog->appendResource({ task->getName(), task->getFilename(), task->getCustomPath(), - ProviderCaps.name(task->getProvider()), extraInfo.required_by, + ModPlatform::ProviderCapabilities::name(task->getProvider()), extraInfo.required_by, task->getVersion().version_type.toString(), !extraInfo.maybe_installed }); } From 53557c4d03c63c1e3ccca601c3ac8ef2273ec2ba Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 18 Jun 2024 22:27:18 +0300 Subject: [PATCH 6/6] more types Signed-off-by: Trial97 --- launcher/minecraft/mod/ModDetails.h | 15 +++++++++++++++ launcher/modplatform/helpers/HashUtils.cpp | 5 ----- launcher/modplatform/helpers/HashUtils.h | 2 -- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/launcher/minecraft/mod/ModDetails.h b/launcher/minecraft/mod/ModDetails.h index 161ae99d25..053d5fcb14 100644 --- a/launcher/minecraft/mod/ModDetails.h +++ b/launcher/minecraft/mod/ModDetails.h @@ -146,4 +146,19 @@ struct ProviderInfo { 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/modplatform/helpers/HashUtils.cpp b/launcher/modplatform/helpers/HashUtils.cpp index 2f7e7bd591..68460b46ba 100644 --- a/launcher/modplatform/helpers/HashUtils.cpp +++ b/launcher/modplatform/helpers/HashUtils.cpp @@ -24,11 +24,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) {} diff --git a/launcher/modplatform/helpers/HashUtils.h b/launcher/modplatform/helpers/HashUtils.h index 3ebd615ac6..b59586779d 100644 --- a/launcher/modplatform/helpers/HashUtils.h +++ b/launcher/modplatform/helpers/HashUtils.h @@ -46,8 +46,6 @@ 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 {