diff --git a/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp b/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp index e1608bcad..77b8de972 100644 --- a/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp +++ b/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp @@ -21,53 +21,108 @@ #include #include #include +#include #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(inst)->getPackProfile()->getComponent("net.minecraft")->getVersion(); } -static ModPlatform::ModLoaderTypes mcLoaders(BaseInstance* inst) +ModPlatform::ModLoaderTypes mcLoaders(BaseInstance* inst) { return static_cast(inst)->getPackProfile()->getSupportedModLoaders().value(); } -static bool checkDependencies(std::shared_ptr sel, - Version mcVersion, - ModPlatform::ModLoaderTypes loaders) +bool checkDependencies(const std::shared_ptr& 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 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> 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(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 GetModDependenciesTask::getDependenciesForVersion(const ModPlatform::IndexedVersion& version, const ModPlatform::ResourceProvider providerName) { - QList c_dependencies; - for (auto ver_dep : version.dependencies) { - if (ver_dep.type != ModPlatform::DependencyType::REQUIRED) { + QList 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& 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& 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& 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& 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& 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& 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 pDep) @@ -141,12 +198,11 @@ Task::Ptr GetModDependenciesTask::getProjectInfoTask(std::shared_ptrpack->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& 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 { QHash 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 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 pDep) { return pDep->version.fileName.isEmpty() || + std::ranges::find_if(m_selected, + [pDep](const std::shared_ptr& 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 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 i) { + std::ranges::find_if(m_packDependencies, [pDep](std::shared_ptr 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 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 } diff --git a/launcher/minecraft/mod/tasks/GetModDependenciesTask.h b/launcher/minecraft/mod/tasks/GetModDependenciesTask.h index d6c2985b0..cc605ee22 100644 --- a/launcher/minecraft/mod/tasks/GetModDependenciesTask.h +++ b/launcher/minecraft/mod/tasks/GetModDependenciesTask.h @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -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> selected); - auto getDependecies() const -> QList> { return m_pack_dependencies; } + auto getDependecies() const -> QList> { return m_packDependencies; } QHash getExtraInfo(); private: @@ -80,10 +79,10 @@ class GetModDependenciesTask : public SequentialTask { bool maybeInstalled(std::shared_ptr pDep); private: - QList> m_pack_dependencies; + QList> m_packDependencies; QList> m_mods; QList> m_selected; - QStringList m_mods_file_names; + QStringList m_modsFileNames; Version m_version; ModPlatform::ModLoaderTypes m_loaderType; diff --git a/launcher/modplatform/ModIndex.h b/launcher/modplatform/ModIndex.h index e1278ae84..cfdda419d 100644 --- a/launcher/modplatform/ModIndex.h +++ b/launcher/modplatform/ModIndex.h @@ -26,6 +26,7 @@ #include #include #include +#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 { diff --git a/launcher/modplatform/ResourceType.h b/launcher/modplatform/ResourceType.h index 390ade7ff..49e29e16b 100644 --- a/launcher/modplatform/ResourceType.h +++ b/launcher/modplatform/ResourceType.h @@ -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 VALID_RESOURCES = { ResourceType::DataPack, ResourceType::ResourcePack, ResourceType::TexturePack, diff --git a/launcher/modplatform/flame/FileResolvingTask.cpp b/launcher/modplatform/flame/FileResolvingTask.cpp index 9cd85aef7..7d4b1ee94 100644 --- a/launcher/modplatform/flame/FileResolvingTask.cpp +++ b/launcher/modplatform/flame/FileResolvingTask.cpp @@ -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"; } } diff --git a/launcher/modplatform/flame/FlameAPI.cpp b/launcher/modplatform/flame/FlameAPI.cpp index b9b5c2207..fa0e3616d 100644 --- a/launcher/modplatform/flame/FlameAPI.cpp +++ b/launcher/modplatform/flame/FlameAPI.cpp @@ -162,14 +162,41 @@ std::pair FlameAPI::getFile(const QString& addonId, cons QList 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 FlameAPI::getCategories(ModPlatform::ResourceType type) diff --git a/launcher/modplatform/flame/FlameAPI.h b/launcher/modplatform/flame/FlameAPI.h index 607b32cab..9faf97967 100644 --- a/launcher/modplatform/flame/FlameAPI.h +++ b/launcher/modplatform/flame/FlameAPI.h @@ -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) { diff --git a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp index 534132a6e..f4d11a5ce 100644 --- a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp +++ b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp @@ -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 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 const& blocked_mods) +void FlameCreationTask::copyBlockedMods(const QList& 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; diff --git a/launcher/modplatform/flame/FlameModIndex.cpp b/launcher/modplatform/flame/FlameModIndex.cpp index 3b0f7f6ae..06e2a64f7 100644 --- a/launcher/modplatform/flame/FlameModIndex.cpp +++ b/launcher/modplatform/flame/FlameModIndex.cpp @@ -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); } diff --git a/launcher/modplatform/flame/PackManifest.h b/launcher/modplatform/flame/PackManifest.h index 049a99871..ff9bec7df 100644 --- a/launcher/modplatform/flame/PackManifest.h +++ b/launcher/modplatform/flame/PackManifest.h @@ -41,7 +41,6 @@ #include #include #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 { diff --git a/launcher/modplatform/modrinth/ModrinthAPI.cpp b/launcher/modplatform/modrinth/ModrinthAPI.cpp index d5bea52bc..eb1f55a62 100644 --- a/launcher/modplatform/modrinth/ModrinthAPI.cpp +++ b/launcher/modplatform/modrinth/ModrinthAPI.cpp @@ -3,9 +3,11 @@ // SPDX-License-Identifier: GPL-3.0-only #include "ModrinthAPI.h" +#include #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 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(type); + return ""; +} std::pair ModrinthAPI::getModCategories() { diff --git a/launcher/modplatform/modrinth/ModrinthAPI.h b/launcher/modplatform/modrinth/ModrinthAPI.h index 731ac1b09..91de24793 100644 --- a/launcher/modplatform/modrinth/ModrinthAPI.h +++ b/launcher/modplatform/modrinth/ModrinthAPI.h @@ -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 { diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp index 48d28feee..1884beb1c 100644 --- a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp @@ -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()) { diff --git a/launcher/ui/dialogs/ResourceDownloadDialog.cpp b/launcher/ui/dialogs/ResourceDownloadDialog.cpp index bcb30c761..eb24db604 100644 --- a/launcher/ui/dialogs/ResourceDownloadDialog.cpp +++ b/launcher/ui/dialogs/ResourceDownloadDialog.cpp @@ -25,6 +25,7 @@ #include #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(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(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()); diff --git a/launcher/ui/dialogs/ResourceDownloadDialog.h b/launcher/ui/dialogs/ResourceDownloadDialog.h index bea6c7689..1b04cf8c4 100644 --- a/launcher/ui/dialogs/ResourceDownloadDialog.h +++ b/launcher/ui/dialogs/ResourceDownloadDialog.h @@ -51,7 +51,7 @@ class ResourceDownloadDialog : public QDialog, public BasePageProvider { public: using DownloadTaskPtr = shared_qobject_ptr; - 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 { diff --git a/launcher/ui/dialogs/ResourceUpdateDialog.cpp b/launcher/ui/dialogs/ResourceUpdateDialog.cpp index e9776c660..8a54958ba 100644 --- a/launcher/ui/dialogs/ResourceUpdateDialog.cpp +++ b/launcher/ui/dialogs/ResourceUpdateDialog.cpp @@ -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:
" "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 +auto ResourceUpdateDialog::getTasks() const -> QList { QList list; diff --git a/launcher/ui/dialogs/ResourceUpdateDialog.h b/launcher/ui/dialogs/ResourceUpdateDialog.h index 9de1ee246..19663fc5a 100644 --- a/launcher/ui/dialogs/ResourceUpdateDialog.h +++ b/launcher/ui/dialogs/ResourceUpdateDialog.h @@ -27,7 +27,7 @@ class ResourceUpdateDialog final : public ReviewMessageBox { void appendResource(const CheckUpdateTask::Update& info, QStringList requiredBy = {}); - const QList getTasks(); + QList getTasks() const; auto indexDir() const -> QDir { return m_resourceModel->indexDir(); } auto noUpdates() const -> bool { return m_noUpdates; };