diff --git a/application/ConsoleWindow.cpp b/application/ConsoleWindow.cpp index 6a3cd6b2..98492414 100644 --- a/application/ConsoleWindow.cpp +++ b/application/ConsoleWindow.cpp @@ -53,7 +53,7 @@ private: BasePage * m_log_page; }; -ConsoleWindow::ConsoleWindow(BaseLauncher *process, QWidget *parent) +ConsoleWindow::ConsoleWindow(std::shared_ptr 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); diff --git a/application/ConsoleWindow.h b/application/ConsoleWindow.h index a5e9c3a4..33ae67c7 100644 --- a/application/ConsoleWindow.h +++ b/application/ConsoleWindow.h @@ -26,7 +26,7 @@ class ConsoleWindow : public QMainWindow Q_OBJECT public: - explicit ConsoleWindow(BaseLauncher *proc, QWidget *parent = 0); + explicit ConsoleWindow(std::shared_ptr proc, QWidget *parent = 0); virtual ~ConsoleWindow(); /** @@ -56,7 +56,7 @@ protected: void closeEvent(QCloseEvent *); private: - BaseLauncher *m_proc = nullptr; + std::shared_ptr m_proc; bool m_mayclose = true; QSystemTrayIcon *m_trayIcon = nullptr; PageContainer *m_container = nullptr; diff --git a/application/MainWindow.cpp b/application/MainWindow.cpp index 8e43ff0e..eb258d20 100644 --- a/application/MainWindow.cpp +++ b/application/MainWindow.cpp @@ -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 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. diff --git a/application/MainWindow.h b/application/MainWindow.h index 010db55c..292a8d28 100644 --- a/application/MainWindow.h +++ b/application/MainWindow.h @@ -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); 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; diff --git a/application/pages/LogPage.cpp b/application/pages/LogPage.cpp index 0b88193c..cdf6b345 100644 --- a/application/pages/LogPage.cpp +++ b/application/pages/LogPage.cpp @@ -11,12 +11,12 @@ #include #include "GuiUtil.h" -LogPage::LogPage(BaseLauncher *proc, QWidget *parent) +LogPage::LogPage(std::shared_ptr 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 diff --git a/application/pages/LogPage.h b/application/pages/LogPage.h index a420a75f..0bd74846 100644 --- a/application/pages/LogPage.h +++ b/application/pages/LogPage.h @@ -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 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 m_process; int m_last_scroll_value = 0; bool m_scroll_active = true; int m_saved_offset = 0; diff --git a/logic/BaseInstance.h b/logic/BaseInstance.h index 91d46df1..497431d0 100644 --- a/logic/BaseInstance.h +++ b/logic/BaseInstance.h @@ -138,7 +138,7 @@ public: virtual std::shared_ptr doUpdate() = 0; /// returns a valid process, ready for launch with the given account. - virtual BaseLauncher *prepareForLaunch(AuthSessionPtr account) = 0; + virtual std::shared_ptr prepareForLaunch(AuthSessionPtr account) = 0; /// do any necessary cleanups after the instance finishes. also runs before /// 'prepareForLaunch' diff --git a/logic/BaseLauncher.cpp b/logic/BaseLauncher.cpp index 464a2783..991973e7 100644 --- a/logic/BaseLauncher.cpp +++ b/logic/BaseLauncher.cpp @@ -19,6 +19,7 @@ #include "MessageLevel.h" #include "MMCStrings.h" #include "java/JavaChecker.h" +#include "tasks/Task.h" #include #include #include @@ -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::create(MinecraftInstancePtr inst) +{ + std::shared_ptr 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(); + m_JavaChecker = std::make_shared(); 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; } diff --git a/logic/BaseLauncher.h b/logic/BaseLauncher.h index 59e1fdbb..076d664b 100644 --- a/logic/BaseLauncher.h +++ b/logic/BaseLauncher.h @@ -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 { Q_OBJECT protected: @@ -31,7 +35,7 @@ protected: void init(); public: /* methods */ - static BaseLauncher *create(MinecraftInstancePtr inst); + static std::shared_ptr 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 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 m_JavaChecker; + std::shared_ptr m_updateTask; protected: /* HACK: MINECRAFT: split! */ - bool checkJava(QString path); + void checkJava(); QStringList javaArguments() const; +private slots: + void updateFinished(); }; + +class BaseProfilerFactory; \ No newline at end of file diff --git a/logic/NullInstance.h b/logic/NullInstance.h index 5e81b2e4..6f737e86 100644 --- a/logic/NullInstance.h +++ b/logic/NullInstance.h @@ -43,7 +43,7 @@ public: { return instanceRoot(); }; - virtual BaseLauncher* prepareForLaunch(AuthSessionPtr) + virtual std::shared_ptr prepareForLaunch(AuthSessionPtr) { return nullptr; } diff --git a/logic/minecraft/LegacyInstance.cpp b/logic/minecraft/LegacyInstance.cpp index 0eb379dc..3fe51a4a 100644 --- a/logic/minecraft/LegacyInstance.cpp +++ b/logic/minecraft/LegacyInstance.cpp @@ -95,7 +95,7 @@ std::shared_ptr LegacyInstance::doUpdate() return std::shared_ptr(new LegacyUpdate(this, this)); } -BaseLauncher *LegacyInstance::prepareForLaunch(AuthSessionPtr account) +std::shared_ptr LegacyInstance::prepareForLaunch(AuthSessionPtr account) { QString launchScript; QIcon icon = ENV.icons()->getIcon(iconKey()); diff --git a/logic/minecraft/LegacyInstance.h b/logic/minecraft/LegacyInstance.h index 236771f4..a8363e58 100644 --- a/logic/minecraft/LegacyInstance.h +++ b/logic/minecraft/LegacyInstance.h @@ -111,7 +111,7 @@ public: virtual void setShouldUpdate(bool val) override; virtual std::shared_ptr doUpdate() override; - virtual BaseLauncher *prepareForLaunch(AuthSessionPtr account) override; + virtual std::shared_ptr prepareForLaunch(AuthSessionPtr account) override; virtual void cleanupAfterRun() override; virtual QString getStatusbarDescription() override; diff --git a/logic/minecraft/OneSixInstance.cpp b/logic/minecraft/OneSixInstance.cpp index fd3df715..63bc071f 100644 --- a/logic/minecraft/OneSixInstance.cpp +++ b/logic/minecraft/OneSixInstance.cpp @@ -123,7 +123,7 @@ QStringList OneSixInstance::processMinecraftArgs(AuthSessionPtr session) return parts; } -BaseLauncher *OneSixInstance::prepareForLaunch(AuthSessionPtr session) +std::shared_ptr OneSixInstance::prepareForLaunch(AuthSessionPtr session) { QString launchScript; QIcon icon = ENV.icons()->getIcon(iconKey()); diff --git a/logic/minecraft/OneSixInstance.h b/logic/minecraft/OneSixInstance.h index 5c71687d..3825ba6a 100644 --- a/logic/minecraft/OneSixInstance.h +++ b/logic/minecraft/OneSixInstance.h @@ -49,7 +49,7 @@ public: virtual QString instanceConfigFolder() const override; virtual std::shared_ptr doUpdate() override; - virtual BaseLauncher *prepareForLaunch(AuthSessionPtr account) override; + virtual std::shared_ptr prepareForLaunch(AuthSessionPtr account) override; virtual void cleanupAfterRun() override; diff --git a/logic/tools/BaseProfiler.cpp b/logic/tools/BaseProfiler.cpp index cfac47d4..42ed1d93 100644 --- a/logic/tools/BaseProfiler.cpp +++ b/logic/tools/BaseProfiler.cpp @@ -7,7 +7,7 @@ BaseProfiler::BaseProfiler(SettingsObjectPtr settings, InstancePtr instance, QOb { } -void BaseProfiler::beginProfiling(BaseLauncher *process) +void BaseProfiler::beginProfiling(std::shared_ptr process) { beginProfilingImpl(process); } diff --git a/logic/tools/BaseProfiler.h b/logic/tools/BaseProfiler.h index 54ba89ce..709c7cb4 100644 --- a/logic/tools/BaseProfiler.h +++ b/logic/tools/BaseProfiler.h @@ -15,13 +15,13 @@ public: public slots: - void beginProfiling(BaseLauncher *process); + void beginProfiling(std::shared_ptr process); void abortProfiling(); protected: QProcess *m_profilerProcess; - virtual void beginProfilingImpl(BaseLauncher *process) = 0; + virtual void beginProfilingImpl(std::shared_ptr process) = 0; virtual void abortProfilingImpl(); signals: diff --git a/logic/tools/JProfiler.cpp b/logic/tools/JProfiler.cpp index 73121239..975345d5 100644 --- a/logic/tools/JProfiler.cpp +++ b/logic/tools/JProfiler.cpp @@ -18,7 +18,7 @@ private slots: void profilerFinished(int exit, QProcess::ExitStatus status); protected: - void beginProfilingImpl(BaseLauncher *process); + void beginProfilingImpl(std::shared_ptr process); private: int listeningPort = 0; @@ -48,7 +48,7 @@ void JProfiler::profilerFinished(int exit, QProcess::ExitStatus status) } } -void JProfiler::beginProfilingImpl(BaseLauncher *process) +void JProfiler::beginProfilingImpl(std::shared_ptr process) { listeningPort = globalSettings->get("JProfilerPort").toInt(); QProcess *profiler = new QProcess(this); diff --git a/logic/tools/JVisualVM.cpp b/logic/tools/JVisualVM.cpp index fbfd858a..a749012b 100644 --- a/logic/tools/JVisualVM.cpp +++ b/logic/tools/JVisualVM.cpp @@ -18,7 +18,7 @@ private slots: void profilerFinished(int exit, QProcess::ExitStatus status); protected: - void beginProfilingImpl(BaseLauncher *process); + void beginProfilingImpl(std::shared_ptr process); }; @@ -45,7 +45,7 @@ void JVisualVM::profilerFinished(int exit, QProcess::ExitStatus status) } } -void JVisualVM::beginProfilingImpl(BaseLauncher *process) +void JVisualVM::beginProfilingImpl(std::shared_ptr process) { QProcess *profiler = new QProcess(this); QStringList profilerArgs =