summaryrefslogtreecommitdiffstats
path: root/api/logic/minecraft/launch
diff options
context:
space:
mode:
Diffstat (limited to 'api/logic/minecraft/launch')
-rw-r--r--api/logic/minecraft/launch/ClaimAccount.cpp20
-rw-r--r--api/logic/minecraft/launch/ClaimAccount.h24
-rw-r--r--api/logic/minecraft/launch/CreateServerResourcePacksFolder.cpp14
-rw-r--r--api/logic/minecraft/launch/CreateServerResourcePacksFolder.h18
-rw-r--r--api/logic/minecraft/launch/DirectJavaLaunch.cpp198
-rw-r--r--api/logic/minecraft/launch/DirectJavaLaunch.h40
-rw-r--r--api/logic/minecraft/launch/ExtractNatives.cpp122
-rw-r--r--api/logic/minecraft/launch/ExtractNatives.h20
-rw-r--r--api/logic/minecraft/launch/LauncherPartLaunch.cpp294
-rw-r--r--api/logic/minecraft/launch/LauncherPartLaunch.h44
-rw-r--r--api/logic/minecraft/launch/ModMinecraftJar.cpp92
-rw-r--r--api/logic/minecraft/launch/ModMinecraftJar.h22
-rw-r--r--api/logic/minecraft/launch/PrintInstanceInfo.cpp97
-rw-r--r--api/logic/minecraft/launch/PrintInstanceInfo.h20
-rw-r--r--api/logic/minecraft/launch/ReconstructAssets.cpp36
-rw-r--r--api/logic/minecraft/launch/ReconstructAssets.h33
-rw-r--r--api/logic/minecraft/launch/ScanModFolders.cpp54
-rw-r--r--api/logic/minecraft/launch/ScanModFolders.h42
18 files changed, 692 insertions, 498 deletions
diff --git a/api/logic/minecraft/launch/ClaimAccount.cpp b/api/logic/minecraft/launch/ClaimAccount.cpp
index 71670b4f..a1180f0a 100644
--- a/api/logic/minecraft/launch/ClaimAccount.cpp
+++ b/api/logic/minecraft/launch/ClaimAccount.cpp
@@ -3,22 +3,22 @@
ClaimAccount::ClaimAccount(LaunchTask* parent, AuthSessionPtr session): LaunchStep(parent)
{
- if(session->status == AuthSession::Status::PlayableOnline)
- {
- m_account = session->m_accountPtr;
- }
+ if(session->status == AuthSession::Status::PlayableOnline)
+ {
+ m_account = session->m_accountPtr;
+ }
}
void ClaimAccount::executeTask()
{
- if(m_account)
- {
- lock.reset(new UseLock(m_account));
- emitSucceeded();
- }
+ if(m_account)
+ {
+ lock.reset(new UseLock(m_account));
+ emitSucceeded();
+ }
}
void ClaimAccount::finalize()
{
- lock.reset();
+ lock.reset();
}
diff --git a/api/logic/minecraft/launch/ClaimAccount.h b/api/logic/minecraft/launch/ClaimAccount.h
index de9007d1..d0892981 100644
--- a/api/logic/minecraft/launch/ClaimAccount.h
+++ b/api/logic/minecraft/launch/ClaimAccount.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,16 +20,18 @@
class ClaimAccount: public LaunchStep
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit ClaimAccount(LaunchTask *parent, AuthSessionPtr session);
- void executeTask() override;
- void finalize() override;
- bool canAbort() const override
- {
- return false;
- }
+ explicit ClaimAccount(LaunchTask *parent, AuthSessionPtr session);
+ virtual ~ClaimAccount() {};
+
+ void executeTask() override;
+ void finalize() override;
+ bool canAbort() const override
+ {
+ return false;
+ }
private:
- std::unique_ptr<UseLock> lock;
- MojangAccountPtr m_account;
+ std::unique_ptr<UseLock> lock;
+ MojangAccountPtr m_account;
};
diff --git a/api/logic/minecraft/launch/CreateServerResourcePacksFolder.cpp b/api/logic/minecraft/launch/CreateServerResourcePacksFolder.cpp
index 5398f7d0..ae426e31 100644
--- a/api/logic/minecraft/launch/CreateServerResourcePacksFolder.cpp
+++ b/api/logic/minecraft/launch/CreateServerResourcePacksFolder.cpp
@@ -9,11 +9,11 @@ CreateServerResourcePacksFolder::CreateServerResourcePacksFolder(LaunchTask* par
void CreateServerResourcePacksFolder::executeTask()
{
- auto instance = m_parent->instance();
- std::shared_ptr<MinecraftInstance> minecraftInstance = std::dynamic_pointer_cast<MinecraftInstance>(instance);
- if(!FS::ensureFolderPathExists(FS::PathCombine(minecraftInstance->minecraftRoot(), "server-resource-packs")))
- {
- emit logLine(tr("Couldn't create the 'server-resource-packs' folder"), MessageLevel::Error);
- }
- emitSucceeded();
+ auto instance = m_parent->instance();
+ std::shared_ptr<MinecraftInstance> minecraftInstance = std::dynamic_pointer_cast<MinecraftInstance>(instance);
+ if(!FS::ensureFolderPathExists(FS::PathCombine(minecraftInstance->gameRoot(), "server-resource-packs")))
+ {
+ emit logLine(tr("Couldn't create the 'server-resource-packs' folder"), MessageLevel::Error);
+ }
+ emitSucceeded();
}
diff --git a/api/logic/minecraft/launch/CreateServerResourcePacksFolder.h b/api/logic/minecraft/launch/CreateServerResourcePacksFolder.h
index 92026ecb..00ab2f2d 100644
--- a/api/logic/minecraft/launch/CreateServerResourcePacksFolder.h
+++ b/api/logic/minecraft/launch/CreateServerResourcePacksFolder.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,14 +22,16 @@
// HACK: this is a workaround for MCL-3732 - 'server-resource-packs' folder is created.
class CreateServerResourcePacksFolder: public LaunchStep
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit CreateServerResourcePacksFolder(LaunchTask *parent);
- virtual void executeTask();
- virtual bool canAbort() const
- {
- return false;
- }
+ explicit CreateServerResourcePacksFolder(LaunchTask *parent);
+ virtual ~CreateServerResourcePacksFolder() {};
+
+ virtual void executeTask();
+ virtual bool canAbort() const
+ {
+ return false;
+ }
};
diff --git a/api/logic/minecraft/launch/DirectJavaLaunch.cpp b/api/logic/minecraft/launch/DirectJavaLaunch.cpp
index 4ccc5c3c..5c2bb91e 100644
--- a/api/logic/minecraft/launch/DirectJavaLaunch.cpp
+++ b/api/logic/minecraft/launch/DirectJavaLaunch.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,128 +22,128 @@
DirectJavaLaunch::DirectJavaLaunch(LaunchTask *parent) : LaunchStep(parent)
{
- connect(&m_process, &LoggedProcess::log, this, &DirectJavaLaunch::logLines);
- connect(&m_process, &LoggedProcess::stateChanged, this, &DirectJavaLaunch::on_state);
+ connect(&m_process, &LoggedProcess::log, this, &DirectJavaLaunch::logLines);
+ connect(&m_process, &LoggedProcess::stateChanged, this, &DirectJavaLaunch::on_state);
}
void DirectJavaLaunch::executeTask()
{
- auto instance = m_parent->instance();
- std::shared_ptr<MinecraftInstance> minecraftInstance = std::dynamic_pointer_cast<MinecraftInstance>(instance);
- QStringList args = minecraftInstance->javaArguments();
+ auto instance = m_parent->instance();
+ std::shared_ptr<MinecraftInstance> minecraftInstance = std::dynamic_pointer_cast<MinecraftInstance>(instance);
+ QStringList args = minecraftInstance->javaArguments();
- args.append("-Djava.library.path=" + minecraftInstance->getNativePath());
+ args.append("-Djava.library.path=" + minecraftInstance->getNativePath());
- auto classPathEntries = minecraftInstance->getClassPath();
- args.append("-cp");
- QString classpath;
+ auto classPathEntries = minecraftInstance->getClassPath();
+ args.append("-cp");
+ QString classpath;
#ifdef Q_OS_WIN32
- classpath = classPathEntries.join(';');
+ classpath = classPathEntries.join(';');
#else
- classpath = classPathEntries.join(':');
+ classpath = classPathEntries.join(':');
#endif
- args.append(classpath);
- args.append(minecraftInstance->getMainClass());
-
- QString allArgs = args.join(", ");
- emit logLine("Java Arguments:\n[" + m_parent->censorPrivateInfo(allArgs) + "]\n\n", MessageLevel::MultiMC);
-
- auto javaPath = FS::ResolveExecutable(instance->settings()->get("JavaPath").toString());
-
- m_process.setProcessEnvironment(instance->createEnvironment());
-
- // make detachable - this will keep the process running even if the object is destroyed
- m_process.setDetachable(true);
-
- auto mcArgs = minecraftInstance->processMinecraftArgs(m_session);
- args.append(mcArgs);
-
- QString wrapperCommandStr = instance->getWrapperCommand().trimmed();
- if(!wrapperCommandStr.isEmpty())
- {
- auto wrapperArgs = Commandline::splitArgs(wrapperCommandStr);
- auto wrapperCommand = wrapperArgs.takeFirst();
- 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" + wrapperCommandStr + "\n\n", MessageLevel::MultiMC);
- args.prepend(javaPath);
- m_process.start(wrapperCommand, wrapperArgs + args);
- }
- else
- {
- m_process.start(javaPath, args);
- }
+ args.append(classpath);
+ args.append(minecraftInstance->getMainClass());
+
+ QString allArgs = args.join(", ");
+ emit logLine("Java Arguments:\n[" + m_parent->censorPrivateInfo(allArgs) + "]\n\n", MessageLevel::MultiMC);
+
+ auto javaPath = FS::ResolveExecutable(instance->settings()->get("JavaPath").toString());
+
+ m_process.setProcessEnvironment(instance->createEnvironment());
+
+ // make detachable - this will keep the process running even if the object is destroyed
+ m_process.setDetachable(true);
+
+ auto mcArgs = minecraftInstance->processMinecraftArgs(m_session);
+ args.append(mcArgs);
+
+ QString wrapperCommandStr = instance->getWrapperCommand().trimmed();
+ if(!wrapperCommandStr.isEmpty())
+ {
+ auto wrapperArgs = Commandline::splitArgs(wrapperCommandStr);
+ auto wrapperCommand = wrapperArgs.takeFirst();
+ 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" + wrapperCommandStr + "\n\n", MessageLevel::MultiMC);
+ args.prepend(javaPath);
+ m_process.start(wrapperCommand, wrapperArgs + args);
+ }
+ else
+ {
+ m_process.start(javaPath, args);
+ }
}
void DirectJavaLaunch::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);
- // if the exit code wasn't 0, report this as a crash
- auto exitCode = m_process.exitCode();
- if(exitCode != 0)
- {
- emitFailed("Game crashed.");
- return;
- }
- //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.processId());
- m_parent->instance()->setLastLaunch();
- break;
- default:
- break;
- }
+ 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);
+ // if the exit code wasn't 0, report this as a crash
+ auto exitCode = m_process.exitCode();
+ if(exitCode != 0)
+ {
+ emitFailed("Game crashed.");
+ return;
+ }
+ //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.processId());
+ m_parent->instance()->setLastLaunch();
+ break;
+ default:
+ break;
+ }
}
void DirectJavaLaunch::setWorkingDirectory(const QString &wd)
{
- m_process.setWorkingDirectory(wd);
+ m_process.setWorkingDirectory(wd);
}
void DirectJavaLaunch::proceed()
{
- // nil
+ // nil
}
bool DirectJavaLaunch::abort()
{
- auto state = m_process.state();
- if (state == LoggedProcess::Running || state == LoggedProcess::Starting)
- {
- m_process.kill();
- }
- return true;
+ auto state = m_process.state();
+ if (state == LoggedProcess::Running || state == LoggedProcess::Starting)
+ {
+ m_process.kill();
+ }
+ return true;
}
diff --git a/api/logic/minecraft/launch/DirectJavaLaunch.h b/api/logic/minecraft/launch/DirectJavaLaunch.h
index 19087b50..9f57272c 100644
--- a/api/logic/minecraft/launch/DirectJavaLaunch.h
+++ b/api/logic/minecraft/launch/DirectJavaLaunch.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,27 +21,29 @@
class DirectJavaLaunch: public LaunchStep
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit DirectJavaLaunch(LaunchTask *parent);
- virtual void executeTask();
- virtual bool abort();
- virtual void proceed();
- virtual bool canAbort() const
- {
- return true;
- }
- void setWorkingDirectory(const QString &wd);
- void setAuthSession(AuthSessionPtr session)
- {
- m_session = session;
- }
+ explicit DirectJavaLaunch(LaunchTask *parent);
+ virtual ~DirectJavaLaunch() {};
+
+ virtual void executeTask();
+ virtual bool abort();
+ virtual void proceed();
+ virtual bool canAbort() const
+ {
+ return true;
+ }
+ void setWorkingDirectory(const QString &wd);
+ void setAuthSession(AuthSessionPtr session)
+ {
+ m_session = session;
+ }
private slots:
- void on_state(LoggedProcess::State state);
+ void on_state(LoggedProcess::State state);
private:
- LoggedProcess m_process;
- QString m_command;
- AuthSessionPtr m_session;
+ LoggedProcess m_process;
+ QString m_command;
+ AuthSessionPtr m_session;
};
diff --git a/api/logic/minecraft/launch/ExtractNatives.cpp b/api/logic/minecraft/launch/ExtractNatives.cpp
index 7ddde374..253d13bc 100644
--- a/api/logic/minecraft/launch/ExtractNatives.cpp
+++ b/api/logic/minecraft/launch/ExtractNatives.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,76 +25,76 @@
static QString replaceSuffix (QString target, const QString &suffix, const QString &replacement)
{
- if (!target.endsWith(suffix))
- {
- return target;
- }
- target.resize(target.length() - suffix.length());
- return target + replacement;
+ if (!target.endsWith(suffix))
+ {
+ return target;
+ }
+ target.resize(target.length() - suffix.length());
+ return target + replacement;
}
static bool unzipNatives(QString source, QString targetFolder, bool applyJnilibHack)
{
- QuaZip zip(source);
- if(!zip.open(QuaZip::mdUnzip))
- {
- return false;
- }
- QDir directory(targetFolder);
- if (!zip.goToFirstFile())
- {
- return false;
- }
- do
- {
- QString name = zip.getCurrentFileName();
- if(applyJnilibHack)
- {
- name = replaceSuffix(name, ".jnilib", ".dylib");
- }
- QString absFilePath = directory.absoluteFilePath(name);
- if (!JlCompress::extractFile(&zip, "", absFilePath))
- {
- return false;
- }
- } while (zip.goToNextFile());
- zip.close();
- if(zip.getZipError()!=0)
- {
- return false;
- }
- return true;
+ QuaZip zip(source);
+ if(!zip.open(QuaZip::mdUnzip))
+ {
+ return false;
+ }
+ QDir directory(targetFolder);
+ if (!zip.goToFirstFile())
+ {
+ return false;
+ }
+ do
+ {
+ QString name = zip.getCurrentFileName();
+ if(applyJnilibHack)
+ {
+ name = replaceSuffix(name, ".jnilib", ".dylib");
+ }
+ QString absFilePath = directory.absoluteFilePath(name);
+ if (!JlCompress::extractFile(&zip, "", absFilePath))
+ {
+ return false;
+ }
+ } while (zip.goToNextFile());
+ zip.close();
+ if(zip.getZipError()!=0)
+ {
+ return false;
+ }
+ return true;
}
void ExtractNatives::executeTask()
{
- auto instance = m_parent->instance();
- std::shared_ptr<MinecraftInstance> minecraftInstance = std::dynamic_pointer_cast<MinecraftInstance>(instance);
- auto toExtract = minecraftInstance->getNativeJars();
- if(toExtract.isEmpty())
- {
- emitSucceeded();
- return;
- }
- auto outputPath = minecraftInstance->getNativePath();
- auto javaVersion = minecraftInstance->getJavaVersion();
- bool jniHackEnabled = javaVersion.major() >= 8;
- for(const auto &source: toExtract)
- {
- if(!unzipNatives(source, outputPath, jniHackEnabled))
- {
- auto reason = tr("Couldn't extract native jar '%1' to destination '%2'").arg(source, outputPath);
- emit logLine(reason, MessageLevel::Fatal);
- emitFailed(reason);
- }
- }
- emitSucceeded();
+ auto instance = m_parent->instance();
+ std::shared_ptr<MinecraftInstance> minecraftInstance = std::dynamic_pointer_cast<MinecraftInstance>(instance);
+ auto toExtract = minecraftInstance->getNativeJars();
+ if(toExtract.isEmpty())
+ {
+ emitSucceeded();
+ return;
+ }
+ auto outputPath = minecraftInstance->getNativePath();
+ auto javaVersion = minecraftInstance->getJavaVersion();
+ bool jniHackEnabled = javaVersion.major() >= 8;
+ for(const auto &source: toExtract)
+ {
+ if(!unzipNatives(source, outputPath, jniHackEnabled))
+ {
+ auto reason = tr("Couldn't extract native jar '%1' to destination '%2'").arg(source, outputPath);
+ emit logLine(reason, MessageLevel::Fatal);
+ emitFailed(reason);
+ }
+ }
+ emitSucceeded();
}
void ExtractNatives::finalize()
{
- auto instance = m_parent->instance();
- QString target_dir = FS::PathCombine(instance->instanceRoot(), "natives/");
- QDir dir(target_dir);
- dir.removeRecursively();
+ auto instance = m_parent->instance();
+ QString target_dir = FS::PathCombine(instance->instanceRoot(), "natives/");
+ QDir dir(target_dir);
+ dir.removeRecursively();
}
diff --git a/api/logic/minecraft/launch/ExtractNatives.h b/api/logic/minecraft/launch/ExtractNatives.h
index 6e1e7cd4..abb3bd7a 100644
--- a/api/logic/minecraft/launch/ExtractNatives.h
+++ b/api/logic/minecraft/launch/ExtractNatives.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,17 +22,17 @@
// FIXME: temporary wrapper for existing task.
class ExtractNatives: public LaunchStep
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit ExtractNatives(LaunchTask *parent) : LaunchStep(parent){};
- virtual ~ExtractNatives(){};
+ explicit ExtractNatives(LaunchTask *parent) : LaunchStep(parent){};
+ virtual ~ExtractNatives(){};
- void executeTask() override;
- bool canAbort() const override
- {
- return false;
- }
- void finalize() override;
+ void executeTask() override;
+ bool canAbort() const override
+ {
+ return false;
+ }
+ void finalize() override;
};
diff --git a/api/logic/minecraft/launch/LauncherPartLaunch.cpp b/api/logic/minecraft/launch/LauncherPartLaunch.cpp
index 1fe9c323..e854a3a6 100644
--- a/api/logic/minecraft/launch/LauncherPartLaunch.cpp
+++ b/api/logic/minecraft/launch/LauncherPartLaunch.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,8 +24,8 @@
LauncherPartLaunch::LauncherPartLaunch(LaunchTask *parent) : LaunchStep(parent)
{
- connect(&m_process, &LoggedProcess::log, this, &LauncherPartLaunch::logLines);
- connect(&m_process, &LoggedProcess::stateChanged, this, &LauncherPartLaunch::on_state);
+ connect(&m_process, &LoggedProcess::log, this, &LauncherPartLaunch::logLines);
+ connect(&m_process, &LoggedProcess::stateChanged, this, &LauncherPartLaunch::on_state);
}
#ifdef Q_OS_WIN
@@ -33,187 +33,187 @@ LauncherPartLaunch::LauncherPartLaunch(LaunchTask *parent) : LaunchStep(parent)
#include <windows.h>
QString shortPathName(const QString & file)
{
- auto input = file.toStdWString();
- std::wstring output;
- long length = GetShortPathNameW(input.c_str(), NULL, 0);
- // NOTE: this resizing might seem weird...
- // when GetShortPathNameW fails, it returns length including null character
- // when it succeeds, it returns length excluding null character
- // See: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364989(v=vs.85).aspx
- output.resize(length);
- GetShortPathNameW(input.c_str(),(LPWSTR)output.c_str(),length);
- output.resize(length-1);
- QString ret = QString::fromStdWString(output);
- return ret;
+ auto input = file.toStdWString();
+ std::wstring output;
+ long length = GetShortPathNameW(input.c_str(), NULL, 0);
+ // NOTE: this resizing might seem weird...
+ // when GetShortPathNameW fails, it returns length including null character
+ // when it succeeds, it returns length excluding null character
+ // See: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364989(v=vs.85).aspx
+ output.resize(length);
+ GetShortPathNameW(input.c_str(),(LPWSTR)output.c_str(),length);
+ output.resize(length-1);
+ QString ret = QString::fromStdWString(output);
+ return ret;
}
#endif
// if the string survives roundtrip through local 8bit encoding...
bool fitsInLocal8bit(const QString & string)
{
- return string == QString::fromLocal8Bit(string.toLocal8Bit());
+ return string == QString::fromLocal8Bit(string.toLocal8Bit());
}
void LauncherPartLaunch::executeTask()
{
- auto instance = m_parent->instance();
- std::shared_ptr<MinecraftInstance> minecraftInstance = std::dynamic_pointer_cast<MinecraftInstance>(instance);
+ auto instance = m_parent->instance();
+ std::shared_ptr<MinecraftInstance> minecraftInstance = std::dynamic_pointer_cast<MinecraftInstance>(instance);
- m_launchScript = minecraftInstance->createLaunchScript(m_session);
- QStringList args = minecraftInstance->javaArguments();
- QString allArgs = args.join(", ");
- emit logLine("Java Arguments:\n[" + m_parent->censorPrivateInfo(allArgs) + "]\n\n", MessageLevel::MultiMC);
+ m_launchScript = minecraftInstance->createLaunchScript(m_session);
+ QStringList args = minecraftInstance->javaArguments();
+ QString allArgs = args.join(", ");
+ emit logLine("Java Arguments:\n[" + m_parent->censorPrivateInfo(allArgs) + "]\n\n", MessageLevel::MultiMC);
- auto javaPath = FS::ResolveExecutable(instance->settings()->get("JavaPath").toString());
+ auto javaPath = FS::ResolveExecutable(instance->settings()->get("JavaPath").toString());
- m_process.setProcessEnvironment(instance->createEnvironment());
+ m_process.setProcessEnvironment(instance->createEnvironment());
- // make detachable - this will keep the process running even if the object is destroyed
- m_process.setDetachable(true);
+ // make detachable - this will keep the process running even if the object is destroyed
+ m_process.setDetachable(true);
- auto classPath = minecraftInstance->getClassPath();
- classPath.prepend(FS::PathCombine(ENV.getJarsPath(), "NewLaunch.jar"));
+ auto classPath = minecraftInstance->getClassPath();
+ classPath.prepend(FS::PathCombine(ENV.getJarsPath(), "NewLaunch.jar"));
- auto natPath = minecraftInstance->getNativePath();
+ auto natPath = minecraftInstance->getNativePath();
#ifdef Q_OS_WIN
- if (!fitsInLocal8bit(natPath))
- {
- args << "-Djava.library.path=" + shortPathName(natPath);
- }
- else
- {
- args << "-Djava.library.path=" + natPath;
- }
+ if (!fitsInLocal8bit(natPath))
+ {
+ args << "-Djava.library.path=" + shortPathName(natPath);
+ }
+ else
+ {
+ args << "-Djava.library.path=" + natPath;
+ }
#else
- args << "-Djava.library.path=" + natPath;
+ args << "-Djava.library.path=" + natPath;
#endif
- args << "-cp";
+ args << "-cp";
#ifdef Q_OS_WIN
- QStringList processed;
- for(auto & item: classPath)
- {
- if (!fitsInLocal8bit(item))
- {
- processed << shortPathName(item);
- }
- else
- {
- processed << item;
- }
- }
- args << processed.join(';');
+ QStringList processed;
+ for(auto & item: classPath)
+ {
+ if (!fitsInLocal8bit(item))
+ {
+ processed << shortPathName(item);
+ }
+ else
+ {
+ processed << item;
+ }
+ }
+ args << processed.join(';');
#else
- args << classPath.join(':');
+ args << classPath.join(':');
#endif
- args << "org.multimc.EntryPoint";
-
- qDebug() << args.join(' ');
-
- QString wrapperCommandStr = instance->getWrapperCommand().trimmed();
- if(!wrapperCommandStr.isEmpty())
- {
- auto wrapperArgs = Commandline::splitArgs(wrapperCommandStr);
- auto wrapperCommand = wrapperArgs.takeFirst();
- 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" + wrapperCommandStr + "\n\n", MessageLevel::MultiMC);
- args.prepend(javaPath);
- m_process.start(wrapperCommand, wrapperArgs + args);
- }
- else
- {
- m_process.start(javaPath, args);
- }
+ args << "org.multimc.EntryPoint";
+
+ qDebug() << args.join(' ');
+
+ QString wrapperCommandStr = instance->getWrapperCommand().trimmed();
+ if(!wrapperCommandStr.isEmpty())
+ {
+ auto wrapperArgs = Commandline::splitArgs(wrapperCommandStr);
+ auto wrapperCommand = wrapperArgs.takeFirst();
+ 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" + wrapperCommandStr + "\n\n", MessageLevel::MultiMC);
+ args.prepend(javaPath);
+ m_process.start(wrapperCommand, wrapperArgs + args);
+ }
+ else
+ {
+ m_process.start(javaPath, args);
+ }
}
void LauncherPartLaunch::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);
- // if the exit code wasn't 0, report this as a crash
- auto exitCode = m_process.exitCode();
- if(exitCode != 0)
- {
- emitFailed("Game crashed.");
- return;
- }
- //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.processId());
- 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;
- }
+ 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);
+ // if the exit code wasn't 0, report this as a crash
+ auto exitCode = m_process.exitCode();
+ if(exitCode != 0)
+ {
+ emitFailed("Game crashed.");
+ return;
+ }
+ //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.processId());
+ 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 LauncherPartLaunch::setWorkingDirectory(const QString &wd)
{
- m_process.setWorkingDirectory(wd);
+ m_process.setWorkingDirectory(wd);
}
void LauncherPartLaunch::proceed()
{
- if(mayProceed)
- {
- QString launchString("launch\n");
- m_process.write(launchString.toUtf8());
- mayProceed = false;
- }
+ if(mayProceed)
+ {
+ QString launchString("launch\n");
+ m_process.write(launchString.toUtf8());
+ mayProceed = false;
+ }
}
bool LauncherPartLaunch::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;
+ 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;
}
diff --git a/api/logic/minecraft/launch/LauncherPartLaunch.h b/api/logic/minecraft/launch/LauncherPartLaunch.h
index d384c2d1..1bc4a5f8 100644
--- a/api/logic/minecraft/launch/LauncherPartLaunch.h
+++ b/api/logic/minecraft/launch/LauncherPartLaunch.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,29 +21,31 @@
class LauncherPartLaunch: public LaunchStep
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit LauncherPartLaunch(LaunchTask *parent);
- virtual void executeTask();
- virtual bool abort();
- virtual void proceed();
- virtual bool canAbort() const
- {
- return true;
- }
- void setWorkingDirectory(const QString &wd);
- void setAuthSession(AuthSessionPtr session)
- {
- m_session = session;
- }
+ explicit LauncherPartLaunch(LaunchTask *parent);
+ virtual ~LauncherPartLaunch() {};
+
+ virtual void executeTask();
+ virtual bool abort();
+ virtual void proceed();
+ virtual bool canAbort() const
+ {
+ return true;
+ }
+ void setWorkingDirectory(const QString &wd);
+ void setAuthSession(AuthSessionPtr session)
+ {
+ m_session = session;
+ }
private slots:
- void on_state(LoggedProcess::State state);
+ void on_state(LoggedProcess::State state);
private:
- LoggedProcess m_process;
- QString m_command;
- AuthSessionPtr m_session;
- QString m_launchScript;
- bool mayProceed = false;
+ LoggedProcess m_process;
+ QString m_command;
+ AuthSessionPtr m_session;
+ QString m_launchScript;
+ bool mayProceed = false;
};
diff --git a/api/logic/minecraft/launch/ModMinecraftJar.cpp b/api/logic/minecraft/launch/ModMinecraftJar.cpp
index 34825b45..ceaad175 100644
--- a/api/logic/minecraft/launch/ModMinecraftJar.cpp
+++ b/api/logic/minecraft/launch/ModMinecraftJar.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,60 +23,60 @@
void ModMinecraftJar::executeTask()
{
- auto m_inst = std::dynamic_pointer_cast<MinecraftInstance>(m_parent->instance());
+ auto m_inst = std::dynamic_pointer_cast<MinecraftInstance>(m_parent->instance());
- if(!m_inst->getJarMods().size())
- {
- emitSucceeded();
- return;
- }
- // nuke obsolete stripped jar(s) if needed
- if(!FS::ensureFolderPathExists(m_inst->binRoot()))
- {
- emitFailed(tr("Couldn't create the bin folder for Minecraft.jar"));
- }
+ if(!m_inst->getJarMods().size())
+ {
+ emitSucceeded();
+ return;
+ }
+ // nuke obsolete stripped jar(s) if needed
+ if(!FS::ensureFolderPathExists(m_inst->binRoot()))
+ {
+ emitFailed(tr("Couldn't create the bin folder for Minecraft.jar"));
+ }
- auto finalJarPath = QDir(m_inst->binRoot()).absoluteFilePath("minecraft.jar");
- if(!removeJar())
- {
- emitFailed(tr("Couldn't remove stale jar file: %1").arg(finalJarPath));
- }
+ auto finalJarPath = QDir(m_inst->binRoot()).absoluteFilePath("minecraft.jar");
+ if(!removeJar())
+ {
+ emitFailed(tr("Couldn't remove stale jar file: %1").arg(finalJarPath));
+ }
- // create temporary modded jar, if needed
- auto components = m_inst->getComponentList();
- auto profile = components->getProfile();
- auto jarMods = m_inst->getJarMods();
- if(jarMods.size())
- {
- auto mainJar = profile->getMainJar();
- QStringList jars, temp1, temp2, temp3, temp4;
- mainJar->getApplicableFiles(currentSystem, jars, temp1, temp2, temp3, m_inst->getLocalLibraryPath());
- auto sourceJarPath = jars[0];
- if(!MMCZip::createModdedJar(sourceJarPath, finalJarPath, jarMods))
- {
- emitFailed(tr("Failed to create the custom Minecraft jar file."));
- return;
- }
- }
- emitSucceeded();
+ // create temporary modded jar, if needed
+ auto components = m_inst->getComponentList();
+ auto profile = components->getProfile();
+ auto jarMods = m_inst->getJarMods();
+ if(jarMods.size())
+ {
+ auto mainJar = profile->getMainJar();
+ QStringList jars, temp1, temp2, temp3, temp4;
+ mainJar->getApplicableFiles(currentSystem, jars, temp1, temp2, temp3, m_inst->getLocalLibraryPath());
+ auto sourceJarPath = jars[0];
+ if(!MMCZip::createModdedJar(sourceJarPath, finalJarPath, jarMods))
+ {
+ emitFailed(tr("Failed to create the custom Minecraft jar file."));
+ return;
+ }
+ }
+ emitSucceeded();
}
void ModMinecraftJar::finalize()
{
- removeJar();
+ removeJar();
}
bool ModMinecraftJar::removeJar()
{
- auto m_inst = std::dynamic_pointer_cast<MinecraftInstance>(m_parent->instance());
- auto finalJarPath = QDir(m_inst->binRoot()).absoluteFilePath("minecraft.jar");
- QFile finalJar(finalJarPath);
- if(finalJar.exists())
- {
- if(!finalJar.remove())
- {
- return false;
- }
- }
- return true;
+ auto m_inst = std::dynamic_pointer_cast<MinecraftInstance>(m_parent->instance());
+ auto finalJarPath = QDir(m_inst->binRoot()).absoluteFilePath("minecraft.jar");
+ QFile finalJar(finalJarPath);
+ if(finalJar.exists())
+ {
+ if(!finalJar.remove())
+ {
+ return false;
+ }
+ }
+ return true;
}
diff --git a/api/logic/minecraft/launch/ModMinecraftJar.h b/api/logic/minecraft/launch/ModMinecraftJar.h
index b9a2d35b..bed5079f 100644
--- a/api/logic/minecraft/launch/ModMinecraftJar.h
+++ b/api/logic/minecraft/launch/ModMinecraftJar.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,17 +20,17 @@
class ModMinecraftJar: public LaunchStep
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit ModMinecraftJar(LaunchTask *parent) : LaunchStep(parent) {};
- virtual ~ModMinecraftJar(){};
+ explicit ModMinecraftJar(LaunchTask *parent) : LaunchStep(parent) {};
+ virtual ~ModMinecraftJar(){};
- virtual void executeTask();
- virtual bool canAbort() const
- {
- return false;
- }
- void finalize() override;
+ virtual void executeTask() override;
+ virtual bool canAbort() const override
+ {
+ return false;
+ }
+ void finalize() override;
private:
- bool removeJar();
+ bool removeJar();
};
diff --git a/api/logic/minecraft/launch/PrintInstanceInfo.cpp b/api/logic/minecraft/launch/PrintInstanceInfo.cpp
index 83bf584f..4cc180fd 100644
--- a/api/logic/minecraft/launch/PrintInstanceInfo.cpp
+++ b/api/logic/minecraft/launch/PrintInstanceInfo.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,67 +19,88 @@
#include "PrintInstanceInfo.h"
#include <launch/LaunchTask.h>
-void PrintInstanceInfo::executeTask()
-{
- auto instance = m_parent->instance();
- auto lines = instance->verboseDescription(m_session);
-
#ifdef Q_OS_LINUX
+namespace {
+void probeProcCpuinfo(QStringList &log)
+{
std::ifstream cpuin("/proc/cpuinfo");
for (std::string line; std::getline(cpuin, line);)
{
if (strncmp(line.c_str(), "model name", 10) == 0)
{
- QStringList clines = (QStringList() << QString::fromStdString(line.substr(13, std::string::npos)));
- logLines(clines, MessageLevel::MultiMC);
+ log << QString::fromStdString(line.substr(13, std::string::npos));
break;
}
}
+}
+void runLspci(QStringList &log)
+{
+ // FIXME: fixed size buffers...
char buff[512];
int gpuline = -1;
int cline = 0;
- FILE *fp = popen("lspci -k", "r");
- if (fp != NULL)
+ FILE * lspci = popen("lspci -k", "r");
+
+ if (!lspci)
+ return;
+
+ while (fgets(buff, 512, lspci) != NULL)
{
- while (fgets(buff, 512, fp) != NULL)
+ std::string str(buff);
+ if (str.length() < 9)
+ continue;
+ if (str.substr(8, 3) == "VGA")
{
- std::string str(buff);
- if (str.length() < 9)
- continue;
- if (str.substr(8, 3) == "VGA")
- {
- gpuline = cline;
- QStringList glines = (QStringList() << QString::fromStdString(str.substr(35, std::string::npos)));
- logLines(glines, MessageLevel::MultiMC);
- }
- if (gpuline > -1 && gpuline != cline)
+ gpuline = cline;
+ log << QString::fromStdString(str.substr(35, std::string::npos));
+ }
+ if (gpuline > -1 && gpuline != cline)
+ {
+ if (cline - gpuline < 3)
{
- if (cline - gpuline < 3)
- {
- QStringList alines = (QStringList() << QString::fromStdString(str.substr(1, std::string::npos)));
- logLines(alines, MessageLevel::MultiMC);
- }
+ log << QString::fromStdString(str.substr(1, std::string::npos));
}
- cline++;
}
+ cline++;
}
-
- FILE *fp2 = popen("glxinfo", "r");
- if (fp2 != NULL)
+ pclose(lspci);
+}
+
+void runGlxinfo(QStringList & log)
+{
+ // FIXME: fixed size buffers...
+ char buff[512];
+ FILE *glxinfo = popen("glxinfo", "r");
+ if (!glxinfo)
+ return;
+
+ while (fgets(buff, 512, glxinfo) != NULL)
{
- while (fgets(buff, 512, fp2) != NULL)
+ if (strncmp(buff, "OpenGL version string:", 22) == 0)
{
- if (strncmp(buff, "OpenGL version string:", 22) == 0)
- {
- QStringList drlines = (QStringList() << QString::fromUtf8(buff));
- logLines(drlines, MessageLevel::MultiMC);
- break;
- }
+ log << QString::fromUtf8(buff);
+ break;
}
}
+ pclose(glxinfo);
+}
+
+}
+#endif
+
+void PrintInstanceInfo::executeTask()
+{
+ auto instance = m_parent->instance();
+ QStringList log;
+
+#ifdef Q_OS_LINUX
+ ::probeProcCpuinfo(log);
+ ::runLspci(log);
+ ::runGlxinfo(log);
#endif
- logLines(lines, MessageLevel::MultiMC);
+ logLines(log, MessageLevel::MultiMC);
+ logLines(instance->verboseDescription(m_session), MessageLevel::MultiMC);
emitSucceeded();
}
diff --git a/api/logic/minecraft/launch/PrintInstanceInfo.h b/api/logic/minecraft/launch/PrintInstanceInfo.h
index 61615ba1..1d081f3e 100644
--- a/api/logic/minecraft/launch/PrintInstanceInfo.h
+++ b/api/logic/minecraft/launch/PrintInstanceInfo.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2018 MultiMC Contributors
+/* Copyright 2013-2019 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,17 +22,17 @@
// FIXME: temporary wrapper for existing task.
class PrintInstanceInfo: public LaunchStep
{
- Q_OBJECT
+ Q_OBJECT
public:
- explicit PrintInstanceInfo(LaunchTask *parent, AuthSessionPtr session) : LaunchStep(parent), m_session(session) {};
- virtual ~PrintInstanceInfo(){};
+ explicit PrintInstanceInfo(LaunchTask *parent, AuthSessionPtr session) : LaunchStep(parent), m_session(session) {};
+ virtual ~PrintInstanceInfo(){};
- virtual void executeTask();
- virtual bool canAbort() const
- {
- return false;
- }
+ virtual void executeTask();
+ virtual bool canAbort() const
+ {
+ return false;
+ }
private:
- AuthSessionPtr m_session;
+ AuthSessionPtr m_session;
};
diff --git a/api/logic/minecraft/launch/ReconstructAssets.cpp b/api/logic/minecraft/launch/ReconstructAssets.cpp
new file mode 100644
index 00000000..af9af127
--- /dev/null
+++ b/api/logic/minecraft/launch/ReconstructAssets.cpp
@@ -0,0 +1,36 @@
+/* Copyright 2013-2019 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 "ReconstructAssets.h"
+#include "minecraft/MinecraftInstance.h"
+#include "minecraft/ComponentList.h"
+#include "minecraft/AssetsUtils.h"
+#include "launch/LaunchTask.h"
+
+void ReconstructAssets::executeTask()
+{
+ auto instance = m_parent->instance();
+ std::shared_ptr<MinecraftInstance> minecraftInstance = std::dynamic_pointer_cast<MinecraftInstance>(instance);
+ auto components = minecraftInstance->getComponentList();
+ auto profile = components->getProfile();
+ auto assets = profile->getMinecraftAssets();
+
+ if(!AssetsUtils::reconstructAssets(assets->id, minecraftInstance->resourcesDir()))
+ {
+ emit logLine("Failed to reconstruct Minecraft assets.", MessageLevel::Error);
+ }
+
+ emitSucceeded();
+}
diff --git a/api/logic/minecraft/launch/ReconstructAssets.h b/api/logic/minecraft/launch/ReconstructAssets.h
new file mode 100644
index 00000000..228fa083
--- /dev/null
+++ b/api/logic/minecraft/launch/ReconstructAssets.h
@@ -0,0 +1,33 @@
+/* Copyright 2013-2019 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>
+
+class ReconstructAssets: public LaunchStep
+{
+ Q_OBJECT
+public:
+ explicit ReconstructAssets(LaunchTask *parent) : LaunchStep(parent){};
+ virtual ~ReconstructAssets(){};
+
+ void executeTask() override;
+ bool canAbort() const override
+ {
+ return false;
+ }
+};
diff --git a/api/logic/minecraft/launch/ScanModFolders.cpp b/api/logic/minecraft/launch/ScanModFolders.cpp
new file mode 100644
index 00000000..485c3dc4
--- /dev/null
+++ b/api/logic/minecraft/launch/ScanModFolders.cpp
@@ -0,0 +1,54 @@
+/* Copyright 2013-2019 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 "ScanModFolders.h"
+#include "launch/LaunchTask.h"
+#include "MMCZip.h"
+#include "minecraft/OpSys.h"
+#include "FileSystem.h"
+#include "minecraft/MinecraftInstance.h"
+#include "minecraft/mod/ModFolderModel.h"
+
+void ScanModFolders::executeTask()
+{
+ auto m_inst = std::dynamic_pointer_cast<MinecraftInstance>(m_parent->instance());
+
+ auto loaders = m_inst->loaderModList();
+ connect(loaders.get(), &ModFolderModel::updateFinished, this, &ScanModFolders::modsDone);
+ loaders->update();
+
+ auto cores = m_inst->coreModList();
+ connect(cores.get(), &ModFolderModel::updateFinished, this, &ScanModFolders::coreModsDone);
+ cores->update();
+}
+
+void ScanModFolders::modsDone()
+{
+ m_modsDone = true;
+ checkDone();
+}
+
+void ScanModFolders::coreModsDone()
+{
+ m_coreModsDone = true;
+ checkDone();
+}
+
+void ScanModFolders::checkDone()
+{
+ if(m_modsDone && m_coreModsDone) {
+ emitSucceeded();
+ }
+}
diff --git a/api/logic/minecraft/launch/ScanModFolders.h b/api/logic/minecraft/launch/ScanModFolders.h
new file mode 100644
index 00000000..360df98d
--- /dev/null
+++ b/api/logic/minecraft/launch/ScanModFolders.h
@@ -0,0 +1,42 @@
+/* Copyright 2013-2019 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>
+
+class ScanModFolders: public LaunchStep
+{
+ Q_OBJECT
+public:
+ explicit ScanModFolders(LaunchTask *parent) : LaunchStep(parent) {};
+ virtual ~ScanModFolders(){};
+
+ virtual void executeTask() override;
+ virtual bool canAbort() const override
+ {
+ return false;
+ }
+private slots:
+ void coreModsDone();
+ void modsDone();
+private:
+ void checkDone();
+
+private: // DATA
+ bool m_modsDone = false;
+ bool m_coreModsDone = false;
+};