suppoer non mods deps

fixes #3962

Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
This commit is contained in:
Trial97 2026-04-03 15:20:25 +03:00
parent 245ff2b555
commit 2e45d135c5
No known key found for this signature in database
GPG key ID: 55EF5DA53DB36318
17 changed files with 282 additions and 205 deletions

View file

@ -21,53 +21,108 @@
#include <QDebug>
#include <algorithm>
#include <memory>
#include <utility>
#include "Json.h"
#include "QObjectPtr.h"
#include "minecraft/PackProfile.h"
#include "minecraft/mod/MetadataHandler.h"
#include "minecraft/mod/ModFolderModel.h"
#include "minecraft/mod/ResourceFolderModel.h"
#include "modplatform/ModIndex.h"
#include "modplatform/ResourceAPI.h"
#include "tasks/SequentialTask.h"
#include "ui/pages/modplatform/ModModel.h"
static Version mcVersion(BaseInstance* inst)
namespace {
Version mcVersion(BaseInstance* inst)
{
return static_cast<MinecraftInstance*>(inst)->getPackProfile()->getComponent("net.minecraft")->getVersion();
}
static ModPlatform::ModLoaderTypes mcLoaders(BaseInstance* inst)
ModPlatform::ModLoaderTypes mcLoaders(BaseInstance* inst)
{
return static_cast<MinecraftInstance*>(inst)->getPackProfile()->getSupportedModLoaders().value();
}
static bool checkDependencies(std::shared_ptr<GetModDependenciesTask::PackDependency> sel,
Version mcVersion,
ModPlatform::ModLoaderTypes loaders)
bool checkDependencies(const std::shared_ptr<GetModDependenciesTask::PackDependency>& sel,
const Version& mcVersion,
ModPlatform::ModLoaderTypes loaders)
{
return (sel->pack->versions.isEmpty() || sel->version.mcVersion.contains(mcVersion.toString())) &&
(!loaders || !sel->version.loaders || sel->version.loaders & loaders);
(!loaders || !sel->version.loaders || (sel->version.loaders & loaders) != 0U);
}
// super lax compare (but not fuzzy)
// convert to lowercase
// convert all speratores to whitespace
// simplify sequence of internal whitespace to a single space
// efectivly compare two strings ignoring all separators and case
bool laxCompare(const QString& fsfilename, const QString& metadataFilename, bool excludeDigits = false)
{
// allowed character seperators
QList<QChar> allowedSeperators = { '-', '+', '.', '_' };
if (excludeDigits) {
allowedSeperators.append({ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' });
}
// copy in lowercase
auto fsName = fsfilename.toLower();
auto metaName = metadataFilename.toLower();
// replace all potential allowed seperatores with whitespace
for (auto sep : allowedSeperators) {
fsName = fsName.replace(sep, ' ');
metaName = metaName.replace(sep, ' ');
}
// remove extraneous whitespace
fsName = fsName.simplified();
metaName = metaName.simplified();
return fsName.compare(metaName) == 0;
};
} // namespace
GetModDependenciesTask::GetModDependenciesTask(BaseInstance* instance,
ModFolderModel* folder,
QList<std::shared_ptr<PackDependency>> selected)
: SequentialTask(tr("Get dependencies")), m_selected(selected), m_version(mcVersion(instance)), m_loaderType(mcLoaders(instance))
: SequentialTask(tr("Get dependencies"))
, m_selected(std::move(selected))
, m_version(mcVersion(instance))
, m_loaderType(mcLoaders(instance))
{
for (auto mod : folder->allMods()) {
m_mods_file_names << mod->fileinfo().fileName();
if (auto meta = mod->metadata(); meta)
for (auto* mod : folder->allMods()) {
m_modsFileNames << mod->fileinfo().fileName();
if (auto meta = mod->metadata(); meta) {
m_mods.append(meta);
}
}
auto* mInstance = dynamic_cast<MinecraftInstance*>(instance);
if (mInstance) {
for (auto* model : mInstance->resourceLists()) {
if (model) {
for (auto* mod : model->allResources()) { // only append meta
if (auto meta = mod->metadata(); meta) {
m_mods.append(meta);
}
}
}
}
}
prepare();
}
void GetModDependenciesTask::prepare()
{
for (auto sel : m_selected) {
if (checkDependencies(sel, m_version, m_loaderType))
for (auto dep : getDependenciesForVersion(sel->version, sel->pack->provider)) {
for (const auto& sel : m_selected) {
if (checkDependencies(sel, m_version, m_loaderType)) {
for (const auto& dep : getDependenciesForVersion(sel->version, sel->pack->provider)) {
addTask(prepareDependencyTask(dep, sel->pack->provider, 20));
}
}
}
}
@ -76,7 +131,7 @@ ModPlatform::Dependency GetModDependenciesTask::getOverride(const ModPlatform::D
{
if (auto isQuilt = (m_loaderType & ModPlatform::Quilt) != 0U; isQuilt || (m_loaderType & ModPlatform::Fabric) != 0U) {
auto overide = ModPlatform::getOverrideDeps();
auto over = std::find_if(overide.cbegin(), overide.cend(), [dep, providerName, isQuilt](const auto& o) {
auto over = std::ranges::find_if(overide, [dep, providerName, isQuilt](const auto& o) {
return o.provider == providerName && dep.addonId == (isQuilt ? o.fabric : o.quilt);
});
if (over != overide.cend()) {
@ -89,51 +144,53 @@ ModPlatform::Dependency GetModDependenciesTask::getOverride(const ModPlatform::D
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) {
QList<ModPlatform::Dependency> cDependencies;
for (auto verDep : version.dependencies) {
if (verDep.type != ModPlatform::DependencyType::REQUIRED) {
continue;
}
ver_dep = getOverride(ver_dep, providerName);
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()) {
verDep = getOverride(verDep, providerName);
auto isOnlyVersion = providerName == ModPlatform::ResourceProvider::MODRINTH && verDep.addonId.toString().isEmpty();
if (auto dep = std::ranges::find_if(cDependencies,
[&verDep, isOnlyVersion](const ModPlatform::Dependency& i) {
return isOnlyVersion ? i.version == verDep.version : i.addonId == verDep.addonId;
});
dep != cDependencies.end()) {
continue; // check the current dependency list
}
if (auto dep = std::find_if(m_selected.begin(), m_selected.end(),
[&ver_dep, providerName, isOnlyVersion](const std::shared_ptr<PackDependency>& i) {
return i->pack->provider == providerName && (isOnlyVersion ? i->version.version == ver_dep.version
: i->pack->addonId == ver_dep.addonId);
});
if (auto dep =
std::ranges::find_if(m_selected,
[&verDep, providerName, isOnlyVersion](const std::shared_ptr<PackDependency>& i) {
return i->pack->provider == providerName &&
(isOnlyVersion ? i->version.version == verDep.version : i->pack->addonId == verDep.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](const std::shared_ptr<Metadata::ModStruct>& i) {
return i->provider == providerName &&
(isOnlyVersion ? i->file_id == ver_dep.version : i->project_id == ver_dep.addonId);
});
if (auto dep = std::ranges::find_if(m_mods,
[&verDep, providerName, isOnlyVersion](const std::shared_ptr<Metadata::ModStruct>& i) {
return i->provider == providerName &&
(isOnlyVersion ? i->file_id == verDep.version : i->project_id == verDep.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](const 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
if (auto dep =
std::ranges::find_if(m_packDependencies,
[&verDep, providerName, isOnlyVersion](const std::shared_ptr<PackDependency>& i) {
return i->pack->provider == providerName &&
(isOnlyVersion ? i->version.version == verDep.addonId : i->pack->addonId == verDep.addonId);
});
dep != m_packDependencies.end()) { // check loaded dependencies
continue;
}
c_dependencies.append(ver_dep);
cDependencies.append(verDep);
}
return c_dependencies;
return cDependencies;
}
Task::Ptr GetModDependenciesTask::getProjectInfoTask(std::shared_ptr<PackDependency> pDep)
@ -141,12 +198,11 @@ Task::Ptr GetModDependenciesTask::getProjectInfoTask(std::shared_ptr<PackDepende
auto provider = pDep->pack->provider;
auto [info, responseInfo] = getAPI(provider)->getProject(pDep->pack->addonId.toString());
connect(info.get(), &NetJob::succeeded, [this, responseInfo, provider, pDep] {
QJsonParseError parse_error{};
QJsonDocument doc = QJsonDocument::fromJson(*responseInfo, &parse_error);
if (parse_error.error != QJsonParseError::NoError) {
QJsonParseError parseError{};
QJsonDocument doc = QJsonDocument::fromJson(*responseInfo, &parseError);
if (parseError.error != QJsonParseError::NoError) {
removePack(pDep->pack->addonId);
qWarning() << "Error while parsing JSON response for mod info at" << parse_error.offset
<< "reason:" << parse_error.errorString();
qWarning() << "Error while parsing JSON response for mod info at" << parseError.offset << "reason:" << parseError.errorString();
qDebug() << *responseInfo;
return;
}
@ -178,7 +234,7 @@ Task::Ptr GetModDependenciesTask::prepareDependencyTask(const ModPlatform::Depen
pDep->pack->addonId = dep.addonId;
pDep->pack->provider = providerName;
m_pack_dependencies.append(pDep);
m_packDependencies.append(pDep);
auto provider = providerName;
@ -223,10 +279,10 @@ Task::Ptr GetModDependenciesTask::prepareDependencyTask(const ModPlatform::Depen
}
if (dep.addonId.toString().isEmpty() && !pDep->version.addonId.toString().isEmpty()) {
pDep->pack->addonId = pDep->version.addonId;
auto dep_ = getOverride({ .addonId = pDep->version.addonId, .type = pDep->dependency.type, .version = "" }, provider);
if (dep_.addonId != pDep->version.addonId) {
auto overrideDep = getOverride({ .addonId = pDep->version.addonId, .type = pDep->dependency.type, .version = "" }, provider);
if (overrideDep.addonId != pDep->version.addonId) {
removePack(pDep->version.addonId);
addTask(prepareDependencyTask(dep_, provider, level));
addTask(prepareDependencyTask(overrideDep, provider, level));
} else {
addTask(getProjectInfoTask(pDep));
}
@ -235,8 +291,8 @@ Task::Ptr GetModDependenciesTask::prepareDependencyTask(const ModPlatform::Depen
removePack(pDep->version.addonId);
return;
}
for (const auto& dep_ : getDependenciesForVersion(pDep->version, provider)) {
addTask(prepareDependencyTask(dep_, provider, level - 1));
for (const auto& dependency : getDependenciesForVersion(pDep->version, provider)) {
addTask(prepareDependencyTask(dependency, provider, level - 1));
}
};
@ -253,7 +309,7 @@ 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);
m_packDependencies.removeIf(pred);
#else
for (auto it = m_pack_dependencies.begin(); it != m_pack_dependencies.end();)
if (pred(*it))
@ -266,82 +322,55 @@ void GetModDependenciesTask::removePack(const QVariant& addonId)
auto GetModDependenciesTask::getExtraInfo() -> QHash<QString, PackDependencyExtraInfo>
{
QHash<QString, PackDependencyExtraInfo> rby;
auto fullList = m_selected + m_pack_dependencies;
auto fullList = m_selected + m_packDependencies;
for (auto& mod : fullList) {
auto addonId = mod->pack->addonId;
auto provider = mod->pack->provider;
auto version = mod->version.fileId;
auto req = QStringList();
for (auto& smod : fullList) {
if (provider != smod->pack->provider)
if (provider != smod->pack->provider) {
continue;
}
auto deps = smod->version.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);
});
if (auto dep =
std::ranges::find_if(deps,
[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(smod->pack->name);
}
}
rby[addonId.toString()] = { maybeInstalled(mod), req };
rby[addonId.toString()] = { .maybeInstalled = maybeInstalled(mod), .requiredBy = req };
}
return rby;
}
// super lax compare (but not fuzzy)
// convert to lowercase
// convert all speratores to whitespace
// simplify sequence of internal whitespace to a single space
// efectivly compare two strings ignoring all separators and case
auto laxCompare = [](QString fsfilename, QString metadataFilename, bool excludeDigits = false) {
// allowed character seperators
QList<QChar> allowedSeperators = { '-', '+', '.', '_' };
if (excludeDigits)
allowedSeperators.append({ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' });
// copy in lowercase
auto fsName = fsfilename.toLower();
auto metaName = metadataFilename.toLower();
// replace all potential allowed seperatores with whitespace
for (auto sep : allowedSeperators) {
fsName = fsName.replace(sep, ' ');
metaName = metaName.replace(sep, ' ');
}
// remove extraneous whitespace
fsName = fsName.simplified();
metaName = metaName.simplified();
return fsName.compare(metaName) == 0;
};
bool GetModDependenciesTask::isLocalyInstalled(std::shared_ptr<PackDependency> pDep)
{
return pDep->version.fileName.isEmpty() ||
std::ranges::find_if(m_selected,
[pDep](const std::shared_ptr<PackDependency>& i) {
return !i->version.fileName.isEmpty() && laxCompare(i->version.fileName, pDep->version.fileName);
}) != m_selected.end() || // check the selected versions
std::find_if(m_selected.begin(), m_selected.end(),
[pDep](std::shared_ptr<PackDependency> i) {
return !i->version.fileName.isEmpty() && laxCompare(i->version.fileName, pDep->version.fileName);
}) != m_selected.end() || // check the selected versions
std::ranges::find_if(m_modsFileNames,
[pDep](const QString& i) { return !i.isEmpty() && laxCompare(i, pDep->version.fileName); }) !=
m_modsFileNames.end() || // check the existing mods
std::find_if(m_mods_file_names.begin(), m_mods_file_names.end(),
[pDep](QString i) { return !i.isEmpty() && laxCompare(i, pDep->version.fileName); }) !=
m_mods_file_names.end() || // check the existing mods
std::find_if(m_pack_dependencies.begin(), m_pack_dependencies.end(), [pDep](std::shared_ptr<PackDependency> i) {
std::ranges::find_if(m_packDependencies, [pDep](std::shared_ptr<PackDependency> i) {
return pDep->pack->addonId != i->pack->addonId && !i->version.fileName.isEmpty() &&
laxCompare(pDep->version.fileName, i->version.fileName);
}) != m_pack_dependencies.end(); // check loaded dependencies
}) != m_packDependencies.end(); // check loaded dependencies
}
bool GetModDependenciesTask::maybeInstalled(std::shared_ptr<PackDependency> pDep)
{
return std::find_if(m_mods_file_names.begin(), m_mods_file_names.end(), [pDep](QString i) {
return std::ranges::find_if(m_modsFileNames, [pDep](const QString& i) {
return !i.isEmpty() && laxCompare(i, pDep->version.fileName, true);
}) != m_mods_file_names.end(); // check the existing mods
}) != m_modsFileNames.end(); // check the existing mods
}

View file

@ -21,7 +21,6 @@
#include <QDir>
#include <QList>
#include <QVariant>
#include <functional>
#include <memory>
#include <utility>
@ -49,13 +48,13 @@ class GetModDependenciesTask : public SequentialTask {
};
struct PackDependencyExtraInfo {
bool maybe_installed{};
QStringList required_by;
bool maybeInstalled{};
QStringList requiredBy;
};
explicit GetModDependenciesTask(BaseInstance* instance, ModFolderModel* folder, QList<std::shared_ptr<PackDependency>> selected);
auto getDependecies() const -> QList<std::shared_ptr<PackDependency>> { return m_pack_dependencies; }
auto getDependecies() const -> QList<std::shared_ptr<PackDependency>> { return m_packDependencies; }
QHash<QString, PackDependencyExtraInfo> getExtraInfo();
private:
@ -80,10 +79,10 @@ class GetModDependenciesTask : public SequentialTask {
bool maybeInstalled(std::shared_ptr<PackDependency> pDep);
private:
QList<std::shared_ptr<PackDependency>> m_pack_dependencies;
QList<std::shared_ptr<PackDependency>> m_packDependencies;
QList<std::shared_ptr<Metadata::ModStruct>> m_mods;
QList<std::shared_ptr<PackDependency>> m_selected;
QStringList m_mods_file_names;
QStringList m_modsFileNames;
Version m_version;
ModPlatform::ModLoaderTypes m_loaderType;

View file

@ -26,6 +26,7 @@
#include <compare>
#include <cstdint>
#include <memory>
#include "modplatform/ResourceType.h"
class QIODevice;
@ -181,6 +182,8 @@ struct IndexedPack {
bool extraDataLoaded = true;
ExtraPackData extraData;
ResourceType resourceType = ResourceType::Unknown;
// For internal use, not provided by APIs
bool isVersionSelected(int index) const
{

View file

@ -29,7 +29,7 @@
namespace ModPlatform {
enum class ResourceType { Mod, ResourcePack, ShaderPack, Modpack, DataPack, World, Screenshots, TexturePack, Unknown };
enum class ResourceType : std::uint8_t { Mod, ResourcePack, ShaderPack, Modpack, DataPack, World, Screenshots, TexturePack, Unknown };
namespace ResourceTypeUtils {
static const std::set<ResourceType> VALID_RESOURCES = { ResourceType::DataPack, ResourceType::ResourcePack, ResourceType::TexturePack,

View file

@ -86,30 +86,6 @@ void Flame::FileResolvingTask::executeTask()
m_task->start();
}
ModPlatform::ResourceType getResourceType(int classId)
{
switch (classId) {
case 17: // Worlds
return ModPlatform::ResourceType::World;
case 6: // Mods
return ModPlatform::ResourceType::Mod;
case 12: // Resource Packs
// return ModPlatform::ResourceType::ResourcePack; // not really a resourcepack
/* fallthrough */
case 4546: // Customization
// return ModPlatform::ResourceType::ShaderPack; // not really a shaderPack
/* fallthrough */
case 4471: // Modpacks
/* fallthrough */
case 5: // Bukkit Plugins
/* fallthrough */
case 4559: // Addons
/* fallthrough */
default:
return ModPlatform::ResourceType::Unknown;
}
}
void Flame::FileResolvingTask::netJobFinished(QByteArray* response)
{
setProgress(1, 3);
@ -171,8 +147,8 @@ void Flame::FileResolvingTask::netJobFinished(QByteArray* response)
getFlameProjects();
return;
}
if (APPLICATION->settings()->get("FallbackMRBlockedMods").toBool()){
}
if (APPLICATION->settings()->get("FallbackMRBlockedMods").toBool()) {
try {
auto entries = Json::requireObject(doc);
for (auto& out : m_manifest.files) {
@ -253,8 +229,7 @@ void Flame::FileResolvingTask::getFlameProjects()
setStatus(tr("Parsing API response from CurseForge for '%1'...").arg(file->version.fileName));
FlameMod::loadIndexedPack(file->pack, entry_obj);
file->resourceType = getResourceType(Json::requireInteger(entry_obj, "classId", "modClassId"));
if (file->resourceType == ModPlatform::ResourceType::World) {
if (file->pack.resourceType == ModPlatform::ResourceType::World) {
file->targetFolder = "saves";
}
}

View file

@ -162,14 +162,41 @@ std::pair<Task::Ptr, QByteArray*> FlameAPI::getFile(const QString& addonId, cons
QList<ResourceAPI::SortingMethod> FlameAPI::getSortingMethods() const
{
// https://docs.curseforge.com/?python#tocS_ModsSearchSortField
return { { 1, "Featured", QObject::tr("Sort by Featured") },
{ 2, "Popularity", QObject::tr("Sort by Popularity") },
{ 3, "LastUpdated", QObject::tr("Sort by Last Updated") },
{ 4, "Name", QObject::tr("Sort by Name") },
{ 5, "Author", QObject::tr("Sort by Author") },
{ 6, "TotalDownloads", QObject::tr("Sort by Downloads") },
{ 7, "Category", QObject::tr("Sort by Category") },
{ 8, "GameVersion", QObject::tr("Sort by Game Version") } };
return { { .index = 1, .name = "Featured", .readable_name = QObject::tr("Sort by Featured") },
{ .index = 2, .name = "Popularity", .readable_name = QObject::tr("Sort by Popularity") },
{ .index = 3, .name = "LastUpdated", .readable_name = QObject::tr("Sort by Last Updated") },
{ .index = 4, .name = "Name", .readable_name = QObject::tr("Sort by Name") },
{ .index = 5, .name = "Author", .readable_name = QObject::tr("Sort by Author") },
{ .index = 6, .name = "TotalDownloads", .readable_name = QObject::tr("Sort by Downloads") },
{ .index = 7, .name = "Category", .readable_name = QObject::tr("Sort by Category") },
{ .index = 8, .name = "GameVersion", .readable_name = QObject::tr("Sort by Game Version") } };
}
namespace {
const auto g_classIDMappings = std::array{
std::pair{ ModPlatform::ResourceType::Mod, 6 }, std::pair{ ModPlatform::ResourceType::ResourcePack, 12 },
std::pair{ ModPlatform::ResourceType::World, 17 }, std::pair{ ModPlatform::ResourceType::ShaderPack, 6552 },
std::pair{ ModPlatform::ResourceType::Modpack, 4471 }, std::pair{ ModPlatform::ResourceType::DataPack, 6945 },
};
}
int FlameAPI::getClassId(ModPlatform::ResourceType type)
{
for (auto&& [e, classId] : g_classIDMappings) {
if (e == type) {
return classId;
}
}
return 0;
}
ModPlatform::ResourceType FlameAPI::getResourceType(int classId)
{
for (auto&& [type, c] : g_classIDMappings) {
if (c == classId) {
return type;
}
}
return ModPlatform::ResourceType::Unknown;
}
std::pair<Task::Ptr, QByteArray*> FlameAPI::getCategories(ModPlatform::ResourceType type)

View file

@ -39,23 +39,10 @@ class FlameAPI : public ResourceAPI {
return loaders & (ModPlatform::NeoForge | ModPlatform::Forge | ModPlatform::Fabric | ModPlatform::Quilt);
}
static ModPlatform::ResourceType getResourceType(int classId);
private:
static int getClassId(ModPlatform::ResourceType type)
{
switch (type) {
default:
case ModPlatform::ResourceType::Mod:
return 6;
case ModPlatform::ResourceType::ResourcePack:
return 12;
case ModPlatform::ResourceType::ShaderPack:
return 6552;
case ModPlatform::ResourceType::Modpack:
return 4471;
case ModPlatform::ResourceType::DataPack:
return 6945;
}
}
static int getClassId(ModPlatform::ResourceType type);
static int getMappedModLoader(ModPlatform::ModLoaderType loaders)
{

View file

@ -146,7 +146,7 @@ bool FlameCreationTask::updateInstance()
// Remove repeated files, we don't need to download them!
auto files_iterator = files.begin();
while (files_iterator != files.end()) {
auto const& file = files_iterator;
const auto& file = files_iterator;
auto old_file = old_files.find(file.key());
if (old_file != old_files.end()) {
@ -511,7 +511,7 @@ void FlameCreationTask::idResolverSucceeded(QEventLoop& loop)
QList<BlockedMod> blocked_mods;
auto anyBlocked = false;
for (const auto& result : results.values()) {
if (result.resourceType != ModPlatform::ResourceType::Mod) {
if (result.pack.resourceType != ModPlatform::ResourceType::Mod) {
m_otherResources.append(std::make_pair(result.version.fileName, result.targetFolder));
}
@ -602,14 +602,14 @@ void FlameCreationTask::setupDownloadJob(QEventLoop& loop)
/// @brief copy the matched blocked mods to the instance staging area
/// @param blocked_mods list of the blocked mods and their matched paths
void FlameCreationTask::copyBlockedMods(QList<BlockedMod> const& blocked_mods)
void FlameCreationTask::copyBlockedMods(const QList<BlockedMod>& blocked_mods)
{
setStatus(tr("Copying Blocked Mods..."));
setAbortable(false);
int i = 0;
int total = blocked_mods.length();
setProgress(i, total);
for (auto const& mod : blocked_mods) {
for (const auto& mod : blocked_mods) {
if (!mod.matched) {
qDebug() << mod.name << "was not matched to a local file, skipping copy";
continue;

View file

@ -37,6 +37,7 @@ void FlameMod::loadIndexedPack(ModPlatform::IndexedPack& pack, QJsonObject& obj)
}
}
pack.resourceType = FlameAPI::getResourceType(obj["classId"].toInt(0));
pack.extraDataLoaded = false;
loadURLs(pack, obj);
}

View file

@ -41,7 +41,6 @@
#include <QString>
#include <QUrl>
#include "modplatform/ModIndex.h"
#include "modplatform/ResourceType.h"
namespace Flame {
struct File {
@ -55,7 +54,6 @@ struct File {
// our
QString targetFolder = QStringLiteral("mods");
ModPlatform::ResourceType resourceType;
};
struct Modloader {

View file

@ -3,9 +3,11 @@
// SPDX-License-Identifier: GPL-3.0-only
#include "ModrinthAPI.h"
#include <array>
#include "Application.h"
#include "Json.h"
#include "modplatform/ResourceType.h"
#include "net/ApiDownload.h"
#include "net/ApiUpload.h"
#include "net/NetJob.h"
@ -122,6 +124,37 @@ QList<ResourceAPI::SortingMethod> ModrinthAPI::getSortingMethods() const
{ .index = 4, .name = "newest", .readable_name = QObject::tr("Sort by Newest") },
{ .index = 5, .name = "updated", .readable_name = QObject::tr("Sort by Last Updated") } };
}
namespace {
const auto resourceTypeMap = std::array{
std::pair{ ModPlatform::ResourceType::Mod, "mod" }, std::pair{ ModPlatform::ResourceType::ResourcePack, "resourcepack" },
std::pair{ ModPlatform::ResourceType::ShaderPack, "shader" }, std::pair{ ModPlatform::ResourceType::DataPack, "datapack" },
std::pair{ ModPlatform::ResourceType::Modpack, "modpack" },
};
}
ModPlatform::ResourceType ModrinthAPI::getResourceType(const QString& param)
{
for (const auto& [key, value] : resourceTypeMap) {
if (value == param) {
return key;
}
}
qWarning() << "Invalid resource type for Modrinth API!" << param;
return ModPlatform::ResourceType::Unknown;
}
QString ModrinthAPI::resourceTypeParameter(ModPlatform::ResourceType type)
{
for (const auto& [key, value] : resourceTypeMap) {
if (key == type) {
return value;
}
}
qWarning() << "Invalid resource type for Modrinth API!" << static_cast<std::uint8_t>(type);
return "";
}
std::pair<Task::Ptr, QByteArray*> ModrinthAPI::getModCategories()
{

View file

@ -100,28 +100,10 @@ class ModrinthAPI : public ResourceAPI {
}
return v;
}
static ModPlatform::ResourceType getResourceType(const QString& param);
private:
static QString resourceTypeParameter(ModPlatform::ResourceType type)
{
switch (type) {
case ModPlatform::ResourceType::Mod:
return "mod";
case ModPlatform::ResourceType::ResourcePack:
return "resourcepack";
case ModPlatform::ResourceType::ShaderPack:
return "shader";
case ModPlatform::ResourceType::DataPack:
return "datapack";
case ModPlatform::ResourceType::Modpack:
return "modpack";
default:
qWarning() << "Invalid resource type for Modrinth API!";
break;
}
return "";
}
static QString resourceTypeParameter(ModPlatform::ResourceType type);
QString createFacets(const SearchArgs& args) const
{

View file

@ -41,6 +41,7 @@ void Modrinth::loadIndexedPack(ModPlatform::IndexedPack& pack, QJsonObject& obj)
pack.provider = ModPlatform::ResourceProvider::MODRINTH;
pack.name = Json::requireString(obj, "title");
pack.resourceType = ModrinthAPI::getResourceType(obj["project_type"].toString());
pack.slug = obj["slug"].toString("");
if (!pack.slug.isEmpty()) {

View file

@ -25,6 +25,7 @@
#include <utility>
#include "Application.h"
#include "BaseInstance.h"
#include "ResourceDownloadTask.h"
#include "minecraft/PackProfile.h"
@ -50,12 +51,16 @@
namespace ResourceDownload {
ResourceDownloadDialog::ResourceDownloadDialog(QWidget* parent, ResourceFolderModel* baseModel, bool suppressInitialSearch)
ResourceDownloadDialog::ResourceDownloadDialog(QWidget* parent,
ResourceFolderModel* baseModel,
BaseInstance* inst,
bool suppressInitialSearch)
: QDialog(parent)
, m_base_model(baseModel)
, m_buttons(QDialogButtonBox::Help | QDialogButtonBox::Ok | QDialogButtonBox::Cancel)
, m_vertical_layout(this)
, m_suppressInitialSearch(suppressInitialSearch)
, m_instance(inst)
{
setObjectName(QStringLiteral("ResourceDownloadDialog"));
@ -200,9 +205,9 @@ void ResourceDownloadDialog::confirm()
confirmDialog->appendResource({ .name = task->getName(),
.filename = task->getFilename(),
.provider = ModPlatform::ProviderCapabilities::name(task->getProvider()),
.required_by = extraInfo.required_by,
.required_by = extraInfo.requiredBy,
.version_type = task->getVersion().version_type.toString(),
.enabled = !extraInfo.maybe_installed });
.enabled = !extraInfo.maybeInstalled });
}
if (confirmDialog->exec() != 0) {
@ -237,7 +242,32 @@ ResourcePage* ResourceDownloadDialog::selectedPage()
void ResourceDownloadDialog::addResource(ModPlatform::IndexedPack::Ptr pack, ModPlatform::IndexedVersion& ver, QString downloadReason)
{
removeResource(pack->name);
selectedPage()->addResourceToPage(pack, ver, getBaseModel(), std::move(downloadReason));
auto* model = getBaseModel();
auto* instance = dynamic_cast<MinecraftInstance*>(m_instance);
if (instance) {
switch (pack->resourceType) {
case ModPlatform::ResourceType::Mod:
model = instance->loaderModList();
break;
case ModPlatform::ResourceType::ResourcePack:
model = instance->resourcePackList();
break;
case ModPlatform::ResourceType::ShaderPack:
model = instance->shaderPackList();
break;
case ModPlatform::ResourceType::DataPack:
model = instance->dataPackList();
break;
// case ModPlatform::ResourceType::World:
// model = instance->worldList();
case ModPlatform::ResourceType::TexturePack:
model = instance->texturePackList();
break;
default:
break;
}
}
selectedPage()->addResourceToPage(pack, ver, model, std::move(downloadReason));
setButtonStatus();
}
@ -289,13 +319,25 @@ void ResourceDownloadDialog::selectedPageChanged(BasePage* previous, BasePage* s
}
ModDownloadDialog::ModDownloadDialog(QWidget* parent, ModFolderModel* mods, BaseInstance* instance, bool suppressInitialSearch)
: ResourceDownloadDialog(parent, mods, suppressInitialSearch), m_instance(instance)
: ResourceDownloadDialog(parent, mods, instance, suppressInitialSearch), m_instance(instance)
{
setWindowTitle(dialogTitle());
initializeContainer();
connectButtons();
// need to load all resources for dependency task
auto* mInstance = dynamic_cast<MinecraftInstance*>(instance);
if (mInstance) {
for (auto* model : mInstance->resourceLists()) {
if (model) {
if (model->empty()) {
model->startWatching();
}
}
}
}
if (!geometrySaveKey().isEmpty()) {
restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get(geometrySaveKey()).toString().toUtf8()));
}
@ -340,7 +382,7 @@ ResourcePackDownloadDialog::ResourcePackDownloadDialog(QWidget* parent,
ResourcePackFolderModel* resourcePacks,
BaseInstance* instance,
bool suppressInitialSearch)
: ResourceDownloadDialog(parent, resourcePacks, suppressInitialSearch), m_instance(instance)
: ResourceDownloadDialog(parent, resourcePacks, instance, suppressInitialSearch), m_instance(instance)
{
setWindowTitle(dialogTitle());
@ -372,7 +414,7 @@ TexturePackDownloadDialog::TexturePackDownloadDialog(QWidget* parent,
TexturePackFolderModel* resourcePacks,
BaseInstance* instance,
bool suppressInitialSearch)
: ResourceDownloadDialog(parent, resourcePacks, suppressInitialSearch), m_instance(instance)
: ResourceDownloadDialog(parent, resourcePacks, instance, suppressInitialSearch), m_instance(instance)
{
setWindowTitle(dialogTitle());
@ -404,7 +446,7 @@ ShaderPackDownloadDialog::ShaderPackDownloadDialog(QWidget* parent,
ShaderPackFolderModel* shaders,
BaseInstance* instance,
bool suppressInitialSearch)
: ResourceDownloadDialog(parent, shaders, suppressInitialSearch), m_instance(instance)
: ResourceDownloadDialog(parent, shaders, instance, suppressInitialSearch), m_instance(instance)
{
setWindowTitle(dialogTitle());
@ -452,7 +494,7 @@ DataPackDownloadDialog::DataPackDownloadDialog(QWidget* parent,
DataPackFolderModel* dataPacks,
BaseInstance* instance,
bool suppressInitialSearch)
: ResourceDownloadDialog(parent, dataPacks, suppressInitialSearch), m_instance(instance)
: ResourceDownloadDialog(parent, dataPacks, instance, suppressInitialSearch), m_instance(instance)
{
setWindowTitle(dialogTitle());

View file

@ -51,7 +51,7 @@ class ResourceDownloadDialog : public QDialog, public BasePageProvider {
public:
using DownloadTaskPtr = shared_qobject_ptr<ResourceDownloadTask>;
ResourceDownloadDialog(QWidget* parent, ResourceFolderModel* baseModel, bool suppressInitialSearch = false);
ResourceDownloadDialog(QWidget* parent, ResourceFolderModel* baseModel, BaseInstance* instance, bool suppressInitialSearch = false);
void initializeContainer();
void connectButtons();
@ -95,8 +95,8 @@ class ResourceDownloadDialog : public QDialog, public BasePageProvider {
QDialogButtonBox m_buttons;
QVBoxLayout m_vertical_layout;
protected:
bool m_suppressInitialSearch = false;
BaseInstance* m_instance = nullptr;
};
class ModDownloadDialog final : public ResourceDownloadDialog {

View file

@ -183,7 +183,7 @@ void ResourceUpdateDialog::checkCandidates()
ScrollMessageBox messageDialog(m_parent, tr("Failed to check for updates"),
tr("Could not check or get the following resources for updates:<br>"
"Do you wish to proceed without those resources?"),
text, "Disable unavailable mods");
text, tr("Disable unavailable mods"));
messageDialog.setModal(true);
if (messageDialog.exec() == QDialog::Rejected) {
m_aborted = true;
@ -244,10 +244,10 @@ void ResourceUpdateDialog::checkCandidates()
auto extraInfo = dependencyExtraInfo.value(dep->version.addonId.toString());
CheckUpdateTask::Update updatable = {
dep->pack->name, dep->version.hash, tr("Not installed"), dep->version.version, dep->version.version_type,
changelog, dep->pack->provider, downloadTask, !extraInfo.maybe_installed
changelog, dep->pack->provider, downloadTask, !extraInfo.maybeInstalled,
};
appendResource(updatable, extraInfo.required_by);
appendResource(updatable, extraInfo.requiredBy);
m_tasks.insert(updatable.name, updatable.download);
}
}
@ -517,7 +517,7 @@ void ResourceUpdateDialog::appendResource(const CheckUpdateTask::Update& info, Q
ui->modTreeWidget->addTopLevelItem(itemTop);
}
auto ResourceUpdateDialog::getTasks() -> const QList<ResourceDownloadTask::Ptr>
auto ResourceUpdateDialog::getTasks() const -> QList<ResourceDownloadTask::Ptr>
{
QList<ResourceDownloadTask::Ptr> list;

View file

@ -27,7 +27,7 @@ class ResourceUpdateDialog final : public ReviewMessageBox {
void appendResource(const CheckUpdateTask::Update& info, QStringList requiredBy = {});
const QList<ResourceDownloadTask::Ptr> getTasks();
QList<ResourceDownloadTask::Ptr> getTasks() const;
auto indexDir() const -> QDir { return m_resourceModel->indexDir(); }
auto noUpdates() const -> bool { return m_noUpdates; };