summaryrefslogtreecommitdiffstats
path: root/logic
diff options
context:
space:
mode:
authorPetr Mrázek <peterix@gmail.com>2015-01-27 22:31:07 +0100
committerPetr Mrázek <peterix@gmail.com>2015-04-02 00:14:06 +0200
commit791221e923586bb717396ecf18bd13e57034df99 (patch)
tree9f608af07375b38626c8964671620477158341ba /logic
parent593111b14463e9d5d08256061b981b5ab1cfb710 (diff)
downloadMultiMC-791221e923586bb717396ecf18bd13e57034df99.tar
MultiMC-791221e923586bb717396ecf18bd13e57034df99.tar.gz
MultiMC-791221e923586bb717396ecf18bd13e57034df99.tar.lz
MultiMC-791221e923586bb717396ecf18bd13e57034df99.tar.xz
MultiMC-791221e923586bb717396ecf18bd13e57034df99.zip
NOISSUE Refactors and moving of things
Diffstat (limited to 'logic')
-rw-r--r--logic/BaseInstance.cpp24
-rw-r--r--logic/BaseInstance.h40
-rw-r--r--logic/BaseProcess.cpp (renamed from logic/MinecraftProcess.cpp)272
-rw-r--r--logic/BaseProcess.h (renamed from logic/MinecraftProcess.h)110
-rw-r--r--logic/InstanceFactory.cpp43
-rw-r--r--logic/InstanceFactory.h8
-rw-r--r--logic/InstanceList.cpp9
-rw-r--r--logic/InstanceList.h3
-rw-r--r--logic/JarUtils.cpp3
-rw-r--r--logic/LegacyInstance.cpp28
-rw-r--r--logic/LegacyInstance.h31
-rw-r--r--logic/LegacyUpdate.cpp8
-rw-r--r--logic/LegacyUpdate.h2
-rw-r--r--logic/OneSixInstance.cpp240
-rw-r--r--logic/OneSixInstance.h47
-rw-r--r--logic/OneSixUpdate.cpp28
-rw-r--r--logic/OneSixUpdate.h2
-rw-r--r--logic/assets/AssetsMigrateTask.cpp2
-rw-r--r--logic/assets/AssetsUtils.cpp62
-rw-r--r--logic/assets/AssetsUtils.h2
-rw-r--r--logic/forge/ForgeInstaller.cpp21
-rw-r--r--logic/forge/ForgeInstaller.h5
-rw-r--r--logic/forge/ForgeVersion.cpp2
-rw-r--r--logic/ftb/FTBVersion.h32
-rw-r--r--logic/ftb/LegacyFTBInstance.cpp (renamed from logic/LegacyFTBInstance.cpp)0
-rw-r--r--logic/ftb/LegacyFTBInstance.h (renamed from logic/LegacyFTBInstance.h)2
-rw-r--r--logic/ftb/OneSixFTBInstance.cpp (renamed from logic/OneSixFTBInstance.cpp)10
-rw-r--r--logic/ftb/OneSixFTBInstance.h (renamed from logic/OneSixFTBInstance.h)3
-rw-r--r--logic/liteloader/LiteLoaderInstaller.cpp4
-rw-r--r--logic/minecraft/JarMod.cpp34
-rw-r--r--logic/minecraft/JarMod.h4
-rw-r--r--logic/minecraft/MinecraftInstance.cpp58
-rw-r--r--logic/minecraft/MinecraftInstance.h30
-rw-r--r--logic/minecraft/MinecraftProcess.cpp216
-rw-r--r--logic/minecraft/MinecraftProcess.h77
-rw-r--r--logic/minecraft/MinecraftProfile.cpp (renamed from logic/minecraft/InstanceVersion.cpp)282
-rw-r--r--logic/minecraft/MinecraftProfile.h (renamed from logic/minecraft/InstanceVersion.h)113
-rw-r--r--logic/minecraft/MinecraftVersion.cpp18
-rw-r--r--logic/minecraft/MinecraftVersion.h20
-rw-r--r--logic/minecraft/MinecraftVersionList.cpp65
-rw-r--r--logic/minecraft/MinecraftVersionList.h40
-rw-r--r--logic/minecraft/NullProfileStrategy.h24
-rw-r--r--logic/minecraft/OneSixLibrary.cpp4
-rw-r--r--logic/minecraft/OneSixProfileStrategy.cpp270
-rw-r--r--logic/minecraft/OneSixProfileStrategy.h24
-rw-r--r--logic/minecraft/ProfilePatch.h (renamed from logic/minecraft/VersionPatch.h)16
-rw-r--r--logic/minecraft/ProfileStrategy.h30
-rw-r--r--logic/minecraft/ProfileUtils.cpp145
-rw-r--r--logic/minecraft/ProfileUtils.h25
-rw-r--r--logic/minecraft/VersionBuilder.cpp296
-rw-r--r--logic/minecraft/VersionBuilder.h27
-rw-r--r--logic/minecraft/VersionFile.cpp7
-rw-r--r--logic/minecraft/VersionFile.h8
-rw-r--r--logic/minecraft/VersionFilterData.cpp (renamed from logic/VersionFilterData.cpp)2
-rw-r--r--logic/minecraft/VersionFilterData.h (renamed from logic/VersionFilterData.h)0
-rw-r--r--logic/net/PasteUpload.cpp2
-rw-r--r--logic/tools/BaseExternalTool.cpp25
-rw-r--r--logic/tools/BaseExternalTool.h2
-rw-r--r--logic/tools/BaseProfiler.cpp2
-rw-r--r--logic/tools/BaseProfiler.h6
-rw-r--r--logic/tools/JProfiler.cpp4
-rw-r--r--logic/tools/JProfiler.h2
-rw-r--r--logic/tools/JVisualVM.cpp4
-rw-r--r--logic/tools/JVisualVM.h2
-rw-r--r--logic/tools/MCEditTool.cpp33
-rw-r--r--logic/tools/MCEditTool.h1
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/logic/BaseProcess.h
@@ -16,9 +16,7 @@
*/
#pragma once
-
#include <QProcess>
-#include <QString>
#include "BaseInstance.h"
/**
@@ -38,41 +36,18 @@ enum Enum
Fatal, /**< Fatal Errors */
PrePost, /**< Pre/Post Launch command output */
};
+MessageLevel::Enum getLevel(const QString &levelName);
}
-/**
- * @file data/minecraftprocess.h
- * @brief The MinecraftProcess class
- */
-class MinecraftProcess : public QProcess
+class BaseProcess: public QProcess
{
Q_OBJECT
-public:
- /**
- * @brief MinecraftProcess constructor
- * @param inst the Instance pointer to launch
- */
- MinecraftProcess(InstancePtr inst);
-
- virtual ~MinecraftProcess()
- {
-
- };
-
- /**
- * @brief start the launcher part with the provided launch script
- */
- void arm();
-
- /**
- * @brief launch the armed instance!
- */
- void launch();
+protected:
+ explicit BaseProcess(InstancePtr instance);
+ void init();
- /**
- * @brief abort launch!
- */
- void abort();
+public: /* methods */
+ virtual ~BaseProcess() {};
InstancePtr instance()
{
@@ -81,26 +56,36 @@ public:
void setWorkdir(QString path);
- void setLaunchScript(QString script)
- {
- launchScript = script;
- }
+ void killProcess();
- void setNativeFolder(QString natives)
- {
- m_nativeFolder = natives;
- }
+ /**
+ * @brief prepare the process for launch (for multi-stage launch)
+ */
+ virtual void arm() = 0;
- void killMinecraft();
+ /**
+ * @brief launch the armed instance
+ */
+ virtual void launch() = 0;
- inline void setLogin(AuthSessionPtr session)
- {
- m_session = session;
- }
+ /**
+ * @brief abort launch
+ */
+ virtual void abort() = 0;
+
+protected: /* methods */
+ bool preLaunch();
+ bool postLaunch();
+ bool waitForPrePost();
+ QString substituteVariables(const QString &cmd) const;
+
+ virtual QMap<QString, QString> getVariables() const = 0;
+ virtual QString censorPrivateInfo(QString in) = 0;
+ virtual MessageLevel::Enum guessLevel(const QString &message, MessageLevel::Enum defaultLevel) = 0;
signals:
/**
- * @brief emitted when Minecraft immediately fails to run
+ * @brief emitted when the Process immediately fails to run
*/
void launch_failed(InstancePtr);
@@ -115,7 +100,7 @@ signals:
void postlaunch_failed(InstancePtr, int code, QProcess::ExitStatus status);
/**
- * @brief emitted when mc has finished and the PostLaunchCommand was run
+ * @brief emitted when the process has finished and the PostLaunchCommand was run
*/
void ended(InstancePtr, int code, QProcess::ExitStatus status);
@@ -126,26 +111,7 @@ signals:
*/
void log(QString text, MessageLevel::Enum level = MessageLevel::MultiMC);
-protected:
- InstancePtr m_instance;
- QString m_err_leftover;
- QString m_out_leftover;
- QProcess m_prepostlaunchprocess;
- bool killed = false;
- AuthSessionPtr m_session;
- QString launchScript;
- QString m_nativeFolder;
-
- bool preLaunch();
- bool postLaunch();
- bool waitForPrePost();
- QMap<QString, QString> getVariables() const;
- QString substituteVariables(const QString &cmd) const;
-
- QStringList javaArguments() const;
-
-protected
-slots:
+protected slots:
void finish(int, QProcess::ExitStatus status);
void on_stdErr();
void on_stdOut();
@@ -158,8 +124,10 @@ slots:
MessageLevel::Enum defaultLevel = MessageLevel::Message,
bool guessLevel = true, bool censor = true);
-private:
- QString censorPrivateInfo(QString in);
- MessageLevel::Enum guessLevel(const QString &message, MessageLevel::Enum defaultLevel);
- MessageLevel::Enum getLevel(const QString &levelName);
+protected:
+ InstancePtr m_instance;
+ QString m_err_leftover;
+ QString m_out_leftover;
+ QProcess m_prepostlaunchprocess;
+ bool killed = false;
};
diff --git a/logic/InstanceFactory.cpp b/logic/InstanceFactory.cpp
index 0462aec0..857d3a09 100644
--- a/logic/InstanceFactory.cpp
+++ b/logic/InstanceFactory.cpp
@@ -27,12 +27,13 @@
#include "logic/BaseInstance.h"
#include "logic/LegacyInstance.h"
-#include "logic/LegacyFTBInstance.h"
#include "logic/OneSixInstance.h"
-#include "logic/OneSixFTBInstance.h"
#include "logic/OneSixInstance.h"
#include "logic/BaseVersion.h"
#include "logic/minecraft/MinecraftVersion.h"
+#include "logic/ftb/LegacyFTBInstance.h"
+#include "logic/ftb/OneSixFTBInstance.h"
+#include "logic/ftb/FTBVersion.h"
InstanceFactory InstanceFactory::loader;
@@ -74,8 +75,8 @@ InstanceFactory::InstLoadError InstanceFactory::loadInstance(InstancePtr &inst,
return NoLoadError;
}
-InstanceFactory::InstCreateError InstanceFactory::createInstance(InstancePtr &inst, BaseVersionPtr version,
- const QString &instDir, const InstanceFactory::InstType type)
+InstanceFactory::InstCreateError
+InstanceFactory::createInstance(InstancePtr &inst, BaseVersionPtr version, const QString &instDir)
{
QDir rootDir(instDir);
@@ -85,8 +86,8 @@ InstanceFactory::InstCreateError InstanceFactory::createInstance(InstancePtr &in
QLOG_ERROR() << "Can't create instance folder" << instDir;
return InstanceFactory::CantCreateDir;
}
- auto mcVer = std::dynamic_pointer_cast<MinecraftVersion>(version);
- if (!mcVer)
+
+ if (!version)
{
QLOG_ERROR() << "Can't create instance for non-existing MC version";
return InstanceFactory::NoSuchVersion;
@@ -95,37 +96,37 @@ InstanceFactory::InstCreateError InstanceFactory::createInstance(InstancePtr &in
auto m_settings = new INISettingsObject(PathCombine(instDir, "instance.cfg"));
m_settings->registerSetting("InstanceType", "Legacy");
- if (type == NormalInst)
+ auto minecraftVersion = std::dynamic_pointer_cast<MinecraftVersion>(version);
+ if(minecraftVersion)
{
+ auto mcVer = std::dynamic_pointer_cast<MinecraftVersion>(version);
m_settings->set("InstanceType", "OneSix");
inst.reset(new OneSixInstance(instDir, m_settings));
inst->setIntendedVersionId(version->descriptor());
+ inst->init();
+ return InstanceFactory::NoCreateError;
}
- else if (type == FTBInstance)
+ auto ftbVersion = std::dynamic_pointer_cast<FTBVersion>(version);
+ if(ftbVersion)
{
- if(mcVer->usesLegacyLauncher())
+ auto mcversion = ftbVersion->getMinecraftVersion();
+ if (mcversion->usesLegacyLauncher())
{
m_settings->set("InstanceType", "LegacyFTB");
inst.reset(new LegacyFTBInstance(instDir, m_settings));
- inst->setIntendedVersionId(version->descriptor());
+ inst->setIntendedVersionId(mcversion->descriptor());
}
else
{
m_settings->set("InstanceType", "OneSixFTB");
inst.reset(new OneSixFTBInstance(instDir, m_settings));
- inst->setIntendedVersionId(version->descriptor());
+ inst->setIntendedVersionId(mcversion->descriptor());
+ inst->init();
}
+ return InstanceFactory::NoCreateError;
}
- else
- {
- delete m_settings;
- return InstanceFactory::NoSuchVersion;
- }
-
- inst->init();
-
- // FIXME: really, how do you even know?
- return InstanceFactory::NoCreateError;
+ delete m_settings;
+ return InstanceFactory::NoSuchVersion;
}
InstanceFactory::InstCreateError InstanceFactory::copyInstance(InstancePtr &newInstance,
diff --git a/logic/InstanceFactory.h b/logic/InstanceFactory.h
index 5ddb1d81..17ef8f38 100644
--- a/logic/InstanceFactory.h
+++ b/logic/InstanceFactory.h
@@ -56,12 +56,6 @@ public:
CantCreateDir
};
- enum InstType
- {
- NormalInst,
- FTBInstance
- };
-
/*!
* \brief Creates a stub instance
*
@@ -74,7 +68,7 @@ public:
* - CantCreateDir if the given instance directory cannot be created.
*/
InstCreateError createInstance(InstancePtr &inst, BaseVersionPtr version,
- const QString &instDir, const InstType type = NormalInst);
+ const QString &instDir);
/*!
* \brief Creates a copy of an existing instance with a new name
diff --git a/logic/InstanceList.cpp b/logic/InstanceList.cpp
index 29908e01..ec7dbdbf 100644
--- a/logic/InstanceList.cpp
+++ b/logic/InstanceList.cpp
@@ -32,6 +32,7 @@
#include "logic/minecraft/MinecraftVersionList.h"
#include "logic/BaseInstance.h"
#include "logic/InstanceFactory.h"
+#include "ftb/FTBVersion.h"
#include "logger/QsLog.h"
#include "gui/groupview/GroupView.h"
@@ -403,16 +404,16 @@ void InstanceList::loadFTBInstances(QMap<QString, QString> &groupMap,
QLOG_INFO() << "Converting " << record.name << " as new.";
InstancePtr instPtr;
auto &factory = InstanceFactory::get();
- auto version = MMC->minecraftlist()->findVersion(record.mcVersion);
- if (!version)
+ auto mcVersion = std::dynamic_pointer_cast<MinecraftVersion>(MMC->minecraftlist()->findVersion(record.mcVersion));
+ if (!mcVersion)
{
QLOG_ERROR() << "Can't load instance " << record.instanceDir
<< " because minecraft version " << record.mcVersion
<< " can't be resolved.";
continue;
}
- auto error = factory.createInstance(instPtr, version, record.instanceDir,
- InstanceFactory::FTBInstance);
+ auto ftbVersion = std::make_shared<FTBVersion>(mcVersion);
+ auto error = factory.createInstance(instPtr, ftbVersion, record.instanceDir);
if (!instPtr || error != InstanceFactory::NoCreateError)
continue;
diff --git a/logic/InstanceList.h b/logic/InstanceList.h
index 4cb8ab6f..c251be5a 100644
--- a/logic/InstanceList.h
+++ b/logic/InstanceList.h
@@ -19,7 +19,6 @@
#include <QAbstractListModel>
#include <QSet>
#include <gui/groupview/GroupedProxyModel.h>
-#include <QIcon>
#include "logic/BaseInstance.h"
@@ -55,7 +54,7 @@ private:
QSet<FTBRecord> discoverFTBInstances();
void loadFTBInstances(QMap<QString, QString> &groupMap, QList<InstancePtr> & tempList);
-private
+public
slots:
void saveGroupList();
diff --git a/logic/JarUtils.cpp b/logic/JarUtils.cpp
index 3b4f780a..d4f1ed56 100644
--- a/logic/JarUtils.cpp
+++ b/logic/JarUtils.cpp
@@ -30,7 +30,6 @@ bool mergeZipFiles(QuaZip *into, QFileInfo from, QSet<QString> &contained,
continue;
}
contained.insert(filename);
- QLOG_INFO() << "Adding file " << filename << " from " << from.fileName();
if (!fileInsideMod.open(QIODevice::ReadOnly))
{
@@ -103,8 +102,6 @@ bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<M
return false;
}
addedFiles.insert(filename.fileName());
- QLOG_INFO() << "Adding file " << filename.fileName() << " from "
- << filename.absoluteFilePath();
}
else if (mod.type() == Mod::MOD_FOLDER)
{
diff --git a/logic/LegacyInstance.cpp b/logic/LegacyInstance.cpp
index 38010f77..3d2a83b2 100644
--- a/logic/LegacyInstance.cpp
+++ b/logic/LegacyInstance.cpp
@@ -24,9 +24,9 @@
#include "LegacyInstance.h"
-#include "logic/MinecraftProcess.h"
#include "logic/LegacyUpdate.h"
#include "logic/icons/IconList.h"
+#include "logic/minecraft/MinecraftProcess.h"
#include "gui/pages/LegacyUpgradePage.h"
#include "gui/pages/ModFolderPage.h"
#include "gui/pages/LegacyJarModPage.h"
@@ -36,7 +36,7 @@
#include <gui/pages/ScreenshotsPage.h>
LegacyInstance::LegacyInstance(const QString &rootDir, SettingsObject *settings, QObject *parent)
- : BaseInstance(rootDir, settings, parent)
+ : MinecraftInstance(rootDir, settings, parent)
{
settings->registerSetting("NeedsRebuild", true);
settings->registerSetting("ShouldUpdate", false);
@@ -66,7 +66,7 @@ QList<BasePage *> LegacyInstance::getPages()
"Loader-mods"));
values.append(new TexturePackPage(this));
values.append(new NotesPage(this));
- values.append(new ScreenshotsPage(this));
+ values.append(new ScreenshotsPage(PathCombine(minecraftRoot(), "screenshots")));
values.append(new InstanceSettingsPage(this));
return values;
}
@@ -124,8 +124,9 @@ std::shared_ptr<Task> LegacyInstance::doUpdate()
return std::shared_ptr<Task>(new LegacyUpdate(this, this));
}
-bool LegacyInstance::prepareForLaunch(AuthSessionPtr account, QString &launchScript)
+BaseProcess *LegacyInstance::prepareForLaunch(AuthSessionPtr account)
{
+ QString launchScript;
QIcon icon = MMC->icons()->getIcon(iconKey());
auto pixmap = icon.pixmap(128, 128);
pixmap.save(PathCombine(minecraftRoot(), "icon.png"), "PNG");
@@ -150,7 +151,11 @@ bool LegacyInstance::prepareForLaunch(AuthSessionPtr account, QString &launchScr
launchScript += "lwjgl " + lwjgl + "\n";
launchScript += "launcher legacy\n";
}
- return true;
+ auto process = MinecraftProcess::create(std::dynamic_pointer_cast<MinecraftInstance>(getSharedPtr()));
+ process->setLaunchScript(launchScript);
+ process->setWorkdir(minecraftRoot());
+ process->setLogin(account);
+ return process;
}
void LegacyInstance::cleanupAfterRun()
@@ -158,7 +163,7 @@ void LegacyInstance::cleanupAfterRun()
// FIXME: delete the launcher and icons and whatnot.
}
-std::shared_ptr<ModList> LegacyInstance::coreModList()
+std::shared_ptr<ModList> LegacyInstance::coreModList() const
{
if (!core_mod_list)
{
@@ -168,7 +173,7 @@ std::shared_ptr<ModList> LegacyInstance::coreModList()
return core_mod_list;
}
-std::shared_ptr<ModList> LegacyInstance::jarModList()
+std::shared_ptr<ModList> LegacyInstance::jarModList() const
{
if (!jar_mod_list)
{
@@ -180,13 +185,18 @@ std::shared_ptr<ModList> LegacyInstance::jarModList()
return jar_mod_list;
}
+QList<Mod> LegacyInstance::getJarMods() const
+{
+ return jarModList()->allMods();
+}
+
void LegacyInstance::jarModsChanged()
{
QLOG_INFO() << "Jar mods of instance " << name() << " have changed. Jar will be rebuilt.";
setShouldRebuild(true);
}
-std::shared_ptr<ModList> LegacyInstance::loaderModList()
+std::shared_ptr<ModList> LegacyInstance::loaderModList() const
{
if (!loader_mod_list)
{
@@ -196,7 +206,7 @@ std::shared_ptr<ModList> LegacyInstance::loaderModList()
return loader_mod_list;
}
-std::shared_ptr<ModList> LegacyInstance::texturePackList()
+std::shared_ptr<ModList> LegacyInstance::texturePackList() const
{
if (!texture_pack_list)
{
diff --git a/logic/LegacyInstance.h b/logic/LegacyInstance.h
index 0ced2b77..de7b2bd2 100644
--- a/logic/LegacyInstance.h
+++ b/logic/LegacyInstance.h
@@ -15,13 +15,13 @@
#pragma once
-#include "BaseInstance.h"
+#include "logic/minecraft/MinecraftInstance.h"
#include "gui/pages/BasePageProvider.h"
class ModList;
class Task;
-class LegacyInstance : public BaseInstance, public BasePageProvider
+class LegacyInstance : public MinecraftInstance, public BasePageProvider
{
Q_OBJECT
public:
@@ -29,6 +29,8 @@ public:
explicit LegacyInstance(const QString &rootDir, SettingsObject *settings,
QObject *parent = 0);
+ virtual void init() {};
+
/// Path to the instance's minecraft.jar
QString runnableJar() const;
@@ -40,10 +42,11 @@ public:
virtual QString dialogTitle();
////// Mod Lists //////
- std::shared_ptr<ModList> jarModList();
- std::shared_ptr<ModList> coreModList();
- std::shared_ptr<ModList> loaderModList();
- std::shared_ptr<ModList> texturePackList();
+ std::shared_ptr<ModList> jarModList() const ;
+ virtual QList< Mod > getJarMods() const override;
+ std::shared_ptr<ModList> coreModList() const;
+ std::shared_ptr<ModList> loaderModList() const;
+ std::shared_ptr<ModList> texturePackList() const override;
////// Directories //////
QString libDir() const;
@@ -94,12 +97,6 @@ public:
virtual QString intendedVersionId() const override;
virtual bool setIntendedVersionId(QString version) override;
- // the `version' of Legacy instances is defined by the launcher code.
- // in contrast with OneSix, where `version' is described in a json file
- virtual bool versionIsCustom() override
- {
- return false;
- }
virtual QSet<QString> traits()
{
@@ -110,16 +107,16 @@ public:
virtual void setShouldUpdate(bool val) override;
virtual std::shared_ptr<Task> doUpdate() override;
- virtual bool prepareForLaunch(AuthSessionPtr account, QString & launchScript) override;
+ virtual BaseProcess *prepareForLaunch(AuthSessionPtr account) override;
virtual void cleanupAfterRun() override;
virtual QString getStatusbarDescription() override;
protected:
- std::shared_ptr<ModList> jar_mod_list;
- std::shared_ptr<ModList> core_mod_list;
- std::shared_ptr<ModList> loader_mod_list;
- std::shared_ptr<ModList> texture_pack_list;
+ mutable std::shared_ptr<ModList> jar_mod_list;
+ mutable std::shared_ptr<ModList> core_mod_list;
+ mutable std::shared_ptr<ModList> loader_mod_list;
+ mutable std::shared_ptr<ModList> texture_pack_list;
protected
slots:
diff --git a/logic/LegacyUpdate.cpp b/logic/LegacyUpdate.cpp
index a6dae1b4..30f781ab 100644
--- a/logic/LegacyUpdate.cpp
+++ b/logic/LegacyUpdate.cpp
@@ -409,7 +409,7 @@ void LegacyUpdate::ModTheJar()
}
// Get the mod list
- auto modList = inst->jarModList();
+ auto modList = inst->getJarMods();
QFileInfo runnableJar(inst->runnableJar());
QFileInfo baseJar(inst->baseJar());
@@ -421,7 +421,7 @@ void LegacyUpdate::ModTheJar()
// yes, this can happen if the instance only has the runnable jar and not the base jar
// it *could* be assumed that such an instance is vanilla, but that wouldn't be safe
// because that's not something mmc4 guarantees
- if (runnableJar.isFile() && !baseJar.exists() && modList->empty())
+ if (runnableJar.isFile() && !baseJar.exists() && modList.empty())
{
inst->setShouldRebuild(false);
emitSucceeded();
@@ -452,14 +452,12 @@ void LegacyUpdate::ModTheJar()
return;
}
- // TaskStep(); // STEP 1
setStatus(tr("Installing mods: Opening minecraft.jar ..."));
- const auto & mods = modList->allMods();
QString outputJarPath = runnableJar.filePath();
QString inputJarPath = baseJar.filePath();
- if(!JarUtils::createModdedJar(inputJarPath, outputJarPath, mods))
+ if(!JarUtils::createModdedJar(inputJarPath, outputJarPath, modList))
{
emitFailed(tr("Failed to create the custom Minecraft jar file."));
return;
diff --git a/logic/LegacyUpdate.h b/logic/LegacyUpdate.h
index f840e76c..78e456a1 100644
--- a/logic/LegacyUpdate.h
+++ b/logic/LegacyUpdate.h
@@ -21,7 +21,7 @@
#include "logic/net/NetJob.h"
#include "logic/tasks/Task.h"
-#include "logic/VersionFilterData.h"
+#include "logic/minecraft/VersionFilterData.h"
class MinecraftVersion;
class BaseInstance;
diff --git a/logic/OneSixInstance.cpp b/logic/OneSixInstance.cpp
index 58b1359b..15dd0585 100644
--- a/logic/OneSixInstance.cpp
+++ b/logic/OneSixInstance.cpp
@@ -22,12 +22,13 @@
#include "logic/OneSixInstance.h"
#include "logic/OneSixUpdate.h"
-#include "logic/minecraft/InstanceVersion.h"
+#include "logic/minecraft/MinecraftProfile.h"
#include "minecraft/VersionBuildError.h"
+#include "logic/minecraft/MinecraftProcess.h"
+#include "minecraft/OneSixProfileStrategy.h"
#include "logic/assets/AssetsUtils.h"
-#include "icons/IconList.h"
-#include "logic/MinecraftProcess.h"
+#include "logic/icons/IconList.h"
#include "gui/pagedialog/PageDialog.h"
#include "gui/pages/VersionPage.h"
#include "gui/pages/ModFolderPage.h"
@@ -39,24 +40,22 @@
#include "gui/pages/OtherLogsPage.h"
OneSixInstance::OneSixInstance(const QString &rootDir, SettingsObject *settings, QObject *parent)
- : BaseInstance(rootDir, settings, parent)
+ : MinecraftInstance(rootDir, settings, parent)
{
m_settings->registerSetting("IntendedVersion", "");
- version.reset(new InstanceVersion(this, this));
}
void OneSixInstance::init()
{
- try
- {
- reloadVersion();
- }
- catch (MMCError &e)
- {
- QLOG_ERROR() << "Caught exception on instance init: " << e.cause();
- }
+ createProfile();
+}
+
+void OneSixInstance::createProfile()
+{
+ m_version.reset(new MinecraftProfile(new OneSixProfileStrategy(this)));
}
+
QList<BasePage *> OneSixInstance::getPages()
{
QList<BasePage *> values;
@@ -68,9 +67,9 @@ QList<BasePage *> OneSixInstance::getPages()
values.append(new ResourcePackPage(this));
values.append(new TexturePackPage(this));
values.append(new NotesPage(this));
- values.append(new ScreenshotsPage(this));
+ values.append(new ScreenshotsPage(PathCombine(minecraftRoot(), "screenshots")));
values.append(new InstanceSettingsPage(this));
- values.append(new OtherLogsPage(this));
+ values.append(new OtherLogsPage(minecraftRoot()));
return values;
}
@@ -81,7 +80,7 @@ QString OneSixInstance::dialogTitle()
QSet<QString> OneSixInstance::traits()
{
- auto version = getFullVersion();
+ auto version = getMinecraftProfile();
if (!version)
{
return {"version-incomplete"};
@@ -119,70 +118,10 @@ QString replaceTokensIn(QString text, QMap<QString, QString> with)
return result;
}
-QDir OneSixInstance::reconstructAssets(std::shared_ptr<InstanceVersion> version)
-{
- QDir assetsDir = QDir("assets/");
- QDir indexDir = QDir(PathCombine(assetsDir.path(), "indexes"));
- QDir objectDir = QDir(PathCombine(assetsDir.path(), "objects"));
- QDir virtualDir = QDir(PathCombine(assetsDir.path(), "virtual"));
-
- QString indexPath = PathCombine(indexDir.path(), version->assets + ".json");
- QFile indexFile(indexPath);
- QDir virtualRoot(PathCombine(virtualDir.path(), version->assets));
-
- if (!indexFile.exists())
- {
- QLOG_ERROR() << "No assets index file" << indexPath << "; can't reconstruct assets";
- return virtualRoot;
- }
-
- QLOG_DEBUG() << "reconstructAssets" << assetsDir.path() << indexDir.path()
- << objectDir.path() << virtualDir.path() << virtualRoot.path();
-
- AssetsIndex index;
- bool loadAssetsIndex = AssetsUtils::loadAssetsIndexJson(indexPath, &index);
-
- if (loadAssetsIndex && index.isVirtual)
- {
- QLOG_INFO() << "Reconstructing virtual assets folder at" << virtualRoot.path();
-
- for (QString map : index.objects.keys())
- {
- AssetObject asset_object = index.objects.value(map);
- QString target_path = PathCombine(virtualRoot.path(), map);
- QFile target(target_path);
-
- QString tlk = asset_object.hash.left(2);
-
- QString original_path =
- PathCombine(PathCombine(objectDir.path(), tlk), asset_object.hash);
- QFile original(original_path);
- if (!original.exists())
- continue;
- if (!target.exists())
- {
- QFileInfo info(target_path);
- QDir target_dir = info.dir();
- // QLOG_DEBUG() << target_dir;
- if (!target_dir.exists())
- QDir("").mkpath(target_dir.path());
-
- bool couldCopy = original.copy(target_path);
- QLOG_DEBUG() << " Copying" << original_path << "to" << target_path
- << QString::number(couldCopy); // << original.errorString();
- }
- }
-
- // TODO: Write last used time to virtualRoot/.lastused
- }
-
- return virtualRoot;
-}
-
QStringList OneSixInstance::processMinecraftArgs(AuthSessionPtr session)
{
- QString args_pattern = version->minecraftArguments;
- for (auto tweaker : version->tweakers)
+ QString args_pattern = m_version->minecraftArguments;
+ for (auto tweaker : m_version->tweakers)
{
args_pattern += " --tweakClass " + tweaker;
}
@@ -197,18 +136,18 @@ QStringList OneSixInstance::processMinecraftArgs(AuthSessionPtr session)
// these do nothing and are stupid.
token_mapping["profile_name"] = name();
- token_mapping["version_name"] = version->id;
+ token_mapping["version_name"] = m_version->id;
QString absRootDir = QDir(minecraftRoot()).absolutePath();
token_mapping["game_directory"] = absRootDir;
QString absAssetsDir = QDir("assets/").absolutePath();
- token_mapping["game_assets"] = reconstructAssets(version).absolutePath();
+ token_mapping["game_assets"] = AssetsUtils::reconstructAssets(m_version->assets).absolutePath();
token_mapping["user_properties"] = session->serializeUserProperties();
token_mapping["user_type"] = session->user_type;
// 1.7.3+ assets tokens
token_mapping["assets_root"] = absAssetsDir;
- token_mapping["assets_index_name"] = version->assets;
+ token_mapping["assets_index_name"] = m_version->assets;
QStringList parts = args_pattern.split(' ', QString::SkipEmptyParts);
for (int i = 0; i < parts.length(); i++)
@@ -218,40 +157,41 @@ QStringList OneSixInstance::processMinecraftArgs(AuthSessionPtr session)
return parts;
}
-bool OneSixInstance::prepareForLaunch(AuthSessionPtr session, QString &launchScript)
+BaseProcess *OneSixInstance::prepareForLaunch(AuthSessionPtr session)
{
-
+ QString launchScript;
QIcon icon = MMC->icons()->getIcon(iconKey());
auto pixmap = icon.pixmap(128, 128);
pixmap.save(PathCombine(minecraftRoot(), "icon.png"), "PNG");
- if (!version)
+ if (!m_version)
return nullptr;
// libraries and class path.
{
- auto libs = version->getActiveNormalLibs();
+ auto libs = m_version->getActiveNormalLibs();
for (auto lib : libs)
{
launchScript += "cp " + librariesPath().absoluteFilePath(lib->storagePath()) + "\n";
}
- if (version->hasJarMods())
+ auto jarMods = getJarMods();
+ if (!jarMods.isEmpty())
{
launchScript += "cp " + QDir(instanceRoot()).absoluteFilePath("temp.jar") + "\n";
}
else
{
- QString relpath = version->id + "/" + version->id + ".jar";
+ QString relpath = m_version->id + "/" + m_version->id + ".jar";
launchScript += "cp " + versionsPath().absoluteFilePath(relpath) + "\n";
}
}
- if (!version->mainClass.isEmpty())
+ if (!m_version->mainClass.isEmpty())
{
- launchScript += "mainClass " + version->mainClass + "\n";
+ launchScript += "mainClass " + m_version->mainClass + "\n";
}
- if (!version->appletClass.isEmpty())
+ if (!m_version->appletClass.isEmpty())
{
- launchScript += "appletClass " + version->appletClass + "\n";
+ launchScript += "appletClass " + m_version->appletClass + "\n";
}
// generic minecraft params
@@ -282,7 +222,7 @@ bool OneSixInstance::prepareForLaunch(AuthSessionPtr session, QString &launchScr
// native libraries (mostly LWJGL)
{
QDir natives_dir(PathCombine(instanceRoot(), "natives/"));
- for (auto native : version->getActiveNativeLibs())
+ for (auto native : m_version->getActiveNativeLibs())
{
QFileInfo finfo(PathCombine("libraries", native->storagePath()));
launchScript += "ext " + finfo.absoluteFilePath() + "\n";
@@ -291,12 +231,17 @@ bool OneSixInstance::prepareForLaunch(AuthSessionPtr session, QString &launchScr
}
// traits. including legacyLaunch and others ;)
- for (auto trait : version->traits)
+ for (auto trait : m_version->traits)
{
launchScript += "traits " + trait + "\n";
}
launchScript += "launcher onesix\n";
- return true;
+
+ auto process = MinecraftProcess::create(std::dynamic_pointer_cast<MinecraftInstance>(getSharedPtr()));
+ process->setLaunchScript(launchScript);
+ process->setWorkdir(minecraftRoot());
+ process->setLogin(session);
+ return process;
}
void OneSixInstance::cleanupAfterRun()
@@ -306,54 +251,68 @@ void OneSixInstance::cleanupAfterRun()
dir.removeRecursively();
}
-std::shared_ptr<ModList> OneSixInstance::loaderModList()
+std::shared_ptr<ModList> OneSixInstance::loaderModList() const
{
- if (!loader_mod_list)
+ if (!m_loader_mod_list)
{
- loader_mod_list.reset(new ModList(loaderModsDir()));
+ m_loader_mod_list.reset(new ModList(loaderModsDir()));
}
- loader_mod_list->update();
- return loader_mod_list;
+ m_loader_mod_list->update();
+ return m_loader_mod_list;
}
-std::shared_ptr<ModList> OneSixInstance::coreModList()
+std::shared_ptr<ModList> OneSixInstance::coreModList() const
{
- if (!core_mod_list)
+ if (!m_core_mod_list)
{
- core_mod_list.reset(new ModList(coreModsDir()));
+ m_core_mod_list.reset(new ModList(coreModsDir()));
}
- core_mod_list->update();
- return core_mod_list;
+ m_core_mod_list->update();
+ return m_core_mod_list;
}
-std::shared_ptr<ModList> OneSixInstance::resourcePackList()
+std::shared_ptr<ModList> OneSixInstance::resourcePackList() const
{
- if (!resource_pack_list)
+ if (!m_resource_pack_list)
{
- resource_pack_list.reset(new ModList(resourcePacksDir()));
+ m_resource_pack_list.reset(new ModList(resourcePacksDir()));
}
- resource_pack_list->update();
- return resource_pack_list;
+ m_resource_pack_list->update();
+ return m_resource_pack_list;
}
-std::shared_ptr<ModList> OneSixInstance::texturePackList()
+std::shared_ptr<ModList> OneSixInstance::texturePackList() const
{
- if (!texture_pack_list)
+ if (!m_texture_pack_list)
{
- texture_pack_list.reset(new ModList(texturePacksDir()));
+ m_texture_pack_list.reset(new ModList(texturePacksDir()));
}
- texture_pack_list->update();
- return texture_pack_list;
+ m_texture_pack_list->update();
+ return m_texture_pack_list;
}
bool OneSixInstance::setIntendedVersionId(QString version)
{
settings().set("IntendedVersion", version);
- QFile::remove(PathCombine(instanceRoot(), "version.json"));
- clearVersion();
+ if(getMinecraftProfile())
+ {
+ clearProfile();
+ }
return true;
}
+QList< Mod > OneSixInstance::getJarMods() const
+{
+ QList<Mod> mods;
+ for (auto jarmod : m_version->jarMods)
+ {
+ QString filePath = jarmodsPath().absoluteFilePath(jarmod->name);
+ mods.push_back(Mod(QFileInfo(filePath)));
+ }
+ return mods;
+}
+
+
QString OneSixInstance::intendedVersionId() const
{
return settings().get("IntendedVersion").toString();
@@ -368,35 +327,16 @@ bool OneSixInstance::shouldUpdate() const
return true;
}
-bool OneSixInstance::versionIsCustom()
-{
- if (version)
- {
- return !version->isVanilla();
- }
- return false;
-}
-
-bool OneSixInstance::versionIsFTBPack()
-{
- if (version)
- {
- return version->hasFtbPack();
- }
- return false;
-}
-
QString OneSixInstance::currentVersionId() const
{
return intendedVersionId();
}
-void OneSixInstance::reloadVersion()
+void OneSixInstance::reloadProfile()
{
-
try
{
- version->reload(externalPatches());
+ m_version->reload();
unsetFlag(VersionBrokenFlag);
emit versionReloaded();
}
@@ -405,7 +345,7 @@ void OneSixInstance::reloadVersion()
}
catch (MMCError &error)
{
- version->clear();
+ m_version->clear();
setFlag(VersionBrokenFlag);
// TODO: rethrow to show some error message(s)?
emit versionReloaded();
@@ -413,24 +353,20 @@ void OneSixInstance::reloadVersion()
}
}
-void OneSixInstance::clearVersion()
+void OneSixInstance::clearProfile()
{
- version->clear();
+ m_version->clear();
emit versionReloaded();
}
-std::shared_ptr<InstanceVersion> OneSixInstance::getFullVersion() const
+std::shared_ptr<MinecraftProfile> OneSixInstance::getMinecraftProfile() const
{
- return version;
+ return m_version;
}
QString OneSixInstance::getStatusbarDescription()
{
QStringList traits;
- if (versionIsCustom())
- {
- traits.append(tr("custom"));
- }
if (flags() & VersionBrokenFlag)
{
traits.append(tr("broken"));
@@ -461,11 +397,6 @@ QDir OneSixInstance::versionsPath() const
return QDir::current().absoluteFilePath("versions");
}
-QStringList OneSixInstance::externalPatches() const
-{
- return QStringList();
-}
-
bool OneSixInstance::providesVersionFile() const
{
return false;
@@ -477,7 +408,7 @@ bool OneSixInstance::reload()
{
try
{
- reloadVersion();
+ reloadProfile();
return true;
}
catch (...)
@@ -526,10 +457,11 @@ QString OneSixInstance::libDir() const
QStringList OneSixInstance::extraArguments() const
{
auto list = BaseInstance::extraArguments();
- auto version = getFullVersion();
+ auto version = getMinecraftProfile();
if (!version)
return list;
- if (version->hasJarMods())
+ auto jarMods = getJarMods();
+ if (!jarMods.isEmpty())
{
list.append({"-Dfml.ignoreInvalidMinecraftCertificates=true",
"-Dfml.ignorePatchDiscrepancies=true"});
diff --git a/logic/OneSixInstance.h b/logic/OneSixInstance.h
index ddb296ac..d6593d1b 100644
--- a/logic/OneSixInstance.h
+++ b/logic/OneSixInstance.h
@@ -15,13 +15,13 @@
#pragma once
-#include "BaseInstance.h"
+#include "logic/minecraft/MinecraftInstance.h"
-#include "logic/minecraft/InstanceVersion.h"
+#include "logic/minecraft/MinecraftProfile.h"
#include "logic/ModList.h"
#include "gui/pages/BasePageProvider.h"
-class OneSixInstance : public BaseInstance, public BasePageProvider
+class OneSixInstance : public MinecraftInstance, public BasePageProvider
{
Q_OBJECT
public:
@@ -29,17 +29,19 @@ public:
QObject *parent = 0);
virtual ~OneSixInstance(){};
- virtual void init() override;
+ virtual void init();
////// Edit Instance Dialog stuff //////
virtual QList<BasePage *> getPages();
virtual QString dialogTitle();
////// Mod Lists //////
- std::shared_ptr<ModList> loaderModList();
- std::shared_ptr<ModList> coreModList();
- std::shared_ptr<ModList> resourcePackList() override;
- std::shared_ptr<ModList> texturePackList() override;
+ std::shared_ptr<ModList> loaderModList() const;
+ std::shared_ptr<ModList> coreModList() const;
+ std::shared_ptr<ModList> resourcePackList() const override;
+ std::shared_ptr<ModList> texturePackList() const override;
+ virtual QList<Mod> getJarMods() const override;
+ virtual void createProfile();
virtual QSet<QString> traits();
@@ -53,7 +55,7 @@ public:
virtual QString instanceConfigFolder() const override;
virtual std::shared_ptr<Task> doUpdate() override;
- virtual bool prepareForLaunch(AuthSessionPtr account, QString & launchScript) override;
+ virtual BaseProcess *prepareForLaunch(AuthSessionPtr account) override;
virtual void cleanupAfterRun() override;
@@ -66,30 +68,23 @@ public:
virtual void setShouldUpdate(bool val) override;
/**
- * reload the full version json files.
+ * reload the profile, including version json files.
*
* throws various exceptions :3
*/
- void reloadVersion();
+ void reloadProfile();
/// clears all version information in preparation for an update
- void clearVersion();
+ void clearProfile();
/// get the current full version info
- std::shared_ptr<InstanceVersion> getFullVersion() const;
-
- /// is the current version original, or custom?
- virtual bool versionIsCustom() override;
-
- /// does this instance have an FTB pack patch inside?
- bool versionIsFTBPack();
+ std::shared_ptr<MinecraftProfile> getMinecraftProfile() const;
virtual QString getStatusbarDescription() override;
virtual QDir jarmodsPath() const;
virtual QDir librariesPath() const;
virtual QDir versionsPath() const;
- virtual QStringList externalPatches() const;
virtual bool providesVersionFile() const;
bool reload() override;
@@ -103,15 +98,13 @@ signals:
private:
QStringList processMinecraftArgs(AuthSessionPtr account);
- QDir reconstructAssets(std::shared_ptr<InstanceVersion> version);
protected:
- std::shared_ptr<InstanceVersion> version;
- std::shared_ptr<ModList> jar_mod_list;
- std::shared_ptr<ModList> loader_mod_list;
- std::shared_ptr<ModList> core_mod_list;
- std::shared_ptr<ModList> resource_pack_list;
- std::shared_ptr<ModList> texture_pack_list;
+ std::shared_ptr<MinecraftProfile> m_version;
+ mutable std::shared_ptr<ModList> m_loader_mod_list;
+ mutable std::shared_ptr<ModList> m_core_mod_list;
+ mutable std::shared_ptr<ModList> m_resource_pack_list;
+ mutable std::shared_ptr<ModList> m_texture_pack_list;
};
Q_DECLARE_METATYPE(std::shared_ptr<OneSixInstance>)
diff --git a/logic/OneSixUpdate.cpp b/logic/OneSixUpdate.cpp
index 5663484a..692e4ce3 100644
--- a/logic/OneSixUpdate.cpp
+++ b/logic/OneSixUpdate.cpp
@@ -27,7 +27,7 @@
#include "logic/BaseInstance.h"
#include "logic/minecraft/MinecraftVersionList.h"
-#include "logic/minecraft/InstanceVersion.h"
+#include "logic/minecraft/MinecraftProfile.h"
#include "logic/minecraft/OneSixLibrary.h"
#include "logic/OneSixInstance.h"
#include "logic/forge/ForgeMirrors.h"
@@ -88,7 +88,7 @@ void OneSixUpdate::assetIndexStart()
{
setStatus(tr("Updating assets index..."));
OneSixInstance *inst = (OneSixInstance *)m_inst;
- std::shared_ptr<InstanceVersion> version = inst->getFullVersion();
+ std::shared_ptr<MinecraftProfile> version = inst->getMinecraftProfile();
QString assetName = version->assets;
QUrl indexUrl = "http://" + URLConstants::AWS_DOWNLOAD_INDEXES + assetName + ".json";
QString localPath = assetName + ".json";
@@ -112,7 +112,7 @@ void OneSixUpdate::assetIndexFinished()
AssetsIndex index;
OneSixInstance *inst = (OneSixInstance *)m_inst;
- std::shared_ptr<InstanceVersion> version = inst->getFullVersion();
+ std::shared_ptr<MinecraftProfile> version = inst->getMinecraftProfile();
QString assetName = version->assets;
QString asset_fname = "assets/indexes/" + assetName + ".json";
@@ -177,7 +177,7 @@ void OneSixUpdate::jarlibStart()
OneSixInstance *inst = (OneSixInstance *)m_inst;
try
{
- inst->reloadVersion();
+ inst->reloadProfile();
}
catch (MMCError &e)
{
@@ -191,7 +191,7 @@ void OneSixUpdate::jarlibStart()
}
// Build a list of URLs that will need to be downloaded.
- std::shared_ptr<InstanceVersion> version = inst->getFullVersion();
+ std::shared_ptr<MinecraftProfile> version = inst->getMinecraftProfile();
// minecraft.jar for this version
{
QString version_id = version->id;
@@ -290,7 +290,7 @@ void OneSixUpdate::jarlibStart()
void OneSixUpdate::jarlibFinished()
{
OneSixInstance *inst = (OneSixInstance *)m_inst;
- std::shared_ptr<InstanceVersion> version = inst->getFullVersion();
+ std::shared_ptr<MinecraftProfile> version = inst->getMinecraftProfile();
// nuke obsolete stripped jar(s) if needed
QString version_id = version->id;
@@ -311,22 +311,16 @@ void OneSixUpdate::jarlibFinished()
}
}
- // create stripped jar, if needed
- if (version->hasJarMods())
+ // create temporary modded jar, if needed
+ auto jarMods = inst->getJarMods();
+ if(jarMods.size())
{
auto sourceJarPath = m_inst->versionsPath().absoluteFilePath(version->id + "/" + version->id + ".jar");
QString localPath = version_id + "/" + version_id + ".jar";
auto metacache = MMC->metacache();
auto entry = metacache->resolveEntry("versions", localPath);
QString fullJarPath = entry->getFullPath();
- //FIXME: remove need to convert to different objects here
- QList<Mod> mods;
- for (auto jarmod : version->jarMods)
- {
- QString filePath = m_inst->jarmodsPath().absoluteFilePath(jarmod->name);
- mods.push_back(Mod(QFileInfo(filePath)));
- }
- if(!JarUtils::createModdedJar(sourceJarPath, finalJarPath, mods))
+ if(!JarUtils::createModdedJar(sourceJarPath, finalJarPath, jarMods))
{
emitFailed(tr("Failed to create the custom Minecraft jar file."));
return;
@@ -354,7 +348,7 @@ void OneSixUpdate::fmllibsStart()
{
// Get the mod list
OneSixInstance *inst = (OneSixInstance *)m_inst;
- std::shared_ptr<InstanceVersion> fullversion = inst->getFullVersion();
+ std::shared_ptr<MinecraftProfile> fullversion = inst->getMinecraftProfile();
bool forge_present = false;
QString version = inst->intendedVersionId();
diff --git a/logic/OneSixUpdate.h b/logic/OneSixUpdate.h
index 79215f56..e3571e5a 100644
--- a/logic/OneSixUpdate.h
+++ b/logic/OneSixUpdate.h
@@ -21,7 +21,7 @@
#include "logic/net/NetJob.h"
#include "logic/tasks/Task.h"
-#include "logic/VersionFilterData.h"
+#include "logic/minecraft/VersionFilterData.h"
#include <quazip.h>
class MinecraftVersion;
diff --git a/logic/assets/AssetsMigrateTask.cpp b/logic/assets/AssetsMigrateTask.cpp
index 7c1f5204..9ded3cc2 100644
--- a/logic/assets/AssetsMigrateTask.cpp
+++ b/logic/assets/AssetsMigrateTask.cpp
@@ -5,8 +5,6 @@
#include <QJsonDocument>
#include <QDirIterator>
#include <QCryptographicHash>
-#include "gui/dialogs/CustomMessageBox.h"
-#include <QDesktopServices>
AssetsMigrateTask::AssetsMigrateTask(int expected, QObject *parent)
: Task(parent)
diff --git a/logic/assets/AssetsUtils.cpp b/logic/assets/AssetsUtils.cpp
index e418d14a..472b9589 100644
--- a/logic/assets/AssetsUtils.cpp
+++ b/logic/assets/AssetsUtils.cpp
@@ -22,6 +22,7 @@
#include "AssetsUtils.h"
#include "MultiMC.h"
+#include <pathutils.h>
namespace AssetsUtils
{
@@ -151,4 +152,65 @@ bool loadAssetsIndexJson(QString path, AssetsIndex *index)
return true;
}
+
+QDir reconstructAssets(QString assetsId)
+{
+ QDir assetsDir = QDir("assets/");
+ QDir indexDir = QDir(PathCombine(assetsDir.path(), "indexes"));
+ QDir objectDir = QDir(PathCombine(assetsDir.path(), "objects"));
+ QDir virtualDir = QDir(PathCombine(assetsDir.path(), "virtual"));
+
+ QString indexPath = PathCombine(indexDir.path(), assetsId + ".json");
+ QFile indexFile(indexPath);
+ QDir virtualRoot(PathCombine(virtualDir.path(), assetsId));
+
+ if (!indexFile.exists())
+ {
+ QLOG_ERROR() << "No assets index file" << indexPath << "; can't reconstruct assets";
+ return virtualRoot;
+ }
+
+ QLOG_DEBUG() << "reconstructAssets" << assetsDir.path() << indexDir.path()
+ << objectDir.path() << virtualDir.path() << virtualRoot.path();
+
+ AssetsIndex index;
+ bool loadAssetsIndex = AssetsUtils::loadAssetsIndexJson(indexPath, &index);
+
+ if (loadAssetsIndex && index.isVirtual)
+ {
+ QLOG_INFO() << "Reconstructing virtual assets folder at" << virtualRoot.path();
+
+ for (QString map : index.objects.keys())
+ {
+ AssetObject asset_object = index.objects.value(map);
+ QString target_path = PathCombine(virtualRoot.path(), map);
+ QFile target(target_path);
+
+ QString tlk = asset_object.hash.left(2);
+
+ QString original_path =
+ PathCombine(PathCombine(objectDir.path(), tlk), asset_object.hash);
+ QFile original(original_path);
+ if (!original.exists())
+ continue;
+ if (!target.exists())
+ {
+ QFileInfo info(target_path);
+ QDir target_dir = info.dir();
+ // QLOG_DEBUG() << target_dir;
+ if (!target_dir.exists())
+ QDir("").mkpath(target_dir.path());
+
+ bool couldCopy = original.copy(target_path);
+ QLOG_DEBUG() << " Copying" << original_path << "to" << target_path
+ << QString::number(couldCopy); // << original.errorString();
+ }
+ }
+
+ // TODO: Write last used time to virtualRoot/.lastused
+ }
+
+ return virtualRoot;
+}
+
}
diff --git a/logic/assets/AssetsUtils.h b/logic/assets/AssetsUtils.h
index 88fa89c4..ea12136d 100644
--- a/logic/assets/AssetsUtils.h
+++ b/logic/assets/AssetsUtils.h
@@ -34,4 +34,6 @@ namespace AssetsUtils
{
bool loadAssetsIndexJson(QString file, AssetsIndex* index);
int findLegacyAssets();
+/// Reconstruct a virtual assets folder for the given assets ID and return the folder
+QDir reconstructAssets(QString assetsId);
}
diff --git a/logic/forge/ForgeInstaller.cpp b/logic/forge/ForgeInstaller.cpp
index 13027ae7..01671306 100644
--- a/logic/forge/ForgeInstaller.cpp
+++ b/logic/forge/ForgeInstaller.cpp
@@ -14,14 +14,13 @@
*/
#include "ForgeInstaller.h"
-#include "logic/minecraft/InstanceVersion.h"
+#include "logic/minecraft/MinecraftProfile.h"
#include "logic/minecraft/OneSixLibrary.h"
#include "logic/net/HttpMetaCache.h"
#include "logic/tasks/Task.h"
#include "logic/OneSixInstance.h"
#include "logic/forge/ForgeVersionList.h"
-#include "logic/VersionFilterData.h"
-#include "gui/dialogs/ProgressDialog.h"
+#include "logic/minecraft/VersionFilterData.h"
#include <quazip.h>
#include <quazipfile.h>
@@ -41,7 +40,7 @@ ForgeInstaller::ForgeInstaller() : BaseInstaller()
void ForgeInstaller::prepare(const QString &filename, const QString &universalUrl)
{
- std::shared_ptr<InstanceVersion> newVersion;
+ std::shared_ptr<MinecraftProfile> newVersion;
m_universal_url = universalUrl;
QuaZip zip(filename);
@@ -74,7 +73,7 @@ void ForgeInstaller::prepare(const QString &filename, const QString &universalUr
// read the forge version info
{
- newVersion = InstanceVersion::fromJson(versionInfoVal.toObject());
+ newVersion = MinecraftProfile::fromJson(versionInfoVal.toObject());
if (!newVersion)
return;
}
@@ -116,7 +115,7 @@ void ForgeInstaller::prepare(const QString &filename, const QString &universalUr
file.close();
m_forge_json = newVersion;
- realVersionId = m_forge_json->id = installObj.value("minecraft").toString();
+ m_forge_json->id = installObj.value("minecraft").toString();
}
bool ForgeInstaller::add(OneSixInstance *to)
@@ -194,7 +193,7 @@ bool ForgeInstaller::add(OneSixInstance *to)
bool found = false;
bool equals = false;
// find an entry that matches this one
- for (auto tolib : to->getFullVersion()->vanillaLibraries)
+ for (auto tolib : to->getMinecraftProfile()->vanillaLibraries)
{
if (tolib->artifactId() != libName)
continue;
@@ -237,7 +236,7 @@ bool ForgeInstaller::add(OneSixInstance *to)
match = expression.match(args);
}
}
- if (!args.isEmpty() && args != to->getFullVersion()->vanillaMinecraftArguments)
+ if (!args.isEmpty() && args != to->getMinecraftProfile()->vanillaMinecraftArguments)
{
obj.insert("minecraftArguments", args);
}
@@ -246,7 +245,7 @@ bool ForgeInstaller::add(OneSixInstance *to)
obj.insert("+tweakers", QJsonArray::fromStringList(tweakers));
}
if (!m_forge_json->processArguments.isEmpty() &&
- m_forge_json->processArguments != to->getFullVersion()->vanillaProcessArguments)
+ m_forge_json->processArguments != to->getMinecraftProfile()->vanillaProcessArguments)
{
obj.insert("processArguments", m_forge_json->processArguments);
}
@@ -308,7 +307,7 @@ bool ForgeInstaller::addLegacy(OneSixInstance *to)
traitsPlus.append(QString("legacyFML"));
obj.insert("+traits", traitsPlus);
}
- auto fullversion = to->getFullVersion();
+ auto fullversion = to->getMinecraftProfile();
fullversion->remove("net.minecraftforge");
QFile file(filename(to->instanceRoot()));
@@ -409,7 +408,7 @@ protected:
{
try
{
- m_instance->reloadVersion();
+ m_instance->reloadProfile();
emitSucceeded();
}
catch (MMCError &e)
diff --git a/logic/forge/ForgeInstaller.h b/logic/forge/ForgeInstaller.h
index f2e5e393..e85582fd 100644
--- a/logic/forge/ForgeInstaller.h
+++ b/logic/forge/ForgeInstaller.h
@@ -20,7 +20,7 @@
#include <QString>
#include <memory>
-class InstanceVersion;
+class MinecraftProfile;
class ForgeInstallTask;
struct ForgeVersion;
@@ -40,12 +40,11 @@ protected:
private:
// the parsed version json, read from the installer
- std::shared_ptr<InstanceVersion> m_forge_json;
+ std::shared_ptr<MinecraftProfile> m_forge_json;
// the actual forge version
std::shared_ptr<ForgeVersion> m_forge_version;
QString internalPath;
QString finalPath;
- QString realVersionId;
QString m_forgeVersionString;
QString m_universal_url;
};
diff --git a/logic/forge/ForgeVersion.cpp b/logic/forge/ForgeVersion.cpp
index 3131ec39..f3e64204 100644
--- a/logic/forge/ForgeVersion.cpp
+++ b/logic/forge/ForgeVersion.cpp
@@ -1,5 +1,5 @@
#include "ForgeVersion.h"
-#include "logic/VersionFilterData.h"
+#include "logic/minecraft/VersionFilterData.h"
#include <QObject>
QString ForgeVersion::name()
diff --git a/logic/ftb/FTBVersion.h b/logic/ftb/FTBVersion.h
new file mode 100644
index 00000000..dbd9c29e
--- /dev/null
+++ b/logic/ftb/FTBVersion.h
@@ -0,0 +1,32 @@
+#pragma once
+#include <logic/minecraft/MinecraftVersion.h>
+
+class FTBVersion : public BaseVersion
+{
+public:
+ FTBVersion(MinecraftVersionPtr parent) : m_version(parent){};
+
+public:
+ virtual QString descriptor() override
+ {
+ return m_version->descriptor();
+ }
+
+ virtual QString name() override
+ {
+ return m_version->name();
+ }
+
+ virtual QString typeString() const override
+ {
+ return m_version->typeString();
+ }
+
+ MinecraftVersionPtr getMinecraftVersion()
+ {
+ return m_version;
+ }
+
+private:
+ MinecraftVersionPtr m_version;
+};
diff --git a/logic/LegacyFTBInstance.cpp b/logic/ftb/LegacyFTBInstance.cpp
index 06bef948..06bef948 100644
--- a/logic/LegacyFTBInstance.cpp
+++ b/logic/ftb/LegacyFTBInstance.cpp
diff --git a/logic/LegacyFTBInstance.h b/logic/ftb/LegacyFTBInstance.h
index a2fe1ead..7ae7a97c 100644
--- a/logic/LegacyFTBInstance.h
+++ b/logic/ftb/LegacyFTBInstance.h
@@ -1,6 +1,6 @@
#pragma once
-#include "LegacyInstance.h"
+#include "logic/LegacyInstance.h"
class LegacyFTBInstance : public LegacyInstance
{
diff --git a/logic/OneSixFTBInstance.cpp b/logic/ftb/OneSixFTBInstance.cpp
index bf1361dd..d55b1ea9 100644
--- a/logic/OneSixFTBInstance.cpp
+++ b/logic/ftb/OneSixFTBInstance.cpp
@@ -1,11 +1,11 @@
#include "OneSixFTBInstance.h"
-#include "logic/minecraft/InstanceVersion.h"
+#include "logic/minecraft/MinecraftProfile.h"
#include "logic/minecraft/OneSixLibrary.h"
#include "logic/minecraft/VersionBuilder.h"
-#include "tasks/SequentialTask.h"
-#include "forge/ForgeInstaller.h"
-#include "forge/ForgeVersionList.h"
+#include "logic/tasks/SequentialTask.h"
+#include "logic/forge/ForgeInstaller.h"
+#include "logic/forge/ForgeVersionList.h"
#include "MultiMC.h"
#include "pathutils.h"
@@ -109,11 +109,13 @@ QDir OneSixFTBInstance::versionsPath() const
return QDir(MMC->settings()->get("FTBRoot").toString() + "/versions");
}
+/*
QStringList OneSixFTBInstance::externalPatches() const
{
return QStringList() << versionsPath().absoluteFilePath(intendedVersionId() + "/" + intendedVersionId() + ".json")
<< minecraftRoot() + "/pack.json";
}
+*/
bool OneSixFTBInstance::providesVersionFile() const
{
diff --git a/logic/OneSixFTBInstance.h b/logic/ftb/OneSixFTBInstance.h
index 1f9df8ab..3419e94c 100644
--- a/logic/OneSixFTBInstance.h
+++ b/logic/ftb/OneSixFTBInstance.h
@@ -1,6 +1,6 @@
#pragma once
-#include "OneSixInstance.h"
+#include "logic/OneSixInstance.h"
class OneSixLibrary;
@@ -22,7 +22,6 @@ public:
QDir librariesPath() const override;
QDir versionsPath() const override;
- QStringList externalPatches() const override;
bool providesVersionFile() const override;
private:
diff --git a/logic/liteloader/LiteLoaderInstaller.cpp b/logic/liteloader/LiteLoaderInstaller.cpp
index 82c3b063..be1791ee 100644
--- a/logic/liteloader/LiteLoaderInstaller.cpp
+++ b/logic/liteloader/LiteLoaderInstaller.cpp
@@ -20,7 +20,7 @@
#include "logger/QsLog.h"
-#include "logic/minecraft/InstanceVersion.h"
+#include "logic/minecraft/MinecraftProfile.h"
#include "logic/minecraft/OneSixLibrary.h"
#include "logic/OneSixInstance.h"
#include "MultiMC.h"
@@ -116,7 +116,7 @@ protected:
{
try
{
- m_instance->reloadVersion();
+ m_instance->reloadProfile();
emitSucceeded();
}
catch (MMCError &e)
diff --git a/logic/minecraft/JarMod.cpp b/logic/minecraft/JarMod.cpp
index 18a9411c..fce8a492 100644
--- a/logic/minecraft/JarMod.cpp
+++ b/logic/minecraft/JarMod.cpp
@@ -11,30 +11,6 @@ JarmodPtr Jarmod::fromJson(const QJsonObject &libObj, const QString &filename)
"contains a jarmod that doesn't have a 'name' field");
}
out->name = libObj.value("name").toString();
-
- auto readString = [libObj, filename](const QString & key, QString & variable)
- {
- if (libObj.contains(key))
- {
- QJsonValue val = libObj.value(key);
- if (!val.isString())
- {
- QLOG_WARN() << key << "is not a string in" << filename << "(skipping)";
- }
- else
- {
- variable = val.toString();
- }
- }
- };
-
- readString("url", out->baseurl);
- readString("MMC-hint", out->hint);
- readString("MMC-absoluteUrl", out->absoluteUrl);
- if(!out->baseurl.isEmpty() && out->absoluteUrl.isEmpty())
- {
- out->absoluteUrl = out->baseurl + out->name;
- }
return out;
}
@@ -42,15 +18,5 @@ QJsonObject Jarmod::toJson()
{
QJsonObject out;
writeString(out, "name", name);
- writeString(out, "url", baseurl);
- writeString(out, "MMC-absoluteUrl", absoluteUrl);
- writeString(out, "MMC-hint", hint);
return out;
}
-
-QString Jarmod::url()
-{
- if(!absoluteUrl.isEmpty())
- return absoluteUrl;
- else return baseurl + name;
-}
diff --git a/logic/minecraft/JarMod.h b/logic/minecraft/JarMod.h
index c438dbcd..7d9fa038 100644
--- a/logic/minecraft/JarMod.h
+++ b/logic/minecraft/JarMod.h
@@ -9,10 +9,6 @@ class Jarmod
public: /* methods */
static JarmodPtr fromJson(const QJsonObject &libObj, const QString &filename);
QJsonObject toJson();
- QString url();
public: /* data */
QString name;
- QString baseurl;
- QString hint;
- QString absoluteUrl;
};
diff --git a/logic/minecraft/MinecraftInstance.cpp b/logic/minecraft/MinecraftInstance.cpp
new file mode 100644
index 00000000..090c9389
--- /dev/null
+++ b/logic/minecraft/MinecraftInstance.cpp
@@ -0,0 +1,58 @@
+#include "MinecraftInstance.h"
+#include "MultiMC.h"
+#include "logic/settings/SettingsObject.h"
+#include <pathutils.h>
+#include "logic/minecraft/MinecraftVersionList.h"
+
+MinecraftInstance::MinecraftInstance(const QString &rootDir, SettingsObject *settings, QObject *parent)
+ : BaseInstance(rootDir, settings, parent)
+{
+ auto globalSettings = MMC->settings();
+
+ // Java Settings
+ m_settings->registerSetting("OverrideJava", false);
+ m_settings->registerSetting("OverrideJavaLocation", false);
+ m_settings->registerSetting("OverrideJavaArgs", false);
+ m_settings->registerOverride(globalSettings->getSetting("JavaPath"));
+ m_settings->registerOverride(globalSettings->getSetting("JvmArgs"));
+
+ // Custom Commands
+ m_settings->registerSetting({"OverrideCommands","OverrideLaunchCmd"}, false);
+ m_settings->registerOverride(globalSettings->getSetting("PreLaunchCommand"));
+ m_settings->registerOverride(globalSettings->getSetting("PostExitCommand"));
+
+ // Window Size
+ m_settings->registerSetting("OverrideWindow", false);
+ m_settings->registerOverride(globalSettings->getSetting("LaunchMaximized"));
+ m_settings->registerOverride(globalSettings->getSetting("MinecraftWinWidth"));
+ m_settings->registerOverride(globalSettings->getSetting("MinecraftWinHeight"));
+
+ // Memory
+ m_settings->registerSetting("OverrideMemory", false);
+ m_settings->registerOverride(globalSettings->getSetting("MinMemAlloc"));
+ m_settings->registerOverride(globalSettings->getSetting("MaxMemAlloc"));
+ m_settings->registerOverride(globalSettings->getSetting("PermGen"));
+
+ // Console
+ m_settings->registerSetting("OverrideConsole", false);
+ m_settings->registerOverride(globalSettings->getSetting("ShowConsole"));
+ m_settings->registerOverride(globalSettings->getSetting("AutoCloseConsole"));
+ m_settings->registerOverride(globalSettings->getSetting("LogPrePostOutput"));
+}
+
+QString MinecraftInstance::minecraftRoot() const
+{
+ QFileInfo mcDir(PathCombine(instanceRoot(), "minecraft"));
+ QFileInfo dotMCDir(PathCombine(instanceRoot(), ".minecraft"));
+
+ if (dotMCDir.exists() && !mcDir.exists())
+ return dotMCDir.filePath();
+ else
+ return mcDir.filePath();
+}
+
+std::shared_ptr< BaseVersionList > MinecraftInstance::versionList() const
+{
+ return std::dynamic_pointer_cast<BaseVersionList>(MMC->minecraftlist());
+}
+
diff --git a/logic/minecraft/MinecraftInstance.h b/logic/minecraft/MinecraftInstance.h
new file mode 100644
index 00000000..9097a2da
--- /dev/null
+++ b/logic/minecraft/MinecraftInstance.h
@@ -0,0 +1,30 @@
+#pragma once
+#include "logic/BaseInstance.h"
+
+class MinecraftInstance: public BaseInstance
+{
+public:
+ MinecraftInstance(const QString& rootDir, SettingsObject* settings, QObject* parent = 0);
+ virtual ~MinecraftInstance() {};
+
+ /// Path to the instance's minecraft directory.
+ QString minecraftRoot() const;
+
+ ////// Mod Lists //////
+ virtual std::shared_ptr<ModList> resourcePackList() const
+ {
+ return nullptr;
+ }
+ virtual std::shared_ptr<ModList> texturePackList() const
+ {
+ return nullptr;
+ }
+ /// get all jar mods applicable to this instance's jar
+ virtual QList<Mod> getJarMods() const
+ {
+ return QList<Mod>();
+ }
+ virtual std::shared_ptr< BaseVersionList > versionList() const;
+};
+
+typedef std::shared_ptr<MinecraftInstance> MinecraftInstancePtr;
diff --git a/logic/minecraft/MinecraftProcess.cpp b/logic/minecraft/MinecraftProcess.cpp
new file mode 100644
index 00000000..0fc3f067
--- /dev/null
+++ b/logic/minecraft/MinecraftProcess.cpp
@@ -0,0 +1,216 @@
+/* Copyright 2013-2014 MultiMC Contributors
+ *
+ * Authors: Orochimarufan <orochimarufan.x3@gmail.com>
+ *
+ * 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 "MultiMC.h"
+#include "BuildConfig.h"
+
+#include "logic/minecraft/MinecraftProcess.h"
+#include "logic/BaseInstance.h"
+
+#include <QDataStream>
+#include <QFile>
+#include <QDir>
+#include <QProcessEnvironment>
+#include <QRegularExpression>
+#include <QStandardPaths>
+
+#include "osutils.h"
+#include "pathutils.h"
+#include "cmdutils.h"
+
+#define IBUS "@im=ibus"
+
+// constructor
+MinecraftProcess::MinecraftProcess(MinecraftInstancePtr inst) : BaseProcess(inst)
+{
+}
+
+MinecraftProcess* MinecraftProcess::create(MinecraftInstancePtr inst)
+{
+ auto proc = new MinecraftProcess(inst);
+ proc->init();
+ return proc;
+}
+
+
+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;
+}
+
+QMap<QString, QString> MinecraftProcess::getVariables() const
+{
+ auto mcInstance = std::dynamic_pointer_cast<MinecraftInstance>(m_instance);
+ QMap<QString, QString> out;
+ out.insert("INST_NAME", mcInstance->name());
+ out.insert("INST_ID", mcInstance->id());
+ out.insert("INST_DIR", QDir(mcInstance->instanceRoot()).absolutePath());
+ out.insert("INST_MC_DIR", QDir(mcInstance->minecraftRoot()).absolutePath());
+ out.insert("INST_JAVA", mcInstance->settings().get("JavaPath").toString());
+ out.insert("INST_JAVA_ARGS", javaArguments().join(' '));
+ return out;
+}
+
+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/minecraft/MinecraftProcess.h b/logic/minecraft/MinecraftProcess.h
new file mode 100644
index 00000000..30a59e91
--- /dev/null
+++ b/logic/minecraft/MinecraftProcess.h
@@ -0,0 +1,77 @@
+/* Copyright 2013-2014 MultiMC Contributors
+ *
+ * Authors: Orochimarufan <orochimarufan.x3@gmail.com>
+ *
+ * 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 <QString>
+#include "logic/minecraft/MinecraftInstance.h"
+#include "logic/BaseProcess.h"
+
+/**
+ * The MinecraftProcess class
+ */
+class MinecraftProcess : public BaseProcess
+{
+ Q_OBJECT
+protected:
+ MinecraftProcess(MinecraftInstancePtr inst);
+public:
+ static MinecraftProcess *create(MinecraftInstancePtr inst);
+
+ virtual ~MinecraftProcess(){};
+
+ /**
+ * @brief start the launcher part with the provided launch script
+ */
+ void arm() override;
+
+ /**
+ * @brief launch the armed instance!
+ */
+ void launch() override;
+
+ /**
+ * @brief abort launch!
+ */
+ void abort() override;
+
+ void setLaunchScript(QString script)
+ {
+ launchScript = script;
+ }
+
+ void setNativeFolder(QString natives)
+ {
+ m_nativeFolder = natives;
+ }
+
+ inline void setLogin(AuthSessionPtr session)
+ {
+ m_session = session;
+ }
+
+protected:
+ AuthSessionPtr m_session;
+ QString launchScript;
+ QString m_nativeFolder;
+
+ virtual QMap<QString, QString> getVariables() const override;
+
+ QStringList javaArguments() const;
+ virtual QString censorPrivateInfo(QString in) override;
+ virtual MessageLevel::Enum guessLevel(const QString &message, MessageLevel::Enum defaultLevel) override;
+};
diff --git a/logic/minecraft/InstanceVersion.cpp b/logic/minecraft/MinecraftProfile.cpp
index cc077767..3fbfd105 100644
--- a/logic/minecraft/InstanceVersion.cpp
+++ b/logic/minecraft/MinecraftProfile.cpp
@@ -15,31 +15,50 @@
#include <QFile>
#include <QDir>
-#include <QUuid>
#include <QJsonDocument>
#include <QJsonArray>
#include <pathutils.h>
-#include "logic/minecraft/InstanceVersion.h"
+#include "logic/minecraft/MinecraftProfile.h"
#include "logic/minecraft/VersionBuilder.h"
+#include "ProfileUtils.h"
+#include "NullProfileStrategy.h"
#include "logic/OneSixInstance.h"
-InstanceVersion::InstanceVersion(OneSixInstance *instance, QObject *parent)
- : QAbstractListModel(parent), m_instance(instance)
+MinecraftProfile::MinecraftProfile(ProfileStrategy *strategy)
+ : QAbstractListModel()
{
+ setStrategy(strategy);
clear();
}
-void InstanceVersion::reload(const QStringList &external)
+void MinecraftProfile::setStrategy(ProfileStrategy* strategy)
+{
+ Q_ASSERT(strategy != nullptr);
+
+ if(m_strategy != nullptr)
+ {
+ delete m_strategy;
+ m_strategy = nullptr;
+ }
+ m_strategy = strategy;
+ m_strategy->profile = this;
+}
+
+ProfileStrategy* MinecraftProfile::strategy()
+{
+ return m_strategy;
+}
+
+void MinecraftProfile::reload()
{
- m_externalPatches = external;
beginResetModel();
- VersionBuilder::build(this, m_instance, m_externalPatches);
- reapply(true);
+ m_strategy->load();
+ reapply();
endResetModel();
}
-void InstanceVersion::clear()
+void MinecraftProfile::clear()
{
id.clear();
m_updateTimeString.clear();
@@ -59,44 +78,45 @@ void InstanceVersion::clear()
traits.clear();
}
-bool InstanceVersion::canRemove(const int index) const
+void MinecraftProfile::clearPatches()
{
- return VersionPatches.at(index)->isMoveable();
+ beginResetModel();
+ VersionPatches.clear();
+ endResetModel();
}
-bool InstanceVersion::preremove(VersionPatchPtr patch)
+void MinecraftProfile::appendPatch(ProfilePatchPtr patch)
{
- bool ok = true;
- for(auto & jarmod: patch->getJarMods())
- {
- QString fullpath =PathCombine(m_instance->jarModsDir(), jarmod->name);
- QFileInfo finfo (fullpath);
- if(finfo.exists())
- ok &= QFile::remove(fullpath);
- }
- return ok;
+ int index = VersionPatches.size();
+ beginInsertRows(QModelIndex(), index, index);
+ VersionPatches.append(patch);
+ endInsertRows();
}
-bool InstanceVersion::remove(const int index)
+bool MinecraftProfile::canRemove(const int index) const
+{
+ return VersionPatches.at(index)->isMoveable();
+}
+
+bool MinecraftProfile::remove(const int index)
{
if (!canRemove(index))
return false;
- if(!preremove(VersionPatches[index]))
+
+ if(!m_strategy->removePatch(VersionPatches.at(index)))
{
return false;
}
- auto toDelete = VersionPatches.at(index)->getPatchFilename();
- if(!QFile::remove(toDelete))
- return false;
+
beginRemoveRows(QModelIndex(), index, index);
VersionPatches.removeAt(index);
endRemoveRows();
- reapply(true);
+ reapply();
saveCurrentOrder();
return true;
}
-bool InstanceVersion::remove(const QString id)
+bool MinecraftProfile::remove(const QString id)
{
int i = 0;
for (auto patch : VersionPatches)
@@ -110,7 +130,7 @@ bool InstanceVersion::remove(const QString id)
return false;
}
-QString InstanceVersion::versionFileId(const int index) const
+QString MinecraftProfile::versionFileId(const int index) const
{
if (index < 0 || index >= VersionPatches.size())
{
@@ -119,7 +139,7 @@ QString InstanceVersion::versionFileId(const int index) const
return VersionPatches.at(index)->getPatchID();
}
-VersionPatchPtr InstanceVersion::versionPatch(const QString &id)
+ProfilePatchPtr MinecraftProfile::versionPatch(const QString &id)
{
for (auto file : VersionPatches)
{
@@ -131,67 +151,27 @@ VersionPatchPtr InstanceVersion::versionPatch(const QString &id)
return 0;
}
-VersionPatchPtr InstanceVersion::versionPatch(int index)
+ProfilePatchPtr MinecraftProfile::versionPatch(int index)
{
if(index < 0 || index >= VersionPatches.size())
return 0;
return VersionPatches[index];
}
-
-bool InstanceVersion::hasJarMods()
-{
- return !jarMods.isEmpty();
-}
-
-bool InstanceVersion::hasFtbPack()
-{
- return versionPatch("org.multimc.ftb.pack.json") != nullptr;
-}
-
-bool InstanceVersion::removeFtbPack()
+bool MinecraftProfile::isVanilla()
{
- return remove("org.multimc.ftb.pack.json");
-}
-
-bool InstanceVersion::isVanilla()
-{
- QDir patches(PathCombine(m_instance->instanceRoot(), "patches/"));
for(auto patchptr: VersionPatches)
{
if(patchptr->isCustom())
return false;
}
- if(QFile::exists(PathCombine(m_instance->instanceRoot(), "custom.json")))
- return false;
- if(QFile::exists(PathCombine(m_instance->instanceRoot(), "version.json")))
- return false;
return true;
}
-bool InstanceVersion::revertToVanilla()
+bool MinecraftProfile::revertToVanilla()
{
+ /*
beginResetModel();
- // remove custom.json, if present
- QString customPath = PathCombine(m_instance->instanceRoot(), "custom.json");
- if(QFile::exists(customPath))
- {
- if(!QFile::remove(customPath))
- {
- endResetModel();
- return false;
- }
- }
- // remove version.json, if present
- QString versionPath = PathCombine(m_instance->instanceRoot(), "version.json");
- if(QFile::exists(versionPath))
- {
- if(!QFile::remove(versionPath))
- {
- endResetModel();
- return false;
- }
- }
// remove patches, if present
auto it = VersionPatches.begin();
while (it != VersionPatches.end())
@@ -215,49 +195,15 @@ bool InstanceVersion::revertToVanilla()
else
it++;
}
- reapply(true);
+ reapply();
endResetModel();
saveCurrentOrder();
return true;
-}
-
-bool InstanceVersion::hasDeprecatedVersionFiles()
-{
- if(QFile::exists(PathCombine(m_instance->instanceRoot(), "custom.json")))
- return true;
- if(QFile::exists(PathCombine(m_instance->instanceRoot(), "version.json")))
- return true;
+ */
return false;
}
-bool InstanceVersion::removeDeprecatedVersionFiles()
-{
- beginResetModel();
- // remove custom.json, if present
- QString customPath = PathCombine(m_instance->instanceRoot(), "custom.json");
- if(QFile::exists(customPath))
- {
- if(!QFile::remove(customPath))
- {
- endResetModel();
- return false;
- }
- }
- // remove version.json, if present
- QString versionPath = PathCombine(m_instance->instanceRoot(), "version.json");
- if(QFile::exists(versionPath))
- {
- if(!QFile::remove(versionPath))
- {
- endResetModel();
- return false;
- }
- }
- endResetModel();
- return true;
-}
-
-QList<std::shared_ptr<OneSixLibrary> > InstanceVersion::getActiveNormalLibs()
+QList<std::shared_ptr<OneSixLibrary> > MinecraftProfile::getActiveNormalLibs()
{
QList<std::shared_ptr<OneSixLibrary> > output;
for (auto lib : libraries)
@@ -277,7 +223,8 @@ QList<std::shared_ptr<OneSixLibrary> > InstanceVersion::getActiveNormalLibs()
}
return output;
}
-QList<std::shared_ptr<OneSixLibrary> > InstanceVersion::getActiveNativeLibs()
+
+QList<std::shared_ptr<OneSixLibrary> > MinecraftProfile::getActiveNativeLibs()
{
QList<std::shared_ptr<OneSixLibrary> > output;
for (auto lib : libraries)
@@ -290,9 +237,9 @@ QList<std::shared_ptr<OneSixLibrary> > InstanceVersion::getActiveNativeLibs()
return output;
}
-std::shared_ptr<InstanceVersion> InstanceVersion::fromJson(const QJsonObject &obj)
+std::shared_ptr<MinecraftProfile> MinecraftProfile::fromJson(const QJsonObject &obj)
{
- std::shared_ptr<InstanceVersion> version(new InstanceVersion(0));
+ std::shared_ptr<MinecraftProfile> version(new MinecraftProfile(new NullProfileStrategy()));
try
{
VersionBuilder::readJsonAndApplyToVersion(version.get(), obj);
@@ -304,7 +251,7 @@ std::shared_ptr<InstanceVersion> InstanceVersion::fromJson(const QJsonObject &ob
return version;
}
-QVariant InstanceVersion::data(const QModelIndex &index, int role) const
+QVariant MinecraftProfile::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
@@ -329,7 +276,7 @@ QVariant InstanceVersion::data(const QModelIndex &index, int role) const
}
return QVariant();
}
-QVariant InstanceVersion::headerData(int section, Qt::Orientation orientation, int role) const
+QVariant MinecraftProfile::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal)
{
@@ -348,36 +295,36 @@ QVariant InstanceVersion::headerData(int section, Qt::Orientation orientation, i
}
return QVariant();
}
-Qt::ItemFlags InstanceVersion::flags(const QModelIndex &index) const
+Qt::ItemFlags MinecraftProfile::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::NoItemFlags;
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
}
-int InstanceVersion::rowCount(const QModelIndex &parent) const
+int MinecraftProfile::rowCount(const QModelIndex &parent) const
{
return VersionPatches.size();
}
-int InstanceVersion::columnCount(const QModelIndex &parent) const
+int MinecraftProfile::columnCount(const QModelIndex &parent) const
{
return 2;
}
-void InstanceVersion::saveCurrentOrder() const
+void MinecraftProfile::saveCurrentOrder() const
{
- PatchOrder order;
+ ProfileUtils::PatchOrder order;
for(auto item: VersionPatches)
{
if(!item->isMoveable())
continue;
order.append(item->getPatchID());
}
- VersionBuilder::writeOverrideOrders(m_instance, order);
+ m_strategy->saveOrder(order);
}
-void InstanceVersion::move(const int index, const MoveDirection direction)
+void MinecraftProfile::move(const int index, const MoveDirection direction)
{
int theirIndex;
if (direction == MoveUp)
@@ -388,7 +335,7 @@ void InstanceVersion::move(const int index, const MoveDirection direction)
{
theirIndex = index + 1;
}
-
+
if (index < 0 || index >= VersionPatches.size())
return;
if (theirIndex >= rowCount())
@@ -401,7 +348,7 @@ void InstanceVersion::move(const int index, const MoveDirection direction)
auto from = versionPatch(index);
auto to = versionPatch(theirIndex);
-
+
if (!from || !to || !to->isMoveable() || !from->isMoveable())
{
return;
@@ -412,13 +359,13 @@ void InstanceVersion::move(const int index, const MoveDirection direction)
saveCurrentOrder();
reapply();
}
-void InstanceVersion::resetOrder()
+void MinecraftProfile::resetOrder()
{
- QDir(m_instance->instanceRoot()).remove("order.json");
- reload(m_externalPatches);
+ m_strategy->resetOrder();
+ reload();
}
-void InstanceVersion::reapply(const bool alreadyReseting)
+void MinecraftProfile::reapply()
{
clear();
for(auto file: VersionPatches)
@@ -428,7 +375,7 @@ void InstanceVersion::reapply(const bool alreadyReseting)
finalize();
}
-void InstanceVersion::finalize()
+void MinecraftProfile::finalize()
{
// HACK: deny april fools. my head hurts enough already.
QDate now = QDate::currentDate();
@@ -465,78 +412,15 @@ void InstanceVersion::finalize()
finalizeArguments(minecraftArguments, processArguments);
}
-void InstanceVersion::installJarMods(QStringList selectedFiles)
-{
- for(auto filename: selectedFiles)
- {
- installJarModByFilename(filename);
- }
-}
-
-void InstanceVersion::installJarModByFilename(QString filepath)
+void MinecraftProfile::installJarMods(QStringList selectedFiles)
{
- QString patchDir = PathCombine(m_instance->instanceRoot(), "patches");
- if(!ensureFolderPathExists(patchDir))
- {
- // THROW...
- return;
- }
-
- if (!ensureFolderPathExists(m_instance->jarModsDir()))
- {
- // THROW...
- return;
- }
-
- QFileInfo sourceInfo(filepath);
- auto uuid = QUuid::createUuid();
- QString id = uuid.toString().remove('{').remove('}');
- QString target_filename = id + ".jar";
- QString target_id = "org.multimc.jarmod." + id;
- QString target_name = sourceInfo.completeBaseName() + " (jar mod)";
- QString finalPath = PathCombine(m_instance->jarModsDir(), target_filename);
-
- QFileInfo targetInfo(finalPath);
- if(targetInfo.exists())
- {
- // THROW
- return;
- }
-
- if (!QFile::copy(sourceInfo.absoluteFilePath(),QFileInfo(finalPath).absoluteFilePath()))
- {
- // THROW
- return;
- }
-
- auto f = std::make_shared<VersionFile>();
- auto jarMod = std::make_shared<Jarmod>();
- jarMod->name = target_filename;
- f->jarMods.append(jarMod);
- f->name = target_name;
- f->fileId = target_id;
- f->order = getFreeOrderNumber();
- QString patchFileName = PathCombine(patchDir, target_id + ".json");
- f->filename = patchFileName;
-
- QFile file(patchFileName);
- if (!file.open(QFile::WriteOnly))
- {
- QLOG_ERROR() << "Error opening" << file.fileName()
- << "for reading:" << file.errorString();
- return;
- // THROW
- }
- file.write(f->toJson(true).toJson());
- file.close();
- int index = VersionPatches.size();
- beginInsertRows(QModelIndex(), index, index);
- VersionPatches.append(f);
- endInsertRows();
- saveCurrentOrder();
+ m_strategy->installJarMods(selectedFiles);
}
-int InstanceVersion::getFreeOrderNumber()
+/*
+ * TODO: get rid of this. Get rid of all order numbers.
+ */
+int MinecraftProfile::getFreeOrderNumber()
{
int largest = 100;
// yes, I do realize this is dumb. The order thing itself is dumb. and to be removed next.
diff --git a/logic/minecraft/InstanceVersion.h b/logic/minecraft/MinecraftProfile.h
index a4849d6a..ef7e1369 100644
--- a/logic/minecraft/InstanceVersion.h
+++ b/logic/minecraft/MinecraftProfile.h
@@ -25,13 +25,22 @@
#include "VersionFile.h"
#include "JarMod.h"
+class ProfileStrategy;
class OneSixInstance;
-class InstanceVersion : public QAbstractListModel
+class MinecraftProfile : public QAbstractListModel
{
Q_OBJECT
+ friend class ProfileStrategy;
+
public:
- explicit InstanceVersion(OneSixInstance *instance, QObject *parent = 0);
+ explicit MinecraftProfile(ProfileStrategy *strategy);
+
+ /// construct a MinecraftProfile from a single file
+ static std::shared_ptr<MinecraftProfile> fromJson(const QJsonObject &obj);
+
+ void setStrategy(ProfileStrategy * strategy);
+ ProfileStrategy *strategy();
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
@@ -39,57 +48,72 @@ public:
virtual int columnCount(const QModelIndex &parent) const;
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
- void reload(const QStringList &external = QStringList());
- void clear();
-
- bool canRemove(const int index) const;
-
- QString versionFileId(const int index) const;
-
- // is this version unmodded vanilla minecraft?
+ /// is this version unchanged by the user?
bool isVanilla();
- // remove any customizations on top of vanilla
+
+ /// remove any customizations on top of whatever 'vanilla' means
bool revertToVanilla();
-
- // does this version consist of obsolete files?
- bool hasDeprecatedVersionFiles();
- // remove obsolete files
- bool removeDeprecatedVersionFiles();
-
- // does this version have an FTB pack patch file?
- bool hasFtbPack();
- // remove FTB pack
- bool removeFtbPack();
-
- // does this version have any jar mods?
- bool hasJarMods();
+
+ /// install more jar mods
void installJarMods(QStringList selectedFiles);
- void installJarModByFilename(QString filepath);
+
+ /// DEPRECATED, remove ASAP
+ int getFreeOrderNumber();
+
+ /// Can patch file # be removed?
+ bool canRemove(const int index) const;
enum MoveDirection { MoveUp, MoveDown };
+ /// move patch file # up or down the list
void move(const int index, const MoveDirection direction);
- void resetOrder();
- // clears and reapplies all version files
- void reapply(const bool alreadyReseting = false);
- void finalize();
-
-public
-slots:
+ /// remove patch file # - including files/records
bool remove(const int index);
+
+ /// remove patch file by id - including files/records
bool remove(const QString id);
+ void resetOrder();
+
+ /// reload all profile patches from storage, clear the profile and apply the patches
+ void reload();
+
+ /// clear the profile
+ void clear();
+
+ /// apply the patches
+ void reapply();
+
+ /// do a finalization step (should always be done after applying all patches to profile)
+ void finalize();
+
public:
+ /// get all java libraries that belong to the classpath
QList<std::shared_ptr<OneSixLibrary>> getActiveNormalLibs();
+
+ /// get all native libraries that need to be available to the process
QList<std::shared_ptr<OneSixLibrary>> getActiveNativeLibs();
- static std::shared_ptr<InstanceVersion> fromJson(const QJsonObject &obj);
+ /// get file ID of the patch file at #
+ QString versionFileId(const int index) const;
-private:
- bool preremove(VersionPatchPtr patch);
-
- // data members
-public:
+ /// get the profile patch by id
+ ProfilePatchPtr versionPatch(const QString &id);
+
+ /// get the profile patch by index
+ ProfilePatchPtr versionPatch(int index);
+
+ /// save the current patch order
+ void saveCurrentOrder() const;
+
+public: /* only use in ProfileStrategy */
+ /// Remove all the patches
+ void clearPatches();
+
+ /// Add the patch object to the internal list of patches
+ void appendPatch(ProfilePatchPtr patch);
+
+public: /* data */
/// the ID - determines which jar to use! ACTUALLY IMPORTANT!
QString id;
@@ -138,7 +162,7 @@ public:
* The applet class, for some very old minecraft releases
*/
QString appletClass;
-
+
/// the list of libs - both active and inactive, native and java
QList<OneSixLibraryPtr> libraries;
@@ -171,14 +195,7 @@ public:
}
*/
// QList<Rule> rules;
-
- QList<VersionPatchPtr> VersionPatches;
- VersionPatchPtr versionPatch(const QString &id);
- VersionPatchPtr versionPatch(int index);
-
private:
- QStringList m_externalPatches;
- OneSixInstance *m_instance;
- void saveCurrentOrder() const;
- int getFreeOrderNumber();
+ QList<ProfilePatchPtr> VersionPatches;
+ ProfileStrategy *m_strategy = nullptr;
};
diff --git a/logic/minecraft/MinecraftVersion.cpp b/logic/minecraft/MinecraftVersion.cpp
index bd53997b..32682bfb 100644
--- a/logic/minecraft/MinecraftVersion.cpp
+++ b/logic/minecraft/MinecraftVersion.cpp
@@ -1,7 +1,8 @@
#include "MinecraftVersion.h"
-#include "InstanceVersion.h"
+#include "MinecraftProfile.h"
#include "VersionBuildError.h"
#include "VersionBuilder.h"
+#include "ProfileUtils.h"
#include "MultiMC.h"
#include "logic/settings/SettingsObject.h"
@@ -56,15 +57,20 @@ bool MinecraftVersion::isMinecraftVersion()
// 1. assume the local file is good. load, check. If it's good, apply.
// 2. if discrepancies are found, fall out and fail (impossible to apply incomplete version).
-void MinecraftVersion::applyFileTo(InstanceVersion *version)
+void MinecraftVersion::applyFileTo(MinecraftProfile *version)
+{
+ getVersionFile()->applyTo(version);
+}
+
+VersionFilePtr MinecraftVersion::getVersionFile()
{
QFileInfo versionFile(QString("versions/%1/%1.dat").arg(m_descriptor));
-
- auto versionObj = VersionBuilder::parseBinaryJsonFile(versionFile);
- versionObj->applyTo(version);
+
+ return ProfileUtils::parseBinaryJsonFile(versionFile);
}
-void MinecraftVersion::applyTo(InstanceVersion *version)
+
+void MinecraftVersion::applyTo(MinecraftProfile *version)
{
// do we have this one cached?
if (m_versionSource == Local)
diff --git a/logic/minecraft/MinecraftVersion.h b/logic/minecraft/MinecraftVersion.h
index 84d0773e..fbb209f2 100644
--- a/logic/minecraft/MinecraftVersion.h
+++ b/logic/minecraft/MinecraftVersion.h
@@ -20,15 +20,15 @@
#include <QDateTime>
#include "logic/BaseVersion.h"
-#include "VersionPatch.h"
+#include "ProfilePatch.h"
#include "VersionFile.h"
#include "VersionSource.h"
-class InstanceVersion;
+class MinecraftProfile;
class MinecraftVersion;
typedef std::shared_ptr<MinecraftVersion> MinecraftVersionPtr;
-class MinecraftVersion : public BaseVersion, public VersionPatch
+class MinecraftVersion : public BaseVersion, public ProfilePatch
{
public: /* methods */
bool usesLegacyLauncher();
@@ -37,9 +37,9 @@ public: /* methods */
virtual QString typeString() const override;
virtual bool hasJarMods() override;
virtual bool isMinecraftVersion() override;
- virtual void applyTo(InstanceVersion *version) override;
- virtual int getOrder();
- virtual void setOrder(int order);
+ virtual void applyTo(MinecraftProfile *version) override;
+ virtual int getOrder() override;
+ virtual void setOrder(int order) override;
virtual QList<JarmodPtr> getJarMods() override;
virtual QString getPatchID() override;
virtual QString getPatchVersion() override;
@@ -47,10 +47,12 @@ public: /* methods */
virtual QString getPatchFilename() override;
bool needsUpdate();
bool hasUpdate();
- virtual bool isCustom();
+ virtual bool isCustom() override;
+
+ VersionFilePtr getVersionFile();
private: /* methods */
- void applyFileTo(InstanceVersion *version);
+ void applyFileTo(MinecraftProfile *version);
public: /* data */
/// The URL that this version will be downloaded from. maybe.
@@ -92,7 +94,7 @@ public: /* data */
/// order of this file... default = -2
int order = -2;
-
+
/// an update available from Mojang
MinecraftVersionPtr upstreamUpdate;
};
diff --git a/logic/minecraft/MinecraftVersionList.cpp b/logic/minecraft/MinecraftVersionList.cpp
index a93ea301..68e93d54 100644
--- a/logic/minecraft/MinecraftVersionList.cpp
+++ b/logic/minecraft/MinecraftVersionList.cpp
@@ -25,12 +25,53 @@
#include "logic/net/URLConstants.h"
#include "ParseUtils.h"
+#include "ProfileUtils.h"
#include "VersionBuilder.h"
-#include <logic/VersionFilterData.h>
+#include "VersionFilterData.h"
+
#include <pathutils.h>
static const char * localVersionCache = "versions/versions.dat";
+class MCVListLoadTask : public Task
+{
+ Q_OBJECT
+
+public:
+ explicit MCVListLoadTask(MinecraftVersionList *vlist);
+ virtual ~MCVListLoadTask() override{};
+
+ virtual void executeTask() override;
+
+protected
+slots:
+ void list_downloaded();
+
+protected:
+ QNetworkReply *vlistReply;
+ MinecraftVersionList *m_list;
+ MinecraftVersion *m_currentStable;
+};
+
+class MCVListVersionUpdateTask : public Task
+{
+ Q_OBJECT
+
+public:
+ explicit MCVListVersionUpdateTask(MinecraftVersionList *vlist, QString updatedVersion);
+ virtual ~MCVListVersionUpdateTask() override{};
+ virtual void executeTask() override;
+
+protected
+slots:
+ void json_downloaded();
+
+protected:
+ NetJobPtr specificVersionDownloadJob;
+ QString versionToUpdate;
+ MinecraftVersionList *m_list;
+};
+
class ListLoadError : public MMCError
{
public:
@@ -442,21 +483,9 @@ void MCVListVersionUpdateTask::json_downloaded()
emitFailed(tr("Couldn't process version file: %1").arg(e.cause()));
return;
}
- QList<RawLibraryPtr> filteredLibs;
- QList<RawLibraryPtr> lwjglLibs;
- for (auto lib : file->overwriteLibs)
- {
- if (g_VersionFilterData.lwjglWhitelist.contains(lib->artifactPrefix()))
- {
- lwjglLibs.append(lib);
- }
- else
- {
- filteredLibs.append(lib);
- }
- }
- file->overwriteLibs = filteredLibs;
+ // Strip LWJGL from the version file. We use our own.
+ ProfileUtils::removeLwjglFromPatch(file);
// TODO: recognize and add LWJGL versions here.
@@ -523,7 +552,7 @@ void MinecraftVersionList::saveCachedList()
entriesArr.append(entryObj);
}
toplevel.insert("versions", entriesArr);
-
+
{
bool someLatest = false;
QJsonObject latestObj;
@@ -542,7 +571,7 @@ void MinecraftVersionList::saveCachedList()
toplevel.insert("latest", latestObj);
}
}
-
+
QJsonDocument doc(toplevel);
QByteArray jsonData = doc.toBinaryData();
qint64 result = tfile.write(jsonData);
@@ -593,3 +622,5 @@ void MinecraftVersionList::finalizeUpdate(QString version)
saveCachedList();
}
+
+#include "MinecraftVersionList.moc" \ No newline at end of file
diff --git a/logic/minecraft/MinecraftVersionList.h b/logic/minecraft/MinecraftVersionList.h
index 17708444..be9f8581 100644
--- a/logic/minecraft/MinecraftVersionList.h
+++ b/logic/minecraft/MinecraftVersionList.h
@@ -26,7 +26,6 @@
class MCVListLoadTask;
class MCVListVersionUpdateTask;
-class QNetworkReply;
class MinecraftVersionList : public BaseVersionList
{
@@ -67,42 +66,3 @@ protected
slots:
virtual void updateListData(QList<BaseVersionPtr> versions);
};
-
-class MCVListLoadTask : public Task
-{
- Q_OBJECT
-
-public:
- explicit MCVListLoadTask(MinecraftVersionList *vlist);
- virtual ~MCVListLoadTask() override{};
-
- virtual void executeTask() override;
-
-protected
-slots:
- void list_downloaded();
-
-protected:
- QNetworkReply *vlistReply;
- MinecraftVersionList *m_list;
- MinecraftVersion *m_currentStable;
-};
-
-class MCVListVersionUpdateTask : public Task
-{
- Q_OBJECT
-
-public:
- explicit MCVListVersionUpdateTask(MinecraftVersionList *vlist, QString updatedVersion);
- virtual ~MCVListVersionUpdateTask() override{};
- virtual void executeTask() override;
-
-protected
-slots:
- void json_downloaded();
-
-protected:
- NetJobPtr specificVersionDownloadJob;
- QString versionToUpdate;
- MinecraftVersionList *m_list;
-};
diff --git a/logic/minecraft/NullProfileStrategy.h b/logic/minecraft/NullProfileStrategy.h
new file mode 100644
index 00000000..eaabd3c7
--- /dev/null
+++ b/logic/minecraft/NullProfileStrategy.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "ProfileStrategy.h"
+
+class NullProfileStrategy: public ProfileStrategy
+{
+ virtual bool installJarMods(QStringList filepaths)
+ {
+ return false;
+ }
+ virtual void load() {};
+ virtual bool removePatch(ProfilePatchPtr jarMod)
+ {
+ return false;
+ }
+ virtual bool resetOrder()
+ {
+ return false;
+ }
+ virtual bool saveOrder(ProfileUtils::PatchOrder order)
+ {
+ return false;
+ }
+}; \ No newline at end of file
diff --git a/logic/minecraft/OneSixLibrary.cpp b/logic/minecraft/OneSixLibrary.cpp
index 67257a55..43d381fb 100644
--- a/logic/minecraft/OneSixLibrary.cpp
+++ b/logic/minecraft/OneSixLibrary.cpp
@@ -18,10 +18,6 @@
#include "OneSixLibrary.h"
#include "OneSixRule.h"
#include "OpSys.h"
-#include "logic/net/URLConstants.h"
-#include <pathutils.h>
-#include <JlCompress.h>
-#include "logger/QsLog.h"
OneSixLibrary::OneSixLibrary(RawLibraryPtr base)
{
diff --git a/logic/minecraft/OneSixProfileStrategy.cpp b/logic/minecraft/OneSixProfileStrategy.cpp
new file mode 100644
index 00000000..bdb2f8ee
--- /dev/null
+++ b/logic/minecraft/OneSixProfileStrategy.cpp
@@ -0,0 +1,270 @@
+#include "logic/minecraft/OneSixProfileStrategy.h"
+#include "logic/minecraft/VersionBuildError.h"
+#include "logic/OneSixInstance.h"
+#include "logic/minecraft/MinecraftVersionList.h"
+
+#include "MultiMC.h"
+
+#include <pathutils.h>
+#include <QDir>
+#include <QUuid>
+#include <QJsonDocument>
+#include <QJsonArray>
+
+OneSixProfileStrategy::OneSixProfileStrategy(OneSixInstance* instance)
+{
+ m_instance = instance;
+}
+
+void OneSixProfileStrategy::upgradeDeprecatedFiles()
+{
+ auto versionJsonPath = PathCombine(m_instance->instanceRoot(), "version.json");
+ auto customJsonPath = PathCombine(m_instance->instanceRoot(), "custom.json");
+ auto mcJson = PathCombine(m_instance->instanceRoot(), "patches" , "net.minecraft.json");
+
+ // convert old crap.
+ if(QFile::exists(customJsonPath))
+ {
+ if(!ensureFilePathExists(mcJson))
+ {
+ // WHAT DO???
+ }
+ if(!QFile::rename(customJsonPath, mcJson))
+ {
+ // WHAT DO???
+ }
+ if(QFile::exists(versionJsonPath))
+ {
+ if(!QFile::remove(versionJsonPath))
+ {
+ // WHAT DO???
+ }
+ }
+ }
+ else if(QFile::exists(versionJsonPath))
+ {
+ if(!ensureFilePathExists(mcJson))
+ {
+ // WHAT DO???
+ }
+ if(!QFile::rename(versionJsonPath, mcJson))
+ {
+ // WHAT DO???
+ }
+ }
+}
+
+
+void OneSixProfileStrategy::loadDefaultBuiltinPatches()
+{
+ auto mcJson = PathCombine(m_instance->instanceRoot(), "patches" , "net.minecraft.json");
+ // load up the base minecraft patch
+ ProfilePatchPtr minecraftPatch;
+ if(QFile::exists(mcJson))
+ {
+ auto file = ProfileUtils::parseJsonFile(QFileInfo(mcJson), false);
+ file->fileId = "net.minecraft";
+ file->name = "Minecraft";
+ if(file->version.isEmpty())
+ {
+ file->version = m_instance->intendedVersionId();
+ }
+ minecraftPatch = std::dynamic_pointer_cast<ProfilePatch>(file);
+ }
+ else
+ {
+ auto minecraftList = MMC->minecraftlist();
+ auto mcversion = minecraftList->findVersion(m_instance->intendedVersionId());
+ minecraftPatch = std::dynamic_pointer_cast<ProfilePatch>(mcversion);
+ }
+ if (!minecraftPatch)
+ {
+ throw VersionIncomplete("net.minecraft");
+ }
+ minecraftPatch->setOrder(-2);
+ profile->appendPatch(minecraftPatch);
+
+
+ // TODO: this is obviously fake.
+ QResource LWJGL(":/versions/LWJGL/2.9.1.json");
+ auto lwjgl = ProfileUtils::parseJsonFile(LWJGL.absoluteFilePath(), false, false);
+ auto lwjglPatch = std::dynamic_pointer_cast<ProfilePatch>(lwjgl);
+ if (!lwjglPatch)
+ {
+ throw VersionIncomplete("org.lwjgl");
+ }
+ lwjglPatch->setOrder(-1);
+ lwjgl->setVanilla(true);
+ profile->appendPatch(lwjglPatch);
+}
+
+void OneSixProfileStrategy::loadUserPatches()
+{
+ // load all patches, put into map for ordering, apply in the right order
+ ProfileUtils::PatchOrder userOrder;
+ ProfileUtils::readOverrideOrders(PathCombine(m_instance->instanceRoot(), "order.json"), userOrder);
+ QDir patches(PathCombine(m_instance->instanceRoot(),"patches"));
+
+ // first, load things by sort order.
+ for (auto id : userOrder)
+ {
+ // ignore builtins
+ if (id == "net.minecraft")
+ continue;
+ if (id == "org.lwjgl")
+ continue;
+ // parse the file
+ QString filename = patches.absoluteFilePath(id + ".json");
+ QFileInfo finfo(filename);
+ if(!finfo.exists())
+ {
+ QLOG_INFO() << "Patch file " << filename << " was deleted by external means...";
+ continue;
+ }
+ QLOG_INFO() << "Reading" << filename << "by user order";
+ auto file = ProfileUtils::parseJsonFile(finfo, false);
+ // sanity check. prevent tampering with files.
+ if (file->fileId != id)
+ {
+ throw VersionBuildError(
+ QObject::tr("load id %1 does not match internal id %2").arg(id, file->fileId));
+ }
+ profile->appendPatch(file);
+ }
+ // now load the rest by internal preference.
+ QMap<int, QPair<QString, VersionFilePtr>> files;
+ for (auto info : patches.entryInfoList(QStringList() << "*.json", QDir::Files))
+ {
+ // parse the file
+ QLOG_INFO() << "Reading" << info.fileName();
+ auto file = ProfileUtils::parseJsonFile(info, true);
+ // ignore builtins
+ if (file->fileId == "net.minecraft")
+ continue;
+ if (file->fileId == "org.lwjgl")
+ continue;
+ // do not load what we already loaded in the first pass
+ if (userOrder.contains(file->fileId))
+ continue;
+ if (files.contains(file->order))
+ {
+ // FIXME: do not throw?
+ throw VersionBuildError(QObject::tr("%1 has the same order as %2")
+ .arg(file->fileId, files[file->order].second->fileId));
+ }
+ files.insert(file->order, qMakePair(info.fileName(), file));
+ }
+ for (auto order : files.keys())
+ {
+ auto &filePair = files[order];
+ profile->appendPatch(filePair.second);
+ }
+}
+
+
+void OneSixProfileStrategy::load()
+{
+ profile->clearPatches();
+
+ upgradeDeprecatedFiles();
+ loadDefaultBuiltinPatches();
+ loadUserPatches();
+
+ profile->finalize();
+}
+
+bool OneSixProfileStrategy::saveOrder(ProfileUtils::PatchOrder order)
+{
+ return ProfileUtils::writeOverrideOrders(PathCombine(m_instance->instanceRoot(), "order.json"), order);
+}
+
+bool OneSixProfileStrategy::resetOrder()
+{
+ return QDir(m_instance->instanceRoot()).remove("order.json");
+}
+
+bool OneSixProfileStrategy::removePatch(ProfilePatchPtr patch)
+{
+ bool ok = true;
+ // first, remove the patch file. this ensures it's not used anymore
+ auto fileName = patch->getPatchFilename();
+
+
+ auto preRemoveJarMod = [&](JarmodPtr jarMod) -> bool
+ {
+ QString fullpath = PathCombine(m_instance->jarModsDir(), jarMod->name);
+ QFileInfo finfo (fullpath);
+ if(finfo.exists())
+ {
+ return QFile::remove(fullpath);
+ }
+ return true;
+ };
+
+ for(auto &jarmod: patch->getJarMods())
+ {
+ ok &= preRemoveJarMod(jarmod);
+ }
+ return ok;
+}
+
+bool OneSixProfileStrategy::installJarMods(QStringList filepaths)
+{
+ QString patchDir = PathCombine(m_instance->instanceRoot(), "patches");
+ if(!ensureFolderPathExists(patchDir))
+ {
+ return false;
+ }
+
+ if (!ensureFolderPathExists(m_instance->jarModsDir()))
+ {
+ return false;
+ }
+
+ for(auto filepath:filepaths)
+ {
+ QFileInfo sourceInfo(filepath);
+ auto uuid = QUuid::createUuid();
+ QString id = uuid.toString().remove('{').remove('}');
+ QString target_filename = id + ".jar";
+ QString target_id = "org.multimc.jarmod." + id;
+ QString target_name = sourceInfo.completeBaseName() + " (jar mod)";
+ QString finalPath = PathCombine(m_instance->jarModsDir(), target_filename);
+
+ QFileInfo targetInfo(finalPath);
+ if(targetInfo.exists())
+ {
+ return false;
+ }
+
+ if (!QFile::copy(sourceInfo.absoluteFilePath(),QFileInfo(finalPath).absoluteFilePath()))
+ {
+ return false;
+ }
+
+ auto f = std::make_shared<VersionFile>();
+ auto jarMod = std::make_shared<Jarmod>();
+ jarMod->name = target_filename;
+ f->jarMods.append(jarMod);
+ f->name = target_name;
+ f->fileId = target_id;
+ f->order = profile->getFreeOrderNumber();
+ QString patchFileName = PathCombine(patchDir, target_id + ".json");
+ f->filename = patchFileName;
+
+ QFile file(patchFileName);
+ if (!file.open(QFile::WriteOnly))
+ {
+ QLOG_ERROR() << "Error opening" << file.fileName()
+ << "for reading:" << file.errorString();
+ return false;
+ }
+ file.write(f->toJson(true).toJson());
+ file.close();
+ profile->appendPatch(f);
+ }
+ profile->saveCurrentOrder();
+ profile->reapply();
+ return true;
+}
+
diff --git a/logic/minecraft/OneSixProfileStrategy.h b/logic/minecraft/OneSixProfileStrategy.h
new file mode 100644
index 00000000..b554b1ea
--- /dev/null
+++ b/logic/minecraft/OneSixProfileStrategy.h
@@ -0,0 +1,24 @@
+#pragma once
+#include "ProfileStrategy.h"
+
+class OneSixInstance;
+
+class OneSixProfileStrategy : public ProfileStrategy
+{
+public:
+ OneSixProfileStrategy(OneSixInstance * instance);
+ virtual ~OneSixProfileStrategy() {};
+ virtual void load() override;
+ virtual bool resetOrder() override;
+ virtual bool saveOrder(ProfileUtils::PatchOrder order) override;
+ virtual bool installJarMods(QStringList filepaths) override;
+ virtual bool removePatch(ProfilePatchPtr patch) override;
+
+protected:
+ void loadDefaultBuiltinPatches();
+ void loadUserPatches();
+ void upgradeDeprecatedFiles();
+
+protected:
+ OneSixInstance *m_instance;
+}; \ No newline at end of file
diff --git a/logic/minecraft/VersionPatch.h b/logic/minecraft/ProfilePatch.h
index 6c7bd7cf..2e97677e 100644
--- a/logic/minecraft/VersionPatch.h
+++ b/logic/minecraft/ProfilePatch.h
@@ -4,24 +4,24 @@
#include <QList>
#include "JarMod.h"
-class InstanceVersion;
-class VersionPatch
+class MinecraftProfile;
+class ProfilePatch
{
public:
- virtual ~VersionPatch(){};
- virtual void applyTo(InstanceVersion *version) = 0;
-
+ virtual ~ProfilePatch(){};
+ virtual void applyTo(MinecraftProfile *version) = 0;
+
virtual bool isMinecraftVersion() = 0;
virtual bool hasJarMods() = 0;
virtual QList<JarmodPtr> getJarMods() = 0;
-
+
virtual bool isMoveable()
{
return getOrder() >= 0;
}
virtual void setOrder(int order) = 0;
virtual int getOrder() = 0;
-
+
virtual QString getPatchID() = 0;
virtual QString getPatchName() = 0;
virtual QString getPatchVersion() = 0;
@@ -29,4 +29,4 @@ public:
virtual bool isCustom() = 0;
};
-typedef std::shared_ptr<VersionPatch> VersionPatchPtr;
+typedef std::shared_ptr<ProfilePatch> ProfilePatchPtr;
diff --git a/logic/minecraft/ProfileStrategy.h b/logic/minecraft/ProfileStrategy.h
new file mode 100644
index 00000000..364458f5
--- /dev/null
+++ b/logic/minecraft/ProfileStrategy.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include "ProfileUtils.h"
+
+class MinecraftProfile;
+
+class ProfileStrategy
+{
+ friend class MinecraftProfile;
+public:
+ virtual ~ProfileStrategy(){};
+
+ /// load the patch files into the profile
+ virtual void load() = 0;
+
+ /// reset the order of patches
+ virtual bool resetOrder() = 0;
+
+ /// save the order of patches, given the order
+ virtual bool saveOrder(ProfileUtils::PatchOrder order) = 0;
+
+ /// install a list of jar mods into the instance
+ virtual bool installJarMods(QStringList filepaths) = 0;
+
+ /// remove any files or records that constitute the version patch
+ virtual bool removePatch(ProfilePatchPtr jarMod) = 0;
+
+protected:
+ MinecraftProfile *profile;
+};
diff --git a/logic/minecraft/ProfileUtils.cpp b/logic/minecraft/ProfileUtils.cpp
new file mode 100644
index 00000000..48e73472
--- /dev/null
+++ b/logic/minecraft/ProfileUtils.cpp
@@ -0,0 +1,145 @@
+#include "ProfileUtils.h"
+#include "logic/minecraft/VersionFilterData.h"
+#include "logic/MMCJson.h"
+#include "logger/QsLog.h"
+
+#include <QJsonDocument>
+#include <QJsonArray>
+#include <QRegularExpression>
+
+namespace ProfileUtils
+{
+
+static const int currentOrderFileVersion = 1;
+
+bool writeOverrideOrders(QString path, const PatchOrder &order)
+{
+ QJsonObject obj;
+ obj.insert("version", currentOrderFileVersion);
+ QJsonArray orderArray;
+ for(auto str: order)
+ {
+ orderArray.append(str);
+ }
+ obj.insert("order", orderArray);
+ QFile orderFile(path);
+ if (!orderFile.open(QFile::WriteOnly))
+ {
+ QLOG_ERROR() << "Couldn't open" << orderFile.fileName()
+ << "for writing:" << orderFile.errorString();
+ return false;
+ }
+ orderFile.write(QJsonDocument(obj).toJson(QJsonDocument::Indented));
+ return true;
+}
+
+bool readOverrideOrders(QString path, PatchOrder &order)
+{
+ QFile orderFile(path);
+ if (!orderFile.exists())
+ {
+ QLOG_WARN() << "Order file doesn't exist. Ignoring.";
+ return false;
+ }
+ if (!orderFile.open(QFile::ReadOnly))
+ {
+ QLOG_ERROR() << "Couldn't open" << orderFile.fileName()
+ << " for reading:" << orderFile.errorString();
+ QLOG_WARN() << "Ignoring overriden order";
+ return false;
+ }
+
+ // and it's valid JSON
+ QJsonParseError error;
+ QJsonDocument doc = QJsonDocument::fromJson(orderFile.readAll(), &error);
+ if (error.error != QJsonParseError::NoError)
+ {
+ QLOG_ERROR() << "Couldn't parse" << orderFile.fileName() << ":" << error.errorString();
+ QLOG_WARN() << "Ignoring overriden order";
+ return false;
+ }
+
+ // and then read it and process it if all above is true.
+ try
+ {
+ auto obj = MMCJson::ensureObject(doc);
+ // check order file version.
+ auto version = MMCJson::ensureInteger(obj.value("version"), "version");
+ if (version != currentOrderFileVersion)
+ {
+ throw JSONValidationError(QObject::tr("Invalid order file version, expected %1")
+ .arg(currentOrderFileVersion));
+ }
+ auto orderArray = MMCJson::ensureArray(obj.value("order"));
+ for(auto item: orderArray)
+ {
+ order.append(MMCJson::ensureString(item));
+ }
+ }
+ catch (JSONValidationError &err)
+ {
+ QLOG_ERROR() << "Couldn't parse" << orderFile.fileName() << ": bad file format";
+ QLOG_WARN() << "Ignoring overriden order";
+ order.clear();
+ return false;
+ }
+ return true;
+}
+
+VersionFilePtr parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder, bool isFTB)
+{
+ QFile file(fileInfo.absoluteFilePath());
+ if (!file.open(QFile::ReadOnly))
+ {
+ throw JSONValidationError(QObject::tr("Unable to open the version file %1: %2.")
+ .arg(fileInfo.fileName(), file.errorString()));
+ }
+ QJsonParseError error;
+ QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &error);
+ if (error.error != QJsonParseError::NoError)
+ {
+ throw JSONValidationError(
+ QObject::tr("Unable to process the version file %1: %2 at %3.")
+ .arg(fileInfo.fileName(), error.errorString())
+ .arg(error.offset));
+ }
+ return VersionFile::fromJson(doc, file.fileName(), requireOrder, isFTB);
+}
+
+VersionFilePtr parseBinaryJsonFile(const QFileInfo &fileInfo)
+{
+ QFile file(fileInfo.absoluteFilePath());
+ if (!file.open(QFile::ReadOnly))
+ {
+ throw JSONValidationError(QObject::tr("Unable to open the version file %1: %2.")
+ .arg(fileInfo.fileName(), file.errorString()));
+ }
+ QJsonDocument doc = QJsonDocument::fromBinaryData(file.readAll());
+ file.close();
+ if (doc.isNull())
+ {
+ file.remove();
+ throw JSONValidationError(
+ QObject::tr("Unable to process the version file %1.").arg(fileInfo.fileName()));
+ }
+ return VersionFile::fromJson(doc, file.fileName(), false, false);
+}
+
+void removeLwjglFromPatch(VersionFilePtr patch)
+{
+ auto filter = [](QList<RawLibraryPtr>& libs)
+ {
+ QList<RawLibraryPtr> filteredLibs;
+ for (auto lib : libs)
+ {
+ if (!g_VersionFilterData.lwjglWhitelist.contains(lib->artifactPrefix()))
+ {
+ filteredLibs.append(lib);
+ }
+ }
+ libs = filteredLibs;
+ };
+ filter(patch->addLibs);
+ filter(patch->overwriteLibs);
+}
+}
diff --git a/logic/minecraft/ProfileUtils.h b/logic/minecraft/ProfileUtils.h
new file mode 100644
index 00000000..88027374
--- /dev/null
+++ b/logic/minecraft/ProfileUtils.h
@@ -0,0 +1,25 @@
+#pragma once
+#include "RawLibrary.h"
+#include "VersionFile.h"
+
+namespace ProfileUtils
+{
+typedef QStringList PatchOrder;
+
+/// Read and parse a OneSix format order file
+bool readOverrideOrders(QString path, PatchOrder &order);
+
+/// Write a OneSix format order file
+bool writeOverrideOrders(QString path, const PatchOrder &order);
+
+
+/// Parse a version file in JSON format
+VersionFilePtr parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder, bool isFTB = false);
+
+/// Parse a version file in binary JSON format
+VersionFilePtr parseBinaryJsonFile(const QFileInfo &fileInfo);
+
+/// Remove LWJGL from a patch file. This is applied to all Mojang-like profile files.
+void removeLwjglFromPatch(VersionFilePtr patch);
+
+}
diff --git a/logic/minecraft/VersionBuilder.cpp b/logic/minecraft/VersionBuilder.cpp
index b1622b58..7f77b493 100644
--- a/logic/minecraft/VersionBuilder.cpp
+++ b/logic/minecraft/VersionBuilder.cpp
@@ -24,15 +24,17 @@
#include <QDir>
#include <qresource.h>
#include <modutils.h>
+#include <pathutils.h>
#include "MultiMC.h"
#include "logic/minecraft/VersionBuilder.h"
-#include "logic/minecraft/InstanceVersion.h"
+#include "logic/minecraft/MinecraftProfile.h"
#include "logic/minecraft/OneSixRule.h"
-#include "logic/minecraft/VersionPatch.h"
+#include "logic/minecraft/ProfilePatch.h"
#include "logic/minecraft/VersionFile.h"
#include "VersionBuildError.h"
#include "MinecraftVersionList.h"
+#include "ProfileUtils.h"
#include "logic/OneSixInstance.h"
#include "logic/MMCJson.h"
@@ -43,17 +45,15 @@ VersionBuilder::VersionBuilder()
{
}
-void VersionBuilder::build(InstanceVersion *version, OneSixInstance *instance,
- const QStringList &external)
+void VersionBuilder::build(MinecraftProfile *version, OneSixInstance *instance)
{
VersionBuilder builder;
builder.m_version = version;
builder.m_instance = instance;
- builder.external_patches = external;
builder.buildInternal();
}
-void VersionBuilder::readJsonAndApplyToVersion(InstanceVersion *version, const QJsonObject &obj)
+void VersionBuilder::readJsonAndApplyToVersion(MinecraftProfile *version, const QJsonObject &obj)
{
VersionBuilder builder;
builder.m_version = version;
@@ -61,178 +61,6 @@ void VersionBuilder::readJsonAndApplyToVersion(InstanceVersion *version, const Q
builder.readJsonAndApply(obj);
}
-void VersionBuilder::buildFromCustomJson()
-{
- QLOG_INFO() << "Building version from custom.json within the instance.";
- QLOG_INFO() << "Reading custom.json";
- auto file = parseJsonFile(QFileInfo(instance_root.absoluteFilePath("custom.json")), false);
- file->name = "custom.json";
- file->filename = "custom.json";
- file->fileId = "org.multimc.custom.json";
- file->order = -1;
- file->version = QString();
- m_version->VersionPatches.append(file);
- m_version->finalize();
- return;
-}
-
-void VersionBuilder::buildFromVersionJson()
-{
- QLOG_INFO() << "Building version from version.json and patches within the instance.";
- QLOG_INFO() << "Reading version.json";
- auto file = parseJsonFile(QFileInfo(instance_root.absoluteFilePath("version.json")), false);
- file->name = "Minecraft";
- file->fileId = "org.multimc.version.json";
- file->order = -1;
- file->version = m_instance->intendedVersionId();
- file->mcVersion = m_instance->intendedVersionId();
- m_version->VersionPatches.append(file);
-
- // load all patches, put into map for ordering, apply in the right order
- readInstancePatches();
-
- // some final touches
- m_version->finalize();
-}
-
-void VersionBuilder::readInstancePatches()
-{
- PatchOrder userOrder;
- readOverrideOrders(m_instance, userOrder);
- QDir patches(instance_root.absoluteFilePath("patches/"));
-
- // first, load things by sort order.
- for (auto id : userOrder)
- {
- // ignore builtins
- if (id == "net.minecraft")
- continue;
- if (id == "org.lwjgl")
- continue;
- // parse the file
- QString filename = patches.absoluteFilePath(id + ".json");
- QFileInfo finfo(filename);
- if(!finfo.exists())
- {
- QLOG_INFO() << "Patch file " << filename << " was deleted by external means...";
- continue;
- }
- QLOG_INFO() << "Reading" << filename << "by user order";
- auto file = parseJsonFile(finfo, false);
- // sanity check. prevent tampering with files.
- if (file->fileId != id)
- {
- throw VersionBuildError(
- QObject::tr("load id %1 does not match internal id %2").arg(id, file->fileId));
- }
- m_version->VersionPatches.append(file);
- }
- // now load the rest by internal preference.
- QMap<int, QPair<QString, VersionFilePtr>> files;
- for (auto info : patches.entryInfoList(QStringList() << "*.json", QDir::Files))
- {
- // parse the file
- QLOG_INFO() << "Reading" << info.fileName();
- auto file = parseJsonFile(info, true);
- // ignore builtins
- if (file->fileId == "net.minecraft")
- continue;
- if (file->fileId == "org.lwjgl")
- continue;
- // do not load what we already loaded in the first pass
- if (userOrder.contains(file->fileId))
- continue;
- if (files.contains(file->order))
- {
- // FIXME: do not throw?
- throw VersionBuildError(QObject::tr("%1 has the same order as %2")
- .arg(file->fileId, files[file->order].second->fileId));
- }
- files.insert(file->order, qMakePair(info.fileName(), file));
- }
- for (auto order : files.keys())
- {
- auto &filePair = files[order];
- m_version->VersionPatches.append(filePair.second);
- }
-}
-
-void VersionBuilder::buildFromExternalPatches()
-{
- QLOG_INFO() << "Building version from external files.";
- int externalOrder = -1;
- for (auto fileName : external_patches)
- {
- QLOG_INFO() << "Reading" << fileName;
- auto file = parseJsonFile(QFileInfo(fileName), false, fileName.endsWith("pack.json"));
- file->name = QFileInfo(fileName).fileName();
- file->fileId = "org.multimc.external." + file->name;
- file->order = (externalOrder += 1);
- file->version = QString();
- file->mcVersion = QString();
- m_version->VersionPatches.append(file);
- }
- // some final touches
- m_version->finalize();
-}
-
-void VersionBuilder::buildFromMultilayer()
-{
- QLOG_INFO() << "Building version from multilayered sources.";
- // just the builtin stuff for now
- auto minecraftList = MMC->minecraftlist();
- auto mcversion = minecraftList->findVersion(m_instance->intendedVersionId());
- auto minecraftPatch = std::dynamic_pointer_cast<VersionPatch>(mcversion);
- if (!minecraftPatch)
- {
- throw VersionIncomplete("net.minecraft");
- }
- minecraftPatch->setOrder(-2);
- m_version->VersionPatches.append(minecraftPatch);
-
- // TODO: this is obviously fake.
- QResource LWJGL(":/versions/LWJGL/2.9.1.json");
- auto lwjgl = parseJsonFile(LWJGL.absoluteFilePath(), false, false);
- auto lwjglPatch = std::dynamic_pointer_cast<VersionPatch>(lwjgl);
- if (!lwjglPatch)
- {
- throw VersionIncomplete("org.lwjgl");
- }
- lwjglPatch->setOrder(-1);
- lwjgl->setVanilla(true);
- m_version->VersionPatches.append(lwjglPatch);
-
- // load all patches, put into map for ordering, apply in the right order
- readInstancePatches();
-
- m_version->finalize();
-}
-
-void VersionBuilder::buildInternal()
-{
- m_version->VersionPatches.clear();
- instance_root = QDir(m_instance->instanceRoot());
- // if we do external files, do just those.
- if (!external_patches.isEmpty())
- {
- buildFromExternalPatches();
- }
- // else, if there's custom json, we just do that.
- else if (QFile::exists(instance_root.absoluteFilePath("custom.json")))
- {
- buildFromCustomJson();
- }
- // version.json -> patches/*.json
- else if (QFile::exists(instance_root.absoluteFilePath("version.json")))
- {
- buildFromVersionJson();
- }
- else
- {
- buildFromMultilayer();
- }
-}
-
void VersionBuilder::readJsonAndApply(const QJsonObject &obj)
{
m_version->clear();
@@ -240,121 +68,17 @@ void VersionBuilder::readJsonAndApply(const QJsonObject &obj)
auto file = VersionFile::fromJson(QJsonDocument(obj), QString(), false);
file->applyTo(m_version);
- m_version->VersionPatches.append(file);
+ m_version->appendPatch(file);
}
-VersionFilePtr VersionBuilder::parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder,
- bool isFTB)
-{
- QFile file(fileInfo.absoluteFilePath());
- if (!file.open(QFile::ReadOnly))
- {
- throw JSONValidationError(QObject::tr("Unable to open the version file %1: %2.")
- .arg(fileInfo.fileName(), file.errorString()));
- }
- QJsonParseError error;
- QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &error);
- if (error.error != QJsonParseError::NoError)
- {
- throw JSONValidationError(
- QObject::tr("Unable to process the version file %1: %2 at %3.")
- .arg(fileInfo.fileName(), error.errorString())
- .arg(error.offset));
- }
- return VersionFile::fromJson(doc, file.fileName(), requireOrder, isFTB);
-}
-VersionFilePtr VersionBuilder::parseBinaryJsonFile(const QFileInfo &fileInfo)
+void VersionBuilder::readInstancePatches()
{
- QFile file(fileInfo.absoluteFilePath());
- if (!file.open(QFile::ReadOnly))
- {
- throw JSONValidationError(QObject::tr("Unable to open the version file %1: %2.")
- .arg(fileInfo.fileName(), file.errorString()));
- }
- QJsonDocument doc = QJsonDocument::fromBinaryData(file.readAll());
- file.close();
- if (doc.isNull())
- {
- file.remove();
- throw JSONValidationError(
- QObject::tr("Unable to process the version file %1.").arg(fileInfo.fileName()));
- }
- return VersionFile::fromJson(doc, file.fileName(), false, false);
-}
-static const int currentOrderFileVersion = 1;
+}
-bool VersionBuilder::readOverrideOrders(OneSixInstance *instance, PatchOrder &order)
+void VersionBuilder::buildInternal()
{
- QFile orderFile(instance->instanceRoot() + "/order.json");
- if (!orderFile.exists())
- {
- QLOG_WARN() << "Order file doesn't exist. Ignoring.";
- return false;
- }
- if (!orderFile.open(QFile::ReadOnly))
- {
- QLOG_ERROR() << "Couldn't open" << orderFile.fileName()
- << " for reading:" << orderFile.errorString();
- QLOG_WARN() << "Ignoring overriden order";
- return false;
- }
-
- // and it's valid JSON
- QJsonParseError error;
- QJsonDocument doc = QJsonDocument::fromJson(orderFile.readAll(), &error);
- if (error.error != QJsonParseError::NoError)
- {
- QLOG_ERROR() << "Couldn't parse" << orderFile.fileName() << ":" << error.errorString();
- QLOG_WARN() << "Ignoring overriden order";
- return false;
- }
- // and then read it and process it if all above is true.
- try
- {
- auto obj = MMCJson::ensureObject(doc);
- // check order file version.
- auto version = MMCJson::ensureInteger(obj.value("version"), "version");
- if (version != currentOrderFileVersion)
- {
- throw JSONValidationError(QObject::tr("Invalid order file version, expected %1")
- .arg(currentOrderFileVersion));
- }
- auto orderArray = MMCJson::ensureArray(obj.value("order"));
- for(auto item: orderArray)
- {
- order.append(MMCJson::ensureString(item));
- }
- }
- catch (JSONValidationError &err)
- {
- QLOG_ERROR() << "Couldn't parse" << orderFile.fileName() << ": bad file format";
- QLOG_WARN() << "Ignoring overriden order";
- order.clear();
- return false;
- }
- return true;
}
-bool VersionBuilder::writeOverrideOrders(OneSixInstance *instance, const PatchOrder &order)
-{
- QJsonObject obj;
- obj.insert("version", currentOrderFileVersion);
- QJsonArray orderArray;
- for(auto str: order)
- {
- orderArray.append(str);
- }
- obj.insert("order", orderArray);
- QFile orderFile(instance->instanceRoot() + "/order.json");
- if (!orderFile.open(QFile::WriteOnly))
- {
- QLOG_ERROR() << "Couldn't open" << orderFile.fileName()
- << "for writing:" << orderFile.errorString();
- return false;
- }
- orderFile.write(QJsonDocument(obj).toJson(QJsonDocument::Indented));
- return true;
-}
diff --git a/logic/minecraft/VersionBuilder.h b/logic/minecraft/VersionBuilder.h
index 2f7e6b6b..b2d23da5 100644
--- a/logic/minecraft/VersionBuilder.h
+++ b/logic/minecraft/VersionBuilder.h
@@ -19,38 +19,25 @@
#include <QMap>
#include "VersionFile.h"
-class InstanceVersion;
+class MinecraftProfile;
class OneSixInstance;
class QJsonObject;
class QFileInfo;
-typedef QStringList PatchOrder;
-
class VersionBuilder
{
VersionBuilder();
public:
- static void build(InstanceVersion *version, OneSixInstance *instance, const QStringList &external);
- static void readJsonAndApplyToVersion(InstanceVersion *version, const QJsonObject &obj);
- static VersionFilePtr parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder, bool isFTB = false);
- static VersionFilePtr parseBinaryJsonFile(const QFileInfo &fileInfo);
-
- bool readOverrideOrders(OneSixInstance *instance, PatchOrder &order);
- static bool writeOverrideOrders(OneSixInstance *instance, const PatchOrder &order);
+ static void build(MinecraftProfile *version, OneSixInstance *instance);
+ static void readJsonAndApplyToVersion(MinecraftProfile *version, const QJsonObject &obj);
private:
- InstanceVersion *m_version;
+ MinecraftProfile *m_version;
OneSixInstance *m_instance;
- QStringList external_patches;
- QDir instance_root;
-
+
void buildInternal();
- void buildFromExternalPatches();
- void buildFromCustomJson();
- void buildFromVersionJson();
- void buildFromMultilayer();
-
+
void readInstancePatches();
-
+
void readJsonAndApply(const QJsonObject &obj);
};
diff --git a/logic/minecraft/VersionFile.cpp b/logic/minecraft/VersionFile.cpp
index 3e0648cc..97ce6535 100644
--- a/logic/minecraft/VersionFile.cpp
+++ b/logic/minecraft/VersionFile.cpp
@@ -6,7 +6,7 @@
#include "logic/minecraft/VersionFile.h"
#include "logic/minecraft/OneSixLibrary.h"
-#include "logic/minecraft/InstanceVersion.h"
+#include "logic/minecraft/MinecraftProfile.h"
#include "logic/minecraft/JarMod.h"
#include "ParseUtils.h"
@@ -256,8 +256,7 @@ QJsonDocument VersionFile::toJson(bool saveOrder)
bool VersionFile::isMinecraftVersion()
{
- return (fileId == "org.multimc.version.json") || (fileId == "net.minecraft") ||
- (fileId == "org.multimc.custom.json");
+ return fileId == "net.minecraft";
}
bool VersionFile::hasJarMods()
@@ -265,7 +264,7 @@ bool VersionFile::hasJarMods()
return !jarMods.isEmpty();
}
-void VersionFile::applyTo(InstanceVersion *version)
+void VersionFile::applyTo(MinecraftProfile *version)
{
if (minimumLauncherVersion != -1)
{
diff --git a/logic/minecraft/VersionFile.h b/logic/minecraft/VersionFile.h
index 96856891..ddc3f849 100644
--- a/logic/minecraft/VersionFile.h
+++ b/logic/minecraft/VersionFile.h
@@ -6,23 +6,23 @@
#include <memory>
#include "logic/minecraft/OpSys.h"
#include "logic/minecraft/OneSixRule.h"
-#include "VersionPatch.h"
+#include "ProfilePatch.h"
#include "MMCError.h"
#include "OneSixLibrary.h"
#include "JarMod.h"
-class InstanceVersion;
+class MinecraftProfile;
class VersionFile;
typedef std::shared_ptr<VersionFile> VersionFilePtr;
-class VersionFile : public VersionPatch
+class VersionFile : public ProfilePatch
{
public: /* methods */
static VersionFilePtr fromJson(const QJsonDocument &doc, const QString &filename,
const bool requireOrder, const bool isFTB = false);
QJsonDocument toJson(bool saveOrder);
- virtual void applyTo(InstanceVersion *version) override;
+ virtual void applyTo(MinecraftProfile *version) override;
virtual bool isMinecraftVersion() override;
virtual bool hasJarMods() override;
virtual int getOrder() override
diff --git a/logic/VersionFilterData.cpp b/logic/minecraft/VersionFilterData.cpp
index 866d4947..ef8b049e 100644
--- a/logic/VersionFilterData.cpp
+++ b/logic/minecraft/VersionFilterData.cpp
@@ -1,5 +1,5 @@
#include "VersionFilterData.h"
-#include "minecraft/ParseUtils.h"
+#include "ParseUtils.h"
VersionFilterData g_VersionFilterData = VersionFilterData();
diff --git a/logic/VersionFilterData.h b/logic/minecraft/VersionFilterData.h
index 98ecb36c..98ecb36c 100644
--- a/logic/VersionFilterData.h
+++ b/logic/minecraft/VersionFilterData.h
diff --git a/logic/net/PasteUpload.cpp b/logic/net/PasteUpload.cpp
index 5fd8d679..c7bde06e 100644
--- a/logic/net/PasteUpload.cpp
+++ b/logic/net/PasteUpload.cpp
@@ -3,8 +3,6 @@
#include "logger/QsLog.h"
#include <QJsonObject>
#include <QJsonDocument>
-#include "gui/dialogs/CustomMessageBox.h"
-#include <QDesktopServices>
PasteUpload::PasteUpload(QWidget *window, QString text) : m_window(window)
{
diff --git a/logic/tools/BaseExternalTool.cpp b/logic/tools/BaseExternalTool.cpp
index 23f154e2..04edece8 100644
--- a/logic/tools/BaseExternalTool.cpp
+++ b/logic/tools/BaseExternalTool.cpp
@@ -30,31 +30,6 @@ qint64 BaseExternalTool::pid(QProcess *process)
#endif
}
-QString BaseExternalTool::getSave() const
-{
- QDir saves(m_instance->minecraftRoot() + "/saves");
- QStringList worlds = saves.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
- QMutableListIterator<QString> it(worlds);
- while (it.hasNext())
- {
- it.next();
- if (!QDir(saves.absoluteFilePath(it.value())).exists("level.dat"))
- {
- it.remove();
- }
- }
- bool ok = true;
- const QString save = QInputDialog::getItem(
- MMC->activeWindow(), tr("MCEdit"), tr("Choose which world to open:"),
- worlds, 0, false, &ok);
- if (ok)
- {
- return saves.absoluteFilePath(save);
- }
- return QString();
-}
-
-
BaseDetachedTool::BaseDetachedTool(InstancePtr instance, QObject *parent)
: BaseExternalTool(instance, parent)
{
diff --git a/logic/tools/BaseExternalTool.h b/logic/tools/BaseExternalTool.h
index 5f112970..8b8b2790 100644
--- a/logic/tools/BaseExternalTool.h
+++ b/logic/tools/BaseExternalTool.h
@@ -5,7 +5,6 @@
class BaseInstance;
class SettingsObject;
-class MinecraftProcess;
class QProcess;
class BaseExternalTool : public QObject
@@ -19,7 +18,6 @@ protected:
InstancePtr m_instance;
qint64 pid(QProcess *process);
- QString getSave() const;
};
class BaseDetachedTool : public BaseExternalTool
diff --git a/logic/tools/BaseProfiler.cpp b/logic/tools/BaseProfiler.cpp
index 7cd1c5c7..d3c8d41e 100644
--- a/logic/tools/BaseProfiler.cpp
+++ b/logic/tools/BaseProfiler.cpp
@@ -7,7 +7,7 @@ BaseProfiler::BaseProfiler(InstancePtr instance, QObject *parent)
{
}
-void BaseProfiler::beginProfiling(MinecraftProcess *process)
+void BaseProfiler::beginProfiling(BaseProcess *process)
{
beginProfilingImpl(process);
}
diff --git a/logic/tools/BaseProfiler.h b/logic/tools/BaseProfiler.h
index dd841da4..decaa5b8 100644
--- a/logic/tools/BaseProfiler.h
+++ b/logic/tools/BaseProfiler.h
@@ -4,7 +4,7 @@
class BaseInstance;
class SettingsObject;
-class MinecraftProcess;
+class BaseProcess;
class QProcess;
class BaseProfiler : public BaseExternalTool
@@ -15,13 +15,13 @@ public:
public
slots:
- void beginProfiling(MinecraftProcess *process);
+ void beginProfiling(BaseProcess *process);
void abortProfiling();
protected:
QProcess *m_profilerProcess;
- virtual void beginProfilingImpl(MinecraftProcess *process) = 0;
+ virtual void beginProfilingImpl(BaseProcess *process) = 0;
virtual void abortProfilingImpl();
signals:
diff --git a/logic/tools/JProfiler.cpp b/logic/tools/JProfiler.cpp
index 659d80b6..7cdf0268 100644
--- a/logic/tools/JProfiler.cpp
+++ b/logic/tools/JProfiler.cpp
@@ -4,7 +4,7 @@
#include <QMessageBox>
#include "logic/settings/SettingsObject.h"
-#include "logic/MinecraftProcess.h"
+#include "logic/BaseProcess.h"
#include "logic/BaseInstance.h"
#include "MultiMC.h"
@@ -12,7 +12,7 @@ JProfiler::JProfiler(InstancePtr instance, QObject *parent) : BaseProfiler(insta
{
}
-void JProfiler::beginProfilingImpl(MinecraftProcess *process)
+void JProfiler::beginProfilingImpl(BaseProcess *process)
{
int port = MMC->settings()->get("JProfilerPort").toInt();
QProcess *profiler = new QProcess(this);
diff --git a/logic/tools/JProfiler.h b/logic/tools/JProfiler.h
index 3085511b..0763a799 100644
--- a/logic/tools/JProfiler.h
+++ b/logic/tools/JProfiler.h
@@ -9,7 +9,7 @@ public:
JProfiler(InstancePtr instance, QObject *parent = 0);
protected:
- void beginProfilingImpl(MinecraftProcess *process);
+ void beginProfilingImpl(BaseProcess *process);
};
class JProfilerFactory : public BaseProfilerFactory
diff --git a/logic/tools/JVisualVM.cpp b/logic/tools/JVisualVM.cpp
index f47294d7..312be863 100644
--- a/logic/tools/JVisualVM.cpp
+++ b/logic/tools/JVisualVM.cpp
@@ -4,7 +4,7 @@
#include <QStandardPaths>
#include "logic/settings/SettingsObject.h"
-#include "logic/MinecraftProcess.h"
+#include "logic/BaseProcess.h"
#include "logic/BaseInstance.h"
#include "MultiMC.h"
@@ -12,7 +12,7 @@ JVisualVM::JVisualVM(InstancePtr instance, QObject *parent) : BaseProfiler(insta
{
}
-void JVisualVM::beginProfilingImpl(MinecraftProcess *process)
+void JVisualVM::beginProfilingImpl(BaseProcess *process)
{
QProcess *profiler = new QProcess(this);
profiler->setArguments(QStringList() << "--openpid" << QString::number(pid(process)));
diff --git a/logic/tools/JVisualVM.h b/logic/tools/JVisualVM.h
index a646c681..2a273568 100644
--- a/logic/tools/JVisualVM.h
+++ b/logic/tools/JVisualVM.h
@@ -9,7 +9,7 @@ public:
JVisualVM(InstancePtr instance, QObject *parent = 0);
protected:
- void beginProfilingImpl(MinecraftProcess *process);
+ void beginProfilingImpl(BaseProcess *process);
};
class JVisualVMFactory : public BaseProfilerFactory
diff --git a/logic/tools/MCEditTool.cpp b/logic/tools/MCEditTool.cpp
index e44ce784..c918d5d0 100644
--- a/logic/tools/MCEditTool.cpp
+++ b/logic/tools/MCEditTool.cpp
@@ -4,9 +4,12 @@
#include <QProcess>
#include <QDesktopServices>
#include <QUrl>
+// FIXME: mixing logic and UI!!!!
+#include <QInputDialog>
#include "logic/settings/SettingsObject.h"
#include "logic/BaseInstance.h"
+#include "logic/minecraft/MinecraftInstance.h"
#include "MultiMC.h"
MCEditTool::MCEditTool(InstancePtr instance, QObject *parent)
@@ -14,6 +17,36 @@ MCEditTool::MCEditTool(InstancePtr instance, QObject *parent)
{
}
+QString MCEditTool::getSave() const
+{
+ // FIXME: mixing logic and UI!!!!
+ auto mcInstance = std::dynamic_pointer_cast<MinecraftInstance>(m_instance);
+ if(!mcInstance)
+ {
+ return QString();
+ }
+ QDir saves(mcInstance->minecraftRoot() + "/saves");
+ QStringList worlds = saves.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
+ QMutableListIterator<QString> it(worlds);
+ while (it.hasNext())
+ {
+ it.next();
+ if (!QDir(saves.absoluteFilePath(it.value())).exists("level.dat"))
+ {
+ it.remove();
+ }
+ }
+ bool ok = true;
+ const QString save = QInputDialog::getItem(
+ MMC->activeWindow(), tr("MCEdit"), tr("Choose which world to open:"),
+ worlds, 0, false, &ok);
+ if (ok)
+ {
+ return saves.absoluteFilePath(save);
+ }
+ return QString();
+}
+
void MCEditTool::runImpl()
{
const QString mceditPath = MMC->settings()->get("MCEditPath").toString();
diff --git a/logic/tools/MCEditTool.h b/logic/tools/MCEditTool.h
index 810caf25..b5cfc64e 100644
--- a/logic/tools/MCEditTool.h
+++ b/logic/tools/MCEditTool.h
@@ -9,6 +9,7 @@ public:
explicit MCEditTool(InstancePtr instance, QObject *parent = 0);
protected:
+ QString getSave() const;
void runImpl() override;
};