From 9f174ad4e7853b5864d7478ce97d7afa75d76636 Mon Sep 17 00:00:00 2001 From: Orochimarufan Date: Fri, 22 Feb 2013 16:17:31 +0100 Subject: Implement Instance launching Use --launch to test --- data/minecraftprocess.cpp | 214 ++++++++++++++++++++++++++++++++++++++++++++++ data/minecraftprocess.h | 94 ++++++++++++++++++++ 2 files changed, 308 insertions(+) create mode 100644 data/minecraftprocess.cpp create mode 100644 data/minecraftprocess.h (limited to 'data') diff --git a/data/minecraftprocess.cpp b/data/minecraftprocess.cpp new file mode 100644 index 00000000..4cbe7208 --- /dev/null +++ b/data/minecraftprocess.cpp @@ -0,0 +1,214 @@ +/* Copyright 2013 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 "minecraftprocess.h" + +#include +#include +#include +#include +#include + +#include "instance.h" + +#include "osutils.h" +#include "pathutils.h" + +#define LAUNCHER_FILE "MultiMCLauncher.jar" +#define IBUS "@im=ibus" + +// commandline splitter +QStringList MinecraftProcess::splitArgs(QString args) +{ + QStringList argv; + QString current; + bool escape = false; + QChar inquotes; + for (int i=0; iiconKey()).save(destination); +} + +inline void MinecraftProcess::extractLauncher(QString destination) +{ + QFile(":/launcher/launcher.jar").copy(destination); +} + +void MinecraftProcess::prepare(InstancePtr inst) +{ + extractLauncher(PathCombine(inst->minecraftDir(), LAUNCHER_FILE)); + extractIcon(inst, PathCombine(inst->minecraftDir(), "icon.png")); +} + +// constructor +MinecraftProcess::MinecraftProcess(InstancePtr inst, QString user, QString session, ConsoleWindow *console) : + m_instance(inst), m_user(user), m_session(session), m_console(console) +{ + connect(this, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(finish(int, QProcess::ExitStatus))); + + // prepare the process environment + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + +#ifdef LINUX + // Strip IBus + if (env.value("XMODIFIERS").contains(IBUS)) + env.insert("XMODIFIERS", env.value("XMODIFIERS").replace(IBUS, "")); +#endif + + // export some infos + env.insert("INST_NAME", inst->name()); + env.insert("INST_ID", inst->id()); + env.insert("INST_DIR", QDir(inst->rootDir()).absolutePath()); + + this->setProcessEnvironment(env); + m_prepostlaunchprocess.setProcessEnvironment(env); + + // set the cwd + QDir mcDir(inst->minecraftDir()); + this->setWorkingDirectory(mcDir.absolutePath()); + m_prepostlaunchprocess.setWorkingDirectory(mcDir.absolutePath()); + + //TODO: do console redirection +} + +void MinecraftProcess::finish(int code, ExitStatus status) +{ + if (status != NormalExit) + { + //TODO: error handling + } + + m_prepostlaunchprocess.processEnvironment().insert("INST_EXITCODE", QString(code)); + + // run post-exit + if (!m_instance->getPostExitCommand().isEmpty()) + { + m_prepostlaunchprocess.start(m_instance->getPostExitCommand()); + m_prepostlaunchprocess.waitForFinished(); + if (m_prepostlaunchprocess.exitStatus() != NormalExit) + { + //TODO: error handling + } + } + + emit ended(); +} + +void MinecraftProcess::launch() +{ + if (!m_instance->getPreLaunchCommand().isEmpty()) + { + m_prepostlaunchprocess.start(m_instance->getPreLaunchCommand()); + m_prepostlaunchprocess.waitForFinished(); + if (m_prepostlaunchprocess.exitStatus() != NormalExit) + { + //TODO: error handling + return; + } + } + + m_instance->setLastLaunch(); + + prepare(m_instance); + + genArgs(); + + qDebug("Minecraft folder is: '%s'", qPrintable(workingDirectory())); + qDebug("Instance launched with arguments: '%s'", qPrintable(m_arguments.join("' '"))); + + start(m_instance->getJavaPath(), m_arguments); + if (!waitForStarted()) + { + //TODO: error handling + } +} + +void MinecraftProcess::genArgs() +{ + // start fresh + m_arguments.clear(); + + // window size + QString windowSize; + if (m_instance->getLaunchMaximized()) + windowSize = "max"; + else + windowSize = QString("%1x%2").arg(m_instance->getMinecraftWinWidth()).arg(m_instance->getMinecraftWinHeight()); + + // window title + QString windowTitle; + windowTitle.append("MultiMC: ").append(m_instance->name()); + + // Java arguments + m_arguments.append(splitArgs(m_instance->getJvmArgs())); + +#ifdef OSX + // OSX dock icon and name + m_arguments << "-Xdock:icon=icon.png"; + m_arguments << QString("-Xdock:name=\"%1\"").arg(windowTitle); +#endif + + // lwjgl + QString lwjgl = m_instance->lwjglVersion(); + if (lwjgl != "Mojang") + lwjgl = QDir(settings->getLWJGLDir() + "/" + lwjgl).absolutePath(); + + // launcher arguments + m_arguments << QString("-Xms%1m").arg(m_instance->getMinMemAlloc()); + m_arguments << QString("-Xmx%1m").arg(m_instance->getMaxMemAlloc()); + m_arguments << "-jar" << LAUNCHER_FILE; + m_arguments << m_user; + m_arguments << m_session; + m_arguments << windowTitle; + m_arguments << windowSize; + m_arguments << lwjgl; +} diff --git a/data/minecraftprocess.h b/data/minecraftprocess.h new file mode 100644 index 00000000..99a3bed6 --- /dev/null +++ b/data/minecraftprocess.h @@ -0,0 +1,94 @@ +/* Copyright 2013 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. + */ +#ifndef MINECRAFTPROCESS_H +#define MINECRAFTPROCESS_H + +#include + +class ConsoleWindow; + +#include "instance.h" + +/** + * @file data/minecraftprocess.h + * @brief The MinecraftProcess class + */ +class MinecraftProcess : public QProcess +{ + Q_OBJECT +public: + /** + * @brief MinecraftProcess constructor + * @param inst the Instance pointer to launch + * @param user the minecraft username + * @param session the minecraft session id + * @param console the instance console window + */ + MinecraftProcess(InstancePtr inst, QString user, QString session, ConsoleWindow *console); + + /** + * @brief launch minecraft + */ + void launch(); + + /** + * @brief extract the instance icon + * @param inst the instance + * @param destination the destination path + */ + static inline void extractIcon(InstancePtr inst, QString destination); + + /** + * @brief extract the MultiMC launcher.jar + * @param destination the destination path + */ + static inline void extractLauncher(QString destination); + + /** + * @brief prepare the launch by extracting icon and launcher + * @param inst the instance + */ + static void prepare(InstancePtr inst); + + /** + * @brief split a string into argv items like a shell would do + * @param args the argument string + * @return a QStringList containing all arguments + */ + static QStringList splitArgs(QString args); + +signals: + /** + * @brief emitted when mc has finished and the PostLaunchCommand was run + */ + void ended(); + +protected: + ConsoleWindow *m_console; + InstancePtr m_instance; + QString m_user; + QString m_session; + QProcess m_prepostlaunchprocess; + QStringList m_arguments; + + void genArgs(); + +protected slots: + void finish(int, QProcess::ExitStatus status); +}; + +#endif // MINECRAFTPROCESS_H -- cgit v1.2.3 From 3a173648e789f30b2843241ee38e694d16e10358 Mon Sep 17 00:00:00 2001 From: Orochimarufan Date: Fri, 22 Feb 2013 18:18:23 +0100 Subject: Implement ConsoleWindow --- data/minecraftprocess.cpp | 38 +++++++++++++++++++++++++++++++++++--- data/minecraftprocess.h | 6 +++++- 2 files changed, 40 insertions(+), 4 deletions(-) (limited to 'data') diff --git a/data/minecraftprocess.cpp b/data/minecraftprocess.cpp index 4cbe7208..d08b767c 100644 --- a/data/minecraftprocess.cpp +++ b/data/minecraftprocess.cpp @@ -117,9 +117,33 @@ MinecraftProcess::MinecraftProcess(InstancePtr inst, QString user, QString sessi this->setWorkingDirectory(mcDir.absolutePath()); m_prepostlaunchprocess.setWorkingDirectory(mcDir.absolutePath()); - //TODO: do console redirection + // std channels + connect(this, SIGNAL(readyReadStandardError()), SLOT(on_stdErr())); + connect(this, SIGNAL(readyReadStandardOutput()), SLOT(on_stdOut())); } +// console window +void MinecraftProcess::on_stdErr() +{ + if (m_console != nullptr) + m_console->write(readAllStandardError(), ConsoleWindow::ERROR); +} + +void MinecraftProcess::on_stdOut() +{ + if (m_console != nullptr) + m_console->write(readAllStandardOutput(), ConsoleWindow::DEFAULT); +} + +void MinecraftProcess::log(QString text) +{ + if (m_console != nullptr) + m_console->write(text); + else + qDebug(qPrintable(text)); +} + +// exit handler void MinecraftProcess::finish(int code, ExitStatus status) { if (status != NormalExit) @@ -127,6 +151,8 @@ void MinecraftProcess::finish(int code, ExitStatus status) //TODO: error handling } + log("Minecraft exited."); + m_prepostlaunchprocess.processEnvironment().insert("INST_EXITCODE", QString(code)); // run post-exit @@ -140,6 +166,9 @@ void MinecraftProcess::finish(int code, ExitStatus status) } } + if (m_console != nullptr) + m_console->setMayClose(true); + emit ended(); } @@ -162,14 +191,17 @@ void MinecraftProcess::launch() genArgs(); - qDebug("Minecraft folder is: '%s'", qPrintable(workingDirectory())); - qDebug("Instance launched with arguments: '%s'", qPrintable(m_arguments.join("' '"))); + log(QString("Minecraft folder is: '%1'").arg(workingDirectory())); + log(QString("Instance launched with arguments: '%1'").arg(m_arguments.join("' '"))); start(m_instance->getJavaPath(), m_arguments); if (!waitForStarted()) { //TODO: error handling } + + if(m_console != nullptr) + m_console->setMayClose(false); } void MinecraftProcess::genArgs() diff --git a/data/minecraftprocess.h b/data/minecraftprocess.h index 99a3bed6..bede9486 100644 --- a/data/minecraftprocess.h +++ b/data/minecraftprocess.h @@ -19,7 +19,7 @@ #include -class ConsoleWindow; +#include "gui/consolewindow.h" #include "instance.h" @@ -86,9 +86,13 @@ protected: QStringList m_arguments; void genArgs(); + void log(QString text); protected slots: void finish(int, QProcess::ExitStatus status); + void on_stdErr(); + void on_stdOut(); + }; #endif // MINECRAFTPROCESS_H -- cgit v1.2.3