aboutsummaryrefslogtreecommitdiff
path: root/logic/minecraft
diff options
context:
space:
mode:
authorPetr Mrázek <peterix@gmail.com>2014-05-08 21:20:10 +0200
committerPetr Mrázek <peterix@gmail.com>2014-06-09 01:38:30 +0200
commit8a3a0f5a529a95c7511436051b63887dff158c50 (patch)
tree0162e0d6a37cd5a5b3aa5facf6ba6561e33f60bf /logic/minecraft
parent69a9ca39ad0685663092a4455de3865715f0122e (diff)
downloadPrismLauncher-8a3a0f5a529a95c7511436051b63887dff158c50.tar.gz
PrismLauncher-8a3a0f5a529a95c7511436051b63887dff158c50.tar.bz2
PrismLauncher-8a3a0f5a529a95c7511436051b63887dff158c50.zip
Reorganize logic code.
Diffstat (limited to 'logic/minecraft')
-rw-r--r--logic/minecraft/MinecraftVersion.h92
-rw-r--r--logic/minecraft/MinecraftVersionList.cpp330
-rw-r--r--logic/minecraft/MinecraftVersionList.h76
-rw-r--r--logic/minecraft/OneSixLibrary.cpp274
-rw-r--r--logic/minecraft/OneSixLibrary.h148
-rw-r--r--logic/minecraft/OneSixRule.cpp89
-rw-r--r--logic/minecraft/OneSixRule.h98
-rw-r--r--logic/minecraft/OneSixVersionBuilder.cpp249
-rw-r--r--logic/minecraft/OneSixVersionBuilder.h46
-rw-r--r--logic/minecraft/OpSys.cpp42
-rw-r--r--logic/minecraft/OpSys.h37
-rw-r--r--logic/minecraft/VersionFile.cpp635
-rw-r--r--logic/minecraft/VersionFile.h145
-rw-r--r--logic/minecraft/VersionFinal.cpp429
-rw-r--r--logic/minecraft/VersionFinal.h172
15 files changed, 2862 insertions, 0 deletions
diff --git a/logic/minecraft/MinecraftVersion.h b/logic/minecraft/MinecraftVersion.h
new file mode 100644
index 00000000..3be25912
--- /dev/null
+++ b/logic/minecraft/MinecraftVersion.h
@@ -0,0 +1,92 @@
+/* Copyright 2013 Andrew Okin
+ *
+ * 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 "logic/BaseVersion.h"
+#include <QStringList>
+#include <QSet>
+
+struct MinecraftVersion : public BaseVersion
+{
+ /// The version's timestamp - this is primarily used for sorting versions in a list.
+ qint64 timestamp;
+
+ /// The URL that this version will be downloaded from. maybe.
+ QString download_url;
+
+ /// is this the latest version?
+ bool is_latest = false;
+
+ /// is this a snapshot?
+ bool is_snapshot = false;
+
+ /// is this a built-in version that comes with MultiMC?
+ bool is_builtin = false;
+
+ /// the human readable version name
+ QString m_name;
+
+ /// the version ID.
+ QString m_descriptor;
+
+ /// version traits. generally launcher business...
+ QSet<QString> m_traits;
+
+ /// The main class this version uses (if any, can be empty).
+ QString m_mainClass;
+
+ /// The applet class this version uses (if any, can be empty).
+ QString m_appletClass;
+
+ bool usesLegacyLauncher()
+ {
+ return m_traits.contains("legacyLaunch") || m_traits.contains("aplhaLaunch");
+ }
+
+ virtual QString descriptor() override
+ {
+ return m_descriptor;
+ }
+
+ virtual QString name() override
+ {
+ return m_name;
+ }
+
+ virtual QString typeString() const override
+ {
+ if (is_latest && is_snapshot)
+ {
+ return QObject::tr("Latest snapshot");
+ }
+ else if(is_latest)
+ {
+ return QObject::tr("Latest release");
+ }
+ else if(is_snapshot)
+ {
+ return QObject::tr("Snapshot");
+ }
+ else if(is_builtin)
+ {
+ return QObject::tr("Museum piece");
+ }
+ else
+ {
+ return QObject::tr("Regular release");
+ }
+ }
+};
diff --git a/logic/minecraft/MinecraftVersionList.cpp b/logic/minecraft/MinecraftVersionList.cpp
new file mode 100644
index 00000000..cdf5fa77
--- /dev/null
+++ b/logic/minecraft/MinecraftVersionList.cpp
@@ -0,0 +1,330 @@
+/* Copyright 2013 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MinecraftVersionList.h"
+#include "MultiMC.h"
+#include "logic/net/URLConstants.h"
+#include <logic/MMCJson.h>
+
+#include <QtXml>
+
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QJsonArray>
+#include <QJsonValue>
+#include <QJsonParseError>
+
+#include <QtAlgorithms>
+
+#include <QtNetwork>
+
+inline QDateTime timeFromS3Time(QString str)
+{
+ return QDateTime::fromString(str, Qt::ISODate);
+}
+
+MinecraftVersionList::MinecraftVersionList(QObject *parent) : BaseVersionList(parent)
+{
+ loadBuiltinList();
+}
+
+Task *MinecraftVersionList::getLoadTask()
+{
+ return new MCVListLoadTask(this);
+}
+
+bool MinecraftVersionList::isLoaded()
+{
+ return m_loaded;
+}
+
+const BaseVersionPtr MinecraftVersionList::at(int i) const
+{
+ return m_vlist.at(i);
+}
+
+int MinecraftVersionList::count() const
+{
+ return m_vlist.count();
+}
+
+static bool cmpVersions(BaseVersionPtr first, BaseVersionPtr second)
+{
+ auto left = std::dynamic_pointer_cast<MinecraftVersion>(first);
+ auto right = std::dynamic_pointer_cast<MinecraftVersion>(second);
+ return left->timestamp > right->timestamp;
+}
+
+void MinecraftVersionList::sortInternal()
+{
+ qSort(m_vlist.begin(), m_vlist.end(), cmpVersions);
+}
+
+void MinecraftVersionList::loadBuiltinList()
+{
+ // grab the version list data from internal resources.
+ QResource versionList(":/versions/minecraft.json");
+ QFile filez(versionList.absoluteFilePath());
+ filez.open(QIODevice::ReadOnly);
+ auto data = filez.readAll();
+
+ // parse the data as json
+ QJsonParseError jsonError;
+ QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
+ QJsonObject root = jsonDoc.object();
+
+ // parse all the versions
+ for (const auto version : MMCJson::ensureArray(root.value("versions")))
+ {
+ QJsonObject versionObj = version.toObject();
+ QString versionID = versionObj.value("id").toString("");
+ QString versionTimeStr = versionObj.value("releaseTime").toString("");
+ QString versionTypeStr = versionObj.value("type").toString("");
+ QSet<QString> traits;
+ if (versionObj.contains("+traits"))
+ {
+ for (auto traitVal : MMCJson::ensureArray(versionObj.value("+traits")))
+ {
+ traits.insert(MMCJson::ensureString(traitVal));
+ }
+ }
+ if (versionID.isEmpty() || versionTimeStr.isEmpty() || versionTypeStr.isEmpty())
+ {
+ // FIXME: log this somewhere
+ continue;
+ }
+ // Parse the timestamp.
+ QDateTime versionTime = timeFromS3Time(versionTimeStr);
+ if (!versionTime.isValid())
+ {
+ // FIXME: log this somewhere
+ continue;
+ }
+ // Get the download URL.
+ QString dlUrl = "http://" + URLConstants::AWS_DOWNLOAD_VERSIONS + versionID + "/";
+
+ // main class and applet class
+ QString mainClass = versionObj.value("type").toString("");
+ QString appletClass = versionObj.value("type").toString("");
+
+ // Now, we construct the version object and add it to the list.
+ std::shared_ptr<MinecraftVersion> mcVersion(new MinecraftVersion());
+ mcVersion->m_name = mcVersion->m_descriptor = versionID;
+ mcVersion->timestamp = versionTime.toMSecsSinceEpoch();
+ mcVersion->download_url = dlUrl;
+ mcVersion->is_builtin = true;
+ mcVersion->m_appletClass = appletClass;
+ mcVersion->m_mainClass = mainClass;
+ mcVersion->m_traits = traits;
+ m_vlist.append(mcVersion);
+ }
+}
+
+void MinecraftVersionList::sort()
+{
+ beginResetModel();
+ sortInternal();
+ endResetModel();
+}
+
+BaseVersionPtr MinecraftVersionList::getLatestStable() const
+{
+ for (int i = 0; i < m_vlist.length(); i++)
+ {
+ auto ver = std::dynamic_pointer_cast<MinecraftVersion>(m_vlist.at(i));
+ if (ver->is_latest && !ver->is_snapshot)
+ {
+ return m_vlist.at(i);
+ }
+ }
+ return BaseVersionPtr();
+}
+
+void MinecraftVersionList::updateListData(QList<BaseVersionPtr> versions)
+{
+ beginResetModel();
+ for (auto version : versions)
+ {
+ auto descr = version->descriptor();
+ for (auto builtin_v : m_vlist)
+ {
+ if (descr == builtin_v->descriptor())
+ {
+ goto SKIP_THIS_ONE;
+ }
+ }
+ m_vlist.append(version);
+ SKIP_THIS_ONE:
+ {
+ }
+ }
+ m_loaded = true;
+ sortInternal();
+ endResetModel();
+}
+
+inline QDomElement getDomElementByTagName(QDomElement parent, QString tagname)
+{
+ QDomNodeList elementList = parent.elementsByTagName(tagname);
+ if (elementList.count())
+ return elementList.at(0).toElement();
+ else
+ return QDomElement();
+}
+
+MCVListLoadTask::MCVListLoadTask(MinecraftVersionList *vlist)
+{
+ m_list = vlist;
+ m_currentStable = NULL;
+ vlistReply = nullptr;
+}
+
+MCVListLoadTask::~MCVListLoadTask()
+{
+}
+
+void MCVListLoadTask::executeTask()
+{
+ setStatus(tr("Loading instance version list..."));
+ auto worker = MMC->qnam();
+ vlistReply = worker->get(QNetworkRequest(
+ QUrl("http://" + URLConstants::AWS_DOWNLOAD_VERSIONS + "versions.json")));
+ connect(vlistReply, SIGNAL(finished()), this, SLOT(list_downloaded()));
+}
+
+void MCVListLoadTask::list_downloaded()
+{
+ if (vlistReply->error() != QNetworkReply::NoError)
+ {
+ vlistReply->deleteLater();
+ emitFailed("Failed to load Minecraft main version list" + vlistReply->errorString());
+ return;
+ }
+
+ auto foo = vlistReply->readAll();
+ QJsonParseError jsonError;
+ QLOG_INFO() << foo;
+ QJsonDocument jsonDoc = QJsonDocument::fromJson(foo, &jsonError);
+ vlistReply->deleteLater();
+
+ if (jsonError.error != QJsonParseError::NoError)
+ {
+ emitFailed("Error parsing version list JSON:" + jsonError.errorString());
+ return;
+ }
+
+ if (!jsonDoc.isObject())
+ {
+ emitFailed("Error parsing version list JSON: jsonDoc is not an object");
+ return;
+ }
+
+ QJsonObject root = jsonDoc.object();
+
+ QString latestReleaseID = "INVALID";
+ QString latestSnapshotID = "INVALID";
+ try
+ {
+ QJsonObject latest = MMCJson::ensureObject(root.value("latest"));
+ latestReleaseID = MMCJson::ensureString(latest.value("release"));
+ latestSnapshotID = MMCJson::ensureString(latest.value("snapshot"));
+ }
+ catch (MMCError &err)
+ {
+ QLOG_ERROR()
+ << tr("Error parsing version list JSON: couldn't determine latest versions");
+ }
+
+ // Now, get the array of versions.
+ if (!root.value("versions").isArray())
+ {
+ emitFailed(
+ "Error parsing version list JSON: version list object is missing 'versions' array");
+ return;
+ }
+ QJsonArray versions = root.value("versions").toArray();
+
+ QList<BaseVersionPtr> tempList;
+ for (auto version : versions)
+ {
+ bool is_snapshot = false;
+ bool is_latest = false;
+
+ // Load the version info.
+ if (!version.isObject())
+ {
+ // FIXME: log this somewhere
+ continue;
+ }
+ QJsonObject versionObj = version.toObject();
+ QString versionID = versionObj.value("id").toString("");
+ QString versionTimeStr = versionObj.value("releaseTime").toString("");
+ QString versionTypeStr = versionObj.value("type").toString("");
+ if (versionID.isEmpty() || versionTimeStr.isEmpty() || versionTypeStr.isEmpty())
+ {
+ // FIXME: log this somewhere
+ continue;
+ }
+
+ // Parse the timestamp.
+ QDateTime versionTime = timeFromS3Time(versionTimeStr);
+ if (!versionTime.isValid())
+ {
+ // FIXME: log this somewhere
+ continue;
+ }
+ // OneSix or Legacy. use filter to determine type
+ if (versionTypeStr == "release")
+ {
+ is_latest = (versionID == latestReleaseID);
+ is_snapshot = false;
+ }
+ else if (versionTypeStr == "snapshot") // It's a snapshot... yay
+ {
+ is_latest = (versionID == latestSnapshotID);
+ is_snapshot = true;
+ }
+ else if (versionTypeStr == "old_alpha")
+ {
+ is_latest = false;
+ is_snapshot = false;
+ }
+ else if (versionTypeStr == "old_beta")
+ {
+ is_latest = false;
+ is_snapshot = false;
+ }
+ else
+ {
+ // FIXME: log this somewhere
+ continue;
+ }
+ // Get the download URL.
+ QString dlUrl = "http://" + URLConstants::AWS_DOWNLOAD_VERSIONS + versionID + "/";
+
+ // Now, we construct the version object and add it to the list.
+ std::shared_ptr<MinecraftVersion> mcVersion(new MinecraftVersion());
+ mcVersion->m_name = mcVersion->m_descriptor = versionID;
+ mcVersion->timestamp = versionTime.toMSecsSinceEpoch();
+ mcVersion->download_url = dlUrl;
+ mcVersion->is_latest = is_latest;
+ mcVersion->is_snapshot = is_snapshot;
+ tempList.append(mcVersion);
+ }
+ m_list->updateListData(tempList);
+
+ emitSucceeded();
+ return;
+}
diff --git a/logic/minecraft/MinecraftVersionList.h b/logic/minecraft/MinecraftVersionList.h
new file mode 100644
index 00000000..18b9b21e
--- /dev/null
+++ b/logic/minecraft/MinecraftVersionList.h
@@ -0,0 +1,76 @@
+/* Copyright 2013 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <QObject>
+#include <QList>
+#include <QSet>
+
+#include "logic/BaseVersionList.h"
+#include "logic/tasks/Task.h"
+#include "logic/minecraft/MinecraftVersion.h"
+
+class MCVListLoadTask;
+class QNetworkReply;
+
+class MinecraftVersionList : public BaseVersionList
+{
+ Q_OBJECT
+private:
+ void sortInternal();
+ void loadBuiltinList();
+public:
+ friend class MCVListLoadTask;
+
+ explicit MinecraftVersionList(QObject *parent = 0);
+
+ virtual Task *getLoadTask();
+ virtual bool isLoaded();
+ virtual const BaseVersionPtr at(int i) const;
+ virtual int count() const;
+ virtual void sort();
+
+ virtual BaseVersionPtr getLatestStable() const;
+
+protected:
+ QList<BaseVersionPtr> m_vlist;
+
+ bool m_loaded = false;
+
+protected
+slots:
+ virtual void updateListData(QList<BaseVersionPtr> versions);
+};
+
+class MCVListLoadTask : public Task
+{
+ Q_OBJECT
+
+public:
+ explicit MCVListLoadTask(MinecraftVersionList *vlist);
+ ~MCVListLoadTask();
+
+ virtual void executeTask();
+
+protected
+slots:
+ void list_downloaded();
+
+protected:
+ QNetworkReply *vlistReply;
+ MinecraftVersionList *m_list;
+ MinecraftVersion *m_currentStable;
+};
diff --git a/logic/minecraft/OneSixLibrary.cpp b/logic/minecraft/OneSixLibrary.cpp
new file mode 100644
index 00000000..45fa169e
--- /dev/null
+++ b/logic/minecraft/OneSixLibrary.cpp
@@ -0,0 +1,274 @@
+/* Copyright 2013 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <QJsonArray>
+
+#include "OneSixLibrary.h"
+#include "OneSixRule.h"
+#include "OpSys.h"
+#include "logic/net/URLConstants.h"
+#include <pathutils.h>
+#include <JlCompress.h>
+#include "logger/QsLog.h"
+
+void OneSixLibrary::finalize()
+{
+ QStringList parts = m_name.split(':');
+ QString relative = parts[0];
+ relative.replace('.', '/');
+ relative += '/' + parts[1] + '/' + parts[2] + '/' + parts[1] + '-' + parts[2];
+
+ if (!m_is_native)
+ relative += ".jar";
+ else
+ {
+ if (m_native_suffixes.contains(currentSystem))
+ {
+ relative += "-" + m_native_suffixes[currentSystem] + ".jar";
+ }
+ else
+ {
+ // really, bad.
+ relative += ".jar";
+ }
+ }
+
+ m_decentname = parts[1];
+ m_decentversion = minVersion = parts[2];
+ m_storage_path = relative;
+ m_download_url = m_base_url + relative;
+
+ if (m_rules.empty())
+ {
+ m_is_active = true;
+ }
+ else
+ {
+ RuleAction result = Disallow;
+ for (auto rule : m_rules)
+ {
+ RuleAction temp = rule->apply(this);
+ if (temp != Defer)
+ result = temp;
+ }
+ m_is_active = (result == Allow);
+ }
+ if (m_is_native)
+ {
+ m_is_active = m_is_active && m_native_suffixes.contains(currentSystem);
+ m_decenttype = "Native";
+ }
+ else
+ {
+ m_decenttype = "Java";
+ }
+}
+
+void OneSixLibrary::setName(const QString &name)
+{
+ m_name = name;
+}
+void OneSixLibrary::setBaseUrl(const QString &base_url)
+{
+ m_base_url = base_url;
+}
+void OneSixLibrary::setIsNative()
+{
+ m_is_native = true;
+}
+void OneSixLibrary::addNative(OpSys os, const QString &suffix)
+{
+ m_is_native = true;
+ m_native_suffixes[os] = suffix;
+}
+void OneSixLibrary::clearSuffixes()
+{
+ m_native_suffixes.clear();
+}
+void OneSixLibrary::setRules(QList<std::shared_ptr<Rule>> rules)
+{
+ m_rules = rules;
+}
+bool OneSixLibrary::isActive() const
+{
+ return m_is_active;
+}
+bool OneSixLibrary::isNative() const
+{
+ return m_is_native;
+}
+QString OneSixLibrary::downloadUrl() const
+{
+ if (m_absolute_url.size())
+ return m_absolute_url;
+ return m_download_url;
+}
+QString OneSixLibrary::storagePath() const
+{
+ return m_storage_path;
+}
+
+void OneSixLibrary::setAbsoluteUrl(const QString &absolute_url)
+{
+ m_absolute_url = absolute_url;
+}
+
+QString OneSixLibrary::absoluteUrl() const
+{
+ return m_absolute_url;
+}
+
+void OneSixLibrary::setHint(const QString &hint)
+{
+ m_hint = hint;
+}
+
+QString OneSixLibrary::hint() const
+{
+ return m_hint;
+}
+
+QStringList OneSixLibrary::files()
+{
+ QStringList retval;
+ QString storage = storagePath();
+ if (storage.contains("${arch}"))
+ {
+ QString cooked_storage = storage;
+ cooked_storage.replace("${arch}", "32");
+ retval.append(cooked_storage);
+ cooked_storage = storage;
+ cooked_storage.replace("${arch}", "64");
+ retval.append(cooked_storage);
+ }
+ else
+ retval.append(storage);
+ return retval;
+}
+
+bool OneSixLibrary::filesExist(const QDir &base)
+{
+ auto libFiles = files();
+ for(auto file: libFiles)
+ {
+ QFileInfo info(base, file);
+ QLOG_WARN() << info.absoluteFilePath() << "doesn't exist";
+ if (!info.exists())
+ return false;
+ }
+ return true;
+}
+
+bool OneSixLibrary::extractTo(QString target_dir)
+{
+ QString storage = storagePath();
+ if (storage.contains("${arch}"))
+ {
+ QString cooked_storage = storage;
+ cooked_storage.replace("${arch}", "32");
+ QString origin = PathCombine("libraries", cooked_storage);
+ QString target_dir_cooked = PathCombine(target_dir, "32");
+ if (!ensureFolderPathExists(target_dir_cooked))
+ {
+ QLOG_ERROR() << "Couldn't create folder " + target_dir_cooked;
+ return false;
+ }
+ if (JlCompress::extractWithExceptions(origin, target_dir_cooked, extract_excludes)
+ .isEmpty())
+ {
+ QLOG_ERROR() << "Couldn't extract " + origin;
+ return false;
+ }
+ cooked_storage = storage;
+ cooked_storage.replace("${arch}", "64");
+ origin = PathCombine("libraries", cooked_storage);
+ target_dir_cooked = PathCombine(target_dir, "64");
+ if (!ensureFolderPathExists(target_dir_cooked))
+ {
+ QLOG_ERROR() << "Couldn't create folder " + target_dir_cooked;
+ return false;
+ }
+ if (JlCompress::extractWithExceptions(origin, target_dir_cooked, extract_excludes)
+ .isEmpty())
+ {
+ QLOG_ERROR() << "Couldn't extract " + origin;
+ return false;
+ }
+ }
+ else
+ {
+ if (!ensureFolderPathExists(target_dir))
+ {
+ QLOG_ERROR() << "Couldn't create folder " + target_dir;
+ return false;
+ }
+ QString path = PathCombine("libraries", storage);
+ if (JlCompress::extractWithExceptions(path, target_dir, extract_excludes).isEmpty())
+ {
+ QLOG_ERROR() << "Couldn't extract " + path;
+ return false;
+ }
+ }
+ return true;
+}
+
+QJsonObject OneSixLibrary::toJson()
+{
+ QJsonObject libRoot;
+ libRoot.insert("name", m_name);
+ if (m_absolute_url.size())
+ libRoot.insert("MMC-absoluteUrl", m_absolute_url);
+ if (m_hint.size())
+ libRoot.insert("MMC-hint", m_hint);
+ if (m_base_url != "http://" + URLConstants::AWS_DOWNLOAD_LIBRARIES &&
+ m_base_url != "https://" + URLConstants::AWS_DOWNLOAD_LIBRARIES &&
+ m_base_url != "https://" + URLConstants::LIBRARY_BASE && !m_base_url.isEmpty())
+ {
+ libRoot.insert("url", m_base_url);
+ }
+ if (isNative() && m_native_suffixes.size())
+ {
+ QJsonObject nativeList;
+ auto iter = m_native_suffixes.begin();
+ while (iter != m_native_suffixes.end())
+ {
+ nativeList.insert(OpSys_toString(iter.key()), iter.value());
+ iter++;
+ }
+ libRoot.insert("natives", nativeList);
+ }
+ if (isNative() && extract_excludes.size())
+ {
+ QJsonArray excludes;
+ QJsonObject extract;
+ for (auto exclude : extract_excludes)
+ {
+ excludes.append(exclude);
+ }
+ extract.insert("exclude", excludes);
+ libRoot.insert("extract", extract);
+ }
+ if (m_rules.size())
+ {
+ QJsonArray allRules;
+ for (auto &rule : m_rules)
+ {
+ QJsonObject ruleObj = rule->toJson();
+ allRules.append(ruleObj);
+ }
+ libRoot.insert("rules", allRules);
+ }
+ return libRoot;
+}
diff --git a/logic/minecraft/OneSixLibrary.h b/logic/minecraft/OneSixLibrary.h
new file mode 100644
index 00000000..13df0606
--- /dev/null
+++ b/logic/minecraft/OneSixLibrary.h
@@ -0,0 +1,148 @@
+/* Copyright 2013 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <QString>
+#include <QStringList>
+#include <QMap>
+#include <QJsonObject>
+#include <QDir>
+#include <memory>
+
+#include "logic/net/URLConstants.h"
+#include "logic/minecraft/OpSys.h"
+
+class Rule;
+
+class OneSixLibrary;
+typedef std::shared_ptr<OneSixLibrary> OneSixLibraryPtr;
+
+class OneSixLibrary
+{
+private:
+ // basic values used internally (so far)
+ QString m_name;
+ QString m_base_url = "https://" + URLConstants::LIBRARY_BASE;
+ QList<std::shared_ptr<Rule>> m_rules;
+
+ // custom values
+ /// absolute URL. takes precedence over m_download_path, if defined
+ QString m_absolute_url;
+ /// type hint - modifies how the library is treated
+ QString m_hint;
+
+ // derived values used for real things
+ /// a decent name fit for display
+ QString m_decentname;
+ /// a decent version fit for display
+ QString m_decentversion;
+ /// a decent type fit for display
+ QString m_decenttype;
+ /// where to store the lib locally
+ QString m_storage_path;
+ /// where to download the lib from
+ QString m_download_url;
+ /// is this lib actually active on the current OS?
+ bool m_is_active = false;
+ /// is the library a native?
+ bool m_is_native = false;
+ /// native suffixes per OS
+ QMap<OpSys, QString> m_native_suffixes;
+
+public:
+ QStringList extract_excludes;
+ QString minVersion;
+
+ enum DependType
+ {
+ Soft,
+ Hard
+ };
+ DependType dependType;
+
+public:
+ /// Constructor
+ OneSixLibrary(const QString &name, const DependType type = Soft)
+ {
+ m_name = name;
+ dependType = type;
+ }
+
+ /// Returns the raw name field
+ QString rawName() const
+ {
+ return m_name;
+ }
+
+ QJsonObject toJson();
+
+ /**
+ * finalize the library, processing the input values into derived values and state
+ *
+ * This SHALL be called after all the values are parsed or after any further change.
+ */
+ void finalize();
+
+ /// Set the library composite name
+ void setName(const QString &name);
+ /// get a decent-looking name
+ QString name() const
+ {
+ return m_decentname;
+ }
+ /// get a decent-looking version
+ QString version() const
+ {
+ return m_decentversion;
+ }
+ /// what kind of library is it? (for display)
+ QString type() const
+ {
+ return m_decenttype;
+ }
+ /// Set the url base for downloads
+ void setBaseUrl(const QString &base_url);
+
+ /// Call this to mark the library as 'native' (it's a zip archive with DLLs)
+ void setIsNative();
+ /// Attach a name suffix to the specified OS native
+ void addNative(OpSys os, const QString &suffix);
+ /// Clears all suffixes
+ void clearSuffixes();
+ /// Set the load rules
+ void setRules(QList<std::shared_ptr<Rule>> rules);
+
+ /// Returns true if the library should be loaded (or extracted, in case of natives)
+ bool isActive() const;
+ /// Returns true if the library is native
+ bool isNative() const;
+ /// Get the URL to download the library from
+ QString downloadUrl() const;
+ /// Get the relative path where the library should be saved
+ QString storagePath() const;
+
+ /// set an absolute URL for the library. This is an MMC extension.
+ void setAbsoluteUrl(const QString &absolute_url);
+ QString absoluteUrl() const;
+
+ /// set a hint about how to treat the library. This is an MMC extension.
+ void setHint(const QString &hint);
+ QString hint() const;
+
+ bool extractTo(QString target_dir);
+ bool filesExist(const QDir &base);
+ QStringList files();
+};
diff --git a/logic/minecraft/OneSixRule.cpp b/logic/minecraft/OneSixRule.cpp
new file mode 100644
index 00000000..d8d13b50
--- /dev/null
+++ b/logic/minecraft/OneSixRule.cpp
@@ -0,0 +1,89 @@
+/* Copyright 2013 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <QJsonObject>
+#include <QJsonArray>
+
+#include "OneSixRule.h"
+
+QList<std::shared_ptr<Rule>> rulesFromJsonV4(const QJsonObject &objectWithRules)
+{
+ QList<std::shared_ptr<Rule>> rules;
+ auto rulesVal = objectWithRules.value("rules");
+ if (!rulesVal.isArray())
+ return rules;
+
+ QJsonArray ruleList = rulesVal.toArray();
+ for (auto ruleVal : ruleList)
+ {
+ std::shared_ptr<Rule> rule;
+ if (!ruleVal.isObject())
+ continue;
+ auto ruleObj = ruleVal.toObject();
+ auto actionVal = ruleObj.value("action");
+ if (!actionVal.isString())
+ continue;
+ auto action = RuleAction_fromString(actionVal.toString());
+ if (action == Defer)
+ continue;
+
+ auto osVal = ruleObj.value("os");
+ if (!osVal.isObject())
+ {
+ // add a new implicit action rule
+ rules.append(ImplicitRule::create(action));
+ continue;
+ }
+
+ auto osObj = osVal.toObject();
+ auto osNameVal = osObj.value("name");
+ if (!osNameVal.isString())
+ continue;
+ OpSys requiredOs = OpSys_fromString(osNameVal.toString());
+ QString versionRegex = osObj.value("version").toString();
+ // add a new OS rule
+ rules.append(OsRule::create(action, requiredOs, versionRegex));
+ }
+ return rules;
+}
+
+QJsonObject ImplicitRule::toJson()
+{
+ QJsonObject ruleObj;
+ ruleObj.insert("action", m_result == Allow ? QString("allow") : QString("disallow"));
+ return ruleObj;
+}
+
+QJsonObject OsRule::toJson()
+{
+ QJsonObject ruleObj;
+ ruleObj.insert("action", m_result == Allow ? QString("allow") : QString("disallow"));
+ QJsonObject osObj;
+ {
+ osObj.insert("name", OpSys_toString(m_system));
+ osObj.insert("version", m_version_regexp);
+ }
+ ruleObj.insert("os", osObj);
+ return ruleObj;
+}
+
+RuleAction RuleAction_fromString(QString name)
+{
+ if (name == "allow")
+ return Allow;
+ if (name == "disallow")
+ return Disallow;
+ return Defer;
+}
diff --git a/logic/minecraft/OneSixRule.h b/logic/minecraft/OneSixRule.h
new file mode 100644
index 00000000..2c569b9f
--- /dev/null
+++ b/logic/minecraft/OneSixRule.h
@@ -0,0 +1,98 @@
+/* Copyright 2013 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * Se