From 0d234703322bd1a72944fcf700fbaf209db31ece Mon Sep 17 00:00:00 2001 From: 0x189D7997 <199489335+0x189D7997@users.noreply.github.com> Date: Sat, 4 Apr 2026 07:17:58 +0000 Subject: [PATCH 1/7] Allow requesting project info without manual retry on fail Signed-off-by: 0x189D7997 <199489335+0x189D7997@users.noreply.github.com> (cherry picked from commit 983bf34807fe86d23e8317ffd5dfaa51ce947951) --- launcher/modplatform/ResourceAPI.cpp | 7 ++++--- launcher/modplatform/ResourceAPI.h | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/launcher/modplatform/ResourceAPI.cpp b/launcher/modplatform/ResourceAPI.cpp index cda90b677..bd683ed21 100644 --- a/launcher/modplatform/ResourceAPI.cpp +++ b/launcher/modplatform/ResourceAPI.cpp @@ -148,9 +148,9 @@ Task::Ptr ResourceAPI::getProjectVersions(VersionSearchArgs&& args, Callback&& callbacks) const +Task::Ptr ResourceAPI::getProjectInfo(ProjectInfoArgs&& args, Callback&& callbacks, bool askRetry) const { - auto [job, response] = getProject(args.pack->addonId.toString()); + auto [job, response] = getProject(args.pack->addonId.toString(), askRetry); QObject::connect(job.get(), &NetJob::succeeded, [this, response, callbacks, args] { auto pack = args.pack; @@ -284,7 +284,7 @@ QString ResourceAPI::mapMCVersionToModrinth(Version v) const return verStr; } -std::pair ResourceAPI::getProject(QString addonId) const +std::pair ResourceAPI::getProject(QString addonId, bool askRetry) const { auto project_url_optional = getInfoURL(addonId); if (!project_url_optional.has_value()) @@ -293,6 +293,7 @@ std::pair ResourceAPI::getProject(QString addonId) const auto project_url = project_url_optional.value(); auto netJob = makeShared(QString("%1::GetProject").arg(addonId), APPLICATION->network()); + netJob->setAskRetry(askRetry); auto [action, response] = Net::ApiDownload::makeByteArray(QUrl(project_url)); netJob->addNetAction(action); diff --git a/launcher/modplatform/ResourceAPI.h b/launcher/modplatform/ResourceAPI.h index 0ad55775c..51b6d4b50 100644 --- a/launcher/modplatform/ResourceAPI.h +++ b/launcher/modplatform/ResourceAPI.h @@ -115,10 +115,10 @@ class ResourceAPI { public slots: virtual Task::Ptr searchProjects(SearchArgs&&, Callback>&&) const; - virtual std::pair getProject(QString addonId) const; + virtual std::pair getProject(QString addonId, bool askRetry = true) const; virtual std::pair getProjects(QStringList addonIds) const = 0; - virtual Task::Ptr getProjectInfo(ProjectInfoArgs&&, Callback&&) const; + virtual Task::Ptr getProjectInfo(ProjectInfoArgs&&, Callback&&, bool askRetry = true) const; Task::Ptr getProjectVersions(VersionSearchArgs&& args, Callback>&& callbacks) const; virtual Task::Ptr getDependencyVersion(DependencySearchArgs&&, Callback&&) const; From f4eae05afcb312eed7a78cd7082890767a3b5a4d Mon Sep 17 00:00:00 2001 From: 0x189D7997 <199489335+0x189D7997@users.noreply.github.com> Date: Sat, 4 Apr 2026 07:27:29 +0000 Subject: [PATCH 2/7] Make search by id fail quietly Signed-off-by: 0x189D7997 <199489335+0x189D7997@users.noreply.github.com> (cherry picked from commit bf75d50bafdb589f1075be23f4ba29cc880bc90f) --- launcher/ui/pages/modplatform/flame/FlameModel.cpp | 2 +- launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/launcher/ui/pages/modplatform/flame/FlameModel.cpp b/launcher/ui/pages/modplatform/flame/FlameModel.cpp index 5d968d65a..56c655302 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModel.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModel.cpp @@ -178,7 +178,7 @@ void ListModel::performPaginatedSearch() }; auto project = std::make_shared(); project->addonId = projectId; - if (auto job = api.getProjectInfo({ project }, std::move(callbacks)); job) { + if (auto job = api.getProjectInfo({ project }, std::move(callbacks), false); job) { m_jobPtr = job; m_jobPtr->start(); } diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index 05cd2970c..9c1af44c0 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -148,7 +148,7 @@ void ModpackListModel::performPaginatedSearch() }; auto project = std::make_shared(); project->addonId = projectId; - if (auto job = api.getProjectInfo({ project }, std::move(callbacks)); job) { + if (auto job = api.getProjectInfo({ project }, std::move(callbacks), false); job) { m_jobPtr = job; m_jobPtr->start(); } From e03200df8f9d09cb752602d39446b38d9206a999 Mon Sep 17 00:00:00 2001 From: 0x189D7997 <199489335+0x189D7997@users.noreply.github.com> Date: Sat, 4 Apr 2026 07:29:19 +0000 Subject: [PATCH 3/7] Activate search by project id only for numarical values for CurseForge Signed-off-by: 0x189D7997 <199489335+0x189D7997@users.noreply.github.com> (cherry picked from commit 4706f894e315260be2a67b63127da6273d764354) --- launcher/ui/pages/modplatform/flame/FlameModel.cpp | 5 ++++- launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/launcher/ui/pages/modplatform/flame/FlameModel.cpp b/launcher/ui/pages/modplatform/flame/FlameModel.cpp index 56c655302..cf2bbd890 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModel.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModel.cpp @@ -165,7 +165,10 @@ void ListModel::fetchMore(const QModelIndex& parent) void ListModel::performPaginatedSearch() { static const FlameAPI api; - if (m_currentSearchTerm.startsWith("#")) { + + // activate search by id only for numerical values because all CurseForge ids are numerical + static const QRegularExpression s_projectIdExpr("^\\#[0-9]+$"); + if (s_projectIdExpr.match(m_currentSearchTerm).hasMatch()) { auto projectId = m_currentSearchTerm.mid(1); if (!projectId.isEmpty()) { ResourceAPI::Callback callbacks; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index 9c1af44c0..5cc515536 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -135,6 +135,7 @@ void ModpackListModel::performPaginatedSearch() return; static const ModrinthAPI api; + // Modrinth ids are not limited to numbers and can be any length if (m_currentSearchTerm.startsWith("#")) { auto projectId = m_currentSearchTerm.mid(1); if (!projectId.isEmpty()) { From 126f6b8f2076f8d646e5406ec37105bfa19f7b8c Mon Sep 17 00:00:00 2001 From: 0x189D7997 <199489335+0x189D7997@users.noreply.github.com> Date: Sat, 4 Apr 2026 13:12:23 +0000 Subject: [PATCH 4/7] Fallback to normal search on error and apply same changes to ResourceModel Signed-off-by: 0x189D7997 <199489335+0x189D7997@users.noreply.github.com> (cherry picked from commit 4151db6c94ac369595b2f07afcd9bab01b19bf22) --- .../ui/pages/modplatform/ResourceModel.cpp | 19 +++++++++++++++---- .../ui/pages/modplatform/flame/FlameModel.cpp | 9 ++++++--- .../modplatform/modrinth/ModrinthModel.cpp | 7 +++++-- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/launcher/ui/pages/modplatform/ResourceModel.cpp b/launcher/ui/pages/modplatform/ResourceModel.cpp index e90eafbf2..4e46a08d6 100644 --- a/launcher/ui/pages/modplatform/ResourceModel.cpp +++ b/launcher/ui/pages/modplatform/ResourceModel.cpp @@ -139,15 +139,16 @@ void ResourceModel::search() if (hasActiveSearchJob()) return; - if (m_search_term.startsWith("#")) { + if (m_search_state != SearchState::ResetRequested && m_search_term.startsWith("#")) { auto projectId = m_search_term.mid(1); if (!projectId.isEmpty()) { ResourceAPI::Callback callbacks; - callbacks.on_fail = [this](QString reason, int) { + callbacks.on_fail = [this](QString reason, int network_error_code) { if (!s_running_models.constFind(this).value()) return; - searchRequestFailed(reason, -1); + m_search_state = SearchState::ResetRequested;; + searchRequestFailed(reason, network_error_code); }; callbacks.on_abort = [this] { if (!s_running_models.constFind(this).value()) @@ -407,6 +408,9 @@ void ResourceModel::searchRequestFailed([[maybe_unused]] QString reason, int net // Network error QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load mods.")); break; + case 404: + // 404 Not Found, some APIs return this when nothing is found, no need to bother the user + break; case 409: // 409 Gone, notify user to update QMessageBox::critical(nullptr, tr("Error"), @@ -414,7 +418,14 @@ void ResourceModel::searchRequestFailed([[maybe_unused]] QString reason, int net break; } - m_search_state = SearchState::Finished; + if (m_search_state == SearchState::ResetRequested) { + clearData(); + + m_next_search_offset = 0; + search(); + } else { + m_search_state = SearchState::Finished; + } } void ResourceModel::searchRequestAborted() diff --git a/launcher/ui/pages/modplatform/flame/FlameModel.cpp b/launcher/ui/pages/modplatform/flame/FlameModel.cpp index cf2bbd890..0fcdc841f 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModel.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModel.cpp @@ -166,14 +166,17 @@ void ListModel::performPaginatedSearch() { static const FlameAPI api; - // activate search by id only for numerical values because all CurseForge ids are numerical + // activate id search only for numerical values because all CurseForge ids are numerical static const QRegularExpression s_projectIdExpr("^\\#[0-9]+$"); - if (s_projectIdExpr.match(m_currentSearchTerm).hasMatch()) { + if (m_searchState != ResetRequested && s_projectIdExpr.match(m_currentSearchTerm).hasMatch()) { auto projectId = m_currentSearchTerm.mid(1); if (!projectId.isEmpty()) { ResourceAPI::Callback callbacks; - callbacks.on_fail = [this](QString reason, int) { searchRequestFailed(reason); }; + callbacks.on_fail = [this](QString reason, int) { + m_searchState = ResetRequested; + searchRequestFailed(reason); + }; callbacks.on_succeed = [this](auto& pack) { searchRequestForOneSucceeded(pack); }; callbacks.on_abort = [this] { qCritical() << "Search task aborted by an unknown reason!"; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index 5cc515536..0308e7214 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -136,12 +136,15 @@ void ModpackListModel::performPaginatedSearch() static const ModrinthAPI api; // Modrinth ids are not limited to numbers and can be any length - if (m_currentSearchTerm.startsWith("#")) { + if (m_searchState != ResetRequested && m_currentSearchTerm.startsWith("#")) { auto projectId = m_currentSearchTerm.mid(1); if (!projectId.isEmpty()) { ResourceAPI::Callback callbacks; - callbacks.on_fail = [this](QString reason, int) { searchRequestFailed(reason); }; + callbacks.on_fail = [this](QString reason, int) { + m_searchState = ResetRequested; + searchRequestFailed(reason); + }; callbacks.on_succeed = [this](auto& pack) { searchRequestForOneSucceeded(pack); }; callbacks.on_abort = [this] { qCritical() << "Search task aborted by an unknown reason!"; From c06cc8f9ae6481e05a2ffc5295fc9aa1dd606175 Mon Sep 17 00:00:00 2001 From: 0x189D7997 <199489335+0x189D7997@users.noreply.github.com> Date: Sat, 4 Apr 2026 13:35:06 +0000 Subject: [PATCH 5/7] oops forgot again Signed-off-by: 0x189D7997 <199489335+0x189D7997@users.noreply.github.com> (cherry picked from commit fdd1a5dde8f9eb0986365dd650e05bcc297d8ea3) --- launcher/ui/pages/modplatform/ResourceModel.cpp | 2 +- launcher/ui/pages/modplatform/flame/FlameModel.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/launcher/ui/pages/modplatform/ResourceModel.cpp b/launcher/ui/pages/modplatform/ResourceModel.cpp index 4e46a08d6..b96061b43 100644 --- a/launcher/ui/pages/modplatform/ResourceModel.cpp +++ b/launcher/ui/pages/modplatform/ResourceModel.cpp @@ -163,7 +163,7 @@ void ResourceModel::search() }; auto project = std::make_shared(); project->addonId = projectId; - if (auto job = m_api->getProjectInfo({ project }, std::move(callbacks)); job) + if (auto job = m_api->getProjectInfo({ project }, std::move(callbacks), false); job) runSearchJob(job); return; } diff --git a/launcher/ui/pages/modplatform/flame/FlameModel.cpp b/launcher/ui/pages/modplatform/flame/FlameModel.cpp index 0fcdc841f..c22d12da0 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModel.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModel.cpp @@ -166,7 +166,7 @@ void ListModel::performPaginatedSearch() { static const FlameAPI api; - // activate id search only for numerical values because all CurseForge ids are numerical + // activate search by id only for numerical values because all CurseForge ids are numerical static const QRegularExpression s_projectIdExpr("^\\#[0-9]+$"); if (m_searchState != ResetRequested && s_projectIdExpr.match(m_currentSearchTerm).hasMatch()) { auto projectId = m_currentSearchTerm.mid(1); From 6b60a243bcd12cd1625960436fc635b77166e636 Mon Sep 17 00:00:00 2001 From: 0x189D7997 <199489335+0x189D7997@users.noreply.github.com> Date: Tue, 7 Apr 2026 12:57:09 +0000 Subject: [PATCH 6/7] Use network_error_code from callbacks Signed-off-by: 0x189D7997 <199489335+0x189D7997@users.noreply.github.com> (cherry picked from commit 364968a6b44cfe5e6639ae34c9feba55336b35f8) --- .../modplatform/modrinth/ModrinthModel.cpp | 19 +++++++++---------- .../modplatform/modrinth/ModrinthModel.h | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index 0308e7214..fba9f3bc9 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -141,14 +141,14 @@ void ModpackListModel::performPaginatedSearch() if (!projectId.isEmpty()) { ResourceAPI::Callback callbacks; - callbacks.on_fail = [this](QString reason, int) { + callbacks.on_fail = [this](QString reason, int network_error_code) { m_searchState = ResetRequested; - searchRequestFailed(reason); + searchRequestFailed(reason, network_error_code); }; callbacks.on_succeed = [this](auto& pack) { searchRequestForOneSucceeded(pack); }; callbacks.on_abort = [this] { qCritical() << "Search task aborted by an unknown reason!"; - searchRequestFailed("Aborted"); + searchRequestFailed("Aborted", 0); }; auto project = std::make_shared(); project->addonId = projectId; @@ -165,10 +165,10 @@ void ModpackListModel::performPaginatedSearch() ResourceAPI::Callback> callbacks{}; callbacks.on_succeed = [this](auto& doc) { searchRequestFinished(doc); }; - callbacks.on_fail = [this](QString reason, int) { searchRequestFailed(reason); }; + callbacks.on_fail = [this](QString reason, int network_error_code) { searchRequestFailed(reason, network_error_code); }; callbacks.on_abort = [this] { qCritical() << "Search task aborted by an unknown reason!"; - searchRequestFailed("Aborted"); + searchRequestFailed("Aborted", 0); }; auto netJob = api.searchProjects({ ModPlatform::ResourceType::Modpack, m_nextSearchOffset, m_currentSearchTerm, sort, m_filter->loaders, @@ -320,13 +320,12 @@ void ModpackListModel::searchRequestForOneSucceeded(ModPlatform::IndexedPack::Pt endInsertRows(); } -void ModpackListModel::searchRequestFailed(QString) +void ModpackListModel::searchRequestFailed(QString reason, int network_error_code) { - auto failed_action = dynamic_cast(m_jobPtr.get())->getFailedActions().at(0); - if (failed_action->replyStatusCode() == -1) { - // Network error + if (network_error_code == -1) { + // Unknown error in network stack QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load modpacks.")); - } else if (failed_action->replyStatusCode() == 409) { + } else if (network_error_code == 409) { // 409 Gone, notify user to update QMessageBox::critical(nullptr, tr("Error"), //: %1 refers to the launcher itself diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h index 96f6fd128..3e0fc1686 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h @@ -85,7 +85,7 @@ class ModpackListModel : public QAbstractListModel { public slots: void searchRequestFinished(QList& doc_all); - void searchRequestFailed(QString reason); + void searchRequestFailed(QString reason, int network_error_code); void searchRequestForOneSucceeded(ModPlatform::IndexedPack::Ptr); protected slots: From f89a1f6378a461a1bb2c579f65356ec454bd1053 Mon Sep 17 00:00:00 2001 From: 0x189D7997 <199489335+0x189D7997@users.noreply.github.com> Date: Tue, 14 Apr 2026 23:51:34 +0000 Subject: [PATCH 7/7] Limit normal search fallback to 404 respnse Signed-off-by: 0x189D7997 <199489335+0x189D7997@users.noreply.github.com> (cherry picked from commit 28c42d04b620bc707ce4fe7261abf1a7cc18fae2) --- launcher/ui/pages/modplatform/ResourceModel.cpp | 4 +++- launcher/ui/pages/modplatform/flame/FlameModel.cpp | 6 ++++-- launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp | 4 +++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/launcher/ui/pages/modplatform/ResourceModel.cpp b/launcher/ui/pages/modplatform/ResourceModel.cpp index b96061b43..a3a043ba9 100644 --- a/launcher/ui/pages/modplatform/ResourceModel.cpp +++ b/launcher/ui/pages/modplatform/ResourceModel.cpp @@ -147,7 +147,9 @@ void ResourceModel::search() callbacks.on_fail = [this](QString reason, int network_error_code) { if (!s_running_models.constFind(this).value()) return; - m_search_state = SearchState::ResetRequested;; + if (network_error_code == 404) { + m_search_state = SearchState::ResetRequested; + } searchRequestFailed(reason, network_error_code); }; callbacks.on_abort = [this] { diff --git a/launcher/ui/pages/modplatform/flame/FlameModel.cpp b/launcher/ui/pages/modplatform/flame/FlameModel.cpp index c22d12da0..861dd9f22 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModel.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModel.cpp @@ -173,8 +173,10 @@ void ListModel::performPaginatedSearch() if (!projectId.isEmpty()) { ResourceAPI::Callback callbacks; - callbacks.on_fail = [this](QString reason, int) { - m_searchState = ResetRequested; + callbacks.on_fail = [this](QString reason, int network_error_code) { + if (network_error_code == 404) { + m_searchState = ResetRequested; + } searchRequestFailed(reason); }; callbacks.on_succeed = [this](auto& pack) { searchRequestForOneSucceeded(pack); }; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index fba9f3bc9..03518c3af 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -142,7 +142,9 @@ void ModpackListModel::performPaginatedSearch() ResourceAPI::Callback callbacks; callbacks.on_fail = [this](QString reason, int network_error_code) { - m_searchState = ResetRequested; + if (network_error_code == 404) { + m_searchState = ResetRequested; + } searchRequestFailed(reason, network_error_code); }; callbacks.on_succeed = [this](auto& pack) { searchRequestForOneSucceeded(pack); };