GH-1053 move instance update into the launch task (BaseLauncher)
This commit is contained in:
parent
5628d3d379
commit
526a511f45
@ -53,7 +53,7 @@ private:
|
||||
BasePage * m_log_page;
|
||||
};
|
||||
|
||||
ConsoleWindow::ConsoleWindow(BaseLauncher *process, QWidget *parent)
|
||||
ConsoleWindow::ConsoleWindow(std::shared_ptr<BaseLauncher> process, QWidget *parent)
|
||||
: QMainWindow(parent), m_proc(process)
|
||||
{
|
||||
MultiMCPlatform::fixWM_CLASS(this);
|
||||
@ -129,11 +129,11 @@ ConsoleWindow::ConsoleWindow(BaseLauncher *process, QWidget *parent)
|
||||
}
|
||||
|
||||
// Set up signal connections
|
||||
connect(m_proc, SIGNAL(ended(InstancePtr, int, QProcess::ExitStatus)), this,
|
||||
connect(m_proc.get(), SIGNAL(ended(InstancePtr, int, QProcess::ExitStatus)), this,
|
||||
SLOT(onEnded(InstancePtr, int, QProcess::ExitStatus)));
|
||||
connect(m_proc, SIGNAL(prelaunch_failed(InstancePtr, int, QProcess::ExitStatus)), this,
|
||||
connect(m_proc.get(), SIGNAL(prelaunch_failed(InstancePtr, int, QProcess::ExitStatus)), this,
|
||||
SLOT(onEnded(InstancePtr, int, QProcess::ExitStatus)));
|
||||
connect(m_proc, SIGNAL(launch_failed(InstancePtr)), this,
|
||||
connect(m_proc.get(), SIGNAL(launch_failed(InstancePtr)), this,
|
||||
SLOT(onLaunchFailed(InstancePtr)));
|
||||
|
||||
setMayClose(false);
|
||||
|
@ -26,7 +26,7 @@ class ConsoleWindow : public QMainWindow
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConsoleWindow(BaseLauncher *proc, QWidget *parent = 0);
|
||||
explicit ConsoleWindow(std::shared_ptr<BaseLauncher> proc, QWidget *parent = 0);
|
||||
virtual ~ConsoleWindow();
|
||||
|
||||
/**
|
||||
@ -56,7 +56,7 @@ protected:
|
||||
void closeEvent(QCloseEvent *);
|
||||
|
||||
private:
|
||||
BaseLauncher *m_proc = nullptr;
|
||||
std::shared_ptr<BaseLauncher> m_proc;
|
||||
bool m_mayclose = true;
|
||||
QSystemTrayIcon *m_trayIcon = nullptr;
|
||||
PageContainer *m_container = nullptr;
|
||||
|
@ -1699,39 +1699,14 @@ void MainWindow::doLaunch(bool online, BaseProfilerFactory *profiler)
|
||||
}
|
||||
case AuthSession::PlayableOnline:
|
||||
{
|
||||
// update first if the server actually responded
|
||||
if (session->auth_server_online)
|
||||
{
|
||||
updateInstance(m_selectedInstance, session, profiler);
|
||||
}
|
||||
else
|
||||
{
|
||||
launchInstance(m_selectedInstance, session, profiler);
|
||||
}
|
||||
launchInstance(m_selectedInstance, session, profiler);
|
||||
tryagain = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::updateInstance(InstancePtr instance, AuthSessionPtr session,
|
||||
BaseProfilerFactory *profiler)
|
||||
{
|
||||
auto updateTask = instance->doUpdate();
|
||||
if (!updateTask)
|
||||
{
|
||||
launchInstance(instance, session, profiler);
|
||||
return;
|
||||
}
|
||||
ProgressDialog tDialog(this);
|
||||
connect(updateTask.get(), &Task::succeeded, [this, instance, session, profiler]
|
||||
{ launchInstance(instance, session, profiler); });
|
||||
connect(updateTask.get(), SIGNAL(failed(QString)), SLOT(onGameUpdateError(QString)));
|
||||
tDialog.exec(updateTask.get());
|
||||
}
|
||||
|
||||
void MainWindow::launchInstance(InstancePtr instance, AuthSessionPtr session,
|
||||
BaseProfilerFactory *profiler)
|
||||
void MainWindow::launchInstance(InstancePtr instance, AuthSessionPtr session, BaseProfilerFactory *profiler)
|
||||
{
|
||||
Q_ASSERT_X(instance != NULL, "launchInstance", "instance is NULL");
|
||||
Q_ASSERT_X(session.get() != nullptr, "launchInstance", "session is NULL");
|
||||
@ -1744,35 +1719,43 @@ void MainWindow::launchInstance(InstancePtr instance, AuthSessionPtr session,
|
||||
return;
|
||||
}
|
||||
|
||||
BaseLauncher *proc = instance->prepareForLaunch(session);
|
||||
auto proc = instance->prepareForLaunch(session);
|
||||
if (!proc)
|
||||
return;
|
||||
|
||||
proc->setProfiler(profiler);
|
||||
|
||||
this->hide();
|
||||
|
||||
console = new ConsoleWindow(proc);
|
||||
connect(console, &ConsoleWindow::isClosing, this, &MainWindow::instanceEnded);
|
||||
connect(proc.get(), &BaseLauncher::readyForLaunch, this, &MainWindow::readyForLaunch);
|
||||
|
||||
proc->setHeader("MultiMC version: " + BuildConfig.printableVersionString() + "\n\n");
|
||||
proc->arm();
|
||||
proc->start();
|
||||
}
|
||||
|
||||
void MainWindow::readyForLaunch(std::shared_ptr<BaseLauncher> launcher)
|
||||
{
|
||||
auto profiler = launcher->getProfiler();
|
||||
|
||||
if (!profiler)
|
||||
{
|
||||
proc->launch();
|
||||
launcher->launch();
|
||||
return;
|
||||
}
|
||||
|
||||
QString error;
|
||||
if (!profiler->check(&error))
|
||||
{
|
||||
proc->abort();
|
||||
launcher->abort();
|
||||
QMessageBox::critical(this, tr("Error"), tr("Couldn't start profiler: %1").arg(error));
|
||||
return;
|
||||
}
|
||||
BaseProfiler *profilerInstance = profiler->createProfiler(instance, this);
|
||||
BaseProfiler *profilerInstance = profiler->createProfiler(launcher->instance(), this);
|
||||
|
||||
connect(profilerInstance, &BaseProfiler::readyToLaunch,
|
||||
[this, proc](const QString & message)
|
||||
[this, launcher](const QString & message)
|
||||
{
|
||||
QMessageBox msg;
|
||||
msg.setText(tr("The game launch is delayed until you press the "
|
||||
@ -1783,10 +1766,10 @@ void MainWindow::launchInstance(InstancePtr instance, AuthSessionPtr session,
|
||||
msg.addButton(tr("Launch"), QMessageBox::AcceptRole);
|
||||
msg.setModal(true);
|
||||
msg.exec();
|
||||
proc->launch();
|
||||
launcher->launch();
|
||||
});
|
||||
connect(profilerInstance, &BaseProfiler::abortLaunch,
|
||||
[this, proc](const QString & message)
|
||||
[this, launcher](const QString & message)
|
||||
{
|
||||
QMessageBox msg;
|
||||
msg.setText(tr("Couldn't start the profiler: %1").arg(message));
|
||||
@ -1795,17 +1778,17 @@ void MainWindow::launchInstance(InstancePtr instance, AuthSessionPtr session,
|
||||
msg.addButton(QMessageBox::Ok);
|
||||
msg.setModal(true);
|
||||
msg.exec();
|
||||
proc->abort();
|
||||
launcher->abort();
|
||||
});
|
||||
profilerInstance->beginProfiling(proc);
|
||||
profilerInstance->beginProfiling(launcher);
|
||||
}
|
||||
|
||||
/*
|
||||
void MainWindow::onGameUpdateError(QString error)
|
||||
{
|
||||
CustomMessageBox::selectable(this, tr("Error updating instance"), error,
|
||||
QMessageBox::Warning)->show();
|
||||
}
|
||||
|
||||
*/
|
||||
void MainWindow::taskStart()
|
||||
{
|
||||
// Nothing to do here yet.
|
||||
|
@ -128,12 +128,7 @@ slots:
|
||||
*/
|
||||
void launchInstance(InstancePtr instance, AuthSessionPtr session, BaseProfilerFactory *profiler = 0);
|
||||
|
||||
/*!
|
||||
* Prepares the given instance for launch with the given account.
|
||||
*/
|
||||
void updateInstance(InstancePtr instance, AuthSessionPtr account, BaseProfilerFactory *profiler = 0);
|
||||
|
||||
void onGameUpdateError(QString error);
|
||||
void readyForLaunch(std::shared_ptr<BaseLauncher>);
|
||||
|
||||
void taskStart();
|
||||
void taskEnd();
|
||||
@ -196,7 +191,6 @@ private:
|
||||
class GroupView *view;
|
||||
InstanceProxyModel *proxymodel;
|
||||
NetJobPtr skin_download_job;
|
||||
MinecraftLauncher *proc;
|
||||
ConsoleWindow *console;
|
||||
LabeledToolButton *renameButton;
|
||||
QToolButton *changeIconButton;
|
||||
|
@ -11,12 +11,12 @@
|
||||
#include <settings/Setting.h>
|
||||
#include "GuiUtil.h"
|
||||
|
||||
LogPage::LogPage(BaseLauncher *proc, QWidget *parent)
|
||||
LogPage::LogPage(std::shared_ptr<BaseLauncher> proc, QWidget *parent)
|
||||
: QWidget(parent), ui(new Ui::LogPage), m_process(proc)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->tabWidget->tabBar()->hide();
|
||||
connect(m_process, SIGNAL(log(QString, MessageLevel::Enum)), this,
|
||||
connect(m_process.get(), SIGNAL(log(QString, MessageLevel::Enum)), this,
|
||||
SLOT(write(QString, MessageLevel::Enum)));
|
||||
|
||||
// create the format and set its font
|
||||
|
@ -33,7 +33,7 @@ class LogPage : public QWidget, public BasePage
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit LogPage(BaseLauncher *proc, QWidget *parent = 0);
|
||||
explicit LogPage(std::shared_ptr<BaseLauncher> proc, QWidget *parent = 0);
|
||||
virtual ~LogPage();
|
||||
virtual QString displayName() const override
|
||||
{
|
||||
@ -77,7 +77,7 @@ private slots:
|
||||
|
||||
private:
|
||||
Ui::LogPage *ui;
|
||||
BaseLauncher *m_process;
|
||||
std::shared_ptr<BaseLauncher> m_process;
|
||||
int m_last_scroll_value = 0;
|
||||
bool m_scroll_active = true;
|
||||
int m_saved_offset = 0;
|
||||
|
@ -138,7 +138,7 @@ public:
|
||||
virtual std::shared_ptr<Task> doUpdate() = 0;
|
||||
|
||||
/// returns a valid process, ready for launch with the given account.
|
||||
virtual BaseLauncher *prepareForLaunch(AuthSessionPtr account) = 0;
|
||||
virtual std::shared_ptr<BaseLauncher> prepareForLaunch(AuthSessionPtr account) = 0;
|
||||
|
||||
/// do any necessary cleanups after the instance finishes. also runs before
|
||||
/// 'prepareForLaunch'
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "MessageLevel.h"
|
||||
#include "MMCStrings.h"
|
||||
#include "java/JavaChecker.h"
|
||||
#include "tasks/Task.h"
|
||||
#include <pathutils.h>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
@ -29,14 +30,108 @@
|
||||
|
||||
#define IBUS "@im=ibus"
|
||||
|
||||
BaseLauncher* BaseLauncher::create(MinecraftInstancePtr inst)
|
||||
void BaseLauncher::initializeEnvironment()
|
||||
{
|
||||
auto proc = new BaseLauncher(inst);
|
||||
// prepare the process environment
|
||||
QProcessEnvironment rawenv = QProcessEnvironment::systemEnvironment();
|
||||
|
||||
QStringList ignored =
|
||||
{
|
||||
"JAVA_ARGS",
|
||||
"CLASSPATH",
|
||||
"CONFIGPATH",
|
||||
"JAVA_HOME",
|
||||
"JRE_HOME",
|
||||
"_JAVA_OPTIONS",
|
||||
"JAVA_OPTIONS",
|
||||
"JAVA_TOOL_OPTIONS"
|
||||
};
|
||||
for(auto key: rawenv.keys())
|
||||
{
|
||||
auto value = rawenv.value(key);
|
||||
// filter out dangerous java crap
|
||||
if(ignored.contains(key))
|
||||
{
|
||||
qDebug() << "Env: ignoring" << key << value;
|
||||
continue;
|
||||
}
|
||||
// filter MultiMC-related things
|
||||
if(key.startsWith("QT_"))
|
||||
{
|
||||
qDebug() << "Env: ignoring" << key << value;
|
||||
continue;
|
||||
}
|
||||
#ifdef Q_OS_LINUX
|
||||
// Do not pass LD_* variables to java. They were intended for MultiMC
|
||||
if(key.startsWith("LD_"))
|
||||
{
|
||||
qDebug() << "Env: ignoring" << key << value;
|
||||
continue;
|
||||
}
|
||||
// Strip IBus
|
||||
// IBus is a Linux IME framework. For some reason, it breaks MC?
|
||||
if (key == "XMODIFIERS" && value.contains(IBUS))
|
||||
{
|
||||
QString save = value;
|
||||
value.replace(IBUS, "");
|
||||
qDebug() << "Env: stripped" << IBUS << "from" << save << ":" << value;
|
||||
}
|
||||
if(key == "GAME_PRELOAD")
|
||||
{
|
||||
m_env.insert("LD_PRELOAD", value);
|
||||
continue;
|
||||
}
|
||||
if(key == "GAME_LIBRARY_PATH")
|
||||
{
|
||||
m_env.insert("LD_LIBRARY_PATH", value);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
qDebug() << "Env: " << key << value;
|
||||
m_env.insert(key, value);
|
||||
}
|
||||
#ifdef Q_OS_LINUX
|
||||
// HACK: Workaround for QTBUG42500
|
||||
if(!m_env.contains("LD_LIBRARY_PATH"))
|
||||
{
|
||||
m_env.insert("LD_LIBRARY_PATH", "");
|
||||
}
|
||||
#endif
|
||||
|
||||
// export some infos
|
||||
auto variables = getVariables();
|
||||
for (auto it = variables.begin(); it != variables.end(); ++it)
|
||||
{
|
||||
m_env.insert(it.key(), it.value());
|
||||
}
|
||||
}
|
||||
|
||||
void BaseLauncher::init()
|
||||
{
|
||||
initializeEnvironment();
|
||||
|
||||
m_process.setProcessEnvironment(m_env);
|
||||
connect(&m_process, &LoggedProcess::log, this, &BaseLauncher::on_log);
|
||||
connect(&m_process, &LoggedProcess::stateChanged, this, &BaseLauncher::on_state);
|
||||
|
||||
m_prelaunchprocess.setProcessEnvironment(m_env);
|
||||
connect(&m_prelaunchprocess, &LoggedProcess::log, this, &BaseLauncher::on_log);
|
||||
connect(&m_prelaunchprocess, &LoggedProcess::stateChanged, this, &BaseLauncher::on_pre_state);
|
||||
|
||||
m_postlaunchprocess.setProcessEnvironment(m_env);
|
||||
connect(&m_postlaunchprocess, &LoggedProcess::log, this, &BaseLauncher::on_log);
|
||||
connect(&m_postlaunchprocess, &LoggedProcess::stateChanged, this, &BaseLauncher::on_post_state);
|
||||
|
||||
m_instance->setRunning(true);
|
||||
}
|
||||
|
||||
std::shared_ptr<BaseLauncher> BaseLauncher::create(MinecraftInstancePtr inst)
|
||||
{
|
||||
std::shared_ptr<BaseLauncher> proc(new BaseLauncher(inst));
|
||||
proc->init();
|
||||
return proc;
|
||||
}
|
||||
|
||||
|
||||
BaseLauncher::BaseLauncher(InstancePtr instance): m_instance(instance)
|
||||
{
|
||||
}
|
||||
@ -158,126 +253,68 @@ QStringList BaseLauncher::javaArguments() const
|
||||
return args;
|
||||
}
|
||||
|
||||
bool BaseLauncher::checkJava(QString JavaPath)
|
||||
void BaseLauncher::checkJava()
|
||||
{
|
||||
auto realJavaPath = QStandardPaths::findExecutable(JavaPath);
|
||||
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(JavaPath),
|
||||
"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)
|
||||
{
|
||||
QEventLoop ev;
|
||||
auto checker = std::make_shared<JavaChecker>();
|
||||
m_JavaChecker = 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);
|
||||
connect(m_JavaChecker.get(), &JavaChecker::checkFinished, this, &BaseLauncher::checkJavaFinished);
|
||||
m_JavaChecker->m_path = realJavaPath;
|
||||
m_JavaChecker->performCheck();
|
||||
}
|
||||
return true;
|
||||
preLaunch();
|
||||
}
|
||||
|
||||
void BaseLauncher::arm()
|
||||
void BaseLauncher::checkJavaFinished(JavaCheckResult result)
|
||||
{
|
||||
printHeader();
|
||||
emit log("Minecraft folder is:\n" + m_process.workingDirectory() + "\n\n");
|
||||
|
||||
/*
|
||||
if (!preLaunch())
|
||||
if(!result.valid)
|
||||
{
|
||||
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())
|
||||
// Error message displayed if java can't start
|
||||
emit log(tr("Could not start java:"), MessageLevel::Error);
|
||||
auto lines = result.errorLog.split('\n');
|
||||
for(auto line: lines)
|
||||
{
|
||||
emit log(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(line, MessageLevel::Error);
|
||||
}
|
||||
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);
|
||||
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;
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
emit log(tr("Minecraft process ID: %1\n\n").arg(m_process.processId()), MessageLevel::MultiMC);
|
||||
void BaseLauncher::executeTask()
|
||||
{
|
||||
printHeader();
|
||||
emit log("Minecraft folder is:\n" + m_process.workingDirectory() + "\n\n");
|
||||
|
||||
// send the launch script to the launcher part
|
||||
m_process.write(launchScript.toUtf8());
|
||||
checkJava();
|
||||
}
|
||||
|
||||
void BaseLauncher::launch()
|
||||
@ -293,103 +330,6 @@ void BaseLauncher::abort()
|
||||
}
|
||||
|
||||
|
||||
void BaseLauncher::initializeEnvironment()
|
||||
{
|
||||
// prepare the process environment
|
||||
QProcessEnvironment rawenv = QProcessEnvironment::systemEnvironment();
|
||||
|
||||
QStringList ignored =
|
||||
{
|
||||
"JAVA_ARGS",
|
||||
"CLASSPATH",
|
||||
"CONFIGPATH",
|
||||
"JAVA_HOME",
|
||||
"JRE_HOME",
|
||||
"_JAVA_OPTIONS",
|
||||
"JAVA_OPTIONS",
|
||||
"JAVA_TOOL_OPTIONS"
|
||||
};
|
||||
for(auto key: rawenv.keys())
|
||||
{
|
||||
auto value = rawenv.value(key);
|
||||
// filter out dangerous java crap
|
||||
if(ignored.contains(key))
|
||||
{
|
||||
qDebug() << "Env: ignoring" << key << value;
|
||||
continue;
|
||||
}
|
||||
// filter MultiMC-related things
|
||||
if(key.startsWith("QT_"))
|
||||
{
|
||||
qDebug() << "Env: ignoring" << key << value;
|
||||
continue;
|
||||
}
|
||||
#ifdef Q_OS_LINUX
|
||||
// Do not pass LD_* variables to java. They were intended for MultiMC
|
||||
if(key.startsWith("LD_"))
|
||||
{
|
||||
qDebug() << "Env: ignoring" << key << value;
|
||||
continue;
|
||||
}
|
||||
// Strip IBus
|
||||
// IBus is a Linux IME framework. For some reason, it breaks MC?
|
||||
if (key == "XMODIFIERS" && value.contains(IBUS))
|
||||
{
|
||||
QString save = value;
|
||||
value.replace(IBUS, "");
|
||||
qDebug() << "Env: stripped" << IBUS << "from" << save << ":" << value;
|
||||
}
|
||||
if(key == "GAME_PRELOAD")
|
||||
{
|
||||
m_env.insert("LD_PRELOAD", value);
|
||||
continue;
|
||||
}
|
||||
if(key == "GAME_LIBRARY_PATH")
|
||||
{
|
||||
m_env.insert("LD_LIBRARY_PATH", value);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
qDebug() << "Env: " << key << value;
|
||||
m_env.insert(key, value);
|
||||
}
|
||||
#ifdef Q_OS_LINUX
|
||||
// HACK: Workaround for QTBUG42500
|
||||
if(!m_env.contains("LD_LIBRARY_PATH"))
|
||||
{
|
||||
m_env.insert("LD_LIBRARY_PATH", "");
|
||||
}
|
||||
#endif
|
||||
|
||||
// export some infos
|
||||
auto variables = getVariables();
|
||||
for (auto it = variables.begin(); it != variables.end(); ++it)
|
||||
{
|
||||
m_env.insert(it.key(), it.value());
|
||||
}
|
||||
}
|
||||
|
||||
void BaseLauncher::init()
|
||||
{
|
||||
initializeEnvironment();
|
||||
|
||||
m_process.setProcessEnvironment(m_env);
|
||||
connect(&m_process, &LoggedProcess::log, this, &BaseLauncher::on_log);
|
||||
connect(&m_process, &LoggedProcess::stateChanged, this, &BaseLauncher::on_state);
|
||||
|
||||
m_prelaunchprocess.setProcessEnvironment(m_env);
|
||||
connect(&m_prelaunchprocess, &LoggedProcess::log, this, &BaseLauncher::on_log);
|
||||
connect(&m_prelaunchprocess, &LoggedProcess::stateChanged, this, &BaseLauncher::on_pre_state);
|
||||
|
||||
m_postlaunchprocess.setProcessEnvironment(m_env);
|
||||
connect(&m_postlaunchprocess, &LoggedProcess::log, this, &BaseLauncher::on_log);
|
||||
connect(&m_postlaunchprocess, &LoggedProcess::stateChanged, this, &BaseLauncher::on_post_state);
|
||||
|
||||
// a process has been constructed for the instance. It is running from MultiMC POV
|
||||
m_instance->setRunning(true);
|
||||
}
|
||||
|
||||
|
||||
void BaseLauncher::setWorkdir(QString path)
|
||||
{
|
||||
QDir mcDir(path);
|
||||
@ -468,18 +408,98 @@ void BaseLauncher::on_pre_state(LoggedProcess::State state)
|
||||
emit prelaunch_failed(m_instance, m_prelaunchprocess.exitCode(), m_prelaunchprocess.exitStatus());
|
||||
// not running, failed
|
||||
m_instance->setRunning(false);
|
||||
return;
|
||||
}
|
||||
case LoggedProcess::Finished:
|
||||
{
|
||||
emit log(tr("Pre-Launch command ran successfully.\n\n"));
|
||||
m_instance->reload();
|
||||
}
|
||||
case LoggedProcess::Skipped:
|
||||
{
|
||||
m_instance->reload();
|
||||
updateInstance();
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BaseLauncher::updateInstance()
|
||||
{
|
||||
m_updateTask = m_instance->doUpdate();
|
||||
if(m_updateTask)
|
||||
{
|
||||
connect(m_updateTask.get(), SIGNAL(finished()), this, SLOT(updateFinished()));
|
||||
m_updateTask->start();
|
||||
return;
|
||||
}
|
||||
makeReady();
|
||||
}
|
||||
|
||||
void BaseLauncher::updateFinished()
|
||||
{
|
||||
if(m_updateTask->successful())
|
||||
{
|
||||
makeReady();
|
||||
}
|
||||
else
|
||||
{
|
||||
QString reason = tr("Instance update failed because: %1.\n\n").arg(m_updateTask->failReason());
|
||||
emit log(reason, MessageLevel::Fatal);
|
||||
m_instance->cleanupAfterRun();
|
||||
emit update_failed(m_instance);
|
||||
emitFailed(reason);
|
||||
m_instance->setRunning(false);
|
||||
}
|
||||
}
|
||||
|
||||
void BaseLauncher::makeReady()
|
||||
{
|
||||
QStringList args = javaArguments();
|
||||
QString allArgs = args.join(", ");
|
||||
emit log("Java Arguments:\n[" + censorPrivateInfo(allArgs) + "]\n\n");
|
||||
|
||||
QString wrapperCommand = m_instance->settings()->get("WrapperCommand").toString();
|
||||
if(!wrapperCommand.isEmpty())
|
||||
{
|
||||
auto realWrapperCommand = QStandardPaths::findExecutable(wrapperCommand);
|
||||
if (realWrapperCommand.isEmpty())
|
||||
{
|
||||
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(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
|
||||
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());
|
||||
|
||||
emit readyForLaunch(shared_from_this());
|
||||
}
|
||||
|
||||
void BaseLauncher::on_state(LoggedProcess::State state)
|
||||
{
|
||||
QProcess::ExitStatus estat = QProcess::NormalExit;
|
||||
@ -500,9 +520,14 @@ void BaseLauncher::on_state(LoggedProcess::State state)
|
||||
// no longer running...
|
||||
m_instance->setRunning(false);
|
||||
emit ended(m_instance, exitCode, estat);
|
||||
break;
|
||||
}
|
||||
case LoggedProcess::Skipped:
|
||||
qWarning() << "Illegal game state: Skipped";
|
||||
break;
|
||||
case LoggedProcess::Running:
|
||||
m_instance->setLastLaunch();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -22,8 +22,12 @@
|
||||
#include "LoggedProcess.h"
|
||||
/* HACK: MINECRAFT: split! */
|
||||
#include "minecraft/MinecraftInstance.h"
|
||||
#include "java/JavaChecker.h"
|
||||
#include "QObjectPtr.h"
|
||||
#include "tasks/Task.h"
|
||||
|
||||
class BaseLauncher: public QObject
|
||||
class BaseProfilerFactory;
|
||||
class BaseLauncher: public Task, public std::enable_shared_from_this<BaseLauncher>
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
@ -31,7 +35,7 @@ protected:
|
||||
void init();
|
||||
|
||||
public: /* methods */
|
||||
static BaseLauncher *create(MinecraftInstancePtr inst);
|
||||
static std::shared_ptr<BaseLauncher> create(MinecraftInstancePtr inst);
|
||||
virtual ~BaseLauncher() {};
|
||||
|
||||
InstancePtr instance()
|
||||
@ -47,6 +51,16 @@ public: /* methods */
|
||||
|
||||
void setWorkdir(QString path);
|
||||
|
||||
BaseProfilerFactory * getProfiler()
|
||||
{
|
||||
return m_profiler;
|
||||
}
|
||||
|
||||
void setProfiler(BaseProfilerFactory * profiler)
|
||||
{
|
||||
m_profiler = profiler;
|
||||
}
|
||||
|
||||
void killProcess();
|
||||
|
||||
qint64 pid();
|
||||
@ -54,7 +68,7 @@ public: /* methods */
|
||||
/**
|
||||
* @brief prepare the process for launch (for multi-stage launch)
|
||||
*/
|
||||
virtual void arm();
|
||||
virtual void executeTask() override;
|
||||
|
||||
/**
|
||||
* @brief launch the armed instance
|
||||
@ -85,6 +99,8 @@ public: /* HACK: MINECRAFT: split! */
|
||||
|
||||
protected: /* methods */
|
||||
void preLaunch();
|
||||
void updateInstance();
|
||||
void makeReady();
|
||||
void postLaunch();
|
||||
QString substituteVariables(const QString &cmd) const;
|
||||
void initializeEnvironment();
|
||||
@ -106,6 +122,11 @@ signals:
|
||||
*/
|
||||
void prelaunch_failed(InstancePtr, int code, QProcess::ExitStatus status);
|
||||
|
||||
/**
|
||||
* @brief emitted when the instance update fails
|
||||
*/
|
||||
void update_failed(InstancePtr);
|
||||
|
||||
/**
|
||||
* @brief emitted when the PostLaunchCommand fails
|
||||
*/
|
||||
@ -116,6 +137,11 @@ signals:
|
||||
*/
|
||||
void ended(InstancePtr, int code, QProcess::ExitStatus status);
|
||||
|
||||
/**
|
||||
* @brief emitted when the launch preparations are done
|
||||
*/
|
||||
void readyForLaunch(std::shared_ptr<BaseLauncher> launcher);
|
||||
|
||||
/**
|
||||
* @brief emitted when we want to log something
|
||||
* @param text the text to log
|
||||
@ -132,6 +158,8 @@ protected slots:
|
||||
void on_state(LoggedProcess::State state);
|
||||
void on_post_state(LoggedProcess::State state);
|
||||
|
||||
void checkJavaFinished(JavaCheckResult result);
|
||||
|
||||
protected:
|
||||
InstancePtr m_instance;
|
||||
|
||||
@ -139,16 +167,27 @@ protected:
|
||||
LoggedProcess m_postlaunchprocess;
|
||||
LoggedProcess m_process;
|
||||
QProcessEnvironment m_env;
|
||||
BaseProfilerFactory * m_profiler = nullptr;
|
||||
|
||||
bool killed = false;
|
||||
QString m_header;
|
||||
|
||||
// for java checker and launch
|
||||
QString m_javaPath;
|
||||
qlonglong m_javaUnixTime;
|
||||
|
||||
protected: /* HACK: MINECRAFT: split! */
|
||||
AuthSessionPtr m_session;
|
||||
QString launchScript;
|
||||
QString m_nativeFolder;
|
||||
std::shared_ptr<JavaChecker> m_JavaChecker;
|
||||
std::shared_ptr<Task> m_updateTask;
|
||||
|
||||
protected: /* HACK: MINECRAFT: split! */
|
||||
bool checkJava(QString path);
|
||||
void checkJava();
|
||||
QStringList javaArguments() const;
|
||||
private slots:
|
||||
void updateFinished();
|
||||
};
|
||||
|
||||
class BaseProfilerFactory;
|
@ -43,7 +43,7 @@ public:
|
||||
{
|
||||
return instanceRoot();
|
||||
};
|
||||
virtual BaseLauncher* prepareForLaunch(AuthSessionPtr)
|
||||
virtual std::shared_ptr<BaseLauncher> prepareForLaunch(AuthSessionPtr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ std::shared_ptr<Task> LegacyInstance::doUpdate()
|
||||
return std::shared_ptr<Task>(new LegacyUpdate(this, this));
|
||||
}
|
||||
|
||||
BaseLauncher *LegacyInstance::prepareForLaunch(AuthSessionPtr account)
|
||||
std::shared_ptr<BaseLauncher> LegacyInstance::prepareForLaunch(AuthSessionPtr account)
|
||||
{
|
||||
QString launchScript;
|
||||
QIcon icon = ENV.icons()->getIcon(iconKey());
|
||||
|
@ -111,7 +111,7 @@ public:
|
||||
virtual void setShouldUpdate(bool val) override;
|
||||
virtual std::shared_ptr<Task> doUpdate() override;
|
||||
|
||||
virtual BaseLauncher *prepareForLaunch(AuthSessionPtr account) override;
|
||||
virtual std::shared_ptr<BaseLauncher> prepareForLaunch(AuthSessionPtr account) override;
|
||||
virtual void cleanupAfterRun() override;
|
||||
|
||||
virtual QString getStatusbarDescription() override;
|
||||
|
@ -123,7 +123,7 @@ QStringList OneSixInstance::processMinecraftArgs(AuthSessionPtr session)
|
||||
return parts;
|
||||
}
|
||||
|
||||
BaseLauncher *OneSixInstance::prepareForLaunch(AuthSessionPtr session)
|
||||
std::shared_ptr<BaseLauncher> OneSixInstance::prepareForLaunch(AuthSessionPtr session)
|
||||
{
|
||||
QString launchScript;
|
||||
QIcon icon = ENV.icons()->getIcon(iconKey());
|
||||
|
@ -49,7 +49,7 @@ public:
|
||||
virtual QString instanceConfigFolder() const override;
|
||||
|
||||
virtual std::shared_ptr<Task> doUpdate() override;
|
||||
virtual BaseLauncher *prepareForLaunch(AuthSessionPtr account) override;
|
||||
virtual std::shared_ptr<BaseLauncher> prepareForLaunch(AuthSessionPtr account) override;
|
||||
|
||||
virtual void cleanupAfterRun() override;
|
||||
|
||||
|
@ -7,7 +7,7 @@ BaseProfiler::BaseProfiler(SettingsObjectPtr settings, InstancePtr instance, QOb
|
||||
{
|
||||
}
|
||||
|
||||
void BaseProfiler::beginProfiling(BaseLauncher *process)
|
||||
void BaseProfiler::beginProfiling(std::shared_ptr<BaseLauncher> process)
|
||||
{
|
||||
beginProfilingImpl(process);
|
||||
}
|
||||
|
@ -15,13 +15,13 @@ public:
|
||||
|
||||
public
|
||||
slots:
|
||||
void beginProfiling(BaseLauncher *process);
|
||||
void beginProfiling(std::shared_ptr<BaseLauncher> process);
|
||||
void abortProfiling();
|
||||
|
||||
protected:
|
||||
QProcess *m_profilerProcess;
|
||||
|
||||
virtual void beginProfilingImpl(BaseLauncher *process) = 0;
|
||||
virtual void beginProfilingImpl(std::shared_ptr<BaseLauncher> process) = 0;
|
||||
virtual void abortProfilingImpl();
|
||||
|
||||
signals:
|
||||
|
@ -18,7 +18,7 @@ private slots:
|
||||
void profilerFinished(int exit, QProcess::ExitStatus status);
|
||||
|
||||
protected:
|
||||
void beginProfilingImpl(BaseLauncher *process);
|
||||
void beginProfilingImpl(std::shared_ptr<BaseLauncher> process);
|
||||
|
||||
private:
|
||||
int listeningPort = 0;
|
||||
@ -48,7 +48,7 @@ void JProfiler::profilerFinished(int exit, QProcess::ExitStatus status)
|
||||
}
|
||||
}
|
||||
|
||||
void JProfiler::beginProfilingImpl(BaseLauncher *process)
|
||||
void JProfiler::beginProfilingImpl(std::shared_ptr<BaseLauncher> process)
|
||||
{
|
||||
listeningPort = globalSettings->get("JProfilerPort").toInt();
|
||||
QProcess *profiler = new QProcess(this);
|
||||
|
@ -18,7 +18,7 @@ private slots:
|
||||
void profilerFinished(int exit, QProcess::ExitStatus status);
|
||||
|
||||
protected:
|
||||
void beginProfilingImpl(BaseLauncher *process);
|
||||
void beginProfilingImpl(std::shared_ptr<BaseLauncher> process);
|
||||
};
|
||||
|
||||
|
||||
@ -45,7 +45,7 @@ void JVisualVM::profilerFinished(int exit, QProcess::ExitStatus status)
|
||||
}
|
||||
}
|
||||
|
||||
void JVisualVM::beginProfilingImpl(BaseLauncher *process)
|
||||
void JVisualVM::beginProfilingImpl(std::shared_ptr<BaseLauncher> process)
|
||||
{
|
||||
QProcess *profiler = new QProcess(this);
|
||||
QStringList profilerArgs =
|
||||
|
Loading…
Reference in New Issue
Block a user