From 8e7caf4e25dc3f56877a504c45d157860215496b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 10 Jul 2015 01:11:06 +0200 Subject: GH-1053 move launch related things and rename them --- application/ConsoleWindow.cpp | 8 +- application/ConsoleWindow.h | 6 +- application/LaunchInteraction.cpp | 2 +- application/LaunchInteraction.h | 2 +- application/MainWindow.cpp | 2 +- application/pages/LogPage.cpp | 4 +- application/pages/LogPage.h | 6 +- logic/BaseInstance.h | 4 +- logic/BaseLauncher.cpp | 641 ------------------------------------- logic/BaseLauncher.h | 178 ---------- logic/CMakeLists.txt | 14 +- logic/LoggedProcess.cpp | 147 --------- logic/LoggedProcess.h | 60 ---- logic/MessageLevel.cpp | 36 --- logic/MessageLevel.h | 28 -- logic/NullInstance.h | 2 +- logic/launch/LaunchTask.cpp | 641 +++++++++++++++++++++++++++++++++++++ logic/launch/LaunchTask.h | 178 ++++++++++ logic/launch/LoggedProcess.cpp | 147 +++++++++ logic/launch/LoggedProcess.h | 60 ++++ logic/launch/MessageLevel.cpp | 36 +++ logic/launch/MessageLevel.h | 28 ++ logic/minecraft/LegacyInstance.cpp | 6 +- logic/minecraft/LegacyInstance.h | 2 +- logic/minecraft/OneSixInstance.cpp | 6 +- logic/minecraft/OneSixInstance.h | 2 +- logic/tools/BaseProfiler.cpp | 2 +- logic/tools/BaseProfiler.h | 6 +- logic/tools/JProfiler.cpp | 6 +- logic/tools/JVisualVM.cpp | 6 +- 30 files changed, 1134 insertions(+), 1132 deletions(-) delete mode 100644 logic/BaseLauncher.cpp delete mode 100644 logic/BaseLauncher.h delete mode 100644 logic/LoggedProcess.cpp delete mode 100644 logic/LoggedProcess.h delete mode 100644 logic/MessageLevel.cpp delete mode 100644 logic/MessageLevel.h create mode 100644 logic/launch/LaunchTask.cpp create mode 100644 logic/launch/LaunchTask.h create mode 100644 logic/launch/LoggedProcess.cpp create mode 100644 logic/launch/LoggedProcess.h create mode 100644 logic/launch/MessageLevel.cpp create mode 100644 logic/launch/MessageLevel.h diff --git a/application/ConsoleWindow.cpp b/application/ConsoleWindow.cpp index 84140516..35bc9a8a 100644 --- a/application/ConsoleWindow.cpp +++ b/application/ConsoleWindow.cpp @@ -53,8 +53,8 @@ private: BasePage * m_log_page; }; -ConsoleWindow::ConsoleWindow(std::shared_ptr process, QWidget *parent) - : QMainWindow(parent), m_proc(process) +ConsoleWindow::ConsoleWindow(std::shared_ptr proc, QWidget *parent) + : QMainWindow(parent), m_proc(proc) { MultiMCPlatform::fixWM_CLASS(this); setAttribute(Qt::WA_DeleteOnClose); @@ -129,8 +129,8 @@ ConsoleWindow::ConsoleWindow(std::shared_ptr process, QWidget *par } // Set up signal connections - connect(m_proc.get(), &BaseLauncher::succeeded, this, &ConsoleWindow::onSucceeded); - connect(m_proc.get(), &BaseLauncher::failed, this, &ConsoleWindow::onFailed); + connect(m_proc.get(), &LaunchTask::succeeded, this, &ConsoleWindow::onSucceeded); + connect(m_proc.get(), &LaunchTask::failed, this, &ConsoleWindow::onFailed); setMayClose(false); diff --git a/application/ConsoleWindow.h b/application/ConsoleWindow.h index 228b58e9..f9e4c89e 100644 --- a/application/ConsoleWindow.h +++ b/application/ConsoleWindow.h @@ -17,7 +17,7 @@ #include #include -#include "BaseLauncher.h" +#include "launch/LaunchTask.h" class QPushButton; class PageContainer; @@ -26,7 +26,7 @@ class ConsoleWindow : public QMainWindow Q_OBJECT public: - explicit ConsoleWindow(std::shared_ptr proc, QWidget *parent = 0); + explicit ConsoleWindow(std::shared_ptr proc, QWidget *parent = 0); virtual ~ConsoleWindow(); /** @@ -56,7 +56,7 @@ protected: void closeEvent(QCloseEvent *); private: - std::shared_ptr m_proc; + std::shared_ptr m_proc; bool m_mayclose = true; QSystemTrayIcon *m_trayIcon = nullptr; PageContainer *m_container = nullptr; diff --git a/application/LaunchInteraction.cpp b/application/LaunchInteraction.cpp index ea966129..8ccc46a4 100644 --- a/application/LaunchInteraction.cpp +++ b/application/LaunchInteraction.cpp @@ -170,7 +170,7 @@ void LaunchController::launchInstance() m_console = new ConsoleWindow(m_launcher); connect(m_console, &ConsoleWindow::isClosing, this, &LaunchController::instanceEnded); - connect(m_launcher.get(), &BaseLauncher::readyForLaunch, this, &LaunchController::readyForLaunch); + connect(m_launcher.get(), &LaunchTask::readyForLaunch, this, &LaunchController::readyForLaunch); m_launcher->setHeader("MultiMC version: " + BuildConfig.printableVersionString() + "\n\n"); m_launcher->start(); diff --git a/application/LaunchInteraction.h b/application/LaunchInteraction.h index f62d5124..d64c3f6a 100644 --- a/application/LaunchInteraction.h +++ b/application/LaunchInteraction.h @@ -45,5 +45,5 @@ private: QWidget * m_parentWidget = nullptr; ConsoleWindow *m_console = nullptr; AuthSessionPtr m_session; - std::shared_ptr m_launcher; + std::shared_ptr m_launcher; }; diff --git a/application/MainWindow.cpp b/application/MainWindow.cpp index bd50e06d..0747e442 100644 --- a/application/MainWindow.cpp +++ b/application/MainWindow.cpp @@ -368,7 +368,7 @@ namespace Ui { #include "Env.h" #include "BaseInstance.h" -#include "BaseLauncher.h" +#include "launch/LaunchTask.h" #include "java/JavaUtils.h" #include "JavaCommon.h" #include "InstancePageProvider.h" diff --git a/application/pages/LogPage.cpp b/application/pages/LogPage.cpp index cdf6b345..77d5d6b8 100644 --- a/application/pages/LogPage.cpp +++ b/application/pages/LogPage.cpp @@ -7,11 +7,11 @@ #include #include -#include "BaseLauncher.h" +#include "launch/LaunchTask.h" #include #include "GuiUtil.h" -LogPage::LogPage(std::shared_ptr proc, QWidget *parent) +LogPage::LogPage(std::shared_ptr proc, QWidget *parent) : QWidget(parent), ui(new Ui::LogPage), m_process(proc) { ui->setupUi(this); diff --git a/application/pages/LogPage.h b/application/pages/LogPage.h index 0bd74846..f2cd90c3 100644 --- a/application/pages/LogPage.h +++ b/application/pages/LogPage.h @@ -18,7 +18,7 @@ #include #include "BaseInstance.h" -#include "BaseLauncher.h" +#include "launch/LaunchTask.h" #include "BasePage.h" #include @@ -33,7 +33,7 @@ class LogPage : public QWidget, public BasePage Q_OBJECT public: - explicit LogPage(std::shared_ptr proc, QWidget *parent = 0); + explicit LogPage(std::shared_ptr proc, QWidget *parent = 0); virtual ~LogPage(); virtual QString displayName() const override { @@ -77,7 +77,7 @@ private slots: private: Ui::LogPage *ui; - std::shared_ptr m_process; + std::shared_ptr m_process; int m_last_scroll_value = 0; bool m_scroll_active = true; int m_saved_offset = 0; diff --git a/logic/BaseInstance.h b/logic/BaseInstance.h index 720385c8..7152ba2d 100644 --- a/logic/BaseInstance.h +++ b/logic/BaseInstance.h @@ -27,7 +27,7 @@ class QDir; class Task; -class BaseLauncher; +class LaunchTask; class BaseInstance; // pointer for lazy people @@ -138,7 +138,7 @@ public: virtual std::shared_ptr createUpdateTask() = 0; /// returns a valid launcher (task container) - virtual std::shared_ptr createLaunchTask(AuthSessionPtr account) = 0; + virtual std::shared_ptr createLaunchTask(AuthSessionPtr account) = 0; /*! * Returns a task that should be done right before launch diff --git a/logic/BaseLauncher.cpp b/logic/BaseLauncher.cpp deleted file mode 100644 index 4ab0c41a..00000000 --- a/logic/BaseLauncher.cpp +++ /dev/null @@ -1,641 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Authors: Orochimarufan - * - * 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 "BaseLauncher.h" -#include "MessageLevel.h" -#include "MMCStrings.h" -#include "java/JavaChecker.h" -#include "tasks/Task.h" -#include -#include -#include -#include -#include -#include -#include - -#define IBUS "@im=ibus" - -void BaseLauncher::initializeEnvironment() -{ - // prepare the process environment - QProcessEnvironment rawenv = QProcessEnvironment::systemEnvironment(); - - QStringList ignored = - { - "JAVA_ARGS", - "CLASSPATH", - "CONFIGPATH", - "JAVA_HOME", - "JRE_HOME", - "_JAVA_OPTIONS", - "JAVA_OPTIONS", - "JAVA_TOOL_OPTIONS" - }; - for(auto key: rawenv.keys()) - { - auto value = rawenv.value(key); - // filter out dangerous java crap - if(ignored.contains(key)) - { - qDebug() << "Env: ignoring" << key << value; - continue; - } - // filter MultiMC-related things - if(key.startsWith("QT_")) - { - qDebug() << "Env: ignoring" << key << value; - continue; - } -#ifdef Q_OS_LINUX - // Do not pass LD_* variables to java. They were intended for MultiMC - if(key.startsWith("LD_")) - { - qDebug() << "Env: ignoring" << key << value; - continue; - } - // Strip IBus - // IBus is a Linux IME framework. For some reason, it breaks MC? - if (key == "XMODIFIERS" && value.contains(IBUS)) - { - QString save = value; - value.replace(IBUS, ""); - qDebug() << "Env: stripped" << IBUS << "from" << save << ":" << value; - } - if(key == "GAME_PRELOAD") - { - m_env.insert("LD_PRELOAD", value); - continue; - } - if(key == "GAME_LIBRARY_PATH") - { - m_env.insert("LD_LIBRARY_PATH", value); - continue; - } -#endif - qDebug() << "Env: " << key << value; - m_env.insert(key, value); - } -#ifdef Q_OS_LINUX - // HACK: Workaround for QTBUG42500 - if(!m_env.contains("LD_LIBRARY_PATH")) - { - m_env.insert("LD_LIBRARY_PATH", ""); - } -#endif - - // export some infos - auto variables = getVariables(); - for (auto it = variables.begin(); it != variables.end(); ++it) - { - m_env.insert(it.key(), it.value()); - } -} - -void BaseLauncher::init() -{ - initializeEnvironment(); - - m_process.setProcessEnvironment(m_env); - connect(&m_process, &LoggedProcess::log, this, &BaseLauncher::on_log); - connect(&m_process, &LoggedProcess::stateChanged, this, &BaseLauncher::on_state); - - m_prelaunchprocess.setProcessEnvironment(m_env); - connect(&m_prelaunchprocess, &LoggedProcess::log, this, &BaseLauncher::on_log); - connect(&m_prelaunchprocess, &LoggedProcess::stateChanged, this, &BaseLauncher::on_pre_state); - - m_postlaunchprocess.setProcessEnvironment(m_env); - connect(&m_postlaunchprocess, &LoggedProcess::log, this, &BaseLauncher::on_log); - connect(&m_postlaunchprocess, &LoggedProcess::stateChanged, this, &BaseLauncher::on_post_state); - - m_instance->setRunning(true); -} - -std::shared_ptr BaseLauncher::create(MinecraftInstancePtr inst) -{ - std::shared_ptr proc(new BaseLauncher(inst)); - proc->init(); - return proc; -} - -BaseLauncher::BaseLauncher(InstancePtr instance): m_instance(instance) -{ -} - -QString BaseLauncher::censorPrivateInfo(QString in) -{ - if (!m_session) - return in; - - if (m_session->session != "-") - in.replace(m_session->session, ""); - in.replace(m_session->access_token, ""); - in.replace(m_session->client_token, ""); - in.replace(m_session->uuid, ""); - in.replace(m_session->player_name, ""); - - auto i = m_session->u.properties.begin(); - while (i != m_session->u.properties.end()) - { - in.replace(i.value(), "<" + i.key().toUpper() + ">"); - ++i; - } - - return in; -} - -// console window -MessageLevel::Enum BaseLauncher::guessLevel(const QString &line, MessageLevel::Enum level) -{ - QRegularExpression re("\\[(?[0-9:]+)\\] \\[[^/]+/(?[^\\]]+)\\]"); - auto match = re.match(line); - if(match.hasMatch()) - { - // New style logs from log4j - QString timestamp = match.captured("timestamp"); - QString levelStr = match.captured("level"); - if(levelStr == "INFO") - level = MessageLevel::Message; - if(levelStr == "WARN") - level = MessageLevel::Warning; - if(levelStr == "ERROR") - level = MessageLevel::Error; - if(levelStr == "FATAL") - level = MessageLevel::Fatal; - if(levelStr == "TRACE" || levelStr == "DEBUG") - level = MessageLevel::Debug; - } - else - { - // Old style forge logs - if (line.contains("[INFO]") || line.contains("[CONFIG]") || line.contains("[FINE]") || - line.contains("[FINER]") || line.contains("[FINEST]")) - level = MessageLevel::Message; - if (line.contains("[SEVERE]") || line.contains("[STDERR]")) - level = MessageLevel::Error; - if (line.contains("[WARNING]")) - level = MessageLevel::Warning; - if (line.contains("[DEBUG]")) - level = MessageLevel::Debug; - } - if (line.contains("overwriting existing")) - return MessageLevel::Fatal; - if (line.contains("Exception in thread") || line.contains(QRegularExpression("\\s+at "))) - return MessageLevel::Error; - return level; -} - -QMap BaseLauncher::getVariables() const -{ - auto mcInstance = std::dynamic_pointer_cast(m_instance); - QMap out; - out.insert("INST_NAME", mcInstance->name()); - out.insert("INST_ID", mcInstance->id()); - out.insert("INST_DIR", QDir(mcInstance->instanceRoot()).absolutePath()); - out.insert("INST_MC_DIR", QDir(mcInstance->minecraftRoot()).absolutePath()); - out.insert("INST_JAVA", mcInstance->settings()->get("JavaPath").toString()); - out.insert("INST_JAVA_ARGS", javaArguments().join(' ')); - return out; -} - -QStringList BaseLauncher::javaArguments() const -{ - QStringList args; - - // custom args go first. we want to override them if we have our own here. - args.append(m_instance->extraArguments()); - - // OSX dock icon and name -#ifdef Q_OS_MAC - args << "-Xdock:icon=icon.png"; - args << QString("-Xdock:name=\"%1\"").arg(m_instance->windowTitle()); -#endif - - // HACK: Stupid hack for Intel drivers. See: https://mojang.atlassian.net/browse/MCL-767 -#ifdef Q_OS_WIN32 - args << QString("-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_" - "minecraft.exe.heapdump"); -#endif - - args << QString("-Xms%1m").arg(m_instance->settings()->get("MinMemAlloc").toInt()); - args << QString("-Xmx%1m").arg(m_instance->settings()->get("MaxMemAlloc").toInt()); - - // No PermGen in newer java. - auto javaVersion = m_instance->settings()->get("JavaVersion"); - if(Strings::naturalCompare(javaVersion.toString(), "1.8.0", Qt::CaseInsensitive) < 0) - { - auto permgen = m_instance->settings()->get("PermGen").toInt(); - if (permgen != 64) - { - args << QString("-XX:PermSize=%1m").arg(permgen); - } - } - - args << "-Duser.language=en"; - if (!m_nativeFolder.isEmpty()) - args << QString("-Djava.library.path=%1").arg(m_nativeFolder); - args << "-jar" << PathCombine(QCoreApplication::applicationDirPath(), "jars", "NewLaunch.jar"); - - return args; -} - -void BaseLauncher::checkJava() -{ - m_javaPath = m_instance->settings()->get("JavaPath").toString(); - emit log("Java path is:\n" + m_javaPath + "\n\n"); - - auto realJavaPath = QStandardPaths::findExecutable(m_javaPath); - if (realJavaPath.isEmpty()) - { - emit log(tr("The java binary \"%1\" couldn't be found. You may have to set up java " - "if Minecraft fails to launch.").arg(m_javaPath), - MessageLevel::Warning); - } - - QFileInfo javaInfo(realJavaPath); - qlonglong javaUnixTime = javaInfo.lastModified().toMSecsSinceEpoch(); - auto storedUnixTime = m_instance->settings()->get("JavaTimestamp").toLongLong(); - this->m_javaUnixTime = javaUnixTime; - // if they are not the same, check! - if(javaUnixTime != storedUnixTime) - { - m_JavaChecker = std::make_shared(); - bool successful = false; - QString errorLog; - QString version; - emit log(tr("Checking Java version..."), MessageLevel::MultiMC); - connect(m_JavaChecker.get(), &JavaChecker::checkFinished, this, &BaseLauncher::checkJavaFinished); - m_JavaChecker->m_path = realJavaPath; - m_JavaChecker->performCheck(); - } - preLaunch(); -} - -void BaseLauncher::checkJavaFinished(JavaCheckResult result) -{ - if(!result.valid) - { - // Error message displayed if java can't start - emit log(tr("Could not start java:"), MessageLevel::Error); - auto lines = result.errorLog.split('\n'); - for(auto line: lines) - { - emit log(line, MessageLevel::Error); - } - emit log("\nCheck your MultiMC Java settings.", MessageLevel::MultiMC); - emitFailed(tr("Could not start java!")); - } - else - { - emit log(tr("Java version is %1!\n").arg(result.javaVersion), MessageLevel::MultiMC); - m_instance->settings()->set("JavaVersion", result.javaVersion); - m_instance->settings()->set("JavaTimestamp", m_javaUnixTime); - preLaunch(); - } -} - -void BaseLauncher::executeTask() -{ - printHeader(); - emit log("Minecraft folder is:\n" + m_process.workingDirectory() + "\n\n"); - - checkJava(); -} - -void BaseLauncher::launch() -{ - QString launchString("launch\n"); - m_process.write(launchString.toUtf8()); -} - -void BaseLauncher::abort() -{ - QString launchString("abort\n"); - m_process.write(launchString.toUtf8()); -} - - -void BaseLauncher::setWorkdir(QString path) -{ - QDir mcDir(path); - m_process.setWorkingDirectory(mcDir.absolutePath()); - m_prelaunchprocess.setWorkingDirectory(mcDir.absolutePath()); - m_postlaunchprocess.setWorkingDirectory(mcDir.absolutePath()); -} - -void BaseLauncher::printHeader() -{ - emit log(m_header); -} - -void BaseLauncher::on_log(QStringList lines, MessageLevel::Enum level) -{ - logOutput(lines, level); -} - -void BaseLauncher::logOutput(const QStringList &lines, MessageLevel::Enum defaultLevel) -{ - for (auto & line: lines) - { - logOutput(line, defaultLevel); - } -} - -void BaseLauncher::logOutput(QString line, MessageLevel::Enum level) -{ - // if the launcher part set a log level, use it - auto innerLevel = MessageLevel::fromLine(line); - if(innerLevel != MessageLevel::Unknown) - { - level = innerLevel; - } - - // If the level is still undetermined, guess level - if (level == MessageLevel::StdErr || level == MessageLevel::StdOut || level == MessageLevel::Unknown) - { - level = this->guessLevel(line, level); - } - - // censor private user info - line = censorPrivateInfo(line); - - emit log(line, level); -} - -void BaseLauncher::preLaunch() -{ - QString prelaunch_cmd = m_instance->settings()->get("PreLaunchCommand").toString(); - if (!prelaunch_cmd.isEmpty()) - { - prelaunch_cmd = substituteVariables(prelaunch_cmd); - // Launch - emit log(tr("Running Pre-Launch command: %1").arg(prelaunch_cmd)); - m_prelaunchprocess.start(prelaunch_cmd); - } - else - { - on_pre_state(LoggedProcess::Skipped); - } -} - -void BaseLauncher::on_pre_state(LoggedProcess::State state) -{ - switch(state) - { - case LoggedProcess::Aborted: - case LoggedProcess::Crashed: - case LoggedProcess::FailedToStart: - { - QString error = tr("Pre-Launch command failed with code %1.\n\n").arg(m_prelaunchprocess.exitCode()); - emit log(error, MessageLevel::Fatal); - emitFailed(error); - return; - } - case LoggedProcess::Finished: - { - emit log(tr("Pre-Launch command ran successfully.\n\n")); - } - case LoggedProcess::Skipped: - { - m_instance->reload(); - updateInstance(); - } - default: - break; - } -} - -void BaseLauncher::updateInstance() -{ - m_updateTask = m_instance->createUpdateTask(); - if(m_updateTask) - { - connect(m_updateTask.get(), SIGNAL(finished()), this, SLOT(updateFinished())); - m_updateTask->start(); - return; - } - makeReady(); -} - -void BaseLauncher::updateFinished() -{ - if(m_updateTask->successful()) - { - doJarModding(); - } - else - { - QString reason = tr("Instance update failed because: %1.\n\n").arg(m_updateTask->failReason()); - emit log(reason, MessageLevel::Fatal); - emitFailed(reason); - } -} - -void BaseLauncher::doJarModding() -{ - m_jarModTask = m_instance->createJarModdingTask(); - if(!m_jarModTask) - { - jarModdingSucceeded(); - } - connect(m_jarModTask.get(), SIGNAL(succeeded()), this, SLOT(jarModdingSucceeded())); - connect(m_jarModTask.get(), SIGNAL(failed(QString)), this, SLOT(jarModdingFailed(QString))); - m_jarModTask->start(); -} - -void BaseLauncher::jarModdingSucceeded() -{ - makeReady(); -} - -void BaseLauncher::jarModdingFailed(QString reason) -{ - emitFailed(reason); -} - -void BaseLauncher::makeReady() -{ - QStringList args = javaArguments(); - QString allArgs = args.join(", "); - emit log("Java Arguments:\n[" + censorPrivateInfo(allArgs) + "]\n\n"); - - QString wrapperCommand = m_instance->settings()->get("WrapperCommand").toString(); - if(!wrapperCommand.isEmpty()) - { - auto realWrapperCommand = QStandardPaths::findExecutable(wrapperCommand); - if (realWrapperCommand.isEmpty()) - { - QString reason = tr("The wrapper command \"%1\" couldn't be found.").arg(wrapperCommand); - emit log(reason, MessageLevel::Fatal); - emitFailed(reason); - return; - } - emit log("Wrapper command is:\n" + wrapperCommand + "\n\n"); - args.prepend(m_javaPath); - m_process.start(wrapperCommand, args); - } - else - { - m_process.start(m_javaPath, args); - } - - // instantiate the launcher part - if (!m_process.waitForStarted()) - { - //: Error message displayed if instace can't start - QString reason = tr("Could not launch minecraft!"); - emit log(reason, MessageLevel::Fatal); - emitFailed(reason); - return; - } - - emit log(tr("Minecraft process ID: %1\n\n").arg(m_process.processId()), MessageLevel::MultiMC); - - // send the launch script to the launcher part - m_process.write(launchScript.toUtf8()); - - emit readyForLaunch(); -} - -void BaseLauncher::on_state(LoggedProcess::State state) -{ - QProcess::ExitStatus estat = QProcess::NormalExit; - switch(state) - { - case LoggedProcess::Aborted: - case LoggedProcess::Crashed: - case LoggedProcess::FailedToStart: - { - estat = QProcess::CrashExit; - emitFailed("Game crashed."); - return; - } - case LoggedProcess::Finished: - { - auto exitCode = m_process.exitCode(); - m_postlaunchprocess.processEnvironment().insert("INST_EXITCODE", QString(exitCode)); - // run post-exit - postLaunch(); - break; - } - case LoggedProcess::Skipped: - qWarning() << "Illegal game state: Skipped"; - break; - case LoggedProcess::Running: - m_instance->setLastLaunch(); - break; - default: - break; - } -} - -void BaseLauncher::killProcess() -{ - killed = true; - if (m_prelaunchprocess.state() == LoggedProcess::Running) - { - m_prelaunchprocess.kill(); - } - else if(m_process.state() == LoggedProcess::Running) - { - m_process.kill(); - } - else if(m_postlaunchprocess.state() == LoggedProcess::Running) - { - m_postlaunchprocess.kill(); - } -} - -void BaseLauncher::postLaunch() -{ - if(killed) - return; - QString postlaunch_cmd = m_instance->settings()->get("PostExitCommand").toString(); - if (!postlaunch_cmd.isEmpty()) - { - postlaunch_cmd = substituteVariables(postlaunch_cmd); - emit log(tr("Running Post-Launch command: %1").arg(postlaunch_cmd)); - m_postlaunchprocess.start(postlaunch_cmd); - return; - } - emitSucceeded(); -} - -void BaseLauncher::on_post_state(LoggedProcess::State state) -{ - switch(state) - { - case LoggedProcess::Aborted: - case LoggedProcess::Crashed: - case LoggedProcess::FailedToStart: - { - QString error = tr("Post-Launch command failed with code %1.\n\n").arg(m_postlaunchprocess.exitCode()); - emit log(error, MessageLevel::Error); - emitFailed(error); - } - case LoggedProcess::Finished: - { - emit log(tr("Post-Launch command ran successfully.\n\n")); - } - case LoggedProcess::Skipped: - { - emitSucceeded(); - } - default: - break; - } -} - -void BaseLauncher::emitSucceeded() -{ - m_instance->cleanupAfterRun(); - m_instance->setRunning(false); - Task::emitSucceeded(); -} - -void BaseLauncher::emitFailed(QString reason) -{ - m_instance->cleanupAfterRun(); - m_instance->setRunning(false); - Task::emitFailed(reason); -} - -QString BaseLauncher::substituteVariables(const QString &cmd) const -{ - QString out = cmd; - auto variables = getVariables(); - for (auto it = variables.begin(); it != variables.end(); ++it) - { - out.replace("$" + it.key(), it.value()); - } - auto env = QProcessEnvironment::systemEnvironment(); - for (auto var : env.keys()) - { - out.replace("$" + var, env.value(var)); - } - return out; -} - -qint64 BaseLauncher::pid() -{ -#ifdef Q_OS_WIN - struct _PROCESS_INFORMATION *procinfo = m_process.pid(); - return procinfo->dwProcessId; -#else - return m_process.pid(); -#endif -} diff --git a/logic/BaseLauncher.h b/logic/BaseLauncher.h deleted file mode 100644 index f7b52c89..00000000 --- a/logic/BaseLauncher.h +++ /dev/null @@ -1,178 +0,0 @@ -/* Copyright 2013-2015 MultiMC Contributors - * - * Authors: Orochimarufan - * - * 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 "BaseInstance.h" -#include "MessageLevel.h" -#include "LoggedProcess.h" -/* HACK: MINECRAFT: split! */ -#include "minecraft/MinecraftInstance.h" -#include "java/JavaChecker.h" -#include "QObjectPtr.h" -#include "tasks/Task.h" - -class ProcessTask -{ - -}; - -class BaseProfilerFactory; -class BaseLauncher: public Task -{ - Q_OBJECT -protected: - explicit BaseLauncher(InstancePtr instance); - void init(); - -public: /* methods */ - static std::shared_ptr create(MinecraftInstancePtr inst); - virtual ~BaseLauncher() {}; - - InstancePtr instance() - { - return m_instance; - } - - /// Set the text printed on top of the log - void setHeader(QString header) - { - m_header = header; - } - - void setWorkdir(QString path); - - void killProcess(); - - qint64 pid(); - - /** - * @brief prepare the process for launch (for multi-stage launch) - */ - virtual void executeTask() override; - - /** - * @brief launch the armed instance - */ - virtual void launch(); - - /** - * @brief abort launch - */ - virtual void abort(); - -public: /* HACK: MINECRAFT: split! */ - void setLaunchScript(QString script) - { - launchScript = script; - } - - void setNativeFolder(QString natives) - { - m_nativeFolder = natives; - } - - inline void setLogin(AuthSessionPtr session) - { - m_session = session; - } - - -protected: /* methods */ - void preLaunch(); - void updateInstance(); - void doJarModding(); - void makeReady(); - void postLaunch(); - virtual void emitFailed(QString reason); - virtual void emitSucceeded(); - QString substituteVariables(const QString &cmd) const; - void initializeEnvironment(); - - void printHeader(); - - virtual QMap getVariables() const; - virtual QString censorPrivateInfo(QString in); - virtual MessageLevel::Enum guessLevel(const QString &message, MessageLevel::Enum defaultLevel); - -protected slots: - void jarModdingSucceeded(); - void jarModdingFailed(QString reason); - -signals: - /** - * @brief emitted when the launch preparations are done - */ - void readyForLaunch(); - - /** - * @brief emitted when we want to log something - * @param text the text to log - * @param level the level to log at - */ - void log(QString text, MessageLevel::Enum level = MessageLevel::MultiMC); - -protected slots: - void on_log(QStringList lines, MessageLevel::Enum level); - void logOutput(const QStringList& lines, MessageLevel::Enum defaultLevel = MessageLevel::Message); - void logOutput(QString line, MessageLevel::Enum defaultLevel = MessageLevel::Message); - - void on_pre_state(LoggedProcess::State state); - void on_state(LoggedProcess::State state); - void on_post_state(LoggedProcess::State state); - - - -protected: - InstancePtr m_instance; - - LoggedProcess m_prelaunchprocess; - LoggedProcess m_postlaunchprocess; - LoggedProcess m_process; - QProcessEnvironment m_env; - BaseProfilerFactory * m_profiler = nullptr; - - bool killed = false; - QString m_header; - -/** - * java check step - */ -protected slots: - void checkJavaFinished(JavaCheckResult result); - -protected: - // for java checker and launch - QString m_javaPath; - qlonglong m_javaUnixTime; - std::shared_ptr m_JavaChecker; - -protected: /* HACK: MINECRAFT: split! */ - AuthSessionPtr m_session; - QString launchScript; - QString m_nativeFolder; - std::shared_ptr m_updateTask; - std::shared_ptr m_jarModTask; - -protected: /* HACK: MINECRAFT: split! */ - void checkJava(); - QStringList javaArguments() const; -private slots: - void updateFinished(); -}; - -class BaseProfilerFactory; \ No newline at end of file diff --git a/logic/CMakeLists.txt b/logic/CMakeLists.txt index 3286b091..53715fa6 100644 --- a/logic/CMakeLists.txt +++ b/logic/CMakeLists.txt @@ -8,13 +8,7 @@ set(LOGIC_SOURCES BaseVersionList.cpp InstanceList.h InstanceList.cpp - LoggedProcess.h - LoggedProcess.cpp - MessageLevel.cpp - MessageLevel.h BaseVersion.h - BaseLauncher.h - BaseLauncher.cpp BaseInstance.h BaseInstance.cpp NullInstance.h @@ -98,6 +92,14 @@ set(LOGIC_SOURCES auth/flows/ValidateTask.h auth/flows/ValidateTask.cpp + # Game launch logic + launch/LoggedProcess.h + launch/LoggedProcess.cpp + launch/MessageLevel.cpp + launch/MessageLevel.h + launch/LaunchTask.h + launch/LaunchTask.cpp + # Update system updater/GoUpdate.h updater/GoUpdate.cpp diff --git a/logic/LoggedProcess.cpp b/logic/LoggedProcess.cpp deleted file mode 100644 index 53840621..00000000 --- a/logic/LoggedProcess.cpp +++ /dev/null @@ -1,147 +0,0 @@ -#include "LoggedProcess.h" -#include "MessageLevel.h" -#include - -LoggedProcess::LoggedProcess(QObject *parent) : QProcess(parent) -{ - // QProcess has a strange interface... let's map a lot of those into a few. - connect(this, &QProcess::readyReadStandardOutput, this, &LoggedProcess::on_stdOut); - connect(this, &QProcess::readyReadStandardError, this, &LoggedProcess::on_stdErr); - connect(this, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(on_exit(int,QProcess::ExitStatus))); - connect(this, SIGNAL(error(QProcess::ProcessError)), this, SLOT(on_error(QProcess::ProcessError))); - connect(this, &QProcess::stateChanged, this, &LoggedProcess::on_stateChange); -} - -QStringList reprocess(const QByteArray & data, QString & leftover) -{ - QString str = leftover + QString::fromLocal8Bit(data); - - str.remove('\r'); - QStringList lines = str.split("\n"); - leftover = lines.takeLast(); - return lines; -} - -void LoggedProcess::on_stdErr() -{ - auto lines = reprocess(readAllStandardError(), m_err_leftover); - emit log(lines, MessageLevel::StdErr); -} - -void LoggedProcess::on_stdOut() -{ - auto lines = reprocess(readAllStandardOutput(), m_out_leftover); - emit log(lines, MessageLevel::StdOut); -} - -void LoggedProcess::on_exit(int exit_code, QProcess::ExitStatus status) -{ - // Flush console window - if (!m_err_leftover.isEmpty()) - { - emit log({m_err_leftover}, MessageLevel::StdErr); - m_err_leftover.clear(); - } - if (!m_out_leftover.isEmpty()) - { - emit log({m_err_leftover}, MessageLevel::StdOut); - m_out_leftover.clear(); - } - - // based on state, send signals - if (!m_is_aborting) - { - if (status == QProcess::NormalExit) - { - //: Message displayed on instance exit - emit log({tr("Process exited with code %1.").arg(exit_code)}, MessageLevel::MultiMC); - changeState(LoggedProcess::Finished); - } - else - { - //: Message displayed on instance crashed - if(exit_code == -1) - emit log({tr("Process crashed.").arg(exit_code)}, MessageLevel::MultiMC); - else - emit log({tr("Process crashed with exitcode %1.").arg(exit_code)}, MessageLevel::MultiMC); - changeState(LoggedProcess::Crashed); - } - } - else - { - //: Message displayed after the instance exits due to kill request - emit log({tr("Process was killed by user.")}, MessageLevel::Error); - changeState(LoggedProcess::Aborted); - } -} - -void LoggedProcess::on_error(QProcess::ProcessError error) -{ - switch(error) - { - case QProcess::FailedToStart: - { - emit log({tr("The process failed to start.")}, MessageLevel::Fatal); - changeState(LoggedProcess::FailedToStart); - break; - } - // we'll just ignore those... never needed them - case QProcess::Crashed: - case QProcess::ReadError: - case QProcess::Timedout: - case QProcess::UnknownError: - case QProcess::WriteError: - break; - } -} - -void LoggedProcess::kill() -{ - m_is_aborting = true; - QProcess::kill(); -} - -int LoggedProcess::exitCode() const -{ - return m_exit_code; -} - -void LoggedProcess::changeState(LoggedProcess::State state) -{ - if(state == m_state) - return; - m_state = state; - emit stateChanged(m_state); -} - -LoggedProcess::State LoggedProcess::state() const -{ - return m_state; -} - -void LoggedProcess::on_stateChange(QProcess::ProcessState state) -{ - switch(state) - { - case QProcess::NotRunning: - break; // let's not - there are too many that handle this already. - case QProcess::Starting: - { - if(m_state != LoggedProcess::NotRunning) - { - qWarning() << "Wrong state change for process from state" << m_state << "to" << (int) LoggedProcess::Starting; - } - changeState(LoggedProcess::Starting); - return; - } - case QProcess::Running: - { - if(m_state != LoggedProcess::Starting) - { - qWarning() << "Wrong state change for process from state" << m_state << "to" << (int) LoggedProcess::Running; - } - changeState(LoggedProcess::Running); - return; - } - } -} diff --git a/logic/LoggedProcess.h b/logic/LoggedProcess.h deleted file mode 100644 index 253be2c1..00000000 --- a/logic/LoggedProcess.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once -#include -#include "MessageLevel.h" - -/* - * This is a basic process. - * It has line-based logging support and hides some of the nasty bits. - */ -class LoggedProcess : public QProcess -{ -Q_OBJECT -public: - enum State - { - NotRunning, - Starting, - FailedToStart, - Running, - Finished, - Crashed, - Aborted, - Skipped - }; - -public: - explicit LoggedProcess(QObject* parent = 0); - virtual ~LoggedProcess() {}; - - State state() const; - int exitCode() const; - -signals: - void log(QStringList lines, MessageLevel::Enum level); - void stateChanged(LoggedProcess::State state); - -public slots: - /** - * @brief kill the process - equivalent to kill -9 - */ - void kill(); - - -private slots: - void on_stdErr(); - void on_stdOut(); - void on_exit(int exit_code, QProcess::ExitStatus status); - void on_error(QProcess::ProcessError error); - void on_stateChange(QProcess::ProcessState); - -private: - void changeState(LoggedProcess::State state); - -private: - QString m_err_leftover; - QString m_out_leftover; - bool m_killed = false; - State m_state = NotRunning; - int m_exit_code = 0; - bool m_is_aborting = false; -}; diff --git a/logic/MessageLevel.cpp b/logic/MessageLevel.cpp deleted file mode 100644 index a5191290..00000000 --- a/logic/MessageLevel.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "MessageLevel.h" - -MessageLevel::Enum MessageLevel::getLevel(const QString& levelName) -{ - if (levelName == "MultiMC") - return MessageLevel::MultiMC; - else if (levelName == "Debug") - return MessageLevel::Debug; - else if (levelName == "Info") - return MessageLevel::Info; - else if (levelName == "Message") - return MessageLevel::Message; - else if (levelName == "Warning") - return MessageLevel::Warning; - else if (levelName == "Error") - return MessageLevel::Error; - else if (levelName == "Fatal") - return MessageLevel::Fatal; - // Skip PrePost, it's not exposed to !![]! - // Also skip StdErr and StdOut - else - return MessageLevel::Unknown; -} - -MessageLevel::Enum MessageLevel::fromLine(QString &line) -{ - // Level prefix - int endmark = line.indexOf("]!"); - if (line.startsWith("!![") && endmark != -1) - { - auto level = MessageLevel::getLevel(line.left(endmark).mid(3)); - line = line.mid(endmark + 2); - return level; - } - return MessageLevel::Unknown; -} diff --git a/logic/MessageLevel.h b/logic/MessageLevel.h deleted file mode 100644 index 0128148d..00000000 --- a/logic/MessageLevel.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include - -/** - * @brief the MessageLevel Enum - * defines what level a log message is - */ -namespace MessageLevel -{ -enum Enum -{ - Unknown, /**< No idea what this is or where it came from */ - StdOut, /**< Undetermined stderr messages */ - StdErr, /**< Undetermined stdout messages */ - MultiMC, /**< MultiMC Messages */ - Debug, /**< Debug Messages */ - Info, /**< Info Messages */ - Message, /**< Standard Messages */ - Warning, /**< Warnings */ - Error, /**< Errors */ - Fatal, /**< Fatal Errors */ -}; -MessageLevel::Enum getLevel(const QString &levelName); - -/* Get message level from a line. Line is modified if it was successful. */ -MessageLevel::Enum fromLine(QString &line); -} diff --git a/logic/NullInstance.h b/logic/NullInstance.h index 0927322e..bad4b4de 100644 --- a/logic/NullInstance.h +++ b/logic/NullInstance.h @@ -43,7 +43,7 @@ public: { return instanceRoot(); }; - virtual std::shared_ptr createLaunchTask(AuthSessionPtr) + virtual std::shared_ptr createLaunchTask(AuthSessionPtr) { return nullptr; } diff --git a/logic/launch/LaunchTask.cpp b/logic/launch/LaunchTask.cpp new file mode 100644 index 00000000..83bbba97 --- /dev/null +++ b/logic/launch/LaunchTask.cpp @@ -0,0 +1,641 @@ +/* Copyright 2013-2015 MultiMC Contributors + * + * Authors: Orochimarufan + * + * 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 "launch/LaunchTask.h" +#include "MessageLevel.h" +#include "MMCStrings.h" +#include "java/JavaChecker.h" +#include "tasks/Task.h" +#include +#include +#include +#include +#include +#include +#include + +#define IBUS "@im=ibus" + +void LaunchTask::initializeEnvironment() +{ + // prepare the process environment + QProcessEnvironment rawenv = QProcessEnvironment::systemEnvironment(); + + QStringList ignored = + { + "JAVA_ARGS", + "CLASSPATH", + "CONFIGPATH", + "JAVA_HOME", + "JRE_HOME", + "_JAVA_OPTIONS", + "JAVA_OPTIONS", + "JAVA_TOOL_OPTIONS" + }; + for(auto key: rawenv.keys()) + { + auto value = rawenv.value(key); + // filter out dangerous java crap + if(ignored.contains(key)) + { + qDebug() << "Env: ignoring" << key << value; + continue; + } + // filter MultiMC-related things + if(key.startsWith("QT_")) + { + qDebug() << "Env: ignoring" << key << value; + continue; + } +#ifdef Q_OS_LINUX + // Do not pass LD_* variables to java. They were intended for MultiMC + if(key.startsWith("LD_")) + { + qDebug() << "Env: ignoring" << key << value; + continue; + } + // Strip IBus + // IBus is a Linux IME framework. For some reason, it breaks MC? + if (key == "XMODIFIERS" && value.contains(IBUS)) + { + QString save = value; + value.replace(IBUS, ""); + qDebug() << "Env: stripped" << IBUS << "from" << save << ":" << value; + } + if(key == "GAME_PRELOAD") + { + m_env.insert("LD_PRELOAD", value); + continue; + } + if(key == "GAME_LIBRARY_PATH") + { + m_env.insert("LD_LIBRARY_PATH", value); + continue; + } +#endif + qDebug() << "Env: " << key << value; + m_env.insert(key, value); + } +#ifdef Q_OS_LINUX + // HACK: Workaround for QTBUG42500 + if(!m_env.contains("LD_LIBRARY_PATH")) + { + m_env.insert("LD_LIBRARY_PATH", ""); + } +#endif + + // export some infos + auto variables = getVariables(); + for (auto it = variables.begin(); it != variables.end(); ++it) + { + m_env.insert(it.key(), it.value()); + } +} + +void LaunchTask::init() +{ + initializeEnvironment(); + + m_process.setProcessEnvironment(m_env); + connect(&m_process, &LoggedProcess::log, this, &LaunchTask::on_log); + connect(&m_process, &LoggedProcess::stateChanged, this, &LaunchTask::on_state); + + m_prelaunchprocess.setProcessEnvironment(m_env); + connect(&m_prelaunchprocess, &LoggedProcess::log, this, &LaunchTask::on_log); + connect(&m_prelaunchprocess, &LoggedProcess::stateChanged, this, &LaunchTask::on_pre_state); + + m_postlaunchprocess.setProcessEnvironment(m_env); + connect(&m_postlaunchprocess, &LoggedProcess::log, this, &LaunchTask::on_log); + connect(&m_postlaunchprocess, &LoggedProcess::stateChanged, this, &LaunchTask::on_post_state); + + m_instance->setRunning(true); +} + +std::shared_ptr LaunchTask::create(MinecraftInstancePtr inst) +{ + std::shared_ptr proc(new LaunchTask(inst)); + proc->init(); + return proc; +} + +LaunchTask::LaunchTask(InstancePtr instance): m_instance(instance) +{ +} + +QString LaunchTask::censorPrivateInfo(QString in) +{ + if (!m_session) + return in; + + if (m_session->session != "-") + in.replace(m_session->session, ""); + in.replace(m_session->access_token, ""); + in.replace(m_session->client_token, ""); + in.replace(m_session->uuid, ""); + in.replace(m_session->player_name, ""); + + auto i = m_session->u.properties.begin(); + while (i != m_session->u.properties.end()) + { + in.replace(i.value(), "<" + i.key().toUpper() + ">"); + ++i; + } + + return in; +} + +// console window +MessageLevel::Enum LaunchTask::guessLevel(const QString &line, MessageLevel::Enum level) +{ + QRegularExpression re("\\[(?[0-9:]+)\\] \\[[^/]+/(?[^\\]]+)\\]"); + auto match = re.match(line); + if(match.hasMatch()) + { + // New style logs from log4j + QString timestamp = match.captured("timestamp"); + QString levelStr = match.captured("level"); + if(levelStr == "INFO") + level = MessageLevel::Message; + if(levelStr == "WARN") + level = MessageLevel::Warning; + if(levelStr == "ERROR") + level = MessageLevel::Error; + if(levelStr == "FATAL") + level = MessageLevel::Fatal; + if(levelStr == "TRACE" || levelStr == "DEBUG") + level = MessageLevel::Debug; + } + else + { + // Old style forge logs + if (line.contains("[INFO]") || line.contains("[CONFIG]") || line.contains("[FINE]") || + line.contains("[FINER]") || line.contains("[FINEST]")) + level = MessageLevel::Message; + if (line.contains("[SEVERE]") || line.contains("[STDERR]")) + level = MessageLevel::Error; + if (line.contains("[WARNING]")) + level = MessageLevel::Warning; + if (line.contains("[DEBUG]")) + level = MessageLevel::Debug; + } + if (line.contains("overwriting existing")) + return MessageLevel::Fatal; + if (line.contains("Exception in thread") || line.contains(QRegularExpression("\\s+at "))) + return MessageLevel::Error; + return level; +} + +QMap LaunchTask::getVariables() const +{ + auto mcInstance = std::dynamic_pointer_cast(m_instance); + QMap out; + out.insert("INST_NAME", mcInstance->name()); + out.insert("INST_ID", mcInstance->id()); + out.insert("INST_DIR", QDir(mcInstance->instanceRoot()).absolutePath()); + out.insert("INST_MC_DIR", QDir(mcInstance->minecraftRoot()).absolutePath()); + out.insert("INST_JAVA", mcInstance->settings()->get("JavaPath").toString()); + out.insert("INST_JAVA_ARGS", javaArguments().join(' ')); + return out; +} + +QStringList LaunchTask::javaArguments() const +{ + QStringList args; + + // custom args go first. we want to override them if we have our own here. + args.append(m_instance->extraArguments()); + + // OSX dock icon and name +#ifdef Q_OS_MAC + args << "-Xdock:icon=icon.png"; + args << QString("-Xdock:name=\"%1\"").arg(m_instance->windowTitle()); +#endif + + // HACK: Stupid hack for Intel drivers. See: https://mojang.atlassian.net/browse/MCL-767 +#ifdef Q_OS_WIN32 + args << QString("-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_" + "minecraft.exe.heapdump"); +#endif + + args << QString("-Xms%1m").arg(m_instance->settings()->get("MinMemAlloc").toInt()); + args << QString("-Xmx%1m").arg(m_instance->settings()->get("MaxMemAlloc").toInt()); + + // No PermGen in newer java. + auto javaVersion = m_instance->settings()->get("JavaVersion"); + if(Strings::naturalCompare(javaVersion.toString(), "1.8.0", Qt::CaseInsensitive) < 0) + { + auto permgen = m_instance->settings()->get("PermGen").toInt(); + if (permgen != 64) + { + args << QString("-XX:PermSize=%1m").arg(permgen); + } + } + + args << "-Duser.language=en"; + if (!m_nativeFolder.isEmpty()) + args << QString("-Djava.library.path=%1").arg(m_nativeFolder); + args << "-jar" << PathCombine(QCoreApplication::applicationDirPath(), "jars", "NewLaunch.jar"); + + return args; +} + +void LaunchTask::checkJava() +{ + m_javaPath = m_instance->settings()->get("JavaPath").toString(); + emit log("Java path is:\n" + m_javaPath + "\n\n"); + + auto realJavaPath = QStandardPaths::findExecutable(m_javaPath); + if (realJavaPath.isEmpty()) + { + emit log(tr("The java binary \"%1\" couldn't be found. You may have to set up java " + "if Minecraft fails to launch.").arg(m_javaPath), + MessageLevel::Warning); + } + + QFileInfo javaInfo(realJavaPath); + qlonglong javaUnixTime = javaInfo.lastModified().toMSecsSinceEpoch(); + auto storedUnixTime = m_instance->settings()->get("JavaTimestamp").toLongLong(); + this->m_javaUnixTime = javaUnixTime; + // if they are not the same, check! + if(javaUnixTime != storedUnixTime) + { + m_JavaChecker = std::make_shared(); + bool successful = false; + QString errorLog; + QString version; + emit log(tr("Checking Java version..."), MessageLevel::MultiMC); + connect(m_JavaChecker.get(), &JavaChecker::checkFinished, this, &LaunchTask::checkJavaFinished); + m_JavaChecker->m_path = realJavaPath; + m_JavaChecker->performCheck(); + } + preLaunch(); +} + +void LaunchTask::checkJavaFinished(JavaCheckResult result) +{ + if(!result.valid) + { + // Error message displayed if java can't start + emit log(tr("Could not start java:"), MessageLevel::Error); + auto lines = result.errorLog.split('\n'); + for(auto line: lines) + { + emit log(line, MessageLevel::Error); + } + emit log("\nCheck your MultiMC Java settings.", MessageLevel::MultiMC); + emitFailed(tr("Could not start java!")); + } + else + { + emit log(tr("Java version is %1!\n").arg(result.javaVersion), MessageLevel::MultiMC); + m_instance->settings()->set("JavaVersion", result.javaVersion); + m_instance->settings()->set("JavaTimestamp", m_javaUnixTime); + preLaunch(); + } +} + +void LaunchTask::executeTask() +{ + printHeader(); + emit log("Minecraft folder is:\n" + m_process.workingDirectory() + "\n\n"); + + checkJava(); +} + +void LaunchTask::launch() +{ + QString launchString("launch\n"); + m_process.write(launchString.toUtf8()); +} + +void LaunchTask::abort() +{ + QString launchString("abort\n"); + m_process.write(launchString.toUtf8()); +} + + +void LaunchTask::setWorkdir(QString path) +{ + QDir mcDir(path); + m_process.setWorkingDirectory(mcDir.absolutePath()); + m_prelaunchprocess.setWorkingDirectory(mcDir.absolutePath()); + m_postlaunchprocess.setWorkingDirectory(mcDir.absolutePath()); +} + +void LaunchTask::printHeader() +{ + emit log(m_header); +} + +void LaunchTask::on_log(QStringList lines, MessageLevel::Enum level) +{ + logOutput(lines, level); +} + +void LaunchTask::logOutput(const QStringList &lines, MessageLevel::Enum defaultLevel) +{ + for (auto & line: lines) + { + logOutput(line, defaultLevel); + } +} + +void LaunchTask::logOutput(QString line, MessageLevel::Enum level) +{ + // if the launcher part set a log level, use it + auto innerLevel = MessageLevel::fromLine(line); + if(innerLevel != MessageLevel::Unknown) + { + level = innerLevel; + } + + // If the level is still undetermined, guess level + if (level == MessageLevel::StdErr || level == MessageLevel::StdOut || level == MessageLevel::Unknown) + { + level = this->guessLevel(line, level); + } + + // censor private user info + line = censorPrivateInfo(line); + + emit log(line, level); +} + +void LaunchTask::preLaunch() +{ + QString prelaunch_cmd = m_instance->settings()->get("PreLaunchCommand").toString(); + if (!prelaunch_cmd.isEmpty()) + { + prelaunch_cmd = substituteVariables(prelaunch_cmd); + // Launch + emit log(tr("Running Pre-Launch command: %1").arg(prelaunch_cmd)); + m_prelaunchprocess.start(prelaunch_cmd); + } + else + { + on_pre_state(LoggedProcess::Skipped); + } +} + +void LaunchTask::on_pre_state(LoggedProcess::State state) +{ + switch(state) + { + case LoggedProcess::Aborted: + case LoggedProcess::Crashed: + case LoggedProcess::FailedToStart: + { + QString error = tr("Pre-Launch command failed with code %1.\n\n").arg(m_prelaunchprocess.exitCode()); + emit log(error, MessageLevel::Fatal); + emitFailed(error); + return; + } + case LoggedProcess::Finished: + { + emit log(tr("Pre-Launch command ran successfully.\n\n")); + } + case LoggedProcess::Skipped: + { + m_instance->reload(); + updateInstance(); + } + default: + break; + } +} + +void LaunchTask::updateInstance() +{ + m_updateTask = m_instance->createUpdateTask(); + if(m_updateTask) + { + connect(m_updateTask.get(), SIGNAL(finished()), this, SLOT(updateFinished())); + m_updateTask->start(); + return; + } + makeReady(); +} + +void LaunchTask::updateFinished() +{ + if(m_updateTask->successful()) + { + doJarModding(); + } + else + { + QString reason = tr("Instance update failed because: %1.\n\n").arg(m_updateTask->failReason()); + emit log(reason, MessageLevel::Fatal); + emitFailed(reason); + } +} + +void LaunchTask::doJarModding() +{ + m_jarModTask = m_instance->createJarModdingTask(); + if(!m_jarModTask) + { + jarModdingSucceeded(); + } + connect(m_jarModTask.get(), SIGNAL(succeeded()), this, SLOT(jarModdingSucceeded())); + connect(m_jarModTask.get(), SIGNAL(failed(QString)), this, SLOT(jarModdingFailed(QString))); + m_jarModTask->start(); +} + +void LaunchTask::jarModdingSucceeded() +{ + makeReady(); +} + +void LaunchTask::jarModdingFailed(QString reason) +{ + emitFailed(reason); +} + +void LaunchTask::makeReady() +{ + QStringList args = javaArguments(); + QString allArgs = args.join(", "); + emit log("Java Arguments:\n[" + censorPrivateInfo(allArgs) + "]\n\n"); + + QString wrapperCommand = m_instance->settings()->get("WrapperCommand").toString(); + if(!wrapperCommand.isEmpty()) + { + auto realWrapperCommand = QStandardPaths::findExecutable(wrapperCommand); + if (realWrapperCommand.isEmpty()) + { + QString reason = tr("The wrapper command \"%1\" couldn't be found.").arg(wrapperCommand); + emit log(reason, MessageLevel::Fatal); + emitFailed(reason); + return; + } + emit log("Wrapper command is:\n" + wrapperCommand + "\n\n"); + args.prepend(m_javaPath); + m_process.start(wrapperCommand, args); + } + else + { + m_process.start(m_javaPath, args); + } + + // instantiate the launcher part + if (!m_process.waitForStarted()) + { + //: Error message displayed if instace can't start + QString reason = tr("Could not launch minecraft!"); + emit log(reason, MessageLevel::Fatal); + emitFailed(reason); + return; + } + + emit log(tr("Minecraft process ID: %1\n\n").arg(m_process.processId()), MessageLevel::MultiMC); + + // send the launch script to the launcher part + m_process.write(launchScript.toUtf8()); + + emit readyForLaunch(); +} + +void LaunchTask::on_state(LoggedProcess::State state) +{ + QProcess::ExitStatus estat = QProcess::NormalExit; + switch(state) + { + case LoggedProcess::Aborted: + case LoggedProcess::Crashed: + case LoggedProcess::FailedToStart: + { + estat = QProcess::CrashExit; + emitFailed("Game crashed."); + return; + } + case LoggedProcess::Finished: + { + auto exitCode = m_process.exitCode(); + m_postlaunchprocess.processEnvironment().insert("INST_EXITCODE", QString(exitCode)); + // run post-exit + postLaunch(); + break; + } + case LoggedProcess::Skipped: + qWarning() << "Illegal game state: Skipped"; + break; + case LoggedProcess::Running: + m_instance->setLastLaunch(); + break; + default: + break; + } +} + +void LaunchTask::killProcess() +{ + killed = true; + if (m_prelaunchprocess.state() == LoggedProcess::Running) + { + m_prelaunchprocess.kill(); + } + else if(m_process.state() == LoggedProcess::Running) + { + m_process.kill(); + } + else if(m_postlaunchprocess.state() == LoggedProcess::Running) + { + m_postlaunchprocess.kill(); + } +} + +void LaunchTask::postLaunch() +{ + if(killed) + return; + QString postlaunch_cmd = m_instance->settings()->get("PostExitCommand").toString(); + if (!postlaunch_cmd.isEmpty()) + { + postlaunch_cmd = substituteVariables(postlaunch_cmd); + emit log(tr("Running Post-Launch command: %1").arg(postlaunch_cmd)); + m_postlaunchprocess.start(postlaunch_cmd); + return; + } + emitSucceeded(); +} + +void LaunchTask::on_post_state(LoggedProcess::State state) +{ + switch(state) + { + case LoggedProcess::Aborted: + case LoggedProcess::Crashed: + case LoggedProcess::FailedToStart: + { + QString error = tr("Post-Launch command failed with code %1.\n\n").arg(m_postlaunchprocess.exitCode()); + emit log(error, MessageLevel::Error); + emitFailed(error); + } + case LoggedProcess::Finished: + { + emit log(tr("Post-Launch command ran successfully.\n\n")); + } + case LoggedProcess::Skipped: + { + emitSucceeded(); + } + default: + break; + } +} + +void LaunchTask::emitSucceeded() +{ + m_instance->cleanupAfterRun(); + m_instance->setRunning(false); + Task::emitSucceeded(); +} + +void LaunchTask::emitFailed(QString reason) +{ + m_instance->cleanupAfterRun(); + m_instance->setRunning(false); + Task::emitFailed(reason); +} + +QString LaunchTask::substituteVariables(const QString &cmd) const +{ + QString out = cmd; + auto variables = getVariables(); + for (auto it = variables.begin(); it != variables.end(); ++it) + { + out.replace("$" + it.key(), it.value()); + } + auto env = QProcessEnvironment::systemEnvironment(); + for (auto var : env.keys()) + { + out.replace("$" + var, env.value(var)); + } + return out; +} + +qint64 LaunchTask::pid() +{ +#ifdef Q_OS_WIN + struct _PROCESS_INFORMATION *procinfo = m_process.pid(); + return procinfo->dwProcessId; +#else + return m_process.pid(); +#endif +} diff --git a/logic/launch/LaunchTask.h b/logic/launch/LaunchTask.h new file mode 100644 index 00000000..38142189 --- /dev/null +++ b/logic/launch/LaunchTask.h @@ -0,0 +1,178 @@ +/* Copyright 2013-2015 MultiMC Contributors + * + * Authors: Orochimarufan + * + * 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 "BaseInstance.h" +#include "MessageLevel.h" +#include "LoggedProcess.h" +/* HACK: MINECRAFT: split! */ +#include "minecraft/MinecraftInstance.h" +#include "java/JavaChecker.h" +#include "QObjectPtr.h" +#include "tasks/Task.h" + +class ProcessTask +{ + +}; + +class BaseProfilerFactory; +class LaunchTask: public Task +{ + Q_OBJECT +protected: + explicit LaunchTask(InstancePtr instance); + void init(); + +public: /* methods */ + static std::shared_ptr create(MinecraftInstancePtr inst); + virtual ~LaunchTask() {}; + + InstancePtr instance() + { + return m_instance; + } + + /// Set the text printed on top of the log + void setHeader(QString header) + { + m_header = header; + } + + void setWorkdir(QString path); + + void killProcess(); + + qint64 pid(); + + /** + * @brief prepare the process for launch (for multi-stage launch) + */ + virtual void executeTask() override; + + /** + * @brief launch the armed instance + */ + virtual void launch(); + + /** + * @brief abort launch + */ + virtual void abort(); + +public: /* HACK: MINECRAFT: split! */ + void setLaunchScript(QString script) + { + launchScript = script; + } + + void setNativeFolder(QString natives) + { + m_nativeFolder = natives; + } + + inline void setLogin(AuthSessionPtr session) + { + m_session = session; + } + + +protected: /* methods */ + void preLaunch(); + void updateInstance(); + void doJarModding(); + void makeReady(); + void postLaunch(); + virtual void emitFailed(QString reason); + virtual void emitSucceeded(); + QString substituteVariables(const QString &cmd) const; + void initializeEnvironment(); + + void printHeader(); + + virtual QMap getVariables() const; + virtual QString censorPrivateInfo(QString in); + virtual MessageLevel::Enum guessLevel(const QString &message, MessageLevel::Enum defaultLevel); + +protected slots: + void jarModdingSucceeded(); + void jarModdingFailed(QString reason); + +signals: + /** + * @brief emitted when the launch preparations are done + */ + void readyForLaunch(); + + /** + * @brief emitted when we want to log something + * @param text the text to log + * @param level the level to log at + */ + void log(QString text, MessageLevel::Enum level = MessageLevel::MultiMC); + +protected slots: + void on_log(QStringList lines, MessageLevel::Enum level); + void logOutput(const QStringList& lines, MessageLevel::Enum defaultLevel = MessageLevel::Message); + void logOutput(QString line, MessageLevel::Enum defaultLevel = MessageLevel::Message); + + void on_pre_state(LoggedProcess::State state); + void on_state(LoggedProcess::State state); + void on_post_state(LoggedProcess::State state); + + + +protected: + InstancePtr m_instance; + + LoggedProcess m_prelaunchprocess; + LoggedProcess m_postlaunchprocess; + LoggedProcess m_process; + QProcessEnvironment m_env; + BaseProfilerFactory * m_profiler = nullptr; + + bool killed = false; + QString m_header; + +/** + * java check step + */ +protected slots: + void checkJavaFinished(JavaCheckResult result); + +protected: + // for java checker and launch + QString m_javaPath; + qlonglong m_javaUnixTime; + std::shared_ptr m_JavaChecker; + +protected: /* HACK: MINECRAFT: split! */ + AuthSessionPtr m_session; + QString launchScript; + QString m_nativeFolder; + std::shared_ptr m_updateTask; + std::shared_ptr m_jarModTask; + +protected: /* HACK: MINECRAFT: split! */ + void checkJava(); + QStringList javaArguments() const; +private slots: + void updateFinished(); +}; + +class BaseProfilerFactory; \ No newline at end of file diff --git a/logic/launch/LoggedProcess.cpp b/logic/launch/LoggedProcess.cpp new file mode 100644 index 00000000..53840621 --- /dev/null +++ b/logic/launch/LoggedProcess.cpp @@ -0,0 +1,147 @@ +#include "LoggedProcess.h" +#include "MessageLevel.h" +#include + +LoggedProcess::LoggedProcess(QObject *parent) : QProcess(parent) +{ + // QProcess has a strange interface... let's map a lot of those into a few. + connect(this, &QProcess::readyReadStandardOutput, this, &LoggedProcess::on_stdOut); + connect(this, &QProcess::readyReadStandardError, this, &LoggedProcess::on_stdErr); + connect(this, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(on_exit(int,QProcess::ExitStatus))); + connect(this, SIGNAL(error(QProcess::ProcessError)), this, SLOT(on_error(QProcess::ProcessError))); + connect(this, &QProcess::stateChanged, this, &LoggedProcess::on_stateChange); +} + +QStringList reprocess(const QByteArray & data, QString & leftover) +{ + QString str = leftover + QString::fromLocal8Bit(data); + + str.remove('\r'); + QStringList lines = str.split("\n"); + leftover = lines.takeLast(); + return lines; +} + +void LoggedProcess::on_stdErr() +{ + auto lines = reprocess(readAllStandardError(), m_err_leftover); + emit log(lines, MessageLevel::StdErr); +} + +void LoggedProcess::on_stdOut() +{ + auto lines = reprocess(readAllStandardOutput(), m_out_leftover); + emit log(lines, MessageLevel::StdOut); +} + +void LoggedProcess::on_exit(int exit_code, QProcess::ExitStatus status) +{ + // Flush console window + if (!m_err_leftover.isEmpty()) + { + emit log({m_err_leftover}, MessageLevel::StdErr); + m_err_leftover.clear(); + } + if (!m_out_leftover.isEmpty()) + { + emit log({m_err_leftover}, MessageLevel::StdOut); + m_out_leftover.clear(); + } + + // based on state, send signals + if (!m_is_aborting) + { + if (status == QProcess::NormalExit) + { + //: Message displayed on instance exit + emit log({tr("Process exited with code %1.").arg(exit_code)}, MessageLevel::MultiMC); + changeState(LoggedProcess::Finished); + } + else + { + //: Message displayed on instance crashed + if(exit_code == -1) + emit log({tr("Process crashed.").arg(exit_code)}, MessageLevel::MultiMC); + else + emit log({tr("Process crashed with exitcode %1.").arg(exit_code)}, MessageLevel::MultiMC); + changeState(LoggedProcess::Crashed); + } + } + else + { + //: Message displayed after the instance exits due to kill request + emit log({tr("Process was killed by user.")}, MessageLevel::Error); + changeState(LoggedProcess::Aborted); + } +} + +void LoggedProcess::on_error(QProcess::ProcessError error) +{ + switch(error) + { + case QProcess::FailedToStart: + { + emit log({tr("The process failed to start.")}, MessageLevel::Fatal); + changeState(LoggedProcess::FailedToStart); + break; + } + // we'll just ignore those... never needed them + case QProcess::Crashed: + case QProcess::ReadError: + case QProcess::Timedout: + case QProcess::UnknownError: + case QProcess::WriteError: + break; + } +} + +void LoggedProcess::kill() +{ + m_is_aborting = true; + QProcess::kill(); +} + +int LoggedProcess::exitCode() const +{ + return m_exit_code; +} + +void LoggedProcess::changeState(LoggedProcess::State state) +{ + if(state == m_state) + return; + m_state = state; + emit stateChanged(m_state); +} + +LoggedProcess::State LoggedProcess::state() const +{ + return m_state; +} + +void LoggedProcess::on_stateChange(QProcess::ProcessState state) +{ + switch(state) + { + case QProcess::NotRunning: + break; // let's not - there are too many that handle this already. + case QProcess::Starting: + { + if(m_state != LoggedProcess::NotRunning) + { + qWarning() << "Wrong state change for process from state" << m_state << "to" << (int) LoggedProcess::Starting; + } + changeState(LoggedProcess::Starting); + return; + } + case QProcess::Running: + { + if(m_state != LoggedProcess::Starting) + { + qWarning() << "Wrong state change for process from state" << m_state << "to" << (int) LoggedProcess::Running; + } + changeState(LoggedProcess::Running); + return; + } + } +} diff --git a/logic/launch/LoggedProcess.h b/logic/launch/LoggedProcess.h new file mode 100644 index 00000000..253be2c1 --- /dev/null +++ b/logic/launch/LoggedProcess.h @@ -0,0 +1,60 @@ +#pragma once +#include +#include "MessageLevel.h" + +/* + * This is a basic process. + * It has line-based logging support and hides some of the nasty bits. + */ +class LoggedProcess : public QProcess +{ +Q_OBJECT +public: + enum State + { + NotRunning, + Starting, + FailedToStart, + Running, + Finished, + Crashed, + Aborted, + Skipped + }; + +public: + explicit LoggedProcess(QObject* parent = 0); + virtual ~LoggedProcess() {}; + + State state() const; + int exitCode() const; + +signals: + void log(QStringList lines, MessageLevel::Enum level); + void stateChanged(LoggedProcess::State state); + +public slots: + /** + * @brief kill the process - equivalent to kill -9 + */ + void kill(); + + +private slots: + void on_stdErr(); + void on_stdOut(); + void on_exit(int exit_code, QProcess::ExitStatus status); + void on_error(QProcess::ProcessError error); + void on_stateChange(QProcess::ProcessState); + +private: + void changeState(LoggedProcess::State state); + +private: + QString m_err_leftover; + QString m_out_leftover; + bool m_killed = false; + State m_state = NotRunning; + int m_exit_code = 0; + bool m_is_aborting = false; +}; diff --git a/logic/launch/MessageLevel.cpp b/logic/launch/MessageLevel.cpp new file mode 100644 index 00000000..a5191290 --- /dev/null +++ b/logic/launch/MessageLevel.cpp @@ -0,0 +1,36 @@ +#include "MessageLevel.h" + +MessageLevel::Enum MessageLevel::getLevel(const QString& levelName) +{ + if (levelName == "MultiMC") + return MessageLevel::MultiMC; + else if (levelName == "Debug") + return MessageLevel::Debug; + else if (levelName == "Info") + return MessageLevel::Info; + else if (levelName == "Message") + return MessageLevel::Message; + else if (levelName == "Warning") + return MessageLevel::Warning; + else if (levelName == "Error") + return MessageLevel::Error; + else if (levelName == "Fatal") + return MessageLevel::Fatal; + // Skip PrePost, it's not exposed to !![]! + // Also skip StdErr and StdOut + else + return MessageLevel::Unknown; +} + +MessageLevel::Enum MessageLevel::fromLine(QString &line) +{ + // Level prefix + int endmark = line.indexOf("]!"); + if (line.startsWith("!![") && endmark != -1) + { + auto level = MessageLevel::getLevel(line.left(endmark).mid(3)); + line = line.mid(endmark + 2); + return level; + } + return MessageLevel::Unknown; +} diff --git a/logic/launch/MessageLevel.h b/logic/launch/MessageLevel.h new file mode 100644 index 00000000..0128148d --- /dev/null +++ b/logic/launch/MessageLevel.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +/** + * @brief the MessageLevel Enum + * defines what level a log message is + */ +namespace MessageLevel +{ +enum Enum +{ + Unknown, /**< No idea what this is or where it came from */ + StdOut, /**< Undetermined stderr messages */ + StdErr, /**< Undetermined stdout messages */ + MultiMC, /**< MultiMC Messages */ + Debug, /**< Debug Messages */ + Info, /**< Info Messages */ + Message, /**< Standard Messages */ + Warning, /**< Warnings */ + Error, /**< Errors */ + Fatal, /**< Fatal Errors */ +}; +MessageLevel::Enum getLevel(const QString &levelName); + +/* Get message level from a line. Line is modified if it was successful. */ +MessageLevel::Enum fromLine(QString &line); +} diff --git a/logic/minecraft/LegacyInstance.cpp b/logic/minecraft/LegacyInstance.cpp index 8431c35b..0991b7b5 100644 --- a/logic/minecraft/LegacyInstance.cpp +++ b/logic/minecraft/LegacyInstance.cpp @@ -24,7 +24,7 @@ #include "minecraft/LegacyUpdate.h" #include "icons/IconList.h" -#include "BaseLauncher.h" +#include "launch/LaunchTask.h" #include "minecraft/ModList.h" #include @@ -96,7 +96,7 @@ std::shared_ptr LegacyInstance::createUpdateTask() return std::shared_ptr(new LegacyUpdate(this, this)); } -std::shared_ptr LegacyInstance::createLaunchTask(AuthSessionPtr account) +std::shared_ptr LegacyInstance::createLaunchTask(AuthSessionPtr account) { QString launchScript; QIcon icon = ENV.icons()->getIcon(iconKey()); @@ -123,7 +123,7 @@ std::shared_ptr LegacyInstance::createLaunchTask(AuthSessionPtr ac launchScript += "lwjgl " + lwjgl + "\n"; launchScript += "launcher legacy\n"; } - auto process = BaseLauncher::create(std::dynamic_pointer_cast(getSharedPtr())); + auto process = LaunchTask::create(std::dynamic_pointer_cast(getSharedPtr())); process->setLaunchScript(launchScript); process->setWorkdir(minecraftRoot()); process->setLogin(account); diff --git a/logic/minecraft/LegacyInstance.h b/logic/minecraft/LegacyInstance.h index 51871876..0930c290 100644 --- a/logic/minecraft/LegacyInstance.h +++ b/logic/minecraft/LegacyInstance.h @@ -111,7 +111,7 @@ public: virtual void setShouldUpdate(bool val) override; virtual std::shared_ptr createUpdateTask() override; - virtual std::shared_ptr createLaunchTask(AuthSessionPtr account) override; + virtual std::shared_ptr createLaunchTask(AuthSessionPtr account) override; virtual std::shared_ptr createJarModdingTask() override; diff --git a/logic/minecraft/OneSixInstance.cpp b/logic/minecraft/OneSixInstance.cpp index 4af56b54..d66236f4 100644 --- a/logic/minecraft/OneSixInstance.cpp +++ b/logic/minecraft/OneSixInstance.cpp @@ -22,7 +22,7 @@ #include "minecraft/OneSixUpdate.h" #include "minecraft/MinecraftProfile.h" #include "minecraft/VersionBuildError.h" -#include "BaseLauncher.h" +#include "launch/LaunchTask.h" #include "minecraft/OneSixProfileStrategy.h" #include "MMCZip.h" @@ -123,7 +123,7 @@ QStringList OneSixInstance::processMinecraftArgs(AuthSessionPtr session) return parts; } -std::shared_ptr OneSixInstance::createLaunchTask(AuthSessionPtr session) +std::shared_ptr OneSixInstance::createLaunchTask(AuthSessionPtr session) { QString launchScript; QIcon icon = ENV.icons()->getIcon(iconKey()); @@ -230,7 +230,7 @@ std::shared_ptr OneSixInstance::createLaunchTask(AuthSessionPtr se } launchScript += "launcher onesix\n"; - auto process = BaseLauncher::create(std::dynamic_pointer_cast(getSharedPtr())); + auto process = LaunchTask::create(std::dynamic_pointer_cast(getSharedPtr())); process->setLaunchScript(launchScript); process->setWorkdir(minecraftRoot()); process->setLogin(session); diff --git a/logic/minecraft/OneSixInstance.h b/logic/minecraft/OneSixInstance.h index 46545462..42902366 100644 --- a/logic/minecraft/OneSixInstance.h +++ b/logic/minecraft/OneSixInstance.h @@ -49,7 +49,7 @@ public: virtual QString instanceConfigFolder() const override; virtual std::shared_ptr createUpdateTask() override; - virtual std::shared_ptr createLaunchTask(AuthSessionPtr account) override; + virtual std::shared_ptr createLaunchTask(AuthSessionPtr account) override; virtual std::shared_ptr createJarModdingTask() override; virtual void cleanupAfterRun() override; diff --git a/logic/tools/BaseProfiler.cpp b/logic/tools/BaseProfiler.cpp index 42ed1d93..5ff0fa44 100644 --- a/logic/tools/BaseProfiler.cpp +++ b/logic/tools/BaseProfiler.cpp @@ -7,7 +7,7 @@ BaseProfiler::BaseProfiler(SettingsObjectPtr settings, InstancePtr instance, QOb { } -void BaseProfiler::beginProfiling(std::shared_ptr process) +void BaseProfiler::beginProfiling(std::shared_ptr process) { beginProfilingImpl(process); } diff --git a/logic/tools/BaseProfiler.h b/logic/tools/BaseProfiler.h index 709c7cb4..5191f7b8 100644 --- a/logic/tools/BaseProfiler.h +++ b/logic/tools/BaseProfiler.h @@ -4,7 +4,7 @@ class BaseInstance; class SettingsObject; -class BaseLauncher; +class LaunchTask; class QProcess; class BaseProfiler : public BaseExternalTool @@ -15,13 +15,13 @@ public: public slots: - void beginProfiling(std::shared_ptr process); + void beginProfiling(std::shared_ptr process); void abortProfiling(); protected: QProcess *m_profilerProcess; - virtual void beginProfilingImpl(std::shared_ptr process) = 0; + virtual void beginProfilingImpl(std::shared_ptr process) = 0; virtual void abortProfilingImpl(); signals: diff --git a/logic/tools/JProfiler.cpp b/logic/tools/JProfiler.cpp index 975345d5..45b33f79 100644 --- a/logic/tools/JProfiler.cpp +++ b/logic/tools/JProfiler.cpp @@ -4,7 +4,7 @@ #include #include "settings/SettingsObject.h" -#include "BaseLauncher.h" +#include "launch/LaunchTask.h" #include "BaseInstance.h" class JProfiler : public BaseProfiler @@ -18,7 +18,7 @@ private slots: void profilerFinished(int exit, QProcess::ExitStatus status); protected: - void beginProfilingImpl(std::shared_ptr process); + void beginProfilingImpl(std::shared_ptr process); private: int listeningPort = 0; @@ -48,7 +48,7 @@ void JProfiler::profilerFinished(int exit, QProcess::ExitStatus status) } } -void JProfiler::beginProfilingImpl(std::shared_ptr process) +void JProfiler::beginProfilingImpl(std::shared_ptr process) { listeningPort = globalSettings->get("JProfilerPort").toInt(); QProcess *profiler = new QProcess(this); diff --git a/logic/tools/JVisualVM.cpp b/logic/tools/JVisualVM.cpp index a749012b..169967d9 100644 --- a/logic/tools/JVisualVM.cpp +++ b/logic/tools/JVisualVM.cpp @@ -4,7 +4,7 @@ #include #include "settings/SettingsObject.h" -#include "BaseLauncher.h" +#include "launch/LaunchTask.h" #include "BaseInstance.h" class JVisualVM : public BaseProfiler @@ -18,7 +18,7 @@ private slots: void profilerFinished(int exit, QProcess::ExitStatus status); protected: - void beginProfilingImpl(std::shared_ptr process); + void beginProfilingImpl(std::shared_ptr process); }; @@ -45,7 +45,7 @@ void JVisualVM::profilerFinished(int exit, QProcess::ExitStatus status) } } -void JVisualVM::beginProfilingImpl(std::shared_ptr process) +void JVisualVM::beginProfilingImpl(std::shared_ptr process) { QProcess *profiler = new QProcess(this); QStringList profilerArgs = -- cgit v1.2.3