From 48d3052ac1bf55dfc0d149d5e2590bcd6545dc67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 20 May 2014 01:17:54 +0200 Subject: [PATCH] New, simpler and versioned format for the patch load order. --- logic/minecraft/InstanceVersion.cpp | 39 +++++------- logic/minecraft/InstanceVersion.h | 3 +- logic/minecraft/VersionBuilder.cpp | 97 +++++++++++++++++------------ logic/minecraft/VersionBuilder.h | 6 +- 4 files changed, 79 insertions(+), 66 deletions(-) diff --git a/logic/minecraft/InstanceVersion.cpp b/logic/minecraft/InstanceVersion.cpp index eb1eeae23..73beceb31 100644 --- a/logic/minecraft/InstanceVersion.cpp +++ b/logic/minecraft/InstanceVersion.cpp @@ -33,8 +33,9 @@ InstanceVersion::InstanceVersion(OneSixInstance *instance, QObject *parent) void InstanceVersion::reload(const QStringList &external) { + m_externalPatches = external; beginResetModel(); - VersionBuilder::build(this, m_instance, external); + VersionBuilder::build(this, m_instance, m_externalPatches); reapply(true); endResetModel(); } @@ -87,10 +88,11 @@ bool InstanceVersion::remove(const int index) } if(!QFile::remove(VersionPatches.at(index)->getPatchFilename())) return false; - beginResetModel(); + beginRemoveRows(QModelIndex(), index, index); VersionPatches.removeAt(index); + endRemoveRows(); reapply(true); - endResetModel(); + saveCurrentOrder(); return true; } @@ -173,11 +175,13 @@ bool InstanceVersion::revertToVanilla() if(!preremove(*it)) { endResetModel(); + saveCurrentOrder(); return false; } if(!QFile::remove((*it)->getPatchFilename())) { endResetModel(); + saveCurrentOrder(); return false; } it = VersionPatches.erase(it); @@ -187,6 +191,7 @@ bool InstanceVersion::revertToVanilla() } reapply(true); endResetModel(); + saveCurrentOrder(); return true; } @@ -295,32 +300,17 @@ int InstanceVersion::columnCount(const QModelIndex &parent) const return 2; } -QMap InstanceVersion::getExistingOrder() const +void InstanceVersion::saveCurrentOrder() const { - QMap order; + PatchOrder order; int index = 0; - // overriden - { - QMap overridenOrder = VersionBuilder::readOverrideOrders(m_instance); - for (auto id : order.keys()) - { - if (overridenOrder.contains(id)) - { - order[id] = overridenOrder[id]; - } - } - } for(auto item: VersionPatches) { - // things with fixed (negative) order. if(!item->isMoveable()) continue; - // the other things. - auto id = item->getPatchID(); - order[id] = index; - index++; + order.append(item->getPatchID()); } - return order; + VersionBuilder::writeOverrideOrders(m_instance, order); } void InstanceVersion::move(const int index, const MoveDirection direction) @@ -352,16 +342,16 @@ void InstanceVersion::move(const int index, const MoveDirection direction) { return; } - beginMoveRows(QModelIndex(), index, index, QModelIndex(), togap); VersionPatches.swap(index, theirIndex); endMoveRows(); + saveCurrentOrder(); reapply(); } void InstanceVersion::resetOrder() { QDir(m_instance->instanceRoot()).remove("order.json"); - reapply(); + reload(m_externalPatches); } void InstanceVersion::reapply(const bool alreadyReseting) @@ -477,6 +467,7 @@ void InstanceVersion::installJarModByFilename(QString filepath) beginInsertRows(QModelIndex(), index, index); VersionPatches.append(f); endInsertRows(); + saveCurrentOrder(); } int InstanceVersion::getFreeOrderNumber() diff --git a/logic/minecraft/InstanceVersion.h b/logic/minecraft/InstanceVersion.h index 00fbf8bb9..60df59dfa 100644 --- a/logic/minecraft/InstanceVersion.h +++ b/logic/minecraft/InstanceVersion.h @@ -175,7 +175,8 @@ public: VersionPatchPtr versionPatch(int index); private: + QStringList m_externalPatches; OneSixInstance *m_instance; - QMap getExistingOrder() const; + void saveCurrentOrder() const; int getFreeOrderNumber(); }; diff --git a/logic/minecraft/VersionBuilder.cpp b/logic/minecraft/VersionBuilder.cpp index 86c1da9ed..6e96191ff 100644 --- a/logic/minecraft/VersionBuilder.cpp +++ b/logic/minecraft/VersionBuilder.cpp @@ -73,10 +73,6 @@ void VersionBuilder::buildFromCustomJson() file->order = -1; file->version = QString(); m_version->VersionPatches.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.") - // some final touches m_version->finalize(); return; } @@ -102,18 +98,48 @@ void VersionBuilder::buildFromVersionJson() void VersionBuilder::readInstancePatches() { + PatchOrder userOrder; + readOverrideOrders(m_instance, userOrder); QDir patches(instance_root.absoluteFilePath("patches/")); + + // first, load things by sort order. + for (auto id : userOrder) + { + // ignore builtins + if (id == "net.minecraft") + continue; + if (id == "org.lwjgl") + continue; + // parse the file + QString filename = patches.absoluteFilePath(id + ".json"); + QLOG_INFO() << "Reading" << filename << "by user order"; + auto file = parseJsonFile(QFileInfo(filename), false); + // sanity check. prevent tampering with files. + if (file->fileId != id) + { + throw VersionBuildError( + QObject::tr("load id %1 does not match internal id %2").arg(id, file->fileId)); + } + m_version->VersionPatches.append(file); + } + // now load the rest by internal preference. QMap> files; for (auto info : patches.entryInfoList(QStringList() << "*.json", QDir::Files)) { + // parse the file QLOG_INFO() << "Reading" << info.fileName(); auto file = parseJsonFile(info, true); - if(file->fileId == "net.minecraft") + // ignore builtins + if (file->fileId == "net.minecraft") continue; - if(file->fileId == "org.lwjgl") + if (file->fileId == "org.lwjgl") + continue; + // do not load what we already loaded in the first pass + if (userOrder.contains(file->fileId)) continue; if (files.contains(file->order)) { + // FIXME: do not throw? throw VersionBuildError(QObject::tr("%1 has the same order as %2") .arg(file->fileId, files[file->order].second->fileId)); } @@ -152,7 +178,7 @@ void VersionBuilder::buildFromMultilayer() auto minecraftList = MMC->minecraftlist(); auto mcversion = minecraftList->findVersion(m_instance->intendedVersionId()); auto minecraftPatch = std::dynamic_pointer_cast(mcversion); - if(!minecraftPatch) + if (!minecraftPatch) { throw VersionIncomplete("net.minecraft"); } @@ -162,7 +188,7 @@ void VersionBuilder::buildFromMultilayer() QResource LWJGL(":/versions/LWJGL/2.9.1.json"); auto lwjgl = parseJsonFile(LWJGL.absoluteFilePath(), false, false); auto lwjglPatch = std::dynamic_pointer_cast(lwjgl); - if(!lwjglPatch) + if (!lwjglPatch) { throw VersionIncomplete("org.lwjgl"); } @@ -205,13 +231,9 @@ void VersionBuilder::readJsonAndApply(const QJsonObject &obj) m_version->clear(); auto file = VersionFile::fromJson(QJsonDocument(obj), QString(), false); - // QObject::tr("Error while reading. Please check MultiMC-0.log for more info.")); file->applyTo(m_version); m_version->VersionPatches.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")); } VersionFilePtr VersionBuilder::parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder, @@ -233,8 +255,6 @@ VersionFilePtr VersionBuilder::parseJsonFile(const QFileInfo &fileInfo, const bo .arg(error.offset)); } 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()); } VersionFilePtr VersionBuilder::parseBinaryJsonFile(const QFileInfo &fileInfo) @@ -256,22 +276,17 @@ VersionFilePtr VersionBuilder::parseBinaryJsonFile(const QFileInfo &fileInfo) return VersionFile::fromJson(doc, file.fileName(), false, false); } -QMap VersionBuilder::readOverrideOrders(OneSixInstance *instance) +static const int currentOrderFileVersion = 1; + +bool VersionBuilder::readOverrideOrders(OneSixInstance *instance, PatchOrder &order) { - QMap out; - - // 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)) { QLOG_ERROR() << "Couldn't open" << orderFile.fileName() << " for reading:" << orderFile.errorString(); QLOG_WARN() << "Ignoring overriden order"; - return out; + return false; } // and it's valid JSON @@ -281,42 +296,46 @@ QMap VersionBuilder::readOverrideOrders(OneSixInstance *instance) { QLOG_ERROR() << "Couldn't parse" << orderFile.fileName() << ":" << error.errorString(); QLOG_WARN() << "Ignoring overriden order"; - return out; + return false; } // 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) + // check order file version. + auto version = MMCJson::ensureInteger(obj.value("version"), "version"); + if (version != currentOrderFileVersion) { - if (it.key().startsWith("org.multimc.")) - { - continue; - } - out.insert(it.key(), MMCJson::ensureInteger(it.value())); + throw JSONValidationError(QObject::tr("Invalid order file version, expected %1") + .arg(currentOrderFileVersion)); + } + auto orderArray = MMCJson::ensureArray(obj.value("order")); + for(auto item: orderArray) + { + order.append(MMCJson::ensureString(item)); } } catch (JSONValidationError &err) { QLOG_ERROR() << "Couldn't parse" << orderFile.fileName() << ": bad file format"; QLOG_WARN() << "Ignoring overriden order"; - return out; + order.clear(); + return false; } - return out; + return true; } -bool VersionBuilder::writeOverrideOrders(const QMap &order, - OneSixInstance *instance) +bool VersionBuilder::writeOverrideOrders(OneSixInstance *instance, const PatchOrder &order) { QJsonObject obj; - for (auto it = order.cbegin(); it != order.cend(); ++it) + obj.insert("version", currentOrderFileVersion); + QJsonArray orderArray; + for(auto str: order) { - int order = it.value(); - if(order < 0) - continue; - obj.insert(it.key(), it.value()); + orderArray.append(str); } + obj.insert("order", orderArray); QFile orderFile(instance->instanceRoot() + "/order.json"); if (!orderFile.open(QFile::WriteOnly)) { diff --git a/logic/minecraft/VersionBuilder.h b/logic/minecraft/VersionBuilder.h index 777461990..350179b90 100644 --- a/logic/minecraft/VersionBuilder.h +++ b/logic/minecraft/VersionBuilder.h @@ -24,6 +24,8 @@ class OneSixInstance; class QJsonObject; class QFileInfo; +typedef QStringList PatchOrder; + class VersionBuilder { VersionBuilder(); @@ -33,8 +35,8 @@ public: static VersionFilePtr parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder, bool isFTB = false); static VersionFilePtr parseBinaryJsonFile(const QFileInfo &fileInfo); - static QMap readOverrideOrders(OneSixInstance *instance); - static bool writeOverrideOrders(const QMap &order, OneSixInstance *instance); + bool readOverrideOrders(OneSixInstance *instance, PatchOrder &order); + static bool writeOverrideOrders(OneSixInstance *instance, const PatchOrder &order); private: InstanceVersion *m_version;