From aaab95ba5528c67f1056f2cc7e42656348ca3ec6 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Mon, 12 Jun 2023 12:08:18 +0100 Subject: [PATCH 001/223] Basic Quick Play support Signed-off-by: TheKodeToad --- launcher/minecraft/MinecraftInstance.cpp | 11 ++++++++-- .../launcher/impl/StandardLauncher.java | 21 +++++++++++++++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index 2c624a365..caba8f9a7 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -564,8 +564,15 @@ QStringList MinecraftInstance::processMinecraftArgs( if (serverToJoin && !serverToJoin->address.isEmpty()) { - args_pattern += " --server " + serverToJoin->address; - args_pattern += " --port " + QString::number(serverToJoin->port); + if (profile->hasTrait("quickPlay")) + { + args_pattern += " --quickPlayMultiplayer " + serverToJoin->address + ':' + QString::number(serverToJoin->port); + } + else + { + args_pattern += " --server " + serverToJoin->address; + args_pattern += " --port " + QString::number(serverToJoin->port); + } } QMap token_mapping; diff --git a/libraries/launcher/org/prismlauncher/launcher/impl/StandardLauncher.java b/libraries/launcher/org/prismlauncher/launcher/impl/StandardLauncher.java index 9436ff15e..c9ec34909 100644 --- a/libraries/launcher/org/prismlauncher/launcher/impl/StandardLauncher.java +++ b/libraries/launcher/org/prismlauncher/launcher/impl/StandardLauncher.java @@ -55,14 +55,21 @@ package org.prismlauncher.launcher.impl; import java.lang.invoke.MethodHandle; +import java.util.Collections; +import java.util.List; import org.prismlauncher.utils.Parameters; import org.prismlauncher.utils.ReflectionUtils; public final class StandardLauncher extends AbstractLauncher { + private final boolean quickPlaySupported; + public StandardLauncher(Parameters params) { super(params); + + List traits = params.getList("traits", Collections.emptyList()); + quickPlaySupported = traits.contains("quickPlay"); } @Override @@ -77,10 +84,16 @@ public final class StandardLauncher extends AbstractLauncher { } if (serverAddress != null) { - gameArgs.add("--server"); - gameArgs.add(serverAddress); - gameArgs.add("--port"); - gameArgs.add(serverPort); + if (quickPlaySupported) { + // as of 23w14a + gameArgs.add("--quickPlayMultiplayer"); + gameArgs.add(serverAddress + ':' + serverPort); + } else { + gameArgs.add("--server"); + gameArgs.add(serverAddress); + gameArgs.add("--port"); + gameArgs.add(serverPort); + } } // find and invoke the main method From 7f4665e3cca891bdd42d67a5a82a8c6561d1c86e Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 14 Jul 2023 21:07:34 +0300 Subject: [PATCH 002/223] format Signed-off-by: Trial97 --- .../modplatform/flame/FileResolvingTask.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/launcher/modplatform/flame/FileResolvingTask.cpp b/launcher/modplatform/flame/FileResolvingTask.cpp index ce7a60551..f84002385 100644 --- a/launcher/modplatform/flame/FileResolvingTask.cpp +++ b/launcher/modplatform/flame/FileResolvingTask.cpp @@ -128,12 +128,13 @@ void Flame::FileResolvingTask::netJobFinished() m_checkJob->start(); } -void Flame::FileResolvingTask::modrinthCheckFinished() { +void Flame::FileResolvingTask::modrinthCheckFinished() +{ setProgress(2, 3); qDebug() << "Finished with blocked mods : " << blockedProjects.size(); for (auto it = blockedProjects.keyBegin(); it != blockedProjects.keyEnd(); it++) { - auto &out = *it; + auto& out = *it; auto bytes = blockedProjects[out]; if (!out->resolved) { continue; @@ -153,15 +154,13 @@ void Flame::FileResolvingTask::modrinthCheckFinished() { out->resolved = false; } } - //copy to an output list and filter out projects found on modrinth + // copy to an output list and filter out projects found on modrinth auto block = std::make_shared>(); auto it = blockedProjects.keys(); - std::copy_if(it.begin(), it.end(), std::back_inserter(*block), [](File *f) { - return !f->resolved; - }); - //Display not found mods early + std::copy_if(it.begin(), it.end(), std::back_inserter(*block), [](File* f) { return !f->resolved; }); + // Display not found mods early if (!block->empty()) { - //blocked mods found, we need the slug for displaying.... we need another job :D ! + // blocked mods found, we need the slug for displaying.... we need another job :D ! m_slugJob.reset(new NetJob("Slug Job", m_network)); int index = 0; for (auto mod : *block) { @@ -173,8 +172,8 @@ void Flame::FileResolvingTask::modrinthCheckFinished() { QObject::connect(dl.get(), &Net::Download::succeeded, [block, index, output]() { auto mod = block->at(index); // use the shared_ptr so it is captured and only freed when we are done auto json = QJsonDocument::fromJson(*output); - auto base = Json::requireString(Json::requireObject(Json::requireObject(Json::requireObject(json),"data"),"links"), - "websiteUrl"); + auto base = + Json::requireString(Json::requireObject(Json::requireObject(Json::requireObject(json), "data"), "links"), "websiteUrl"); auto link = QString("%1/download/%2").arg(base, QString::number(mod->fileId)); mod->websiteUrl = link; }); From d3dc00dcab31ecf4a8ae5886db310ff0bedc9018 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 14 Jul 2023 21:07:53 +0300 Subject: [PATCH 003/223] made concurent task fail Signed-off-by: Trial97 --- .../modplatform/flame/FileResolvingTask.cpp | 1 - launcher/tasks/ConcurrentTask.cpp | 20 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/launcher/modplatform/flame/FileResolvingTask.cpp b/launcher/modplatform/flame/FileResolvingTask.cpp index f84002385..7695dfcdf 100644 --- a/launcher/modplatform/flame/FileResolvingTask.cpp +++ b/launcher/modplatform/flame/FileResolvingTask.cpp @@ -112,7 +112,6 @@ void Flame::FileResolvingTask::netJobFinished() connect(m_checkJob.get(), &NetJob::failed, this, [this, step_progress](QString reason) { step_progress->state = TaskStepState::Failed; stepProgress(*step_progress); - emitFailed(reason); }); connect(m_checkJob.get(), &NetJob::stepProgress, this, &FileResolvingTask::propogateStepProgress); connect(m_checkJob.get(), &NetJob::progress, this, [this, step_progress](qint64 current, qint64 total) { diff --git a/launcher/tasks/ConcurrentTask.cpp b/launcher/tasks/ConcurrentTask.cpp index 9aada5e69..7c7cfaf72 100644 --- a/launcher/tasks/ConcurrentTask.cpp +++ b/launcher/tasks/ConcurrentTask.cpp @@ -118,8 +118,11 @@ void ConcurrentTask::startNext() if (m_aborted || m_doing.count() > m_total_max_size) return; - if (m_queue.isEmpty() && m_doing.isEmpty() && !wasSuccessful()) { - emitSucceeded(); + if (m_queue.isEmpty() && m_doing.isEmpty() && isRunning()) { + if (m_failed.isEmpty()) + emitSucceeded(); + else + emitFailed(tr("One or more subtasks failed")); return; } @@ -194,7 +197,7 @@ void ConcurrentTask::subTaskStatus(Task::Ptr task, const QString& msg) auto task_progress = m_task_progress.value(task->getUid()); task_progress->status = msg; task_progress->state = TaskStepState::Running; - + emit stepProgress(*task_progress); if (totalSize() == 1) { @@ -207,7 +210,7 @@ void ConcurrentTask::subTaskDetails(Task::Ptr task, const QString& msg) auto task_progress = m_task_progress.value(task->getUid()); task_progress->details = msg; task_progress->state = TaskStepState::Running; - + emit stepProgress(*task_progress); if (totalSize() == 1) { @@ -220,7 +223,7 @@ void ConcurrentTask::subTaskProgress(Task::Ptr task, qint64 current, qint64 tota auto task_progress = m_task_progress.value(task->getUid()); task_progress->update(current, total); - + emit stepProgress(*task_progress); updateStepProgress(*task_progress, Operation::CHANGED); updateState(); @@ -233,7 +236,7 @@ void ConcurrentTask::subTaskProgress(Task::Ptr task, qint64 current, qint64 tota void ConcurrentTask::subTaskStepProgress(Task::Ptr task, TaskStepProgress const& task_progress) { Operation op = Operation::ADDED; - + if (!m_task_progress.contains(task_progress.uid)) { m_task_progress.insert(task_progress.uid, std::make_shared(task_progress)); op = Operation::ADDED; @@ -254,12 +257,10 @@ void ConcurrentTask::subTaskStepProgress(Task::Ptr task, TaskStepProgress const& emit stepProgress(*tp.get()); updateStepProgress(*tp.get(), op); } - } void ConcurrentTask::updateStepProgress(TaskStepProgress const& changed_progress, Operation op) { - switch (op) { case Operation::ADDED: m_stepProgress += changed_progress.current; @@ -274,9 +275,8 @@ void ConcurrentTask::updateStepProgress(TaskStepProgress const& changed_progress m_stepTotalProgress -= changed_progress.old_total; m_stepProgress += changed_progress.current; m_stepTotalProgress += changed_progress.total; - break; + break; } - } void ConcurrentTask::updateState() From 0880d4d37b654ffe68c4497a78883e73933dfe98 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sat, 15 Jul 2023 09:16:37 +0300 Subject: [PATCH 004/223] made sure abort signal is catched in cocurent task Signed-off-by: Trial97 --- launcher/tasks/ConcurrentTask.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/launcher/tasks/ConcurrentTask.cpp b/launcher/tasks/ConcurrentTask.cpp index 7c7cfaf72..7bb02e57d 100644 --- a/launcher/tasks/ConcurrentTask.cpp +++ b/launcher/tasks/ConcurrentTask.cpp @@ -88,6 +88,7 @@ bool ConcurrentTask::abort() QMutableHashIterator doing_iter(m_doing); while (doing_iter.hasNext()) { auto task = doing_iter.next(); + disconnect(task.value().get(), &Task::aborted, this, 0); suceedeed &= (task.value())->abort(); } @@ -133,6 +134,9 @@ void ConcurrentTask::startNext() connect(next.get(), &Task::succeeded, this, [this, next]() { subTaskSucceeded(next); }); connect(next.get(), &Task::failed, this, [this, next](QString msg) { subTaskFailed(next, msg); }); + // this should never happen but if it does better to fail the task that being stuck + // most + connect(next.get(), &Task::aborted, this, [this, next] { subTaskFailed(next, "Aborted"); }); connect(next.get(), &Task::status, this, [this, next](QString msg) { subTaskStatus(next, msg); }); connect(next.get(), &Task::details, this, [this, next](QString msg) { subTaskDetails(next, msg); }); From a7e0c9db9694a153a94cf0c924296576b0e9b767 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sat, 15 Jul 2023 12:01:07 +0300 Subject: [PATCH 005/223] connected failed event for some tasks Signed-off-by: Trial97 --- launcher/modplatform/EnsureMetadataTask.cpp | 2 ++ .../modplatform/flame/FlameCheckUpdate.cpp | 7 ++--- launcher/modplatform/flame/FlameCheckUpdate.h | 8 +++++- .../flame/FlameInstanceCreationTask.cpp | 1 + .../modplatform/flame/FlamePackExportTask.cpp | 1 + .../modrinth/ModrinthCheckUpdate.cpp | 14 ++++------ launcher/ui/dialogs/ModUpdateDialog.cpp | 8 +++++- .../ui/pages/modplatform/flame/FlamePage.cpp | 12 ++++----- .../modplatform/modrinth/ModrinthPage.cpp | 5 ++++ .../pages/modplatform/technic/TechnicPage.cpp | 10 ++++--- .../ui/widgets/VariableSizedImageObject.cpp | 26 +++++++++++++------ 11 files changed, 63 insertions(+), 31 deletions(-) diff --git a/launcher/modplatform/EnsureMetadataTask.cpp b/launcher/modplatform/EnsureMetadataTask.cpp index c3eadd06d..22581e43e 100644 --- a/launcher/modplatform/EnsureMetadataTask.cpp +++ b/launcher/modplatform/EnsureMetadataTask.cpp @@ -148,6 +148,7 @@ void EnsureMetadataTask::executeTask() if (m_current_task) m_current_task.reset(); }); + connect(project_task.get(), &Task::failed, this, &EnsureMetadataTask::emitFailed); m_current_task = project_task; project_task->start(); @@ -158,6 +159,7 @@ void EnsureMetadataTask::executeTask() if (m_current_task) m_current_task.reset(); }); + connect(version_task.get(), &Task::failed, this, &EnsureMetadataTask::emitFailed); if (m_mods.size() > 1) setStatus(tr("Requesting metadata information from %1...").arg(ProviderCaps.readableName(m_provider))); diff --git a/launcher/modplatform/flame/FlameCheckUpdate.cpp b/launcher/modplatform/flame/FlameCheckUpdate.cpp index a2628e34c..092133f1a 100644 --- a/launcher/modplatform/flame/FlameCheckUpdate.cpp +++ b/launcher/modplatform/flame/FlameCheckUpdate.cpp @@ -23,7 +23,7 @@ bool FlameCheckUpdate::abort() return true; } -ModPlatform::IndexedPack getProjectInfo(ModPlatform::IndexedVersion& ver_info) +ModPlatform::IndexedPack FlameCheckUpdate::getProjectInfo(ModPlatform::IndexedVersion& ver_info) { ModPlatform::IndexedPack pack; @@ -56,6 +56,7 @@ ModPlatform::IndexedPack getProjectInfo(ModPlatform::IndexedVersion& ver_info) } }); + connect(get_project_job, &NetJob::failed, this, &FlameCheckUpdate::emitFailed); QObject::connect(get_project_job, &NetJob::finished, [&loop, get_project_job] { get_project_job->deleteLater(); loop.quit(); @@ -67,7 +68,7 @@ ModPlatform::IndexedPack getProjectInfo(ModPlatform::IndexedVersion& ver_info) return pack; } -ModPlatform::IndexedVersion getFileInfo(int addonId, int fileId) +ModPlatform::IndexedVersion FlameCheckUpdate::getFileInfo(int addonId, int fileId) { ModPlatform::IndexedVersion ver; @@ -99,7 +100,7 @@ ModPlatform::IndexedVersion getFileInfo(int addonId, int fileId) qDebug() << doc; } }); - + connect(get_file_info_job, &NetJob::failed, this, &FlameCheckUpdate::emitFailed); QObject::connect(get_file_info_job, &NetJob::finished, [&loop, get_file_info_job] { get_file_info_job->deleteLater(); loop.quit(); diff --git a/launcher/modplatform/flame/FlameCheckUpdate.h b/launcher/modplatform/flame/FlameCheckUpdate.h index 4a98d684f..0dbd199e7 100644 --- a/launcher/modplatform/flame/FlameCheckUpdate.h +++ b/launcher/modplatform/flame/FlameCheckUpdate.h @@ -8,7 +8,10 @@ class FlameCheckUpdate : public CheckUpdateTask { Q_OBJECT public: - FlameCheckUpdate(QList& mods, std::list& mcVersions, std::optional loaders, std::shared_ptr mods_folder) + FlameCheckUpdate(QList& mods, + std::list& mcVersions, + std::optional loaders, + std::shared_ptr mods_folder) : CheckUpdateTask(mods, mcVersions, loaders, mods_folder) {} @@ -19,6 +22,9 @@ class FlameCheckUpdate : public CheckUpdateTask { void executeTask() override; private: + ModPlatform::IndexedPack getProjectInfo(ModPlatform::IndexedVersion& ver_info); + ModPlatform::IndexedVersion getFileInfo(int addonId, int fileId); + NetJob* m_net_job = nullptr; bool m_was_aborted = false; diff --git a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp index b57db288a..fa5057e5c 100644 --- a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp +++ b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp @@ -229,6 +229,7 @@ bool FlameCreationTask::updateInstance() m_files_to_remove.append(old_minecraft_dir.absoluteFilePath(relative_path)); } }); + connect(job.get(), &Task::failed, this, [](QString reason) { qCritical() << "Failed to get files: " << reason; }); connect(job.get(), &Task::finished, &loop, &QEventLoop::quit); m_process_update_file_info_job = job; diff --git a/launcher/modplatform/flame/FlamePackExportTask.cpp b/launcher/modplatform/flame/FlamePackExportTask.cpp index ac0da2142..69f88127e 100644 --- a/launcher/modplatform/flame/FlamePackExportTask.cpp +++ b/launcher/modplatform/flame/FlamePackExportTask.cpp @@ -327,6 +327,7 @@ void FlamePackExportTask::getProjectsInfo() } buildZip(); }); + connect(projTask.get(), &Task::failed, this, &FlamePackExportTask::emitFailed); task.reset(projTask); task->start(); } diff --git a/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp b/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp index a7c22832a..c83ef2fd4 100644 --- a/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp +++ b/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp @@ -73,8 +73,6 @@ void ModrinthCheckUpdate::executeTask() auto response = std::make_shared(); auto job = api.latestVersions(hashes, best_hash_type, m_game_versions, m_loaders, response); - QEventLoop lock; - connect(job.get(), &Task::succeeded, this, [this, response, &mappings, best_hash_type, job] { QJsonParseError parse_error{}; QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); @@ -83,7 +81,7 @@ void ModrinthCheckUpdate::executeTask() << " reason: " << parse_error.errorString(); qWarning() << *response; - failed(parse_error.errorString()); + emitFailed(parse_error.errorString()); return; } @@ -167,19 +165,17 @@ void ModrinthCheckUpdate::executeTask() } } } catch (Json::JsonException& e) { - failed(e.cause() + " : " + e.what()); + emitFailed(e.cause() + " : " + e.what()); + return; } + emitSucceeded(); }); - connect(job.get(), &Task::finished, &lock, &QEventLoop::quit); + connect(job.get(), &Task::failed, this, &ModrinthCheckUpdate::emitFailed); setStatus(tr("Waiting for the API response from Modrinth...")); setProgress(1, 3); m_net_job = qSharedPointerObjectCast(job); job->start(); - - lock.exec(); - - emitSucceeded(); } diff --git a/launcher/ui/dialogs/ModUpdateDialog.cpp b/launcher/ui/dialogs/ModUpdateDialog.cpp index 8618b9240..df45cbbcf 100644 --- a/launcher/ui/dialogs/ModUpdateDialog.cpp +++ b/launcher/ui/dialogs/ModUpdateDialog.cpp @@ -271,6 +271,8 @@ auto ModUpdateDialog::ensureMetadata() -> bool connect(modrinth_task.get(), &EnsureMetadataTask::metadataFailed, [this, &should_try_others](Mod* candidate) { onMetadataFailed(candidate, should_try_others.find(candidate->internal_id()).value(), ModPlatform::ResourceProvider::MODRINTH); }); + connect(modrinth_task.get(), &EnsureMetadataTask::failed, + [this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); }); if (modrinth_task->getHashingTask()) seq.addTask(modrinth_task->getHashingTask()); @@ -284,6 +286,8 @@ auto ModUpdateDialog::ensureMetadata() -> bool connect(flame_task.get(), &EnsureMetadataTask::metadataFailed, [this, &should_try_others](Mod* candidate) { onMetadataFailed(candidate, should_try_others.find(candidate->internal_id()).value(), ModPlatform::ResourceProvider::FLAME); }); + connect(flame_task.get(), &EnsureMetadataTask::failed, + [this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); }); if (flame_task->getHashingTask()) seq.addTask(flame_task->getHashingTask()); @@ -337,12 +341,14 @@ void ModUpdateDialog::onMetadataFailed(Mod* mod, bool try_others, ModPlatform::R auto task = makeShared(mod, index_dir, next(first_choice)); connect(task.get(), &EnsureMetadataTask::metadataReady, [this](Mod* candidate) { onMetadataEnsured(candidate); }); connect(task.get(), &EnsureMetadataTask::metadataFailed, [this](Mod* candidate) { onMetadataFailed(candidate, false); }); + connect(task.get(), &EnsureMetadataTask::failed, + [this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); }); m_second_try_metadata->addTask(task); } else { QString reason{ tr("Couldn't find a valid version on the selected mod provider(s)") }; - m_failed_metadata.append({mod, reason}); + m_failed_metadata.append({ mod, reason }); } } diff --git a/launcher/ui/pages/modplatform/flame/FlamePage.cpp b/launcher/ui/pages/modplatform/flame/FlamePage.cpp index cef26bb6b..133a3981a 100644 --- a/launcher/ui/pages/modplatform/flame/FlamePage.cpp +++ b/launcher/ui/pages/modplatform/flame/FlamePage.cpp @@ -34,6 +34,7 @@ */ #include "FlamePage.h" +#include "ui/dialogs/CustomMessageBox.h" #include "ui_FlamePage.h" #include @@ -42,9 +43,9 @@ #include "FlameModel.h" #include "InstanceImportTask.h" #include "Json.h" +#include "modplatform/flame/FlameAPI.h" #include "ui/dialogs/NewInstanceDialog.h" #include "ui/widgets/ProjectItem.h" -#include "modplatform/flame/FlameAPI.h" static FlameAPI api; @@ -171,6 +172,8 @@ void FlamePage::onSelectionChanged(QModelIndex curr, QModelIndex prev) suggestCurrent(); }); QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { netJob->deleteLater(); }); + connect(netJob, &NetJob::failed, + [this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); }); netJob->start(); } else { for (auto version : current.versions) { @@ -252,10 +255,8 @@ void FlamePage::updateUi() text += "
" + tr(" by ") + authorStrs.join(", "); } - if(current.extraInfoLoaded) { - if (!current.extra.issuesUrl.isEmpty() - || !current.extra.sourceUrl.isEmpty() - || !current.extra.wikiUrl.isEmpty()) { + if (current.extraInfoLoaded) { + if (!current.extra.issuesUrl.isEmpty() || !current.extra.sourceUrl.isEmpty() || !current.extra.wikiUrl.isEmpty()) { text += "

" + tr("External links:") + "
"; } @@ -267,7 +268,6 @@ void FlamePage::updateUi() text += "- " + tr("Source code: %1").arg(current.extra.sourceUrl) + "
"; } - text += "
"; text += api.getModDescription(current.addonId).toUtf8(); diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index c71dd9038..68ce8fd63 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -35,6 +35,7 @@ */ #include "ModrinthPage.h" +#include "ui/dialogs/CustomMessageBox.h" #include "ui_ModrinthPage.h" #include "ModrinthModel.h" @@ -163,6 +164,8 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, QModelIndex prev) suggestCurrent(); }); QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { netJob->deleteLater(); }); + connect(netJob, &NetJob::failed, + [this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); }); netJob->start(); } else updateUI(); @@ -215,6 +218,8 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, QModelIndex prev) suggestCurrent(); }); QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { netJob->deleteLater(); }); + connect(netJob, &NetJob::failed, + [this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); }); netJob->start(); } else { diff --git a/launcher/ui/pages/modplatform/technic/TechnicPage.cpp b/launcher/ui/pages/modplatform/technic/TechnicPage.cpp index fc678fa20..c7f74d5ac 100644 --- a/launcher/ui/pages/modplatform/technic/TechnicPage.cpp +++ b/launcher/ui/pages/modplatform/technic/TechnicPage.cpp @@ -34,6 +34,7 @@ */ #include "TechnicPage.h" +#include "ui/dialogs/CustomMessageBox.h" #include "ui_TechnicPage.h" #include @@ -41,16 +42,15 @@ #include "ui/dialogs/NewInstanceDialog.h" #include "BuildConfig.h" +#include "Json.h" #include "TechnicModel.h" #include "modplatform/technic/SingleZipPackInstallTask.h" #include "modplatform/technic/SolderPackInstallTask.h" -#include "Json.h" #include "Application.h" #include "modplatform/technic/SolderPackManifest.h" -TechnicPage::TechnicPage(NewInstanceDialog* dialog, QWidget *parent) - : QWidget(parent), ui(new Ui::TechnicPage), dialog(dialog) +TechnicPage::TechnicPage(NewInstanceDialog* dialog, QWidget* parent) : QWidget(parent), ui(new Ui::TechnicPage), dialog(dialog) { ui->setupUi(this); connect(ui->searchButton, &QPushButton::clicked, this, &TechnicPage::triggerSearch); @@ -201,6 +201,8 @@ void TechnicPage::suggestCurrent() metadataLoaded(); }); + connect(jobPtr.get(), &NetJob::failed, + [this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); }); jobPtr = netJob; jobPtr->start(); @@ -252,6 +254,8 @@ void TechnicPage::metadataLoaded() netJob->addNetAction(Net::Download::makeByteArray(QUrl(url), response)); QObject::connect(netJob.get(), &NetJob::succeeded, this, &TechnicPage::onSolderLoaded); + connect(jobPtr.get(), &NetJob::failed, + [this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); }); jobPtr = netJob; jobPtr->start(); diff --git a/launcher/ui/widgets/VariableSizedImageObject.cpp b/launcher/ui/widgets/VariableSizedImageObject.cpp index 991b4a047..a787f61e6 100644 --- a/launcher/ui/widgets/VariableSizedImageObject.cpp +++ b/launcher/ui/widgets/VariableSizedImageObject.cpp @@ -101,14 +101,7 @@ void VariableSizedImageObject::loadImage(QTextDocument* doc, const QUrl& source, auto full_entry_path = entry->getFullPath(); auto source_url = source; - connect(job, &NetJob::succeeded, this, [this, doc, full_entry_path, source_url, posInDocument] { - qDebug() << "Loaded resource at" << full_entry_path; - - // If we flushed, don't proceed. - if (!m_fetching_images.contains(source_url)) - return; - - QImage image(full_entry_path); + auto loadImage = [this, doc, full_entry_path, source_url, posInDocument](const QImage& image) { doc->addResource(QTextDocument::ImageResource, source_url, image); parseImage(doc, image, posInDocument); @@ -120,6 +113,23 @@ void VariableSizedImageObject::loadImage(QTextDocument* doc, const QUrl& source, doc->setPageSize(size); m_fetching_images.remove(source_url); + }; + connect(job, &NetJob::succeeded, this, [this, full_entry_path, source_url, loadImage] { + qDebug() << "Loaded resource at:" << full_entry_path; + // If we flushed, don't proceed. + if (!m_fetching_images.contains(source_url)) + return; + + QImage image(full_entry_path); + loadImage(image); + }); + connect(job, &NetJob::failed, this, [this, full_entry_path, source_url, loadImage](QString reason) { + qWarning() << "Failed resource at:" << full_entry_path << " because:" << reason; + // If we flushed, don't proceed. + if (!m_fetching_images.contains(source_url)) + return; + + loadImage(QImage()); }); connect(job, &NetJob::finished, job, &NetJob::deleteLater); From 6cf7c0a647e513978e692f02babd0140d909c3af Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sat, 15 Jul 2023 20:17:16 +0300 Subject: [PATCH 006/223] Connected last fail signals Signed-off-by: Trial97 --- .../mod/tasks/GetModDependenciesTask.cpp | 4 +++- launcher/modplatform/ResourceAPI.h | 3 +++ .../modplatform/helpers/NetworkResourceAPI.cpp | 15 ++++++++++++++- launcher/ui/pages/modplatform/ResourceModel.cpp | 8 ++++++++ 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp b/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp index f8ecdb33e..09fc66f59 100644 --- a/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp +++ b/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp @@ -180,7 +180,9 @@ Task::Ptr GetModDependenciesTask::prepareDependencyTask(const ModPlatform::Depen ResourceAPI::DependencySearchArgs args = { dep, m_version, m_loaderType }; ResourceAPI::DependencySearchCallbacks callbacks; - + callbacks.on_fail = [](QString reason, int) { + qCritical() << tr("A network error occurred. Could not load project dependenies:%1").arg(reason); + }; callbacks.on_succeed = [dep, provider, pDep, level, this](auto& doc, auto& pack) { try { QJsonArray arr; diff --git a/launcher/modplatform/ResourceAPI.h b/launcher/modplatform/ResourceAPI.h index d3277761e..6f92fa108 100644 --- a/launcher/modplatform/ResourceAPI.h +++ b/launcher/modplatform/ResourceAPI.h @@ -99,6 +99,7 @@ class ResourceAPI { }; struct VersionSearchCallbacks { std::function on_succeed; + std::function on_fail; }; struct ProjectInfoArgs { @@ -109,6 +110,7 @@ class ResourceAPI { }; struct ProjectInfoCallbacks { std::function on_succeed; + std::function on_fail; }; struct DependencySearchArgs { @@ -119,6 +121,7 @@ class ResourceAPI { struct DependencySearchCallbacks { std::function on_succeed; + std::function on_fail; }; public: diff --git a/launcher/modplatform/helpers/NetworkResourceAPI.cpp b/launcher/modplatform/helpers/NetworkResourceAPI.cpp index c278f800d..771486005 100644 --- a/launcher/modplatform/helpers/NetworkResourceAPI.cpp +++ b/launcher/modplatform/helpers/NetworkResourceAPI.cpp @@ -70,7 +70,7 @@ Task::Ptr NetworkResourceAPI::getProjectInfo(ProjectInfoArgs&& args, ProjectInfo callbacks.on_succeed(doc, args.pack); }); - + QObject::connect(job.get(), &NetJob::failed, [callbacks](QString reason) { callbacks.on_fail(reason); }); return job; } @@ -99,6 +99,13 @@ Task::Ptr NetworkResourceAPI::getProjectVersions(VersionSearchArgs&& args, Versi callbacks.on_succeed(doc, args.pack); }); + QObject::connect(netJob.get(), &NetJob::failed, [&netJob, callbacks](QString reason) { + int network_error_code = -1; + if (auto* failed_action = netJob->getFailedActions().at(0); failed_action && failed_action->m_reply) + network_error_code = failed_action->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + callbacks.on_fail(reason, network_error_code); + }); return netJob; } @@ -143,6 +150,12 @@ Task::Ptr NetworkResourceAPI::getDependencyVersion(DependencySearchArgs&& args, callbacks.on_succeed(doc, args.dependency); }); + QObject::connect(netJob.get(), &NetJob::failed, [&netJob, callbacks](QString reason) { + int network_error_code = -1; + if (auto* failed_action = netJob->getFailedActions().at(0); failed_action && failed_action->m_reply) + network_error_code = failed_action->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + callbacks.on_fail(reason, network_error_code); + }); return netJob; }; diff --git a/launcher/ui/pages/modplatform/ResourceModel.cpp b/launcher/ui/pages/modplatform/ResourceModel.cpp index 49405a02b..170b016ad 100644 --- a/launcher/ui/pages/modplatform/ResourceModel.cpp +++ b/launcher/ui/pages/modplatform/ResourceModel.cpp @@ -178,6 +178,10 @@ void ResourceModel::loadEntry(QModelIndex& entry) return; versionRequestSucceeded(doc, pack, entry); }; + if (!callbacks.on_fail) + callbacks.on_fail = [](QString reason, int) { + QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load project versions:%1").arg(reason)); + }; if (auto job = m_api->getProjectVersions(std::move(args), std::move(callbacks)); job) runInfoJob(job); @@ -194,6 +198,10 @@ void ResourceModel::loadEntry(QModelIndex& entry) return; infoRequestSucceeded(doc, pack, entry); }; + if (!callbacks.on_fail) + callbacks.on_fail = [](QString reason) { + QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load project info:%1").arg(reason)); + }; if (auto job = m_api->getProjectInfo(std::move(args), std::move(callbacks)); job) runInfoJob(job); From f42514a1a3848f750241661138b89fdead1a3370 Mon Sep 17 00:00:00 2001 From: Alexandru Ionut Tripon Date: Sun, 16 Jul 2023 00:38:39 +0300 Subject: [PATCH 007/223] Update launcher/tasks/ConcurrentTask.cpp Co-authored-by: seth Signed-off-by: Alexandru Ionut Tripon --- launcher/tasks/ConcurrentTask.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/launcher/tasks/ConcurrentTask.cpp b/launcher/tasks/ConcurrentTask.cpp index 7bb02e57d..b8d6ae598 100644 --- a/launcher/tasks/ConcurrentTask.cpp +++ b/launcher/tasks/ConcurrentTask.cpp @@ -134,8 +134,7 @@ void ConcurrentTask::startNext() connect(next.get(), &Task::succeeded, this, [this, next]() { subTaskSucceeded(next); }); connect(next.get(), &Task::failed, this, [this, next](QString msg) { subTaskFailed(next, msg); }); - // this should never happen but if it does better to fail the task that being stuck - // most + // this should never happen but if it does, it's better to fail the task than get stuck connect(next.get(), &Task::aborted, this, [this, next] { subTaskFailed(next, "Aborted"); }); connect(next.get(), &Task::status, this, [this, next](QString msg) { subTaskStatus(next, msg); }); From 748a644e2cf173540a60b7fc5815c89f02382cfd Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 15 Aug 2023 18:50:32 +0300 Subject: [PATCH 008/223] added wait profiler Signed-off-by: Trial97 --- launcher/Application.cpp | 2 ++ launcher/CMakeLists.txt | 2 ++ launcher/tools/WaitProfiler.cpp | 44 +++++++++++++++++++++++++++++++++ launcher/tools/WaitProfiler.h | 29 ++++++++++++++++++++++ 4 files changed, 77 insertions(+) create mode 100644 launcher/tools/WaitProfiler.cpp create mode 100644 launcher/tools/WaitProfiler.h diff --git a/launcher/Application.cpp b/launcher/Application.cpp index a13935101..a546d0a85 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -49,6 +49,7 @@ #include "pathmatcher/MultiMatcher.h" #include "pathmatcher/SimplePrefixMatcher.h" #include "settings/INIFile.h" +#include "tools/WaitProfiler.h" #include "ui/InstanceWindow.h" #include "ui/MainWindow.h" @@ -816,6 +817,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) // FIXME: what to do with these? m_profilers.insert("jprofiler", std::shared_ptr(new JProfilerFactory())); m_profilers.insert("jvisualvm", std::shared_ptr(new JVisualVMFactory())); + m_profilers.insert("waitprofiler", std::shared_ptr(new WaitProfilerFactory())); for (auto profiler : m_profilers.values()) { profiler->registerSettings(m_settings); } diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 18e0acab1..28359a4b1 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -457,6 +457,8 @@ set(TOOLS_SOURCES tools/JVisualVM.h tools/MCEditTool.cpp tools/MCEditTool.h + tools/WaitProfiler.cpp + tools/WaitProfiler.h ) set(META_SOURCES diff --git a/launcher/tools/WaitProfiler.cpp b/launcher/tools/WaitProfiler.cpp new file mode 100644 index 000000000..c43af0a89 --- /dev/null +++ b/launcher/tools/WaitProfiler.cpp @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2023 Trial97 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "WaitProfiler.h" + +#include "BaseInstance.h" +#include "launch/LaunchTask.h" +#include "settings/SettingsObject.h" + +class WaitProfiler : public BaseProfiler { + Q_OBJECT + public: + WaitProfiler(SettingsObjectPtr settings, InstancePtr instance, QObject* parent = 0); + + protected: + void beginProfilingImpl(shared_qobject_ptr process); +}; + +WaitProfiler::WaitProfiler(SettingsObjectPtr settings, InstancePtr instance, QObject* parent) : BaseProfiler(settings, instance, parent) {} + +void WaitProfiler::beginProfilingImpl(shared_qobject_ptr process) +{ + emit readyToLaunch(tr("Started process: %1").arg(process->pid())); +} + +BaseExternalTool* WaitProfilerFactory::createTool(InstancePtr instance, QObject* parent) +{ + return new WaitProfiler(globalSettings, instance, parent); +} +#include "WaitProfiler.moc" \ No newline at end of file diff --git a/launcher/tools/WaitProfiler.h b/launcher/tools/WaitProfiler.h new file mode 100644 index 000000000..ff2b9c2bf --- /dev/null +++ b/launcher/tools/WaitProfiler.h @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2023 Trial97 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include "BaseProfiler.h" + +class WaitProfilerFactory : public BaseProfilerFactory { + public: + QString name() const override { return "WaitProfiler"; } + void registerSettings(SettingsObjectPtr settings) override{}; + BaseExternalTool* createTool(InstancePtr instance, QObject* parent = 0) override; + bool check(QString* error) override { return true; }; + bool check(const QString& path, QString* error) override { return true; }; +}; From c28d9161cfc52aa21f1217d36032eb4e174b215c Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 15 Aug 2023 18:54:22 +0300 Subject: [PATCH 009/223] added unused Signed-off-by: Trial97 --- launcher/tools/WaitProfiler.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/launcher/tools/WaitProfiler.h b/launcher/tools/WaitProfiler.h index ff2b9c2bf..fe813402c 100644 --- a/launcher/tools/WaitProfiler.h +++ b/launcher/tools/WaitProfiler.h @@ -22,8 +22,8 @@ class WaitProfilerFactory : public BaseProfilerFactory { public: QString name() const override { return "WaitProfiler"; } - void registerSettings(SettingsObjectPtr settings) override{}; + void registerSettings([[maybe_unused]] SettingsObjectPtr settings) override{}; BaseExternalTool* createTool(InstancePtr instance, QObject* parent = 0) override; - bool check(QString* error) override { return true; }; - bool check(const QString& path, QString* error) override { return true; }; + bool check([[maybe_unused]] QString* error) override { return true; }; + bool check([[maybe_unused]] const QString& path, [[maybe_unused]] QString* error) override { return true; }; }; From fa164aa0813687eed862fbd781aab47288d9bb8f Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 15 Aug 2023 22:18:28 +0300 Subject: [PATCH 010/223] rename to GenericProfiler Signed-off-by: Trial97 --- launcher/Application.cpp | 4 ++-- launcher/CMakeLists.txt | 4 ++-- .../{WaitProfiler.cpp => GenericProfiler.cpp} | 18 ++++++++++-------- .../{WaitProfiler.h => GenericProfiler.h} | 4 ++-- 4 files changed, 16 insertions(+), 14 deletions(-) rename launcher/tools/{WaitProfiler.cpp => GenericProfiler.cpp} (63%) rename launcher/tools/{WaitProfiler.h => GenericProfiler.h} (90%) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index a546d0a85..7f03b4d10 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -49,7 +49,7 @@ #include "pathmatcher/MultiMatcher.h" #include "pathmatcher/SimplePrefixMatcher.h" #include "settings/INIFile.h" -#include "tools/WaitProfiler.h" +#include "tools/GenericProfiler.h" #include "ui/InstanceWindow.h" #include "ui/MainWindow.h" @@ -817,7 +817,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) // FIXME: what to do with these? m_profilers.insert("jprofiler", std::shared_ptr(new JProfilerFactory())); m_profilers.insert("jvisualvm", std::shared_ptr(new JVisualVMFactory())); - m_profilers.insert("waitprofiler", std::shared_ptr(new WaitProfilerFactory())); + m_profilers.insert("generic", std::shared_ptr(new GenericProfilerFactory())); for (auto profiler : m_profilers.values()) { profiler->registerSettings(m_settings); } diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 28359a4b1..a14f279e7 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -457,8 +457,8 @@ set(TOOLS_SOURCES tools/JVisualVM.h tools/MCEditTool.cpp tools/MCEditTool.h - tools/WaitProfiler.cpp - tools/WaitProfiler.h + tools/GenericProfiler.cpp + tools/GenericProfiler.h ) set(META_SOURCES diff --git a/launcher/tools/WaitProfiler.cpp b/launcher/tools/GenericProfiler.cpp similarity index 63% rename from launcher/tools/WaitProfiler.cpp rename to launcher/tools/GenericProfiler.cpp index c43af0a89..594024a7d 100644 --- a/launcher/tools/WaitProfiler.cpp +++ b/launcher/tools/GenericProfiler.cpp @@ -15,30 +15,32 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include "WaitProfiler.h" +#include "GenericProfiler.h" #include "BaseInstance.h" #include "launch/LaunchTask.h" #include "settings/SettingsObject.h" -class WaitProfiler : public BaseProfiler { +class GenericProfiler : public BaseProfiler { Q_OBJECT public: - WaitProfiler(SettingsObjectPtr settings, InstancePtr instance, QObject* parent = 0); + GenericProfiler(SettingsObjectPtr settings, InstancePtr instance, QObject* parent = 0); protected: void beginProfilingImpl(shared_qobject_ptr process); }; -WaitProfiler::WaitProfiler(SettingsObjectPtr settings, InstancePtr instance, QObject* parent) : BaseProfiler(settings, instance, parent) {} +GenericProfiler::GenericProfiler(SettingsObjectPtr settings, InstancePtr instance, QObject* parent) + : BaseProfiler(settings, instance, parent) +{} -void WaitProfiler::beginProfilingImpl(shared_qobject_ptr process) +void GenericProfiler::beginProfilingImpl(shared_qobject_ptr process) { emit readyToLaunch(tr("Started process: %1").arg(process->pid())); } -BaseExternalTool* WaitProfilerFactory::createTool(InstancePtr instance, QObject* parent) +BaseExternalTool* GenericProfilerFactory::createTool(InstancePtr instance, QObject* parent) { - return new WaitProfiler(globalSettings, instance, parent); + return new GenericProfiler(globalSettings, instance, parent); } -#include "WaitProfiler.moc" \ No newline at end of file +#include "GenericProfiler.moc" \ No newline at end of file diff --git a/launcher/tools/WaitProfiler.h b/launcher/tools/GenericProfiler.h similarity index 90% rename from launcher/tools/WaitProfiler.h rename to launcher/tools/GenericProfiler.h index fe813402c..e99fc059f 100644 --- a/launcher/tools/WaitProfiler.h +++ b/launcher/tools/GenericProfiler.h @@ -19,9 +19,9 @@ #include "BaseProfiler.h" -class WaitProfilerFactory : public BaseProfilerFactory { +class GenericProfilerFactory : public BaseProfilerFactory { public: - QString name() const override { return "WaitProfiler"; } + QString name() const override { return "Generic"; } void registerSettings([[maybe_unused]] SettingsObjectPtr settings) override{}; BaseExternalTool* createTool(InstancePtr instance, QObject* parent = 0) override; bool check([[maybe_unused]] QString* error) override { return true; }; From 8fbc665acb83e47fed1ffd0ae5c9aa1f59fd49bd Mon Sep 17 00:00:00 2001 From: Trial97 Date: Wed, 16 Aug 2023 18:28:46 +0300 Subject: [PATCH 011/223] Added UserData as another posible path for portable builds Signed-off-by: Trial97 --- launcher/Application.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index a13935101..6237967fb 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -263,7 +263,11 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) adjustedBy = "Persistent data path"; #ifndef Q_OS_MACOS - if (QFile::exists(FS::PathCombine(m_rootPath, "portable.txt"))) { + if (auto portableUserData = FS::PathCombine(m_rootPath, "UserData"); QDir(portableUserData).exists()) { + dataPath = portableUserData; + adjustedBy = "Portable user data path"; + m_portable = true; + } else if (QFile::exists(FS::PathCombine(m_rootPath, "portable.txt"))) { dataPath = m_rootPath; adjustedBy = "Portable data path"; m_portable = true; From 47dbb0911509804d8df795d2db0581ab73955e87 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sat, 7 Oct 2023 00:21:40 +0300 Subject: [PATCH 012/223] Improvements to concurrent task Signed-off-by: Trial97 --- launcher/tasks/ConcurrentTask.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/launcher/tasks/ConcurrentTask.cpp b/launcher/tasks/ConcurrentTask.cpp index 6cfd864cc..2ab69d04f 100644 --- a/launcher/tasks/ConcurrentTask.cpp +++ b/launcher/tasks/ConcurrentTask.cpp @@ -152,8 +152,12 @@ void ConcurrentTask::startNext() QMetaObject::invokeMethod(next.get(), &Task::start, Qt::QueuedConnection); // Allow going up the number of concurrent tasks in case of tasks being added in the middle of a running task. - for (int i = 0; i < num_starts; i++) + for (int i = 0; i < num_starts; i++) { + QCoreApplication::processEvents(); + if (m_aborted || m_doing.count() > m_total_max_size) + return; QMetaObject::invokeMethod(this, &ConcurrentTask::startNext, Qt::QueuedConnection); + } } void ConcurrentTask::subTaskSucceeded(Task::Ptr task) From 8dd640819dd961d1195f515713e0d8938763da54 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Mon, 9 Oct 2023 01:50:14 +0300 Subject: [PATCH 013/223] removed processEvents from ConcurrentTask Signed-off-by: Trial97 --- launcher/net/NetJob.cpp | 18 +++-- launcher/net/NetJob.h | 5 +- launcher/tasks/ConcurrentTask.cpp | 96 ++++++++++++-------------- launcher/tasks/ConcurrentTask.h | 9 +-- launcher/tasks/MultipleOptionsTask.cpp | 11 ++- launcher/tasks/MultipleOptionsTask.h | 6 +- launcher/tasks/SequentialTask.cpp | 13 ++-- launcher/tasks/SequentialTask.h | 4 +- tests/Task_test.cpp | 9 ++- 9 files changed, 84 insertions(+), 87 deletions(-) diff --git a/launcher/net/NetJob.cpp b/launcher/net/NetJob.cpp index b99c5acb0..52f6f1517 100644 --- a/launcher/net/NetJob.cpp +++ b/launcher/net/NetJob.cpp @@ -37,6 +37,7 @@ #include "NetJob.h" #include "Application.h" +#include "tasks/ConcurrentTask.h" NetJob::NetJob(QString job_name, shared_qobject_ptr network) : ConcurrentTask(nullptr, job_name, APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt()), m_network(network) @@ -51,18 +52,15 @@ auto NetJob::addNetAction(NetAction::Ptr action) -> bool return true; } -void NetJob::startNext() +void NetJob::executeNextSubTask() { - if (m_queue.isEmpty() && m_doing.isEmpty()) { - // We're finished, check for failures and retry if we can (up to 3 times) - if (!m_failed.isEmpty() && m_try < 3) { - m_try += 1; - while (!m_failed.isEmpty()) - m_queue.enqueue(m_failed.take(*m_failed.keyBegin())); - } + // We're finished, check for failures and retry if we can (up to 3 times) + if (isRunning() && m_queue.isEmpty() && m_doing.isEmpty() && !m_failed.isEmpty() && m_try < 3) { + m_try += 1; + while (!m_failed.isEmpty()) + m_queue.enqueue(m_failed.take(*m_failed.keyBegin())); } - - ConcurrentTask::startNext(); + ConcurrentTask::executeNextSubTask(); } auto NetJob::size() const -> int diff --git a/launcher/net/NetJob.h b/launcher/net/NetJob.h index 1c4337ec6..f6c005809 100644 --- a/launcher/net/NetJob.h +++ b/launcher/net/NetJob.h @@ -55,8 +55,6 @@ class NetJob : public ConcurrentTask { explicit NetJob(QString job_name, shared_qobject_ptr network); ~NetJob() override = default; - void startNext() override; - auto size() const -> int; auto canAbort() const -> bool override; @@ -69,6 +67,9 @@ class NetJob : public ConcurrentTask { // Qt can't handle auto at the start for some reason? bool abort() override; + protected slots: + void executeNextSubTask() override; + protected: void updateState() override; diff --git a/launcher/tasks/ConcurrentTask.cpp b/launcher/tasks/ConcurrentTask.cpp index 2ab69d04f..97406d58f 100644 --- a/launcher/tasks/ConcurrentTask.cpp +++ b/launcher/tasks/ConcurrentTask.cpp @@ -35,7 +35,6 @@ */ #include "ConcurrentTask.h" -#include #include #include "tasks/Task.h" @@ -51,6 +50,10 @@ ConcurrentTask::~ConcurrentTask() if (task) task->deleteLater(); } + for (auto task : m_done) { + if (task) + task->deleteLater(); + } } auto ConcurrentTask::getStepProgress() const -> TaskStepProgressList @@ -65,15 +68,13 @@ void ConcurrentTask::addTask(Task::Ptr task) void ConcurrentTask::executeTask() { - // Start one task, startNext handles starting the up to the m_total_max_size - // while tracking the number currently being done - QMetaObject::invokeMethod(this, &ConcurrentTask::startNext, Qt::QueuedConnection); + for (auto i = 0; i <= m_total_max_size; i++) + executeNextSubTask(); } bool ConcurrentTask::abort() { m_queue.clear(); - m_aborted = true; if (m_doing.isEmpty()) { // Don't call emitAborted() here, we want to bypass the 'is the task running' check @@ -108,27 +109,33 @@ void ConcurrentTask::clear() m_failed.clear(); m_queue.clear(); - m_aborted = false; - m_progress = 0; m_stepProgress = 0; } -void ConcurrentTask::startNext() +void ConcurrentTask::executeNextSubTask() { - if (m_aborted || m_doing.count() > m_total_max_size) + if (!isRunning()) { return; - - if (m_queue.isEmpty() && m_doing.isEmpty() && !wasSuccessful()) { - emitSucceeded(); + } + if (m_queue.isEmpty()) { + if (m_doing.isEmpty()) { + // if (m_failed.isEmpty()) + emitSucceeded(); + // else + // emitFailed(tr("One or more subtasks failed")); + } + return; + } + if (m_doing.count() > m_total_max_size) { return; } - if (m_queue.isEmpty()) - return; - - Task::Ptr next = m_queue.dequeue(); + startSubTask(m_queue.dequeue()); +} +void ConcurrentTask::startSubTask(Task::Ptr next) +{ connect(next.get(), &Task::succeeded, this, [this, next]() { subTaskSucceeded(next); }); connect(next.get(), &Task::failed, this, [this, next](QString msg) { subTaskFailed(next, msg); }); connect(next.get(), &Task::aborted, this, [this, next] { subTaskFailed(next, "Aborted"); }); @@ -140,59 +147,42 @@ void ConcurrentTask::startNext() connect(next.get(), &Task::progress, this, [this, next](qint64 current, qint64 total) { subTaskProgress(next, current, total); }); m_doing.insert(next.get(), next); - qsizetype num_starts = qMin(m_queue.size(), m_total_max_size - m_doing.size()); + auto task_progress = std::make_shared(next->getUid()); m_task_progress.insert(next->getUid(), task_progress); updateState(); updateStepProgress(*task_progress.get(), Operation::ADDED); - QCoreApplication::processEvents(); - QMetaObject::invokeMethod(next.get(), &Task::start, Qt::QueuedConnection); +} - // Allow going up the number of concurrent tasks in case of tasks being added in the middle of a running task. - for (int i = 0; i < num_starts; i++) { - QCoreApplication::processEvents(); - if (m_aborted || m_doing.count() > m_total_max_size) - return; - QMetaObject::invokeMethod(this, &ConcurrentTask::startNext, Qt::QueuedConnection); - } +void ConcurrentTask::subTaskFinished(Task::Ptr task, TaskStepState state) +{ + m_done.insert(task.get(), task); + (state == TaskStepState::Succeeded ? m_succeeded : m_failed).insert(task.get(), task); + + m_doing.remove(task.get()); + + auto task_progress = m_task_progress.value(task->getUid()); + task_progress->state = state; + + disconnect(task.get(), 0, this, 0); + + emit stepProgress(*task_progress); + updateState(); + updateStepProgress(*task_progress, Operation::REMOVED); + QMetaObject::invokeMethod(this, &ConcurrentTask::executeNextSubTask, Qt::QueuedConnection); } void ConcurrentTask::subTaskSucceeded(Task::Ptr task) { - m_done.insert(task.get(), task); - m_succeeded.insert(task.get(), task); - - m_doing.remove(task.get()); - auto task_progress = m_task_progress.value(task->getUid()); - task_progress->state = TaskStepState::Succeeded; - - disconnect(task.get(), 0, this, 0); - - emit stepProgress(*task_progress); - updateState(); - updateStepProgress(*task_progress, Operation::REMOVED); - startNext(); + subTaskFinished(task, TaskStepState::Succeeded); } void ConcurrentTask::subTaskFailed(Task::Ptr task, [[maybe_unused]] const QString& msg) { - m_done.insert(task.get(), task); - m_failed.insert(task.get(), task); - - m_doing.remove(task.get()); - - auto task_progress = m_task_progress.value(task->getUid()); - task_progress->state = TaskStepState::Failed; - - disconnect(task.get(), 0, this, 0); - - emit stepProgress(*task_progress); - updateState(); - updateStepProgress(*task_progress, Operation::REMOVED); - startNext(); + subTaskFinished(task, TaskStepState::Failed); } void ConcurrentTask::subTaskStatus(Task::Ptr task, const QString& msg) diff --git a/launcher/tasks/ConcurrentTask.h b/launcher/tasks/ConcurrentTask.h index 00b1d48d6..07ea58575 100644 --- a/launcher/tasks/ConcurrentTask.h +++ b/launcher/tasks/ConcurrentTask.h @@ -72,10 +72,11 @@ class ConcurrentTask : public Task { protected slots: void executeTask() override; - virtual void startNext(); + virtual void executeNextSubTask(); void subTaskSucceeded(Task::Ptr); - void subTaskFailed(Task::Ptr, const QString& msg); + virtual void subTaskFailed(Task::Ptr, const QString& msg); + void subTaskFinished(Task::Ptr, TaskStepState); void subTaskStatus(Task::Ptr task, const QString& msg); void subTaskDetails(Task::Ptr task, const QString& msg); void subTaskProgress(Task::Ptr task, qint64 current, qint64 total); @@ -90,6 +91,8 @@ class ConcurrentTask : public Task { virtual void updateState(); + void startSubTask(Task::Ptr task); + protected: QString m_name; QString m_step_status; @@ -107,6 +110,4 @@ class ConcurrentTask : public Task { qint64 m_stepProgress = 0; qint64 m_stepTotalProgress = 100; - - bool m_aborted = false; }; diff --git a/launcher/tasks/MultipleOptionsTask.cpp b/launcher/tasks/MultipleOptionsTask.cpp index 89187a26d..b95fc3d5e 100644 --- a/launcher/tasks/MultipleOptionsTask.cpp +++ b/launcher/tasks/MultipleOptionsTask.cpp @@ -34,11 +34,12 @@ */ #include "MultipleOptionsTask.h" +#include #include -MultipleOptionsTask::MultipleOptionsTask(QObject* parent, const QString& task_name) : SequentialTask(parent, task_name) {} +MultipleOptionsTask::MultipleOptionsTask(QObject* parent, const QString& task_name) : ConcurrentTask(parent, task_name, 1) {} -void MultipleOptionsTask::startNext() +void MultipleOptionsTask::executeNextSubTask() { if (m_done.size() != m_failed.size()) { emitSucceeded(); @@ -51,7 +52,11 @@ void MultipleOptionsTask::startNext() return; } - ConcurrentTask::startNext(); + ConcurrentTask::executeNextSubTask(); + // not sure why this is needed here but tests fail without it + // as the MultipleOptionsTask is yet to be used not sure if + // it works correcly + QCoreApplication::processEvents(); } void MultipleOptionsTask::updateState() diff --git a/launcher/tasks/MultipleOptionsTask.h b/launcher/tasks/MultipleOptionsTask.h index a344343ef..9a88a9999 100644 --- a/launcher/tasks/MultipleOptionsTask.h +++ b/launcher/tasks/MultipleOptionsTask.h @@ -34,18 +34,18 @@ */ #pragma once -#include "SequentialTask.h" +#include "ConcurrentTask.h" /* This task type will attempt to do run each of it's subtasks in sequence, * until one of them succeeds. When that happens, the remaining tasks will not run. * */ -class MultipleOptionsTask : public SequentialTask { +class MultipleOptionsTask : public ConcurrentTask { Q_OBJECT public: explicit MultipleOptionsTask(QObject* parent = nullptr, const QString& task_name = ""); ~MultipleOptionsTask() override = default; private slots: - void startNext() override; + void executeNextSubTask() override; void updateState() override; }; diff --git a/launcher/tasks/SequentialTask.cpp b/launcher/tasks/SequentialTask.cpp index abf7536b9..180430c8c 100644 --- a/launcher/tasks/SequentialTask.cpp +++ b/launcher/tasks/SequentialTask.cpp @@ -36,18 +36,15 @@ #include "SequentialTask.h" #include +#include "tasks/ConcurrentTask.h" SequentialTask::SequentialTask(QObject* parent, QString task_name) : ConcurrentTask(parent, task_name, 1) {} -void SequentialTask::startNext() +void SequentialTask::subTaskFailed(Task::Ptr task, const QString& msg) { - if (m_failed.size() > 0) { - emitFailed(tr("One of the tasks failed!")); - qWarning() << m_failed.constBegin()->get()->failReason(); - return; - } - - ConcurrentTask::startNext(); + emitFailed(msg); + qWarning() << m_failed.constBegin()->get()->failReason(); + ConcurrentTask::subTaskFailed(task, msg); } void SequentialTask::updateState() diff --git a/launcher/tasks/SequentialTask.h b/launcher/tasks/SequentialTask.h index cec3b2be8..a7c101ab4 100644 --- a/launcher/tasks/SequentialTask.h +++ b/launcher/tasks/SequentialTask.h @@ -50,7 +50,9 @@ class SequentialTask : public ConcurrentTask { explicit SequentialTask(QObject* parent = nullptr, QString task_name = ""); ~SequentialTask() override = default; + protected slots: + virtual void subTaskFailed(Task::Ptr, const QString& msg) override; + protected: - void startNext() override; void updateState() override; }; diff --git a/tests/Task_test.cpp b/tests/Task_test.cpp index abc9be905..0740ba0a3 100644 --- a/tests/Task_test.cpp +++ b/tests/Task_test.cpp @@ -37,13 +37,13 @@ class BasicTask_MultiStep : public Task { class BigConcurrentTask : public ConcurrentTask { Q_OBJECT - void startNext() override + void executeNextSubTask() override { // This is here only to help fill the stack a bit more quickly (if there's an issue, of course :^)) // Each tasks thus adds 1024 * 4 bytes to the stack, at the very least. [[maybe_unused]] volatile std::array some_data_on_the_stack{}; - ConcurrentTask::startNext(); + ConcurrentTask::executeNextSubTask(); } }; @@ -71,11 +71,14 @@ class BigConcurrentTaskThread : public QThread { quit(); }); - m_deadline.start(); + if (thread() != QThread::currentThread()) { + QMetaObject::invokeMethod(this, &BigConcurrentTaskThread::start_timer, Qt::QueuedConnection); + } big_task.run(); exec(); } + void start_timer() { m_deadline.start(); } public: bool passed_the_deadline = false; From b075711be08b4d3e3badb1def5b0f4d24e0ad51a Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 15 Oct 2023 16:03:14 +0300 Subject: [PATCH 014/223] ensured totalTimePlayed is allways greater than 0 Signed-off-by: Trial97 --- launcher/BaseInstance.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/launcher/BaseInstance.cpp b/launcher/BaseInstance.cpp index 725036395..66b44b229 100644 --- a/launcher/BaseInstance.cpp +++ b/launcher/BaseInstance.cpp @@ -278,6 +278,8 @@ void BaseInstance::setRunning(bool running) QDateTime timeEnded = QDateTime::currentDateTime(); qint64 current = settings()->get("totalTimePlayed").toLongLong(); + if (current < 0) + current = 0; settings()->set("totalTimePlayed", current + m_timeStarted.secsTo(timeEnded)); settings()->set("lastTimePlayed", m_timeStarted.secsTo(timeEnded)); @@ -290,6 +292,8 @@ void BaseInstance::setRunning(bool running) int64_t BaseInstance::totalTimePlayed() const { qint64 current = m_settings->get("totalTimePlayed").toLongLong(); + if (current < 0) + current = 0; if (m_isRunning) { QDateTime timeNow = QDateTime::currentDateTime(); return current + m_timeStarted.secsTo(timeNow); From 52c94eb568a22e95e7696af0a1177b1b3bf54aec Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 15 Oct 2023 16:24:23 +0300 Subject: [PATCH 015/223] reset the setting if is under 0 Signed-off-by: Trial97 --- launcher/BaseInstance.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/launcher/BaseInstance.cpp b/launcher/BaseInstance.cpp index 66b44b229..d0b0ad3bc 100644 --- a/launcher/BaseInstance.cpp +++ b/launcher/BaseInstance.cpp @@ -64,6 +64,8 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s m_settings->registerSetting("lastLaunchTime", 0); m_settings->registerSetting("totalTimePlayed", 0); + if (m_settings->get("totalTimePlayed").toLongLong() < 0) + m_settings->set("totalTimePlayed", 0); m_settings->registerSetting("lastTimePlayed", 0); m_settings->registerSetting("linkedInstances", "[]"); @@ -278,8 +280,6 @@ void BaseInstance::setRunning(bool running) QDateTime timeEnded = QDateTime::currentDateTime(); qint64 current = settings()->get("totalTimePlayed").toLongLong(); - if (current < 0) - current = 0; settings()->set("totalTimePlayed", current + m_timeStarted.secsTo(timeEnded)); settings()->set("lastTimePlayed", m_timeStarted.secsTo(timeEnded)); @@ -292,8 +292,6 @@ void BaseInstance::setRunning(bool running) int64_t BaseInstance::totalTimePlayed() const { qint64 current = m_settings->get("totalTimePlayed").toLongLong(); - if (current < 0) - current = 0; if (m_isRunning) { QDateTime timeNow = QDateTime::currentDateTime(); return current + m_timeStarted.secsTo(timeNow); From 03a27d5b5a43116bafbd08aa8a2f5b7a592710b8 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 19 Oct 2023 19:47:48 +0300 Subject: [PATCH 016/223] Updated Managed Packs Signed-off-by: Trial97 --- .../flame/FlameInstanceCreationTask.cpp | 3 +++ .../modrinth/ModrinthInstanceCreationTask.cpp | 5 +++- .../ui/pages/instance/ManagedPackPage.cpp | 23 +++++++++++++++++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp index 2a26ce944..c8df8b627 100644 --- a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp +++ b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp @@ -427,6 +427,9 @@ bool FlameCreationTask::createInstance() // Don't add managed info to packs without an ID (most likely imported from ZIP) if (!m_managed_id.isEmpty()) instance.setManagedPack("flame", m_managed_id, m_pack.name, m_managed_version_id, m_pack.version); + else + instance.setManagedPack("flame", "", name(), "", ""); + instance.setName(name()); m_mod_id_resolver.reset(new Flame::FileResolvingTask(APPLICATION->network(), m_pack)); diff --git a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp index e732ad39c..96d9c84d2 100644 --- a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp +++ b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp @@ -226,6 +226,9 @@ bool ModrinthCreationTask::createInstance() // Don't add managed info to packs without an ID (most likely imported from ZIP) if (!m_managed_id.isEmpty()) instance.setManagedPack("modrinth", m_managed_id, m_managed_name, m_managed_version_id, version()); + else + instance.setManagedPack("modrinth", "", name(), "", ""); + instance.setName(name()); instance.saveNow(); @@ -289,7 +292,7 @@ bool ModrinthCreationTask::createInstance() // Only change the name if it didn't use a custom name, so that the previous custom name // is preserved, but if we're using the original one, we update the version string. // NOTE: This needs to come before the copyManagedPack call! - if (inst->name().contains(inst->getManagedPackVersionName())) { + if (inst->name().contains(inst->getManagedPackVersionName()) && inst->name() != instance.name()) { if (askForChangingInstanceName(m_parent, inst->name(), instance.name()) == InstanceNameChange::ShouldChange) inst->setName(instance.name()); } diff --git a/launcher/ui/pages/instance/ManagedPackPage.cpp b/launcher/ui/pages/instance/ManagedPackPage.cpp index 26a8302db..c419066a0 100644 --- a/launcher/ui/pages/instance/ManagedPackPage.cpp +++ b/launcher/ui/pages/instance/ManagedPackPage.cpp @@ -131,6 +131,22 @@ ManagedPackPage::~ManagedPackPage() void ManagedPackPage::openedImpl() { + if (m_inst->getManagedPackID().isEmpty()) { + ui->packVersion->hide(); + ui->packVersionLabel->hide(); + ui->packOrigin->hide(); + ui->packOriginLabel->hide(); + ui->versionsComboBox->hide(); + ui->updateButton->hide(); + ui->updateToVersionLabel->hide(); + ui->updateFromFileButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + + ui->packName->setText(m_inst->name()); + ui->changelogTextBrowser->setText(tr("This is a local modpack.\n" + "This can be updated only using a file in %1 format\n") + .arg(displayName())); + return; + } ui->packName->setText(m_inst->getManagedPackName()); ui->packVersion->setText(m_inst->getManagedPackVersionName()); ui->packOrigin->setText(tr("Website: %2 | Pack ID: %3 | Version ID: %4") @@ -355,6 +371,8 @@ void ModrinthManagedPackPage::update() void ModrinthManagedPackPage::updateFromFile() { auto output = QFileDialog::getOpenFileUrl(this, tr("Choose update file"), QDir::homePath(), "Modrinth pack (*.mrpack *.zip)"); + if (output.isEmpty()) + return; QMap extra_info; extra_info.insert("pack_id", m_inst->getManagedPackID()); extra_info.insert("pack_version_id", QString()); @@ -471,8 +489,7 @@ void FlameManagedPackPage::parseManagedPack() QString FlameManagedPackPage::url() const { - // FIXME: We should display the websiteUrl field, but this requires doing the API request first :( - return {}; + return "https://www.curseforge.com/projects/" + m_inst->getManagedPackID(); } void FlameManagedPackPage::suggestVersion() @@ -519,6 +536,8 @@ void FlameManagedPackPage::update() void FlameManagedPackPage::updateFromFile() { auto output = QFileDialog::getOpenFileUrl(this, tr("Choose update file"), QDir::homePath(), "CurseForge pack (*.zip)"); + if (output.isEmpty()) + return; QMap extra_info; extra_info.insert("pack_id", m_inst->getManagedPackID()); From 1ac9757a86884d3c8299b8bf3749a82c9e7339ff Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 19 Oct 2023 21:51:51 +0300 Subject: [PATCH 017/223] Added back the processEvents Signed-off-by: Trial97 --- launcher/tasks/ConcurrentTask.cpp | 3 +++ launcher/tasks/MultipleOptionsTask.cpp | 5 ----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/launcher/tasks/ConcurrentTask.cpp b/launcher/tasks/ConcurrentTask.cpp index 77d9ab29d..0183b5124 100644 --- a/launcher/tasks/ConcurrentTask.cpp +++ b/launcher/tasks/ConcurrentTask.cpp @@ -35,6 +35,7 @@ */ #include "ConcurrentTask.h" +#include #include #include "tasks/Task.h" @@ -132,6 +133,8 @@ void ConcurrentTask::executeNextSubTask() } startSubTask(m_queue.dequeue()); + + QCoreApplication::processEvents(); } void ConcurrentTask::startSubTask(Task::Ptr next) diff --git a/launcher/tasks/MultipleOptionsTask.cpp b/launcher/tasks/MultipleOptionsTask.cpp index b95fc3d5e..5afe03964 100644 --- a/launcher/tasks/MultipleOptionsTask.cpp +++ b/launcher/tasks/MultipleOptionsTask.cpp @@ -34,7 +34,6 @@ */ #include "MultipleOptionsTask.h" -#include #include MultipleOptionsTask::MultipleOptionsTask(QObject* parent, const QString& task_name) : ConcurrentTask(parent, task_name, 1) {} @@ -53,10 +52,6 @@ void MultipleOptionsTask::executeNextSubTask() } ConcurrentTask::executeNextSubTask(); - // not sure why this is needed here but tests fail without it - // as the MultipleOptionsTask is yet to be used not sure if - // it works correcly - QCoreApplication::processEvents(); } void MultipleOptionsTask::updateState() From 35a8ab2393e132481e7e0ee2a2eca338918d17f6 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 20 Oct 2023 10:32:45 +0300 Subject: [PATCH 018/223] Removed processEvents Signed-off-by: Trial97 --- launcher/tasks/ConcurrentTask.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/launcher/tasks/ConcurrentTask.cpp b/launcher/tasks/ConcurrentTask.cpp index 0183b5124..92b13cfa8 100644 --- a/launcher/tasks/ConcurrentTask.cpp +++ b/launcher/tasks/ConcurrentTask.cpp @@ -35,7 +35,6 @@ */ #include "ConcurrentTask.h" -#include #include #include "tasks/Task.h" @@ -69,7 +68,7 @@ void ConcurrentTask::addTask(Task::Ptr task) void ConcurrentTask::executeTask() { - for (auto i = 0; i <= m_total_max_size; i++) + for (auto i = 0; i < m_total_max_size; i++) executeNextSubTask(); } @@ -133,8 +132,6 @@ void ConcurrentTask::executeNextSubTask() } startSubTask(m_queue.dequeue()); - - QCoreApplication::processEvents(); } void ConcurrentTask::startSubTask(Task::Ptr next) From db4a7ce23951019005ecc8111d1c007087a02053 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Fri, 20 Oct 2023 13:11:17 +0100 Subject: [PATCH 019/223] Fix code style Signed-off-by: TheKodeToad --- .../org/prismlauncher/launcher/impl/StandardLauncher.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/launcher/org/prismlauncher/launcher/impl/StandardLauncher.java b/libraries/launcher/org/prismlauncher/launcher/impl/StandardLauncher.java index b687b20ec..70ee015bd 100644 --- a/libraries/launcher/org/prismlauncher/launcher/impl/StandardLauncher.java +++ b/libraries/launcher/org/prismlauncher/launcher/impl/StandardLauncher.java @@ -63,7 +63,7 @@ import java.util.List; public final class StandardLauncher extends AbstractLauncher { private final boolean quickPlaySupported; - + public StandardLauncher(Parameters params) { super(params); From a9d7af909614404b6cc58ccc568d46d505f541cd Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 20 Oct 2023 16:44:37 +0300 Subject: [PATCH 020/223] removed some unused stuff Signed-off-by: Trial97 --- launcher/ui/dialogs/AboutDialog.h | 4 ---- launcher/ui/pages/instance/VersionPage.cpp | 7 ------- launcher/ui/pages/instance/VersionPage.h | 1 - 3 files changed, 12 deletions(-) diff --git a/launcher/ui/dialogs/AboutDialog.h b/launcher/ui/dialogs/AboutDialog.h index 356f005e0..5da686b5f 100644 --- a/launcher/ui/dialogs/AboutDialog.h +++ b/launcher/ui/dialogs/AboutDialog.h @@ -15,7 +15,6 @@ #pragma once -#include #include namespace Ui { @@ -31,7 +30,4 @@ class AboutDialog : public QDialog { private: Ui::AboutDialog* ui; - - NetJob::Ptr netJob; - QByteArray dataSink; }; diff --git a/launcher/ui/pages/instance/VersionPage.cpp b/launcher/ui/pages/instance/VersionPage.cpp index 2918261d2..e425269c8 100644 --- a/launcher/ui/pages/instance/VersionPage.cpp +++ b/launcher/ui/pages/instance/VersionPage.cpp @@ -295,13 +295,6 @@ void VersionPage::on_actionRemove_triggered() m_container->refreshContainer(); } -void VersionPage::on_actionInstall_mods_triggered() -{ - if (m_container) { - m_container->selectPage("mods"); - } -} - void VersionPage::on_actionAdd_to_Minecraft_jar_triggered() { auto list = GuiUtil::BrowseForFiles("jarmod", tr("Select jar mods"), tr("Minecraft.jar mods (*.zip *.jar)"), diff --git a/launcher/ui/pages/instance/VersionPage.h b/launcher/ui/pages/instance/VersionPage.h index 6915be883..951643743 100644 --- a/launcher/ui/pages/instance/VersionPage.h +++ b/launcher/ui/pages/instance/VersionPage.h @@ -80,7 +80,6 @@ class VersionPage : public QMainWindow, public BasePage { void on_actionAdd_Agents_triggered(); void on_actionRevert_triggered(); void on_actionEdit_triggered(); - void on_actionInstall_mods_triggered(); void on_actionCustomize_triggered(); void on_actionDownload_All_triggered(); From 0ca3873f1c492ad78257eb9ca2c1568a90c353c0 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 22 Oct 2023 17:48:19 +0300 Subject: [PATCH 021/223] small fix Signed-off-by: Trial97 --- launcher/tasks/ConcurrentTask.cpp | 4 ++-- launcher/tasks/SequentialTask.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/launcher/tasks/ConcurrentTask.cpp b/launcher/tasks/ConcurrentTask.cpp index 92b13cfa8..c042894b4 100644 --- a/launcher/tasks/ConcurrentTask.cpp +++ b/launcher/tasks/ConcurrentTask.cpp @@ -69,7 +69,7 @@ void ConcurrentTask::addTask(Task::Ptr task) void ConcurrentTask::executeTask() { for (auto i = 0; i < m_total_max_size; i++) - executeNextSubTask(); + QMetaObject::invokeMethod(this, &ConcurrentTask::executeNextSubTask, Qt::QueuedConnection); } bool ConcurrentTask::abort() @@ -127,7 +127,7 @@ void ConcurrentTask::executeNextSubTask() } return; } - if (m_doing.count() > m_total_max_size) { + if (m_doing.count() >= m_total_max_size) { return; } diff --git a/launcher/tasks/SequentialTask.cpp b/launcher/tasks/SequentialTask.cpp index 180430c8c..509d91cf7 100644 --- a/launcher/tasks/SequentialTask.cpp +++ b/launcher/tasks/SequentialTask.cpp @@ -43,7 +43,7 @@ SequentialTask::SequentialTask(QObject* parent, QString task_name) : ConcurrentT void SequentialTask::subTaskFailed(Task::Ptr task, const QString& msg) { emitFailed(msg); - qWarning() << m_failed.constBegin()->get()->failReason(); + qWarning() << msg; ConcurrentTask::subTaskFailed(task, msg); } From 2aeb8291767e1832f81f3a4e3f8e3736613175ed Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 22 Oct 2023 19:58:10 +0300 Subject: [PATCH 022/223] removed the concurent task destructor behaivior Signed-off-by: Trial97 --- launcher/modplatform/EnsureMetadataTask.cpp | 1 - launcher/tasks/ConcurrentTask.cpp | 14 +++++--------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/launcher/modplatform/EnsureMetadataTask.cpp b/launcher/modplatform/EnsureMetadataTask.cpp index a9ed30119..ce53ee62d 100644 --- a/launcher/modplatform/EnsureMetadataTask.cpp +++ b/launcher/modplatform/EnsureMetadataTask.cpp @@ -160,7 +160,6 @@ void EnsureMetadataTask::executeTask() if (m_current_task) m_current_task.reset(); }); - connect(version_task.get(), &Task::failed, this, &EnsureMetadataTask::emitFailed); if (m_mods.size() > 1) setStatus(tr("Requesting metadata information from %1...").arg(ProviderCaps.readableName(m_provider))); diff --git a/launcher/tasks/ConcurrentTask.cpp b/launcher/tasks/ConcurrentTask.cpp index c042894b4..6f4a94e7f 100644 --- a/launcher/tasks/ConcurrentTask.cpp +++ b/launcher/tasks/ConcurrentTask.cpp @@ -46,13 +46,9 @@ ConcurrentTask::ConcurrentTask(QObject* parent, QString task_name, int max_concu ConcurrentTask::~ConcurrentTask() { - for (auto task : m_queue) { + for (auto task : m_doing) { if (task) - task->deleteLater(); - } - for (auto task : m_done) { - if (task) - task->deleteLater(); + task->disconnect(this); } } @@ -118,6 +114,9 @@ void ConcurrentTask::executeNextSubTask() if (!isRunning()) { return; } + if (m_doing.count() >= m_total_max_size) { + return; + } if (m_queue.isEmpty()) { if (m_doing.isEmpty()) { if (m_failed.isEmpty()) @@ -127,9 +126,6 @@ void ConcurrentTask::executeNextSubTask() } return; } - if (m_doing.count() >= m_total_max_size) { - return; - } startSubTask(m_queue.dequeue()); } From dba54332fb7785400ffc6d9eac1f3a0b9d3412cd Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 26 Oct 2023 18:31:52 +0300 Subject: [PATCH 023/223] fixed some asan stuf Signed-off-by: Trial97 --- launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp | 2 +- launcher/screenshots/ImgurUpload.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp b/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp index e56fc3d1d..e78061f27 100644 --- a/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp +++ b/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp @@ -72,7 +72,7 @@ void ModrinthCheckUpdate::executeTask() auto response = std::make_shared(); auto job = api.latestVersions(hashes, best_hash_type, m_game_versions, m_loaders, response); - connect(job.get(), &Task::succeeded, this, [this, response, &mappings, best_hash_type, job] { + connect(job.get(), &Task::succeeded, this, [this, response, mappings, best_hash_type, job] { QJsonParseError parse_error{}; QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); if (parse_error.error != QJsonParseError::NoError) { diff --git a/launcher/screenshots/ImgurUpload.cpp b/launcher/screenshots/ImgurUpload.cpp index 7ed672eb7..15fb043e4 100644 --- a/launcher/screenshots/ImgurUpload.cpp +++ b/launcher/screenshots/ImgurUpload.cpp @@ -58,14 +58,14 @@ void ImgurUpload::init() QNetworkReply* ImgurUpload::getReply(QNetworkRequest& request) { - auto file = new QFile(m_fileInfo.absoluteFilePath()); + auto file = new QFile(m_fileInfo.absoluteFilePath(), this); if (!file->open(QFile::ReadOnly)) { emitFailed(); return nullptr; } - QHttpMultiPart* multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType); + QHttpMultiPart* multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType, this); file->setParent(multipart); QHttpPart filePart; filePart.setBodyDevice(file); From 1490193402096381c81a940a9926da18bba2ce5a Mon Sep 17 00:00:00 2001 From: Trial97 Date: Mon, 30 Oct 2023 22:14:26 +0200 Subject: [PATCH 024/223] added button to disable dependencies on the mod review Signed-off-by: Trial97 --- launcher/ui/dialogs/ModUpdateDialog.cpp | 3 +++ launcher/ui/dialogs/ReviewMessageBox.cpp | 10 ++++++++++ launcher/ui/dialogs/ReviewMessageBox.h | 7 +++++++ launcher/ui/dialogs/ReviewMessageBox.ui | 11 ++++++++--- 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/launcher/ui/dialogs/ModUpdateDialog.cpp b/launcher/ui/dialogs/ModUpdateDialog.cpp index 1a70ea59a..762f3ad50 100644 --- a/launcher/ui/dialogs/ModUpdateDialog.cpp +++ b/launcher/ui/dialogs/ModUpdateDialog.cpp @@ -435,6 +435,9 @@ void ModUpdateDialog::appendMod(CheckUpdateTask::UpdatableMod const& info, QStri reqItem->insertChildren(i++, { reqItem }); } } + + ui->toggleDepsButton->show(); + m_deps << item_top; } auto changelog_item = new QTreeWidgetItem(item_top); diff --git a/launcher/ui/dialogs/ReviewMessageBox.cpp b/launcher/ui/dialogs/ReviewMessageBox.cpp index aa668f8c2..41b832e03 100644 --- a/launcher/ui/dialogs/ReviewMessageBox.cpp +++ b/launcher/ui/dialogs/ReviewMessageBox.cpp @@ -13,6 +13,7 @@ ReviewMessageBox::ReviewMessageBox(QWidget* parent, [[maybe_unused]] QString con auto back_button = ui->buttonBox->button(QDialogButtonBox::Cancel); back_button->setText(tr("Back")); + ui->toggleDepsButton->hide(); ui->modTreeWidget->header()->setSectionResizeMode(0, QHeaderView::Stretch); ui->modTreeWidget->header()->setStretchLastSection(false); ui->modTreeWidget->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents); @@ -75,6 +76,8 @@ void ReviewMessageBox::appendResource(ResourceInformation&& info) } itemTop->insertChildren(childIndx++, { requiredByItem }); + ui->toggleDepsButton->show(); + m_deps << itemTop; } auto versionTypeItem = new QTreeWidgetItem(itemTop); @@ -108,3 +111,10 @@ void ReviewMessageBox::retranslateUi(QString resources_name) ui->explainLabel->setText(tr("You're about to download the following %1:").arg(resources_name)); ui->onlyCheckedLabel->setText(tr("Only %1 with a check will be downloaded!").arg(resources_name)); } +void ReviewMessageBox::on_toggleDepsButton_clicked() +{ + m_deps_checked = !m_deps_checked; + auto state = m_deps_checked ? Qt::Checked : Qt::Unchecked; + for (auto dep : m_deps) + dep->setCheckState(0, state); +}; \ No newline at end of file diff --git a/launcher/ui/dialogs/ReviewMessageBox.h b/launcher/ui/dialogs/ReviewMessageBox.h index 596f39c8e..7dd2732a0 100644 --- a/launcher/ui/dialogs/ReviewMessageBox.h +++ b/launcher/ui/dialogs/ReviewMessageBox.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace Ui { class ReviewMessageBox; @@ -28,8 +29,14 @@ class ReviewMessageBox : public QDialog { ~ReviewMessageBox() override; + protected slots: + void on_toggleDepsButton_clicked(); + protected: ReviewMessageBox(QWidget* parent, const QString& title, const QString& icon); Ui::ReviewMessageBox* ui; + + QList m_deps; + bool m_deps_checked = true; }; diff --git a/launcher/ui/dialogs/ReviewMessageBox.ui b/launcher/ui/dialogs/ReviewMessageBox.ui index bf53ae80b..dbe351019 100644 --- a/launcher/ui/dialogs/ReviewMessageBox.ui +++ b/launcher/ui/dialogs/ReviewMessageBox.ui @@ -44,15 +44,20 @@ - - + - + + + Toggle Dependencies + + + + From e42a2404a9451b822c5d034f40c79ed006e708e9 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Mon, 30 Oct 2023 22:55:23 +0200 Subject: [PATCH 025/223] added more microsoft error codes Signed-off-by: Trial97 --- .../auth/steps/XboxAuthorizationStep.cpp | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp b/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp index c33d7e629..36a76b870 100644 --- a/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp +++ b/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp @@ -126,7 +126,34 @@ bool XboxAuthorizationStep::processSTSError(QNetworkReply::NetworkError error, Q emit finished( AccountTaskState::STATE_FAILED_SOFT, tr("This Microsoft account is underaged and is not linked to a family.\n\nPlease set up your account according to %1.") - .arg("help.minecraft.net")); + .arg("help.minecraft.net")); + return true; + } + case 2148916236: { + emit finished(AccountTaskState::STATE_FAILED_SOFT, + tr("This Microsoft account requires proof of age to play. Please login to %1 to provide proof of age.") + .arg("login.live.com")); + return true; + } + case 2148916237: + emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("This Microsoft account has reached the its limit for playtime. This " + "Microsoft account has been blocked from logging in.")); + return true; + case 2148916227: { + emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("This Microsoft account was banned by Xbox for violating one or more " + "Community Standards for Xbox and is unable to be used.")); + return true; + } + case 2148916229: { + emit finished(AccountTaskState::STATE_FAILED_SOFT, + tr("This Microsoft account is currently restricted and your guardian has not given you permission to play " + "online. Login to %1 and have your guardian change your permissions.") + .arg("account.microsoft.com")); + return true; + } + case 2148916234: { + emit finished(AccountTaskState::STATE_FAILED_SOFT, + tr("This Microsoft account has not accepted Xbox's Terms of Service. Please login and accept them.")); return true; } default: { From 7166d68736e17573b2bd04d78d5a8a61433f5948 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 31 Oct 2023 00:45:18 +0200 Subject: [PATCH 026/223] fixed account refresh after sleep Signed-off-by: Trial97 --- launcher/LaunchController.cpp | 41 ++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/launcher/LaunchController.cpp b/launcher/LaunchController.cpp index 9fb385777..8844ae105 100644 --- a/launcher/LaunchController.cpp +++ b/launcher/LaunchController.cpp @@ -36,12 +36,14 @@ #include "LaunchController.h" #include "Application.h" +#include "minecraft/auth/AccountData.h" #include "minecraft/auth/AccountList.h" #include "ui/InstanceWindow.h" #include "ui/MainWindow.h" #include "ui/dialogs/CustomMessageBox.h" #include "ui/dialogs/EditAccountDialog.h" +#include "ui/dialogs/MSALoginDialog.h" #include "ui/dialogs/ProfileSelectDialog.h" #include "ui/dialogs/ProfileSetupDialog.h" #include "ui/dialogs/ProgressDialog.h" @@ -154,6 +156,12 @@ void LaunchController::login() return; } } + if (!m_accountToUse->isOffline() && m_accountToUse->accountState() == AccountState::Offline && tries == 0) { + // Force account refresh on the account used to launch the instance updating the AccountState + // only on first try and if it is not meant to be offline + auto accounts = APPLICATION->accounts(); + accounts->requestRefresh(m_accountToUse->internalId()); + } tries++; m_session = std::make_shared(); m_session->wants_online = m_online; @@ -249,17 +257,30 @@ void LaunchController::login() progDialog.execWithTask(task.get()); continue; } - // FIXME: this is missing - the meaning is that the account is queued for refresh and we should wait for that - /* - case AccountState::Queued: { - return; - } - */ case AccountState::Expired: { - auto errorString = tr("The account has expired and needs to be logged into manually again."); - QMessageBox::warning(m_parentWidget, tr("Account refresh failed"), errorString, QMessageBox::StandardButton::Ok, - QMessageBox::StandardButton::Ok); - emitFailed(errorString); + auto errorString = tr("The account has expired and needs to be logged into manually. Press OK to log in again."); + auto button = QMessageBox::warning(m_parentWidget, tr("Account refresh failed"), errorString, + QMessageBox::StandardButton::Ok | QMessageBox::StandardButton::Cancel, + QMessageBox::StandardButton::Ok); + if (button == QMessageBox::StandardButton::Ok) { + auto accounts = APPLICATION->accounts(); + bool isDefault = accounts->defaultAccount() == m_accountToUse; + accounts->removeAccount(accounts->index(accounts->findAccountByProfileId(m_accountToUse->profileId()))); + if (m_accountToUse->isMSA()) { + auto newAccount = MSALoginDialog::newAccount( + m_parentWidget, tr("Please enter your Mojang account email and password to add your account.")); + accounts->addAccount(newAccount); + if (isDefault) { + accounts->setDefaultAccount(newAccount); + } + m_accountToUse = nullptr; + decideAccount(); + continue; + } + emitFailed(tr("Account expired and re-login attempt failed")); + } else { + emitFailed(errorString); + } return; } case AccountState::Disabled: { From 60fd7f0ae69c65538c22f9ac9f3ecbc13679804e Mon Sep 17 00:00:00 2001 From: Alexandru Ionut Tripon Date: Tue, 31 Oct 2023 08:43:26 +0200 Subject: [PATCH 027/223] Update launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp Co-authored-by: Tayou Signed-off-by: Alexandru Ionut Tripon --- launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp b/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp index 36a76b870..820e03ec9 100644 --- a/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp +++ b/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp @@ -136,7 +136,7 @@ bool XboxAuthorizationStep::processSTSError(QNetworkReply::NetworkError error, Q return true; } case 2148916237: - emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("This Microsoft account has reached the its limit for playtime. This " + emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("This Microsoft account has reached its limit for playtime. This " "Microsoft account has been blocked from logging in.")); return true; case 2148916227: { From 2863a691ef4687eefa47e8fbfd4e5f6e06cce877 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 31 Oct 2023 08:45:08 +0200 Subject: [PATCH 028/223] moved refresh out of the loop Signed-off-by: Trial97 --- launcher/LaunchController.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/launcher/LaunchController.cpp b/launcher/LaunchController.cpp index 8844ae105..2c76fee4f 100644 --- a/launcher/LaunchController.cpp +++ b/launcher/LaunchController.cpp @@ -145,6 +145,12 @@ void LaunchController::login() bool tryagain = true; unsigned int tries = 0; + if (!m_accountToUse->isOffline() && m_accountToUse->accountState() == AccountState::Offline) { + // Force account refresh on the account used to launch the instance updating the AccountState + // only on first try and if it is not meant to be offline + auto accounts = APPLICATION->accounts(); + accounts->requestRefresh(m_accountToUse->internalId()); + } while (tryagain) { if (tries > 0 && tries % 3 == 0) { auto result = @@ -156,12 +162,6 @@ void LaunchController::login() return; } } - if (!m_accountToUse->isOffline() && m_accountToUse->accountState() == AccountState::Offline && tries == 0) { - // Force account refresh on the account used to launch the instance updating the AccountState - // only on first try and if it is not meant to be offline - auto accounts = APPLICATION->accounts(); - accounts->requestRefresh(m_accountToUse->internalId()); - } tries++; m_session = std::make_shared(); m_session->wants_online = m_online; From 4081c51573b76b59a1551045ded4256d6886d3ef Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 2 Nov 2023 23:52:12 +0200 Subject: [PATCH 029/223] made dependency check more lax Signed-off-by: Trial97 --- .../mod/tasks/GetModDependenciesTask.cpp | 67 ++++++++++++++++++- .../mod/tasks/GetModDependenciesTask.h | 4 ++ 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp b/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp index df8c690af..682f98240 100644 --- a/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp +++ b/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp @@ -57,9 +57,11 @@ GetModDependenciesTask::GetModDependenciesTask(QObject* parent, , m_version(mcVersion(instance)) , m_loaderType(mcLoaders(instance)) { - for (auto mod : folder->allMods()) + for (auto mod : folder->allMods()) { + m_mods_file_names << mod->fileinfo().fileName(); if (auto meta = mod->metadata(); meta) m_mods.append(meta); + } prepare(); } @@ -225,8 +227,13 @@ Task::Ptr GetModDependenciesTask::prepareDependencyTask(const ModPlatform::Depen if (dep_.addonId != pDep->version.addonId) { removePack(pDep->version.addonId); addTask(prepareDependencyTask(dep_, provider.name, level)); - } else + } else { addTask(getProjectInfoTask(pDep)); + } + } + if (isLocalyInstalled(pDep)) { + removePack(pDep->version.addonId); + return; } for (auto dep_ : getDependenciesForVersion(pDep->version, provider.name)) { addTask(prepareDependencyTask(dep_, provider.name, level - 1)); @@ -279,4 +286,58 @@ QHash GetModDependenciesTask::getRequiredBy() rby[addonId.toString()] = req; } return rby; -} \ No newline at end of file +} + +// 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::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::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) { + 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 +} + +bool GetModDependenciesTask::isLaxInstalled(std::shared_ptr pDep) +{ + return std::find_if(m_mods_file_names.begin(), m_mods_file_names.end(), [pDep](QString i) { + return !i.isEmpty() && laxCompare(i, pDep->version.fileName, true); + }) != m_mods_file_names.end(); // check the existing mods +} diff --git a/launcher/minecraft/mod/tasks/GetModDependenciesTask.h b/launcher/minecraft/mod/tasks/GetModDependenciesTask.h index 2580f8077..6ec373525 100644 --- a/launcher/minecraft/mod/tasks/GetModDependenciesTask.h +++ b/launcher/minecraft/mod/tasks/GetModDependenciesTask.h @@ -73,10 +73,14 @@ class GetModDependenciesTask : public SequentialTask { ModPlatform::Dependency getOverride(const ModPlatform::Dependency&, const ModPlatform::ResourceProvider providerName); void removePack(const QVariant addonId); + bool isLocalyInstalled(std::shared_ptr pDep); + bool isLaxInstalled(std::shared_ptr pDep); + private: QList> m_pack_dependencies; QList> m_mods; QList> m_selected; + QStringList m_mods_file_names; Provider m_flame_provider; Provider m_modrinth_provider; From a4978946d56f1c21df4d812d33df14897ebfae1b Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sat, 4 Nov 2023 00:07:51 +0200 Subject: [PATCH 030/223] disabled lax deps Signed-off-by: Trial97 --- .../mod/tasks/GetModDependenciesTask.cpp | 8 +++---- .../mod/tasks/GetModDependenciesTask.h | 9 ++++++-- launcher/modplatform/CheckUpdateTask.h | 5 +++- launcher/ui/dialogs/ModUpdateDialog.cpp | 23 +++++++++++++------ .../ui/dialogs/ResourceDownloadDialog.cpp | 9 ++++---- launcher/ui/dialogs/ReviewMessageBox.cpp | 5 +++- launcher/ui/dialogs/ReviewMessageBox.h | 1 + 7 files changed, 41 insertions(+), 19 deletions(-) diff --git a/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp b/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp index 682f98240..e2563ebe8 100644 --- a/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp +++ b/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp @@ -259,9 +259,9 @@ void GetModDependenciesTask::removePack(const QVariant addonId) #endif } -QHash GetModDependenciesTask::getRequiredBy() +auto GetModDependenciesTask::getExtraInfo() -> QHash { - QHash rby; + QHash rby; auto fullList = m_selected + m_pack_dependencies; for (auto& mod : fullList) { auto addonId = mod->pack->addonId; @@ -283,7 +283,7 @@ QHash GetModDependenciesTask::getRequiredBy() req.append(smod->pack->name); } } - rby[addonId.toString()] = req; + rby[addonId.toString()] = { maybeInstalled(mod), req }; } return rby; } @@ -335,7 +335,7 @@ bool GetModDependenciesTask::isLocalyInstalled(std::shared_ptr p }) != m_pack_dependencies.end(); // check loaded dependencies } -bool GetModDependenciesTask::isLaxInstalled(std::shared_ptr pDep) +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 !i.isEmpty() && laxCompare(i, pDep->version.fileName, true); diff --git a/launcher/minecraft/mod/tasks/GetModDependenciesTask.h b/launcher/minecraft/mod/tasks/GetModDependenciesTask.h index 6ec373525..4b2608045 100644 --- a/launcher/minecraft/mod/tasks/GetModDependenciesTask.h +++ b/launcher/minecraft/mod/tasks/GetModDependenciesTask.h @@ -50,6 +50,11 @@ class GetModDependenciesTask : public SequentialTask { } }; + struct PackDependencyExtraInfo { + bool maybe_installed; + QStringList required_by; + }; + struct Provider { ModPlatform::ResourceProvider name; std::shared_ptr mod; @@ -62,7 +67,7 @@ class GetModDependenciesTask : public SequentialTask { QList> selected); auto getDependecies() const -> QList> { return m_pack_dependencies; } - QHash getRequiredBy(); + QHash getExtraInfo(); protected slots: Task::Ptr prepareDependencyTask(const ModPlatform::Dependency&, const ModPlatform::ResourceProvider, int); @@ -74,7 +79,7 @@ class GetModDependenciesTask : public SequentialTask { void removePack(const QVariant addonId); bool isLocalyInstalled(std::shared_ptr pDep); - bool isLaxInstalled(std::shared_ptr pDep); + bool maybeInstalled(std::shared_ptr pDep); private: QList> m_pack_dependencies; diff --git a/launcher/modplatform/CheckUpdateTask.h b/launcher/modplatform/CheckUpdateTask.h index 8bd83d988..b19b25484 100644 --- a/launcher/modplatform/CheckUpdateTask.h +++ b/launcher/modplatform/CheckUpdateTask.h @@ -28,6 +28,7 @@ class CheckUpdateTask : public Task { QString changelog; ModPlatform::ResourceProvider provider; shared_qobject_ptr download; + bool enabled = true; public: UpdatableMod(QString name, @@ -37,7 +38,8 @@ class CheckUpdateTask : public Task { std::optional new_v_type, QString changelog, ModPlatform::ResourceProvider p, - shared_qobject_ptr t) + shared_qobject_ptr t, + bool enabled = true) : name(name) , old_hash(old_h) , old_version(old_v) @@ -46,6 +48,7 @@ class CheckUpdateTask : public Task { , changelog(changelog) , provider(p) , download(t) + , enabled(enabled) {} }; diff --git a/launcher/ui/dialogs/ModUpdateDialog.cpp b/launcher/ui/dialogs/ModUpdateDialog.cpp index 1a70ea59a..b7e8eea14 100644 --- a/launcher/ui/dialogs/ModUpdateDialog.cpp +++ b/launcher/ui/dialogs/ModUpdateDialog.cpp @@ -212,19 +212,25 @@ void ModUpdateDialog::checkCandidates() } static FlameAPI api; - auto getRequiredBy = depTask->getRequiredBy(); + auto dependencyExtraInfo = depTask->getExtraInfo(); for (auto dep : depTask->getDependecies()) { 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_mod_model); - CheckUpdateTask::UpdatableMod updatable = { - dep->pack->name, dep->version.hash, "", dep->version.version, dep->version.version_type, - changelog, dep->pack->provider, download_task - }; + auto extraInfo = dependencyExtraInfo.value(dep->version.addonId.toString()); + CheckUpdateTask::UpdatableMod updatable = { dep->pack->name, + dep->version.hash, + "", + dep->version.version, + dep->version.version_type, + changelog, + dep->pack->provider, + download_task, + !extraInfo.maybe_installed }; - appendMod(updatable, getRequiredBy.value(dep->version.addonId.toString())); + appendMod(updatable, extraInfo.required_by); m_tasks.insert(updatable.name, updatable.download); } } @@ -404,7 +410,10 @@ void ModUpdateDialog::onMetadataFailed(Mod* mod, bool try_others, ModPlatform::R void ModUpdateDialog::appendMod(CheckUpdateTask::UpdatableMod const& info, QStringList requiredBy) { auto item_top = new QTreeWidgetItem(ui->modTreeWidget); - item_top->setCheckState(0, Qt::CheckState::Checked); + item_top->setCheckState(0, info.enabled ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); + if (!info.enabled) { + item_top->setToolTip(0, tr("Mod was disabled as it may be already instaled.")); + } item_top->setText(0, info.name); item_top->setExpanded(true); diff --git a/launcher/ui/dialogs/ResourceDownloadDialog.cpp b/launcher/ui/dialogs/ResourceDownloadDialog.cpp index dc7cfff06..cae4cb4dd 100644 --- a/launcher/ui/dialogs/ResourceDownloadDialog.cpp +++ b/launcher/ui/dialogs/ResourceDownloadDialog.cpp @@ -132,7 +132,7 @@ void ResourceDownloadDialog::confirm() auto confirm_dialog = ReviewMessageBox::create(this, tr("Confirm %1 to download").arg(resourcesString())); confirm_dialog->retranslateUi(resourcesString()); - QHash getRequiredBy; + QHash dependencyExtraInfo; if (auto task = getModDependenciesTask(); task) { connect(task.get(), &Task::failed, this, [&](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); }); @@ -157,7 +157,7 @@ void ResourceDownloadDialog::confirm() } else { for (auto dep : task->getDependecies()) addResource(dep->pack, dep->version); - getRequiredBy = task->getRequiredBy(); + dependencyExtraInfo = task->getExtraInfo(); } } @@ -166,9 +166,10 @@ void ResourceDownloadDialog::confirm() return QString::compare(a->getName(), b->getName(), Qt::CaseInsensitive) < 0; }); for (auto& task : selected) { + auto extraInfo = dependencyExtraInfo.value(task->getPack()->addonId.toString()); confirm_dialog->appendResource({ task->getName(), task->getFilename(), task->getCustomPath(), - ProviderCaps.name(task->getProvider()), getRequiredBy.value(task->getPack()->addonId.toString()), - task->getVersion().version_type.toString() }); + ProviderCaps.name(task->getProvider()), extraInfo.required_by, + task->getVersion().version_type.toString(), !extraInfo.maybe_installed }); } if (confirm_dialog->exec()) { diff --git a/launcher/ui/dialogs/ReviewMessageBox.cpp b/launcher/ui/dialogs/ReviewMessageBox.cpp index aa668f8c2..e25186755 100644 --- a/launcher/ui/dialogs/ReviewMessageBox.cpp +++ b/launcher/ui/dialogs/ReviewMessageBox.cpp @@ -34,8 +34,11 @@ auto ReviewMessageBox::create(QWidget* parent, QString&& title, QString&& icon) void ReviewMessageBox::appendResource(ResourceInformation&& info) { auto itemTop = new QTreeWidgetItem(ui->modTreeWidget); - itemTop->setCheckState(0, Qt::CheckState::Checked); + itemTop->setCheckState(0, info.enabled ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); itemTop->setText(0, info.name); + if (!info.enabled) { + itemTop->setToolTip(0, tr("Mod was disabled as it may be already instaled.")); + } auto filenameItem = new QTreeWidgetItem(itemTop); filenameItem->setText(0, tr("Filename: %1").arg(info.filename)); diff --git a/launcher/ui/dialogs/ReviewMessageBox.h b/launcher/ui/dialogs/ReviewMessageBox.h index 596f39c8e..d9b4b0b7a 100644 --- a/launcher/ui/dialogs/ReviewMessageBox.h +++ b/launcher/ui/dialogs/ReviewMessageBox.h @@ -19,6 +19,7 @@ class ReviewMessageBox : public QDialog { QString provider; QStringList required_by; QString version_type; + bool enabled = true; }; void appendResource(ResourceInformation&& info); From 7532a410433296eb5b84865e921857580f646c38 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 9 Nov 2023 21:38:38 +0200 Subject: [PATCH 031/223] Improvements to catpack Signed-off-by: Trial97 --- launcher/ui/instanceview/InstanceView.cpp | 2 +- launcher/ui/themes/CatPack.cpp | 23 +++++++++++++++++++++-- launcher/ui/themes/CatPack.h | 2 +- launcher/ui/themes/ThemeManager.cpp | 14 +++++++------- launcher/ui/themes/ThemeManager.h | 2 +- 5 files changed, 31 insertions(+), 12 deletions(-) diff --git a/launcher/ui/instanceview/InstanceView.cpp b/launcher/ui/instanceview/InstanceView.cpp index 7530fdfba..4500f6d4d 100644 --- a/launcher/ui/instanceview/InstanceView.cpp +++ b/launcher/ui/instanceview/InstanceView.cpp @@ -465,7 +465,7 @@ void InstanceView::paintEvent([[maybe_unused]] QPaintEvent* event) widWidth = m_catPixmap.width(); if (m_catPixmap.height() < widHeight) widHeight = m_catPixmap.height(); - auto pixmap = m_catPixmap.scaled(widWidth, widHeight, Qt::KeepAspectRatio); + auto pixmap = m_catPixmap.scaled(widWidth, widHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation); QRect rectOfPixmap = pixmap.rect(); rectOfPixmap.moveBottomRight(this->viewport()->rect().bottomRight()); painter.drawPixmap(rectOfPixmap.topLeft(), pixmap); diff --git a/launcher/ui/themes/CatPack.cpp b/launcher/ui/themes/CatPack.cpp index bbcb58bc8..cd1a5772d 100644 --- a/launcher/ui/themes/CatPack.cpp +++ b/launcher/ui/themes/CatPack.cpp @@ -36,7 +36,10 @@ #include "ui/themes/CatPack.h" #include #include +#include #include +#include +#include #include "FileSystem.h" #include "Json.h" @@ -79,7 +82,7 @@ JsonCatPack::JsonCatPack(QFileInfo& manifestInfo) : BasicCatPack(manifestInfo.di auto doc = Json::requireDocument(manifestInfo.absoluteFilePath(), "CatPack JSON file"); const auto root = doc.object(); m_name = Json::requireString(root, "name", "Catpack name"); - m_defaultPath = FS::PathCombine(path, Json::requireString(root, "default", "Default Cat")); + m_default_path = FS::PathCombine(path, Json::requireString(root, "default", "Default Cat")); auto variants = Json::ensureArray(root, "variants", QJsonArray(), "Catpack Variants"); for (auto v : variants) { auto variant = Json::ensureObject(v, QJsonObject(), "Cat variant"); @@ -117,5 +120,21 @@ QString JsonCatPack::path(QDate now) if (startDate <= now && now <= endDate) return var.path; } - return m_defaultPath; + auto dInfo = QFileInfo(m_default_path); + if (!dInfo.isDir()) + return m_default_path; + + QStringList supportedImageFormats; + for (auto format : QImageReader::supportedImageFormats()) { + supportedImageFormats.append("*." + format); + } + + auto files = QDir(m_default_path).entryInfoList(supportedImageFormats, QDir::Files, QDir::Name); + if (files.length() == 0) + return ""; + auto idx = now.dayOfYear() % files.length(); + auto isRandom = dInfo.fileName().compare("random", Qt::CaseInsensitive) == 0; + if (isRandom) + idx = QRandomGenerator::global()->bounded(0, files.length()); + return files[idx].absoluteFilePath(); } diff --git a/launcher/ui/themes/CatPack.h b/launcher/ui/themes/CatPack.h index 1d310e796..5a13d0cef 100644 --- a/launcher/ui/themes/CatPack.h +++ b/launcher/ui/themes/CatPack.h @@ -87,6 +87,6 @@ class JsonCatPack : public BasicCatPack { QString path(QDate now); private: - QString m_defaultPath; + QString m_default_path; QList m_variants; }; diff --git a/launcher/ui/themes/ThemeManager.cpp b/launcher/ui/themes/ThemeManager.cpp index 0bcac100c..a128fc3f5 100644 --- a/launcher/ui/themes/ThemeManager.cpp +++ b/launcher/ui/themes/ThemeManager.cpp @@ -178,8 +178,8 @@ QList ThemeManager::getValidApplicationThemes() QList ThemeManager::getValidCatPacks() { QList ret; - ret.reserve(m_catPacks.size()); - for (auto&& [id, theme] : m_catPacks) { + ret.reserve(m_cat_packs.size()); + for (auto&& [id, theme] : m_cat_packs) { ret.append(theme.get()); } return ret; @@ -244,8 +244,8 @@ void ThemeManager::applyCurrentlySelectedTheme(bool initial) QString ThemeManager::getCatPack(QString catName) { - auto catIter = m_catPacks.find(!catName.isEmpty() ? catName : APPLICATION->settings()->get("BackgroundCat").toString()); - if (catIter != m_catPacks.end()) { + auto catIter = m_cat_packs.find(!catName.isEmpty() ? catName : APPLICATION->settings()->get("BackgroundCat").toString()); + if (catIter != m_cat_packs.end()) { auto& catPack = catIter->second; themeDebugLog() << "applying catpack" << catPack->id(); return catPack->path(); @@ -253,14 +253,14 @@ QString ThemeManager::getCatPack(QString catName) themeWarningLog() << "Tried to get invalid catPack:" << catName; } - return m_catPacks.begin()->second->path(); + return m_cat_packs.begin()->second->path(); } QString ThemeManager::addCatPack(std::unique_ptr catPack) { QString id = catPack->id(); - if (m_catPacks.find(id) == m_catPacks.end()) - m_catPacks.emplace(id, std::move(catPack)); + if (m_cat_packs.find(id) == m_cat_packs.end()) + m_cat_packs.emplace(id, std::move(catPack)); else themeWarningLog() << "CatPack(" << id << ") not added to prevent id duplication"; return id; diff --git a/launcher/ui/themes/ThemeManager.h b/launcher/ui/themes/ThemeManager.h index b5c66677b..b77b5947a 100644 --- a/launcher/ui/themes/ThemeManager.h +++ b/launcher/ui/themes/ThemeManager.h @@ -61,7 +61,7 @@ class ThemeManager { QDir m_iconThemeFolder{ "iconthemes" }; QDir m_applicationThemeFolder{ "themes" }; QDir m_catPacksFolder{ "catpacks" }; - std::map> m_catPacks; + std::map> m_cat_packs; void initializeThemes(); void initializeCatPacks(); From 5e2eb7bbbb6b84ab8b8b85fe03a65ea9579e9f37 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 9 Nov 2023 23:30:30 +0200 Subject: [PATCH 032/223] Added button to select the FTBApp instances directory Signed-off-by: Trial97 --- launcher/Application.cpp | 3 + .../modplatform/import_ftb/ImportFTBPage.cpp | 8 ++ .../modplatform/import_ftb/ImportFTBPage.ui | 73 +++++++++++++------ .../modplatform/import_ftb/ListModel.cpp | 21 +++++- .../pages/modplatform/import_ftb/ListModel.h | 3 +- 5 files changed, 81 insertions(+), 27 deletions(-) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index be252f1c5..a280a6013 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -740,6 +740,9 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) m_settings->registerSetting("ModrinthToken", ""); m_settings->registerSetting("UserAgentOverride", ""); + // FTBApp instances + m_settings->registerSetting("FTBAppInstancesPath", ""); + // Init page provider { m_globalSettingsProvider = std::make_shared(tr("Settings")); diff --git a/launcher/ui/pages/modplatform/import_ftb/ImportFTBPage.cpp b/launcher/ui/pages/modplatform/import_ftb/ImportFTBPage.cpp index d46f16b4d..ac06f4cdd 100644 --- a/launcher/ui/pages/modplatform/import_ftb/ImportFTBPage.cpp +++ b/launcher/ui/pages/modplatform/import_ftb/ImportFTBPage.cpp @@ -20,6 +20,7 @@ #include "ui/widgets/ProjectItem.h" #include "ui_ImportFTBPage.h" +#include #include #include "FileSystem.h" #include "ListModel.h" @@ -56,6 +57,13 @@ ImportFTBPage::ImportFTBPage(NewInstanceDialog* dialog, QWidget* parent) : QWidg connect(ui->searchEdit, &QLineEdit::textChanged, this, &ImportFTBPage::triggerSearch); + connect(ui->browseButton, &QPushButton::clicked, this, [this] { + auto path = listModel->getPath(); + QString dir = QFileDialog::getExistingDirectory(this, tr("Select FTBApp instances directory"), path, QFileDialog::ShowDirsOnly); + if (!dir.isEmpty()) + listModel->setPath(dir); + }); + ui->modpackList->setItemDelegate(new ProjectItemDelegate(this)); ui->modpackList->selectionModel()->reset(); } diff --git a/launcher/ui/pages/modplatform/import_ftb/ImportFTBPage.ui b/launcher/ui/pages/modplatform/import_ftb/ImportFTBPage.ui index 5e09fb6d1..6613a5939 100644 --- a/launcher/ui/pages/modplatform/import_ftb/ImportFTBPage.ui +++ b/launcher/ui/pages/modplatform/import_ftb/ImportFTBPage.ui @@ -11,7 +11,7 @@ - + @@ -21,28 +21,7 @@ - - - - - - Search and filter... - - - true - - - - - - - Search - - - - - - + @@ -69,6 +48,54 @@ + + + + + + Search and filter... + + + true + + + + + + + Search + + + + + + + Select FTBApp instances directory + + + + + + + .. + + + true + + + + + + + + + Note: If your FTB instances are not in the default location, select it using the button next to search. + + + Qt::AlignCenter + + + diff --git a/launcher/ui/pages/modplatform/import_ftb/ListModel.cpp b/launcher/ui/pages/modplatform/import_ftb/ListModel.cpp index 134bdc0c3..e058937a6 100644 --- a/launcher/ui/pages/modplatform/import_ftb/ListModel.cpp +++ b/launcher/ui/pages/modplatform/import_ftb/ListModel.cpp @@ -17,11 +17,13 @@ */ #include "ListModel.h" +#include #include #include #include #include #include +#include "Application.h" #include "FileSystem.h" #include "StringUtils.h" #include "modplatform/import_ftb/PackHelpers.h" @@ -29,7 +31,7 @@ namespace FTBImportAPP { -QString getPath() +QString getStaticPath() { QString partialPath; #if defined(Q_OS_OSX) @@ -42,14 +44,14 @@ QString getPath() return FS::PathCombine(partialPath, ".ftba"); } -const QString ListModel::FTB_APP_PATH = getPath(); +static const QString FTB_APP_PATH = FS::PathCombine(getStaticPath(), "instances"); void ListModel::update() { beginResetModel(); modpacks.clear(); - QString instancesPath = FS::PathCombine(FTB_APP_PATH, "instances"); + QString instancesPath = getPath(); if (auto instancesInfo = QFileInfo(instancesPath); instancesInfo.exists() && instancesInfo.isDir()) { QDirIterator directoryIterator(instancesPath, QDir::Dirs | QDir::NoDotAndDotDot | QDir::Readable | QDir::Hidden, QDirIterator::FollowSymlinks); @@ -168,4 +170,17 @@ FilterModel::Sorting FilterModel::getCurrentSorting() { return currentSorting; } +void ListModel::setPath(QString path) +{ + APPLICATION->settings()->set("FTBAppInstancesPath", path); + update(); +} + +QString ListModel::getPath() +{ + auto path = APPLICATION->settings()->get("FTBAppInstancesPath").toString(); + if (path.isEmpty() || !QFileInfo(path).exists()) + path = FTB_APP_PATH; + return path; +} } // namespace FTBImportAPP \ No newline at end of file diff --git a/launcher/ui/pages/modplatform/import_ftb/ListModel.h b/launcher/ui/pages/modplatform/import_ftb/ListModel.h index 111928276..ed33a88f3 100644 --- a/launcher/ui/pages/modplatform/import_ftb/ListModel.h +++ b/launcher/ui/pages/modplatform/import_ftb/ListModel.h @@ -60,7 +60,8 @@ class ListModel : public QAbstractListModel { void update(); - static const QString FTB_APP_PATH; + QString getPath(); + void setPath(QString path); private: ModpackList modpacks; From 463608b289eeffc3e20e2af396875ee084db11d1 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 10 Nov 2023 19:37:11 +0200 Subject: [PATCH 033/223] fixed shader packs detection Signed-off-by: Trial97 --- .../minecraft/mod/ResourceFolderModel.cpp | 30 ++++++++++++++++++- launcher/minecraft/mod/ResourceFolderModel.h | 7 ++--- launcher/minecraft/mod/ShaderPack.cpp | 5 ---- launcher/minecraft/mod/ShaderPack.h | 1 - .../minecraft/mod/tasks/LocalModParseTask.cpp | 2 +- .../mod/tasks/LocalResourcePackParseTask.cpp | 4 ++- .../mod/tasks/LocalShaderPackParseTask.cpp | 4 ++- .../mod/tasks/LocalTexturePackParseTask.cpp | 4 ++- .../pages/instance/ExternalResourcesPage.cpp | 1 + 9 files changed, 42 insertions(+), 16 deletions(-) diff --git a/launcher/minecraft/mod/ResourceFolderModel.cpp b/launcher/minecraft/mod/ResourceFolderModel.cpp index 0503b660b..de638681e 100644 --- a/launcher/minecraft/mod/ResourceFolderModel.cpp +++ b/launcher/minecraft/mod/ResourceFolderModel.cpp @@ -283,7 +283,12 @@ void ResourceFolderModel::resolveResource(Resource* res) connect( task.get(), &Task::failed, this, [=] { onParseFailed(ticket, res->internal_id()); }, Qt::ConnectionType::QueuedConnection); connect( - task.get(), &Task::finished, this, [=] { m_active_parse_tasks.remove(ticket); }, Qt::ConnectionType::QueuedConnection); + task.get(), &Task::finished, this, + [=] { + m_active_parse_tasks.remove(ticket); + emit parseFinished(); + }, + Qt::ConnectionType::QueuedConnection); m_helper_thread_task.addTask(task); @@ -630,3 +635,26 @@ QString ResourceFolderModel::instDirPath() const { return QFileInfo(m_instance->instanceRoot()).absoluteFilePath(); } + +void ResourceFolderModel::onParseFailed(int ticket, QString resource_id) +{ + auto iter = m_active_parse_tasks.constFind(ticket); + if (iter == m_active_parse_tasks.constEnd()) + return; + + auto removed_index = m_resources_index[resource_id]; + auto removed_it = m_resources.begin() + removed_index; + Q_ASSERT(removed_it != m_resources.end()); + + beginRemoveRows(QModelIndex(), removed_index, removed_index); + m_resources.erase(removed_it); + + // update index + m_resources_index.clear(); + int idx = 0; + for (auto const& mod : qAsConst(m_resources)) { + m_resources_index[mod->internal_id()] = idx; + idx++; + } + endRemoveRows(); +} diff --git a/launcher/minecraft/mod/ResourceFolderModel.h b/launcher/minecraft/mod/ResourceFolderModel.h index 60b8879c0..d6ac6e0df 100644 --- a/launcher/minecraft/mod/ResourceFolderModel.h +++ b/launcher/minecraft/mod/ResourceFolderModel.h @@ -143,6 +143,7 @@ class ResourceFolderModel : public QAbstractListModel { signals: void updateFinished(); + void parseFinished(); protected: /** This creates a new update task to be executed by update(). @@ -189,11 +190,7 @@ class ResourceFolderModel : public QAbstractListModel { * if the resource is complex and has more stuff to parse. */ virtual void onParseSucceeded(int ticket, QString resource_id); - virtual void onParseFailed(int ticket, QString resource_id) - { - Q_UNUSED(ticket); - Q_UNUSED(resource_id); - } + virtual void onParseFailed(int ticket, QString resource_id); protected: // Represents the relationship between a column's index (represented by the list index), and it's sorting key. diff --git a/launcher/minecraft/mod/ShaderPack.cpp b/launcher/minecraft/mod/ShaderPack.cpp index 2c094f26a..ccb344cb5 100644 --- a/launcher/minecraft/mod/ShaderPack.cpp +++ b/launcher/minecraft/mod/ShaderPack.cpp @@ -35,8 +35,3 @@ bool ShaderPack::valid() const { return m_pack_format != ShaderPackFormat::INVALID; } - -bool ShaderPack::applyFilter(QRegularExpression filter) const -{ - return valid() && Resource::applyFilter(filter); -} diff --git a/launcher/minecraft/mod/ShaderPack.h b/launcher/minecraft/mod/ShaderPack.h index d07c124be..ec0f9404e 100644 --- a/launcher/minecraft/mod/ShaderPack.h +++ b/launcher/minecraft/mod/ShaderPack.h @@ -54,7 +54,6 @@ class ShaderPack : public Resource { void setPackFormat(ShaderPackFormat new_format); bool valid() const override; - [[nodiscard]] bool applyFilter(QRegularExpression filter) const override; protected: mutable QMutex m_data_lock; diff --git a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp index e9e12d86a..0594351cb 100644 --- a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp @@ -746,7 +746,7 @@ void LocalModParseTask::executeTask() m_result->details = mod.details(); if (m_aborted) - emit finished(); + emitAborted(); else emitSucceeded(); } diff --git a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp index 26bc07637..f495c9b8d 100644 --- a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp @@ -286,8 +286,10 @@ bool LocalResourcePackParseTask::abort() void LocalResourcePackParseTask::executeTask() { - if (!ResourcePackUtils::process(m_resource_pack)) + if (!ResourcePackUtils::process(m_resource_pack)) { + emitFailed("this is not a resource pack"); return; + } if (m_aborted) emitAborted(); diff --git a/launcher/minecraft/mod/tasks/LocalShaderPackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalShaderPackParseTask.cpp index a9949735b..4deebcd1d 100644 --- a/launcher/minecraft/mod/tasks/LocalShaderPackParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalShaderPackParseTask.cpp @@ -103,8 +103,10 @@ bool LocalShaderPackParseTask::abort() void LocalShaderPackParseTask::executeTask() { - if (!ShaderPackUtils::process(m_shader_pack)) + if (!ShaderPackUtils::process(m_shader_pack)) { + emitFailed("this is not a shader pack"); return; + } if (m_aborted) emitAborted(); diff --git a/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp index d7e61ca90..00cc2def2 100644 --- a/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp @@ -241,8 +241,10 @@ bool LocalTexturePackParseTask::abort() void LocalTexturePackParseTask::executeTask() { - if (!TexturePackUtils::process(m_texture_pack)) + if (!TexturePackUtils::process(m_texture_pack)) { + emitFailed("this is not a texture pack"); return; + } if (m_aborted) emitAborted(); diff --git a/launcher/ui/pages/instance/ExternalResourcesPage.cpp b/launcher/ui/pages/instance/ExternalResourcesPage.cpp index 1a8fafa9b..f46f8af5f 100644 --- a/launcher/ui/pages/instance/ExternalResourcesPage.cpp +++ b/launcher/ui/pages/instance/ExternalResourcesPage.cpp @@ -87,6 +87,7 @@ ExternalResourcesPage::ExternalResourcesPage(BaseInstance* instance, std::shared }; connect(selection_model, &QItemSelectionModel::selectionChanged, this, updateExtra); connect(model.get(), &ResourceFolderModel::updateFinished, this, updateExtra); + connect(model.get(), &ResourceFolderModel::parseFinished, this, updateExtra); connect(ui->filterEdit, &QLineEdit::textChanged, this, &ExternalResourcesPage::filterTextChanged); From 17916dbd2439f3af8a5b29f1fba2cf9703e6c8ad Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 12 Nov 2023 20:27:55 +0200 Subject: [PATCH 034/223] Fixed inconsistent Ok in instance import Signed-off-by: Trial97 --- launcher/ui/dialogs/NewInstanceDialog.cpp | 3 +++ launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp | 1 + 2 files changed, 4 insertions(+) diff --git a/launcher/ui/dialogs/NewInstanceDialog.cpp b/launcher/ui/dialogs/NewInstanceDialog.cpp index 6f3f7f7ec..3524d43f8 100644 --- a/launcher/ui/dialogs/NewInstanceDialog.cpp +++ b/launcher/ui/dialogs/NewInstanceDialog.cpp @@ -97,6 +97,9 @@ NewInstanceDialog::NewInstanceDialog(const QString& initialGroup, ui->verticalLayout->insertWidget(2, m_container); m_container->addButtons(m_buttons); + connect(m_container, &PageContainer::selectedPageChanged, this, [this](BasePage* previous, BasePage* selected) { + m_buttons->button(QDialogButtonBox::Ok)->setEnabled(creationTask && !instName().isEmpty()); + }); // Bonk Qt over its stupid head and make sure it understands which button is the default one... // See: https://stackoverflow.com/questions/24556831/qbuttonbox-set-default-button diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index 8e2b9a902..2da9a712d 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -103,6 +103,7 @@ void ModrinthPage::retranslate() void ModrinthPage::openedImpl() { BasePage::openedImpl(); + suggestCurrent(); triggerSearch(); } From a531f32b693cd621de5abfbe0e6cf97b344f51a4 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 16 Nov 2023 13:26:29 +0200 Subject: [PATCH 035/223] fixed settings saving Signed-off-by: Trial97 --- launcher/InstanceCopyTask.cpp | 3 +-- launcher/settings/INIFile.cpp | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/launcher/InstanceCopyTask.cpp b/launcher/InstanceCopyTask.cpp index 8abf30640..cdcd61ba6 100644 --- a/launcher/InstanceCopyTask.cpp +++ b/launcher/InstanceCopyTask.cpp @@ -142,9 +142,8 @@ void InstanceCopyTask::copyFinished() if (!m_keepPlaytime) { inst->resetTimePlayed(); } - if (m_useLinks) - inst->addLinkedInstanceId(m_origInstance->id()); if (m_useLinks) { + inst->addLinkedInstanceId(m_origInstance->id()); auto allowed_symlinks_file = QFileInfo(FS::PathCombine(inst->gameRoot(), "allowed_symlinks.txt")); QByteArray allowed_symlinks; diff --git a/launcher/settings/INIFile.cpp b/launcher/settings/INIFile.cpp index 4fb11ed35..e97741f20 100644 --- a/launcher/settings/INIFile.cpp +++ b/launcher/settings/INIFile.cpp @@ -54,6 +54,7 @@ bool INIFile::saveFile(QString fileName) insert("ConfigVersion", "1.2"); QSettings _settings_obj{ fileName, QSettings::Format::IniFormat }; _settings_obj.setFallbacksEnabled(false); + _settings_obj.clear(); for (Iterator iter = begin(); iter != end(); iter++) _settings_obj.setValue(iter.key(), iter.value()); From 4e3132e8b2b18057f905668d3177098157ba2dac Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 17 Nov 2023 22:40:36 +0200 Subject: [PATCH 036/223] reseted the setting Signed-off-by: Trial97 --- launcher/BaseInstance.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/BaseInstance.cpp b/launcher/BaseInstance.cpp index d0b0ad3bc..3b6d69a78 100644 --- a/launcher/BaseInstance.cpp +++ b/launcher/BaseInstance.cpp @@ -65,7 +65,7 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s m_settings->registerSetting("lastLaunchTime", 0); m_settings->registerSetting("totalTimePlayed", 0); if (m_settings->get("totalTimePlayed").toLongLong() < 0) - m_settings->set("totalTimePlayed", 0); + m_settings->reset("totalTimePlayed"); m_settings->registerSetting("lastTimePlayed", 0); m_settings->registerSetting("linkedInstances", "[]"); From f7e478c7559549c1342a23f488f9df7b85d4ffbd Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 19 Nov 2023 02:02:02 +0200 Subject: [PATCH 037/223] Added all supported files filter Signed-off-by: Trial97 --- launcher/ui/pages/modplatform/ImportPage.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/launcher/ui/pages/modplatform/ImportPage.cpp b/launcher/ui/pages/modplatform/ImportPage.cpp index 3e3c36b7b..26cd25e5f 100644 --- a/launcher/ui/pages/modplatform/ImportPage.cpp +++ b/launcher/ui/pages/modplatform/ImportPage.cpp @@ -200,7 +200,9 @@ void ImportPage::setExtraInfo(const QMap& extra_info) void ImportPage::on_modpackBtn_clicked() { - auto filter = QMimeDatabase().mimeTypeForName("application/zip").filterString(); + auto filter = + tr("Supported files") + QString(" (%1 *.mrpack)").arg(QMimeDatabase().mimeTypeForName("application/zip").globPatterns().join(" ")); + filter += ";;" + QMimeDatabase().mimeTypeForName("application/zip").filterString(); //: Option for filtering for *.mrpack files when importing filter += ";;" + tr("Modrinth pack") + " (*.mrpack)"; const QUrl url = QFileDialog::getOpenFileUrl(this, tr("Choose modpack"), modpackUrl(), filter); From 76216335b1b81e51885d66eeac55359435705f7b Mon Sep 17 00:00:00 2001 From: Alexandru Ionut Tripon Date: Sun, 19 Nov 2023 15:26:47 +0200 Subject: [PATCH 038/223] Update launcher/ui/pages/modplatform/ImportPage.cpp Co-authored-by: TheKodeToad Signed-off-by: Alexandru Ionut Tripon --- launcher/ui/pages/modplatform/ImportPage.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/launcher/ui/pages/modplatform/ImportPage.cpp b/launcher/ui/pages/modplatform/ImportPage.cpp index 26cd25e5f..d4f6339e1 100644 --- a/launcher/ui/pages/modplatform/ImportPage.cpp +++ b/launcher/ui/pages/modplatform/ImportPage.cpp @@ -200,9 +200,10 @@ void ImportPage::setExtraInfo(const QMap& extra_info) void ImportPage::on_modpackBtn_clicked() { - auto filter = - tr("Supported files") + QString(" (%1 *.mrpack)").arg(QMimeDatabase().mimeTypeForName("application/zip").globPatterns().join(" ")); - filter += ";;" + QMimeDatabase().mimeTypeForName("application/zip").filterString(); + const QMimeType zip = QMimeDatabase().mimeTypeForName("application/zip"); + const QString filter = + tr("Supported files") + QString(" (%1 *.mrpack)").arg(zip.globPatterns().join(" ")); + filter += ";;" + zip.filterString(); //: Option for filtering for *.mrpack files when importing filter += ";;" + tr("Modrinth pack") + " (*.mrpack)"; const QUrl url = QFileDialog::getOpenFileUrl(this, tr("Choose modpack"), modpackUrl(), filter); From 80c85aef99e47a767f45767106e72fbb10ef33d0 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 19 Nov 2023 15:37:18 +0200 Subject: [PATCH 039/223] fixed const stuff Signed-off-by: Trial97 --- launcher/ui/pages/modplatform/ImportPage.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/launcher/ui/pages/modplatform/ImportPage.cpp b/launcher/ui/pages/modplatform/ImportPage.cpp index d4f6339e1..ae4bd49d7 100644 --- a/launcher/ui/pages/modplatform/ImportPage.cpp +++ b/launcher/ui/pages/modplatform/ImportPage.cpp @@ -200,9 +200,8 @@ void ImportPage::setExtraInfo(const QMap& extra_info) void ImportPage::on_modpackBtn_clicked() { - const QMimeType zip = QMimeDatabase().mimeTypeForName("application/zip"); - const QString filter = - tr("Supported files") + QString(" (%1 *.mrpack)").arg(zip.globPatterns().join(" ")); + const QMimeType zip = QMimeDatabase().mimeTypeForName("application/zip"); + auto filter = tr("Supported files") + QString(" (%1 *.mrpack)").arg(zip.globPatterns().join(" ")); filter += ";;" + zip.filterString(); //: Option for filtering for *.mrpack files when importing filter += ";;" + tr("Modrinth pack") + " (*.mrpack)"; From 681e76c551df3e1c9daf07d0b8075d2cca77c832 Mon Sep 17 00:00:00 2001 From: bit6tream Date: Wed, 22 Nov 2023 01:48:31 +0300 Subject: [PATCH 040/223] (#1693) Notify user if /tmp directory has `noexec` mount option Minecraft versions starting from 1.19 would not start at all if /tmp is mounted as `noexec`. Signed-off-by: bit6tream --- launcher/Application.cpp | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index be252f1c5..619215162 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -82,6 +82,7 @@ #include #include +#include #include #include @@ -132,6 +133,10 @@ #include "gamemode_client.h" #endif +#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) +#include +#endif + #if defined(Q_OS_MAC) #if defined(SPARKLE_ENABLED) #include "updater/MacSparkleUpdater.h" @@ -988,6 +993,36 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) } } +#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) + + // notify user if /tmp is mounted with `noexec` (#1693) + { + FILE* description = setmntent(MOUNTED, "r"); + mntent* info = nullptr; + + while ((info = getmntent(description)) != nullptr) { + std::string_view directory = info->mnt_dir; + std::string_view options = info->mnt_opts; + + if (directory == "/tmp" && options.rfind("noexec") != std::string_view::npos) { + auto infoMsg = + tr("Your /tmp directory is currently mounted with the 'noexec' flag enabled.\n" + "Some versions of Minecraft may not launch.\n"); + auto msgBox = new QMessageBox(QMessageBox::Information, tr("Incompatible system configuration"), infoMsg, QMessageBox::Ok); + msgBox->setDefaultButton(QMessageBox::Ok); + msgBox->setAttribute(Qt::WA_DeleteOnClose); + msgBox->setMinimumWidth(460); + msgBox->adjustSize(); + msgBox->open(); + break; + } + } + + endmntent(description); + } + +#endif + if (createSetupWizard()) { return; } From 6169af70db9a58304e5517a8caeb05515a083aa6 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 23 Nov 2023 11:59:35 +0200 Subject: [PATCH 041/223] Added back the FIXME comment Signed-off-by: Trial97 --- launcher/ui/pages/instance/ManagedPackPage.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/launcher/ui/pages/instance/ManagedPackPage.cpp b/launcher/ui/pages/instance/ManagedPackPage.cpp index c419066a0..2210d0263 100644 --- a/launcher/ui/pages/instance/ManagedPackPage.cpp +++ b/launcher/ui/pages/instance/ManagedPackPage.cpp @@ -489,6 +489,7 @@ void FlameManagedPackPage::parseManagedPack() QString FlameManagedPackPage::url() const { + // FIXME: We should display the websiteUrl field, but this requires doing the API request first :( return "https://www.curseforge.com/projects/" + m_inst->getManagedPackID(); } From ceb88a170e4851baa722761235736fb9d025fb31 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 23 Nov 2023 12:22:31 +0200 Subject: [PATCH 042/223] Extracted reauthenticateCurrentAccount as a separate function Signed-off-by: Trial97 --- launcher/LaunchController.cpp | 53 ++++++++++++++++++++--------------- launcher/LaunchController.h | 1 + 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/launcher/LaunchController.cpp b/launcher/LaunchController.cpp index 2c76fee4f..a72cc58b1 100644 --- a/launcher/LaunchController.cpp +++ b/launcher/LaunchController.cpp @@ -258,29 +258,8 @@ void LaunchController::login() continue; } case AccountState::Expired: { - auto errorString = tr("The account has expired and needs to be logged into manually. Press OK to log in again."); - auto button = QMessageBox::warning(m_parentWidget, tr("Account refresh failed"), errorString, - QMessageBox::StandardButton::Ok | QMessageBox::StandardButton::Cancel, - QMessageBox::StandardButton::Ok); - if (button == QMessageBox::StandardButton::Ok) { - auto accounts = APPLICATION->accounts(); - bool isDefault = accounts->defaultAccount() == m_accountToUse; - accounts->removeAccount(accounts->index(accounts->findAccountByProfileId(m_accountToUse->profileId()))); - if (m_accountToUse->isMSA()) { - auto newAccount = MSALoginDialog::newAccount( - m_parentWidget, tr("Please enter your Mojang account email and password to add your account.")); - accounts->addAccount(newAccount); - if (isDefault) { - accounts->setDefaultAccount(newAccount); - } - m_accountToUse = nullptr; - decideAccount(); - continue; - } - emitFailed(tr("Account expired and re-login attempt failed")); - } else { - emitFailed(errorString); - } + if (reauthenticateCurrentAccount()) + continue; return; } case AccountState::Disabled: { @@ -304,6 +283,34 @@ void LaunchController::login() emitFailed(tr("Failed to launch.")); } +bool LaunchController::reauthenticateCurrentAccount() +{ + auto button = + QMessageBox::warning(m_parentWidget, tr("Account refresh failed"), + tr("The account has expired and needs to be reauthenticated. Do you want to reauthenticate this account?"), + QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No, QMessageBox::StandardButton::Yes); + if (button == QMessageBox::StandardButton::Yes) { + auto accounts = APPLICATION->accounts(); + bool isDefault = accounts->defaultAccount() == m_accountToUse; + accounts->removeAccount(accounts->index(accounts->findAccountByProfileId(m_accountToUse->profileId()))); + if (m_accountToUse->isMSA()) { + auto newAccount = + MSALoginDialog::newAccount(m_parentWidget, tr("Please enter your Mojang account email and password to add your account.")); + accounts->addAccount(newAccount); + if (isDefault) { + accounts->setDefaultAccount(newAccount); + } + m_accountToUse = nullptr; + decideAccount(); + return true; + } + emitFailed(tr("Account expired and re-login attempt failed")); + } else { + emitFailed(tr("The account has expired and needs to be reauthenticated")); + } + return false; +} + void LaunchController::launchInstance() { Q_ASSERT_X(m_instance != NULL, "launchInstance", "instance is NULL"); diff --git a/launcher/LaunchController.h b/launcher/LaunchController.h index f1c88afb7..33aedb063 100644 --- a/launcher/LaunchController.h +++ b/launcher/LaunchController.h @@ -74,6 +74,7 @@ class LaunchController : public Task { void login(); void launchInstance(); void decideAccount(); + bool reauthenticateCurrentAccount(); private slots: void readyForLaunch(); From 93454163618f4500732a079b7943db2fbe22fc66 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 23 Nov 2023 12:29:42 +0200 Subject: [PATCH 043/223] Fixed localization stuff Signed-off-by: Trial97 --- launcher/LaunchController.cpp | 5 ++--- launcher/minecraft/auth/AccountList.cpp | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/launcher/LaunchController.cpp b/launcher/LaunchController.cpp index 271297d5c..3f3cf2e7e 100644 --- a/launcher/LaunchController.cpp +++ b/launcher/LaunchController.cpp @@ -42,7 +42,6 @@ #include "ui/InstanceWindow.h" #include "ui/MainWindow.h" #include "ui/dialogs/CustomMessageBox.h" -#include "ui/dialogs/EditAccountDialog.h" #include "ui/dialogs/MSALoginDialog.h" #include "ui/dialogs/ProfileSelectDialog.h" #include "ui/dialogs/ProfileSetupDialog.h" @@ -145,7 +144,7 @@ void LaunchController::login() bool tryagain = true; unsigned int tries = 0; - if (!m_accountToUse->isOffline() && m_accountToUse->accountState() == AccountState::Offline) { + if (m_accountToUse->accountType() != AccountType::Offline && m_accountToUse->accountState() == AccountState::Offline) { // Force account refresh on the account used to launch the instance updating the AccountState // only on first try and if it is not meant to be offline auto accounts = APPLICATION->accounts(); @@ -293,7 +292,7 @@ bool LaunchController::reauthenticateCurrentAccount() auto accounts = APPLICATION->accounts(); bool isDefault = accounts->defaultAccount() == m_accountToUse; accounts->removeAccount(accounts->index(accounts->findAccountByProfileId(m_accountToUse->profileId()))); - if (m_accountToUse->isMSA()) { + if (m_accountToUse->accountType() == AccountType::MSA) { auto newAccount = MSALoginDialog::newAccount(m_parentWidget, tr("Please enter your Mojang account email and password to add your account.")); accounts->addAccount(newAccount); diff --git a/launcher/minecraft/auth/AccountList.cpp b/launcher/minecraft/auth/AccountList.cpp index c3c09003c..68ebe3626 100644 --- a/launcher/minecraft/auth/AccountList.cpp +++ b/launcher/minecraft/auth/AccountList.cpp @@ -52,8 +52,6 @@ #include #include -#include - enum AccountListVersion { MojangMSA = 3 }; AccountList::AccountList(QObject* parent) : QAbstractListModel(parent) From d414599974c6a8dc1a11fa769dff9e0f8feb5f01 Mon Sep 17 00:00:00 2001 From: bit6tream Date: Thu, 23 Nov 2023 15:19:04 +0300 Subject: [PATCH 044/223] (#1693) Use a better approach to detect a noexec mount option Signed-off-by: bit6tream --- launcher/Application.cpp | 55 ++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 619215162..cfede9dc1 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -82,7 +82,6 @@ #include #include -#include #include #include @@ -133,8 +132,13 @@ #include "gamemode_client.h" #endif -#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) -#include +#if defined(Q_OS_LINUX) +#include +#endif + +#if defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) +#include +#include #endif #if defined(Q_OS_MAC) @@ -993,36 +997,37 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) } } -#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) - // notify user if /tmp is mounted with `noexec` (#1693) { - FILE* description = setmntent(MOUNTED, "r"); - mntent* info = nullptr; + bool is_tmp_noexec = false; - while ((info = getmntent(description)) != nullptr) { - std::string_view directory = info->mnt_dir; - std::string_view options = info->mnt_opts; +#if defined(Q_OS_LINUX) - if (directory == "/tmp" && options.rfind("noexec") != std::string_view::npos) { - auto infoMsg = - tr("Your /tmp directory is currently mounted with the 'noexec' flag enabled.\n" - "Some versions of Minecraft may not launch.\n"); - auto msgBox = new QMessageBox(QMessageBox::Information, tr("Incompatible system configuration"), infoMsg, QMessageBox::Ok); - msgBox->setDefaultButton(QMessageBox::Ok); - msgBox->setAttribute(Qt::WA_DeleteOnClose); - msgBox->setMinimumWidth(460); - msgBox->adjustSize(); - msgBox->open(); - break; - } - } + struct statvfs tmp_stat; + statvfs("/tmp", &tmp_stat); + is_tmp_noexec = tmp_stat.f_flag & ST_NOEXEC; - endmntent(description); - } +#elif defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) + + struct statfs tmp_stat; + statfs("/tmp", &tmp_stat); + is_tmp_noexec = tmp_stat.f_flags & MNT_NOEXEC; #endif + if (is_tmp_noexec) { + auto infoMsg = + tr("Your /tmp directory is currently mounted with the 'noexec' flag enabled.\n" + "Some versions of Minecraft may not launch.\n"); + auto msgBox = new QMessageBox(QMessageBox::Information, tr("Incompatible system configuration"), infoMsg, QMessageBox::Ok); + msgBox->setDefaultButton(QMessageBox::Ok); + msgBox->setAttribute(Qt::WA_DeleteOnClose); + msgBox->setMinimumWidth(460); + msgBox->adjustSize(); + msgBox->open(); + } + } + if (createSetupWizard()) { return; } From 67b51b7a184bd9d8432f253ffb6fee4fa1259c33 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 26 Nov 2023 00:19:22 +0000 Subject: [PATCH 045/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'nixpkgs': 'github:nixos/nixpkgs/7414e9ee0b3e9903c24d3379f577a417f0aae5f1' (2023-11-16) → 'github:nixos/nixpkgs/0bd59c54ef06bc34eca01e37d689f5e46b3fe2f1' (2023-11-24) • Updated input 'pre-commit-hooks': 'github:cachix/pre-commit-hooks.nix/e558068cba67b23b4fbc5537173dbb43748a17e8' (2023-11-15) → 'github:cachix/pre-commit-hooks.nix/e5ee5c5f3844550c01d2131096c7271cec5e9b78' (2023-11-25) --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index 3422af0ac..18ae9c463 100644 --- a/flake.lock +++ b/flake.lock @@ -106,11 +106,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1700108881, - "narHash": "sha256-+Lqybl8kj0+nD/IlAWPPG/RDTa47gff9nbei0u7BntE=", + "lastModified": 1700856099, + "narHash": "sha256-RnEA7iJ36Ay9jI0WwP+/y4zjEhmeN6Cjs9VOFBH7eVQ=", "owner": "nixos", "repo": "nixpkgs", - "rev": "7414e9ee0b3e9903c24d3379f577a417f0aae5f1", + "rev": "0bd59c54ef06bc34eca01e37d689f5e46b3fe2f1", "type": "github" }, "original": { @@ -153,11 +153,11 @@ ] }, "locked": { - "lastModified": 1700064067, - "narHash": "sha256-1ZWNDzhu8UlVCK7+DUN9dVQfiHX1bv6OQP9VxstY/gs=", + "lastModified": 1700922917, + "narHash": "sha256-ej2fch/T584b5K9sk1UhmZF7W6wEfDHuoUYpFN8dtvM=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "e558068cba67b23b4fbc5537173dbb43748a17e8", + "rev": "e5ee5c5f3844550c01d2131096c7271cec5e9b78", "type": "github" }, "original": { From 2d91bd09d413177c9382e7b101cc4cd8f7d78b45 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 26 Nov 2023 23:49:56 +0200 Subject: [PATCH 046/223] Fixed crash on abort function not initialized Signed-off-by: Trial97 --- launcher/ui/pages/modplatform/ResourceModel.cpp | 6 ++++++ launcher/ui/pages/modplatform/flame/FlameModel.cpp | 4 ++++ launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp | 4 ++++ 3 files changed, 14 insertions(+) diff --git a/launcher/ui/pages/modplatform/ResourceModel.cpp b/launcher/ui/pages/modplatform/ResourceModel.cpp index c83e844c3..6c02150bd 100644 --- a/launcher/ui/pages/modplatform/ResourceModel.cpp +++ b/launcher/ui/pages/modplatform/ResourceModel.cpp @@ -234,6 +234,12 @@ void ResourceModel::loadEntry(QModelIndex& entry) return; QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load project info:%1").arg(reason)); }; + if (!callbacks.on_abort) + callbacks.on_abort = [this] { + if (!s_running_models.constFind(this).value()) + return; + qCritical() << tr("The request was abborted for an unknown reason"); + }; if (auto job = m_api->getProjectInfo(std::move(args), std::move(callbacks)); job) runInfoJob(job); diff --git a/launcher/ui/pages/modplatform/flame/FlameModel.cpp b/launcher/ui/pages/modplatform/flame/FlameModel.cpp index 8875a9452..3b266bcef 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModel.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModel.cpp @@ -170,6 +170,10 @@ void ListModel::performPaginatedSearch() callbacks.on_fail = [this](QString reason) { searchRequestFailed(reason); }; callbacks.on_succeed = [this](auto& doc, auto& pack) { searchRequestForOneSucceeded(doc); }; + callbacks.on_abort = [this] { + qCritical() << "Search task aborted by an unknown reason!"; + searchRequestFailed("Abborted"); + }; static const FlameAPI api; if (auto job = api.getProjectInfo({ projectId }, std::move(callbacks)); job) { jobPtr = job; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index f691a185d..227ed646b 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -140,6 +140,10 @@ void ModpackListModel::performPaginatedSearch() callbacks.on_fail = [this](QString reason) { searchRequestFailed(reason); }; callbacks.on_succeed = [this](auto& doc, auto& pack) { searchRequestForOneSucceeded(doc); }; + callbacks.on_abort = [this] { + qCritical() << "Search task aborted by an unknown reason!"; + searchRequestFailed("Abborted"); + }; static const ModrinthAPI api; if (auto job = api.getProjectInfo({ projectId }, std::move(callbacks)); job) { jobPtr = job; From 463ff4c6ae9362c70e4f70eea0805ce7b6931145 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Mon, 27 Nov 2023 11:30:07 +0200 Subject: [PATCH 047/223] Removed assert permanantly Signed-off-by: Trial97 --- launcher/minecraft/mod/ResourceFolderModel.h | 1 - 1 file changed, 1 deletion(-) diff --git a/launcher/minecraft/mod/ResourceFolderModel.h b/launcher/minecraft/mod/ResourceFolderModel.h index d764280b6..90e3aac2d 100644 --- a/launcher/minecraft/mod/ResourceFolderModel.h +++ b/launcher/minecraft/mod/ResourceFolderModel.h @@ -306,7 +306,6 @@ void ResourceFolderModel::applyUpdates(QSet& current_set, QSet auto removed_it = m_resources.begin() + removed_index; Q_ASSERT(removed_it != m_resources.end()); - Q_ASSERT(removed_set.contains(removed_it->get()->internal_id())); if ((*removed_it)->isResolving()) { auto ticket = (*removed_it)->resolutionTicket(); From a74c3d57b44a297760863e2ed42dfa643beade0d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 20:27:48 +0000 Subject: [PATCH 048/223] chore(deps): update cachix/install-nix-action action to v24 --- .github/workflows/update-flake.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-flake.yml b/.github/workflows/update-flake.yml index 6a16b0369..538972968 100644 --- a/.github/workflows/update-flake.yml +++ b/.github/workflows/update-flake.yml @@ -17,7 +17,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: cachix/install-nix-action@6a9a9e84a173d90b3ffb42c5ddaf9ea033fad011 # v23 + - uses: cachix/install-nix-action@7ac1ec25491415c381d9b62f0657c7a028df52a7 # v24 - uses: DeterminateSystems/update-flake-lock@v20 with: From eb011e6729fe49da867e6ae1ab2524424eedac46 Mon Sep 17 00:00:00 2001 From: DioEgizio <83089242+DioEgizio@users.noreply.github.com> Date: Sat, 2 Dec 2023 17:42:24 +0100 Subject: [PATCH 049/223] chore: update qt to qt 6.6.1 Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com> --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4fb2d6794..24e7194ae 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -61,7 +61,7 @@ jobs: qt_ver: 6 qt_host: windows qt_arch: '' - qt_version: '6.6.0' + qt_version: '6.6.1' qt_modules: 'qt5compat qtimageformats' qt_tools: '' @@ -73,7 +73,7 @@ jobs: qt_ver: 6 qt_host: windows qt_arch: 'win64_msvc2019_arm64' - qt_version: '6.6.0' + qt_version: '6.6.1' qt_modules: 'qt5compat qtimageformats' qt_tools: '' @@ -83,7 +83,7 @@ jobs: qt_ver: 6 qt_host: mac qt_arch: '' - qt_version: '6.6.0' + qt_version: '6.6.1' qt_modules: 'qt5compat qtimageformats' qt_tools: '' From 8b4b0f2f018b84d545e4fba1071cf4b0456cec87 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 3 Dec 2023 00:19:28 +0000 Subject: [PATCH 050/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'flake-parts': 'github:hercules-ci/flake-parts/8c9fa2545007b49a5db5f650ae91f227672c3877' (2023-11-01) → 'github:hercules-ci/flake-parts/34fed993f1674c8d06d58b37ce1e0fe5eebcb9f5' (2023-12-01) • Updated input 'flake-parts/nixpkgs-lib': 'github:NixOS/nixpkgs/0cbe9f69c234a7700596e943bfae7ef27a31b735?dir=lib' (2023-10-29) → 'github:NixOS/nixpkgs/e92039b55bcd58469325ded85d4f58dd5a4eaf58?dir=lib' (2023-11-29) • Updated input 'nixpkgs': 'github:nixos/nixpkgs/0bd59c54ef06bc34eca01e37d689f5e46b3fe2f1' (2023-11-24) → 'github:nixos/nixpkgs/f5c27c6136db4d76c30e533c20517df6864c46ee' (2023-11-30) --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index 18ae9c463..efaa524f6 100644 --- a/flake.lock +++ b/flake.lock @@ -21,11 +21,11 @@ "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1698882062, - "narHash": "sha256-HkhafUayIqxXyHH1X8d9RDl1M2CkFgZLjKD3MzabiEo=", + "lastModified": 1701473968, + "narHash": "sha256-YcVE5emp1qQ8ieHUnxt1wCZCC3ZfAS+SRRWZ2TMda7E=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "8c9fa2545007b49a5db5f650ae91f227672c3877", + "rev": "34fed993f1674c8d06d58b37ce1e0fe5eebcb9f5", "type": "github" }, "original": { @@ -106,11 +106,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1700856099, - "narHash": "sha256-RnEA7iJ36Ay9jI0WwP+/y4zjEhmeN6Cjs9VOFBH7eVQ=", + "lastModified": 1701336116, + "narHash": "sha256-kEmpezCR/FpITc6yMbAh4WrOCiT2zg5pSjnKrq51h5Y=", "owner": "nixos", "repo": "nixpkgs", - "rev": "0bd59c54ef06bc34eca01e37d689f5e46b3fe2f1", + "rev": "f5c27c6136db4d76c30e533c20517df6864c46ee", "type": "github" }, "original": { @@ -123,11 +123,11 @@ "nixpkgs-lib": { "locked": { "dir": "lib", - "lastModified": 1698611440, - "narHash": "sha256-jPjHjrerhYDy3q9+s5EAsuhyhuknNfowY6yt6pjn9pc=", + "lastModified": 1701253981, + "narHash": "sha256-ztaDIyZ7HrTAfEEUt9AtTDNoCYxUdSd6NrRHaYOIxtk=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "0cbe9f69c234a7700596e943bfae7ef27a31b735", + "rev": "e92039b55bcd58469325ded85d4f58dd5a4eaf58", "type": "github" }, "original": { From 577c737d686df43ee777a3b0382b788bb34ec170 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 3 Dec 2023 20:00:50 +0200 Subject: [PATCH 051/223] Fixed askIfShouldUpdate dialog on mac Signed-off-by: Trial97 --- launcher/InstanceTask.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/launcher/InstanceTask.cpp b/launcher/InstanceTask.cpp index 5b2398268..53476897c 100644 --- a/launcher/InstanceTask.cpp +++ b/launcher/InstanceTask.cpp @@ -2,6 +2,8 @@ #include "ui/dialogs/CustomMessageBox.h" +#include + InstanceNameChange askForChangingInstanceName(QWidget* parent, const QString& old_name, const QString& new_name) { auto dialog = @@ -27,16 +29,15 @@ ShouldUpdate askIfShouldUpdate(QWidget* parent, QString original_version_name) "separate instance, or update the existing one?\n\nNOTE: Make sure you made a backup of your important instance data before " "updating, as worlds can be corrupted and some configuration may be lost (due to pack overrides).") .arg(original_version_name), - QMessageBox::Information, QMessageBox::Ok | QMessageBox::Reset | QMessageBox::Abort); - info->setButtonText(QMessageBox::Ok, QObject::tr("Update existing instance")); - info->setButtonText(QMessageBox::Abort, QObject::tr("Create new instance")); - info->setButtonText(QMessageBox::Reset, QObject::tr("Cancel")); + QMessageBox::Information, QMessageBox::Cancel); + QAbstractButton* update = info->addButton(QObject::tr("Update existing instance"), QMessageBox::AcceptRole); + QAbstractButton* skip = info->addButton(QObject::tr("Create new instance"), QMessageBox::ResetRole); info->exec(); - if (info->clickedButton() == info->button(QMessageBox::Ok)) + if (info->clickedButton() == update) return ShouldUpdate::Update; - if (info->clickedButton() == info->button(QMessageBox::Abort)) + if (info->clickedButton() == skip) return ShouldUpdate::SkipUpdating; return ShouldUpdate::Cancel; } From 132344df1cff26f2dbc16dd3a7dfacc53091b975 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 12:06:39 +0000 Subject: [PATCH 052/223] chore(deps): update korthout/backport-action action to v2.2.0 --- .github/workflows/backport.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index e5443439d..12850d697 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -24,7 +24,7 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} - name: Create backport PRs - uses: korthout/backport-action@v2.1.1 + uses: korthout/backport-action@v2.2.0 with: # Config README: https://github.com/korthout/backport-action#backport-action pull_description: |- From faedd0fd65123d328f4f767649d6529424642299 Mon Sep 17 00:00:00 2001 From: Archy <59789660+IceCryptonym@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:40:46 +1000 Subject: [PATCH 053/223] Add togglable status bar Signed-off-by: Archy <59789660+IceCryptonym@users.noreply.github.com> --- launcher/Application.cpp | 2 ++ launcher/ui/MainWindow.cpp | 15 +++++++++++++++ launcher/ui/MainWindow.h | 2 ++ launcher/ui/MainWindow.ui | 9 +++++++++ 4 files changed, 28 insertions(+) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index cfede9dc1..ff5eb2a66 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -668,6 +668,8 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) // The cat m_settings->registerSetting("TheCat", false); + m_settings->registerSetting("StatusBarVisible", true); + m_settings->registerSetting("ToolbarsLocked", false); m_settings->registerSetting("InstSortMode", "Name"); diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index 7b4d1c8a5..42de6c2c0 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -186,6 +186,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi ui->instanceToolBar->addContextMenuAction(ui->newsToolBar->toggleViewAction()); ui->instanceToolBar->addContextMenuAction(ui->instanceToolBar->toggleViewAction()); + ui->instanceToolBar->addContextMenuAction(ui->actionToggleStatusBar); ui->instanceToolBar->addContextMenuAction(ui->actionLockToolbars); } @@ -319,6 +320,14 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi setCatBackground(cat_enable); } + // Togglable status bar + { + bool statusBarVisible = APPLICATION->settings()->get("StatusBarVisible").toBool(); + ui->actionToggleStatusBar->setChecked(statusBarVisible); + connect(ui->actionToggleStatusBar, &QAction::toggled, this, &MainWindow::setStatusBarVisibility); + setStatusBarVisibility(statusBarVisible); + } + // Lock toolbars { bool toolbarsLocked = APPLICATION->settings()->get("ToolbarsLocked").toBool(); @@ -451,10 +460,16 @@ QMenu* MainWindow::createPopupMenu() QMenu* filteredMenu = QMainWindow::createPopupMenu(); filteredMenu->removeAction(ui->mainToolBar->toggleViewAction()); + filteredMenu->addAction(ui->actionToggleStatusBar); filteredMenu->addAction(ui->actionLockToolbars); return filteredMenu; } +void MainWindow::setStatusBarVisibility(bool state) +{ + statusBar()->setVisible(state); + APPLICATION->settings()->set("StatusBarVisible", state); +} void MainWindow::lockToolbars(bool state) { ui->mainToolBar->setMovable(!state); diff --git a/launcher/ui/MainWindow.h b/launcher/ui/MainWindow.h index d2e154643..07a6e1eba 100644 --- a/launcher/ui/MainWindow.h +++ b/launcher/ui/MainWindow.h @@ -205,6 +205,8 @@ class MainWindow : public QMainWindow { void globalSettingsClosed(); + void setStatusBarVisibility(bool); + void lockToolbars(bool); #ifndef Q_OS_MAC diff --git a/launcher/ui/MainWindow.ui b/launcher/ui/MainWindow.ui index 1ee3a5632..889012105 100644 --- a/launcher/ui/MainWindow.ui +++ b/launcher/ui/MainWindow.ui @@ -176,6 +176,7 @@ + @@ -257,6 +258,14 @@ It's a fluffy kitty :3 + + + true + + + Status Bar + + true From 877eb4172a737c44505b3c784e84ab710b291e5e Mon Sep 17 00:00:00 2001 From: Tayou Date: Thu, 7 Dec 2023 17:26:47 +0100 Subject: [PATCH 054/223] add line back to group separator Signed-off-by: Tayou --- launcher/ui/instanceview/VisualGroup.cpp | 28 +++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/launcher/ui/instanceview/VisualGroup.cpp b/launcher/ui/instanceview/VisualGroup.cpp index aaf31941d..7bff727fe 100644 --- a/launcher/ui/instanceview/VisualGroup.cpp +++ b/launcher/ui/instanceview/VisualGroup.cpp @@ -158,13 +158,14 @@ void VisualGroup::drawHeader(QPainter* painter, const QStyleOptionViewItem& opti painter->setRenderHint(QPainter::Antialiasing); // sizes and offsets, to keep things consistent below - int arrowOffsetLeft = fontMetrics.height() / 2 + 7; - int textOffsetLeft = arrowOffsetLeft * 2; - int arrowSize = 6; - int centerHeight = optRect.top() + fontMetrics.height() / 2; + const int arrowOffsetLeft = fontMetrics.height() / 2 + 7; + const int textOffsetLeft = arrowOffsetLeft * 2; + const int centerHeight = optRect.top() + fontMetrics.height() / 2; + const QString& textToDraw = text.isEmpty() ? QObject::tr("Ungrouped") : text; // BEGIN: arrow { + constexpr int arrowSize = 6; QPolygon arrowPolygon; if (collapsed) { arrowPolygon << QPoint(arrowOffsetLeft - arrowSize / 2, centerHeight - arrowSize) @@ -188,9 +189,26 @@ void VisualGroup::drawHeader(QPainter* painter, const QStyleOptionViewItem& opti textRect.setHeight(fontMetrics.height()); textRect.setRight(textRect.right() - 7); - painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, !text.isEmpty() ? text : QObject::tr("Ungrouped")); + painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, textToDraw); } // END: text + + // BEGIN: horizontal line + { + penColor.setAlphaF(0.05); + pen.setColor(penColor); + painter->setPen(pen); + // startPoint is left + arrow + text + space + const int startPoint = + optRect.left() + fontMetrics.height() + fontMetrics.size(Qt::AlignLeft | Qt::AlignVCenter, textToDraw).width() + 20; + painter->setRenderHint(QPainter::Antialiasing, false); + QPolygon polygon; + // for some reason the height (yPos) doesn't look centered, so we are adding 1 to the center height + const int lineHeight = centerHeight + 1; + polygon << QPoint(startPoint, lineHeight) << QPoint(optRect.right() - 3, lineHeight); + painter->drawPolyline(polygon); + } + // END: horizontal line } int VisualGroup::totalHeight() const From d7cb139235c732abb68ffbee70c45a76c998f2db Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 10 Dec 2023 00:20:06 +0000 Subject: [PATCH 055/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'nix-filter': 'github:numtide/nix-filter/41fd48e00c22b4ced525af521ead8792402de0ea' (2023-09-16) → 'github:numtide/nix-filter/c843418ecfd0344ecb85844b082ff5675e02c443' (2023-12-04) • Updated input 'nixpkgs': 'github:nixos/nixpkgs/f5c27c6136db4d76c30e533c20517df6864c46ee' (2023-11-30) → 'github:nixos/nixpkgs/09dc04054ba2ff1f861357d0e7e76d021b273cd7' (2023-12-08) --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index efaa524f6..afc584a24 100644 --- a/flake.lock +++ b/flake.lock @@ -91,11 +91,11 @@ }, "nix-filter": { "locked": { - "lastModified": 1694857738, - "narHash": "sha256-bxxNyLHjhu0N8T3REINXQ2ZkJco0ABFPn6PIe2QUfqo=", + "lastModified": 1701697642, + "narHash": "sha256-L217WytWZHSY8GW9Gx1A64OnNctbuDbfslaTEofXXRw=", "owner": "numtide", "repo": "nix-filter", - "rev": "41fd48e00c22b4ced525af521ead8792402de0ea", + "rev": "c843418ecfd0344ecb85844b082ff5675e02c443", "type": "github" }, "original": { @@ -106,11 +106,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1701336116, - "narHash": "sha256-kEmpezCR/FpITc6yMbAh4WrOCiT2zg5pSjnKrq51h5Y=", + "lastModified": 1701998057, + "narHash": "sha256-gAJGhcTO9cso7XDfAScXUlPcva427AUT2q02qrmXPdo=", "owner": "nixos", "repo": "nixpkgs", - "rev": "f5c27c6136db4d76c30e533c20517df6864c46ee", + "rev": "09dc04054ba2ff1f861357d0e7e76d021b273cd7", "type": "github" }, "original": { From 3567369d44c6ba9a3b702caf2db18b126f1b4fc4 Mon Sep 17 00:00:00 2001 From: theMackabu Date: Tue, 12 Dec 2023 13:18:12 -0800 Subject: [PATCH 056/223] #1945 resolve minimized windows pull from dock Signed-off-by: theMackabu --- .gitignore | 3 +++ launcher/Application.cpp | 8 ++++++++ maidfile.toml | 13 +++++++++++++ 3 files changed, 24 insertions(+) create mode 100644 maidfile.toml diff --git a/.gitignore b/.gitignore index b5523f685..9f69e985c 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,6 @@ flatbuild # Snap *.snap + +# maid build +.maid \ No newline at end of file diff --git a/launcher/Application.cpp b/launcher/Application.cpp index ff5eb2a66..9e95712a7 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -1513,6 +1513,13 @@ InstanceWindow* Application::showInstanceWindow(InstancePtr instance, QString pa auto& window = extras.window; if (window) { + // If the window is minimized on macOS, activate and bring it up + #ifdef Q_OS_MACOS + if (window->isMinimized()) { + window->setWindowState(window->windowState() & ~Qt::WindowMinimized); + } + #endif + window->raise(); window->activateWindow(); } else { @@ -1520,6 +1527,7 @@ InstanceWindow* Application::showInstanceWindow(InstancePtr instance, QString pa m_openWindows++; connect(window, &InstanceWindow::isClosing, this, &Application::on_windowClose); } + if (!page.isEmpty()) { window->selectPage(page); } diff --git a/maidfile.toml b/maidfile.toml new file mode 100644 index 000000000..fbd76b2e7 --- /dev/null +++ b/maidfile.toml @@ -0,0 +1,13 @@ +[project] +name = "Prism" +version = "8.0" + +[tasks] +run = { script = "./build/prismlauncher.app/Contents/MacOS/prismlauncher" } +clean = { script = ["rm -rf build", "mkdir build"] } +build = { script = ["maid init -q", "bash -c 'cd build && ninja'"] } + +[tasks.init] +depends = ["clean"] +path = "build" +script = "cmake -G Ninja -DCMAKE_INSTALL_PREFIX=install -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH='/opt/homebrew/opt/qt' -DQt6_DIR='/opt/homebrew/opt/qt' -DLauncher_BUILD_PLATFORM=macOS -DENABLE_LTO=ON .." From 836f74cd4629748ce8056f9f186284fc55d0d8b4 Mon Sep 17 00:00:00 2001 From: theMackabu Date: Tue, 12 Dec 2023 13:19:16 -0800 Subject: [PATCH 057/223] #1945 resolve issue on windows Signed-off-by: theMackabu --- launcher/Application.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 9e95712a7..6715a0709 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -1513,13 +1513,17 @@ InstanceWindow* Application::showInstanceWindow(InstancePtr instance, QString pa auto& window = extras.window; if (window) { - // If the window is minimized on macOS, activate and bring it up + // If the window is minimized on macOS or Windows, activate and bring it up #ifdef Q_OS_MACOS if (window->isMinimized()) { window->setWindowState(window->windowState() & ~Qt::WindowMinimized); } + #elif defined(Q_OS_WIN) + if (window->isMinimized()) { + window->showNormal(); + } #endif - + window->raise(); window->activateWindow(); } else { From 201c9783d56cef2e1bba1fdbffdc377bdf294468 Mon Sep 17 00:00:00 2001 From: theMackabu Date: Tue, 12 Dec 2023 13:31:18 -0800 Subject: [PATCH 058/223] clang-format: fix formatting Signed-off-by: theMackabu --- launcher/Application.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 6715a0709..5f524219e 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -1513,17 +1513,17 @@ InstanceWindow* Application::showInstanceWindow(InstancePtr instance, QString pa auto& window = extras.window; if (window) { - // If the window is minimized on macOS or Windows, activate and bring it up - #ifdef Q_OS_MACOS +// If the window is minimized on macOS or Windows, activate and bring it up +#ifdef Q_OS_MACOS if (window->isMinimized()) { window->setWindowState(window->windowState() & ~Qt::WindowMinimized); } - #elif defined(Q_OS_WIN) +#elif defined(Q_OS_WIN) if (window->isMinimized()) { window->showNormal(); } - #endif - +#endif + window->raise(); window->activateWindow(); } else { From 7c33a8e448d238960b89f1e1c2f14a18d12040eb Mon Sep 17 00:00:00 2001 From: theMackabu Date: Tue, 12 Dec 2023 13:37:24 -0800 Subject: [PATCH 059/223] remove: maidfile.toml (local build tool) Signed-off-by: theMackabu --- .gitignore | 5 +---- maidfile.toml | 13 ------------- 2 files changed, 1 insertion(+), 17 deletions(-) delete mode 100644 maidfile.toml diff --git a/.gitignore b/.gitignore index 9f69e985c..c699a54c3 100644 --- a/.gitignore +++ b/.gitignore @@ -55,7 +55,4 @@ result flatbuild # Snap -*.snap - -# maid build -.maid \ No newline at end of file +*.snap \ No newline at end of file diff --git a/maidfile.toml b/maidfile.toml deleted file mode 100644 index fbd76b2e7..000000000 --- a/maidfile.toml +++ /dev/null @@ -1,13 +0,0 @@ -[project] -name = "Prism" -version = "8.0" - -[tasks] -run = { script = "./build/prismlauncher.app/Contents/MacOS/prismlauncher" } -clean = { script = ["rm -rf build", "mkdir build"] } -build = { script = ["maid init -q", "bash -c 'cd build && ninja'"] } - -[tasks.init] -depends = ["clean"] -path = "build" -script = "cmake -G Ninja -DCMAKE_INSTALL_PREFIX=install -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH='/opt/homebrew/opt/qt' -DQt6_DIR='/opt/homebrew/opt/qt' -DLauncher_BUILD_PLATFORM=macOS -DENABLE_LTO=ON .." From 2391ad200f80ef6a84ffef246ed236d66928f0e4 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Tue, 12 Dec 2023 23:21:34 +0000 Subject: [PATCH 060/223] Revert change to .gitignore Signed-off-by: TheKodeToad --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index c699a54c3..b5523f685 100644 --- a/.gitignore +++ b/.gitignore @@ -55,4 +55,4 @@ result flatbuild # Snap -*.snap \ No newline at end of file +*.snap From 469aaf6051ab0d7bd22181d53e90bd8b7e73aedb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 13 Dec 2023 16:16:06 +0000 Subject: [PATCH 061/223] chore(deps): update github/codeql-action action to v3 --- .github/workflows/codeql.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a77b4ae1e..d40d7eb68 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -13,7 +13,7 @@ jobs: submodules: 'true' - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: config-file: ./.github/codeql/codeql-config.yml queries: security-and-quality @@ -32,4 +32,4 @@ jobs: cmake --build build - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 From 3d50bef10ccf74008642cda8c382d804b2750d3f Mon Sep 17 00:00:00 2001 From: guihkx <626206+guihkx@users.noreply.github.com> Date: Wed, 13 Dec 2023 15:09:13 -0300 Subject: [PATCH 062/223] chore: sync nightly flatpak manifest with flathub's Signed-off-by: guihkx <626206+guihkx@users.noreply.github.com> --- flatpak/org.prismlauncher.PrismLauncher.yml | 11 ++++------- flatpak/patches/gamemode.patch | 12 ------------ flatpak/shared-modules | 2 +- 3 files changed, 5 insertions(+), 20 deletions(-) delete mode 100644 flatpak/patches/gamemode.patch diff --git a/flatpak/org.prismlauncher.PrismLauncher.yml b/flatpak/org.prismlauncher.PrismLauncher.yml index 89727751e..c3ac132b1 100644 --- a/flatpak/org.prismlauncher.PrismLauncher.yml +++ b/flatpak/org.prismlauncher.PrismLauncher.yml @@ -1,6 +1,6 @@ id: org.prismlauncher.PrismLauncher runtime: org.kde.Platform -runtime-version: "5.15-23.08" +runtime-version: 5.15-23.08 sdk: org.kde.Sdk sdk-extensions: - org.freedesktop.Sdk.Extension.openjdk17 @@ -104,18 +104,15 @@ modules: - install -Dm755 ../data/gamemoderun -t /app/bin sources: - type: archive - archive-type: tar-gzip - url: https://api.github.com/repos/FeralInteractive/gamemode/tarball/1.7 - sha256: 57ce73ba605d1cf12f8d13725006a895182308d93eba0f69f285648449641803 + dest-filename: gamemode.tar.gz + url: https://api.github.com/repos/FeralInteractive/gamemode/tarball/1.8.1 + sha256: 969cf85b5ca3944f3e315cd73a0ee9bea4f9c968cd7d485e9f4745bc1e679c4e x-checker-data: type: json url: https://api.github.com/repos/FeralInteractive/gamemode/releases/latest version-query: .tag_name url-query: .tarball_url timestamp-query: .published_at - # from https://github.com/flathub/net.gaijin.WarThunder/blob/7ea6f7a9f84b9c77150c003a7059dc03f8dcbc7f/gamemode.patch - - type: patch - path: patches/gamemode.patch cleanup: - /include - /lib/pkgconfig diff --git a/flatpak/patches/gamemode.patch b/flatpak/patches/gamemode.patch deleted file mode 100644 index 3cc0d7412..000000000 --- a/flatpak/patches/gamemode.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -ruN a/common/common-pidfds.c b/common/common-pidfds.c ---- a/common/common-pidfds.c 2021-02-18 20:00:12.000000000 +0100 -+++ b/common/common-pidfds.c 2023-09-07 08:57:42.954362763 +0200 -@@ -58,6 +58,8 @@ - { - return (int)syscall(__NR_pidfd_open, pid, flags); - } -+#else -+#include - #endif - - /* pidfd functions */ diff --git a/flatpak/shared-modules b/flatpak/shared-modules index 45094ca57..55a8e460c 160000 --- a/flatpak/shared-modules +++ b/flatpak/shared-modules @@ -1 +1 @@ -Subproject commit 45094ca570be383d06df729b6972830ec63bd3df +Subproject commit 55a8e460c6343229597a13e973ba4855c27a1c4c From 400b518bc21b8a56131384fd4a56988d31bceb9f Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 14 Dec 2023 00:02:15 +0200 Subject: [PATCH 063/223] Removed auto reauthenticate Signed-off-by: Trial97 --- launcher/LaunchController.cpp | 35 ++++------------------------------- launcher/LaunchController.h | 1 - 2 files changed, 4 insertions(+), 32 deletions(-) diff --git a/launcher/LaunchController.cpp b/launcher/LaunchController.cpp index 3f3cf2e7e..a30f99439 100644 --- a/launcher/LaunchController.cpp +++ b/launcher/LaunchController.cpp @@ -42,7 +42,6 @@ #include "ui/InstanceWindow.h" #include "ui/MainWindow.h" #include "ui/dialogs/CustomMessageBox.h" -#include "ui/dialogs/MSALoginDialog.h" #include "ui/dialogs/ProfileSelectDialog.h" #include "ui/dialogs/ProfileSetupDialog.h" #include "ui/dialogs/ProgressDialog.h" @@ -257,8 +256,10 @@ void LaunchController::login() continue; } case AccountState::Expired: { - if (reauthenticateCurrentAccount()) - continue; + auto errorString = tr("The account has expired and needs to be logged into manually again."); + QMessageBox::warning(m_parentWidget, tr("Account refresh failed"), errorString, QMessageBox::StandardButton::Ok, + QMessageBox::StandardButton::Ok); + emitFailed(errorString); return; } case AccountState::Disabled: { @@ -282,34 +283,6 @@ void LaunchController::login() emitFailed(tr("Failed to launch.")); } -bool LaunchController::reauthenticateCurrentAccount() -{ - auto button = - QMessageBox::warning(m_parentWidget, tr("Account refresh failed"), - tr("The account has expired and needs to be reauthenticated. Do you want to reauthenticate this account?"), - QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No, QMessageBox::StandardButton::Yes); - if (button == QMessageBox::StandardButton::Yes) { - auto accounts = APPLICATION->accounts(); - bool isDefault = accounts->defaultAccount() == m_accountToUse; - accounts->removeAccount(accounts->index(accounts->findAccountByProfileId(m_accountToUse->profileId()))); - if (m_accountToUse->accountType() == AccountType::MSA) { - auto newAccount = - MSALoginDialog::newAccount(m_parentWidget, tr("Please enter your Mojang account email and password to add your account.")); - accounts->addAccount(newAccount); - if (isDefault) { - accounts->setDefaultAccount(newAccount); - } - m_accountToUse = nullptr; - decideAccount(); - return true; - } - emitFailed(tr("Account expired and re-login attempt failed")); - } else { - emitFailed(tr("The account has expired and needs to be reauthenticated")); - } - return false; -} - void LaunchController::launchInstance() { Q_ASSERT_X(m_instance != NULL, "launchInstance", "instance is NULL"); diff --git a/launcher/LaunchController.h b/launcher/LaunchController.h index 33aedb063..f1c88afb7 100644 --- a/launcher/LaunchController.h +++ b/launcher/LaunchController.h @@ -74,7 +74,6 @@ class LaunchController : public Task { void login(); void launchInstance(); void decideAccount(); - bool reauthenticateCurrentAccount(); private slots: void readyForLaunch(); From 0ccdcd23e3f3889f3e516d48bb03b27d3ddb62cc Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Thu, 14 Dec 2023 13:02:24 +0100 Subject: [PATCH 064/223] fix: open paths directly Signed-off-by: Sefa Eyeoglu --- launcher/DesktopServices.cpp | 68 +++---------------- launcher/DesktopServices.h | 17 +++-- launcher/FileSystem.cpp | 10 ++- launcher/FileSystem.h | 8 ++- launcher/ui/MainWindow.cpp | 18 ++--- launcher/ui/dialogs/IconPickerDialog.cpp | 2 +- .../pages/instance/ExternalResourcesPage.cpp | 4 +- .../ui/pages/instance/ScreenshotsPage.cpp | 4 +- launcher/ui/pages/instance/VersionPage.cpp | 4 +- launcher/ui/pages/instance/WorldListPage.cpp | 4 +- .../ui/widgets/ThemeCustomizationWidget.cpp | 6 +- 11 files changed, 52 insertions(+), 93 deletions(-) diff --git a/launcher/DesktopServices.cpp b/launcher/DesktopServices.cpp index 17eb7c2df..851516399 100644 --- a/launcher/DesktopServices.cpp +++ b/launcher/DesktopServices.cpp @@ -37,6 +37,7 @@ #include #include #include +#include "FileSystem.h" /** * This shouldn't exist, but until QTBUG-9328 and other unreported bugs are fixed, it needs to be a thing. @@ -96,81 +97,30 @@ bool IndirectOpen(T callable, qint64* pid_forked = nullptr) #endif namespace DesktopServices { -bool openDirectory(const QString& path, [[maybe_unused]] bool ensureExists) +bool openPath(const QFileInfo& path, [[maybe_unused]] bool ensureExists) { - qDebug() << "Opening directory" << path; - QDir parentPath; - QDir dir(path); - if (ensureExists && !dir.exists()) { - parentPath.mkpath(dir.absolutePath()); + qDebug() << "Opening path" << path; + if (ensureExists) { + FS::ensureFolderPathExists(path); } - auto f = [&]() { return QDesktopServices::openUrl(QUrl::fromLocalFile(dir.absolutePath())); }; -#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) - if (!isSandbox()) { - return IndirectOpen(f); - } -#endif - return f(); + return openUrl(QUrl::fromLocalFile(QFileInfo(path).absolutePath())); } -bool openFile(const QString& path) +bool openPath(const QString& path, [[maybe_unused]] bool ensureExists) { - qDebug() << "Opening file" << path; - auto f = [&]() { return QDesktopServices::openUrl(QUrl::fromLocalFile(path)); }; -#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) - if (!isSandbox()) { - return IndirectOpen(f); - } else { - return f(); - } -#else - return f(); -#endif -} - -bool openFile(const QString& application, const QString& path, const QString& workingDirectory, qint64* pid) -{ - qDebug() << "Opening file" << path << "using" << application; -#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) - // FIXME: the pid here is fake. So if something depends on it, it will likely misbehave - if (!isSandbox()) { - return IndirectOpen([&]() { return QProcess::startDetached(application, QStringList() << path, workingDirectory); }, pid); - } else { - return QProcess::startDetached(application, QStringList() << path, workingDirectory, pid); - } -#else - return QProcess::startDetached(application, QStringList() << path, workingDirectory, pid); -#endif + return openPath(QFileInfo(path), ensureExists); } bool run(const QString& application, const QStringList& args, const QString& workingDirectory, qint64* pid) { qDebug() << "Running" << application << "with args" << args.join(' '); -#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) - if (!isSandbox()) { - // FIXME: the pid here is fake. So if something depends on it, it will likely misbehave - return IndirectOpen([&]() { return QProcess::startDetached(application, args, workingDirectory); }, pid); - } else { - return QProcess::startDetached(application, args, workingDirectory, pid); - } -#else return QProcess::startDetached(application, args, workingDirectory, pid); -#endif } bool openUrl(const QUrl& url) { qDebug() << "Opening URL" << url.toString(); - auto f = [&]() { return QDesktopServices::openUrl(url); }; -#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) - if (!isSandbox()) { - return IndirectOpen(f); - } else { - return f(); - } -#else - return f(); -#endif + return QDesktopServices::openUrl(url); } bool isFlatpak() diff --git a/launcher/DesktopServices.h b/launcher/DesktopServices.h index 151db5557..770eac984 100644 --- a/launcher/DesktopServices.h +++ b/launcher/DesktopServices.h @@ -3,31 +3,30 @@ #include #include +class QFileInfo; + /** * This wraps around QDesktopServices and adds workarounds where needed * Use this instead of QDesktopServices! */ namespace DesktopServices { /** - * Open a file in whatever application is applicable + * Open a path in whatever application is applicable. + * @param ensurePathExists Make sure the path exists */ -bool openFile(const QString& path); +bool openPath(const QFileInfo& path, bool ensurePathExists = false); /** - * Open a file in the specified application + * Open a path in whatever application is applicable. + * @param ensurePathExists Make sure the path exists */ -bool openFile(const QString& application, const QString& path, const QString& workingDirectory = QString(), qint64* pid = 0); +bool openPath(const QString& path, bool ensurePathExists = false); /** * Run an application */ bool run(const QString& application, const QStringList& args, const QString& workingDirectory = QString(), qint64* pid = 0); -/** - * Open a directory - */ -bool openDirectory(const QString& path, bool ensureExists = false); - /** * Open the URL, most likely in a browser. Maybe. */ diff --git a/launcher/FileSystem.cpp b/launcher/FileSystem.cpp index a30d0ae0b..f9be91a2a 100644 --- a/launcher/FileSystem.cpp +++ b/launcher/FileSystem.cpp @@ -272,15 +272,19 @@ bool ensureFilePathExists(QString filenamepath) return success; } -bool ensureFolderPathExists(QString foldernamepath) +bool ensureFolderPathExists(const QFileInfo folderPath) { - QFileInfo a(foldernamepath); QDir dir; - QString ensuredPath = a.filePath(); + QString ensuredPath = folderPath.filePath(); bool success = dir.mkpath(ensuredPath); return success; } +bool ensureFolderPathExists(const QString folderPathName) +{ + return ensureFolderPathExists(QFileInfo(folderPathName)); +} + bool copyFileAttributes(QString src, QString dst) { #ifdef Q_OS_WIN32 diff --git a/launcher/FileSystem.h b/launcher/FileSystem.h index 861cfa267..f13fb9f28 100644 --- a/launcher/FileSystem.h +++ b/launcher/FileSystem.h @@ -91,7 +91,13 @@ bool ensureFilePathExists(QString filenamepath); * Creates all the folders in a path for the specified path * last segment of the path is treated as a folder name and is created! */ -bool ensureFolderPathExists(QString filenamepath); +bool ensureFolderPathExists(const QFileInfo folderPath); + +/** + * Creates all the folders in a path for the specified path + * last segment of the path is treated as a folder name and is created! + */ +bool ensureFolderPathExists(const QString folderPathName); /** * @brief Copies a directory and it's contents from src to dest diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index 42de6c2c0..9f2cc434f 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -1197,43 +1197,43 @@ void MainWindow::undoTrashInstance() void MainWindow::on_actionViewLauncherRootFolder_triggered() { - DesktopServices::openDirectory("."); + DesktopServices::openPath("."); } void MainWindow::on_actionViewInstanceFolder_triggered() { QString str = APPLICATION->settings()->get("InstanceDir").toString(); - DesktopServices::openDirectory(str); + DesktopServices::openPath(str); } void MainWindow::on_actionViewCentralModsFolder_triggered() { - DesktopServices::openDirectory(APPLICATION->settings()->get("CentralModsDir").toString(), true); + DesktopServices::openPath(APPLICATION->settings()->get("CentralModsDir").toString(), true); } void MainWindow::on_actionViewIconThemeFolder_triggered() { - DesktopServices::openDirectory(APPLICATION->themeManager()->getIconThemesFolder().path(), true); + DesktopServices::openPath(APPLICATION->themeManager()->getIconThemesFolder().path(), true); } void MainWindow::on_actionViewWidgetThemeFolder_triggered() { - DesktopServices::openDirectory(APPLICATION->themeManager()->getApplicationThemesFolder().path(), true); + DesktopServices::openPath(APPLICATION->themeManager()->getApplicationThemesFolder().path(), true); } void MainWindow::on_actionViewCatPackFolder_triggered() { - DesktopServices::openDirectory(APPLICATION->themeManager()->getCatPacksFolder().path(), true); + DesktopServices::openPath(APPLICATION->themeManager()->getCatPacksFolder().path(), true); } void MainWindow::on_actionViewIconsFolder_triggered() { - DesktopServices::openDirectory(APPLICATION->icons()->getDirectory(), true); + DesktopServices::openPath(APPLICATION->icons()->getDirectory(), true); } void MainWindow::on_actionViewLogsFolder_triggered() { - DesktopServices::openDirectory("logs", true); + DesktopServices::openPath("logs", true); } void MainWindow::refreshInstances() @@ -1452,7 +1452,7 @@ void MainWindow::on_actionViewSelectedInstFolder_triggered() { if (m_selectedInstance) { QString str = m_selectedInstance->instanceRoot(); - DesktopServices::openDirectory(QDir(str).absolutePath()); + DesktopServices::openPath(QDir(str).absolutePath()); } } diff --git a/launcher/ui/dialogs/IconPickerDialog.cpp b/launcher/ui/dialogs/IconPickerDialog.cpp index faad3ce75..a196fd587 100644 --- a/launcher/ui/dialogs/IconPickerDialog.cpp +++ b/launcher/ui/dialogs/IconPickerDialog.cpp @@ -159,5 +159,5 @@ IconPickerDialog::~IconPickerDialog() void IconPickerDialog::openFolder() { - DesktopServices::openDirectory(APPLICATION->icons()->getDirectory(), true); + DesktopServices::openPath(APPLICATION->icons()->getDirectory(), true); } diff --git a/launcher/ui/pages/instance/ExternalResourcesPage.cpp b/launcher/ui/pages/instance/ExternalResourcesPage.cpp index 48a71b809..2068fa6b1 100644 --- a/launcher/ui/pages/instance/ExternalResourcesPage.cpp +++ b/launcher/ui/pages/instance/ExternalResourcesPage.cpp @@ -290,12 +290,12 @@ void ExternalResourcesPage::disableItem() void ExternalResourcesPage::viewConfigs() { - DesktopServices::openDirectory(m_instance->instanceConfigFolder(), true); + DesktopServices::openPath(m_instance->instanceConfigFolder(), true); } void ExternalResourcesPage::viewFolder() { - DesktopServices::openDirectory(m_model->dir().absolutePath(), true); + DesktopServices::openPath(m_model->dir().absolutePath(), true); } bool ExternalResourcesPage::current(const QModelIndex& current, const QModelIndex& previous) diff --git a/launcher/ui/pages/instance/ScreenshotsPage.cpp b/launcher/ui/pages/instance/ScreenshotsPage.cpp index 83fb0d5ff..01061160b 100644 --- a/launcher/ui/pages/instance/ScreenshotsPage.cpp +++ b/launcher/ui/pages/instance/ScreenshotsPage.cpp @@ -325,7 +325,7 @@ void ScreenshotsPage::onItemActivated(QModelIndex index) return; auto info = m_model->fileInfo(index); QString fileName = info.absoluteFilePath(); - DesktopServices::openFile(info.absoluteFilePath()); + DesktopServices::openPath(info.absoluteFilePath()); } void ScreenshotsPage::onCurrentSelectionChanged(const QItemSelection& selected) @@ -352,7 +352,7 @@ void ScreenshotsPage::onCurrentSelectionChanged(const QItemSelection& selected) void ScreenshotsPage::on_actionView_Folder_triggered() { - DesktopServices::openDirectory(m_folder, true); + DesktopServices::openPath(m_folder, true); } void ScreenshotsPage::on_actionUpload_triggered() diff --git a/launcher/ui/pages/instance/VersionPage.cpp b/launcher/ui/pages/instance/VersionPage.cpp index e425269c8..487433230 100644 --- a/launcher/ui/pages/instance/VersionPage.cpp +++ b/launcher/ui/pages/instance/VersionPage.cpp @@ -447,12 +447,12 @@ void VersionPage::on_actionAdd_Empty_triggered() void VersionPage::on_actionLibrariesFolder_triggered() { - DesktopServices::openDirectory(m_inst->getLocalLibraryPath(), true); + DesktopServices::openPath(m_inst->getLocalLibraryPath(), true); } void VersionPage::on_actionMinecraftFolder_triggered() { - DesktopServices::openDirectory(m_inst->gameRoot(), true); + DesktopServices::openPath(m_inst->gameRoot(), true); } void VersionPage::versionCurrent(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous) diff --git a/launcher/ui/pages/instance/WorldListPage.cpp b/launcher/ui/pages/instance/WorldListPage.cpp index 587bb6ce6..692db7ad7 100644 --- a/launcher/ui/pages/instance/WorldListPage.cpp +++ b/launcher/ui/pages/instance/WorldListPage.cpp @@ -207,7 +207,7 @@ void WorldListPage::on_actionRemove_triggered() void WorldListPage::on_actionView_Folder_triggered() { - DesktopServices::openDirectory(m_worlds->dir().absolutePath(), true); + DesktopServices::openPath(m_worlds->dir().absolutePath(), true); } void WorldListPage::on_actionDatapacks_triggered() @@ -223,7 +223,7 @@ void WorldListPage::on_actionDatapacks_triggered() auto fullPath = m_worlds->data(index, WorldList::FolderRole).toString(); - DesktopServices::openDirectory(FS::PathCombine(fullPath, "datapacks"), true); + DesktopServices::openPath(FS::PathCombine(fullPath, "datapacks"), true); } void WorldListPage::on_actionReset_Icon_triggered() diff --git a/launcher/ui/widgets/ThemeCustomizationWidget.cpp b/launcher/ui/widgets/ThemeCustomizationWidget.cpp index 0de97441f..25b91857c 100644 --- a/launcher/ui/widgets/ThemeCustomizationWidget.cpp +++ b/launcher/ui/widgets/ThemeCustomizationWidget.cpp @@ -34,11 +34,11 @@ ThemeCustomizationWidget::ThemeCustomizationWidget(QWidget* parent) : QWidget(pa connect(ui->backgroundCatComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &ThemeCustomizationWidget::applyCatTheme); connect(ui->iconsFolder, &QPushButton::clicked, this, - [] { DesktopServices::openDirectory(APPLICATION->themeManager()->getIconThemesFolder().path()); }); + [] { DesktopServices::openPath(APPLICATION->themeManager()->getIconThemesFolder().path()); }); connect(ui->widgetStyleFolder, &QPushButton::clicked, this, - [] { DesktopServices::openDirectory(APPLICATION->themeManager()->getApplicationThemesFolder().path()); }); + [] { DesktopServices::openPath(APPLICATION->themeManager()->getApplicationThemesFolder().path()); }); connect(ui->catPackFolder, &QPushButton::clicked, this, - [] { DesktopServices::openDirectory(APPLICATION->themeManager()->getCatPacksFolder().path()); }); + [] { DesktopServices::openPath(APPLICATION->themeManager()->getCatPacksFolder().path()); }); } ThemeCustomizationWidget::~ThemeCustomizationWidget() From d0fe700b530bdc12afb945f6e2822e45bc68693e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 14 Dec 2023 20:23:26 +0000 Subject: [PATCH 065/223] chore(deps): update actions/download-artifact action to v4 --- .github/workflows/trigger_release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/trigger_release.yml b/.github/workflows/trigger_release.yml index 28578165f..ebf5f96e6 100644 --- a/.github/workflows/trigger_release.yml +++ b/.github/workflows/trigger_release.yml @@ -32,7 +32,7 @@ jobs: submodules: "true" path: "PrismLauncher-source" - name: Download artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 - name: Grab and store version run: | tag_name=$(echo ${{ github.ref }} | grep -oE "[^/]+$") From 317d52b44a8b72652b01bd0b155427e0892a8d91 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 14 Dec 2023 20:23:30 +0000 Subject: [PATCH 066/223] chore(deps): update actions/upload-artifact action to v4 --- .github/workflows/build.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 24e7194ae..e24ccbf6d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -517,70 +517,70 @@ jobs: - name: Upload binary tarball (macOS) if: runner.os == 'macOS' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }} path: PrismLauncher.tar.gz - name: Upload binary zip (Windows) if: runner.os == 'Windows' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }} path: ${{ env.INSTALL_DIR }}/** - name: Upload binary zip (Windows, portable) if: runner.os == 'Windows' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: PrismLauncher-${{ matrix.name }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }} path: ${{ env.INSTALL_PORTABLE_DIR }}/** - name: Upload installer (Windows) if: runner.os == 'Windows' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: PrismLauncher-${{ matrix.name }}-Setup-${{ env.VERSION }}-${{ inputs.build_type }} path: PrismLauncher-Setup.exe - name: Upload binary tarball (Linux, Qt 5) if: runner.os == 'Linux' && matrix.qt_ver != 6 - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: PrismLauncher-${{ runner.os }}-Qt5-${{ env.VERSION }}-${{ inputs.build_type }} path: PrismLauncher.tar.gz - name: Upload binary tarball (Linux, portable, Qt 5) if: runner.os == 'Linux' && matrix.qt_ver != 6 - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: PrismLauncher-${{ runner.os }}-Qt5-Portable-${{ env.VERSION }}-${{ inputs.build_type }} path: PrismLauncher-portable.tar.gz - name: Upload binary tarball (Linux, Qt 6) if: runner.os == 'Linux' && matrix.qt_ver !=5 - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: PrismLauncher-${{ runner.os }}-Qt6-${{ env.VERSION }}-${{ inputs.build_type }} path: PrismLauncher.tar.gz - name: Upload binary tarball (Linux, portable, Qt 6) if: runner.os == 'Linux' && matrix.qt_ver != 5 - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: PrismLauncher-${{ runner.os }}-Qt6-Portable-${{ env.VERSION }}-${{ inputs.build_type }} path: PrismLauncher-portable.tar.gz - name: Upload AppImage (Linux) if: runner.os == 'Linux' && matrix.qt_ver != 5 - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage path: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage - name: Upload AppImage Zsync (Linux) if: runner.os == 'Linux' && matrix.qt_ver != 5 - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage.zsync path: PrismLauncher-Linux-x86_64.AppImage.zsync From 8cbdecc454de7ee8f3dadbd00c35b339a8581c45 Mon Sep 17 00:00:00 2001 From: lumiscosity Date: Sat, 16 Dec 2023 12:52:59 +0100 Subject: [PATCH 067/223] Update GetModDependenciesTask.cpp Signed-off-by: lumiscosity --- launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp b/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp index 5457d5a9c..5aef4e585 100644 --- a/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp +++ b/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp @@ -183,7 +183,7 @@ Task::Ptr GetModDependenciesTask::prepareDependencyTask(const ModPlatform::Depen ResourceAPI::DependencySearchArgs args = { dep, m_version, m_loaderType }; ResourceAPI::DependencySearchCallbacks callbacks; callbacks.on_fail = [](QString reason, int) { - qCritical() << tr("A network error occurred. Could not load project dependenies:%1").arg(reason); + qCritical() << tr("A network error occurred. Could not load project dependencies:%1").arg(reason); }; callbacks.on_succeed = [dep, provider, pDep, level, this](auto& doc, [[maybe_unused]] auto& pack) { try { @@ -285,4 +285,4 @@ QHash GetModDependenciesTask::getRequiredBy() rby[addonId.toString()] = req; } return rby; -} \ No newline at end of file +} From 56397446dbe05ea346359f401587383d4a1a84dd Mon Sep 17 00:00:00 2001 From: lumiscosity Date: Sat, 16 Dec 2023 12:53:59 +0100 Subject: [PATCH 068/223] Update ModFolderPage.cpp Signed-off-by: lumiscosity --- launcher/ui/pages/instance/ModFolderPage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/pages/instance/ModFolderPage.cpp b/launcher/ui/pages/instance/ModFolderPage.cpp index ce1cc3a90..313fef2b6 100644 --- a/launcher/ui/pages/instance/ModFolderPage.cpp +++ b/launcher/ui/pages/instance/ModFolderPage.cpp @@ -242,7 +242,7 @@ void ModFolderPage::updateMods(bool includeDeps) if (m_instance != nullptr && m_instance->isRunning()) { auto response = CustomMessageBox::selectable(this, tr("Confirm Update"), - tr("If you update mods while the game is running may cause mod duplication and game crashes.\n" + tr("Updating mods while the game is running may cause mod duplication and game crashes.\n" "The old files may not be deleted as they are in use.\n" "Are you sure you want to do this?"), QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No) From eb8e150fa804f0b34b21d7a95e840516cd119c97 Mon Sep 17 00:00:00 2001 From: lumiscosity Date: Sat, 16 Dec 2023 13:00:22 +0100 Subject: [PATCH 069/223] one more Signed-off-by: lumiscosity --- launcher/ui/pages/modplatform/ResourceModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/pages/modplatform/ResourceModel.cpp b/launcher/ui/pages/modplatform/ResourceModel.cpp index 6c02150bd..8a70eb4de 100644 --- a/launcher/ui/pages/modplatform/ResourceModel.cpp +++ b/launcher/ui/pages/modplatform/ResourceModel.cpp @@ -238,7 +238,7 @@ void ResourceModel::loadEntry(QModelIndex& entry) callbacks.on_abort = [this] { if (!s_running_models.constFind(this).value()) return; - qCritical() << tr("The request was abborted for an unknown reason"); + qCritical() << tr("The request was aborted for an unknown reason"); }; if (auto job = m_api->getProjectInfo(std::move(args), std::move(callbacks)); job) From 213963257cf2b2f7a265893c3112cd71bbce6199 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Sat, 16 Dec 2023 13:03:51 +0100 Subject: [PATCH 070/223] chore: remove maybe_unused Signed-off-by: Sefa Eyeoglu --- launcher/DesktopServices.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launcher/DesktopServices.cpp b/launcher/DesktopServices.cpp index 851516399..c9d515323 100644 --- a/launcher/DesktopServices.cpp +++ b/launcher/DesktopServices.cpp @@ -97,7 +97,7 @@ bool IndirectOpen(T callable, qint64* pid_forked = nullptr) #endif namespace DesktopServices { -bool openPath(const QFileInfo& path, [[maybe_unused]] bool ensureExists) +bool openPath(const QFileInfo& path, bool ensureExists) { qDebug() << "Opening path" << path; if (ensureExists) { @@ -106,7 +106,7 @@ bool openPath(const QFileInfo& path, [[maybe_unused]] bool ensureExists) return openUrl(QUrl::fromLocalFile(QFileInfo(path).absolutePath())); } -bool openPath(const QString& path, [[maybe_unused]] bool ensureExists) +bool openPath(const QString& path, bool ensureExists) { return openPath(QFileInfo(path), ensureExists); } From a8220cd296a5b9540df07bce7be7e1f6cc28ffe0 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Sat, 16 Dec 2023 13:12:12 +0100 Subject: [PATCH 071/223] chore: remove unused methods Signed-off-by: Sefa Eyeoglu --- launcher/DesktopServices.cpp | 62 ------------------------------------ launcher/DesktopServices.h | 5 --- 2 files changed, 67 deletions(-) diff --git a/launcher/DesktopServices.cpp b/launcher/DesktopServices.cpp index c9d515323..ecad825a5 100644 --- a/launcher/DesktopServices.cpp +++ b/launcher/DesktopServices.cpp @@ -39,63 +39,6 @@ #include #include "FileSystem.h" -/** - * This shouldn't exist, but until QTBUG-9328 and other unreported bugs are fixed, it needs to be a thing. - */ -#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) - -#include -#include -#include -#include - -template -bool IndirectOpen(T callable, qint64* pid_forked = nullptr) -{ - auto pid = fork(); - if (pid_forked) { - if (pid > 0) - *pid_forked = pid; - else - *pid_forked = 0; - } - if (pid == -1) { - qWarning() << "IndirectOpen failed to fork: " << errno; - return false; - } - // child - do the stuff - if (pid == 0) { - // unset all this garbage so it doesn't get passed to the child process - qunsetenv("LD_PRELOAD"); - qunsetenv("LD_LIBRARY_PATH"); - qunsetenv("LD_DEBUG"); - qunsetenv("QT_PLUGIN_PATH"); - qunsetenv("QT_FONTPATH"); - - // open the URL - auto status = callable(); - - // detach from the parent process group. - setsid(); - - // die. now. do not clean up anything, it would just hang forever. - _exit(status ? 0 : 1); - } else { - // parent - assume it worked. - int status; - while (waitpid(pid, &status, 0)) { - if (WIFEXITED(status)) { - return WEXITSTATUS(status) == 0; - } - if (WIFSIGNALED(status)) { - return false; - } - } - return true; - } -} -#endif - namespace DesktopServices { bool openPath(const QFileInfo& path, bool ensureExists) { @@ -141,9 +84,4 @@ bool isSnap() #endif } -bool isSandbox() -{ - return isSnap() || isFlatpak(); -} - } // namespace DesktopServices diff --git a/launcher/DesktopServices.h b/launcher/DesktopServices.h index 770eac984..6c4cbdce7 100644 --- a/launcher/DesktopServices.h +++ b/launcher/DesktopServices.h @@ -41,9 +41,4 @@ bool isFlatpak(); * Determine whether the launcher is running in a Snap environment */ bool isSnap(); - -/** - * Determine whether the launcher is running in a sandboxed (Flatpak or Snap) environment - */ -bool isSandbox(); } // namespace DesktopServices From 8f29cdf1956d4ef9fa58fe8fdf22eb99a8e24aa5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 16 Dec 2023 15:27:48 +0000 Subject: [PATCH 072/223] chore(deps): update korthout/backport-action action to v2.3.0 --- .github/workflows/backport.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 12850d697..dee01e084 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -24,7 +24,7 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} - name: Create backport PRs - uses: korthout/backport-action@v2.2.0 + uses: korthout/backport-action@v2.3.0 with: # Config README: https://github.com/korthout/backport-action#backport-action pull_description: |- From 74e2e491340f19282c480beb0c89402661f0a053 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 17 Dec 2023 00:20:10 +0000 Subject: [PATCH 073/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'nixpkgs': 'github:nixos/nixpkgs/09dc04054ba2ff1f861357d0e7e76d021b273cd7' (2023-12-08) → 'github:nixos/nixpkgs/aa9d4729cbc99dabacb50e3994dcefb3ea0f7447' (2023-12-14) • Updated input 'pre-commit-hooks': 'github:cachix/pre-commit-hooks.nix/e5ee5c5f3844550c01d2131096c7271cec5e9b78' (2023-11-25) → 'github:cachix/pre-commit-hooks.nix/007a45d064c1c32d04e1b8a0de5ef00984c419bc' (2023-12-13) --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index afc584a24..f754388af 100644 --- a/flake.lock +++ b/flake.lock @@ -106,11 +106,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1701998057, - "narHash": "sha256-gAJGhcTO9cso7XDfAScXUlPcva427AUT2q02qrmXPdo=", + "lastModified": 1702539185, + "narHash": "sha256-KnIRG5NMdLIpEkZTnN5zovNYc0hhXjAgv6pfd5Z4c7U=", "owner": "nixos", "repo": "nixpkgs", - "rev": "09dc04054ba2ff1f861357d0e7e76d021b273cd7", + "rev": "aa9d4729cbc99dabacb50e3994dcefb3ea0f7447", "type": "github" }, "original": { @@ -153,11 +153,11 @@ ] }, "locked": { - "lastModified": 1700922917, - "narHash": "sha256-ej2fch/T584b5K9sk1UhmZF7W6wEfDHuoUYpFN8dtvM=", + "lastModified": 1702456155, + "narHash": "sha256-I2XhXGAecdGlqi6hPWYT83AQtMgL+aa3ulA85RAEgOk=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "e5ee5c5f3844550c01d2131096c7271cec5e9b78", + "rev": "007a45d064c1c32d04e1b8a0de5ef00984c419bc", "type": "github" }, "original": { From a1e3901b3f4e4910e3fe40206879907a1f7ff03c Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Sun, 17 Dec 2023 12:39:17 +0100 Subject: [PATCH 074/223] fix: don't log katabasis by default Signed-off-by: Sefa Eyeoglu --- launcher/qtlogging.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/launcher/qtlogging.ini b/launcher/qtlogging.ini index c12d1e109..5266de59b 100644 --- a/launcher/qtlogging.ini +++ b/launcher/qtlogging.ini @@ -5,6 +5,7 @@ qt.*.debug=false # don't log credentials by default launcher.auth.credentials.debug=false +katabasis.*.debug=false # remove the debug lines, other log levels still get through launcher.task.net.download.debug=false # enable or disable whole catageries From 43306350e07a5cb5866aa1ee4e7bee8d6945cf48 Mon Sep 17 00:00:00 2001 From: lumiscosity Date: Fri, 22 Dec 2023 15:02:41 +0100 Subject: [PATCH 075/223] Add cat opacity Signed-off-by: lumiscosity --- launcher/Application.cpp | 1 + launcher/ui/instanceview/InstanceView.cpp | 2 + launcher/ui/pages/global/LauncherPage.cpp | 6 +++ launcher/ui/pages/global/LauncherPage.ui | 50 ++++++++++++++++++++++- 4 files changed, 58 insertions(+), 1 deletion(-) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 5f524219e..98773efe1 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -667,6 +667,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) // The cat m_settings->registerSetting("TheCat", false); + m_settings->registerSetting("CatOpacity", 100); m_settings->registerSetting("StatusBarVisible", true); diff --git a/launcher/ui/instanceview/InstanceView.cpp b/launcher/ui/instanceview/InstanceView.cpp index e665097f4..6f3812a62 100644 --- a/launcher/ui/instanceview/InstanceView.cpp +++ b/launcher/ui/instanceview/InstanceView.cpp @@ -458,6 +458,7 @@ void InstanceView::paintEvent([[maybe_unused]] QPaintEvent* event) QPainter painter(this->viewport()); if (m_catVisible) { + painter.setOpacity(APPLICATION->settings()->get("CatOpacity").toFloat() / 100); int widWidth = this->viewport()->width(); int widHeight = this->viewport()->height(); if (m_catPixmap.width() < widWidth) @@ -468,6 +469,7 @@ void InstanceView::paintEvent([[maybe_unused]] QPaintEvent* event) QRect rectOfPixmap = pixmap.rect(); rectOfPixmap.moveBottomRight(this->viewport()->rect().bottomRight()); painter.drawPixmap(rectOfPixmap.topLeft(), pixmap); + painter.setOpacity(1.0); } #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) diff --git a/launcher/ui/pages/global/LauncherPage.cpp b/launcher/ui/pages/global/LauncherPage.cpp index d15883db5..78c44380a 100644 --- a/launcher/ui/pages/global/LauncherPage.cpp +++ b/launcher/ui/pages/global/LauncherPage.cpp @@ -221,6 +221,9 @@ void LauncherPage::applySettings() break; } + // Cat + s->set("CatOpacity", ui->catOpacitySpinBox->value()); + // Mods s->set("ModMetadataDisabled", ui->metadataDisableBtn->isChecked()); s->set("ModDependenciesDisabled", ui->dependenciesDisableBtn->isChecked()); @@ -276,6 +279,9 @@ void LauncherPage::loadSettings() ui->sortByNameBtn->setChecked(true); } + // Cat + ui->catOpacitySpinBox->setValue(s->get("CatOpacity").toInt()); + // Mods ui->metadataDisableBtn->setChecked(s->get("ModMetadataDisabled").toBool()); ui->metadataWarningLabel->setHidden(!ui->metadataDisableBtn->isChecked()); diff --git a/launcher/ui/pages/global/LauncherPage.ui b/launcher/ui/pages/global/LauncherPage.ui index 83897f7a7..18b52e1b8 100644 --- a/launcher/ui/pages/global/LauncherPage.ui +++ b/launcher/ui/pages/global/LauncherPage.ui @@ -186,7 +186,7 @@ - + Disable the automatic detection, installation, and updating of mod dependencies. @@ -300,6 +300,54 @@ + + + + Cat + + + + + + Set the cat's opacity. 0% is fully transparent and 100% is fully opaque. + + + Opacity + + + + + + + + + + % + + + 100 + + + 0 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + From 358cf5b3485cfb23cce226c02fef03523468d4eb Mon Sep 17 00:00:00 2001 From: lumiscosity Date: Fri, 22 Dec 2023 22:01:05 +0100 Subject: [PATCH 076/223] add archived project warning Signed-off-by: lumiscosity --- launcher/modplatform/ModIndex.h | 2 ++ launcher/modplatform/modrinth/ModrinthPackIndex.cpp | 2 ++ launcher/modplatform/modrinth/ModrinthPackManifest.cpp | 2 ++ launcher/modplatform/modrinth/ModrinthPackManifest.h | 2 ++ launcher/ui/pages/modplatform/ResourcePage.cpp | 4 ++++ launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp | 2 +- launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp | 4 ++++ 7 files changed, 17 insertions(+), 1 deletion(-) diff --git a/launcher/modplatform/ModIndex.h b/launcher/modplatform/ModIndex.h index 72294c399..eff7e7f9f 100644 --- a/launcher/modplatform/ModIndex.h +++ b/launcher/modplatform/ModIndex.h @@ -122,6 +122,8 @@ struct ExtraPackData { QString wikiUrl; QString discordUrl; + QString status; + QString body; }; diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp index 7d0893261..c1c30ab5f 100644 --- a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp @@ -104,6 +104,8 @@ void Modrinth::loadExtraPackData(ModPlatform::IndexedPack& pack, QJsonObject& ob pack.extraData.donate.append(donate); } + pack.extraData.status = Json::ensureString(obj, "status"); + pack.extraData.body = Json::ensureString(obj, "body").remove("
"); pack.extraDataLoaded = true; diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp index d86f1c0e5..014d990f0 100644 --- a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp @@ -94,6 +94,8 @@ void loadIndexedInfo(Modpack& pack, QJsonObject& obj) pack.extra.donate.append(donate); } + + pack.extra.status = Json::ensureString(obj, "status"); pack.extraInfoLoaded = true; } diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.h b/launcher/modplatform/modrinth/ModrinthPackManifest.h index 6fc55a043..1ffd31d83 100644 --- a/launcher/modplatform/modrinth/ModrinthPackManifest.h +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.h @@ -77,6 +77,8 @@ struct ModpackExtra { QString discordUrl; QList donate; + + QString status; }; struct ModpackVersion { diff --git a/launcher/ui/pages/modplatform/ResourcePage.cpp b/launcher/ui/pages/modplatform/ResourcePage.cpp index 44a91003d..42139a8a5 100644 --- a/launcher/ui/pages/modplatform/ResourcePage.cpp +++ b/launcher/ui/pages/modplatform/ResourcePage.cpp @@ -200,6 +200,10 @@ void ResourcePage::updateUi() } if (current_pack->extraDataLoaded) { + if (current_pack->extraData.status == "archived") { + text += "

" + tr("This project has been archived. It will not receive any further updates unless the author decides to unarchive the project."); + } + if (!current_pack->extraData.donate.isEmpty()) { text += "

" + tr("Donate information: "); auto donateToStr = [](ModPlatform::DonationData& donate) -> QString { diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index 227ed646b..bac294b60 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -142,7 +142,7 @@ void ModpackListModel::performPaginatedSearch() callbacks.on_succeed = [this](auto& doc, auto& pack) { searchRequestForOneSucceeded(doc); }; callbacks.on_abort = [this] { qCritical() << "Search task aborted by an unknown reason!"; - searchRequestFailed("Abborted"); + searchRequestFailed("Aborted"); }; static const ModrinthAPI api; if (auto job = api.getProjectInfo({ projectId }, std::move(callbacks)); job) { diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index b4045a046..79ebfefd6 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -267,6 +267,10 @@ void ModrinthPage::updateUI() text += "
" + tr(" by ") + QString("%2").arg(std::get<1>(current.author).toString(), std::get<0>(current.author)); if (current.extraInfoLoaded) { + if (current.extra.status == "archived") { + text += "

" + tr("This project has been archived. It will not receive any further updates unless the author decides to unarchive the project."); + } + if (!current.extra.donate.isEmpty()) { text += "

" + tr("Donate information: "); auto donateToStr = [](Modrinth::DonationData& donate) -> QString { From 526e580fbb77b0758ba4141969a4380ac7de4472 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sat, 23 Dec 2023 00:33:38 +0200 Subject: [PATCH 077/223] Force clear the resource selection Signed-off-by: Trial97 --- launcher/ui/pages/modplatform/ModPage.cpp | 1 + launcher/ui/pages/modplatform/ResourcePackPage.cpp | 1 + launcher/ui/pages/modplatform/ShaderPackPage.cpp | 1 + 3 files changed, 3 insertions(+) diff --git a/launcher/ui/pages/modplatform/ModPage.cpp b/launcher/ui/pages/modplatform/ModPage.cpp index d6cc1fdcc..851c1c9e5 100644 --- a/launcher/ui/pages/modplatform/ModPage.cpp +++ b/launcher/ui/pages/modplatform/ModPage.cpp @@ -90,6 +90,7 @@ void ModPage::filterMods() void ModPage::triggerSearch() { m_filter = m_filter_widget->getFilter(); + m_ui->packView->selectionModel()->setCurrentIndex({}, QItemSelectionModel::SelectionFlag::ClearAndSelect); m_ui->packView->clearSelection(); m_ui->packDescription->clear(); m_ui->versionSelectionBox->clear(); diff --git a/launcher/ui/pages/modplatform/ResourcePackPage.cpp b/launcher/ui/pages/modplatform/ResourcePackPage.cpp index 2a4d02815..fc2dc15f3 100644 --- a/launcher/ui/pages/modplatform/ResourcePackPage.cpp +++ b/launcher/ui/pages/modplatform/ResourcePackPage.cpp @@ -23,6 +23,7 @@ ResourcePackResourcePage::ResourcePackResourcePage(ResourceDownloadDialog* dialo void ResourcePackResourcePage::triggerSearch() { + m_ui->packView->selectionModel()->setCurrentIndex({}, QItemSelectionModel::SelectionFlag::ClearAndSelect); m_ui->packView->clearSelection(); m_ui->packDescription->clear(); m_ui->versionSelectionBox->clear(); diff --git a/launcher/ui/pages/modplatform/ShaderPackPage.cpp b/launcher/ui/pages/modplatform/ShaderPackPage.cpp index 586dffc55..8be068312 100644 --- a/launcher/ui/pages/modplatform/ShaderPackPage.cpp +++ b/launcher/ui/pages/modplatform/ShaderPackPage.cpp @@ -24,6 +24,7 @@ ShaderPackResourcePage::ShaderPackResourcePage(ShaderPackDownloadDialog* dialog, void ShaderPackResourcePage::triggerSearch() { + m_ui->packView->selectionModel()->setCurrentIndex({}, QItemSelectionModel::SelectionFlag::ClearAndSelect); m_ui->packView->clearSelection(); m_ui->packDescription->clear(); m_ui->versionSelectionBox->clear(); From 9a33bdcf501655dbef2981094ee05662f34cd671 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sat, 23 Dec 2023 01:02:04 +0200 Subject: [PATCH 078/223] Fixed openURL cast for resource Signed-off-by: Trial97 --- launcher/ui/pages/modplatform/ResourcePage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launcher/ui/pages/modplatform/ResourcePage.cpp b/launcher/ui/pages/modplatform/ResourcePage.cpp index 44a91003d..8f660a8b0 100644 --- a/launcher/ui/pages/modplatform/ResourcePage.cpp +++ b/launcher/ui/pages/modplatform/ResourcePage.cpp @@ -404,9 +404,9 @@ void ResourcePage::openUrl(const QUrl& url) auto jump = [url, slug, model, view] { for (int row = 0; row < model->rowCount({}); row++) { const QModelIndex index = model->index(row); - const auto pack = model->data(index, Qt::UserRole).value(); + const auto pack = model->data(index, Qt::UserRole).value(); - if (pack.slug == slug) { + if (pack->slug == slug) { view->setCurrentIndex(index); return; } From 1bf386603dece42df0815495ae6b43b0e2d665c8 Mon Sep 17 00:00:00 2001 From: lumiscosity Date: Sat, 23 Dec 2023 11:27:19 +0100 Subject: [PATCH 079/223] Strip newlines in mod descriptions Mirrors Modrinth page behaviour. Signed-off-by: lumiscosity --- launcher/ui/pages/modplatform/ResourceModel.cpp | 2 +- launcher/ui/pages/modplatform/modrinth/ModrinthModel.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 8a70eb4de..aafec7f57 100644 --- a/launcher/ui/pages/modplatform/ResourceModel.cpp +++ b/launcher/ui/pages/modplatform/ResourceModel.cpp @@ -77,7 +77,7 @@ auto ResourceModel::data(const QModelIndex& index, int role) const -> QVariant case UserDataTypes::TITLE: return pack->name; case UserDataTypes::DESCRIPTION: - return pack->description; + return pack->description.simplified(); case UserDataTypes::SELECTED: return pack->isAnyVersionSelected(); case UserDataTypes::INSTALLED: diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index bac294b60..6ee3e0c67 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -105,7 +105,7 @@ auto ModpackListModel::data(const QModelIndex& index, int role) const -> QVarian case UserDataTypes::TITLE: return pack.name; case UserDataTypes::DESCRIPTION: - return pack.description; + return pack.description.simplified(); case UserDataTypes::SELECTED: return false; case UserDataTypes::INSTALLED: From 1e48bf838db3f72fd391ecf9c91aa8e693daf213 Mon Sep 17 00:00:00 2001 From: lumiscosity Date: Sat, 23 Dec 2023 12:05:07 +0100 Subject: [PATCH 080/223] move simplify call to drawing Signed-off-by: lumiscosity --- launcher/ui/pages/modplatform/ResourceModel.cpp | 2 +- launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp | 2 +- launcher/ui/widgets/ProjectItem.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/launcher/ui/pages/modplatform/ResourceModel.cpp b/launcher/ui/pages/modplatform/ResourceModel.cpp index aafec7f57..8a70eb4de 100644 --- a/launcher/ui/pages/modplatform/ResourceModel.cpp +++ b/launcher/ui/pages/modplatform/ResourceModel.cpp @@ -77,7 +77,7 @@ auto ResourceModel::data(const QModelIndex& index, int role) const -> QVariant case UserDataTypes::TITLE: return pack->name; case UserDataTypes::DESCRIPTION: - return pack->description.simplified(); + return pack->description; case UserDataTypes::SELECTED: return pack->isAnyVersionSelected(); case UserDataTypes::INSTALLED: diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index 6ee3e0c67..bac294b60 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -105,7 +105,7 @@ auto ModpackListModel::data(const QModelIndex& index, int role) const -> QVarian case UserDataTypes::TITLE: return pack.name; case UserDataTypes::DESCRIPTION: - return pack.description.simplified(); + return pack.description; case UserDataTypes::SELECTED: return false; case UserDataTypes::INSTALLED: diff --git a/launcher/ui/widgets/ProjectItem.cpp b/launcher/ui/widgets/ProjectItem.cpp index 60b92b28b..6946df41f 100644 --- a/launcher/ui/widgets/ProjectItem.cpp +++ b/launcher/ui/widgets/ProjectItem.cpp @@ -88,7 +88,7 @@ void ProjectItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o } { // Description painting - auto description = index.data(UserDataTypes::DESCRIPTION).toString(); + auto description = index.data(UserDataTypes::DESCRIPTION).toString().simplified(); QTextLayout text_layout(description, opt.font); From c29af83dc328612d340c54e3ec037b1264d66d51 Mon Sep 17 00:00:00 2001 From: lumiscosity Date: Sat, 23 Dec 2023 14:16:29 +0100 Subject: [PATCH 081/223] fix styling Signed-off-by: lumiscosity --- launcher/modplatform/modrinth/ModrinthPackManifest.cpp | 2 +- launcher/ui/pages/modplatform/ResourcePage.cpp | 3 ++- launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp index 014d990f0..7846e966d 100644 --- a/launcher/modplatform/modrinth/ModrinthPackManifest.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackManifest.cpp @@ -94,7 +94,7 @@ void loadIndexedInfo(Modpack& pack, QJsonObject& obj) pack.extra.donate.append(donate); } - + pack.extra.status = Json::ensureString(obj, "status"); pack.extraInfoLoaded = true; diff --git a/launcher/ui/pages/modplatform/ResourcePage.cpp b/launcher/ui/pages/modplatform/ResourcePage.cpp index 42139a8a5..d8e8a652c 100644 --- a/launcher/ui/pages/modplatform/ResourcePage.cpp +++ b/launcher/ui/pages/modplatform/ResourcePage.cpp @@ -201,7 +201,8 @@ void ResourcePage::updateUi() if (current_pack->extraDataLoaded) { if (current_pack->extraData.status == "archived") { - text += "

" + tr("This project has been archived. It will not receive any further updates unless the author decides to unarchive the project."); + text += "

" + tr("This project has been archived. It will not receive any further updates unless the author decides " + "to unarchive the project."); } if (!current_pack->extraData.donate.isEmpty()) { diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index 79ebfefd6..fffa21940 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -268,7 +268,8 @@ void ModrinthPage::updateUI() if (current.extraInfoLoaded) { if (current.extra.status == "archived") { - text += "

" + tr("This project has been archived. It will not receive any further updates unless the author decides to unarchive the project."); + text += "

" + tr("This project has been archived. It will not receive any further updates unless the author decides " + "to unarchive the project."); } if (!current.extra.donate.isEmpty()) { From ea38f8168a066cb8922c8c3b32914f1eb2584c8a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 24 Dec 2023 00:19:31 +0000 Subject: [PATCH 082/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'nixpkgs': 'github:nixos/nixpkgs/aa9d4729cbc99dabacb50e3994dcefb3ea0f7447' (2023-12-14) → 'github:nixos/nixpkgs/d6863cbcbbb80e71cecfc03356db1cda38919523' (2023-12-21) --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index f754388af..70affded6 100644 --- a/flake.lock +++ b/flake.lock @@ -106,11 +106,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1702539185, - "narHash": "sha256-KnIRG5NMdLIpEkZTnN5zovNYc0hhXjAgv6pfd5Z4c7U=", + "lastModified": 1703134684, + "narHash": "sha256-SQmng1EnBFLzS7WSRyPM9HgmZP2kLJcPAz+Ug/nug6o=", "owner": "nixos", "repo": "nixpkgs", - "rev": "aa9d4729cbc99dabacb50e3994dcefb3ea0f7447", + "rev": "d6863cbcbbb80e71cecfc03356db1cda38919523", "type": "github" }, "original": { From eca5d88576900d32edea2000258f37d700af5f06 Mon Sep 17 00:00:00 2001 From: tildejustin Date: Sun, 24 Dec 2023 22:20:06 -0500 Subject: [PATCH 083/223] remove legacy processArguments code Signed-off-by: tildejustin --- launcher/minecraft/MojangVersionFormat.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/launcher/minecraft/MojangVersionFormat.cpp b/launcher/minecraft/MojangVersionFormat.cpp index 6ee10ec15..bb782e47f 100644 --- a/launcher/minecraft/MojangVersionFormat.cpp +++ b/launcher/minecraft/MojangVersionFormat.cpp @@ -157,20 +157,6 @@ void MojangVersionFormat::readVersionProperties(const QJsonObject& in, VersionFi Bits::readString(in, "id", out->minecraftVersion); Bits::readString(in, "mainClass", out->mainClass); Bits::readString(in, "minecraftArguments", out->minecraftArguments); - if (out->minecraftArguments.isEmpty()) { - QString processArguments; - Bits::readString(in, "processArguments", processArguments); - QString toCompare = processArguments.toLower(); - if (toCompare == "legacy") { - out->minecraftArguments = " ${auth_player_name} ${auth_session}"; - } else if (toCompare == "username_session") { - out->minecraftArguments = "--username ${auth_player_name} --session ${auth_session}"; - } else if (toCompare == "username_session_version") { - out->minecraftArguments = "--username ${auth_player_name} --session ${auth_session} --version ${profile_name}"; - } else if (!toCompare.isEmpty()) { - out->addProblem(ProblemSeverity::Error, QObject::tr("processArguments is set to unknown value '%1'").arg(processArguments)); - } - } Bits::readString(in, "type", out->type); Bits::readString(in, "assets", out->assets); From ad01102badd42b9418828fbd73a197f78f9a33b3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 31 Dec 2023 00:20:06 +0000 Subject: [PATCH 084/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'nixpkgs': 'github:nixos/nixpkgs/d6863cbcbbb80e71cecfc03356db1cda38919523' (2023-12-21) → 'github:nixos/nixpkgs/e1fa12d4f6c6fe19ccb59cac54b5b3f25e160870' (2023-12-25) • Updated input 'pre-commit-hooks': 'github:cachix/pre-commit-hooks.nix/007a45d064c1c32d04e1b8a0de5ef00984c419bc' (2023-12-13) → 'github:cachix/pre-commit-hooks.nix/9d3d7e18c6bc4473d7520200d4ddab12f8402d38' (2023-12-30) --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index 70affded6..774f394cd 100644 --- a/flake.lock +++ b/flake.lock @@ -106,11 +106,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1703134684, - "narHash": "sha256-SQmng1EnBFLzS7WSRyPM9HgmZP2kLJcPAz+Ug/nug6o=", + "lastModified": 1703499205, + "narHash": "sha256-lF9rK5mSUfIZJgZxC3ge40tp1gmyyOXZ+lRY3P8bfbg=", "owner": "nixos", "repo": "nixpkgs", - "rev": "d6863cbcbbb80e71cecfc03356db1cda38919523", + "rev": "e1fa12d4f6c6fe19ccb59cac54b5b3f25e160870", "type": "github" }, "original": { @@ -153,11 +153,11 @@ ] }, "locked": { - "lastModified": 1702456155, - "narHash": "sha256-I2XhXGAecdGlqi6hPWYT83AQtMgL+aa3ulA85RAEgOk=", + "lastModified": 1703939133, + "narHash": "sha256-Gxe+mfOT6bL7wLC/tuT2F+V+Sb44jNr8YsJ3cyIl4Mo=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "007a45d064c1c32d04e1b8a0de5ef00984c419bc", + "rev": "9d3d7e18c6bc4473d7520200d4ddab12f8402d38", "type": "github" }, "original": { From 73f956c897e50f79353291e46af0daadff8640b8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Jan 2024 07:30:12 +0000 Subject: [PATCH 085/223] chore(deps): update hendrikmuhs/ccache-action action to v1.2.11 --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e24ccbf6d..1159aad6c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -145,7 +145,7 @@ jobs: - name: Setup ccache if: (runner.os != 'Windows' || matrix.msystem == '') && inputs.build_type == 'Debug' - uses: hendrikmuhs/ccache-action@v1.2.10 + uses: hendrikmuhs/ccache-action@v1.2.11 with: key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}-${{ matrix.architecture }} From 1130fe851012b3d7deff207db495b455501e17fc Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Tue, 2 Jan 2024 17:57:24 +0000 Subject: [PATCH 086/223] Happy new year :D Signed-off-by: TheKodeToad --- CMakeLists.txt | 2 +- COPYING.md | 4 ++-- launcher/Application.cpp | 3 +-- launcher/ui/dialogs/AboutDialog.cpp | 3 +-- launcher/updater/prismupdater/PrismUpdater.cpp | 4 ++-- program_info/CMakeLists.txt | 4 ++-- 6 files changed, 9 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index faeb1c44e..e42186cb5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -377,7 +377,7 @@ if(UNIX AND APPLE) set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_NAME}") set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_NAME}") set(MACOSX_BUNDLE_ICON_FILE ${Launcher_Name}.icns) - set(MACOSX_BUNDLE_COPYRIGHT "© 2022-2023 ${Launcher_Copyright_Mac}") + set(MACOSX_BUNDLE_COPYRIGHT "${Launcher_Copyright_Mac}") set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "v55ZWWD6QlPoXGV6VLzOTZxZUggWeE51X8cRQyQh6vA=" CACHE STRING "Public key for Sparkle update feed") set(MACOSX_SPARKLE_UPDATE_FEED_URL "https://prismlauncher.org/feed/appcast.xml" CACHE STRING "URL for Sparkle update feed") diff --git a/COPYING.md b/COPYING.md index 0221d1b08..f14e2958e 100644 --- a/COPYING.md +++ b/COPYING.md @@ -1,7 +1,7 @@ ## Prism Launcher Prism Launcher - Minecraft Launcher - Copyright (C) 2022-2023 Prism Launcher Contributors + Copyright (C) 2022-2024 Prism Launcher Contributors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -436,7 +436,7 @@ Copyright (C) 2007 Johann Ollivier Lapeyre Copyright (C) 2007 Kenneth Wimer Copyright (C) 2007 Riccardo Iaconelli - + and others This library is free software; you can redistribute it and/or diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 5f524219e..75a0ce702 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -494,8 +494,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) } { - qDebug() << qPrintable(BuildConfig.LAUNCHER_DISPLAYNAME) << ", (c) 2022-2023 " - << qPrintable(QString(BuildConfig.LAUNCHER_COPYRIGHT).replace("\n", ", ")); + qDebug() << qPrintable(BuildConfig.LAUNCHER_DISPLAYNAME + ", " + QString(BuildConfig.LAUNCHER_COPYRIGHT).replace("\n", ", ")); qDebug() << "Version : " << BuildConfig.printableVersionString(); qDebug() << "Platform : " << BuildConfig.BUILD_PLATFORM; qDebug() << "Git commit : " << BuildConfig.GIT_COMMIT; diff --git a/launcher/ui/dialogs/AboutDialog.cpp b/launcher/ui/dialogs/AboutDialog.cpp index cee01e821..17b79ecaa 100644 --- a/launcher/ui/dialogs/AboutDialog.cpp +++ b/launcher/ui/dialogs/AboutDialog.cpp @@ -174,8 +174,7 @@ AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent), ui(new Ui::AboutDia QString urlText("

%1

"); ui->urlLabel->setText(urlText.arg(BuildConfig.LAUNCHER_GIT)); - QString copyText("© 2022-2023 %1"); - ui->copyLabel->setText(copyText.arg(BuildConfig.LAUNCHER_COPYRIGHT)); + ui->copyLabel->setText(BuildConfig.LAUNCHER_COPYRIGHT); connect(ui->closeButton, SIGNAL(clicked()), SLOT(close())); diff --git a/launcher/updater/prismupdater/PrismUpdater.cpp b/launcher/updater/prismupdater/PrismUpdater.cpp index 1c5aaf1e8..5fe22bdd0 100644 --- a/launcher/updater/prismupdater/PrismUpdater.cpp +++ b/launcher/updater/prismupdater/PrismUpdater.cpp @@ -436,8 +436,8 @@ PrismUpdaterApp::PrismUpdaterApp(int& argc, char** argv) : QApplication(argc, ar } { // log debug program info - qDebug() << qPrintable(BuildConfig.LAUNCHER_DISPLAYNAME) << "Updater" - << ", (c) 2022-2023 " << qPrintable(QString(BuildConfig.LAUNCHER_COPYRIGHT).replace("\n", ", ")); + qDebug() << qPrintable(BuildConfig.LAUNCHER_DISPLAYNAME + " Updater, " + + QString(BuildConfig.LAUNCHER_COPYRIGHT).replace("\n", ", ")); qDebug() << "Version : " << BuildConfig.printableVersionString(); qDebug() << "Git commit : " << BuildConfig.GIT_COMMIT; qDebug() << "Git refspec : " << BuildConfig.GIT_REFSPEC; diff --git a/program_info/CMakeLists.txt b/program_info/CMakeLists.txt index 8c6827119..91b213274 100644 --- a/program_info/CMakeLists.txt +++ b/program_info/CMakeLists.txt @@ -14,8 +14,8 @@ set(Launcher_DisplayName "Prism Launcher") set(Launcher_Name "${Launcher_CommonName}" PARENT_SCOPE) set(Launcher_DisplayName "${Launcher_DisplayName}" PARENT_SCOPE) -set(Launcher_Copyright "Prism Launcher Contributors\\n© 2021-2022 PolyMC Contributors \\n© 2012-2021 MultiMC Contributors") -set(Launcher_Copyright_Mac "Prism Launcher Contributors, © 2021-2022 PolyMC Contributors and © 2012-2021 MultiMC Contributors" PARENT_SCOPE) +set(Launcher_Copyright "© 2022-2024 Prism Launcher Contributors\\n© 2021-2022 PolyMC Contributors\\n© 2012-2021 MultiMC Contributors") +set(Launcher_Copyright_Mac "© 2022-2024 Prism Launcher Contributors, © 2021-2022 PolyMC Contributors and © 2012-2021 MultiMC Contributors" PARENT_SCOPE) set(Launcher_Copyright "${Launcher_Copyright}" PARENT_SCOPE) set(Launcher_Domain "prismlauncher.org" PARENT_SCOPE) set(Launcher_UserAgent "${Launcher_CommonName}/${Launcher_VERSION_NAME}" PARENT_SCOPE) From 05e453309629d2c4cc1cf4b1322669cb8aed21ff Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sun, 24 Dec 2023 16:39:56 +0000 Subject: [PATCH 087/223] Add online mode fix for legacy versions; minor refactors in legacy Signed-off-by: TheKodeToad --- launcher/ui/pages/global/MinecraftPage.ui | 2 +- .../ui/pages/instance/InstanceSettingsPage.ui | 2 +- libraries/launcher/CMakeLists.txt | 3 +- .../legacy/fix/online/Handler.java | 7 +- .../legacy/fix/online/OnlineFixes.java | 2 + .../legacy/fix/online/OnlineModeFix.java | 64 +++++++++++++++++++ .../legacy/fix/online/SkinFix.java | 8 +-- ...ction.java => ByteArrayUrlConnection.java} | 17 ++--- .../legacy/utils/url/UrlUtils.java | 2 +- .../org/prismlauncher/EntryPoint.java | 46 ++----------- .../org/prismlauncher/SystemProperties.java | 38 +++++++++++ .../prismlauncher/utils/ReflectionUtils.java | 6 -- 12 files changed, 129 insertions(+), 68 deletions(-) create mode 100644 libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineModeFix.java rename libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/{CustomUrlConnection.java => ByteArrayUrlConnection.java} (86%) create mode 100644 libraries/launcher/org/prismlauncher/SystemProperties.java diff --git a/launcher/ui/pages/global/MinecraftPage.ui b/launcher/ui/pages/global/MinecraftPage.ui index 2a3c0d96d..3008099e3 100644 --- a/launcher/ui/pages/global/MinecraftPage.ui +++ b/launcher/ui/pages/global/MinecraftPage.ui @@ -206,7 +206,7 @@ - <html><head/><body><p>Emulates usages of old online services which are no longer operating.</p><p>This currently allows modern skins to be used.</p></body></html> + <html><head/><body><p>Emulates usages of old online services which are no longer operating.</p><p>Current fixes include: skin and online mode support.</p></body></html> Enable online fixes (experimental) diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.ui b/launcher/ui/pages/instance/InstanceSettingsPage.ui index 3b06ac865..632569e0c 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.ui +++ b/launcher/ui/pages/instance/InstanceSettingsPage.ui @@ -605,7 +605,7 @@ - <html><head/><body><p>Emulates usages of old online services which are no longer operating.</p><p>This currently allows modern skins to be used.</p></body></html> + <html><head/><body><p>Emulates usages of old online services which are no longer operating.</p><p>Current fixes include: skin and online mode support.</p></body></html> Enable online fixes (experimental) diff --git a/libraries/launcher/CMakeLists.txt b/libraries/launcher/CMakeLists.txt index 7bf160760..4cd1ba58b 100644 --- a/libraries/launcher/CMakeLists.txt +++ b/libraries/launcher/CMakeLists.txt @@ -25,13 +25,14 @@ set(LEGACY_SRC legacy/org/prismlauncher/legacy/LegacyLauncher.java legacy/org/prismlauncher/legacy/fix/online/Handler.java legacy/org/prismlauncher/legacy/fix/online/OnlineFixes.java + legacy/org/prismlauncher/legacy/fix/online/OnlineModeFix.java legacy/org/prismlauncher/legacy/fix/online/SkinFix.java legacy/org/prismlauncher/legacy/utils/Base64.java legacy/org/prismlauncher/legacy/utils/api/MojangApi.java legacy/org/prismlauncher/legacy/utils/api/Texture.java legacy/org/prismlauncher/legacy/utils/json/JsonParseException.java legacy/org/prismlauncher/legacy/utils/json/JsonParser.java - legacy/org/prismlauncher/legacy/utils/url/CustomUrlConnection.java + legacy/org/prismlauncher/legacy/utils/url/ByteArrayUrlConnection.java legacy/org/prismlauncher/legacy/utils/url/UrlUtils.java legacy/net/minecraft/Launcher.java legacy/org/prismlauncher/legacy/LegacyProxy.java diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/Handler.java b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/Handler.java index f85a8bc79..5ef3d7ac2 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/Handler.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/Handler.java @@ -53,11 +53,16 @@ final class Handler extends URLStreamHandler { protected URLConnection openConnection(URL address, Proxy proxy) throws IOException { URLConnection result; - // try skin fix + // try various fixes... result = SkinFix.openConnection(address, proxy); if (result != null) return result; + result = OnlineModeFix.openConnection(address, proxy); + if (result != null) + return result; + + // ...then give up and make the request directly return UrlUtils.openConnection(address, proxy); } } diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineFixes.java b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineFixes.java index 88facff69..9ba57ff71 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineFixes.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineFixes.java @@ -46,6 +46,8 @@ import java.net.URLStreamHandlerFactory; /** * Fixes skins by redirecting to other URLs. + * Thanks to MineOnline for the implementation from which this was inspired! + * See https://github.com/ahnewark/MineOnline/tree/main/src/main/java/gg/codie/mineonline/protocol. * * @see {@link Handler} * @see {@link UrlUtils} diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineModeFix.java b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineModeFix.java new file mode 100644 index 000000000..6476dd882 --- /dev/null +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineModeFix.java @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2023 TheKodeToad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.prismlauncher.legacy.fix.online; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.Proxy; +import java.net.URL; +import java.net.URLConnection; + +public final class OnlineModeFix { + public static URLConnection openConnection(URL address, Proxy proxy) throws IOException { + // we start with "http://www.minecraft.net/game/joinserver.jsp?user=..." + if (!(address.getHost().equals("www.minecraft.net") && address.getPath().equals("/game/joinserver.jsp"))) + return null; + + // change it to "https://session.minecraft.net/game/joinserver.jsp?user=..." + // this seems to be the modern version of the same endpoint... + // maybe Mojang planned to patch old versions of the game to use it + // if it ever disappears this should be changed to use sessionserver.mojang.com/session/minecraft/join + // which of course has a different usage requiring JSON serialisation... + URL url; + try { + url = new URL("https", "session.minecraft.net", address.getPort(), address.getFile()); + } catch (MalformedURLException e) { + throw new AssertionError("url should be valid", e); + } + + return url.openConnection(); + } +} diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/SkinFix.java b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/SkinFix.java index e734bdbc7..d5b185450 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/SkinFix.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/SkinFix.java @@ -54,7 +54,7 @@ package org.prismlauncher.legacy.fix.online; import org.prismlauncher.legacy.utils.api.MojangApi; import org.prismlauncher.legacy.utils.api.Texture; -import org.prismlauncher.legacy.utils.url.CustomUrlConnection; +import org.prismlauncher.legacy.utils.url.ByteArrayUrlConnection; import org.prismlauncher.legacy.utils.url.UrlUtils; import java.awt.AlphaComposite; @@ -97,9 +97,9 @@ final class SkinFix { URLConnection connection = UrlUtils.openConnection(texture.getUrl(), proxy); try (InputStream in = connection.getInputStream()) { - // thank you craftycodie! + // thank you ahnewark! // this is heavily based on - // https://github.com/craftycodie/MineOnline/blob/4f4f86f9d051e0a6fd7ff0b95b2a05f7437683d7/src/main/java/gg/codie/mineonline/gui/textures/TextureHelper.java#L17 + // https://github.com/ahnewark/MineOnline/blob/4f4f86f9d051e0a6fd7ff0b95b2a05f7437683d7/src/main/java/gg/codie/mineonline/gui/textures/TextureHelper.java#L17 BufferedImage image = ImageIO.read(in); Graphics2D graphics = image.createGraphics(); graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); @@ -131,7 +131,7 @@ final class SkinFix { image = image.getSubimage(0, 0, 64, 32); ImageIO.write(image, "png", out); - return new CustomUrlConnection(out.toByteArray()); + return new ByteArrayUrlConnection(out.toByteArray()); } } diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/CustomUrlConnection.java b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/ByteArrayUrlConnection.java similarity index 86% rename from libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/CustomUrlConnection.java rename to libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/ByteArrayUrlConnection.java index 71b0e68f2..bc9cf2cc2 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/CustomUrlConnection.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/ByteArrayUrlConnection.java @@ -40,16 +40,12 @@ import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; -public final class CustomUrlConnection extends HttpURLConnection { +public final class ByteArrayUrlConnection extends HttpURLConnection { private final InputStream in; - public CustomUrlConnection(byte[] data) { - this(new ByteArrayInputStream(data)); - } - - public CustomUrlConnection(InputStream in) { + public ByteArrayUrlConnection(byte[] data) { super(null); - this.in = in; + this.in = new ByteArrayInputStream(data); } @Override @@ -58,12 +54,7 @@ public final class CustomUrlConnection extends HttpURLConnection { } @Override - public void disconnect() { - try { - in.close(); - } catch (IOException e) { - } - } + public void disconnect() {} @Override public InputStream getInputStream() throws IOException { diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/UrlUtils.java b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/UrlUtils.java index b0072485e..ae91b683c 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/UrlUtils.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/UrlUtils.java @@ -101,7 +101,7 @@ public final class UrlUtils { } catch (IOException | Error | RuntimeException e) { throw e; // rethrow if possible } catch (Throwable e) { - throw new AssertionError(e); // oh dear! this isn't meant to happen + throw new AssertionError("openConnection should not throw", e); // oh dear! this isn't meant to happen } } } diff --git a/libraries/launcher/org/prismlauncher/EntryPoint.java b/libraries/launcher/org/prismlauncher/EntryPoint.java index 699adfe30..8b9046f0c 100644 --- a/libraries/launcher/org/prismlauncher/EntryPoint.java +++ b/libraries/launcher/org/prismlauncher/EntryPoint.java @@ -81,10 +81,9 @@ public final class EntryPoint { PreLaunchAction action = PreLaunchAction.PROCEED; try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8))) { - String line; - while (action == PreLaunchAction.PROCEED) { - if ((line = reader.readLine()) != null) + String line = reader.readLine(); + if (line != null) action = parseLine(line, params); else action = PreLaunchAction.ABORT; @@ -105,7 +104,7 @@ public final class EntryPoint { return ExitCode.ABORT; } - setProperties(params); + SystemProperties.apply(params); String launcherType = params.getString("launcher"); @@ -141,43 +140,10 @@ public final class EntryPoint { } } - private static void setProperties(Parameters params) { - String launcherBrand = params.getString("launcherBrand", null); - String launcherVersion = params.getString("launcherVersion", null); - String name = params.getString("instanceName", null); - String iconId = params.getString("instanceIconKey", null); - String iconPath = params.getString("instanceIconPath", null); - String windowTitle = params.getString("windowTitle", null); - String windowDimensions = params.getString("windowParams", null); - - if (launcherBrand != null) - System.setProperty("minecraft.launcher.brand", launcherBrand); - if (launcherVersion != null) - System.setProperty("minecraft.launcher.version", launcherVersion); - - // set useful properties for mods - if (name != null) - System.setProperty("org.prismlauncher.instance.name", name); - if (iconId != null) - System.setProperty("org.prismlauncher.instance.icon.id", iconId); - if (iconPath != null) - System.setProperty("org.prismlauncher.instance.icon.path", iconPath); - if (windowTitle != null) - System.setProperty("org.prismlauncher.window.title", windowTitle); - if (windowDimensions != null) - System.setProperty("org.prismlauncher.window.dimensions", windowDimensions); - - // set multimc properties for compatibility - if (name != null) - System.setProperty("multimc.instance.title", name); - if (iconId != null) - System.setProperty("multimc.instance.icon", iconId); - } - private static PreLaunchAction parseLine(String input, Parameters params) throws ParseException { switch (input) { case "": - break; + return PreLaunchAction.PROCEED; case "launch": return PreLaunchAction.LAUNCH; @@ -192,9 +158,9 @@ public final class EntryPoint { throw new ParseException(input, "[key] [value]"); params.add(pair[0], pair[1]); - } - return PreLaunchAction.PROCEED; + return PreLaunchAction.PROCEED; + } } private enum PreLaunchAction { PROCEED, LAUNCH, ABORT } diff --git a/libraries/launcher/org/prismlauncher/SystemProperties.java b/libraries/launcher/org/prismlauncher/SystemProperties.java new file mode 100644 index 000000000..5120e930d --- /dev/null +++ b/libraries/launcher/org/prismlauncher/SystemProperties.java @@ -0,0 +1,38 @@ +package org.prismlauncher; + +import org.prismlauncher.utils.Parameters; + +public final class SystemProperties { + public static void apply(Parameters params) { + String launcherBrand = params.getString("launcherBrand", null); + String launcherVersion = params.getString("launcherVersion", null); + String name = params.getString("instanceName", null); + String iconId = params.getString("instanceIconKey", null); + String iconPath = params.getString("instanceIconPath", null); + String windowTitle = params.getString("windowTitle", null); + String windowDimensions = params.getString("windowParams", null); + + if (launcherBrand != null) + System.setProperty("minecraft.launcher.brand", launcherBrand); + if (launcherVersion != null) + System.setProperty("minecraft.launcher.version", launcherVersion); + + // set useful properties for mods + if (name != null) + System.setProperty("org.prismlauncher.instance.name", name); + if (iconId != null) + System.setProperty("org.prismlauncher.instance.icon.id", iconId); + if (iconPath != null) + System.setProperty("org.prismlauncher.instance.icon.path", iconPath); + if (windowTitle != null) + System.setProperty("org.prismlauncher.window.title", windowTitle); + if (windowDimensions != null) + System.setProperty("org.prismlauncher.window.dimensions", windowDimensions); + + // set multimc properties for compatibility + if (name != null) + System.setProperty("multimc.instance.title", name); + if (iconId != null) + System.setProperty("multimc.instance.icon", iconId); + } +} diff --git a/libraries/launcher/org/prismlauncher/utils/ReflectionUtils.java b/libraries/launcher/org/prismlauncher/utils/ReflectionUtils.java index 3b2bfd9bb..9d03a90a6 100644 --- a/libraries/launcher/org/prismlauncher/utils/ReflectionUtils.java +++ b/libraries/launcher/org/prismlauncher/utils/ReflectionUtils.java @@ -54,15 +54,9 @@ package org.prismlauncher.utils; -import org.prismlauncher.utils.logging.Log; - -import java.applet.Applet; -import java.io.File; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; public final class ReflectionUtils { private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); From 345cdf5c9d6417b5c2ce15e8967de3886d1113f1 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Tue, 2 Jan 2024 19:10:41 +0000 Subject: [PATCH 088/223] Pass proxy Signed-off-by: TheKodeToad --- .../org/prismlauncher/legacy/fix/online/OnlineModeFix.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineModeFix.java b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineModeFix.java index 6476dd882..5ed33b85c 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineModeFix.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineModeFix.java @@ -41,6 +41,8 @@ import java.net.Proxy; import java.net.URL; import java.net.URLConnection; +import org.prismlauncher.legacy.utils.url.UrlUtils; + public final class OnlineModeFix { public static URLConnection openConnection(URL address, Proxy proxy) throws IOException { // we start with "http://www.minecraft.net/game/joinserver.jsp?user=..." @@ -59,6 +61,6 @@ public final class OnlineModeFix { throw new AssertionError("url should be valid", e); } - return url.openConnection(); + return UrlUtils.openConnection(url, proxy); } } From e5b608447a1c4860343aed15ef1e1bd5940ba17d Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Wed, 3 Jan 2024 18:14:47 +0100 Subject: [PATCH 089/223] chore: improve param name Signed-off-by: Sefa Eyeoglu --- launcher/DesktopServices.cpp | 8 ++++---- launcher/DesktopServices.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/launcher/DesktopServices.cpp b/launcher/DesktopServices.cpp index ecad825a5..7c070bd31 100644 --- a/launcher/DesktopServices.cpp +++ b/launcher/DesktopServices.cpp @@ -40,18 +40,18 @@ #include "FileSystem.h" namespace DesktopServices { -bool openPath(const QFileInfo& path, bool ensureExists) +bool openPath(const QFileInfo& path, bool ensureFolderPathExists) { qDebug() << "Opening path" << path; - if (ensureExists) { + if (ensureFolderPathExists) { FS::ensureFolderPathExists(path); } return openUrl(QUrl::fromLocalFile(QFileInfo(path).absolutePath())); } -bool openPath(const QString& path, bool ensureExists) +bool openPath(const QString& path, bool ensureFolderPathExists) { - return openPath(QFileInfo(path), ensureExists); + return openPath(QFileInfo(path), ensureFolderPathExists); } bool run(const QString& application, const QStringList& args, const QString& workingDirectory, qint64* pid) diff --git a/launcher/DesktopServices.h b/launcher/DesktopServices.h index 6c4cbdce7..6c6208e82 100644 --- a/launcher/DesktopServices.h +++ b/launcher/DesktopServices.h @@ -12,15 +12,15 @@ class QFileInfo; namespace DesktopServices { /** * Open a path in whatever application is applicable. - * @param ensurePathExists Make sure the path exists + * @param ensureFolderPathExists Make sure the path exists */ -bool openPath(const QFileInfo& path, bool ensurePathExists = false); +bool openPath(const QFileInfo& path, bool ensureFolderPathExists = false); /** * Open a path in whatever application is applicable. - * @param ensurePathExists Make sure the path exists + * @param ensureFolderPathExists Make sure the path exists */ -bool openPath(const QString& path, bool ensurePathExists = false); +bool openPath(const QString& path, bool ensureFolderPathExists = false); /** * Run an application From 786e03571b529c610ada33d87581e65cefc4cae3 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Wed, 3 Jan 2024 22:50:55 +0200 Subject: [PATCH 090/223] Format java code Signed-off-by: Trial97 --- .../org/prismlauncher/legacy/fix/online/OnlineModeFix.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineModeFix.java b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineModeFix.java index 5ed33b85c..1bab76d53 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineModeFix.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineModeFix.java @@ -35,14 +35,14 @@ package org.prismlauncher.legacy.fix.online; +import org.prismlauncher.legacy.utils.url.UrlUtils; + import java.io.IOException; import java.net.MalformedURLException; import java.net.Proxy; import java.net.URL; import java.net.URLConnection; -import org.prismlauncher.legacy.utils.url.UrlUtils; - public final class OnlineModeFix { public static URLConnection openConnection(URL address, Proxy proxy) throws IOException { // we start with "http://www.minecraft.net/game/joinserver.jsp?user=..." From 219e2862f9d67d6a81ef634846237e1eec177d69 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 5 Jan 2024 23:02:42 +0200 Subject: [PATCH 091/223] Fixed openAL placeholder Signed-off-by: Trial97 --- launcher/ui/pages/instance/InstanceSettingsPage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.cpp b/launcher/ui/pages/instance/InstanceSettingsPage.cpp index 74785f97e..d4fd0ec5b 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.cpp +++ b/launcher/ui/pages/instance/InstanceSettingsPage.cpp @@ -346,7 +346,7 @@ void InstanceSettingsPage::loadSettings() #ifdef Q_OS_LINUX ui->lineEditOpenALPath->setPlaceholderText(APPLICATION->m_detectedOpenALPath); #else - ui->lineEditGLFWPath->setPlaceholderText(tr("Path to %1 library file").arg(BuildConfig.OPENAL_LIBRARY_NAME)); + ui->lineEditOpenALPath->setPlaceholderText(tr("Path to %1 library file").arg(BuildConfig.OPENAL_LIBRARY_NAME)); #endif // Performance From 2cb07d3e380be6caaf922648aa75b822915818f2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 7 Jan 2024 00:20:13 +0000 Subject: [PATCH 092/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'flake-parts': 'github:hercules-ci/flake-parts/34fed993f1674c8d06d58b37ce1e0fe5eebcb9f5' (2023-12-01) → 'github:hercules-ci/flake-parts/88a2cd8166694ba0b6cb374700799cec53aef527' (2024-01-01) • Updated input 'flake-parts/nixpkgs-lib': 'github:NixOS/nixpkgs/e92039b55bcd58469325ded85d4f58dd5a4eaf58?dir=lib' (2023-11-29) → 'github:NixOS/nixpkgs/b0d36bd0a420ecee3bc916c91886caca87c894e9?dir=lib' (2023-12-30) • Updated input 'nixpkgs': 'github:nixos/nixpkgs/e1fa12d4f6c6fe19ccb59cac54b5b3f25e160870' (2023-12-25) → 'github:nixos/nixpkgs/63143ac2c9186be6d9da6035fa22620018c85932' (2024-01-02) --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index 774f394cd..9ed93f9fd 100644 --- a/flake.lock +++ b/flake.lock @@ -21,11 +21,11 @@ "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1701473968, - "narHash": "sha256-YcVE5emp1qQ8ieHUnxt1wCZCC3ZfAS+SRRWZ2TMda7E=", + "lastModified": 1704152458, + "narHash": "sha256-DS+dGw7SKygIWf9w4eNBUZsK+4Ug27NwEWmn2tnbycg=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "34fed993f1674c8d06d58b37ce1e0fe5eebcb9f5", + "rev": "88a2cd8166694ba0b6cb374700799cec53aef527", "type": "github" }, "original": { @@ -106,11 +106,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1703499205, - "narHash": "sha256-lF9rK5mSUfIZJgZxC3ge40tp1gmyyOXZ+lRY3P8bfbg=", + "lastModified": 1704161960, + "narHash": "sha256-QGua89Pmq+FBAro8NriTuoO/wNaUtugt29/qqA8zeeM=", "owner": "nixos", "repo": "nixpkgs", - "rev": "e1fa12d4f6c6fe19ccb59cac54b5b3f25e160870", + "rev": "63143ac2c9186be6d9da6035fa22620018c85932", "type": "github" }, "original": { @@ -123,11 +123,11 @@ "nixpkgs-lib": { "locked": { "dir": "lib", - "lastModified": 1701253981, - "narHash": "sha256-ztaDIyZ7HrTAfEEUt9AtTDNoCYxUdSd6NrRHaYOIxtk=", + "lastModified": 1703961334, + "narHash": "sha256-M1mV/Cq+pgjk0rt6VxoyyD+O8cOUiai8t9Q6Yyq4noY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "e92039b55bcd58469325ded85d4f58dd5a4eaf58", + "rev": "b0d36bd0a420ecee3bc916c91886caca87c894e9", "type": "github" }, "original": { From 26474d13749dd81869e155d64125c4b7d73ff0f2 Mon Sep 17 00:00:00 2001 From: seth Date: Thu, 11 Jan 2024 03:06:37 -0500 Subject: [PATCH 093/223] nix: deduplicate nixpkgs input Signed-off-by: seth --- flake.lock | 22 +++------------------- flake.nix | 13 +++++++++---- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/flake.lock b/flake.lock index 9ed93f9fd..1af961f3d 100644 --- a/flake.lock +++ b/flake.lock @@ -18,7 +18,9 @@ }, "flake-parts": { "inputs": { - "nixpkgs-lib": "nixpkgs-lib" + "nixpkgs-lib": [ + "nixpkgs" + ] }, "locked": { "lastModified": 1704152458, @@ -120,24 +122,6 @@ "type": "github" } }, - "nixpkgs-lib": { - "locked": { - "dir": "lib", - "lastModified": 1703961334, - "narHash": "sha256-M1mV/Cq+pgjk0rt6VxoyyD+O8cOUiai8t9Q6Yyq4noY=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "b0d36bd0a420ecee3bc916c91886caca87c894e9", - "type": "github" - }, - "original": { - "dir": "lib", - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, "pre-commit-hooks": { "inputs": { "flake-compat": [ diff --git a/flake.nix b/flake.nix index afb0ec63a..4e2bd8a34 100644 --- a/flake.nix +++ b/flake.nix @@ -3,13 +3,18 @@ inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; - flake-parts.url = "github:hercules-ci/flake-parts"; + flake-parts = { + url = "github:hercules-ci/flake-parts"; + inputs.nixpkgs-lib.follows = "nixpkgs"; + }; nix-filter.url = "github:numtide/nix-filter"; pre-commit-hooks = { url = "github:cachix/pre-commit-hooks.nix"; - inputs.nixpkgs.follows = "nixpkgs"; - inputs.nixpkgs-stable.follows = "nixpkgs"; - inputs.flake-compat.follows = "flake-compat"; + inputs = { + nixpkgs.follows = "nixpkgs"; + nixpkgs-stable.follows = "nixpkgs"; + flake-compat.follows = "flake-compat"; + }; }; flake-compat = { url = "github:edolstra/flake-compat"; From 839adfc90bac8204581b930efc7cf2ad55629546 Mon Sep 17 00:00:00 2001 From: seth Date: Thu, 11 Jan 2024 03:11:58 -0500 Subject: [PATCH 094/223] nix: add garnix cache to nixConfig Signed-off-by: seth --- flake.nix | 5 +++++ nix/README.md | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 4e2bd8a34..1582400f1 100644 --- a/flake.nix +++ b/flake.nix @@ -1,6 +1,11 @@ { description = "A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once (Fork of MultiMC)"; + nixConfig = { + extra-substituters = ["https://cache.garnix.io"]; + extra-trusted-public-keys = ["cache.garnix.io:CTFPyKSLcx5RMJKfLo5EEPUObbA78b0YQ2DTCJXqr9g="]; + }; + inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; flake-parts = { diff --git a/nix/README.md b/nix/README.md index 7a422fc5b..f7923577f 100644 --- a/nix/README.md +++ b/nix/README.md @@ -9,7 +9,8 @@ See [Package variants](#package-variants) for a list of available packages. ## Installing a development release (flake) We use [garnix](https://garnix.io/) to build and cache our development builds. -If you want to avoid rebuilds you may add the garnix cache to your substitutors. +If you want to avoid rebuilds you may add the garnix cache to your substitutors, or use `--accept-flake-config` +to temporarily enable it when using `nix` commands. Example (NixOS): From b0f65476d987623eeb1d6f1a32e2c6cfc552cbaa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 11 Jan 2024 18:59:17 +0000 Subject: [PATCH 095/223] chore(deps): update actions/cache action to v3.3.3 --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1159aad6c..c602a6dbe 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -151,7 +151,7 @@ jobs: - name: Retrieve ccache cache (Windows MinGW-w64) if: runner.os == 'Windows' && matrix.msystem != '' && inputs.build_type == 'Debug' - uses: actions/cache@v3.3.2 + uses: actions/cache@v3.3.3 with: path: '${{ github.workspace }}\.ccache' key: ${{ matrix.os }}-mingw-w64-ccache-${{ github.run_id }} From 9c610b616abb60b41d600a10820faf965ed51b81 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 12 Jan 2024 18:02:43 +0000 Subject: [PATCH 096/223] chore(deps): update cachix/install-nix-action action to v25 --- .github/workflows/update-flake.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-flake.yml b/.github/workflows/update-flake.yml index 538972968..2d78997ed 100644 --- a/.github/workflows/update-flake.yml +++ b/.github/workflows/update-flake.yml @@ -17,7 +17,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: cachix/install-nix-action@7ac1ec25491415c381d9b62f0657c7a028df52a7 # v24 + - uses: cachix/install-nix-action@6004951b182f8860210c8d6f0d808ec5b1a33d28 # v25 - uses: DeterminateSystems/update-flake-lock@v20 with: From 96c714de6eb27bf10ea0f295067e92b853130dbc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 14 Jan 2024 00:20:26 +0000 Subject: [PATCH 097/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'flake-parts': 'github:hercules-ci/flake-parts/88a2cd8166694ba0b6cb374700799cec53aef527' (2024-01-01) → 'github:hercules-ci/flake-parts/07f6395285469419cf9d078f59b5b49993198c00' (2024-01-11) • Updated input 'nixpkgs': 'github:nixos/nixpkgs/63143ac2c9186be6d9da6035fa22620018c85932' (2024-01-02) → 'github:nixos/nixpkgs/eabe8d3eface69f5bb16c18f8662a702f50c20d5' (2024-01-09) • Updated input 'pre-commit-hooks': 'github:cachix/pre-commit-hooks.nix/9d3d7e18c6bc4473d7520200d4ddab12f8402d38' (2023-12-30) → 'github:cachix/pre-commit-hooks.nix/274ae3979a0eacae422e1bbcf63b8b7a335e1114' (2024-01-12) --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index 1af961f3d..ea11e9f26 100644 --- a/flake.lock +++ b/flake.lock @@ -23,11 +23,11 @@ ] }, "locked": { - "lastModified": 1704152458, - "narHash": "sha256-DS+dGw7SKygIWf9w4eNBUZsK+4Ug27NwEWmn2tnbycg=", + "lastModified": 1704982712, + "narHash": "sha256-2Ptt+9h8dczgle2Oo6z5ni5rt/uLMG47UFTR1ry/wgg=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "88a2cd8166694ba0b6cb374700799cec53aef527", + "rev": "07f6395285469419cf9d078f59b5b49993198c00", "type": "github" }, "original": { @@ -108,11 +108,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1704161960, - "narHash": "sha256-QGua89Pmq+FBAro8NriTuoO/wNaUtugt29/qqA8zeeM=", + "lastModified": 1704842529, + "narHash": "sha256-OTeQA+F8d/Evad33JMfuXC89VMetQbsU4qcaePchGr4=", "owner": "nixos", "repo": "nixpkgs", - "rev": "63143ac2c9186be6d9da6035fa22620018c85932", + "rev": "eabe8d3eface69f5bb16c18f8662a702f50c20d5", "type": "github" }, "original": { @@ -137,11 +137,11 @@ ] }, "locked": { - "lastModified": 1703939133, - "narHash": "sha256-Gxe+mfOT6bL7wLC/tuT2F+V+Sb44jNr8YsJ3cyIl4Mo=", + "lastModified": 1705072518, + "narHash": "sha256-90dERRuG781f0EWjn2AOtScZqsTcpIFLpY8TN2VbkL8=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "9d3d7e18c6bc4473d7520200d4ddab12f8402d38", + "rev": "274ae3979a0eacae422e1bbcf63b8b7a335e1114", "type": "github" }, "original": { From 67d088dc53337fc2abeae3ce20c89c9495f5c9be Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Sun, 14 Jan 2024 11:36:17 +0100 Subject: [PATCH 098/223] fix: simplify openPath calls Signed-off-by: Sefa Eyeoglu --- launcher/ui/MainWindow.cpp | 2 +- launcher/ui/pages/instance/ScreenshotsPage.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index 9f2cc434f..85573314d 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -1452,7 +1452,7 @@ void MainWindow::on_actionViewSelectedInstFolder_triggered() { if (m_selectedInstance) { QString str = m_selectedInstance->instanceRoot(); - DesktopServices::openPath(QDir(str).absolutePath()); + DesktopServices::openPath(QFileInfo(str)); } } diff --git a/launcher/ui/pages/instance/ScreenshotsPage.cpp b/launcher/ui/pages/instance/ScreenshotsPage.cpp index 01061160b..c3f955733 100644 --- a/launcher/ui/pages/instance/ScreenshotsPage.cpp +++ b/launcher/ui/pages/instance/ScreenshotsPage.cpp @@ -324,8 +324,7 @@ void ScreenshotsPage::onItemActivated(QModelIndex index) if (!index.isValid()) return; auto info = m_model->fileInfo(index); - QString fileName = info.absoluteFilePath(); - DesktopServices::openPath(info.absoluteFilePath()); + DesktopServices::openPath(info); } void ScreenshotsPage::onCurrentSelectionChanged(const QItemSelection& selected) From baebef982eebbe7ea30d9d54cda9cadac279e1be Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Sat, 13 Jan 2024 16:10:48 +0100 Subject: [PATCH 099/223] feat: add macOS code signing Signed-off-by: Sefa Eyeoglu --- .github/workflows/build.yml | 32 ++++++++++++++++++++++++++- .github/workflows/trigger_builds.yml | 3 +++ .github/workflows/trigger_release.yml | 3 +++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c602a6dbe..ec1ac220d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,6 +21,15 @@ on: WINDOWS_CODESIGN_PASSWORD: description: Password for signing Windows builds required: false + APPLE_CODESIGN_CERT: + description: Certificate for signing macOS builds + required: false + APPLE_CODESIGN_PASSWORD: + description: Password for signing macOS builds + required: false + APPLE_CODESIGN_ID: + description: Certificate ID for signing macOS builds + required: false CACHIX_AUTH_TOKEN: description: Private token for authenticating against Cachix cache required: false @@ -336,6 +345,20 @@ jobs: # PACKAGE BUILDS ## + - name: Fetch codesign certificate (macOS) + if: runner.os == 'macOS' + run: | + echo '${{ secrets.APPLE_CODESIGN_CERT }}' | base64 --decode > codesign.p12 + if [ -n '${{ secrets.APPLE_CODESIGN_ID }}' ]; then + security create-keychain -p '${{ secrets.APPLE_CODESIGN_PASSWORD }}' build.keychain + security default-keychain -s build.keychain + security unlock-keychain -p '${{ secrets.APPLE_CODESIGN_PASSWORD }}' build.keychain + security import codesign.p12 -k build.keychain -P '${{ secrets.APPLE_CODESIGN_PASSWORD }}' -T /usr/bin/codesign + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k '${{ secrets.APPLE_CODESIGN_PASSWORD }}' build.keychain + else + echo ":warning: Using ad-hoc code signing for macOS, as certificate was not present." >> $GITHUB_STEP_SUMMARY + fi + - name: Package (macOS) if: runner.os == 'macOS' run: | @@ -343,7 +366,14 @@ jobs: cd ${{ env.INSTALL_DIR }} chmod +x "PrismLauncher.app/Contents/MacOS/prismlauncher" - sudo codesign --sign - --deep --force --entitlements "../program_info/App.entitlements" --options runtime "PrismLauncher.app/Contents/MacOS/prismlauncher" + + if [ -n '${{ secrets.APPLE_CODESIGN_ID }}' ]; then + APPLE_CODESIGN_ID='${{ secrets.APPLE_CODESIGN_ID }}' + else + APPLE_CODESIGN_ID='-' + fi + + sudo codesign --sign "$APPLE_CODESIGN_ID" --deep --force --entitlements "../program_info/App.entitlements" --options runtime "PrismLauncher.app/Contents/MacOS/prismlauncher" mv "PrismLauncher.app" "Prism Launcher.app" tar -czf ../PrismLauncher.tar.gz * diff --git a/.github/workflows/trigger_builds.yml b/.github/workflows/trigger_builds.yml index 70fda60ed..9df647759 100644 --- a/.github/workflows/trigger_builds.yml +++ b/.github/workflows/trigger_builds.yml @@ -32,6 +32,9 @@ jobs: SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }} WINDOWS_CODESIGN_CERT: ${{ secrets.WINDOWS_CODESIGN_CERT }} WINDOWS_CODESIGN_PASSWORD: ${{ secrets.WINDOWS_CODESIGN_PASSWORD }} + APPLE_CODESIGN_CERT: ${{ secrets.APPLE_CODESIGN_CERT }} + APPLE_CODESIGN_PASSWORD: ${{ secrets.APPLE_CODESIGN_PASSWORD }} + APPLE_CODESIGN_ID: ${{ secrets.APPLE_CODESIGN_ID }} CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} GPG_PRIVATE_KEY_ID: ${{ secrets.GPG_PRIVATE_KEY_ID }} diff --git a/.github/workflows/trigger_release.yml b/.github/workflows/trigger_release.yml index ebf5f96e6..ea2a7f3a1 100644 --- a/.github/workflows/trigger_release.yml +++ b/.github/workflows/trigger_release.yml @@ -16,6 +16,9 @@ jobs: SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }} WINDOWS_CODESIGN_CERT: ${{ secrets.WINDOWS_CODESIGN_CERT }} WINDOWS_CODESIGN_PASSWORD: ${{ secrets.WINDOWS_CODESIGN_PASSWORD }} + APPLE_CODESIGN_CERT: ${{ secrets.APPLE_CODESIGN_CERT }} + APPLE_CODESIGN_PASSWORD: ${{ secrets.APPLE_CODESIGN_PASSWORD }} + APPLE_CODESIGN_ID: ${{ secrets.APPLE_CODESIGN_ID }} CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} GPG_PRIVATE_KEY_ID: ${{ secrets.GPG_PRIVATE_KEY_ID }} From 27c52eff8b9add54c23f4e033c64e8e9bd7aaa9a Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Sat, 13 Jan 2024 18:04:46 +0100 Subject: [PATCH 100/223] feat: add macOS notarization Signed-off-by: Sefa Eyeoglu --- .github/workflows/build.yml | 31 +++++++++++++++++++++++++-- .github/workflows/trigger_builds.yml | 3 +++ .github/workflows/trigger_release.yml | 11 ++++++---- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ec1ac220d..4c296fa8c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,6 +30,15 @@ on: APPLE_CODESIGN_ID: description: Certificate ID for signing macOS builds required: false + APPLE_NOTARIZE_APPLE_ID: + description: Apple ID used for notarizing macOS builds + required: false + APPLE_NOTARIZE_TEAM_ID: + description: Team ID used for notarizing macOS builds + required: false + APPLE_NOTARIZE_PASSWORD: + description: Password used for notarizing macOS builds + required: false CACHIX_AUTH_TOKEN: description: Private token for authenticating against Cachix cache required: false @@ -375,7 +384,25 @@ jobs: sudo codesign --sign "$APPLE_CODESIGN_ID" --deep --force --entitlements "../program_info/App.entitlements" --options runtime "PrismLauncher.app/Contents/MacOS/prismlauncher" mv "PrismLauncher.app" "Prism Launcher.app" - tar -czf ../PrismLauncher.tar.gz * + + - name: Notarize (macOS) + if: runner.os == 'macOS' + run: | + cd ${{ env.INSTALL_DIR }} + + if [ -n '${{ secrets.APPLE_NOTARIZE_PASSWORD }}' ]; then + ditto -c -k --sequesterRsrc --keepParent "Prism Launcher.app" ../PrismLauncher.zip + xcrun notarytool submit ../PrismLauncher.zip \ + --wait --progress \ + --apple-id '${{ secrets.APPLE_NOTARIZE_APPLE_ID }}' \ + --team-id '${{ secrets.APPLE_NOTARIZE_TEAM_ID }}' \ + --password '${{ secrets.APPLE_NOTARIZE_PASSWORD }}' + + xcrun stapler staple "Prism Launcher.app" + else + echo ":warning: Skipping notarization as credentials are not present." >> $GITHUB_STEP_SUMMARY + fi + ditto -c -k --sequesterRsrc --keepParent "Prism Launcher.app" ../PrismLauncher.zip - name: Make Sparkle signature (macOS) if: matrix.name == 'macOS' @@ -550,7 +577,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }} - path: PrismLauncher.tar.gz + path: PrismLauncher.zip - name: Upload binary zip (Windows) if: runner.os == 'Windows' diff --git a/.github/workflows/trigger_builds.yml b/.github/workflows/trigger_builds.yml index 9df647759..0b8386d69 100644 --- a/.github/workflows/trigger_builds.yml +++ b/.github/workflows/trigger_builds.yml @@ -35,6 +35,9 @@ jobs: APPLE_CODESIGN_CERT: ${{ secrets.APPLE_CODESIGN_CERT }} APPLE_CODESIGN_PASSWORD: ${{ secrets.APPLE_CODESIGN_PASSWORD }} APPLE_CODESIGN_ID: ${{ secrets.APPLE_CODESIGN_ID }} + APPLE_NOTARIZE_APPLE_ID: ${{ secrets.APPLE_NOTARIZE_APPLE_ID }} + APPLE_NOTARIZE_TEAM_ID: ${{ secrets.APPLE_NOTARIZE_TEAM_ID }} + APPLE_NOTARIZE_PASSWORD: ${{ secrets.APPLE_NOTARIZE_PASSWORD }} CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} GPG_PRIVATE_KEY_ID: ${{ secrets.GPG_PRIVATE_KEY_ID }} diff --git a/.github/workflows/trigger_release.yml b/.github/workflows/trigger_release.yml index ea2a7f3a1..9b2bf810f 100644 --- a/.github/workflows/trigger_release.yml +++ b/.github/workflows/trigger_release.yml @@ -19,6 +19,9 @@ jobs: APPLE_CODESIGN_CERT: ${{ secrets.APPLE_CODESIGN_CERT }} APPLE_CODESIGN_PASSWORD: ${{ secrets.APPLE_CODESIGN_PASSWORD }} APPLE_CODESIGN_ID: ${{ secrets.APPLE_CODESIGN_ID }} + APPLE_NOTARIZE_APPLE_ID: ${{ secrets.APPLE_NOTARIZE_APPLE_ID }} + APPLE_NOTARIZE_TEAM_ID: ${{ secrets.APPLE_NOTARIZE_TEAM_ID }} + APPLE_NOTARIZE_PASSWORD: ${{ secrets.APPLE_NOTARIZE_PASSWORD }} CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} GPG_PRIVATE_KEY_ID: ${{ secrets.GPG_PRIVATE_KEY_ID }} @@ -49,8 +52,8 @@ jobs: mv PrismLauncher-Linux-Qt5*/PrismLauncher.tar.gz PrismLauncher-Linux-Qt5-${{ env.VERSION }}.tar.gz mv PrismLauncher-*.AppImage/PrismLauncher-*.AppImage PrismLauncher-Linux-x86_64.AppImage mv PrismLauncher-*.AppImage.zsync/PrismLauncher-*.AppImage.zsync PrismLauncher-Linux-x86_64.AppImage.zsync - mv PrismLauncher-macOS-Legacy*/PrismLauncher.tar.gz PrismLauncher-macOS-Legacy-${{ env.VERSION }}.tar.gz - mv PrismLauncher-macOS*/PrismLauncher.tar.gz PrismLauncher-macOS-${{ env.VERSION }}.tar.gz + mv PrismLauncher-macOS-Legacy*/PrismLauncher.zip PrismLauncher-macOS-Legacy-${{ env.VERSION }}.zip + mv PrismLauncher-macOS*/PrismLauncher.zip PrismLauncher-macOS-${{ env.VERSION }}.zip tar --exclude='.git' -czf PrismLauncher-${{ env.VERSION }}.tar.gz PrismLauncher-${{ env.VERSION }} @@ -105,6 +108,6 @@ jobs: PrismLauncher-Windows-MSVC-${{ env.VERSION }}.zip PrismLauncher-Windows-MSVC-Portable-${{ env.VERSION }}.zip PrismLauncher-Windows-MSVC-Setup-${{ env.VERSION }}.exe - PrismLauncher-macOS-${{ env.VERSION }}.tar.gz - PrismLauncher-macOS-Legacy-${{ env.VERSION }}.tar.gz + PrismLauncher-macOS-${{ env.VERSION }}.zip + PrismLauncher-macOS-Legacy-${{ env.VERSION }}.zip PrismLauncher-${{ env.VERSION }}.tar.gz From de9232783e50cf3fa522dc13bddf937754ff33ce Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Wed, 17 Jan 2024 13:09:56 +0100 Subject: [PATCH 101/223] chore: remove cachix auth token secret Signed-off-by: Sefa Eyeoglu --- .github/workflows/build.yml | 3 --- .github/workflows/trigger_builds.yml | 1 - .github/workflows/trigger_release.yml | 1 - 3 files changed, 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4c296fa8c..22d8defaa 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -39,9 +39,6 @@ on: APPLE_NOTARIZE_PASSWORD: description: Password used for notarizing macOS builds required: false - CACHIX_AUTH_TOKEN: - description: Private token for authenticating against Cachix cache - required: false GPG_PRIVATE_KEY: description: Private key for AppImage signing required: false diff --git a/.github/workflows/trigger_builds.yml b/.github/workflows/trigger_builds.yml index 0b8386d69..9efafc8cc 100644 --- a/.github/workflows/trigger_builds.yml +++ b/.github/workflows/trigger_builds.yml @@ -38,6 +38,5 @@ jobs: APPLE_NOTARIZE_APPLE_ID: ${{ secrets.APPLE_NOTARIZE_APPLE_ID }} APPLE_NOTARIZE_TEAM_ID: ${{ secrets.APPLE_NOTARIZE_TEAM_ID }} APPLE_NOTARIZE_PASSWORD: ${{ secrets.APPLE_NOTARIZE_PASSWORD }} - CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} GPG_PRIVATE_KEY_ID: ${{ secrets.GPG_PRIVATE_KEY_ID }} diff --git a/.github/workflows/trigger_release.yml b/.github/workflows/trigger_release.yml index 9b2bf810f..2afbaeb61 100644 --- a/.github/workflows/trigger_release.yml +++ b/.github/workflows/trigger_release.yml @@ -22,7 +22,6 @@ jobs: APPLE_NOTARIZE_APPLE_ID: ${{ secrets.APPLE_NOTARIZE_APPLE_ID }} APPLE_NOTARIZE_TEAM_ID: ${{ secrets.APPLE_NOTARIZE_TEAM_ID }} APPLE_NOTARIZE_PASSWORD: ${{ secrets.APPLE_NOTARIZE_PASSWORD }} - CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} GPG_PRIVATE_KEY_ID: ${{ secrets.GPG_PRIVATE_KEY_ID }} From bfd1262c14fd2c57ecb8ebf081687212b11a738e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 20:29:50 +0000 Subject: [PATCH 102/223] chore(deps): update actions/cache action to v4 --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c602a6dbe..982ecee4a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -151,7 +151,7 @@ jobs: - name: Retrieve ccache cache (Windows MinGW-w64) if: runner.os == 'Windows' && matrix.msystem != '' && inputs.build_type == 'Debug' - uses: actions/cache@v3.3.3 + uses: actions/cache@v4.0.0 with: path: '${{ github.workspace }}\.ccache' key: ${{ matrix.os }}-mingw-w64-ccache-${{ github.run_id }} From 30913fdb2bef0f09843e1834f5c69e345327329e Mon Sep 17 00:00:00 2001 From: "erik.lundstedt" Date: Sun, 21 Jan 2024 00:31:00 +0100 Subject: [PATCH 103/223] fix a minor spelling misstake in Mod.cpp closes https://github.com/PrismLauncher/PrismLauncher/issues/2047 Signed-off-by: erik.lundstedt --- launcher/minecraft/mod/Mod.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/minecraft/mod/Mod.cpp b/launcher/minecraft/mod/Mod.cpp index 310946379..32d0d1614 100644 --- a/launcher/minecraft/mod/Mod.cpp +++ b/launcher/minecraft/mod/Mod.cpp @@ -274,7 +274,7 @@ QPixmap Mod::icon(QSize size, Qt::AspectRatioMode mode) const return {}; if (m_pack_image_cache_key.was_ever_used) { - qDebug() << "Mod" << name() << "Had it's icon evicted form the cache. reloading..."; + qDebug() << "Mod" << name() << "Had it's icon evicted from the cache. reloading..."; PixmapCache::markCacheMissByEviciton(); } // Image got evicted from the cache or an attempt to load it has not been made. load it and retry. From c7cd8b787704133e1581a0264f69cf9b9549dfd5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 21 Jan 2024 00:20:26 +0000 Subject: [PATCH 104/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'nix-filter': 'github:numtide/nix-filter/c843418ecfd0344ecb85844b082ff5675e02c443' (2023-12-04) → 'github:numtide/nix-filter/3449dc925982ad46246cfc36469baf66e1b64f17' (2024-01-15) • Updated input 'nixpkgs': 'github:nixos/nixpkgs/eabe8d3eface69f5bb16c18f8662a702f50c20d5' (2024-01-09) → 'github:nixos/nixpkgs/e5d1c87f5813afde2dda384ac807c57a105721cc' (2024-01-19) • Updated input 'pre-commit-hooks': 'github:cachix/pre-commit-hooks.nix/274ae3979a0eacae422e1bbcf63b8b7a335e1114' (2024-01-12) → 'github:cachix/pre-commit-hooks.nix/f56597d53fd174f796b5a7d3ee0b494f9e2285cc' (2024-01-20) • Updated input 'pre-commit-hooks/flake-utils': 'github:numtide/flake-utils/a1720a10a6cfe8234c0e93907ffe81be440f4cef' (2023-05-31) → 'github:numtide/flake-utils/4022d587cbbfd70fe950c1e2083a02621806a725' (2023-12-04) • Updated input 'pre-commit-hooks/gitignore': 'github:hercules-ci/gitignore.nix/a20de23b925fd8264fd7fad6454652e142fd7f73' (2022-08-14) → 'github:hercules-ci/gitignore.nix/43e1aa1308018f37118e34d3a9cb4f5e75dc11d5' (2023-12-29) --- flake.lock | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/flake.lock b/flake.lock index ea11e9f26..5b0619292 100644 --- a/flake.lock +++ b/flake.lock @@ -41,11 +41,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1685518550, - "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", + "lastModified": 1701680307, + "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", "owner": "numtide", "repo": "flake-utils", - "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", + "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", "type": "github" }, "original": { @@ -62,11 +62,11 @@ ] }, "locked": { - "lastModified": 1660459072, - "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=", + "lastModified": 1703887061, + "narHash": "sha256-gGPa9qWNc6eCXT/+Z5/zMkyYOuRZqeFZBDbopNZQkuY=", "owner": "hercules-ci", "repo": "gitignore.nix", - "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73", + "rev": "43e1aa1308018f37118e34d3a9cb4f5e75dc11d5", "type": "github" }, "original": { @@ -93,11 +93,11 @@ }, "nix-filter": { "locked": { - "lastModified": 1701697642, - "narHash": "sha256-L217WytWZHSY8GW9Gx1A64OnNctbuDbfslaTEofXXRw=", + "lastModified": 1705332318, + "narHash": "sha256-kcw1yFeJe9N4PjQji9ZeX47jg0p9A0DuU4djKvg1a7I=", "owner": "numtide", "repo": "nix-filter", - "rev": "c843418ecfd0344ecb85844b082ff5675e02c443", + "rev": "3449dc925982ad46246cfc36469baf66e1b64f17", "type": "github" }, "original": { @@ -108,11 +108,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1704842529, - "narHash": "sha256-OTeQA+F8d/Evad33JMfuXC89VMetQbsU4qcaePchGr4=", + "lastModified": 1705697961, + "narHash": "sha256-XepT3WS516evSFYkme3GrcI3+7uwXHqtHbip+t24J7E=", "owner": "nixos", "repo": "nixpkgs", - "rev": "eabe8d3eface69f5bb16c18f8662a702f50c20d5", + "rev": "e5d1c87f5813afde2dda384ac807c57a105721cc", "type": "github" }, "original": { @@ -137,11 +137,11 @@ ] }, "locked": { - "lastModified": 1705072518, - "narHash": "sha256-90dERRuG781f0EWjn2AOtScZqsTcpIFLpY8TN2VbkL8=", + "lastModified": 1705757126, + "narHash": "sha256-Eksr+n4Q8EYZKAN0Scef5JK4H6FcHc+TKNHb95CWm+c=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "274ae3979a0eacae422e1bbcf63b8b7a335e1114", + "rev": "f56597d53fd174f796b5a7d3ee0b494f9e2285cc", "type": "github" }, "original": { From f54ac25614b62b0a43d014d8b47f9faee8112d12 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sun, 21 Jan 2024 02:28:44 +0000 Subject: [PATCH 105/223] Use `minecraft` instead of `.minecraft` for better accessibility Signed-off-by: TheKodeToad --- launcher/InstanceCopyTask.cpp | 6 +++--- launcher/InstanceImportTask.cpp | 4 ++-- launcher/minecraft/MinecraftInstance.cpp | 6 +++--- launcher/modplatform/import_ftb/PackInstallTask.cpp | 2 +- launcher/modplatform/legacy_ftb/PackInstallTask.cpp | 4 ++-- .../modplatform/modrinth/ModrinthInstanceCreationTask.cpp | 4 ++-- launcher/modplatform/technic/SingleZipPackInstallTask.cpp | 2 +- launcher/modplatform/technic/SolderPackInstallTask.cpp | 2 +- launcher/modplatform/technic/TechnicPackProcessor.cpp | 2 +- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/launcher/InstanceCopyTask.cpp b/launcher/InstanceCopyTask.cpp index cdcd61ba6..52eb7d879 100644 --- a/launcher/InstanceCopyTask.cpp +++ b/launcher/InstanceCopyTask.cpp @@ -43,10 +43,10 @@ void InstanceCopyTask::executeTask() QFileInfo dotMCDir(FS::PathCombine(m_stagingPath, ".minecraft")); QString staging_mc_dir; - if (mcDir.exists() && !dotMCDir.exists()) - staging_mc_dir = mcDir.filePath(); - else + if (dotMCDir.exists() && !mcDir.exists()) staging_mc_dir = dotMCDir.filePath(); + else + staging_mc_dir = mcDir.filePath(); FS::copy savesCopy(FS::PathCombine(m_origInstance->gameRoot(), "saves"), FS::PathCombine(staging_mc_dir, "saves")); savesCopy.followSymlinks(true); diff --git a/launcher/InstanceImportTask.cpp b/launcher/InstanceImportTask.cpp index 9f0cf7460..d4676f358 100644 --- a/launcher/InstanceImportTask.cpp +++ b/launcher/InstanceImportTask.cpp @@ -164,8 +164,8 @@ void InstanceImportTask::processZipPack() } else if (technicFound) { // process as Technic pack qDebug() << "Technic:" << technicFound; - extractDir.mkpath(".minecraft"); - extractDir.cd(".minecraft"); + extractDir.mkpath("minecraft"); + extractDir.cd("minecraft"); m_modpackType = ModpackType::Technic; } else { QStringList paths_to_ignore{ "overrides/" }; diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index 4229f73eb..5a8c0d28a 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -292,10 +292,10 @@ QString MinecraftInstance::gameRoot() const QFileInfo mcDir(FS::PathCombine(instanceRoot(), "minecraft")); QFileInfo dotMCDir(FS::PathCombine(instanceRoot(), ".minecraft")); - if (mcDir.exists() && !dotMCDir.exists()) - return mcDir.filePath(); - else + if (dotMCDir.exists() && !mcDir.exists()) return dotMCDir.filePath(); + else + return mcDir.filePath(); } QString MinecraftInstance::binRoot() const diff --git a/launcher/modplatform/import_ftb/PackInstallTask.cpp b/launcher/modplatform/import_ftb/PackInstallTask.cpp index 9a3b2595b..946ec4eb7 100644 --- a/launcher/modplatform/import_ftb/PackInstallTask.cpp +++ b/launcher/modplatform/import_ftb/PackInstallTask.cpp @@ -37,7 +37,7 @@ void PackInstallTask::executeTask() progress(1, 2); m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this] { - FS::copy folderCopy(m_pack.path, FS::PathCombine(m_stagingPath, ".minecraft")); + FS::copy folderCopy(m_pack.path, FS::PathCombine(m_stagingPath, "minecraft")); folderCopy.followSymlinks(true); return folderCopy(); }); diff --git a/launcher/modplatform/legacy_ftb/PackInstallTask.cpp b/launcher/modplatform/legacy_ftb/PackInstallTask.cpp index 091296751..0048c7fac 100644 --- a/launcher/modplatform/legacy_ftb/PackInstallTask.cpp +++ b/launcher/modplatform/legacy_ftb/PackInstallTask.cpp @@ -137,7 +137,7 @@ void PackInstallTask::install() QDir unzipMcDir(m_stagingPath + "/unzip/minecraft"); if (unzipMcDir.exists()) { // ok, found minecraft dir, move contents to instance dir - if (!QDir().rename(m_stagingPath + "/unzip/minecraft", m_stagingPath + "/.minecraft")) { + if (!QDir().rename(m_stagingPath + "/unzip/minecraft", m_stagingPath + "/minecraft")) { emitFailed(tr("Failed to move unzipped Minecraft!")); return; } @@ -155,7 +155,7 @@ void PackInstallTask::install() bool fallback = true; // handle different versions - QFile packJson(m_stagingPath + "/.minecraft/pack.json"); + QFile packJson(m_stagingPath + "/minecraft/pack.json"); QDir jarmodDir = QDir(m_stagingPath + "/unzip/instMods"); if (packJson.exists()) { packJson.open(QIODevice::ReadOnly | QIODevice::Text); diff --git a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp index 96d9c84d2..824fdce7e 100644 --- a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp +++ b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp @@ -173,7 +173,7 @@ bool ModrinthCreationTask::createInstance() FS::ensureFilePathExists(new_index_place); QFile::rename(index_path, new_index_place); - auto mcPath = FS::PathCombine(m_stagingPath, ".minecraft"); + auto mcPath = FS::PathCombine(m_stagingPath, "minecraft"); auto override_path = FS::PathCombine(m_stagingPath, "overrides"); if (QFile::exists(override_path)) { @@ -234,7 +234,7 @@ bool ModrinthCreationTask::createInstance() m_files_job.reset(new NetJob(tr("Mod Download Modrinth"), APPLICATION->network())); - auto root_modpack_path = FS::PathCombine(m_stagingPath, ".minecraft"); + auto root_modpack_path = FS::PathCombine(m_stagingPath, "minecraft"); auto root_modpack_url = QUrl::fromLocalFile(root_modpack_path); for (auto file : m_files) { diff --git a/launcher/modplatform/technic/SingleZipPackInstallTask.cpp b/launcher/modplatform/technic/SingleZipPackInstallTask.cpp index ad08d72d4..cc9ced10b 100644 --- a/launcher/modplatform/technic/SingleZipPackInstallTask.cpp +++ b/launcher/modplatform/technic/SingleZipPackInstallTask.cpp @@ -62,7 +62,7 @@ void Technic::SingleZipPackInstallTask::downloadSucceeded() m_abortable = false; setStatus(tr("Extracting modpack")); - QDir extractDir(FS::PathCombine(m_stagingPath, ".minecraft")); + QDir extractDir(FS::PathCombine(m_stagingPath, "minecraft")); qDebug() << "Attempting to create instance from" << m_archivePath; // open the zip and find relevant files in it diff --git a/launcher/modplatform/technic/SolderPackInstallTask.cpp b/launcher/modplatform/technic/SolderPackInstallTask.cpp index c162d6253..ed8b0a8a4 100644 --- a/launcher/modplatform/technic/SolderPackInstallTask.cpp +++ b/launcher/modplatform/technic/SolderPackInstallTask.cpp @@ -140,7 +140,7 @@ void Technic::SolderPackInstallTask::downloadSucceeded() m_filesNetJob.reset(); m_extractFuture = QtConcurrent::run([this]() { int i = 0; - QString extractDir = FS::PathCombine(m_stagingPath, ".minecraft"); + QString extractDir = FS::PathCombine(m_stagingPath, "minecraft"); FS::ensureFolderPathExists(extractDir); while (m_modCount > i) { diff --git a/launcher/modplatform/technic/TechnicPackProcessor.cpp b/launcher/modplatform/technic/TechnicPackProcessor.cpp index 3b9424bf8..90f59ce54 100644 --- a/launcher/modplatform/technic/TechnicPackProcessor.cpp +++ b/launcher/modplatform/technic/TechnicPackProcessor.cpp @@ -33,7 +33,7 @@ void Technic::TechnicPackProcessor::run(SettingsObjectPtr globalSettings, const QString& minecraftVersion, [[maybe_unused]] const bool isSolder) { - QString minecraftPath = FS::PathCombine(stagingPath, ".minecraft"); + QString minecraftPath = FS::PathCombine(stagingPath, "minecraft"); QString configPath = FS::PathCombine(stagingPath, "instance.cfg"); auto instanceSettings = std::make_shared(configPath); MinecraftInstance instance(globalSettings, instanceSettings, stagingPath); From e4306d5cb6f61368b1b3dcc77af2e268814f0c82 Mon Sep 17 00:00:00 2001 From: Alexandru Ionut Tripon Date: Sun, 21 Jan 2024 08:52:49 +0200 Subject: [PATCH 106/223] Update launcher/ui/themes/CatPack.cpp Co-authored-by: TheKodeToad Signed-off-by: Alexandru Ionut Tripon --- launcher/ui/themes/CatPack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/themes/CatPack.cpp b/launcher/ui/themes/CatPack.cpp index 0fe628fe9..85eb85a18 100644 --- a/launcher/ui/themes/CatPack.cpp +++ b/launcher/ui/themes/CatPack.cpp @@ -132,7 +132,7 @@ QString JsonCatPack::path(QDate now) auto files = QDir(m_default_path).entryInfoList(supportedImageFormats, QDir::Files, QDir::Name); if (files.length() == 0) return ""; - auto idx = now.dayOfYear() % files.length(); + auto idx = (now.dayOfYear() - 1) % files.length(); auto isRandom = dInfo.fileName().compare("random", Qt::CaseInsensitive) == 0; if (isRandom) idx = QRandomGenerator::global()->bounded(0, files.length()); From 0dc4a10f4898dfce43a6febdcfbb675e0182f38a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 22 Jan 2024 17:26:37 +0000 Subject: [PATCH 107/223] chore(deps): update korthout/backport-action action to v2.4.0 --- .github/workflows/backport.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index dee01e084..866e9a898 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -24,7 +24,7 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} - name: Create backport PRs - uses: korthout/backport-action@v2.3.0 + uses: korthout/backport-action@v2.4.0 with: # Config README: https://github.com/korthout/backport-action#backport-action pull_description: |- From 12bf91376411d74432f5e88c85d68cef003fd899 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Mon, 22 Jan 2024 20:36:57 +0200 Subject: [PATCH 108/223] Fixed open path a second time Signed-off-by: Trial97 --- launcher/DesktopServices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/DesktopServices.cpp b/launcher/DesktopServices.cpp index 7c070bd31..841c1399c 100644 --- a/launcher/DesktopServices.cpp +++ b/launcher/DesktopServices.cpp @@ -46,7 +46,7 @@ bool openPath(const QFileInfo& path, bool ensureFolderPathExists) if (ensureFolderPathExists) { FS::ensureFolderPathExists(path); } - return openUrl(QUrl::fromLocalFile(QFileInfo(path).absolutePath())); + return openUrl(QUrl::fromLocalFile(QFileInfo(path).absoluteFilePath())); } bool openPath(const QString& path, bool ensureFolderPathExists) From 72e6218df9df28f657b6626bb775ace58d507647 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 23 Jan 2024 19:21:30 +0000 Subject: [PATCH 109/223] chore(deps): update korthout/backport-action action to v2.4.1 --- .github/workflows/backport.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 866e9a898..9b51b201e 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -24,7 +24,7 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} - name: Create backport PRs - uses: korthout/backport-action@v2.4.0 + uses: korthout/backport-action@v2.4.1 with: # Config README: https://github.com/korthout/backport-action#backport-action pull_description: |- From 8312713dc2274670db6f9167125af8a27c2fd8a6 Mon Sep 17 00:00:00 2001 From: seth Date: Wed, 17 Jan 2024 22:46:29 -0500 Subject: [PATCH 110/223] refactor(nix): nix-filter -> lib.fileset with our own use of `map`, this is basically a drop-in replacement for nix-filter, but already in nixpkgs! Signed-off-by: seth --- flake.lock | 16 ---------------- flake.nix | 1 - nix/distribution.nix | 16 ---------------- nix/pkg/default.nix | 15 +++++++++++++-- 4 files changed, 13 insertions(+), 35 deletions(-) diff --git a/flake.lock b/flake.lock index 5b0619292..79075c3c7 100644 --- a/flake.lock +++ b/flake.lock @@ -91,21 +91,6 @@ "type": "github" } }, - "nix-filter": { - "locked": { - "lastModified": 1705332318, - "narHash": "sha256-kcw1yFeJe9N4PjQji9ZeX47jg0p9A0DuU4djKvg1a7I=", - "owner": "numtide", - "repo": "nix-filter", - "rev": "3449dc925982ad46246cfc36469baf66e1b64f17", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "nix-filter", - "type": "github" - } - }, "nixpkgs": { "locked": { "lastModified": 1705697961, @@ -155,7 +140,6 @@ "flake-compat": "flake-compat", "flake-parts": "flake-parts", "libnbtplusplus": "libnbtplusplus", - "nix-filter": "nix-filter", "nixpkgs": "nixpkgs", "pre-commit-hooks": "pre-commit-hooks" } diff --git a/flake.nix b/flake.nix index 1582400f1..e16c76699 100644 --- a/flake.nix +++ b/flake.nix @@ -12,7 +12,6 @@ url = "github:hercules-ci/flake-parts"; inputs.nixpkgs-lib.follows = "nixpkgs"; }; - nix-filter.url = "github:numtide/nix-filter"; pre-commit-hooks = { url = "github:cachix/pre-commit-hooks.nix"; inputs = { diff --git a/nix/distribution.nix b/nix/distribution.nix index ca9999dcb..01c90f783 100644 --- a/nix/distribution.nix +++ b/nix/distribution.nix @@ -26,24 +26,8 @@ overlays.default = final: prev: let version = builtins.substring 0 8 self.lastModifiedDate or "dirty"; - filteredSelf = inputs.nix-filter.lib.filter { - root = ../.; - include = [ - "buildconfig" - "cmake" - "launcher" - "libraries" - "program_info" - "tests" - ../COPYING.md - ../CMakeLists.txt - ]; - }; - # common args for prismlauncher evaluations unwrappedArgs = { - self = filteredSelf; - inherit (inputs) libnbtplusplus; inherit ((final.darwin or prev.darwin).apple_sdk.frameworks) Cocoa; inherit version; diff --git a/nix/pkg/default.nix b/nix/pkg/default.nix index fd19a0b3d..0078def8c 100644 --- a/nix/pkg/default.nix +++ b/nix/pkg/default.nix @@ -16,7 +16,6 @@ gamemode, msaClientID ? null, gamemodeSupport ? stdenv.isLinux, - self, version, libnbtplusplus, }: @@ -25,7 +24,19 @@ assert lib.assertMsg (stdenv.isLinux || !gamemodeSupport) "gamemodeSupport is on pname = "prismlauncher-unwrapped"; inherit version; - src = lib.cleanSource self; + src = lib.fileset.toSource { + root = ../../.; + fileset = lib.fileset.unions (map (fileName: ../../${fileName}) [ + "buildconfig" + "cmake" + "launcher" + "libraries" + "program_info" + "tests" + "COPYING.md" + "CMakeLists.txt" + ]); + }; nativeBuildInputs = [extra-cmake-modules cmake jdk17 ninja canonicalize-jars-hook]; buildInputs = From 8de1060bfb8eba7ad6efbb2093df61992e25e3cd Mon Sep 17 00:00:00 2001 From: DioEgizio <83089242+DioEgizio@users.noreply.github.com> Date: Wed, 24 Jan 2024 16:42:01 +0100 Subject: [PATCH 111/223] fix: remove alpha notice on modrinth packs with the modrinth app being released for quite a while now it's weird to still have this (tbh they've never been truly alpha) Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com> --- .../modplatform/modrinth/ModrinthPage.ui | 58 +++++++------------ 1 file changed, 20 insertions(+), 38 deletions(-) diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui index 78a25feae..68b1d4e24 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui @@ -11,43 +11,7 @@ - - - - - true - - - - Note: Modrinth modpacks are still in alpha phase. Some things may be rough on the edges, or not working at all! Use it with caution. - - - Qt::AlignCenter - - - true - - - - - - - - - Search and filter ... - - - - - - - Search - - - - - - + @@ -77,7 +41,7 @@ - + @@ -97,6 +61,24 @@ + + + + + + Search and filter ... + + + + + + + Search + + + + + From ab4974629c8e4087e804297e156c7bbc889a840e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 26 Jan 2024 07:12:13 +0000 Subject: [PATCH 112/223] chore(deps): update hendrikmuhs/ccache-action action to v1.2.12 --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a0a8d6db9..b9b3597c3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -160,7 +160,7 @@ jobs: - name: Setup ccache if: (runner.os != 'Windows' || matrix.msystem == '') && inputs.build_type == 'Debug' - uses: hendrikmuhs/ccache-action@v1.2.11 + uses: hendrikmuhs/ccache-action@v1.2.12 with: key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}-${{ matrix.architecture }} From 901cc4e4dd051459040ac93c6ab762e0a4b219bd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 28 Jan 2024 00:19:08 +0000 Subject: [PATCH 113/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'nixpkgs': 'github:nixos/nixpkgs/e5d1c87f5813afde2dda384ac807c57a105721cc' (2024-01-19) → 'github:nixos/nixpkgs/4fddc9be4eaf195d631333908f2a454b03628ee5' (2024-01-25) --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 79075c3c7..bbbab1e45 100644 --- a/flake.lock +++ b/flake.lock @@ -93,11 +93,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1705697961, - "narHash": "sha256-XepT3WS516evSFYkme3GrcI3+7uwXHqtHbip+t24J7E=", + "lastModified": 1706173671, + "narHash": "sha256-lciR7kQUK2FCAYuszyd7zyRRmTaXVeoZsCyK6QFpGdk=", "owner": "nixos", "repo": "nixpkgs", - "rev": "e5d1c87f5813afde2dda384ac807c57a105721cc", + "rev": "4fddc9be4eaf195d631333908f2a454b03628ee5", "type": "github" }, "original": { From 15670cc27bbed41def06df9de749a8c645bfcc83 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 4 Feb 2024 00:19:10 +0000 Subject: [PATCH 114/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'flake-parts': 'github:hercules-ci/flake-parts/07f6395285469419cf9d078f59b5b49993198c00' (2024-01-11) → 'github:hercules-ci/flake-parts/b253292d9c0a5ead9bc98c4e9a26c6312e27d69f' (2024-02-01) • Updated input 'nixpkgs': 'github:nixos/nixpkgs/4fddc9be4eaf195d631333908f2a454b03628ee5' (2024-01-25) → 'github:nixos/nixpkgs/79a13f1437e149dc7be2d1290c74d378dad60814' (2024-02-03) • Updated input 'pre-commit-hooks': 'github:cachix/pre-commit-hooks.nix/f56597d53fd174f796b5a7d3ee0b494f9e2285cc' (2024-01-20) → 'github:cachix/pre-commit-hooks.nix/7c54e08a689b53c8a1e5d70169f2ec9e2a68ffaf' (2024-01-28) --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index bbbab1e45..c825c54bb 100644 --- a/flake.lock +++ b/flake.lock @@ -23,11 +23,11 @@ ] }, "locked": { - "lastModified": 1704982712, - "narHash": "sha256-2Ptt+9h8dczgle2Oo6z5ni5rt/uLMG47UFTR1ry/wgg=", + "lastModified": 1706830856, + "narHash": "sha256-a0NYyp+h9hlb7ddVz4LUn1vT/PLwqfrWYcHMvFB1xYg=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "07f6395285469419cf9d078f59b5b49993198c00", + "rev": "b253292d9c0a5ead9bc98c4e9a26c6312e27d69f", "type": "github" }, "original": { @@ -93,11 +93,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1706173671, - "narHash": "sha256-lciR7kQUK2FCAYuszyd7zyRRmTaXVeoZsCyK6QFpGdk=", + "lastModified": 1706925685, + "narHash": "sha256-hVInjWMmgH4yZgA4ZtbgJM1qEAel72SYhP5nOWX4UIM=", "owner": "nixos", "repo": "nixpkgs", - "rev": "4fddc9be4eaf195d631333908f2a454b03628ee5", + "rev": "79a13f1437e149dc7be2d1290c74d378dad60814", "type": "github" }, "original": { @@ -122,11 +122,11 @@ ] }, "locked": { - "lastModified": 1705757126, - "narHash": "sha256-Eksr+n4Q8EYZKAN0Scef5JK4H6FcHc+TKNHb95CWm+c=", + "lastModified": 1706424699, + "narHash": "sha256-Q3RBuOpZNH2eFA1e+IHgZLAOqDD9SKhJ/sszrL8bQD4=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "f56597d53fd174f796b5a7d3ee0b494f9e2285cc", + "rev": "7c54e08a689b53c8a1e5d70169f2ec9e2a68ffaf", "type": "github" }, "original": { From 7cac8ad2b42f19dd3f38fe5c5ef5f93116ca5aa9 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Tue, 6 Feb 2024 20:42:18 +0000 Subject: [PATCH 115/223] Use QTextFragment for inserting log lines Signed-off-by: TheKodeToad --- launcher/ui/widgets/LogView.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/launcher/ui/widgets/LogView.cpp b/launcher/ui/widgets/LogView.cpp index 4096889d3..6578b1f12 100644 --- a/launcher/ui/widgets/LogView.cpp +++ b/launcher/ui/widgets/LogView.cpp @@ -36,6 +36,7 @@ #include "LogView.h" #include #include +#include LogView::LogView(QWidget* parent) : QPlainTextEdit(parent) { @@ -117,6 +118,9 @@ void LogView::rowsAboutToBeInserted(const QModelIndex& parent, int first, int la void LogView::rowsInserted(const QModelIndex& parent, int first, int last) { + QTextDocument document; + QTextCursor cursor(&document); + for (int i = first; i <= last; i++) { auto idx = m_model->index(i, 0, parent); auto text = m_model->data(idx, Qt::DisplayRole).toString(); @@ -133,11 +137,16 @@ void LogView::rowsInserted(const QModelIndex& parent, int first, int last) if (bg.isValid()) { format.setBackground(bg.value()); } - auto workCursor = textCursor(); - workCursor.movePosition(QTextCursor::End); - workCursor.insertText(text, format); - workCursor.insertBlock(); + cursor.movePosition(QTextCursor::End); + cursor.insertText(text, format); + cursor.insertBlock(); } + + QTextDocumentFragment fragment(&document); + QTextCursor workCursor = textCursor(); + workCursor.movePosition(QTextCursor::End); + workCursor.insertFragment(fragment); + if (m_scroll && !m_scrolling) { m_scrolling = true; QMetaObject::invokeMethod(this, "scrollToBottom", Qt::QueuedConnection); From 830ce246e17e381807d9394819c175dc0b730ff8 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sat, 10 Feb 2024 13:48:02 +0200 Subject: [PATCH 116/223] Fixed curseforge neoforge import for 1.20.1 versions Signed-off-by: Trial97 --- launcher/modplatform/flame/FlameInstanceCreationTask.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp index 7c3dfe6d4..93745bacf 100644 --- a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp +++ b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp @@ -354,6 +354,8 @@ bool FlameCreationTask::createInstance() auto id = loader.id; if (id.startsWith("neoforge-")) { id.remove("neoforge-"); + if (id.startsWith("1.20.1-")) + id = id.mid(7); // this is a mess for curseforge loaderType = "neoforge"; loaderUid = "net.neoforged"; } else if (id.startsWith("forge-")) { From 29bf6cc68c132c036f8c9ee90a337fb2db7d3cf2 Mon Sep 17 00:00:00 2001 From: Alexandru Ionut Tripon Date: Sat, 10 Feb 2024 23:15:26 +0200 Subject: [PATCH 117/223] Update launcher/modplatform/flame/FlameInstanceCreationTask.cpp Signed-off-by: Alexandru Ionut Tripon --- launcher/modplatform/flame/FlameInstanceCreationTask.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp index 93745bacf..ef552c3c2 100644 --- a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp +++ b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp @@ -355,7 +355,7 @@ bool FlameCreationTask::createInstance() if (id.startsWith("neoforge-")) { id.remove("neoforge-"); if (id.startsWith("1.20.1-")) - id = id.mid(7); // this is a mess for curseforge + id.remove("1.20.1-"); // this is a mess for curseforge loaderType = "neoforge"; loaderUid = "net.neoforged"; } else if (id.startsWith("forge-")) { From 0f254c842543d08ed5520c359ad8e13f0a751b39 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 11 Feb 2024 00:19:31 +0000 Subject: [PATCH 118/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'nixpkgs': 'github:nixos/nixpkgs/79a13f1437e149dc7be2d1290c74d378dad60814' (2024-02-03) → 'github:nixos/nixpkgs/442d407992384ed9c0e6d352de75b69079904e4e' (2024-02-09) • Updated input 'pre-commit-hooks': 'github:cachix/pre-commit-hooks.nix/7c54e08a689b53c8a1e5d70169f2ec9e2a68ffaf' (2024-01-28) → 'github:cachix/pre-commit-hooks.nix/0db2e67ee49910adfa13010e7f012149660af7f0' (2024-02-07) --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index c825c54bb..11bf876f9 100644 --- a/flake.lock +++ b/flake.lock @@ -93,11 +93,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1706925685, - "narHash": "sha256-hVInjWMmgH4yZgA4ZtbgJM1qEAel72SYhP5nOWX4UIM=", + "lastModified": 1707451808, + "narHash": "sha256-UwDBUNHNRsYKFJzyTMVMTF5qS4xeJlWoeyJf+6vvamU=", "owner": "nixos", "repo": "nixpkgs", - "rev": "79a13f1437e149dc7be2d1290c74d378dad60814", + "rev": "442d407992384ed9c0e6d352de75b69079904e4e", "type": "github" }, "original": { @@ -122,11 +122,11 @@ ] }, "locked": { - "lastModified": 1706424699, - "narHash": "sha256-Q3RBuOpZNH2eFA1e+IHgZLAOqDD9SKhJ/sszrL8bQD4=", + "lastModified": 1707297608, + "narHash": "sha256-ADjo/5VySGlvtCW3qR+vdFF4xM9kJFlRDqcC9ZGI8EA=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "7c54e08a689b53c8a1e5d70169f2ec9e2a68ffaf", + "rev": "0db2e67ee49910adfa13010e7f012149660af7f0", "type": "github" }, "original": { From ded77e61832661557a6985d9aa587f3b5d1e1f87 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sun, 11 Feb 2024 15:32:17 +0000 Subject: [PATCH 119/223] Fix NetJob use-after-free Signed-off-by: TheKodeToad --- launcher/modplatform/helpers/NetworkResourceAPI.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/launcher/modplatform/helpers/NetworkResourceAPI.cpp b/launcher/modplatform/helpers/NetworkResourceAPI.cpp index 16ec90ec2..225583764 100644 --- a/launcher/modplatform/helpers/NetworkResourceAPI.cpp +++ b/launcher/modplatform/helpers/NetworkResourceAPI.cpp @@ -43,7 +43,7 @@ Task::Ptr NetworkResourceAPI::searchProjects(SearchArgs&& args, SearchCallbacks& callbacks.on_succeed(doc); }); - QObject::connect(netJob.get(), &NetJob::failed, [&netJob, callbacks](QString reason) { + QObject::connect(netJob.get(), &NetJob::failed, [netJob, callbacks](const QString& reason) { int network_error_code = -1; if (auto* failed_action = netJob->getFailedActions().at(0); failed_action && failed_action->m_reply) network_error_code = failed_action->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); @@ -102,7 +102,7 @@ Task::Ptr NetworkResourceAPI::getProjectVersions(VersionSearchArgs&& args, Versi callbacks.on_succeed(doc, args.pack); }); - QObject::connect(netJob.get(), &NetJob::failed, [&netJob, callbacks](QString reason) { + QObject::connect(netJob.get(), &NetJob::failed, [netJob, callbacks](const QString& reason) { int network_error_code = -1; if (auto* failed_action = netJob->getFailedActions().at(0); failed_action && failed_action->m_reply) network_error_code = failed_action->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); @@ -153,7 +153,7 @@ Task::Ptr NetworkResourceAPI::getDependencyVersion(DependencySearchArgs&& args, callbacks.on_succeed(doc, args.dependency); }); - QObject::connect(netJob.get(), &NetJob::failed, [&netJob, callbacks](QString reason) { + QObject::connect(netJob.get(), &NetJob::failed, [netJob, callbacks](const QString& reason) { int network_error_code = -1; if (auto* failed_action = netJob->getFailedActions().at(0); failed_action && failed_action->m_reply) network_error_code = failed_action->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); From ff989b4305d5ae4578d2154afe27ce6bf72cadaf Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sun, 11 Feb 2024 15:38:39 +0000 Subject: [PATCH 120/223] Fix ResourceModel error display Signed-off-by: TheKodeToad --- launcher/ui/pages/modplatform/ResourceModel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launcher/ui/pages/modplatform/ResourceModel.cpp b/launcher/ui/pages/modplatform/ResourceModel.cpp index 8a70eb4de..b38108d28 100644 --- a/launcher/ui/pages/modplatform/ResourceModel.cpp +++ b/launcher/ui/pages/modplatform/ResourceModel.cpp @@ -209,7 +209,7 @@ void ResourceModel::loadEntry(QModelIndex& entry) }; if (!callbacks.on_fail) callbacks.on_fail = [](QString reason, int) { - QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load project versions:%1").arg(reason)); + QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load project versions: %1").arg(reason)); }; if (auto job = m_api->getProjectVersions(std::move(args), std::move(callbacks)); job) @@ -232,7 +232,7 @@ void ResourceModel::loadEntry(QModelIndex& entry) callbacks.on_fail = [this](QString reason) { if (!s_running_models.constFind(this).value()) return; - QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load project info:%1").arg(reason)); + QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load project info: %1").arg(reason)); }; if (!callbacks.on_abort) callbacks.on_abort = [this] { From fdaaee64d193472144dd95c15c8d03f6fc4ed83a Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 11 Feb 2024 21:49:28 +0200 Subject: [PATCH 121/223] Fixed curseforge neoforge export for 1.20.1 Signed-off-by: Trial97 --- launcher/modplatform/flame/FlamePackExportTask.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/launcher/modplatform/flame/FlamePackExportTask.cpp b/launcher/modplatform/flame/FlamePackExportTask.cpp index 3827170b3..e28c82b4c 100644 --- a/launcher/modplatform/flame/FlamePackExportTask.cpp +++ b/launcher/modplatform/flame/FlamePackExportTask.cpp @@ -398,8 +398,12 @@ QByteArray FlamePackExportTask::generateIndex() id = "fabric-" + fabric->getVersion(); else if (forge != nullptr) id = "forge-" + forge->getVersion(); - else if (neoforge != nullptr) - id = "neoforge-" + neoforge->getVersion(); + else if (neoforge != nullptr) { + id = "neoforge-"; + if (minecraft->m_version == "1.20.1") + id += "1.20.1-"; + id += neoforge->getVersion(); + } version["modLoaders"] = QJsonArray(); if (!id.isEmpty()) { QJsonObject loader; From 7f4c74ffbe413fcf191842606c12056fbc6493c7 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sun, 11 Feb 2024 22:15:39 +0000 Subject: [PATCH 122/223] Fix immediate free in Exception.h Signed-off-by: TheKodeToad --- launcher/Exception.h | 45 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/launcher/Exception.h b/launcher/Exception.h index ef1e4e0d8..0e869fb14 100644 --- a/launcher/Exception.h +++ b/launcher/Exception.h @@ -1,4 +1,37 @@ -// Licensed under the Apache-2.0 license. See README.md for details. +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2024 TheKodeToad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #pragma once @@ -8,12 +41,12 @@ class Exception : public std::exception { public: - Exception(const QString& message) : std::exception(), m_message(message) { qCritical() << "Exception:" << message; } - Exception(const Exception& other) : std::exception(), m_message(other.cause()) {} + Exception(const QString& message) : std::exception(), m_message(message.toUtf8()) { qCritical() << "Exception:" << message; } + Exception(const Exception& other) : std::exception(), m_message(other.m_message) {} virtual ~Exception() noexcept {} - const char* what() const noexcept { return m_message.toLatin1().constData(); } - QString cause() const { return m_message; } + const char* what() const noexcept { return m_message.constData(); } + QString cause() const { return QString::fromUtf8(m_message); } private: - QString m_message; + QByteArray m_message; }; From 8cf2a04f317c59920e8af90d7e16fea872b2c122 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Mon, 12 Feb 2024 15:24:56 +0000 Subject: [PATCH 123/223] Fix formatting issues Signed-off-by: TheKodeToad --- launcher/Exception.h | 2 +- launcher/ui/pages/modplatform/ResourceModel.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/launcher/Exception.h b/launcher/Exception.h index 0e869fb14..55b40fdc8 100644 --- a/launcher/Exception.h +++ b/launcher/Exception.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-License-Identifier: GPL-3.0-only AND Apache-2.0 /* * Prism Launcher - Minecraft Launcher * Copyright (c) 2024 TheKodeToad diff --git a/launcher/ui/pages/modplatform/ResourceModel.cpp b/launcher/ui/pages/modplatform/ResourceModel.cpp index b38108d28..f3c7ff60b 100644 --- a/launcher/ui/pages/modplatform/ResourceModel.cpp +++ b/launcher/ui/pages/modplatform/ResourceModel.cpp @@ -209,7 +209,8 @@ void ResourceModel::loadEntry(QModelIndex& entry) }; if (!callbacks.on_fail) callbacks.on_fail = [](QString reason, int) { - QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load project versions: %1").arg(reason)); + QMessageBox::critical(nullptr, tr("Error"), + tr("A network error occurred. Could not load project versions: %1").arg(reason)); }; if (auto job = m_api->getProjectVersions(std::move(args), std::move(callbacks)); job) From 01180c20e19fcdd9a902d9cd51514549eeceb531 Mon Sep 17 00:00:00 2001 From: Echo J Date: Tue, 13 Feb 2024 23:54:49 +0200 Subject: [PATCH 124/223] Use absolute path to load MangoHUD library This should finally fix the Arch Linux Java symbol issue with MangoHUD enabled: https://bugs.archlinux.org/task/77183 Signed-off-by: Echo J --- launcher/minecraft/MinecraftInstance.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index 5a8c0d28a..edeebd34d 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -594,9 +594,6 @@ QProcessEnvironment MinecraftInstance::createLaunchEnvironment() QStringList preloadList; if (auto value = env.value("LD_PRELOAD"); !value.isEmpty()) preloadList = value.split(QLatin1String(":")); - QStringList libPaths; - if (auto value = env.value("LD_LIBRARY_PATH"); !value.isEmpty()) - libPaths = value.split(QLatin1String(":")); auto mangoHudLibString = MangoHud::getLibraryString(); if (!mangoHudLibString.isEmpty()) { @@ -604,18 +601,16 @@ QProcessEnvironment MinecraftInstance::createLaunchEnvironment() QString libPath = mangoHudLib.absolutePath(); auto appendLib = [libPath, &preloadList](QString fileName) { if (QFileInfo(FS::PathCombine(libPath, fileName)).exists()) - preloadList << fileName; + preloadList << FS::PathCombine(libPath, fileName); }; // dlsym variant is only needed for OpenGL and not included in the vulkan layer appendLib("libMangoHud_dlsym.so"); appendLib("libMangoHud_opengl.so"); appendLib(mangoHudLib.fileName()); - libPaths << libPath; } env.insert("LD_PRELOAD", preloadList.join(QLatin1String(":"))); - env.insert("LD_LIBRARY_PATH", libPaths.join(QLatin1String(":"))); env.insert("MANGOHUD", "1"); } From 5d36067c749c55b4ca3ff37fa7382dcd54e60ca2 Mon Sep 17 00:00:00 2001 From: DioEgizio <83089242+DioEgizio@users.noreply.github.com> Date: Fri, 16 Feb 2024 16:21:53 +0100 Subject: [PATCH 125/223] chore: update libraries updated qt to 6.6.2 updated some submodules updated sparkle framework to the latest version Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com> --- .github/workflows/build.yml | 6 +++--- CMakeLists.txt | 2 +- flatpak/shared-modules | 2 +- libraries/cmark | 2 +- libraries/filesystem | 2 +- libraries/libnbtplusplus | 2 +- libraries/quazip | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b9b3597c3..a26e6c094 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -76,7 +76,7 @@ jobs: qt_ver: 6 qt_host: windows qt_arch: '' - qt_version: '6.6.1' + qt_version: '6.6.2' qt_modules: 'qt5compat qtimageformats' qt_tools: '' @@ -88,7 +88,7 @@ jobs: qt_ver: 6 qt_host: windows qt_arch: 'win64_msvc2019_arm64' - qt_version: '6.6.1' + qt_version: '6.6.2' qt_modules: 'qt5compat qtimageformats' qt_tools: '' @@ -98,7 +98,7 @@ jobs: qt_ver: 6 qt_host: mac qt_arch: '' - qt_version: '6.6.1' + qt_version: '6.6.2' qt_modules: 'qt5compat qtimageformats' qt_tools: '' diff --git a/CMakeLists.txt b/CMakeLists.txt index e42186cb5..5fe85c80c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -381,7 +381,7 @@ if(UNIX AND APPLE) set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "v55ZWWD6QlPoXGV6VLzOTZxZUggWeE51X8cRQyQh6vA=" CACHE STRING "Public key for Sparkle update feed") set(MACOSX_SPARKLE_UPDATE_FEED_URL "https://prismlauncher.org/feed/appcast.xml" CACHE STRING "URL for Sparkle update feed") - set(MACOSX_SPARKLE_DOWNLOAD_URL "https://github.com/sparkle-project/Sparkle/releases/download/2.1.0/Sparkle-2.1.0.tar.xz" CACHE STRING "URL to Sparkle release archive") + set(MACOSX_SPARKLE_DOWNLOAD_URL "https://github.com/sparkle-project/Sparkle/releases/download/2.5.2/Sparkle-2.5.2.tar.xz" CACHE STRING "URL to Sparkle release archive") set(MACOSX_SPARKLE_SHA256 "bf6ac1caa9f8d321d5784859c88da874f28412f37fb327bc21b7b14c5d61ef94" CACHE STRING "SHA256 checksum for Sparkle release archive") set(MACOSX_SPARKLE_DIR "${CMAKE_BINARY_DIR}/frameworks/Sparkle") diff --git a/flatpak/shared-modules b/flatpak/shared-modules index 55a8e460c..f2b0c16a2 160000 --- a/flatpak/shared-modules +++ b/flatpak/shared-modules @@ -1 +1 @@ -Subproject commit 55a8e460c6343229597a13e973ba4855c27a1c4c +Subproject commit f2b0c16a2a217a1822ce5a6538ba8f755ed1dd32 diff --git a/libraries/cmark b/libraries/cmark index 5ba25ff40..8fbf02968 160000 --- a/libraries/cmark +++ b/libraries/cmark @@ -1 +1 @@ -Subproject commit 5ba25ff40eba44c811f79ab6a792baf945b8307c +Subproject commit 8fbf029685482827828b5858444157052f1b0a5f diff --git a/libraries/filesystem b/libraries/filesystem index 8a2edd6d9..2fc4b4637 160000 --- a/libraries/filesystem +++ b/libraries/filesystem @@ -1 +1 @@ -Subproject commit 8a2edd6d92ed820521d42c94d179462bf06b5ed3 +Subproject commit 2fc4b463759e043476fc0036da094e5877e3dd50 diff --git a/libraries/libnbtplusplus b/libraries/libnbtplusplus index a5e8fd52b..23b955121 160000 --- a/libraries/libnbtplusplus +++ b/libraries/libnbtplusplus @@ -1 +1 @@ -Subproject commit a5e8fd52b8bf4ab5d5bcc042b2a247867589985f +Subproject commit 23b955121b8217c1c348a9ed2483167a6f3ff4ad diff --git a/libraries/quazip b/libraries/quazip index 6117161af..9d3aa3ee9 160000 --- a/libraries/quazip +++ b/libraries/quazip @@ -1 +1 @@ -Subproject commit 6117161af08e366c37499895b00ef62f93adc345 +Subproject commit 9d3aa3ee948c1cde5a9f873ecbc3bb229c1182ee From 94b48e970241a122da43957ea457b29fa7ce499d Mon Sep 17 00:00:00 2001 From: DioEgizio <83089242+DioEgizio@users.noreply.github.com> Date: Fri, 16 Feb 2024 16:28:46 +0100 Subject: [PATCH 126/223] fix: remove cmark_static cmark 0.31 removed CMARK_STATIC/CMARK_SHARED and replaced it with the native cmake BUILD_SHARED_LIBS Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com> --- CMakeLists.txt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fe85c80c..e4e224f1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -504,11 +504,10 @@ else() endif() if(NOT cmark_FOUND) message(STATUS "Using bundled cmark") - set(CMARK_STATIC ON CACHE BOOL "Build static libcmark library" FORCE) - set(CMARK_SHARED OFF CACHE BOOL "Build shared libcmark library" FORCE) - set(CMARK_TESTS OFF CACHE BOOL "Build cmark tests and enable testing" FORCE) + set(BUILD_TESTING 0) + set(BUILD_SHARED_LIBS 0) add_subdirectory(libraries/cmark EXCLUDE_FROM_ALL) # Markdown parser - add_library(cmark::cmark ALIAS cmark_static) + add_library(cmark::cmark ALIAS cmark) else() message(STATUS "Using system cmark") endif() From 25b69b4c0d7d0b6863c7f158c382eb85cf040c14 Mon Sep 17 00:00:00 2001 From: DioEgizio <83089242+DioEgizio@users.noreply.github.com> Date: Fri, 16 Feb 2024 17:29:49 +0100 Subject: [PATCH 127/223] fix: fix sparkle hash :/ oops Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com> --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e4e224f1c..6cceb2599 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -382,7 +382,7 @@ if(UNIX AND APPLE) set(MACOSX_SPARKLE_UPDATE_FEED_URL "https://prismlauncher.org/feed/appcast.xml" CACHE STRING "URL for Sparkle update feed") set(MACOSX_SPARKLE_DOWNLOAD_URL "https://github.com/sparkle-project/Sparkle/releases/download/2.5.2/Sparkle-2.5.2.tar.xz" CACHE STRING "URL to Sparkle release archive") - set(MACOSX_SPARKLE_SHA256 "bf6ac1caa9f8d321d5784859c88da874f28412f37fb327bc21b7b14c5d61ef94" CACHE STRING "SHA256 checksum for Sparkle release archive") + set(MACOSX_SPARKLE_SHA256 "572dd67ae398a466f19f343a449e1890bac1ef74885b4739f68f979a8a89884b" CACHE STRING "SHA256 checksum for Sparkle release archive") set(MACOSX_SPARKLE_DIR "${CMAKE_BINARY_DIR}/frameworks/Sparkle") # directories to look for dependencies From 54bfbe562ee0b16ac4799951595850d15ccc2bbf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 18 Feb 2024 00:18:59 +0000 Subject: [PATCH 128/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'nixpkgs': 'github:nixos/nixpkgs/442d407992384ed9c0e6d352de75b69079904e4e' (2024-02-09) → 'github:nixos/nixpkgs/6e2f00c83911461438301db0dba5281197fe4b3a' (2024-02-17) • Updated input 'pre-commit-hooks': 'github:cachix/pre-commit-hooks.nix/0db2e67ee49910adfa13010e7f012149660af7f0' (2024-02-07) → 'github:cachix/pre-commit-hooks.nix/5df5a70ad7575f6601d91f0efec95dd9bc619431' (2024-02-15) --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index 11bf876f9..b5d8e7494 100644 --- a/flake.lock +++ b/flake.lock @@ -93,11 +93,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1707451808, - "narHash": "sha256-UwDBUNHNRsYKFJzyTMVMTF5qS4xeJlWoeyJf+6vvamU=", + "lastModified": 1708151420, + "narHash": "sha256-MGT/4aGCWQPQiu6COqJdCj9kSpLPiShgbwpbC38YXC8=", "owner": "nixos", "repo": "nixpkgs", - "rev": "442d407992384ed9c0e6d352de75b69079904e4e", + "rev": "6e2f00c83911461438301db0dba5281197fe4b3a", "type": "github" }, "original": { @@ -122,11 +122,11 @@ ] }, "locked": { - "lastModified": 1707297608, - "narHash": "sha256-ADjo/5VySGlvtCW3qR+vdFF4xM9kJFlRDqcC9ZGI8EA=", + "lastModified": 1708018599, + "narHash": "sha256-M+Ng6+SePmA8g06CmUZWi1AjG2tFBX9WCXElBHEKnyM=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "0db2e67ee49910adfa13010e7f012149660af7f0", + "rev": "5df5a70ad7575f6601d91f0efec95dd9bc619431", "type": "github" }, "original": { From 44327980db851edbe1fe909c9e934b1f4c559c6a Mon Sep 17 00:00:00 2001 From: DioEgizio <83089242+DioEgizio@users.noreply.github.com> Date: Sun, 18 Feb 2024 13:28:32 +0100 Subject: [PATCH 129/223] feat: add "use zink" button Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com> --- launcher/Application.cpp | 3 ++- launcher/minecraft/MinecraftInstance.cpp | 10 +++++++++- launcher/ui/pages/global/MinecraftPage.cpp | 2 ++ launcher/ui/pages/global/MinecraftPage.ui | 10 ++++++++++ launcher/ui/pages/instance/InstanceSettingsPage.cpp | 4 ++++ launcher/ui/pages/instance/InstanceSettingsPage.ui | 10 ++++++++++ 6 files changed, 37 insertions(+), 2 deletions(-) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 42343ff8f..db4b0d9cd 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -639,10 +639,11 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) m_settings->registerSetting("UseNativeGLFW", false); m_settings->registerSetting("CustomGLFWPath", ""); - // Peformance related options + // Performance related options m_settings->registerSetting("EnableFeralGamemode", false); m_settings->registerSetting("EnableMangoHud", false); m_settings->registerSetting("UseDiscreteGpu", false); + m_settings->registerSetting("UseZink", false); // Game time m_settings->registerSetting("ShowGameTime", true); diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index edeebd34d..e0b677b69 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -173,11 +173,12 @@ void MinecraftInstance::loadSpecificSettings() m_settings->registerOverride(global_settings->getSetting("UseNativeGLFW"), nativeLibraryWorkaroundsOverride); m_settings->registerOverride(global_settings->getSetting("CustomGLFWPath"), nativeLibraryWorkaroundsOverride); - // Peformance related options + // Performance related options auto performanceOverride = m_settings->registerSetting("OverridePerformance", false); m_settings->registerOverride(global_settings->getSetting("EnableFeralGamemode"), performanceOverride); m_settings->registerOverride(global_settings->getSetting("EnableMangoHud"), performanceOverride); m_settings->registerOverride(global_settings->getSetting("UseDiscreteGpu"), performanceOverride); + m_settings->registerOverride(global_settings->getSetting("UseZink"), performanceOverride); // Miscellaneous auto miscellaneousOverride = m_settings->registerSetting("OverrideMiscellaneous", false); @@ -622,6 +623,13 @@ QProcessEnvironment MinecraftInstance::createLaunchEnvironment() env.insert("__VK_LAYER_NV_optimus", "NVIDIA_only"); env.insert("__GLX_VENDOR_LIBRARY_NAME", "nvidia"); } + + if (settings()->get("UseZink").toBool()) { + // taken from https://wiki.archlinux.org/title/OpenGL#OpenGL_over_Vulkan_(Zink) + env.insert("__GLX_VENDOR_LIBRARY_NAME", "mesa"); + env.insert("MESA_LOADER_DRIVER_OVERRIDE", "zink"); + env.insert("GALLIUM_DRIVER", "zink"); + } #endif return env; } diff --git a/launcher/ui/pages/global/MinecraftPage.cpp b/launcher/ui/pages/global/MinecraftPage.cpp index a9530effc..3431dcb9c 100644 --- a/launcher/ui/pages/global/MinecraftPage.cpp +++ b/launcher/ui/pages/global/MinecraftPage.cpp @@ -109,6 +109,7 @@ void MinecraftPage::applySettings() s->set("EnableFeralGamemode", ui->enableFeralGamemodeCheck->isChecked()); s->set("EnableMangoHud", ui->enableMangoHud->isChecked()); s->set("UseDiscreteGpu", ui->useDiscreteGpuCheck->isChecked()); + s->set("UseZink", ui->useZink->isChecked()); // Game time s->set("ShowGameTime", ui->showGameTime->isChecked()); @@ -151,6 +152,7 @@ void MinecraftPage::loadSettings() ui->enableFeralGamemodeCheck->setChecked(s->get("EnableFeralGamemode").toBool()); ui->enableMangoHud->setChecked(s->get("EnableMangoHud").toBool()); ui->useDiscreteGpuCheck->setChecked(s->get("UseDiscreteGpu").toBool()); + ui->useZink->setChecked(s->get("UseZink").toBool()); #if !defined(Q_OS_LINUX) ui->perfomanceGroupBox->setVisible(false); diff --git a/launcher/ui/pages/global/MinecraftPage.ui b/launcher/ui/pages/global/MinecraftPage.ui index 3008099e3..7d2741250 100644 --- a/launcher/ui/pages/global/MinecraftPage.ui +++ b/launcher/ui/pages/global/MinecraftPage.ui @@ -309,6 +309,16 @@ + + + + <html><head/><body><p>Use Zink, a Mesa OpenGL driver that implements OpenGL on top of Vulkan. Performance may vary depending on the situation. Note: If no suitable Vulkan driver is found, software rendering will be used.</p></body></html> + + + Use Zink + + +
diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.cpp b/launcher/ui/pages/instance/InstanceSettingsPage.cpp index d4fd0ec5b..76add9402 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.cpp +++ b/launcher/ui/pages/instance/InstanceSettingsPage.cpp @@ -232,10 +232,13 @@ void InstanceSettingsPage::applySettings() m_settings->set("EnableFeralGamemode", ui->enableFeralGamemodeCheck->isChecked()); m_settings->set("EnableMangoHud", ui->enableMangoHud->isChecked()); m_settings->set("UseDiscreteGpu", ui->useDiscreteGpuCheck->isChecked()); + m_settings->set("UseZink", ui->useZink->isChecked()); + } else { m_settings->reset("EnableFeralGamemode"); m_settings->reset("EnableMangoHud"); m_settings->reset("UseDiscreteGpu"); + m_settings->reset("UseZink"); } // Game time @@ -354,6 +357,7 @@ void InstanceSettingsPage::loadSettings() ui->enableFeralGamemodeCheck->setChecked(m_settings->get("EnableFeralGamemode").toBool()); ui->enableMangoHud->setChecked(m_settings->get("EnableMangoHud").toBool()); ui->useDiscreteGpuCheck->setChecked(m_settings->get("UseDiscreteGpu").toBool()); + ui->useZink->setChecked(m_settings->get("UseZink").toBool()); #if !defined(Q_OS_LINUX) ui->settingsTabs->setTabVisible(ui->settingsTabs->indexOf(ui->performancePage), false); diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.ui b/launcher/ui/pages/instance/InstanceSettingsPage.ui index 632569e0c..9490860ae 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.ui +++ b/launcher/ui/pages/instance/InstanceSettingsPage.ui @@ -567,6 +567,16 @@ + + + + Use Zink, a Mesa OpenGL driver that implements OpenGL on top of Vulkan. Performance may vary depending on the situation. Note: If no suitable Vulkan driver is found, software rendering will be used. + + + Use Zink + + + From 9aa81cf00508c45ad6fe6b1d53c0933f1494571c Mon Sep 17 00:00:00 2001 From: crpz1 <8588315+crpz1@users.noreply.github.com> Date: Tue, 20 Feb 2024 00:21:37 +1100 Subject: [PATCH 130/223] Use empty list label code for welcome screen Signed-off-by: crpz1 <8588315+crpz1@users.noreply.github.com> --- launcher/ui/instanceview/InstanceView.cpp | 56 +++++++++++++---------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/launcher/ui/instanceview/InstanceView.cpp b/launcher/ui/instanceview/InstanceView.cpp index 6f3812a62..0723b5add 100644 --- a/launcher/ui/instanceview/InstanceView.cpp +++ b/launcher/ui/instanceview/InstanceView.cpp @@ -482,32 +482,42 @@ void InstanceView::paintEvent([[maybe_unused]] QPaintEvent* event) if (model()->rowCount() == 0) { painter.save(); - const QString line1 = tr("Welcome!"); - const QString line2 = tr("Click \"Add Instance\" to get started."); - auto rect = this->viewport()->rect(); - auto font = option.font; - font.setPointSize(37); - painter.setFont(font); - auto fm = painter.fontMetrics(); + QString emptyString = tr("Welcome!") + "\n" + tr("Click \"Add Instance\" to get started."); - if (rect.height() <= (fm.height() * 5) || rect.width() <= fm.horizontalAdvance(line2)) { - auto s = rect.height() / (5. * fm.height()); - auto sx = rect.width() * 1. / fm.horizontalAdvance(line2); - if (s >= sx) - s = sx; - auto ps = font.pointSize() * s; - if (ps <= 0) - ps = 1; - font.setPointSize(ps); - painter.setFont(font); - fm = painter.fontMetrics(); + // calculate the rect for the overlay + painter.setRenderHint(QPainter::Antialiasing, true); + QFont font("sans", 20); + font.setBold(true); + + QRect bounds = viewport()->geometry(); + bounds.moveTop(0); + auto innerBounds = bounds; + innerBounds.adjust(10, 10, -10, -10); + + QColor background = QApplication::palette().color(QPalette::WindowText); + QColor foreground = QApplication::palette().color(QPalette::Base); + foreground.setAlpha(190); + painter.setFont(font); + auto fontMetrics = painter.fontMetrics(); + auto textRect = fontMetrics.boundingRect(innerBounds, Qt::AlignHCenter | Qt::TextWordWrap, emptyString); + textRect.moveCenter(bounds.center()); + + auto wrapRect = textRect; + wrapRect.adjust(-10, -10, 10, 10); + + // check if we are allowed to draw in our area + if (!event->rect().intersects(wrapRect)) { + return; } - // text - rect.setTop(rect.top() + fm.height() * 1.5); - painter.drawText(rect, Qt::AlignHCenter, line1); - rect.setTop(rect.top() + fm.height()); - painter.drawText(rect, Qt::AlignHCenter, line2); + painter.setBrush(QBrush(background)); + painter.setPen(foreground); + painter.drawRoundedRect(wrapRect, 5.0, 5.0); + + painter.setPen(foreground); + painter.setFont(font); + painter.drawText(textRect, Qt::AlignHCenter | Qt::TextWordWrap, emptyString); + painter.restore(); return; } From 4421746c0e0c2eda0e9aab14371aaf40024f76e9 Mon Sep 17 00:00:00 2001 From: DioEgizio <83089242+DioEgizio@users.noreply.github.com> Date: Thu, 22 Feb 2024 10:00:21 +0100 Subject: [PATCH 131/223] fix: fix sparkle signing Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com> --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a26e6c094..0352988f7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -407,7 +407,7 @@ jobs: if [ '${{ secrets.SPARKLE_ED25519_KEY }}' != '' ]; then brew install openssl@3 echo '${{ secrets.SPARKLE_ED25519_KEY }}' > ed25519-priv.pem - signature=$(/usr/local/opt/openssl@3/bin/openssl pkeyutl -sign -rawin -in ${{ github.workspace }}/PrismLauncher.tar.gz -inkey ed25519-priv.pem | openssl base64 | tr -d \\n) + signature=$(/usr/local/opt/openssl@3/bin/openssl pkeyutl -sign -rawin -in ${{ github.workspace }}/PrismLauncher.zip -inkey ed25519-priv.pem | openssl base64 | tr -d \\n) rm ed25519-priv.pem cat >> $GITHUB_STEP_SUMMARY << EOF ### Artifact Information :information_source: From f747ae949cdc70d0ef832a2751d0adb5405ba5cf Mon Sep 17 00:00:00 2001 From: seth Date: Thu, 22 Feb 2024 06:13:27 -0500 Subject: [PATCH 132/223] ci: fix permissions for backport workflow Signed-off-by: seth --- .github/workflows/backport.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 9b51b201e..5df88fe86 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -16,6 +16,7 @@ jobs: permissions: contents: write # for korthout/backport-action to create branch pull-requests: write # for korthout/backport-action to create PR to backport + actions: write # for korthout/backport-action to create PR with workflow changes name: Backport Pull Request if: github.repository_owner == 'PrismLauncher' && github.event.pull_request.merged == true && (github.event_name != 'labeled' || startsWith('backport', github.event.label.name)) runs-on: ubuntu-latest From 726b0ffb3b0488bd289d85feacea31066c464a45 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 22 Feb 2024 19:40:24 +0200 Subject: [PATCH 133/223] Reduced temporary instance folder name Signed-off-by: Trial97 --- launcher/InstanceList.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/launcher/InstanceList.cpp b/launcher/InstanceList.cpp index c884a4f12..c663d22d0 100644 --- a/launcher/InstanceList.cpp +++ b/launcher/InstanceList.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -933,8 +934,12 @@ Task* InstanceList::wrapInstanceTask(InstanceTask* task) QString InstanceList::getStagedInstancePath() { - QString key = QUuid::createUuid().toString(QUuid::WithoutBraces); QString tempDir = ".LAUNCHER_TEMP/"; + auto tempPath = FS::PathCombine(m_instDir, tempDir); + if (QFileInfo::exists(tempPath)) { + FS::deletePath(tempPath); // clean the path to prevent any collisions + } + QString key = QUuid::createUuid().toString(QUuid::WithoutBraces).left(6); // reduce the size from 36 to 6 QString relPath = FS::PathCombine(tempDir, key); QDir rootPath(m_instDir); auto path = FS::PathCombine(m_instDir, relPath); @@ -942,7 +947,6 @@ QString InstanceList::getStagedInstancePath() return QString(); } #ifdef Q_OS_WIN32 - auto tempPath = FS::PathCombine(m_instDir, tempDir); SetFileAttributesA(tempPath.toStdString().c_str(), FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED); #endif return path; From aac6fea724e029b9ef4e4ed3e98b04c40149add0 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 22 Feb 2024 20:34:34 +0200 Subject: [PATCH 134/223] Updated application manifest Signed-off-by: Trial97 --- program_info/prismlauncher.manifest.in | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/program_info/prismlauncher.manifest.in b/program_info/prismlauncher.manifest.in index fb28afc17..71378134c 100644 --- a/program_info/prismlauncher.manifest.in +++ b/program_info/prismlauncher.manifest.in @@ -1,5 +1,10 @@ + + + true + + From 6a9f5540d385cd2edf7e43f3ad308041571a9f83 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sat, 24 Feb 2024 13:38:19 +0000 Subject: [PATCH 135/223] Re-randomise key until it does not collide Signed-off-by: TheKodeToad --- launcher/InstanceList.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/launcher/InstanceList.cpp b/launcher/InstanceList.cpp index c663d22d0..9c1f8f71b 100644 --- a/launcher/InstanceList.cpp +++ b/launcher/InstanceList.cpp @@ -934,22 +934,21 @@ Task* InstanceList::wrapInstanceTask(InstanceTask* task) QString InstanceList::getStagedInstancePath() { - QString tempDir = ".LAUNCHER_TEMP/"; - auto tempPath = FS::PathCombine(m_instDir, tempDir); - if (QFileInfo::exists(tempPath)) { - FS::deletePath(tempPath); // clean the path to prevent any collisions - } - QString key = QUuid::createUuid().toString(QUuid::WithoutBraces).left(6); // reduce the size from 36 to 6 - QString relPath = FS::PathCombine(tempDir, key); - QDir rootPath(m_instDir); - auto path = FS::PathCombine(m_instDir, relPath); - if (!rootPath.mkpath(relPath)) { - return QString(); - } + const QString tempRoot = FS::PathCombine(m_instDir, ".LAUNCHER_TEMP"); + + QString result; + + do { + const QString key = QUuid::createUuid().toString(QUuid::Id128).left(6); + result = FS::PathCombine(tempRoot, key); + } while (QFileInfo::exists(result)); + + if (!QDir::current().mkpath(result)) + return {}; #ifdef Q_OS_WIN32 SetFileAttributesA(tempPath.toStdString().c_str(), FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED); #endif - return path; + return result; } bool InstanceList::commitStagedInstance(const QString& path, From 9574ebe480a6a837533fc4339c1f3605300555ca Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sat, 24 Feb 2024 14:12:30 +0000 Subject: [PATCH 136/223] Delete staging on abort Previously instances would get "stuck" in the folder Signed-off-by: TheKodeToad --- launcher/InstanceList.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/launcher/InstanceList.cpp b/launcher/InstanceList.cpp index 9c1f8f71b..5297b1444 100644 --- a/launcher/InstanceList.cpp +++ b/launcher/InstanceList.cpp @@ -907,7 +907,11 @@ class InstanceStaging : public Task { emitFailed(reason); } - void childAborted() { emitAborted(); } + void childAborted() + { + m_parent->destroyStagingPath(m_stagingPath); + emitAborted(); + } private: InstanceList* m_parent; From df60f5cc9650a111a65ada2ea589bf7ecf9ac506 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sat, 24 Feb 2024 18:38:45 +0000 Subject: [PATCH 137/223] Add error when staging folder could not be created Signed-off-by: TheKodeToad --- launcher/InstanceList.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/launcher/InstanceList.cpp b/launcher/InstanceList.cpp index 5297b1444..f50d21a6b 100644 --- a/launcher/InstanceList.cpp +++ b/launcher/InstanceList.cpp @@ -848,13 +848,10 @@ class InstanceStaging : public Task { const unsigned maxBackoff = 16; public: - InstanceStaging(InstanceList* parent, InstanceTask* child, QString stagingPath, InstanceName const& instanceName, QString groupName) - : m_parent(parent) - , backoff(minBackoff, maxBackoff) - , m_stagingPath(std::move(stagingPath)) - , m_instance_name(std::move(instanceName)) - , m_groupName(std::move(groupName)) + InstanceStaging(InstanceList* parent, InstanceTask* child) : m_parent(parent), backoff(minBackoff, maxBackoff) { + m_stagingPath = parent->getStagedInstancePath(); + m_child.reset(child); connect(child, &Task::succeeded, this, &InstanceStaging::childSucceeded); connect(child, &Task::failed, this, &InstanceStaging::childFailed); @@ -867,7 +864,7 @@ class InstanceStaging : public Task { connect(&m_backoffTimer, &QTimer::timeout, this, &InstanceStaging::childSucceeded); } - virtual ~InstanceStaging(){}; + virtual ~InstanceStaging() {} // FIXME/TODO: add ability to abort during instance commit retries bool abort() override @@ -882,14 +879,22 @@ class InstanceStaging : public Task { bool canAbort() const override { return (m_child && m_child->canAbort()); } protected: - virtual void executeTask() override { m_child->start(); } + virtual void executeTask() override + { + if (m_stagingPath.isNull()) { + emitFailed(tr("Could not create staging folder")); + return; + } + + m_child->start(); + } QStringList warnings() const override { return m_child->warnings(); } private slots: void childSucceeded() { unsigned sleepTime = backoff(); - if (m_parent->commitStagedInstance(m_stagingPath, m_instance_name, m_groupName, *m_child.get())) { + if (m_parent->commitStagedInstance(m_stagingPath, *m_child.get(), m_child->group(), *m_child.get())) { emitSucceeded(); return; } @@ -898,7 +903,7 @@ class InstanceStaging : public Task { emitFailed(tr("Failed to commit instance, even after multiple retries. It is being blocked by something.")); return; } - qDebug() << "Failed to commit instance" << m_instance_name.name() << "Initiating backoff:" << sleepTime; + qDebug() << "Failed to commit instance" << m_child->name() << "Initiating backoff:" << sleepTime; m_backoffTimer.start(sleepTime * 500); } void childFailed(const QString& reason) @@ -923,17 +928,12 @@ class InstanceStaging : public Task { ExponentialSeries backoff; QString m_stagingPath; unique_qobject_ptr m_child; - InstanceName m_instance_name; - QString m_groupName; QTimer m_backoffTimer; }; Task* InstanceList::wrapInstanceTask(InstanceTask* task) { - auto stagingPath = getStagedInstancePath(); - task->setStagingPath(stagingPath); - task->setParentSettings(m_globalSettings); - return new InstanceStaging(this, task, stagingPath, *task, task->group()); + return new InstanceStaging(this, task); } QString InstanceList::getStagedInstancePath() From bd0cd828269ee259dd10439c84baeaec2f1220df Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sat, 24 Feb 2024 18:41:01 +0000 Subject: [PATCH 138/223] Add upper-bound for randomisation Signed-off-by: TheKodeToad --- launcher/InstanceList.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/launcher/InstanceList.cpp b/launcher/InstanceList.cpp index f50d21a6b..f4f225fd9 100644 --- a/launcher/InstanceList.cpp +++ b/launcher/InstanceList.cpp @@ -938,11 +938,15 @@ Task* InstanceList::wrapInstanceTask(InstanceTask* task) QString InstanceList::getStagedInstancePath() { - const QString tempRoot = FS::PathCombine(m_instDir, ".LAUNCHER_TEMP"); + const QString tempRoot = FS::PathCombine(m_instDir, ".tmp"); QString result; + int tries = 0; do { + if (++tries > 256) + return {}; + const QString key = QUuid::createUuid().toString(QUuid::Id128).left(6); result = FS::PathCombine(tempRoot, key); } while (QFileInfo::exists(result)); From fccf857d8e5040fd64d7bc302463c1c9184f110f Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sat, 24 Feb 2024 19:16:39 +0000 Subject: [PATCH 139/223] Fix a mistake Signed-off-by: TheKodeToad --- launcher/InstanceList.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/launcher/InstanceList.cpp b/launcher/InstanceList.cpp index f4f225fd9..acde60568 100644 --- a/launcher/InstanceList.cpp +++ b/launcher/InstanceList.cpp @@ -848,11 +848,15 @@ class InstanceStaging : public Task { const unsigned maxBackoff = 16; public: - InstanceStaging(InstanceList* parent, InstanceTask* child) : m_parent(parent), backoff(minBackoff, maxBackoff) + InstanceStaging(InstanceList* parent, InstanceTask* child, SettingsObjectPtr settings) : m_parent(parent), backoff(minBackoff, maxBackoff) { m_stagingPath = parent->getStagedInstancePath(); m_child.reset(child); + + m_child->setStagingPath(m_stagingPath); + m_child->setParentSettings(std::move(settings)); + connect(child, &Task::succeeded, this, &InstanceStaging::childSucceeded); connect(child, &Task::failed, this, &InstanceStaging::childFailed); connect(child, &Task::aborted, this, &InstanceStaging::childAborted); @@ -933,7 +937,7 @@ class InstanceStaging : public Task { Task* InstanceList::wrapInstanceTask(InstanceTask* task) { - return new InstanceStaging(this, task); + return new InstanceStaging(this, task, m_globalSettings); } QString InstanceList::getStagedInstancePath() From c0eb80947db57c4b0de376213d53aac4f694e1b0 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sat, 24 Feb 2024 21:06:03 +0000 Subject: [PATCH 140/223] Fix build on Windows and formatting Signed-off-by: TheKodeToad --- launcher/InstanceList.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/launcher/InstanceList.cpp b/launcher/InstanceList.cpp index acde60568..5e4abf020 100644 --- a/launcher/InstanceList.cpp +++ b/launcher/InstanceList.cpp @@ -848,7 +848,8 @@ class InstanceStaging : public Task { const unsigned maxBackoff = 16; public: - InstanceStaging(InstanceList* parent, InstanceTask* child, SettingsObjectPtr settings) : m_parent(parent), backoff(minBackoff, maxBackoff) + InstanceStaging(InstanceList* parent, InstanceTask* child, SettingsObjectPtr settings) + : m_parent(parent), backoff(minBackoff, maxBackoff) { m_stagingPath = parent->getStagedInstancePath(); @@ -958,7 +959,7 @@ QString InstanceList::getStagedInstancePath() if (!QDir::current().mkpath(result)) return {}; #ifdef Q_OS_WIN32 - SetFileAttributesA(tempPath.toStdString().c_str(), FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED); + SetFileAttributesA(tempRoot.toStdString().c_str(), FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED); #endif return result; } From 1b89c63ad477c1cfd7cb7f18ea32b045ae7ed59d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 25 Feb 2024 00:18:54 +0000 Subject: [PATCH 141/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'nixpkgs': 'github:nixos/nixpkgs/6e2f00c83911461438301db0dba5281197fe4b3a' (2024-02-17) → 'github:nixos/nixpkgs/f63ce824cd2f036216eb5f637dfef31e1a03ee89' (2024-02-24) --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index b5d8e7494..ead111da1 100644 --- a/flake.lock +++ b/flake.lock @@ -93,11 +93,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1708151420, - "narHash": "sha256-MGT/4aGCWQPQiu6COqJdCj9kSpLPiShgbwpbC38YXC8=", + "lastModified": 1708751719, + "narHash": "sha256-0uWOKSpXJXmXswOvDM5Vk3blB74apFB6rNGWV5IjoN0=", "owner": "nixos", "repo": "nixpkgs", - "rev": "6e2f00c83911461438301db0dba5281197fe4b3a", + "rev": "f63ce824cd2f036216eb5f637dfef31e1a03ee89", "type": "github" }, "original": { From 322a8899ed574d20056f4ac0b52c4dd28f05ea46 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 17:19:39 +0000 Subject: [PATCH 142/223] chore(deps): update determinatesystems/update-flake-lock action to v21 --- .github/workflows/update-flake.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-flake.yml b/.github/workflows/update-flake.yml index 2d78997ed..a6005cfe4 100644 --- a/.github/workflows/update-flake.yml +++ b/.github/workflows/update-flake.yml @@ -19,7 +19,7 @@ jobs: - uses: actions/checkout@v4 - uses: cachix/install-nix-action@6004951b182f8860210c8d6f0d808ec5b1a33d28 # v25 - - uses: DeterminateSystems/update-flake-lock@v20 + - uses: DeterminateSystems/update-flake-lock@v21 with: commit-msg: "chore(nix): update lockfile" pr-title: "chore(nix): update lockfile" From e1146455a3fe2bcdfd68a295d317606dc2c45507 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 23:16:59 +0000 Subject: [PATCH 143/223] chore(deps): update actions/cache action to v4.0.1 --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0352988f7..9cb737df6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -166,7 +166,7 @@ jobs: - name: Retrieve ccache cache (Windows MinGW-w64) if: runner.os == 'Windows' && matrix.msystem != '' && inputs.build_type == 'Debug' - uses: actions/cache@v4.0.0 + uses: actions/cache@v4.0.1 with: path: '${{ github.workspace }}\.ccache' key: ${{ matrix.os }}-mingw-w64-ccache-${{ github.run_id }} From 138df66355b54151302f0b143ec1c2a5a4eb11c8 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Fri, 1 Mar 2024 00:03:20 +0000 Subject: [PATCH 144/223] Fix server side mods being marked as unsupported on client Signed-off-by: TheKodeToad --- .../modrinth/ModrinthPackExportTask.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/launcher/modplatform/modrinth/ModrinthPackExportTask.cpp b/launcher/modplatform/modrinth/ModrinthPackExportTask.cpp index e9e8a3b75..c704708ad 100644 --- a/launcher/modplatform/modrinth/ModrinthPackExportTask.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackExportTask.cpp @@ -287,16 +287,12 @@ QByteArray ModrinthPackExportTask::generateIndex() env["client"] = "required"; env["server"] = "required"; } - switch (iterator->side) { - case Metadata::ModSide::ClientSide: - env["server"] = "unsupported"; - break; - case Metadata::ModSide::ServerSide: - env["client"] = "unsupported"; - break; - case Metadata::ModSide::UniversalSide: - break; - } + + // a server side mod does not imply that the mod does not work on the client + // however, if a mrpack mod is marked as server-only it will not install on the client + if (iterator->side == Metadata::ModSide::ClientSide) + env["server"] = "unsupported"; + fileOut["env"] = env; fileOut["path"] = path; From 4101fbb63433d1ee90476f55d76a7a7f0ced6ccb Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Fri, 1 Mar 2024 00:54:18 +0000 Subject: [PATCH 145/223] Allow multiline description Signed-off-by: TheKodeToad --- launcher/ui/dialogs/ExportPackDialog.cpp | 25 +++++++--- launcher/ui/dialogs/ExportPackDialog.ui | 60 +++++++++++++++--------- 2 files changed, 57 insertions(+), 28 deletions(-) diff --git a/launcher/ui/dialogs/ExportPackDialog.cpp b/launcher/ui/dialogs/ExportPackDialog.cpp index 5af24b1b7..73e44efb1 100644 --- a/launcher/ui/dialogs/ExportPackDialog.cpp +++ b/launcher/ui/dialogs/ExportPackDialog.cpp @@ -47,11 +47,18 @@ ExportPackDialog::ExportPackDialog(InstancePtr instance, QWidget* parent, ModPla if (m_provider == ModPlatform::ResourceProvider::MODRINTH) { setWindowTitle(tr("Export Modrinth Pack")); - ui->summary->setText(instance->settings()->get("ExportSummary").toString()); + + ui->authorLabel->hide(); + ui->author->hide(); + + ui->summary->setPlainText(instance->settings()->get("ExportSummary").toString()); } else { setWindowTitle(tr("Export CurseForge Pack")); - ui->summaryLabel->setText(tr("&Author")); - ui->summary->setText(instance->settings()->get("ExportAuthor").toString()); + + ui->summaryLabel->hide(); + ui->summary->hide(); + + ui->author->setText(instance->settings()->get("ExportAuthor").toString()); } // ensure a valid pack is generated @@ -108,9 +115,13 @@ void ExportPackDialog::done(int result) auto settings = instance->settings(); settings->set("ExportName", ui->name->text()); settings->set("ExportVersion", ui->version->text()); - settings->set(m_provider == ModPlatform::ResourceProvider::FLAME ? "ExportAuthor" : "ExportSummary", ui->summary->text()); settings->set("ExportOptionalFiles", ui->optionalFiles->isChecked()); + if (m_provider == ModPlatform::ResourceProvider::MODRINTH) + settings->set("ExportSummary", ui->summary->toPlainText()); + else + settings->set("ExportAuthor", ui->author->text()); + if (result == Accepted) { const QString name = ui->name->text().isEmpty() ? instance->name() : ui->name->text(); const QString filename = FS::RemoveInvalidFilenameChars(name); @@ -134,10 +145,10 @@ void ExportPackDialog::done(int result) Task* task; if (m_provider == ModPlatform::ResourceProvider::MODRINTH) { - task = new ModrinthPackExportTask(name, ui->version->text(), ui->summary->text(), ui->optionalFiles->isChecked(), instance, - output, std::bind(&FileIgnoreProxy::filterFile, proxy, std::placeholders::_1)); + task = new ModrinthPackExportTask(name, ui->version->text(), ui->summary->toPlainText(), ui->optionalFiles->isChecked(), + instance, output, std::bind(&FileIgnoreProxy::filterFile, proxy, std::placeholders::_1)); } else { - task = new FlamePackExportTask(name, ui->version->text(), ui->summary->text(), ui->optionalFiles->isChecked(), instance, output, + task = new FlamePackExportTask(name, ui->version->text(), ui->author->text(), ui->optionalFiles->isChecked(), instance, output, std::bind(&FileIgnoreProxy::filterFile, proxy, std::placeholders::_1)); } diff --git a/launcher/ui/dialogs/ExportPackDialog.ui b/launcher/ui/dialogs/ExportPackDialog.ui index 09dea72a8..a4a174212 100644 --- a/launcher/ui/dialogs/ExportPackDialog.ui +++ b/launcher/ui/dialogs/ExportPackDialog.ui @@ -7,7 +7,7 @@ 0 0 650 - 510 + 532 @@ -19,21 +19,8 @@ &Description - - - - - &Summary - - - summary - - - - - - - + + &Name @@ -43,7 +30,10 @@ - + + + + &Version @@ -53,16 +43,43 @@ - - - - + 1.0.0 + + + + &Summary + + + summary + + + + + + + true + + + + + + + &Author + + + author + + + + + + @@ -124,6 +141,7 @@ name version summary + author files optionalFiles From d6abcb73c599695d41bd82501688c96dea7878f2 Mon Sep 17 00:00:00 2001 From: DioEgizio <83089242+DioEgizio@users.noreply.github.com> Date: Mon, 4 Mar 2024 16:32:45 +0100 Subject: [PATCH 146/223] chore: bump develop to 9.0 until it's too late lol Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com> --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6cceb2599..2e46bb605 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -178,7 +178,7 @@ set(Launcher_NEWS_OPEN_URL "https://prismlauncher.org/news" CACHE STRING "URL th set(Launcher_HELP_URL "https://prismlauncher.org/wiki/help-pages/%1" CACHE STRING "URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help") ######## Set version numbers ######## -set(Launcher_VERSION_MAJOR 8) +set(Launcher_VERSION_MAJOR 9) set(Launcher_VERSION_MINOR 0) set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}") From 6591379a8ac36e22970043460eecdc38fab4eb2a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 8 Mar 2024 07:47:18 +0000 Subject: [PATCH 147/223] chore(deps): update cachix/install-nix-action action to v26 --- .github/workflows/update-flake.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-flake.yml b/.github/workflows/update-flake.yml index a6005cfe4..855b105ea 100644 --- a/.github/workflows/update-flake.yml +++ b/.github/workflows/update-flake.yml @@ -17,7 +17,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: cachix/install-nix-action@6004951b182f8860210c8d6f0d808ec5b1a33d28 # v25 + - uses: cachix/install-nix-action@8887e596b4ee1134dae06b98d573bd674693f47c # v26 - uses: DeterminateSystems/update-flake-lock@v21 with: From 03def913aded7e9c4e39bcd07baee55406c43a17 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 8 Mar 2024 21:26:24 +0000 Subject: [PATCH 148/223] chore(deps): update softprops/action-gh-release action to v2 --- .github/workflows/trigger_release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/trigger_release.yml b/.github/workflows/trigger_release.yml index 2afbaeb61..fa22c96d5 100644 --- a/.github/workflows/trigger_release.yml +++ b/.github/workflows/trigger_release.yml @@ -84,7 +84,7 @@ jobs: - name: Create release id: create_release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 with: token: ${{ secrets.GITHUB_TOKEN }} tag_name: ${{ github.ref }} From 92113e233aefbd2b255775d4e858e45845a94a2c Mon Sep 17 00:00:00 2001 From: chouzz Date: Sat, 9 Mar 2024 19:34:16 +0800 Subject: [PATCH 149/223] Add totalTimePlayed for FTBApp import Signed-off-by: chouzz --- launcher/modplatform/import_ftb/PackHelpers.cpp | 1 + launcher/modplatform/import_ftb/PackHelpers.h | 1 + launcher/modplatform/import_ftb/PackInstallTask.cpp | 1 + 3 files changed, 3 insertions(+) diff --git a/launcher/modplatform/import_ftb/PackHelpers.cpp b/launcher/modplatform/import_ftb/PackHelpers.cpp index ecf973452..e523b9d20 100644 --- a/launcher/modplatform/import_ftb/PackHelpers.cpp +++ b/launcher/modplatform/import_ftb/PackHelpers.cpp @@ -43,6 +43,7 @@ Modpack parseDirectory(QString path) modpack.version = Json::requireString(root, "version", "version"); modpack.mcVersion = Json::requireString(root, "mcVersion", "mcVersion"); modpack.jvmArgs = Json::ensureVariant(root, "jvmArgs", {}, "jvmArgs"); + modpack.totalPlayTime = Json::requireInteger(root, "totalPlayTime", "totalPlayTime"); } catch (const Exception& e) { qDebug() << "Couldn't load ftb instance json: " << e.cause(); return {}; diff --git a/launcher/modplatform/import_ftb/PackHelpers.h b/launcher/modplatform/import_ftb/PackHelpers.h index 221eb5bf6..449ed2546 100644 --- a/launcher/modplatform/import_ftb/PackHelpers.h +++ b/launcher/modplatform/import_ftb/PackHelpers.h @@ -36,6 +36,7 @@ struct Modpack { QString name; QString version; QString mcVersion; + int totalPlayTime; // not needed for instance creation QVariant jvmArgs; diff --git a/launcher/modplatform/import_ftb/PackInstallTask.cpp b/launcher/modplatform/import_ftb/PackInstallTask.cpp index 946ec4eb7..8046300e1 100644 --- a/launcher/modplatform/import_ftb/PackInstallTask.cpp +++ b/launcher/modplatform/import_ftb/PackInstallTask.cpp @@ -55,6 +55,7 @@ void PackInstallTask::copySettings() instanceSettings->suspendSave(); MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath); instance.settings()->set("InstanceType", "OneSix"); + instance.settings()->set("totalTimePlayed", m_pack.totalPlayTime / 1000); if (m_pack.jvmArgs.isValid() && !m_pack.jvmArgs.toString().isEmpty()) { instance.settings()->set("OverrideJavaArgs", true); From 75628bf81ec48925417374d7ae2672a0e48ce6d1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 10 Mar 2024 00:19:11 +0000 Subject: [PATCH 150/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'flake-parts': 'github:hercules-ci/flake-parts/b253292d9c0a5ead9bc98c4e9a26c6312e27d69f' (2024-02-01) → 'github:hercules-ci/flake-parts/f7b3c975cf067e56e7cda6cb098ebe3fb4d74ca2' (2024-03-01) • Updated input 'nixpkgs': 'github:nixos/nixpkgs/f63ce824cd2f036216eb5f637dfef31e1a03ee89' (2024-02-24) → 'github:nixos/nixpkgs/0e7f98a5f30166cbed344569426850b21e4091d4' (2024-03-09) --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index ead111da1..e7d3ba95f 100644 --- a/flake.lock +++ b/flake.lock @@ -23,11 +23,11 @@ ] }, "locked": { - "lastModified": 1706830856, - "narHash": "sha256-a0NYyp+h9hlb7ddVz4LUn1vT/PLwqfrWYcHMvFB1xYg=", + "lastModified": 1709336216, + "narHash": "sha256-Dt/wOWeW6Sqm11Yh+2+t0dfEWxoMxGBvv3JpIocFl9E=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "b253292d9c0a5ead9bc98c4e9a26c6312e27d69f", + "rev": "f7b3c975cf067e56e7cda6cb098ebe3fb4d74ca2", "type": "github" }, "original": { @@ -93,11 +93,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1708751719, - "narHash": "sha256-0uWOKSpXJXmXswOvDM5Vk3blB74apFB6rNGWV5IjoN0=", + "lastModified": 1709968316, + "narHash": "sha256-4rZEtEDT6jcgRaqxsatBeds7x1PoEiEjb6QNGb4mNrk=", "owner": "nixos", "repo": "nixpkgs", - "rev": "f63ce824cd2f036216eb5f637dfef31e1a03ee89", + "rev": "0e7f98a5f30166cbed344569426850b21e4091d4", "type": "github" }, "original": { From 853e4a13abfc2da266d505663c3784278ea5afad Mon Sep 17 00:00:00 2001 From: AtomHare <29772841+AtomHare@users.noreply.github.com> Date: Sat, 16 Mar 2024 12:44:55 +0100 Subject: [PATCH 151/223] fix: Compressing typo Signed-off-by: AtomHare <29772841+AtomHare@users.noreply.github.com> --- launcher/MMCZip.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/MMCZip.cpp b/launcher/MMCZip.cpp index ce2573329..033aa0755 100644 --- a/launcher/MMCZip.cpp +++ b/launcher/MMCZip.cpp @@ -463,7 +463,7 @@ auto ExportToZipTask::exportZip() -> ZipResult auto absolute = file.absoluteFilePath(); auto relative = m_dir.relativeFilePath(absolute); - setStatus("Compresing: " + relative); + setStatus("Compressing: " + relative); setProgress(m_progress + 1, m_progressTotal); if (m_follow_symlinks) { if (file.isSymLink()) From 95c3daca596f31d61fa947c6f62df60da33c07f7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 17 Mar 2024 00:19:13 +0000 Subject: [PATCH 152/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'nixpkgs': 'github:nixos/nixpkgs/0e7f98a5f30166cbed344569426850b21e4091d4' (2024-03-09) → 'github:nixos/nixpkgs/9af9c1c87ed3e3ed271934cb896e0cdd33dae212' (2024-03-15) --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index e7d3ba95f..ab1026c08 100644 --- a/flake.lock +++ b/flake.lock @@ -93,11 +93,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1709968316, - "narHash": "sha256-4rZEtEDT6jcgRaqxsatBeds7x1PoEiEjb6QNGb4mNrk=", + "lastModified": 1710534455, + "narHash": "sha256-huQT4Xs0y4EeFKn2BTBVYgEwJSv8SDlm82uWgMnCMmI=", "owner": "nixos", "repo": "nixpkgs", - "rev": "0e7f98a5f30166cbed344569426850b21e4091d4", + "rev": "9af9c1c87ed3e3ed271934cb896e0cdd33dae212", "type": "github" }, "original": { From 05487152fe4eae0ad3d12b18c398ea2a99b44e32 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 17 Mar 2024 20:53:26 +0200 Subject: [PATCH 153/223] Fixed curesforge export Signed-off-by: Trial97 --- launcher/modplatform/flame/FlamePackExportTask.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/launcher/modplatform/flame/FlamePackExportTask.cpp b/launcher/modplatform/flame/FlamePackExportTask.cpp index e28c82b4c..3a2028fd1 100644 --- a/launcher/modplatform/flame/FlamePackExportTask.cpp +++ b/launcher/modplatform/flame/FlamePackExportTask.cpp @@ -393,16 +393,16 @@ QByteArray FlamePackExportTask::generateIndex() version["version"] = minecraft->m_version; QString id; if (quilt != nullptr) - id = "quilt-" + quilt->getVersion(); + id = "quilt-" + quilt->m_version; else if (fabric != nullptr) - id = "fabric-" + fabric->getVersion(); + id = "fabric-" + fabric->m_version; else if (forge != nullptr) - id = "forge-" + forge->getVersion(); + id = "forge-" + forge->m_version; else if (neoforge != nullptr) { id = "neoforge-"; if (minecraft->m_version == "1.20.1") id += "1.20.1-"; - id += neoforge->getVersion(); + id += neoforge->m_version; } version["modLoaders"] = QJsonArray(); if (!id.isEmpty()) { From 7ffebcad72696e6779b065340098667ccaecd440 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 19 Mar 2024 17:41:32 +0000 Subject: [PATCH 154/223] chore(deps): update actions/cache action to v4.0.2 --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9cb737df6..ab2bd64b9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -166,7 +166,7 @@ jobs: - name: Retrieve ccache cache (Windows MinGW-w64) if: runner.os == 'Windows' && matrix.msystem != '' && inputs.build_type == 'Debug' - uses: actions/cache@v4.0.1 + uses: actions/cache@v4.0.2 with: path: '${{ github.workspace }}\.ccache' key: ${{ matrix.os }}-mingw-w64-ccache-${{ github.run_id }} From d72bd70c055d23223ee78fa62e6ae4ccfcb490d7 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Tue, 19 Mar 2024 20:34:55 +0000 Subject: [PATCH 155/223] Use UTF-8 for ZIP creation Signed-off-by: TheKodeToad --- launcher/MMCZip.cpp | 2 ++ launcher/MMCZip.h | 1 + 2 files changed, 3 insertions(+) diff --git a/launcher/MMCZip.cpp b/launcher/MMCZip.cpp index 033aa0755..2fb4d13df 100644 --- a/launcher/MMCZip.cpp +++ b/launcher/MMCZip.cpp @@ -119,6 +119,7 @@ bool compressDirFiles(QuaZip* zip, QString dir, QFileInfoList files, bool follow bool compressDirFiles(QString fileCompressed, QString dir, QFileInfoList files, bool followSymlinks) { QuaZip zip(fileCompressed); + zip.setUtf8Enabled(true); QDir().mkpath(QFileInfo(fileCompressed).absolutePath()); if (!zip.open(QuaZip::mdCreate)) { QFile::remove(fileCompressed); @@ -141,6 +142,7 @@ bool compressDirFiles(QString fileCompressed, QString dir, QFileInfoList files, bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList& mods) { QuaZip zipOut(targetJarPath); + zipOut.setUtf8Enabled(true); if (!zipOut.open(QuaZip::mdCreate)) { QFile::remove(targetJarPath); qCritical() << "Failed to open the minecraft.jar for modding"; diff --git a/launcher/MMCZip.h b/launcher/MMCZip.h index 93692d0d2..43b4ab933 100644 --- a/launcher/MMCZip.h +++ b/launcher/MMCZip.h @@ -163,6 +163,7 @@ class ExportToZipTask : public Task { , m_follow_symlinks(followSymlinks) { setAbortable(true); + m_output.setUtf8Enabled(true); }; ExportToZipTask(QString outputPath, QString dir, QFileInfoList files, QString destinationPrefix = "", bool followSymlinks = false) : ExportToZipTask(outputPath, QDir(dir), files, destinationPrefix, followSymlinks){}; From 93f19bda6eccf31642bfeeb323b435d9da678e63 Mon Sep 17 00:00:00 2001 From: Alexandru Ionut Tripon Date: Thu, 21 Mar 2024 00:07:06 +0200 Subject: [PATCH 156/223] Update launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp Signed-off-by: Alexandru Ionut Tripon --- launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp b/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp index 820e03ec9..84c52c386 100644 --- a/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp +++ b/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp @@ -129,6 +129,7 @@ bool XboxAuthorizationStep::processSTSError(QNetworkReply::NetworkError error, Q .arg("help.minecraft.net")); return true; } + // the following codes where copied from: https://github.com/PrismarineJS/prismarine-auth/pull/44 case 2148916236: { emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("This Microsoft account requires proof of age to play. Please login to %1 to provide proof of age.") From 37d348e60ee97995f7fdbc4c98c3a240992cfed2 Mon Sep 17 00:00:00 2001 From: DioEgizio <83089242+DioEgizio@users.noreply.github.com> Date: Wed, 20 Mar 2024 13:16:28 +0100 Subject: [PATCH 157/223] fix: include libbz2.so.1.0 fixes portable installs not working on fedora anymore i did this only on portable builds and not system installs so that it doesn't create problems to people packaging them, as to fix system installs i would have to put it in bin/ Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com> --- .github/workflows/build.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9cb737df6..89e51ed99 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -496,7 +496,6 @@ jobs: run: | cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_DIR }} for l in $(find ${{ env.INSTALL_DIR }} -type f); do l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_DIR }}/}; l=${l#./}; echo $l; done > ${{ env.INSTALL_DIR }}/manifest.txt - cd ${{ env.INSTALL_DIR }} tar --owner root --group root -czf ../PrismLauncher.tar.gz * @@ -505,9 +504,12 @@ jobs: run: | cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable + + # workaround to make portable installs to work on fedora + mkdir ${{ env.INSTALL_PORTABLE_DIR }}/lib + cp /lib/x86_64-linux-gnu/libbz2.so.1.0 ${{ env.INSTALL_PORTABLE_DIR }}/lib + for l in $(find ${{ env.INSTALL_PORTABLE_DIR }} -type f); do l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_PORTABLE_DIR }}/}; l=${l#./}; echo $l; done > ${{ env.INSTALL_PORTABLE_DIR }}/manifest.txt - - cd ${{ env.INSTALL_PORTABLE_DIR }} tar -czf ../PrismLauncher-portable.tar.gz * From 3a833b659a581274f15f609be12bfaa1a9efd1ab Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 24 Mar 2024 00:19:57 +0000 Subject: [PATCH 158/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'nixpkgs': 'github:nixos/nixpkgs/9af9c1c87ed3e3ed271934cb896e0cdd33dae212' (2024-03-15) → 'github:nixos/nixpkgs/20bc93ca7b2158ebc99b8cef987a2173a81cde35' (2024-03-23) • Updated input 'pre-commit-hooks': 'github:cachix/pre-commit-hooks.nix/5df5a70ad7575f6601d91f0efec95dd9bc619431' (2024-02-15) → 'github:cachix/pre-commit-hooks.nix/e611897ddfdde3ed3eaac4758635d7177ff78673' (2024-03-20) • Updated input 'pre-commit-hooks/flake-utils': 'github:numtide/flake-utils/4022d587cbbfd70fe950c1e2083a02621806a725' (2023-12-04) → 'github:numtide/flake-utils/b1d9ab70662946ef0850d488da1c9019f3a9752a' (2024-03-11) • Updated input 'pre-commit-hooks/gitignore': 'github:hercules-ci/gitignore.nix/43e1aa1308018f37118e34d3a9cb4f5e75dc11d5' (2023-12-29) → 'github:hercules-ci/gitignore.nix/637db329424fd7e46cf4185293b9cc8c88c95394' (2024-02-28) --- flake.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/flake.lock b/flake.lock index ab1026c08..492f7855e 100644 --- a/flake.lock +++ b/flake.lock @@ -41,11 +41,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1701680307, - "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", "owner": "numtide", "repo": "flake-utils", - "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", "type": "github" }, "original": { @@ -62,11 +62,11 @@ ] }, "locked": { - "lastModified": 1703887061, - "narHash": "sha256-gGPa9qWNc6eCXT/+Z5/zMkyYOuRZqeFZBDbopNZQkuY=", + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", "owner": "hercules-ci", "repo": "gitignore.nix", - "rev": "43e1aa1308018f37118e34d3a9cb4f5e75dc11d5", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", "type": "github" }, "original": { @@ -93,11 +93,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1710534455, - "narHash": "sha256-huQT4Xs0y4EeFKn2BTBVYgEwJSv8SDlm82uWgMnCMmI=", + "lastModified": 1711200738, + "narHash": "sha256-dkJmk/ET/tRV4007O6kU101UEg1svUwiyk/zEEX9Tdg=", "owner": "nixos", "repo": "nixpkgs", - "rev": "9af9c1c87ed3e3ed271934cb896e0cdd33dae212", + "rev": "20bc93ca7b2158ebc99b8cef987a2173a81cde35", "type": "github" }, "original": { @@ -122,11 +122,11 @@ ] }, "locked": { - "lastModified": 1708018599, - "narHash": "sha256-M+Ng6+SePmA8g06CmUZWi1AjG2tFBX9WCXElBHEKnyM=", + "lastModified": 1710923068, + "narHash": "sha256-6hOpUiuxuwpXXc/xfJsBUJeqqgGI+JMJuLo45aG3cKc=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "5df5a70ad7575f6601d91f0efec95dd9bc619431", + "rev": "e611897ddfdde3ed3eaac4758635d7177ff78673", "type": "github" }, "original": { From 765bdf67c95ffee27d4b8342982b3e7bcc382c4b Mon Sep 17 00:00:00 2001 From: Trial97 Date: Wed, 27 Mar 2024 00:56:12 +0200 Subject: [PATCH 159/223] Changed the trait name Signed-off-by: Trial97 --- launcher/minecraft/MinecraftInstance.cpp | 2 +- .../org/prismlauncher/launcher/impl/StandardLauncher.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index 4a72ae1e4..1de822b7f 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -665,7 +665,7 @@ QStringList MinecraftInstance::processMinecraftArgs(AuthSessionPtr session, Mine } if (serverToJoin && !serverToJoin->address.isEmpty()) { - if (profile->hasTrait("quickPlay")) { + if (profile->hasTrait("feature:is_quick_play_multiplayer")) { args_pattern += " --quickPlayMultiplayer " + serverToJoin->address + ':' + QString::number(serverToJoin->port); } else { args_pattern += " --server " + serverToJoin->address; diff --git a/libraries/launcher/org/prismlauncher/launcher/impl/StandardLauncher.java b/libraries/launcher/org/prismlauncher/launcher/impl/StandardLauncher.java index 70ee015bd..49e5d518f 100644 --- a/libraries/launcher/org/prismlauncher/launcher/impl/StandardLauncher.java +++ b/libraries/launcher/org/prismlauncher/launcher/impl/StandardLauncher.java @@ -68,7 +68,7 @@ public final class StandardLauncher extends AbstractLauncher { super(params); List traits = params.getList("traits", Collections.emptyList()); - quickPlaySupported = traits.contains("quickPlay"); + quickPlaySupported = traits.contains("feature:is_quick_play_multiplayer"); } @Override From e6a9badb738caee498ebe74c90714fe01af07f0b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 30 Mar 2024 10:42:48 +0000 Subject: [PATCH 160/223] chore(deps): update korthout/backport-action action to v2.5.0 --- .github/workflows/backport.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 5df88fe86..60bd86eec 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -25,7 +25,7 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} - name: Create backport PRs - uses: korthout/backport-action@v2.4.1 + uses: korthout/backport-action@v2.5.0 with: # Config README: https://github.com/korthout/backport-action#backport-action pull_description: |- From f1351a143e70937242e37e633717640c54ad604e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 31 Mar 2024 00:20:10 +0000 Subject: [PATCH 161/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'nixpkgs': 'github:nixos/nixpkgs/20bc93ca7b2158ebc99b8cef987a2173a81cde35' (2024-03-23) → 'github:nixos/nixpkgs/807c549feabce7eddbf259dbdcec9e0600a0660d' (2024-03-29) • Updated input 'pre-commit-hooks': 'github:cachix/pre-commit-hooks.nix/e611897ddfdde3ed3eaac4758635d7177ff78673' (2024-03-20) → 'github:cachix/pre-commit-hooks.nix/c11e43aed6f17336c25cd120eac886b96c455731' (2024-03-30) --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index 492f7855e..dcc028b2d 100644 --- a/flake.lock +++ b/flake.lock @@ -93,11 +93,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1711200738, - "narHash": "sha256-dkJmk/ET/tRV4007O6kU101UEg1svUwiyk/zEEX9Tdg=", + "lastModified": 1711715736, + "narHash": "sha256-9slQ609YqT9bT/MNX9+5k5jltL9zgpn36DpFB7TkttM=", "owner": "nixos", "repo": "nixpkgs", - "rev": "20bc93ca7b2158ebc99b8cef987a2173a81cde35", + "rev": "807c549feabce7eddbf259dbdcec9e0600a0660d", "type": "github" }, "original": { @@ -122,11 +122,11 @@ ] }, "locked": { - "lastModified": 1710923068, - "narHash": "sha256-6hOpUiuxuwpXXc/xfJsBUJeqqgGI+JMJuLo45aG3cKc=", + "lastModified": 1711760932, + "narHash": "sha256-DqUTQ2iAAqSDwMhKBqvi24v0Oc7pD3LCK/0FCG//TdA=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "e611897ddfdde3ed3eaac4758635d7177ff78673", + "rev": "c11e43aed6f17336c25cd120eac886b96c455731", "type": "github" }, "original": { From 5f11b2e77fbf14f9f9e5459b80a2308bc211d03f Mon Sep 17 00:00:00 2001 From: DioEgizio <83089242+DioEgizio@users.noreply.github.com> Date: Tue, 2 Apr 2024 19:10:40 +0200 Subject: [PATCH 162/223] chore: update to Qt 6.7.0 Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com> --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 14c725b63..44779386f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -76,7 +76,7 @@ jobs: qt_ver: 6 qt_host: windows qt_arch: '' - qt_version: '6.6.2' + qt_version: '6.7.0' qt_modules: 'qt5compat qtimageformats' qt_tools: '' @@ -88,7 +88,7 @@ jobs: qt_ver: 6 qt_host: windows qt_arch: 'win64_msvc2019_arm64' - qt_version: '6.6.2' + qt_version: '6.7.0' qt_modules: 'qt5compat qtimageformats' qt_tools: '' @@ -98,7 +98,7 @@ jobs: qt_ver: 6 qt_host: mac qt_arch: '' - qt_version: '6.6.2' + qt_version: '6.7.0' qt_modules: 'qt5compat qtimageformats' qt_tools: '' From 450b73328e20941eba12be3b7c7f8bb13dc0f944 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Wed, 3 Apr 2024 19:34:35 +0300 Subject: [PATCH 163/223] Fixed crash on non-latin instance name Signed-off-by: Trial97 --- .../minecraft/launch/LauncherPartLaunch.cpp | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/launcher/minecraft/launch/LauncherPartLaunch.cpp b/launcher/minecraft/launch/LauncherPartLaunch.cpp index aa94edb5d..dcfb3d148 100644 --- a/launcher/minecraft/launch/LauncherPartLaunch.cpp +++ b/launcher/minecraft/launch/LauncherPartLaunch.cpp @@ -74,16 +74,36 @@ QString shortPathName(const QString& file) auto input = file.toStdWString(); std::wstring output; long length = GetShortPathNameW(input.c_str(), NULL, 0); + if (length == 0) + return {}; // NOTE: this resizing might seem weird... // when GetShortPathNameW fails, it returns length including null character // when it succeeds, it returns length excluding null character // See: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364989(v=vs.85).aspx output.resize(length); - GetShortPathNameW(input.c_str(), (LPWSTR)output.c_str(), length); + if (GetShortPathNameW(input.c_str(), (LPWSTR)output.c_str(), length) == 0) + return {}; output.resize(length - 1); QString ret = QString::fromStdWString(output); return ret; } + +QString getShortPathName(const QString& file) +{ + auto path = shortPathName(file); + if (!path.isEmpty()) + return path; + // the path can not be getted due to the file/folder not existing + // so create the parrent folder + // and assume that we can concatenate the short path of the parent folder with the file name + // usually the 8 bit characters are in the instance name not in the name of the end files/folders we need + FS::ensureFilePathExists(file); + QFileInfo a(file); + auto partialShortPath = shortPathName(a.path()); + if (!partialShortPath.isEmpty()) + return FS::PathCombine(partialShortPath, a.fileName()); + return file; +} #endif // if the string survives roundtrip through local 8bit encoding... @@ -137,7 +157,7 @@ void LauncherPartLaunch::executeTask() auto natPath = minecraftInstance->getNativePath(); #ifdef Q_OS_WIN if (!fitsInLocal8bit(natPath)) { - args << "-Djava.library.path=" + shortPathName(natPath); + args << "-Djava.library.path=" + getShortPathName(natPath); } else { args << "-Djava.library.path=" + natPath; } @@ -150,7 +170,7 @@ void LauncherPartLaunch::executeTask() QStringList processed; for (auto& item : classPath) { if (!fitsInLocal8bit(item)) { - processed << shortPathName(item); + processed << getShortPathName(item); } else { processed << item; } From 0d372d2fbfd76b54f156faeca6a31fff80875999 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Wed, 3 Apr 2024 21:04:26 +0200 Subject: [PATCH 164/223] fix(nix): add jdk21 Signed-off-by: Sefa Eyeoglu --- nix/pkg/wrapper.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nix/pkg/wrapper.nix b/nix/pkg/wrapper.nix index cd356c8d7..1bcff1f9b 100644 --- a/nix/pkg/wrapper.nix +++ b/nix/pkg/wrapper.nix @@ -15,6 +15,7 @@ openal, jdk8, jdk17, + jdk21, gamemode, flite, mesa-demos, @@ -24,7 +25,7 @@ gamemodeSupport ? stdenv.isLinux, textToSpeechSupport ? stdenv.isLinux, controllerSupport ? stdenv.isLinux, - jdks ? [jdk17 jdk8], + jdks ? [jdk21 jdk17 jdk8], additionalLibs ? [], additionalPrograms ? [], }: let From 8ecab305ac67afb70a278d286df13cc85134dec2 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 4 Apr 2024 13:49:27 +0300 Subject: [PATCH 165/223] Moved the creation of natives folder in ExtractNatives task Signed-off-by: Trial97 --- launcher/minecraft/launch/ExtractNatives.cpp | 1 + launcher/minecraft/launch/ExtractNatives.h | 2 -- .../minecraft/launch/LauncherPartLaunch.cpp | 36 ++++++------------- 3 files changed, 12 insertions(+), 27 deletions(-) diff --git a/launcher/minecraft/launch/ExtractNatives.cpp b/launcher/minecraft/launch/ExtractNatives.cpp index 8f3cac4d1..405008f40 100644 --- a/launcher/minecraft/launch/ExtractNatives.cpp +++ b/launcher/minecraft/launch/ExtractNatives.cpp @@ -79,6 +79,7 @@ void ExtractNatives::executeTask() auto settings = minecraftInstance->settings(); auto outputPath = minecraftInstance->getNativePath(); + FS::ensureFolderPathExists(outputPath); auto javaVersion = minecraftInstance->getJavaVersion(); bool jniHackEnabled = javaVersion.major() >= 8; for (const auto& source : toExtract) { diff --git a/launcher/minecraft/launch/ExtractNatives.h b/launcher/minecraft/launch/ExtractNatives.h index 2ab8816bd..4837a9dbb 100644 --- a/launcher/minecraft/launch/ExtractNatives.h +++ b/launcher/minecraft/launch/ExtractNatives.h @@ -16,8 +16,6 @@ #pragma once #include -#include -#include "minecraft/auth/AuthSession.h" // FIXME: temporary wrapper for existing task. class ExtractNatives : public LaunchStep { diff --git a/launcher/minecraft/launch/LauncherPartLaunch.cpp b/launcher/minecraft/launch/LauncherPartLaunch.cpp index dcfb3d148..3662f2bb6 100644 --- a/launcher/minecraft/launch/LauncherPartLaunch.cpp +++ b/launcher/minecraft/launch/LauncherPartLaunch.cpp @@ -88,20 +88,15 @@ QString shortPathName(const QString& file) return ret; } -QString getShortPathName(const QString& file) +QString getPathNameInLocal8bit(const QString& file) { - auto path = shortPathName(file); - if (!path.isEmpty()) - return path; - // the path can not be getted due to the file/folder not existing - // so create the parrent folder - // and assume that we can concatenate the short path of the parent folder with the file name - // usually the 8 bit characters are in the instance name not in the name of the end files/folders we need - FS::ensureFilePathExists(file); - QFileInfo a(file); - auto partialShortPath = shortPathName(a.path()); - if (!partialShortPath.isEmpty()) - return FS::PathCombine(partialShortPath, a.fileName()); + if (!fitsInLocal8bit(file)) { + auto path = shortPathName(file); + if (!path.isEmpty()) { + return path; + } + // in case shortPathName fails just return the path as is + } return file; } #endif @@ -156,24 +151,15 @@ void LauncherPartLaunch::executeTask() auto natPath = minecraftInstance->getNativePath(); #ifdef Q_OS_WIN - if (!fitsInLocal8bit(natPath)) { - args << "-Djava.library.path=" + getShortPathName(natPath); - } else { - args << "-Djava.library.path=" + natPath; - } -#else - args << "-Djava.library.path=" + natPath; + natPath = getPathNameInLocal8bit(natPath); #endif + args << "-Djava.library.path=" + natPath; args << "-cp"; #ifdef Q_OS_WIN QStringList processed; for (auto& item : classPath) { - if (!fitsInLocal8bit(item)) { - processed << getShortPathName(item); - } else { - processed << item; - } + processed << getPathNameInLocal8bit(item); } args << processed.join(';'); #else From 3ddcadcdd1f72f8135333986e55cf583204da1e2 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 4 Apr 2024 18:01:24 +0300 Subject: [PATCH 166/223] Moved getPathNameInLocal8bit inside FileSystem namespace Signed-off-by: Trial97 --- launcher/FileSystem.cpp | 40 +++++++++++++++++ launcher/FileSystem.h | 4 ++ launcher/InstanceImportTask.h | 4 -- launcher/java/JavaChecker.cpp | 3 ++ .../minecraft/launch/LauncherPartLaunch.cpp | 45 +------------------ 5 files changed, 49 insertions(+), 47 deletions(-) diff --git a/launcher/FileSystem.cpp b/launcher/FileSystem.cpp index f9be91a2a..31c1c0fc6 100644 --- a/launcher/FileSystem.cpp +++ b/launcher/FileSystem.cpp @@ -1585,4 +1585,44 @@ uintmax_t hardLinkCount(const QString& path) return count; } +#ifdef Q_OS_WIN +// returns 8.3 file format from long path +QString shortPathName(const QString& file) +{ + auto input = file.toStdWString(); + std::wstring output; + long length = GetShortPathNameW(input.c_str(), NULL, 0); + if (length == 0) + return {}; + // NOTE: this resizing might seem weird... + // when GetShortPathNameW fails, it returns length including null character + // when it succeeds, it returns length excluding null character + // See: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364989(v=vs.85).aspx + output.resize(length); + if (GetShortPathNameW(input.c_str(), (LPWSTR)output.c_str(), length) == 0) + return {}; + output.resize(length - 1); + QString ret = QString::fromStdWString(output); + return ret; +} + +// if the string survives roundtrip through local 8bit encoding... +bool fitsInLocal8bit(const QString& string) +{ + return string == QString::fromLocal8Bit(string.toLocal8Bit()); +} + +QString getPathNameInLocal8bit(const QString& file) +{ + if (!fitsInLocal8bit(file)) { + auto path = shortPathName(file); + if (!path.isEmpty()) { + return path; + } + // in case shortPathName fails just return the path as is + } + return file; +} +#endif + } // namespace FS diff --git a/launcher/FileSystem.h b/launcher/FileSystem.h index f13fb9f28..428507ff7 100644 --- a/launcher/FileSystem.h +++ b/launcher/FileSystem.h @@ -551,4 +551,8 @@ bool canLink(const QString& src, const QString& dst); uintmax_t hardLinkCount(const QString& path); +#ifdef Q_OS_WIN +QString getPathNameInLocal8bit(const QString& file); +#endif + } // namespace FS diff --git a/launcher/InstanceImportTask.h b/launcher/InstanceImportTask.h index a1cf2560b..28efd7ec5 100644 --- a/launcher/InstanceImportTask.h +++ b/launcher/InstanceImportTask.h @@ -47,9 +47,6 @@ #include class QuaZip; -namespace Flame { -class FileResolvingTask; -} class InstanceImportTask : public InstanceTask { Q_OBJECT @@ -79,7 +76,6 @@ class InstanceImportTask : public InstanceTask { private: /* data */ NetJob::Ptr m_filesNetJob; - shared_qobject_ptr m_modIdResolver; QUrl m_sourceUrl; QString m_archivePath; bool m_downloadRequired = false; diff --git a/launcher/java/JavaChecker.cpp b/launcher/java/JavaChecker.cpp index 20caba189..fc8da55c2 100644 --- a/launcher/java/JavaChecker.cpp +++ b/launcher/java/JavaChecker.cpp @@ -55,6 +55,9 @@ void JavaChecker::performCheck() qDebug() << "Java checker library could not be found. Please check your installation."; return; } +#ifdef Q_OS_WIN + checkerJar = FS::getPathNameInLocal8bit(checkerJar); +#endif QStringList args; diff --git a/launcher/minecraft/launch/LauncherPartLaunch.cpp b/launcher/minecraft/launch/LauncherPartLaunch.cpp index 3662f2bb6..4e021c4a8 100644 --- a/launcher/minecraft/launch/LauncherPartLaunch.cpp +++ b/launcher/minecraft/launch/LauncherPartLaunch.cpp @@ -66,47 +66,6 @@ LauncherPartLaunch::LauncherPartLaunch(LaunchTask* parent) : LaunchStep(parent) connect(&m_process, &LoggedProcess::stateChanged, this, &LauncherPartLaunch::on_state); } -#ifdef Q_OS_WIN -// returns 8.3 file format from long path -#include -QString shortPathName(const QString& file) -{ - auto input = file.toStdWString(); - std::wstring output; - long length = GetShortPathNameW(input.c_str(), NULL, 0); - if (length == 0) - return {}; - // NOTE: this resizing might seem weird... - // when GetShortPathNameW fails, it returns length including null character - // when it succeeds, it returns length excluding null character - // See: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364989(v=vs.85).aspx - output.resize(length); - if (GetShortPathNameW(input.c_str(), (LPWSTR)output.c_str(), length) == 0) - return {}; - output.resize(length - 1); - QString ret = QString::fromStdWString(output); - return ret; -} - -QString getPathNameInLocal8bit(const QString& file) -{ - if (!fitsInLocal8bit(file)) { - auto path = shortPathName(file); - if (!path.isEmpty()) { - return path; - } - // in case shortPathName fails just return the path as is - } - return file; -} -#endif - -// if the string survives roundtrip through local 8bit encoding... -bool fitsInLocal8bit(const QString& string) -{ - return string == QString::fromLocal8Bit(string.toLocal8Bit()); -} - void LauncherPartLaunch::executeTask() { QString jarPath = APPLICATION->getJarPath("NewLaunch.jar"); @@ -151,7 +110,7 @@ void LauncherPartLaunch::executeTask() auto natPath = minecraftInstance->getNativePath(); #ifdef Q_OS_WIN - natPath = getPathNameInLocal8bit(natPath); + natPath = FS::getPathNameInLocal8bit(natPath); #endif args << "-Djava.library.path=" + natPath; @@ -159,7 +118,7 @@ void LauncherPartLaunch::executeTask() #ifdef Q_OS_WIN QStringList processed; for (auto& item : classPath) { - processed << getPathNameInLocal8bit(item); + processed << FS::getPathNameInLocal8bit(item); } args << processed.join(';'); #else From e704fbbcec4268e2ff41db7f851ddd3e961eb8b9 Mon Sep 17 00:00:00 2001 From: DioEgizio <83089242+DioEgizio@users.noreply.github.com> Date: Thu, 4 Apr 2024 17:53:30 +0200 Subject: [PATCH 167/223] fix: update flatpak manifest for java 21 backport of https://github.com/flathub/org.prismlauncher.PrismLauncher/pull/54 for our CI builds Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com> --- flatpak/org.prismlauncher.PrismLauncher.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/flatpak/org.prismlauncher.PrismLauncher.yml b/flatpak/org.prismlauncher.PrismLauncher.yml index c3ac132b1..b4c6e8143 100644 --- a/flatpak/org.prismlauncher.PrismLauncher.yml +++ b/flatpak/org.prismlauncher.PrismLauncher.yml @@ -3,6 +3,7 @@ runtime: org.kde.Platform runtime-version: 5.15-23.08 sdk: org.kde.Sdk sdk-extensions: + - org.freedesktop.Sdk.Extension.openjdk21 - org.freedesktop.Sdk.Extension.openjdk17 - org.freedesktop.Sdk.Extension.openjdk8 @@ -50,6 +51,8 @@ modules: buildsystem: simple build-commands: - mkdir -p /app/jdk/ + - /usr/lib/sdk/openjdk21/install.sh + - mv /app/jre /app/jdk/21 - /usr/lib/sdk/openjdk17/install.sh - mv /app/jre /app/jdk/17 - /usr/lib/sdk/openjdk8/install.sh From 8056a2fa460b11739b080d96deda35cd8897c40c Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Fri, 5 Apr 2024 23:12:31 +0100 Subject: [PATCH 168/223] Replace invalid characters when extracting ZIP Signed-off-by: TheKodeToad --- launcher/FileSystem.cpp | 19 ++++++++++++++----- launcher/FileSystem.h | 2 ++ launcher/MMCZip.cpp | 5 ++++- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/launcher/FileSystem.cpp b/launcher/FileSystem.cpp index f9be91a2a..7bfa24de9 100644 --- a/launcher/FileSystem.cpp +++ b/launcher/FileSystem.cpp @@ -801,15 +801,24 @@ QString NormalizePath(QString path) } } -QString badFilenameChars = "\"\\/?<>:;*|!+\r\n"; +static const QString BAD_PATH_CHARS = "\"?<>:;*|!+\r\n"; +static const QString BAD_FILENAME_CHARS = BAD_PATH_CHARS + "\\/"; QString RemoveInvalidFilenameChars(QString string, QChar replaceWith) { - for (int i = 0; i < string.length(); i++) { - if (badFilenameChars.contains(string[i])) { + for (int i = 0; i < string.length(); i++) + if (string.at(i).toLatin1() < ' ' || BAD_FILENAME_CHARS.contains(string.at(i))) string[i] = replaceWith; - } - } + + return string; +} + +QString RemoveInvalidPathChars(QString string, QChar replaceWith) +{ + for (int i = 0; i < string.length(); i++) + if (string.at(i) < ' ' || BAD_PATH_CHARS.contains(string.at(i))) + string[i] = replaceWith; + return string; } diff --git a/launcher/FileSystem.h b/launcher/FileSystem.h index f13fb9f28..1c9ba2672 100644 --- a/launcher/FileSystem.h +++ b/launcher/FileSystem.h @@ -342,6 +342,8 @@ QString NormalizePath(QString path); QString RemoveInvalidFilenameChars(QString string, QChar replaceWith = '-'); +QString RemoveInvalidPathChars(QString string, QChar replaceWith = '-'); + QString DirNameFromString(QString string, QString inDir = "."); /// Checks if the a given Path contains "!" diff --git a/launcher/MMCZip.cpp b/launcher/MMCZip.cpp index 033aa0755..6f7c83952 100644 --- a/launcher/MMCZip.cpp +++ b/launcher/MMCZip.cpp @@ -286,10 +286,13 @@ std::optional extractSubDir(QuaZip* zip, const QString& subdir, con do { QString file_name = zip->getCurrentFileName(); +#ifdef Q_OS_WIN + file_name = FS::RemoveInvalidPathChars(file_name); +#endif if (!file_name.startsWith(subdir)) continue; - auto relative_file_name = QDir::fromNativeSeparators(file_name.remove(0, subdir.size())); + auto relative_file_name = QDir::fromNativeSeparators(file_name.mid(subdir.size())); auto original_name = relative_file_name; // Fix subdirs/files ending with a / getting transformed into absolute paths From 9986fe4c45be7f3ce22fdce64812677f16cf7b4c Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sat, 6 Apr 2024 13:28:42 +0100 Subject: [PATCH 169/223] Fix unicode characters being invalid in filenames Signed-off-by: TheKodeToad --- launcher/FileSystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/FileSystem.cpp b/launcher/FileSystem.cpp index 7bfa24de9..93e001f64 100644 --- a/launcher/FileSystem.cpp +++ b/launcher/FileSystem.cpp @@ -807,7 +807,7 @@ static const QString BAD_FILENAME_CHARS = BAD_PATH_CHARS + "\\/"; QString RemoveInvalidFilenameChars(QString string, QChar replaceWith) { for (int i = 0; i < string.length(); i++) - if (string.at(i).toLatin1() < ' ' || BAD_FILENAME_CHARS.contains(string.at(i))) + if (string.at(i) < ' ' || BAD_FILENAME_CHARS.contains(string.at(i))) string[i] = replaceWith; return string; From 74fcfbae3219612e8715e6fcb21194b78f951389 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 7 Apr 2024 00:20:19 +0000 Subject: [PATCH 170/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'flake-parts': 'github:hercules-ci/flake-parts/f7b3c975cf067e56e7cda6cb098ebe3fb4d74ca2' (2024-03-01) → 'github:hercules-ci/flake-parts/9126214d0a59633752a136528f5f3b9aa8565b7d' (2024-04-01) • Updated input 'nixpkgs': 'github:nixos/nixpkgs/807c549feabce7eddbf259dbdcec9e0600a0660d' (2024-03-29) → 'github:nixos/nixpkgs/9e7f26f82acb057498335362905fde6fea4ca50a' (2024-04-06) • Updated input 'pre-commit-hooks': 'github:cachix/pre-commit-hooks.nix/c11e43aed6f17336c25cd120eac886b96c455731' (2024-03-30) → 'github:cachix/pre-commit-hooks.nix/e35aed5fda3cc79f88ed7f1795021e559582093a' (2024-04-02) --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index dcc028b2d..b84278d0e 100644 --- a/flake.lock +++ b/flake.lock @@ -23,11 +23,11 @@ ] }, "locked": { - "lastModified": 1709336216, - "narHash": "sha256-Dt/wOWeW6Sqm11Yh+2+t0dfEWxoMxGBvv3JpIocFl9E=", + "lastModified": 1712014858, + "narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "f7b3c975cf067e56e7cda6cb098ebe3fb4d74ca2", + "rev": "9126214d0a59633752a136528f5f3b9aa8565b7d", "type": "github" }, "original": { @@ -93,11 +93,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1711715736, - "narHash": "sha256-9slQ609YqT9bT/MNX9+5k5jltL9zgpn36DpFB7TkttM=", + "lastModified": 1712420723, + "narHash": "sha256-VnG0Eu394Ga2FCe8Q66m6OEQF8iAqjDYsjmtl+N2omk=", "owner": "nixos", "repo": "nixpkgs", - "rev": "807c549feabce7eddbf259dbdcec9e0600a0660d", + "rev": "9e7f26f82acb057498335362905fde6fea4ca50a", "type": "github" }, "original": { @@ -122,11 +122,11 @@ ] }, "locked": { - "lastModified": 1711760932, - "narHash": "sha256-DqUTQ2iAAqSDwMhKBqvi24v0Oc7pD3LCK/0FCG//TdA=", + "lastModified": 1712055707, + "narHash": "sha256-4XLvuSIDZJGS17xEwSrNuJLL7UjDYKGJSbK1WWX2AK8=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "c11e43aed6f17336c25cd120eac886b96c455731", + "rev": "e35aed5fda3cc79f88ed7f1795021e559582093a", "type": "github" }, "original": { From 9cc58fe62c776dd206bb6dd99c886ce491662214 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 7 Apr 2024 21:25:08 +0300 Subject: [PATCH 171/223] Fixed crash on invalid curseforge link on import Signed-off-by: Trial97 --- launcher/ui/pages/modplatform/ImportPage.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/launcher/ui/pages/modplatform/ImportPage.cpp b/launcher/ui/pages/modplatform/ImportPage.cpp index ae4bd49d7..ed7ebfad9 100644 --- a/launcher/ui/pages/modplatform/ImportPage.cpp +++ b/launcher/ui/pages/modplatform/ImportPage.cpp @@ -123,6 +123,10 @@ void ImportPage::updateState() // need to find the download link for the modpack // format of url curseforge://install?addonId=IDHERE&fileId=IDHERE QUrlQuery query(url); + if (query.allQueryItemValues("addonId").isEmpty() || query.allQueryItemValues("fileId").isEmpty()) { + qDebug() << "Invalid curseforge link:" << url; + return; + } auto addonId = query.allQueryItemValues("addonId")[0]; auto fileId = query.allQueryItemValues("fileId")[0]; auto array = std::make_shared(); From f91f97e56dd27fe4fb355a800e853c782f92baa6 Mon Sep 17 00:00:00 2001 From: ColonelGerdauf Date: Sun, 7 Apr 2024 16:49:39 -0400 Subject: [PATCH 172/223] Renaming and removing redundancies old's do not make sense here Signed-off-by: ColonelGerdauf --- launcher/ui/pages/modplatform/CustomPage.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/launcher/ui/pages/modplatform/CustomPage.cpp b/launcher/ui/pages/modplatform/CustomPage.cpp index 068fb3a36..d2b73008d 100644 --- a/launcher/ui/pages/modplatform/CustomPage.cpp +++ b/launcher/ui/pages/modplatform/CustomPage.cpp @@ -55,7 +55,6 @@ CustomPage::CustomPage(NewInstanceDialog* dialog, QWidget* parent) : QWidget(par connect(ui->alphaFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged); connect(ui->betaFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged); connect(ui->snapshotFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged); - connect(ui->oldSnapshotFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged); connect(ui->releaseFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged); connect(ui->experimentsFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged); connect(ui->refreshBtn, &QPushButton::clicked, this, &CustomPage::refresh); @@ -96,13 +95,11 @@ void CustomPage::filterChanged() { QStringList out; if (ui->alphaFilter->isChecked()) - out << "(old_alpha)"; + out << "(alpha)"; if (ui->betaFilter->isChecked()) - out << "(old_beta)"; + out << "(beta)"; if (ui->snapshotFilter->isChecked()) out << "(snapshot)"; - if (ui->oldSnapshotFilter->isChecked()) - out << "(old_snapshot)"; if (ui->releaseFilter->isChecked()) out << "(release)"; if (ui->experimentsFilter->isChecked()) From a877f9146de17a09b4803f6241f675d9a2ba739c Mon Sep 17 00:00:00 2001 From: ColonelGerdauf Date: Sun, 7 Apr 2024 16:53:53 -0400 Subject: [PATCH 173/223] Change of parameters To help deal with adjustments Signed-off-by: ColonelGerdauf --- launcher/ui/pages/modplatform/CustomPage.ui | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/launcher/ui/pages/modplatform/CustomPage.ui b/launcher/ui/pages/modplatform/CustomPage.ui index 23351ccd4..fda3e8a2e 100644 --- a/launcher/ui/pages/modplatform/CustomPage.ui +++ b/launcher/ui/pages/modplatform/CustomPage.ui @@ -93,16 +93,6 @@ - - - - Old Snapshots - - - true - - - @@ -286,7 +276,6 @@ tabWidget releaseFilter snapshotFilter - oldSnapshotFilter betaFilter alphaFilter experimentsFilter From 9f48694eb2be5f62efb122b554c7066e49f3383d Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 9 Apr 2024 08:28:09 +0300 Subject: [PATCH 174/223] Fixed application close on open file dialog Signed-off-by: Trial97 --- launcher/Application.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 9f54e7dd9..bb8751ccc 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -225,6 +225,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) // Don't quit on hiding the last window this->setQuitOnLastWindowClosed(false); + this->setQuitLockEnabled(false); // Commandline parsing QCommandLineParser parser; From 8121a6536bda27221123842b11f118851904fe5e Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 12 Apr 2024 23:45:31 +0300 Subject: [PATCH 175/223] Fixed pack update Signed-off-by: Trial97 --- .../modplatform/modrinth/ModrinthInstanceCreationTask.cpp | 6 ++++-- .../modplatform/modrinth/ModrinthInstanceCreationTask.h | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp index 824fdce7e..a688cea87 100644 --- a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp +++ b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp @@ -20,6 +20,7 @@ #include "ui/pages/modplatform/OptionalModDialog.h" #include +#include #include bool ModrinthCreationTask::abort() @@ -58,6 +59,7 @@ bool ModrinthCreationTask::updateInstance() return false; auto version_name = inst->getManagedPackVersionName(); + m_root_path = QFileInfo(inst->gameRoot()).fileName(); auto version_str = !version_name.isEmpty() ? tr(" (version %1)").arg(version_name) : ""; if (shouldConfirmUpdate()) { @@ -173,7 +175,7 @@ bool ModrinthCreationTask::createInstance() FS::ensureFilePathExists(new_index_place); QFile::rename(index_path, new_index_place); - auto mcPath = FS::PathCombine(m_stagingPath, "minecraft"); + auto mcPath = FS::PathCombine(m_stagingPath, m_root_path); auto override_path = FS::PathCombine(m_stagingPath, "overrides"); if (QFile::exists(override_path)) { @@ -234,7 +236,7 @@ bool ModrinthCreationTask::createInstance() m_files_job.reset(new NetJob(tr("Mod Download Modrinth"), APPLICATION->network())); - auto root_modpack_path = FS::PathCombine(m_stagingPath, "minecraft"); + auto root_modpack_path = FS::PathCombine(m_stagingPath, m_root_path); auto root_modpack_url = QUrl::fromLocalFile(root_modpack_path); for (auto file : m_files) { diff --git a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.h b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.h index 1bd5b7de9..f07734a58 100644 --- a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.h +++ b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.h @@ -46,4 +46,6 @@ class ModrinthCreationTask final : public InstanceCreationTask { NetJob::Ptr m_files_job; std::optional m_instance; + + QString m_root_path = "minecraft"; }; From cb8936ed68ca8c05017f9827dcdcbd49a97c58ad Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 14 Apr 2024 00:21:24 +0000 Subject: [PATCH 176/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'nixpkgs': 'github:nixos/nixpkgs/9e7f26f82acb057498335362905fde6fea4ca50a' (2024-04-06) → 'github:nixos/nixpkgs/a0c9e3aee1000ac2bfb0e5b98c94c946a5d180a9' (2024-04-12) • Updated input 'pre-commit-hooks': 'github:cachix/pre-commit-hooks.nix/e35aed5fda3cc79f88ed7f1795021e559582093a' (2024-04-02) → 'github:cachix/pre-commit-hooks.nix/40e6053ecb65fcbf12863338a6dcefb3f55f1bf8' (2024-04-12) --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index b84278d0e..408c26cbd 100644 --- a/flake.lock +++ b/flake.lock @@ -93,11 +93,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1712420723, - "narHash": "sha256-VnG0Eu394Ga2FCe8Q66m6OEQF8iAqjDYsjmtl+N2omk=", + "lastModified": 1712883908, + "narHash": "sha256-icE1IJE9fHcbDfJ0+qWoDdcBXUoZCcIJxME4lMHwvSM=", "owner": "nixos", "repo": "nixpkgs", - "rev": "9e7f26f82acb057498335362905fde6fea4ca50a", + "rev": "a0c9e3aee1000ac2bfb0e5b98c94c946a5d180a9", "type": "github" }, "original": { @@ -122,11 +122,11 @@ ] }, "locked": { - "lastModified": 1712055707, - "narHash": "sha256-4XLvuSIDZJGS17xEwSrNuJLL7UjDYKGJSbK1WWX2AK8=", + "lastModified": 1712897695, + "narHash": "sha256-nMirxrGteNAl9sWiOhoN5tIHyjBbVi5e2tgZUgZlK3Y=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "e35aed5fda3cc79f88ed7f1795021e559582093a", + "rev": "40e6053ecb65fcbf12863338a6dcefb3f55f1bf8", "type": "github" }, "original": { From 77aead6470acfc0eab53321e64b3f35b1c7885ee Mon Sep 17 00:00:00 2001 From: DylanJOrr Date: Tue, 16 Apr 2024 15:51:18 -0400 Subject: [PATCH 177/223] Rename object name "userInterfaceTab" from "generalTab" The "User Interface" tab was innacurately named "General" which I just went in and fixed. This also renamed the object for respective vertical spacers. Signed-off-by: SolidStateDj --- launcher/ui/pages/global/LauncherPage.ui | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/launcher/ui/pages/global/LauncherPage.ui b/launcher/ui/pages/global/LauncherPage.ui index 18b52e1b8..928ec8103 100644 --- a/launcher/ui/pages/global/LauncherPage.ui +++ b/launcher/ui/pages/global/LauncherPage.ui @@ -237,7 +237,7 @@ - + Qt::Vertical @@ -251,7 +251,7 @@ - + User Interface @@ -374,7 +374,7 @@ - + Qt::Vertical From 252406ba3e793b4b096ed1e7bde43c2d2a9c2eca Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Fri, 19 Apr 2024 21:19:36 +0100 Subject: [PATCH 178/223] Support neoforge.mods.toml Signed-off-by: TheKodeToad --- launcher/minecraft/mod/tasks/LocalModParseTask.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp index e9e12d86a..3982f3338 100644 --- a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp @@ -469,7 +469,7 @@ bool processZIP(Mod& mod, [[maybe_unused]] ProcessingLevel level) QuaZipFile file(&zip); - if (zip.setCurrentFile("META-INF/mods.toml")) { + if (zip.setCurrentFile("META-INF/mods.toml") || zip.setCurrentFile("META-INF/neoforge.mods.toml")) { if (!file.open(QIODevice::ReadOnly)) { zip.close(); return false; From 210841606c72644e427e49921868982155d77622 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 21 Apr 2024 00:19:37 +0000 Subject: [PATCH 179/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'nixpkgs': 'github:nixos/nixpkgs/a0c9e3aee1000ac2bfb0e5b98c94c946a5d180a9' (2024-04-12) → 'github:nixos/nixpkgs/fd16bb6d3bcca96039b11aa52038fafeb6e4f4be' (2024-04-20) --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 408c26cbd..0fbfca9cc 100644 --- a/flake.lock +++ b/flake.lock @@ -93,11 +93,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1712883908, - "narHash": "sha256-icE1IJE9fHcbDfJ0+qWoDdcBXUoZCcIJxME4lMHwvSM=", + "lastModified": 1713596654, + "narHash": "sha256-LJbHQQ5aX1LVth2ST+Kkse/DRzgxlVhTL1rxthvyhZc=", "owner": "nixos", "repo": "nixpkgs", - "rev": "a0c9e3aee1000ac2bfb0e5b98c94c946a5d180a9", + "rev": "fd16bb6d3bcca96039b11aa52038fafeb6e4f4be", "type": "github" }, "original": { From 9f4654ede91a81a3d1099c949164690e295995a4 Mon Sep 17 00:00:00 2001 From: William Gray Date: Sun, 21 Apr 2024 03:35:27 -0500 Subject: [PATCH 180/223] Update JavaUtils.cpp Signed-off-by: William Gray --- launcher/java/JavaUtils.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/launcher/java/JavaUtils.cpp b/launcher/java/JavaUtils.cpp index 074bf54df..639eaf4e7 100644 --- a/launcher/java/JavaUtils.cpp +++ b/launcher/java/JavaUtils.cpp @@ -413,6 +413,8 @@ QList JavaUtils::FindJavaPaths() scanJavaDirs(FS::PathCombine(home, ".jdks")); // javas downloaded by sdkman scanJavaDirs(FS::PathCombine(home, ".sdkman/candidates/java")); + // javas downloaded by gradle (toolchains) + scanJavaDirs(FS::PathCombine(home, ".gradle/jdks")); javas.append(getMinecraftJavaBundle()); javas = addJavasFromEnv(javas); From a96f957b020355f51975ecdaa0486febd997ccf3 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 21 Apr 2024 14:48:27 +0300 Subject: [PATCH 181/223] Removed java from appimage Signed-off-by: Trial97 --- .github/scripts/prepare_JREs.sh | 41 --------------------------------- .github/workflows/build.yml | 10 -------- 2 files changed, 51 deletions(-) delete mode 100755 .github/scripts/prepare_JREs.sh diff --git a/.github/scripts/prepare_JREs.sh b/.github/scripts/prepare_JREs.sh deleted file mode 100755 index ee713f81f..000000000 --- a/.github/scripts/prepare_JREs.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash - -URL_JDK8="https://api.adoptium.net/v3/binary/version/jdk8u312-b07/linux/x64/jre/hotspot/normal/eclipse" -URL_JDK17="https://api.adoptium.net/v3/binary/latest/17/ga/linux/x64/jre/hotspot/normal/eclipse" - -mkdir -p JREs -pushd JREs - -wget --content-disposition "$URL_JDK8" -wget --content-disposition "$URL_JDK17" - -for file in *; -do - mkdir temp - - re='(OpenJDK([[:digit:]]+)U-jre_x64_linux_hotspot_([[:digit:]]+)(.*).tar.gz)' - if [[ $file =~ $re ]]; - then - version_major=${BASH_REMATCH[2]} - version_trailing=${BASH_REMATCH[4]} - - if [ $version_major = 17 ]; - then - hyphen='-' - else - hyphen='' - fi - - version_edit=$(echo $version_trailing | sed -e 's/_/+/g' | sed -e 's/b/-b/g') - dir_name=jdk$hyphen$version_major$version_edit-jre - mkdir jre$version_major - tar -xzf $file -C temp - pushd temp/$dir_name - cp -r . ../../jre$version_major - popd - fi - - rm -rf temp -done - -popd diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 44779386f..bc8129fba 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -259,7 +259,6 @@ jobs: wget "https://github.com/AppImageCommunity/AppImageUpdate/releases/download/continuous/AppImageUpdate-x86_64.AppImage" - ${{ github.workspace }}/.github/scripts/prepare_JREs.sh sudo apt install libopengl0 - name: Add QT_HOST_PATH var (Windows MSVC arm64) @@ -528,13 +527,8 @@ jobs: chmod +x linuxdeploy-*.AppImage - mkdir -p ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-{8,17}-openjdk mkdir -p ${{ env.INSTALL_APPIMAGE_DIR }}/usr/plugins/iconengines - cp -r ${{ github.workspace }}/JREs/jre8/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-8-openjdk - - cp -r ${{ github.workspace }}/JREs/jre17/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-17-openjdk - cp -r ${{ runner.workspace }}/Qt/${{ matrix.qt_version }}/gcc_64/plugins/iconengines/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/plugins/iconengines cp /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/ @@ -542,10 +536,6 @@ jobs: cp /usr/lib/x86_64-linux-gnu/libOpenGL.so.0* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/ LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib" - LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-8-openjdk/lib/amd64/server" - LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-8-openjdk/lib/amd64" - LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-17-openjdk/lib/server" - LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-17-openjdk/lib" export LD_LIBRARY_PATH chmod +x AppImageUpdate-x86_64.AppImage From 1c8d333bfd93bcafe5514f024adaf1236d1aed26 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 21 Apr 2024 15:07:10 +0300 Subject: [PATCH 182/223] Fixed build Signed-off-by: Trial97 --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bc8129fba..f3896550f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -527,6 +527,7 @@ jobs: chmod +x linuxdeploy-*.AppImage + mkdir -p ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib mkdir -p ${{ env.INSTALL_APPIMAGE_DIR }}/usr/plugins/iconengines cp -r ${{ runner.workspace }}/Qt/${{ matrix.qt_version }}/gcc_64/plugins/iconengines/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/plugins/iconengines From dbfd535b38d799a773b3843709bbeae7f5a9e7d3 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 23 Apr 2024 08:52:17 +0300 Subject: [PATCH 183/223] Fix bundled java detection on mac Signed-off-by: Trial97 --- launcher/java/JavaUtils.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/launcher/java/JavaUtils.cpp b/launcher/java/JavaUtils.cpp index 639eaf4e7..35d9ec610 100644 --- a/launcher/java/JavaUtils.cpp +++ b/launcher/java/JavaUtils.cpp @@ -441,13 +441,13 @@ QString JavaUtils::getJavaCheckPath() QStringList getMinecraftJavaBundle() { - QString partialPath; QString executable = "java"; QStringList processpaths; #if defined(Q_OS_OSX) - partialPath = FS::PathCombine(QDir::homePath(), "Library/Application Support"); + processpaths << FS::PathCombine(QDir::homePath(), FS::PathCombine("Library", "Application Support", "minecraft", "runtime")); #elif defined(Q_OS_WIN32) - partialPath = QProcessEnvironment::systemEnvironment().value("LOCALAPPDATA", ""); + QString partialPath = QProcessEnvironment::systemEnvironment().value("LOCALAPPDATA", ""); + processpaths << FS::PathCombine(partialPath, ".minecraft", "runtime"); executable += "w.exe"; // add the microsoft store version of the launcher to the search. the current path is: @@ -457,10 +457,8 @@ QStringList getMinecraftJavaBundle() minecraftMSStorePath = FS::PathCombine(minecraftMSStorePath, "LocalCache", "Local", "runtime"); processpaths << minecraftMSStorePath; #else - partialPath = QDir::homePath(); + processpaths << FS::PathCombine(QDir::homePath(), ".minecraft", "runtime"); #endif - auto minecraftDataPath = FS::PathCombine(partialPath, ".minecraft", "runtime"); - processpaths << minecraftDataPath; QStringList javas; while (!processpaths.isEmpty()) { From dac70278462913b7c0191c56a04e62529d5c774b Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 23 Apr 2024 18:59:31 +0300 Subject: [PATCH 184/223] Fixed windows appdata path Signed-off-by: Trial97 --- launcher/java/JavaUtils.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/launcher/java/JavaUtils.cpp b/launcher/java/JavaUtils.cpp index 35d9ec610..d1d58b0cf 100644 --- a/launcher/java/JavaUtils.cpp +++ b/launcher/java/JavaUtils.cpp @@ -446,16 +446,16 @@ QStringList getMinecraftJavaBundle() #if defined(Q_OS_OSX) processpaths << FS::PathCombine(QDir::homePath(), FS::PathCombine("Library", "Application Support", "minecraft", "runtime")); #elif defined(Q_OS_WIN32) - QString partialPath = QProcessEnvironment::systemEnvironment().value("LOCALAPPDATA", ""); - processpaths << FS::PathCombine(partialPath, ".minecraft", "runtime"); + auto appDataPath = QProcessEnvironment::systemEnvironment().value("AppData", ""); + processpaths << FS::PathCombine(QFileInfo(appDataPath).absolutePath(), ".minecraft", "runtime"); executable += "w.exe"; // add the microsoft store version of the launcher to the search. the current path is: // C:\Users\USERNAME\AppData\Local\Packages\Microsoft.4297127D64EC6_8wekyb3d8bbwe\LocalCache\Local\runtime + auto localAppDataPath = QProcessEnvironment::systemEnvironment().value("LOCALAPPDATA", ""); auto minecraftMSStorePath = - FS::PathCombine(QFileInfo(partialPath).absolutePath(), "Local", "Packages", "Microsoft.4297127D64EC6_8wekyb3d8bbwe"); - minecraftMSStorePath = FS::PathCombine(minecraftMSStorePath, "LocalCache", "Local", "runtime"); - processpaths << minecraftMSStorePath; + FS::PathCombine(QFileInfo(localAppDataPath).absolutePath(), "Local", "Packages", "Microsoft.4297127D64EC6_8wekyb3d8bbwe"); + processpaths << FS::PathCombine(minecraftMSStorePath, "LocalCache", "Local", "runtime"); #else processpaths << FS::PathCombine(QDir::homePath(), ".minecraft", "runtime"); #endif From 73c3794c1bfa9d3cd01339039ad8597971b5fb53 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 23 Apr 2024 19:03:19 +0300 Subject: [PATCH 185/223] Changed env variable Signed-off-by: Trial97 --- launcher/java/JavaUtils.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/launcher/java/JavaUtils.cpp b/launcher/java/JavaUtils.cpp index d1d58b0cf..c0bb39d72 100644 --- a/launcher/java/JavaUtils.cpp +++ b/launcher/java/JavaUtils.cpp @@ -446,10 +446,11 @@ QStringList getMinecraftJavaBundle() #if defined(Q_OS_OSX) processpaths << FS::PathCombine(QDir::homePath(), FS::PathCombine("Library", "Application Support", "minecraft", "runtime")); #elif defined(Q_OS_WIN32) - auto appDataPath = QProcessEnvironment::systemEnvironment().value("AppData", ""); - processpaths << FS::PathCombine(QFileInfo(appDataPath).absolutePath(), ".minecraft", "runtime"); executable += "w.exe"; + auto appDataPath = QProcessEnvironment::systemEnvironment().value("APPDATA", ""); + processpaths << FS::PathCombine(QFileInfo(appDataPath).absolutePath(), ".minecraft", "runtime"); + // add the microsoft store version of the launcher to the search. the current path is: // C:\Users\USERNAME\AppData\Local\Packages\Microsoft.4297127D64EC6_8wekyb3d8bbwe\LocalCache\Local\runtime auto localAppDataPath = QProcessEnvironment::systemEnvironment().value("LOCALAPPDATA", ""); From 10d1720da5c350250390fa8b38a5c4db6429462b Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 23 Apr 2024 19:08:14 +0300 Subject: [PATCH 186/223] Removed duplicate local Signed-off-by: Trial97 --- launcher/java/JavaUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/java/JavaUtils.cpp b/launcher/java/JavaUtils.cpp index c0bb39d72..b12461f44 100644 --- a/launcher/java/JavaUtils.cpp +++ b/launcher/java/JavaUtils.cpp @@ -455,7 +455,7 @@ QStringList getMinecraftJavaBundle() // C:\Users\USERNAME\AppData\Local\Packages\Microsoft.4297127D64EC6_8wekyb3d8bbwe\LocalCache\Local\runtime auto localAppDataPath = QProcessEnvironment::systemEnvironment().value("LOCALAPPDATA", ""); auto minecraftMSStorePath = - FS::PathCombine(QFileInfo(localAppDataPath).absolutePath(), "Local", "Packages", "Microsoft.4297127D64EC6_8wekyb3d8bbwe"); + FS::PathCombine(QFileInfo(localAppDataPath).absolutePath(), "Packages", "Microsoft.4297127D64EC6_8wekyb3d8bbwe"); processpaths << FS::PathCombine(minecraftMSStorePath, "LocalCache", "Local", "runtime"); #else processpaths << FS::PathCombine(QDir::homePath(), ".minecraft", "runtime"); From 5ae98f4f901200647ea3b4ff855248705f28fd3b Mon Sep 17 00:00:00 2001 From: Trial97 Date: Wed, 24 Apr 2024 15:49:05 +0300 Subject: [PATCH 187/223] Fixed windows bundled java path Signed-off-by: Trial97 --- launcher/java/JavaUtils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launcher/java/JavaUtils.cpp b/launcher/java/JavaUtils.cpp index b12461f44..3627cec39 100644 --- a/launcher/java/JavaUtils.cpp +++ b/launcher/java/JavaUtils.cpp @@ -449,13 +449,13 @@ QStringList getMinecraftJavaBundle() executable += "w.exe"; auto appDataPath = QProcessEnvironment::systemEnvironment().value("APPDATA", ""); - processpaths << FS::PathCombine(QFileInfo(appDataPath).absolutePath(), ".minecraft", "runtime"); + processpaths << FS::PathCombine(QFileInfo(appDataPath).absoluteFilePath(), ".minecraft", "runtime"); // add the microsoft store version of the launcher to the search. the current path is: // C:\Users\USERNAME\AppData\Local\Packages\Microsoft.4297127D64EC6_8wekyb3d8bbwe\LocalCache\Local\runtime auto localAppDataPath = QProcessEnvironment::systemEnvironment().value("LOCALAPPDATA", ""); auto minecraftMSStorePath = - FS::PathCombine(QFileInfo(localAppDataPath).absolutePath(), "Packages", "Microsoft.4297127D64EC6_8wekyb3d8bbwe"); + FS::PathCombine(QFileInfo(localAppDataPath).absoluteFilePath(), "Packages", "Microsoft.4297127D64EC6_8wekyb3d8bbwe"); processpaths << FS::PathCombine(minecraftMSStorePath, "LocalCache", "Local", "runtime"); #else processpaths << FS::PathCombine(QDir::homePath(), ".minecraft", "runtime"); From c902da446174840c38fee8c8ff20ab2b21699739 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Wed, 24 Apr 2024 22:02:55 +0300 Subject: [PATCH 188/223] Fix image width in project description Signed-off-by: Trial97 --- .../ui/widgets/VariableSizedImageObject.cpp | 67 +++++++++++++++---- .../ui/widgets/VariableSizedImageObject.h | 13 +++- 2 files changed, 66 insertions(+), 14 deletions(-) diff --git a/launcher/ui/widgets/VariableSizedImageObject.cpp b/launcher/ui/widgets/VariableSizedImageObject.cpp index cebf2a5f1..a4e0872cb 100644 --- a/launcher/ui/widgets/VariableSizedImageObject.cpp +++ b/launcher/ui/widgets/VariableSizedImageObject.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "Application.h" @@ -36,6 +37,30 @@ QSizeF VariableSizedImageObject::intrinsicSize(QTextDocument* doc, int posInDocu auto image = qvariant_cast(format.property(ImageData)); auto size = image.size(); + if (size.isEmpty()) // can't resize a empty image + return { size }; + + // calculate the new image size based on the properties + int width = 0; + int height = 0; + auto widthVar = format.property(QTextFormat::ImageWidth); + if (widthVar.isValid()) { + width = widthVar.toInt(); + } + auto heigthVar = format.property(QTextFormat::ImageHeight); + if (heigthVar.isValid()) { + height = heigthVar.toInt(); + } + if (width != 0 && height != 0) { + size.setWidth(width); + size.setHeight(height); + } else if (width != 0) { + size.setHeight((width * size.height()) / size.width()); + size.setWidth(width); + } else if (height != 0) { + size.setWidth((height * size.width()) / size.height()); + size.setHeight(height); + } // Get the width of the text content to make the image similar sized. // doc->textWidth() includes the margin, so we need to remove it. @@ -46,6 +71,7 @@ QSizeF VariableSizedImageObject::intrinsicSize(QTextDocument* doc, int posInDocu return { size }; } + void VariableSizedImageObject::drawObject(QPainter* painter, const QRectF& rect, QTextDocument* doc, @@ -57,7 +83,20 @@ void VariableSizedImageObject::drawObject(QPainter* painter, if (m_fetching_images.contains(image_url)) return; - loadImage(doc, image_url, posInDocument); + auto meta = std::make_shared(); + meta->posInDocument = posInDocument; + meta->url = image_url; + + auto widthVar = format.property(QTextFormat::ImageWidth); + if (widthVar.isValid()) { + meta->width = widthVar.toInt(); + } + auto heigthVar = format.property(QTextFormat::ImageHeight); + if (heigthVar.isValid()) { + meta->height = heigthVar.toInt(); + } + + loadImage(doc, meta); return; } @@ -72,16 +111,19 @@ void VariableSizedImageObject::flush() m_fetching_images.clear(); } -void VariableSizedImageObject::parseImage(QTextDocument* doc, QImage image, int posInDocument) +void VariableSizedImageObject::parseImage(QTextDocument* doc, std::shared_ptr meta) { QTextCursor cursor(doc); - cursor.setPosition(posInDocument); + cursor.setPosition(meta->posInDocument); cursor.setKeepPositionOnInsert(true); auto image_char_format = cursor.charFormat(); image_char_format.setObjectType(QTextFormat::ImageObject); - image_char_format.setProperty(ImageData, image); + image_char_format.setProperty(ImageData, meta->image); + image_char_format.setProperty(QTextFormat::ImageName, meta->url.toDisplayString()); + image_char_format.setProperty(QTextFormat::ImageWidth, meta->width); + image_char_format.setProperty(QTextFormat::ImageHeight, meta->height); // Qt doesn't allow us to modify the properties of an existing object in the document. // So we remove the old one and add the new one with the ImageData property set. @@ -89,23 +131,24 @@ void VariableSizedImageObject::parseImage(QTextDocument* doc, QImage image, int cursor.insertText(QString(QChar::ObjectReplacementCharacter), image_char_format); } -void VariableSizedImageObject::loadImage(QTextDocument* doc, const QUrl& source, int posInDocument) +void VariableSizedImageObject::loadImage(QTextDocument* doc, std::shared_ptr meta) { - m_fetching_images.insert(source); + m_fetching_images.insert(meta->url); MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry( m_meta_entry, - QString("images/%1").arg(QString(QCryptographicHash::hash(source.toEncoded(), QCryptographicHash::Algorithm::Sha1).toHex()))); + QString("images/%1").arg(QString(QCryptographicHash::hash(meta->url.toEncoded(), QCryptographicHash::Algorithm::Sha1).toHex()))); - auto job = new NetJob(QString("Load Image: %1").arg(source.fileName()), APPLICATION->network()); - job->addNetAction(Net::ApiDownload::makeCached(source, entry)); + auto job = new NetJob(QString("Load Image: %1").arg(meta->url.fileName()), APPLICATION->network()); + job->addNetAction(Net::ApiDownload::makeCached(meta->url, entry)); auto full_entry_path = entry->getFullPath(); - auto source_url = source; - auto loadImage = [this, doc, full_entry_path, source_url, posInDocument](const QImage& image) { + auto source_url = meta->url; + auto loadImage = [this, doc, full_entry_path, source_url, meta](const QImage& image) { doc->addResource(QTextDocument::ImageResource, source_url, image); - parseImage(doc, image, posInDocument); + meta->image = image; + parseImage(doc, meta); // This size hack is needed to prevent the content from being laid out in an area smaller // than the total width available (weird). diff --git a/launcher/ui/widgets/VariableSizedImageObject.h b/launcher/ui/widgets/VariableSizedImageObject.h index ca67af0c9..df3ab4f77 100644 --- a/launcher/ui/widgets/VariableSizedImageObject.h +++ b/launcher/ui/widgets/VariableSizedImageObject.h @@ -22,6 +22,7 @@ #include #include #include +#include /** Custom image text object to be used instead of the normal one in ProjectDescriptionPage. * @@ -32,6 +33,14 @@ class VariableSizedImageObject final : public QObject, public QTextObjectInterfa Q_OBJECT Q_INTERFACES(QTextObjectInterface) + struct ImageMetadata { + int posInDocument; + QUrl url; + QImage image; + int width; + int height; + }; + public: QSizeF intrinsicSize(QTextDocument* doc, int posInDocument, const QTextFormat& format) override; void drawObject(QPainter* painter, const QRectF& rect, QTextDocument* doc, int posInDocument, const QTextFormat& format) override; @@ -49,13 +58,13 @@ class VariableSizedImageObject final : public QObject, public QTextObjectInterfa private: /** Adds the image to the document, in the given position. */ - void parseImage(QTextDocument* doc, QImage image, int posInDocument); + void parseImage(QTextDocument* doc, std::shared_ptr meta); /** Loads an image from an external source, and adds it to the document. * * This uses m_meta_entry to cache the image. */ - void loadImage(QTextDocument* doc, const QUrl& source, int posInDocument); + void loadImage(QTextDocument* doc, std::shared_ptr meta); private: QString m_meta_entry; From a30c7193a2e0b90e16e866ec351beb5cf3b9f807 Mon Sep 17 00:00:00 2001 From: Jan200101 Date: Thu, 25 Apr 2024 16:55:15 +0200 Subject: [PATCH 189/223] remove server side decorations FIXME and document why its needed Signed-off-by: Jan200101 --- launcher/ui/MainWindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index 85573314d..6bbb10532 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -231,7 +231,8 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi setInstanceActionsEnabled(false); // add a close button at the end of the main toolbar when running on gamescope / steam deck - // FIXME: detect if we don't have server side decorations instead + // this is only needed on gamescope because it defaults to an X11/XWayland session and + // does not implement decorations if (qgetenv("XDG_CURRENT_DESKTOP") == "gamescope") { ui->mainToolBar->addAction(ui->actionCloseWindow); } From 3c9a207192e680262d44f25b509a77d74dd6dbe0 Mon Sep 17 00:00:00 2001 From: Alexandru Ionut Tripon Date: Fri, 26 Apr 2024 22:04:50 +0300 Subject: [PATCH 190/223] Update launcher/ui/widgets/VariableSizedImageObject.cpp Signed-off-by: Alexandru Ionut Tripon --- launcher/ui/widgets/VariableSizedImageObject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/widgets/VariableSizedImageObject.cpp b/launcher/ui/widgets/VariableSizedImageObject.cpp index a4e0872cb..3dd9d5634 100644 --- a/launcher/ui/widgets/VariableSizedImageObject.cpp +++ b/launcher/ui/widgets/VariableSizedImageObject.cpp @@ -37,7 +37,7 @@ QSizeF VariableSizedImageObject::intrinsicSize(QTextDocument* doc, int posInDocu auto image = qvariant_cast(format.property(ImageData)); auto size = image.size(); - if (size.isEmpty()) // can't resize a empty image + if (size.isEmpty()) // can't resize an empty image return { size }; // calculate the new image size based on the properties From e3f55f68657f63c15933dc0fdde4319390600a98 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Fri, 26 Apr 2024 20:43:57 +0100 Subject: [PATCH 191/223] Use proxy style to force ActivateItemOnSingleClick off Signed-off-by: TheKodeToad --- launcher/CMakeLists.txt | 2 ++ launcher/ui/themes/HintOverrideProxyStyle.cpp | 30 ++++++++++++++++ launcher/ui/themes/HintOverrideProxyStyle.h | 34 +++++++++++++++++++ launcher/ui/themes/ITheme.cpp | 4 ++- launcher/ui/themes/SystemTheme.cpp | 7 +++- 5 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 launcher/ui/themes/HintOverrideProxyStyle.cpp create mode 100644 launcher/ui/themes/HintOverrideProxyStyle.h diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 99acf8fc5..0d74966a8 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -827,6 +827,8 @@ SET(LAUNCHER_SOURCES ui/themes/DarkTheme.h ui/themes/ITheme.cpp ui/themes/ITheme.h + ui/themes/HintOverrideProxyStyle.cpp + ui/themes/HintOverrideProxyStyle.h ui/themes/SystemTheme.cpp ui/themes/SystemTheme.h ui/themes/IconTheme.cpp diff --git a/launcher/ui/themes/HintOverrideProxyStyle.cpp b/launcher/ui/themes/HintOverrideProxyStyle.cpp new file mode 100644 index 000000000..80e821349 --- /dev/null +++ b/launcher/ui/themes/HintOverrideProxyStyle.cpp @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2024 TheKodeToad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "HintOverrideProxyStyle.h" + +int HintOverrideProxyStyle::styleHint(QStyle::StyleHint hint, + const QStyleOption* option, + const QWidget* widget, + QStyleHintReturn* returnData) const +{ + if (hint == QStyle::SH_ItemView_ActivateItemOnSingleClick) + return 0; + + return QProxyStyle::styleHint(hint, option, widget, returnData); +} diff --git a/launcher/ui/themes/HintOverrideProxyStyle.h b/launcher/ui/themes/HintOverrideProxyStyle.h new file mode 100644 index 000000000..09b296018 --- /dev/null +++ b/launcher/ui/themes/HintOverrideProxyStyle.h @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2024 TheKodeToad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include + +/// Used to override platform-specific behaviours which the launcher does work well with. +class HintOverrideProxyStyle : public QProxyStyle { + Q_OBJECT + public: + HintOverrideProxyStyle(QStyle* style) : QProxyStyle(style) {} + + int styleHint(QStyle::StyleHint hint, + const QStyleOption* option = nullptr, + const QWidget* widget = nullptr, + QStyleHintReturn* returnData = nullptr) const override; +}; diff --git a/launcher/ui/themes/ITheme.cpp b/launcher/ui/themes/ITheme.cpp index 316b0f2ed..046ae16b4 100644 --- a/launcher/ui/themes/ITheme.cpp +++ b/launcher/ui/themes/ITheme.cpp @@ -2,6 +2,7 @@ /* * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 Tayou + * Copyright (C) 2024 TheKodeToad * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,12 +37,13 @@ #include #include #include "Application.h" +#include "HintOverrideProxyStyle.h" #include "rainbow.h" void ITheme::apply(bool) { APPLICATION->setStyleSheet(QString()); - QApplication::setStyle(QStyleFactory::create(qtTheme())); + QApplication::setStyle(new HintOverrideProxyStyle(QStyleFactory::create(qtTheme()))); if (hasColorScheme()) { QApplication::setPalette(colorScheme()); } diff --git a/launcher/ui/themes/SystemTheme.cpp b/launcher/ui/themes/SystemTheme.cpp index 7ad144c7a..cefe664db 100644 --- a/launcher/ui/themes/SystemTheme.cpp +++ b/launcher/ui/themes/SystemTheme.cpp @@ -2,6 +2,7 @@ /* * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 Tayou + * Copyright (C) 2024 TheKodeToad * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,6 +38,7 @@ #include #include #include +#include "HintOverrideProxyStyle.h" #include "ThemeManager.h" SystemTheme::SystemTheme() @@ -64,8 +66,11 @@ void SystemTheme::apply(bool initial) { // See https://github.com/MultiMC/Launcher/issues/1790 // or https://github.com/PrismLauncher/PrismLauncher/issues/490 - if (initial) + if (initial) { + QApplication::setStyle(new HintOverrideProxyStyle(QStyleFactory::create(qtTheme()))); return; + } + ITheme::apply(initial); } From 46b291d02e0c673eaba514ee7567ae10b57d890b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 27 Apr 2024 07:16:54 +0000 Subject: [PATCH 192/223] chore(deps): update hendrikmuhs/ccache-action action to v1.2.13 --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f3896550f..a4b103714 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -160,7 +160,7 @@ jobs: - name: Setup ccache if: (runner.os != 'Windows' || matrix.msystem == '') && inputs.build_type == 'Debug' - uses: hendrikmuhs/ccache-action@v1.2.12 + uses: hendrikmuhs/ccache-action@v1.2.13 with: key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}-${{ matrix.architecture }} From ccf0b01de796ae439a7811648e5805bbe29dc2e0 Mon Sep 17 00:00:00 2001 From: DioEgizio <83089242+DioEgizio@users.noreply.github.com> Date: Sat, 27 Apr 2024 10:18:04 +0200 Subject: [PATCH 193/223] chore!: make install_bundle work on linux, removed prebuilt tarballs Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com> --- .github/workflows/build.yml | 22 ---------------------- .github/workflows/trigger_release.yml | 4 ---- CMakeLists.txt | 6 +++++- launcher/CMakeLists.txt | 17 +++++++++-------- 4 files changed, 14 insertions(+), 35 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f3896550f..701812ffe 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -490,14 +490,6 @@ jobs: ":warning: Skipped code signing for Windows, as certificate was not present." >> $env:GITHUB_STEP_SUMMARY } - - name: Package (Linux) - if: runner.os == 'Linux' - run: | - cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_DIR }} - for l in $(find ${{ env.INSTALL_DIR }} -type f); do l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_DIR }}/}; l=${l#./}; echo $l; done > ${{ env.INSTALL_DIR }}/manifest.txt - cd ${{ env.INSTALL_DIR }} - tar --owner root --group root -czf ../PrismLauncher.tar.gz * - - name: Package (Linux, portable) if: runner.os == 'Linux' run: | @@ -590,13 +582,6 @@ jobs: name: PrismLauncher-${{ matrix.name }}-Setup-${{ env.VERSION }}-${{ inputs.build_type }} path: PrismLauncher-Setup.exe - - name: Upload binary tarball (Linux, Qt 5) - if: runner.os == 'Linux' && matrix.qt_ver != 6 - uses: actions/upload-artifact@v4 - with: - name: PrismLauncher-${{ runner.os }}-Qt5-${{ env.VERSION }}-${{ inputs.build_type }} - path: PrismLauncher.tar.gz - - name: Upload binary tarball (Linux, portable, Qt 5) if: runner.os == 'Linux' && matrix.qt_ver != 6 uses: actions/upload-artifact@v4 @@ -604,13 +589,6 @@ jobs: name: PrismLauncher-${{ runner.os }}-Qt5-Portable-${{ env.VERSION }}-${{ inputs.build_type }} path: PrismLauncher-portable.tar.gz - - name: Upload binary tarball (Linux, Qt 6) - if: runner.os == 'Linux' && matrix.qt_ver !=5 - uses: actions/upload-artifact@v4 - with: - name: PrismLauncher-${{ runner.os }}-Qt6-${{ env.VERSION }}-${{ inputs.build_type }} - path: PrismLauncher.tar.gz - - name: Upload binary tarball (Linux, portable, Qt 6) if: runner.os == 'Linux' && matrix.qt_ver != 5 uses: actions/upload-artifact@v4 diff --git a/.github/workflows/trigger_release.yml b/.github/workflows/trigger_release.yml index fa22c96d5..134281b2c 100644 --- a/.github/workflows/trigger_release.yml +++ b/.github/workflows/trigger_release.yml @@ -46,9 +46,7 @@ jobs: run: | mv ${{ github.workspace }}/PrismLauncher-source PrismLauncher-${{ env.VERSION }} mv PrismLauncher-Linux-Qt6-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz - mv PrismLauncher-Linux-Qt6*/PrismLauncher.tar.gz PrismLauncher-Linux-Qt6-${{ env.VERSION }}.tar.gz mv PrismLauncher-Linux-Qt5-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Qt5-Portable-${{ env.VERSION }}.tar.gz - mv PrismLauncher-Linux-Qt5*/PrismLauncher.tar.gz PrismLauncher-Linux-Qt5-${{ env.VERSION }}.tar.gz mv PrismLauncher-*.AppImage/PrismLauncher-*.AppImage PrismLauncher-Linux-x86_64.AppImage mv PrismLauncher-*.AppImage.zsync/PrismLauncher-*.AppImage.zsync PrismLauncher-Linux-x86_64.AppImage.zsync mv PrismLauncher-macOS-Legacy*/PrismLauncher.zip PrismLauncher-macOS-Legacy-${{ env.VERSION }}.zip @@ -92,11 +90,9 @@ jobs: draft: true prerelease: false files: | - PrismLauncher-Linux-Qt5-${{ env.VERSION }}.tar.gz PrismLauncher-Linux-Qt5-Portable-${{ env.VERSION }}.tar.gz PrismLauncher-Linux-x86_64.AppImage PrismLauncher-Linux-x86_64.AppImage.zsync - PrismLauncher-Linux-Qt6-${{ env.VERSION }}.tar.gz PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz PrismLauncher-Windows-MinGW-w64-${{ env.VERSION }}.zip PrismLauncher-Windows-MinGW-w64-Portable-${{ env.VERSION }}.zip diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e46bb605..5bf45be88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -417,7 +417,11 @@ elseif(UNIX) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_mrpack_MIMEInfo} DESTINATION ${KDE_INSTALL_MIMEDIR}) install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/launcher/qtlogging.ini" DESTINATION "share/${Launcher_Name}") - + + if (INSTALL_BUNDLE STREQUAL full) + set(PLUGIN_DEST_DIR "./plugins/") + endif() + if(Launcher_ManPage) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_ManPage} DESTINATION "${KDE_INSTALL_MANDIR}/man6") endif() diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 99acf8fc5..fc025521a 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -1492,7 +1492,6 @@ if(INSTALL_BUNDLE STREQUAL "full") CONFIGURATIONS Debug RelWithDebInfo "" DESTINATION ${PLUGIN_DEST_DIR} COMPONENT Runtime - PATTERN "*qopensslbackend*" EXCLUDE PATTERN "*qcertonlybackend*" EXCLUDE ) install( @@ -1503,14 +1502,16 @@ if(INSTALL_BUNDLE STREQUAL "full") REGEX "dd\\." EXCLUDE REGEX "_debug\\." EXCLUDE REGEX "\\.dSYM" EXCLUDE - PATTERN "*qopensslbackend*" EXCLUDE PATTERN "*qcertonlybackend*" EXCLUDE ) endif() - configure_file( - "${CMAKE_CURRENT_SOURCE_DIR}/install_prereqs.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/install_prereqs.cmake" - @ONLY - ) - install(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/install_prereqs.cmake" COMPONENT Runtime) + # ignore fixup_bundle on Linux + if (NOT (UNIX AND NOT APPLE)) + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/install_prereqs.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/install_prereqs.cmake" + @ONLY + ) + install(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/install_prereqs.cmake" COMPONENT Runtime) + endif() endif() From 890fd0b09c1cabe136e51bae92a41270de7f093e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 28 Apr 2024 00:20:12 +0000 Subject: [PATCH 194/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'nixpkgs': 'github:nixos/nixpkgs/fd16bb6d3bcca96039b11aa52038fafeb6e4f4be' (2024-04-20) → 'github:nixos/nixpkgs/d6f6eb2a984f2ba9a366c31e4d36d65465683450' (2024-04-27) • Updated input 'pre-commit-hooks': 'github:cachix/pre-commit-hooks.nix/40e6053ecb65fcbf12863338a6dcefb3f55f1bf8' (2024-04-12) → 'github:cachix/pre-commit-hooks.nix/6fb82e44254d6a0ece014ec423cb62d92435336f' (2024-04-24) --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index 0fbfca9cc..24898ecba 100644 --- a/flake.lock +++ b/flake.lock @@ -93,11 +93,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1713596654, - "narHash": "sha256-LJbHQQ5aX1LVth2ST+Kkse/DRzgxlVhTL1rxthvyhZc=", + "lastModified": 1714213793, + "narHash": "sha256-Yg5D5LhyAZvd3DZrQQfJAVK8K3TkUYKooFtH1ulM0mw=", "owner": "nixos", "repo": "nixpkgs", - "rev": "fd16bb6d3bcca96039b11aa52038fafeb6e4f4be", + "rev": "d6f6eb2a984f2ba9a366c31e4d36d65465683450", "type": "github" }, "original": { @@ -122,11 +122,11 @@ ] }, "locked": { - "lastModified": 1712897695, - "narHash": "sha256-nMirxrGteNAl9sWiOhoN5tIHyjBbVi5e2tgZUgZlK3Y=", + "lastModified": 1713954846, + "narHash": "sha256-RWFafuSb5nkWGu8dDbW7gVb8FOQOPqmX/9MlxUUDguw=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "40e6053ecb65fcbf12863338a6dcefb3f55f1bf8", + "rev": "6fb82e44254d6a0ece014ec423cb62d92435336f", "type": "github" }, "original": { From a5b059ebad1221d10eeb5d4b953817441fabfd1d Mon Sep 17 00:00:00 2001 From: Trial97 Date: Mon, 29 Apr 2024 00:27:15 +0300 Subject: [PATCH 195/223] Fixed curseforge export Signed-off-by: Trial97 --- launcher/MMCZip.h | 18 ++++++++++++++---- .../modplatform/flame/FlamePackExportTask.cpp | 11 ++++++----- .../modrinth/ModrinthPackExportTask.cpp | 2 +- launcher/ui/dialogs/ExportInstanceDialog.cpp | 2 +- 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/launcher/MMCZip.h b/launcher/MMCZip.h index 43b4ab933..b28eb195c 100644 --- a/launcher/MMCZip.h +++ b/launcher/MMCZip.h @@ -154,7 +154,12 @@ bool collectFileListRecursively(const QString& rootDir, const QString& subDir, Q #if defined(LAUNCHER_APPLICATION) class ExportToZipTask : public Task { public: - ExportToZipTask(QString outputPath, QDir dir, QFileInfoList files, QString destinationPrefix = "", bool followSymlinks = false) + ExportToZipTask(QString outputPath, + QDir dir, + QFileInfoList files, + QString destinationPrefix = "", + bool followSymlinks = false, + bool utf8Enabled = false) : m_output_path(outputPath) , m_output(outputPath) , m_dir(dir) @@ -163,10 +168,15 @@ class ExportToZipTask : public Task { , m_follow_symlinks(followSymlinks) { setAbortable(true); - m_output.setUtf8Enabled(true); + m_output.setUtf8Enabled(utf8Enabled); }; - ExportToZipTask(QString outputPath, QString dir, QFileInfoList files, QString destinationPrefix = "", bool followSymlinks = false) - : ExportToZipTask(outputPath, QDir(dir), files, destinationPrefix, followSymlinks){}; + ExportToZipTask(QString outputPath, + QString dir, + QFileInfoList files, + QString destinationPrefix = "", + bool followSymlinks = false, + bool utf8Enabled = false) + : ExportToZipTask(outputPath, QDir(dir), files, destinationPrefix, followSymlinks, utf8Enabled){}; virtual ~ExportToZipTask() = default; diff --git a/launcher/modplatform/flame/FlamePackExportTask.cpp b/launcher/modplatform/flame/FlamePackExportTask.cpp index 3a2028fd1..569181732 100644 --- a/launcher/modplatform/flame/FlamePackExportTask.cpp +++ b/launcher/modplatform/flame/FlamePackExportTask.cpp @@ -201,7 +201,7 @@ void FlamePackExportTask::makeApiRequest() << " reason: " << parseError.errorString(); qWarning() << *response; - failed(parseError.errorString()); + emitFailed(parseError.errorString()); return; } @@ -213,6 +213,7 @@ void FlamePackExportTask::makeApiRequest() if (dataArr.isEmpty()) { qWarning() << "No matches found for fingerprint search!"; + getProjectsInfo(); return; } for (auto match : dataArr) { @@ -243,9 +244,9 @@ void FlamePackExportTask::makeApiRequest() qDebug() << doc; } pendingHashes.clear(); + getProjectsInfo(); }); - connect(task.get(), &Task::finished, this, &FlamePackExportTask::getProjectsInfo); - connect(task.get(), &NetJob::failed, this, &FlamePackExportTask::emitFailed); + connect(task.get(), &NetJob::failed, this, &FlamePackExportTask::getProjectsInfo); task->start(); } @@ -279,7 +280,7 @@ void FlamePackExportTask::getProjectsInfo() qWarning() << "Error while parsing JSON response from CurseForge projects task at " << parseError.offset << " reason: " << parseError.errorString(); qWarning() << *response; - failed(parseError.errorString()); + emitFailed(parseError.errorString()); return; } @@ -333,7 +334,7 @@ void FlamePackExportTask::buildZip() setStatus(tr("Adding files...")); setProgress(4, 5); - auto zipTask = makeShared(output, gameRoot, files, "overrides/", true); + auto zipTask = makeShared(output, gameRoot, files, "overrides/", true, false); zipTask->addExtraFile("manifest.json", generateIndex()); zipTask->addExtraFile("modlist.html", generateHTML()); diff --git a/launcher/modplatform/modrinth/ModrinthPackExportTask.cpp b/launcher/modplatform/modrinth/ModrinthPackExportTask.cpp index c704708ad..7e52153b9 100644 --- a/launcher/modplatform/modrinth/ModrinthPackExportTask.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackExportTask.cpp @@ -200,7 +200,7 @@ void ModrinthPackExportTask::buildZip() { setStatus(tr("Adding files...")); - auto zipTask = makeShared(output, gameRoot, files, "overrides/", true); + auto zipTask = makeShared(output, gameRoot, files, "overrides/", true, true); zipTask->addExtraFile("modrinth.index.json", generateIndex()); zipTask->setExcludeFiles(resolvedFiles.keys()); diff --git a/launcher/ui/dialogs/ExportInstanceDialog.cpp b/launcher/ui/dialogs/ExportInstanceDialog.cpp index 703736d68..9f2b3ac42 100644 --- a/launcher/ui/dialogs/ExportInstanceDialog.cpp +++ b/launcher/ui/dialogs/ExportInstanceDialog.cpp @@ -146,7 +146,7 @@ void ExportInstanceDialog::doExport() return; } - auto task = makeShared(output, m_instance->instanceRoot(), files, "", true); + auto task = makeShared(output, m_instance->instanceRoot(), files, "", true, true); connect(task.get(), &Task::failed, this, [this, output](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show(); }); From be8ac0b5bbd9cce5e8b36d625ca5628295004d1c Mon Sep 17 00:00:00 2001 From: DioEgizio <83089242+DioEgizio@users.noreply.github.com> Date: Sat, 27 Apr 2024 10:35:26 +0200 Subject: [PATCH 196/223] fix: make portable builds bundle Qt Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com> --- .github/workflows/build.yml | 35 +++++++------ CMakeLists.txt | 10 +++- launcher/CMakeLists.txt | 82 ++++++++++++++++++++++++++++--- launcher/install_prereqs.cmake.in | 1 - 4 files changed, 103 insertions(+), 25 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 701812ffe..11adfe68b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -210,7 +210,7 @@ jobs: - name: Install Qt (Linux) if: runner.os == 'Linux' && matrix.qt_ver != 6 run: | - sudo apt-get -y install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5 + sudo apt-get -y install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5 qtwayland5 - name: Install host Qt (Windows MSVC arm64) if: runner.os == 'Windows' && matrix.architecture == 'arm64' @@ -490,20 +490,6 @@ jobs: ":warning: Skipped code signing for Windows, as certificate was not present." >> $env:GITHUB_STEP_SUMMARY } - - name: Package (Linux, portable) - if: runner.os == 'Linux' - run: | - cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} - cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable - - # workaround to make portable installs to work on fedora - mkdir ${{ env.INSTALL_PORTABLE_DIR }}/lib - cp /lib/x86_64-linux-gnu/libbz2.so.1.0 ${{ env.INSTALL_PORTABLE_DIR }}/lib - - for l in $(find ${{ env.INSTALL_PORTABLE_DIR }} -type f); do l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_PORTABLE_DIR }}/}; l=${l#./}; echo $l; done > ${{ env.INSTALL_PORTABLE_DIR }}/manifest.txt - cd ${{ env.INSTALL_PORTABLE_DIR }} - tar -czf ../PrismLauncher-portable.tar.gz * - - name: Package AppImage (Linux) if: runner.os == 'Linux' && matrix.qt_ver != 5 shell: bash @@ -550,6 +536,25 @@ jobs: mv "PrismLauncher-Linux-x86_64.AppImage" "PrismLauncher-Linux-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage" + - name: Package (Linux, portable) + if: runner.os == 'Linux' + run: | + cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_PORTABLE_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DLauncher_BUILD_ARTIFACT=Linux-Qt${{ matrix.qt_ver }} -DINSTALL_BUNDLE=full -G Ninja + cmake --install ${{ env.BUILD_DIR }} + cmake --install ${{ env.BUILD_DIR }} --component portable + + mkdir ${{ env.INSTALL_PORTABLE_DIR }}/lib + cp /lib/x86_64-linux-gnu/libbz2.so.1.0 ${{ env.INSTALL_PORTABLE_DIR }}/lib + cp /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0 ${{ env.INSTALL_PORTABLE_DIR }}/lib + cp /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 ${{ env.INSTALL_PORTABLE_DIR }}/lib + cp /usr/lib/x86_64-linux-gnu/libssl.so.1.1 ${{ env.INSTALL_PORTABLE_DIR }}/lib + cp /usr/lib/x86_64-linux-gnu/libffi.so.7 ${{ env.INSTALL_PORTABLE_DIR }}/lib + mv ${{ env.INSTALL_PORTABLE_DIR }}/bin/*.so* ${{ env.INSTALL_PORTABLE_DIR }}/lib + + for l in $(find ${{ env.INSTALL_PORTABLE_DIR }} -type f); do l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_PORTABLE_DIR }}/}; l=${l#./}; echo $l; done > ${{ env.INSTALL_PORTABLE_DIR }}/manifest.txt + cd ${{ env.INSTALL_PORTABLE_DIR }} + tar -czf ../PrismLauncher-portable.tar.gz * + ## # UPLOAD BUILDS ## diff --git a/CMakeLists.txt b/CMakeLists.txt index 5bf45be88..63408ec21 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -419,7 +419,15 @@ elseif(UNIX) install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/launcher/qtlogging.ini" DESTINATION "share/${Launcher_Name}") if (INSTALL_BUNDLE STREQUAL full) - set(PLUGIN_DEST_DIR "./plugins/") + set(PLUGIN_DEST_DIR "plugins") + set(BUNDLE_DEST_DIR ".") + set(RESOURCES_DEST_DIR ".") + + # Apps to bundle + set(APPS "\${CMAKE_INSTALL_PREFIX}/bin/${Launcher_APP_BINARY_NAME}") + + # directories to look for dependencies + set(DIRS ${QT_LIBS_DIR} ${QT_LIBEXECS_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) endif() if(Launcher_ManPage) diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index fc025521a..03ef3ae27 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -1505,13 +1505,79 @@ if(INSTALL_BUNDLE STREQUAL "full") PATTERN "*qcertonlybackend*" EXCLUDE ) endif() - # ignore fixup_bundle on Linux - if (NOT (UNIX AND NOT APPLE)) - configure_file( - "${CMAKE_CURRENT_SOURCE_DIR}/install_prereqs.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/install_prereqs.cmake" - @ONLY - ) - install(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/install_prereqs.cmake" COMPONENT Runtime) + # Wayland support + if(EXISTS "${QT_PLUGINS_DIR}/wayland-graphics-integration-client") + install( + DIRECTORY "${QT_PLUGINS_DIR}/wayland-graphics-integration-client" + CONFIGURATIONS Debug RelWithDebInfo "" + DESTINATION ${PLUGIN_DEST_DIR} + COMPONENT Runtime + ) + install( + DIRECTORY "${QT_PLUGINS_DIR}/wayland-graphics-integration-client" + CONFIGURATIONS Release MinSizeRel + DESTINATION ${PLUGIN_DEST_DIR} + COMPONENT Runtime + REGEX "dd\\." EXCLUDE + REGEX "_debug\\." EXCLUDE + REGEX "\\.dSYM" EXCLUDE + ) endif() + if(EXISTS "${QT_PLUGINS_DIR}/wayland-graphics-integration-server") + install( + DIRECTORY "${QT_PLUGINS_DIR}/wayland-graphics-integration-server" + CONFIGURATIONS Debug RelWithDebInfo "" + DESTINATION ${PLUGIN_DEST_DIR} + COMPONENT Runtime + ) + install( + DIRECTORY "${QT_PLUGINS_DIR}/wayland-graphics-integration-server" + CONFIGURATIONS Release MinSizeRel + DESTINATION ${PLUGIN_DEST_DIR} + COMPONENT Runtime + REGEX "dd\\." EXCLUDE + REGEX "_debug\\." EXCLUDE + REGEX "\\.dSYM" EXCLUDE + ) + endif() + if(EXISTS "${QT_PLUGINS_DIR}/wayland-decoration-client") + install( + DIRECTORY "${QT_PLUGINS_DIR}/wayland-decoration-client" + CONFIGURATIONS Debug RelWithDebInfo "" + DESTINATION ${PLUGIN_DEST_DIR} + COMPONENT Runtime + ) + install( + DIRECTORY "${QT_PLUGINS_DIR}/wayland-decoration-client" + CONFIGURATIONS Release MinSizeRel + DESTINATION ${PLUGIN_DEST_DIR} + COMPONENT Runtime + REGEX "dd\\." EXCLUDE + REGEX "_debug\\." EXCLUDE + REGEX "\\.dSYM" EXCLUDE + ) + endif() + if(EXISTS "${QT_PLUGINS_DIR}/wayland-shell-integration") + install( + DIRECTORY "${QT_PLUGINS_DIR}/wayland-shell-integration" + CONFIGURATIONS Debug RelWithDebInfo "" + DESTINATION ${PLUGIN_DEST_DIR} + COMPONENT Runtime + ) + install( + DIRECTORY "${QT_PLUGINS_DIR}/wayland-shell-integration" + CONFIGURATIONS Release MinSizeRel + DESTINATION ${PLUGIN_DEST_DIR} + COMPONENT Runtime + REGEX "dd\\." EXCLUDE + REGEX "_debug\\." EXCLUDE + REGEX "\\.dSYM" EXCLUDE + ) + endif() + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/install_prereqs.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/install_prereqs.cmake" + @ONLY + ) + install(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/install_prereqs.cmake" COMPONENT Runtime) endif() diff --git a/launcher/install_prereqs.cmake.in b/launcher/install_prereqs.cmake.in index e4408d161..acbce9650 100644 --- a/launcher/install_prereqs.cmake.in +++ b/launcher/install_prereqs.cmake.in @@ -1,5 +1,4 @@ set(CMAKE_MODULE_PATH "@CMAKE_MODULE_PATH@") - file(GLOB_RECURSE QTPLUGINS "${CMAKE_INSTALL_PREFIX}/@PLUGIN_DEST_DIR@/*@CMAKE_SHARED_LIBRARY_SUFFIX@") function(gp_resolved_file_type_override resolved_file type_var) if(resolved_file MATCHES "^/(usr/)?lib/libQt") From cb9a83320c70ebd6802651066251d31f8da59bf6 Mon Sep 17 00:00:00 2001 From: DioEgizio <83089242+DioEgizio@users.noreply.github.com> Date: Mon, 29 Apr 2024 15:51:31 +0200 Subject: [PATCH 197/223] chore: make Qt 5 Linux use official Qt builds Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com> --- .github/workflows/build.yml | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 11adfe68b..6854fe5d9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -54,6 +54,10 @@ jobs: include: - os: ubuntu-20.04 qt_ver: 5 + qt_host: linux + qt_arch: "" + qt_version: "5.12.8" + qt_modules: "" - os: ubuntu-20.04 qt_ver: 6 @@ -61,7 +65,6 @@ jobs: qt_arch: "" qt_version: "6.2.4" qt_modules: "qt5compat qtimageformats" - qt_tools: "" - os: windows-2022 name: "Windows-MinGW-w64" @@ -78,7 +81,6 @@ jobs: qt_arch: '' qt_version: '6.7.0' qt_modules: 'qt5compat qtimageformats' - qt_tools: '' - os: windows-2022 name: "Windows-MSVC-arm64" @@ -90,7 +92,6 @@ jobs: qt_arch: 'win64_msvc2019_arm64' qt_version: '6.7.0' qt_modules: 'qt5compat qtimageformats' - qt_tools: '' - os: macos-12 name: macOS @@ -100,7 +101,6 @@ jobs: qt_arch: '' qt_version: '6.7.0' qt_modules: 'qt5compat qtimageformats' - qt_tools: '' - os: macos-12 name: macOS-Legacy @@ -109,7 +109,6 @@ jobs: qt_host: mac qt_version: "5.15.2" qt_modules: "" - qt_tools: "" runs-on: ${{ matrix.os }} @@ -207,11 +206,6 @@ jobs: brew update brew install ninja extra-cmake-modules - - name: Install Qt (Linux) - if: runner.os == 'Linux' && matrix.qt_ver != 6 - run: | - sudo apt-get -y install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5 qtwayland5 - - name: Install host Qt (Windows MSVC arm64) if: runner.os == 'Windows' && matrix.architecture == 'arm64' uses: jurplel/install-qt-action@v3 @@ -223,20 +217,18 @@ jobs: target: "desktop" arch: "" modules: ${{ matrix.qt_modules }} - tools: ${{ matrix.qt_tools }} cache: ${{ inputs.is_qt_cached }} cache-key-prefix: host-qt-arm64-windows dir: ${{ github.workspace }}\HostQt set-env: false - - name: Install Qt (macOS, Linux, Qt 6 & Windows MSVC) - if: runner.os == 'Linux' && matrix.qt_ver == 6 || runner.os == 'macOS' || (runner.os == 'Windows' && matrix.msystem == '') + - name: Install Qt (macOS, Linux & Windows MSVC) + if: matrix.msystem == '' uses: jurplel/install-qt-action@v3 with: aqtversion: "==3.1.*" py7zrversion: ">=0.20.2" version: ${{ matrix.qt_version }} - host: ${{ matrix.qt_host }} target: "desktop" arch: ${{ matrix.qt_arch }} modules: ${{ matrix.qt_modules }} @@ -432,12 +424,6 @@ jobs: run: | cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build_type }} - cd ${{ env.INSTALL_DIR }} - if ("${{ matrix.qt_ver }}" -eq "5") - { - Copy-Item ${{ runner.workspace }}/Qt/Tools/OpenSSL/Win_x86/bin/libcrypto-1_1.dll -Destination libcrypto-1_1.dll - Copy-Item ${{ runner.workspace }}/Qt/Tools/OpenSSL/Win_x86/bin/libssl-1_1.dll -Destination libssl-1_1.dll - } cd ${{ github.workspace }} Get-ChildItem ${{ env.INSTALL_DIR }} -Recurse | ForEach FullName | Resolve-Path -Relative | %{ $_.TrimStart('.\') } | %{ $_.TrimStart('${{ env.INSTALL_DIR }}') } | %{ $_.TrimStart('\') } | Out-File -FilePath ${{ env.INSTALL_DIR }}/manifest.txt From 48f3ca56bafcf1a7e10b865a910221eefe6b84d0 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 30 Apr 2024 22:38:01 +0300 Subject: [PATCH 198/223] Fixed NetRequest not failing on sink init Signed-off-by: Trial97 --- launcher/net/NetRequest.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/launcher/net/NetRequest.cpp b/launcher/net/NetRequest.cpp index 728c0e077..526fe77a5 100644 --- a/launcher/net/NetRequest.cpp +++ b/launcher/net/NetRequest.cpp @@ -68,7 +68,8 @@ void NetRequest::executeTask() if (getState() == Task::State::AbortedByUser) { qCWarning(logCat) << getUid().toString() << "Attempt to start an aborted Request:" << m_url.toString(); - emitAborted(); + emit aborted(); + emit finished(); return; } @@ -85,10 +86,12 @@ void NetRequest::executeTask() break; case State::Inactive: case State::Failed: - emitFailed(); + emit failed("Failed to initilize sink"); + emit finished(); return; case State::AbortedByUser: - emitAborted(); + emit aborted(); + emit finished(); return; } From e06812037560036b2c1ade1e75b06fce1f8a13bf Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 30 Apr 2024 22:56:03 +0300 Subject: [PATCH 199/223] Fix invalid characters filename download on windows Signed-off-by: Trial97 --- launcher/modplatform/flame/FlameInstanceCreationTask.cpp | 7 ++++++- .../modplatform/modrinth/ModrinthInstanceCreationTask.cpp | 8 ++++++-- launcher/net/HttpMetaCache.cpp | 3 +++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp index ef552c3c2..a1f10c156 100644 --- a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp +++ b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp @@ -537,7 +537,12 @@ void FlameCreationTask::setupDownloadJob(QEventLoop& loop) selectedOptionalMods = optionalModDialog.getResult(); } for (const auto& result : results) { - auto relpath = FS::PathCombine(result.targetFolder, result.fileName); + auto fileName = result.fileName; +#ifdef Q_OS_WIN + fileName = FS::RemoveInvalidPathChars(fileName); +#endif + auto relpath = FS::PathCombine(result.targetFolder, fileName); + if (!result.required && !selectedOptionalMods.contains(relpath)) { relpath += ".disabled"; } diff --git a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp index a688cea87..3b875103b 100644 --- a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp +++ b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp @@ -240,11 +240,15 @@ bool ModrinthCreationTask::createInstance() auto root_modpack_url = QUrl::fromLocalFile(root_modpack_path); for (auto file : m_files) { - auto file_path = FS::PathCombine(root_modpack_path, file.path); + auto fileName = file.path; +#ifdef Q_OS_WIN + fileName = FS::RemoveInvalidPathChars(fileName); +#endif + auto file_path = FS::PathCombine(root_modpack_path, fileName); if (!root_modpack_url.isParentOf(QUrl::fromLocalFile(file_path))) { // This means we somehow got out of the root folder, so abort here to prevent exploits setError(tr("One of the files has a path that leads to an arbitrary location (%1). This is a security risk and isn't allowed.") - .arg(file.path)); + .arg(fileName)); return false; } diff --git a/launcher/net/HttpMetaCache.cpp b/launcher/net/HttpMetaCache.cpp index f37bc0bf8..648155412 100644 --- a/launcher/net/HttpMetaCache.cpp +++ b/launcher/net/HttpMetaCache.cpp @@ -84,6 +84,9 @@ auto HttpMetaCache::getEntry(QString base, QString resource_path) -> MetaEntryPt auto HttpMetaCache::resolveEntry(QString base, QString resource_path, QString expected_etag) -> MetaEntryPtr { +#ifdef Q_OS_WIN + resource_path = FS::RemoveInvalidPathChars(resource_path); +#endif auto entry = getEntry(base, resource_path); // it's not present? generate a default stale entry if (!entry) { From 5400c24c7324213a1af102c96e8bd6f9be672006 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 30 Apr 2024 23:04:50 +0300 Subject: [PATCH 200/223] Ensure valid file names for resource names Signed-off-by: Trial97 --- launcher/modplatform/flame/FlameModIndex.cpp | 3 +++ launcher/modplatform/modrinth/ModrinthPackIndex.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/launcher/modplatform/flame/FlameModIndex.cpp b/launcher/modplatform/flame/FlameModIndex.cpp index 345883c17..70d07c201 100644 --- a/launcher/modplatform/flame/FlameModIndex.cpp +++ b/launcher/modplatform/flame/FlameModIndex.cpp @@ -138,6 +138,9 @@ auto FlameMod::loadIndexedPackVersion(QJsonObject& obj, bool load_changelog) -> file.version = Json::requireString(obj, "displayName"); file.downloadUrl = Json::ensureString(obj, "downloadUrl"); file.fileName = Json::requireString(obj, "fileName"); +#ifdef Q_OS_WIN + file.fileName = FS::RemoveInvalidPathChars(file.fileName); +#endif ModPlatform::IndexedVersionType::VersionType ver_type; switch (Json::requireInteger(obj, "releaseType")) { diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp index c1c30ab5f..561976dc3 100644 --- a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp @@ -226,6 +226,9 @@ auto Modrinth::loadIndexedPackVersion(QJsonObject& obj, QString preferred_hash_t if (parent.contains("url")) { file.downloadUrl = Json::requireString(parent, "url"); file.fileName = Json::requireString(parent, "filename"); +#ifdef Q_OS_WIN + file.fileName = FS::RemoveInvalidPathChars(file.fileName); +#endif file.is_preferred = Json::requireBoolean(parent, "primary") || (files.count() == 1); auto hash_list = Json::requireObject(parent, "hashes"); From 30ce8ecb5ff08bcec110b3b291025cfd72d4d4fe Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 30 Apr 2024 23:20:24 +0300 Subject: [PATCH 201/223] Fixed imports Signed-off-by: Trial97 --- launcher/modplatform/flame/FlameModIndex.cpp | 1 + launcher/modplatform/modrinth/ModrinthPackIndex.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/launcher/modplatform/flame/FlameModIndex.cpp b/launcher/modplatform/flame/FlameModIndex.cpp index 70d07c201..83a28fa2b 100644 --- a/launcher/modplatform/flame/FlameModIndex.cpp +++ b/launcher/modplatform/flame/FlameModIndex.cpp @@ -1,5 +1,6 @@ #include "FlameModIndex.h" +#include "FileSystem.h" #include "Json.h" #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp index 561976dc3..4671a330d 100644 --- a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp @@ -17,6 +17,7 @@ */ #include "ModrinthPackIndex.h" +#include "FileSystem.h" #include "ModrinthAPI.h" #include "Json.h" From 5d36ed9cf99d202aaceb63acaae27cd260192f01 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 5 May 2024 00:19:38 +0000 Subject: [PATCH 202/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'flake-parts': 'github:hercules-ci/flake-parts/9126214d0a59633752a136528f5f3b9aa8565b7d' (2024-04-01) → 'github:hercules-ci/flake-parts/e5d10a24b66c3ea8f150e47dfdb0416ab7c3390e' (2024-05-02) • Updated input 'nixpkgs': 'github:nixos/nixpkgs/d6f6eb2a984f2ba9a366c31e4d36d65465683450' (2024-04-27) → 'github:nixos/nixpkgs/5fd8536a9a5932d4ae8de52b7dc08d92041237fc' (2024-05-03) • Updated input 'pre-commit-hooks': 'github:cachix/pre-commit-hooks.nix/6fb82e44254d6a0ece014ec423cb62d92435336f' (2024-04-24) → 'github:cachix/pre-commit-hooks.nix/2849da033884f54822af194400f8dff435ada242' (2024-04-30) --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index 24898ecba..78f774342 100644 --- a/flake.lock +++ b/flake.lock @@ -23,11 +23,11 @@ ] }, "locked": { - "lastModified": 1712014858, - "narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=", + "lastModified": 1714641030, + "narHash": "sha256-yzcRNDoyVP7+SCNX0wmuDju1NUCt8Dz9+lyUXEI0dbI=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "9126214d0a59633752a136528f5f3b9aa8565b7d", + "rev": "e5d10a24b66c3ea8f150e47dfdb0416ab7c3390e", "type": "github" }, "original": { @@ -93,11 +93,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1714213793, - "narHash": "sha256-Yg5D5LhyAZvd3DZrQQfJAVK8K3TkUYKooFtH1ulM0mw=", + "lastModified": 1714750952, + "narHash": "sha256-oOUdvPrO8CbupgDSaPou+Jv6GL+uQA2QlE33D7OLzkM=", "owner": "nixos", "repo": "nixpkgs", - "rev": "d6f6eb2a984f2ba9a366c31e4d36d65465683450", + "rev": "5fd8536a9a5932d4ae8de52b7dc08d92041237fc", "type": "github" }, "original": { @@ -122,11 +122,11 @@ ] }, "locked": { - "lastModified": 1713954846, - "narHash": "sha256-RWFafuSb5nkWGu8dDbW7gVb8FOQOPqmX/9MlxUUDguw=", + "lastModified": 1714478972, + "narHash": "sha256-q//cgb52vv81uOuwz1LaXElp3XAe1TqrABXODAEF6Sk=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "6fb82e44254d6a0ece014ec423cb62d92435336f", + "rev": "2849da033884f54822af194400f8dff435ada242", "type": "github" }, "original": { From 8e0af16de979ba92e9983b47c44ee0f321fcb116 Mon Sep 17 00:00:00 2001 From: Samuel Stidham Date: Sun, 5 May 2024 19:53:18 -0400 Subject: [PATCH 203/223] Add extra java locations for MacOs. Signed-off-by: Samuel Stidham --- launcher/java/JavaUtils.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/launcher/java/JavaUtils.cpp b/launcher/java/JavaUtils.cpp index 3627cec39..b996bf046 100644 --- a/launcher/java/JavaUtils.cpp +++ b/launcher/java/JavaUtils.cpp @@ -362,6 +362,12 @@ QList JavaUtils::FindJavaPaths() javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/bin/java"); javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Commands/java"); } + + auto home = qEnvironmentVariable("HOME"); + + // javas downloaded by sdkman + scanJavaDirs(FS::PathCombine(home, ".sdkman/candidates/java")); + javas.append(getMinecraftJavaBundle()); javas = addJavasFromEnv(javas); javas.removeDuplicates(); From adf0cfdebf2d27148139da2965900a9b3c1ec389 Mon Sep 17 00:00:00 2001 From: Samuel Stidham Date: Sun, 5 May 2024 20:01:29 -0400 Subject: [PATCH 204/223] Fixed the code. Signed-off-by: Samuel Stidham --- launcher/java/JavaUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/java/JavaUtils.cpp b/launcher/java/JavaUtils.cpp index b996bf046..e767eff89 100644 --- a/launcher/java/JavaUtils.cpp +++ b/launcher/java/JavaUtils.cpp @@ -366,7 +366,7 @@ QList JavaUtils::FindJavaPaths() auto home = qEnvironmentVariable("HOME"); // javas downloaded by sdkman - scanJavaDirs(FS::PathCombine(home, ".sdkman/candidates/java")); + javas.append(FS::PathCombine(home, ".sdkman/candidates/java")); javas.append(getMinecraftJavaBundle()); javas = addJavasFromEnv(javas); From 47871416982836e282e2da373a317d3df0cf4f38 Mon Sep 17 00:00:00 2001 From: Kenneth Chew <79120643+kthchew@users.noreply.github.com> Date: Tue, 7 May 2024 18:22:23 -0400 Subject: [PATCH 205/223] Improved blocked mods dialog permissions prompt Targeted to macOS (where `~/Downloads` is considered a sensitive location that the system protects behind a prompt even from non-sandboxed apps) Signed-off-by: Kenneth Chew <79120643+kthchew@users.noreply.github.com> --- cmake/MacOSXBundleInfo.plist.in | 2 ++ launcher/ui/dialogs/BlockedModsDialog.cpp | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/cmake/MacOSXBundleInfo.plist.in b/cmake/MacOSXBundleInfo.plist.in index d36ac3e8f..c439efe25 100644 --- a/cmake/MacOSXBundleInfo.plist.in +++ b/cmake/MacOSXBundleInfo.plist.in @@ -6,6 +6,8 @@ A Minecraft mod wants to access your camera. NSMicrophoneUsageDescription A Minecraft mod wants to access your microphone. + NSDownloadsFolderUsageDescription + Prism uses access to your Downloads folder to help you more quickly add mods that can't be automatically downloaded to your instance. You can change where Prism scans for downloaded mods in Settings or the prompt that appears. NSPrincipalClass NSApplication NSHighResolutionCapable diff --git a/launcher/ui/dialogs/BlockedModsDialog.cpp b/launcher/ui/dialogs/BlockedModsDialog.cpp index 7a5a16818..df351e845 100644 --- a/launcher/ui/dialogs/BlockedModsDialog.cpp +++ b/launcher/ui/dialogs/BlockedModsDialog.cpp @@ -40,6 +40,7 @@ #include #include #include +#include BlockedModsDialog::BlockedModsDialog(QWidget* parent, const QString& title, const QString& text, QList& mods, QString hash_type) : QDialog(parent), ui(new Ui::BlockedModsDialog), m_mods(mods), m_hash_type(hash_type) @@ -60,8 +61,13 @@ BlockedModsDialog::BlockedModsDialog(QWidget* parent, const QString& title, cons qDebug() << "[Blocked Mods Dialog] Mods List: " << mods; - setupWatch(); - scanPaths(); + // defer setup of file system watchers until after the dialog is shown + // this allows OS (namely macOS) permission prompts to show after the relevant dialog appears + QTimer::singleShot(0, this, [this] { + setupWatch(); + scanPaths(); + update(); + }); this->setWindowTitle(title); ui->labelDescription->setText(text); @@ -194,6 +200,10 @@ void BlockedModsDialog::setupWatch() void BlockedModsDialog::watchPath(QString path, bool watch_recursive) { auto to_watch = QFileInfo(path); + if (!to_watch.isReadable()) { + qWarning() << "[Blocked Mods Dialog] Failed to add Watch Path (unable to read):" << path; + return; + } auto to_watch_path = to_watch.canonicalFilePath(); if (m_watcher.directories().contains(to_watch_path)) return; // don't watch the same path twice (no loops!) From e7c95c9ccb92474cbbaf125814d3085a63b2b746 Mon Sep 17 00:00:00 2001 From: Kenneth Chew <79120643+kthchew@users.noreply.github.com> Date: Tue, 7 May 2024 18:57:04 -0400 Subject: [PATCH 206/223] Fix bug where watched directories are not clickable on macOS Signed-off-by: Kenneth Chew <79120643+kthchew@users.noreply.github.com> --- launcher/ui/dialogs/BlockedModsDialog.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/launcher/ui/dialogs/BlockedModsDialog.cpp b/launcher/ui/dialogs/BlockedModsDialog.cpp index df351e845..2b415c2d9 100644 --- a/launcher/ui/dialogs/BlockedModsDialog.cpp +++ b/launcher/ui/dialogs/BlockedModsDialog.cpp @@ -164,7 +164,8 @@ void BlockedModsDialog::update() QString watching; for (auto& dir : m_watcher.directories()) { - watching += QString("%1
").arg(dir); + QUrl fileURL = QUrl::fromLocalFile(dir); + watching += QString("%2
").arg(fileURL.toString(), dir); } ui->textBrowserWatched->setText(watching); From a95c1768a778f3ade8d61fef4c636a21a55bb4fe Mon Sep 17 00:00:00 2001 From: Trial97 Date: Wed, 8 May 2024 14:16:12 +0300 Subject: [PATCH 207/223] Add neoforge support for technic packs and atlauncher packs Signed-off-by: Trial97 --- .../atlauncher/ATLPackInstallTask.cpp | 6 +++++ .../technic/TechnicPackProcessor.cpp | 23 +++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp b/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp index 8ae8145de..01de88b04 100644 --- a/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp +++ b/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp @@ -1031,6 +1031,12 @@ void PackInstallTask::install() return; components->setComponentVersion("net.minecraftforge", version); + } else if (m_version.loader.type == QString("neoforge")) { + auto version = getVersionForLoader("net.neoforged"); + if (version == Q_NULLPTR) + return; + + components->setComponentVersion("net.neoforged", version); } else if (m_version.loader.type == QString("fabric")) { auto version = getVersionForLoader("net.fabricmc.fabric-loader"); if (version == Q_NULLPTR) diff --git a/launcher/modplatform/technic/TechnicPackProcessor.cpp b/launcher/modplatform/technic/TechnicPackProcessor.cpp index 90f59ce54..a47a4811f 100644 --- a/launcher/modplatform/technic/TechnicPackProcessor.cpp +++ b/launcher/modplatform/technic/TechnicPackProcessor.cpp @@ -155,8 +155,26 @@ void Technic::TechnicPackProcessor::run(SettingsObjectPtr globalSettings, auto libraryObject = Json::ensureObject(library, {}, ""); auto libraryName = Json::ensureString(libraryObject, "name", "", ""); - if ((libraryName.startsWith("net.minecraftforge:forge:") || libraryName.startsWith("net.minecraftforge:fmlloader:")) && - libraryName.contains('-')) { + if (libraryName.startsWith("net.neoforged.fancymodloader:")) { // it is neoforge + // no easy way to get the version from the libs so use the arguments + auto arguments = Json::ensureObject(root, "arguments", {}); + bool isVersionArg = false; + QString neoforgeVersion; + for (auto arg : Json::ensureArray(arguments, "game", {})) { + auto argument = Json::ensureString(arg, ""); + if (isVersionArg) { + neoforgeVersion = argument; + break; + } else { + isVersionArg = "--fml.neoForgeVersion" == argument || "--fml.forgeVersion" == argument; + } + } + if (!neoforgeVersion.isEmpty()) { + components->setComponentVersion("net.neoforged", neoforgeVersion); + } + break; + } else if ((libraryName.startsWith("net.minecraftforge:forge:") || libraryName.startsWith("net.minecraftforge:fmlloader:")) && + libraryName.contains('-')) { QString libraryVersion = libraryName.section(':', 2); if (!libraryVersion.startsWith("1.7.10-")) { components->setComponentVersion("net.minecraftforge", libraryName.section('-', 1)); @@ -164,6 +182,7 @@ void Technic::TechnicPackProcessor::run(SettingsObjectPtr globalSettings, // 1.7.10 versions sometimes look like 1.7.10-10.13.4.1614-1.7.10, this filters out the 10.13.4.1614 part components->setComponentVersion("net.minecraftforge", libraryName.section('-', 1, 1)); } + break; } else { // -> static QMap loaderMap{ { "net.minecraftforge:minecraftforge:", "net.minecraftforge" }, From d74926e60dd879d0f5b0dab307cf8b9259fcbaf7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 12 May 2024 00:20:20 +0000 Subject: [PATCH 208/223] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'nixpkgs': 'github:nixos/nixpkgs/5fd8536a9a5932d4ae8de52b7dc08d92041237fc' (2024-05-03) → 'github:nixos/nixpkgs/e4e7a43a9db7e22613accfeb1005cca1b2b1ee0d' (2024-05-11) --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 78f774342..740d5c43e 100644 --- a/flake.lock +++ b/flake.lock @@ -93,11 +93,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1714750952, - "narHash": "sha256-oOUdvPrO8CbupgDSaPou+Jv6GL+uQA2QlE33D7OLzkM=", + "lastModified": 1715413075, + "narHash": "sha256-FCi3R1MeS5bVp0M0xTheveP6hhcCYfW/aghSTPebYL4=", "owner": "nixos", "repo": "nixpkgs", - "rev": "5fd8536a9a5932d4ae8de52b7dc08d92041237fc", + "rev": "e4e7a43a9db7e22613accfeb1005cca1b2b1ee0d", "type": "github" }, "original": { From 3336f8107c48e8d0c85e45fcc2e0ca46db25fc10 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Mon, 13 May 2024 23:25:08 +0300 Subject: [PATCH 209/223] Removed AuthRequest and NetAction Signed-off-by: Trial97 --- launcher/CMakeLists.txt | 4 - launcher/InstanceCreationTask.cpp | 2 - launcher/InstanceCreationTask.h | 2 +- launcher/minecraft/AssetsUtils.cpp | 3 +- launcher/minecraft/AssetsUtils.h | 4 +- launcher/minecraft/Library.cpp | 11 +- launcher/minecraft/Library.h | 10 +- launcher/minecraft/auth/AccountList.cpp | 5 +- launcher/minecraft/auth/AuthRequest.cpp | 175 ------------------ launcher/minecraft/auth/AuthRequest.h | 67 ------- launcher/minecraft/auth/AuthStep.cpp | 2 - launcher/minecraft/auth/AuthStep.h | 3 +- launcher/minecraft/auth/MinecraftAccount.cpp | 2 +- launcher/minecraft/auth/flows/Offline.cpp | 5 - launcher/minecraft/auth/flows/Offline.h | 6 - .../minecraft/auth/steps/EntitlementsStep.cpp | 50 ++--- .../minecraft/auth/steps/EntitlementsStep.h | 12 +- launcher/minecraft/auth/steps/GetSkinStep.cpp | 34 ++-- launcher/minecraft/auth/steps/GetSkinStep.h | 12 +- .../auth/steps/LauncherLoginStep.cpp | 54 +++--- .../minecraft/auth/steps/LauncherLoginStep.h | 12 +- launcher/minecraft/auth/steps/MSAStep.cpp | 20 -- launcher/minecraft/auth/steps/MSAStep.h | 3 +- .../auth/steps/MinecraftProfileStep.cpp | 57 +++--- .../auth/steps/MinecraftProfileStep.h | 12 +- launcher/minecraft/auth/steps/OfflineStep.cpp | 8 - launcher/minecraft/auth/steps/OfflineStep.h | 6 +- .../auth/steps/XboxAuthorizationStep.cpp | 59 +++--- .../auth/steps/XboxAuthorizationStep.h | 13 +- .../minecraft/auth/steps/XboxProfileStep.cpp | 55 +++--- .../minecraft/auth/steps/XboxProfileStep.h | 12 +- .../minecraft/auth/steps/XboxUserStep.cpp | 51 +++-- launcher/minecraft/auth/steps/XboxUserStep.h | 12 +- .../helpers/NetworkResourceAPI.cpp | 12 +- .../modrinth/ModrinthInstanceCreationTask.cpp | 2 +- launcher/net/ApiDownload.cpp | 1 - launcher/net/ApiUpload.cpp | 3 - launcher/net/Download.cpp | 2 - launcher/net/NetAction.h | 100 ---------- launcher/net/NetJob.cpp | 11 +- launcher/net/NetJob.h | 6 +- launcher/net/NetRequest.cpp | 36 +++- launcher/net/NetRequest.h | 44 +++-- launcher/net/Sink.h | 3 +- launcher/net/Validator.h | 2 +- launcher/ui/dialogs/ProfileSetupDialog.cpp | 73 ++++---- launcher/ui/dialogs/ProfileSetupDialog.h | 12 +- .../ui/pages/modplatform/ResourceModel.cpp | 4 +- .../modplatform/modrinth/ModrinthModel.cpp | 4 +- tests/Library_test.cpp | 26 +-- 50 files changed, 381 insertions(+), 743 deletions(-) delete mode 100644 launcher/minecraft/auth/AuthRequest.cpp delete mode 100644 launcher/minecraft/auth/AuthRequest.h delete mode 100644 launcher/net/NetAction.h diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index e93219015..cf1ab8798 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -126,7 +126,6 @@ set(NET_SOURCES net/MetaCacheSink.h net/Logging.h net/Logging.cpp - net/NetAction.h net/NetJob.cpp net/NetJob.h net/NetUtils.h @@ -212,8 +211,6 @@ set(MINECRAFT_SOURCES minecraft/auth/AccountList.h minecraft/auth/AccountTask.cpp minecraft/auth/AccountTask.h - minecraft/auth/AuthRequest.cpp - minecraft/auth/AuthRequest.h minecraft/auth/AuthSession.cpp minecraft/auth/AuthSession.h minecraft/auth/AuthStep.cpp @@ -624,7 +621,6 @@ set(PRISMUPDATER_SOURCES net/HttpMetaCache.h net/Logging.h net/Logging.cpp - net/NetAction.h net/NetRequest.cpp net/NetRequest.h net/NetJob.cpp diff --git a/launcher/InstanceCreationTask.cpp b/launcher/InstanceCreationTask.cpp index 73dc17891..1499199ae 100644 --- a/launcher/InstanceCreationTask.cpp +++ b/launcher/InstanceCreationTask.cpp @@ -3,8 +3,6 @@ #include #include -InstanceCreationTask::InstanceCreationTask() = default; - void InstanceCreationTask::executeTask() { setAbortable(true); diff --git a/launcher/InstanceCreationTask.h b/launcher/InstanceCreationTask.h index 380fdf8a4..84fb2a145 100644 --- a/launcher/InstanceCreationTask.h +++ b/launcher/InstanceCreationTask.h @@ -6,7 +6,7 @@ class InstanceCreationTask : public InstanceTask { Q_OBJECT public: - InstanceCreationTask(); + InstanceCreationTask() = default; virtual ~InstanceCreationTask() = default; protected: diff --git a/launcher/minecraft/AssetsUtils.cpp b/launcher/minecraft/AssetsUtils.cpp index 48e150d16..6bbe0bb2c 100644 --- a/launcher/minecraft/AssetsUtils.cpp +++ b/launcher/minecraft/AssetsUtils.cpp @@ -51,6 +51,7 @@ #include "net/Download.h" #include "Application.h" +#include "net/NetRequest.h" namespace { QSet collectPathsFromDir(QString dirPath) @@ -276,7 +277,7 @@ bool reconstructAssets(QString assetsId, QString resourcesFolder) } // namespace AssetsUtils -NetAction::Ptr AssetObject::getDownloadAction() +Net::NetRequest::Ptr AssetObject::getDownloadAction() { QFileInfo objectFile(getLocalPath()); if ((!objectFile.isFile()) || (objectFile.size() != size)) { diff --git a/launcher/minecraft/AssetsUtils.h b/launcher/minecraft/AssetsUtils.h index 87956e57a..ea3613bd0 100644 --- a/launcher/minecraft/AssetsUtils.h +++ b/launcher/minecraft/AssetsUtils.h @@ -17,14 +17,14 @@ #include #include -#include "net/NetAction.h" #include "net/NetJob.h" +#include "net/NetRequest.h" struct AssetObject { QString getRelPath(); QUrl getUrl(); QString getLocalPath(); - NetAction::Ptr getDownloadAction(); + Net::NetRequest::Ptr getDownloadAction(); QString hash; qint64 size; diff --git a/launcher/minecraft/Library.cpp b/launcher/minecraft/Library.cpp index 0e8ddf03d..2c3f2035f 100644 --- a/launcher/minecraft/Library.cpp +++ b/launcher/minecraft/Library.cpp @@ -35,6 +35,7 @@ #include "Library.h" #include "MinecraftInstance.h" +#include "net/NetRequest.h" #include #include @@ -74,12 +75,12 @@ void Library::getApplicableFiles(const RuntimeContext& runtimeContext, } } -QList Library::getDownloads(const RuntimeContext& runtimeContext, - class HttpMetaCache* cache, - QStringList& failedLocalFiles, - const QString& overridePath) const +QList Library::getDownloads(const RuntimeContext& runtimeContext, + class HttpMetaCache* cache, + QStringList& failedLocalFiles, + const QString& overridePath) const { - QList out; + QList out; bool stale = isAlwaysStale(); bool local = isLocal(); diff --git a/launcher/minecraft/Library.h b/launcher/minecraft/Library.h index adb89c4c6..d3019e814 100644 --- a/launcher/minecraft/Library.h +++ b/launcher/minecraft/Library.h @@ -34,7 +34,6 @@ */ #pragma once -#include #include #include #include @@ -48,6 +47,7 @@ #include "MojangDownloadInfo.h" #include "Rule.h" #include "RuntimeContext.h" +#include "net/NetRequest.h" class Library; class MinecraftInstance; @@ -144,10 +144,10 @@ class Library { bool isForge() const; // Get a list of downloads for this library - QList getDownloads(const RuntimeContext& runtimeContext, - class HttpMetaCache* cache, - QStringList& failedLocalFiles, - const QString& overridePath) const; + QList getDownloads(const RuntimeContext& runtimeContext, + class HttpMetaCache* cache, + QStringList& failedLocalFiles, + const QString& overridePath) const; QString getCompatibleNative(const RuntimeContext& runtimeContext) const; diff --git a/launcher/minecraft/auth/AccountList.cpp b/launcher/minecraft/auth/AccountList.cpp index 68ebe3626..af83502bc 100644 --- a/launcher/minecraft/auth/AccountList.cpp +++ b/launcher/minecraft/auth/AccountList.cpp @@ -36,6 +36,7 @@ #include "AccountList.h" #include "AccountData.h" #include "AccountTask.h" +#include "tasks/Task.h" #include #include @@ -639,8 +640,8 @@ void AccountList::tryNext() if (account->internalId() == accountId) { m_currentTask = account->refresh(); if (m_currentTask) { - connect(m_currentTask.get(), &AccountTask::succeeded, this, &AccountList::authSucceeded); - connect(m_currentTask.get(), &AccountTask::failed, this, &AccountList::authFailed); + connect(m_currentTask.get(), &Task::succeeded, this, &AccountList::authSucceeded); + connect(m_currentTask.get(), &Task::failed, this, &AccountList::authFailed); m_currentTask->start(); qDebug() << "RefreshSchedule: Processing account " << account->accountDisplayString() << " with internal ID " << accountId; diff --git a/launcher/minecraft/auth/AuthRequest.cpp b/launcher/minecraft/auth/AuthRequest.cpp deleted file mode 100644 index 189978cc0..000000000 --- a/launcher/minecraft/auth/AuthRequest.cpp +++ /dev/null @@ -1,175 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -/* - * Prism Launcher - Minecraft Launcher - * Copyright (C) 2022 Sefa Eyeoglu - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * - * Copyright 2013-2021 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include -#include -#include -#include - -#include "Application.h" -#include "AuthRequest.h" -#include "katabasis/Globals.h" - -AuthRequest::AuthRequest(QObject* parent) : QObject(parent) {} - -AuthRequest::~AuthRequest() {} - -void AuthRequest::get(const QNetworkRequest& req, int timeout /* = 60*1000*/) -{ - setup(req, QNetworkAccessManager::GetOperation); - reply_ = APPLICATION->network()->get(request_); - status_ = Requesting; - timedReplies_.add(new Katabasis::Reply(reply_, timeout)); -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15 - connect(reply_, &QNetworkReply::errorOccurred, this, &AuthRequest::onRequestError); -#else // &QNetworkReply::error SIGNAL depricated - connect(reply_, QOverload::of(&QNetworkReply::error), this, &AuthRequest::onRequestError); -#endif - connect(reply_, &QNetworkReply::finished, this, &AuthRequest::onRequestFinished); - connect(reply_, &QNetworkReply::sslErrors, this, &AuthRequest::onSslErrors); -} - -void AuthRequest::post(const QNetworkRequest& req, const QByteArray& data, int timeout /* = 60*1000*/) -{ - setup(req, QNetworkAccessManager::PostOperation); - data_ = data; - status_ = Requesting; - reply_ = APPLICATION->network()->post(request_, data_); - timedReplies_.add(new Katabasis::Reply(reply_, timeout)); -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15 - connect(reply_, &QNetworkReply::errorOccurred, this, &AuthRequest::onRequestError); -#else // &QNetworkReply::error SIGNAL depricated - connect(reply_, QOverload::of(&QNetworkReply::error), this, &AuthRequest::onRequestError); -#endif - connect(reply_, &QNetworkReply::finished, this, &AuthRequest::onRequestFinished); - connect(reply_, &QNetworkReply::sslErrors, this, &AuthRequest::onSslErrors); - connect(reply_, &QNetworkReply::uploadProgress, this, &AuthRequest::onUploadProgress); -} - -void AuthRequest::onRequestFinished() -{ - if (status_ == Idle) { - return; - } - if (reply_ != qobject_cast(sender())) { - return; - } - httpStatus_ = reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - finish(); -} - -void AuthRequest::onRequestError(QNetworkReply::NetworkError error) -{ - qWarning() << "AuthRequest::onRequestError: Error" << (int)error; - if (status_ == Idle) { - return; - } - if (reply_ != qobject_cast(sender())) { - return; - } - errorString_ = reply_->errorString(); - httpStatus_ = reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - error_ = error; - qWarning() << "AuthRequest::onRequestError: Error string: " << errorString_; - qWarning() << "AuthRequest::onRequestError: HTTP status" << httpStatus_ - << reply_->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString(); - - // QTimer::singleShot(10, this, SLOT(finish())); -} - -void AuthRequest::onSslErrors(QList errors) -{ - int i = 1; - for (auto error : errors) { - qCritical() << "LOGIN SSL Error #" << i << " : " << error.errorString(); - auto cert = error.certificate(); - qCritical() << "Certificate in question:\n" << cert.toText(); - i++; - } -} - -void AuthRequest::onUploadProgress(qint64 uploaded, qint64 total) -{ - if (status_ == Idle) { - qWarning() << "AuthRequest::onUploadProgress: No pending request"; - return; - } - if (reply_ != qobject_cast(sender())) { - return; - } - // Restart timeout because request in progress - Katabasis::Reply* o2Reply = timedReplies_.find(reply_); - if (o2Reply) { - o2Reply->start(); - } - emit uploadProgress(uploaded, total); -} - -void AuthRequest::setup(const QNetworkRequest& req, QNetworkAccessManager::Operation operation, const QByteArray& verb) -{ - request_ = req; - operation_ = operation; - url_ = req.url(); - - QUrl url = url_; - request_.setUrl(url); - - if (!verb.isEmpty()) { - request_.setRawHeader(Katabasis::HTTP_HTTP_HEADER, verb); - } - - status_ = Requesting; - error_ = QNetworkReply::NoError; - errorString_.clear(); - httpStatus_ = 0; -} - -void AuthRequest::finish() -{ - QByteArray data; - if (status_ == Idle) { - qWarning() << "AuthRequest::finish: No pending request"; - return; - } - data = reply_->readAll(); - status_ = Idle; - timedReplies_.remove(reply_); - reply_->disconnect(this); - reply_->deleteLater(); - QList headers = reply_->rawHeaderPairs(); - emit finished(error_, data, headers); -} diff --git a/launcher/minecraft/auth/AuthRequest.h b/launcher/minecraft/auth/AuthRequest.h deleted file mode 100644 index 84d2a7d68..000000000 --- a/launcher/minecraft/auth/AuthRequest.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include - -#include "katabasis/Reply.h" - -/// Makes authentication requests. -class AuthRequest : public QObject { - Q_OBJECT - - public: - explicit AuthRequest(QObject* parent = 0); - ~AuthRequest(); - - public slots: - void get(const QNetworkRequest& req, int timeout = 60 * 1000); - void post(const QNetworkRequest& req, const QByteArray& data, int timeout = 60 * 1000); - - signals: - - /// Emitted when a request has been completed or failed. - void finished(QNetworkReply::NetworkError error, QByteArray data, QList headers); - - /// Emitted when an upload has progressed. - void uploadProgress(qint64 bytesSent, qint64 bytesTotal); - - protected slots: - - /// Handle request finished. - void onRequestFinished(); - - /// Handle request error. - void onRequestError(QNetworkReply::NetworkError error); - - /// Handle ssl errors. - void onSslErrors(QList errors); - - /// Finish the request, emit finished() signal. - void finish(); - - /// Handle upload progress. - void onUploadProgress(qint64 uploaded, qint64 total); - - public: - QNetworkReply::NetworkError error_; - int httpStatus_ = 0; - QString errorString_; - - protected: - void setup(const QNetworkRequest& request, QNetworkAccessManager::Operation operation, const QByteArray& verb = QByteArray()); - - enum Status { Idle, Requesting, ReRequesting }; - - QNetworkRequest request_; - QByteArray data_; - QNetworkReply* reply_; - Status status_; - QNetworkAccessManager::Operation operation_; - QUrl url_; - Katabasis::ReplyList timedReplies_; - - QTimer* timer_; -}; diff --git a/launcher/minecraft/auth/AuthStep.cpp b/launcher/minecraft/auth/AuthStep.cpp index 6240cc549..6b78c415a 100644 --- a/launcher/minecraft/auth/AuthStep.cpp +++ b/launcher/minecraft/auth/AuthStep.cpp @@ -1,5 +1,3 @@ #include "AuthStep.h" AuthStep::AuthStep(AccountData* data) : QObject(nullptr), m_data(data) {} - -AuthStep::~AuthStep() noexcept = default; diff --git a/launcher/minecraft/auth/AuthStep.h b/launcher/minecraft/auth/AuthStep.h index becd9b0c5..b837b5703 100644 --- a/launcher/minecraft/auth/AuthStep.h +++ b/launcher/minecraft/auth/AuthStep.h @@ -15,13 +15,12 @@ class AuthStep : public QObject { public: explicit AuthStep(AccountData* data); - virtual ~AuthStep() noexcept; + virtual ~AuthStep() noexcept = default; virtual QString describe() = 0; public slots: virtual void perform() = 0; - virtual void rehydrate() = 0; signals: void finished(AccountTaskState resultingState, QString message); diff --git a/launcher/minecraft/auth/MinecraftAccount.cpp b/launcher/minecraft/auth/MinecraftAccount.cpp index ecee93d98..db4d1c07b 100644 --- a/launcher/minecraft/auth/MinecraftAccount.cpp +++ b/launcher/minecraft/auth/MinecraftAccount.cpp @@ -153,7 +153,7 @@ shared_qobject_ptr MinecraftAccount::refresh() if (data.type == AccountType::MSA) { m_currentTask.reset(new MSASilent(&data)); } else { - m_currentTask.reset(new OfflineRefresh(&data)); + m_currentTask.reset(new OfflineLogin(&data)); } connect(m_currentTask.get(), &Task::succeeded, this, &MinecraftAccount::authSucceeded); diff --git a/launcher/minecraft/auth/flows/Offline.cpp b/launcher/minecraft/auth/flows/Offline.cpp index 3770b869a..1836533bd 100644 --- a/launcher/minecraft/auth/flows/Offline.cpp +++ b/launcher/minecraft/auth/flows/Offline.cpp @@ -2,11 +2,6 @@ #include "minecraft/auth/steps/OfflineStep.h" -OfflineRefresh::OfflineRefresh(AccountData* data, QObject* parent) : AuthFlow(data, parent) -{ - m_steps.append(makeShared(m_data)); -} - OfflineLogin::OfflineLogin(AccountData* data, QObject* parent) : AuthFlow(data, parent) { m_steps.append(makeShared(m_data)); diff --git a/launcher/minecraft/auth/flows/Offline.h b/launcher/minecraft/auth/flows/Offline.h index 2bc9c7612..a8d378e16 100644 --- a/launcher/minecraft/auth/flows/Offline.h +++ b/launcher/minecraft/auth/flows/Offline.h @@ -1,12 +1,6 @@ #pragma once #include "AuthFlow.h" -class OfflineRefresh : public AuthFlow { - Q_OBJECT - public: - explicit OfflineRefresh(AccountData* data, QObject* parent = 0); -}; - class OfflineLogin : public AuthFlow { Q_OBJECT public: diff --git a/launcher/minecraft/auth/steps/EntitlementsStep.cpp b/launcher/minecraft/auth/steps/EntitlementsStep.cpp index 0573dcb6e..19cbe6898 100644 --- a/launcher/minecraft/auth/steps/EntitlementsStep.cpp +++ b/launcher/minecraft/auth/steps/EntitlementsStep.cpp @@ -1,16 +1,20 @@ #include "EntitlementsStep.h" +#include #include +#include #include +#include +#include "Application.h" #include "Logging.h" -#include "minecraft/auth/AuthRequest.h" #include "minecraft/auth/Parsers.h" +#include "net/Download.h" +#include "net/StaticHeaderProxy.h" +#include "tasks/Task.h" EntitlementsStep::EntitlementsStep(AccountData* data) : AuthStep(data) {} -EntitlementsStep::~EntitlementsStep() noexcept = default; - QString EntitlementsStep::describe() { return tr("Determining game ownership."); @@ -19,35 +23,31 @@ QString EntitlementsStep::describe() void EntitlementsStep::perform() { auto uuid = QUuid::createUuid(); - m_entitlementsRequestId = uuid.toString().remove('{').remove('}'); - auto url = "https://api.minecraftservices.com/entitlements/license?requestId=" + m_entitlementsRequestId; - QNetworkRequest request = QNetworkRequest(url); - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - request.setRawHeader("Accept", "application/json"); - request.setRawHeader("Authorization", QString("Bearer %1").arg(m_data->yggdrasilToken.token).toUtf8()); - AuthRequest* requestor = new AuthRequest(this); - connect(requestor, &AuthRequest::finished, this, &EntitlementsStep::onRequestDone); - requestor->get(request); + m_entitlements_request_id = uuid.toString().remove('{').remove('}'); + + QUrl url("https://api.minecraftservices.com/entitlements/license?requestId=" + m_entitlements_request_id); + auto headers = QList{ { "Content-Type", "application/json" }, + { "Accept", "application/json" }, + { "Authorization", QString("Bearer %1").arg(m_data->yggdrasilToken.token).toUtf8() } }; + + m_response.reset(new QByteArray()); + m_task = Net::Download::makeByteArray(url, m_response); + m_task->addHeaderProxy(new Net::StaticHeaderProxy(headers)); + + connect(m_task.get(), &Task::finished, this, &EntitlementsStep::onRequestDone); + + m_task->setNetwork(APPLICATION->network()); + m_task->start(); qDebug() << "Getting entitlements..."; } -void EntitlementsStep::rehydrate() +void EntitlementsStep::onRequestDone() { - // NOOP, for now. We only save bools and there's nothing to check. -} - -void EntitlementsStep::onRequestDone([[maybe_unused]] QNetworkReply::NetworkError error, - QByteArray data, - [[maybe_unused]] QList headers) -{ - auto requestor = qobject_cast(QObject::sender()); - requestor->deleteLater(); - - qCDebug(authCredentials()) << data; + qCDebug(authCredentials()) << *m_response; // TODO: check presence of same entitlementsRequestId? // TODO: validate JWTs? - Parsers::parseMinecraftEntitlements(data, m_data->minecraftEntitlement); + Parsers::parseMinecraftEntitlements(*m_response, m_data->minecraftEntitlement); emit finished(AccountTaskState::STATE_WORKING, tr("Got entitlements")); } diff --git a/launcher/minecraft/auth/steps/EntitlementsStep.h b/launcher/minecraft/auth/steps/EntitlementsStep.h index be16bda13..dd8ec7aaa 100644 --- a/launcher/minecraft/auth/steps/EntitlementsStep.h +++ b/launcher/minecraft/auth/steps/EntitlementsStep.h @@ -1,24 +1,26 @@ #pragma once #include +#include -#include "QObjectPtr.h" #include "minecraft/auth/AuthStep.h" +#include "net/Download.h" class EntitlementsStep : public AuthStep { Q_OBJECT public: explicit EntitlementsStep(AccountData* data); - virtual ~EntitlementsStep() noexcept; + virtual ~EntitlementsStep() noexcept = default; void perform() override; - void rehydrate() override; QString describe() override; private slots: - void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList); + void onRequestDone(); private: - QString m_entitlementsRequestId; + QString m_entitlements_request_id; + std::shared_ptr m_response; + Net::Download::Ptr m_task; }; diff --git a/launcher/minecraft/auth/steps/GetSkinStep.cpp b/launcher/minecraft/auth/steps/GetSkinStep.cpp index 520877020..d9785b16a 100644 --- a/launcher/minecraft/auth/steps/GetSkinStep.cpp +++ b/launcher/minecraft/auth/steps/GetSkinStep.cpp @@ -3,13 +3,10 @@ #include -#include "minecraft/auth/AuthRequest.h" -#include "minecraft/auth/Parsers.h" +#include "Application.h" GetSkinStep::GetSkinStep(AccountData* data) : AuthStep(data) {} -GetSkinStep::~GetSkinStep() noexcept = default; - QString GetSkinStep::describe() { return tr("Getting skin."); @@ -17,25 +14,20 @@ QString GetSkinStep::describe() void GetSkinStep::perform() { - auto url = QUrl(m_data->minecraftProfile.skin.url); - QNetworkRequest request = QNetworkRequest(url); - AuthRequest* requestor = new AuthRequest(this); - connect(requestor, &AuthRequest::finished, this, &GetSkinStep::onRequestDone); - requestor->get(request); + QUrl url(m_data->minecraftProfile.skin.url); + + m_response.reset(new QByteArray()); + m_task = Net::Download::makeByteArray(url, m_response); + + connect(m_task.get(), &Task::finished, this, &GetSkinStep::onRequestDone); + + m_task->setNetwork(APPLICATION->network()); + m_task->start(); } -void GetSkinStep::rehydrate() +void GetSkinStep::onRequestDone() { - // NOOP, for now. -} - -void GetSkinStep::onRequestDone(QNetworkReply::NetworkError error, QByteArray data, QList headers) -{ - auto requestor = qobject_cast(QObject::sender()); - requestor->deleteLater(); - - if (error == QNetworkReply::NoError) { - m_data->minecraftProfile.skin.data = data; - } + if (m_task->error() == QNetworkReply::NoError) + m_data->minecraftProfile.skin.data = *m_response; emit finished(AccountTaskState::STATE_SUCCEEDED, tr("Got skin")); } diff --git a/launcher/minecraft/auth/steps/GetSkinStep.h b/launcher/minecraft/auth/steps/GetSkinStep.h index 105e497d1..fffd8be03 100644 --- a/launcher/minecraft/auth/steps/GetSkinStep.h +++ b/launcher/minecraft/auth/steps/GetSkinStep.h @@ -1,21 +1,25 @@ #pragma once #include +#include -#include "QObjectPtr.h" #include "minecraft/auth/AuthStep.h" +#include "net/Download.h" class GetSkinStep : public AuthStep { Q_OBJECT public: explicit GetSkinStep(AccountData* data); - virtual ~GetSkinStep() noexcept; + virtual ~GetSkinStep() noexcept = default; void perform() override; - void rehydrate() override; QString describe() override; private slots: - void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList); + void onRequestDone(); + + private: + std::shared_ptr m_response; + Net::Download::Ptr m_task; }; diff --git a/launcher/minecraft/auth/steps/LauncherLoginStep.cpp b/launcher/minecraft/auth/steps/LauncherLoginStep.cpp index c57f51113..8981c5752 100644 --- a/launcher/minecraft/auth/steps/LauncherLoginStep.cpp +++ b/launcher/minecraft/auth/steps/LauncherLoginStep.cpp @@ -1,17 +1,18 @@ #include "LauncherLoginStep.h" #include +#include +#include "Application.h" #include "Logging.h" #include "minecraft/auth/AccountTask.h" -#include "minecraft/auth/AuthRequest.h" #include "minecraft/auth/Parsers.h" #include "net/NetUtils.h" +#include "net/StaticHeaderProxy.h" +#include "net/Upload.h" LauncherLoginStep::LauncherLoginStep(AccountData* data) : AuthStep(data) {} -LauncherLoginStep::~LauncherLoginStep() noexcept = default; - QString LauncherLoginStep::describe() { return tr("Accessing Mojang services."); @@ -19,7 +20,7 @@ QString LauncherLoginStep::describe() void LauncherLoginStep::perform() { - auto requestURL = "https://api.minecraftservices.com/launcher/login"; + QUrl url("https://api.minecraftservices.com/launcher/login"); auto uhs = m_data->mojangservicesToken.extra["uhs"].toString(); auto xToken = m_data->mojangservicesToken.token; @@ -31,40 +32,37 @@ void LauncherLoginStep::perform() )XXX"; auto requestBody = mc_auth_template.arg(uhs, xToken); - QNetworkRequest request = QNetworkRequest(QUrl(requestURL)); - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - request.setRawHeader("Accept", "application/json"); - AuthRequest* requestor = new AuthRequest(this); - connect(requestor, &AuthRequest::finished, this, &LauncherLoginStep::onRequestDone); - requestor->post(request, requestBody.toUtf8()); + auto headers = QList{ + { "Content-Type", "application/json" }, + { "Accept", "application/json" }, + }; + + m_response.reset(new QByteArray()); + m_task = Net::Upload::makeByteArray(url, m_response, requestBody.toUtf8()); + m_task->addHeaderProxy(new Net::StaticHeaderProxy(headers)); + + connect(m_task.get(), &Task::finished, this, &LauncherLoginStep::onRequestDone); + + m_task->setNetwork(APPLICATION->network()); + m_task->start(); qDebug() << "Getting Minecraft access token..."; } -void LauncherLoginStep::rehydrate() +void LauncherLoginStep::onRequestDone() { - // TODO: check the token validity -} - -void LauncherLoginStep::onRequestDone(QNetworkReply::NetworkError error, QByteArray data, QList headers) -{ - auto requestor = qobject_cast(QObject::sender()); - requestor->deleteLater(); - - qCDebug(authCredentials()) << data; - if (error != QNetworkReply::NoError) { - qWarning() << "Reply error:" << error; - qCDebug(authCredentials()) << data; - if (Net::isApplicationError(error)) { - emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("Failed to get Minecraft access token: %1").arg(requestor->errorString_)); + qCDebug(authCredentials()) << *m_response; + if (m_task->error() != QNetworkReply::NoError) { + qWarning() << "Reply error:" << m_task->error(); + if (Net::isApplicationError(m_task->error())) { + emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("Failed to get Minecraft access token: %1").arg(m_task->errorString())); } else { - emit finished(AccountTaskState::STATE_OFFLINE, tr("Failed to get Minecraft access token: %1").arg(requestor->errorString_)); + emit finished(AccountTaskState::STATE_OFFLINE, tr("Failed to get Minecraft access token: %1").arg(m_task->errorString())); } return; } - if (!Parsers::parseMojangResponse(data, m_data->yggdrasilToken)) { + if (!Parsers::parseMojangResponse(*m_response, m_data->yggdrasilToken)) { qWarning() << "Could not parse login_with_xbox response..."; - qCDebug(authCredentials()) << data; emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("Failed to parse the Minecraft access token response.")); return; } diff --git a/launcher/minecraft/auth/steps/LauncherLoginStep.h b/launcher/minecraft/auth/steps/LauncherLoginStep.h index 30c18e675..21a2a4920 100644 --- a/launcher/minecraft/auth/steps/LauncherLoginStep.h +++ b/launcher/minecraft/auth/steps/LauncherLoginStep.h @@ -1,21 +1,25 @@ #pragma once #include +#include -#include "QObjectPtr.h" #include "minecraft/auth/AuthStep.h" +#include "net/Upload.h" class LauncherLoginStep : public AuthStep { Q_OBJECT public: explicit LauncherLoginStep(AccountData* data); - virtual ~LauncherLoginStep() noexcept; + virtual ~LauncherLoginStep() noexcept = default; void perform() override; - void rehydrate() override; QString describe() override; private slots: - void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList); + void onRequestDone(); + + private: + std::shared_ptr m_response; + Net::Upload::Ptr m_task; }; diff --git a/launcher/minecraft/auth/steps/MSAStep.cpp b/launcher/minecraft/auth/steps/MSAStep.cpp index 1aa22765d..0a4b7c814 100644 --- a/launcher/minecraft/auth/steps/MSAStep.cpp +++ b/launcher/minecraft/auth/steps/MSAStep.cpp @@ -37,10 +37,6 @@ #include -#include "BuildConfig.h" -#include "minecraft/auth/AuthRequest.h" -#include "minecraft/auth/Parsers.h" - #include "Application.h" #include "Logging.h" @@ -63,27 +59,11 @@ MSAStep::MSAStep(AccountData* data, Action action) : AuthStep(data), m_action(ac connect(m_oauth2, &OAuth2::showVerificationUriAndCode, this, &MSAStep::showVerificationUriAndCode); } -MSAStep::~MSAStep() noexcept = default; - QString MSAStep::describe() { return tr("Logging in with Microsoft account."); } -void MSAStep::rehydrate() -{ - switch (m_action) { - case Refresh: { - // TODO: check the tokens and see if they are old (older than a day) - return; - } - case Login: { - // NOOP - return; - } - } -} - void MSAStep::perform() { switch (m_action) { diff --git a/launcher/minecraft/auth/steps/MSAStep.h b/launcher/minecraft/auth/steps/MSAStep.h index b6635d4a5..ee441308f 100644 --- a/launcher/minecraft/auth/steps/MSAStep.h +++ b/launcher/minecraft/auth/steps/MSAStep.h @@ -48,10 +48,9 @@ class MSAStep : public AuthStep { public: explicit MSAStep(AccountData* data, Action action); - virtual ~MSAStep() noexcept; + virtual ~MSAStep() noexcept = default; void perform() override; - void rehydrate() override; QString describe() override; diff --git a/launcher/minecraft/auth/steps/MinecraftProfileStep.cpp b/launcher/minecraft/auth/steps/MinecraftProfileStep.cpp index a854342bc..305f44320 100644 --- a/launcher/minecraft/auth/steps/MinecraftProfileStep.cpp +++ b/launcher/minecraft/auth/steps/MinecraftProfileStep.cpp @@ -2,15 +2,13 @@ #include -#include "Logging.h" -#include "minecraft/auth/AuthRequest.h" +#include "Application.h" #include "minecraft/auth/Parsers.h" #include "net/NetUtils.h" +#include "net/StaticHeaderProxy.h" MinecraftProfileStep::MinecraftProfileStep(AccountData* data) : AuthStep(data) {} -MinecraftProfileStep::~MinecraftProfileStep() noexcept = default; - QString MinecraftProfileStep::describe() { return tr("Fetching the Minecraft profile."); @@ -18,52 +16,47 @@ QString MinecraftProfileStep::describe() void MinecraftProfileStep::perform() { - auto url = QUrl("https://api.minecraftservices.com/minecraft/profile"); - QNetworkRequest request = QNetworkRequest(url); - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - request.setRawHeader("Authorization", QString("Bearer %1").arg(m_data->yggdrasilToken.token).toUtf8()); + QUrl url("https://api.minecraftservices.com/minecraft/profile"); + auto headers = QList{ { "Content-Type", "application/json" }, + { "Accept", "application/json" }, + { "Authorization", QString("Bearer %1").arg(m_data->yggdrasilToken.token).toUtf8() } }; - AuthRequest* requestor = new AuthRequest(this); - connect(requestor, &AuthRequest::finished, this, &MinecraftProfileStep::onRequestDone); - requestor->get(request); + m_response.reset(new QByteArray()); + m_task = Net::Download::makeByteArray(url, m_response); + m_task->addHeaderProxy(new Net::StaticHeaderProxy(headers)); + + connect(m_task.get(), &Task::finished, this, &MinecraftProfileStep::onRequestDone); + + m_task->setNetwork(APPLICATION->network()); + m_task->start(); } -void MinecraftProfileStep::rehydrate() +void MinecraftProfileStep::onRequestDone() { - // NOOP, for now. We only save bools and there's nothing to check. -} - -void MinecraftProfileStep::onRequestDone(QNetworkReply::NetworkError error, QByteArray data, QList headers) -{ - auto requestor = qobject_cast(QObject::sender()); - requestor->deleteLater(); - - qCDebug(authCredentials()) << data; - if (error == QNetworkReply::ContentNotFoundError) { + if (m_task->error() == QNetworkReply::ContentNotFoundError) { // NOTE: Succeed even if we do not have a profile. This is a valid account state. m_data->minecraftProfile = MinecraftProfile(); emit finished(AccountTaskState::STATE_SUCCEEDED, tr("Account has no Minecraft profile.")); return; } - if (error != QNetworkReply::NoError) { + if (m_task->error() != QNetworkReply::NoError) { qWarning() << "Error getting profile:"; - qWarning() << " HTTP Status: " << requestor->httpStatus_; - qWarning() << " Internal error no.: " << error; - qWarning() << " Error string: " << requestor->errorString_; + qWarning() << " HTTP Status: " << m_task->replyStatusCode(); + qWarning() << " Internal error no.: " << m_task->error(); + qWarning() << " Error string: " << m_task->errorString(); qWarning() << " Response:"; - qWarning() << QString::fromUtf8(data); + qWarning() << QString::fromUtf8(*m_response); - if (Net::isApplicationError(error)) { + if (Net::isApplicationError(m_task->error())) { emit finished(AccountTaskState::STATE_FAILED_SOFT, - tr("Minecraft Java profile acquisition failed: %1").arg(requestor->errorString_)); + tr("Minecraft Java profile acquisition failed: %1").arg(m_task->errorString())); } else { - emit finished(AccountTaskState::STATE_OFFLINE, - tr("Minecraft Java profile acquisition failed: %1").arg(requestor->errorString_)); + emit finished(AccountTaskState::STATE_OFFLINE, tr("Minecraft Java profile acquisition failed: %1").arg(m_task->errorString())); } return; } - if (!Parsers::parseMinecraftProfile(data, m_data->minecraftProfile)) { + if (!Parsers::parseMinecraftProfile(*m_response, m_data->minecraftProfile)) { m_data->minecraftProfile = MinecraftProfile(); emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("Minecraft Java profile response could not be parsed")); return; diff --git a/launcher/minecraft/auth/steps/MinecraftProfileStep.h b/launcher/minecraft/auth/steps/MinecraftProfileStep.h index cb30dab21..831cd52f7 100644 --- a/launcher/minecraft/auth/steps/MinecraftProfileStep.h +++ b/launcher/minecraft/auth/steps/MinecraftProfileStep.h @@ -1,21 +1,25 @@ #pragma once #include +#include -#include "QObjectPtr.h" #include "minecraft/auth/AuthStep.h" +#include "net/Download.h" class MinecraftProfileStep : public AuthStep { Q_OBJECT public: explicit MinecraftProfileStep(AccountData* data); - virtual ~MinecraftProfileStep() noexcept; + virtual ~MinecraftProfileStep() noexcept = default; void perform() override; - void rehydrate() override; QString describe() override; private slots: - void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList); + void onRequestDone(); + + private: + std::shared_ptr m_response; + Net::Download::Ptr m_task; }; diff --git a/launcher/minecraft/auth/steps/OfflineStep.cpp b/launcher/minecraft/auth/steps/OfflineStep.cpp index bf111abe8..a96b08377 100644 --- a/launcher/minecraft/auth/steps/OfflineStep.cpp +++ b/launcher/minecraft/auth/steps/OfflineStep.cpp @@ -1,20 +1,12 @@ #include "OfflineStep.h" -#include "Application.h" - OfflineStep::OfflineStep(AccountData* data) : AuthStep(data) {} -OfflineStep::~OfflineStep() noexcept = default; QString OfflineStep::describe() { return tr("Creating offline account."); } -void OfflineStep::rehydrate() -{ - // NOOP -} - void OfflineStep::perform() { emit finished(AccountTaskState::STATE_WORKING, tr("Created offline account.")); diff --git a/launcher/minecraft/auth/steps/OfflineStep.h b/launcher/minecraft/auth/steps/OfflineStep.h index 3bf123d6a..411879b10 100644 --- a/launcher/minecraft/auth/steps/OfflineStep.h +++ b/launcher/minecraft/auth/steps/OfflineStep.h @@ -1,19 +1,15 @@ #pragma once #include -#include "QObjectPtr.h" #include "minecraft/auth/AuthStep.h" -#include - class OfflineStep : public AuthStep { Q_OBJECT public: explicit OfflineStep(AccountData* data); - virtual ~OfflineStep() noexcept; + virtual ~OfflineStep() noexcept = default; void perform() override; - void rehydrate() override; QString describe() override; }; diff --git a/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp b/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp index 84c52c386..2ae3af0dd 100644 --- a/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp +++ b/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp @@ -4,27 +4,22 @@ #include #include +#include "Application.h" #include "Logging.h" -#include "minecraft/auth/AuthRequest.h" #include "minecraft/auth/Parsers.h" #include "net/NetUtils.h" +#include "net/StaticHeaderProxy.h" +#include "net/Upload.h" XboxAuthorizationStep::XboxAuthorizationStep(AccountData* data, Katabasis::Token* token, QString relyingParty, QString authorizationKind) : AuthStep(data), m_token(token), m_relyingParty(relyingParty), m_authorizationKind(authorizationKind) {} -XboxAuthorizationStep::~XboxAuthorizationStep() noexcept = default; - QString XboxAuthorizationStep::describe() { return tr("Getting authorization to access %1 services.").arg(m_authorizationKind); } -void XboxAuthorizationStep::rehydrate() -{ - // FIXME: check if the tokens are good? -} - void XboxAuthorizationStep::perform() { QString xbox_auth_template = R"XXX( @@ -41,40 +36,44 @@ void XboxAuthorizationStep::perform() )XXX"; auto xbox_auth_data = xbox_auth_template.arg(m_data->userToken.token, m_relyingParty); // http://xboxlive.com - QNetworkRequest request = QNetworkRequest(QUrl("https://xsts.auth.xboxlive.com/xsts/authorize")); - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - request.setRawHeader("Accept", "application/json"); - AuthRequest* requestor = new AuthRequest(this); - connect(requestor, &AuthRequest::finished, this, &XboxAuthorizationStep::onRequestDone); - requestor->post(request, xbox_auth_data.toUtf8()); + QUrl url("https://xsts.auth.xboxlive.com/xsts/authorize"); + auto headers = QList{ + { "Content-Type", "application/json" }, + { "Accept", "application/json" }, + }; + m_response.reset(new QByteArray()); + m_task = Net::Upload::makeByteArray(url, m_response, xbox_auth_data.toUtf8()); + m_task->addHeaderProxy(new Net::StaticHeaderProxy(headers)); + + connect(m_task.get(), &Task::finished, this, &XboxAuthorizationStep::onRequestDone); + + m_task->setNetwork(APPLICATION->network()); + m_task->start(); qDebug() << "Getting authorization token for " << m_relyingParty; } -void XboxAuthorizationStep::onRequestDone(QNetworkReply::NetworkError error, QByteArray data, QList headers) +void XboxAuthorizationStep::onRequestDone() { - auto requestor = qobject_cast(QObject::sender()); - requestor->deleteLater(); - - qCDebug(authCredentials()) << data; - if (error != QNetworkReply::NoError) { - qWarning() << "Reply error:" << error; - if (Net::isApplicationError(error)) { - if (!processSTSError(error, data, headers)) { + qCDebug(authCredentials()) << *m_response; + if (m_task->error() != QNetworkReply::NoError) { + qWarning() << "Reply error:" << m_task->error(); + if (Net::isApplicationError(m_task->error())) { + if (!processSTSError()) { emit finished(AccountTaskState::STATE_FAILED_SOFT, - tr("Failed to get authorization for %1 services. Error %2.").arg(m_authorizationKind, error)); + tr("Failed to get authorization for %1 services. Error %2.").arg(m_authorizationKind, m_task->error())); } else { emit finished(AccountTaskState::STATE_FAILED_SOFT, - tr("Unknown STS error for %1 services: %2").arg(m_authorizationKind, requestor->errorString_)); + tr("Unknown STS error for %1 services: %2").arg(m_authorizationKind, m_task->errorString())); } } else { emit finished(AccountTaskState::STATE_OFFLINE, - tr("Failed to get authorization for %1 services: %2").arg(m_authorizationKind, requestor->errorString_)); + tr("Failed to get authorization for %1 services: %2").arg(m_authorizationKind, m_task->errorString())); } return; } Katabasis::Token temp; - if (!Parsers::parseXTokenResponse(data, temp, m_authorizationKind)) { + if (!Parsers::parseXTokenResponse(*m_response, temp, m_authorizationKind)) { emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("Could not parse authorization response for access to %1 services.").arg(m_authorizationKind)); return; @@ -91,11 +90,11 @@ void XboxAuthorizationStep::onRequestDone(QNetworkReply::NetworkError error, QBy emit finished(AccountTaskState::STATE_WORKING, tr("Got authorization to access %1").arg(m_relyingParty)); } -bool XboxAuthorizationStep::processSTSError(QNetworkReply::NetworkError error, QByteArray data, QList headers) +bool XboxAuthorizationStep::processSTSError() { - if (error == QNetworkReply::AuthenticationRequiredError) { + if (m_task->error() == QNetworkReply::AuthenticationRequiredError) { QJsonParseError jsonError; - QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError); + QJsonDocument doc = QJsonDocument::fromJson(*m_response, &jsonError); if (jsonError.error) { qWarning() << "Cannot parse error XSTS response as JSON: " << jsonError.errorString(); emit finished(AccountTaskState::STATE_FAILED_SOFT, diff --git a/launcher/minecraft/auth/steps/XboxAuthorizationStep.h b/launcher/minecraft/auth/steps/XboxAuthorizationStep.h index dee24c954..eb7097f6f 100644 --- a/launcher/minecraft/auth/steps/XboxAuthorizationStep.h +++ b/launcher/minecraft/auth/steps/XboxAuthorizationStep.h @@ -1,29 +1,32 @@ #pragma once #include +#include -#include "QObjectPtr.h" #include "minecraft/auth/AuthStep.h" +#include "net/Upload.h" class XboxAuthorizationStep : public AuthStep { Q_OBJECT public: explicit XboxAuthorizationStep(AccountData* data, Katabasis::Token* token, QString relyingParty, QString authorizationKind); - virtual ~XboxAuthorizationStep() noexcept; + virtual ~XboxAuthorizationStep() noexcept = default; void perform() override; - void rehydrate() override; QString describe() override; private: - bool processSTSError(QNetworkReply::NetworkError error, QByteArray data, QList headers); + bool processSTSError(); private slots: - void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList); + void onRequestDone(); private: Katabasis::Token* m_token; QString m_relyingParty; QString m_authorizationKind; + + std::shared_ptr m_response; + Net::Upload::Ptr m_task; }; diff --git a/launcher/minecraft/auth/steps/XboxProfileStep.cpp b/launcher/minecraft/auth/steps/XboxProfileStep.cpp index fd2b32cce..440a4657c 100644 --- a/launcher/minecraft/auth/steps/XboxProfileStep.cpp +++ b/launcher/minecraft/auth/steps/XboxProfileStep.cpp @@ -3,28 +3,21 @@ #include #include +#include "Application.h" #include "Logging.h" -#include "minecraft/auth/AuthRequest.h" -#include "minecraft/auth/Parsers.h" #include "net/NetUtils.h" +#include "net/StaticHeaderProxy.h" XboxProfileStep::XboxProfileStep(AccountData* data) : AuthStep(data) {} -XboxProfileStep::~XboxProfileStep() noexcept = default; - QString XboxProfileStep::describe() { return tr("Fetching Xbox profile."); } -void XboxProfileStep::rehydrate() -{ - // NOOP, for now. We only save bools and there's nothing to check. -} - void XboxProfileStep::perform() { - auto url = QUrl("https://profile.xboxlive.com/users/me/profile/settings"); + QUrl url("https://profile.xboxlive.com/users/me/profile/settings"); QUrlQuery q; q.addQueryItem("settings", "GameDisplayName,AppDisplayName,AppDisplayPicRaw,GameDisplayPicRaw," @@ -33,36 +26,38 @@ void XboxProfileStep::perform() "PreferredColor,Location,Bio,Watermarks," "RealName,RealNameOverride,IsQuarantined"); url.setQuery(q); + auto headers = QList{ + { "Content-Type", "application/json" }, + { "Accept", "application/json" }, + { "x-xbl-contract-version", "3" }, + { "Authorization", QString("XBL3.0 x=%1;%2").arg(m_data->userToken.extra["uhs"].toString(), m_data->xboxApiToken.token).toUtf8() } + }; - QNetworkRequest request = QNetworkRequest(url); - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - request.setRawHeader("Accept", "application/json"); - request.setRawHeader("x-xbl-contract-version", "3"); - request.setRawHeader("Authorization", - QString("XBL3.0 x=%1;%2").arg(m_data->userToken.extra["uhs"].toString(), m_data->xboxApiToken.token).toUtf8()); - AuthRequest* requestor = new AuthRequest(this); - connect(requestor, &AuthRequest::finished, this, &XboxProfileStep::onRequestDone); - requestor->get(request); + m_response.reset(new QByteArray()); + m_task = Net::Download::makeByteArray(url, m_response); + m_task->addHeaderProxy(new Net::StaticHeaderProxy(headers)); + + connect(m_task.get(), &Task::finished, this, &XboxProfileStep::onRequestDone); + + m_task->setNetwork(APPLICATION->network()); + m_task->start(); qDebug() << "Getting Xbox profile..."; } -void XboxProfileStep::onRequestDone(QNetworkReply::NetworkError error, QByteArray data, QList headers) +void XboxProfileStep::onRequestDone() { - auto requestor = qobject_cast(QObject::sender()); - requestor->deleteLater(); - - if (error != QNetworkReply::NoError) { - qWarning() << "Reply error:" << error; - qCDebug(authCredentials()) << data; - if (Net::isApplicationError(error)) { - emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("Failed to retrieve the Xbox profile: %1").arg(requestor->errorString_)); + if (m_task->error() != QNetworkReply::NoError) { + qWarning() << "Reply error:" << m_task->error(); + qCDebug(authCredentials()) << *m_response; + if (Net::isApplicationError(m_task->error())) { + emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("Failed to retrieve the Xbox profile: %1").arg(m_task->errorString())); } else { - emit finished(AccountTaskState::STATE_OFFLINE, tr("Failed to retrieve the Xbox profile: %1").arg(requestor->errorString_)); + emit finished(AccountTaskState::STATE_OFFLINE, tr("Failed to retrieve the Xbox profile: %1").arg(m_task->errorString())); } return; } - qCDebug(authCredentials()) << "XBox profile: " << data; + qCDebug(authCredentials()) << "XBox profile: " << *m_response; emit finished(AccountTaskState::STATE_WORKING, tr("Got Xbox profile")); } diff --git a/launcher/minecraft/auth/steps/XboxProfileStep.h b/launcher/minecraft/auth/steps/XboxProfileStep.h index b8494b6e5..dfa273d9c 100644 --- a/launcher/minecraft/auth/steps/XboxProfileStep.h +++ b/launcher/minecraft/auth/steps/XboxProfileStep.h @@ -1,21 +1,25 @@ #pragma once #include +#include -#include "QObjectPtr.h" #include "minecraft/auth/AuthStep.h" +#include "net/Download.h" class XboxProfileStep : public AuthStep { Q_OBJECT public: explicit XboxProfileStep(AccountData* data); - virtual ~XboxProfileStep() noexcept; + virtual ~XboxProfileStep() noexcept = default; void perform() override; - void rehydrate() override; QString describe() override; private slots: - void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList); + void onRequestDone(); + + private: + std::shared_ptr m_response; + Net::Download::Ptr m_task; }; diff --git a/launcher/minecraft/auth/steps/XboxUserStep.cpp b/launcher/minecraft/auth/steps/XboxUserStep.cpp index 856036d23..46c3f0365 100644 --- a/launcher/minecraft/auth/steps/XboxUserStep.cpp +++ b/launcher/minecraft/auth/steps/XboxUserStep.cpp @@ -2,24 +2,18 @@ #include -#include "minecraft/auth/AuthRequest.h" +#include "Application.h" #include "minecraft/auth/Parsers.h" #include "net/NetUtils.h" +#include "net/StaticHeaderProxy.h" XboxUserStep::XboxUserStep(AccountData* data) : AuthStep(data) {} -XboxUserStep::~XboxUserStep() noexcept = default; - QString XboxUserStep::describe() { return tr("Logging in as an Xbox user."); } -void XboxUserStep::rehydrate() -{ - // NOOP, for now. We only save bools and there's nothing to check. -} - void XboxUserStep::perform() { QString xbox_auth_template = R"XXX( @@ -35,36 +29,39 @@ void XboxUserStep::perform() )XXX"; auto xbox_auth_data = xbox_auth_template.arg(m_data->msaToken.token); - QNetworkRequest request = QNetworkRequest(QUrl("https://user.auth.xboxlive.com/user/authenticate")); - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - request.setRawHeader("Accept", "application/json"); - // set contract-version header (prevent err 400 bad-request?) - // https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/reference/live/rest/additional/httpstandardheaders - request.setRawHeader("x-xbl-contract-version", "1"); + QUrl url("https://user.auth.xboxlive.com/user/authenticate"); + auto headers = QList{ + { "Content-Type", "application/json" }, + { "Accept", "application/json" }, + // set contract-version header (prevent err 400 bad-request?) + // https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/reference/live/rest/additional/httpstandardheaders + { "x-xbl-contract-version", "1" } + }; + m_response.reset(new QByteArray()); + m_task = Net::Upload::makeByteArray(url, m_response, xbox_auth_data.toUtf8()); + m_task->addHeaderProxy(new Net::StaticHeaderProxy(headers)); - auto* requestor = new AuthRequest(this); - connect(requestor, &AuthRequest::finished, this, &XboxUserStep::onRequestDone); - requestor->post(request, xbox_auth_data.toUtf8()); + connect(m_task.get(), &Task::finished, this, &XboxUserStep::onRequestDone); + + m_task->setNetwork(APPLICATION->network()); + m_task->start(); qDebug() << "First layer of XBox auth ... commencing."; } -void XboxUserStep::onRequestDone(QNetworkReply::NetworkError error, QByteArray data, QList headers) +void XboxUserStep::onRequestDone() { - auto requestor = qobject_cast(QObject::sender()); - requestor->deleteLater(); - - if (error != QNetworkReply::NoError) { - qWarning() << "Reply error:" << error; - if (Net::isApplicationError(error)) { - emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("XBox user authentication failed: %1").arg(requestor->errorString_)); + if (m_task->error() != QNetworkReply::NoError) { + qWarning() << "Reply error:" << m_task->error(); + if (Net::isApplicationError(m_task->error())) { + emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("XBox user authentication failed: %1").arg(m_task->errorString())); } else { - emit finished(AccountTaskState::STATE_OFFLINE, tr("XBox user authentication failed: %1").arg(requestor->errorString_)); + emit finished(AccountTaskState::STATE_OFFLINE, tr("XBox user authentication failed: %1").arg(m_task->errorString())); } return; } Katabasis::Token temp; - if (!Parsers::parseXTokenResponse(data, temp, "UToken")) { + if (!Parsers::parseXTokenResponse(*m_response, temp, "UToken")) { qWarning() << "Could not parse user authentication response..."; emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("XBox user authentication response could not be understood.")); return; diff --git a/launcher/minecraft/auth/steps/XboxUserStep.h b/launcher/minecraft/auth/steps/XboxUserStep.h index e92727a4d..934a00c52 100644 --- a/launcher/minecraft/auth/steps/XboxUserStep.h +++ b/launcher/minecraft/auth/steps/XboxUserStep.h @@ -1,21 +1,25 @@ #pragma once #include +#include -#include "QObjectPtr.h" #include "minecraft/auth/AuthStep.h" +#include "net/Upload.h" class XboxUserStep : public AuthStep { Q_OBJECT public: explicit XboxUserStep(AccountData* data); - virtual ~XboxUserStep() noexcept; + virtual ~XboxUserStep() noexcept = default; void perform() override; - void rehydrate() override; QString describe() override; private slots: - void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList); + void onRequestDone(); + + private: + std::shared_ptr m_response; + Net::Upload::Ptr m_task; }; diff --git a/launcher/modplatform/helpers/NetworkResourceAPI.cpp b/launcher/modplatform/helpers/NetworkResourceAPI.cpp index 225583764..974e732a7 100644 --- a/launcher/modplatform/helpers/NetworkResourceAPI.cpp +++ b/launcher/modplatform/helpers/NetworkResourceAPI.cpp @@ -45,8 +45,8 @@ Task::Ptr NetworkResourceAPI::searchProjects(SearchArgs&& args, SearchCallbacks& QObject::connect(netJob.get(), &NetJob::failed, [netJob, callbacks](const QString& reason) { int network_error_code = -1; - if (auto* failed_action = netJob->getFailedActions().at(0); failed_action && failed_action->m_reply) - network_error_code = failed_action->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + if (auto* failed_action = netJob->getFailedActions().at(0); failed_action) + network_error_code = failed_action->replyStatusCode(); callbacks.on_fail(reason, network_error_code); }); @@ -104,8 +104,8 @@ Task::Ptr NetworkResourceAPI::getProjectVersions(VersionSearchArgs&& args, Versi }); QObject::connect(netJob.get(), &NetJob::failed, [netJob, callbacks](const QString& reason) { int network_error_code = -1; - if (auto* failed_action = netJob->getFailedActions().at(0); failed_action && failed_action->m_reply) - network_error_code = failed_action->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + if (auto* failed_action = netJob->getFailedActions().at(0); failed_action) + network_error_code = failed_action->replyStatusCode(); callbacks.on_fail(reason, network_error_code); }); @@ -155,8 +155,8 @@ Task::Ptr NetworkResourceAPI::getDependencyVersion(DependencySearchArgs&& args, }); QObject::connect(netJob.get(), &NetJob::failed, [netJob, callbacks](const QString& reason) { int network_error_code = -1; - if (auto* failed_action = netJob->getFailedActions().at(0); failed_action && failed_action->m_reply) - network_error_code = failed_action->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + if (auto* failed_action = netJob->getFailedActions().at(0); failed_action) + network_error_code = failed_action->replyStatusCode(); callbacks.on_fail(reason, network_error_code); }); diff --git a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp index 3b875103b..e92489999 100644 --- a/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp +++ b/launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp @@ -261,7 +261,7 @@ bool ModrinthCreationTask::createInstance() // FIXME: This really needs to be put into a ConcurrentTask of // MultipleOptionsTask's , once those exist :) auto param = dl.toWeakRef(); - connect(dl.get(), &NetAction::failed, [this, &file, file_path, param] { + connect(dl.get(), &Task::failed, [this, &file, file_path, param] { auto ndl = Net::ApiDownload::makeFile(file.downloads.dequeue(), file_path); ndl->addValidator(new Net::ChecksumValidator(file.hashAlgorithm, file.hash)); m_files_job->addNetAction(ndl); diff --git a/launcher/net/ApiDownload.cpp b/launcher/net/ApiDownload.cpp index aaa8ff650..8768b63f8 100644 --- a/launcher/net/ApiDownload.cpp +++ b/launcher/net/ApiDownload.cpp @@ -21,7 +21,6 @@ #include "ByteArraySink.h" #include "ChecksumValidator.h" #include "MetaCacheSink.h" -#include "net/NetAction.h" namespace Net { diff --git a/launcher/net/ApiUpload.cpp b/launcher/net/ApiUpload.cpp index c1221b764..505cbd9f9 100644 --- a/launcher/net/ApiUpload.cpp +++ b/launcher/net/ApiUpload.cpp @@ -19,9 +19,6 @@ #include "net/ApiUpload.h" #include "ByteArraySink.h" -#include "ChecksumValidator.h" -#include "MetaCacheSink.h" -#include "net/NetAction.h" namespace Net { diff --git a/launcher/net/Download.cpp b/launcher/net/Download.cpp index bae364f12..49686db98 100644 --- a/launcher/net/Download.cpp +++ b/launcher/net/Download.cpp @@ -47,8 +47,6 @@ #include "ChecksumValidator.h" #include "MetaCacheSink.h" -#include "net/NetAction.h" - namespace Net { #if defined(LAUNCHER_APPLICATION) diff --git a/launcher/net/NetAction.h b/launcher/net/NetAction.h deleted file mode 100644 index b66b91941..000000000 --- a/launcher/net/NetAction.h +++ /dev/null @@ -1,100 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -/* - * Prism Launcher - Minecraft Launcher - * Copyright (c) 2022 flowln - * Copyright (C) 2023 Rachel Powers <508861+Ryex@users.noreply.github.com> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * - * Copyright 2013-2021 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include "QObjectPtr.h" -#include "tasks/Task.h" - -#include "HeaderProxy.h" - -class NetAction : public Task { - Q_OBJECT - protected: - explicit NetAction() : Task() {} - - public: - using Ptr = shared_qobject_ptr; - - virtual ~NetAction() = default; - - QUrl url() { return m_url; } - - void setNetwork(shared_qobject_ptr network) { m_network = network; } - - void addHeaderProxy(Net::HeaderProxy* proxy) { m_headerProxies.push_back(std::shared_ptr(proxy)); } - virtual void init() = 0; - - protected slots: - virtual void downloadProgress(qint64 bytesReceived, qint64 bytesTotal) = 0; - virtual void downloadError(QNetworkReply::NetworkError error) = 0; - virtual void downloadFinished() = 0; - virtual void downloadReadyRead() = 0; - - virtual void sslErrors(const QList& errors) - { - int i = 1; - for (auto error : errors) { - qCritical() << "Network SSL Error #" << i << " : " << error.errorString(); - auto cert = error.certificate(); - qCritical() << "Certificate in question:\n" << cert.toText(); - i++; - } - } - - public slots: - void startAction(shared_qobject_ptr network) - { - m_network = network; - executeTask(); - } - - protected: - void executeTask() override {} - - public: - shared_qobject_ptr m_network; - - /// the network reply - unique_qobject_ptr m_reply; - - /// source URL - QUrl m_url; - std::vector> m_headerProxies; -}; diff --git a/launcher/net/NetJob.cpp b/launcher/net/NetJob.cpp index d027e31c9..1ceb0a860 100644 --- a/launcher/net/NetJob.cpp +++ b/launcher/net/NetJob.cpp @@ -36,6 +36,7 @@ */ #include "NetJob.h" +#include "net/NetRequest.h" #include "tasks/ConcurrentTask.h" #if defined(LAUNCHER_APPLICATION) #include "Application.h" @@ -48,7 +49,7 @@ NetJob::NetJob(QString job_name, shared_qobject_ptr netwo #endif } -auto NetJob::addNetAction(NetAction::Ptr action) -> bool +auto NetJob::addNetAction(Net::NetRequest::Ptr action) -> bool { action->setNetwork(m_network); @@ -111,11 +112,11 @@ auto NetJob::abort() -> bool return fullyAborted; } -auto NetJob::getFailedActions() -> QList +auto NetJob::getFailedActions() -> QList { - QList failed; + QList failed; for (auto index : m_failed) { - failed.push_back(dynamic_cast(index.get())); + failed.push_back(dynamic_cast(index.get())); } return failed; } @@ -124,7 +125,7 @@ auto NetJob::getFailedFiles() -> QList { QList failed; for (auto index : m_failed) { - failed.append(static_cast(index.get())->url().toString()); + failed.append(static_cast(index.get())->url().toString()); } return failed; } diff --git a/launcher/net/NetJob.h b/launcher/net/NetJob.h index f6c005809..1661842f0 100644 --- a/launcher/net/NetJob.h +++ b/launcher/net/NetJob.h @@ -39,7 +39,7 @@ #include #include -#include "NetAction.h" +#include "net/NetRequest.h" #include "tasks/ConcurrentTask.h" // Those are included so that they are also included by anyone using NetJob @@ -58,9 +58,9 @@ class NetJob : public ConcurrentTask { auto size() const -> int; auto canAbort() const -> bool override; - auto addNetAction(NetAction::Ptr action) -> bool; + auto addNetAction(Net::NetRequest::Ptr action) -> bool; - auto getFailedActions() -> QList; + auto getFailedActions() -> QList; auto getFailedFiles() -> QList; public slots: diff --git a/launcher/net/NetRequest.cpp b/launcher/net/NetRequest.cpp index 526fe77a5..009213332 100644 --- a/launcher/net/NetRequest.cpp +++ b/launcher/net/NetRequest.cpp @@ -37,6 +37,7 @@ */ #include "NetRequest.h" +#include #include #include @@ -48,8 +49,6 @@ #endif #include "BuildConfig.h" -#include "net/NetAction.h" - #include "MMCTime.h" #include "StringUtils.h" @@ -105,20 +104,18 @@ void NetRequest::executeTask() for (auto& header_proxy : m_headerProxies) { header_proxy->writeHeaders(request); } - // TODO remove duplication -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) - request.setTransferTimeout(); -#endif + request.setTransferTimeout(QNetworkRequest::DefaultTransferTimeoutConstant); m_last_progress_time = m_clock.now(); m_last_progress_bytes = 0; - QNetworkReply* rep = getReply(request); + auto rep = getReply(request); if (rep == nullptr) // it failed return; m_reply.reset(rep); - connect(rep, &QNetworkReply::downloadProgress, this, &NetRequest::downloadProgress); + connect(rep, &QNetworkReply::uploadProgress, this, &NetRequest::onProgress); + connect(rep, &QNetworkReply::downloadProgress, this, &NetRequest::onProgress); connect(rep, &QNetworkReply::finished, this, &NetRequest::downloadFinished); #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15 connect(rep, &QNetworkReply::errorOccurred, this, &NetRequest::downloadError); @@ -129,7 +126,7 @@ void NetRequest::executeTask() connect(rep, &QNetworkReply::readyRead, this, &NetRequest::downloadReadyRead); } -void NetRequest::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) +void NetRequest::onProgress(qint64 bytesReceived, qint64 bytesTotal) { auto now = m_clock.now(); auto elapsed = now - m_last_progress_time; @@ -237,7 +234,7 @@ auto NetRequest::handleRedirect() -> bool m_url = QUrl(redirect.toString()); qCDebug(logCat) << getUid().toString() << "Following redirect to " << m_url.toString(); - startAction(m_network); + executeTask(); return true; } @@ -334,4 +331,23 @@ auto NetRequest::abort() -> bool return true; } +int NetRequest::replyStatusCode() const +{ + return m_reply ? m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() : -1; +} + +QNetworkReply::NetworkError NetRequest::error() const +{ + return m_reply ? m_reply->error() : QNetworkReply::NoError; +} + +QUrl NetRequest::url() const +{ + return m_url; +} + +QString NetRequest::errorString() const +{ + return m_reply ? m_reply->errorString() : ""; +} } // namespace Net diff --git a/launcher/net/NetRequest.h b/launcher/net/NetRequest.h index 0b307b4f6..6c32215b0 100644 --- a/launcher/net/NetRequest.h +++ b/launcher/net/NetRequest.h @@ -39,20 +39,23 @@ #pragma once #include +#include +#include #include -#include "NetAction.h" +#include "HeaderProxy.h" #include "Sink.h" #include "Validator.h" #include "QObjectPtr.h" #include "net/Logging.h" +#include "tasks/Task.h" namespace Net { -class NetRequest : public NetAction { +class NetRequest : public Task { Q_OBJECT protected: - explicit NetRequest() : NetAction() {} + explicit NetRequest() : Task() {} public: using Ptr = shared_qobject_ptr; @@ -61,26 +64,30 @@ class NetRequest : public NetAction { public: ~NetRequest() override = default; - - void init() override {} - - public: void addValidator(Validator* v); auto abort() -> bool override; auto canAbort() const -> bool override { return true; } + void setNetwork(shared_qobject_ptr network) { m_network = network; } + void addHeaderProxy(Net::HeaderProxy* proxy) { m_headerProxies.push_back(std::shared_ptr(proxy)); } + + virtual void init() {} + + QUrl url() const; + int replyStatusCode() const; + QNetworkReply::NetworkError error() const; + QString errorString() const; + private: auto handleRedirect() -> bool; virtual QNetworkReply* getReply(QNetworkRequest&) = 0; protected slots: - void downloadProgress(qint64 bytesReceived, qint64 bytesTotal) override; - void downloadError(QNetworkReply::NetworkError error) override; - void sslErrors(const QList& errors) override; - void downloadFinished() override; - void downloadReadyRead() override; - - public slots: + void onProgress(qint64 bytesReceived, qint64 bytesTotal); + void downloadError(QNetworkReply::NetworkError error); + void sslErrors(const QList& errors); + void downloadFinished(); + void downloadReadyRead(); void executeTask() override; protected: @@ -93,6 +100,15 @@ class NetRequest : public NetAction { std::chrono::steady_clock m_clock; std::chrono::time_point m_last_progress_time; qint64 m_last_progress_bytes; + + shared_qobject_ptr m_network; + + /// the network reply + unique_qobject_ptr m_reply; + + /// source URL + QUrl m_url; + std::vector> m_headerProxies; }; } // namespace Net diff --git a/launcher/net/Sink.h b/launcher/net/Sink.h index fcdabf372..d1fd9de10 100644 --- a/launcher/net/Sink.h +++ b/launcher/net/Sink.h @@ -35,9 +35,8 @@ #pragma once -#include "net/NetAction.h" - #include "Validator.h" +#include "tasks/Task.h" namespace Net { class Sink { diff --git a/launcher/net/Validator.h b/launcher/net/Validator.h index 92ac6ea15..6d1945ee6 100644 --- a/launcher/net/Validator.h +++ b/launcher/net/Validator.h @@ -34,7 +34,7 @@ #pragma once -#include "net/NetAction.h" +#include namespace Net { class Validator { diff --git a/launcher/ui/dialogs/ProfileSetupDialog.cpp b/launcher/ui/dialogs/ProfileSetupDialog.cpp index 4b0c5b768..c5d4c2621 100644 --- a/launcher/ui/dialogs/ProfileSetupDialog.cpp +++ b/launcher/ui/dialogs/ProfileSetupDialog.cpp @@ -45,8 +45,9 @@ #include "ui/dialogs/ProgressDialog.h" #include -#include "minecraft/auth/AuthRequest.h" #include "minecraft/auth/Parsers.h" +#include "net/StaticHeaderProxy.h" +#include "net/Upload.h" ProfileSetupDialog::ProfileSetupDialog(MinecraftAccountPtr accountToSetup, QWidget* parent) : QDialog(parent), m_accountToSetup(accountToSetup), ui(new Ui::ProfileSetupDialog) @@ -150,28 +151,27 @@ void ProfileSetupDialog::checkName(const QString& name) currentCheck = name; isChecking = true; - auto token = m_accountToSetup->accessToken(); + QUrl url(QString("https://api.minecraftservices.com/minecraft/profile/name/%1/available").arg(name)); + auto headers = QList{ { "Content-Type", "application/json" }, + { "Accept", "application/json" }, + { "Authorization", QString("Bearer %1").arg(m_accountToSetup->accessToken()).toUtf8() } }; - auto url = QString("https://api.minecraftservices.com/minecraft/profile/name/%1/available").arg(name); - QNetworkRequest request = QNetworkRequest(url); - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - request.setRawHeader("Accept", "application/json"); - request.setRawHeader("Authorization", QString("Bearer %1").arg(token).toUtf8()); + m_check_response.reset(new QByteArray()); + if (m_check_task) + disconnect(m_check_task.get(), nullptr, this, nullptr); + m_check_task = Net::Download::makeByteArray(url, m_check_response); + m_check_task->addHeaderProxy(new Net::StaticHeaderProxy(headers)); - AuthRequest* requestor = new AuthRequest(this); - connect(requestor, &AuthRequest::finished, this, &ProfileSetupDialog::checkFinished); - requestor->get(request); + connect(m_check_task.get(), &Task::finished, this, &ProfileSetupDialog::checkFinished); + + m_check_task->setNetwork(APPLICATION->network()); + m_check_task->start(); } -void ProfileSetupDialog::checkFinished(QNetworkReply::NetworkError error, - QByteArray profileData, - [[maybe_unused]] QList headers) +void ProfileSetupDialog::checkFinished() { - auto requestor = qobject_cast(QObject::sender()); - requestor->deleteLater(); - - if (error == QNetworkReply::NoError) { - auto doc = QJsonDocument::fromJson(profileData); + if (m_check_task->error() == QNetworkReply::NoError) { + auto doc = QJsonDocument::fromJson(*m_check_response); auto root = doc.object(); auto statusValue = root.value("status").toString("INVALID"); if (statusValue == "AVAILABLE") { @@ -195,20 +195,22 @@ void ProfileSetupDialog::setupProfile(const QString& profileName) return; } - auto token = m_accountToSetup->accessToken(); - - auto url = QString("https://api.minecraftservices.com/minecraft/profile"); - QNetworkRequest request = QNetworkRequest(url); - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - request.setRawHeader("Accept", "application/json"); - request.setRawHeader("Authorization", QString("Bearer %1").arg(token).toUtf8()); - QString payloadTemplate("{\"profileName\":\"%1\"}"); - auto profileData = payloadTemplate.arg(profileName).toUtf8(); - AuthRequest* requestor = new AuthRequest(this); - connect(requestor, &AuthRequest::finished, this, &ProfileSetupDialog::setupProfileFinished); - requestor->post(request, profileData); + QUrl url("https://api.minecraftservices.com/minecraft/profile"); + auto headers = QList{ { "Content-Type", "application/json" }, + { "Accept", "application/json" }, + { "Authorization", QString("Bearer %1").arg(m_accountToSetup->accessToken()).toUtf8() } }; + + m_profile_response.reset(new QByteArray()); + m_profile_task = Net::Upload::makeByteArray(url, m_profile_response, payloadTemplate.arg(profileName).toUtf8()); + m_profile_task->addHeaderProxy(new Net::StaticHeaderProxy(headers)); + + connect(m_profile_task.get(), &Task::finished, this, &ProfileSetupDialog::setupProfileFinished); + + m_profile_task->setNetwork(APPLICATION->network()); + m_profile_task->start(); + isWorking = true; auto button = ui->buttonBox->button(QDialogButtonBox::Cancel); @@ -244,22 +246,17 @@ struct MojangError { } // namespace -void ProfileSetupDialog::setupProfileFinished(QNetworkReply::NetworkError error, - QByteArray errorData, - [[maybe_unused]] QList headers) +void ProfileSetupDialog::setupProfileFinished() { - auto requestor = qobject_cast(QObject::sender()); - requestor->deleteLater(); - isWorking = false; - if (error == QNetworkReply::NoError) { + if (m_profile_task->error() == QNetworkReply::NoError) { /* * data contains the profile in the response * ... we could parse it and update the account, but let's just return back to the normal login flow instead... */ accept(); } else { - auto parsedError = MojangError::fromJSON(errorData); + auto parsedError = MojangError::fromJSON(*m_profile_response); ui->errorLabel->setVisible(true); ui->errorLabel->setText(tr("The server returned the following error:") + "\n\n" + parsedError.errorMessage); qDebug() << parsedError.rawError; diff --git a/launcher/ui/dialogs/ProfileSetupDialog.h b/launcher/ui/dialogs/ProfileSetupDialog.h index 09f8124e2..c005a4138 100644 --- a/launcher/ui/dialogs/ProfileSetupDialog.h +++ b/launcher/ui/dialogs/ProfileSetupDialog.h @@ -22,6 +22,8 @@ #include #include +#include "net/Download.h" +#include "net/Upload.h" namespace Ui { class ProfileSetupDialog; @@ -40,10 +42,10 @@ class ProfileSetupDialog : public QDialog { void on_buttonBox_rejected(); void nameEdited(const QString& name); - void checkFinished(QNetworkReply::NetworkError error, QByteArray data, QList headers); void startCheck(); - void setupProfileFinished(QNetworkReply::NetworkError error, QByteArray data, QList headers); + void checkFinished(); + void setupProfileFinished(); protected: void scheduleCheck(const QString& name); @@ -67,4 +69,10 @@ class ProfileSetupDialog : public QDialog { QString currentCheck; QTimer checkStartTimer; + + std::shared_ptr m_check_response; + Net::Download::Ptr m_check_task; + + std::shared_ptr m_profile_response; + Net::Upload::Ptr m_profile_task; }; diff --git a/launcher/ui/pages/modplatform/ResourceModel.cpp b/launcher/ui/pages/modplatform/ResourceModel.cpp index f3c7ff60b..8a69e910d 100644 --- a/launcher/ui/pages/modplatform/ResourceModel.cpp +++ b/launcher/ui/pages/modplatform/ResourceModel.cpp @@ -331,7 +331,7 @@ std::optional ResourceModel::getIcon(QModelIndex& index, const QUrl& url) auto icon_fetch_action = Net::ApiDownload::makeCached(url, cache_entry); auto full_file_path = cache_entry->getFullPath(); - connect(icon_fetch_action.get(), &NetAction::succeeded, this, [=] { + connect(icon_fetch_action.get(), &Task::succeeded, this, [=] { auto icon = QIcon(full_file_path); QPixmapCache::insert(url.toString(), icon.pixmap(icon.actualSize({ 64, 64 }))); @@ -339,7 +339,7 @@ std::optional ResourceModel::getIcon(QModelIndex& index, const QUrl& url) emit dataChanged(index, index, { Qt::DecorationRole }); }); - connect(icon_fetch_action.get(), &NetAction::failed, this, [=] { + connect(icon_fetch_action.get(), &Task::failed, this, [=] { m_currently_running_icon_actions.remove(url); m_failed_icon_actions.insert(url); }); diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index bac294b60..ccfe7eccb 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -352,10 +352,10 @@ void ModpackListModel::searchRequestForOneSucceeded(QJsonDocument& doc) void ModpackListModel::searchRequestFailed(QString reason) { auto failed_action = dynamic_cast(jobPtr.get())->getFailedActions().at(0); - if (!failed_action->m_reply) { + if (failed_action->replyStatusCode() == -1) { // Network error QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load modpacks.")); - } else if (failed_action->m_reply && failed_action->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 409) { + } else if (failed_action->replyStatusCode() == 409) { // 409 Gone, notify user to update QMessageBox::critical(nullptr, tr("Error"), //: %1 refers to the launcher itself diff --git a/tests/Library_test.cpp b/tests/Library_test.cpp index 8b8d4c55c..9826abbdf 100644 --- a/tests/Library_test.cpp +++ b/tests/Library_test.cpp @@ -95,8 +95,8 @@ class LibraryTest : public QObject { auto downloads = test.getDownloads(r, cache.get(), failedFiles, QString()); QCOMPARE(downloads.size(), 1); QCOMPARE(failedFiles, {}); - NetAction::Ptr dl = downloads[0]; - QCOMPARE(dl->m_url, QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion.jar")); + Net::NetRequest::Ptr dl = downloads[0]; + QCOMPARE(dl->url(), QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion.jar")); } void test_legacy_url_local_broken() { @@ -147,7 +147,7 @@ class LibraryTest : public QObject { QCOMPARE(dls.size(), 1); QCOMPARE(failedFiles, {}); auto dl = dls[0]; - QCOMPARE(dl->m_url, QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion-linux.jar")); + QCOMPARE(dl->url(), QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion-linux.jar")); } } void test_legacy_native_arch() @@ -170,8 +170,8 @@ class LibraryTest : public QObject { auto dls = test.getDownloads(r, cache.get(), failedFiles, QString()); QCOMPARE(dls.size(), 2); QCOMPARE(failedFiles, {}); - QCOMPARE(dls[0]->m_url, QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion-linux-32.jar")); - QCOMPARE(dls[1]->m_url, QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion-linux-64.jar")); + QCOMPARE(dls[0]->url(), QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion-linux-32.jar")); + QCOMPARE(dls[1]->url(), QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion-linux-64.jar")); } r.system = "windows"; { @@ -185,8 +185,8 @@ class LibraryTest : public QObject { auto dls = test.getDownloads(r, cache.get(), failedFiles, QString()); QCOMPARE(dls.size(), 2); QCOMPARE(failedFiles, {}); - QCOMPARE(dls[0]->m_url, QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion-windows-32.jar")); - QCOMPARE(dls[1]->m_url, QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion-windows-64.jar")); + QCOMPARE(dls[0]->url(), QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion-windows-32.jar")); + QCOMPARE(dls[1]->url(), QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion-windows-64.jar")); } r.system = "osx"; { @@ -200,8 +200,8 @@ class LibraryTest : public QObject { auto dls = test.getDownloads(r, cache.get(), failedFiles, QString()); QCOMPARE(dls.size(), 2); QCOMPARE(failedFiles, {}); - QCOMPARE(dls[0]->m_url, QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion-osx-32.jar")); - QCOMPARE(dls[1]->m_url, QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion-osx-64.jar")); + QCOMPARE(dls[0]->url(), QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion-osx-32.jar")); + QCOMPARE(dls[1]->url(), QUrl("file://foo/bar/test/package/testname/testversion/testname-testversion-osx-64.jar")); } } void test_legacy_native_arch_local_override() @@ -244,7 +244,7 @@ class LibraryTest : public QObject { auto dls = test->getDownloads(r, cache.get(), failedFiles, QString()); QCOMPARE(dls.size(), 1); QCOMPARE(failedFiles, {}); - QCOMPARE(dls[0]->m_url, QUrl("https://libraries.minecraft.net/com/paulscode/codecwav/20101023/codecwav-20101023.jar")); + QCOMPARE(dls[0]->url(), QUrl("https://libraries.minecraft.net/com/paulscode/codecwav/20101023/codecwav-20101023.jar")); } r.system = "osx"; test->setHint("local"); @@ -300,7 +300,7 @@ class LibraryTest : public QObject { auto dls = test->getDownloads(r, cache.get(), failedFiles, QString()); QCOMPARE(dls.size(), 1); QCOMPARE(failedFiles, {}); - QCOMPARE(dls[0]->m_url, QUrl("https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/" + QCOMPARE(dls[0]->url(), QUrl("https://libraries.minecraft.net/org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/" "lwjgl-platform-2.9.4-nightly-20150209-natives-osx.jar")); } void test_onenine_native_arch() @@ -317,9 +317,9 @@ class LibraryTest : public QObject { auto dls = test->getDownloads(r, cache.get(), failedFiles, QString()); QCOMPARE(dls.size(), 2); QCOMPARE(failedFiles, {}); - QCOMPARE(dls[0]->m_url, + QCOMPARE(dls[0]->url(), QUrl("https://libraries.minecraft.net/tv/twitch/twitch-platform/5.16/twitch-platform-5.16-natives-windows-32.jar")); - QCOMPARE(dls[1]->m_url, + QCOMPARE(dls[1]->url(), QUrl("https://libraries.minecraft.net/tv/twitch/twitch-platform/5.16/twitch-platform-5.16-natives-windows-64.jar")); } From e285a85fe88e78ddced5c0d839056f2132e4c3b6 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 14 May 2024 00:20:32 +0300 Subject: [PATCH 210/223] Removed AccountTask Signed-off-by: Trial97 --- launcher/CMakeLists.txt | 3 - launcher/LaunchController.cpp | 1 - launcher/minecraft/auth/AccountList.cpp | 1 - launcher/minecraft/auth/AccountList.h | 3 +- launcher/minecraft/auth/AccountTask.cpp | 134 ------------------ launcher/minecraft/auth/AccountTask.h | 92 ------------ launcher/minecraft/auth/AuthStep.cpp | 3 - launcher/minecraft/auth/AuthStep.h | 19 ++- launcher/minecraft/auth/MinecraftAccount.cpp | 10 +- launcher/minecraft/auth/MinecraftAccount.h | 14 +- launcher/minecraft/auth/flows/AuthFlow.cpp | 93 ++++++++++-- launcher/minecraft/auth/flows/AuthFlow.h | 32 +++-- .../auth/steps/LauncherLoginStep.cpp | 1 - launcher/net/NetRequest.cpp | 2 + launcher/ui/dialogs/MSALoginDialog.cpp | 6 +- launcher/ui/dialogs/MSALoginDialog.h | 3 +- launcher/ui/dialogs/OfflineLoginDialog.cpp | 2 - 17 files changed, 143 insertions(+), 276 deletions(-) delete mode 100644 launcher/minecraft/auth/AccountTask.cpp delete mode 100644 launcher/minecraft/auth/AccountTask.h delete mode 100644 launcher/minecraft/auth/AuthStep.cpp diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index cf1ab8798..e4143ee28 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -209,11 +209,8 @@ set(MINECRAFT_SOURCES minecraft/auth/AccountData.h minecraft/auth/AccountList.cpp minecraft/auth/AccountList.h - minecraft/auth/AccountTask.cpp - minecraft/auth/AccountTask.h minecraft/auth/AuthSession.cpp minecraft/auth/AuthSession.h - minecraft/auth/AuthStep.cpp minecraft/auth/AuthStep.h minecraft/auth/MinecraftAccount.cpp minecraft/auth/MinecraftAccount.h diff --git a/launcher/LaunchController.cpp b/launcher/LaunchController.cpp index a30f99439..cf8d0a794 100644 --- a/launcher/LaunchController.cpp +++ b/launcher/LaunchController.cpp @@ -57,7 +57,6 @@ #include "BuildConfig.h" #include "JavaCommon.h" #include "launch/steps/TextPrint.h" -#include "minecraft/auth/AccountTask.h" #include "tasks/Task.h" LaunchController::LaunchController(QObject* parent) : Task(parent) {} diff --git a/launcher/minecraft/auth/AccountList.cpp b/launcher/minecraft/auth/AccountList.cpp index af83502bc..d276d4c41 100644 --- a/launcher/minecraft/auth/AccountList.cpp +++ b/launcher/minecraft/auth/AccountList.cpp @@ -35,7 +35,6 @@ #include "AccountList.h" #include "AccountData.h" -#include "AccountTask.h" #include "tasks/Task.h" #include diff --git a/launcher/minecraft/auth/AccountList.h b/launcher/minecraft/auth/AccountList.h index 039730739..b6038edb7 100644 --- a/launcher/minecraft/auth/AccountList.h +++ b/launcher/minecraft/auth/AccountList.h @@ -36,6 +36,7 @@ #pragma once #include "MinecraftAccount.h" +#include "minecraft/auth/flows/AuthFlow.h" #include #include @@ -144,7 +145,7 @@ class AccountList : public QAbstractListModel { QList m_refreshQueue; QTimer* m_refreshTimer; QTimer* m_nextTimer; - shared_qobject_ptr m_currentTask; + shared_qobject_ptr m_currentTask; /*! * Called whenever the list changes. diff --git a/launcher/minecraft/auth/AccountTask.cpp b/launcher/minecraft/auth/AccountTask.cpp deleted file mode 100644 index 4c3d6ee19..000000000 --- a/launcher/minecraft/auth/AccountTask.cpp +++ /dev/null @@ -1,134 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -/* - * Prism Launcher - Minecraft Launcher - * Copyright (C) 2022 Sefa Eyeoglu - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * - * Copyright 2013-2021 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "AccountTask.h" -#include "MinecraftAccount.h" - -#include -#include -#include -#include -#include -#include - -#include - -AccountTask::AccountTask(AccountData* data, QObject* parent) : Task(parent), m_data(data) -{ - changeState(AccountTaskState::STATE_CREATED); -} - -QString AccountTask::getStateMessage() const -{ - switch (m_taskState) { - case AccountTaskState::STATE_CREATED: - return "Waiting..."; - case AccountTaskState::STATE_WORKING: - return tr("Sending request to auth servers..."); - case AccountTaskState::STATE_SUCCEEDED: - return tr("Authentication task succeeded."); - case AccountTaskState::STATE_OFFLINE: - return tr("Failed to contact the authentication server."); - case AccountTaskState::STATE_DISABLED: - return tr("Client ID has changed. New session needs to be created."); - case AccountTaskState::STATE_FAILED_SOFT: - return tr("Encountered an error during authentication."); - case AccountTaskState::STATE_FAILED_HARD: - return tr("Failed to authenticate. The session has expired."); - case AccountTaskState::STATE_FAILED_GONE: - return tr("Failed to authenticate. The account no longer exists."); - default: - return tr("..."); - } -} - -bool AccountTask::changeState(AccountTaskState newState, QString reason) -{ - m_taskState = newState; - // FIXME: virtual method invoked in constructor. - // We want that behavior, but maybe make it less weird? - setStatus(getStateMessage()); - switch (newState) { - case AccountTaskState::STATE_CREATED: { - m_data->errorString.clear(); - return true; - } - case AccountTaskState::STATE_WORKING: { - m_data->accountState = AccountState::Working; - return true; - } - case AccountTaskState::STATE_SUCCEEDED: { - m_data->accountState = AccountState::Online; - emitSucceeded(); - return false; - } - case AccountTaskState::STATE_OFFLINE: { - m_data->errorString = reason; - m_data->accountState = AccountState::Offline; - emitFailed(reason); - return false; - } - case AccountTaskState::STATE_DISABLED: { - m_data->errorString = reason; - m_data->accountState = AccountState::Disabled; - emitFailed(reason); - return false; - } - case AccountTaskState::STATE_FAILED_SOFT: { - m_data->errorString = reason; - m_data->accountState = AccountState::Errored; - emitFailed(reason); - return false; - } - case AccountTaskState::STATE_FAILED_HARD: { - m_data->errorString = reason; - m_data->accountState = AccountState::Expired; - emitFailed(reason); - return false; - } - case AccountTaskState::STATE_FAILED_GONE: { - m_data->errorString = reason; - m_data->accountState = AccountState::Gone; - emitFailed(reason); - return false; - } - default: { - QString error = tr("Unknown account task state: %1").arg(int(newState)); - m_data->accountState = AccountState::Errored; - emitFailed(error); - return false; - } - } -} diff --git a/launcher/minecraft/auth/AccountTask.h b/launcher/minecraft/auth/AccountTask.h deleted file mode 100644 index 82332c0b9..000000000 --- a/launcher/minecraft/auth/AccountTask.h +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -/* - * Prism Launcher - Minecraft Launcher - * Copyright (C) 2022 Sefa Eyeoglu - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * - * Copyright 2013-2021 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include - -#include -#include -#include -#include - -#include "MinecraftAccount.h" - -class QNetworkReply; - -/** - * Enum for describing the state of the current task. - * Used by the getStateMessage function to determine what the status message should be. - */ -enum class AccountTaskState { - STATE_CREATED, - STATE_WORKING, - STATE_SUCCEEDED, - STATE_DISABLED, //!< MSA Client ID has changed. Tell user to reloginn - STATE_FAILED_SOFT, //!< soft failure. authentication went through partially - STATE_FAILED_HARD, //!< hard failure. main tokens are invalid - STATE_FAILED_GONE, //!< hard failure. main tokens are invalid, and the account no longer exists - STATE_OFFLINE //!< soft failure. authentication failed in the first step in a 'soft' way -}; - -class AccountTask : public Task { - Q_OBJECT - public: - explicit AccountTask(AccountData* data, QObject* parent = 0); - virtual ~AccountTask(){}; - - AccountTaskState m_taskState = AccountTaskState::STATE_CREATED; - - AccountTaskState taskState() { return m_taskState; } - - signals: - void showVerificationUriAndCode(const QUrl& uri, const QString& code, int expiresIn); - void hideVerificationUriAndCode(); - - protected: - /** - * Returns the state message for the given state. - * Used to set the status message for the task. - * Should be overridden by subclasses that want to change messages for a given state. - */ - virtual QString getStateMessage() const; - - protected slots: - // NOTE: true -> non-terminal state, false -> terminal state - bool changeState(AccountTaskState newState, QString reason = QString()); - - protected: - AccountData* m_data = nullptr; -}; diff --git a/launcher/minecraft/auth/AuthStep.cpp b/launcher/minecraft/auth/AuthStep.cpp deleted file mode 100644 index 6b78c415a..000000000 --- a/launcher/minecraft/auth/AuthStep.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "AuthStep.h" - -AuthStep::AuthStep(AccountData* data) : QObject(nullptr), m_data(data) {} diff --git a/launcher/minecraft/auth/AuthStep.h b/launcher/minecraft/auth/AuthStep.h index b837b5703..dccbec11e 100644 --- a/launcher/minecraft/auth/AuthStep.h +++ b/launcher/minecraft/auth/AuthStep.h @@ -3,18 +3,31 @@ #include #include -#include "AccountTask.h" #include "QObjectPtr.h" #include "minecraft/auth/AccountData.h" +/** + * Enum for describing the state of the current task. + * Used by the getStateMessage function to determine what the status message should be. + */ +enum class AccountTaskState { + STATE_CREATED, + STATE_WORKING, + STATE_SUCCEEDED, + STATE_DISABLED, //!< MSA Client ID has changed. Tell user to reloginn + STATE_FAILED_SOFT, //!< soft failure. authentication went through partially + STATE_FAILED_HARD, //!< hard failure. main tokens are invalid + STATE_FAILED_GONE, //!< hard failure. main tokens are invalid, and the account no longer exists + STATE_OFFLINE //!< soft failure. authentication failed in the first step in a 'soft' way +}; + class AuthStep : public QObject { Q_OBJECT public: using Ptr = shared_qobject_ptr; - public: - explicit AuthStep(AccountData* data); + explicit AuthStep(AccountData* data) : QObject(nullptr), m_data(data){}; virtual ~AuthStep() noexcept = default; virtual QString describe() = 0; diff --git a/launcher/minecraft/auth/MinecraftAccount.cpp b/launcher/minecraft/auth/MinecraftAccount.cpp index db4d1c07b..d927cd6b4 100644 --- a/launcher/minecraft/auth/MinecraftAccount.cpp +++ b/launcher/minecraft/auth/MinecraftAccount.cpp @@ -53,6 +53,8 @@ #include "flows/MSA.h" #include "flows/Offline.h" #include "minecraft/auth/AccountData.h" +#include "minecraft/auth/flows/AuthFlow.h" +#include "tasks/Task.h" MinecraftAccount::MinecraftAccount(QObject* parent) : QObject(parent) { @@ -120,7 +122,7 @@ QPixmap MinecraftAccount::getFace() const return skin.scaled(64, 64, Qt::KeepAspectRatio); } -shared_qobject_ptr MinecraftAccount::loginMSA() +shared_qobject_ptr MinecraftAccount::loginMSA() { Q_ASSERT(m_currentTask.get() == nullptr); @@ -132,7 +134,7 @@ shared_qobject_ptr MinecraftAccount::loginMSA() return m_currentTask; } -shared_qobject_ptr MinecraftAccount::loginOffline() +shared_qobject_ptr MinecraftAccount::loginOffline() { Q_ASSERT(m_currentTask.get() == nullptr); @@ -144,7 +146,7 @@ shared_qobject_ptr MinecraftAccount::loginOffline() return m_currentTask; } -shared_qobject_ptr MinecraftAccount::refresh() +shared_qobject_ptr MinecraftAccount::refresh() { if (m_currentTask) { return m_currentTask; @@ -163,7 +165,7 @@ shared_qobject_ptr MinecraftAccount::refresh() return m_currentTask; } -shared_qobject_ptr MinecraftAccount::currentTask() +shared_qobject_ptr MinecraftAccount::currentTask() { return m_currentTask; } diff --git a/launcher/minecraft/auth/MinecraftAccount.h b/launcher/minecraft/auth/MinecraftAccount.h index f773b3bc9..24600cb73 100644 --- a/launcher/minecraft/auth/MinecraftAccount.h +++ b/launcher/minecraft/auth/MinecraftAccount.h @@ -43,15 +43,13 @@ #include #include -#include - #include "AccountData.h" #include "AuthSession.h" #include "QObjectPtr.h" #include "Usable.h" +#include "minecraft/auth/flows/AuthFlow.h" class Task; -class AccountTask; class MinecraftAccount; using MinecraftAccountPtr = shared_qobject_ptr; @@ -97,13 +95,13 @@ class MinecraftAccount : public QObject, public Usable { QJsonObject saveToJson() const; public: /* manipulation */ - shared_qobject_ptr loginMSA(); + shared_qobject_ptr loginMSA(); - shared_qobject_ptr loginOffline(); + shared_qobject_ptr loginOffline(); - shared_qobject_ptr refresh(); + shared_qobject_ptr refresh(); - shared_qobject_ptr currentTask(); + shared_qobject_ptr currentTask(); public: /* queries */ QString internalId() const { return data.internalId; } @@ -166,7 +164,7 @@ class MinecraftAccount : public QObject, public Usable { AccountData data; // current task we are executing here - shared_qobject_ptr m_currentTask; + shared_qobject_ptr m_currentTask; protected: /* methods */ void incrementUses() override; diff --git a/launcher/minecraft/auth/flows/AuthFlow.cpp b/launcher/minecraft/auth/flows/AuthFlow.cpp index c51839a8c..20d90f504 100644 --- a/launcher/minecraft/auth/flows/AuthFlow.cpp +++ b/launcher/minecraft/auth/flows/AuthFlow.cpp @@ -4,11 +4,13 @@ #include #include "AuthFlow.h" -#include "katabasis/Globals.h" #include -AuthFlow::AuthFlow(AccountData* data, QObject* parent) : AccountTask(data, parent) {} +AuthFlow::AuthFlow(AccountData* data, QObject* parent) : Task(parent), m_data(data) +{ + changeState(AccountTaskState::STATE_CREATED); +} void AuthFlow::succeed() { @@ -46,16 +48,26 @@ void AuthFlow::nextStep() QString AuthFlow::getStateMessage() const { switch (m_taskState) { - case AccountTaskState::STATE_WORKING: { - if (m_currentStep) { + case AccountTaskState::STATE_CREATED: + return "Waiting..."; + case AccountTaskState::STATE_WORKING: + if (m_currentStep) return m_currentStep->describe(); - } else { - return tr("Working..."); - } - } - default: { - return AccountTask::getStateMessage(); - } + return tr("Working..."); + case AccountTaskState::STATE_SUCCEEDED: + return tr("Authentication task succeeded."); + case AccountTaskState::STATE_OFFLINE: + return tr("Failed to contact the authentication server."); + case AccountTaskState::STATE_DISABLED: + return tr("Client ID has changed. New session needs to be created."); + case AccountTaskState::STATE_FAILED_SOFT: + return tr("Encountered an error during authentication."); + case AccountTaskState::STATE_FAILED_HARD: + return tr("Failed to authenticate. The session has expired."); + case AccountTaskState::STATE_FAILED_GONE: + return tr("Failed to authenticate. The account no longer exists."); + default: + return tr("..."); } } @@ -65,3 +77,62 @@ void AuthFlow::stepFinished(AccountTaskState resultingState, QString message) nextStep(); } } + +bool AuthFlow::changeState(AccountTaskState newState, QString reason) +{ + m_taskState = newState; + // FIXME: virtual method invoked in constructor. + // We want that behavior, but maybe make it less weird? + setStatus(getStateMessage()); + switch (newState) { + case AccountTaskState::STATE_CREATED: { + m_data->errorString.clear(); + return true; + } + case AccountTaskState::STATE_WORKING: { + m_data->accountState = AccountState::Working; + return true; + } + case AccountTaskState::STATE_SUCCEEDED: { + m_data->accountState = AccountState::Online; + emitSucceeded(); + return false; + } + case AccountTaskState::STATE_OFFLINE: { + m_data->errorString = reason; + m_data->accountState = AccountState::Offline; + emitFailed(reason); + return false; + } + case AccountTaskState::STATE_DISABLED: { + m_data->errorString = reason; + m_data->accountState = AccountState::Disabled; + emitFailed(reason); + return false; + } + case AccountTaskState::STATE_FAILED_SOFT: { + m_data->errorString = reason; + m_data->accountState = AccountState::Errored; + emitFailed(reason); + return false; + } + case AccountTaskState::STATE_FAILED_HARD: { + m_data->errorString = reason; + m_data->accountState = AccountState::Expired; + emitFailed(reason); + return false; + } + case AccountTaskState::STATE_FAILED_GONE: { + m_data->errorString = reason; + m_data->accountState = AccountState::Gone; + emitFailed(reason); + return false; + } + default: { + QString error = tr("Unknown account task state: %1").arg(int(newState)); + m_data->accountState = AccountState::Errored; + emitFailed(error); + return false; + } + } +} \ No newline at end of file diff --git a/launcher/minecraft/auth/flows/AuthFlow.h b/launcher/minecraft/auth/flows/AuthFlow.h index e39e926dd..10fdd22fa 100644 --- a/launcher/minecraft/auth/flows/AuthFlow.h +++ b/launcher/minecraft/auth/flows/AuthFlow.h @@ -10,32 +10,48 @@ #include #include "minecraft/auth/AccountData.h" -#include "minecraft/auth/AccountTask.h" #include "minecraft/auth/AuthStep.h" +#include "tasks/Task.h" -class AuthFlow : public AccountTask { +class AuthFlow : public Task { Q_OBJECT public: explicit AuthFlow(AccountData* data, QObject* parent = 0); + virtual ~AuthFlow() = default; Katabasis::Validity validity() { return m_data->validity_; }; - QString getStateMessage() const override; - void executeTask() override; + AccountTaskState taskState() { return m_taskState; } + signals: + void showVerificationUriAndCode(const QUrl& uri, const QString& code, int expiresIn); + void hideVerificationUriAndCode(); + void activityChanged(Katabasis::Activity activity); + protected: + /** + * Returns the state message for the given state. + * Used to set the status message for the task. + * Should be overridden by subclasses that want to change messages for a given state. + */ + virtual QString getStateMessage() const; + void succeed(); + void nextStep(); + + protected slots: + // NOTE: true -> non-terminal state, false -> terminal state + bool changeState(AccountTaskState newState, QString reason = QString()); + private slots: void stepFinished(AccountTaskState resultingState, QString message); protected: - void succeed(); - void nextStep(); - - protected: + AccountTaskState m_taskState = AccountTaskState::STATE_CREATED; QList m_steps; AuthStep::Ptr m_currentStep; + AccountData* m_data = nullptr; }; diff --git a/launcher/minecraft/auth/steps/LauncherLoginStep.cpp b/launcher/minecraft/auth/steps/LauncherLoginStep.cpp index 8981c5752..d72346c74 100644 --- a/launcher/minecraft/auth/steps/LauncherLoginStep.cpp +++ b/launcher/minecraft/auth/steps/LauncherLoginStep.cpp @@ -5,7 +5,6 @@ #include "Application.h" #include "Logging.h" -#include "minecraft/auth/AccountTask.h" #include "minecraft/auth/Parsers.h" #include "net/NetUtils.h" #include "net/StaticHeaderProxy.h" diff --git a/launcher/net/NetRequest.cpp b/launcher/net/NetRequest.cpp index 009213332..29de2febf 100644 --- a/launcher/net/NetRequest.cpp +++ b/launcher/net/NetRequest.cpp @@ -170,6 +170,8 @@ void NetRequest::downloadError(QNetworkReply::NetworkError error) } // error happened during download. qCCritical(logCat) << getUid().toString() << "Failed " << m_url.toString() << " with reason " << error; + if (m_reply) + qCCritical(logCat) << getUid().toString() << "HTTP Status " << replyStatusCode() << ";error " << errorString(); m_state = State::Failed; } } diff --git a/launcher/ui/dialogs/MSALoginDialog.cpp b/launcher/ui/dialogs/MSALoginDialog.cpp index 7df423412..e396c01f6 100644 --- a/launcher/ui/dialogs/MSALoginDialog.cpp +++ b/launcher/ui/dialogs/MSALoginDialog.cpp @@ -37,7 +37,7 @@ #include "ui_MSALoginDialog.h" #include "DesktopServices.h" -#include "minecraft/auth/AccountTask.h" +#include "minecraft/auth/flows/AuthFlow.h" #include #include @@ -67,8 +67,8 @@ int MSALoginDialog::exec() connect(m_loginTask.get(), &Task::succeeded, this, &MSALoginDialog::onTaskSucceeded); connect(m_loginTask.get(), &Task::status, this, &MSALoginDialog::onTaskStatus); connect(m_loginTask.get(), &Task::progress, this, &MSALoginDialog::onTaskProgress); - connect(m_loginTask.get(), &AccountTask::showVerificationUriAndCode, this, &MSALoginDialog::showVerificationUriAndCode); - connect(m_loginTask.get(), &AccountTask::hideVerificationUriAndCode, this, &MSALoginDialog::hideVerificationUriAndCode); + connect(m_loginTask.get(), &AuthFlow::showVerificationUriAndCode, this, &MSALoginDialog::showVerificationUriAndCode); + connect(m_loginTask.get(), &AuthFlow::hideVerificationUriAndCode, this, &MSALoginDialog::hideVerificationUriAndCode); connect(&m_externalLoginTimer, &QTimer::timeout, this, &MSALoginDialog::externalLoginTick); m_loginTask->start(); diff --git a/launcher/ui/dialogs/MSALoginDialog.h b/launcher/ui/dialogs/MSALoginDialog.h index 03e276bc0..531ae3cc1 100644 --- a/launcher/ui/dialogs/MSALoginDialog.h +++ b/launcher/ui/dialogs/MSALoginDialog.h @@ -20,6 +20,7 @@ #include #include "minecraft/auth/MinecraftAccount.h" +#include "minecraft/auth/flows/AuthFlow.h" namespace Ui { class MSALoginDialog; @@ -52,7 +53,7 @@ class MSALoginDialog : public QDialog { private: Ui::MSALoginDialog* ui; MinecraftAccountPtr m_account; - shared_qobject_ptr m_loginTask; + shared_qobject_ptr m_loginTask; QTimer m_externalLoginTimer; int m_externalLoginElapsed = 0; int m_externalLoginTimeout = 0; diff --git a/launcher/ui/dialogs/OfflineLoginDialog.cpp b/launcher/ui/dialogs/OfflineLoginDialog.cpp index 137620be4..cd3102135 100644 --- a/launcher/ui/dialogs/OfflineLoginDialog.cpp +++ b/launcher/ui/dialogs/OfflineLoginDialog.cpp @@ -1,8 +1,6 @@ #include "OfflineLoginDialog.h" #include "ui_OfflineLoginDialog.h" -#include "minecraft/auth/AccountTask.h" - #include OfflineLoginDialog::OfflineLoginDialog(QWidget* parent) : QDialog(parent), ui(new Ui::OfflineLoginDialog) From c2ed50627dfb09d3ef99f38a70955d8ef2803de3 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 14 May 2024 00:36:35 +0300 Subject: [PATCH 211/223] Added back qt version check Signed-off-by: Trial97 --- launcher/net/NetRequest.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/launcher/net/NetRequest.cpp b/launcher/net/NetRequest.cpp index 29de2febf..90ce15451 100644 --- a/launcher/net/NetRequest.cpp +++ b/launcher/net/NetRequest.cpp @@ -105,7 +105,9 @@ void NetRequest::executeTask() header_proxy->writeHeaders(request); } - request.setTransferTimeout(QNetworkRequest::DefaultTransferTimeoutConstant); +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + request.setTransferTimeout(); +#endif m_last_progress_time = m_clock.now(); m_last_progress_bytes = 0; From 80d8e3ee06e8f71503523d4f388b1f729ae7a75e Mon Sep 17 00:00:00 2001 From: Trial97 Date: Wed, 15 May 2024 12:53:06 +0300 Subject: [PATCH 212/223] Remove katabasis Signed-off-by: Trial97 --- .github/workflows/build.yml | 25 +- CMakeLists.txt | 5 +- COPYING.md | 26 - launcher/CMakeLists.txt | 3 +- launcher/minecraft/auth/AccountData.h | 33 +- launcher/minecraft/auth/AuthStep.h | 2 - launcher/minecraft/auth/flows/AuthFlow.cpp | 42 +- launcher/minecraft/auth/flows/AuthFlow.h | 11 - launcher/minecraft/auth/steps/MSAStep.cpp | 102 ++-- launcher/minecraft/auth/steps/MSAStep.h | 9 +- launcher/net/NetRequest.cpp | 4 +- launcher/qtlogging.ini | 1 - launcher/ui/dialogs/MSALoginDialog.cpp | 52 -- launcher/ui/dialogs/MSALoginDialog.h | 8 - libraries/README.md | 8 - libraries/katabasis/.gitignore | 2 - libraries/katabasis/CMakeLists.txt | 58 --- libraries/katabasis/LICENSE | 23 - libraries/katabasis/README.md | 36 -- libraries/katabasis/acknowledgements.md | 108 ---- libraries/katabasis/include/katabasis/Bits.h | 33 -- .../katabasis/include/katabasis/DeviceFlow.h | 149 ------ .../katabasis/include/katabasis/Globals.h | 59 --- .../katabasis/include/katabasis/PollServer.h | 51 -- libraries/katabasis/include/katabasis/Reply.h | 63 --- .../include/katabasis/RequestParameter.h | 13 - libraries/katabasis/src/DeviceFlow.cpp | 467 ------------------ libraries/katabasis/src/JsonResponse.cpp | 27 - libraries/katabasis/src/JsonResponse.h | 12 - libraries/katabasis/src/PollServer.cpp | 118 ----- libraries/katabasis/src/Reply.cpp | 74 --- 31 files changed, 99 insertions(+), 1525 deletions(-) delete mode 100644 libraries/katabasis/.gitignore delete mode 100644 libraries/katabasis/CMakeLists.txt delete mode 100644 libraries/katabasis/LICENSE delete mode 100644 libraries/katabasis/README.md delete mode 100644 libraries/katabasis/acknowledgements.md delete mode 100644 libraries/katabasis/include/katabasis/Bits.h delete mode 100644 libraries/katabasis/include/katabasis/DeviceFlow.h delete mode 100644 libraries/katabasis/include/katabasis/Globals.h delete mode 100644 libraries/katabasis/include/katabasis/PollServer.h delete mode 100644 libraries/katabasis/include/katabasis/Reply.h delete mode 100644 libraries/katabasis/include/katabasis/RequestParameter.h delete mode 100644 libraries/katabasis/src/DeviceFlow.cpp delete mode 100644 libraries/katabasis/src/JsonResponse.cpp delete mode 100644 libraries/katabasis/src/JsonResponse.h delete mode 100644 libraries/katabasis/src/PollServer.cpp delete mode 100644 libraries/katabasis/src/Reply.cpp diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e502318a3..999029bd2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -57,14 +57,14 @@ jobs: qt_host: linux qt_arch: "" qt_version: "5.12.8" - qt_modules: "" + qt_modules: "qtnetworkauth" - os: ubuntu-20.04 qt_ver: 6 qt_host: linux qt_arch: "" qt_version: "6.2.4" - qt_modules: "qt5compat qtimageformats" + qt_modules: "qt5compat qtimageformats qtnetworkauth" - os: windows-2022 name: "Windows-MinGW-w64" @@ -78,9 +78,9 @@ jobs: vcvars_arch: "amd64" qt_ver: 6 qt_host: windows - qt_arch: '' - qt_version: '6.7.0' - qt_modules: 'qt5compat qtimageformats' + qt_arch: "" + qt_version: "6.7.0" + qt_modules: "qt5compat qtimageformats qtnetworkauth" - os: windows-2022 name: "Windows-MSVC-arm64" @@ -89,18 +89,18 @@ jobs: vcvars_arch: "amd64_arm64" qt_ver: 6 qt_host: windows - qt_arch: 'win64_msvc2019_arm64' - qt_version: '6.7.0' - qt_modules: 'qt5compat qtimageformats' + qt_arch: "win64_msvc2019_arm64" + qt_version: "6.7.0" + qt_modules: "qt5compat qtimageformats qtnetworkauth" - os: macos-12 name: macOS macosx_deployment_target: 11.0 qt_ver: 6 qt_host: mac - qt_arch: '' - qt_version: '6.7.0' - qt_modules: 'qt5compat qtimageformats' + qt_arch: "" + qt_version: "6.7.0" + qt_modules: "qt5compat qtimageformats qtnetworkauth" - os: macos-12 name: macOS-Legacy @@ -108,7 +108,7 @@ jobs: qt_ver: 5 qt_host: mac qt_version: "5.15.2" - qt_modules: "" + qt_modules: "qtnetworkauth" runs-on: ${{ matrix.os }} @@ -150,6 +150,7 @@ jobs: quazip-qt6:p ccache:p qt6-5compat:p + qt6-networkauth:p cmark:p - name: Force newer ccache diff --git a/CMakeLists.txt b/CMakeLists.txt index 63408ec21..5c3987406 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -282,7 +282,7 @@ endif() include(QtVersionlessBackport) if(Launcher_QT_VERSION_MAJOR EQUAL 5) set(QT_VERSION_MAJOR 5) - find_package(Qt5 REQUIRED COMPONENTS Core Widgets Concurrent Network Test Xml) + find_package(Qt5 REQUIRED COMPONENTS Core Widgets Concurrent Network Test Xml NetworkAuth) if(NOT Launcher_FORCE_BUNDLED_LIBS) find_package(QuaZip-Qt5 1.3 QUIET) @@ -296,7 +296,7 @@ if(Launcher_QT_VERSION_MAJOR EQUAL 5) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUNICODE -D_UNICODE") elseif(Launcher_QT_VERSION_MAJOR EQUAL 6) set(QT_VERSION_MAJOR 6) - find_package(Qt6 REQUIRED COMPONENTS Core CoreTools Widgets Concurrent Network Test Xml Core5Compat) + find_package(Qt6 REQUIRED COMPONENTS Core CoreTools Widgets Concurrent Network Test Xml Core5Compat NetworkAuth) list(APPEND Launcher_QT_LIBS Qt6::Core5Compat) if(NOT Launcher_FORCE_BUNDLED_LIBS) @@ -523,7 +523,6 @@ if(NOT cmark_FOUND) else() message(STATUS "Using system cmark") endif() -add_subdirectory(libraries/katabasis) # An OAuth2 library that tried to do too much add_subdirectory(libraries/gamemode) add_subdirectory(libraries/murmur2) # Hash for usage with the CurseForge API if (NOT ghc_filesystem_FOUND) diff --git a/COPYING.md b/COPYING.md index f14e2958e..111587060 100644 --- a/COPYING.md +++ b/COPYING.md @@ -333,32 +333,6 @@ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -## O2 (Katabasis fork) - - Copyright (c) 2012, Akos Polster - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ## Gamemode Copyright (c) 2017-2022, Feral Interactive diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index e4143ee28..e5eb4b733 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -1234,7 +1234,6 @@ target_link_libraries(Launcher_logic tomlplusplus::tomlplusplus qdcss BuildConfig - Katabasis Qt${QT_VERSION_MAJOR}::Widgets ghcFilesystem::ghc_filesystem ) @@ -1252,6 +1251,7 @@ target_link_libraries(Launcher_logic Qt${QT_VERSION_MAJOR}::Concurrent Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Widgets + Qt${QT_VERSION_MAJOR}::NetworkAuth ${Launcher_QT_LIBS} ) target_link_libraries(Launcher_logic @@ -1322,7 +1322,6 @@ if(Launcher_BUILD_UPDATER) Qt${QT_VERSION_MAJOR}::Network ${Launcher_QT_LIBS} cmark::cmark - Katabasis ) add_executable("${Launcher_Name}_updater" WIN32 updater/prismupdater/updater_main.cpp) diff --git a/launcher/minecraft/auth/AccountData.h b/launcher/minecraft/auth/AccountData.h index bac77e17f..71f1d00b2 100644 --- a/launcher/minecraft/auth/AccountData.h +++ b/launcher/minecraft/auth/AccountData.h @@ -34,12 +34,43 @@ */ #pragma once -#include #include #include #include #include +#include +#include +#include +#include + +namespace Katabasis { +enum class Activity { + Idle, + LoggingIn, + LoggingOut, + Refreshing, + FailedSoft, //!< soft failure. this generally means the user auth details haven't been invalidated + FailedHard, //!< hard failure. auth is invalid + FailedGone, //!< hard failure. auth is invalid, and the account no longer exists + Succeeded +}; + +enum class Validity { None, Assumed, Certain }; + +struct Token { + QDateTime issueInstant; + QDateTime notAfter; + QString token; + QString refresh_token; + QVariantMap extra; + + Validity validity = Validity::None; + bool persistent = true; +}; + +} // namespace Katabasis + struct Skin { QString id; QString url; diff --git a/launcher/minecraft/auth/AuthStep.h b/launcher/minecraft/auth/AuthStep.h index dccbec11e..4d2cf69c1 100644 --- a/launcher/minecraft/auth/AuthStep.h +++ b/launcher/minecraft/auth/AuthStep.h @@ -37,8 +37,6 @@ class AuthStep : public QObject { signals: void finished(AccountTaskState resultingState, QString message); - void showVerificationUriAndCode(const QUrl& uri, const QString& code, int expiresIn); - void hideVerificationUriAndCode(); protected: AccountData* m_data; diff --git a/launcher/minecraft/auth/flows/AuthFlow.cpp b/launcher/minecraft/auth/flows/AuthFlow.cpp index 20d90f504..1b5e01569 100644 --- a/launcher/minecraft/auth/flows/AuthFlow.cpp +++ b/launcher/minecraft/auth/flows/AuthFlow.cpp @@ -21,6 +21,7 @@ void AuthFlow::succeed() void AuthFlow::executeTask() { if (m_currentStep) { + emitFailed("No task"); return; } changeState(AccountTaskState::STATE_WORKING, tr("Initializing")); @@ -39,38 +40,10 @@ void AuthFlow::nextStep() qDebug() << "AuthFlow:" << m_currentStep->describe(); m_steps.pop_front(); connect(m_currentStep.get(), &AuthStep::finished, this, &AuthFlow::stepFinished); - connect(m_currentStep.get(), &AuthStep::showVerificationUriAndCode, this, &AuthFlow::showVerificationUriAndCode); - connect(m_currentStep.get(), &AuthStep::hideVerificationUriAndCode, this, &AuthFlow::hideVerificationUriAndCode); m_currentStep->perform(); } -QString AuthFlow::getStateMessage() const -{ - switch (m_taskState) { - case AccountTaskState::STATE_CREATED: - return "Waiting..."; - case AccountTaskState::STATE_WORKING: - if (m_currentStep) - return m_currentStep->describe(); - return tr("Working..."); - case AccountTaskState::STATE_SUCCEEDED: - return tr("Authentication task succeeded."); - case AccountTaskState::STATE_OFFLINE: - return tr("Failed to contact the authentication server."); - case AccountTaskState::STATE_DISABLED: - return tr("Client ID has changed. New session needs to be created."); - case AccountTaskState::STATE_FAILED_SOFT: - return tr("Encountered an error during authentication."); - case AccountTaskState::STATE_FAILED_HARD: - return tr("Failed to authenticate. The session has expired."); - case AccountTaskState::STATE_FAILED_GONE: - return tr("Failed to authenticate. The account no longer exists."); - default: - return tr("..."); - } -} - void AuthFlow::stepFinished(AccountTaskState resultingState, QString message) { if (changeState(resultingState, message)) { @@ -81,54 +54,61 @@ void AuthFlow::stepFinished(AccountTaskState resultingState, QString message) bool AuthFlow::changeState(AccountTaskState newState, QString reason) { m_taskState = newState; - // FIXME: virtual method invoked in constructor. - // We want that behavior, but maybe make it less weird? - setStatus(getStateMessage()); + setDetails(reason); switch (newState) { case AccountTaskState::STATE_CREATED: { + setStatus(tr("Waiting...")); m_data->errorString.clear(); return true; } case AccountTaskState::STATE_WORKING: { + setStatus(m_currentStep ? m_currentStep->describe() : tr("Working...")); m_data->accountState = AccountState::Working; return true; } case AccountTaskState::STATE_SUCCEEDED: { + setStatus(tr("Authentication task succeeded.")); m_data->accountState = AccountState::Online; emitSucceeded(); return false; } case AccountTaskState::STATE_OFFLINE: { + setStatus(tr("Failed to contact the authentication server.")); m_data->errorString = reason; m_data->accountState = AccountState::Offline; emitFailed(reason); return false; } case AccountTaskState::STATE_DISABLED: { + setStatus(tr("Client ID has changed. New session needs to be created.")); m_data->errorString = reason; m_data->accountState = AccountState::Disabled; emitFailed(reason); return false; } case AccountTaskState::STATE_FAILED_SOFT: { + setStatus(tr("Encountered an error during authentication.")); m_data->errorString = reason; m_data->accountState = AccountState::Errored; emitFailed(reason); return false; } case AccountTaskState::STATE_FAILED_HARD: { + setStatus(tr("Failed to authenticate. The session has expired.")); m_data->errorString = reason; m_data->accountState = AccountState::Expired; emitFailed(reason); return false; } case AccountTaskState::STATE_FAILED_GONE: { + setStatus(tr("Failed to authenticate. The account no longer exists.")); m_data->errorString = reason; m_data->accountState = AccountState::Gone; emitFailed(reason); return false; } default: { + setStatus(tr("...")); QString error = tr("Unknown account task state: %1").arg(int(newState)); m_data->accountState = AccountState::Errored; emitFailed(error); diff --git a/launcher/minecraft/auth/flows/AuthFlow.h b/launcher/minecraft/auth/flows/AuthFlow.h index 10fdd22fa..de563c3c5 100644 --- a/launcher/minecraft/auth/flows/AuthFlow.h +++ b/launcher/minecraft/auth/flows/AuthFlow.h @@ -7,8 +7,6 @@ #include #include -#include - #include "minecraft/auth/AccountData.h" #include "minecraft/auth/AuthStep.h" #include "tasks/Task.h" @@ -27,18 +25,9 @@ class AuthFlow : public Task { AccountTaskState taskState() { return m_taskState; } signals: - void showVerificationUriAndCode(const QUrl& uri, const QString& code, int expiresIn); - void hideVerificationUriAndCode(); - void activityChanged(Katabasis::Activity activity); protected: - /** - * Returns the state message for the given state. - * Used to set the status message for the task. - * Should be overridden by subclasses that want to change messages for a given state. - */ - virtual QString getStateMessage() const; void succeed(); void nextStep(); diff --git a/launcher/minecraft/auth/steps/MSAStep.cpp b/launcher/minecraft/auth/steps/MSAStep.cpp index 0a4b7c814..71bd25096 100644 --- a/launcher/minecraft/auth/steps/MSAStep.cpp +++ b/launcher/minecraft/auth/steps/MSAStep.cpp @@ -35,28 +35,44 @@ #include "MSAStep.h" +#include +#include +#include #include #include "Application.h" -#include "Logging.h" - -using OAuth2 = Katabasis::DeviceFlow; -using Activity = Katabasis::Activity; MSAStep::MSAStep(AccountData* data, Action action) : AuthStep(data), m_action(action) { m_clientId = APPLICATION->getMSAClientID(); - OAuth2::Options opts; - opts.scope = "XboxLive.signin offline_access"; - opts.clientIdentifier = m_clientId; - opts.authorizationUrl = "https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode"; - opts.accessTokenUrl = "https://login.microsoftonline.com/consumers/oauth2/v2.0/token"; - // FIXME: OAuth2 is not aware of our fancy shared pointers - m_oauth2 = new OAuth2(opts, m_data->msaToken, this, APPLICATION->network().get()); + auto replyHandler = new QOAuthHttpServerReplyHandler(1337, this); + oauth2.setReplyHandler(replyHandler); + oauth2.setAuthorizationUrl(QUrl("https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize")); + oauth2.setAccessTokenUrl(QUrl("https://login.microsoftonline.com/consumers/oauth2/v2.0/token")); + oauth2.setScope("XboxLive.SignIn XboxLive.offline_access"); + oauth2.setClientIdentifier(m_clientId); + oauth2.setNetworkAccessManager(APPLICATION->network().get()); - connect(m_oauth2, &OAuth2::activityChanged, this, &MSAStep::onOAuthActivityChanged); - connect(m_oauth2, &OAuth2::showVerificationUriAndCode, this, &MSAStep::showVerificationUriAndCode); + connect(&oauth2, &QOAuth2AuthorizationCodeFlow::granted, this, [this] { + m_data->msaClientID = oauth2.clientIdentifier(); + m_data->msaToken.issueInstant = QDateTime::currentDateTimeUtc(); + m_data->msaToken.notAfter = oauth2.expirationAt(); + m_data->msaToken.extra = oauth2.extraTokens(); + m_data->msaToken.refresh_token = oauth2.refreshToken(); + m_data->msaToken.token = oauth2.token(); + emit finished(AccountTaskState::STATE_WORKING, tr("Got ")); + }); + connect(&oauth2, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser, this, &QDesktopServices::openUrl); + connect(&oauth2, &QOAuth2AuthorizationCodeFlow::requestFailed, this, [this](const QAbstractOAuth2::Error err) { + emit finished(AccountTaskState::STATE_FAILED_HARD, tr("Microsoft user authentication failed.")); + }); + + connect(&oauth2, &QOAuth2AuthorizationCodeFlow::extraTokensChanged, this, + [this](const QVariantMap& tokens) { m_data->msaToken.extra = tokens; }); + + connect(&oauth2, &QOAuth2AuthorizationCodeFlow::clientIdentifierChanged, this, + [this](const QString& clientIdentifier) { m_data->msaClientID = clientIdentifier; }); } QString MSAStep::describe() @@ -69,68 +85,22 @@ void MSAStep::perform() switch (m_action) { case Refresh: { if (m_data->msaClientID != m_clientId) { - emit hideVerificationUriAndCode(); emit finished(AccountTaskState::STATE_DISABLED, tr("Microsoft user authentication failed - client identification has changed.")); } - m_oauth2->refresh(); + oauth2.setRefreshToken(m_data->msaToken.refresh_token); + oauth2.refreshAccessToken(); return; } case Login: { - QVariantMap extraOpts; - extraOpts["prompt"] = "select_account"; - m_oauth2->setExtraRequestParams(extraOpts); + oauth2.setModifyParametersFunction([](QAbstractOAuth::Stage stage, QMultiMap* map) { + map->insert("prompt", "select_account"); + map->insert("cobrandid", "8058f65d-ce06-4c30-9559-473c9275a65d"); + }); *m_data = AccountData(); m_data->msaClientID = m_clientId; - m_oauth2->login(); - return; - } - } -} - -void MSAStep::onOAuthActivityChanged(Katabasis::Activity activity) -{ - switch (activity) { - case Katabasis::Activity::Idle: - case Katabasis::Activity::LoggingIn: - case Katabasis::Activity::Refreshing: - case Katabasis::Activity::LoggingOut: { - // We asked it to do something, it's doing it. Nothing to act upon. - return; - } - case Katabasis::Activity::Succeeded: { - // Succeeded or did not invalidate tokens - emit hideVerificationUriAndCode(); - QVariantMap extraTokens = m_oauth2->extraTokens(); - if (!extraTokens.isEmpty()) { - qCDebug(authCredentials()) << "Extra tokens in response:"; - foreach (QString key, extraTokens.keys()) { - qCDebug(authCredentials()) << "\t" << key << ":" << extraTokens.value(key); - } - } - emit finished(AccountTaskState::STATE_WORKING, tr("Got ")); - return; - } - case Katabasis::Activity::FailedSoft: { - // NOTE: soft error in the first step means 'offline' - emit hideVerificationUriAndCode(); - emit finished(AccountTaskState::STATE_OFFLINE, tr("Microsoft user authentication ended with a network error.")); - return; - } - case Katabasis::Activity::FailedGone: { - emit hideVerificationUriAndCode(); - emit finished(AccountTaskState::STATE_FAILED_GONE, tr("Microsoft user authentication failed - user no longer exists.")); - return; - } - case Katabasis::Activity::FailedHard: { - emit hideVerificationUriAndCode(); - emit finished(AccountTaskState::STATE_FAILED_HARD, tr("Microsoft user authentication failed.")); - return; - } - default: { - emit hideVerificationUriAndCode(); - emit finished(AccountTaskState::STATE_FAILED_HARD, tr("Microsoft user authentication completed with an unrecognized result.")); + oauth2.grant(); return; } } diff --git a/launcher/minecraft/auth/steps/MSAStep.h b/launcher/minecraft/auth/steps/MSAStep.h index ee441308f..f38f5c70e 100644 --- a/launcher/minecraft/auth/steps/MSAStep.h +++ b/launcher/minecraft/auth/steps/MSAStep.h @@ -36,11 +36,9 @@ #pragma once #include -#include "QObjectPtr.h" #include "minecraft/auth/AuthStep.h" -#include - +#include class MSAStep : public AuthStep { Q_OBJECT public: @@ -54,11 +52,8 @@ class MSAStep : public AuthStep { QString describe() override; - private slots: - void onOAuthActivityChanged(Katabasis::Activity activity); - private: - Katabasis::DeviceFlow* m_oauth2 = nullptr; Action m_action; QString m_clientId; + QOAuth2AuthorizationCodeFlow oauth2; }; diff --git a/launcher/net/NetRequest.cpp b/launcher/net/NetRequest.cpp index 90ce15451..55a4f185c 100644 --- a/launcher/net/NetRequest.cpp +++ b/launcher/net/NetRequest.cpp @@ -171,9 +171,9 @@ void NetRequest::downloadError(QNetworkReply::NetworkError error) } } // error happened during download. - qCCritical(logCat) << getUid().toString() << "Failed " << m_url.toString() << " with reason " << error; + qCCritical(logCat) << getUid().toString() << "Failed" << m_url.toString() << "with reason" << error; if (m_reply) - qCCritical(logCat) << getUid().toString() << "HTTP Status " << replyStatusCode() << ";error " << errorString(); + qCCritical(logCat) << getUid().toString() << "HTTP Status" << replyStatusCode() << ";error" << errorString(); m_state = State::Failed; } } diff --git a/launcher/qtlogging.ini b/launcher/qtlogging.ini index 5266de59b..c12d1e109 100644 --- a/launcher/qtlogging.ini +++ b/launcher/qtlogging.ini @@ -5,7 +5,6 @@ qt.*.debug=false # don't log credentials by default launcher.auth.credentials.debug=false -katabasis.*.debug=false # remove the debug lines, other log levels still get through launcher.task.net.download.debug=false # enable or disable whole catageries diff --git a/launcher/ui/dialogs/MSALoginDialog.cpp b/launcher/ui/dialogs/MSALoginDialog.cpp index e396c01f6..b249346a4 100644 --- a/launcher/ui/dialogs/MSALoginDialog.cpp +++ b/launcher/ui/dialogs/MSALoginDialog.cpp @@ -67,9 +67,6 @@ int MSALoginDialog::exec() connect(m_loginTask.get(), &Task::succeeded, this, &MSALoginDialog::onTaskSucceeded); connect(m_loginTask.get(), &Task::status, this, &MSALoginDialog::onTaskStatus); connect(m_loginTask.get(), &Task::progress, this, &MSALoginDialog::onTaskProgress); - connect(m_loginTask.get(), &AuthFlow::showVerificationUriAndCode, this, &MSALoginDialog::showVerificationUriAndCode); - connect(m_loginTask.get(), &AuthFlow::hideVerificationUriAndCode, this, &MSALoginDialog::hideVerificationUriAndCode); - connect(&m_externalLoginTimer, &QTimer::timeout, this, &MSALoginDialog::externalLoginTick); m_loginTask->start(); return QDialog::exec(); @@ -80,55 +77,6 @@ MSALoginDialog::~MSALoginDialog() delete ui; } -void MSALoginDialog::externalLoginTick() -{ - m_externalLoginElapsed++; - ui->progressBar->setValue(m_externalLoginElapsed); - ui->progressBar->repaint(); - - if (m_externalLoginElapsed >= m_externalLoginTimeout) { - m_externalLoginTimer.stop(); - } -} - -void MSALoginDialog::showVerificationUriAndCode(const QUrl& uri, const QString& code, int expiresIn) -{ - m_externalLoginElapsed = 0; - m_externalLoginTimeout = expiresIn; - - m_externalLoginTimer.setInterval(1000); - m_externalLoginTimer.setSingleShot(false); - m_externalLoginTimer.start(); - - ui->progressBar->setMaximum(expiresIn); - ui->progressBar->setValue(m_externalLoginElapsed); - - QString urlString = uri.toString(); - QString linkString = QString("%2").arg(urlString, urlString); - if (urlString == "https://www.microsoft.com/link" && !code.isEmpty()) { - urlString += QString("?otc=%1").arg(code); - DesktopServices::openUrl(urlString); - ui->label->setText(tr("

Please login in the opened browser. If no browser was opened, please open up %1 in " - "a browser and put in the code %2 to proceed with login.

") - .arg(linkString, code)); - } else { - ui->label->setText( - tr("

Please open up %1 in a browser and put in the code %2 to proceed with login.

").arg(linkString, code)); - } - ui->actionButton->setVisible(true); - connect(ui->actionButton, &QPushButton::clicked, [=]() { - DesktopServices::openUrl(uri); - QClipboard* cb = QApplication::clipboard(); - cb->setText(code); - }); -} - -void MSALoginDialog::hideVerificationUriAndCode() -{ - m_externalLoginTimer.stop(); - ui->actionButton->setVisible(false); -} - void MSALoginDialog::setUserInputsEnabled(bool enable) { ui->buttonBox->setEnabled(enable); diff --git a/launcher/ui/dialogs/MSALoginDialog.h b/launcher/ui/dialogs/MSALoginDialog.h index 531ae3cc1..f14e04776 100644 --- a/launcher/ui/dialogs/MSALoginDialog.h +++ b/launcher/ui/dialogs/MSALoginDialog.h @@ -15,7 +15,6 @@ #pragma once -#include #include #include @@ -45,16 +44,9 @@ class MSALoginDialog : public QDialog { void onTaskSucceeded(); void onTaskStatus(const QString& status); void onTaskProgress(qint64 current, qint64 total); - void showVerificationUriAndCode(const QUrl& uri, const QString& code, int expiresIn); - void hideVerificationUriAndCode(); - - void externalLoginTick(); private: Ui::MSALoginDialog* ui; MinecraftAccountPtr m_account; shared_qobject_ptr m_loginTask; - QTimer m_externalLoginTimer; - int m_externalLoginElapsed = 0; - int m_externalLoginTimeout = 0; }; diff --git a/libraries/README.md b/libraries/README.md index e75a381ee..67d78dade 100644 --- a/libraries/README.md +++ b/libraries/README.md @@ -32,14 +32,6 @@ Simple Java tool that prints the JVM details - version and platform bitness. Do what you want with it. It is so trivial that noone cares. -## Katabasis - -Oauth2 library customized for Microsoft authentication. - -This is a fork of the [O2 library](https://github.com/pipacs/o2). - -MIT licensed. - ## launcher Java launcher part for Minecraft. diff --git a/libraries/katabasis/.gitignore b/libraries/katabasis/.gitignore deleted file mode 100644 index 35e189c5e..000000000 --- a/libraries/katabasis/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -build/ -*.kdev4 diff --git a/libraries/katabasis/CMakeLists.txt b/libraries/katabasis/CMakeLists.txt deleted file mode 100644 index 643244ede..000000000 --- a/libraries/katabasis/CMakeLists.txt +++ /dev/null @@ -1,58 +0,0 @@ -cmake_minimum_required(VERSION 3.9.4) - -string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BUILD_DIR}" IS_IN_SOURCE_BUILD) -if(IS_IN_SOURCE_BUILD) - message(FATAL_ERROR "You are building Katabasis in-source. Please separate the build tree from the source tree.") -endif() - -project(Katabasis) -enable_testing() - -set(CMAKE_AUTOMOC ON) -set(CMAKE_INCLUDE_CURRENT_DIR ON) - -set(CMAKE_CXX_STANDARD_REQUIRED true) -set(CMAKE_C_STANDARD_REQUIRED true) -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_C_STANDARD 11) - -if(QT_VERSION_MAJOR EQUAL 5) - find_package(Qt5 COMPONENTS Core Network REQUIRED) -elseif(Launcher_QT_VERSION_MAJOR EQUAL 6) - find_package(Qt6 COMPONENTS Core Network REQUIRED) -endif() - -set( katabasis_PRIVATE - src/DeviceFlow.cpp - src/JsonResponse.cpp - src/JsonResponse.h - src/PollServer.cpp - src/Reply.cpp -) - -set( katabasis_PUBLIC - include/katabasis/DeviceFlow.h - include/katabasis/Globals.h - include/katabasis/PollServer.h - include/katabasis/Reply.h - include/katabasis/RequestParameter.h -) - -ecm_qt_declare_logging_category(katabasis_PRIVATE - HEADER KatabasisLogging.h # NOTE: this won't be in src/, but CMAKE_BINARY_DIR/src isn't included by default so this should be fine - IDENTIFIER katabasisCredentials - CATEGORY_NAME "katabasis.credentials" - DEFAULT_SEVERITY Warning - DESCRIPTION "Secrets and credentials from Katabasis" - EXPORT "Katabasis" -) - -add_library( Katabasis STATIC ${katabasis_PRIVATE} ${katabasis_PUBLIC} ) -target_link_libraries(Katabasis Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Network) - -# needed for statically linked Katabasis in shared libs on x86_64 -set_target_properties(Katabasis - PROPERTIES POSITION_INDEPENDENT_CODE TRUE -) - -target_include_directories(Katabasis PUBLIC include PRIVATE src include/katabasis) diff --git a/libraries/katabasis/LICENSE b/libraries/katabasis/LICENSE deleted file mode 100644 index 9ac8d42fb..000000000 --- a/libraries/katabasis/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) 2012, Akos Polster -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this -list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/libraries/katabasis/README.md b/libraries/katabasis/README.md deleted file mode 100644 index fe6dd4aca..000000000 --- a/libraries/katabasis/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# Katabasis - MS-flavored OAuth for Qt, derived from the O2 library - -This library's sole purpose is to make interacting with MSA and various MSA and XBox authenticated services less painful. - -It may be possible to backport some of the changes to O2 in the future, but for the sake of going fast, all compatibility concerns have been ignored. - -[You can find the original library's git repository here.](https://github.com/pipacs/o2) - -Notes to contributors: - -* Please follow the coding style of the existing source, where reasonable -* Code contributions are released under Simplified BSD License, as specified in LICENSE. Do not contribute if this license does not suit your code -* If you are interested in working on this, come to the Prism Launcher Discord server and talk first - -## Installation - -Clone the Github repository, integrate the it into your CMake build system. - -The library is static only, dynamic linking and system-wide installation are out of scope and undesirable. - -## Usage - -At this stage, don't, unless you want to help with the library itself. - -This is an experimental fork of the O2 library and is undergoing a big design/architecture shift in order to support different features: - -* Multiple accounts -* Multi-stage authentication/authorization schemes -* Tighter control over token chains and their storage -* Talking to complex APIs and individually authorized microservices -* Token lifetime management, 'offline mode' and resilience in face of network failures -* Token and claims/entitlements validation -* Caching of some API results -* XBox magic -* Mojang magic -* Generally, magic that you would spend weeks on researching while getting confused by contradictory/incomplete documentation (if any is available) diff --git a/libraries/katabasis/acknowledgements.md b/libraries/katabasis/acknowledgements.md deleted file mode 100644 index a6989d15a..000000000 --- a/libraries/katabasis/acknowledgements.md +++ /dev/null @@ -1,108 +0,0 @@ -## O2 library by Akos Polster and contributors - -[The origin of this fork.](https://github.com/pipacs/o2) - -> Copyright (c) 2012, Akos Polster -> All rights reserved. -> -> Redistribution and use in source and binary forms, with or without -> modification, are permitted provided that the following conditions are met: -> -> * Redistributions of source code must retain the above copyright notice, this -> list of conditions and the following disclaimer. -> -> * Redistributions in binary form must reproduce the above copyright notice, -> this list of conditions and the following disclaimer in the documentation -> and/or other materials provided with the distribution. -> -> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -> AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -> IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -> DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -> FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -> DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -> SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -> CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -> OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -> OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -## SimpleCrypt by Andre Somers - -Cryptographic methods for Qt. - -> Copyright (c) 2011, Andre Somers -> All rights reserved. -> -> Redistribution and use in source and binary forms, with or without -> modification, are permitted provided that the following conditions are met: -> -> * Redistributions of source code must retain the above copyright -> notice, this list of conditions and the following disclaimer. -> * Redistributions in binary form must reproduce the above copyright -> notice, this list of conditions and the following disclaimer in the -> documentation and/or other materials provided with the distribution. -> * Neither the name of the Rathenau Instituut, Andre Somers nor the -> names of its contributors may be used to endorse or promote products -> derived from this software without specific prior written permission. -> -> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -> ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -> WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -> DISCLAIMED. IN NO EVENT SHALL ANDRE SOMERS BE LIABLE FOR ANY -> DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -> (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -> LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -> ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -> (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -> SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -## Mandeep Sandhu - -Configurable settings storage, Twitter XAuth specialization, new demos, cleanups. - -> "Hi Akos, -> -> I'm writing this mail to confirm that my contributions to the O2 library, available here , can be freely distributed according to the project's license (as shown in the LICENSE file). -> -> Regards, -> -mandeep" - -## Sergey Gavrushkin - -FreshBooks specialization - -## Theofilos Intzoglou - -Hubic specialization - -## Dimitar - -SurveyMonkey specialization - -## David Brooks - -CMake related fixes and improvements. - -## Lukas Vogel - -Spotify support - -## Alan Garny - -Windows DLL build support - -## MartinMikita - -Bug fixes - -## Larry Shaffer - -Versioning, shared lib, install target and header support - -## Gilmanov Ildar - -Bug fixes, support for ```qml``` module - -## Fabian Vogt - -Bug fixes, support for building without Qt keywords enabled diff --git a/libraries/katabasis/include/katabasis/Bits.h b/libraries/katabasis/include/katabasis/Bits.h deleted file mode 100644 index 15da2a5a8..000000000 --- a/libraries/katabasis/include/katabasis/Bits.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace Katabasis { -enum class Activity { - Idle, - LoggingIn, - LoggingOut, - Refreshing, - FailedSoft, //!< soft failure. this generally means the user auth details haven't been invalidated - FailedHard, //!< hard failure. auth is invalid - FailedGone, //!< hard failure. auth is invalid, and the account no longer exists - Succeeded -}; - -enum class Validity { None, Assumed, Certain }; - -struct Token { - QDateTime issueInstant; - QDateTime notAfter; - QString token; - QString refresh_token; - QVariantMap extra; - - Validity validity = Validity::None; - bool persistent = true; -}; - -} // namespace Katabasis diff --git a/libraries/katabasis/include/katabasis/DeviceFlow.h b/libraries/katabasis/include/katabasis/DeviceFlow.h deleted file mode 100644 index 98724d81b..000000000 --- a/libraries/katabasis/include/katabasis/DeviceFlow.h +++ /dev/null @@ -1,149 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "Bits.h" -#include "Reply.h" -#include "RequestParameter.h" - -namespace Katabasis { - -class ReplyServer; -class PollServer; - -/// Simple OAuth2 Device Flow authenticator. -class DeviceFlow : public QObject { - Q_OBJECT - public: - Q_ENUMS(GrantFlow) - - public: - struct Options { - QString userAgent = QStringLiteral("Katabasis/1.0"); - QString responseType = QStringLiteral("code"); - QString scope; - QString clientIdentifier; - QString clientSecret; - QUrl authorizationUrl; - QUrl accessTokenUrl; - }; - - public: - /// Are we authenticated? - bool linked(); - - /// Authentication token. - QString token(); - - /// Provider-specific extra tokens, available after a successful authentication - QVariantMap extraTokens(); - - public: - // TODO: put in `Options` - /// User-defined extra parameters to append to request URL - QVariantMap extraRequestParams(); - void setExtraRequestParams(const QVariantMap& value); - - // TODO: split up the class into multiple, each implementing one OAuth2 flow - /// Grant type (if non-standard) - QString grantType(); - void setGrantType(const QString& value); - - public: - /// Constructor. - /// @param parent Parent object. - explicit DeviceFlow(Options& opts, Token& token, QObject* parent = 0, QNetworkAccessManager* manager = 0); - - /// Get refresh token. - QString refreshToken(); - - /// Get token expiration time - QDateTime expires(); - - public slots: - /// Authenticate. - void login(); - - /// De-authenticate. - void logout(); - - /// Refresh token. - bool refresh(); - - /// Handle situation where reply server has opted to close its connection - void serverHasClosed(bool paramsfound = false); - - signals: - /// Emitted when client needs to open a web browser window, with the given URL. - void openBrowser(const QUrl& url); - - /// Emitted when client can close the browser window. - void closeBrowser(); - - /// Emitted when client needs to show a verification uri and user code - void showVerificationUriAndCode(const QUrl& uri, const QString& code, int expiresIn); - - /// Emitted when the internal state changes - void activityChanged(Activity activity); - - public slots: - /// Handle verification response. - void onVerificationReceived(QMap); - - protected slots: - /// Handle completion of a Device Authorization Request - void onDeviceAuthReplyFinished(); - - /// Handle completion of a refresh request. - void onRefreshFinished(); - - /// Handle failure of a refresh request. - void onRefreshError(QNetworkReply::NetworkError error, QNetworkReply* reply); - - protected: - /// Set refresh token. - void setRefreshToken(const QString& v); - - /// Set token expiration time. - void setExpires(QDateTime v); - - /// Start polling authorization server - void startPollServer(const QVariantMap& params, int expiresIn); - - /// Set authentication token. - void setToken(const QString& v); - - /// Set the linked state - void setLinked(bool v); - - /// Set extra tokens found in OAuth response - void setExtraTokens(QVariantMap extraTokens); - - /// Set local poll server - void setPollServer(PollServer* server); - - PollServer* pollServer() const; - - void updateActivity(Activity activity); - - protected: - Options options_; - - QVariantMap extraReqParams_; - QNetworkAccessManager* manager_ = nullptr; - ReplyList timedReplies_; - QString grantType_; - - protected: - Token& token_; - - private: - PollServer* pollServer_ = nullptr; - Activity activity_ = Activity::Idle; -}; - -} // namespace Katabasis diff --git a/libraries/katabasis/include/katabasis/Globals.h b/libraries/katabasis/include/katabasis/Globals.h deleted file mode 100644 index 02fe1cf45..000000000 --- a/libraries/katabasis/include/katabasis/Globals.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -namespace Katabasis { - -// Common constants -const char ENCRYPTION_KEY[] = "12345678"; -const char MIME_TYPE_XFORM[] = "application/x-www-form-urlencoded"; -const char MIME_TYPE_JSON[] = "application/json"; - -// OAuth 1/1.1 Request Parameters -const char OAUTH_CALLBACK[] = "oauth_callback"; -const char OAUTH_CONSUMER_KEY[] = "oauth_consumer_key"; -const char OAUTH_NONCE[] = "oauth_nonce"; -const char OAUTH_SIGNATURE[] = "oauth_signature"; -const char OAUTH_SIGNATURE_METHOD[] = "oauth_signature_method"; -const char OAUTH_TIMESTAMP[] = "oauth_timestamp"; -const char OAUTH_VERSION[] = "oauth_version"; -// OAuth 1/1.1 Response Parameters -const char OAUTH_TOKEN[] = "oauth_token"; -const char OAUTH_TOKEN_SECRET[] = "oauth_token_secret"; -const char OAUTH_CALLBACK_CONFIRMED[] = "oauth_callback_confirmed"; -const char OAUTH_VERFIER[] = "oauth_verifier"; - -// OAuth 2 Request Parameters -const char OAUTH2_RESPONSE_TYPE[] = "response_type"; -const char OAUTH2_CLIENT_ID[] = "client_id"; -const char OAUTH2_CLIENT_SECRET[] = "client_secret"; -const char OAUTH2_USERNAME[] = "username"; -const char OAUTH2_PASSWORD[] = "password"; -const char OAUTH2_REDIRECT_URI[] = "redirect_uri"; -const char OAUTH2_SCOPE[] = "scope"; -const char OAUTH2_GRANT_TYPE_CODE[] = "code"; -const char OAUTH2_GRANT_TYPE_TOKEN[] = "token"; -const char OAUTH2_GRANT_TYPE_PASSWORD[] = "password"; -const char OAUTH2_GRANT_TYPE_DEVICE[] = "urn:ietf:params:oauth:grant-type:device_code"; -const char OAUTH2_GRANT_TYPE[] = "grant_type"; -const char OAUTH2_API_KEY[] = "api_key"; -const char OAUTH2_STATE[] = "state"; -const char OAUTH2_CODE[] = "code"; - -// OAuth 2 Response Parameters -const char OAUTH2_ACCESS_TOKEN[] = "access_token"; -const char OAUTH2_REFRESH_TOKEN[] = "refresh_token"; -const char OAUTH2_EXPIRES_IN[] = "expires_in"; -const char OAUTH2_DEVICE_CODE[] = "device_code"; -const char OAUTH2_USER_CODE[] = "user_code"; -const char OAUTH2_VERIFICATION_URI[] = "verification_uri"; -const char OAUTH2_VERIFICATION_URL[] = "verification_url"; // Google sign-in -const char OAUTH2_VERIFICATION_URI_COMPLETE[] = "verification_uri_complete"; -const char OAUTH2_INTERVAL[] = "interval"; - -// Parameter values -const char AUTHORIZATION_CODE[] = "authorization_code"; - -// Standard HTTP headers -const char HTTP_HTTP_HEADER[] = "HTTP"; -const char HTTP_AUTHORIZATION_HEADER[] = "Authorization"; - -} // namespace Katabasis diff --git a/libraries/katabasis/include/katabasis/PollServer.h b/libraries/katabasis/include/katabasis/PollServer.h deleted file mode 100644 index fd6a5351c..000000000 --- a/libraries/katabasis/include/katabasis/PollServer.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -class QNetworkAccessManager; - -namespace Katabasis { - -/// Poll an authorization server for token -class PollServer : public QObject { - Q_OBJECT - - public: - explicit PollServer(QNetworkAccessManager* manager, - const QNetworkRequest& request, - const QByteArray& payload, - int expiresIn, - QObject* parent = 0); - - /// Seconds to wait between polling requests - Q_PROPERTY(int interval READ interval WRITE setInterval) - int interval() const; - void setInterval(int interval); - - signals: - void verificationReceived(QMap); - void serverClosed(bool); // whether it has found parameters - - public slots: - void startPolling(); - - protected slots: - void onPollTimeout(); - void onExpiration(); - void onReplyFinished(); - - protected: - QNetworkAccessManager* manager_; - const QNetworkRequest request_; - const QByteArray payload_; - const int expiresIn_; - QTimer expirationTimer; - QTimer pollTimer; -}; - -} // namespace Katabasis diff --git a/libraries/katabasis/include/katabasis/Reply.h b/libraries/katabasis/include/katabasis/Reply.h deleted file mode 100644 index 89ee90e98..000000000 --- a/libraries/katabasis/include/katabasis/Reply.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace Katabasis { - -constexpr int defaultTimeout = 30 * 1000; - -/// A network request/reply pair that can time out. -class Reply : public QTimer { - Q_OBJECT - - public: - Reply(QNetworkReply* reply, int timeOut = defaultTimeout, QObject* parent = 0); - - signals: - void error(QNetworkReply::NetworkError); - - public slots: - /// When time out occurs, the QNetworkReply's error() signal is triggered. - void onTimeOut(); - - public: - QNetworkReply* reply; - bool timedOut = false; -}; - -/// List of O2Replies. -class ReplyList { - public: - ReplyList() { ignoreSslErrors_ = false; } - - /// Destructor. - /// Deletes all O2Reply instances in the list. - virtual ~ReplyList(); - - /// Create a new O2Reply from a QNetworkReply, and add it to this list. - void add(QNetworkReply* reply, int timeOut = defaultTimeout); - - /// Add an O2Reply to the list, while taking ownership of it. - void add(Reply* reply); - - /// Remove item from the list that corresponds to a QNetworkReply. - void remove(QNetworkReply* reply); - - /// Find an O2Reply in the list, corresponding to a QNetworkReply. - /// @return Matching O2Reply or NULL. - Reply* find(QNetworkReply* reply); - - bool ignoreSslErrors(); - void setIgnoreSslErrors(bool ignoreSslErrors); - - protected: - QList replies_; - bool ignoreSslErrors_; -}; - -} // namespace Katabasis diff --git a/libraries/katabasis/include/katabasis/RequestParameter.h b/libraries/katabasis/include/katabasis/RequestParameter.h deleted file mode 100644 index 1d23cf0e1..000000000 --- a/libraries/katabasis/include/katabasis/RequestParameter.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -namespace Katabasis { - -/// Request parameter (name-value pair) participating in authentication. -struct RequestParameter { - RequestParameter(const QByteArray& n, const QByteArray& v) : name(n), value(v) {} - bool operator<(const RequestParameter& other) const { return (name == other.name) ? (value < other.value) : (name < other.name); } - QByteArray name; - QByteArray value; -}; - -} // namespace Katabasis diff --git a/libraries/katabasis/src/DeviceFlow.cpp b/libraries/katabasis/src/DeviceFlow.cpp deleted file mode 100644 index 3b9d9c53f..000000000 --- a/libraries/katabasis/src/DeviceFlow.cpp +++ /dev/null @@ -1,467 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "katabasis/DeviceFlow.h" -#include "katabasis/Globals.h" -#include "katabasis/PollServer.h" - -#include "JsonResponse.h" -#include "KatabasisLogging.h" - -namespace { - -// ref: https://tools.ietf.org/html/rfc8628#section-3.2 -// Exception: Google sign-in uses "verification_url" instead of "*_uri" - we'll accept both. -bool hasMandatoryDeviceAuthParams(const QVariantMap& params) -{ - if (!params.contains(Katabasis::OAUTH2_DEVICE_CODE)) - return false; - - if (!params.contains(Katabasis::OAUTH2_USER_CODE)) - return false; - - if (!(params.contains(Katabasis::OAUTH2_VERIFICATION_URI) || params.contains(Katabasis::OAUTH2_VERIFICATION_URL))) - return false; - - if (!params.contains(Katabasis::OAUTH2_EXPIRES_IN)) - return false; - - return true; -} - -QByteArray createQueryParameters(const QList& parameters) -{ - QByteArray ret; - bool first = true; - for (auto& h : parameters) { - if (first) { - first = false; - } else { - ret.append("&"); - } - ret.append(QUrl::toPercentEncoding(h.name) + "=" + QUrl::toPercentEncoding(h.value)); - } - return ret; -} -} // namespace - -namespace Katabasis { - -DeviceFlow::DeviceFlow(Options& opts, Token& token, QObject* parent, QNetworkAccessManager* manager) : QObject(parent), token_(token) -{ - manager_ = manager ? manager : new QNetworkAccessManager(this); - qRegisterMetaType("QNetworkReply::NetworkError"); - options_ = opts; -} - -bool DeviceFlow::linked() -{ - return token_.validity != Validity::None; -} -void DeviceFlow::setLinked(bool v) -{ - qDebug() << "DeviceFlow::setLinked:" << (v ? "true" : "false"); - token_.validity = v ? Validity::Certain : Validity::None; -} - -void DeviceFlow::updateActivity(Activity activity) -{ - if (activity_ == activity) { - return; - } - - activity_ = activity; - switch (activity) { - case Katabasis::Activity::Idle: - case Katabasis::Activity::LoggingIn: - case Katabasis::Activity::LoggingOut: - case Katabasis::Activity::Refreshing: - // non-terminal states... - break; - case Katabasis::Activity::FailedSoft: - // terminal state, tokens did not change - break; - case Katabasis::Activity::FailedHard: - case Katabasis::Activity::FailedGone: - // terminal state, tokens are invalid - token_ = Token(); - break; - case Katabasis::Activity::Succeeded: - setLinked(true); - break; - } - emit activityChanged(activity_); -} - -QString DeviceFlow::token() -{ - return token_.token; -} -void DeviceFlow::setToken(const QString& v) -{ - token_.token = v; -} - -QVariantMap DeviceFlow::extraTokens() -{ - return token_.extra; -} - -void DeviceFlow::setExtraTokens(QVariantMap extraTokens) -{ - token_.extra = extraTokens; -} - -void DeviceFlow::setPollServer(PollServer* server) -{ - if (pollServer_) - pollServer_->deleteLater(); - - pollServer_ = server; -} - -PollServer* DeviceFlow::pollServer() const -{ - return pollServer_; -} - -QVariantMap DeviceFlow::extraRequestParams() -{ - return extraReqParams_; -} - -void DeviceFlow::setExtraRequestParams(const QVariantMap& value) -{ - extraReqParams_ = value; -} - -QString DeviceFlow::grantType() -{ - if (!grantType_.isEmpty()) - return grantType_; - - return OAUTH2_GRANT_TYPE_DEVICE; -} - -void DeviceFlow::setGrantType(const QString& value) -{ - grantType_ = value; -} - -// First get the URL and token to display to the user -void DeviceFlow::login() -{ - qDebug() << "DeviceFlow::link"; - - updateActivity(Activity::LoggingIn); - setLinked(false); - setToken(""); - setExtraTokens(QVariantMap()); - setRefreshToken(QString()); - setExpires(QDateTime()); - - QList parameters; - parameters.append(RequestParameter(OAUTH2_CLIENT_ID, options_.clientIdentifier.toUtf8())); - parameters.append(RequestParameter(OAUTH2_SCOPE, options_.scope.toUtf8())); - QByteArray payload = createQueryParameters(parameters); - - QUrl url(options_.authorizationUrl); - QNetworkRequest deviceRequest(url); - deviceRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); - QNetworkReply* tokenReply = manager_->post(deviceRequest, payload); - - connect(tokenReply, &QNetworkReply::finished, this, &DeviceFlow::onDeviceAuthReplyFinished, Qt::QueuedConnection); -} - -// Then, once we get them, present them to the user -void DeviceFlow::onDeviceAuthReplyFinished() -{ - qDebug() << "DeviceFlow::onDeviceAuthReplyFinished"; - QNetworkReply* tokenReply = qobject_cast(sender()); - if (!tokenReply) { - qDebug() << "DeviceFlow::onDeviceAuthReplyFinished: reply is null"; - return; - } - if (tokenReply->error() == QNetworkReply::NoError) { - QByteArray replyData = tokenReply->readAll(); - - // Dump replyData - // SENSITIVE DATA in RelWithDebInfo or Debug builds - // qDebug() << "DeviceFlow::onDeviceAuthReplyFinished: replyData\n"; - // qDebug() << QString( replyData ); - - QVariantMap params = parseJsonResponse(replyData); - - // Dump tokens - qDebug() << "DeviceFlow::onDeviceAuthReplyFinished: Tokens returned:\n"; - foreach (QString key, params.keys()) { - // SENSITIVE DATA in RelWithDebInfo or Debug builds, so it is truncated first - qDebug() << key << ": " << params.value(key).toString(); - } - - // Check for mandatory parameters - if (hasMandatoryDeviceAuthParams(params)) { - qDebug() << "DeviceFlow::onDeviceAuthReplyFinished: Device auth request response"; - - const QString userCode = params.take(OAUTH2_USER_CODE).toString(); - QUrl uri = params.take(OAUTH2_VERIFICATION_URI).toUrl(); - if (uri.isEmpty()) - uri = params.take(OAUTH2_VERIFICATION_URL).toUrl(); - - if (params.contains(OAUTH2_VERIFICATION_URI_COMPLETE)) - emit openBrowser(params.take(OAUTH2_VERIFICATION_URI_COMPLETE).toUrl()); - - bool ok = false; - int expiresIn = params[OAUTH2_EXPIRES_IN].toInt(&ok); - if (!ok) { - qWarning() << "DeviceFlow::startPollServer: No expired_in parameter"; - updateActivity(Activity::FailedHard); - return; - } - - emit showVerificationUriAndCode(uri, userCode, expiresIn); - - startPollServer(params, expiresIn); - } else { - qWarning() << "DeviceFlow::onDeviceAuthReplyFinished: Mandatory parameters missing from response"; - updateActivity(Activity::FailedHard); - } - } - tokenReply->deleteLater(); -} - -// Spin up polling for the user completing the login flow out of band -void DeviceFlow::startPollServer(const QVariantMap& params, int expiresIn) -{ - qDebug() << "DeviceFlow::startPollServer: device_ and user_code expires in" << expiresIn << "seconds"; - - QUrl url(options_.accessTokenUrl); - QNetworkRequest authRequest(url); - authRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); - - const QString deviceCode = params[OAUTH2_DEVICE_CODE].toString(); - const QString grantType = grantType_.isEmpty() ? OAUTH2_GRANT_TYPE_DEVICE : grantType_; - - QList parameters; - parameters.append(RequestParameter(OAUTH2_CLIENT_ID, options_.clientIdentifier.toUtf8())); - if (!options_.clientSecret.isEmpty()) { - parameters.append(RequestParameter(OAUTH2_CLIENT_SECRET, options_.clientSecret.toUtf8())); - } - parameters.append(RequestParameter(OAUTH2_CODE, deviceCode.toUtf8())); - parameters.append(RequestParameter(OAUTH2_GRANT_TYPE, grantType.toUtf8())); - QByteArray payload = createQueryParameters(parameters); - - PollServer* pollServer = new PollServer(manager_, authRequest, payload, expiresIn, this); - if (params.contains(OAUTH2_INTERVAL)) { - bool ok = false; - int interval = params[OAUTH2_INTERVAL].toInt(&ok); - if (ok) { - pollServer->setInterval(interval); - } - } - connect(pollServer, &PollServer::verificationReceived, this, &DeviceFlow::onVerificationReceived); - connect(pollServer, &PollServer::serverClosed, this, &DeviceFlow::serverHasClosed); - setPollServer(pollServer); - pollServer->startPolling(); -} - -// Once the user completes the flow, update the internal state and report it to observers -void DeviceFlow::onVerificationReceived(const QMap response) -{ - qDebug() << "DeviceFlow::onVerificationReceived: Emitting closeBrowser()"; - emit closeBrowser(); - - if (response.contains("error")) { - qWarning() << "DeviceFlow::onVerificationReceived: Verification failed:" << response; - updateActivity(Activity::FailedHard); - return; - } - - // Check for mandatory tokens - if (response.contains(OAUTH2_ACCESS_TOKEN)) { - qDebug() << "DeviceFlow::onVerificationReceived: Access token returned for implicit or device flow"; - setToken(response.value(OAUTH2_ACCESS_TOKEN)); - if (response.contains(OAUTH2_EXPIRES_IN)) { - bool ok = false; - int expiresIn = response.value(OAUTH2_EXPIRES_IN).toInt(&ok); - if (ok) { - qDebug() << "DeviceFlow::onVerificationReceived: Token expires in" << expiresIn << "seconds"; - setExpires(QDateTime::currentDateTimeUtc().addSecs(expiresIn)); - } - } - if (response.contains(OAUTH2_REFRESH_TOKEN)) { - setRefreshToken(response.value(OAUTH2_REFRESH_TOKEN)); - } - updateActivity(Activity::Succeeded); - } else { - qWarning() << "DeviceFlow::onVerificationReceived: Access token missing from response for implicit or device flow"; - updateActivity(Activity::FailedHard); - } -} - -// Or if the flow fails or the polling times out, update the internal state with error and report it to observers -void DeviceFlow::serverHasClosed(bool paramsfound) -{ - if (!paramsfound) { - // server has probably timed out after receiving first response - updateActivity(Activity::FailedHard); - } - // poll server is not re-used for later auth requests - setPollServer(NULL); -} - -void DeviceFlow::logout() -{ - qDebug() << "DeviceFlow::unlink"; - updateActivity(Activity::LoggingOut); - // FIXME: implement logout flows... if they exist - token_ = Token(); - updateActivity(Activity::FailedHard); -} - -QDateTime DeviceFlow::expires() -{ - return token_.notAfter; -} -void DeviceFlow::setExpires(QDateTime v) -{ - token_.notAfter = v; -} - -QString DeviceFlow::refreshToken() -{ - return token_.refresh_token; -} - -void DeviceFlow::setRefreshToken(const QString& v) -{ - qCDebug(katabasisCredentials) << "new refresh token:" << v; - token_.refresh_token = v; -} - -namespace { -QByteArray buildRequestBody(const QMap& parameters) -{ - QByteArray body; - bool first = true; - foreach (QString key, parameters.keys()) { - if (first) { - first = false; - } else { - body.append("&"); - } - QString value = parameters.value(key); - body.append(QUrl::toPercentEncoding(key) + QString("=").toUtf8() + QUrl::toPercentEncoding(value)); - } - return body; -} -} // namespace - -bool DeviceFlow::refresh() -{ - qDebug() << "DeviceFlow::refresh: Token: ..." << refreshToken().right(7); - - updateActivity(Activity::Refreshing); - - if (refreshToken().isEmpty()) { - qWarning() << "DeviceFlow::refresh: No refresh token"; - onRefreshError(QNetworkReply::AuthenticationRequiredError, nullptr); - return false; - } - if (options_.accessTokenUrl.isEmpty()) { - qWarning() << "DeviceFlow::refresh: Refresh token URL not set"; - onRefreshError(QNetworkReply::AuthenticationRequiredError, nullptr); - return false; - } - - QNetworkRequest refreshRequest(options_.accessTokenUrl); - refreshRequest.setHeader(QNetworkRequest::ContentTypeHeader, MIME_TYPE_XFORM); - QMap parameters; - parameters.insert(OAUTH2_CLIENT_ID, options_.clientIdentifier); - if (!options_.clientSecret.isEmpty()) { - parameters.insert(OAUTH2_CLIENT_SECRET, options_.clientSecret); - } - parameters.insert(OAUTH2_REFRESH_TOKEN, refreshToken()); - parameters.insert(OAUTH2_GRANT_TYPE, OAUTH2_REFRESH_TOKEN); - - QByteArray data = buildRequestBody(parameters); - QNetworkReply* refreshReply = manager_->post(refreshRequest, data); - timedReplies_.add(refreshReply); - connect(refreshReply, &QNetworkReply::finished, this, &DeviceFlow::onRefreshFinished, Qt::QueuedConnection); - return true; -} - -void DeviceFlow::onRefreshFinished() -{ - QNetworkReply* refreshReply = qobject_cast(sender()); - - auto networkError = refreshReply->error(); - if (networkError == QNetworkReply::NoError) { - QByteArray reply = refreshReply->readAll(); - QVariantMap tokens = parseJsonResponse(reply); - setToken(tokens.value(OAUTH2_ACCESS_TOKEN).toString()); - setExpires(QDateTime::currentDateTimeUtc().addSecs(tokens.value(OAUTH2_EXPIRES_IN).toInt())); - QString refreshToken = tokens.value(OAUTH2_REFRESH_TOKEN).toString(); - if (!refreshToken.isEmpty()) { - setRefreshToken(refreshToken); - } else { - qDebug() << "No new refresh token. Keep the old one."; - } - timedReplies_.remove(refreshReply); - refreshReply->deleteLater(); - updateActivity(Activity::Succeeded); - qDebug() << "New token expires in" << expires() << "seconds"; - } else { - // FIXME: differentiate the error more here - onRefreshError(networkError, refreshReply); - } -} - -void DeviceFlow::onRefreshError(QNetworkReply::NetworkError error, QNetworkReply* refreshReply) -{ - QString errorString = "No Reply"; - if (refreshReply) { - timedReplies_.remove(refreshReply); - errorString = refreshReply->errorString(); - } - - switch (error) { - // used for invalid credentials and similar errors. Fall through. - case QNetworkReply::AuthenticationRequiredError: - case QNetworkReply::ContentAccessDenied: - case QNetworkReply::ContentOperationNotPermittedError: - case QNetworkReply::ProtocolInvalidOperationError: - updateActivity(Activity::FailedHard); - break; - case QNetworkReply::ContentGoneError: { - updateActivity(Activity::FailedGone); - break; - } - case QNetworkReply::TimeoutError: - case QNetworkReply::OperationCanceledError: - case QNetworkReply::SslHandshakeFailedError: - default: - updateActivity(Activity::FailedSoft); - return; - } - if (refreshReply) { - refreshReply->deleteLater(); - } - qDebug() << "DeviceFlow::onRefreshFinished: Error" << static_cast(error) << " - " << errorString; -} - -} // namespace Katabasis diff --git a/libraries/katabasis/src/JsonResponse.cpp b/libraries/katabasis/src/JsonResponse.cpp deleted file mode 100644 index 6840627ac..000000000 --- a/libraries/katabasis/src/JsonResponse.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "JsonResponse.h" - -#include -#include -#include -#include - -namespace Katabasis { - -QVariantMap parseJsonResponse(const QByteArray& data) -{ - QJsonParseError err; - QJsonDocument doc = QJsonDocument::fromJson(data, &err); - if (err.error != QJsonParseError::NoError) { - qWarning() << "parseTokenResponse: Failed to parse token response due to err:" << err.errorString(); - return QVariantMap(); - } - - if (!doc.isObject()) { - qWarning() << "parseTokenResponse: Token response is not an object"; - return QVariantMap(); - } - - return doc.object().toVariantMap(); -} - -} // namespace Katabasis diff --git a/libraries/katabasis/src/JsonResponse.h b/libraries/katabasis/src/JsonResponse.h deleted file mode 100644 index ff3471752..000000000 --- a/libraries/katabasis/src/JsonResponse.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include - -class QByteArray; - -namespace Katabasis { - -/// Parse JSON data into a QVariantMap -QVariantMap parseJsonResponse(const QByteArray& data); - -} // namespace Katabasis diff --git a/libraries/katabasis/src/PollServer.cpp b/libraries/katabasis/src/PollServer.cpp deleted file mode 100644 index c1c316df9..000000000 --- a/libraries/katabasis/src/PollServer.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include -#include - -#include "JsonResponse.h" -#include "katabasis/PollServer.h" - -namespace { -QMap toVerificationParams(const QVariantMap& map) -{ - QMap params; - for (QVariantMap::const_iterator i = map.constBegin(); i != map.constEnd(); ++i) { - params[i.key()] = i.value().toString(); - } - return params; -} -} // namespace - -namespace Katabasis { - -PollServer::PollServer(QNetworkAccessManager* manager, - const QNetworkRequest& request, - const QByteArray& payload, - int expiresIn, - QObject* parent) - : QObject(parent), manager_(manager), request_(request), payload_(payload), expiresIn_(expiresIn) -{ - expirationTimer.setTimerType(Qt::VeryCoarseTimer); - expirationTimer.setInterval(expiresIn * 1000); - expirationTimer.setSingleShot(true); - connect(&expirationTimer, SIGNAL(timeout()), this, SLOT(onExpiration())); - expirationTimer.start(); - - pollTimer.setTimerType(Qt::VeryCoarseTimer); - pollTimer.setInterval(5 * 1000); - pollTimer.setSingleShot(true); - connect(&pollTimer, SIGNAL(timeout()), this, SLOT(onPollTimeout())); -} - -int PollServer::interval() const -{ - return pollTimer.interval() / 1000; -} - -void PollServer::setInterval(int interval) -{ - pollTimer.setInterval(interval * 1000); -} - -void PollServer::startPolling() -{ - if (expirationTimer.isActive()) { - pollTimer.start(); - } -} - -void PollServer::onPollTimeout() -{ - qDebug() << "PollServer::onPollTimeout: retrying"; - QNetworkReply* reply = manager_->post(request_, payload_); - connect(reply, SIGNAL(finished()), this, SLOT(onReplyFinished())); -} - -void PollServer::onExpiration() -{ - pollTimer.stop(); - emit serverClosed(false); -} - -void PollServer::onReplyFinished() -{ - QNetworkReply* reply = qobject_cast(sender()); - - if (!reply) { - qDebug() << "PollServer::onReplyFinished: reply is null"; - return; - } - - QByteArray replyData = reply->readAll(); - QMap params = toVerificationParams(parseJsonResponse(replyData)); - - // Dump replyData - // SENSITIVE DATA in RelWithDebInfo or Debug builds - // qDebug() << "PollServer::onReplyFinished: replyData\n"; - // qDebug() << QString( replyData ); - - if (reply->error() == QNetworkReply::TimeoutError) { - // rfc8628#section-3.2 - // "On encountering a connection timeout, clients MUST unilaterally - // reduce their polling frequency before retrying. The use of an - // exponential backoff algorithm to achieve this, such as doubling the - // polling interval on each such connection timeout, is RECOMMENDED." - setInterval(interval() * 2); - pollTimer.start(); - } else { - QString error = params.value("error"); - if (error == "slow_down") { - // rfc8628#section-3.2 - // "A variant of 'authorization_pending', the authorization request is - // still pending and polling should continue, but the interval MUST - // be increased by 5 seconds for this and all subsequent requests." - setInterval(interval() + 5); - pollTimer.start(); - } else if (error == "authorization_pending") { - // keep trying - rfc8628#section-3.2 - // "The authorization request is still pending as the end user hasn't - // yet completed the user-interaction steps (Section 3.3)." - pollTimer.start(); - } else { - expirationTimer.stop(); - emit serverClosed(true); - // let O2 handle the other cases - emit verificationReceived(params); - } - } - reply->deleteLater(); -} - -} // namespace Katabasis diff --git a/libraries/katabasis/src/Reply.cpp b/libraries/katabasis/src/Reply.cpp deleted file mode 100644 index 4a5017e22..000000000 --- a/libraries/katabasis/src/Reply.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include -#include - -#include "katabasis/Reply.h" - -namespace Katabasis { - -Reply::Reply(QNetworkReply* r, int timeOut, QObject* parent) : QTimer(parent), reply(r) -{ - setSingleShot(true); - connect(this, &Reply::timeout, this, &Reply::onTimeOut, Qt::QueuedConnection); - start(timeOut); -} - -void Reply::onTimeOut() -{ - timedOut = true; - reply->abort(); -} - -// ---------------------------- - -ReplyList::~ReplyList() -{ - foreach (Reply* timedReply, replies_) { - delete timedReply; - } -} - -void ReplyList::add(QNetworkReply* reply, int timeOut) -{ - if (reply && ignoreSslErrors()) { - reply->ignoreSslErrors(); - } - add(new Reply(reply, timeOut)); -} - -void ReplyList::add(Reply* reply) -{ - replies_.append(reply); -} - -void ReplyList::remove(QNetworkReply* reply) -{ - Reply* o2Reply = find(reply); - if (o2Reply) { - o2Reply->stop(); - (void)replies_.removeOne(o2Reply); - // we took ownership, we must free - delete o2Reply; - } -} - -Reply* ReplyList::find(QNetworkReply* reply) -{ - foreach (Reply* timedReply, replies_) { - if (timedReply->reply == reply) { - return timedReply; - } - } - return 0; -} - -bool ReplyList::ignoreSslErrors() -{ - return ignoreSslErrors_; -} - -void ReplyList::setIgnoreSslErrors(bool ignoreSslErrors) -{ - ignoreSslErrors_ = ignoreSslErrors; -} - -} // namespace Katabasis From 849c3faeb4dfeb9761fba4bc9b1d35e0b8129c41 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Wed, 15 May 2024 13:06:55 +0300 Subject: [PATCH 213/223] Fix CI Signed-off-by: Trial97 --- .github/workflows/codeql.yml | 2 +- launcher/minecraft/auth/steps/MSAStep.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index d40d7eb68..261f67819 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -23,7 +23,7 @@ jobs: run: sudo apt-get -y update - sudo apt-get -y install ninja-build extra-cmake-modules scdoc qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5 + sudo apt-get -y install ninja-build extra-cmake-modules scdoc qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5 libqt5networkauth5 - name: Configure and Build run: | diff --git a/launcher/minecraft/auth/steps/MSAStep.cpp b/launcher/minecraft/auth/steps/MSAStep.cpp index 71bd25096..79cb062b6 100644 --- a/launcher/minecraft/auth/steps/MSAStep.cpp +++ b/launcher/minecraft/auth/steps/MSAStep.cpp @@ -93,7 +93,11 @@ void MSAStep::perform() return; } case Login: { +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) // QMultiMap param changed in 6.0 oauth2.setModifyParametersFunction([](QAbstractOAuth::Stage stage, QMultiMap* map) { +#else + oauth2.setModifyParametersFunction([](QAbstractOAuth::Stage stage, QMap* map) { +#endif map->insert("prompt", "select_account"); map->insert("cobrandid", "8058f65d-ce06-4c30-9559-473c9275a65d"); }); From abedc6a23ce85c27f2816f9510d1acdcd59480f4 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Wed, 15 May 2024 17:25:15 +0300 Subject: [PATCH 214/223] Improve login UI Signed-off-by: Trial97 --- launcher/CMakeLists.txt | 10 +-- launcher/minecraft/auth/AccountData.cpp | 18 +++--- launcher/minecraft/auth/AccountData.h | 30 +++------ launcher/minecraft/auth/AccountList.h | 2 +- .../minecraft/auth/{flows => }/AuthFlow.cpp | 35 +++++++--- .../minecraft/auth/{flows => }/AuthFlow.h | 12 ++-- launcher/minecraft/auth/MinecraftAccount.cpp | 47 ++++---------- launcher/minecraft/auth/MinecraftAccount.h | 6 +- launcher/minecraft/auth/Parsers.cpp | 14 ++-- launcher/minecraft/auth/Parsers.h | 4 +- launcher/minecraft/auth/flows/MSA.cpp | 36 ----------- launcher/minecraft/auth/flows/MSA.h | 14 ---- launcher/minecraft/auth/flows/Offline.cpp | 8 --- launcher/minecraft/auth/flows/Offline.h | 8 --- launcher/minecraft/auth/steps/MSAStep.cpp | 40 +++++------- launcher/minecraft/auth/steps/MSAStep.h | 10 +-- launcher/minecraft/auth/steps/OfflineStep.cpp | 13 ---- launcher/minecraft/auth/steps/OfflineStep.h | 15 ----- .../auth/steps/XboxAuthorizationStep.cpp | 4 +- .../auth/steps/XboxAuthorizationStep.h | 4 +- .../minecraft/auth/steps/XboxUserStep.cpp | 2 +- launcher/ui/dialogs/MSALoginDialog.cpp | 64 ++++++++++--------- launcher/ui/dialogs/MSALoginDialog.h | 7 +- launcher/ui/dialogs/MSALoginDialog.ui | 41 ++++++------ launcher/ui/dialogs/OfflineLoginDialog.cpp | 2 +- 25 files changed, 159 insertions(+), 287 deletions(-) rename launcher/minecraft/auth/{flows => }/AuthFlow.cpp (70%) rename launcher/minecraft/auth/{flows => }/AuthFlow.h (80%) delete mode 100644 launcher/minecraft/auth/flows/MSA.cpp delete mode 100644 launcher/minecraft/auth/flows/MSA.h delete mode 100644 launcher/minecraft/auth/flows/Offline.cpp delete mode 100644 launcher/minecraft/auth/flows/Offline.h delete mode 100644 launcher/minecraft/auth/steps/OfflineStep.cpp delete mode 100644 launcher/minecraft/auth/steps/OfflineStep.h diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index e5eb4b733..e63328e6e 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -217,15 +217,9 @@ set(MINECRAFT_SOURCES minecraft/auth/Parsers.cpp minecraft/auth/Parsers.h - minecraft/auth/flows/AuthFlow.cpp - minecraft/auth/flows/AuthFlow.h - minecraft/auth/flows/MSA.cpp - minecraft/auth/flows/MSA.h - minecraft/auth/flows/Offline.cpp - minecraft/auth/flows/Offline.h + minecraft/auth/AuthFlow.cpp + minecraft/auth/AuthFlow.h - minecraft/auth/steps/OfflineStep.cpp - minecraft/auth/steps/OfflineStep.h minecraft/auth/steps/EntitlementsStep.cpp minecraft/auth/steps/EntitlementsStep.h minecraft/auth/steps/GetSkinStep.cpp diff --git a/launcher/minecraft/auth/AccountData.cpp b/launcher/minecraft/auth/AccountData.cpp index e1f1e9b1e..fd2082035 100644 --- a/launcher/minecraft/auth/AccountData.cpp +++ b/launcher/minecraft/auth/AccountData.cpp @@ -42,7 +42,7 @@ #include namespace { -void tokenToJSONV3(QJsonObject& parent, Katabasis::Token t, const char* tokenName) +void tokenToJSONV3(QJsonObject& parent, Token t, const char* tokenName) { if (!t.persistent) { return; @@ -74,9 +74,9 @@ void tokenToJSONV3(QJsonObject& parent, Katabasis::Token t, const char* tokenNam } } -Katabasis::Token tokenFromJSONV3(const QJsonObject& parent, const char* tokenName) +Token tokenFromJSONV3(const QJsonObject& parent, const char* tokenName) { - Katabasis::Token out; + Token out; auto tokenObject = parent.value(tokenName).toObject(); if (tokenObject.isEmpty()) { return out; @@ -94,7 +94,7 @@ Katabasis::Token tokenFromJSONV3(const QJsonObject& parent, const char* tokenNam auto token = tokenObject.value("token"); if (token.isString()) { out.token = token.toString(); - out.validity = Katabasis::Validity::Assumed; + out.validity = Validity::Assumed; } auto refresh_token = tokenObject.value("refresh_token"); @@ -241,13 +241,13 @@ MinecraftProfile profileFromJSONV3(const QJsonObject& parent, const char* tokenN } } } - out.validity = Katabasis::Validity::Assumed; + out.validity = Validity::Assumed; return out; } void entitlementToJSONV3(QJsonObject& parent, MinecraftEntitlement p) { - if (p.validity == Katabasis::Validity::None) { + if (p.validity == Validity::None) { return; } QJsonObject out; @@ -271,7 +271,7 @@ bool entitlementFromJSONV3(const QJsonObject& parent, MinecraftEntitlement& out) } out.canPlayMinecraft = canPlayMinecraftV.toBool(false); out.ownsMinecraft = ownsMinecraftV.toBool(false); - out.validity = Katabasis::Validity::Assumed; + out.validity = Validity::Assumed; } return true; } @@ -313,10 +313,10 @@ bool AccountData::resumeStateFromV3(QJsonObject data) minecraftProfile = profileFromJSONV3(data, "profile"); if (!entitlementFromJSONV3(data, minecraftEntitlement)) { - if (minecraftProfile.validity != Katabasis::Validity::None) { + if (minecraftProfile.validity != Validity::None) { minecraftEntitlement.canPlayMinecraft = true; minecraftEntitlement.ownsMinecraft = true; - minecraftEntitlement.validity = Katabasis::Validity::Assumed; + minecraftEntitlement.validity = Validity::Assumed; } } diff --git a/launcher/minecraft/auth/AccountData.h b/launcher/minecraft/auth/AccountData.h index 71f1d00b2..1ada4e38a 100644 --- a/launcher/minecraft/auth/AccountData.h +++ b/launcher/minecraft/auth/AccountData.h @@ -44,18 +44,6 @@ #include #include -namespace Katabasis { -enum class Activity { - Idle, - LoggingIn, - LoggingOut, - Refreshing, - FailedSoft, //!< soft failure. this generally means the user auth details haven't been invalidated - FailedHard, //!< hard failure. auth is invalid - FailedGone, //!< hard failure. auth is invalid, and the account no longer exists - Succeeded -}; - enum class Validity { None, Assumed, Certain }; struct Token { @@ -69,8 +57,6 @@ struct Token { bool persistent = true; }; -} // namespace Katabasis - struct Skin { QString id; QString url; @@ -90,7 +76,7 @@ struct Cape { struct MinecraftEntitlement { bool ownsMinecraft = false; bool canPlayMinecraft = false; - Katabasis::Validity validity = Katabasis::Validity::None; + Validity validity = Validity::None; }; struct MinecraftProfile { @@ -99,7 +85,7 @@ struct MinecraftProfile { Skin skin; QString currentCape; QMap capes; - Katabasis::Validity validity = Katabasis::Validity::None; + Validity validity = Validity::None; }; enum class AccountType { MSA, Offline }; @@ -124,15 +110,15 @@ struct AccountData { AccountType type = AccountType::MSA; QString msaClientID; - Katabasis::Token msaToken; - Katabasis::Token userToken; - Katabasis::Token xboxApiToken; - Katabasis::Token mojangservicesToken; + Token msaToken; + Token userToken; + Token xboxApiToken; + Token mojangservicesToken; - Katabasis::Token yggdrasilToken; + Token yggdrasilToken; MinecraftProfile minecraftProfile; MinecraftEntitlement minecraftEntitlement; - Katabasis::Validity validity_ = Katabasis::Validity::None; + Validity validity_ = Validity::None; // runtime only information (not saved with the account) QString internalId; diff --git a/launcher/minecraft/auth/AccountList.h b/launcher/minecraft/auth/AccountList.h index b6038edb7..d3be6740e 100644 --- a/launcher/minecraft/auth/AccountList.h +++ b/launcher/minecraft/auth/AccountList.h @@ -36,7 +36,7 @@ #pragma once #include "MinecraftAccount.h" -#include "minecraft/auth/flows/AuthFlow.h" +#include "minecraft/auth/AuthFlow.h" #include #include diff --git a/launcher/minecraft/auth/flows/AuthFlow.cpp b/launcher/minecraft/auth/AuthFlow.cpp similarity index 70% rename from launcher/minecraft/auth/flows/AuthFlow.cpp rename to launcher/minecraft/auth/AuthFlow.cpp index 1b5e01569..c98d0b2c9 100644 --- a/launcher/minecraft/auth/flows/AuthFlow.cpp +++ b/launcher/minecraft/auth/AuthFlow.cpp @@ -3,27 +3,47 @@ #include #include +#include "minecraft/auth/AccountData.h" +#include "minecraft/auth/steps/EntitlementsStep.h" +#include "minecraft/auth/steps/GetSkinStep.h" +#include "minecraft/auth/steps/LauncherLoginStep.h" +#include "minecraft/auth/steps/MSAStep.h" +#include "minecraft/auth/steps/MinecraftProfileStep.h" +#include "minecraft/auth/steps/XboxAuthorizationStep.h" +#include "minecraft/auth/steps/XboxProfileStep.h" +#include "minecraft/auth/steps/XboxUserStep.h" + #include "AuthFlow.h" #include -AuthFlow::AuthFlow(AccountData* data, QObject* parent) : Task(parent), m_data(data) +AuthFlow::AuthFlow(AccountData* data, bool silent, QObject* parent) : Task(parent), m_data(data) { + if (data->type == AccountType::MSA) { + auto oauthStep = makeShared(m_data, silent); + connect(oauthStep.get(), &MSAStep::authorizeWithBrowser, this, &AuthFlow::authorizeWithBrowser); + m_steps.append(oauthStep); + m_steps.append(makeShared(m_data)); + m_steps.append(makeShared(m_data, &m_data->xboxApiToken, "http://xboxlive.com", "Xbox")); + m_steps.append( + makeShared(m_data, &m_data->mojangservicesToken, "rp://api.minecraftservices.com/", "Mojang")); + m_steps.append(makeShared(m_data)); + m_steps.append(makeShared(m_data)); + m_steps.append(makeShared(m_data)); + m_steps.append(makeShared(m_data)); + m_steps.append(makeShared(m_data)); + } changeState(AccountTaskState::STATE_CREATED); } void AuthFlow::succeed() { - m_data->validity_ = Katabasis::Validity::Certain; + m_data->validity_ = Validity::Certain; changeState(AccountTaskState::STATE_SUCCEEDED, tr("Finished all authentication steps")); } void AuthFlow::executeTask() { - if (m_currentStep) { - emitFailed("No task"); - return; - } changeState(AccountTaskState::STATE_WORKING, tr("Initializing")); nextStep(); } @@ -46,9 +66,8 @@ void AuthFlow::nextStep() void AuthFlow::stepFinished(AccountTaskState resultingState, QString message) { - if (changeState(resultingState, message)) { + if (changeState(resultingState, message)) nextStep(); - } } bool AuthFlow::changeState(AccountTaskState newState, QString reason) diff --git a/launcher/minecraft/auth/flows/AuthFlow.h b/launcher/minecraft/auth/AuthFlow.h similarity index 80% rename from launcher/minecraft/auth/flows/AuthFlow.h rename to launcher/minecraft/auth/AuthFlow.h index de563c3c5..611c25058 100644 --- a/launcher/minecraft/auth/flows/AuthFlow.h +++ b/launcher/minecraft/auth/AuthFlow.h @@ -15,30 +15,26 @@ class AuthFlow : public Task { Q_OBJECT public: - explicit AuthFlow(AccountData* data, QObject* parent = 0); + explicit AuthFlow(AccountData* data, bool silent = false, QObject* parent = 0); virtual ~AuthFlow() = default; - Katabasis::Validity validity() { return m_data->validity_; }; - void executeTask() override; AccountTaskState taskState() { return m_taskState; } signals: - void activityChanged(Katabasis::Activity activity); + void authorizeWithBrowser(const QUrl& url); protected: void succeed(); void nextStep(); - protected slots: + private slots: // NOTE: true -> non-terminal state, false -> terminal state bool changeState(AccountTaskState newState, QString reason = QString()); - - private slots: void stepFinished(AccountTaskState resultingState, QString message); - protected: + private: AccountTaskState m_taskState = AccountTaskState::STATE_CREATED; QList m_steps; AuthStep::Ptr m_currentStep; diff --git a/launcher/minecraft/auth/MinecraftAccount.cpp b/launcher/minecraft/auth/MinecraftAccount.cpp index d927cd6b4..f8a43900b 100644 --- a/launcher/minecraft/auth/MinecraftAccount.cpp +++ b/launcher/minecraft/auth/MinecraftAccount.cpp @@ -50,11 +50,8 @@ #include -#include "flows/MSA.h" -#include "flows/Offline.h" #include "minecraft/auth/AccountData.h" -#include "minecraft/auth/flows/AuthFlow.h" -#include "tasks/Task.h" +#include "minecraft/auth/AuthFlow.h" MinecraftAccount::MinecraftAccount(QObject* parent) : QObject(parent) { @@ -82,7 +79,7 @@ MinecraftAccountPtr MinecraftAccount::createOffline(const QString& username) auto account = makeShared(); account->data.type = AccountType::Offline; account->data.yggdrasilToken.token = "0"; - account->data.yggdrasilToken.validity = Katabasis::Validity::Certain; + account->data.yggdrasilToken.validity = Validity::Certain; account->data.yggdrasilToken.issueInstant = QDateTime::currentDateTimeUtc(); account->data.yggdrasilToken.extra["userName"] = username; account->data.yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]")); @@ -90,7 +87,7 @@ MinecraftAccountPtr MinecraftAccount::createOffline(const QString& username) account->data.minecraftEntitlement.canPlayMinecraft = true; account->data.minecraftProfile.id = uuidFromUsername(username).toString().remove(QRegularExpression("[{}-]")); account->data.minecraftProfile.name = username; - account->data.minecraftProfile.validity = Katabasis::Validity::Certain; + account->data.minecraftProfile.validity = Validity::Certain; return account; } @@ -122,23 +119,11 @@ QPixmap MinecraftAccount::getFace() const return skin.scaled(64, 64, Qt::KeepAspectRatio); } -shared_qobject_ptr MinecraftAccount::loginMSA() +shared_qobject_ptr MinecraftAccount::login() { Q_ASSERT(m_currentTask.get() == nullptr); - m_currentTask.reset(new MSAInteractive(&data)); - connect(m_currentTask.get(), &Task::succeeded, this, &MinecraftAccount::authSucceeded); - connect(m_currentTask.get(), &Task::failed, this, &MinecraftAccount::authFailed); - connect(m_currentTask.get(), &Task::aborted, this, [this] { authFailed(tr("Aborted")); }); - emit activityChanged(true); - return m_currentTask; -} - -shared_qobject_ptr MinecraftAccount::loginOffline() -{ - Q_ASSERT(m_currentTask.get() == nullptr); - - m_currentTask.reset(new OfflineLogin(&data)); + m_currentTask.reset(new AuthFlow(&data, false, this)); connect(m_currentTask.get(), &Task::succeeded, this, &MinecraftAccount::authSucceeded); connect(m_currentTask.get(), &Task::failed, this, &MinecraftAccount::authFailed); connect(m_currentTask.get(), &Task::aborted, this, [this] { authFailed(tr("Aborted")); }); @@ -152,11 +137,7 @@ shared_qobject_ptr MinecraftAccount::refresh() return m_currentTask; } - if (data.type == AccountType::MSA) { - m_currentTask.reset(new MSASilent(&data)); - } else { - m_currentTask.reset(new OfflineLogin(&data)); - } + m_currentTask.reset(new AuthFlow(&data, true, this)); connect(m_currentTask.get(), &Task::succeeded, this, &MinecraftAccount::authSucceeded); connect(m_currentTask.get(), &Task::failed, this, &MinecraftAccount::authFailed); @@ -191,17 +172,17 @@ void MinecraftAccount::authFailed(QString reason) if (accountType() == AccountType::MSA) { data.msaToken.token = QString(); data.msaToken.refresh_token = QString(); - data.msaToken.validity = Katabasis::Validity::None; - data.validity_ = Katabasis::Validity::None; + data.msaToken.validity = Validity::None; + data.validity_ = Validity::None; } else { data.yggdrasilToken.token = QString(); - data.yggdrasilToken.validity = Katabasis::Validity::None; - data.validity_ = Katabasis::Validity::None; + data.yggdrasilToken.validity = Validity::None; + data.validity_ = Validity::None; } emit changed(); } break; case AccountTaskState::STATE_FAILED_GONE: { - data.validity_ = Katabasis::Validity::None; + data.validity_ = Validity::None; emit changed(); } break; case AccountTaskState::STATE_CREATED: @@ -231,13 +212,13 @@ bool MinecraftAccount::shouldRefresh() const return false; } switch (data.validity_) { - case Katabasis::Validity::Certain: { + case Validity::Certain: { break; } - case Katabasis::Validity::None: { + case Validity::None: { return false; } - case Katabasis::Validity::Assumed: { + case Validity::Assumed: { return true; } } diff --git a/launcher/minecraft/auth/MinecraftAccount.h b/launcher/minecraft/auth/MinecraftAccount.h index 24600cb73..6f540c572 100644 --- a/launcher/minecraft/auth/MinecraftAccount.h +++ b/launcher/minecraft/auth/MinecraftAccount.h @@ -47,7 +47,7 @@ #include "AuthSession.h" #include "QObjectPtr.h" #include "Usable.h" -#include "minecraft/auth/flows/AuthFlow.h" +#include "minecraft/auth/AuthFlow.h" class Task; class MinecraftAccount; @@ -95,9 +95,7 @@ class MinecraftAccount : public QObject, public Usable { QJsonObject saveToJson() const; public: /* manipulation */ - shared_qobject_ptr loginMSA(); - - shared_qobject_ptr loginOffline(); + shared_qobject_ptr login(); shared_qobject_ptr refresh(); diff --git a/launcher/minecraft/auth/Parsers.cpp b/launcher/minecraft/auth/Parsers.cpp index f6179a93e..a2b97e278 100644 --- a/launcher/minecraft/auth/Parsers.cpp +++ b/launcher/minecraft/auth/Parsers.cpp @@ -79,7 +79,7 @@ bool getBool(QJsonValue value, bool& out) // 2148916238 = child account not linked to a family */ -bool parseXTokenResponse(QByteArray& data, Katabasis::Token& output, QString name) +bool parseXTokenResponse(QByteArray& data, Token& output, QString name) { qDebug() << "Parsing" << name << ":"; qCDebug(authCredentials()) << data; @@ -135,7 +135,7 @@ bool parseXTokenResponse(QByteArray& data, Katabasis::Token& output, QString nam qWarning() << "Missing uhs"; return false; } - output.validity = Katabasis::Validity::Certain; + output.validity = Validity::Certain; qDebug() << name << "is valid."; return true; } @@ -213,7 +213,7 @@ bool parseMinecraftProfile(QByteArray& data, MinecraftProfile& output) output.capes[capeOut.id] = capeOut; } output.currentCape = currentCape; - output.validity = Katabasis::Validity::Certain; + output.validity = Validity::Certain; return true; } @@ -388,7 +388,7 @@ bool parseMinecraftProfileMojang(QByteArray& data, MinecraftProfile& output) output.currentCape = capeOut.alias; } - output.validity = Katabasis::Validity::Certain; + output.validity = Validity::Certain; return true; } @@ -422,7 +422,7 @@ bool parseMinecraftEntitlements(QByteArray& data, MinecraftEntitlement& output) output.ownsMinecraft = true; } } - output.validity = Katabasis::Validity::Certain; + output.validity = Validity::Certain; return true; } @@ -456,7 +456,7 @@ bool parseRolloutResponse(QByteArray& data, bool& result) return true; } -bool parseMojangResponse(QByteArray& data, Katabasis::Token& output) +bool parseMojangResponse(QByteArray& data, Token& output) { QJsonParseError jsonError; qDebug() << "Parsing Mojang response..."; @@ -488,7 +488,7 @@ bool parseMojangResponse(QByteArray& data, Katabasis::Token& output) qWarning() << "access_token is not valid"; return false; } - output.validity = Katabasis::Validity::Certain; + output.validity = Validity::Certain; qDebug() << "Mojang response is valid."; return true; } diff --git a/launcher/minecraft/auth/Parsers.h b/launcher/minecraft/auth/Parsers.h index d073f9994..4a235e4c2 100644 --- a/launcher/minecraft/auth/Parsers.h +++ b/launcher/minecraft/auth/Parsers.h @@ -9,8 +9,8 @@ bool getNumber(QJsonValue value, double& out); bool getNumber(QJsonValue value, int64_t& out); bool getBool(QJsonValue value, bool& out); -bool parseXTokenResponse(QByteArray& data, Katabasis::Token& output, QString name); -bool parseMojangResponse(QByteArray& data, Katabasis::Token& output); +bool parseXTokenResponse(QByteArray& data, Token& output, QString name); +bool parseMojangResponse(QByteArray& data, Token& output); bool parseMinecraftProfile(QByteArray& data, MinecraftProfile& output); bool parseMinecraftProfileMojang(QByteArray& data, MinecraftProfile& output); diff --git a/launcher/minecraft/auth/flows/MSA.cpp b/launcher/minecraft/auth/flows/MSA.cpp deleted file mode 100644 index f0399342e..000000000 --- a/launcher/minecraft/auth/flows/MSA.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "MSA.h" - -#include "minecraft/auth/steps/EntitlementsStep.h" -#include "minecraft/auth/steps/GetSkinStep.h" -#include "minecraft/auth/steps/LauncherLoginStep.h" -#include "minecraft/auth/steps/MSAStep.h" -#include "minecraft/auth/steps/MinecraftProfileStep.h" -#include "minecraft/auth/steps/XboxAuthorizationStep.h" -#include "minecraft/auth/steps/XboxProfileStep.h" -#include "minecraft/auth/steps/XboxUserStep.h" - -MSASilent::MSASilent(AccountData* data, QObject* parent) : AuthFlow(data, parent) -{ - m_steps.append(makeShared(m_data, MSAStep::Action::Refresh)); - m_steps.append(makeShared(m_data)); - m_steps.append(makeShared(m_data, &m_data->xboxApiToken, "http://xboxlive.com", "Xbox")); - m_steps.append(makeShared(m_data, &m_data->mojangservicesToken, "rp://api.minecraftservices.com/", "Mojang")); - m_steps.append(makeShared(m_data)); - m_steps.append(makeShared(m_data)); - m_steps.append(makeShared(m_data)); - m_steps.append(makeShared(m_data)); - m_steps.append(makeShared(m_data)); -} - -MSAInteractive::MSAInteractive(AccountData* data, QObject* parent) : AuthFlow(data, parent) -{ - m_steps.append(makeShared(m_data, MSAStep::Action::Login)); - m_steps.append(makeShared(m_data)); - m_steps.append(makeShared(m_data, &m_data->xboxApiToken, "http://xboxlive.com", "Xbox")); - m_steps.append(makeShared(m_data, &m_data->mojangservicesToken, "rp://api.minecraftservices.com/", "Mojang")); - m_steps.append(makeShared(m_data)); - m_steps.append(makeShared(m_data)); - m_steps.append(makeShared(m_data)); - m_steps.append(makeShared(m_data)); - m_steps.append(makeShared(m_data)); -} diff --git a/launcher/minecraft/auth/flows/MSA.h b/launcher/minecraft/auth/flows/MSA.h deleted file mode 100644 index e403d530f..000000000 --- a/launcher/minecraft/auth/flows/MSA.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once -#include "AuthFlow.h" - -class MSAInteractive : public AuthFlow { - Q_OBJECT - public: - explicit MSAInteractive(AccountData* data, QObject* parent = 0); -}; - -class MSASilent : public AuthFlow { - Q_OBJECT - public: - explicit MSASilent(AccountData* data, QObject* parent = 0); -}; diff --git a/launcher/minecraft/auth/flows/Offline.cpp b/launcher/minecraft/auth/flows/Offline.cpp deleted file mode 100644 index 1836533bd..000000000 --- a/launcher/minecraft/auth/flows/Offline.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "Offline.h" - -#include "minecraft/auth/steps/OfflineStep.h" - -OfflineLogin::OfflineLogin(AccountData* data, QObject* parent) : AuthFlow(data, parent) -{ - m_steps.append(makeShared(m_data)); -} diff --git a/launcher/minecraft/auth/flows/Offline.h b/launcher/minecraft/auth/flows/Offline.h deleted file mode 100644 index a8d378e16..000000000 --- a/launcher/minecraft/auth/flows/Offline.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include "AuthFlow.h" - -class OfflineLogin : public AuthFlow { - Q_OBJECT - public: - explicit OfflineLogin(AccountData* data, QObject* parent = 0); -}; diff --git a/launcher/minecraft/auth/steps/MSAStep.cpp b/launcher/minecraft/auth/steps/MSAStep.cpp index 79cb062b6..4d3c2d202 100644 --- a/launcher/minecraft/auth/steps/MSAStep.cpp +++ b/launcher/minecraft/auth/steps/MSAStep.cpp @@ -37,12 +37,11 @@ #include #include -#include #include #include "Application.h" -MSAStep::MSAStep(AccountData* data, Action action) : AuthStep(data), m_action(action) +MSAStep::MSAStep(AccountData* data, bool silent) : AuthStep(data), m_silent(silent) { m_clientId = APPLICATION->getMSAClientID(); @@ -63,7 +62,7 @@ MSAStep::MSAStep(AccountData* data, Action action) : AuthStep(data), m_action(ac m_data->msaToken.token = oauth2.token(); emit finished(AccountTaskState::STATE_WORKING, tr("Got ")); }); - connect(&oauth2, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser, this, &QDesktopServices::openUrl); + connect(&oauth2, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser, this, &MSAStep::authorizeWithBrowser); connect(&oauth2, &QOAuth2AuthorizationCodeFlow::requestFailed, this, [this](const QAbstractOAuth2::Error err) { emit finished(AccountTaskState::STATE_FAILED_HARD, tr("Microsoft user authentication failed.")); }); @@ -82,30 +81,25 @@ QString MSAStep::describe() void MSAStep::perform() { - switch (m_action) { - case Refresh: { - if (m_data->msaClientID != m_clientId) { - emit finished(AccountTaskState::STATE_DISABLED, - tr("Microsoft user authentication failed - client identification has changed.")); - } - oauth2.setRefreshToken(m_data->msaToken.refresh_token); - oauth2.refreshAccessToken(); - return; + if (m_silent) { + if (m_data->msaClientID != m_clientId) { + emit finished(AccountTaskState::STATE_DISABLED, + tr("Microsoft user authentication failed - client identification has changed.")); } - case Login: { + oauth2.setRefreshToken(m_data->msaToken.refresh_token); + oauth2.refreshAccessToken(); + } else { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) // QMultiMap param changed in 6.0 - oauth2.setModifyParametersFunction([](QAbstractOAuth::Stage stage, QMultiMap* map) { + oauth2.setModifyParametersFunction([](QAbstractOAuth::Stage stage, QMultiMap* map) { #else - oauth2.setModifyParametersFunction([](QAbstractOAuth::Stage stage, QMap* map) { + oauth2.setModifyParametersFunction([](QAbstractOAuth::Stage stage, QMap* map) { #endif - map->insert("prompt", "select_account"); - map->insert("cobrandid", "8058f65d-ce06-4c30-9559-473c9275a65d"); - }); + map->insert("prompt", "select_account"); + map->insert("cobrandid", "8058f65d-ce06-4c30-9559-473c9275a65d"); + }); - *m_data = AccountData(); - m_data->msaClientID = m_clientId; - oauth2.grant(); - return; - } + *m_data = AccountData(); + m_data->msaClientID = m_clientId; + oauth2.grant(); } } diff --git a/launcher/minecraft/auth/steps/MSAStep.h b/launcher/minecraft/auth/steps/MSAStep.h index f38f5c70e..675cfb2ca 100644 --- a/launcher/minecraft/auth/steps/MSAStep.h +++ b/launcher/minecraft/auth/steps/MSAStep.h @@ -42,18 +42,18 @@ class MSAStep : public AuthStep { Q_OBJECT public: - enum Action { Refresh, Login }; - - public: - explicit MSAStep(AccountData* data, Action action); + explicit MSAStep(AccountData* data, bool silent = false); virtual ~MSAStep() noexcept = default; void perform() override; QString describe() override; + signals: + void authorizeWithBrowser(const QUrl& url); + private: - Action m_action; + bool m_silent; QString m_clientId; QOAuth2AuthorizationCodeFlow oauth2; }; diff --git a/launcher/minecraft/auth/steps/OfflineStep.cpp b/launcher/minecraft/auth/steps/OfflineStep.cpp deleted file mode 100644 index a96b08377..000000000 --- a/launcher/minecraft/auth/steps/OfflineStep.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "OfflineStep.h" - -OfflineStep::OfflineStep(AccountData* data) : AuthStep(data) {} - -QString OfflineStep::describe() -{ - return tr("Creating offline account."); -} - -void OfflineStep::perform() -{ - emit finished(AccountTaskState::STATE_WORKING, tr("Created offline account.")); -} diff --git a/launcher/minecraft/auth/steps/OfflineStep.h b/launcher/minecraft/auth/steps/OfflineStep.h deleted file mode 100644 index 411879b10..000000000 --- a/launcher/minecraft/auth/steps/OfflineStep.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include - -#include "minecraft/auth/AuthStep.h" - -class OfflineStep : public AuthStep { - Q_OBJECT - public: - explicit OfflineStep(AccountData* data); - virtual ~OfflineStep() noexcept = default; - - void perform() override; - - QString describe() override; -}; diff --git a/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp b/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp index 2ae3af0dd..f07220986 100644 --- a/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp +++ b/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp @@ -11,7 +11,7 @@ #include "net/StaticHeaderProxy.h" #include "net/Upload.h" -XboxAuthorizationStep::XboxAuthorizationStep(AccountData* data, Katabasis::Token* token, QString relyingParty, QString authorizationKind) +XboxAuthorizationStep::XboxAuthorizationStep(AccountData* data, Token* token, QString relyingParty, QString authorizationKind) : AuthStep(data), m_token(token), m_relyingParty(relyingParty), m_authorizationKind(authorizationKind) {} @@ -72,7 +72,7 @@ void XboxAuthorizationStep::onRequestDone() return; } - Katabasis::Token temp; + Token temp; if (!Parsers::parseXTokenResponse(*m_response, temp, m_authorizationKind)) { emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("Could not parse authorization response for access to %1 services.").arg(m_authorizationKind)); diff --git a/launcher/minecraft/auth/steps/XboxAuthorizationStep.h b/launcher/minecraft/auth/steps/XboxAuthorizationStep.h index eb7097f6f..f6329b7f0 100644 --- a/launcher/minecraft/auth/steps/XboxAuthorizationStep.h +++ b/launcher/minecraft/auth/steps/XboxAuthorizationStep.h @@ -9,7 +9,7 @@ class XboxAuthorizationStep : public AuthStep { Q_OBJECT public: - explicit XboxAuthorizationStep(AccountData* data, Katabasis::Token* token, QString relyingParty, QString authorizationKind); + explicit XboxAuthorizationStep(AccountData* data, Token* token, QString relyingParty, QString authorizationKind); virtual ~XboxAuthorizationStep() noexcept = default; void perform() override; @@ -23,7 +23,7 @@ class XboxAuthorizationStep : public AuthStep { void onRequestDone(); private: - Katabasis::Token* m_token; + Token* m_token; QString m_relyingParty; QString m_authorizationKind; diff --git a/launcher/minecraft/auth/steps/XboxUserStep.cpp b/launcher/minecraft/auth/steps/XboxUserStep.cpp index 46c3f0365..c9453dba1 100644 --- a/launcher/minecraft/auth/steps/XboxUserStep.cpp +++ b/launcher/minecraft/auth/steps/XboxUserStep.cpp @@ -60,7 +60,7 @@ void XboxUserStep::onRequestDone() return; } - Katabasis::Token temp; + Token temp; if (!Parsers::parseXTokenResponse(*m_response, temp, "UToken")) { qWarning() << "Could not parse user authentication response..."; emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("XBox user authentication response could not be understood.")); diff --git a/launcher/ui/dialogs/MSALoginDialog.cpp b/launcher/ui/dialogs/MSALoginDialog.cpp index b249346a4..33df1876e 100644 --- a/launcher/ui/dialogs/MSALoginDialog.cpp +++ b/launcher/ui/dialogs/MSALoginDialog.cpp @@ -37,7 +37,7 @@ #include "ui_MSALoginDialog.h" #include "DesktopServices.h" -#include "minecraft/auth/flows/AuthFlow.h" +#include "minecraft/auth/AuthFlow.h" #include #include @@ -47,26 +47,24 @@ MSALoginDialog::MSALoginDialog(QWidget* parent) : QDialog(parent), ui(new Ui::MSALoginDialog) { ui->setupUi(this); - ui->progressBar->setVisible(false); - ui->actionButton->setVisible(false); - // ui->buttonBox->button(QDialogButtonBox::Cancel)->setEnabled(false); - connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); - connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + ui->cancel->setEnabled(false); + ui->link->setVisible(false); + ui->copy->setVisible(false); + + connect(ui->cancel, &QPushButton::pressed, this, &QDialog::reject); + connect(ui->copy, &QPushButton::pressed, this, &MSALoginDialog::copyUrl); } int MSALoginDialog::exec() { - setUserInputsEnabled(false); - ui->progressBar->setVisible(true); - // Setup the login task and start it m_account = MinecraftAccount::createBlankMSA(); - m_loginTask = m_account->loginMSA(); + m_loginTask = m_account->login(); connect(m_loginTask.get(), &Task::failed, this, &MSALoginDialog::onTaskFailed); connect(m_loginTask.get(), &Task::succeeded, this, &MSALoginDialog::onTaskSucceeded); connect(m_loginTask.get(), &Task::status, this, &MSALoginDialog::onTaskStatus); - connect(m_loginTask.get(), &Task::progress, this, &MSALoginDialog::onTaskProgress); + connect(m_loginTask.get(), &AuthFlow::authorizeWithBrowser, this, &MSALoginDialog::authorizeWithBrowser); m_loginTask->start(); return QDialog::exec(); @@ -77,11 +75,6 @@ MSALoginDialog::~MSALoginDialog() delete ui; } -void MSALoginDialog::setUserInputsEnabled(bool enable) -{ - ui->buttonBox->setEnabled(enable); -} - void MSALoginDialog::onTaskFailed(const QString& reason) { // Set message @@ -94,12 +87,7 @@ void MSALoginDialog::onTaskFailed(const QString& reason) processed += "
"; } } - ui->label->setText(processed); - - // Re-enable user-interaction - setUserInputsEnabled(true); - ui->progressBar->setVisible(false); - ui->actionButton->setVisible(false); + ui->message->setText(processed); } void MSALoginDialog::onTaskSucceeded() @@ -109,22 +97,38 @@ void MSALoginDialog::onTaskSucceeded() void MSALoginDialog::onTaskStatus(const QString& status) { - ui->label->setText(status); -} - -void MSALoginDialog::onTaskProgress(qint64 current, qint64 total) -{ - ui->progressBar->setMaximum(total); - ui->progressBar->setValue(current); + ui->message->setText(status); + ui->cancel->setEnabled(false); + ui->link->setVisible(false); + ui->copy->setVisible(false); } // Public interface MinecraftAccountPtr MSALoginDialog::newAccount(QWidget* parent, QString msg) { MSALoginDialog dlg(parent); - dlg.ui->label->setText(msg); + dlg.ui->message->setText(msg); if (dlg.exec() == QDialog::Accepted) { return dlg.m_account; } return nullptr; } + +void MSALoginDialog::authorizeWithBrowser(const QUrl& url) +{ + ui->cancel->setEnabled(true); + ui->link->setVisible(true); + ui->copy->setVisible(true); + DesktopServices::openUrl(url); + ui->link->setText(url.toDisplayString()); + ui->message->setText( + tr("Browser opened to complete the login process." + "

" + "If your browser hasn't opened, please manually open the bellow link in your browser:")); +} + +void MSALoginDialog::copyUrl() +{ + QClipboard* cb = QApplication::clipboard(); + cb->setText(ui->link->text()); +} diff --git a/launcher/ui/dialogs/MSALoginDialog.h b/launcher/ui/dialogs/MSALoginDialog.h index f14e04776..b57b83ec2 100644 --- a/launcher/ui/dialogs/MSALoginDialog.h +++ b/launcher/ui/dialogs/MSALoginDialog.h @@ -18,8 +18,8 @@ #include #include +#include "minecraft/auth/AuthFlow.h" #include "minecraft/auth/MinecraftAccount.h" -#include "minecraft/auth/flows/AuthFlow.h" namespace Ui { class MSALoginDialog; @@ -37,13 +37,12 @@ class MSALoginDialog : public QDialog { private: explicit MSALoginDialog(QWidget* parent = 0); - void setUserInputsEnabled(bool enable); - protected slots: void onTaskFailed(const QString& reason); void onTaskSucceeded(); void onTaskStatus(const QString& status); - void onTaskProgress(qint64 current, qint64 total); + void authorizeWithBrowser(const QUrl& url); + void copyUrl(); private: Ui::MSALoginDialog* ui; diff --git a/launcher/ui/dialogs/MSALoginDialog.ui b/launcher/ui/dialogs/MSALoginDialog.ui index c18d01a16..e6c9f1aad 100644 --- a/launcher/ui/dialogs/MSALoginDialog.ui +++ b/launcher/ui/dialogs/MSALoginDialog.ui @@ -21,11 +21,9 @@ - + - Message label placeholder. - -aaaaa + Qt::RichText @@ -39,36 +37,33 @@ aaaaa
- - - 24 - - - false - - - - - + - - - Open page and copy code + + + false - - - Qt::Horizontal + + + - - QDialogButtonBox::Cancel + + + + + + Cancel + + + diff --git a/launcher/ui/dialogs/OfflineLoginDialog.cpp b/launcher/ui/dialogs/OfflineLoginDialog.cpp index cd3102135..b9d1c2915 100644 --- a/launcher/ui/dialogs/OfflineLoginDialog.cpp +++ b/launcher/ui/dialogs/OfflineLoginDialog.cpp @@ -26,7 +26,7 @@ void OfflineLoginDialog::accept() // Setup the login task and start it m_account = MinecraftAccount::createOffline(ui->userTextBox->text()); - m_loginTask = m_account->loginOffline(); + m_loginTask = m_account->login(); connect(m_loginTask.get(), &Task::failed, this, &OfflineLoginDialog::onTaskFailed); connect(m_loginTask.get(), &Task::succeeded, this, &OfflineLoginDialog::onTaskSucceeded); connect(m_loginTask.get(), &Task::status, this, &OfflineLoginDialog::onTaskStatus); From 8b051b97fd671d7a04ece2e5df580b3099bb90a3 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Wed, 15 May 2024 17:54:35 +0300 Subject: [PATCH 215/223] Fix CI2 Signed-off-by: Trial97 --- .github/workflows/codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 261f67819..5255f865b 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -23,7 +23,7 @@ jobs: run: sudo apt-get -y update - sudo apt-get -y install ninja-build extra-cmake-modules scdoc qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5 libqt5networkauth5 + sudo apt-get -y install ninja-build extra-cmake-modules scdoc qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5 libqt5networkauth5 libqt5networkauth5-dev - name: Configure and Build run: | From 898ee67a07aa62ff01c0224d7d7dc1c7658eee22 Mon Sep 17 00:00:00 2001 From: Alexandru Ionut Tripon Date: Thu, 16 May 2024 00:41:07 +0300 Subject: [PATCH 216/223] Update launcher/ui/dialogs/MSALoginDialog.cpp Co-authored-by: Tayou Signed-off-by: Alexandru Ionut Tripon --- launcher/ui/dialogs/MSALoginDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/dialogs/MSALoginDialog.cpp b/launcher/ui/dialogs/MSALoginDialog.cpp index 33df1876e..b36e8f9b3 100644 --- a/launcher/ui/dialogs/MSALoginDialog.cpp +++ b/launcher/ui/dialogs/MSALoginDialog.cpp @@ -124,7 +124,7 @@ void MSALoginDialog::authorizeWithBrowser(const QUrl& url) ui->message->setText( tr("Browser opened to complete the login process." "

" - "If your browser hasn't opened, please manually open the bellow link in your browser:")); + "If your browser hasn't opened, please manually open the below link in your browser:")); } void MSALoginDialog::copyUrl() From 2a58fb0ac51ebe1a1aa1b81658b4f0334f81cfa8 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 16 May 2024 17:31:25 +0300 Subject: [PATCH 217/223] Remove cobrandid Signed-off-by: Trial97 --- launcher/minecraft/auth/steps/MSAStep.cpp | 1 - launcher/net/NetRequest.cpp | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/launcher/minecraft/auth/steps/MSAStep.cpp b/launcher/minecraft/auth/steps/MSAStep.cpp index 4d3c2d202..3c55540dc 100644 --- a/launcher/minecraft/auth/steps/MSAStep.cpp +++ b/launcher/minecraft/auth/steps/MSAStep.cpp @@ -95,7 +95,6 @@ void MSAStep::perform() oauth2.setModifyParametersFunction([](QAbstractOAuth::Stage stage, QMap* map) { #endif map->insert("prompt", "select_account"); - map->insert("cobrandid", "8058f65d-ce06-4c30-9559-473c9275a65d"); }); *m_data = AccountData(); diff --git a/launcher/net/NetRequest.cpp b/launcher/net/NetRequest.cpp index 55a4f185c..cfd93b61f 100644 --- a/launcher/net/NetRequest.cpp +++ b/launcher/net/NetRequest.cpp @@ -37,11 +37,11 @@ */ #include "NetRequest.h" -#include -#include #include #include +#include +#include #include #if defined(LAUNCHER_APPLICATION) From 09c0c11033756e7fd18b5bb51d4427f6cf793b42 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 16 May 2024 21:58:25 +0300 Subject: [PATCH 218/223] Add back device code flow Signed-off-by: Trial97 --- launcher/CMakeLists.txt | 2 + launcher/minecraft/auth/AuthFlow.cpp | 17 +- launcher/minecraft/auth/AuthFlow.h | 5 +- launcher/minecraft/auth/MinecraftAccount.cpp | 6 +- launcher/minecraft/auth/MinecraftAccount.h | 2 +- .../auth/steps/MSADeviceCodeStep.cpp | 272 ++++++++++++++++++ .../minecraft/auth/steps/MSADeviceCodeStep.h | 76 +++++ launcher/net/ByteArraySink.h | 4 - launcher/net/NetRequest.cpp | 11 +- launcher/net/Upload.cpp | 3 +- launcher/ui/dialogs/MSALoginDialog.cpp | 61 +++- launcher/ui/dialogs/MSALoginDialog.h | 13 +- launcher/ui/dialogs/MSALoginDialog.ui | 32 ++- launcher/ui/pages/global/AccountListPage.cpp | 13 +- 14 files changed, 481 insertions(+), 36 deletions(-) create mode 100644 launcher/minecraft/auth/steps/MSADeviceCodeStep.cpp create mode 100644 launcher/minecraft/auth/steps/MSADeviceCodeStep.h diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index e63328e6e..833f994ff 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -228,6 +228,8 @@ set(MINECRAFT_SOURCES minecraft/auth/steps/LauncherLoginStep.h minecraft/auth/steps/MinecraftProfileStep.cpp minecraft/auth/steps/MinecraftProfileStep.h + minecraft/auth/steps/MSADeviceCodeStep.cpp + minecraft/auth/steps/MSADeviceCodeStep.h minecraft/auth/steps/MSAStep.cpp minecraft/auth/steps/MSAStep.h minecraft/auth/steps/XboxAuthorizationStep.cpp diff --git a/launcher/minecraft/auth/AuthFlow.cpp b/launcher/minecraft/auth/AuthFlow.cpp index c98d0b2c9..5648fe9f6 100644 --- a/launcher/minecraft/auth/AuthFlow.cpp +++ b/launcher/minecraft/auth/AuthFlow.cpp @@ -7,22 +7,31 @@ #include "minecraft/auth/steps/EntitlementsStep.h" #include "minecraft/auth/steps/GetSkinStep.h" #include "minecraft/auth/steps/LauncherLoginStep.h" +#include "minecraft/auth/steps/MSADeviceCodeStep.h" #include "minecraft/auth/steps/MSAStep.h" #include "minecraft/auth/steps/MinecraftProfileStep.h" #include "minecraft/auth/steps/XboxAuthorizationStep.h" #include "minecraft/auth/steps/XboxProfileStep.h" #include "minecraft/auth/steps/XboxUserStep.h" +#include "tasks/Task.h" #include "AuthFlow.h" #include -AuthFlow::AuthFlow(AccountData* data, bool silent, QObject* parent) : Task(parent), m_data(data) +AuthFlow::AuthFlow(AccountData* data, Action action, QObject* parent) : Task(parent), m_data(data) { if (data->type == AccountType::MSA) { - auto oauthStep = makeShared(m_data, silent); - connect(oauthStep.get(), &MSAStep::authorizeWithBrowser, this, &AuthFlow::authorizeWithBrowser); - m_steps.append(oauthStep); + if (action == Action::DeviceCode) { + auto oauthStep = makeShared(m_data); + connect(oauthStep.get(), &MSADeviceCodeStep::authorizeWithBrowser, this, &AuthFlow::authorizeWithBrowserWithExtra); + connect(this, &Task::aborted, oauthStep.get(), &MSADeviceCodeStep::abort); + m_steps.append(oauthStep); + } else { + auto oauthStep = makeShared(m_data, action == Action::Refresh); + connect(oauthStep.get(), &MSAStep::authorizeWithBrowser, this, &AuthFlow::authorizeWithBrowser); + m_steps.append(oauthStep); + } m_steps.append(makeShared(m_data)); m_steps.append(makeShared(m_data, &m_data->xboxApiToken, "http://xboxlive.com", "Xbox")); m_steps.append( diff --git a/launcher/minecraft/auth/AuthFlow.h b/launcher/minecraft/auth/AuthFlow.h index 611c25058..d99deec3c 100644 --- a/launcher/minecraft/auth/AuthFlow.h +++ b/launcher/minecraft/auth/AuthFlow.h @@ -15,7 +15,9 @@ class AuthFlow : public Task { Q_OBJECT public: - explicit AuthFlow(AccountData* data, bool silent = false, QObject* parent = 0); + enum class Action { Refresh, Login, DeviceCode }; + + explicit AuthFlow(AccountData* data, Action action = Action::Refresh, QObject* parent = 0); virtual ~AuthFlow() = default; void executeTask() override; @@ -24,6 +26,7 @@ class AuthFlow : public Task { signals: void authorizeWithBrowser(const QUrl& url); + void authorizeWithBrowserWithExtra(QString url, QString code, int expiresIn); protected: void succeed(); diff --git a/launcher/minecraft/auth/MinecraftAccount.cpp b/launcher/minecraft/auth/MinecraftAccount.cpp index f8a43900b..3c7129d5f 100644 --- a/launcher/minecraft/auth/MinecraftAccount.cpp +++ b/launcher/minecraft/auth/MinecraftAccount.cpp @@ -119,11 +119,11 @@ QPixmap MinecraftAccount::getFace() const return skin.scaled(64, 64, Qt::KeepAspectRatio); } -shared_qobject_ptr MinecraftAccount::login() +shared_qobject_ptr MinecraftAccount::login(bool useDeviceCode) { Q_ASSERT(m_currentTask.get() == nullptr); - m_currentTask.reset(new AuthFlow(&data, false, this)); + m_currentTask.reset(new AuthFlow(&data, useDeviceCode ? AuthFlow::Action::DeviceCode : AuthFlow::Action::Login, this)); connect(m_currentTask.get(), &Task::succeeded, this, &MinecraftAccount::authSucceeded); connect(m_currentTask.get(), &Task::failed, this, &MinecraftAccount::authFailed); connect(m_currentTask.get(), &Task::aborted, this, [this] { authFailed(tr("Aborted")); }); @@ -137,7 +137,7 @@ shared_qobject_ptr MinecraftAccount::refresh() return m_currentTask; } - m_currentTask.reset(new AuthFlow(&data, true, this)); + m_currentTask.reset(new AuthFlow(&data, AuthFlow::Action::Refresh, this)); connect(m_currentTask.get(), &Task::succeeded, this, &MinecraftAccount::authSucceeded); connect(m_currentTask.get(), &Task::failed, this, &MinecraftAccount::authFailed); diff --git a/launcher/minecraft/auth/MinecraftAccount.h b/launcher/minecraft/auth/MinecraftAccount.h index 6f540c572..b5c623a26 100644 --- a/launcher/minecraft/auth/MinecraftAccount.h +++ b/launcher/minecraft/auth/MinecraftAccount.h @@ -95,7 +95,7 @@ class MinecraftAccount : public QObject, public Usable { QJsonObject saveToJson() const; public: /* manipulation */ - shared_qobject_ptr login(); + shared_qobject_ptr login(bool useDeviceCode = false); shared_qobject_ptr refresh(); diff --git a/launcher/minecraft/auth/steps/MSADeviceCodeStep.cpp b/launcher/minecraft/auth/steps/MSADeviceCodeStep.cpp new file mode 100644 index 000000000..436ed58bf --- /dev/null +++ b/launcher/minecraft/auth/steps/MSADeviceCodeStep.cpp @@ -0,0 +1,272 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2024 Trial97 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MSADeviceCodeStep.h" +#include +#include +#include + +#include + +#include "Application.h" +#include "Json.h" +#include "net/StaticHeaderProxy.h" + +// https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-device-code +MSADeviceCodeStep::MSADeviceCodeStep(AccountData* data) : AuthStep(data) +{ + m_clientId = APPLICATION->getMSAClientID(); +} + +QString MSADeviceCodeStep::describe() +{ + return tr("Logging in with Microsoft account(device code)."); +} + +void MSADeviceCodeStep::perform() +{ + QUrlQuery data; + data.addQueryItem("client_id", m_clientId); + data.addQueryItem("scope", "XboxLive.SignIn XboxLive.offline_access"); + auto payload = data.query(QUrl::FullyEncoded).toUtf8(); + QUrl url("https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode"); + auto headers = QList{ + { "Content-Type", "application/x-www-form-urlencoded" }, + { "Accept", "application/json" }, + }; + m_response.reset(new QByteArray()); + m_task = Net::Upload::makeByteArray(url, m_response, payload); + m_task->addHeaderProxy(new Net::StaticHeaderProxy(headers)); + + connect(m_task.get(), &Task::finished, this, &MSADeviceCodeStep::deviceAutorizationFinished); + + m_task->setNetwork(APPLICATION->network()); + m_task->start(); +} + +struct DeviceAutorizationResponse { + QString device_code; + QString user_code; + QString verification_uri; + int expires_in; + int interval; + + QString error; + QString error_description; +}; + +DeviceAutorizationResponse parseDeviceAutorizationResponse(const QByteArray& data) +{ + QJsonParseError err; + QJsonDocument doc = QJsonDocument::fromJson(data, &err); + if (err.error != QJsonParseError::NoError) { + qWarning() << "Failed to parse device autorization response due to err:" << err.errorString(); + return {}; + } + + if (!doc.isObject()) { + qWarning() << "Device autorization response is not an object"; + return {}; + } + auto obj = doc.object(); + return { + Json::ensureString(obj, "device_code"), Json::ensureString(obj, "user_code"), Json::ensureString(obj, "verification_uri"), + Json::ensureInteger(obj, "expires_in"), Json::ensureInteger(obj, "interval"), Json::ensureString(obj, "error"), + Json::ensureString(obj, "error_description"), + }; +} + +void MSADeviceCodeStep::deviceAutorizationFinished() +{ + auto rsp = parseDeviceAutorizationResponse(*m_response); + if (!rsp.error.isEmpty() || !rsp.error_description.isEmpty()) { + qWarning() << "Device authorization failed:" << rsp.error; + emit finished(AccountTaskState::STATE_FAILED_HARD, + tr("Device authorization failed: %1").arg(rsp.error_description.isEmpty() ? rsp.error : rsp.error_description)); + return; + } + if (!m_task->wasSuccessful() || m_task->error() != QNetworkReply::NoError) { + emit finished(AccountTaskState::STATE_FAILED_HARD, tr("Failed to retrieve device authorization")); + qDebug() << *m_response; + return; + } + + if (rsp.device_code.isEmpty() || rsp.user_code.isEmpty() || rsp.verification_uri.isEmpty() || rsp.expires_in == 0) { + emit finished(AccountTaskState::STATE_FAILED_HARD, tr("Device authorization failed: required fields missing")); + return; + } + if (rsp.interval != 0) { + interval = rsp.interval; + } + m_device_code = rsp.device_code; + emit authorizeWithBrowser(rsp.verification_uri, rsp.user_code, rsp.expires_in); + m_expiration_timer.setTimerType(Qt::VeryCoarseTimer); + m_expiration_timer.setInterval(rsp.expires_in * 1000); + m_expiration_timer.setSingleShot(true); + connect(&m_expiration_timer, &QTimer::timeout, this, &MSADeviceCodeStep::abort); + m_expiration_timer.start(); + + m_pool_timer.setTimerType(Qt::VeryCoarseTimer); + m_pool_timer.setSingleShot(true); + startPoolTimer(); +} + +void MSADeviceCodeStep::abort() +{ + m_expiration_timer.stop(); + m_pool_timer.stop(); + if (m_task) { + m_task->abort(); + } + m_is_aborted = true; + emit finished(AccountTaskState::STATE_FAILED_HARD, tr("Task aborted")); +} + +void MSADeviceCodeStep::startPoolTimer() +{ + if (m_is_aborted) { + return; + } + m_pool_timer.setInterval(interval * 1000); + connect(&m_pool_timer, &QTimer::timeout, this, &MSADeviceCodeStep::authenticateUser); + m_pool_timer.start(); +} + +void MSADeviceCodeStep::authenticateUser() +{ + QUrlQuery data; + data.addQueryItem("client_id", m_clientId); + data.addQueryItem("grant_type", "urn:ietf:params:oauth:grant-type:device_code"); + data.addQueryItem("device_code", m_device_code); + auto payload = data.query(QUrl::FullyEncoded).toUtf8(); + QUrl url("https://login.microsoftonline.com/consumers/oauth2/v2.0/token"); + auto headers = QList{ + { "Content-Type", "application/x-www-form-urlencoded" }, + { "Accept", "application/json" }, + }; + m_response.reset(new QByteArray()); + m_task = Net::Upload::makeByteArray(url, m_response, payload); + m_task->addHeaderProxy(new Net::StaticHeaderProxy(headers)); + + connect(m_task.get(), &Task::finished, this, &MSADeviceCodeStep::authenticationFinished); + + m_task->setNetwork(APPLICATION->network()); + m_task->start(); +} + +struct AuthenticationResponse { + QString access_token; + QString token_type; + QString refresh_token; + int expires_in; + + QString error; + QString error_description; + + QVariantMap extra; +}; + +AuthenticationResponse parseAuthenticationResponse(const QByteArray& data) +{ + QJsonParseError err; + QJsonDocument doc = QJsonDocument::fromJson(data, &err); + if (err.error != QJsonParseError::NoError) { + qWarning() << "Failed to parse device autorization response due to err:" << err.errorString(); + return {}; + } + + if (!doc.isObject()) { + qWarning() << "Device autorization response is not an object"; + return {}; + } + auto obj = doc.object(); + return { Json::ensureString(obj, "access_token"), + Json::ensureString(obj, "token_type"), + Json::ensureString(obj, "refresh_token"), + Json::ensureInteger(obj, "expires_in"), + Json::ensureString(obj, "error"), + Json::ensureString(obj, "error_description"), + obj.toVariantMap() }; +} + +void MSADeviceCodeStep::authenticationFinished() +{ + if (m_task->error() == QNetworkReply::TimeoutError) { + // rfc8628#section-3.5 + // "On encountering a connection timeout, clients MUST unilaterally + // reduce their polling frequency before retrying. The use of an + // exponential backoff algorithm to achieve this, such as doubling the + // polling interval on each such connection timeout, is RECOMMENDED." + interval *= 2; + startPoolTimer(); + return; + } + auto rsp = parseAuthenticationResponse(*m_response); + if (rsp.error == "slow_down") { + // rfc8628#section-3.5 + // "A variant of 'authorization_pending', the authorization request is + // still pending and polling should continue, but the interval MUST + // be increased by 5 seconds for this and all subsequent requests." + interval += 5; + startPoolTimer(); + return; + } + if (rsp.error == "authorization_pending") { + // keep trying - rfc8628#section-3.5 + // "The authorization request is still pending as the end user hasn't + // yet completed the user-interaction steps (Section 3.3)." + startPoolTimer(); + return; + } + if (!rsp.error.isEmpty() || !rsp.error_description.isEmpty()) { + qWarning() << "Device Access failed:" << rsp.error; + emit finished(AccountTaskState::STATE_FAILED_HARD, + tr("Device Access failed: %1").arg(rsp.error_description.isEmpty() ? rsp.error : rsp.error_description)); + return; + } + if (!m_task->wasSuccessful() || m_task->error() != QNetworkReply::NoError) { + startPoolTimer(); // it failed so just try again without increasing the interval + return; + } + + m_expiration_timer.stop(); + m_data->msaClientID = m_clientId; + m_data->msaToken.issueInstant = QDateTime::currentDateTimeUtc(); + m_data->msaToken.notAfter = QDateTime::currentDateTime().addSecs(rsp.expires_in); + m_data->msaToken.extra = rsp.extra; + m_data->msaToken.refresh_token = rsp.refresh_token; + m_data->msaToken.token = rsp.access_token; + emit finished(AccountTaskState::STATE_WORKING, tr("Got")); +} \ No newline at end of file diff --git a/launcher/minecraft/auth/steps/MSADeviceCodeStep.h b/launcher/minecraft/auth/steps/MSADeviceCodeStep.h new file mode 100644 index 000000000..e53eebc62 --- /dev/null +++ b/launcher/minecraft/auth/steps/MSADeviceCodeStep.h @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2024 Trial97 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include + +#include "minecraft/auth/AuthStep.h" +#include "net/Upload.h" + +class MSADeviceCodeStep : public AuthStep { + Q_OBJECT + public: + explicit MSADeviceCodeStep(AccountData* data); + virtual ~MSADeviceCodeStep() noexcept = default; + + void perform() override; + + QString describe() override; + + public slots: + void abort(); + + signals: + void authorizeWithBrowser(QString url, QString code, int expiresIn); + + private slots: + void deviceAutorizationFinished(); + void startPoolTimer(); + void authenticateUser(); + void authenticationFinished(); + + private: + QString m_clientId; + QString m_device_code; + bool m_is_aborted = false; + int interval = 5; + + QTimer m_pool_timer; + QTimer m_expiration_timer; + + std::shared_ptr m_response; + Net::Upload::Ptr m_task; +}; diff --git a/launcher/net/ByteArraySink.h b/launcher/net/ByteArraySink.h index 7b8f0f8aa..d636f6634 100644 --- a/launcher/net/ByteArraySink.h +++ b/launcher/net/ByteArraySink.h @@ -74,10 +74,6 @@ class ByteArraySink : public Sink { auto abort() -> Task::State override { - if (m_output) - m_output->clear(); - else - qWarning() << "ByteArraySink did not clear the buffer because it's not addressable"; failAllValidators(); return Task::State::Failed; } diff --git a/launcher/net/NetRequest.cpp b/launcher/net/NetRequest.cpp index cfd93b61f..abecc0cf3 100644 --- a/launcher/net/NetRequest.cpp +++ b/launcher/net/NetRequest.cpp @@ -256,21 +256,18 @@ void NetRequest::downloadFinished() { qCDebug(logCat) << getUid().toString() << "Request failed but we are allowed to proceed:" << m_url.toString(); m_sink->abort(); - m_reply.reset(); emit succeeded(); emit finished(); return; } else if (m_state == State::Failed) { qCDebug(logCat) << getUid().toString() << "Request failed in previous step:" << m_url.toString(); m_sink->abort(); - m_reply.reset(); - emit failed(""); + emit failed(m_reply->errorString()); emit finished(); return; } else if (m_state == State::AbortedByUser) { qCDebug(logCat) << getUid().toString() << "Request aborted in previous step:" << m_url.toString(); m_sink->abort(); - m_reply.reset(); emit aborted(); emit finished(); return; @@ -284,7 +281,7 @@ void NetRequest::downloadFinished() if (m_state != State::Succeeded) { qCDebug(logCat) << getUid().toString() << "Request failed to write:" << m_url.toString(); m_sink->abort(); - emit failed(""); + emit failed("failed to write in sink"); emit finished(); return; } @@ -295,13 +292,11 @@ void NetRequest::downloadFinished() if (m_state != State::Succeeded) { qCDebug(logCat) << getUid().toString() << "Request failed to finalize:" << m_url.toString(); m_sink->abort(); - m_reply.reset(); - emit failed(""); + emit failed("failed to finalize the request"); emit finished(); return; } - m_reply.reset(); qCDebug(logCat) << getUid().toString() << "Request succeeded:" << m_url.toString(); emit succeeded(); emit finished(); diff --git a/launcher/net/Upload.cpp b/launcher/net/Upload.cpp index 726572e52..623ec80f4 100644 --- a/launcher/net/Upload.cpp +++ b/launcher/net/Upload.cpp @@ -46,7 +46,8 @@ namespace Net { QNetworkReply* Upload::getReply(QNetworkRequest& request) { - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + if (!request.hasRawHeader("Content-Type")) + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); return m_network->post(request, m_post_data); } diff --git a/launcher/ui/dialogs/MSALoginDialog.cpp b/launcher/ui/dialogs/MSALoginDialog.cpp index b36e8f9b3..a654c1d29 100644 --- a/launcher/ui/dialogs/MSALoginDialog.cpp +++ b/launcher/ui/dialogs/MSALoginDialog.cpp @@ -51,6 +51,7 @@ MSALoginDialog::MSALoginDialog(QWidget* parent) : QDialog(parent), ui(new Ui::MS ui->cancel->setEnabled(false); ui->link->setVisible(false); ui->copy->setVisible(false); + ui->progressBar->setVisible(false); connect(ui->cancel, &QPushButton::pressed, this, &QDialog::reject); connect(ui->copy, &QPushButton::pressed, this, &MSALoginDialog::copyUrl); @@ -60,12 +61,15 @@ int MSALoginDialog::exec() { // Setup the login task and start it m_account = MinecraftAccount::createBlankMSA(); - m_loginTask = m_account->login(); - connect(m_loginTask.get(), &Task::failed, this, &MSALoginDialog::onTaskFailed); - connect(m_loginTask.get(), &Task::succeeded, this, &MSALoginDialog::onTaskSucceeded); - connect(m_loginTask.get(), &Task::status, this, &MSALoginDialog::onTaskStatus); - connect(m_loginTask.get(), &AuthFlow::authorizeWithBrowser, this, &MSALoginDialog::authorizeWithBrowser); - m_loginTask->start(); + m_task = m_account->login(m_using_device_code); + connect(m_task.get(), &Task::failed, this, &MSALoginDialog::onTaskFailed); + connect(m_task.get(), &Task::succeeded, this, &MSALoginDialog::onTaskSucceeded); + connect(m_task.get(), &Task::status, this, &MSALoginDialog::onTaskStatus); + connect(m_task.get(), &AuthFlow::authorizeWithBrowser, this, &MSALoginDialog::authorizeWithBrowser); + connect(m_task.get(), &AuthFlow::authorizeWithBrowserWithExtra, this, &MSALoginDialog::authorizeWithBrowserWithExtra); + connect(ui->cancel, &QPushButton::pressed, m_task.get(), &Task::abort); + connect(&m_external_timer, &QTimer::timeout, this, &MSALoginDialog::externalLoginTick); + m_task->start(); return QDialog::exec(); } @@ -101,12 +105,14 @@ void MSALoginDialog::onTaskStatus(const QString& status) ui->cancel->setEnabled(false); ui->link->setVisible(false); ui->copy->setVisible(false); + ui->progressBar->setVisible(false); } // Public interface -MinecraftAccountPtr MSALoginDialog::newAccount(QWidget* parent, QString msg) +MinecraftAccountPtr MSALoginDialog::newAccount(QWidget* parent, QString msg, bool usingDeviceCode) { MSALoginDialog dlg(parent); + dlg.m_using_device_code = usingDeviceCode; dlg.ui->message->setText(msg); if (dlg.exec() == QDialog::Accepted) { return dlg.m_account; @@ -132,3 +138,44 @@ void MSALoginDialog::copyUrl() QClipboard* cb = QApplication::clipboard(); cb->setText(ui->link->text()); } + +void MSALoginDialog::authorizeWithBrowserWithExtra(QString url, QString code, int expiresIn) +{ + m_external_elapsed = 0; + m_external_timeout = expiresIn; + + m_external_timer.setInterval(1000); + m_external_timer.setSingleShot(false); + m_external_timer.start(); + + ui->progressBar->setMaximum(expiresIn); + ui->progressBar->setValue(m_external_elapsed); + + QString linkString = QString("%2").arg(url, url); + if (url == "https://www.microsoft.com/link" && !code.isEmpty()) { + url += QString("?otc=%1").arg(code); + ui->message->setText(tr("

Please login in the opened browser. If no browser was opened, please open up %1 in " + "a browser and put in the code %2 to proceed with login.

") + .arg(linkString, code)); + } else { + ui->message->setText( + tr("

Please open up %1 in a browser and put in the code %2 to proceed with login.

").arg(linkString, code)); + } + ui->cancel->setEnabled(true); + ui->link->setVisible(true); + ui->copy->setVisible(true); + ui->progressBar->setVisible(true); + DesktopServices::openUrl(url); + ui->link->setText(code); +} + +void MSALoginDialog::externalLoginTick() +{ + m_external_elapsed++; + ui->progressBar->setValue(m_external_elapsed); + ui->progressBar->repaint(); + + if (m_external_elapsed >= m_external_timeout) { + m_external_timer.stop(); + } +} \ No newline at end of file diff --git a/launcher/ui/dialogs/MSALoginDialog.h b/launcher/ui/dialogs/MSALoginDialog.h index b57b83ec2..cef647ee4 100644 --- a/launcher/ui/dialogs/MSALoginDialog.h +++ b/launcher/ui/dialogs/MSALoginDialog.h @@ -15,6 +15,7 @@ #pragma once +#include #include #include @@ -31,7 +32,7 @@ class MSALoginDialog : public QDialog { public: ~MSALoginDialog(); - static MinecraftAccountPtr newAccount(QWidget* parent, QString message); + static MinecraftAccountPtr newAccount(QWidget* parent, QString message, bool usingDeviceCode = false); int exec() override; private: @@ -42,10 +43,18 @@ class MSALoginDialog : public QDialog { void onTaskSucceeded(); void onTaskStatus(const QString& status); void authorizeWithBrowser(const QUrl& url); + void authorizeWithBrowserWithExtra(QString url, QString code, int expiresIn); void copyUrl(); + void externalLoginTick(); private: Ui::MSALoginDialog* ui; MinecraftAccountPtr m_account; - shared_qobject_ptr m_loginTask; + shared_qobject_ptr m_task; + + int m_external_elapsed; + int m_external_timeout; + QTimer m_external_timer; + + bool m_using_device_code = false; }; diff --git a/launcher/ui/dialogs/MSALoginDialog.ui b/launcher/ui/dialogs/MSALoginDialog.ui index e6c9f1aad..df1b32044 100644 --- a/launcher/ui/dialogs/MSALoginDialog.ui +++ b/launcher/ui/dialogs/MSALoginDialog.ui @@ -7,11 +7,11 @@ 0 0 491 - 143 + 208 - + 0 0 @@ -22,12 +22,27 @@ + + + 0 + 0 + + + + + 500 + 500 + + Qt::RichText + + true + true @@ -51,12 +66,23 @@ - + + .. + + + + 24 + + + false + + + diff --git a/launcher/ui/pages/global/AccountListPage.cpp b/launcher/ui/pages/global/AccountListPage.cpp index abd8fa228..9aec32cef 100644 --- a/launcher/ui/pages/global/AccountListPage.cpp +++ b/launcher/ui/pages/global/AccountListPage.cpp @@ -40,6 +40,7 @@ #include #include +#include #include @@ -134,8 +135,16 @@ void AccountListPage::listChanged() void AccountListPage::on_actionAddMicrosoft_triggered() { - MinecraftAccountPtr account = - MSALoginDialog::newAccount(this, tr("Please enter your Mojang account email and password to add your account.")); + QMessageBox box(this); + box.setWindowTitle(tr("Add account")); + box.setText(tr("How do you want to login?")); + box.setIcon(QMessageBox::Question); + auto deviceCode = box.addButton(tr("Using device code"), QMessageBox::ButtonRole::YesRole); + auto authCode = box.addButton(tr("Using auth code"), QMessageBox::ButtonRole::NoRole); + box.setDefaultButton(authCode); + box.exec(); + MinecraftAccountPtr account = MSALoginDialog::newAccount( + this, tr("Please enter your Mojang account email and password to add your account."), box.clickedButton() == deviceCode); if (account) { m_accounts->addAccount(account); From ce09f06bda74552fddd8e6fbf6588057cd2fb98b Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 16 May 2024 22:16:42 +0300 Subject: [PATCH 219/223] Fix CI3 Signed-off-by: Trial97 --- launcher/minecraft/auth/steps/MSADeviceCodeStep.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/launcher/minecraft/auth/steps/MSADeviceCodeStep.cpp b/launcher/minecraft/auth/steps/MSADeviceCodeStep.cpp index 436ed58bf..22f5d4069 100644 --- a/launcher/minecraft/auth/steps/MSADeviceCodeStep.cpp +++ b/launcher/minecraft/auth/steps/MSADeviceCodeStep.cpp @@ -34,10 +34,8 @@ */ #include "MSADeviceCodeStep.h" -#include -#include -#include +#include #include #include "Application.h" From 75a457ebfaf9009d87f9baa772df993e1ca32644 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 17 May 2024 00:28:37 +0300 Subject: [PATCH 220/223] Add custom page to land after microsoft login Signed-off-by: Trial97 --- launcher/minecraft/auth/steps/MSAStep.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/launcher/minecraft/auth/steps/MSAStep.cpp b/launcher/minecraft/auth/steps/MSAStep.cpp index 3c55540dc..3f31cdc16 100644 --- a/launcher/minecraft/auth/steps/MSAStep.cpp +++ b/launcher/minecraft/auth/steps/MSAStep.cpp @@ -46,6 +46,10 @@ MSAStep::MSAStep(AccountData* data, bool silent) : AuthStep(data), m_silent(sile m_clientId = APPLICATION->getMSAClientID(); auto replyHandler = new QOAuthHttpServerReplyHandler(1337, this); + replyHandler->setCallbackText( + "