summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Mrázek <peterix@gmail.com>2014-03-01 23:06:47 +0100
committerPetr Mrázek <peterix@gmail.com>2014-03-01 23:06:47 +0100
commit7c24bcc83476dcbdd7f7acbe14ecef4398962689 (patch)
tree4ab7e7020927d05274f079c3045bd572c218fa21
parent7dfd6aa051c582e26125e17e1d6eed5e675e1027 (diff)
downloadMultiMC-7c24bcc83476dcbdd7f7acbe14ecef4398962689.tar
MultiMC-7c24bcc83476dcbdd7f7acbe14ecef4398962689.tar.gz
MultiMC-7c24bcc83476dcbdd7f7acbe14ecef4398962689.tar.lz
MultiMC-7c24bcc83476dcbdd7f7acbe14ecef4398962689.tar.xz
MultiMC-7c24bcc83476dcbdd7f7acbe14ecef4398962689.zip
Reorganize the version-related code.
-rw-r--r--CMakeLists.txt21
-rw-r--r--gui/dialogs/OneSixModEditDialog.cpp4
-rw-r--r--gui/dialogs/OneSixModEditDialog.h2
-rw-r--r--logic/BaseInstaller.cpp2
-rw-r--r--logic/ForgeInstaller.cpp6
-rw-r--r--logic/ForgeInstaller.h4
-rw-r--r--logic/LiteLoaderInstaller.cpp2
-rw-r--r--logic/OneSixFTBInstance.cpp2
-rw-r--r--logic/OneSixInstance.cpp12
-rw-r--r--logic/OneSixInstance.h8
-rw-r--r--logic/OneSixInstance_p.h6
-rw-r--r--logic/OneSixUpdate.cpp8
-rw-r--r--logic/OneSixVersionBuilder.cpp797
-rw-r--r--logic/OneSixVersionBuilder.h15
-rw-r--r--logic/VersionFile.cpp702
-rw-r--r--logic/VersionFile.h90
-rw-r--r--logic/VersionFinal.cpp (renamed from logic/OneSixVersion.cpp)40
-rw-r--r--logic/VersionFinal.h (renamed from logic/OneSixVersion.h)8
18 files changed, 880 insertions, 849 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f070684d..229179cb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -414,31 +414,38 @@ logic/LegacyInstance.cpp
logic/LegacyInstance_p.h
logic/LegacyUpdate.h
logic/LegacyUpdate.cpp
+
logic/LegacyForge.h
logic/LegacyForge.cpp
# OneSix instances
logic/OneSixUpdate.h
logic/OneSixUpdate.cpp
-logic/OneSixVersion.h
-logic/OneSixVersion.cpp
+logic/OneSixInstance.h
+logic/OneSixInstance.cpp
+logic/OneSixInstance_p.h
+
+# OneSix version json infrastructure
+logic/OneSixVersionBuilder.h
+logic/OneSixVersionBuilder.cpp
+logic/VersionFile.h
+logic/VersionFile.cpp
+logic/VersionFinal.h
+logic/VersionFinal.cpp
logic/OneSixLibrary.h
logic/OneSixLibrary.cpp
logic/OneSixRule.h
logic/OneSixRule.cpp
logic/OpSys.h
logic/OpSys.cpp
+
+# Mod installers
logic/BaseInstaller.h
logic/BaseInstaller.cpp
logic/ForgeInstaller.h
logic/ForgeInstaller.cpp
logic/LiteLoaderInstaller.h
logic/LiteLoaderInstaller.cpp
-logic/OneSixInstance.h
-logic/OneSixInstance.cpp
-logic/OneSixInstance_p.h
-logic/OneSixVersionBuilder.h
-logic/OneSixVersionBuilder.cpp
# Nostalgia
logic/NostalgiaInstance.h
diff --git a/gui/dialogs/OneSixModEditDialog.cpp b/gui/dialogs/OneSixModEditDialog.cpp
index fe621a9a..67210217 100644
--- a/gui/dialogs/OneSixModEditDialog.cpp
+++ b/gui/dialogs/OneSixModEditDialog.cpp
@@ -34,7 +34,7 @@
#include "gui/dialogs/ProgressDialog.h"
#include "logic/ModList.h"
-#include "logic/OneSixVersion.h"
+#include "logic/VersionFinal.h"
#include "logic/EnabledItemFilter.h"
#include "logic/lists/ForgeVersionList.h"
#include "logic/lists/LiteLoaderVersionList.h"
@@ -353,7 +353,7 @@ QMap<QString, int> OneSixModEditDialog::getExistingOrder() const
QMap<QString, int> order;
// default
{
- for (OneSixVersion::VersionFile file : m_version->versionFiles)
+ for (VersionFinal::VersionFile file : m_version->versionFiles)
{
if (file.id.startsWith("org.multimc."))
{
diff --git a/gui/dialogs/OneSixModEditDialog.h b/gui/dialogs/OneSixModEditDialog.h
index f44b336b..1f3f9f67 100644
--- a/gui/dialogs/OneSixModEditDialog.h
+++ b/gui/dialogs/OneSixModEditDialog.h
@@ -60,7 +60,7 @@ protected:
private:
Ui::OneSixModEditDialog *ui;
- std::shared_ptr<OneSixVersion> m_version;
+ std::shared_ptr<VersionFinal> m_version;
std::shared_ptr<ModList> m_mods;
std::shared_ptr<ModList> m_resourcepacks;
EnabledItemFilter *main_model;
diff --git a/logic/BaseInstaller.cpp b/logic/BaseInstaller.cpp
index 92aa0c92..669fd0ac 100644
--- a/logic/BaseInstaller.cpp
+++ b/logic/BaseInstaller.cpp
@@ -17,7 +17,7 @@
#include <QFile>
-#include "OneSixVersion.h"
+#include "VersionFinal.h"
#include "OneSixLibrary.h"
#include "OneSixInstance.h"
diff --git a/logic/ForgeInstaller.cpp b/logic/ForgeInstaller.cpp
index 3e18d17f..6f238c21 100644
--- a/logic/ForgeInstaller.cpp
+++ b/logic/ForgeInstaller.cpp
@@ -14,7 +14,7 @@
*/
#include "ForgeInstaller.h"
-#include "OneSixVersion.h"
+#include "VersionFinal.h"
#include "OneSixLibrary.h"
#include "net/HttpMetaCache.h"
#include <quazip.h>
@@ -33,7 +33,7 @@
ForgeInstaller::ForgeInstaller(QString filename, QString universal_url)
{
- std::shared_ptr<OneSixVersion> newVersion;
+ std::shared_ptr<VersionFinal> newVersion;
m_universal_url = universal_url;
QuaZip zip(filename);
@@ -66,7 +66,7 @@ ForgeInstaller::ForgeInstaller(QString filename, QString universal_url)
// read the forge version info
{
- newVersion = OneSixVersion::fromJson(versionInfoVal.toObject());
+ newVersion = VersionFinal::fromJson(versionInfoVal.toObject());
if (!newVersion)
return;
}
diff --git a/logic/ForgeInstaller.h b/logic/ForgeInstaller.h
index c5052092..df029f38 100644
--- a/logic/ForgeInstaller.h
+++ b/logic/ForgeInstaller.h
@@ -20,7 +20,7 @@
#include <QString>
#include <memory>
-class OneSixVersion;
+class VersionFinal;
class ForgeInstaller : public BaseInstaller
{
@@ -33,7 +33,7 @@ public:
private:
// the version, read from the installer
- std::shared_ptr<OneSixVersion> m_forge_version;
+ std::shared_ptr<VersionFinal> m_forge_version;
QString internalPath;
QString finalPath;
QString realVersionId;
diff --git a/logic/LiteLoaderInstaller.cpp b/logic/LiteLoaderInstaller.cpp
index 126027fb..44400e8a 100644
--- a/logic/LiteLoaderInstaller.cpp
+++ b/logic/LiteLoaderInstaller.cpp
@@ -20,7 +20,7 @@
#include "logger/QsLog.h"
-#include "OneSixVersion.h"
+#include "VersionFinal.h"
#include "OneSixLibrary.h"
#include "OneSixInstance.h"
diff --git a/logic/OneSixFTBInstance.cpp b/logic/OneSixFTBInstance.cpp
index 8b8465b9..cdb3f53e 100644
--- a/logic/OneSixFTBInstance.cpp
+++ b/logic/OneSixFTBInstance.cpp
@@ -1,6 +1,6 @@
#include "OneSixFTBInstance.h"
-#include "OneSixVersion.h"
+#include "VersionFinal.h"
#include "OneSixLibrary.h"
#include "tasks/SequentialTask.h"
#include "ForgeInstaller.h"
diff --git a/logic/OneSixInstance.cpp b/logic/OneSixInstance.cpp
index 10411c56..bd5d559e 100644
--- a/logic/OneSixInstance.cpp
+++ b/logic/OneSixInstance.cpp
@@ -19,7 +19,7 @@
#include "OneSixInstance_p.h"
#include "OneSixUpdate.h"
-#include "OneSixVersion.h"
+#include "VersionFinal.h"
#include "pathutils.h"
#include "logger/QsLog.h"
#include "assets/AssetsUtils.h"
@@ -34,8 +34,8 @@ OneSixInstance::OneSixInstance(const QString &rootDir, SettingsObject *settings,
I_D(OneSixInstance);
d->m_settings->registerSetting("IntendedVersion", "");
d->m_settings->registerSetting("ShouldUpdate", false);
- d->version.reset(new OneSixVersion(this, this));
- d->vanillaVersion.reset(new OneSixVersion(this, this));
+ d->version.reset(new VersionFinal(this, this));
+ d->vanillaVersion.reset(new VersionFinal(this, this));
}
void OneSixInstance::init()
@@ -79,7 +79,7 @@ QString replaceTokensIn(QString text, QMap<QString, QString> with)
return result;
}
-QDir OneSixInstance::reconstructAssets(std::shared_ptr<OneSixVersion> version)
+QDir OneSixInstance::reconstructAssets(std::shared_ptr<VersionFinal> version)
{
QDir assetsDir = QDir("assets/");
QDir indexDir = QDir(PathCombine(assetsDir.path(), "indexes"));
@@ -345,13 +345,13 @@ void OneSixInstance::clearVersion()
emit versionReloaded();
}
-std::shared_ptr<OneSixVersion> OneSixInstance::getFullVersion() const
+std::shared_ptr<VersionFinal> OneSixInstance::getFullVersion() const
{
I_D(const OneSixInstance);
return d->version;
}
-std::shared_ptr<OneSixVersion> OneSixInstance::getVanillaVersion() const
+std::shared_ptr<VersionFinal> OneSixInstance::getVanillaVersion() const
{
I_D(const OneSixInstance);
return d->vanillaVersion;
diff --git a/logic/OneSixInstance.h b/logic/OneSixInstance.h
index 06fd9de3..75edec1e 100644
--- a/logic/OneSixInstance.h
+++ b/logic/OneSixInstance.h
@@ -17,7 +17,7 @@
#include "BaseInstance.h"
-#include "OneSixVersion.h"
+#include "VersionFinal.h"
#include "ModList.h"
class OneSixInstance : public BaseInstance
@@ -58,9 +58,9 @@ public:
/// clears all version information in preparation for an update
void clearVersion();
/// get the current full version info
- std::shared_ptr<OneSixVersion> getFullVersion() const;
+ std::shared_ptr<VersionFinal> getFullVersion() const;
/// gets the current version info, but only for version.json
- std::shared_ptr<OneSixVersion> getVanillaVersion() const;
+ std::shared_ptr<VersionFinal> getVanillaVersion() const;
/// is the current version original, or custom?
virtual bool versionIsCustom() override;
@@ -80,5 +80,5 @@ signals:
private:
QStringList processMinecraftArgs(AuthSessionPtr account);
- QDir reconstructAssets(std::shared_ptr<OneSixVersion> version);
+ QDir reconstructAssets(std::shared_ptr<VersionFinal> version);
};
diff --git a/logic/OneSixInstance_p.h b/logic/OneSixInstance_p.h
index 0cc46f33..2dffa62c 100644
--- a/logic/OneSixInstance_p.h
+++ b/logic/OneSixInstance_p.h
@@ -16,13 +16,13 @@
#pragma once
#include "BaseInstance_p.h"
-#include "OneSixVersion.h"
+#include "VersionFinal.h"
#include "ModList.h"
struct OneSixInstancePrivate : public BaseInstancePrivate
{
- std::shared_ptr<OneSixVersion> version;
- std::shared_ptr<OneSixVersion> vanillaVersion;
+ std::shared_ptr<VersionFinal> version;
+ std::shared_ptr<VersionFinal> vanillaVersion;
std::shared_ptr<ModList> loader_mod_list;
std::shared_ptr<ModList> resource_pack_list;
};
diff --git a/logic/OneSixUpdate.cpp b/logic/OneSixUpdate.cpp
index f87c65e7..750aeabb 100644
--- a/logic/OneSixUpdate.cpp
+++ b/logic/OneSixUpdate.cpp
@@ -25,7 +25,7 @@
#include "BaseInstance.h"
#include "lists/MinecraftVersionList.h"
-#include "OneSixVersion.h"
+#include "VersionFinal.h"
#include "OneSixLibrary.h"
#include "OneSixInstance.h"
#include "net/ForgeMirrors.h"
@@ -150,7 +150,7 @@ void OneSixUpdate::assetIndexStart()
{
setStatus(tr("Updating assets index..."));
OneSixInstance *inst = (OneSixInstance *)m_inst;
- std::shared_ptr<OneSixVersion> version = inst->getFullVersion();
+ std::shared_ptr<VersionFinal> version = inst->getFullVersion();
QString assetName = version->assets;
QUrl indexUrl = "http://" + URLConstants::AWS_DOWNLOAD_INDEXES + assetName + ".json";
QString localPath = assetName + ".json";
@@ -174,7 +174,7 @@ void OneSixUpdate::assetIndexFinished()
AssetsIndex index;
OneSixInstance *inst = (OneSixInstance *)m_inst;
- std::shared_ptr<OneSixVersion> version = inst->getFullVersion();
+ std::shared_ptr<VersionFinal> version = inst->getFullVersion();
QString assetName = version->assets;
QString asset_fname = "assets/indexes/" + assetName + ".json";
@@ -243,7 +243,7 @@ void OneSixUpdate::jarlibStart()
}
// Build a list of URLs that will need to be downloaded.
- std::shared_ptr<OneSixVersion> version = inst->getFullVersion();
+ std::shared_ptr<VersionFinal> version = inst->getFullVersion();
// minecraft.jar for this version
{
QString version_id = version->id;
diff --git a/logic/OneSixVersionBuilder.cpp b/logic/OneSixVersionBuilder.cpp
index f6917697..0d4d66a2 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 "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,
+bool OneSixVersionBuilder::build(VersionFinal *version, OneSixInstance *instance,
QWidget *widgetParent, 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);
+ return builder.buildInternal(onlyVanilla, external);
}
-bool OneSixVersionBuilder::read(OneSixVersion *version, const QJsonObject &obj)
+bool 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);
+ return builder.readJsonAndApply(obj);
}
-bool OneSixVersionBuilder::build(const bool onlyVanilla, const QStringList &external)
+bool OneSixVersionBuilder::buildInternal(const bool onlyVanilla, const QStringList &external)
{
m_version->clear();
@@ -837,8 +68,7 @@ bool OneSixVersionBuilder::build(const bool onlyVanilla, const QStringList &exte
{
QLOG_INFO() << "Reading" << fileName;
VersionFile file;
- ParseFlags flags = fileName.endsWith("pack.json") ? IsFTBPackJson : NoFlags;
- if (!read(QFileInfo(fileName), false, &file, flags))
+ if (!parseJsonFile(QFileInfo(fileName), false, &file, fileName.endsWith("pack.json") ? IsFTBPackJson : NoFlags))
{
return false;
}
@@ -856,7 +86,7 @@ bool OneSixVersionBuilder::build(const bool onlyVanilla, const QStringList &exte
{
QLOG_INFO() << "Reading custom.json";
VersionFile file;
- if (!read(QFileInfo(root.absoluteFilePath("custom.json")), false, &file))
+ if (!parseJsonFile(QFileInfo(root.absoluteFilePath("custom.json")), false, &file))
{
return false;
}
@@ -876,7 +106,7 @@ bool OneSixVersionBuilder::build(const bool onlyVanilla, const QStringList &exte
// version.json
QLOG_INFO() << "Reading version.json";
VersionFile file;
- if (!read(QFileInfo(root.absoluteFilePath("version.json")), false, &file))
+ if (!parseJsonFile(QFileInfo(root.absoluteFilePath("version.json")), false, &file))
{
return false;
}
@@ -907,7 +137,7 @@ bool OneSixVersionBuilder::build(const bool onlyVanilla, const QStringList &exte
{
QLOG_INFO() << "Reading" << info.fileName();
VersionFile file;
- if (!read(info, true, &file))
+ if (!parseJsonFile(info, true, &file))
{
return false;
}
@@ -968,7 +198,7 @@ bool OneSixVersionBuilder::build(const bool onlyVanilla, const QStringList &exte
return true;
}
-bool OneSixVersionBuilder::read(const QJsonObject &obj)
+bool OneSixVersionBuilder::readJsonAndApply(const QJsonObject &obj)
{
m_version->clear();
@@ -1000,7 +230,7 @@ bool OneSixVersionBuilder::read(const QJsonObject &obj)
return true;
}
-bool OneSixVersionBuilder::read(const QFileInfo &fileInfo, const bool requireOrder,
+bool OneSixVersionBuilder::parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder,
VersionFile *out, const ParseFlags flags)
{
QFile file(fileInfo.absoluteFilePath());
@@ -1072,6 +302,7 @@ QMap<QString, int> OneSixVersionBuilder::readOverrideOrders(OneSixInstance *inst
}
return out;
}
+
bool OneSixVersionBuilder::writeOverrideOrders(const QMap<QString, int> &order,
OneSixInstance *instance)
{
diff --git a/logic/OneSixVersionBuilder.h b/logic/OneSixVersionBuilder.h
index 8cf6f32f..8ca2551a 100644
--- a/logic/OneSixVersionBuilder.h
+++ b/logic/OneSixVersionBuilder.h
@@ -18,7 +18,7 @@
#include <QString>
#include <QMap>
-class OneSixVersion;
+class VersionFinal;
class OneSixInstance;
class QWidget;
class QJsonObject;
@@ -29,8 +29,9 @@ class OneSixVersionBuilder
{
OneSixVersionBuilder();
public:
- static bool build(OneSixVersion *version, OneSixInstance *instance, QWidget *widgetParent, const bool onlyVanilla, const QStringList &external);
- static bool read(OneSixVersion *version, const QJsonObject &obj);
+ static bool build(VersionFinal *version, OneSixInstance *instance, QWidget *widgetParent, const bool onlyVanilla, const QStringList &external);
+ static bool readJsonAndApplyToVersion(VersionFinal *version, const QJsonObject &obj);
+
static QMap<QString, int> readOverrideOrders(OneSixInstance *instance);
static bool writeOverrideOrders(const QMap<QString, int> &order, OneSixInstance *instance);
@@ -42,14 +43,14 @@ public:
Q_DECLARE_FLAGS(ParseFlags, ParseFlag)
private:
- OneSixVersion *m_version;
+ VersionFinal *m_version;
OneSixInstance *m_instance;
QWidget *m_widgetParent;
- bool build(const bool onlyVanilla, const QStringList &external);
- bool read(const QJsonObject &obj);
+ bool buildInternal(const bool onlyVanilla, const QStringList &external);
+ bool readJsonAndApply(const QJsonObject &obj);
- bool read(const QFileInfo &fileInfo, const bool requireOrder, VersionFile *out, const ParseFlags flags = NoFlags);
+ bool parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder, VersionFile *out, const ParseFlags flags = NoFlags);
};
Q_DECLARE_OPERATORS_FOR_FLAGS(OneSixVersionBuilder::ParseFlags)
diff --git a/logic/VersionFile.cpp b/logic/VersionFile.cpp
new file mode 100644
index 00000000..76cf9279
--- /dev/null
+++ b/logic/VersionFile.cpp
@@ -0,0 +1,702 @@
+#include <QJsonArray>
+#include <QJsonDocument>
+
+#include <modutils.h>
+
+#include "logger/QsLog.h"
+#include "logic/VersionFile.h"
+#include "logic/OneSixLibrary.h"
+#include "logic/VersionFinal.h"
+
+
+#define CURRENT_MINIMUM_LAUNCHER_VERSION 14
+
+VersionFile::Library VersionFile::Library::fromJson(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;
+}
+
+VersionFile VersionFile::fromJson(const QJsonDocument &doc, const QString &filename,
+ const bool requireOrder, bool &isError, const bool isFTB)
+{
+ 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();
+ }
+ }
+ };
+
+ // FTB id attribute is completely bogus. We ignore it.
+ if (!isFTB)
+ {
+ 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 = !isFTB;
+ 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 = Library::fromJson(libObj, filename, error);
+ if (error)
+ {
+ QLOG_ERROR() << "Error while reading a library entry in" << filename;
+ return out;
+ }
+ if (isFTB)
+ {
+ 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 = Library::fromJson(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;
+}
+
+std::shared_ptr<OneSixLibrary> VersionFile::createLibrary(const VersionFile::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 VersionFile::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;
+}
+
+VersionFile::ApplyError VersionFile::applyTo(VersionFinal *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)";
+ }
+ }
+
+ VersionFinal::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;
+}
diff --git a/logic/VersionFile.h b/logic/VersionFile.h
new file mode 100644
index 00000000..04694999
--- /dev/null
+++ b/logic/VersionFile.h
@@ -0,0 +1,90 @@
+#pragma once
+
+#include <QString>
+#include <QStringList>
+#include <memory>
+#include "logic/OpSys.h"
+#include "logic/OneSixRule.h"
+class VersionFinal;
+
+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;
+
+ static Library fromJson(const QJsonObject &libObj, const QString &filename,
+ bool &isError);
+ };
+ bool shouldOverwriteLibs = false;
+ QList<Library> overwriteLibs;
+ QList<Library> addLibs;
+ QList<QString> removeLibs;
+
+ enum ApplyError
+ {
+ LauncherVersionError,
+ OtherError,
+ NoApplyError
+ };
+
+ static VersionFile fromJson(const QJsonDocument &doc, const QString &filename,
+ const bool requireOrder, bool &isError,
+ const bool isFTB = false);
+
+ static std::shared_ptr<OneSixLibrary> createLibrary(const Library &lib);
+ int findLibrary(QList<std::shared_ptr<OneSixLibrary>> haystack, const QString &needle);
+ ApplyError applyTo(VersionFinal *version);
+}; \ No newline at end of file
diff --git a/logic/OneSixVersion.cpp b/logic/VersionFinal.cpp
index 06e748bd..ce78e8e3 100644
--- a/logic/OneSixVersion.cpp
+++ b/logic/VersionFinal.cpp
@@ -13,20 +13,20 @@
* limitations under the License.
*/
-#include "OneSixVersion.h"
+#include "VersionFinal.h"
#include <QDebug>
#include <QFile>
#include "OneSixVersionBuilder.h"
-OneSixVersion::OneSixVersion(OneSixInstance *instance, QObject *parent)
+VersionFinal::VersionFinal(OneSixInstance *instance, QObject *parent)
: QAbstractListModel(parent), m_instance(instance)
{
clear();
}
-bool OneSixVersion::reload(QWidget *widgetParent, const bool onlyVanilla, const QStringList &external)
+bool VersionFinal::reload(QWidget *widgetParent, const bool onlyVanilla, const QStringList &external)
{
beginResetModel();
bool ret = OneSixVersionBuilder::build(this, m_instance, widgetParent, onlyVanilla, external);
@@ -34,7 +34,7 @@ bool OneSixVersion::reload(QWidget *widgetParent, const bool onlyVanilla, const
return ret;
}
-void OneSixVersion::clear()
+void VersionFinal::clear()
{
beginResetModel();
id.clear();
@@ -52,9 +52,9 @@ void OneSixVersion::clear()
endResetModel();
}
-void OneSixVersion::dump() const
+void VersionFinal::dump() const
{
- qDebug().nospace() << "OneSixVersion("
+ qDebug().nospace() << "VersionFinal("
<< "\n\tid=" << id
<< "\n\ttime=" << time
<< "\n\treleaseTime=" << releaseTime
@@ -72,7 +72,7 @@ void OneSixVersion::dump() const
qDebug().nospace() << "\n)";
}
-bool OneSixVersion::canRemove(const int index) const
+bool VersionFinal::canRemove(const int index) const
{
if (index < versionFiles.size())
{
@@ -81,7 +81,7 @@ bool OneSixVersion::canRemove(const int index) const
return false;
}
-QString OneSixVersion::versionFileId(const int index) const
+QString VersionFinal::versionFileId(const int index) const
{
if (index < 0 || index >= versionFiles.size())
{
@@ -90,7 +90,7 @@ QString OneSixVersion::versionFileId(const int index) const
return versionFiles.at(index).id;
}
-bool OneSixVersion::remove(const int index)
+bool VersionFinal::remove(const int index)
{
if (canRemove(index))
{
@@ -99,7 +99,7 @@ bool OneSixVersion::remove(const int index)
return false;
}
-QList<std::shared_ptr<OneSixLibrary> > OneSixVersion::getActiveNormalLibs()
+QList<std::shared_ptr<OneSixLibrary> > VersionFinal::getActiveNormalLibs()
{
QList<std::shared_ptr<OneSixLibrary> > output;
for (auto lib : libraries)
@@ -112,7 +112,7 @@ QList<std::shared_ptr<OneSixLibrary> > OneSixVersion::getActiveNormalLibs()
return output;
}
-QList<std::shared_ptr<OneSixLibrary> > OneSixVersion::getActiveNativeLibs()
+QList<std::shared_ptr<OneSixLibrary> > VersionFinal::getActiveNativeLibs()
{
QList<std::shared_ptr<OneSixLibrary> > output;
for (auto lib : libraries)
@@ -125,17 +125,17 @@ QList<std::shared_ptr<OneSixLibrary> > OneSixVersion::getActiveNativeLibs()
return output;
}
-std::shared_ptr<OneSixVersion> OneSixVersion::fromJson(const QJsonObject &obj)
+std::shared_ptr<VersionFinal> VersionFinal::fromJson(const QJsonObject &obj)
{
- std::shared_ptr<OneSixVersion> version(new OneSixVersion(0));
- if (OneSixVersionBuilder::read(version.get(), obj))
+ std::shared_ptr<VersionFinal> version(new VersionFinal(0));
+ if (OneSixVersionBuilder::readJsonAndApplyToVersion(version.get(), obj))
{
return version;
}
return 0;
}
-QVariant OneSixVersion::data(const QModelIndex &index, int role) const
+QVariant VersionFinal::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
@@ -161,7 +161,7 @@ QVariant OneSixVersion::data(const QModelIndex &index, int role) const
return QVariant();
}
-QVariant OneSixVersion::headerData(int section, Qt::Orientation orientation, int role) const
+QVariant VersionFinal::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal)
{
@@ -181,24 +181,24 @@ QVariant OneSixVersion::headerData(int section, Qt::Orientation orientation, int
return QVariant();
}
-Qt::ItemFlags OneSixVersion::flags(const QModelIndex &index) const
+Qt::ItemFlags VersionFinal::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::NoItemFlags;
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
}
-int OneSixVersion::rowCount(const QModelIndex &parent) const
+int VersionFinal::rowCount(const QModelIndex &parent) const
{
return versionFiles.size();
}
-int OneSixVersion::columnCount(const QModelIndex &parent) const
+int VersionFinal::columnCount(const QModelIndex &parent) const
{
return 2;
}
-QDebug operator<<(QDebug &dbg, const OneSixVersion *version)
+QDebug operator<<(QDebug &dbg, const VersionFinal *version)
{
version->dump();
return dbg.maybeSpace();
diff --git a/logic/OneSixVersion.h b/logic/VersionFinal.h
index fee47fa3..c9a5f469 100644
--- a/logic/OneSixVersion.h
+++ b/logic/VersionFinal.h
@@ -25,11 +25,11 @@
class OneSixInstance;
-class OneSixVersion : public QAbstractListModel
+class VersionFinal : public QAbstractListModel
{
Q_OBJECT
public:
- explicit OneSixVersion(OneSixInstance *instance, QObject *parent = 0);
+ explicit VersionFinal(OneSixInstance *instance, QObject *parent = 0);
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
@@ -54,7 +54,7 @@ public:
QList<std::shared_ptr<OneSixLibrary>> getActiveNormalLibs();
QList<std::shared_ptr<OneSixLibrary>> getActiveNativeLibs();
- static std::shared_ptr<OneSixVersion> fromJson(const QJsonObject &obj);
+ static std::shared_ptr<VersionFinal> fromJson(const QJsonObject &obj);
// data members
public:
@@ -133,5 +133,5 @@ private:
OneSixInstance *m_instance;
};
-QDebug operator<<(QDebug &dbg, const OneSixVersion *version);
+QDebug operator<<(QDebug &dbg, const VersionFinal *version);
QDebug operator<<(QDebug &dbg, const OneSixLibrary *library);