summaryrefslogtreecommitdiff
path: root/archived/projt-launcher/launcher/minecraft/launch/LauncherPartLaunch.cpp
diff options
context:
space:
mode:
authorMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-02 18:51:45 +0300
committerMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-02 18:51:45 +0300
commitd3261e64152397db2dca4d691a990c6bc2a6f4dd (patch)
treefac2f7be638651181a72453d714f0f96675c2b8b /archived/projt-launcher/launcher/minecraft/launch/LauncherPartLaunch.cpp
parent31b9a8949ed0a288143e23bf739f2eb64fdc63be (diff)
downloadProject-Tick-d3261e64152397db2dca4d691a990c6bc2a6f4dd.tar.gz
Project-Tick-d3261e64152397db2dca4d691a990c6bc2a6f4dd.zip
NOISSUE add archived projects
Signed-off-by: Mehmet Samet Duman <yongdohyun@projecttick.org>
Diffstat (limited to 'archived/projt-launcher/launcher/minecraft/launch/LauncherPartLaunch.cpp')
-rw-r--r--archived/projt-launcher/launcher/minecraft/launch/LauncherPartLaunch.cpp275
1 files changed, 275 insertions, 0 deletions
diff --git a/archived/projt-launcher/launcher/minecraft/launch/LauncherPartLaunch.cpp b/archived/projt-launcher/launcher/minecraft/launch/LauncherPartLaunch.cpp
new file mode 100644
index 0000000000..642189d4ad
--- /dev/null
+++ b/archived/projt-launcher/launcher/minecraft/launch/LauncherPartLaunch.cpp
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: GPL-3.0-only
+// SPDX-FileCopyrightText: 2026 Project Tick
+// SPDX-FileContributor: Project Tick Team
+/*
+ * ProjT Launcher - Minecraft Launcher
+ * Copyright (C) 2026 Project Tick
+ *
+ * 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, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "LauncherPartLaunch.hpp"
+
+#include <QRegularExpression>
+#include <QStandardPaths>
+#include <QStringConverter>
+
+#include "Application.h"
+#include "Commandline.h"
+#include "FileSystem.h"
+#include "launch/LaunchPipeline.hpp"
+#include "minecraft/MinecraftInstance.h"
+
+#ifdef Q_OS_LINUX
+#include "gamemode_client.h"
+#endif
+
+LauncherPartLaunch::LauncherPartLaunch(projt::launch::LaunchPipeline* parent)
+ : projt::launch::LaunchStage(parent),
+ m_process(parent->instance()->getRuntimeVersion().defaultsToUtf8() ? QStringConverter::Utf8
+ : QStringConverter::System)
+{
+ if (parent->instance()->settings()->get("CloseAfterLaunch").toBool())
+ {
+ static const QRegularExpression s_settingUser(".*Setting user.+", QRegularExpression::CaseInsensitiveOption);
+ std::shared_ptr<QMetaObject::Connection> connection{ new QMetaObject::Connection };
+ *connection = connect(&m_process,
+ &LoggedProcess::log,
+ this,
+ [connection](const QStringList& lines, [[maybe_unused]] MessageLevel::Enum level)
+ {
+ qDebug() << lines;
+ if (lines.filter(s_settingUser).length() != 0)
+ {
+ APPLICATION->closeAllWindows();
+ disconnect(*connection);
+ }
+ });
+ }
+
+ connect(&m_process, &LoggedProcess::log, this, &LauncherPartLaunch::logLines);
+ connect(&m_process, &LoggedProcess::stateChanged, this, &LauncherPartLaunch::on_state);
+}
+
+void LauncherPartLaunch::executeTask()
+{
+ QString jarPath = APPLICATION->getJarPath("ProjTLaunch.jar");
+ if (jarPath.isEmpty())
+ {
+ const char* reason = QT_TR_NOOP("Launcher library could not be found. Please check your installation.");
+ emit logLine(tr(reason), MessageLevel::Fatal);
+ emitFailed(tr(reason));
+ return;
+ }
+
+ auto instance = m_flow->instance();
+
+ QString legacyJarPath;
+ if (instance->getLauncher() == "legacy" || instance->shouldApplyOnlineFixes())
+ {
+ legacyJarPath = APPLICATION->getJarPath("ProjTLaunchLegacy.jar");
+ if (legacyJarPath.isEmpty())
+ {
+ const char* reason =
+ QT_TR_NOOP("Legacy launcher library could not be found. Please check your installation.");
+ emit logLine(tr(reason), MessageLevel::Fatal);
+ emitFailed(tr(reason));
+ return;
+ }
+ }
+
+ m_launchScript = instance->createLaunchScript(m_session, m_targetToJoin);
+ QStringList args = instance->javaArguments();
+ QString allArgs = args.join(", ");
+ emit logLine("Java Arguments:\n[" + m_flow->censorPrivateInfo(allArgs) + "]\n\n", MessageLevel::Launcher);
+
+ auto javaPath = FS::ResolveExecutable(instance->settings()->get("JavaPath").toString());
+
+ m_process.setProcessEnvironment(instance->createLaunchEnvironment());
+
+ // make detachable - this will keep the process running even if the object is destroyed
+ m_process.setDetachable(true);
+
+ auto classPath = instance->getClassPath();
+ classPath.prepend(jarPath);
+
+ if (!legacyJarPath.isEmpty())
+ classPath.prepend(legacyJarPath);
+
+ auto natPath = instance->getNativePath();
+#ifdef Q_OS_WIN
+ natPath = FS::getPathNameInLocal8bit(natPath);
+#endif
+ args << "-Djava.library.path=" + natPath;
+
+ args << "-cp";
+#ifdef Q_OS_WIN
+ QStringList processed;
+ for (auto& item : classPath)
+ {
+ processed << FS::getPathNameInLocal8bit(item);
+ }
+ args << processed.join(';');
+#else
+ args << classPath.join(':');
+#endif
+ args << "org.projecttick.projtlauncher.normal.EntryPoint";
+
+ qDebug() << args.join(' ');
+
+ QString wrapperCommandStr = instance->getWrapperCommand().trimmed();
+ if (!wrapperCommandStr.isEmpty())
+ {
+ wrapperCommandStr = m_flow->substituteVariables(wrapperCommandStr);
+ auto wrapperArgs = Commandline::splitArgs(wrapperCommandStr);
+ auto wrapperCommand = wrapperArgs.takeFirst();
+ auto realWrapperCommand = QStandardPaths::findExecutable(wrapperCommand);
+ if (realWrapperCommand.isEmpty())
+ {
+ const char* reason = QT_TR_NOOP("The wrapper command \"%1\" couldn't be found.");
+ emit logLine(QString(reason).arg(wrapperCommand), MessageLevel::Fatal);
+ emitFailed(tr(reason).arg(wrapperCommand));
+ return;
+ }
+ emit logLine("Wrapper command is:\n" + wrapperCommandStr + "\n\n", MessageLevel::Launcher);
+ args.prepend(javaPath);
+ m_process.start(wrapperCommand, wrapperArgs + args);
+ }
+ else
+ {
+ m_process.start(javaPath, args);
+ }
+
+#ifdef Q_OS_LINUX
+ if (instance->settings()->get("EnableFeralGamemode").toBool()
+ && APPLICATION->capabilities() & Application::SupportsGameMode)
+ {
+ auto pid = m_process.processId();
+ if (pid)
+ {
+ gamemode_request_start_for(pid);
+ }
+ }
+#endif
+}
+
+void LauncherPartLaunch::on_state(LoggedProcess::State state)
+{
+ switch (state)
+ {
+ case LoggedProcess::FailedToStart:
+ {
+ //: Error message displayed if instace can't start
+ const char* reason = QT_TR_NOOP("Could not launch Minecraft!");
+ emit logLine(reason, MessageLevel::Fatal);
+ emitFailed(tr(reason));
+ return;
+ }
+ case LoggedProcess::Aborted:
+ case LoggedProcess::Crashed:
+ {
+ m_flow->setPid(-1);
+ m_flow->instance()->setMinecraftRunning(false);
+ emitFailed(tr("Game crashed."));
+ return;
+ }
+ case LoggedProcess::Finished:
+ {
+ auto instance = m_flow->instance();
+ if (instance->settings()->get("CloseAfterLaunch").toBool())
+ APPLICATION->showMainWindow();
+
+ m_flow->setPid(-1);
+ m_flow->instance()->setMinecraftRunning(false);
+ // if the exit code wasn't 0, report this as a crash
+ auto exitCode = m_process.exitCode();
+ if (exitCode != 0)
+ {
+ emitFailed(tr("Game crashed."));
+ return;
+ }
+
+ // Set exit code in environment for post-launch hooks
+ auto env = m_process.processEnvironment();
+ env.insert("INST_EXITCODE", QString::number(exitCode));
+ env.insert("INST_NAME", instance->name());
+ env.insert("INST_ID", instance->id());
+ env.insert("INST_DIR", instance->instanceRoot());
+ // Post-launch command can be retrieved from instance settings
+ QString postExitCmd = instance->settings()->get("PostExitCommand").toString();
+ if (!postExitCmd.isEmpty())
+ {
+ emit logLine(tr("Running post-exit command: %1").arg(postExitCmd), MessageLevel::Launcher);
+ QProcess postProcess;
+ postProcess.setProcessEnvironment(env);
+ postProcess.setWorkingDirectory(instance->instanceRoot());
+ postProcess.start(postExitCmd);
+ postProcess.waitForFinished(30000); // 30 second timeout
+ if (postProcess.exitCode() != 0)
+ {
+ emit logLine(tr("Post-exit command failed with code %1").arg(postProcess.exitCode()),
+ MessageLevel::Warning);
+ }
+ }
+
+ emitSucceeded();
+ break;
+ }
+ case LoggedProcess::Running:
+ emit logLine(QString("Minecraft process ID: %1\n\n").arg(m_process.processId()), MessageLevel::Launcher);
+ m_flow->setPid(m_process.processId());
+ // send the launch script to the launcher part
+ m_process.write(m_launchScript.toUtf8());
+
+ mayProceed = true;
+ emit readyForLaunch();
+ break;
+ default: break;
+ }
+}
+
+void LauncherPartLaunch::setWorkingDirectory(const QString& wd)
+{
+ m_process.setWorkingDirectory(wd);
+}
+
+void LauncherPartLaunch::proceed()
+{
+ if (mayProceed)
+ {
+ m_flow->instance()->setMinecraftRunning(true);
+ QString launchString("launch\n");
+ m_process.write(launchString.toUtf8());
+ mayProceed = false;
+ }
+}
+
+bool LauncherPartLaunch::abort()
+{
+ if (mayProceed)
+ {
+ mayProceed = false;
+ QString launchString("abort\n");
+ m_process.write(launchString.toUtf8());
+ }
+ else
+ {
+ auto state = m_process.state();
+ if (state == LoggedProcess::Running || state == LoggedProcess::Starting)
+ {
+ m_process.kill();
+ }
+ }
+ return true;
+}