diff options
author | Petr Mrázek <peterix@gmail.com> | 2015-06-16 09:19:55 +0200 |
---|---|---|
committer | Petr Mrázek <peterix@gmail.com> | 2015-06-30 07:16:20 +0200 |
commit | 5628d3d379785c9c6f4a595c70392d9b1e9ea4df (patch) | |
tree | 586eb775fd1f3014ff4dd36984176530af5e70b3 /logic/BaseLauncher.cpp | |
parent | f86a39c21c9898c0b5966abb2b4907eb0b5bac1d (diff) | |
download | MultiMC-5628d3d379785c9c6f4a595c70392d9b1e9ea4df.tar MultiMC-5628d3d379785c9c6f4a595c70392d9b1e9ea4df.tar.gz MultiMC-5628d3d379785c9c6f4a595c70392d9b1e9ea4df.tar.lz MultiMC-5628d3d379785c9c6f4a595c70392d9b1e9ea4df.tar.xz MultiMC-5628d3d379785c9c6f4a595c70392d9b1e9ea4df.zip |
SCRATCH squash MinecraftLauncher into BaseLauncher
needs to be split differently
needs to be squashed together with the logic from MainWindow
Diffstat (limited to 'logic/BaseLauncher.cpp')
-rw-r--r-- | logic/BaseLauncher.cpp | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/logic/BaseLauncher.cpp b/logic/BaseLauncher.cpp index 41bccb68..464a2783 100644 --- a/logic/BaseLauncher.cpp +++ b/logic/BaseLauncher.cpp @@ -17,16 +17,282 @@ #include "BaseLauncher.h" #include "MessageLevel.h" +#include "MMCStrings.h" +#include "java/JavaChecker.h" +#include <pathutils.h> #include <QDebug> #include <QDir> #include <QEventLoop> +#include <QRegularExpression> +#include <QCoreApplication> +#include <QStandardPaths> #define IBUS "@im=ibus" +BaseLauncher* BaseLauncher::create(MinecraftInstancePtr inst) +{ + auto 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, "<SESSION ID>"); + in.replace(m_session->access_token, "<ACCESS TOKEN>"); + in.replace(m_session->client_token, "<CLIENT TOKEN>"); + in.replace(m_session->uuid, "<PROFILE ID>"); + in.replace(m_session->player_name, "<PROFILE 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("\\[(?<timestamp>[0-9:]+)\\] \\[[^/]+/(?<level>[^\\]]+)\\]"); + 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<QString, QString> BaseLauncher::getVariables() const +{ + auto mcInstance = std::dynamic_pointer_cast<MinecraftInstance>(m_instance); + QMap<QString, QString> 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; +} + +bool BaseLauncher::checkJava(QString JavaPath) +{ + auto realJavaPath = QStandardPaths::findExecutable(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(JavaPath), + MessageLevel::Warning); + } + + QFileInfo javaInfo(realJavaPath); + qlonglong javaUnixTime = javaInfo.lastModified().toMSecsSinceEpoch(); + auto storedUnixTime = m_instance->settings()->get("JavaTimestamp").toLongLong(); + // if they are not the same, check! + if(javaUnixTime != storedUnixTime) + { + QEventLoop ev; + auto checker = std::make_shared<JavaChecker>(); + bool successful = false; + QString errorLog; + QString version; + emit log(tr("Checking Java version..."), MessageLevel::MultiMC); + connect(checker.get(), &JavaChecker::checkFinished, + [&](JavaCheckResult result) + { + successful = result.valid; + errorLog = result.errorLog; + version = result.javaVersion; + ev.exit(); + }); + checker->m_path = realJavaPath; + checker->performCheck(); + ev.exec(); + if(!successful) + { + // Error message displayed if java can't start + emit log(tr("Could not start java:"), MessageLevel::Error); + auto lines = errorLog.split('\n'); + for(auto line: lines) + { + emit log(line, MessageLevel::Error); + } + emit log("\nCheck your MultiMC Java settings.", MessageLevel::MultiMC); + m_instance->cleanupAfterRun(); + emit launch_failed(m_instance); + // not running, failed + m_instance->setRunning(false); + return false; + } + emit log(tr("Java version is %1!\n").arg(version), MessageLevel::MultiMC); + m_instance->settings()->set("JavaVersion", version); + m_instance->settings()->set("JavaTimestamp", javaUnixTime); + } + return true; +} + +void BaseLauncher::arm() +{ + printHeader(); + emit log("Minecraft folder is:\n" + m_process.workingDirectory() + "\n\n"); + + /* + if (!preLaunch()) + { + emit ended(m_instance, 1, QProcess::CrashExit); + return; + } + */ + + m_instance->setLastLaunch(); + + QString JavaPath = m_instance->settings()->get("JavaPath").toString(); + emit log("Java path is:\n" + JavaPath + "\n\n"); + + if(!checkJava(JavaPath)) + { + return; + } + + 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()) + { + emit log(tr("The wrapper command \"%1\" couldn't be found.").arg(wrapperCommand), MessageLevel::Warning); + m_instance->cleanupAfterRun(); + emit launch_failed(m_instance); + m_instance->setRunning(false); + return; + } + emit log("Wrapper command is:\n" + wrapperCommand + "\n\n"); + args.prepend(JavaPath); + m_process.start(wrapperCommand, args); + } + else + { + m_process.start(JavaPath, args); + } + + // instantiate the launcher part + if (!m_process.waitForStarted()) + { + //: Error message displayed if instace can't start + emit log(tr("Could not launch minecraft!"), MessageLevel::Error); + m_instance->cleanupAfterRun(); + emit launch_failed(m_instance); + // not running, failed + m_instance->setRunning(false); + 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()); +} + +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::initializeEnvironment() { // prepare the process environment |