From 43e4481b7093cb84c22cc54906fc2bf41208481e Mon Sep 17 00:00:00 2001 From: Michael Tyson Date: Tue, 23 Apr 2024 14:23:53 +1000 Subject: [PATCH 1/4] Support for launching from command line in offline mode This allows launching an offline instance with --offline --name=OfflineName. This is useful for playing split screen by creating two side-by-side instances, which is impossible online, unless one is using two separate paid accounts. With this PR, it makes it possible to launch from a script - otherwise, one has to launch manually, which is a pain, or create offline profiles for each instance, which interferes with some functionality like skins (my autistic son takes great issue with his skin not being visible, when using offline profiles!). Implementation is based on MultiMC, which supports this feature. See also https://github.com/PrismLauncher/PrismLauncher/issues/1059 for discussion. Signed-off-by: Michael Tyson --- launcher/Application.cpp | 28 +++++++++++++++++++++++----- launcher/Application.h | 5 ++++- launcher/LaunchController.cpp | 13 +++++++++---- launcher/LaunchController.h | 3 +++ 4 files changed, 39 insertions(+), 10 deletions(-) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index ea749ca4c..5fa9da4ce 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -242,6 +242,8 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) { { "s", "server" }, "Join the specified server on launch (only valid in combination with --launch)", "address" }, { { "w", "world" }, "Join the specified world on launch (only valid in combination with --launch)", "world" }, { { "a", "profile" }, "Use the account specified by its profile name (only valid in combination with --launch)", "profile" }, + { { "o", "offline" }, "Launch offline (only valid in combination with --launch)", "offline" }, + { { "n", "name" }, "When launching offline, use specified name (only makes sense in combination with --launch and --offline)", "name" }, { "alive", "Write a small '" + liveCheckFile + "' file after the launcher starts" }, { { "I", "import" }, "Import instance or resource from specified local path or URL", "url" }, { "show", "Opens the window for the specified instance (by instance ID)", "show" } }); @@ -257,6 +259,10 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) m_serverToJoin = parser.value("server"); m_worldToJoin = parser.value("world"); m_profileToUse = parser.value("profile"); + if (parser.isSet("offline")) { + m_offline = true; + m_offlineName = parser.value("name"); + } m_liveCheck = parser.isSet("alive"); m_instanceIdToShowWindowOf = parser.value("show"); @@ -271,8 +277,8 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) } // error if --launch is missing with --server or --profile - if (((!m_serverToJoin.isEmpty() || !m_worldToJoin.isEmpty()) || !m_profileToUse.isEmpty()) && m_instanceIdToLaunch.isEmpty()) { - std::cerr << "--server and --profile can only be used in combination with --launch!" << std::endl; + if ((!m_serverToJoin.isEmpty() || !m_worldToJoin.isEmpty() || !m_profileToUse.isEmpty() || m_offline || !m_offlineName.isEmpty()) && m_instanceIdToLaunch.isEmpty()) { + std::cerr << "--server, --profile, --offline and --name can only be used in combination with --launch!" << std::endl; m_status = Application::Failed; return; } @@ -397,6 +403,10 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) if (!m_profileToUse.isEmpty()) { launch.args["profile"] = m_profileToUse; } + if (m_offline) { + launch.args["offline_enabled"] = "true"; + launch.args["offline_name"] = m_offlineName; + } m_peerInstance->sendMessage(launch.serialize(), timeout); } m_status = Application::Succeeded; @@ -1209,7 +1219,7 @@ void Application::performMainStartupAction() qDebug() << " Launching with account" << m_profileToUse; } - launch(inst, true, false, targetToJoin, accountToUse); + launch(inst, !m_offline, false, targetToJoin, accountToUse, m_offlineName); return; } } @@ -1308,6 +1318,8 @@ void Application::messageReceived(const QByteArray& message) QString server = received.args["server"]; QString world = received.args["world"]; QString profile = received.args["profile"]; + bool offline = received.args["offline_enabled"] == "true"; + QString offlineName = received.args["offline_name"]; InstancePtr instance; if (!id.isEmpty()) { @@ -1337,7 +1349,7 @@ void Application::messageReceived(const QByteArray& message) } } - launch(instance, true, false, serverObject, accountObject); + launch(instance, !offline, false, serverObject, accountObject, offlineName); } else { qWarning() << "Received invalid message" << message; } @@ -1375,7 +1387,12 @@ bool Application::openJsonEditor(const QString& filename) } } -bool Application::launch(InstancePtr instance, bool online, bool demo, MinecraftTarget::Ptr targetToJoin, MinecraftAccountPtr accountToUse) +bool Application::launch(InstancePtr instance, + bool online, + bool demo, + MinecraftTarget::Ptr targetToJoin, + MinecraftAccountPtr accountToUse, + const QString& offlineName) { if (m_updateRunning) { qDebug() << "Cannot launch instances while an update is running. Please try again when updates are completed."; @@ -1395,6 +1412,7 @@ bool Application::launch(InstancePtr instance, bool online, bool demo, Minecraft controller->setProfiler(profilers().value(instance->settings()->get("Profiler").toString(), nullptr).get()); controller->setTargetToJoin(targetToJoin); controller->setAccountToUse(accountToUse); + controller->setOfflineName(offlineName); if (window) { controller->setParentWidget(window); } else if (m_mainWindow) { diff --git a/launcher/Application.h b/launcher/Application.h index 692625f4a..5d672a148 100644 --- a/launcher/Application.h +++ b/launcher/Application.h @@ -211,7 +211,8 @@ class Application : public QApplication { bool online = true, bool demo = false, MinecraftTarget::Ptr targetToJoin = nullptr, - MinecraftAccountPtr accountToUse = nullptr); + MinecraftAccountPtr accountToUse = nullptr, + const QString &offlineName = QString()); bool kill(InstancePtr instance); void closeCurrentWindow(); @@ -300,6 +301,8 @@ class Application : public QApplication { QString m_serverToJoin; QString m_worldToJoin; QString m_profileToUse; + bool m_offline = false; + QString m_offlineName; bool m_liveCheck = false; QList m_urlsToImport; QString m_instanceIdToShowWindowOf; diff --git a/launcher/LaunchController.cpp b/launcher/LaunchController.cpp index e736135fa..dcec62e9e 100644 --- a/launcher/LaunchController.cpp +++ b/launcher/LaunchController.cpp @@ -235,10 +235,15 @@ void LaunchController::login() if (!m_session->wants_online) { // we ask the user for a player name bool ok = false; - auto name = askOfflineName(m_session->player_name, m_session->demo, ok); - if (!ok) { - tryagain = false; - break; + QString name; + if (m_offlineName.isEmpty()) { + name = askOfflineName(m_session->player_name, m_session->demo, ok); + if (!ok) { + tryagain = false; + break; + } + } else { + name = m_offlineName; } m_session->MakeOffline(name); // offline flavored game from here :3 diff --git a/launcher/LaunchController.h b/launcher/LaunchController.h index 08fd19cae..82cd2e23d 100644 --- a/launcher/LaunchController.h +++ b/launcher/LaunchController.h @@ -56,6 +56,8 @@ class LaunchController : public Task { void setOnline(bool online) { m_online = online; } + void setOfflineName(const QString &offlineName) { m_offlineName = offlineName; } + void setDemo(bool demo) { m_demo = demo; } void setProfiler(BaseProfilerFactory* profiler) { m_profiler = profiler; } @@ -88,6 +90,7 @@ class LaunchController : public Task { private: BaseProfilerFactory* m_profiler = nullptr; bool m_online = true; + QString m_offlineName; bool m_demo = false; InstancePtr m_instance; QWidget* m_parentWidget = nullptr; From afa1e0599a5c0f1f5276f86b3709ff07c43879bc Mon Sep 17 00:00:00 2001 From: Michael Tyson Date: Tue, 23 Apr 2024 16:05:26 +1000 Subject: [PATCH 2/4] Improved formatting Signed-off-by: Michael Tyson --- launcher/Application.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 5fa9da4ce..e48ed73f0 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -243,7 +243,9 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) { { "w", "world" }, "Join the specified world on launch (only valid in combination with --launch)", "world" }, { { "a", "profile" }, "Use the account specified by its profile name (only valid in combination with --launch)", "profile" }, { { "o", "offline" }, "Launch offline (only valid in combination with --launch)", "offline" }, - { { "n", "name" }, "When launching offline, use specified name (only makes sense in combination with --launch and --offline)", "name" }, + { { "n", "name" }, + "When launching offline, use specified name (only makes sense in combination with --launch and --offline)", + "name" }, { "alive", "Write a small '" + liveCheckFile + "' file after the launcher starts" }, { { "I", "import" }, "Import instance or resource from specified local path or URL", "url" }, { "show", "Opens the window for the specified instance (by instance ID)", "show" } }); From 56614444147afa9379877e591174a4ece7a54f32 Mon Sep 17 00:00:00 2001 From: Michael Tyson Date: Tue, 23 Apr 2024 16:53:29 +1000 Subject: [PATCH 3/4] =?UTF-8?q?Removed=20=E2=80=9C--name=E2=80=9D=20flag?= =?UTF-8?q?=20in=20favour=20of=20specifying=20offline=20player=20name=20vi?= =?UTF-8?q?a=20=E2=80=9C--offline=E2=80=9D=20flag?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michael Tyson --- launcher/Application.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index e48ed73f0..7e85938ce 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -242,10 +242,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) { { "s", "server" }, "Join the specified server on launch (only valid in combination with --launch)", "address" }, { { "w", "world" }, "Join the specified world on launch (only valid in combination with --launch)", "world" }, { { "a", "profile" }, "Use the account specified by its profile name (only valid in combination with --launch)", "profile" }, - { { "o", "offline" }, "Launch offline (only valid in combination with --launch)", "offline" }, - { { "n", "name" }, - "When launching offline, use specified name (only makes sense in combination with --launch and --offline)", - "name" }, + { { "o", "offline" }, "Launch offline, with given player name (only valid in combination with --launch)", "offline" }, { "alive", "Write a small '" + liveCheckFile + "' file after the launcher starts" }, { { "I", "import" }, "Import instance or resource from specified local path or URL", "url" }, { "show", "Opens the window for the specified instance (by instance ID)", "show" } }); @@ -263,7 +260,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) m_profileToUse = parser.value("profile"); if (parser.isSet("offline")) { m_offline = true; - m_offlineName = parser.value("name"); + m_offlineName = parser.value("offline"); } m_liveCheck = parser.isSet("alive"); @@ -279,8 +276,8 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) } // error if --launch is missing with --server or --profile - if ((!m_serverToJoin.isEmpty() || !m_worldToJoin.isEmpty() || !m_profileToUse.isEmpty() || m_offline || !m_offlineName.isEmpty()) && m_instanceIdToLaunch.isEmpty()) { - std::cerr << "--server, --profile, --offline and --name can only be used in combination with --launch!" << std::endl; + if ((!m_serverToJoin.isEmpty() || !m_worldToJoin.isEmpty() || !m_profileToUse.isEmpty() || m_offline) && m_instanceIdToLaunch.isEmpty()) { + std::cerr << "--server, --profile and --offline can only be used in combination with --launch!" << std::endl; m_status = Application::Failed; return; } From ced2f9d1a0c9ef65eb0f42efbf57c149362e88b9 Mon Sep 17 00:00:00 2001 From: Michael Tyson Date: Wed, 30 Oct 2024 12:51:34 +1100 Subject: [PATCH 4/4] Applied clang formatting Signed-off-by: Michael Tyson --- launcher/Application.cpp | 3 ++- launcher/Application.h | 2 +- launcher/LaunchController.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 7e85938ce..9a1ed440e 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -276,7 +276,8 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) } // error if --launch is missing with --server or --profile - if ((!m_serverToJoin.isEmpty() || !m_worldToJoin.isEmpty() || !m_profileToUse.isEmpty() || m_offline) && m_instanceIdToLaunch.isEmpty()) { + if ((!m_serverToJoin.isEmpty() || !m_worldToJoin.isEmpty() || !m_profileToUse.isEmpty() || m_offline) && + m_instanceIdToLaunch.isEmpty()) { std::cerr << "--server, --profile and --offline can only be used in combination with --launch!" << std::endl; m_status = Application::Failed; return; diff --git a/launcher/Application.h b/launcher/Application.h index 5d672a148..6b218f9f8 100644 --- a/launcher/Application.h +++ b/launcher/Application.h @@ -212,7 +212,7 @@ class Application : public QApplication { bool demo = false, MinecraftTarget::Ptr targetToJoin = nullptr, MinecraftAccountPtr accountToUse = nullptr, - const QString &offlineName = QString()); + const QString& offlineName = QString()); bool kill(InstancePtr instance); void closeCurrentWindow(); diff --git a/launcher/LaunchController.h b/launcher/LaunchController.h index 82cd2e23d..0abdeeb15 100644 --- a/launcher/LaunchController.h +++ b/launcher/LaunchController.h @@ -56,7 +56,7 @@ class LaunchController : public Task { void setOnline(bool online) { m_online = online; } - void setOfflineName(const QString &offlineName) { m_offlineName = offlineName; } + void setOfflineName(const QString& offlineName) { m_offlineName = offlineName; } void setDemo(bool demo) { m_demo = demo; }