From bcbf4cd5c8849b8711313ab8b63ddcd3373469e7 Mon Sep 17 00:00:00 2001 From: so5iso4ka Date: Sat, 1 Aug 2026 17:32:27 +0300 Subject: [PATCH] feat(auth): add support for unmojang/loki Signed-off-by: so5iso4ka --- launcher/Application.cpp | 4 + launcher/CMakeLists.txt | 9 +- launcher/KnownJavaAgents.cpp | 66 +++++ ...plyAuthlibInjector.h => KnownJavaAgents.h} | 25 +- launcher/minecraft/MinecraftInstance.cpp | 16 +- launcher/minecraft/launch/ApplyAuthPatch.cpp | 165 ++++++++++++ .../{ApplyElyPatch.h => ApplyAuthPatch.h} | 23 +- .../minecraft/launch/ApplyAuthlibInjector.cpp | 46 ---- launcher/minecraft/launch/ApplyElyPatch.cpp | 90 ------- .../ui/widgets/MinecraftSettingsWidget.cpp | 79 ++++++ launcher/ui/widgets/MinecraftSettingsWidget.h | 4 + .../ui/widgets/MinecraftSettingsWidget.ui | 247 +++++++++++------- 12 files changed, 514 insertions(+), 260 deletions(-) create mode 100644 launcher/KnownJavaAgents.cpp rename launcher/{minecraft/launch/ApplyAuthlibInjector.h => KnownJavaAgents.h} (65%) create mode 100644 launcher/minecraft/launch/ApplyAuthPatch.cpp rename launcher/minecraft/launch/{ApplyElyPatch.h => ApplyAuthPatch.h} (67%) delete mode 100644 launcher/minecraft/launch/ApplyAuthlibInjector.cpp delete mode 100644 launcher/minecraft/launch/ApplyElyPatch.cpp diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 9160a183e..c9ebd6968 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -774,6 +774,10 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) // Elyby settings m_settings->registerSetting("UseElySkins", 2); + // Injectors + m_settings->registerSetting("InjectorUid", "moe.yushi.authlibinjector"); + m_settings->registerSetting("InjectorVersion", ""); + // Legacy settings m_settings->registerSetting("OnlineFixes", false); diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 3ae3776fc..75f79e910 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -280,10 +280,8 @@ set(MINECRAFT_SOURCES minecraft/launch/ApplyLibraryOverride.cpp minecraft/launch/ApplyLibraryOverride.h - minecraft/launch/ApplyAuthlibInjector.cpp - minecraft/launch/ApplyAuthlibInjector.h - minecraft/launch/ApplyElyPatch.cpp - minecraft/launch/ApplyElyPatch.h + minecraft/launch/ApplyAuthPatch.cpp + minecraft/launch/ApplyAuthPatch.h minecraft/launch/ClaimAccount.cpp minecraft/launch/ClaimAccount.h minecraft/launch/CreateGameFolders.cpp @@ -872,6 +870,9 @@ SET(LAUNCHER_SOURCES logs/AnonymizeLog.cpp logs/AnonymizeLog.h + KnownJavaAgents.cpp + KnownJavaAgents.h + # GUI - windows ui/GuiUtil.h ui/GuiUtil.cpp diff --git a/launcher/KnownJavaAgents.cpp b/launcher/KnownJavaAgents.cpp new file mode 100644 index 000000000..b6b471503 --- /dev/null +++ b/launcher/KnownJavaAgents.cpp @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Freesm Launcher - Minecraft Launcher + * Copyright (C) 2026 so5iso4ka + * + * 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 + +#include "KnownJavaAgents.h" + +namespace { +const std::vector& javaAgents() +{ + static const std::vector javaAgents{ + Injectors::KnownJavaAgent{ .uid = "moe.yushi.authlibinjector", .prefix = "moe.yushi:authlibinjector", .name = "authlib-injector" }, + Injectors::KnownJavaAgent{ .uid = "org.unmojang.loki", .prefix = "org.unmojang:Loki", .name = "Loki" } + }; + return javaAgents; +} + +template +const Injectors::KnownJavaAgent* findBy(Proj proj, const QString& value) +{ + auto& agents = javaAgents(); + auto it = std::ranges::find(agents, value, proj); + if (it != agents.end()) { + return &*it; + } + + return nullptr; +} +} // namespace + +namespace Injectors { +const std::vector& getJavaAgents() +{ + return javaAgents(); +} + +const KnownJavaAgent* findByUid(const QString& uid) +{ + return findBy(&KnownJavaAgent::uid, uid); +} + +const KnownJavaAgent* findByPrefix(const QString& prefix) +{ + return findBy(&KnownJavaAgent::prefix, prefix); +} + +const KnownJavaAgent& fallback() +{ + return javaAgents().front(); +} +} // namespace Injectors diff --git a/launcher/minecraft/launch/ApplyAuthlibInjector.h b/launcher/KnownJavaAgents.h similarity index 65% rename from launcher/minecraft/launch/ApplyAuthlibInjector.h rename to launcher/KnownJavaAgents.h index 35c7d9a69..e9e37fa67 100644 --- a/launcher/minecraft/launch/ApplyAuthlibInjector.h +++ b/launcher/KnownJavaAgents.h @@ -18,17 +18,18 @@ #pragma once -#include "ApplyLibraryOverride.h" +#include +#include -class ApplyAuthlibInjector : public ApplyLibraryOverride { - Q_OBJECT - public: - explicit ApplyAuthlibInjector(LaunchTask* parent, RuntimeContext& ctx, Net::Mode netMode); - ~ApplyAuthlibInjector() override; - - protected: - void executeTask() override; - - protected slots: - void onMetaRequestDone(const Meta::VersionList::Ptr& versionList) override; +namespace Injectors { +struct KnownJavaAgent { + QString uid; + QString prefix; + QString name; }; + +const std::vector& getJavaAgents(); +const KnownJavaAgent* findByUid(const QString& uid); +const KnownJavaAgent* findByPrefix(const QString& prefix); +const KnownJavaAgent& fallback(); +} // namespace Injectors diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index d2f27304d..dcc11b4be 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -39,6 +39,7 @@ #include "Application.h" #include "BuildConfig.h" #include "Json.h" +#include "KnownJavaAgents.h" #include "QObjectPtr.h" #include "settings/Setting.h" #include "settings/SettingsObject.h" @@ -47,7 +48,6 @@ #include "MMCTime.h" #include "java/JavaVersion.h" -#include "launch/ApplyAuthlibInjector.h" #include "launch/LaunchTask.h" #include "launch/SetDiscordActivity.h" #include "launch/TaskStepWrapper.h" @@ -58,8 +58,7 @@ #include "launch/steps/QuitAfterGameStop.h" #include "launch/steps/TextPrint.h" -#include "minecraft/launch/ApplyAuthlibInjector.h" -#include "minecraft/launch/ApplyElyPatch.h" +#include "minecraft/launch/ApplyAuthPatch.h" #include "minecraft/launch/AutoInstallJava.h" #include "minecraft/launch/ClaimAccount.h" #include "minecraft/launch/CreateGameFolders.h" @@ -244,6 +243,11 @@ void MinecraftInstance::loadSpecificSettings() auto elybyOverride = m_settings->registerSetting("OverrideElyby", false); m_settings->registerOverride(global_settings->getSetting("UseElySkins"), elybyOverride); + // Injectors + auto injectorsOverride = m_settings->registerSetting("OverrideInjectors", false); + m_settings->registerOverride(global_settings->getSetting("InjectorUid"), injectorsOverride); + m_settings->registerOverride(global_settings->getSetting("InjectorVersion"), injectorsOverride); + // Legacy-related options auto legacySettings = m_settings->registerSetting("OverrideLegacySettings", false); m_settings->registerOverride(global_settings->getSetting("OnlineFixes"), legacySettings); @@ -549,7 +553,7 @@ QStringList MinecraftInstance::extraArguments(AuthSessionPtr session) QStringList jar, temp1, temp2, temp3; agent.library->getApplicableFiles(runtimeContext(), jar, temp1, temp2, temp3, getLocalLibraryPath()); QString arg = agent.argument; - if (session && agent.library->artifactPrefix() == "moe.yushi:authlibinjector") { + if (session && Injectors::findByPrefix(agent.library->artifactPrefix()) != nullptr) { arg = replaceTokensIn(arg, { { "authlib_injector_auth_url", session->authlib_injector_auth_url } }); } list.append("-javaagent:" + jar[0] + (agent.argument.isEmpty() ? "" : "=" + arg)); @@ -1207,9 +1211,9 @@ LaunchTask* MinecraftInstance::createLaunchTask(AuthSessionPtr session, Minecraf } if (session->wants_ely_patch) { - process->appendStep(makeShared(pptr, m_runtimeContext, mode)); + process->appendStep(makeShared(pptr, m_runtimeContext, mode, ApplyAuthPatch::Stage::Ely)); } else if (session->wants_authlib_injector) { - process->appendStep(makeShared(pptr, m_runtimeContext, mode)); + process->appendStep(makeShared(pptr, m_runtimeContext, mode, ApplyAuthPatch::Stage::Injector)); } // if we aren't in offline mode diff --git a/launcher/minecraft/launch/ApplyAuthPatch.cpp b/launcher/minecraft/launch/ApplyAuthPatch.cpp new file mode 100644 index 000000000..1d5a05fee --- /dev/null +++ b/launcher/minecraft/launch/ApplyAuthPatch.cpp @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Freesm Launcher - Minecraft Launcher + * Copyright (C) 2026 so5iso4ka + * + * 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 + +#include "ApplyAuthPatch.h" + +#include "KnownJavaAgents.h" +#include "launch/LaunchTask.h" +#include "minecraft/PackProfile.h" + +ApplyAuthPatch::ApplyAuthPatch(LaunchTask* parent, RuntimeContext& ctx, Net::Mode netMode, Stage stage) + : ApplyLibraryOverride(parent, ctx, netMode), m_stage(stage) +{} + +ApplyAuthPatch::~ApplyAuthPatch() = default; + +void ApplyAuthPatch::executeTask() +{ + emit logLine("", MessageLevel::Launcher); + switch (m_stage) { + case Stage::Ely: { + executeEly(); + break; + } + case Stage::Injector: { + executeInjector(); + break; + } + } +} + +void ApplyAuthPatch::onMetaRequestDone(const Meta::VersionList::Ptr& versionList) +{ + switch (m_stage) { + case Stage::Ely: { + auto libraries = m_instance->getPackProfile()->getProfile()->getLibraries(); + + auto authlibIt = + std::ranges::find_if(libraries, [](const LibraryPtr& p) { return p && p->artifactPrefix() == "com.mojang:authlib"; }); + if (authlibIt == libraries.end()) { + emit logLine(tr("Could not apply ely patch: authlib not found; falling back to injector"), MessageLevel::Warning); + m_stage = Stage::Injector; + return executeInjector(); + } + + auto authlibVersion = (*authlibIt)->version(); + + auto patchedVersions = versionList->versions(); + + auto patchedAuthlibIt = std::ranges::find_if( + patchedVersions, [authlibVersion](const Meta::Version::Ptr& p) { return p->version() == authlibVersion; }); + if (patchedAuthlibIt == patchedVersions.end()) { + emit logLine(tr("Could not apply ely patch: no suitable patched authlib found; falling back to injector"), + MessageLevel::Warning); + m_stage = Stage::Injector; + return executeInjector(); + } + + startApplyTask(*patchedAuthlibIt); + break; + } + case Stage::Injector: { + auto versions = versionList->versions(); + Meta::Version::Ptr recommended; + Meta::Version::Ptr preferred; + + std::ranges::for_each(versions, [this, &recommended, &preferred](const auto& version) { + if (!version) { + return; + } + if (!recommended && version->isRecommended()) { + recommended = version; + } + if (m_decidedInjectorVersion.has_value() && version->descriptor() == *m_decidedInjectorVersion) { + preferred = version; + } + }); + + auto decided = Injectors::findByUid(m_decidedInjectorUid); + + if (!recommended && !preferred) { + if (m_decidedInjectorUid == Injectors::fallback().uid) { + emit logLine(tr("No suitable injector version could be found"), MessageLevel::Error); + emitFailed("No suitable injector version could be found"); + return; + } + + emit logLine(tr("No suitable %1 version could be found; falling back to %2") + .arg(decided ? decided->name : m_decidedInjectorUid, Injectors::fallback().name), + MessageLevel::Warning); + m_decidedInjectorUid = Injectors::fallback().uid; + m_decidedInjectorVersion.reset(); + + return startMetaTask(m_decidedInjectorUid); + } + + if (!preferred && m_decidedInjectorVersion.has_value()) { + emit logLine(tr("No %1 %2 found; falling back to %3") + .arg(decided ? decided->name : m_decidedInjectorUid, *m_decidedInjectorVersion, recommended->descriptor()), + MessageLevel::Warning); + } + + startApplyTask(preferred != nullptr ? preferred : recommended); + break; + } + } +} +void ApplyAuthPatch::apply(const Meta::Version::Ptr& version) +{ + switch (m_stage) { + case Stage::Ely: { + QList& libraries = m_instance->getPackProfile()->getProfile()->libraries(); + auto it = std::ranges::find_if(libraries, [](const LibraryPtr& p) { return p && p->artifactPrefix() == "com.mojang:authlib"; }); + if (it != libraries.end()) { + libraries.erase(it); + } + emit logLine(tr("Using ely patch version %1").arg(version->descriptor()), MessageLevel::Launcher); + ApplyLibraryOverride::apply(version); + break; + } + case Stage::Injector: { + emit logLine(tr("Using %1 %2").arg(version->name(), version->descriptor()), MessageLevel::Launcher); + ApplyLibraryOverride::apply(version); + break; + } + } +} + +void ApplyAuthPatch::executeEly() +{ + startMetaTask("by.ely.authlib"); +} + +void ApplyAuthPatch::executeInjector() +{ + auto preferred = m_parent->instance()->settings()->get("InjectorUid").toString(); + auto preferredVersion = m_parent->instance()->settings()->get("InjectorVersion").toString(); + + if (Injectors::findByUid(preferred) == nullptr) { + m_decidedInjectorUid = Injectors::fallback().uid; + } else { + m_decidedInjectorUid = preferred; + if (!preferredVersion.isEmpty()) { + m_decidedInjectorVersion = preferredVersion; + } + } + + startMetaTask(m_decidedInjectorUid); +} diff --git a/launcher/minecraft/launch/ApplyElyPatch.h b/launcher/minecraft/launch/ApplyAuthPatch.h similarity index 67% rename from launcher/minecraft/launch/ApplyElyPatch.h rename to launcher/minecraft/launch/ApplyAuthPatch.h index 2f76dcf66..b510bc296 100644 --- a/launcher/minecraft/launch/ApplyElyPatch.h +++ b/launcher/minecraft/launch/ApplyAuthPatch.h @@ -18,13 +18,18 @@ #pragma once -#include "minecraft/launch/ApplyLibraryOverride.h" +#include +#include -class ApplyElyPatch : public ApplyLibraryOverride { +#include "ApplyLibraryOverride.h" + +class ApplyAuthPatch : public ApplyLibraryOverride { Q_OBJECT public: - explicit ApplyElyPatch(LaunchTask* parent, RuntimeContext& ctx, Net::Mode netMode); - ~ApplyElyPatch() override; + enum class Stage { Ely, Injector }; + + explicit ApplyAuthPatch(LaunchTask* parent, RuntimeContext& ctx, Net::Mode netMode, Stage stage); + ~ApplyAuthPatch() override; protected: void executeTask() override; @@ -33,7 +38,11 @@ class ApplyElyPatch : public ApplyLibraryOverride { void onMetaRequestDone(const Meta::VersionList::Ptr& versionList) override; void apply(const Meta::Version::Ptr& version) override; -private: - void applyAuthlibInjector(); - bool m_fallbackToAuthlibInjector = false; + private: + void executeEly(); + void executeInjector(); + + Stage m_stage; + QString m_decidedInjectorUid; + std::optional m_decidedInjectorVersion; }; diff --git a/launcher/minecraft/launch/ApplyAuthlibInjector.cpp b/launcher/minecraft/launch/ApplyAuthlibInjector.cpp deleted file mode 100644 index 0c3778eaa..000000000 --- a/launcher/minecraft/launch/ApplyAuthlibInjector.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -/* - * Freesm Launcher - Minecraft Launcher - * Copyright (C) 2026 so5iso4ka - * - * 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 - -#include "ApplyAuthlibInjector.h" - -ApplyAuthlibInjector::ApplyAuthlibInjector(LaunchTask* parent, RuntimeContext& ctx, Net::Mode netMode) : ApplyLibraryOverride(parent, ctx, netMode) {} - -ApplyAuthlibInjector::~ApplyAuthlibInjector() = default; - -void ApplyAuthlibInjector::executeTask() -{ - startMetaTask("moe.yushi.authlibinjector"); -} - -void ApplyAuthlibInjector::onMetaRequestDone(const Meta::VersionList::Ptr& versionList) -{ - auto versions = versionList->versions(); - auto it = std::ranges::find_if(versions, [](const auto& version) { return version && version->isRecommended(); }); - - if (it == versions.end()) { - emit logLine(tr("No recommended authlib-injector version could be found"), MessageLevel::Error); - emitFailed("No recommended authlib-injector version could be found"); - return; - } - - const auto& recommendedVersion = *it; - - startApplyTask(recommendedVersion); -} \ No newline at end of file diff --git a/launcher/minecraft/launch/ApplyElyPatch.cpp b/launcher/minecraft/launch/ApplyElyPatch.cpp deleted file mode 100644 index 0f4696c6e..000000000 --- a/launcher/minecraft/launch/ApplyElyPatch.cpp +++ /dev/null @@ -1,90 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -/* - * Freesm Launcher - Minecraft Launcher - * Copyright (C) 2026 so5iso4ka - * - * 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 - -#include "minecraft/PackProfile.h" -#include "minecraft/MinecraftInstance.h" - -#include "ApplyElyPatch.h" - -ApplyElyPatch::ApplyElyPatch(LaunchTask* parent, RuntimeContext& ctx, Net::Mode netMode) : ApplyLibraryOverride(parent, ctx, netMode) {} - -ApplyElyPatch::~ApplyElyPatch() = default; - -void ApplyElyPatch::executeTask() -{ - startMetaTask("by.ely.authlib"); -} - -void ApplyElyPatch::onMetaRequestDone(const Meta::VersionList::Ptr& versionList) -{ - if (!m_fallbackToAuthlibInjector) { - auto libraries = m_instance->getPackProfile()->getProfile()->getLibraries(); - - auto authlibIt = - std::ranges::find_if(libraries, [](const LibraryPtr& p) { return p && p->artifactPrefix() == "com.mojang:authlib"; }); - if (authlibIt == libraries.end()) { - return applyAuthlibInjector(); - } - - auto authlibVersion = (*authlibIt)->version(); - - auto patchedVersions = versionList->versions(); - - auto patchedAuthlibIt = - std::ranges::find_if(patchedVersions, [authlibVersion](const Meta::Version::Ptr& p) { return p->version() == authlibVersion; }); - if (patchedAuthlibIt == patchedVersions.end()) { - return applyAuthlibInjector(); - } - - startApplyTask(*patchedAuthlibIt); - } else { - auto versions = versionList->versions(); - auto it = std::ranges::find_if(versions, [](const auto& version) { return version && version->isRecommended(); }); - - if (it == versions.end()) { - emit logLine(tr("No recommended authlib-injector version could be found"), MessageLevel::Error); - emitFailed("No recommended authlib-injector version could be found"); - return; - } - - const auto& recommendedVersion = *it; - - startApplyTask(recommendedVersion); - } -} - -void ApplyElyPatch::apply(const Meta::Version::Ptr& version) -{ - if (!m_fallbackToAuthlibInjector) { - QList& libraries = m_instance->getPackProfile()->getProfile()->libraries(); - auto it = std::ranges::find_if(libraries, [](const LibraryPtr& p) { return p && p->artifactPrefix() == "com.mojang:authlib"; }); - if (it != libraries.end()) { - libraries.erase(it); - } - } - - ApplyLibraryOverride::apply(version); -} - -void ApplyElyPatch::applyAuthlibInjector() -{ - m_fallbackToAuthlibInjector = true; - startMetaTask("moe.yushi.authlibinjector"); -} \ No newline at end of file diff --git a/launcher/ui/widgets/MinecraftSettingsWidget.cpp b/launcher/ui/widgets/MinecraftSettingsWidget.cpp index 7c1d12c53..1b8576dcc 100644 --- a/launcher/ui/widgets/MinecraftSettingsWidget.cpp +++ b/launcher/ui/widgets/MinecraftSettingsWidget.cpp @@ -40,13 +40,18 @@ #include "ui_MinecraftSettingsWidget.h" #include +#include +#include #include "Application.h" #include "BuildConfig.h" #include "Json.h" +#include "KnownJavaAgents.h" +#include "meta/Index.h" #include "minecraft/PackProfile.h" #include "minecraft/WorldList.h" #include "minecraft/auth/AccountList.h" #include "settings/Setting.h" +#include "ui/dialogs/VersionSelectDialog.h" MinecraftSettingsWidget::MinecraftSettingsWidget(MinecraftInstance* instance, QWidget* parent) : QWidget(parent), m_instance(std::move(instance)), m_ui(new Ui::MinecraftSettingsWidget) @@ -81,6 +86,7 @@ MinecraftSettingsWidget::MinecraftSettingsWidget(MinecraftInstance* instance, QW m_ui->gameTimeGroupBox->setCheckable(true); m_ui->legacySettingsGroupBox->setCheckable(true); m_ui->elybyGroupBox->setCheckable(true); + m_ui->authGroupBox->setCheckable(true); m_ui->discordGroupBox->setCheckable(true); m_quickPlaySingleplayer = m_instance->traits().contains("feature:is_quick_play_singleplayer"); @@ -124,6 +130,11 @@ MinecraftSettingsWidget::MinecraftSettingsWidget(MinecraftInstance* instance, QW } } + { + std::ranges::for_each(Injectors::getJavaAgents(), + [this](const auto& injector) { m_ui->injectorImplCombo->addItem(injector.name, injector.uid); }); + } + m_ui->maximizedWarning->hide(); connect(m_ui->maximizedCheckBox, &QCheckBox::toggled, this, @@ -146,6 +157,16 @@ MinecraftSettingsWidget::MinecraftSettingsWidget(MinecraftInstance* instance, QW connect(m_ui->useNativeOpenALCheck, &QAbstractButton::toggled, m_ui->lineEditOpenALPath, &QWidget::setEnabled); connect(m_ui->useNativeGLFWCheck, &QAbstractButton::toggled, m_ui->lineEditGLFWPath, &QWidget::setEnabled); + connect(m_ui->injectorImplCombo, &QComboBox::currentIndexChanged, this, [this] { resetInjectorVersion(); }); + + connect(m_ui->injectorImplChangeVersionButton, &QAbstractButton::clicked, this, [this] { chooseInjectorVersion(); }); + + auto injectorMenu = new QMenu(this); + injectorMenu->addAction(tr("Use recommended"), this, &MinecraftSettingsWidget::resetInjectorVersion); + injectorMenu->addAction(tr("Choose version..."), this, &MinecraftSettingsWidget::chooseInjectorVersion); + + m_ui->injectorImplChangeVersionButton->setMenu(injectorMenu); + loadSettings(); } @@ -231,6 +252,27 @@ void MinecraftSettingsWidget::loadSettings() m_ui->elybyGroupBox->setChecked(m_instance == nullptr || settings->get("OverrideElyby").toBool()); m_ui->elySkinSystemComboBox->setCurrentIndex(settings->get("UseElySkins").toInt()); + m_ui->authGroupBox->setChecked(m_instance == nullptr || settings->get("OverrideInjectors").toBool()); + + { + QSignalBlocker blocker(m_ui->injectorImplCombo); + bool found = false; + for (int i = 0; i < m_ui->injectorImplCombo->count(); ++i) { + if (m_ui->injectorImplCombo->itemData(i, Qt::UserRole).toString() == settings->get("InjectorUid").toString()) { + m_ui->injectorImplCombo->setCurrentIndex(i); + found = true; + break; + } + } + if (found) { + m_injectorVersionToSave = settings->get("InjectorVersion").toString(); + } + if (m_injectorVersionToSave.isEmpty()) { + m_ui->injectorImplChangeVersionButton->setText(tr("Recommended")); + } else { + m_ui->injectorImplChangeVersionButton->setText(m_injectorVersionToSave); + } + } m_ui->discordGroupBox->setChecked(m_instance == nullptr || settings->get("OverrideDiscord").toBool()); m_ui->enableRichPresenceCheck->setChecked(settings->get("EnableDiscordRichPresence").toBool()); @@ -445,6 +487,20 @@ void MinecraftSettingsWidget::saveSettings() settings->reset("UseElySkins"); } + bool injectors = m_instance == nullptr || m_ui->authGroupBox->isChecked(); + + if (m_instance != nullptr) { + settings->set("OverrideInjectors", injectors); + } + + if (injectors) { + settings->set("InjectorUid", m_ui->injectorImplCombo->currentData(Qt::UserRole).toString()); + settings->set("InjectorVersion", m_injectorVersionToSave); + } else { + settings->reset("InjectorUid"); + settings->reset("InjectorVersion"); + } + bool discord = m_instance == nullptr || m_ui->discordGroupBox->isChecked(); if (m_instance != nullptr) @@ -621,3 +677,26 @@ void MinecraftSettingsWidget::selectDataPacksFolder() m_ui->dataPacksPathEdit->setText(path); m_instance->settings()->set("GlobalDataPacksPath", path); } + +void MinecraftSettingsWidget::chooseInjectorVersion() +{ + auto index = APPLICATION->metadataIndex(); + + auto versions = index->get(m_ui->injectorImplCombo->currentData(Qt::UserRole).toString()); + + VersionSelectDialog vd(versions.get(), tr("Select implementation version"), this, true); + vd.setCurrentVersion(m_injectorVersionToSave); + + if (!vd.exec() || !vd.selectedVersion()) { + return; + } + + m_injectorVersionToSave = vd.selectedVersion()->descriptor(); + m_ui->injectorImplChangeVersionButton->setText(vd.selectedVersion()->descriptor()); +} + +void MinecraftSettingsWidget::resetInjectorVersion() +{ + m_injectorVersionToSave.clear(); + m_ui->injectorImplChangeVersionButton->setText(tr("Recommended")); +} diff --git a/launcher/ui/widgets/MinecraftSettingsWidget.h b/launcher/ui/widgets/MinecraftSettingsWidget.h index 847e05806..b5d70606f 100644 --- a/launcher/ui/widgets/MinecraftSettingsWidget.h +++ b/launcher/ui/widgets/MinecraftSettingsWidget.h @@ -36,6 +36,7 @@ #pragma once +#include #include #include "JavaSettingsWidget.h" #include "minecraft/MinecraftInstance.h" @@ -60,9 +61,12 @@ class MinecraftSettingsWidget : public QWidget { void saveSelectedLoaders(); void saveDataPacksPath(); void selectDataPacksFolder(); + void chooseInjectorVersion(); + void resetInjectorVersion(); MinecraftInstance* m_instance; Ui::MinecraftSettingsWidget* m_ui; JavaSettingsWidget* m_javaSettings = nullptr; bool m_quickPlaySingleplayer = false; + QString m_injectorVersionToSave; }; diff --git a/launcher/ui/widgets/MinecraftSettingsWidget.ui b/launcher/ui/widgets/MinecraftSettingsWidget.ui index 03906d50f..e3eef16e2 100644 --- a/launcher/ui/widgets/MinecraftSettingsWidget.ui +++ b/launcher/ui/widgets/MinecraftSettingsWidget.ui @@ -59,8 +59,8 @@ 0 0 - 623 - 1352 + 618 + 1340 @@ -150,10 +150,10 @@ - Qt::Vertical + Qt::Orientation::Vertical - QSizePolicy::Fixed + QSizePolicy::Policy::Fixed @@ -212,7 +212,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -288,10 +288,10 @@ - Qt::Vertical + Qt::Orientation::Vertical - QSizePolicy::Fixed + QSizePolicy::Policy::Fixed @@ -407,7 +407,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -432,6 +432,13 @@ false + + + + Singleplayer world: + + + @@ -442,13 +449,6 @@ - - - - Singleplayer world: - - - @@ -456,20 +456,10 @@ - - - - - 200 - 16777215 - - - - - Qt::Horizontal + Qt::Orientation::Horizontal @@ -479,6 +469,16 @@ + + + + + 200 + 16777215 + + + + @@ -572,50 +572,127 @@ Ely.by - - - + + + + + Use Ely.by skin system + + + + + + + + 0 + 0 + + + + 0 + - - - Use Ely.by skin system - - + + Never + - - - - 0 - 0 - - - - 0 - - - - Never - - - - - Always (except for custom accounts) - - - - - With Ely.by accounts - - - - - With Ely.by and Offline accounts - - - + + Always (except for custom accounts) + - + + + With Ely.by accounts + + + + + With Ely.by and Offline accounts + + + + + + + + Qt::Orientation::Horizontal + + + + 140 + 20 + + + + + + + + + + + Authentication injector + + + + + + Version + + + + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + Implementation + + + + + + + ... + + + QToolButton::ToolButtonPopupMode::MenuButtonPopup + + + Qt::ToolButtonStyle::ToolButtonTextOnly + + + Qt::ArrowType::NoArrow + + @@ -642,7 +719,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -673,8 +750,8 @@ 0 0 - 623 - 484 + 593 + 495 @@ -697,8 +774,8 @@ 0 0 - 609 - 499 + 593 + 495 @@ -743,7 +820,7 @@ - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter @@ -758,10 +835,10 @@ - Qt::Vertical + Qt::Orientation::Vertical - QSizePolicy::Fixed + QSizePolicy::Policy::Fixed @@ -873,7 +950,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -943,45 +1020,31 @@ openGlobalSettingsButton settingsTabs scrollArea - - windowSizeGroupBox maximizedCheckBox windowWidthSpinBox windowHeightSpinBox closeAfterLaunchCheck quitAfterGameStopCheck - - consoleSettingsBox showConsoleCheck showConsoleErrorCheck autoCloseConsoleCheck - - globalDataPacksGroupBox dataPacksPathEdit dataPacksPathBrowse - - --> gameTimeGroupBox showGameTime recordGameTime showGlobalGameTime showGameTimeWithoutDays - - instanceAccountGroupBox instanceAccountSelector - - serverJoinGroupBox serverJoinAddressButton serverJoinAddress worldJoinButton worldsCb - - loaderGroup neoForge forge @@ -993,21 +1056,15 @@ legacyFabric ornithe rift - javaScrollArea scrollArea_2 - - legacySettingsGroupBox onlineFixes - - nativeWorkaroundsGroupBox useNativeGLFWCheck lineEditGLFWPath useNativeOpenALCheck lineEditOpenALPath - enableFeralGamemodeCheck enableMangoHud useDiscreteGpuCheck