diff options
Diffstat (limited to 'logic')
66 files changed, 1594 insertions, 1367 deletions
diff --git a/logic/BaseInstance.cpp b/logic/BaseInstance.cpp index 8048beea..a073a921 100644 --- a/logic/BaseInstance.cpp +++ b/logic/BaseInstance.cpp @@ -28,7 +28,6 @@ #include <cmdutils.h> #include "logic/minecraft/MinecraftVersionList.h" #include "logic/icons/IconList.h" -#include "logic/InstanceList.h" BaseInstance::BaseInstance(const QString &rootDir, SettingsObject *settings, QObject *parent) : QObject(parent) @@ -115,30 +114,9 @@ QString BaseInstance::instanceRoot() const return m_rootDir; } -QString BaseInstance::minecraftRoot() const -{ - QFileInfo mcDir(PathCombine(instanceRoot(), "minecraft")); - QFileInfo dotMCDir(PathCombine(instanceRoot(), ".minecraft")); - - if (dotMCDir.exists() && !mcDir.exists()) - return dotMCDir.filePath(); - else - return mcDir.filePath(); -} - -InstanceList *BaseInstance::instList() const -{ - return qobject_cast<InstanceList *>(parent()); -} - InstancePtr BaseInstance::getSharedPtr() { - return instList()->getInstanceById(id()); -} - -std::shared_ptr<BaseVersionList> BaseInstance::versionList() const -{ - return MMC->minecraftlist(); + return shared_from_this(); } SettingsObject &BaseInstance::settings() const diff --git a/logic/BaseInstance.h b/logic/BaseInstance.h index bcf28031..cbac701c 100644 --- a/logic/BaseInstance.h +++ b/logic/BaseInstance.h @@ -24,14 +24,14 @@ #include "logic/settings/INIFile.h" #include "logic/BaseVersionList.h" #include "logic/auth/MojangAccount.h" +#include "Mod.h" class ModList; class QDialog; class QDir; class Task; -class MinecraftProcess; +class BaseProcess; class OneSixUpdate; -class InstanceList; class BaseInstancePrivate; // pointer for lazy people @@ -46,7 +46,7 @@ typedef std::shared_ptr<BaseInstance> InstancePtr; * To create a new instance type, create a new class inheriting from this class * and implement the pure virtual functions. */ -class BaseInstance : public QObject +class BaseInstance : public QObject, public std::enable_shared_from_this<BaseInstance> { Q_OBJECT protected: @@ -57,9 +57,10 @@ public: /// virtual destructor to make sure the destruction is COMPLETE virtual ~BaseInstance() {}; - virtual void init() {} virtual void copy(const QDir &newDir) {} + virtual void init() = 0; + /// nuke thoroughly - deletes the instance contents, notifies the list/model which is /// responsible of cleaning up the husk void nuke(); @@ -77,9 +78,6 @@ public: /// Path to the instance's root directory. QString instanceRoot() const; - /// Path to the instance's minecraft directory. - QString minecraftRoot() const; - QString name() const; void setName(QString val); @@ -101,8 +99,6 @@ public: virtual QString intendedVersionId() const = 0; virtual bool setIntendedVersionId(QString version) = 0; - virtual bool versionIsCustom() = 0; - /*! * The instance's current version. * This value represents the instance's current version. If this value is @@ -112,21 +108,11 @@ public: virtual QString currentVersionId() const = 0; /*! - * Whether or not Minecraft should be downloaded when the instance is launched. + * Whether or not 'the game' should be downloaded when the instance is launched. */ virtual bool shouldUpdate() const = 0; virtual void setShouldUpdate(bool val) = 0; - ////// Mod Lists ////// - virtual std::shared_ptr<ModList> resourcePackList() - { - return nullptr; - } - virtual std::shared_ptr<ModList> texturePackList() - { - return nullptr; - } - /// Traits. Normally inside the version, depends on instance implementation. virtual QSet <QString> traits() = 0; @@ -138,21 +124,13 @@ public: /// Sets the last launched time to 'val' milliseconds since epoch void setLastLaunch(qint64 val = QDateTime::currentMSecsSinceEpoch()); - /*! - * \brief Gets the instance list that this instance is a part of. - * Returns NULL if this instance is not in a list - * (the parent is not an InstanceList). - * \return A pointer to the InstanceList containing this instance. - */ - InstanceList *instList() const; - InstancePtr getSharedPtr(); /*! * \brief Gets a pointer to this instance's version list. * \return A pointer to the available version list for this instance. */ - virtual std::shared_ptr<BaseVersionList> versionList() const; + virtual std::shared_ptr<BaseVersionList> versionList() const = 0; /*! * \brief Gets this instance's settings object. @@ -164,8 +142,8 @@ public: /// returns a valid update task virtual std::shared_ptr<Task> doUpdate() = 0; - /// returns a valid minecraft process, ready for launch with the given account. - virtual bool prepareForLaunch(AuthSessionPtr account, QString & launchScript) = 0; + /// returns a valid process, ready for launch with the given account. + virtual BaseProcess *prepareForLaunch(AuthSessionPtr account) = 0; /// do any necessary cleanups after the instance finishes. also runs before /// 'prepareForLaunch' diff --git a/logic/MinecraftProcess.cpp b/logic/BaseProcess.cpp index 92aae69f..d65e76d9 100644 --- a/logic/MinecraftProcess.cpp +++ b/logic/BaseProcess.cpp @@ -14,28 +14,37 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "MultiMC.h" -#include "BuildConfig.h" - -#include "MinecraftProcess.h" - -#include <QDataStream> -#include <QFile> +#include "logic/BaseProcess.h" +#include "logger/QsLog.h" #include <QDir> -#include <QProcessEnvironment> -#include <QRegularExpression> -#include <QStandardPaths> +#include <QEventLoop> -#include "BaseInstance.h" - -#include "osutils.h" -#include "pathutils.h" -#include "cmdutils.h" +MessageLevel::Enum MessageLevel::getLevel(const QString& levelName) +{ + if (levelName == "MultiMC") + return MessageLevel::MultiMC; + else if (levelName == "Debug") + return MessageLevel::Debug; + else if (levelName == "Info") + return MessageLevel::Info; + else if (levelName == "Message") + return MessageLevel::Message; + else if (levelName == "Warning") + return MessageLevel::Warning; + else if (levelName == "Error") + return MessageLevel::Error; + else if (levelName == "Fatal") + return MessageLevel::Fatal; + // Skip PrePost, it's not exposed to !![]! + else + return MessageLevel::Message; +} -#define IBUS "@im=ibus" +BaseProcess::BaseProcess(InstancePtr instance): QProcess(), m_instance(instance) +{ +} -// constructor -MinecraftProcess::MinecraftProcess(InstancePtr inst) : m_instance(inst) +void BaseProcess::init() { connect(this, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(finish(int, QProcess::ExitStatus))); @@ -113,114 +122,31 @@ MinecraftProcess::MinecraftProcess(InstancePtr inst) : m_instance(inst) if (m_instance->settings().get("LogPrePostOutput").toBool()) { connect(&m_prepostlaunchprocess, &QProcess::readyReadStandardError, this, - &MinecraftProcess::on_prepost_stdErr); + &BaseProcess::on_prepost_stdErr); connect(&m_prepostlaunchprocess, &QProcess::readyReadStandardOutput, this, - &MinecraftProcess::on_prepost_stdOut); + &BaseProcess::on_prepost_stdOut); } // a process has been constructed for the instance. It is running from MultiMC POV m_instance->setRunning(true); } -void MinecraftProcess::setWorkdir(QString path) + +void BaseProcess::setWorkdir(QString path) { QDir mcDir(path); this->setWorkingDirectory(mcDir.absolutePath()); m_prepostlaunchprocess.setWorkingDirectory(mcDir.absolutePath()); } -QString MinecraftProcess::censorPrivateInfo(QString in) -{ - if (!m_session) - return in; - - if (m_session->session != "-") - in.replace(m_session->session, "<SESSION ID>"); - in.replace(m_session->access_token, "<ACCESS TOKEN>"); - in.replace(m_session->client_token, "<CLIENT TOKEN>"); - in.replace(m_session->uuid, "<PROFILE ID>"); - in.replace(m_session->player_name, "<PROFILE NAME>"); - - auto i = m_session->u.properties.begin(); - while (i != m_session->u.properties.end()) - { - in.replace(i.value(), "<" + i.key().toUpper() + ">"); - ++i; - } - - return in; -} - -// console window -MessageLevel::Enum MinecraftProcess::guessLevel(const QString &line, MessageLevel::Enum level) -{ - QRegularExpression re("\\[(?<timestamp>[0-9:]+)\\] \\[[^/]+/(?<level>[^\\]]+)\\]"); - auto match = re.match(line); - if(match.hasMatch()) - { - // New style logs from log4j - QString timestamp = match.captured("timestamp"); - QString levelStr = match.captured("level"); - if(levelStr == "INFO") - level = MessageLevel::Message; - if(levelStr == "WARN") - level = MessageLevel::Warning; - if(levelStr == "ERROR") - level = MessageLevel::Error; - if(levelStr == "FATAL") - level = MessageLevel::Fatal; - if(levelStr == "TRACE" || levelStr == "DEBUG") - level = MessageLevel::Debug; - } - else - { - // Old style forge logs - if (line.contains("[INFO]") || line.contains("[CONFIG]") || line.contains("[FINE]") || - line.contains("[FINER]") || line.contains("[FINEST]")) - level = MessageLevel::Message; - if (line.contains("[SEVERE]") || line.contains("[STDERR]")) - level = MessageLevel::Error; - if (line.contains("[WARNING]")) - level = MessageLevel::Warning; - if (line.contains("[DEBUG]")) - level = MessageLevel::Debug; - } - if (line.contains("overwriting existing")) - return MessageLevel::Fatal; - if (line.contains("Exception in thread") || line.contains(QRegularExpression("\\s+at "))) - return MessageLevel::Error; - return level; -} - -MessageLevel::Enum MinecraftProcess::getLevel(const QString &levelName) -{ - if (levelName == "MultiMC") - return MessageLevel::MultiMC; - else if (levelName == "Debug") - return MessageLevel::Debug; - else if (levelName == "Info") - return MessageLevel::Info; - else if (levelName == "Message") - return MessageLevel::Message; - else if (levelName == "Warning") - return MessageLevel::Warning; - else if (levelName == "Error") - return MessageLevel::Error; - else if (levelName == "Fatal") - return MessageLevel::Fatal; - // Skip PrePost, it's not exposed to !![]! - else - return MessageLevel::Message; -} - -void MinecraftProcess::logOutput(const QStringList &lines, MessageLevel::Enum defaultLevel, +void BaseProcess::logOutput(const QStringList &lines, MessageLevel::Enum defaultLevel, bool guessLevel, bool censor) { for (int i = 0; i < lines.size(); ++i) logOutput(lines[i], defaultLevel, guessLevel, censor); } -void MinecraftProcess::logOutput(QString line, MessageLevel::Enum defaultLevel, bool guessLevel, +void BaseProcess::logOutput(QString line, MessageLevel::Enum defaultLevel, bool guessLevel, bool censor) { MessageLevel::Enum level = defaultLevel; @@ -235,7 +161,7 @@ void MinecraftProcess::logOutput(QString line, MessageLevel::Enum defaultLevel, int endmark = line.indexOf("]!"); if (line.startsWith("!![") && endmark != -1) { - level = getLevel(line.left(endmark).mid(3)); + level = MessageLevel::getLevel(line.left(endmark).mid(3)); line = line.mid(endmark + 2); } // Guess level @@ -248,7 +174,7 @@ void MinecraftProcess::logOutput(QString line, MessageLevel::Enum defaultLevel, emit log(line, level); } -void MinecraftProcess::on_stdErr() +void BaseProcess::on_stdErr() { QByteArray data = readAllStandardError(); QString str = m_err_leftover + QString::fromLocal8Bit(data); @@ -260,7 +186,7 @@ void MinecraftProcess::on_stdErr() logOutput(lines, MessageLevel::Error); } -void MinecraftProcess::on_stdOut() +void BaseProcess::on_stdOut() { QByteArray data = readAllStandardOutput(); QString str = m_out_leftover + QString::fromLocal8Bit(data); @@ -272,7 +198,7 @@ void MinecraftProcess::on_stdOut() logOutput(lines); } -void MinecraftProcess::on_prepost_stdErr() +void BaseProcess::on_prepost_stdErr() { QByteArray data = m_prepostlaunchprocess.readAllStandardError(); QString str = m_err_leftover + QString::fromLocal8Bit(data); @@ -284,7 +210,7 @@ void MinecraftProcess::on_prepost_stdErr() logOutput(lines, MessageLevel::PrePost, false, false); } -void MinecraftProcess::on_prepost_stdOut() +void BaseProcess::on_prepost_stdOut() { QByteArray data = m_prepostlaunchprocess.readAllStandardOutput(); QString str = m_out_leftover + QString::fromLocal8Bit(data); @@ -297,7 +223,7 @@ void MinecraftProcess::on_prepost_stdOut() } // exit handler -void MinecraftProcess::finish(int code, ExitStatus status) +void BaseProcess::finish(int code, ExitStatus status) { // Flush console window if (!m_err_leftover.isEmpty()) @@ -316,18 +242,18 @@ void MinecraftProcess::finish(int code, ExitStatus status) if (status == NormalExit) { //: Message displayed on instance exit - emit log(tr("Minecraft exited with exitcode %1.").arg(code)); + emit log(tr("Game exited with exitcode %1.").arg(code)); } else { //: Message displayed on instance crashed - emit log(tr("Minecraft crashed with exitcode %1.").arg(code)); + emit log(tr("Game crashed with exitcode %1.").arg(code)); } } else { //: Message displayed after the instance exits due to kill request - emit log(tr("Minecraft was killed by user."), MessageLevel::Error); + emit log(tr("Game was killed by user."), MessageLevel::Error); } m_prepostlaunchprocess.processEnvironment().insert("INST_EXITCODE", QString(code)); @@ -340,7 +266,7 @@ void MinecraftProcess::finish(int code, ExitStatus status) emit ended(m_instance, code, status); } -void MinecraftProcess::killMinecraft() +void BaseProcess::killProcess() { killed = true; if (m_prepostlaunchprocess.state() == QProcess::Running) @@ -353,7 +279,7 @@ void MinecraftProcess::killMinecraft() } } -bool MinecraftProcess::preLaunch() +bool BaseProcess::preLaunch() { QString prelaunch_cmd = m_instance->settings().get("PreLaunchCommand").toString(); if (!prelaunch_cmd.isEmpty()) @@ -398,7 +324,7 @@ bool MinecraftProcess::preLaunch() } return true; } -bool MinecraftProcess::postLaunch() +bool BaseProcess::postLaunch() { QString postlaunch_cmd = m_instance->settings().get("PostExitCommand").toString(); if (!postlaunch_cmd.isEmpty()) @@ -439,7 +365,7 @@ bool MinecraftProcess::postLaunch() return true; } -bool MinecraftProcess::waitForPrePost() +bool BaseProcess::waitForPrePost() { if (!m_prepostlaunchprocess.waitForStarted()) return false; @@ -457,18 +383,7 @@ bool MinecraftProcess::waitForPrePost() return ret == 0; } -QMap<QString, QString> MinecraftProcess::getVariables() const -{ - QMap<QString, QString> out; - out.insert("INST_NAME", m_instance->name()); - out.insert("INST_ID", m_instance->id()); - out.insert("INST_DIR", QDir(m_instance->instanceRoot()).absolutePath()); - out.insert("INST_MC_DIR", QDir(m_instance->minecraftRoot()).absolutePath()); - out.insert("INST_JAVA", m_instance->settings().get("JavaPath").toString()); - out.insert("INST_JAVA_ARGS", javaArguments().join(' ')); - return out; -} -QString MinecraftProcess::substituteVariables(const QString &cmd) const +QString BaseProcess::substituteVariables(const QString &cmd) const { QString out = cmd; auto variables = getVariables(); @@ -483,96 +398,3 @@ QString MinecraftProcess::substituteVariables(const QString &cmd) const } return out; } - -QStringList MinecraftProcess::javaArguments() const -{ - QStringList args; - - // custom args go first. we want to override them if we have our own here. - args.append(m_instance->extraArguments()); - -// OSX dock icon and name -#ifdef OSX - 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()); - auto permgen = m_instance->settings().get("PermGen").toInt(); - if (permgen != 64) - { - args << QString("-XX:PermSize=%1m").arg(permgen); - } - args << "-Duser.language=en"; - if (!m_nativeFolder.isEmpty()) - args << QString("-Djava.library.path=%1").arg(m_nativeFolder); - args << "-jar" << PathCombine(MMC->bin(), "jars", "NewLaunch.jar"); - - return args; -} - -void MinecraftProcess::arm() -{ - emit log("MultiMC version: " + BuildConfig.printableVersionString() + "\n\n"); - emit log("Minecraft folder is:\n" + workingDirectory() + "\n\n"); - - if (!preLaunch()) - { - emit ended(m_instance, 1, QProcess::CrashExit); - return; - } - - m_instance->setLastLaunch(); - - QStringList args = javaArguments(); - - QString JavaPath = m_instance->settings().get("JavaPath").toString(); - emit log("Java path is:\n" + JavaPath + "\n\n"); - QString allArgs = args.join(", "); - emit log("Java Arguments:\n[" + censorPrivateInfo(allArgs) + "]\n\n"); - - auto realJavaPath = QStandardPaths::findExecutable(JavaPath); - if (realJavaPath.isEmpty()) - { - emit log(tr("The java binary \"%1\" couldn't be found. You may have to set up java " - "if Minecraft fails to launch.").arg(JavaPath), - MessageLevel::Warning); - } - - // instantiate the launcher part - start(JavaPath, args); - if (!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; - } - // send the launch script to the launcher part - QByteArray bytes = launchScript.toUtf8(); - writeData(bytes.constData(), bytes.length()); -} - -void MinecraftProcess::launch() -{ - QString launchString("launch\n"); - QByteArray bytes = launchString.toUtf8(); - writeData(bytes.constData(), bytes.length()); -} - -void MinecraftProcess::abort() -{ - QString launchString("abort\n"); - QByteArray bytes = launchString.toUtf8(); - writeData(bytes.constData(), bytes.length()); -} diff --git a/logic/MinecraftProcess.h b/logic/BaseProcess.h index d74363f6..ff8b9ed3 100644 --- a/logic/MinecraftProcess.h +++ b/ |
