summaryrefslogtreecommitdiffstats
path: root/logic/OneSixVersionBuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'logic/OneSixVersionBuilder.cpp')
-rw-r--r--logic/OneSixVersionBuilder.cpp1111
1 files changed, 145 insertions, 966 deletions
diff --git a/logic/OneSixVersionBuilder.cpp b/logic/OneSixVersionBuilder.cpp
index f6917697..8eacbce4 100644
--- a/logic/OneSixVersionBuilder.cpp
+++ b/logic/OneSixVersionBuilder.cpp
@@ -26,806 +26,37 @@
#include <QDir>
#include <QDebug>
-#include "OneSixVersion.h"
+#include "VersionFinal.h"
#include "OneSixInstance.h"
#include "OneSixRule.h"
+#include "VersionFile.h"
+#include "MMCJson.h"
#include "modutils.h"
#include "logger/QsLog.h"
-#define CURRENT_MINIMUM_LAUNCHER_VERSION 14
-
-struct VersionFile
-{
- int order;
- QString name;
- QString fileId;
- QString version;
- // TODO use the mcVersion to determine if a version file should be removed on update
- QString mcVersion;
- QString filename;
- // TODO requirements
- // QMap<QString, QString> requirements;
- QString id;
- QString mainClass;
- QString overwriteMinecraftArguments;
- QString addMinecraftArguments;
- QString removeMinecraftArguments;
- QString processArguments;
- QString type;
- QString releaseTime;
- QString time;
- QString assets;
- int minimumLauncherVersion = -1;
-
- bool shouldOverwriteTweakers = false;
- QStringList overwriteTweakers;
- QStringList addTweakers;
- QStringList removeTweakers;
-
- struct Library
- {
- QString name;
- QString url;
- QString hint;
- QString absoluteUrl;
- bool applyExcludes = false;
- QStringList excludes;
- bool applyNatives = false;
- QList<QPair<OpSys, QString>> natives;
- bool applyRules = false;
- QList<std::shared_ptr<Rule>> rules;
-
- // user for '+' libraries
- enum InsertType
- {
- Apply,
- Append,
- Prepend,
- Replace
- };
- InsertType insertType = Append;
- QString insertData;
- enum DependType
- {
- Soft,
- Hard
- };
- DependType dependType = Soft;
- };
- bool shouldOverwriteLibs = false;
- QList<Library> overwriteLibs;
- QList<Library> addLibs;
- QList<QString> removeLibs;
-
- enum ApplyError
- {
- LauncherVersionError,
- OtherError,
- NoApplyError
- };
-
- static Library fromLibraryJson(const QJsonObject &libObj, const QString &filename,
- bool &isError)
- {
- isError = true;
- Library out;
- if (!libObj.contains("name"))
- {
- QLOG_ERROR() << filename << "contains a library that doesn't have a 'name' field";
- return out;
- }
- 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.url);
- readString("MMC-hint", out.hint);
- readString("MMC-absulute_url", out.absoluteUrl);
- readString("MMC-absoluteUrl", out.absoluteUrl);
- if (libObj.contains("extract"))
- {
- if (!libObj.value("extract").isObject())
- {
- QLOG_ERROR()
- << filename
- << "contains a library with an 'extract' field that's not an object";
- return out;
- }
- QJsonObject extractObj = libObj.value("extract").toObject();
- if (!extractObj.contains("exclude") || !extractObj.value("exclude").isArray())
- {
- QLOG_ERROR() << filename
- << "contains a library with an invalid 'extract' field";
- return out;
- }
- out.applyExcludes = true;
- QJsonArray excludeArray = extractObj.value("exclude").toArray();
- for (auto excludeVal : excludeArray)
- {
- if (!excludeVal.isString())
- {
- QLOG_WARN() << filename << "contains a library that contains an 'extract' "
- "field that contains an invalid 'exclude' entry "
- "(skipping)";
- }
- else
- {
- out.excludes.append(excludeVal.toString());
- }
- }
- }
- if (libObj.contains("natives"))
- {
- if (!libObj.value("natives").isObject())
- {
- QLOG_ERROR()
- << filename
- << "contains a library with a 'natives' field that's not an object";
- return out;
- }
- out.applyNatives = true;
- QJsonObject nativesObj = libObj.value("natives").toObject();
- for (auto it = nativesObj.begin(); it != nativesObj.end(); ++it)
- {
- if (!it.value().isString())
- {
- QLOG_WARN() << filename << "contains an invalid native (skipping)";
- }
- OpSys opSys = OpSys_fromString(it.key());
- if (opSys != Os_Other)
- {
- out.natives.append(qMakePair(opSys, it.value().toString()));
- }
- }
- }
- if (libObj.contains("rules"))
- {
- out.applyRules = true;
- out.rules = rulesFromJsonV4(libObj);
- }
- isError = false;
- return out;
- }
- static VersionFile fromJson(const QJsonDocument &doc, const QString &filename,
- const bool requireOrder, bool &isError, const OneSixVersionBuilder::ParseFlags flags = OneSixVersionBuilder::NoFlags)
- {
- VersionFile out;
- isError = true;
- if (doc.isEmpty() || doc.isNull())
- {
- QLOG_ERROR() << filename << "is empty or null";
- return out;
- }
- if (!doc.isObject())
- {
- QLOG_ERROR() << "The root of" << filename << "is not an object";
- return out;
- }
-
- QJsonObject root = doc.object();
-
- if (requireOrder)
- {
- if (root.contains("order"))
- {
- if (root.value("order").isDouble())
- {
- out.order = root.value("order").toDouble();
- }
- else
- {
- QLOG_ERROR() << "'order' field contains an invalid value in" << filename;
- return out;
- }
- }
- else
- {
- QLOG_ERROR() << filename << "doesn't contain an order field";
- }
- }
-
- out.name = root.value("name").toString();
- out.fileId = root.value("fileId").toString();
- out.version = root.value("version").toString();
- out.mcVersion = root.value("mcVersion").toString();
- out.filename = filename;
-
- auto readString = [root, filename](const QString &key, QString &variable)
- {
- if (root.contains(key))
- {
- QJsonValue val = root.value(key);
- if (!val.isString())
- {
- QLOG_WARN() << key << "is not a string in" << filename << "(skipping)";
- }
- else
- {
- variable = val.toString();
- }
- }
- };
-
- if (!(flags & OneSixVersionBuilder::IsFTBPackJson))
- {
- readString("id", out.id);
- }
- readString("mainClass", out.mainClass);
- readString("processArguments", out.processArguments);
- readString("minecraftArguments", out.overwriteMinecraftArguments);
- readString("+minecraftArguments", out.addMinecraftArguments);
- readString("-minecraftArguments", out.removeMinecraftArguments);
- readString("type", out.type);
- readString("releaseTime", out.releaseTime);
- readString("time", out.time);
- readString("assets", out.assets);
- if (root.contains("minimumLauncherVersion"))
- {
- QJsonValue val = root.value("minimumLauncherVersion");
- if (!val.isDouble())
- {
- QLOG_WARN() << "minimumLauncherVersion is not an int in" << filename
- << "(skipping)";
- }
- else
- {
- out.minimumLauncherVersion = val.toDouble();
- }
- }
-
- if (root.contains("tweakers"))
- {
- QJsonValue tweakersVal = root.value("tweakers");
- if (!tweakersVal.isArray())
- {
- QLOG_ERROR() << filename
- << "contains a 'tweakers' field, but it's not an array";
- return out;
- }
- out.shouldOverwriteTweakers = true;
- QJsonArray tweakers = root.value("tweakers").toArray();
- for (auto tweakerVal : tweakers)
- {
- if (!tweakerVal.isString())
- {
- QLOG_ERROR() << filename
- << "contains a 'tweakers' field entry that's not a string";
- return out;
- }
- out.overwriteTweakers.append(tweakerVal.toString());
- }
- }
- if (root.contains("+tweakers"))
- {
- QJsonValue tweakersVal = root.value("+tweakers");
- if (!tweakersVal.isArray())
- {
- QLOG_ERROR() << filename
- << "contains a '+tweakers' field, but it's not an array";
- return out;
- }
- QJsonArray tweakers = root.value("+tweakers").toArray();
- for (auto tweakerVal : tweakers)
- {
- if (!tweakerVal.isString())
- {
- QLOG_ERROR() << filename
- << "contains a '+tweakers' field entry that's not a string";
- return out;
- }
- out.addTweakers.append(tweakerVal.toString());
- }
- }
- if (root.contains("-tweakers"))
- {
- QJsonValue tweakersVal = root.value("-tweakers");
- if (!tweakersVal.isArray())
- {
- QLOG_ERROR() << filename
- << "contains a '-tweakers' field, but it's not an array";
- return out;
- }
- out.shouldOverwriteTweakers = true;
- QJsonArray tweakers = root.value("-tweakers").toArray();
- for (auto tweakerVal : tweakers)
- {
- if (!tweakerVal.isString())
- {
- QLOG_ERROR() << filename
- << "contains a '-tweakers' field entry that's not a string";
- return out;
- }
- out.removeTweakers.append(tweakerVal.toString());
- }
- }
-
- if (root.contains("libraries"))
- {
- out.shouldOverwriteLibs = !(flags & OneSixVersionBuilder::IsFTBPackJson);
- QJsonValue librariesVal = root.value("libraries");
- if (!librariesVal.isArray())
- {
- QLOG_ERROR() << filename
- << "contains a 'libraries' field, but its not an array";
- return out;
- }
- QJsonArray librariesArray = librariesVal.toArray();
- for (auto libVal : librariesArray)
- {
- if (!libVal.isObject())
- {
- QLOG_ERROR() << filename << "contains a library that's not an object";
- return out;
- }
- QJsonObject libObj = libVal.toObject();
- bool error;
- Library lib = fromLibraryJson(libObj, filename, error);
- if (error)
- {
- QLOG_ERROR() << "Error while reading a library entry in" << filename;
- return out;
- }
- if (flags & OneSixVersionBuilder::IsFTBPackJson)
- {
- lib.hint = "local";
- lib.insertType = Library::Prepend;
- out.addLibs.prepend(lib);
- }
- else
- {
- out.overwriteLibs.append(lib);
- }
- }
- }
- if (root.contains("+libraries"))
- {
- QJsonValue librariesVal = root.value("+libraries");
- if (!librariesVal.isArray())
- {
- QLOG_ERROR() << filename
- << "contains a '+libraries' field, but its not an array";
- return out;
- }
- QJsonArray librariesArray = librariesVal.toArray();
- for (auto libVal : librariesArray)
- {
- if (!libVal.isObject())
- {
- QLOG_ERROR() << filename << "contains a library that's not an object";
- return out;
- }
- QJsonObject libObj = libVal.toObject();
- bool error;
- Library lib = fromLibraryJson(libObj, filename, error);
- if (error)
- {
- QLOG_ERROR() << "Error while reading a library entry in" << filename;
- return out;
- }
- if (!libObj.contains("insert"))
- {
- QLOG_ERROR() << "Missing 'insert' field in '+libraries' field in"
- << filename;
- return out;
- }
- QJsonValue insertVal = libObj.value("insert");
- QString insertString;
- {
- if (insertVal.isString())
- {
- insertString = insertVal.toString();
- }
- else if (insertVal.isObject())
- {
- QJsonObject insertObj = insertVal.toObject();
- if (insertObj.isEmpty())
- {
- QLOG_ERROR() << "One library has an empty insert object in"
- << filename;
- return out;
- }
- insertString = insertObj.keys().first();
- lib.insertData = insertObj.value(insertString).toString();
- }
- }
- if (insertString == "apply")
- {
- lib.insertType = Library::Apply;
- }
- else if (insertString == "prepend")
- {
- lib.insertType = Library::Prepend;
- }
- else if (insertString == "append")
- {
- lib.insertType = Library::Prepend;
- }
- else if (insertString == "replace")
- {
- lib.insertType = Library::Replace;
- }
- else
- {
- QLOG_ERROR() << "A '+' library in" << filename
- << "contains an invalid insert type";
- return out;
- }
- if (libObj.contains("MMC-depend") && libObj.value("MMC-depend").isString())
- {
- const QString dependString = libObj.value("MMC-depend").toString();
- if (dependString == "hard")
- {
- lib.dependType = Library::Hard;
- }
- else if (dependString == "soft")
- {
- lib.dependType = Library::Soft;
- }
- else
- {
- QLOG_ERROR() << "A '+' library in" << filename
- << "contains an invalid depend type";
- return out;
- }
- }
- out.addLibs.append(lib);
- }
- }
- if (root.contains("-libraries"))
- {
- QJsonValue librariesVal = root.value("-libraries");
- if (!librariesVal.isArray())
- {
- QLOG_ERROR() << filename
- << "contains a '-libraries' field, but its not an array";
- return out;
- }
- QJsonArray librariesArray = librariesVal.toArray();
- for (auto libVal : librariesArray)
- {
- if (!libVal.isObject())
- {
- QLOG_ERROR() << filename << "contains a library that's not an object";
- return out;
- }
- QJsonObject libObj = libVal.toObject();
- if (!libObj.contains("name"))
- {
- QLOG_ERROR() << filename << "contains a library without a name";
- return out;
- }
- if (!libObj.value("name").isString())
- {
- QLOG_ERROR() << filename
- << "contains a library without a valid 'name' field";
- return out;
- }
- out.removeLibs.append(libObj.value("name").toString());
- }
- }
-
- isError = false;
- return out;
- }
-
- static std::shared_ptr<OneSixLibrary> createLibrary(const Library &lib)
- {
- std::shared_ptr<OneSixLibrary> out(new OneSixLibrary(lib.name));
- if (!lib.url.isEmpty())
- {
- out->setBaseUrl(lib.url);
- }
- out->setHint(lib.hint);
- if (!lib.absoluteUrl.isEmpty())
- {
- out->setAbsoluteUrl(lib.absoluteUrl);
- }
- out->setAbsoluteUrl(lib.absoluteUrl);
- out->extract_excludes = lib.excludes;
- for (auto native : lib.natives)
- {
- out->addNative(native.first, native.second);
- }
- out->setRules(lib.rules);
- out->finalize();
- return out;
- }
- int findLibrary(QList<std::shared_ptr<OneSixLibrary>> haystack, const QString &needle)
- {
- for (int i = 0; i < haystack.size(); ++i)
- {
- if (QRegExp(needle, Qt::CaseSensitive, QRegExp::WildcardUnix)
- .indexIn(haystack.at(i)->rawName()) != -1)
- {
- return i;
- }
- }
- return -1;
- }
- ApplyError applyTo(OneSixVersion *version)
- {
- if (minimumLauncherVersion != -1)
- {
- if (minimumLauncherVersion > CURRENT_MINIMUM_LAUNCHER_VERSION)
- {
- QLOG_ERROR() << filename << "is for a different launcher version ("
- << minimumLauncherVersion << "), current supported is"
- << CURRENT_MINIMUM_LAUNCHER_VERSION;
- return LauncherVersionError;
- }
- }
-
- if (!version->id.isNull() && !mcVersion.isNull())
- {
- if (QRegExp(mcVersion, Qt::CaseInsensitive, QRegExp::Wildcard)
- .indexIn(version->id) == -1)
- {
- QLOG_ERROR() << filename << "is for a different version of Minecraft";
- return OtherError;
- }
- }
-
- if (!id.isNull())
- {
- version->id = id;
- }
- if (!mainClass.isNull())
- {
- version->mainClass = mainClass;
- }
- if (!processArguments.isNull())
- {
- version->processArguments = processArguments;
- }
- if (!type.isNull())
- {
- version->type = type;
- }
- if (!releaseTime.isNull())
- {
- version->releaseTime = releaseTime;
- }
- if (!time.isNull())
- {
- version->time = time;
- }
- if (!assets.isNull())
- {
- version->assets = assets;
- }
- if (minimumLauncherVersion >= 0)
- {
- version->minimumLauncherVersion = minimumLauncherVersion;
- }
- if (!overwriteMinecraftArguments.isNull())
- {
- version->minecraftArguments = overwriteMinecraftArguments;
- }
- if (!addMinecraftArguments.isNull())
- {
- version->minecraftArguments += addMinecraftArguments;
- }
- if (!removeMinecraftArguments.isNull())
- {
- version->minecraftArguments.remove(removeMinecraftArguments);
- }
- if (shouldOverwriteTweakers)
- {
- version->tweakers = overwriteTweakers;
- }
- for (auto tweaker : addTweakers)
- {
- version->tweakers += tweaker;
- }
- for (auto tweaker : removeTweakers)
- {
- version->tweakers.removeAll(tweaker);
- }
- if (shouldOverwriteLibs)
- {
- version->libraries.clear();
- for (auto lib : overwriteLibs)
- {
- version->libraries.append(createLibrary(lib));
- }
- }
- for (auto lib : addLibs)
- {
- switch (lib.insertType)
- {
- case Library::Apply:
- {
-
- int index = findLibrary(version->libraries, lib.name);
- if (index >= 0)
- {
- auto library = version->libraries[index];
- if (!lib.url.isNull())
- {
- library->setBaseUrl(lib.url);
- }
- if (!lib.hint.isNull())
- {
- library->setHint(lib.hint);
- }
- if (!lib.absoluteUrl.isNull())
- {
- library->setAbsoluteUrl(lib.absoluteUrl);
- }
- if (lib.applyExcludes)
- {
- library->extract_excludes = lib.excludes;
- }
- if (lib.applyNatives)
- {
- library->clearSuffixes();
- for (auto native : lib.natives)
- {
- library->addNative(native.first, native.second);
- }
- }
- if (lib.applyRules)
- {
- library->setRules(lib.rules);
- }
- library->finalize();
- }
- else
- {
- QLOG_WARN() << "Couldn't find" << lib.insertData << "(skipping)";
- }
- break;
- }
- case Library::Append:
- case Library::Prepend:
- {
-
- const int startOfVersion = lib.name.lastIndexOf(':') + 1;
- const int index =
- findLibrary(version->libraries,
- QString(lib.name).replace(startOfVersion, INT_MAX, '*'));
- if (index < 0)
- {
- if (lib.insertType == Library::Append)
- {
- version->libraries.append(createLibrary(lib));
- }
- else
- {
- version->libraries.prepend(createLibrary(lib));
- }
- }
- else
- {
- auto otherLib = version->libraries.at(index);
- const Util::Version ourVersion = lib.name.mid(startOfVersion, INT_MAX);
- const Util::Version otherVersion = otherLib->version();
- // if the existing version is a hard dependency we can either use it or
- // fail, but we can't change it
- if (otherLib->dependType == OneSixLibrary::Hard)
- {
- // we need a higher version, or we're hard to and the versions aren't
- // equal
- if (ourVersion > otherVersion ||
- (lib.dependType == Library::Hard && ourVersion != otherVersion))
- {
- QLOG_ERROR() << "Error resolving library dependencies between"
- << otherLib->rawName() << "and" << lib.name << "in"
- << filename;
- return OtherError;
- }
- else
- {
- // the library is already existing, so we don't have to do anything
- }
- }
- else if (otherLib->dependType == OneSixLibrary::Soft)
- {
- // if we are higher it means we should update
- if (ourVersion > otherVersion)
- {
- auto library = createLibrary(lib);
- if (Util::Version(otherLib->minVersion) < ourVersion)
- {
- library->minVersion = ourVersion.toString();
- }
- version->libraries.replace(index, library);
- }
- else
- {
- // our version is smaller than the existing version, but we require
- // it: fail
- if (lib.dependType == Library::Hard)
- {
- QLOG_ERROR() << "Error resolving library dependencies between"
- << otherLib->rawName() << "and" << lib.name << "in"
- << filename;
- return OtherError;
- }
- }
- }
- }
- break;
- }
- case Library::Replace:
- {
- int index = findLibrary(version->libraries, lib.insertData);
- if (index >= 0)
- {
- version->libraries.replace(index, createLibrary(lib));
- }
- else
- {
- QLOG_WARN() << "Couldn't find" << lib.insertData << "(skipping)";
- }
- break;
- }
- }
- }
- for (auto lib : removeLibs)
- {
- int index = findLibrary(version->libraries, lib);
- if (index >= 0)
- {
- version->libraries.removeAt(index);
- }
- else
- {
- QLOG_WARN() << "Couldn't find" << lib << "(skipping)";
- }
- }
-
- OneSixVersion::VersionFile versionFile;
- versionFile.name = name;
- versionFile.id = fileId;
- versionFile.version = this->version;
- versionFile.mcVersion = mcVersion;
- versionFile.filename = filename;
- versionFile.order = order;
- version->versionFiles.append(versionFile);
-
- return NoApplyError;
- }
-};
-
OneSixVersionBuilder::OneSixVersionBuilder()
{
}
-bool OneSixVersionBuilder::build(OneSixVersion *version, OneSixInstance *instance,
- QWidget *widgetParent, const bool onlyVanilla, const QStringList &external)
+void OneSixVersionBuilder::build(VersionFinal *version, OneSixInstance *instance,
+ const bool onlyVanilla, const QStringList &external)
{
OneSixVersionBuilder builder;
builder.m_version = version;
builder.m_instance = instance;
- builder.m_widgetParent = widgetParent;
- return builder.build(onlyVanilla, external);
+ builder.buildInternal(onlyVanilla, external);
}
-bool OneSixVersionBuilder::read(OneSixVersion *version, const QJsonObject &obj)
+void OneSixVersionBuilder::readJsonAndApplyToVersion(VersionFinal *version,
+ const QJsonObject &obj)
{
OneSixVersionBuilder builder;
builder.m_version = version;
builder.m_instance = 0;
- builder.m_widgetParent = 0;
- return builder.read(obj);
+ builder.readJsonAndApply(obj);
}
-bool OneSixVersionBuilder::build(const bool onlyVanilla, const QStringList &external)
+void OneSixVersionBuilder::buildInternal(const bool onlyVanilla, const QStringList &external)
{
m_version->clear();
@@ -833,245 +64,194 @@ bool OneSixVersionBuilder::build(const bool onlyVanilla, const QStringList &exte
QDir patches(root.absoluteFilePath("patches/"));
// if we do external files, do just those.
- if(!external.isEmpty()) for (auto fileName : external)
- {
- QLOG_INFO() << "Reading" << fileName;
- VersionFile file;
- ParseFlags flags = fileName.endsWith("pack.json") ? IsFTBPackJson : NoFlags;
- if (!read(QFileInfo(fileName), false, &file, flags))
- {
- return false;
+ if (!external.isEmpty())
+ for (auto fileName : external)
+ {
+ 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->version = QString();
+ file->mcVersion = QString();
+ file->applyTo(m_version);
+ m_version->versionFiles.append(file);
}
- file.name = QFileInfo(fileName).fileName();
- file.fileId = "org.multimc.external." + file.name;
- file.version = QString();
- file.mcVersion = QString();
- bool isError = false;
- auto errorcode = file.applyTo(m_version);
- if(errorcode != VersionFile::NoApplyError)
- return false;
- }
// else, if there's custom json, we just do that.
else if (QFile::exists(root.absoluteFilePath("custom.json")))
{
QLOG_INFO() << "Reading custom.json";
- VersionFile file;
- if (!read(QFileInfo(root.absoluteFilePath("custom.json")), false, &file))
- {
- return false;
- }
- file.name = "custom.json";
- file.filename = "custom.json";
- file.fileId = "org.multimc.custom.json";
- file.version = QString();
- auto errorcode = file.applyTo(m_version);
- if(errorcode != VersionFile::NoApplyError)
- return false;
- // QObject::tr("The version descriptors of this instance are not compatible with the current version of MultiMC"));
+ auto file = parseJsonFile(QFileInfo(root.absoluteFilePath("custom.json")), false);
+ file->name = "custom.json";
+ file->filename = "custom.json";
+ file->fileId = "org.multimc.custom.json";
+ file->version = QString();
+ file->applyTo(m_version);
+ m_version->versionFiles.append(file);
+ // QObject::tr("The version descriptors of this instance are not compatible with the
+ // current version of MultiMC"));
// QObject::tr("Error while applying %1. Please check MultiMC-0.log for more info.")
}
// version.json -> patches/*.json -> user.json
- else do
- {
- // version.json
- QLOG_INFO() << "Reading version.json";
- VersionFile file;
- if (!read(QFileInfo(root.absoluteFilePath("version.json")), false, &file))
- {
- return false;
- }
- file.name = "version.json";
- file.fileId = "org.multimc.version.json";
- file.version = m_instance->intendedVersionId();
- file.mcVersion = m_instance->intendedVersionId();
- auto error = file.applyTo(m_version);
- if (error != VersionFile::NoApplyError)
- {
- QMessageBox::critical(
- m_widgetParent, QObject::tr("Error"),
- QObject::tr(
- "Error while applying %1. Please check MultiMC-0.log for more info.")
- .arg(root.absoluteFilePath("version.json")));
- return false;
- }
-
- if (onlyVanilla)
- break;
+ else
+ do
+ {
+ // version.json
+ QLOG_INFO() << "Reading version.json";
+ auto file = parseJsonFile(QFileInfo(root.absoluteFilePath("version.json")), false);
+ file->name = "Minecraft";
+ file->fileId = "org.multimc.version.json";
+ file->version = m_instance->intendedVersionId();
+ file->mcVersion = m_instance->intendedVersionId();
+ file->applyTo(m_version);
+ m_version->versionFiles.append(file);
+ // QObject::tr("Error while applying %1. Please check MultiMC-0.log for more
+ // info.").arg(root.absoluteFilePath("version.json")));
+
+ if (onlyVanilla)
+ break;
- // patches/
- // load all, put into map for ordering, apply in the right order
- QMap<QString, int> overrideOrder = readOverrideOrders(m_instance);
+ // patches/
+ // load all, put into map for ordering, apply in the right order
- QMap<int, QPair<QString, VersionFile>> files;
- for (auto info : patches.entryInfoList(QStringList() << "*.json", QDir::Files))
- {
- QLOG_INFO() << "Reading" << info.fileName();
- VersionFile file;
- if (!read(info, true, &file))
- {
- return false;
- }
- if (overrideOrder.contains(file.fileId))
+ QMap<int, QPair<QString, VersionFilePtr>> files;
+ for (auto info : patches.entryInfoList(QStringList() << "*.json", QDir::Files))
{
- file.order = overrideOrder.value(file.fileId);
- }
- if (files.contains(file.order))
- {
- QLOG_ERROR() << file.fileId << "has the same order as" << files[file.order].second.fileId;
- return false;
+ QLOG_INFO() << "Reading" << info.fileName();
+ auto file = parseJsonFile(info, true);
+ if (files.contains(file->order))
+ {
+ 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));
}
- files.insert(file.order, qMakePair(info.fileName(), file));
- }
- for (auto order : files.keys())
- {
- QLOG_DEBUG() << "Applying file with order" << order;
- auto filePair = files[order];
- auto error = filePair.second.applyTo(m_version);
- if (error != VersionFile::NoApplyError)
+ for (auto order : files.keys())
{
- QMessageBox::critical(
- m_widgetParent, QObject::tr("Error"),
- QObject::tr("Error while applying %1. Please check MultiMC-0.log "
- "for more info.").arg(filePair.first));
- return false;
+ QLOG_DEBUG() << "Applying file with order" << order;
+ auto &filePair = files[order];
+ filePair.second->applyTo(m_version);
+ m_version->versionFiles.append(filePair.second);
}
- }
- } while(0);
+ } while (0);
// some final touches
+ finalizeVersion();
+}
+
+void OneSixVersionBuilder::finalizeVersion()
+{
+ if (m_version->assets.isEmpty())
{
- if (m_version->assets.isEmpty())
+ m_version->assets = "legacy";
+ }
+ if (m_version->minecraftArguments.isEmpty())
+ {
+ QString toCompare = m_version->processArguments.toLower();
+ if (toCompare == "legacy")
{
- m_version->assets = "legacy";
+ m_version->minecraftArguments = " ${auth_player_name} ${auth_session}";
}
- if (m_version->minecraftArguments.isEmpty())
+ else if (toCompare == "username_session")
{
- QString toCompare = m_version->processArguments.toLower();
- if (toCompare == "legacy")
- {
- m_version->minecraftArguments = " ${auth_player_name} ${auth_session}";
- }
- else if (toCompare == "username_session")
- {
- m_version->minecraftArguments =
- "--username ${auth_player_name} --session ${auth_session}";
- }
- else if (toCompare == "username_session_version")
- {
- m_version->minecraftArguments = "--username ${auth_player_name} "
- "--session ${auth_session} "
- "--version ${profile_name}";
- }
+ m_version->minecraftArguments =
+ "--username ${auth_player_name} --session ${auth_session}";
+ }
+ else if (toCompare == "username_session_version")
+ {
+ m_version->minecraftArguments = "--username ${auth_player_name} "
+ "--session ${auth_session} "
+ "--version ${profile_name}";
}
}
-
- return true;
}
-bool OneSixVersionBuilder::read(const QJsonObject &obj)
+void OneSixVersionBuilder::readJsonAndApply(const QJsonObject &obj)
{
m_version->clear();
- bool isError = false;
- VersionFile file = VersionFile::fromJson(QJsonDocument(obj), QString(), false, isError);
- if (isError)
- {
- QMessageBox::critical(
- m_widgetParent, QObject::tr("Error"),
- QObject::tr("Error while reading. Please check MultiMC-0.log for more info."));
- return false;
- }
- VersionFile::ApplyError error = file.applyTo(m_version);
- if (error == VersionFile::OtherError)
- {
- QMessageBox::critical(
- m_widgetParent, QObject::tr("Error"),
- QObject::tr("Error while applying. Please check MultiMC-0.log for more info."));
- return false;
- }
- else if (error == VersionFile::LauncherVersionError)
- {
- QMessageBox::critical(
- m_widgetParent, QObject::tr("Error"),
- QObject::tr("The version descriptors of this instance are not compatible with the current version of MultiMC"));
- return false;
- }
+ auto file = VersionFile::fromJson(QJsonDocument(obj), QString(), false);
+ // QObject::tr("Error while reading. Please check MultiMC-0.log for more info."));
- return true;
+ file->applyTo(m_version);
+ m_version->versionFiles.append(file);
+ // QObject::tr("Error while applying. Please check MultiMC-0.log for more info."));
+ // QObject::tr("The version descriptors of this instance are not compatible with the current
+ // version of MultiMC"));
}
-bool OneSixVersionBuilder::read(const QFileInfo &fileInfo, const bool requireOrder,
- VersionFile *out, const ParseFlags flags)
+VersionFilePtr OneSixVersionBuilder::parseJsonFile(const QFileInfo &fileInfo,
+ const bool requireOrder, bool isFTB)
{
QFile file(fileInfo.absoluteFilePath());
if (!file.open(QFile::ReadOnly))
{
- QMessageBox::critical(
- m_widgetParent, QObject::tr("Error"),
- QObject::tr("Unable to open %1: %2").arg(file.fileName(), file.errorString()));
- return false;
+ 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)
{
- QMessageBox::critical(m_widgetParent, QObject::tr("Error"),
- QObject::tr("Unable to parse %1: %2 at %3")
- .arg(file.fileName(), error.errorString())
- .arg(error.offset));
- return false;
+ throw JSONValidationError(QObject::tr("Unable to process the version file %1: %2 at %3.")
+ .arg(fileInfo.fileName(), error.errorString())
+ .arg(error.offset));
}
- bool isError = false;
- *out = VersionFile::fromJson(doc, file.fileName(), requireOrder, isError, flags);
- if (isError)
- {
- QMessageBox::critical(
- m_widgetParent, QObject::tr("Error"),
- QObject::tr("Error while reading %1. Please check MultiMC-0.log for more info.")
- .arg(file.fileName()));
- ;
- }
- return true;
+ return VersionFile::fromJson(doc, file.fileName(), requireOrder, isFTB);
+ // QObject::tr("Error while reading %1. Please check MultiMC-0.log for more
+ // info.").arg(file.fileName());
}
QMap<QString, int> OneSixVersionBuilder::readOverrideOrders(OneSixInstance *instance)
{
QMap<QString, int> out;
- if (QDir(instance->instanceRoot()).exists("order.json"))
+
+ // make sure the order file exists
+ if (!QDir(instance->instanceRoot()).exists("order.json"))
+ return out;
+
+ // and it can be opened
+ QFile orderFile(instance->instanceRoot() + "/order.json");
+ if (!orderFile.open(QFile::ReadOnly))
{
- QFile orderFile(instance->instanceRoot() + "/order.json");
- if (!orderFile.open(QFile::ReadOnly))
- {
- QLOG_ERROR() << "Couldn't open" << orderFile.fileName()
- << " for reading:" << orderFile.errorString();
- QLOG_WARN() << "Ignoring overriden order";
- }
- else
+ QLOG_ERROR() << "Couldn't open" << orderFile.fileName()
+ << " for reading:" << orderFile.errorString();
+ QLOG_WARN() << "Ignoring overriden order";
+ return out;
+ }
+
+ // 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 out;
+ }
+
+ // and then read it and process it if all above is true.
+ try
+ {
+ auto obj = MMCJson::ensureObject(doc);
+ for (auto it = obj.begin(); it != obj.end(); ++it)
{
- QJsonParseError error;
- QJsonDocument doc = QJsonDocument::fromJson(orderFile.readAll(), &error);
- if (error.error != QJsonParseError::NoError || !doc.isObject())
- {
- QLOG_ERROR() << "Couldn't parse" << orderFile.fileName() << ":"
- << error.errorString();
- QLOG_WARN() << "Ignoring overriden order";
- }
- else
+ if (it.key().startsWith("org.multimc."))
{
- QJsonObject obj = doc.object();
- for (auto it = obj.begin(); it != obj.end(); ++it)
- {
- if (it.key().startsWith("org.multimc."))
- {
- continue;
- }
- out.insert(it.key(), it.value().toDouble());
- }
+ continue;
}
+ out.insert(it.key(), MMCJson::ensureInteger(it.value()));
}
}
+ catch (JSONValidationError &err)
+ {
+ QLOG_ERROR() << "Couldn't parse" << orderFile.fileName() << ": bad file format";
+ QLOG_WARN() << "Ignoring overriden order";
+ return out;
+ }
return out;
}
+
bool OneSixVersionBuilder::writeOverrideOrders(const QMap<QString, int> &order,
OneSixInstance *instance)
{
@@ -1094,4 +274,3 @@ bool OneSixVersionBuilder::writeOverrideOrders(const QMap<QString, int> &order,
orderFile.write(QJsonDocument(obj).toJson(QJsonDocument::Indented));
return true;
}
-