diff options
Diffstat (limited to 'launcher/modplatform')
| -rw-r--r-- | launcher/modplatform/ModAPI.h | 15 | ||||
| -rw-r--r-- | launcher/modplatform/flame/FileResolvingTask.cpp | 16 | ||||
| -rw-r--r-- | launcher/modplatform/flame/FlameAPI.h | 17 | ||||
| -rw-r--r-- | launcher/modplatform/flame/FlameModIndex.cpp | 9 | ||||
| -rw-r--r-- | launcher/modplatform/flame/FlamePackIndex.cpp | 10 | ||||
| -rw-r--r-- | launcher/modplatform/flame/FlamePackIndex.h | 1 | ||||
| -rw-r--r-- | launcher/modplatform/flame/PackManifest.cpp | 15 | ||||
| -rw-r--r-- | launcher/modplatform/modrinth/ModrinthAPI.h | 75 | ||||
| -rw-r--r-- | launcher/modplatform/modrinth/ModrinthPackIndex.cpp | 17 | ||||
| -rw-r--r-- | launcher/modplatform/modrinth/ModrinthPackIndex.h | 17 | ||||
| -rw-r--r-- | launcher/modplatform/modrinth/ModrinthPackManifest.cpp | 156 | ||||
| -rw-r--r-- | launcher/modplatform/modrinth/ModrinthPackManifest.h | 107 | ||||
| -rw-r--r-- | launcher/modplatform/technic/SolderPackManifest.cpp | 2 |
13 files changed, 408 insertions, 49 deletions
diff --git a/launcher/modplatform/ModAPI.h b/launcher/modplatform/ModAPI.h index 8e6cd45c..4230df0b 100644 --- a/launcher/modplatform/ModAPI.h +++ b/launcher/modplatform/ModAPI.h @@ -16,14 +16,21 @@ class ModAPI { public: virtual ~ModAPI() = default; - // https://docs.curseforge.com/?http#tocS_ModLoaderType - enum ModLoaderType { Unspecified = 0, Forge = 1, Cauldron = 2, LiteLoader = 3, Fabric = 4, Quilt = 5 }; + enum ModLoaderType { + Unspecified = 0, + Forge = 1 << 0, + Cauldron = 1 << 1, + LiteLoader = 1 << 2, + Fabric = 1 << 3, + Quilt = 1 << 4 + }; + Q_DECLARE_FLAGS(ModLoaderTypes, ModLoaderType) struct SearchArgs { int offset; QString search; QString sorting; - ModLoaderType mod_loader; + ModLoaderTypes loaders; std::list<Version> versions; }; @@ -33,7 +40,7 @@ class ModAPI { struct VersionSearchArgs { QString addonId; std::list<Version> mcVersions; - ModLoaderType loader; + ModLoaderTypes loaders; }; virtual void getVersions(CallerType* caller, VersionSearchArgs&& args) const = 0; diff --git a/launcher/modplatform/flame/FileResolvingTask.cpp b/launcher/modplatform/flame/FileResolvingTask.cpp index 95924a68..0deb99c4 100644 --- a/launcher/modplatform/flame/FileResolvingTask.cpp +++ b/launcher/modplatform/flame/FileResolvingTask.cpp @@ -31,7 +31,21 @@ void Flame::FileResolvingTask::netJobFinished() for (auto& bytes : results) { auto& out = m_toProcess.files[index]; try { - failed &= (!out.parseFromBytes(bytes)); + bool fail = (!out.parseFromBytes(bytes)); + if(fail){ + //failed :( probably disabled mod, try to add to the list + auto doc = Json::requireDocument(bytes); + if (!doc.isObject()) { + throw JSONValidationError(QString("data is not an object? that's not supposed to happen")); + } + auto obj = Json::ensureObject(doc.object(), "data"); + //FIXME : HACK, MAY NOT WORK FOR LONG + out.url = QUrl(QString("https://media.forgecdn.net/files/%1/%2/%3") + .arg(QString::number(QString::number(out.fileId).leftRef(4).toInt()) + ,QString::number(QString::number(out.fileId).rightRef(3).toInt()) + ,QUrl::toPercentEncoding(out.fileName)), QUrl::TolerantMode); + } + failed &= fail; } catch (const JSONValidationError& e) { qCritical() << "Resolving of" << out.projectId << out.fileId << "failed because of a parsing error:"; qCritical() << e.cause(); diff --git a/launcher/modplatform/flame/FlameAPI.h b/launcher/modplatform/flame/FlameAPI.h index 61628e60..8bb33d47 100644 --- a/launcher/modplatform/flame/FlameAPI.h +++ b/launcher/modplatform/flame/FlameAPI.h @@ -37,14 +37,14 @@ class FlameAPI : public NetworkModAPI { .arg(args.offset) .arg(args.search) .arg(getSortFieldInt(args.sorting)) - .arg(getMappedModLoader(args.mod_loader)) + .arg(getMappedModLoader(args.loaders)) .arg(gameVersionStr); }; inline auto getVersionsURL(VersionSearchArgs& args) const -> QString override { QString gameVersionQuery = args.mcVersions.size() == 1 ? QString("gameVersion=%1&").arg(args.mcVersions.front().toString()) : ""; - QString modLoaderQuery = QString("modLoaderType=%1&").arg(getMappedModLoader(args.loader)); + QString modLoaderQuery = QString("modLoaderType=%1&").arg(getMappedModLoader(args.loaders)); return QString("https://api.curseforge.com/v1/mods/%1/files?pageSize=10000&%2%3") .arg(args.addonId) @@ -53,11 +53,16 @@ class FlameAPI : public NetworkModAPI { }; public: - static auto getMappedModLoader(const ModLoaderType type) -> const ModLoaderType + static auto getMappedModLoader(const ModLoaderTypes loaders) -> const int { + // https://docs.curseforge.com/?http#tocS_ModLoaderType + if (loaders & Forge) + return 1; + if (loaders & Fabric) + return 4; // TODO: remove this once Quilt drops official Fabric support - if (type == Quilt) // NOTE: Most if not all Fabric mods should work *currently* - return Fabric; - return type; + if (loaders & Quilt) // NOTE: Most if not all Fabric mods should work *currently* + return 4; // Quilt would probably be 5 + return 0; } }; diff --git a/launcher/modplatform/flame/FlameModIndex.cpp b/launcher/modplatform/flame/FlameModIndex.cpp index ba0824cf..9846b156 100644 --- a/launcher/modplatform/flame/FlameModIndex.cpp +++ b/launcher/modplatform/flame/FlameModIndex.cpp @@ -56,8 +56,15 @@ void FlameMod::loadIndexedPackVersions(ModPlatform::IndexedPack& pack, file.fileId = Json::requireInteger(obj, "id"); file.date = Json::requireString(obj, "fileDate"); file.version = Json::requireString(obj, "displayName"); - file.downloadUrl = Json::requireString(obj, "downloadUrl"); file.fileName = Json::requireString(obj, "fileName"); + file.downloadUrl = Json::ensureString(obj, "downloadUrl", ""); + if(file.downloadUrl.isEmpty()){ + //FIXME : HACK, MAY NOT WORK FOR LONG + file.downloadUrl = QString("https://media.forgecdn.net/files/%1/%2/%3") + .arg(QString::number(QString::number(file.fileId.toInt()).leftRef(4).toInt()) + ,QString::number(QString::number(file.fileId.toInt()).rightRef(3).toInt()) + ,QUrl::toPercentEncoding(file.fileName)); + } unsortedVersions.append(file); } diff --git a/launcher/modplatform/flame/FlamePackIndex.cpp b/launcher/modplatform/flame/FlamePackIndex.cpp index ac24c647..6d48a3bf 100644 --- a/launcher/modplatform/flame/FlamePackIndex.cpp +++ b/launcher/modplatform/flame/FlamePackIndex.cpp @@ -65,7 +65,15 @@ void Flame::loadIndexedPackVersions(Flame::IndexedPack& pack, QJsonArray& arr) // pick the latest version supported file.mcVersion = versionArray[0].toString(); file.version = Json::requireString(version, "displayName"); - file.downloadUrl = Json::requireString(version, "downloadUrl"); + file.fileName = Json::requireString(version, "fileName"); + file.downloadUrl = Json::ensureString(version, "downloadUrl"); + if(file.downloadUrl.isEmpty()){ + //FIXME : HACK, MAY NOT WORK FOR LONG + file.downloadUrl = QString("https://media.forgecdn.net/files/%1/%2/%3") + .arg(QString::number(QString::number(file.fileId).leftRef(4).toInt()) + ,QString::number(QString::number(file.fileId).rightRef(3).toInt()) + ,QUrl::toPercentEncoding(file.fileName)); + } unsortedVersions.append(file); } diff --git a/launcher/modplatform/flame/FlamePackIndex.h b/launcher/modplatform/flame/FlamePackIndex.h index 7ffa29c3..a8bb15be 100644 --- a/launcher/modplatform/flame/FlamePackIndex.h +++ b/launcher/modplatform/flame/FlamePackIndex.h @@ -18,6 +18,7 @@ struct IndexedVersion { QString version; QString mcVersion; QString downloadUrl; + QString fileName; }; struct IndexedPack diff --git a/launcher/modplatform/flame/PackManifest.cpp b/launcher/modplatform/flame/PackManifest.cpp index e4f90c1a..3217a756 100644 --- a/launcher/modplatform/flame/PackManifest.cpp +++ b/launcher/modplatform/flame/PackManifest.cpp @@ -71,11 +71,6 @@ bool Flame::File::parseFromBytes(const QByteArray& bytes) fileName = Json::requireString(obj, "fileName"); - QString rawUrl = Json::requireString(obj, "downloadUrl"); - url = QUrl(rawUrl, QUrl::TolerantMode); - if (!url.isValid()) { - throw JSONValidationError(QString("Invalid URL: %1").arg(rawUrl)); - } // This is a piece of a Flame project JSON pulled out into the file metadata (here) for convenience // It is also optional type = File::Type::SingleFile; @@ -87,7 +82,17 @@ bool Flame::File::parseFromBytes(const QByteArray& bytes) // this is probably a mod, dunno what else could modpacks download targetFolder = "mods"; } + QString rawUrl = Json::ensureString(obj, "downloadUrl"); + if(rawUrl.isEmpty()){ + //either there somehow is an emtpy string as a link, or it's null either way it's invalid + //soft failing + return false; + } + url = QUrl(rawUrl, QUrl::TolerantMode); + if (!url.isValid()) { + throw JSONValidationError(QString("Invalid URL: %1").arg(rawUrl)); + } resolved = true; return true; } diff --git a/launcher/modplatform/modrinth/ModrinthAPI.h b/launcher/modplatform/modrinth/ModrinthAPI.h index 86852c94..79bc5175 100644 --- a/launcher/modplatform/modrinth/ModrinthAPI.h +++ b/launcher/modplatform/modrinth/ModrinthAPI.h @@ -1,5 +1,24 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * Copyright (c) 2022 flowln <flowlnlnln@gmail.com> + * + * 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 <https://www.gnu.org/licenses/>. + */ + #pragma once +#include "BuildConfig.h" #include "modplatform/ModAPI.h" #include "modplatform/helpers/NetworkModAPI.h" @@ -9,30 +28,25 @@ class ModrinthAPI : public NetworkModAPI { public: inline auto getAuthorURL(const QString& name) const -> QString { return "https://modrinth.com/user/" + name; }; - static auto getModLoaderStrings(ModLoaderType type) -> const QStringList + static auto getModLoaderStrings(const ModLoaderTypes types) -> const QStringList { QStringList l; - switch (type) + for (auto loader : {Forge, Fabric, Quilt}) { - case Unspecified: - for (auto loader : {Forge, Fabric, Quilt}) - { - l << ModAPI::getModLoaderString(loader); - } - break; - - case Quilt: - l << ModAPI::getModLoaderString(Fabric); - default: - l << ModAPI::getModLoaderString(type); + if ((types & loader) || types == Unspecified) + { + l << ModAPI::getModLoaderString(loader); + } } + if ((types & Quilt) && (~types & Fabric)) // Add Fabric if Quilt is in use, if Fabric isn't already there + l << ModAPI::getModLoaderString(Fabric); return l; } - static auto getModLoaderFilters(ModLoaderType type) -> const QString + static auto getModLoaderFilters(ModLoaderTypes types) -> const QString { QStringList l; - for (auto loader : getModLoaderStrings(type)) + for (auto loader : getModLoaderStrings(types)) { l << QString("\"categories:%1\"").arg(loader); } @@ -42,33 +56,34 @@ class ModrinthAPI : public NetworkModAPI { private: inline auto getModSearchURL(SearchArgs& args) const -> QString override { - if (!validateModLoader(args.mod_loader)) { + if (!validateModLoaders(args.loaders)) { qWarning() << "Modrinth only have Forge and Fabric-compatible mods!"; return ""; } - return QString( - "https://api.modrinth.com/v2/search?" - "offset=%1&" - "limit=25&" - "query=%2&" - "index=%3&" - "facets=[[%4],%5[\"project_type:mod\"]]") + return QString(BuildConfig.MODRINTH_PROD_URL + + "/search?" + "offset=%1&" + "limit=25&" + "query=%2&" + "index=%3&" + "facets=[[%4],%5[\"project_type:mod\"]]") .arg(args.offset) .arg(args.search) .arg(args.sorting) - .arg(getModLoaderFilters(args.mod_loader)) + .arg(getModLoaderFilters(args.loaders)) .arg(getGameVersionsArray(args.versions)); }; inline auto getVersionsURL(VersionSearchArgs& args) const -> QString override { - return QString("https://api.modrinth.com/v2/project/%1/version?" - "game_versions=[%2]" - "loaders=[\"%3\"]") + return QString(BuildConfig.MODRINTH_PROD_URL + + "/project/%1/version?" + "game_versions=[%2]" + "loaders=[\"%3\"]") .arg(args.addonId) .arg(getGameVersionsString(args.mcVersions)) - .arg(getModLoaderStrings(args.loader).join("\",\"")); + .arg(getModLoaderStrings(args.loaders).join("\",\"")); }; auto getGameVersionsArray(std::list<Version> mcVersions) const -> QString @@ -81,9 +96,9 @@ class ModrinthAPI : public NetworkModAPI { return s.isEmpty() ? QString() : QString("[%1],").arg(s); } - inline auto validateModLoader(ModLoaderType modLoader) const -> bool + inline auto validateModLoaders(ModLoaderTypes loaders) const -> bool { - return modLoader == Unspecified || modLoader == Forge || modLoader == Fabric || modLoader == Quilt; + return (loaders == Unspecified) || (loaders & (Forge | Fabric | Quilt)); } }; diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp index a3c2f166..f7fa9864 100644 --- a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp @@ -1,3 +1,20 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * + * 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 <https://www.gnu.org/licenses/>. + */ + #include "ModrinthPackIndex.h" #include "ModrinthAPI.h" diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.h b/launcher/modplatform/modrinth/ModrinthPackIndex.h index fd17847a..7f306f25 100644 --- a/launcher/modplatform/modrinth/ModrinthPackIndex.h +++ b/launcher/modplatform/modrinth/ModrinthPackIndex.h @@ -1,3 +1,20 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * + * 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 <https://www.gnu.org/licenses/>. + */ + #pragma once #include "modplatform/ModIndex.h" diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp new file mode 100644 index 00000000..f1ad39ce --- /dev/null +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * Copyright (c) 2022 flowln <flowlnlnln@gmail.com> + * + * 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 <https://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * Copyright 2022 kb1000 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ModrinthPackManifest.h" +#include "Json.h" + +#include "modplatform/modrinth/ModrinthAPI.h" + +#include "minecraft/MinecraftInstance.h" +#include "minecraft/PackProfile.h" + +static ModrinthAPI api; + +namespace Modrinth { + +void loadIndexedPack(Modpack& pack, QJsonObject& obj) +{ + pack.id = Json::ensureString(obj, "project_id"); + + pack.name = Json::ensureString(obj, "title"); + pack.description = Json::ensureString(obj, "description"); + auto temp_author_name = Json::ensureString(obj, "author"); + pack.author = std::make_tuple(temp_author_name, api.getAuthorURL(temp_author_name)); + pack.iconName = QString("modrinth_%1").arg(Json::ensureString(obj, "slug")); + pack.iconUrl = Json::ensureString(obj, "icon_url"); +} + +void loadIndexedInfo(Modpack& pack, QJsonObject& obj) +{ + pack.extra.body = Json::ensureString(obj, "body"); + pack.extra.projectUrl = QString("https://modrinth.com/modpack/%1").arg(Json::ensureString(obj, "slug")); + pack.extra.sourceUrl = Json::ensureString(obj, "source_url"); + pack.extra.wikiUrl = Json::ensureString(obj, "wiki_url"); + + pack.extraInfoLoaded = true; +} + +void loadIndexedVersions(Modpack& pack, QJsonDocument& doc) +{ + QVector<ModpackVersion> unsortedVersions; + + auto arr = Json::requireArray(doc); + + for (auto versionIter : arr) { + auto obj = Json::requireObject(versionIter); + auto file = loadIndexedVersion(obj); + + if(!file.id.isEmpty()) // Heuristic to check if the returned value is valid + unsortedVersions.append(file); + } + auto orderSortPredicate = [](const ModpackVersion& a, const ModpackVersion& b) -> bool { + // dates are in RFC 3339 format + return a.date > b.date; + }; + + std::sort(unsortedVersions.begin(), unsortedVersions.end(), orderSortPredicate); + + pack.versions.swap(unsortedVersions); + + pack.versionsLoaded = true; +} + +auto validateDownloadUrl(QUrl url) -> bool +{ + auto domain = url.host(); + if(domain == "cdn.modrinth.com") + return true; + if(domain == "edge.forgecdn.net") + return true; + if(domain == "media.forgecdn.net") + return true; + if(domain == "github.com") + return true; + if(domain == "raw.githubusercontent.com") + return true; + + return false; +} + +auto loadIndexedVersion(QJsonObject &obj) -> ModpackVersion +{ + ModpackVersion file; + + file.name = Json::requireString(obj, "name"); + file.version = Json::requireString(obj, "version_number"); + + file.id = Json::requireString(obj, "id"); + file.project_id = Json::requireString(obj, "project_id"); + + file.date = Json::requireString(obj, "date_published"); + + auto files = Json::requireArray(obj, "files"); + + + for (auto file_iter : files) { + File indexed_file; + auto parent = Json::requireObject(file_iter); + auto is_primary = Json::ensureBoolean(parent, "primary", false); + if (!is_primary) { + auto filename = Json::ensureString(parent, "filename"); + // Checking suffix here is fine because it's the response from Modrinth, + // so one would assume it will always be in English. + if(!filename.endsWith("mrpack") && !filename.endsWith("zip")) + continue; + } + + auto url = Json::requireString(parent, "url"); + + if(!validateDownloadUrl(url)) + continue; + + file.download_url = url; + if(is_primary) + break; + } + + if(file.download_url.isEmpty()) + return {}; + + return file; +} + +} // namespace Modrinth diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.h b/launcher/modplatform/modrinth/ModrinthPackManifest.h new file mode 100644 index 00000000..e5fc9a70 --- /dev/null +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.h @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * Copyright (c) 2022 flowln <flowlnlnln@gmail.com> + * + * 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 <https://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * Copyright 2022 kb1000 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <QMetaType> + +#include <QByteArray> +#include <QCryptographicHash> +#include <QString> +#include <QUrl> +#include <QVector> + +class MinecraftInstance; + +namespace Modrinth { + +struct File +{ + QString path; + + QCryptographicHash::Algorithm hashAlgorithm; + QByteArray hash; + // TODO: should this support multiple download URLs, like the JSON does? + QUrl download; +}; + +struct ModpackExtra { + QString body; + + QString projectUrl; + QString sourceUrl; + QString wikiUrl; +}; + +struct ModpackVersion { + QString name; + QString version; + + QString id; + QString project_id; + + QString date; + + QString download_url; +}; + +struct Modpack { + QString id; + + QString name; + QString description; + std::tuple<QString, QUrl> author; + QString iconName; + QUrl iconUrl; + + bool versionsLoaded = false; + bool extraInfoLoaded = false; + + ModpackExtra extra; + QVector<ModpackVersion> versions; +}; + +void loadIndexedPack(Modpack&, QJsonObject&); +void loadIndexedInfo(Modpack&, QJsonObject&); +void loadIndexedVersions(Modpack&, QJsonDocument&); +auto loadIndexedVersion(QJsonObject&) -> ModpackVersion; + +auto validateDownloadUrl(QUrl) -> bool; + +} + +Q_DECLARE_METATYPE(Modrinth::Modpack) +Q_DECLARE_METATYPE(Modrinth::ModpackVersion) diff --git a/launcher/modplatform/technic/SolderPackManifest.cpp b/launcher/modplatform/technic/SolderPackManifest.cpp index 16fe0b0e..e52a7ec0 100644 --- a/launcher/modplatform/technic/SolderPackManifest.cpp +++ b/launcher/modplatform/technic/SolderPackManifest.cpp @@ -37,7 +37,7 @@ void loadPack(Pack& v, QJsonObject& obj) static void loadPackBuildMod(PackBuildMod& b, QJsonObject& obj) { b.name = Json::requireString(obj, "name"); - b.version = Json::requireString(obj, "version"); + b.version = Json::ensureString(obj, "version", ""); b.md5 = Json::requireString(obj, "md5"); b.url = Json::requireString(obj, "url"); } |
