From ca721f9d67f2bfd4e3b083e2a3b655ea66a36bd5 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 7 May 2026 13:29:35 +0300 Subject: [PATCH] add special modrinth header Signed-off-by: Trial97 --- launcher/ResourceDownloadTask.cpp | 35 ++++++++++++++++-- launcher/ResourceDownloadTask.h | 4 ++- launcher/minecraft/mod/ResourceFolderModel.h | 1 + .../modrinth/ModrinthInstanceCreationTask.cpp | 32 +++++++++++++++-- launcher/net/ApiDownload.cpp | 4 +-- launcher/net/ApiDownload.h | 4 ++- launcher/net/ApiHeaderProxy.h | 36 +++++++++++++++++-- .../ui/dialogs/ResourceDownloadDialog.cpp | 6 ++-- launcher/ui/dialogs/ResourceDownloadDialog.h | 2 +- launcher/ui/dialogs/ResourceUpdateDialog.cpp | 2 +- launcher/ui/pages/modplatform/ModPage.cpp | 4 +-- launcher/ui/pages/modplatform/ModPage.h | 2 +- .../ui/pages/modplatform/ResourceModel.cpp | 5 +-- launcher/ui/pages/modplatform/ResourceModel.h | 3 +- .../ui/pages/modplatform/ResourcePage.cpp | 5 ++- launcher/ui/pages/modplatform/ResourcePage.h | 2 +- .../ui/pages/modplatform/ShaderPackPage.cpp | 5 +-- .../ui/pages/modplatform/ShaderPackPage.h | 2 +- 18 files changed, 127 insertions(+), 27 deletions(-) diff --git a/launcher/ResourceDownloadTask.cpp b/launcher/ResourceDownloadTask.cpp index d50b3d5cf..f9eeea790 100644 --- a/launcher/ResourceDownloadTask.cpp +++ b/launcher/ResourceDownloadTask.cpp @@ -19,20 +19,49 @@ #include "ResourceDownloadTask.h" +#include + #include "Application.h" #include "FileSystem.h" +#include "minecraft/MinecraftInstance.h" +#include "minecraft/PackProfile.h" #include "minecraft/mod/ResourceFolderModel.h" #include "minecraft/mod/ShaderPackFolderModel.h" +#include "modplatform/ModIndex.h" #include "modplatform/helpers/HashUtils.h" #include "net/ApiDownload.h" #include "net/ChecksumValidator.h" +namespace { +Net::ModrinthDownloadMeta createModrinthMeta(BaseInstance* instance, QString reason) +{ + auto* mcInstance = dynamic_cast(instance); + if (!mcInstance) { + return {}; + } + + auto* profile = mcInstance->getPackProfile(); + if (!profile) { + return {}; + } + + auto loaders = profile->getModLoadersList(); + + return { + .reason = std::move(reason), + .gameVersion = profile->getComponentVersion("net.minecraft"), + .loader = !loaders.isEmpty() ? ModPlatform::getModLoaderAsString(loaders.first()) : "", + }; +} +} // namespace + ResourceDownloadTask::ResourceDownloadTask(ModPlatform::IndexedPack::Ptr pack, ModPlatform::IndexedVersion version, ResourceFolderModel* packs, - bool is_indexed) + bool is_indexed, + QString downloadReason) : m_pack(std::move(pack)), m_pack_version(std::move(version)), m_pack_model(packs) { if (is_indexed) { @@ -45,7 +74,9 @@ ResourceDownloadTask::ResourceDownloadTask(ModPlatform::IndexedPack::Ptr pack, m_filesNetJob.reset(new NetJob(tr("Resource download"), APPLICATION->network())); m_filesNetJob->setStatus(tr("Downloading resource:\n%1").arg(m_pack_version.downloadUrl)); - auto action = Net::ApiDownload::makeFile(m_pack_version.downloadUrl, m_pack_model->dir().absoluteFilePath(getFilename())); + auto action = Net::ApiDownload::makeFile(m_pack_version.downloadUrl, m_pack_model->dir().absoluteFilePath(getFilename()), + Net::Download::Option::NoOptions, + createModrinthMeta(m_pack_model->instance(), std::move(downloadReason))); if (!m_pack_version.hash_type.isEmpty() && !m_pack_version.hash.isEmpty()) { switch (Hashing::algorithmFromString(m_pack_version.hash_type)) { case Hashing::Algorithm::Md4: diff --git a/launcher/ResourceDownloadTask.h b/launcher/ResourceDownloadTask.h index 7a04c6f1c..57dfa5eac 100644 --- a/launcher/ResourceDownloadTask.h +++ b/launcher/ResourceDownloadTask.h @@ -20,6 +20,7 @@ #pragma once #include "net/NetJob.h" +#include "net/ApiHeaderProxy.h" #include "tasks/SequentialTask.h" #include "minecraft/mod/tasks/LocalResourceUpdateTask.h" @@ -33,7 +34,8 @@ class ResourceDownloadTask : public SequentialTask { explicit ResourceDownloadTask(ModPlatform::IndexedPack::Ptr pack, ModPlatform::IndexedVersion version, ResourceFolderModel* packs, - bool is_indexed = true); + bool is_indexed = true, + QString downloadReason = "standalone"); const QString& getFilename() const { return m_pack_version.fileName; } const QVariant& getVersionID() const { return m_pack_version.fileId; } const ModPlatform::IndexedVersion& getVersion() const { return m_pack_version; } diff --git a/launcher/minecraft/mod/ResourceFolderModel.h b/launcher/minecraft/mod/ResourceFolderModel.h index 81bc6f5fc..124b9ea77 100644 --- a/launcher/minecraft/mod/ResourceFolderModel.h +++ b/launcher/minecraft/mod/ResourceFolderModel.h @@ -183,6 +183,7 @@ class ResourceFolderModel : public QAbstractListModel { }; QString instDirPath() const; + BaseInstance* instance() const { return m_instance; } signals: void updateFinished(); diff --git a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp index f308c88bc..482a27204 100644 --- a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp +++ b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp @@ -16,7 +16,10 @@ #include "net/ChecksumValidator.h" #include "net/ApiDownload.h" +#include "net/ApiHeaderProxy.h" #include "net/NetJob.h" + +#include "modplatform/ModIndex.h" #include "settings/INISettingsObject.h" #include "ui/dialogs/CustomMessageBox.h" @@ -256,15 +259,38 @@ std::unique_ptr ModrinthCreationTask::createInstance() return nullptr; } qDebug() << "Will try to download" << file.downloads.front() << "to" << file_path; - auto dl = Net::ApiDownload::makeFile(file.downloads.dequeue(), file_path); + + QString loader; + if (m_instance.has_value()) { + auto* mcInstance = dynamic_cast(m_instance.value()); + if (mcInstance) { + auto* profile = mcInstance->getPackProfile(); + if (profile) { + auto loaders = profile->getModLoadersList(); + if (!loaders.isEmpty()) { + loader = ModPlatform::getModLoaderAsString(loaders.first()); + } + } + } + } + + Net::ModrinthDownloadMeta meta{ + .reason = "modpack", + .gameVersion = m_minecraft_version, + .loader = loader, + }; + + QUrl downloadUrl = file.downloads.dequeue(); + auto dl = Net::ApiDownload::makeFile(downloadUrl, file_path, Net::Download::Option::NoOptions, meta); dl->addValidator(new Net::ChecksumValidator(file.hashAlgorithm, file.hash)); downloadMods->addNetAction(dl); if (!file.downloads.empty()) { // FIXME: This really needs to be put into a ConcurrentTask of // MultipleOptionsTask's , once those exist :) auto param = dl.toWeakRef(); - connect(dl.get(), &Task::failed, [&file, file_path, param, downloadMods] { - auto ndl = Net::ApiDownload::makeFile(file.downloads.dequeue(), file_path); + connect(dl.get(), &Task::failed, [&file, file_path, param, downloadMods, meta] { + QUrl fallbackUrl = file.downloads.dequeue(); + auto ndl = Net::ApiDownload::makeFile(fallbackUrl, file_path, Net::Download::Option::NoOptions, meta); ndl->addValidator(new Net::ChecksumValidator(file.hashAlgorithm, file.hash)); downloadMods->addNetAction(ndl); if (auto shared = param.lock()) diff --git a/launcher/net/ApiDownload.cpp b/launcher/net/ApiDownload.cpp index 9a5a44104..3a3804f5b 100644 --- a/launcher/net/ApiDownload.cpp +++ b/launcher/net/ApiDownload.cpp @@ -36,10 +36,10 @@ std::pair ApiDownload::makeByteArray(QUrl url, Downl return { dl, response }; } -Download::Ptr ApiDownload::makeFile(QUrl url, QString path, Download::Options options) +Download::Ptr ApiDownload::makeFile(QUrl url, QString path, Download::Options options, ModrinthDownloadMeta meta) { auto dl = Download::makeFile(url, path, options); - dl->addHeaderProxy(std::make_unique()); + dl->addHeaderProxy(std::make_unique(std::move(meta))); return dl; } diff --git a/launcher/net/ApiDownload.h b/launcher/net/ApiDownload.h index 01a31eb17..fe61887c8 100644 --- a/launcher/net/ApiDownload.h +++ b/launcher/net/ApiDownload.h @@ -20,13 +20,15 @@ #pragma once #include "Download.h" +#include "net/ApiHeaderProxy.h" namespace Net { namespace ApiDownload { Download::Ptr makeCached(QUrl url, MetaEntryPtr entry, Download::Options options = Download::Option::NoOptions); std::pair makeByteArray(QUrl url, Download::Options options = Download::Option::NoOptions); -Download::Ptr makeFile(QUrl url, QString path, Download::Options options = Download::Option::NoOptions); +Download::Ptr makeFile(QUrl url, QString path, Download::Options options = Download::Option::NoOptions, + ModrinthDownloadMeta meta = ModrinthDownloadMeta()); }; // namespace ApiDownload } // namespace Net diff --git a/launcher/net/ApiHeaderProxy.h b/launcher/net/ApiHeaderProxy.h index 789a6fada..feb1913e3 100644 --- a/launcher/net/ApiHeaderProxy.h +++ b/launcher/net/ApiHeaderProxy.h @@ -23,11 +23,35 @@ #include "BuildConfig.h" #include "net/HeaderProxy.h" +#include +#include + namespace Net { +struct ModrinthDownloadMeta { + QString reason; + QString gameVersion; + QString loader; + + bool isEmpty() const { return reason.isEmpty(); } + + QByteArray toJson() const + { + QJsonObject obj; + if (!reason.isEmpty()) + obj["reason"] = reason; + if (!gameVersion.isEmpty()) + obj["game_version"] = gameVersion; + if (!loader.isEmpty()) + obj["loader"] = loader; + return QJsonDocument(obj).toJson(QJsonDocument::Compact); + } +}; + class ApiHeaderProxy : public HeaderProxy { public: ApiHeaderProxy() : HeaderProxy() {} + explicit ApiHeaderProxy(ModrinthDownloadMeta meta) : m_meta(std::move(meta)) {} virtual ~ApiHeaderProxy() = default; public: @@ -39,11 +63,19 @@ class ApiHeaderProxy : public HeaderProxy { } else if (request.url().host() == QUrl(BuildConfig.MODRINTH_PROD_URL).host() || request.url().host() == QUrl(BuildConfig.MODRINTH_STAGING_URL).host()) { QString token = APPLICATION->getModrinthAPIToken(); - if (!token.isNull()) - hdrs.append({ "Authorization", token.toUtf8() }); + if (!token.isNull()) { + hdrs.append({ .headerName = "Authorization", .headerValue = token.toUtf8() }); + } + } + + if (request.url().host() == "cdn.modrinth.com" && !m_meta.isEmpty()) { + hdrs.append({ .headerName = "modrinth-download-meta", .headerValue = m_meta.toJson() }); } return hdrs; }; + + private: + ModrinthDownloadMeta m_meta; }; } // namespace Net diff --git a/launcher/ui/dialogs/ResourceDownloadDialog.cpp b/launcher/ui/dialogs/ResourceDownloadDialog.cpp index 49f263406..8569fadac 100644 --- a/launcher/ui/dialogs/ResourceDownloadDialog.cpp +++ b/launcher/ui/dialogs/ResourceDownloadDialog.cpp @@ -185,7 +185,7 @@ void ResourceDownloadDialog::confirm() return; } for (const auto& dep : task->getDependecies()) { - addResource(dep->pack, dep->version); + addResource(dep->pack, dep->version, "dependency"); depNames << dep->pack->name; } dependencyExtraInfo = task->getExtraInfo(); @@ -234,10 +234,10 @@ ResourcePage* ResourceDownloadDialog::selectedPage() return result; } -void ResourceDownloadDialog::addResource(ModPlatform::IndexedPack::Ptr pack, ModPlatform::IndexedVersion& ver) +void ResourceDownloadDialog::addResource(ModPlatform::IndexedPack::Ptr pack, ModPlatform::IndexedVersion& ver, QString downloadReason) { removeResource(pack->name); - selectedPage()->addResourceToPage(pack, ver, getBaseModel()); + selectedPage()->addResourceToPage(pack, ver, getBaseModel(), downloadReason); setButtonStatus(); } diff --git a/launcher/ui/dialogs/ResourceDownloadDialog.h b/launcher/ui/dialogs/ResourceDownloadDialog.h index c9d9e568c..3e8da4c33 100644 --- a/launcher/ui/dialogs/ResourceDownloadDialog.h +++ b/launcher/ui/dialogs/ResourceDownloadDialog.h @@ -64,7 +64,7 @@ class ResourceDownloadDialog : public QDialog, public BasePageProvider { bool selectPage(QString pageId); ResourcePage* selectedPage(); - void addResource(ModPlatform::IndexedPack::Ptr, ModPlatform::IndexedVersion&); + void addResource(ModPlatform::IndexedPack::Ptr, ModPlatform::IndexedVersion&, QString downloadReason = "standalone"); void removeResource(const QString&); QList getTasks(); diff --git a/launcher/ui/dialogs/ResourceUpdateDialog.cpp b/launcher/ui/dialogs/ResourceUpdateDialog.cpp index 99b01c35d..d4efea78f 100644 --- a/launcher/ui/dialogs/ResourceUpdateDialog.cpp +++ b/launcher/ui/dialogs/ResourceUpdateDialog.cpp @@ -234,7 +234,7 @@ void ResourceUpdateDialog::checkCandidates() auto changelog = dep->version.changelog; if (dep->pack->provider == ModPlatform::ResourceProvider::FLAME) changelog = api.getModFileChangelog(dep->version.addonId.toInt(), dep->version.fileId.toInt()); - auto download_task = makeShared(dep->pack, dep->version, m_resourceModel); + auto download_task = makeShared(dep->pack, dep->version, m_resourceModel, true, "dependency"); 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, diff --git a/launcher/ui/pages/modplatform/ModPage.cpp b/launcher/ui/pages/modplatform/ModPage.cpp index 706d35378..d655d2d29 100644 --- a/launcher/ui/pages/modplatform/ModPage.cpp +++ b/launcher/ui/pages/modplatform/ModPage.cpp @@ -112,10 +112,10 @@ QMap ModPage::urlHandlers() const /******** Make changes to the UI ********/ -void ModPage::addResourceToPage(ModPlatform::IndexedPack::Ptr pack, ModPlatform::IndexedVersion& version, ResourceFolderModel* base_model) +void ModPage::addResourceToPage(ModPlatform::IndexedPack::Ptr pack, ModPlatform::IndexedVersion& version, ResourceFolderModel* base_model, QString downloadReason) { bool is_indexed = !APPLICATION->settings()->get("ModMetadataDisabled").toBool(); - m_model->addPack(pack, version, base_model, is_indexed); + m_model->addPack(pack, version, base_model, is_indexed, downloadReason); } } // namespace ResourceDownload diff --git a/launcher/ui/pages/modplatform/ModPage.h b/launcher/ui/pages/modplatform/ModPage.h index a69ee53f7..112a88bb2 100644 --- a/launcher/ui/pages/modplatform/ModPage.h +++ b/launcher/ui/pages/modplatform/ModPage.h @@ -49,7 +49,7 @@ class ModPage : public ResourcePage { QMap urlHandlers() const override; - void addResourceToPage(ModPlatform::IndexedPack::Ptr, ModPlatform::IndexedVersion&, ResourceFolderModel*) override; + void addResourceToPage(ModPlatform::IndexedPack::Ptr, ModPlatform::IndexedVersion&, ResourceFolderModel*, QString downloadReason = "standalone") override; virtual std::unique_ptr createFilterWidget() = 0; diff --git a/launcher/ui/pages/modplatform/ResourceModel.cpp b/launcher/ui/pages/modplatform/ResourceModel.cpp index a3a043ba9..2111b4328 100644 --- a/launcher/ui/pages/modplatform/ResourceModel.cpp +++ b/launcher/ui/pages/modplatform/ResourceModel.cpp @@ -486,10 +486,11 @@ void ResourceModel::infoRequestSucceeded(ModPlatform::IndexedPack::Ptr pack, con void ResourceModel::addPack(ModPlatform::IndexedPack::Ptr pack, ModPlatform::IndexedVersion& version, ResourceFolderModel* packs, - bool is_indexed) + bool is_indexed, + QString downloadReason) { version.is_currently_selected = true; - m_selected.append(makeShared(pack, version, packs, is_indexed)); + m_selected.append(makeShared(pack, version, packs, is_indexed, downloadReason)); } void ResourceModel::removePack(const QString& rem) diff --git a/launcher/ui/pages/modplatform/ResourceModel.h b/launcher/ui/pages/modplatform/ResourceModel.h index 573ad8b75..2139588c0 100644 --- a/launcher/ui/pages/modplatform/ResourceModel.h +++ b/launcher/ui/pages/modplatform/ResourceModel.h @@ -94,7 +94,8 @@ class ResourceModel : public QAbstractListModel { void addPack(ModPlatform::IndexedPack::Ptr pack, ModPlatform::IndexedVersion& version, ResourceFolderModel* packs, - bool is_indexed = false); + bool is_indexed = false, + QString downloadReason = "standalone"); void removePack(const QString& rem); QList selectedPacks() { return m_selected; } diff --git a/launcher/ui/pages/modplatform/ResourcePage.cpp b/launcher/ui/pages/modplatform/ResourcePage.cpp index 931b4a311..126a4c387 100644 --- a/launcher/ui/pages/modplatform/ResourcePage.cpp +++ b/launcher/ui/pages/modplatform/ResourcePage.cpp @@ -395,7 +395,10 @@ void ResourcePage::removeResourceFromDialog(const QString& packName) m_parentDialog->removeResource(packName); } -void ResourcePage::addResourceToPage(ModPlatform::IndexedPack::Ptr pack, ModPlatform::IndexedVersion& ver, ResourceFolderModel* baseModel) +void ResourcePage::addResourceToPage(ModPlatform::IndexedPack::Ptr pack, + ModPlatform::IndexedVersion& ver, + ResourceFolderModel* baseModel, + QString downloadReason) { bool isIndexed = !APPLICATION->settings()->get("ModMetadataDisabled").toBool(); m_model->addPack(std::move(pack), ver, baseModel, isIndexed); diff --git a/launcher/ui/pages/modplatform/ResourcePage.h b/launcher/ui/pages/modplatform/ResourcePage.h index c11edb1d7..7a5acdffe 100644 --- a/launcher/ui/pages/modplatform/ResourcePage.h +++ b/launcher/ui/pages/modplatform/ResourcePage.h @@ -78,7 +78,7 @@ class ResourcePage : public QWidget, public BasePage { void addResourceToDialog(ModPlatform::IndexedPack::Ptr, ModPlatform::IndexedVersion&); void removeResourceFromDialog(const QString& packName); virtual void removeResourceFromPage(const QString& name); - virtual void addResourceToPage(ModPlatform::IndexedPack::Ptr, ModPlatform::IndexedVersion&, ResourceFolderModel*); + virtual void addResourceToPage(ModPlatform::IndexedPack::Ptr, ModPlatform::IndexedVersion&, ResourceFolderModel*, QString downloadReason = "standalone"); virtual void modelReset(); diff --git a/launcher/ui/pages/modplatform/ShaderPackPage.cpp b/launcher/ui/pages/modplatform/ShaderPackPage.cpp index 99c50352a..3634b0ab4 100644 --- a/launcher/ui/pages/modplatform/ShaderPackPage.cpp +++ b/launcher/ui/pages/modplatform/ShaderPackPage.cpp @@ -44,10 +44,11 @@ QMap ShaderPackResourcePage::urlHandlers() const void ShaderPackResourcePage::addResourceToPage(ModPlatform::IndexedPack::Ptr pack, ModPlatform::IndexedVersion& version, - ResourceFolderModel* base_model) + ResourceFolderModel* base_model, + QString downloadReason) { bool is_indexed = !APPLICATION->settings()->get("ModMetadataDisabled").toBool(); - m_model->addPack(pack, version, base_model, is_indexed); + m_model->addPack(pack, version, base_model, is_indexed, downloadReason); } } // namespace ResourceDownload diff --git a/launcher/ui/pages/modplatform/ShaderPackPage.h b/launcher/ui/pages/modplatform/ShaderPackPage.h index 92ddd9f8a..5726cbc16 100644 --- a/launcher/ui/pages/modplatform/ShaderPackPage.h +++ b/launcher/ui/pages/modplatform/ShaderPackPage.h @@ -39,7 +39,7 @@ class ShaderPackResourcePage : public ResourcePage { bool supportsFiltering() const override { return false; }; - void addResourceToPage(ModPlatform::IndexedPack::Ptr, ModPlatform::IndexedVersion&, ResourceFolderModel*) override; + void addResourceToPage(ModPlatform::IndexedPack::Ptr, ModPlatform::IndexedVersion&, ResourceFolderModel*, QString downloadReason = "standalone") override; QMap urlHandlers() const override;