GH-1053 explode launch task into many small steps, each a Task
This commit is contained in:
		| @@ -211,7 +211,7 @@ void ConsoleWindow::on_btnKillMinecraft_clicked() | ||||
| 		   "is frozen for some reason"), | ||||
| 		QMessageBox::Question, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)->exec(); | ||||
| 	if (response == QMessageBox::Yes) | ||||
| 		m_proc->killProcess(); | ||||
| 		m_proc->abort(); | ||||
| 	else | ||||
| 		m_killButton->setEnabled(true); | ||||
| } | ||||
|   | ||||
| @@ -13,6 +13,7 @@ | ||||
| #include <QInputDialog> | ||||
| #include <tasks/Task.h> | ||||
| #include <auth/YggdrasilTask.h> | ||||
| #include <launch/steps/TextPrint.h> | ||||
|  | ||||
| LaunchController::LaunchController(QObject *parent) : QObject(parent) | ||||
| { | ||||
| @@ -172,7 +173,7 @@ void LaunchController::launchInstance() | ||||
| 	connect(m_console, &ConsoleWindow::isClosing, this, &LaunchController::instanceEnded); | ||||
| 	connect(m_launcher.get(), &LaunchTask::readyForLaunch, this, &LaunchController::readyForLaunch); | ||||
|  | ||||
| 	m_launcher->setHeader("MultiMC version: " + BuildConfig.printableVersionString() + "\n\n"); | ||||
| 	m_launcher->prependStep(std::make_shared<TextPrint>(m_launcher.get(), "MultiMC version: " + BuildConfig.printableVersionString() + "\n\n", MessageLevel::MultiMC)); | ||||
| 	m_launcher->start(); | ||||
| } | ||||
|  | ||||
| @@ -180,7 +181,7 @@ void LaunchController::readyForLaunch() | ||||
| { | ||||
| 	if (!m_profiler) | ||||
| 	{ | ||||
| 		m_launcher->launch(); | ||||
| 		m_launcher->proceed(); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| @@ -204,7 +205,7 @@ void LaunchController::readyForLaunch() | ||||
| 		msg.addButton(tr("Launch"), QMessageBox::AcceptRole); | ||||
| 		msg.setModal(true); | ||||
| 		msg.exec(); | ||||
| 		m_launcher->launch(); | ||||
| 		m_launcher->proceed(); | ||||
| 	}); | ||||
| 	connect(profilerInstance, &BaseProfiler::abortLaunch, [this](const QString & message) | ||||
| 	{ | ||||
|   | ||||
| @@ -52,6 +52,21 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s | ||||
| 	m_settings->registerOverride(globalSettings->getSetting("LogPrePostOutput")); | ||||
| } | ||||
|  | ||||
| QString BaseInstance::getPreLaunchCommand() | ||||
| { | ||||
| 	return settings()->get("PreLaunchCommand").toString(); | ||||
| } | ||||
|  | ||||
| QString BaseInstance::getWrapperCommand() | ||||
| { | ||||
| 	return settings()->get("WrapperCommand").toString(); | ||||
| } | ||||
|  | ||||
| QString BaseInstance::getPostExitCommand() | ||||
| { | ||||
| 	return settings()->get("PostExitCommand").toString(); | ||||
| } | ||||
|  | ||||
| void BaseInstance::iconUpdated(QString key) | ||||
| { | ||||
| 	if(iconKey() == key) | ||||
|   | ||||
| @@ -18,6 +18,7 @@ | ||||
| #include <QObject> | ||||
| #include <QDateTime> | ||||
| #include <QSet> | ||||
| #include <QProcess> | ||||
|  | ||||
| #include "settings/SettingsObject.h" | ||||
|  | ||||
| @@ -89,6 +90,10 @@ public: | ||||
| 	void setGroupInitial(QString val); | ||||
| 	void setGroupPost(QString val); | ||||
|  | ||||
| 	QString getPreLaunchCommand(); | ||||
| 	QString getPostExitCommand(); | ||||
| 	QString getWrapperCommand(); | ||||
|  | ||||
| 	virtual QStringList extraArguments() const; | ||||
|  | ||||
| 	virtual QString intendedVersionId() const = 0; | ||||
| @@ -146,6 +151,12 @@ public: | ||||
| 	 */ | ||||
| 	virtual std::shared_ptr<Task> createJarModdingTask() = 0; | ||||
|  | ||||
|  | ||||
| 	/*! | ||||
| 	 * Create envrironment variables for running the instance | ||||
| 	 */ | ||||
| 	virtual QProcessEnvironment createEnvironment() = 0; | ||||
|  | ||||
| 	/*! | ||||
| 	 * does any necessary cleanups after the instance finishes. also runs before\ | ||||
| 	 * TODO: turn into a task that can run asynchronously | ||||
| @@ -157,6 +168,9 @@ public: | ||||
| 	/// FIXME: this really should be elsewhere... | ||||
| 	virtual QString instanceConfigFolder() const = 0; | ||||
|  | ||||
| 	/// get variables this instance exports | ||||
| 	virtual QMap<QString, QString> getVariables() const = 0; | ||||
|  | ||||
| 	enum InstanceFlag | ||||
| 	{ | ||||
| 		VersionBrokenFlag = 0x01, | ||||
|   | ||||
| @@ -93,12 +93,28 @@ set(LOGIC_SOURCES | ||||
| 	auth/flows/ValidateTask.cpp | ||||
|  | ||||
| 	# Game launch logic | ||||
| 	launch/LoggedProcess.h | ||||
| 	launch/steps/CheckJava.cpp | ||||
| 	launch/steps/CheckJava.h | ||||
| 	launch/steps/LaunchCommand.cpp | ||||
| 	launch/steps/LaunchCommand.h | ||||
| 	launch/steps/ModMinecraftJar.cpp | ||||
| 	launch/steps/ModMinecraftJar.h | ||||
| 	launch/steps/PostLaunchCommand.cpp | ||||
| 	launch/steps/PostLaunchCommand.h | ||||
| 	launch/steps/PreLaunchCommand.cpp | ||||
| 	launch/steps/PreLaunchCommand.h | ||||
| 	launch/steps/TextPrint.cpp | ||||
| 	launch/steps/TextPrint.h | ||||
| 	launch/steps/Update.cpp | ||||
| 	launch/steps/Update.h | ||||
| 	launch/LaunchStep.cpp | ||||
| 	launch/LaunchStep.h | ||||
| 	launch/LaunchTask.cpp | ||||
| 	launch/LaunchTask.h | ||||
| 	launch/LoggedProcess.cpp | ||||
| 	launch/LoggedProcess.h | ||||
| 	launch/MessageLevel.cpp | ||||
| 	launch/MessageLevel.h | ||||
| 	launch/LaunchTask.h | ||||
| 	launch/LaunchTask.cpp | ||||
|  | ||||
| 	# Update system | ||||
| 	updater/GoUpdate.h | ||||
|   | ||||
| @@ -62,4 +62,12 @@ public: | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 	}; | ||||
| 	virtual QProcessEnvironment createEnvironment() | ||||
| 	{ | ||||
| 		return QProcessEnvironment(); | ||||
| 	} | ||||
| 	virtual QMap<QString, QString> getVariables() const | ||||
| 	{ | ||||
| 		return QMap<QString, QString>(); | ||||
| 	} | ||||
| }; | ||||
|   | ||||
| @@ -73,12 +73,13 @@ void YggdrasilTask::heartbeat() | ||||
| 	progress(count, timeout_max); | ||||
| } | ||||
|  | ||||
| void YggdrasilTask::abort() | ||||
| bool YggdrasilTask::abort() | ||||
| { | ||||
| 	progress(timeout_max, timeout_max); | ||||
| 	// TODO: actually use this in a meaningful way | ||||
| 	m_aborted = YggdrasilTask::BY_USER; | ||||
| 	m_netReply->abort(); | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void YggdrasilTask::abortByTimeout() | ||||
|   | ||||
| @@ -131,7 +131,7 @@ slots: | ||||
| 	void changeState(State newState, QString reason=QString()); | ||||
| public | ||||
| slots: | ||||
| 	virtual void abort() override; | ||||
| 	virtual bool abort() override; | ||||
| 	void abortByTimeout(); | ||||
| 	State state(); | ||||
| protected: | ||||
|   | ||||
| @@ -144,9 +144,9 @@ void ForgeListLoadTask::executeTask() | ||||
| 	listJob->start(); | ||||
| } | ||||
|  | ||||
| void ForgeListLoadTask::abort() | ||||
| bool ForgeListLoadTask::abort() | ||||
| { | ||||
| 	listJob->abort(); | ||||
| 	return listJob->abort(); | ||||
| } | ||||
|  | ||||
| bool ForgeListLoadTask::parseForgeList(QList<BaseVersionPtr> &out) | ||||
|   | ||||
| @@ -66,7 +66,7 @@ public: | ||||
| 	explicit ForgeListLoadTask(ForgeVersionList *vlist); | ||||
|  | ||||
| 	virtual void executeTask(); | ||||
| 	virtual void abort(); | ||||
| 	virtual bool abort(); | ||||
|  | ||||
| protected | ||||
| slots: | ||||
|   | ||||
| @@ -68,9 +68,6 @@ signals: | ||||
| 	void started(); | ||||
| 	void finished(QList<JavaCheckResult>); | ||||
|  | ||||
| public slots: | ||||
| 	virtual void abort() {}; | ||||
|  | ||||
| private slots: | ||||
| 	void partFinished(JavaCheckResult result); | ||||
|  | ||||
|   | ||||
							
								
								
									
										26
									
								
								logic/launch/LaunchStep.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								logic/launch/LaunchStep.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| /* Copyright 2013-2015 MultiMC Contributors | ||||
|  * | ||||
|  * 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 "LaunchStep.h" | ||||
| #include "LaunchTask.h" | ||||
|  | ||||
| void LaunchStep::bind(LaunchTask *parent) | ||||
| { | ||||
| 	m_parent = parent; | ||||
| 	connect(this, &LaunchStep::readyForLaunch, parent, &LaunchTask::onReadyForLaunch); | ||||
| 	connect(this, &LaunchStep::logLine, parent, &LaunchTask::onLogLine); | ||||
| 	connect(this, &LaunchStep::logLines, parent, &LaunchTask::onLogLines); | ||||
| 	connect(this, &LaunchStep::finished, parent, &LaunchTask::onStepFinished); | ||||
| } | ||||
							
								
								
									
										47
									
								
								logic/launch/LaunchStep.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								logic/launch/LaunchStep.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| /* Copyright 2013-2015 MultiMC Contributors | ||||
|  * | ||||
|  * 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 "tasks/Task.h" | ||||
| #include "MessageLevel.h" | ||||
|  | ||||
| #include <QStringList> | ||||
|  | ||||
| class LaunchTask; | ||||
| class LaunchStep: public Task | ||||
| { | ||||
| 	Q_OBJECT | ||||
| public: /* methods */ | ||||
| 	explicit LaunchStep(LaunchTask *parent):Task(nullptr), m_parent(parent) | ||||
| 	{ | ||||
| 		bind(parent); | ||||
| 	}; | ||||
| 	virtual ~LaunchStep() {}; | ||||
|  | ||||
| protected: /* methods */ | ||||
| 	virtual void bind(LaunchTask *parent); | ||||
|  | ||||
| signals: | ||||
| 	void logLines(QStringList lines, MessageLevel::Enum level); | ||||
| 	void logLine(QString line, MessageLevel::Enum level); | ||||
| 	void readyForLaunch(); | ||||
|  | ||||
| public slots: | ||||
| 	virtual void proceed() {}; | ||||
|  | ||||
| protected: /* data */ | ||||
| 	LaunchTask *m_parent; | ||||
| }; | ||||
| @@ -27,105 +27,14 @@ | ||||
| #include <QRegularExpression> | ||||
| #include <QCoreApplication> | ||||
| #include <QStandardPaths> | ||||
|  | ||||
| #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()); | ||||
| 	} | ||||
| } | ||||
| #include <assert.h> | ||||
|  | ||||
| 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> LaunchTask::create(MinecraftInstancePtr inst) | ||||
| std::shared_ptr<LaunchTask> LaunchTask::create(InstancePtr inst) | ||||
| { | ||||
| 	std::shared_ptr<LaunchTask> proc(new LaunchTask(inst)); | ||||
| 	proc->init(); | ||||
| @@ -136,25 +45,77 @@ LaunchTask::LaunchTask(InstancePtr instance): m_instance(instance) | ||||
| { | ||||
| } | ||||
|  | ||||
| QString LaunchTask::censorPrivateInfo(QString in) | ||||
| void LaunchTask::appendStep(std::shared_ptr<LaunchStep> step) | ||||
| { | ||||
| 	if (!m_session) | ||||
| 		return in; | ||||
| 	m_steps.append(step); | ||||
| } | ||||
|  | ||||
| 	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>"); | ||||
| void LaunchTask::prependStep(std::shared_ptr<LaunchStep> step) | ||||
| { | ||||
| 	m_steps.prepend(step); | ||||
| } | ||||
|  | ||||
| 	auto i = m_session->u.properties.begin(); | ||||
| 	while (i != m_session->u.properties.end()) | ||||
| void LaunchTask::executeTask() | ||||
| { | ||||
| 	if(!m_steps.size()) | ||||
| 	{ | ||||
| 		in.replace(i.value(), "<" + i.key().toUpper() + ">"); | ||||
| 		++i; | ||||
| 		state = LaunchTask::Finished; | ||||
| 		emitSucceeded(); | ||||
| 	} | ||||
| 	state = LaunchTask::Running; | ||||
| 	onStepFinished(); | ||||
| } | ||||
|  | ||||
| void LaunchTask::onReadyForLaunch() | ||||
| { | ||||
| 	state = LaunchTask::Waiting; | ||||
| 	emit readyForLaunch(); | ||||
| } | ||||
|  | ||||
| void LaunchTask::onStepFinished() | ||||
| { | ||||
| 	// initial -> just start the first step | ||||
| 	if(currentStep == -1) | ||||
| 	{ | ||||
| 		currentStep ++; | ||||
| 		m_steps[currentStep]->start(); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	auto step = m_steps[currentStep]; | ||||
| 	if(step->successful()) | ||||
| 	{ | ||||
| 		// end? | ||||
| 		if(currentStep == m_steps.size() - 1) | ||||
| 		{ | ||||
| 			emitSucceeded(); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			currentStep ++; | ||||
| 			step = m_steps[currentStep]; | ||||
| 			step->start(); | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		emitFailed(step->failReason()); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void LaunchTask::setCensorFilter(QMap<QString, QString> filter) | ||||
| { | ||||
| 	m_censorFilter = filter; | ||||
| } | ||||
|  | ||||
| QString LaunchTask::censorPrivateInfo(QString in) | ||||
| { | ||||
| 	auto iter = m_censorFilter.begin(); | ||||
| 	while (iter != m_censorFilter.end()) | ||||
| 	{ | ||||
| 		in.replace(iter.key(), iter.value()); | ||||
| 		iter++; | ||||
| 	} | ||||
| 	return in; | ||||
| } | ||||
|  | ||||
| @@ -199,163 +160,58 @@ MessageLevel::Enum LaunchTask::guessLevel(const QString &line, MessageLevel::Enu | ||||
| 	return level; | ||||
| } | ||||
|  | ||||
| QMap<QString, QString> LaunchTask::getVariables() const | ||||
| void LaunchTask::proceed() | ||||
| { | ||||
| 	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; | ||||
| 	if(state != LaunchTask::Waiting) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
| 	m_steps[currentStep]->proceed(); | ||||
| } | ||||
|  | ||||
| QStringList LaunchTask::javaArguments() const | ||||
| bool LaunchTask::abort() | ||||
| { | ||||
| 	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) | ||||
| 	switch(state) | ||||
| 	{ | ||||
| 		auto permgen = m_instance->settings()->get("PermGen").toInt(); | ||||
| 		if (permgen != 64) | ||||
| 		case LaunchTask::Aborted: | ||||
| 		case LaunchTask::Failed: | ||||
| 		case LaunchTask::Finished: | ||||
| 			return true; | ||||
| 		case LaunchTask::NotStarted: | ||||
| 		{ | ||||
| 			args << QString("-XX:PermSize=%1m").arg(permgen); | ||||
| 			state = LaunchTask::Aborted; | ||||
| 			emitFailed("Aborted"); | ||||
| 			return true; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	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<JavaChecker>(); | ||||
| 		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) | ||||
| 		case LaunchTask::Running: | ||||
| 		case LaunchTask::Waiting: | ||||
| 		{ | ||||
| 			emit log(line, MessageLevel::Error); | ||||
| 			auto step = m_steps[currentStep]; | ||||
| 			if(!step->canAbort()) | ||||
| 			{ | ||||
| 				return false; | ||||
| 			} | ||||
| 			if(step->abort()) | ||||
| 			{ | ||||
| 				state = LaunchTask::Aborted; | ||||
| 				return true; | ||||
| 			} | ||||
| 		} | ||||
| 		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(); | ||||
| 		default: | ||||
| 			break; | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| 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) | ||||
| void LaunchTask::onLogLines(const QStringList &lines, MessageLevel::Enum defaultLevel) | ||||
| { | ||||
| 	for (auto & line: lines) | ||||
| 	{ | ||||
| 		logOutput(line, defaultLevel); | ||||
| 		onLogLine(line, defaultLevel); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void LaunchTask::logOutput(QString line, MessageLevel::Enum level) | ||||
| void LaunchTask::onLogLine(QString line, MessageLevel::Enum level) | ||||
| { | ||||
| 	// if the launcher part set a log level, use it | ||||
| 	auto innerLevel = MessageLevel::fromLine(line); | ||||
| @@ -376,230 +232,6 @@ void LaunchTask::logOutput(QString line, MessageLevel::Enum level) | ||||
| 	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(); | ||||
| @@ -617,7 +249,7 @@ void LaunchTask::emitFailed(QString reason) | ||||
| QString LaunchTask::substituteVariables(const QString &cmd) const | ||||
| { | ||||
| 	QString out = cmd; | ||||
| 	auto variables = getVariables(); | ||||
| 	auto variables = m_instance->getVariables(); | ||||
| 	for (auto it = variables.begin(); it != variables.end(); ++it) | ||||
| 	{ | ||||
| 		out.replace("$" + it.key(), it.value()); | ||||
| @@ -630,12 +262,3 @@ QString LaunchTask::substituteVariables(const QString &cmd) const | ||||
| 	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 | ||||
| } | ||||
|   | ||||
| @@ -20,6 +20,7 @@ | ||||
| #include "BaseInstance.h" | ||||
| #include "MessageLevel.h" | ||||
| #include "LoggedProcess.h" | ||||
| #include "LaunchStep.h" | ||||
| /* HACK: MINECRAFT: split! */ | ||||
| #include "minecraft/MinecraftInstance.h" | ||||
| #include "java/JavaChecker.h" | ||||
| @@ -39,26 +40,39 @@ protected: | ||||
| 	explicit LaunchTask(InstancePtr instance); | ||||
| 	void init(); | ||||
|  | ||||
| public: | ||||
| 	enum State | ||||
| 	{ | ||||
| 		NotStarted, | ||||
| 		Running, | ||||
| 		Waiting, | ||||
| 		Failed, | ||||
| 		Aborted, | ||||
| 		Finished | ||||
| 	}; | ||||
|  | ||||
| public: /* methods */ | ||||
| 	static std::shared_ptr<LaunchTask> create(MinecraftInstancePtr inst); | ||||
| 	static std::shared_ptr<LaunchTask> create(InstancePtr inst); | ||||
| 	virtual ~LaunchTask() {}; | ||||
|  | ||||
| 	void appendStep(std::shared_ptr<LaunchStep> step); | ||||
| 	void prependStep(std::shared_ptr<LaunchStep> step); | ||||
| 	void setCensorFilter(QMap<QString, QString> filter); | ||||
|  | ||||
| 	InstancePtr instance() | ||||
| 	{ | ||||
| 		return m_instance; | ||||
| 	} | ||||
|  | ||||
| 	/// Set the text printed on top of the log | ||||
| 	void setHeader(QString header) | ||||
| 	void setPid(qint64 pid) | ||||
| 	{ | ||||
| 		m_header = header; | ||||
| 		m_pid = pid; | ||||
| 	} | ||||
|  | ||||
| 	void setWorkdir(QString path); | ||||
|  | ||||
| 	void killProcess(); | ||||
|  | ||||
| 	qint64 pid(); | ||||
| 	qint64 pid() | ||||
| 	{ | ||||
| 		return m_pid; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @brief prepare the process for launch (for multi-stage launch) | ||||
| @@ -68,50 +82,24 @@ public: /* methods */ | ||||
| 	/** | ||||
| 	 * @brief launch the armed instance | ||||
| 	 */ | ||||
| 	virtual void launch(); | ||||
| 	void proceed(); | ||||
|  | ||||
| 	/** | ||||
| 	 * @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; | ||||
| 	} | ||||
| 	virtual bool abort() override; | ||||
|  | ||||
|  | ||||
| protected: /* methods */ | ||||
| 	void preLaunch(); | ||||
| 	void updateInstance(); | ||||
| 	void doJarModding(); | ||||
| 	void makeReady(); | ||||
| 	void postLaunch(); | ||||
| 	virtual void emitFailed(QString reason); | ||||
| 	virtual void emitSucceeded(); | ||||
|  | ||||
| public: /* HACK: remove this from here! */ | ||||
|  | ||||
| 	QString substituteVariables(const QString &cmd) const; | ||||
| 	void initializeEnvironment(); | ||||
|  | ||||
| 	void printHeader(); | ||||
|  | ||||
| 	virtual QMap<QString, QString> getVariables() const; | ||||
| 	virtual QString censorPrivateInfo(QString in); | ||||
| 	QString censorPrivateInfo(QString in); | ||||
| 	virtual MessageLevel::Enum guessLevel(const QString &message, MessageLevel::Enum defaultLevel); | ||||
|  | ||||
| protected slots: | ||||
| 	void jarModdingSucceeded(); | ||||
| 	void jarModdingFailed(QString reason); | ||||
| protected: /* methods */ | ||||
| 	virtual void emitFailed(QString reason); | ||||
| 	virtual void emitSucceeded(); | ||||
|  | ||||
| signals: | ||||
| 	/** | ||||
| @@ -126,53 +114,17 @@ signals: | ||||
| 	 */ | ||||
| 	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); | ||||
| public slots: | ||||
| 	void onLogLines(const QStringList& lines, MessageLevel::Enum defaultLevel = MessageLevel::MultiMC); | ||||
| 	void onLogLine(QString line, MessageLevel::Enum defaultLevel = MessageLevel::MultiMC); | ||||
| 	void onReadyForLaunch(); | ||||
| 	void onStepFinished(); | ||||
|  | ||||
| 	void on_pre_state(LoggedProcess::State state); | ||||
| 	void on_state(LoggedProcess::State state); | ||||
| 	void on_post_state(LoggedProcess::State state); | ||||
|  | ||||
|  | ||||
|  | ||||
| protected: | ||||
| protected: /* data */ | ||||
| 	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<JavaChecker> m_JavaChecker; | ||||
|  | ||||
| protected: /* HACK: MINECRAFT: split! */ | ||||
| 	AuthSessionPtr m_session; | ||||
| 	QString launchScript; | ||||
| 	QString m_nativeFolder; | ||||
| 	std::shared_ptr<Task> m_updateTask; | ||||
| 	std::shared_ptr<Task> m_jarModTask; | ||||
|  | ||||
| protected: /* HACK: MINECRAFT: split! */ | ||||
| 	void checkJava(); | ||||
| 	QStringList javaArguments() const; | ||||
| private slots: | ||||
| 	void updateFinished(); | ||||
| 	QList <std::shared_ptr<LaunchStep>> m_steps; | ||||
| 	QMap<QString, QString> m_censorFilter; | ||||
| 	int currentStep = -1; | ||||
| 	State state = NotStarted; | ||||
| 	qint64 m_pid = -1; | ||||
| }; | ||||
|  | ||||
| class BaseProfilerFactory; | ||||
| @@ -1,4 +1,20 @@ | ||||
| /* Copyright 2013-2015 MultiMC Contributors | ||||
|  * | ||||
|  * 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 <QProcess> | ||||
| #include "MessageLevel.h" | ||||
|  | ||||
| @@ -18,8 +34,7 @@ public: | ||||
| 		Running, | ||||
| 		Finished, | ||||
| 		Crashed, | ||||
| 		Aborted, | ||||
| 		Skipped | ||||
| 		Aborted | ||||
| 	}; | ||||
|  | ||||
| public: | ||||
|   | ||||
							
								
								
									
										71
									
								
								logic/launch/steps/CheckJava.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								logic/launch/steps/CheckJava.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| /* Copyright 2013-2015 MultiMC Contributors | ||||
|  * | ||||
|  * 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 "CheckJava.h" | ||||
| #include <launch/LaunchTask.h> | ||||
| #include <QStandardPaths> | ||||
|  | ||||
| void CheckJava::executeTask() | ||||
| { | ||||
| 	auto instance = m_parent->instance(); | ||||
| 	auto javaPath = instance->settings()->get("JavaPath").toString(); | ||||
| 	emit logLine("Java path is:\n" + m_javaPath + "\n\n", MessageLevel::MultiMC); | ||||
|  | ||||
| 	auto realJavaPath = QStandardPaths::findExecutable(m_javaPath); | ||||
| 	if (realJavaPath.isEmpty()) | ||||
| 	{ | ||||
| 		emit logLine(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 = instance->settings()->get("JavaTimestamp").toLongLong(); | ||||
| 	m_javaUnixTime = javaUnixTime; | ||||
| 	// if they are not the same, check! | ||||
| 	if(javaUnixTime != storedUnixTime) | ||||
| 	{ | ||||
| 		m_JavaChecker = std::make_shared<JavaChecker>(); | ||||
| 		bool successful = false; | ||||
| 		QString errorLog; | ||||
| 		QString version; | ||||
| 		emit logLine(tr("Checking Java version..."), MessageLevel::MultiMC); | ||||
| 		connect(m_JavaChecker.get(), &JavaChecker::checkFinished, this, &CheckJava::checkJavaFinished); | ||||
| 		m_JavaChecker->m_path = realJavaPath; | ||||
| 		m_JavaChecker->performCheck(); | ||||
| 	} | ||||
| 	emitSucceeded(); | ||||
| } | ||||
|  | ||||
| void CheckJava::checkJavaFinished(JavaCheckResult result) | ||||
| { | ||||
| 	if(!result.valid) | ||||
| 	{ | ||||
| 		// Error message displayed if java can't start | ||||
| 		emit logLine(tr("Could not start java:"), MessageLevel::Error); | ||||
| 		emit logLines(result.errorLog.split('\n'), MessageLevel::Error); | ||||
| 		emit logLine("\nCheck your MultiMC Java settings.", MessageLevel::MultiMC); | ||||
| 		emitFailed(tr("Could not start java!")); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		auto instance = m_parent->instance(); | ||||
| 		emit logLine(tr("Java version is %1!\n").arg(result.javaVersion), MessageLevel::MultiMC); | ||||
| 		instance->settings()->set("JavaVersion", result.javaVersion); | ||||
| 		instance->settings()->set("JavaTimestamp", m_javaUnixTime); | ||||
| 		emitSucceeded(); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										41
									
								
								logic/launch/steps/CheckJava.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								logic/launch/steps/CheckJava.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| /* Copyright 2013-2015 MultiMC Contributors | ||||
|  * | ||||
|  * 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 <launch/LaunchStep.h> | ||||
| #include <launch/LoggedProcess.h> | ||||
| #include <java/JavaChecker.h> | ||||
|  | ||||
| class CheckJava: public LaunchStep | ||||
| { | ||||
| 	Q_OBJECT | ||||
| public: | ||||
| 	explicit CheckJava(LaunchTask *parent) :LaunchStep(parent){}; | ||||
| 	virtual ~CheckJava() {}; | ||||
|  | ||||
| 	virtual void executeTask(); | ||||
| 	virtual bool canAbort() const | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| private slots: | ||||
| 	void checkJavaFinished(JavaCheckResult result); | ||||
|  | ||||
| private: | ||||
| 	QString m_javaPath; | ||||
| 	qlonglong m_javaUnixTime; | ||||
| 	JavaCheckerPtr m_JavaChecker; | ||||
| }; | ||||
							
								
								
									
										138
									
								
								logic/launch/steps/LaunchCommand.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								logic/launch/steps/LaunchCommand.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,138 @@ | ||||
| /* Copyright 2013-2015 MultiMC Contributors | ||||
|  * | ||||
|  * 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 "LaunchCommand.h" | ||||
| #include <launch/LaunchTask.h> | ||||
| #include <minecraft/OneSixInstance.h> | ||||
| #include <QStandardPaths> | ||||
|  | ||||
| LaunchCommand::LaunchCommand(LaunchTask *parent) : LaunchStep(parent) | ||||
| { | ||||
| 	connect(&m_process, &LoggedProcess::log, this, &LaunchCommand::logLines); | ||||
| 	connect(&m_process, &LoggedProcess::stateChanged, this, &LaunchCommand::on_state); | ||||
| } | ||||
|  | ||||
| void LaunchCommand::executeTask() | ||||
| { | ||||
| 	auto instance = m_parent->instance(); | ||||
| 	std::shared_ptr<MinecraftInstance> minecraftInstance = std::dynamic_pointer_cast<OneSixInstance>(instance); | ||||
| 	QStringList args = minecraftInstance->javaArguments(); | ||||
|  | ||||
| 	QString allArgs = args.join(", "); | ||||
| 	emit logLine("Java Arguments:\n[" + m_parent->censorPrivateInfo(allArgs) + "]\n\n", MessageLevel::MultiMC); | ||||
|  | ||||
| 	auto javaPath = instance->settings()->get("JavaPath").toString(); | ||||
|  | ||||
| 	m_process.setProcessEnvironment(instance->createEnvironment()); | ||||
|  | ||||
| 	QString wrapperCommand = instance->getWrapperCommand(); | ||||
| 	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 logLine(reason, MessageLevel::Fatal); | ||||
| 			emitFailed(reason); | ||||
| 			return; | ||||
| 		} | ||||
| 		emit logLine("Wrapper command is:\n" + wrapperCommand + "\n\n", MessageLevel::MultiMC); | ||||
| 		args.prepend(javaPath); | ||||
| 		m_process.start(wrapperCommand, args); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		m_process.start(javaPath, args); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void LaunchCommand::on_state(LoggedProcess::State state) | ||||
| { | ||||
| 	switch(state) | ||||
| 	{ | ||||
| 		case LoggedProcess::FailedToStart: | ||||
| 		{ | ||||
| 			//: Error message displayed if instace can't start | ||||
| 			QString reason = tr("Could not launch minecraft!"); | ||||
| 			emit logLine(reason, MessageLevel::Fatal); | ||||
| 			emitFailed(reason); | ||||
| 			return; | ||||
| 		} | ||||
| 		case LoggedProcess::Aborted: | ||||
| 		case LoggedProcess::Crashed: | ||||
|  | ||||
| 		{ | ||||
| 			m_parent->setPid(-1); | ||||
| 			emitFailed("Game crashed."); | ||||
| 			return; | ||||
| 		} | ||||
| 		case LoggedProcess::Finished: | ||||
| 		{ | ||||
| 			m_parent->setPid(-1); | ||||
| 			auto exitCode = m_process.exitCode(); | ||||
| 			//FIXME: make this work again | ||||
| 			// m_postlaunchprocess.processEnvironment().insert("INST_EXITCODE", QString(exitCode)); | ||||
| 			// run post-exit | ||||
| 			emitSucceeded(); | ||||
| 			break; | ||||
| 		} | ||||
| 		case LoggedProcess::Running: | ||||
| 			emit logLine(tr("Minecraft process ID: %1\n\n").arg(m_process.processId()), MessageLevel::MultiMC); | ||||
| 			m_parent->setPid(m_process.pid()); | ||||
| 			m_parent->instance()->setLastLaunch(); | ||||
| 			// send the launch script to the launcher part | ||||
| 			m_process.write(m_launchScript.toUtf8()); | ||||
|  | ||||
| 			mayProceed = true; | ||||
| 			emit readyForLaunch(); | ||||
| 			break; | ||||
| 		default: | ||||
| 			break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void LaunchCommand::setWorkingDirectory(const QString &wd) | ||||
| { | ||||
| 	m_process.setWorkingDirectory(wd); | ||||
| } | ||||
|  | ||||
| void LaunchCommand::proceed() | ||||
| { | ||||
| 	if(mayProceed) | ||||
| 	{ | ||||
| 		QString launchString("launch\n"); | ||||
| 		m_process.write(launchString.toUtf8()); | ||||
| 		mayProceed = false; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool LaunchCommand::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; | ||||
| } | ||||
							
								
								
									
										46
									
								
								logic/launch/steps/LaunchCommand.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								logic/launch/steps/LaunchCommand.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| /* Copyright 2013-2015 MultiMC Contributors | ||||
|  * | ||||
|  * 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 <launch/LaunchStep.h> | ||||
| #include <launch/LoggedProcess.h> | ||||
|  | ||||
| class LaunchCommand: public LaunchStep | ||||
| { | ||||
| 	Q_OBJECT | ||||
| public: | ||||
| 	explicit LaunchCommand(LaunchTask *parent); | ||||
| 	virtual void executeTask(); | ||||
| 	virtual bool abort(); | ||||
| 	virtual void proceed(); | ||||
| 	virtual bool canAbort() const | ||||
| 	{ | ||||
| 		return true; | ||||
| 	} | ||||
| 	void setWorkingDirectory(const QString &wd); | ||||
| 	void setLaunchScript(const QString &ls) | ||||
| 	{ | ||||
| 		m_launchScript = ls; | ||||
| 	} | ||||
| private slots: | ||||
| 	void on_state(LoggedProcess::State state); | ||||
|  | ||||
| private: | ||||
| 	LoggedProcess m_process; | ||||
| 	QString m_command; | ||||
| 	QString m_launchScript; | ||||
| 	bool mayProceed = false; | ||||
| }; | ||||
							
								
								
									
										44
									
								
								logic/launch/steps/ModMinecraftJar.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								logic/launch/steps/ModMinecraftJar.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| /* Copyright 2013-2015 MultiMC Contributors | ||||
|  * | ||||
|  * 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 "ModMinecraftJar.h" | ||||
| #include <launch/LaunchTask.h> | ||||
| #include <QStandardPaths> | ||||
|  | ||||
| void ModMinecraftJar::executeTask() | ||||
| { | ||||
| 	m_jarModTask = m_parent->instance()->createJarModdingTask(); | ||||
| 	if(m_jarModTask) | ||||
| 	{ | ||||
| 		connect(m_jarModTask.get(), SIGNAL(finished()), this, SLOT(jarModdingFinished())); | ||||
| 		m_jarModTask->start(); | ||||
| 		return; | ||||
| 	} | ||||
| 	emitSucceeded(); | ||||
| } | ||||
|  | ||||
| void ModMinecraftJar::jarModdingFinished() | ||||
| { | ||||
| 	if(m_jarModTask->successful()) | ||||
| 	{ | ||||
| 		emitSucceeded(); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		QString reason = tr("jar modding failed because: %1.\n\n").arg(m_jarModTask->failReason()); | ||||
| 		emit logLine(reason, MessageLevel::Fatal); | ||||
| 		emitFailed(reason); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										39
									
								
								logic/launch/steps/ModMinecraftJar.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								logic/launch/steps/ModMinecraftJar.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| /* Copyright 2013-2015 MultiMC Contributors | ||||
|  * | ||||
|  * 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 <launch/LaunchStep.h> | ||||
| #include <memory> | ||||
|  | ||||
| // FIXME: temporary wrapper for existing task. | ||||
| class ModMinecraftJar: public LaunchStep | ||||
| { | ||||
| 	Q_OBJECT | ||||
| public: | ||||
| 	explicit ModMinecraftJar(LaunchTask *parent) : LaunchStep(parent) {}; | ||||
| 	virtual ~ModMinecraftJar(){}; | ||||
|  | ||||
| 	virtual void executeTask(); | ||||
| 	virtual bool canAbort() const | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| private slots: | ||||
| 	void jarModdingFinished(); | ||||
|  | ||||
| private: | ||||
| 	std::shared_ptr<Task> m_jarModTask; | ||||
| }; | ||||
							
								
								
									
										70
									
								
								logic/launch/steps/PostLaunchCommand.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								logic/launch/steps/PostLaunchCommand.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | ||||
| /* Copyright 2013-2015 MultiMC Contributors | ||||
|  * | ||||
|  * 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 "PostLaunchCommand.h" | ||||
| #include <launch/LaunchTask.h> | ||||
|  | ||||
| PostLaunchCommand::PostLaunchCommand(LaunchTask *parent) : LaunchStep(parent) | ||||
| { | ||||
| 	auto instance = m_parent->instance(); | ||||
| 	m_command = instance->getPostExitCommand(); | ||||
| 	m_process.setProcessEnvironment(instance->createEnvironment()); | ||||
| 	connect(&m_process, &LoggedProcess::log, this, &PostLaunchCommand::logLines); | ||||
| 	connect(&m_process, &LoggedProcess::stateChanged, this, &PostLaunchCommand::on_state); | ||||
| } | ||||
|  | ||||
| void PostLaunchCommand::executeTask() | ||||
| { | ||||
| 	QString postlaunch_cmd = m_parent->substituteVariables(m_command); | ||||
| 	emit logLine(tr("Running Post-Launch command: %1").arg(postlaunch_cmd), MessageLevel::MultiMC); | ||||
| 	m_process.start(postlaunch_cmd); | ||||
| } | ||||
|  | ||||
| void PostLaunchCommand::on_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_process.exitCode()); | ||||
| 			emit logLine(error, MessageLevel::Error); | ||||
| 			emitFailed(error); | ||||
| 		} | ||||
| 		case LoggedProcess::Finished: | ||||
| 		{ | ||||
| 			emit logLine(tr("Post-Launch command ran successfully.\n\n"), MessageLevel::MultiMC); | ||||
| 			emitSucceeded(); | ||||
| 		} | ||||
| 		default: | ||||
| 			break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void PostLaunchCommand::setWorkingDirectory(const QString &wd) | ||||
| { | ||||
| 	m_process.setWorkingDirectory(wd); | ||||
| } | ||||
|  | ||||
| bool PostLaunchCommand::abort() | ||||
| { | ||||
| 	auto state = m_process.state(); | ||||
| 	if (state == LoggedProcess::Running || state == LoggedProcess::Starting) | ||||
| 	{ | ||||
| 		m_process.kill(); | ||||
| 	} | ||||
| 	return true; | ||||
| } | ||||
							
								
								
									
										39
									
								
								logic/launch/steps/PostLaunchCommand.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								logic/launch/steps/PostLaunchCommand.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| /* Copyright 2013-2015 MultiMC Contributors | ||||
|  * | ||||
|  * 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 <launch/LaunchStep.h> | ||||
| #include <launch/LoggedProcess.h> | ||||
|  | ||||
| class PostLaunchCommand: public LaunchStep | ||||
| { | ||||
| 	Q_OBJECT | ||||
| public: | ||||
| 	explicit PostLaunchCommand(LaunchTask *parent); | ||||
| 	virtual void executeTask(); | ||||
| 	virtual bool abort(); | ||||
| 	virtual bool canAbort() const | ||||
| 	{ | ||||
| 		return true; | ||||
| 	} | ||||
| 	void setWorkingDirectory(const QString &wd); | ||||
| private slots: | ||||
| 	void on_state(LoggedProcess::State state); | ||||
|  | ||||
| private: | ||||
| 	LoggedProcess m_process; | ||||
| 	QString m_command; | ||||
| }; | ||||
							
								
								
									
										72
									
								
								logic/launch/steps/PreLaunchCommand.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								logic/launch/steps/PreLaunchCommand.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| /* Copyright 2013-2015 MultiMC Contributors | ||||
|  * | ||||
|  * 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 "PreLaunchCommand.h" | ||||
| #include <launch/LaunchTask.h> | ||||
|  | ||||
| PreLaunchCommand::PreLaunchCommand(LaunchTask *parent) : LaunchStep(parent) | ||||
| { | ||||
| 	auto instance = m_parent->instance(); | ||||
| 	m_command = instance->getPreLaunchCommand(); | ||||
| 	m_process.setProcessEnvironment(instance->createEnvironment()); | ||||
| 	connect(&m_process, &LoggedProcess::log, this, &PreLaunchCommand::logLines); | ||||
| 	connect(&m_process, &LoggedProcess::stateChanged, this, &PreLaunchCommand::on_state); | ||||
| } | ||||
|  | ||||
| void PreLaunchCommand::executeTask() | ||||
| { | ||||
| 	//FIXME: where to put this? | ||||
| 	QString prelaunch_cmd = m_parent->substituteVariables(m_command); | ||||
| 	emit logLine(tr("Running Pre-Launch command: %1").arg(prelaunch_cmd), MessageLevel::MultiMC); | ||||
| 	m_process.start(prelaunch_cmd); | ||||
| } | ||||
|  | ||||
| void PreLaunchCommand::on_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_process.exitCode()); | ||||
| 			emit logLine(error, MessageLevel::Fatal); | ||||
| 			emitFailed(error); | ||||
| 			return; | ||||
| 		} | ||||
| 		case LoggedProcess::Finished: | ||||
| 		{ | ||||
| 			emit logLine(tr("Pre-Launch command ran successfully.\n\n"), MessageLevel::MultiMC); | ||||
| 			emitSucceeded(); | ||||
| 		} | ||||
| 		default: | ||||
| 			break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void PreLaunchCommand::setWorkingDirectory(const QString &wd) | ||||
| { | ||||
| 	m_process.setWorkingDirectory(wd); | ||||
| } | ||||
|  | ||||
| bool PreLaunchCommand::abort() | ||||
| { | ||||
| 	auto state = m_process.state(); | ||||
| 	if (state == LoggedProcess::Running || state == LoggedProcess::Starting) | ||||
| 	{ | ||||
| 		m_process.kill(); | ||||
| 	} | ||||
| 	return true; | ||||
| } | ||||
							
								
								
									
										39
									
								
								logic/launch/steps/PreLaunchCommand.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								logic/launch/steps/PreLaunchCommand.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| /* Copyright 2013-2015 MultiMC Contributors | ||||
|  * | ||||
|  * 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 <launch/LaunchStep.h> | ||||
| #include <launch/LoggedProcess.h> | ||||
|  | ||||
| class PreLaunchCommand: public LaunchStep | ||||
| { | ||||
| 	Q_OBJECT | ||||
| public: | ||||
| 	explicit PreLaunchCommand(LaunchTask *parent); | ||||
| 	virtual void executeTask(); | ||||
| 	virtual bool abort(); | ||||
| 	virtual bool canAbort() const | ||||
| 	{ | ||||
| 		return true; | ||||
| 	} | ||||
| 	void setWorkingDirectory(const QString &wd); | ||||
| private slots: | ||||
| 	void on_state(LoggedProcess::State state); | ||||
|  | ||||
| private: | ||||
| 	LoggedProcess m_process; | ||||
| 	QString m_command; | ||||
| }; | ||||
							
								
								
									
										29
									
								
								logic/launch/steps/TextPrint.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								logic/launch/steps/TextPrint.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| #include "TextPrint.h" | ||||
|  | ||||
| TextPrint::TextPrint(LaunchTask * parent, const QStringList &lines, MessageLevel::Enum level) : LaunchStep(parent) | ||||
| { | ||||
| 	m_lines = lines; | ||||
| 	m_level = level; | ||||
| } | ||||
| TextPrint::TextPrint(LaunchTask *parent, const QString &line, MessageLevel::Enum level) : LaunchStep(parent) | ||||
| { | ||||
| 	m_lines.append(line); | ||||
| 	m_level = level; | ||||
| } | ||||
|  | ||||
| void TextPrint::executeTask() | ||||
| { | ||||
| 	emit logLines(m_lines, m_level); | ||||
| 	emitSucceeded(); | ||||
| } | ||||
|  | ||||
| bool TextPrint::canAbort() const | ||||
| { | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| bool TextPrint::abort() | ||||
| { | ||||
| 	emitFailed("Aborted."); | ||||
| 	return true; | ||||
| } | ||||
							
								
								
									
										37
									
								
								logic/launch/steps/TextPrint.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								logic/launch/steps/TextPrint.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| /* Copyright 2013-2015 MultiMC Contributors | ||||
|  * | ||||
|  * 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 <launch/LaunchStep.h> | ||||
| #include <launch/LoggedProcess.h> | ||||
| #include <java/JavaChecker.h> | ||||
|  | ||||
| class TextPrint: public LaunchStep | ||||
| { | ||||
| 	Q_OBJECT | ||||
| public: | ||||
| 	explicit TextPrint(LaunchTask *parent, const QStringList &lines, MessageLevel::Enum level); | ||||
| 	explicit TextPrint(LaunchTask *parent, const QString &line, MessageLevel::Enum level); | ||||
| 	virtual ~TextPrint(){}; | ||||
|  | ||||
| 	virtual void executeTask(); | ||||
| 	virtual bool canAbort() const; | ||||
| 	virtual bool abort(); | ||||
|  | ||||
| private: | ||||
| 	QStringList m_lines; | ||||
| 	MessageLevel::Enum m_level; | ||||
| }; | ||||
							
								
								
									
										43
									
								
								logic/launch/steps/Update.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								logic/launch/steps/Update.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| /* Copyright 2013-2015 MultiMC Contributors | ||||
|  * | ||||
|  * 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 "Update.h" | ||||
| #include <launch/LaunchTask.h> | ||||
|  | ||||
| void Update::executeTask() | ||||
| { | ||||
| 	m_updateTask = m_parent->instance()->createUpdateTask(); | ||||
| 	if(m_updateTask) | ||||
| 	{ | ||||
| 		connect(m_updateTask.get(), SIGNAL(finished()), this, SLOT(updateFinished())); | ||||
| 		m_updateTask->start(); | ||||
| 		return; | ||||
| 	} | ||||
| 	emitSucceeded(); | ||||
| } | ||||
|  | ||||
| void Update::updateFinished() | ||||
| { | ||||
| 	if(m_updateTask->successful()) | ||||
| 	{ | ||||
| 		emitSucceeded(); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		QString reason = tr("Instance update failed because: %1.\n\n").arg(m_updateTask->failReason()); | ||||
| 		emit logLine(reason, MessageLevel::Fatal); | ||||
| 		emitFailed(reason); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										40
									
								
								logic/launch/steps/Update.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								logic/launch/steps/Update.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| /* Copyright 2013-2015 MultiMC Contributors | ||||
|  * | ||||
|  * 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 <launch/LaunchStep.h> | ||||
| #include <launch/LoggedProcess.h> | ||||
| #include <java/JavaChecker.h> | ||||
|  | ||||
| // FIXME: stupid. should be defined by the instance type? or even completely abstracted away... | ||||
| class Update: public LaunchStep | ||||
| { | ||||
| 	Q_OBJECT | ||||
| public: | ||||
| 	explicit Update(LaunchTask *parent):LaunchStep(parent) {}; | ||||
| 	virtual ~Update() {}; | ||||
|  | ||||
| 	virtual void executeTask(); | ||||
| 	virtual bool canAbort() const | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| private slots: | ||||
| 	void updateFinished(); | ||||
|  | ||||
| private: | ||||
| 	std::shared_ptr<Task> m_updateTask; | ||||
| }; | ||||
| @@ -124,9 +124,9 @@ std::shared_ptr<LaunchTask> LegacyInstance::createLaunchTask(AuthSessionPtr acco | ||||
| 		launchScript += "launcher legacy\n"; | ||||
| 	} | ||||
| 	auto process = LaunchTask::create(std::dynamic_pointer_cast<MinecraftInstance>(getSharedPtr())); | ||||
| 	process->setLaunchScript(launchScript); | ||||
| 	process->setWorkdir(minecraftRoot()); | ||||
| 	process->setLogin(account); | ||||
| 	// process->setLaunchScript(launchScript); | ||||
| 	// process->setWorkdir(minecraftRoot()); | ||||
| 	// process->setLogin(account); | ||||
| 	return process; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -4,6 +4,9 @@ | ||||
| #include <pathutils.h> | ||||
| #include "Env.h" | ||||
| #include "minecraft/MinecraftVersionList.h" | ||||
| #include <MMCStrings.h> | ||||
|  | ||||
| #define IBUS "@im=ibus" | ||||
|  | ||||
| // all of this because keeping things compatible with deprecated old settings | ||||
| // if either of the settings {a, b} is true, this also resolves to true | ||||
| @@ -72,4 +75,133 @@ std::shared_ptr< BaseVersionList > MinecraftInstance::versionList() const | ||||
| 	return ENV.getVersionList("net.minecraft"); | ||||
| } | ||||
|  | ||||
| QStringList MinecraftInstance::javaArguments() const | ||||
| { | ||||
| 	QStringList args; | ||||
|  | ||||
| 	// custom args go first. we want to override them if we have our own here. | ||||
| 	args.append(extraArguments()); | ||||
|  | ||||
| 	// OSX dock icon and name | ||||
| #ifdef Q_OS_MAC | ||||
| 	args << "-Xdock:icon=icon.png"; | ||||
| 	args << QString("-Xdock:name=\"%1\"").arg(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(settings()->get("MinMemAlloc").toInt()); | ||||
| 	args << QString("-Xmx%1m").arg(settings()->get("MaxMemAlloc").toInt()); | ||||
|  | ||||
| 	// No PermGen in newer java. | ||||
| 	auto javaVersion = settings()->get("JavaVersion"); | ||||
| 	if(Strings::naturalCompare(javaVersion.toString(), "1.8.0", Qt::CaseInsensitive) < 0) | ||||
| 	{ | ||||
| 		auto permgen = settings()->get("PermGen").toInt(); | ||||
| 		if (permgen != 64) | ||||
| 		{ | ||||
| 			args << QString("-XX:PermSize=%1m").arg(permgen); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	args << "-Duser.language=en"; | ||||
| 	args << "-jar" << PathCombine(QCoreApplication::applicationDirPath(), "jars", "NewLaunch.jar"); | ||||
|  | ||||
| 	return args; | ||||
| } | ||||
|  | ||||
| QMap<QString, QString> MinecraftInstance::getVariables() const | ||||
| { | ||||
| 	QMap<QString, QString> out; | ||||
| 	out.insert("INST_NAME", name()); | ||||
| 	out.insert("INST_ID", id()); | ||||
| 	out.insert("INST_DIR", QDir(instanceRoot()).absolutePath()); | ||||
| 	out.insert("INST_MC_DIR", QDir(minecraftRoot()).absolutePath()); | ||||
| 	out.insert("INST_JAVA", settings()->get("JavaPath").toString()); | ||||
| 	out.insert("INST_JAVA_ARGS", javaArguments().join(' ')); | ||||
| 	return out; | ||||
| } | ||||
|  | ||||
| QProcessEnvironment MinecraftInstance::createEnvironment() | ||||
| { | ||||
| 	// prepare the process environment | ||||
| 	QProcessEnvironment rawenv = QProcessEnvironment::systemEnvironment(); | ||||
| 	QProcessEnvironment env; | ||||
|  | ||||
| 	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") | ||||
| 		{ | ||||
| 			env.insert("LD_PRELOAD", value); | ||||
| 			continue; | ||||
| 		} | ||||
| 		if(key == "GAME_LIBRARY_PATH") | ||||
| 		{ | ||||
| 			env.insert("LD_LIBRARY_PATH", value); | ||||
| 			continue; | ||||
| 		} | ||||
| #endif | ||||
| 		qDebug() << "Env: " << key << value; | ||||
| 		env.insert(key, value); | ||||
| 	} | ||||
| #ifdef Q_OS_LINUX | ||||
| 	// HACK: Workaround for QTBUG42500 | ||||
| 	if(!env.contains("LD_LIBRARY_PATH")) | ||||
| 	{ | ||||
| 		env.insert("LD_LIBRARY_PATH", ""); | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| 	// export some infos | ||||
| 	auto variables = getVariables(); | ||||
| 	for (auto it = variables.begin(); it != variables.end(); ++it) | ||||
| 	{ | ||||
| 		env.insert(it.key(), it.value()); | ||||
| 	} | ||||
| 	return env; | ||||
| } | ||||
|  | ||||
| #include "MinecraftInstance.moc" | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| #pragma once | ||||
| #include "BaseInstance.h" | ||||
| #include "minecraft/Mod.h" | ||||
| #include <QProcess> | ||||
|  | ||||
| class ModList; | ||||
|  | ||||
| @@ -27,7 +28,18 @@ public: | ||||
| 	{ | ||||
| 		return QList<Mod>(); | ||||
| 	} | ||||
|  | ||||
| 	//FIXME: nuke? | ||||
| 	virtual std::shared_ptr< BaseVersionList > versionList() const; | ||||
|  | ||||
| 	/// get arguments passed to java | ||||
| 	QStringList javaArguments() const; | ||||
|  | ||||
| 	/// get variables for launch command variable substitution/environment | ||||
| 	virtual QMap<QString, QString> getVariables() const override; | ||||
|  | ||||
| 	/// create an environment for launching processes | ||||
| 	virtual QProcessEnvironment createEnvironment() override; | ||||
| }; | ||||
|  | ||||
| typedef std::shared_ptr<MinecraftInstance> MinecraftInstancePtr; | ||||
|   | ||||
| @@ -23,6 +23,12 @@ | ||||
| #include "minecraft/MinecraftProfile.h" | ||||
| #include "minecraft/VersionBuildError.h" | ||||
| #include "launch/LaunchTask.h" | ||||
| #include <launch/steps/PreLaunchCommand.h> | ||||
| #include <launch/steps/Update.h> | ||||
| #include <launch/steps/LaunchCommand.h> | ||||
| #include <launch/steps/PostLaunchCommand.h> | ||||
| #include <launch/steps/TextPrint.h> | ||||
| #include <launch/steps/ModMinecraftJar.h> | ||||
| #include "minecraft/OneSixProfileStrategy.h" | ||||
| #include "MMCZip.h" | ||||
|  | ||||
| @@ -231,9 +237,62 @@ std::shared_ptr<LaunchTask> OneSixInstance::createLaunchTask(AuthSessionPtr sess | ||||
| 	launchScript += "launcher onesix\n"; | ||||
|  | ||||
| 	auto process = LaunchTask::create(std::dynamic_pointer_cast<MinecraftInstance>(getSharedPtr())); | ||||
| 	process->setLaunchScript(launchScript); | ||||
| 	process->setWorkdir(minecraftRoot()); | ||||
| 	process->setLogin(session); | ||||
| 	auto pptr = process.get(); | ||||
|  | ||||
| 	// print a header | ||||
| 	{ | ||||
| 		process->appendStep(std::make_shared<TextPrint>(pptr, "Minecraft folder is:\n" + minecraftRoot() + "\n\n", MessageLevel::MultiMC)); | ||||
| 	} | ||||
| 	// run pre-launch command if that's needed | ||||
| 	if(getPreLaunchCommand().size()) | ||||
| 	{ | ||||
| 		auto step = std::make_shared<PreLaunchCommand>(pptr); | ||||
| 		step->setWorkingDirectory(minecraftRoot()); | ||||
| 		process->appendStep(step); | ||||
| 	} | ||||
| 	// if we aren't in offline mode,. | ||||
| 	if(session->status != AuthSession::PlayableOffline) | ||||
| 	{ | ||||
| 		process->appendStep(std::make_shared<Update>(pptr)); | ||||
| 	} | ||||
| 	// if there are any jar mods | ||||
| 	if(getJarMods().size()) | ||||
| 	{ | ||||
| 		auto step = std::make_shared<ModMinecraftJar>(pptr); | ||||
| 		process->appendStep(step); | ||||
| 	} | ||||
| 	// actually launch the game | ||||
| 	{ | ||||
| 		auto step = std::make_shared<LaunchCommand>(pptr); | ||||
| 		step->setWorkingDirectory(minecraftRoot()); | ||||
| 		step->setLaunchScript(launchScript); | ||||
| 		process->appendStep(step); | ||||
| 	} | ||||
| 	// run post-exit command if that's needed | ||||
| 	if(getPostExitCommand().size()) | ||||
| 	{ | ||||
| 		auto step = std::make_shared<PostLaunchCommand>(pptr); | ||||
| 		step->setWorkingDirectory(minecraftRoot()); | ||||
| 		process->appendStep(step); | ||||
| 	} | ||||
| 	if (session) | ||||
| 	{ | ||||
| 		QMap<QString, QString> filter; | ||||
| 		if (session->session != "-") | ||||
| 			filter[session->session] = tr("<SESSION ID>"); | ||||
| 		filter[session->access_token] = tr("<ACCESS TOKEN>"); | ||||
| 		filter[session->client_token] = tr("<CLIENT TOKEN>"); | ||||
| 		filter[session->uuid] = tr("<PROFILE ID>"); | ||||
| 		filter[session->player_name] = tr("<PROFILE NAME>"); | ||||
|  | ||||
| 		auto i = session->u.properties.begin(); | ||||
| 		while (i != session->u.properties.end()) | ||||
| 		{ | ||||
| 			filter[i.value()] = "<" + i.key().toUpper() + ">"; | ||||
| 			++i; | ||||
| 		} | ||||
| 		process->setCensorFilter(filter); | ||||
| 	} | ||||
| 	return process; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -89,7 +89,7 @@ private slots: | ||||
| public slots: | ||||
| 	virtual void executeTask(); | ||||
| 	// FIXME: implement | ||||
| 	virtual void abort() {}; | ||||
| 	virtual bool abort() {return false;}; | ||||
|  | ||||
| private slots: | ||||
| 	void partProgress(int index, qint64 bytesReceived, qint64 bytesTotal); | ||||
|   | ||||
| @@ -52,7 +52,7 @@ signals: | ||||
| public | ||||
| slots: | ||||
| 	virtual void start(); | ||||
| 	virtual void abort() {}; | ||||
| 	virtual bool abort() { return false; }; | ||||
|  | ||||
| protected: | ||||
| 	virtual void executeTask() = 0; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user