commit
bcf45c74a1
@ -362,6 +362,8 @@ set(MINECRAFT_SOURCES
|
||||
minecraft/mod/tasks/LocalWorldSaveParseTask.cpp
|
||||
minecraft/mod/tasks/LocalResourceParse.h
|
||||
minecraft/mod/tasks/LocalResourceParse.cpp
|
||||
minecraft/mod/tasks/GetModDependenciesTask.h
|
||||
minecraft/mod/tasks/GetModDependenciesTask.cpp
|
||||
|
||||
# Assets
|
||||
minecraft/AssetsUtils.h
|
||||
|
@ -38,6 +38,8 @@ class ResourceDownloadTask : public SequentialTask {
|
||||
const QString& getFilename() const { return m_pack_version.fileName; }
|
||||
const QString& getCustomPath() const { return m_custom_target_folder; }
|
||||
const QVariant& getVersionID() const { return m_pack_version.fileId; }
|
||||
const ModPlatform::IndexedVersion& getVersion() const { return m_pack_version; }
|
||||
const ModPlatform::ResourceProvider& getProvider() const { return m_pack->provider; }
|
||||
const QString& getName() const { return m_pack->name; }
|
||||
ModPlatform::IndexedPack::Ptr getPack() { return m_pack; }
|
||||
|
||||
|
252
launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp
Normal file
252
launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp
Normal file
@ -0,0 +1,252 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2023 Trial97 <alexandru.tripon97@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/>.
|
||||
*/
|
||||
|
||||
#include "GetModDependenciesTask.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include "Json.h"
|
||||
#include "QObjectPtr.h"
|
||||
#include "minecraft/mod/MetadataHandler.h"
|
||||
#include "modplatform/ModIndex.h"
|
||||
#include "modplatform/ResourceAPI.h"
|
||||
#include "modplatform/flame/FlameAPI.h"
|
||||
#include "modplatform/modrinth/ModrinthAPI.h"
|
||||
#include "tasks/ConcurrentTask.h"
|
||||
#include "tasks/SequentialTask.h"
|
||||
#include "ui/pages/modplatform/ModModel.h"
|
||||
#include "ui/pages/modplatform/flame/FlameResourceModels.h"
|
||||
#include "ui/pages/modplatform/modrinth/ModrinthResourceModels.h"
|
||||
|
||||
static Version mcVersion(BaseInstance* inst)
|
||||
{
|
||||
return static_cast<MinecraftInstance*>(inst)->getPackProfile()->getComponent("net.minecraft")->getVersion();
|
||||
}
|
||||
|
||||
static ResourceAPI::ModLoaderTypes mcLoaders(BaseInstance* inst)
|
||||
{
|
||||
return static_cast<MinecraftInstance*>(inst)->getPackProfile()->getModLoaders().value();
|
||||
}
|
||||
|
||||
GetModDependenciesTask::GetModDependenciesTask(QObject* parent,
|
||||
BaseInstance* instance,
|
||||
ModFolderModel* folder,
|
||||
QList<std::shared_ptr<PackDependency>> selected)
|
||||
: SequentialTask(parent, tr("Get dependencies"))
|
||||
, m_selected(selected)
|
||||
, m_flame_provider{ ModPlatform::ResourceProvider::FLAME, std::make_shared<ResourceDownload::FlameModModel>(*instance),
|
||||
std::make_shared<FlameAPI>() }
|
||||
, m_modrinth_provider{ ModPlatform::ResourceProvider::MODRINTH, std::make_shared<ResourceDownload::ModrinthModModel>(*instance),
|
||||
std::make_shared<ModrinthAPI>() }
|
||||
, m_version(mcVersion(instance))
|
||||
, m_loaderType(mcLoaders(instance))
|
||||
{
|
||||
for (auto mod : folder->allMods())
|
||||
if (auto meta = mod->metadata(); meta)
|
||||
m_mods.append(meta);
|
||||
prepare();
|
||||
};
|
||||
|
||||
void GetModDependenciesTask::prepare()
|
||||
{
|
||||
for (auto sel : m_selected) {
|
||||
for (auto dep : getDependenciesForVersion(sel->version, sel->pack->provider)) {
|
||||
addTask(prepareDependencyTask(dep, sel->pack->provider, 20));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ModPlatform::Dependency GetModDependenciesTask::getOverride(const ModPlatform::Dependency& dep,
|
||||
const ModPlatform::ResourceProvider providerName)
|
||||
{
|
||||
if (auto isQuilt = m_loaderType & ResourceAPI::Quilt; isQuilt || m_loaderType & ResourceAPI::Fabric) {
|
||||
auto overide = ModPlatform::getOverrideDeps();
|
||||
auto over = std::find_if(overide.cbegin(), overide.cend(), [dep, providerName, isQuilt](auto o) {
|
||||
return o.provider == providerName && dep.addonId == (isQuilt ? o.fabric : o.quilt);
|
||||
});
|
||||
if (over != overide.cend()) {
|
||||
return { isQuilt ? over->quilt : over->fabric, dep.type };
|
||||
}
|
||||
}
|
||||
return dep;
|
||||
}
|
||||
|
||||
QList<ModPlatform::Dependency> GetModDependenciesTask::getDependenciesForVersion(const ModPlatform::IndexedVersion& version,
|
||||
const ModPlatform::ResourceProvider providerName)
|
||||
{
|
||||
QList<ModPlatform::Dependency> c_dependencies;
|
||||
for (auto ver_dep : version.dependencies) {
|
||||
if (ver_dep.type != ModPlatform::DependencyType::REQUIRED)
|
||||
continue;
|
||||
|
||||
auto isOnlyVersion = providerName == ModPlatform::ResourceProvider::MODRINTH && ver_dep.addonId.toString().isEmpty();
|
||||
if (auto dep = std::find_if(c_dependencies.begin(), c_dependencies.end(),
|
||||
[&ver_dep, isOnlyVersion](const ModPlatform::Dependency& i) {
|
||||
return isOnlyVersion ? i.version == ver_dep.version : i.addonId == ver_dep.addonId;
|
||||
});
|
||||
dep != c_dependencies.end())
|
||||
continue; // check the current dependency list
|
||||
|
||||
if (auto dep = std::find_if(m_selected.begin(), m_selected.end(),
|
||||
[&ver_dep, providerName, isOnlyVersion](std::shared_ptr<PackDependency> i) {
|
||||
return i->pack->provider == providerName && (isOnlyVersion ? i->version.version == ver_dep.version
|
||||
: i->pack->addonId == ver_dep.addonId);
|
||||
});
|
||||
dep != m_selected.end())
|
||||
continue; // check the selected versions
|
||||
|
||||
if (auto dep = std::find_if(m_mods.begin(), m_mods.end(),
|
||||
[&ver_dep, providerName, isOnlyVersion](std::shared_ptr<Metadata::ModStruct> i) {
|
||||
return i->provider == providerName &&
|
||||
(isOnlyVersion ? i->file_id == ver_dep.version : i->project_id == ver_dep.addonId);
|
||||
});
|
||||
dep != m_mods.end())
|
||||
continue; // check the existing mods
|
||||
|
||||
if (auto dep = std::find_if(m_pack_dependencies.begin(), m_pack_dependencies.end(),
|
||||
[&ver_dep, providerName, isOnlyVersion](std::shared_ptr<PackDependency> i) {
|
||||
return i->pack->provider == providerName && (isOnlyVersion ? i->version.version == ver_dep.addonId
|
||||
: i->pack->addonId == ver_dep.addonId);
|
||||
});
|
||||
dep != m_pack_dependencies.end()) // check loaded dependencies
|
||||
continue;
|
||||
|
||||
c_dependencies.append(getOverride(ver_dep, providerName));
|
||||
}
|
||||
return c_dependencies;
|
||||
};
|
||||
|
||||
Task::Ptr GetModDependenciesTask::getProjectInfoTask(std::shared_ptr<PackDependency> pDep)
|
||||
{
|
||||
auto provider = pDep->pack->provider == m_flame_provider.name ? m_flame_provider : m_modrinth_provider;
|
||||
auto responseInfo = std::make_shared<QByteArray>();
|
||||
auto info = provider.api->getProject(pDep->pack->addonId.toString(), responseInfo);
|
||||
QObject::connect(info.get(), &NetJob::succeeded, [responseInfo, provider, pDep] {
|
||||
QJsonParseError parse_error{};
|
||||
QJsonDocument doc = QJsonDocument::fromJson(*responseInfo, &parse_error);
|
||||
if (parse_error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "Error while parsing JSON response for mod info at " << parse_error.offset
|
||||
<< " reason: " << parse_error.errorString();
|
||||
qDebug() << *responseInfo;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
auto obj = provider.name == ModPlatform::ResourceProvider::FLAME ? Json::requireObject(Json::requireObject(doc), "data")
|
||||
: Json::requireObject(doc);
|
||||
provider.mod->loadIndexedPack(*pDep->pack, obj);
|
||||
} catch (const JSONValidationError& e) {
|
||||
qDebug() << doc;
|
||||
qWarning() << "Error while reading mod info: " << e.cause();
|
||||
}
|
||||
});
|
||||
return info;
|
||||
}
|
||||
|
||||
Task::Ptr GetModDependenciesTask::prepareDependencyTask(const ModPlatform::Dependency& dep,
|
||||
const ModPlatform::ResourceProvider providerName,
|
||||
int level)
|
||||
{
|
||||
auto pDep = std::make_shared<PackDependency>();
|
||||
pDep->dependency = dep;
|
||||
pDep->pack = std::make_shared<ModPlatform::IndexedPack>();
|
||||
pDep->pack->addonId = dep.addonId;
|
||||
pDep->pack->provider = providerName;
|
||||
|
||||
m_pack_dependencies.append(pDep);
|
||||
auto provider = providerName == m_flame_provider.name ? m_flame_provider : m_modrinth_provider;
|
||||
|
||||
auto tasks = makeShared<SequentialTask>(
|
||||
this, QString("DependencyInfo: %1").arg(dep.addonId.toString().isEmpty() ? dep.version : dep.addonId.toString()));
|
||||
|
||||
if (!dep.addonId.toString().isEmpty()) {
|
||||
tasks->addTask(getProjectInfoTask(pDep));
|
||||
}
|
||||
|
||||
ResourceAPI::DependencySearchArgs args = { dep, m_version, m_loaderType };
|
||||
ResourceAPI::DependencySearchCallbacks callbacks;
|
||||
|
||||
callbacks.on_succeed = [dep, provider, pDep, level, this](auto& doc, auto& pack) {
|
||||
try {
|
||||
QJsonArray arr;
|
||||
if (dep.version.length() != 0 && doc.isObject()) {
|
||||
arr.append(doc.object());
|
||||
} else {
|
||||
arr = doc.isObject() ? Json::ensureArray(doc.object(), "data") : doc.array();
|
||||
}
|
||||
pDep->version = provider.mod->loadDependencyVersions(dep, arr);
|
||||
if (!pDep->version.addonId.isValid()) {
|
||||
if (m_loaderType & ResourceAPI::Quilt) { // falback for quilt
|
||||
auto overide = ModPlatform::getOverrideDeps();
|
||||
auto over = std::find_if(overide.cbegin(), overide.cend(),
|
||||
[dep, provider](auto o) { return o.provider == provider.name && dep.addonId == o.quilt; });
|
||||
if (over != overide.cend()) {
|
||||
removePack(dep.addonId);
|
||||
addTask(prepareDependencyTask({ over->fabric, dep.type }, provider.name, level));
|
||||
return;
|
||||
}
|
||||
}
|
||||
qWarning() << "Error while reading mod version empty ";
|
||||
qDebug() << doc;
|
||||
return;
|
||||
}
|
||||
pDep->version.is_currently_selected = true;
|
||||
pDep->pack->versions = { pDep->version };
|
||||
pDep->pack->versionsLoaded = true;
|
||||
|
||||
} catch (const JSONValidationError& e) {
|
||||
qDebug() << doc;
|
||||
qWarning() << "Error while reading mod version: " << e.cause();
|
||||
return;
|
||||
}
|
||||
if (level == 0) {
|
||||
qWarning() << "Dependency cycle exeeded";
|
||||
return;
|
||||
}
|
||||
if (dep.addonId.toString().isEmpty() && !pDep->version.addonId.toString().isEmpty()) {
|
||||
pDep->pack->addonId = pDep->version.addonId;
|
||||
auto dep = getOverride({ pDep->version.addonId, pDep->dependency.type }, provider.name);
|
||||
if (dep.addonId != pDep->version.addonId) {
|
||||
removePack(pDep->version.addonId);
|
||||
addTask(prepareDependencyTask(dep, provider.name, level));
|
||||
} else
|
||||
addTask(getProjectInfoTask(pDep));
|
||||
}
|
||||
for (auto dep : getDependenciesForVersion(pDep->version, provider.name)) {
|
||||
addTask(prepareDependencyTask(dep, provider.name, level - 1));
|
||||
}
|
||||
};
|
||||
|
||||
auto version = provider.api->getDependencyVersion(std::move(args), std::move(callbacks));
|
||||
tasks->addTask(version);
|
||||
return tasks;
|
||||
};
|
||||
|
||||
void GetModDependenciesTask::removePack(const QVariant addonId)
|
||||
{
|
||||
auto pred = [addonId](const std::shared_ptr<PackDependency>& v) { return v->pack->addonId == addonId; };
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 1, 0)
|
||||
m_pack_dependencies.removeIf(pred);
|
||||
#else
|
||||
for (auto it = m_pack_dependencies.begin(); it != m_pack_dependencies.end();)
|
||||
if (pred(*it))
|
||||
it = m_pack_dependencies.erase(it);
|
||||
else
|
||||
++it;
|
||||
#endif
|
||||
}
|
84
launcher/minecraft/mod/tasks/GetModDependenciesTask.h
Normal file
84
launcher/minecraft/mod/tasks/GetModDependenciesTask.h
Normal file
@ -0,0 +1,84 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2023 Trial97 <alexandru.tripon97@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 <QDir>
|
||||
#include <QEventLoop>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "minecraft/mod/MetadataHandler.h"
|
||||
#include "minecraft/mod/ModFolderModel.h"
|
||||
#include "modplatform/ModIndex.h"
|
||||
#include "modplatform/ResourceAPI.h"
|
||||
#include "tasks/SequentialTask.h"
|
||||
#include "tasks/Task.h"
|
||||
#include "ui/pages/modplatform/ModModel.h"
|
||||
|
||||
class GetModDependenciesTask : public SequentialTask {
|
||||
Q_OBJECT
|
||||
public:
|
||||
using Ptr = shared_qobject_ptr<GetModDependenciesTask>;
|
||||
|
||||
struct PackDependency {
|
||||
ModPlatform::Dependency dependency;
|
||||
ModPlatform::IndexedPack::Ptr pack;
|
||||
ModPlatform::IndexedVersion version;
|
||||
PackDependency() = default;
|
||||
PackDependency(const ModPlatform::IndexedPack::Ptr p, const ModPlatform::IndexedVersion& v)
|
||||
{
|
||||
pack = p;
|
||||
version = v;
|
||||
}
|
||||
};
|
||||
|
||||
struct Provider {
|
||||
ModPlatform::ResourceProvider name;
|
||||
std::shared_ptr<ResourceDownload::ModModel> mod;
|
||||
std::shared_ptr<ResourceAPI> api;
|
||||
};
|
||||
|
||||
explicit GetModDependenciesTask(QObject* parent,
|
||||
BaseInstance* instance,
|
||||
ModFolderModel* folder,
|
||||
QList<std::shared_ptr<PackDependency>> selected);
|
||||
|
||||
auto getDependecies() const -> QList<std::shared_ptr<PackDependency>> { return m_pack_dependencies; }
|
||||
|
||||
protected slots:
|
||||
Task::Ptr prepareDependencyTask(const ModPlatform::Dependency&, const ModPlatform::ResourceProvider, int);
|
||||
QList<ModPlatform::Dependency> getDependenciesForVersion(const ModPlatform::IndexedVersion&,
|
||||
const ModPlatform::ResourceProvider providerName);
|
||||
void prepare();
|
||||
Task::Ptr getProjectInfoTask(std::shared_ptr<PackDependency> pDep);
|
||||
ModPlatform::Dependency getOverride(const ModPlatform::Dependency&, const ModPlatform::ResourceProvider providerName);
|
||||
void removePack(const QVariant addonId);
|
||||
|
||||
private:
|
||||
QList<std::shared_ptr<PackDependency>> m_pack_dependencies;
|
||||
QList<std::shared_ptr<Metadata::ModStruct>> m_mods;
|
||||
QList<std::shared_ptr<PackDependency>> m_selected;
|
||||
Provider m_flame_provider;
|
||||
Provider m_modrinth_provider;
|
||||
|
||||
Version m_version;
|
||||
ResourceAPI::ModLoaderTypes m_loaderType;
|
||||
};
|
@ -1,25 +1,24 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* 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 "LocalModUpdateTask.h"
|
||||
|
||||
#include "Application.h"
|
||||
#include "FileSystem.h"
|
||||
#include "minecraft/mod/MetadataHandler.h"
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
|
||||
* Copyright (c) 2023 Trial97 <alexandru.tripon97@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
|
||||
@ -33,6 +34,8 @@ enum class ResourceProvider { MODRINTH, FLAME };
|
||||
|
||||
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*;
|
||||
@ -52,6 +55,12 @@ struct DonationData {
|
||||
QString url;
|
||||
};
|
||||
|
||||
struct Dependency {
|
||||
QVariant addonId;
|
||||
DependencyType type;
|
||||
QString version;
|
||||
};
|
||||
|
||||
struct IndexedVersion {
|
||||
QVariant addonId;
|
||||
QVariant fileId;
|
||||
@ -66,6 +75,7 @@ struct IndexedVersion {
|
||||
QString hash;
|
||||
bool is_preferred = true;
|
||||
QString changelog;
|
||||
QList<Dependency> dependencies;
|
||||
|
||||
// For internal use, not provided by APIs
|
||||
bool is_currently_selected = false;
|
||||
@ -119,6 +129,22 @@ struct IndexedPack {
|
||||
}
|
||||
};
|
||||
|
||||
struct OverrideDep {
|
||||
QString quilt;
|
||||
QString fabric;
|
||||
QString slug;
|
||||
ModPlatform::ResourceProvider provider;
|
||||
};
|
||||
|
||||
inline auto getOverrideDeps() -> QList<OverrideDep>
|
||||
{
|
||||
return { { "634179", "306612", "API", ModPlatform::ResourceProvider::FLAME },
|
||||
{ "720410", "308769", "KotlinLibraries", ModPlatform::ResourceProvider::FLAME },
|
||||
|
||||
{ "qvIfYCYJ", "P7dR8mSH", "API", ModPlatform::ResourceProvider::MODRINTH },
|
||||
{ "lwVhp9o5", "Ha28R6CL", "KotlinLibraries", ModPlatform::ResourceProvider::MODRINTH } };
|
||||
};
|
||||
|
||||
} // namespace ModPlatform
|
||||
|
||||
Q_DECLARE_METATYPE(ModPlatform::IndexedPack)
|
||||
|
@ -111,6 +111,16 @@ class ResourceAPI {
|
||||
std::function<void(QJsonDocument&, ModPlatform::IndexedPack)> on_succeed;
|
||||
};
|
||||
|
||||
struct DependencySearchArgs {
|
||||
ModPlatform::Dependency dependency;
|
||||
Version mcVersion;
|
||||
ModLoaderTypes loader;
|
||||
};
|
||||
|
||||
struct DependencySearchCallbacks {
|
||||
std::function<void(QJsonDocument&, const ModPlatform::Dependency&)> on_succeed;
|
||||
};
|
||||
|
||||
public:
|
||||
/** Gets a list of available sorting methods for this API. */
|
||||
[[nodiscard]] virtual auto getSortingMethods() const -> QList<SortingMethod> = 0;
|
||||
@ -143,6 +153,12 @@ class ResourceAPI {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual Task::Ptr getDependencyVersion(DependencySearchArgs&&, DependencySearchCallbacks&&) const
|
||||
{
|
||||
qWarning() << "TODO";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static auto getModLoaderString(ModLoaderType type) -> const QString
|
||||
{
|
||||
switch (type) {
|
||||
|
@ -4,8 +4,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include "modplatform/ModIndex.h"
|
||||
#include "modplatform/ResourceAPI.h"
|
||||
#include "modplatform/helpers/NetworkResourceAPI.h"
|
||||
|
||||
class FlameAPI : public NetworkResourceAPI {
|
||||
@ -75,14 +77,44 @@ class FlameAPI : public NetworkResourceAPI {
|
||||
|
||||
[[nodiscard]] std::optional<QString> getVersionsURL(VersionSearchArgs const& args) const override
|
||||
{
|
||||
QString url{ QString("https://api.curseforge.com/v1/mods/%1/files?pageSize=10000&").arg(args.pack.addonId.toString()) };
|
||||
auto mappedModLoader = getMappedModLoader(args.loaders.value());
|
||||
auto addonId = args.pack.addonId.toString();
|
||||
if (args.loaders.value() & Quilt) {
|
||||
auto overide = ModPlatform::getOverrideDeps();
|
||||
auto over = std::find_if(overide.cbegin(), overide.cend(), [addonId](auto dep) {
|
||||
return dep.provider == ModPlatform::ResourceProvider::FLAME && addonId == dep.quilt;
|
||||
});
|
||||
if (over != overide.cend()) {
|
||||
mappedModLoader = 5;
|
||||
}
|
||||
}
|
||||
QString url{ QString("https://api.curseforge.com/v1/mods/%1/files?pageSize=10000&").arg(addonId) };
|
||||
|
||||
QStringList get_parameters;
|
||||
if (args.mcVersions.has_value())
|
||||
get_parameters.append(QString("gameVersion=%1").arg(args.mcVersions.value().front().toString()));
|
||||
if (args.loaders.has_value())
|
||||
get_parameters.append(QString("modLoaderType=%1").arg(getMappedModLoader(args.loaders.value())));
|
||||
get_parameters.append(QString("modLoaderType=%1").arg(mappedModLoader));
|
||||
|
||||
return url + get_parameters.join('&');
|
||||
};
|
||||
|
||||
[[nodiscard]] std::optional<QString> getDependencyURL(DependencySearchArgs const& args) const override
|
||||
{
|
||||
auto mappedModLoader = getMappedModLoader(args.loader);
|
||||
auto addonId = args.dependency.addonId.toString();
|
||||
if (args.loader & Quilt) {
|
||||
auto overide = ModPlatform::getOverrideDeps();
|
||||
auto over = std::find_if(overide.cbegin(), overide.cend(), [addonId](auto dep) {
|
||||
return dep.provider == ModPlatform::ResourceProvider::FLAME && addonId == dep.quilt;
|
||||
});
|
||||
if (over != overide.cend()) {
|
||||
mappedModLoader = 5;
|
||||
}
|
||||
}
|
||||
return QString("https://api.curseforge.com/v1/mods/%1/files?pageSize=10000&gameVersion=%2&modLoaderType=%3")
|
||||
.arg(addonId)
|
||||
.arg(args.mcVersion.toString())
|
||||
.arg(mappedModLoader);
|
||||
};
|
||||
};
|
||||
|
@ -39,15 +39,15 @@ void FlameMod::loadURLs(ModPlatform::IndexedPack& pack, QJsonObject& obj)
|
||||
auto links_obj = Json::ensureObject(obj, "links");
|
||||
|
||||
pack.extraData.issuesUrl = Json::ensureString(links_obj, "issuesUrl");
|
||||
if(pack.extraData.issuesUrl.endsWith('/'))
|
||||
if (pack.extraData.issuesUrl.endsWith('/'))
|
||||
pack.extraData.issuesUrl.chop(1);
|
||||
|
||||
pack.extraData.sourceUrl = Json::ensureString(links_obj, "sourceUrl");
|
||||
if(pack.extraData.sourceUrl.endsWith('/'))
|
||||
if (pack.extraData.sourceUrl.endsWith('/'))
|
||||
pack.extraData.sourceUrl.chop(1);
|
||||
|
||||
pack.extraData.wikiUrl = Json::ensureString(links_obj, "wikiUrl");
|
||||
if(pack.extraData.wikiUrl.endsWith('/'))
|
||||
if (pack.extraData.wikiUrl.endsWith('/'))
|
||||
pack.extraData.wikiUrl.chop(1);
|
||||
|
||||
if (!pack.extraData.body.isEmpty())
|
||||
@ -56,7 +56,7 @@ void FlameMod::loadURLs(ModPlatform::IndexedPack& pack, QJsonObject& obj)
|
||||
|
||||
void FlameMod::loadBody(ModPlatform::IndexedPack& pack, QJsonObject& obj)
|
||||
{
|
||||
pack.extraData.body = api.getModDescription(pack.addonId.toInt());
|
||||
pack.extraData.body = api.getModDescription(pack.addonId.toInt());
|
||||
|
||||
if (!pack.extraData.issuesUrl.isEmpty() || !pack.extraData.sourceUrl.isEmpty() || !pack.extraData.wikiUrl.isEmpty())
|
||||
pack.extraDataLoaded = true;
|
||||
@ -64,12 +64,12 @@ void FlameMod::loadBody(ModPlatform::IndexedPack& pack, QJsonObject& obj)
|
||||
|
||||
static QString enumToString(int hash_algorithm)
|
||||
{
|
||||
switch(hash_algorithm){
|
||||
default:
|
||||
case 1:
|
||||
return "sha1";
|
||||
case 2:
|
||||
return "md5";
|
||||
switch (hash_algorithm) {
|
||||
default:
|
||||
case 1:
|
||||
return "sha1";
|
||||
case 2:
|
||||
return "md5";
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,10 +86,10 @@ void FlameMod::loadIndexedPackVersions(ModPlatform::IndexedPack& pack,
|
||||
auto obj = versionIter.toObject();
|
||||
|
||||
auto file = loadIndexedPackVersion(obj);
|
||||
if(!file.addonId.isValid())
|
||||
if (!file.addonId.isValid())
|
||||
file.addonId = pack.addonId;
|
||||
|
||||
if(file.fileId.isValid()) // Heuristic to check if the returned value is valid
|
||||
if (file.fileId.isValid()) // Heuristic to check if the returned value is valid
|
||||
unsortedVersions.append(file);
|
||||
}
|
||||
|
||||
@ -136,8 +136,61 @@ auto FlameMod::loadIndexedPackVersion(QJsonObject& obj, bool load_changelog) ->
|
||||
}
|
||||
}
|
||||
|
||||
if(load_changelog)
|
||||
auto dependencies = Json::ensureArray(obj, "dependencies");
|
||||
for (auto d : dependencies) {
|
||||
auto dep = Json::ensureObject(d);
|
||||
ModPlatform::Dependency dependency;
|
||||
dependency.addonId = Json::requireInteger(dep, "modId");
|
||||
switch (Json::requireInteger(dep, "relationType")) {
|
||||
case 1: // EmbeddedLibrary
|
||||
dependency.type = ModPlatform::DependencyType::EMBEDDED;
|
||||
break;
|
||||
case 2: // OptionalDependency
|
||||
dependency.type = ModPlatform::DependencyType::OPTIONAL;
|
||||
break;
|
||||
case 3: // RequiredDependency
|
||||
dependency.type = ModPlatform::DependencyType::REQUIRED;
|
||||
break;
|
||||
case 4: // Tool
|
||||
dependency.type = ModPlatform::DependencyType::TOOL;
|
||||
break;
|
||||
case 5: // Incompatible
|
||||
dependency.type = ModPlatform::DependencyType::INCOMPATIBLE;
|
||||
break;
|
||||
case 6: // Include
|
||||
dependency.type = ModPlatform::DependencyType::INCLUDE;
|
||||
break;
|
||||
default:
|
||||
dependency.type = ModPlatform::DependencyType::UNKNOWN;
|
||||
break;
|
||||
}
|
||||
file.dependencies.append(dependency);
|
||||
}
|
||||
|
||||
if (load_changelog)
|
||||
file.changelog = api.getModFileChangelog(file.addonId.toInt(), file.fileId.toInt());
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
ModPlatform::IndexedVersion FlameMod::loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr)
|
||||
{
|
||||
QVector<ModPlatform::IndexedVersion> versions;
|
||||
for (auto versionIter : arr) {
|
||||
auto obj = versionIter.toObject();
|
||||
|
||||
auto file = loadIndexedPackVersion(obj);
|
||||
if (!file.addonId.isValid())
|
||||
file.addonId = m.addonId;
|
||||
|
||||
if (file.fileId.isValid()) // Heuristic to check if the returned value is valid
|
||||
versions.append(file);
|
||||
}
|
||||
|
||||
auto orderSortPredicate = [](const ModPlatform::IndexedVersion& a, const ModPlatform::IndexedVersion& b) -> bool {
|
||||
// dates are in RFC 3339 format
|
||||
return a.date > b.date;
|
||||
};
|
||||
std::sort(versions.begin(), versions.end(), orderSortPredicate);
|
||||
return versions.front();
|
||||
};
|
||||
|
@ -6,8 +6,8 @@
|
||||
|
||||
#include "modplatform/ModIndex.h"
|
||||
|
||||
#include "BaseInstance.h"
|
||||
#include <QNetworkAccessManager>
|
||||
#include "BaseInstance.h"
|
||||
|
||||
namespace FlameMod {
|
||||
|
||||
@ -19,5 +19,5 @@ void loadIndexedPackVersions(ModPlatform::IndexedPack& pack,
|
||||
const shared_qobject_ptr<QNetworkAccessManager>& network,
|
||||
const BaseInstance* inst);
|
||||
auto loadIndexedPackVersion(QJsonObject& obj, bool load_changelog = false) -> ModPlatform::IndexedVersion;
|
||||
|
||||
auto loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion;
|
||||
} // namespace FlameMod
|
@ -4,6 +4,7 @@
|
||||
#include <QMetaType>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
#include "modplatform/ModIndex.h"
|
||||
|
||||
namespace Flame {
|
||||
|
||||
@ -27,8 +28,7 @@ struct ModpackExtra {
|
||||
QString sourceUrl;
|
||||
};
|
||||
|
||||
struct IndexedPack
|
||||
{
|
||||
struct IndexedPack {
|
||||
int addonId;
|
||||
QString name;
|
||||
QString description;
|
||||
@ -43,9 +43,9 @@ struct IndexedPack
|
||||
ModpackExtra extra;
|
||||
};
|
||||
|
||||
void loadIndexedPack(IndexedPack & m, QJsonObject & obj);
|
||||
void loadIndexedPack(IndexedPack& m, QJsonObject& obj);
|
||||
void loadIndexedInfo(IndexedPack&, QJsonObject&);
|
||||
void loadIndexedPackVersions(IndexedPack & m, QJsonArray & arr);
|
||||
}
|
||||
void loadIndexedPackVersions(IndexedPack& m, QJsonArray& arr);
|
||||
} // namespace Flame
|
||||
|
||||
Q_DECLARE_METATYPE(Flame::IndexedPack)
|
||||
|
@ -117,3 +117,32 @@ Task::Ptr NetworkResourceAPI::getProject(QString addonId, std::shared_ptr<QByteA
|
||||
|
||||
return netJob;
|
||||
}
|
||||
|
||||
Task::Ptr NetworkResourceAPI::getDependencyVersion(DependencySearchArgs&& args, DependencySearchCallbacks&& callbacks) const
|
||||
{
|
||||
auto versions_url_optional = getDependencyURL(args);
|
||||
if (!versions_url_optional.has_value())
|
||||
return nullptr;
|
||||
|
||||
auto versions_url = versions_url_optional.value();
|
||||
|
||||
auto netJob = makeShared<NetJob>(QString("%1::Dependency").arg(args.dependency.addonId.toString()), APPLICATION->network());
|
||||
auto response = std::make_shared<QByteArray>();
|
||||
|
||||
netJob->addNetAction(Net::Download::makeByteArray(versions_url, response));
|
||||
|
||||
QObject::connect(netJob.get(), &NetJob::succeeded, [=] {
|
||||
QJsonParseError parse_error{};
|
||||
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
|
||||
if (parse_error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "Error while parsing JSON response for getting versions at " << parse_error.offset
|
||||
<< " reason: " << parse_error.errorString();
|
||||
qWarning() << *response;
|
||||
return;
|
||||
}
|
||||
|
||||
callbacks.on_succeed(doc, args.dependency);
|
||||
});
|
||||
|
||||
return netJob;
|
||||
};
|
||||
|
@ -15,9 +15,11 @@ class NetworkResourceAPI : public ResourceAPI {
|
||||
|
||||
Task::Ptr getProjectInfo(ProjectInfoArgs&&, ProjectInfoCallbacks&&) const override;
|
||||
Task::Ptr getProjectVersions(VersionSearchArgs&&, VersionSearchCallbacks&&) const override;
|
||||
Task::Ptr getDependencyVersion(DependencySearchArgs&&, DependencySearchCallbacks&&) const override;
|
||||
|
||||
protected:
|
||||
[[nodiscard]] virtual auto getSearchURL(SearchArgs const& args) const -> std::optional<QString> = 0;
|
||||
[[nodiscard]] virtual auto getInfoURL(QString const& id) const -> std::optional<QString> = 0;
|
||||
[[nodiscard]] virtual auto getVersionsURL(VersionSearchArgs const& args) const -> std::optional<QString> = 0;
|
||||
[[nodiscard]] virtual auto getDependencyURL(DependencySearchArgs const& args) const -> std::optional<QString> = 0;
|
||||
};
|
||||
|
@ -38,7 +38,7 @@ class ModrinthAPI : public NetworkResourceAPI {
|
||||
static auto getModLoaderStrings(const ModLoaderTypes types) -> const QStringList
|
||||
{
|
||||
QStringList l;
|
||||
for (auto loader : {Forge, Fabric, Quilt}) {
|
||||
for (auto loader : { Forge, Fabric, Quilt }) {
|
||||
if (types & loader) {
|
||||
l << getModLoaderString(loader);
|
||||
}
|
||||
@ -51,8 +51,7 @@ class ModrinthAPI : public NetworkResourceAPI {
|
||||
static auto getModLoaderFilters(ModLoaderTypes types) -> const QString
|
||||
{
|
||||
QStringList l;
|
||||
for (auto loader : getModLoaderStrings(types))
|
||||
{
|
||||
for (auto loader : getModLoaderStrings(types)) {
|
||||
l << QString("\"categories:%1\"").arg(loader);
|
||||
}
|
||||
return l.join(',');
|
||||
@ -135,16 +134,22 @@ class ModrinthAPI : public NetworkResourceAPI {
|
||||
auto getGameVersionsArray(std::list<Version> mcVersions) const -> QString
|
||||
{
|
||||
QString s;
|
||||
for(auto& ver : mcVersions){
|
||||
for (auto& ver : mcVersions) {
|
||||
s += QString("\"versions:%1\",").arg(ver.toString());
|
||||
}
|
||||
s.remove(s.length() - 1, 1); //remove last comma
|
||||
s.remove(s.length() - 1, 1); // remove last comma
|
||||
return s.isEmpty() ? QString() : s;
|
||||
}
|
||||
|
||||
inline auto validateModLoaders(ModLoaderTypes loaders) const -> bool
|
||||
{
|
||||
return loaders & (Forge | Fabric | Quilt);
|
||||
}
|
||||
inline auto validateModLoaders(ModLoaderTypes loaders) const -> bool { return loaders & (Forge | Fabric | Quilt); }
|
||||
|
||||
[[nodiscard]] std::optional<QString> getDependencyURL(DependencySearchArgs const& args) const override
|
||||
{
|
||||
return args.dependency.version.length() != 0 ? QString("%1/version/%2").arg(BuildConfig.MODRINTH_PROD_URL, args.dependency.version)
|
||||
: QString("%1/project/%2/version?game_versions=[\"%3\"]&loaders=[\"%4\"]")
|
||||
.arg(BuildConfig.MODRINTH_PROD_URL)
|
||||
.arg(args.dependency.addonId.toString())
|
||||
.arg(args.mcVersion.toString())
|
||||
.arg(getModLoaderStrings(args.loader).join("\",\""));
|
||||
};
|
||||
};
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include "Json.h"
|
||||
#include "minecraft/MinecraftInstance.h"
|
||||
#include "minecraft/PackProfile.h"
|
||||
#include "net/NetJob.h"
|
||||
#include "modplatform/ModIndex.h"
|
||||
|
||||
static ModrinthAPI api;
|
||||
static ModPlatform::ProviderCapabilities ProviderCaps;
|
||||
@ -140,6 +140,28 @@ auto Modrinth::loadIndexedPackVersion(QJsonObject& obj, QString preferred_hash_t
|
||||
file.version_number = Json::requireString(obj, "version_number");
|
||||
file.changelog = Json::requireString(obj, "changelog");
|
||||
|
||||
auto dependencies = Json::ensureArray(obj, "dependencies");
|
||||
for (auto d : dependencies) {
|
||||
auto dep = Json::ensureObject(d);
|
||||
ModPlatform::Dependency dependency;
|
||||
dependency.addonId = Json::ensureString(dep, "project_id");
|
||||
dependency.version = Json::ensureString(dep, "version_id");
|
||||
auto depType = Json::requireString(dep, "dependency_type");
|
||||
|
||||
if (depType == "required")
|
||||
dependency.type = ModPlatform::DependencyType::REQUIRED;
|
||||
else if (depType == "optional")
|
||||
dependency.type = ModPlatform::DependencyType::OPTIONAL;
|
||||
else if (depType == "incompatible")
|
||||
dependency.type = ModPlatform::DependencyType::INCOMPATIBLE;
|
||||
else if (depType == "embedded")
|
||||
dependency.type = ModPlatform::DependencyType::EMBEDDED;
|
||||
else
|
||||
dependency.type = ModPlatform::DependencyType::UNKNOWN;
|
||||
|
||||
file.dependencies.append(dependency);
|
||||
}
|
||||
|
||||
auto files = Json::requireArray(obj, "files");
|
||||
int i = 0;
|
||||
|
||||
@ -195,3 +217,22 @@ auto Modrinth::loadIndexedPackVersion(QJsonObject& obj, QString preferred_hash_t
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
auto Modrinth::loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion
|
||||
{
|
||||
QVector<ModPlatform::IndexedVersion> versions;
|
||||
|
||||
for (auto versionIter : arr) {
|
||||
auto obj = versionIter.toObject();
|
||||
auto file = loadIndexedPackVersion(obj);
|
||||
|
||||
if (file.fileId.isValid()) // Heuristic to check if the returned value is valid
|
||||
versions.append(file);
|
||||
}
|
||||
auto orderSortPredicate = [](const ModPlatform::IndexedVersion& a, const ModPlatform::IndexedVersion& b) -> bool {
|
||||
// dates are in RFC 3339 format
|
||||
return a.date > b.date;
|
||||
};
|
||||
std::sort(versions.begin(), versions.end(), orderSortPredicate);
|
||||
return versions.length() != 0 ? versions.front() : ModPlatform::IndexedVersion();
|
||||
}
|
@ -19,8 +19,8 @@
|
||||
|
||||
#include "modplatform/ModIndex.h"
|
||||
|
||||
#include "BaseInstance.h"
|
||||
#include <QNetworkAccessManager>
|
||||
#include "BaseInstance.h"
|
||||
|
||||
namespace Modrinth {
|
||||
|
||||
@ -31,5 +31,6 @@ void loadIndexedPackVersions(ModPlatform::IndexedPack& pack,
|
||||
const shared_qobject_ptr<QNetworkAccessManager>& network,
|
||||
const BaseInstance* inst);
|
||||
auto loadIndexedPackVersion(QJsonObject& obj, QString hash_type = "sha512", QString filename_prefer = "") -> ModPlatform::IndexedVersion;
|
||||
auto loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion;
|
||||
|
||||
} // namespace Modrinth
|
||||
|
@ -18,6 +18,8 @@
|
||||
*/
|
||||
|
||||
#include "ResourceDownloadDialog.h"
|
||||
#include <QEventLoop>
|
||||
#include <QList>
|
||||
|
||||
#include <QPushButton>
|
||||
#include <algorithm>
|
||||
@ -30,6 +32,10 @@
|
||||
#include "minecraft/mod/ShaderPackFolderModel.h"
|
||||
#include "minecraft/mod/TexturePackFolderModel.h"
|
||||
|
||||
#include "minecraft/mod/tasks/GetModDependenciesTask.h"
|
||||
#include "modplatform/ModIndex.h"
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
#include "ui/dialogs/ProgressDialog.h"
|
||||
#include "ui/dialogs/ReviewMessageBox.h"
|
||||
|
||||
#include "ui/pages/modplatform/ResourcePage.h"
|
||||
@ -117,18 +123,71 @@ void ResourceDownloadDialog::connectButtons()
|
||||
connect(HelpButton, &QPushButton::clicked, m_container, &PageContainer::help);
|
||||
}
|
||||
|
||||
static ModPlatform::ProviderCapabilities ProviderCaps;
|
||||
|
||||
QStringList getRequiredBy(QList<ResourceDownloadDialog::DownloadTaskPtr> tasks, ResourceDownloadDialog::DownloadTaskPtr pack)
|
||||
{
|
||||
auto addonId = pack->getPack()->addonId;
|
||||
auto provider = pack->getPack()->provider;
|
||||
auto version = pack->getVersionID();
|
||||
auto req = QStringList();
|
||||
for (auto& task : tasks) {
|
||||
if (provider != task->getPack()->provider)
|
||||
continue;
|
||||
auto deps = task->getVersion().dependencies;
|
||||
if (auto dep = std::find_if(deps.begin(), deps.end(),
|
||||
[addonId, provider, version](const ModPlatform::Dependency& d) {
|
||||
return d.type == ModPlatform::DependencyType::REQUIRED &&
|
||||
(provider == ModPlatform::ResourceProvider::MODRINTH && d.addonId.toString().isEmpty()
|
||||
? version == d.version
|
||||
: d.addonId == addonId);
|
||||
});
|
||||
dep != deps.end()) {
|
||||
req.append(task->getName());
|
||||
}
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
void ResourceDownloadDialog::confirm()
|
||||
{
|
||||
auto confirm_dialog = ReviewMessageBox::create(this, tr("Confirm %1 to download").arg(resourcesString()));
|
||||
confirm_dialog->retranslateUi(resourcesString());
|
||||
|
||||
if (auto task = getModDependenciesTask(); task) {
|
||||
connect(task.get(), &Task::failed, this,
|
||||
[&](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); });
|
||||
|
||||
connect(task.get(), &Task::succeeded, this, [&]() {
|
||||
QStringList warnings = task->warnings();
|
||||
if (warnings.count()) {
|
||||
CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->exec();
|
||||
}
|
||||
});
|
||||
|
||||
// Check for updates
|
||||
ProgressDialog progress_dialog(this);
|
||||
progress_dialog.setSkipButton(true, tr("Abort"));
|
||||
progress_dialog.setWindowTitle(tr("Checking for dependencies..."));
|
||||
auto ret = progress_dialog.execWithTask(task.get());
|
||||
|
||||
// If the dialog was skipped / some download error happened
|
||||
if (ret == QDialog::DialogCode::Rejected) {
|
||||
QMetaObject::invokeMethod(this, "reject", Qt::QueuedConnection);
|
||||
return;
|
||||
} else {
|
||||
for (auto dep : task->getDependecies())
|
||||
addResource(dep->pack, dep->version);
|
||||
}
|
||||
}
|
||||
|
||||
auto selected = getTasks();
|
||||
std::sort(selected.begin(), selected.end(), [](const DownloadTaskPtr& a, const DownloadTaskPtr& b) {
|
||||
return QString::compare(a->getName(), b->getName(), Qt::CaseInsensitive) < 0;
|
||||
});
|
||||
|
||||
auto confirm_dialog = ReviewMessageBox::create(this, tr("Confirm %1 to download").arg(resourcesString()));
|
||||
confirm_dialog->retranslateUi(resourcesString());
|
||||
|
||||
for (auto& task : selected) {
|
||||
confirm_dialog->appendResource({ task->getName(), task->getFilename(), task->getCustomPath() });
|
||||
confirm_dialog->appendResource({ task->getName(), task->getFilename(), task->getCustomPath(),
|
||||
ProviderCaps.name(task->getProvider()), getRequiredBy(selected, task) });
|
||||
}
|
||||
|
||||
if (confirm_dialog->exec()) {
|
||||
@ -231,6 +290,19 @@ QList<BasePage*> ModDownloadDialog::getPages()
|
||||
return pages;
|
||||
}
|
||||
|
||||
GetModDependenciesTask::Ptr ModDownloadDialog::getModDependenciesTask()
|
||||
{
|
||||
if (auto model = dynamic_cast<ModFolderModel*>(getBaseModel().get()); model) {
|
||||
QList<std::shared_ptr<GetModDependenciesTask::PackDependency>> selectedVers;
|
||||
for (auto& selected : getTasks()) {
|
||||
selectedVers.append(std::make_shared<GetModDependenciesTask::PackDependency>(selected->getPack(), selected->getVersion()));
|
||||
}
|
||||
|
||||
return makeShared<GetModDependenciesTask>(this, m_instance, model, selectedVers);
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
ResourcePackDownloadDialog::ResourcePackDownloadDialog(QWidget* parent,
|
||||
const std::shared_ptr<ResourcePackFolderModel>& resource_packs,
|
||||
BaseInstance* instance)
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <QLayout>
|
||||
|
||||
#include "QObjectPtr.h"
|
||||
#include "minecraft/mod/tasks/GetModDependenciesTask.h"
|
||||
#include "modplatform/ModIndex.h"
|
||||
#include "ui/pages/BasePageProvider.h"
|
||||
|
||||
@ -81,6 +82,8 @@ class ResourceDownloadDialog : public QDialog, public BasePageProvider {
|
||||
[[nodiscard]] virtual QString geometrySaveKey() const { return ""; }
|
||||
void setButtonStatus();
|
||||
|
||||
[[nodiscard]] virtual GetModDependenciesTask::Ptr getModDependenciesTask() { return nullptr; }
|
||||
|
||||
protected:
|
||||
const std::shared_ptr<ResourceFolderModel> m_base_model;
|
||||
|
||||
@ -103,6 +106,7 @@ class ModDownloadDialog final : public ResourceDownloadDialog {
|
||||
[[nodiscard]] QString geometrySaveKey() const override { return "ModDownloadGeometry"; }
|
||||
|
||||
QList<BasePage*> getPages() override;
|
||||
GetModDependenciesTask::Ptr getModDependenciesTask() override;
|
||||
|
||||
private:
|
||||
BaseInstance* m_instance;
|
||||
|
@ -40,7 +40,8 @@ void ReviewMessageBox::appendResource(ResourceInformation&& info)
|
||||
auto filenameItem = new QTreeWidgetItem(itemTop);
|
||||
filenameItem->setText(0, tr("Filename: %1").arg(info.filename));
|
||||
|
||||
itemTop->insertChildren(0, { filenameItem });
|
||||
auto childIndx = 0;
|
||||
itemTop->insertChildren(childIndx++, { filenameItem });
|
||||
|
||||
if (!info.custom_file_path.isEmpty()) {
|
||||
auto customPathItem = new QTreeWidgetItem(itemTop);
|
||||
@ -49,7 +50,31 @@ void ReviewMessageBox::appendResource(ResourceInformation&& info)
|
||||
itemTop->insertChildren(1, { customPathItem });
|
||||
|
||||
itemTop->setIcon(1, QIcon(APPLICATION->getThemedIcon("status-yellow")));
|
||||
itemTop->setToolTip(1, tr("This file will be downloaded to a folder location different from the default, possibly due to its loader requiring it."));
|
||||
itemTop->setToolTip(
|
||||
childIndx++,
|
||||
tr("This file will be downloaded to a folder location different from the default, possibly due to its loader requiring it."));
|
||||
}
|
||||
|
||||
auto providerItem = new QTreeWidgetItem(itemTop);
|
||||
providerItem->setText(0, tr("Provider: %1").arg(info.provider));
|
||||
|
||||
itemTop->insertChildren(childIndx++, { providerItem });
|
||||
|
||||
if (!info.required_by.isEmpty()) {
|
||||
auto requiredByItem = new QTreeWidgetItem(itemTop);
|
||||
if (info.required_by.length() == 1) {
|
||||
requiredByItem->setText(0, tr("Required by: %1").arg(info.required_by.back()));
|
||||
} else {
|
||||
requiredByItem->setText(0, tr("Required by:"));
|
||||
auto i = 0;
|
||||
for (auto req : info.required_by) {
|
||||
auto reqItem = new QTreeWidgetItem(requiredByItem);
|
||||
reqItem->setText(0, req);
|
||||
reqItem->insertChildren(i++, { reqItem });
|
||||
}
|
||||
}
|
||||
|
||||
itemTop->insertChildren(childIndx++, { requiredByItem });
|
||||
}
|
||||
|
||||
ui->modTreeWidget->addTopLevelItem(itemTop);
|
||||
|
@ -15,7 +15,9 @@ class ReviewMessageBox : public QDialog {
|
||||
using ResourceInformation = struct res_info {
|
||||
QString name;
|
||||
QString filename;
|
||||
QString custom_file_path {};
|
||||
QString custom_file_path{};
|
||||
QString provider;
|
||||
QStringList required_by;
|
||||
};
|
||||
|
||||
void appendResource(ResourceInformation&& info);
|
||||
|
@ -32,6 +32,7 @@ class ModModel : public ResourceModel {
|
||||
void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) override = 0;
|
||||
void loadExtraPackInfo(ModPlatform::IndexedPack& m, QJsonObject& obj) override = 0;
|
||||
void loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr) override = 0;
|
||||
virtual ModPlatform::IndexedVersion loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) = 0;
|
||||
|
||||
void setFilter(std::shared_ptr<ModFilterWidget::Filter> filter) { m_filter = filter; }
|
||||
|
||||
|
@ -29,6 +29,11 @@ void FlameModModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonAr
|
||||
FlameMod::loadIndexedPackVersions(m, arr, APPLICATION->network(), &m_base_instance);
|
||||
}
|
||||
|
||||
auto FlameModModel::loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion
|
||||
{
|
||||
return FlameMod::loadDependencyVersions(m, arr);
|
||||
};
|
||||
|
||||
auto FlameModModel::documentToArray(QJsonDocument& obj) const -> QJsonArray
|
||||
{
|
||||
return Json::ensureArray(obj.object(), "data");
|
||||
@ -81,7 +86,7 @@ void FlameTexturePackModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m,
|
||||
auto const& mc_versions = version.mcVersion;
|
||||
|
||||
if (std::any_of(mc_versions.constBegin(), mc_versions.constEnd(),
|
||||
[this](auto const& mc_version){ return Version(mc_version) <= maximumTexturePackVersion(); }))
|
||||
[this](auto const& mc_version) { return Version(mc_version) <= maximumTexturePackVersion(); }))
|
||||
filtered_versions.push_back(version);
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ class FlameModModel : public ModModel {
|
||||
void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) override;
|
||||
void loadExtraPackInfo(ModPlatform::IndexedPack& m, QJsonObject& obj) override;
|
||||
void loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr) override;
|
||||
auto loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion override;
|
||||
|
||||
auto documentToArray(QJsonDocument& obj) const -> QJsonArray override;
|
||||
};
|
||||
|
@ -42,12 +42,17 @@ void ModrinthModModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJso
|
||||
::Modrinth::loadIndexedPackVersions(m, arr, APPLICATION->network(), &m_base_instance);
|
||||
}
|
||||
|
||||
auto ModrinthModModel::loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion
|
||||
{
|
||||
return ::Modrinth::loadDependencyVersions(m, arr);
|
||||
};
|
||||
|
||||
auto ModrinthModModel::documentToArray(QJsonDocument& obj) const -> QJsonArray
|
||||
{
|
||||
return obj.object().value("hits").toArray();
|
||||
}
|
||||
|
||||
ModrinthResourcePackModel::ModrinthResourcePackModel(const BaseInstance& base) : ResourcePackResourceModel(base, new ModrinthAPI){}
|
||||
ModrinthResourcePackModel::ModrinthResourcePackModel(const BaseInstance& base) : ResourcePackResourceModel(base, new ModrinthAPI) {}
|
||||
|
||||
void ModrinthResourcePackModel::loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj)
|
||||
{
|
||||
@ -69,7 +74,7 @@ auto ModrinthResourcePackModel::documentToArray(QJsonDocument& obj) const -> QJs
|
||||
return obj.object().value("hits").toArray();
|
||||
}
|
||||
|
||||
ModrinthTexturePackModel::ModrinthTexturePackModel(const BaseInstance& base) : TexturePackResourceModel(base, new ModrinthAPI){}
|
||||
ModrinthTexturePackModel::ModrinthTexturePackModel(const BaseInstance& base) : TexturePackResourceModel(base, new ModrinthAPI) {}
|
||||
|
||||
void ModrinthTexturePackModel::loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj)
|
||||
{
|
||||
@ -91,7 +96,7 @@ auto ModrinthTexturePackModel::documentToArray(QJsonDocument& obj) const -> QJso
|
||||
return obj.object().value("hits").toArray();
|
||||
}
|
||||
|
||||
ModrinthShaderPackModel::ModrinthShaderPackModel(const BaseInstance& base) : ShaderPackResourceModel(base, new ModrinthAPI){}
|
||||
ModrinthShaderPackModel::ModrinthShaderPackModel(const BaseInstance& base) : ShaderPackResourceModel(base, new ModrinthAPI) {}
|
||||
|
||||
void ModrinthShaderPackModel::loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj)
|
||||
{
|
||||
|
@ -40,6 +40,7 @@ class ModrinthModModel : public ModModel {
|
||||
void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) override;
|
||||
void loadExtraPackInfo(ModPlatform::IndexedPack& m, QJsonObject& obj) override;
|
||||
void loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr) override;
|
||||
auto loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion override;
|
||||
|
||||
auto documentToArray(QJsonDocument& obj) const -> QJsonArray override;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user