From 9860d5ee12acde8f7893848dac53f59ea66da281 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 9 May 2014 17:16:25 +0200 Subject: Introducing VersionPatch base class for version files and minecraft versions --- logic/OneSixFTBInstance.cpp | 2 +- logic/OneSixUpdate.cpp | 2 +- logic/minecraft/JarMod.cpp | 44 ++++++ logic/minecraft/JarMod.h | 17 +++ logic/minecraft/MinecraftVersion.cpp | 2 + logic/minecraft/MinecraftVersion.h | 18 ++- logic/minecraft/OneSixRule.cpp | 17 ++- logic/minecraft/OneSixRule.h | 1 - logic/minecraft/OneSixVersionBuilder.cpp | 249 ------------------------------- logic/minecraft/OneSixVersionBuilder.h | 46 ------ logic/minecraft/RawLibrary.cpp | 68 +++++++++ logic/minecraft/RawLibrary.h | 47 ++++++ logic/minecraft/VersionBuilder.cpp | 249 +++++++++++++++++++++++++++++++ logic/minecraft/VersionBuilder.h | 46 ++++++ logic/minecraft/VersionFile.cpp | 124 ++------------- logic/minecraft/VersionFile.h | 63 ++------ logic/minecraft/VersionFinal.cpp | 16 +- logic/minecraft/VersionFinal.h | 3 +- logic/minecraft/VersionPatch.h | 15 ++ 19 files changed, 549 insertions(+), 480 deletions(-) create mode 100644 logic/minecraft/JarMod.cpp create mode 100644 logic/minecraft/JarMod.h create mode 100644 logic/minecraft/MinecraftVersion.cpp delete mode 100644 logic/minecraft/OneSixVersionBuilder.cpp delete mode 100644 logic/minecraft/OneSixVersionBuilder.h create mode 100644 logic/minecraft/RawLibrary.cpp create mode 100644 logic/minecraft/RawLibrary.h create mode 100644 logic/minecraft/VersionBuilder.cpp create mode 100644 logic/minecraft/VersionBuilder.h create mode 100644 logic/minecraft/VersionPatch.h (limited to 'logic') diff --git a/logic/OneSixFTBInstance.cpp b/logic/OneSixFTBInstance.cpp index 491b15ba..eb0e4ba4 100644 --- a/logic/OneSixFTBInstance.cpp +++ b/logic/OneSixFTBInstance.cpp @@ -2,7 +2,7 @@ #include "logic/minecraft/VersionFinal.h" #include "logic/minecraft/OneSixLibrary.h" -#include "logic/minecraft/OneSixVersionBuilder.h" +#include "logic/minecraft/VersionBuilder.h" #include "tasks/SequentialTask.h" #include "forge/ForgeInstaller.h" #include "forge/ForgeVersionList.h" diff --git a/logic/OneSixUpdate.cpp b/logic/OneSixUpdate.cpp index 66a699fe..beb293ff 100644 --- a/logic/OneSixUpdate.cpp +++ b/logic/OneSixUpdate.cpp @@ -480,7 +480,7 @@ void OneSixUpdate::fmllibsStart() // determine if we need some libs for FML or forge setStatus(tr("Checking for FML libraries...")); - forge_present = (fullversion->versionFile("net.minecraftforge") != nullptr); + forge_present = (fullversion->versionPatch("net.minecraftforge") != nullptr); // we don't... if (!forge_present) { diff --git a/logic/minecraft/JarMod.cpp b/logic/minecraft/JarMod.cpp new file mode 100644 index 00000000..99a30aa5 --- /dev/null +++ b/logic/minecraft/JarMod.cpp @@ -0,0 +1,44 @@ +#include "JarMod.h" +#include "logic/MMCJson.h" + +JarmodPtr Jarmod::fromJson(const QJsonObject &libObj, const QString &filename) +{ + JarmodPtr out(new Jarmod()); + if (!libObj.contains("name")) + { + throw JSONValidationError(filename + + "contains a jarmod that doesn't have a 'name' field"); + } + out->name = libObj.value("name").toString(); + + auto readString = [libObj, filename](const QString & key, QString & variable) + { + if (libObj.contains(key)) + { + QJsonValue val = libObj.value(key); + if (!val.isString()) + { + QLOG_WARN() << key << "is not a string in" << filename << "(skipping)"; + } + else + { + variable = val.toString(); + } + } + }; + + readString("url", out->baseurl); + readString("MMC-absoluteUrl", out->absoluteUrl); + if(!out->baseurl.isEmpty() && out->absoluteUrl.isEmpty()) + { + out->absoluteUrl = out->baseurl + out->name; + } + return out; +} + +QString Jarmod::url() +{ + if(!absoluteUrl.isEmpty()) + return absoluteUrl; + else return baseurl + name; +} diff --git a/logic/minecraft/JarMod.h b/logic/minecraft/JarMod.h new file mode 100644 index 00000000..da5d8db0 --- /dev/null +++ b/logic/minecraft/JarMod.h @@ -0,0 +1,17 @@ +#pragma once +#include +#include +#include +class Jarmod; +typedef std::shared_ptr JarmodPtr; +class Jarmod +{ +public: /* methods */ + static JarmodPtr fromJson(const QJsonObject &libObj, const QString &filename); + QString url(); +public: /* data */ + QString name; + QString baseurl; + QString hint; + QString absoluteUrl; +}; diff --git a/logic/minecraft/MinecraftVersion.cpp b/logic/minecraft/MinecraftVersion.cpp new file mode 100644 index 00000000..a2e5a50a --- /dev/null +++ b/logic/minecraft/MinecraftVersion.cpp @@ -0,0 +1,2 @@ +#include "MinecraftVersion.h" + diff --git a/logic/minecraft/MinecraftVersion.h b/logic/minecraft/MinecraftVersion.h index 3be25912..dab08bb1 100644 --- a/logic/minecraft/MinecraftVersion.h +++ b/logic/minecraft/MinecraftVersion.h @@ -16,10 +16,11 @@ #pragma once #include "logic/BaseVersion.h" +#include "VersionPatch.h" #include #include -struct MinecraftVersion : public BaseVersion +struct MinecraftVersion : public BaseVersion, public VersionPatch { /// The version's timestamp - this is primarily used for sorting versions in a list. qint64 timestamp; @@ -89,4 +90,19 @@ struct MinecraftVersion : public BaseVersion return QObject::tr("Regular release"); } } + + virtual bool hasJarMods() override + { + return false; + } + + virtual bool isVanilla() override + { + return true; + } + + virtual void applyTo(VersionFinal *version) + { + // umm... what now? + } }; diff --git a/logic/minecraft/OneSixRule.cpp b/logic/minecraft/OneSixRule.cpp index d8d13b50..93c49e5e 100644 --- a/logic/minecraft/OneSixRule.cpp +++ b/logic/minecraft/OneSixRule.cpp @@ -18,6 +18,15 @@ #include "OneSixRule.h" +RuleAction RuleAction_fromString(QString name) +{ + if (name == "allow") + return Allow; + if (name == "disallow") + return Disallow; + return Defer; +} + QList> rulesFromJsonV4(const QJsonObject &objectWithRules) { QList> rules; @@ -79,11 +88,3 @@ QJsonObject OsRule::toJson() 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 index 2c569b9f..23d04151 100644 --- a/logic/minecraft/OneSixRule.h +++ b/logic/minecraft/OneSixRule.h @@ -26,7 +26,6 @@ enum RuleAction Defer }; -RuleAction RuleAction_fromString(QString); QList> rulesFromJsonV4(const QJsonObject &objectWithRules); class Rule diff --git a/logic/minecraft/OneSixVersionBuilder.cpp b/logic/minecraft/OneSixVersionBuilder.cpp deleted file mode 100644 index da8f956c..00000000 --- a/logic/minecraft/OneSixVersionBuilder.cpp +++ /dev/null @@ -1,249 +0,0 @@ -/* 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "logic/minecraft/OneSixVersionBuilder.h" -#include "logic/minecraft/VersionFinal.h" -#include "logic/minecraft/OneSixRule.h" -#include "logic/minecraft/VersionFile.h" - -#include "logic/OneSixInstance.h" -#include "logic/MMCJson.h" - -#include "logger/QsLog.h" - -OneSixVersionBuilder::OneSixVersionBuilder() -{ -} - -void OneSixVersionBuilder::build(VersionFinal *version, OneSixInstance *instance, const QStringList &external) -{ - OneSixVersionBuilder builder; - builder.m_version = version; - builder.m_instance = instance; - builder.buildInternal(external); -} - -void OneSixVersionBuilder::readJsonAndApplyToVersion(VersionFinal *version, - const QJsonObject &obj) -{ - OneSixVersionBuilder builder; - builder.m_version = version; - builder.m_instance = 0; - builder.readJsonAndApply(obj); -} - -void OneSixVersionBuilder::buildInternal(const QStringList &external) -{ - m_version->versionFiles.clear(); - - QDir root(m_instance->instanceRoot()); - QDir patches(root.absoluteFilePath("patches/")); - - // if we do external files, do just those. - if (!external.isEmpty()) - { - int externalOrder = -1; - for (auto fileName : external) - { - QLOG_INFO() << "Reading" << fileName; - auto file = - parseJsonFile(QFileInfo(fileName), false, fileName.endsWith("pack.json")); - file->name = QFileInfo(fileName).fileName(); - file->fileId = "org.multimc.external." + file->name; - file->order = (externalOrder += 1); - file->version = QString(); - file->mcVersion = QString(); - m_version->versionFiles.append(file); - } - } - // else, if there's custom json, we just do that. - else if (QFile::exists(root.absoluteFilePath("custom.json"))) - { - QLOG_INFO() << "Reading custom.json"; - auto file = parseJsonFile(QFileInfo(root.absoluteFilePath("custom.json")), false); - file->name = "custom.json"; - file->filename = "custom.json"; - file->fileId = "org.multimc.custom.json"; - file->order = -1; - file->version = QString(); - m_version->versionFiles.append(file); - // QObject::tr("The version descriptors of this instance are not compatible with the - // current version of MultiMC")); - // QObject::tr("Error while applying %1. Please check MultiMC-0.log for more info.") - } - // version.json -> patches/*.json -> user.json - else - do - { - // version.json - QLOG_INFO() << "Reading version.json"; - auto file = parseJsonFile(QFileInfo(root.absoluteFilePath("version.json")), false); - file->name = "Minecraft"; - file->fileId = "org.multimc.version.json"; - file->order = -1; - file->version = m_instance->intendedVersionId(); - file->mcVersion = m_instance->intendedVersionId(); - m_version->versionFiles.append(file); - // QObject::tr("Error while applying %1. Please check MultiMC-0.log for more - // info.").arg(root.absoluteFilePath("version.json"))); - - // patches/ - // load all, put into map for ordering, apply in the right order - - QMap> files; - for (auto info : patches.entryInfoList(QStringList() << "*.json", QDir::Files)) - { - QLOG_INFO() << "Reading" << info.fileName(); - auto file = parseJsonFile(info, true); - if (files.contains(file->order)) - { - throw VersionBuildError(QObject::tr("%1 has the same order as %2").arg( - file->fileId, files[file->order].second->fileId)); - } - files.insert(file->order, qMakePair(info.fileName(), file)); - } - for (auto order : files.keys()) - { - auto &filePair = files[order]; - m_version->versionFiles.append(filePair.second); - } - } while (0); - - // some final touches - m_version->finalize(); -} - - - -void OneSixVersionBuilder::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->versionFiles.append(file); - // QObject::tr("Error while applying. Please check MultiMC-0.log for more info.")); - // QObject::tr("The version descriptors of this instance are not compatible with the current - // version of MultiMC")); -} - -VersionFilePtr OneSixVersionBuilder::parseJsonFile(const QFileInfo &fileInfo, - const bool requireOrder, bool isFTB) -{ - QFile file(fileInfo.absoluteFilePath()); - if (!file.open(QFile::ReadOnly)) - { - throw JSONValidationError(QObject::tr("Unable to open the version file %1: %2.") - .arg(fileInfo.fileName(), file.errorString())); - } - QJsonParseError error; - QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &error); - if (error.error != QJsonParseError::NoError) - { - throw JSONValidationError(QObject::tr("Unable to process the version file %1: %2 at %3.") - .arg(fileInfo.fileName(), error.errorString()) - .arg(error.offset)); - } - return VersionFile::fromJson(doc, file.fileName(), requireOrder, isFTB); - // QObject::tr("Error while reading %1. Please check MultiMC-0.log for more - // info.").arg(file.fileName()); -} - -QMap OneSixVersionBuilder::readOverrideOrders(OneSixInstance *instance) -{ - 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; - } - - // and it's valid JSON - QJsonParseError error; - QJsonDocument doc = QJsonDocument::fromJson(orderFile.readAll(), &error); - if (error.error != QJsonParseError::NoError) - { - QLOG_ERROR() << "Couldn't parse" << orderFile.fileName() << ":" << error.errorString(); - QLOG_WARN() << "Ignoring overriden order"; - return out; - } - - // and then read it and process it if all above is true. - try - { - auto obj = MMCJson::ensureObject(doc); - for (auto it = obj.begin(); it != obj.end(); ++it) - { - if (it.key().startsWith("org.multimc.")) - { - continue; - } - out.insert(it.key(), MMCJson::ensureInteger(it.value())); - } - } - catch (JSONValidationError &err) - { - QLOG_ERROR() << "Couldn't parse" << orderFile.fileName() << ": bad file format"; - QLOG_WARN() << "Ignoring overriden order"; - return out; - } - return out; -} - -bool OneSixVersionBuilder::writeOverrideOrders(const QMap &order, - OneSixInstance *instance) -{ - QJsonObject obj; - for (auto it = order.cbegin(); it != order.cend(); ++it) - { - if (it.key().startsWith("org.multimc.")) - { - continue; - } - obj.insert(it.key(), it.value()); - } - QFile orderFile(instance->instanceRoot() + "/order.json"); - if (!orderFile.open(QFile::WriteOnly)) - { - QLOG_ERROR() << "Couldn't open" << orderFile.fileName() - << "for writing:" << orderFile.errorString(); - return false; - } - orderFile.write(QJsonDocument(obj).toJson(QJsonDocument::Indented)); - return true; -} diff --git a/logic/minecraft/OneSixVersionBuilder.h b/logic/minecraft/OneSixVersionBuilder.h deleted file mode 100644 index 6646584e..00000000 --- a/logic/minecraft/OneSixVersionBuilder.h +++ /dev/null @@ -1,46 +0,0 @@ -/* 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 -#include -#include "VersionFile.h" - -class VersionFinal; -class OneSixInstance; -class QJsonObject; -class QFileInfo; - -class OneSixVersionBuilder -{ - OneSixVersionBuilder(); -public: - static void build(VersionFinal *version, OneSixInstance *instance, const QStringList &external); - static void readJsonAndApplyToVersion(VersionFinal *version, const QJsonObject &obj); - - static QMap readOverrideOrders(OneSixInstance *instance); - static bool writeOverrideOrders(const QMap &order, OneSixInstance *instance); - -private: - VersionFinal *m_version; - OneSixInstance *m_instance; - - void buildInternal(const QStringList& external); - void readJsonAndApply(const QJsonObject &obj); - - VersionFilePtr parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder, - bool isFTB = false); -}; diff --git a/logic/minecraft/RawLibrary.cpp b/logic/minecraft/RawLibrary.cpp new file mode 100644 index 00000000..12aac8c8 --- /dev/null +++ b/logic/minecraft/RawLibrary.cpp @@ -0,0 +1,68 @@ +#include "logic/MMCJson.h" +using namespace MMCJson; + +#include "RawLibrary.h" + +RawLibraryPtr RawLibrary::fromJson(const QJsonObject &libObj, const QString &filename) +{ + RawLibraryPtr out(new RawLibrary()); + if (!libObj.contains("name")) + { + throw JSONValidationError(filename + + "contains a library that doesn't have a 'name' field"); + } + out->name = libObj.value("name").toString(); + + auto readString = [libObj, filename](const QString & key, QString & variable) + { + if (libObj.contains(key)) + { + QJsonValue val = libObj.value(key); + if (!val.isString()) + { + QLOG_WARN() << key << "is not a string in" << filename << "(skipping)"; + } + else + { + variable = val.toString(); + } + } + }; + + readString("url", out->url); + readString("MMC-hint", out->hint); + readString("MMC-absulute_url", out->absoluteUrl); + readString("MMC-absoluteUrl", out->absoluteUrl); + if (libObj.contains("extract")) + { + out->applyExcludes = true; + auto extractObj = ensureObject(libObj.value("extract")); + for (auto excludeVal : ensureArray(extractObj.value("exclude"))) + { + out->excludes.append(ensureString(excludeVal)); + } + } + if (libObj.contains("natives")) + { + out->applyNatives = true; + QJsonObject nativesObj = ensureObject(libObj.value("natives")); + 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); + } + return out; +} diff --git a/logic/minecraft/RawLibrary.h b/logic/minecraft/RawLibrary.h new file mode 100644 index 00000000..46178d8e --- /dev/null +++ b/logic/minecraft/RawLibrary.h @@ -0,0 +1,47 @@ +#pragma once +#include +#include +#include + +#include "OneSixRule.h" + +class RawLibrary; +typedef std::shared_ptr RawLibraryPtr; + +class RawLibrary +{ +public: /* methods */ + static RawLibraryPtr fromJson(const QJsonObject &libObj, const QString &filename); + +public: /* data */ + QString name; + QString url; + QString hint; + QString absoluteUrl; + + bool applyExcludes = false; + QStringList excludes; + + bool applyNatives = false; + QList> natives; + + bool applyRules = false; + QList> rules; + + // user for '+' libraries + enum InsertType + { + Apply, + Append, + Prepend, + Replace + } insertType = Append; + QString insertData; + + // soft or hard dependency? hard means 'needs equal', soft means 'needs equal or newer' + enum DependType + { + Soft, + Hard + } dependType = Soft; +}; diff --git a/logic/minecraft/VersionBuilder.cpp b/logic/minecraft/VersionBuilder.cpp new file mode 100644 index 00000000..56eef424 --- /dev/null +++ b/logic/minecraft/VersionBuilder.cpp @@ -0,0 +1,249 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "logic/minecraft/VersionBuilder.h" +#include "logic/minecraft/VersionFinal.h" +#include "logic/minecraft/OneSixRule.h" +#include "logic/minecraft/VersionFile.h" + +#include "logic/OneSixInstance.h" +#include "logic/MMCJson.h" + +#include "logger/QsLog.h" + +VersionBuilder::VersionBuilder() +{ +} + +void VersionBuilder::build(VersionFinal *version, OneSixInstance *instance, const QStringList &external) +{ + VersionBuilder builder; + builder.m_version = version; + builder.m_instance = instance; + builder.buildInternal(external); +} + +void VersionBuilder::readJsonAndApplyToVersion(VersionFinal *version, + const QJsonObject &obj) +{ + VersionBuilder builder; + builder.m_version = version; + builder.m_instance = 0; + builder.readJsonAndApply(obj); +} + +void VersionBuilder::buildInternal(const QStringList &external) +{ + m_version->versionFiles.clear(); + + QDir root(m_instance->instanceRoot()); + QDir patches(root.absoluteFilePath("patches/")); + + // if we do external files, do just those. + if (!external.isEmpty()) + { + int externalOrder = -1; + for (auto fileName : external) + { + QLOG_INFO() << "Reading" << fileName; + auto file = + parseJsonFile(QFileInfo(fileName), false, fileName.endsWith("pack.json")); + file->name = QFileInfo(fileName).fileName(); + file->fileId = "org.multimc.external." + file->name; + file->order = (externalOrder += 1); + file->version = QString(); + file->mcVersion = QString(); + m_version->versionFiles.append(file); + } + } + // else, if there's custom json, we just do that. + else if (QFile::exists(root.absoluteFilePath("custom.json"))) + { + QLOG_INFO() << "Reading custom.json"; + auto file = parseJsonFile(QFileInfo(root.absoluteFilePath("custom.json")), false); + file->name = "custom.json"; + file->filename = "custom.json"; + file->fileId = "org.multimc.custom.json"; + file->order = -1; + file->version = QString(); + m_version->versionFiles.append(file); + // QObject::tr("The version descriptors of this instance are not compatible with the + // current version of MultiMC")); + // QObject::tr("Error while applying %1. Please check MultiMC-0.log for more info.") + } + // version.json -> patches/*.json -> user.json + else + do + { + // version.json + QLOG_INFO() << "Reading version.json"; + auto file = parseJsonFile(QFileInfo(root.absoluteFilePath("version.json")), false); + file->name = "Minecraft"; + file->fileId = "org.multimc.version.json"; + file->order = -1; + file->version = m_instance->intendedVersionId(); + file->mcVersion = m_instance->intendedVersionId(); + m_version->versionFiles.append(file); + // QObject::tr("Error while applying %1. Please check MultiMC-0.log for more + // info.").arg(root.absoluteFilePath("version.json"))); + + // patches/ + // load all, put into map for ordering, apply in the right order + + QMap> files; + for (auto info : patches.entryInfoList(QStringList() << "*.json", QDir::Files)) + { + QLOG_INFO() << "Reading" << info.fileName(); + auto file = parseJsonFile(info, true); + if (files.contains(file->order)) + { + throw VersionBuildError(QObject::tr("%1 has the same order as %2").arg( + file->fileId, files[file->order].second->fileId)); + } + files.insert(file->order, qMakePair(info.fileName(), file)); + } + for (auto order : files.keys()) + { + auto &filePair = files[order]; + m_version->versionFiles.append(filePair.second); + } + } while (0); + + // some final touches + m_version->finalize(); +} + + + +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->versionFiles.append(file); + // QObject::tr("Error while applying. Please check MultiMC-0.log for more info.")); + // QObject::tr("The version descriptors of this instance are not compatible with the current + // version of MultiMC")); +} + +VersionFilePtr VersionBuilder::parseJsonFile(const QFileInfo &fileInfo, + const bool requireOrder, bool isFTB) +{ + QFile file(fileInfo.absoluteFilePath()); + if (!file.open(QFile::ReadOnly)) + { + throw JSONValidationError(QObject::tr("Unable to open the version file %1: %2.") + .arg(fileInfo.fileName(), file.errorString())); + } + QJsonParseError error; + QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &error); + if (error.error != QJsonParseError::NoError) + { + throw JSONValidationError(QObject::tr("Unable to process the version file %1: %2 at %3.") + .arg(fileInfo.fileName(), error.errorString()) + .arg(error.offset)); + } + return VersionFile::fromJson(doc, file.fileName(), requireOrder, isFTB); + // QObject::tr("Error while reading %1. Please check MultiMC-0.log for more + // info.").arg(file.fileName()); +} + +QMap VersionBuilder::readOverrideOrders(OneSixInstance *instance) +{ + 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; + } + + // and it's valid JSON + QJsonParseError error; + QJsonDocument doc = QJsonDocument::fromJson(orderFile.readAll(), &error); + if (error.error != QJsonParseError::NoError) + { + QLOG_ERROR() << "Couldn't parse" << orderFile.fileName() << ":" << error.errorString(); + QLOG_WARN() << "Ignoring overriden order"; + return out; + } + + // and then read it and process it if all above is true. + try + { + auto obj = MMCJson::ensureObject(doc); + for (auto it = obj.begin(); it != obj.end(); ++it) + { + if (it.key().startsWith("org.multimc.")) + { + continue; + } + out.insert(it.key(), MMCJson::ensureInteger(it.value())); + } + } + catch (JSONValidationError &err) + { + QLOG_ERROR() << "Couldn't parse" << orderFile.fileName() << ": bad file format"; + QLOG_WARN() << "Ignoring overriden order"; + return out; + } + return out; +} + +bool VersionBuilder::writeOverrideOrders(const QMap &order, + OneSixInstance *instance) +{ + QJsonObject obj; + for (auto it = order.cbegin(); it != order.cend(); ++it) + { + if (it.key().startsWith("org.multimc.")) + { + continue; + } + obj.insert(it.key(), it.value()); + } + QFile orderFile(instance->instanceRoot() + "/order.json"); + if (!orderFile.open(QFile::WriteOnly)) + { + QLOG_ERROR() << "Couldn't open" << orderFile.fileName() + << "for writing:" << orderFile.errorString(); + return false; + } + orderFile.write(QJsonDocument(obj).toJson(QJsonDocument::Indented)); + return true; +} diff --git a/logic/minecraft/VersionBuilder.h b/logic/minecraft/VersionBuilder.h new file mode 100644 index 00000000..ac93ef11 --- /dev/null +++ b/logic/minecraft/VersionBuilder.h @@ -0,0 +1,46 @@ +/* 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 +#include +#include "VersionFile.h" + +class VersionFinal; +class OneSixInstance; +class QJsonObject; +class QFileInfo; + +class VersionBuilder +{ + VersionBuilder(); +public: + static void build(VersionFinal *version, OneSixInstance *instance, const QStringList &external); + static void readJsonAndApplyToVersion(VersionFinal *version, const QJsonObject &obj); + + static QMap readOverrideOrders(OneSixInstance *instance); + static bool writeOverrideOrders(const QMap &order, OneSixInstance *instance); + +private: + VersionFinal *m_version; + OneSixInstance *m_instance; + + void buildInternal(const QStringList& external); + void readJsonAndApply(const QJsonObject &obj); + + VersionFilePtr parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder, + bool isFTB = false); +}; diff --git a/logic/minecraft/VersionFile.cpp b/logic/minecraft/VersionFile.cpp index a011ce1a..e1b03e6c 100644 --- a/logic/minecraft/VersionFile.cpp +++ b/logic/minecraft/VersionFile.cpp @@ -7,111 +7,28 @@ #include "logic/minecraft/VersionFile.h" #include "logic/minecraft/OneSixLibrary.h" #include "logic/minecraft/VersionFinal.h" -#include "logic/MMCJson.h" +#include "logic/minecraft/JarMod.h" +#include "logic/MMCJson.h" using namespace MMCJson; #define CURRENT_MINIMUM_LAUNCHER_VERSION 14 -JarmodPtr Jarmod::fromJson(const QJsonObject &libObj, const QString &filename) -{ - JarmodPtr out(new Jarmod()); - if (!libObj.contains("name")) - { - throw JSONValidationError(filename + - "contains a jarmod that doesn't have a 'name' field"); - } - out->name = libObj.value("name").toString(); - - auto readString = [libObj, filename](const QString & key, QString & variable) - { - if (libObj.contains(key)) - { - QJsonValue val = libObj.value(key); - if (!val.isString()) - { - QLOG_WARN() << key << "is not a string in" << filename << "(skipping)"; - } - else - { - variable = val.toString(); - } - } - }; - - readString("url", out->baseurl); - readString("MMC-absoluteUrl", out->absoluteUrl); - if(!out->baseurl.isEmpty() && out->absoluteUrl.isEmpty()) - { - out->absoluteUrl = out->baseurl + out->name; - } - return out; - -} - - -RawLibraryPtr RawLibrary::fromJson(const QJsonObject &libObj, const QString &filename) +int findLibrary(QList haystack, const QString &needle) { - RawLibraryPtr out(new RawLibrary()); - if (!libObj.contains("name")) - { - throw JSONValidationError(filename + - "contains a library that doesn't have a 'name' field"); - } - out->name = libObj.value("name").toString(); - - auto readString = [libObj, filename](const QString & key, QString & variable) - { - if (libObj.contains(key)) - { - QJsonValue val = libObj.value(key); - if (!val.isString()) - { - QLOG_WARN() << key << "is not a string in" << filename << "(skipping)"; - } - else - { - variable = val.toString(); - } - } - }; - - readString("url", out->url); - readString("MMC-hint", out->hint); - readString("MMC-absulute_url", out->absoluteUrl); - readString("MMC-absoluteUrl", out->absoluteUrl); - if (libObj.contains("extract")) - { - out->applyExcludes = true; - auto extractObj = ensureObject(libObj.value("extract")); - for (auto excludeVal : ensureArray(extractObj.value("exclude"))) - { - out->excludes.append(ensureString(excludeVal)); - } - } - if (libObj.contains("natives")) + int retval = -1; + for (int i = 0; i < haystack.size(); ++i) { - out->applyNatives = true; - QJsonObject nativesObj = ensureObject(libObj.value("natives")); - for (auto it = nativesObj.begin(); it != nativesObj.end(); ++it) + QString chunk = haystack.at(i)->rawName(); + if (QRegExp(needle, Qt::CaseSensitive, QRegExp::WildcardUnix).indexIn(chunk) != -1) { - 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())); - } + // only one is allowed. + if(retval != -1) + return -1; + retval = i; } } - if (libObj.contains("rules")) - { - out->applyRules = true; - out->rules = rulesFromJsonV4(libObj); - } - return out; + return retval; } VersionFilePtr VersionFile::fromJson(const QJsonDocument &doc, const QString &filename, @@ -351,23 +268,6 @@ OneSixLibraryPtr VersionFile::createLibrary(RawLibraryPtr lib) return out; } -int VersionFile::findLibrary(QList haystack, const QString &needle) -{ - int retval = -1; - for (int i = 0; i < haystack.size(); ++i) - { - QString chunk = haystack.at(i)->rawName(); - if (QRegExp(needle, Qt::CaseSensitive, QRegExp::WildcardUnix).indexIn(chunk) != -1) - { - // only one is allowed. - if(retval != -1) - return -1; - retval = i; - } - } - return retval; -} - bool VersionFile::isVanilla() { return fileId == "org.multimc.version.json"; diff --git a/logic/minecraft/VersionFile.h b/logic/minecraft/VersionFile.h index 8234445b..82b16913 100644 --- a/logic/minecraft/VersionFile.h +++ b/logic/minecraft/VersionFile.h @@ -5,10 +5,14 @@ #include #include "logic/minecraft/OpSys.h" #include "logic/minecraft/OneSixRule.h" +#include "VersionPatch.h" #include "MMCError.h" +#include "RawLibrary.h" +#include "JarMod.h" class VersionFinal; + class VersionBuildError : public MMCError { public: @@ -46,66 +50,19 @@ public: virtual ~MinecraftVersionMismatch() noexcept {} }; -struct RawLibrary; -typedef std::shared_ptr RawLibraryPtr; -struct RawLibrary -{ - QString name; - QString url; - QString hint; - QString absoluteUrl; - bool applyExcludes = false; - QStringList excludes; - bool applyNatives = false; - QList> natives; - bool applyRules = false; - QList> rules; - - // user for '+' libraries - enum InsertType - { - Apply, - Append, - Prepend, - Replace - }; - InsertType insertType = Append; - QString insertData; - enum DependType - { - Soft, - Hard - }; - DependType dependType = Soft; - - static RawLibraryPtr fromJson(const QJsonObject &libObj, const QString &filename); -}; - -struct Jarmod; -typedef std::shared_ptr JarmodPtr; -struct Jarmod -{ - QString name; - QString baseurl; - QString hint; - QString absoluteUrl; - - static JarmodPtr fromJson(const QJsonObject &libObj, const QString &filename); -}; - struct VersionFile; typedef std::shared_ptr VersionFilePtr; -struct VersionFile +class VersionFile : public VersionPatch { public: /* methods */ static VersionFilePtr fromJson(const QJsonDocument &doc, const QString &filename, const bool requireOrder, const bool isFTB = false); static OneSixLibraryPtr createLibrary(RawLibraryPtr lib); - int findLibrary(QList haystack, const QString &needle); - void applyTo(VersionFinal *version); - bool isVanilla(); - bool hasJarMods(); + virtual void applyTo(VersionFinal *version) override; + virtual bool isVanilla() override; + virtual bool hasJarMods() override; + public: /* data */ int order = 0; QString name; @@ -143,3 +100,5 @@ public: /* data */ QList jarMods; }; + + diff --git a/logic/minecraft/VersionFinal.cpp b/logic/minecraft/VersionFinal.cpp index fbf6a160..07f58778 100644 --- a/logic/minecraft/VersionFinal.cpp +++ b/logic/minecraft/VersionFinal.cpp @@ -19,7 +19,7 @@ #include #include "logic/minecraft/VersionFinal.h" -#include "logic/minecraft/OneSixVersionBuilder.h" +#include "logic/minecraft/VersionBuilder.h" #include "logic/OneSixInstance.h" VersionFinal::VersionFinal(OneSixInstance *instance, QObject *parent) @@ -31,7 +31,7 @@ VersionFinal::VersionFinal(OneSixInstance *instance, QObject *parent) void VersionFinal::reload(const QStringList &external) { beginResetModel(); - OneSixVersionBuilder::build(this, m_instance, external); + VersionBuilder::build(this, m_instance, external); reapply(true); endResetModel(); } @@ -116,7 +116,7 @@ QString VersionFinal::versionFileId(const int index) const return versionFiles.at(index)->fileId; } -VersionFilePtr VersionFinal::versionFile(const QString &id) +VersionFilePtr VersionFinal::versionPatch(const QString &id) { for (auto file : versionFiles) { @@ -135,7 +135,7 @@ bool VersionFinal::hasJarMods() bool VersionFinal::hasFtbPack() { - return versionFile("org.multimc.ftb.pack.json") != nullptr; + return versionPatch("org.multimc.ftb.pack.json") != nullptr; } bool VersionFinal::removeFtbPack() @@ -216,7 +216,7 @@ std::shared_ptr VersionFinal::fromJson(const QJsonObject &obj) std::shared_ptr version(new VersionFinal(0)); try { - OneSixVersionBuilder::readJsonAndApplyToVersion(version.get(), obj); + VersionBuilder::readJsonAndApplyToVersion(version.get(), obj); } catch(MMCError & err) { @@ -299,7 +299,7 @@ QMap VersionFinal::getExistingOrder() const } // overriden { - QMap overridenOrder = OneSixVersionBuilder::readOverrideOrders(m_instance); + QMap overridenOrder = VersionBuilder::readOverrideOrders(m_instance); for (auto id : order.keys()) { if (overridenOrder.contains(id)) @@ -348,7 +348,7 @@ void VersionFinal::move(const int index, const MoveDirection direction) order[ourId] = theirIndex; order[theirId] = index; - if (!OneSixVersionBuilder::writeOverrideOrders(order, m_instance)) + if (!VersionBuilder::writeOverrideOrders(order, m_instance)) { throw MMCError(tr("Couldn't save the new order")); } @@ -378,7 +378,7 @@ void VersionFinal::reapply(const bool alreadyReseting) QList newVersionFiles; for (auto order : orders) { - auto file = versionFile(existingOrders.key(order)); + auto file = versionPatch(existingOrders.key(order)); newVersionFiles.append(file); file->applyTo(this); } diff --git a/logic/minecraft/VersionFinal.h b/logic/minecraft/VersionFinal.h index ceb90f57..7be981ed 100644 --- a/logic/minecraft/VersionFinal.h +++ b/logic/minecraft/VersionFinal.h @@ -23,6 +23,7 @@ #include "OneSixLibrary.h" #include "VersionFile.h" +#include "JarMod.h" class OneSixInstance; @@ -164,7 +165,7 @@ public: // QList rules; QList versionFiles; - VersionFilePtr versionFile(const QString &id); + VersionFilePtr versionPatch(const QString &id); private: OneSixInstance *m_instance; diff --git a/logic/minecraft/VersionPatch.h b/logic/minecraft/VersionPatch.h new file mode 100644 index 00000000..c2258787 --- /dev/null +++ b/logic/minecraft/VersionPatch.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +class VersionFinal; +class VersionPatch +{ +public: + virtual ~VersionPatch(){}; + virtual void applyTo(VersionFinal *version) = 0; + virtual bool isVanilla() = 0; + virtual bool hasJarMods() = 0; +}; + +typedef std::shared_ptr VersionPatchPtr; -- cgit v1.2.3