diff options
author | Petr Mrázek <peterix@gmail.com> | 2015-01-27 22:31:07 +0100 |
---|---|---|
committer | Petr Mrázek <peterix@gmail.com> | 2015-04-02 00:14:06 +0200 |
commit | 791221e923586bb717396ecf18bd13e57034df99 (patch) | |
tree | 9f608af07375b38626c8964671620477158341ba /logic/minecraft | |
parent | 593111b14463e9d5d08256061b981b5ab1cfb710 (diff) | |
download | MultiMC-791221e923586bb717396ecf18bd13e57034df99.tar MultiMC-791221e923586bb717396ecf18bd13e57034df99.tar.gz MultiMC-791221e923586bb717396ecf18bd13e57034df99.tar.lz MultiMC-791221e923586bb717396ecf18bd13e57034df99.tar.xz MultiMC-791221e923586bb717396ecf18bd13e57034df99.zip |
NOISSUE Refactors and moving of things
Diffstat (limited to 'logic/minecraft')
26 files changed, 1250 insertions, 683 deletions
diff --git a/logic/minecraft/JarMod.cpp b/logic/minecraft/JarMod.cpp index 18a9411c..fce8a492 100644 --- a/logic/minecraft/JarMod.cpp +++ b/logic/minecraft/JarMod.cpp @@ -11,30 +11,6 @@ JarmodPtr Jarmod::fromJson(const QJsonObject &libObj, const QString &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-hint", out->hint); - readString("MMC-absoluteUrl", out->absoluteUrl); - if(!out->baseurl.isEmpty() && out->absoluteUrl.isEmpty()) - { - out->absoluteUrl = out->baseurl + out->name; - } return out; } @@ -42,15 +18,5 @@ QJsonObject Jarmod::toJson() { QJsonObject out; writeString(out, "name", name); - writeString(out, "url", baseurl); - writeString(out, "MMC-absoluteUrl", absoluteUrl); - writeString(out, "MMC-hint", hint); 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 index c438dbcd..7d9fa038 100644 --- a/logic/minecraft/JarMod.h +++ b/logic/minecraft/JarMod.h @@ -9,10 +9,6 @@ class Jarmod public: /* methods */ static JarmodPtr fromJson(const QJsonObject &libObj, const QString &filename); QJsonObject toJson(); - QString url(); public: /* data */ QString name; - QString baseurl; - QString hint; - QString absoluteUrl; }; diff --git a/logic/minecraft/MinecraftInstance.cpp b/logic/minecraft/MinecraftInstance.cpp new file mode 100644 index 00000000..090c9389 --- /dev/null +++ b/logic/minecraft/MinecraftInstance.cpp @@ -0,0 +1,58 @@ +#include "MinecraftInstance.h" +#include "MultiMC.h" +#include "logic/settings/SettingsObject.h" +#include <pathutils.h> +#include "logic/minecraft/MinecraftVersionList.h" + +MinecraftInstance::MinecraftInstance(const QString &rootDir, SettingsObject *settings, QObject *parent) + : BaseInstance(rootDir, settings, parent) +{ + auto globalSettings = MMC->settings(); + + // Java Settings + m_settings->registerSetting("OverrideJava", false); + m_settings->registerSetting("OverrideJavaLocation", false); + m_settings->registerSetting("OverrideJavaArgs", false); + m_settings->registerOverride(globalSettings->getSetting("JavaPath")); + m_settings->registerOverride(globalSettings->getSetting("JvmArgs")); + + // Custom Commands + m_settings->registerSetting({"OverrideCommands","OverrideLaunchCmd"}, false); + m_settings->registerOverride(globalSettings->getSetting("PreLaunchCommand")); + m_settings->registerOverride(globalSettings->getSetting("PostExitCommand")); + + // Window Size + m_settings->registerSetting("OverrideWindow", false); + m_settings->registerOverride(globalSettings->getSetting("LaunchMaximized")); + m_settings->registerOverride(globalSettings->getSetting("MinecraftWinWidth")); + m_settings->registerOverride(globalSettings->getSetting("MinecraftWinHeight")); + + // Memory + m_settings->registerSetting("OverrideMemory", false); + m_settings->registerOverride(globalSettings->getSetting("MinMemAlloc")); + m_settings->registerOverride(globalSettings->getSetting("MaxMemAlloc")); + m_settings->registerOverride(globalSettings->getSetting("PermGen")); + + // Console + m_settings->registerSetting("OverrideConsole", false); + m_settings->registerOverride(globalSettings->getSetting("ShowConsole")); + m_settings->registerOverride(globalSettings->getSetting("AutoCloseConsole")); + m_settings->registerOverride(globalSettings->getSetting("LogPrePostOutput")); +} + +QString MinecraftInstance::minecraftRoot() const +{ + QFileInfo mcDir(PathCombine(instanceRoot(), "minecraft")); + QFileInfo dotMCDir(PathCombine(instanceRoot(), ".minecraft")); + + if (dotMCDir.exists() && !mcDir.exists()) + return dotMCDir.filePath(); + else + return mcDir.filePath(); +} + +std::shared_ptr< BaseVersionList > MinecraftInstance::versionList() const +{ + return std::dynamic_pointer_cast<BaseVersionList>(MMC->minecraftlist()); +} + diff --git a/logic/minecraft/MinecraftInstance.h b/logic/minecraft/MinecraftInstance.h new file mode 100644 index 00000000..9097a2da --- /dev/null +++ b/logic/minecraft/MinecraftInstance.h @@ -0,0 +1,30 @@ +#pragma once +#include "logic/BaseInstance.h" + +class MinecraftInstance: public BaseInstance +{ +public: + MinecraftInstance(const QString& rootDir, SettingsObject* settings, QObject* parent = 0); + virtual ~MinecraftInstance() {}; + + /// Path to the instance's minecraft directory. + QString minecraftRoot() const; + + ////// Mod Lists ////// + virtual std::shared_ptr<ModList> resourcePackList() const + { + return nullptr; + } + virtual std::shared_ptr<ModList> texturePackList() const + { + return nullptr; + } + /// get all jar mods applicable to this instance's jar + virtual QList<Mod> getJarMods() const + { + return QList<Mod>(); + } + virtual std::shared_ptr< BaseVersionList > versionList() const; +}; + +typedef std::shared_ptr<MinecraftInstance> MinecraftInstancePtr; diff --git a/logic/minecraft/MinecraftProcess.cpp b/logic/minecraft/MinecraftProcess.cpp new file mode 100644 index 00000000..0fc3f067 --- /dev/null +++ b/logic/minecraft/MinecraftProcess.cpp @@ -0,0 +1,216 @@ +/* Copyright 2013-2014 MultiMC Contributors + * + * Authors: Orochimarufan <orochimarufan.x3@gmail.com> + * + * 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 "MultiMC.h" +#include "BuildConfig.h" + +#include "logic/minecraft/MinecraftProcess.h" +#include "logic/BaseInstance.h" + +#include <QDataStream> +#include <QFile> +#include <QDir> +#include <QProcessEnvironment> +#include <QRegularExpression> +#include <QStandardPaths> + +#include "osutils.h" +#include "pathutils.h" +#include "cmdutils.h" + +#define IBUS "@im=ibus" + +// constructor +MinecraftProcess::MinecraftProcess(MinecraftInstancePtr inst) : BaseProcess(inst) +{ +} + +MinecraftProcess* MinecraftProcess::create(MinecraftInstancePtr inst) +{ + auto proc = new MinecraftProcess(inst); + proc->init(); + return proc; +} + + +QString MinecraftProcess::censorPrivateInfo(QString in) +{ + if (!m_session) + return in; + + if (m_session->session != "-") + in.replace(m_session->session, "<SESSION ID>"); + in.replace(m_session->access_token, "<ACCESS TOKEN>"); + in.replace(m_session->client_token, "<CLIENT TOKEN>"); + in.replace(m_session->uuid, "<PROFILE ID>"); + in.replace(m_session->player_name, "<PROFILE NAME>"); + + auto i = m_session->u.properties.begin(); + while (i != m_session->u.properties.end()) + { + in.replace(i.value(), "<" + i.key().toUpper() + ">"); + ++i; + } + + return in; +} + +// console window +MessageLevel::Enum MinecraftProcess::guessLevel(const QString &line, MessageLevel::Enum level) +{ + QRegularExpression re("\\[(?<timestamp>[0-9:]+)\\] \\[[^/]+/(?<level>[^\\]]+)\\]"); + auto match = re.match(line); + if(match.hasMatch()) + { + // New style logs from log4j + QString timestamp = match.captured("timestamp"); + QString levelStr = match.captured("level"); + if(levelStr == "INFO") + level = MessageLevel::Message; + if(levelStr == "WARN") + level = MessageLevel::Warning; + if(levelStr == "ERROR") + level = MessageLevel::Error; + if(levelStr == "FATAL") + level = MessageLevel::Fatal; + if(levelStr == "TRACE" || levelStr == "DEBUG") + level = MessageLevel::Debug; + } + else + { + // Old style forge logs + if (line.contains("[INFO]") || line.contains("[CONFIG]") || line.contains("[FINE]") || + line.contains("[FINER]") || line.contains("[FINEST]")) + level = MessageLevel::Message; + if (line.contains("[SEVERE]") || line.contains("[STDERR]")) + level = MessageLevel::Error; + if (line.contains("[WARNING]")) + level = MessageLevel::Warning; + if (line.contains("[DEBUG]")) + level = MessageLevel::Debug; + } + if (line.contains("overwriting existing")) + return MessageLevel::Fatal; + if (line.contains("Exception in thread") || line.contains(QRegularExpression("\\s+at "))) + return MessageLevel::Error; + return level; +} + +QMap<QString, QString> MinecraftProcess::getVariables() const +{ + auto mcInstance = std::dynamic_pointer_cast<MinecraftInstance>(m_instance); + QMap<QString, QString> out; + out.insert("INST_NAME", mcInstance->name()); + out.insert("INST_ID", mcInstance->id()); + out.insert("INST_DIR", QDir(mcInstance->instanceRoot()).absolutePath()); + out.insert("INST_MC_DIR", QDir(mcInstance->minecraftRoot()).absolutePath()); + out.insert("INST_JAVA", mcInstance->settings().get("JavaPath").toString()); + out.insert("INST_JAVA_ARGS", javaArguments().join(' ')); + return out; +} + +QStringList MinecraftProcess::javaArguments() const +{ + QStringList args; + + // custom args go first. we want to override them if we have our own here. + args.append(m_instance->extraArguments()); + + // OSX dock icon and name +#ifdef OSX + args << "-Xdock:icon=icon.png"; + args << QString("-Xdock:name=\"%1\"").arg(m_instance->windowTitle()); +#endif + + // HACK: Stupid hack for Intel drivers. See: https://mojang.atlassian.net/browse/MCL-767 +#ifdef Q_OS_WIN32 + args << QString("-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_" + "minecraft.exe.heapdump"); +#endif + + args << QString("-Xms%1m").arg(m_instance->settings().get("MinMemAlloc").toInt()); + args << QString("-Xmx%1m").arg(m_instance->settings().get("MaxMemAlloc").toInt()); + auto permgen = m_instance->settings().get("PermGen").toInt(); + if (permgen != 64) + { + args << QString("-XX:PermSize=%1m").arg(permgen); + } + args << "-Duser.language=en"; + if (!m_nativeFolder.isEmpty()) + args << QString("-Djava.library.path=%1").arg(m_nativeFolder); + args << "-jar" << PathCombine(MMC->bin(), "jars", "NewLaunch.jar"); + + return args; +} + +void MinecraftProcess::arm() +{ + emit log("MultiMC version: " + BuildConfig.printableVersionString() + "\n\n"); + emit log("Minecraft folder is:\n" + workingDirectory() + "\n\n"); + + if (!preLaunch()) + { + emit ended(m_instance, 1, QProcess::CrashExit); + return; + } + + m_instance->setLastLaunch(); + + QStringList args = javaArguments(); + + QString JavaPath = m_instance->settings().get("JavaPath").toString(); + emit log("Java path is:\n" + JavaPath + "\n\n"); + QString allArgs = args.join(", "); + emit log("Java Arguments:\n[" + censorPrivateInfo(allArgs) + "]\n\n"); + + auto realJavaPath = QStandardPaths::findExecutable(JavaPath); + if (realJavaPath.isEmpty()) + { + emit log(tr("The java binary \"%1\" couldn't be found. You may have to set up java " + "if Minecraft fails to launch.").arg(JavaPath), + MessageLevel::Warning); + } + + // instantiate the launcher part + start(JavaPath, args); + if (!waitForStarted()) + { + //: Error message displayed if instace can't start + emit log(tr("Could not launch minecraft!"), MessageLevel::Error); + m_instance->cleanupAfterRun(); + emit launch_failed(m_instance); + // not running, failed + m_instance->setRunning(false); + return; + } + // send the launch script to the launcher part + QByteArray bytes = launchScript.toUtf8(); + writeData(bytes.constData(), bytes.length()); +} + +void MinecraftProcess::launch() +{ + QString launchString("launch\n"); + QByteArray bytes = launchString.toUtf8(); + writeData(bytes.constData(), bytes.length()); +} + +void MinecraftProcess::abort() +{ + QString launchString("abort\n"); + QByteArray bytes = launchString.toUtf8(); + writeData(bytes.constData(), bytes.length()); +} diff --git a/logic/minecraft/MinecraftProcess.h b/logic/minecraft/MinecraftProcess.h new file mode 100644 index 00000000..30a59e91 --- /dev/null +++ b/logic/minecraft/MinecraftProcess.h @@ -0,0 +1,77 @@ +/* Copyright 2013-2014 MultiMC Contributors + * + * Authors: Orochimarufan <orochimarufan.x3@gmail.com> + * + * 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 "logic/minecraft/MinecraftInstance.h" +#include "logic/BaseProcess.h" + +/** + * The MinecraftProcess class + */ +class MinecraftProcess : public BaseProcess +{ + Q_OBJECT +protected: + MinecraftProcess(MinecraftInstancePtr inst); +public: + static MinecraftProcess *create(MinecraftInstancePtr inst); + + virtual ~MinecraftProcess(){}; + + /** + * @brief start the launcher part with the provided launch script + */ + void arm() override; + + /** + * @brief launch the armed instance! + */ + void launch() override; + + /** + * @brief abort launch! + */ + void abort() override; + + void setLaunchScript(QString script) + { + launchScript = script; + } + + void setNativeFolder(QString natives) + { + m_nativeFolder = natives; + } + + inline void setLogin(AuthSessionPtr session) + { + m_session = session; + } + +protected: + AuthSessionPtr m_session; + QString launchScript; + QString m_nativeFolder; + + virtual QMap<QString, QString> getVariables() const override; + + QStringList javaArguments() const; + virtual QString censorPrivateInfo(QString in) override; + virtual MessageLevel::Enum guessLevel(const QString &message, MessageLevel::Enum defaultLevel) override; +}; diff --git a/logic/minecraft/InstanceVersion.cpp b/logic/minecraft/MinecraftProfile.cpp index cc077767..3fbfd105 100644 --- a/logic/minecraft/InstanceVersion.cpp +++ b/logic/minecraft/MinecraftProfile.cpp @@ -15,31 +15,50 @@ #include <QFile> #include <QDir> -#include <QUuid> #include <QJsonDocument> #include <QJsonArray> #include <pathutils.h> -#include "logic/minecraft/InstanceVersion.h" +#include "logic/minecraft/MinecraftProfile.h" #include "logic/minecraft/VersionBuilder.h" +#include "ProfileUtils.h" +#include "NullProfileStrategy.h" #include "logic/OneSixInstance.h" -InstanceVersion::InstanceVersion(OneSixInstance *instance, QObject *parent) - : QAbstractListModel(parent), m_instance(instance) +MinecraftProfile::MinecraftProfile(ProfileStrategy *strategy) + : QAbstractListModel() { + setStrategy(strategy); clear(); } -void InstanceVersion::reload(const QStringList &external) +void MinecraftProfile::setStrategy(ProfileStrategy* strategy) +{ + Q_ASSERT(strategy != nullptr); + + if(m_strategy != nullptr) + { + delete m_strategy; + m_strategy = nullptr; + } + m_strategy = strategy; + m_strategy->profile = this; +} + +ProfileStrategy* MinecraftProfile::strategy() +{ + return m_strategy; +} + +void MinecraftProfile::reload() { - m_externalPatches = external; beginResetModel(); - VersionBuilder::build(this, m_instance, m_externalPatches); - reapply(true); + m_strategy->load(); + reapply(); endResetModel(); } -void InstanceVersion::clear() +void MinecraftProfile::clear() { id.clear(); m_updateTimeString.clear(); @@ -59,44 +78,45 @@ void InstanceVersion::clear() traits.clear(); } -bool InstanceVersion::canRemove(const int index) const +void MinecraftProfile::clearPatches() { - return VersionPatches.at(index)->isMoveable(); + beginResetModel(); + VersionPatches.clear(); + endResetModel(); } -bool InstanceVersion::preremove(VersionPatchPtr patch) +void MinecraftProfile::appendPatch(ProfilePatchPtr patch) { - bool ok = true; - for(auto & jarmod: patch->getJarMods()) - { - QString fullpath =PathCombine(m_instance->jarModsDir(), jarmod->name); - QFileInfo finfo (fullpath); - if(finfo.exists()) - ok &= QFile::remove(fullpath); - } - return ok; + int index = VersionPatches.size(); + beginInsertRows(QModelIndex(), index, index); + VersionPatches.append(patch); + endInsertRows(); } -bool InstanceVersion::remove(const int index) +bool MinecraftProfile::canRemove(const int index) const +{ + return VersionPatches.at(index)->isMoveable(); +} + +bool MinecraftProfile::remove(const int index) { if (!canRemove(index)) return false; - if(!preremove(VersionPatches[index])) + + if(!m_strategy->removePatch(VersionPatches.at(index))) { return false; } - auto toDelete = VersionPatches.at(index)->getPatchFilename(); - if(!QFile::remove(toDelete)) - return false; + beginRemoveRows(QModelIndex(), index, index); VersionPatches.removeAt(index); endRemoveRows(); - reapply(true); + reapply(); saveCurrentOrder(); return true; } -bool InstanceVersion::remove(const QString id) +bool MinecraftProfile::remove(const QString id) { int i = 0; for (auto patch : VersionPatches) @@ -110,7 +130,7 @@ bool InstanceVersion::remove(const QString id) return false; } -QString InstanceVersion::versionFileId(const int index) const +QString MinecraftProfile::versionFileId(const int index) const { if (index < 0 || index >= VersionPatches.size()) { @@ -119,7 +139,7 @@ QString InstanceVersion::versionFileId(const int index) const return VersionPatches.at(index)->getPatchID(); } -VersionPatchPtr InstanceVersion::versionPatch(const QString &id) +ProfilePatchPtr MinecraftProfile::versionPatch(const QString &id) { for (auto file : VersionPatches) { @@ -131,67 +151,27 @@ VersionPatchPtr InstanceVersion::versionPatch(const QString &id) return 0; } -VersionPatchPtr InstanceVersion::versionPatch(int index) +ProfilePatchPtr MinecraftProfile::versionPatch(int index) { if(index < 0 || index >= VersionPatches.size()) return 0; return VersionPatches[index]; } - -bool InstanceVersion::hasJarMods() -{ - return !jarMods.isEmpty(); -} - -bool InstanceVersion::hasFtbPack() -{ - return versionPatch("org.multimc.ftb.pack.json") != nullptr; -} - -bool InstanceVersion::removeFtbPack() +bool MinecraftProfile::isVanilla() { - return remove("org.multimc.ftb.pack.json"); -} - -bool InstanceVersion::isVanilla() -{ - QDir patches(PathCombine(m_instance->instanceRoot(), "patches/")); for(auto patchptr: VersionPatches) { if(patchptr->isCustom()) return false; } - if(QFile::exists(PathCombine(m_instance->instanceRoot(), "custom.json"))) - return false; - if(QFile::exists(PathCombine(m_instance->instanceRoot(), "version.json"))) - return false; return true; } -bool InstanceVersion::revertToVanilla() +bool MinecraftProfile::revertToVanilla() { + /* beginResetModel(); - // remove custom.json, if present - QString customPath = PathCombine(m_instance->instanceRoot(), "custom.json"); - if(QFile::exists(customPath)) - { - if(!QFile::remove(customPath)) - { - endResetModel(); - return false; - } - } - // remove version.json, if present - QString versionPath = PathCombine(m_instance->instanceRoot(), "version.json"); - if(QFile::exists(versionPath)) - { - if(!QFile::remove(versionPath)) - { - endResetModel(); - return false; - } - } // remove patches, if present auto it = VersionPatches.begin(); while (it != VersionPatches.end()) @@ -215,49 +195,15 @@ bool InstanceVersion::revertToVanilla() else it++; } - reapply(true); + reapply(); endResetModel(); saveCurrentOrder(); return true; -} - -bool InstanceVersion::hasDeprecatedVersionFiles() -{ - if(QFile::exists(PathCombine(m_instance->instanceRoot(), "custom.json"))) - return true; - if(QFile::exists(PathCombine(m_instance->instanceRoot(), "version.json"))) - return true; + */ return false; } -bool InstanceVersion::removeDeprecatedVersionFiles() -{ - beginResetModel(); - // remove custom.json, if present - QString customPath = PathCombine(m_instance->instanceRoot(), "custom.json"); - if(QFile::exists(customPath)) - { - if(!QFile::remove(customPath)) - { - endResetModel(); - return false; - } - } - // remove version.json, if present - QString versionPath = PathCombine(m_instance->instanceRoot(), "version.json"); - if(QFile::exists(versionPath)) - { - if(!QFile::remove(versionPath)) - { - endResetModel(); - return false; - } - } - endResetModel(); - return true; -} - -QList<std::shared_ptr<OneSixLibrary> > InstanceVersion::getActiveNormalLibs() +QList<std::shared_ptr<OneSixLibrary> > MinecraftProfile::getActiveNormalLibs() { QList<std::shared_ptr<OneSixLibrary> > output; for (auto lib : libraries) @@ -277,7 +223,8 @@ QList<std::shared_ptr<OneSixLibrary> > InstanceVersion::getActiveNormalLibs() } return output; } -QList<std::shared_ptr<OneSixLibrary> > InstanceVersion::getActiveNativeLibs() + +QList<std::shared_ptr<OneSixLibrary> > MinecraftProfile::getActiveNativeLibs() { QList<std::shared_ptr<OneSixLibrary> > output; for (auto lib : libraries) @@ -290,9 +237,9 @@ QList<std::shared_ptr<OneSixLibrary> > InstanceVersion::getActiveNativeLibs() return output; } -std::shared_ptr<InstanceVersion> InstanceVersion::fromJson(const QJsonObject &obj) +std::shared_ptr<MinecraftProfile> MinecraftProfile::fromJson(const QJsonObject &obj) { - std::shared_ptr<InstanceVersion> version(new InstanceVersion(0)); + std::shared_ptr<MinecraftProfile> version(new MinecraftProfile(new NullProfileStrategy())); try { VersionBuilder::readJsonAndApplyToVersion(version.get(), obj); @@ -304,7 +251,7 @@ std::shared_ptr<InstanceVersion> InstanceVersion::fromJson(const QJsonObject &ob return version; } -QVariant InstanceVersion::data(const QModelIndex &index, int role) const +QVariant MinecraftProfile::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); @@ -329,7 +276,7 @@ QVariant InstanceVersion::data(const QModelIndex &index, int role) const } return QVariant(); } -QVariant InstanceVersion::headerData(int section, Qt::Orientation orientation, int role) const +QVariant MinecraftProfile::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal) { @@ -348,36 +295,36 @@ QVariant InstanceVersion::headerData(int section, Qt::Orientation orientation, i } return QVariant(); } -Qt::ItemFlags InstanceVersion::flags(const QModelIndex &index) const +Qt::ItemFlags MinecraftProfile::flags(const QModelIndex &index) const { if (!index.isValid()) return Qt::NoItemFlags; return Qt::ItemIsSelectable | Qt::ItemIsEnabled; } -int InstanceVersion::rowCount(const QModelIndex &parent) const +int MinecraftProfile::rowCount(const QModelIndex &parent) const { return VersionPatches.size(); } -int InstanceVersion::columnCount(const QModelIndex &parent) const +int MinecraftProfile::columnCount(const QModelIndex &parent) const { return 2; } -void InstanceVersion::saveCurrentOrder() const +void MinecraftProfile::saveCurrentOrder() const { - PatchOrder order; + ProfileUtils::PatchOrder order; for(auto item: VersionPatches) { if(!item->isMoveable()) continue; order.append(item->getPatchID()); } - VersionBuilder::writeOverrideOrders(m_instance, order); + m_strategy->saveOrder(order); } -void InstanceVersion::move(const int index, const MoveDirection direction) +void MinecraftProfile::move(const int index, const MoveDirection direction) { int theirIndex; if (direction == MoveUp) @@ -388,7 +335,7 @@ void InstanceVersion::move(const int index, const MoveDirection direction) { theirIndex = index + 1; } - + if (index < 0 || index >= VersionPatches.size()) return; if (theirIndex >= rowCount()) @@ -401,7 +348,7 @@ void InstanceVersion::move(const int index, const MoveDirection direction) auto from = versionPatch(index); auto to = versionPatch(theirIndex); - + if (!from || !to || !to->isMoveable() || !from->isMoveable()) { return; @@ -412,13 +359,13 @@ void InstanceVersion::move(const int index, const MoveDirection direction) saveCurrentOrder(); reapply(); } -void InstanceVersion::resetOrder() +void MinecraftProfile::resetOrder() { - QDir(m_instance->instanceRoot()).remove("order.json"); - reload(m_externalPatches); + m_strategy->resetOrder(); + reload(); } -void InstanceVersion::reapply(const bool alreadyReseting) +void MinecraftProfile::reapply() { clear(); for(auto file: VersionPatches) @@ -428,7 +375,7 @@ void InstanceVersion::reapply(const bool alreadyReseting) finalize(); } -void InstanceVersion::finalize() +void MinecraftProfile::finalize() { // HACK: deny april fools. my head hurts enough already. QDate now = QDate::currentDate(); @@ -465,78 +412,15 @@ void InstanceVersion::finalize() finalizeArguments(minecraftArguments, processArguments); } -void InstanceVersion::installJarMods(QStringList selectedFiles) -{ - for(auto filename: selectedFiles) - { - installJarModByFilename(filename); - } -} - -void InstanceVersion::installJarModByFilename(QString filepath) +void MinecraftProfile::installJarMods(QStringList selectedFiles) { - QString patchDir = PathCombine(m_instance->instanceRoot(), "patches"); - if(!ensureFolderPathExists(patchDir)) - { - // THROW... - return; - } - - if (!ensureFolderPathExists(m_instance->jarModsDir())) - { - // THROW... - return; - } - - QFileInfo sourceInfo(filepath); - auto uuid = QUuid::createUuid(); - QString id = uuid.toString().remove('{').remove('}'); - QString target_filename = id + ".jar"; - QString target_id = "org.multimc.jarmod." + id; - QString target_name = sourceInfo.completeBaseName() + " (jar mod)"; - QString finalPath = PathCombine(m_instance->jarModsDir(), target_filename); - - QFileInfo targetInfo(finalPath); - if(targetInfo.exists()) - { - // THROW - return; - } - - if (!QFile::copy(sourceInfo.absoluteFilePath(),QFileInfo(finalPath).absoluteFilePath())) - { - // THROW - return; - } - - auto f = std::make_shared<VersionFile>(); - auto jarMod = std::make_shared<Jarmod>(); - jarMod->name = target_filename; - f->jarMods.append(jarMod); - f->name = target_name; - f->fileId = target_id; - f->order = getFreeOrderNumber(); - QString patchFileName = PathCombine(patchDir, target_id + ".json"); - f->filename = patchFileName; - - QFile file(patchFileName); - if (!file.open(QFile::WriteOnly)) - { - QLOG_ERROR() << "Error opening" << file.fileName() - << "for reading:" << file.errorString(); - return; - // THROW - } - file.write(f->toJson(true).toJson()); - file.close(); - int index = VersionPatches.size(); - beginInsertRows(QModelIndex(), index, index); - VersionPatches.append(f); - endInsertRows(); - saveCurrentOrder(); + m_strategy->installJarMods(selectedFiles); } -int InstanceVersion::getFreeOrderNumber() +/* + * TODO: get rid of this. Get rid of all order numbers. + */ +int MinecraftProfile::getFreeOrderNumber() { int largest = 100; // yes, I do realize this is dumb. The order thing itself is dumb. and to be removed next. diff --git a/logic/minecraft/InstanceVersion.h b/logic/minecraft/MinecraftProfile.h index a4849d6a..ef7e1369 100644 --- a/logic/minecraft/InstanceVersion.h +++ b/logic/minecraft/MinecraftProfile.h @@ -25,13 +25,22 @@ #include "VersionFile.h" #include "JarMod.h" +class ProfileStrategy; class OneSixInstance; -class InstanceVersion : public QAbstractListModel +class MinecraftProfile : public QAbstractListModel { Q_OBJECT + friend class ProfileStrategy; + public: - explicit InstanceVersion(OneSixInstance *instance, QObject *parent = 0); + explicit MinecraftProfile(ProfileStrategy *strategy); + + /// construct a MinecraftProfile from a single file + static std::shared_ptr<MinecraftProfile> fromJson(const QJsonObject &obj); + + void setStrategy(ProfileStrategy * strategy); + ProfileStrategy *strategy(); virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; @@ -39,57 +48,72 @@ public: virtual int columnCount(const QModelIndex &parent) const; virtual Qt::ItemFlags flags(const QModelIndex &index) const; - void reload(const QStringList &external = QStringList()); - void clear(); - - bool canRemove(const int index) const; - - QString versionFileId(const int index) const; - - // is this version unmodded vanilla minecraft? + /// is this version unchanged by the user? bool isVanilla(); - // remove any customizations on top of vanilla + + /// remove any customizations on top of whatever 'vanilla' means bool revertToVanilla(); - - // does this version consist of obsolete files? - bool hasDeprecatedVersionFiles(); - // remove obsolete files - bool removeDeprecatedVersionFiles(); - - // does this version have an FTB pack patch file? - bool hasFtbPack(); - // remove FTB pack - bool removeFtbPack(); - - // does this version have any jar mods? - bool hasJarMods(); + + /// install more jar mods void installJarMods(QStringList selectedFiles); - void installJarModByFilename(QString filepath); + + /// DEPRECATED, remove ASAP + int getFreeOrderNumber(); + + /// Can patch file # be removed? + bool canRemove(const int index) const; enum MoveDirection { MoveUp, MoveDown }; + /// move patch file # up or down the list void move(const int index, const MoveDirection direction); - void resetOrder(); - // clears and reapplies all version files - void reapply(const bool alreadyReseting = false); - void finalize(); - -public -slots: + /// remove patch file # - including files/records bool remove(const int index); + + /// remove patch file by id - including files/records bool remove(const QString id); + void resetOrder(); + + /// reload all profile patches from storage, clear the profile and apply the patches + void reload(); + + /// clear the profile + void clear(); + + /// apply the patches + void reapply(); + + /// do a finalization step (should always be done after applying all patches to profile) + void finalize(); + public: + /// get all java libraries that belong to the classpath QList<std::shared_ptr<OneSixLibrary>> getActiveNormalLibs(); + + /// get all native libraries that need to be available to the process QList<std::shared_ptr<OneSixLibrary>> getActiveNativeLibs(); - static std::shared_ptr<InstanceVersion> fromJson(const QJsonObject &obj); + /// get file ID of the patch file at # + QString versionFileId(const int index) const; -private: - bool preremove(VersionPatchPtr patch); - - // data members -public: + /// get the profile patch by id + ProfilePatchPtr versionPatch(const QString &id); + + /// get the profile patch by index + ProfilePatchPtr versionPatch(int index); + + /// save the current patch order + void saveCurrentOrder() const; + +public: /* only use in ProfileStrategy */ + /// Remove all the patches + void clearPatches(); + + /// Add the patch object to the internal list of patches + void appendPatch(ProfilePatchPtr patch); + +public: /* data */ /// the ID - determines which jar to use! ACTUALLY IMPORTANT! QString id; @@ -138,7 +162,7 @@ public: * The applet class, for some very old minecraft releases */ QString appletClass; - + /// the list of libs - both active and inactive, native and java QList<OneSixLibraryPtr> libraries; @@ -171,14 +195,7 @@ public: } */ // QList<Rule> rules; - - QList<VersionPatchPtr> VersionPatches; - VersionPatchPtr versionPatch(const QString &id); - VersionPatchPtr versionPatch(int index); - private: - QStringList m_externalPatches; - OneSixInstance *m_instance; - void saveCurrentOrder() const; - int getFreeOrderNumber(); + QList<ProfilePatchPtr> VersionPatches; + ProfileStrategy *m_strategy = nullptr; }; diff --git a/logic/minecraft/MinecraftVersion.cpp b/logic/minecraft/MinecraftVersion.cpp index bd53997b..32682bfb 100644 --- a/logic/minecraft/MinecraftVersion.cpp +++ b/logic/minecraft/MinecraftVersion.cpp @@ -1,7 +1,8 @@ #include "MinecraftVersion.h" -#include "InstanceVersion.h" +#include "MinecraftProfile.h" #include "VersionBuildError.h" #include "VersionBuilder.h" +#include "ProfileUtils.h" #include "MultiMC.h" #include "logic/settings/SettingsObject.h" @@ -56,15 +57,20 @@ bool MinecraftVersion::isMinecraftVersion() // 1. assume the local file is good. load, check. If it's good, apply. // 2. if discrepancies are found, fall out and fail (impossible to apply incomplete version). -void MinecraftVersion::applyFileTo(InstanceVersion *version) +void MinecraftVersion::applyFileTo(MinecraftProfile *version) +{ + getVersionFile()->applyTo(version); +} + +VersionFilePtr MinecraftVersion::getVersionFile() { QFileInfo versionFile(QString("versions/%1/%1.dat").arg(m_descriptor)); - - auto versionObj = VersionBuilder::parseBinaryJsonFile(versionFile); - versionObj->applyTo(version); + + return ProfileUtils::parseBinaryJsonFile(versionFile); } -void MinecraftVersion::applyTo(InstanceVersion *version) + +void MinecraftVersion::applyTo(MinecraftProfile *version) { // do we have this one cached? if (m_versionSource == Local) diff --git a/logic/minecraft/MinecraftVersion.h b/logic/minecraft/MinecraftVersion.h index 84d0773e..fbb209f2 100644 --- a/logic/minecraft/MinecraftVersion.h +++ b/logic/minecraft/MinecraftVersion.h @@ -20,15 +20,15 @@ #include <QDateTime> #include "logic/BaseVersion.h" -#include "VersionPatch.h" +#include "ProfilePatch.h" #include "VersionFile.h" #include "VersionSource.h" -class InstanceVersion; +class MinecraftProfile; class MinecraftVersion; typedef std::shared_ptr<MinecraftVersion> MinecraftVersionPtr; -class MinecraftVersion : public BaseVersion, public VersionPatch +class MinecraftVersion : public BaseVersion, public ProfilePatch { public: /* methods */ bool usesLegacyLauncher(); @@ -37,9 +37,9 @@ public: /* methods */ virtual QString typeString() const override; virtual bool hasJarMods() override; virtual bool isMinecraftVersion() override; - virtual void applyTo(InstanceVersion *version) override; - virtual int getOrder(); - virtual void setOrder(int order); + virtual void applyTo(MinecraftProfile *version) override; + virtual int getOrder() override; + virtual void setOrder(int order) override; virtual QList<JarmodPtr> getJarMods() override; virtual QString getPatchID() override; virtual QString getPatchVersion() override; @@ -47,10 +47,12 @@ public: /* methods */ virtual QString getPatchFilename() override; bool needsUpdate(); bool hasUpdate(); - virtual bool isCustom(); + virtual bool isCustom() override; + + VersionFilePtr getVersionFile(); private: /* methods */ - void applyFileTo(InstanceVersion *version); + void applyFileTo(MinecraftProfile *version); public: /* data */ /// The URL that this version will be downloaded from. maybe. @@ -92,7 +94,7 @@ public: /* data */ /// order of this file... default = -2 int order = -2; - + /// an update available from Mojang MinecraftVersionPtr upstreamUpdate; }; diff --git a/logic/minecraft/MinecraftVersionList.cpp b/logic/minecraft/MinecraftVersionList.cpp index a93ea301..68e93d54 100644 --- a/logic/minecraft/MinecraftVersionList.cpp +++ b/logic/minecraft/MinecraftVersionList.cpp @@ -25,12 +25,53 @@ #include "logic/net/URLConstants.h" #include "ParseUtils.h" +#include "ProfileUtils.h" #include "VersionBuilder.h" -#include <logic/VersionFilterData.h> +#include "VersionFilterData.h" + #include <pathutils.h> static const char * localVersionCache = "versions/versions.dat"; +class MCVListLoadTask : public Task +{ + Q_OBJECT + +public: + explicit MCVListLoadTask(MinecraftVersionList *vlist); + virtual ~MCVListLoadTask() override{}; + + virtual void executeTask() override; + +protected +slots: + void list_downloaded(); + +protected: + QNetworkReply *vlistReply; + MinecraftVersionList *m_list; + MinecraftVersion *m_currentStable; +}; + +class MCVListVersionUpdateTask : public Task +{ + Q_OBJECT + +public: + explicit MCVListVersionUpdateTask(MinecraftVersionList *vlist, QString updatedVersion); + virtual ~MCVListVersionUpdateTask() override{}; + virtual void executeTask() override; + +protected +slots: + void json_downloaded(); + +protected: + NetJobPtr specificVersionDownloadJob; + QString versionToUpdate; + MinecraftVersionList *m_list; +}; + class ListLoadError : public MMCError { public: @@ -442,21 +483,9 @@ void MCVListVersionUpdateTask::json_downloaded() emitFailed(tr("Couldn't process version file: %1").arg(e.cause())); return; } - QList<RawLibraryPtr> filteredLibs; - QList<RawLibraryPtr> lwjglLibs; - for (auto lib : file->overwriteLibs) - { - if (g_VersionFilterData.lwjglWhitelist.contains(lib->artifactPrefix())) - { - lwjglLibs.append(lib); - } - else - { - filteredLibs.append(lib); - } - } - file->overwriteLibs = filteredLibs; + // Strip LWJGL from the version file. We use our own. + ProfileUtils::removeLwjglFromPatch(file); // TODO: recognize and add LWJGL versions here. @@ -523,7 +552,7 @@ void MinecraftVersionList::saveCachedList() entriesArr.append(entryObj); } toplevel.insert("versions", entriesArr); - + { bool someLatest = false; QJsonObject latestObj; @@ -542,7 +571,7 @@ void MinecraftVersionList::saveCachedList() toplevel.insert("latest", latestObj); } } - + QJsonDocument doc(toplevel); QByteArray jsonData = doc.toBinaryData(); qint64 result = tfile.write(jsonData); @@ -593,3 +622,5 @@ void MinecraftVersionList::finalizeUpdate(QString version) saveCachedList(); } + +#include "MinecraftVersionList.moc"
\ No newline at end of file diff --git a/logic/minecraft/MinecraftVersionList.h b/logic/minecraft/MinecraftVersionList.h index 17708444..be9f8581 100644 --- a/logic/minecraft/MinecraftVersionList.h +++ b/logic/minecraft/MinecraftVersionList.h @@ -26,7 +26,6 @@ class MCVListLoadTask; class MCVListVersionUpdateTask; -class QNetworkReply; class MinecraftVersionList : public BaseVersionList { @@ -67,42 +66,3 @@ protected slots: virtual void updateListData(QList<BaseVersionPtr> versions); }; - -class MCVListLoadTask : public Task -{ - Q_OBJECT - -public: - explicit MCVListLoadTask(MinecraftVersionList *vlist); - virtual ~MCVListLoadTask() override{}; - - virtual void executeTask() override; - -protected -slots: - void list_downloaded(); - -protected: - QNetworkReply *vlistReply; - MinecraftVersionList *m_list; - MinecraftVersion *m_currentStable; -}; - -class MCVListVersionUpdateTask : public Task -{ - Q_OBJECT - -public: - explicit MCVListVersionUpdateTask(MinecraftVersionList *vlist, QString updatedVersion); - virtual ~MCVListVersionUpdateTask() override{}; - virtual void executeTask() override; - -protected -slots: - void json_downloaded(); - -protected: - NetJobPtr specificVersionDownloadJob; - QString versionToUpdate; - MinecraftVersionList *m_list; -}; diff --git a/logic/minecraft/NullProfileStrategy.h b/logic/minecraft/NullProfileStrategy.h new file mode 100644 index 00000000..eaabd3c7 --- /dev/null +++ b/logic/minecraft/NullProfileStrategy.h @@ -0,0 +1,24 @@ +#pragma once + +#include "ProfileStrategy.h" + +class NullProfileStrategy: public ProfileStrategy +{ + virtual bool installJarMods(QStringList filepaths) + { + return false; + } + virtual void load() {}; + virtual bool removePatch(ProfilePatchPtr jarMod) + { + return false; + } + virtual bool resetOrder() + { + return false; + } + virtual bool saveOrder(ProfileUtils::PatchOrder order) + { + return false; + } +};
\ No newline at end of file diff --git a/logic/minecraft/OneSixLibrary.cpp b/logic/minecraft/OneSixLibrary.cpp index 67257a55..43d381fb 100644 --- a/logic/minecraft/OneSixLibrary.cpp +++ b/logic/minecraft/OneSixLibrary.cpp @@ -18,10 +18,6 @@ #include "OneSixLibrary.h" #include "OneSixRule.h" #include "OpSys.h" -#include "logic/net/URLConstants.h" -#include <pathutils.h> -#include <JlCompress.h> -#include "logger/QsLog.h" OneSixLibrary::OneSixLibrary(RawLibraryPtr base) { diff --git a/logic/minecraft/OneSixProfileStrategy.cpp b/logic/minecraft/OneSixProfileStrategy.cpp new file mode 100644 index 00000000..bdb2f8ee --- /dev/null +++ b/logic/minecraft/OneSixProfileStrategy.cpp @@ -0,0 +1,270 @@ +#include "logic/minecraft/OneSixProfileStrategy.h" +#include "logic/minecraft/VersionBuildError.h" +#include "logic/OneSixInstance.h" +#include "logic/minecraft/MinecraftVersionList.h" + +#include "MultiMC.h" + +#include <pathutils.h> +#include <QDir> +#include <QUuid> +#include <QJsonDocument> +#include <QJsonArray> + +OneSixProfileStrategy::OneSixProfileStrategy(OneSixInstance* instance) +{ + m_instance = instance; +} + +void OneSixProfileStrategy::upgradeDeprecatedFiles() +{ + auto versionJsonPath = PathCombine(m_instance->instanceRoot(), "version.json"); + auto customJsonPath = PathCombine(m_instance->instanceRoot(), "custom.json"); + auto mcJson = PathCombine(m_instance->instanceRoot(), "patches" , "net.minecraft.json"); + + // convert old crap. + if(QFile::exists(customJsonPath)) + { + if(!ensureFilePathExists(mcJson)) + { + // WHAT DO??? + } + if(!QFile::rename(customJsonPath, mcJson)) + { + // WHAT DO??? + } + if(QFile::exists(versionJsonPath)) + { + if(!QFile::remove(versionJsonPath)) + { + // WHAT DO??? + } + } + } + else if(QFile::exists(versionJsonPath)) + { + if(!ensureFilePathExists(mcJson)) + { + // WHAT DO??? + } + if(!QFile::rename(versionJsonPath, mcJson)) + { + // WHAT DO??? + } + } +} + + +void OneSixProfileStrategy::loadDefaultBuiltinPatches() +{ + auto mcJson = PathCombine(m_instance->instanceRoot(), "patches" , "net.minecraft.json"); + // load up the base minecraft patch + ProfilePatchPtr minecraftPatch; + if(QFile::exists(mcJson)) + { + auto file = ProfileUtils::parseJsonFile(QFileInfo(mcJson), false); + file->fileId = "net.minecraft"; + file->name = "Minecraft"; + if(file->version.isEmpty()) + { + file->version = m_instance->intendedVersionId(); + } + minecraftPatch = std::dynamic_pointer_cast<ProfilePatch>(file); + } + else + { + auto minecraftList = MMC->minecraftlist(); + auto mcversion = minecraftList->findVersion(m_instance->intendedVersionId()); + minecraftPatch = std::dynamic_pointer_cast<ProfilePatch>(mcversion); + } + if (!minecraftPatch) + { + throw VersionIncomplete("net.minecraft"); + } + minecraftPatch->setOrder(-2); + profile->appendPatch(minecraftPatch); + + + // TODO: this is obviously fake. + QResource LWJGL(":/versions/LWJGL/2.9.1.json"); + auto lwjgl = ProfileUtils::parseJsonFile(LWJGL.absoluteFilePath(), false, false); + auto lwjglPatch = std::dynamic_pointer_cast<ProfilePatch>(lwjgl); + if (!lwjglPatch) + { + throw VersionIncomplete("org.lwjgl"); + } + lwjglPatch->setOrder(-1); + lwjgl->setVanilla(true); + profile->appendPatch(lwjglPatch); +} + +void OneSixProfileStrategy::loadUserPatches() +{ + // load all patches, put into map for ordering, apply in the right order + ProfileUtils::PatchOrder userOrder; + ProfileUtils::readOverrideOrders(PathCombine(m_instance->instanceRoot(), "order.json"), userOrder); + QDir patches(PathCombine(m_instance->instanceRoot(),"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"); + QFileInfo finfo(filename); + if(!finfo.exists()) + { + QLOG_INFO() << "Patch file " << filename << " was deleted by external means..."; + continue; + } + QLOG_INFO() << "Reading" << filename << "by user order"; + auto file = ProfileUtils::parseJsonFile(finfo, 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)); + } + profile->appendPatch(file); + } + // now load the rest by internal preference. + QMap<int, QPair<QString, VersionFilePtr>> files; + for (auto info : patches.entryInfoList(QStringList() << "*.json", QDir::Files)) + { + // parse the file + QLOG_INFO() << "Reading" << info.fileName(); + auto file = ProfileUtils::parseJsonFile(info, true); + // ignore builtins + if (file->fileId == "net.minecraft") + continue; + 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)); + } + files.insert(file->order, qMakePair(info.fileName(), file)); + } + for (auto order : files.keys()) + { + auto &filePair = files[order]; + profile->appendPatch(filePair.second); + } +} + + +void OneSixProfileStrategy::load() +{ + profile->clearPatches(); + + upgradeDeprecatedFiles(); + loadDefaultBuiltinPatches(); + loadUserPatches(); + + profile->finalize(); +} + +bool OneSixProfileStrategy::saveOrder(ProfileUtils::PatchOrder order) +{ + return ProfileUtils::writeOverrideOrders(PathCombine(m_instance->instanceRoot(), "order.json"), order); +} + +bool OneSixProfileStrategy::resetOrder() +{ + return QDir(m_instance->instanceRoot()).remove("order.json"); +} + +bool OneSixProfileStrategy::removePatch(ProfilePatchPtr patch) +{ + bool ok = true; + // first, remove the patch file. this ensures it's not used anymore + auto fileName = patch->getPatchFilename(); + + + auto preRemoveJarMod = [&](JarmodPtr jarMod) -> bool + { + QString fullpath = PathCombine(m_instance->jarModsDir(), jarMod->name); + QFileInfo finfo (fullpath); + if(finfo.exists()) + { + return QFile::remove(fullpath); + } + return true; + }; + + for(auto &jarmod: patch->getJarMods()) + { + ok &= preRemoveJarMod(jarmod); + } + return ok; +} + +bool OneSixProfileStrategy::installJarMods(QStringList filepaths) +{ + QString patchDir = PathCombine(m_instance->instanceRoot(), "patches"); + if(!ensureFolderPathExists(patchDir)) + { + return false; + } + + if (!ensureFolderPathExists(m_instance->jarModsDir())) + { + return false; + } + + for(auto filepath:filepaths) + { + QFileInfo sourceInfo(filepath); + auto uuid = QUuid::createUuid(); + QString id = uuid.toString().remove('{').remove('}'); + QString target_filename = id + ".jar"; + QString target_id = "org.multimc.jarmod." + id; + QString target_name = sourceInfo.completeBaseName() + " (jar mod)"; + QString finalPath = PathCombine(m_instance->jarModsDir(), target_filename); + + QFileInfo targetInfo(finalPath); + if(targetInfo.exists()) + { + return false; + } + + if (!QFile::copy(sourceInfo.absoluteFilePath(),QFileInfo(finalPath).absoluteFilePath())) + { + return false; + } + + auto f = std::make_shared<VersionFile>(); + auto jarMod = std::make_shared<Jarmod>(); + jarMod->name = target_filename; + f->jarMods.append(jarMod); + f->name = target_name; + f->fileId = target_id; + f->order = profile->getFreeOrderNumber(); + QString patchFileName = PathCombine(patchDir, target_id + ".json"); + f->filename = patchFileName; + + QFile file(patchFileName); + if (!file.open(QFile::WriteOnly)) + { + QLOG_ERROR() << "Error opening" << file.fileName() + << "for reading:" << file.errorString(); + return false; + } + file.write(f->toJson(true).toJson()); + file.close(); + profile->appendPatch(f); + } + profile->saveCurrentOrder(); + profile->reapply(); + return true; +} + diff --git a/logic/minecraft/OneSixProfileStrategy.h b/logic/minecraft/OneSixProfileStrategy.h new file mode 100644 index 00000000..b554b1ea --- /dev/null +++ b/logic/minecraft/OneSixProfileStrategy.h @@ -0,0 +1,24 @@ +#pragma once +#include "ProfileStrategy.h" + +class OneSixInstance; + +class OneSixProfileStrategy : public ProfileStrategy +{ +public: + OneSixProfileStrategy(OneSixInstance * instance); + virtual ~OneSixProfileStrategy() {}; + virtual void load() override; + virtual bool resetOrder() override; + virtual bool saveOrder(ProfileUtils::PatchOrder order) override; + virtual bool installJarMods(QStringList filepaths) override; + virtual bool removePatch(ProfilePatchPtr patch) override; + +protected: + void loadDefaultBuiltinPatches(); + void loadUserPatches(); + void upgradeDeprecatedFiles(); + +protected: + OneSixInstance *m_instance; +};
\ No newline at end of file diff --git a/logic/minecraft/VersionPatch.h b/logic/minecraft/ProfilePatch.h index 6c7bd7cf..2e97677e 100644 --- a/logic/minecraft/VersionPatch.h +++ b/logic/minecraft/ProfilePatch.h @@ -4,24 +4,24 @@ #include <QList> #include "JarMod.h" -class InstanceVersion; -class VersionPatch +class MinecraftProfile; +class ProfilePatch { public: - virtual ~VersionPatch(){}; - virtual void applyTo(InstanceVersion *version) = 0; - + virtual ~ProfilePatch(){}; + virtual void applyTo(MinecraftProfile *version) = 0; + virtual bool isMinecraftVersion() = 0; virtual bool hasJarMods() = 0; virtual QList<JarmodPtr> getJarMods() = 0; - + virtual bool isMoveable() { return getOrder() >= 0; } virtual void setOrder(int order) = 0; virtual int getOrder() = 0; - + virtual QString getPatchID() = 0; virtual QString getPatchName() = 0; virtual QString getPatchVersion() = 0; @@ -29,4 +29,4 @@ public: virtual bool isCustom() = 0; }; -typedef std::shared_ptr<VersionPatch> VersionPatchPtr; +typedef std::shared_ptr<ProfilePatch> ProfilePatchPtr; diff --git a/logic/minecraft/ProfileStrategy.h b/logic/minecraft/ProfileStrategy.h new file mode 100644 index 00000000..364458f5 --- /dev/null +++ b/logic/minecraft/ProfileStrategy.h @@ -0,0 +1,30 @@ +#pragma once + +#include "ProfileUtils.h" + +class MinecraftProfile; + +class ProfileStrategy +{ + friend class MinecraftProfile; +public: + virtual ~ProfileStrategy(){}; + + /// load the patch files into the profile + virtual void load() = 0; + + /// reset the order of patches + virtual bool resetOrder() = 0; + + /// save the order of patches, given the order + virtual bool saveOrder(ProfileUtils::PatchOrder order) = 0; + + /// install a list of jar mods into the instance + virtual bool installJarMods(QStringList filepaths) = 0; + + /// remove any files or records that constitute the version patch + virtual bool removePatch(ProfilePatchPtr jarMod) = 0; + +protected: + MinecraftProfile *profile; +}; diff --git a/logic/minecraft/ProfileUtils.cpp b/logic/minecraft/ProfileUtils.cpp new file mode 100644 index 00000000..48e73472 --- /dev/null +++ b/logic/minecraft/ProfileUtils.cpp @@ -0,0 +1,145 @@ +#include "ProfileUtils.h" +#include "logic/minecraft/VersionFilterData.h" +#include "logic/MMCJson.h" +#include "logger/QsLog.h" + +#include <QJsonDocument> +#include <QJsonArray> +#include <QRegularExpression> + +namespace ProfileUtils +{ + +static const int currentOrderFileVersion = 1; + +bool writeOverrideOrders(QString path, const PatchOrder &order) +{ + QJsonObject obj; + obj.insert("version", currentOrderFileVersion); + QJsonArray orderArray; + for(auto str: order) + { + orderArray.append(str); + } + obj.insert("order", orderArray); + QFile orderFile(path); + 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; +} + +bool readOverrideOrders(QString path, PatchOrder &order) +{ + QFile orderFile(path); + if (!orderFile.exists()) + { + QLOG_WARN() << "Order file doesn't exist. Ignoring."; + return false; + } + if (!orderFile.open(QFile::ReadOnly)) + { + QLOG_ERROR() << "Couldn't open" << orderFile.fileName() + << " for reading:" << orderFile.errorString(); + QLOG_WARN() << "Ignoring overriden order"; + return false; + } + + // 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 false; + } + + // and then read it and process it if all above is true. + try + { + auto obj = MMCJson::ensureObject(doc); + // check order file version. + auto version = MMCJson::ensureInteger(obj.value("version"), "version"); + if (version != currentOrderFileVersion) + { + 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"; + order.clear(); + return false; + } + return true; +} + +VersionFilePtr 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); +} + +VersionFilePtr parseBinaryJsonFile(const QFileInfo &fileInfo) +{ + 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())); + } + QJsonDocument doc = QJsonDocument::fromBinaryData(file.readAll()); + file.close(); + if (doc.isNull()) + { + file.remove(); + throw JSONValidationError( + QObject::tr("Unable to process the version file %1.").arg(fileInfo.fileName())); + } + return VersionFile::fromJson(doc, file.fileName(), false, false); +} + +void removeLwjglFromPatch(VersionFilePtr patch) +{ + auto filter = [](QList<RawLibraryPtr>& libs) + { + QList<RawLibraryPtr> filteredLibs; + for (auto lib : libs) + { + if (!g_VersionFilterData.lwjglWhitelist.contains(lib->artifactPrefix())) + { + filteredLibs.append(lib); + } + } + libs = filteredLibs; + }; + filter(patch->addLibs); + filter(patch->overwriteLibs); +} +} diff --git a/logic/minecraft/ProfileUtils.h b/logic/minecraft/ProfileUtils.h new file mode 100644 index 00000000..88027374 --- /dev/null +++ b/logic/minecraft/ProfileUtils.h @@ -0,0 +1,25 @@ +#pragma once +#include "RawLibrary.h" +#include "VersionFile.h" + +namespace ProfileUtils +{ +typedef QStringList PatchOrder; + +/// Read and parse a OneSix format order file +bool readOverrideOrders(QString path, PatchOrder &order); + +/// Write a OneSix format order file +bool writeOverrideOrders(QString path, const PatchOrder &order); + + +/// Parse a version file in JSON format +VersionFilePtr parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder, bool isFTB = false); + +/// Parse a version file in binary JSON format +VersionFilePtr parseBinaryJsonFile(const QFileInfo &fileInfo); + +/// Remove LWJGL from a patch file. This is applied to all Mojang-like profile files. +void removeLwjglFromPatch(VersionFilePtr patch); + +} diff --git a/logic/minecraft/VersionBuilder.cpp b/logic/minecraft/VersionBuilder.cpp index b1622b58..7f77b493 100644 --- a/logic/minecraft/VersionBuilder.cpp +++ b/logic/minecraft/VersionBuilder.cpp @@ -24,15 +24,17 @@ #include <QDir> #include <qresource.h> #include <modutils.h> +#include <pathutils.h> #include "MultiMC.h" #include "logic/minecraft/VersionBuilder.h" -#include "logic/minecraft/InstanceVersion.h" +#include "logic/minecraft/MinecraftProfile.h" #include "logic/minecraft/OneSixRule.h" -#include "logic/minecraft/VersionPatch.h" +#include "logic/minecraft/ProfilePatch.h" #include "logic/minecraft/VersionFile.h" #include "VersionBuildError.h" #include "MinecraftVersionList.h" +#include "ProfileUtils.h" #include "logic/OneSixInstance.h" #include "logic/MMCJson.h" @@ -43,17 +45,15 @@ VersionBuilder::VersionBuilder() { } -void VersionBuilder::build(InstanceVersion *version, OneSixInstance *instance, - const QStringList &external) +void VersionBuilder::build(MinecraftProfile *version, OneSixInstance *instance) { VersionBuilder builder; builder.m_version = version; builder.m_instance = instance; - builder.external_patches = external; builder.buildInternal(); } -void VersionBuilder::readJsonAndApplyToVersion(InstanceVersion *version, const QJsonObject &obj) +void VersionBuilder::readJsonAndApplyToVersion(MinecraftProfile *version, const QJsonObject &obj) { VersionBuilder builder; builder.m_version = version; @@ -61,178 +61,6 @@ void VersionBuilder::readJsonAndApplyToVersion(InstanceVersion *version, const Q builder.readJsonAndApply(obj); } -void VersionBuilder::buildFromCustomJson() -{ - QLOG_INFO() << "Building version from custom.json within the instance."; - QLOG_INFO() << "Reading custom.json"; - auto file = parseJsonFile(QFileInfo(instance_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->VersionPatches.append(file); - m_version->finalize(); - return; -} - -void VersionBuilder::buildFromVersionJson() -{ - QLOG_INFO() << "Building version from version.json and patches within the instance."; - QLOG_INFO() << "Reading version.json"; - auto file = parseJsonFile(QFileInfo(instance_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->VersionPatches.append(file); - - // load all patches, put into map for ordering, apply in the right order - readInstancePatches(); - - // some final touches - m_version->finalize(); -} - -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"); - QFileInfo finfo(filename); - if(!finfo.exists()) - { - QLOG_INFO() << "Patch file " << filename << " was deleted by external means..."; - continue; - } - QLOG_INFO() << "Reading" << filename << "by user order"; - auto file = parseJsonFile(finfo, 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<int, QPair<QString, VersionFilePtr>> files; - for (auto info : patches.entryInfoList(QStringList() << "*.json", QDir::Files)) - { - // parse the file - QLOG_INFO() << "Reading" << info.fileName(); - auto file = parseJsonFile(info, true); - // ignore builtins - if (file->fileId == "net.minecraft") - continue; - 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)); - } - files.insert(file->order, qMakePair(info.fileName(), file)); - } - for (auto order : files.keys()) - { - auto &filePair = files[order]; - m_version->VersionPatches.append(filePair.second); - } -} - -void VersionBuilder::buildFromExternalPatches() -{ - QLOG_INFO() << "Building version from external files."; - int externalOrder = -1; - for (auto fileName : external_patches) - { - 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->VersionPatches.append(file); - } - // some final touches - m_version->finalize(); -} - -void VersionBuilder::buildFromMultilayer() -{ - QLOG_INFO() << "Building version from multilayered sources."; - // just the builtin stuff for now - auto minecraftList = MMC->minecraftlist(); - auto mcversion = minecraftList->findVersion(m_instance->intendedVersionId()); - auto minecraftPatch = std::dynamic_pointer_cast<VersionPatch>(mcversion); - if (!minecraftPatch) - { - throw VersionIncomplete("net.minecraft"); - } - minecraftPatch->setOrder(-2); - m_version->VersionPatches.append(minecraftPatch); - - // TODO: this is obviously fake. - QResource LWJGL(":/versions/LWJGL/2.9.1.json"); - auto lwjgl = parseJsonFile(LWJGL.absoluteFilePath(), false, false); - auto lwjglPatch = std::dynamic_pointer_cast<VersionPatch>(lwjgl); - if (!lwjglPatch) - { - throw VersionIncomplete("org.lwjgl"); - } - lwjglPatch->setOrder(-1); - lwjgl->setVanilla(true); - m_version->VersionPatches.append(lwjglPatch); - - // load all patches, put into map for ordering, apply in the right order - readInstancePatches(); - - m_version->finalize(); -} - -void VersionBuilder::buildInternal() -{ - m_version->VersionPatches.clear(); - instance_root = QDir(m_instance->instanceRoot()); - // if we do external files, do just those. - if (!external_patches.isEmpty()) - { - buildFromExternalPatches(); - } - // else, if there's custom json, we just do that. - else if (QFile::exists(instance_root.absoluteFilePath("custom.json"))) - { - buildFromCustomJson(); - } - // version.json -> patches/*.json - else if (QFile::exists(instance_root.absoluteFilePath("version.json"))) - { - buildFromVersionJson(); - } - else - { - buildFromMultilayer(); - } -} - void VersionBuilder::readJsonAndApply(const QJsonObject &obj) { m_version->clear(); @@ -240,121 +68,17 @@ void VersionBuilder::readJsonAndApply(const QJsonObject &obj) auto file = VersionFile::fromJson(QJsonDocument(obj), QString(), false); file->applyTo(m_version); - m_version->VersionPatches.append(file); + m_version->appendPatch(file); } -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); -} -VersionFilePtr VersionBuilder::parseBinaryJsonFile(const QFileInfo &fileInfo) +void VersionBuilder::readInstancePatches() { - 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())); - } - QJsonDocument doc = QJsonDocument::fromBinaryData(file.readAll()); - file.close(); - if (doc.isNull()) - { - file.remove(); - throw JSONValidationError( - QObject::tr("Unable to process the version file %1.").arg(fileInfo.fileName())); - } - return VersionFile::fromJson(doc, file.fileName(), false, false); -} -static const int currentOrderFileVersion = 1; +} -bool VersionBuilder::readOverrideOrders(OneSixInstance *instance, PatchOrder &order) +void VersionBuilder::buildInternal() { - QFile orderFile(instance->instanceRoot() + "/order.json"); - if (!orderFile.exists()) - { - QLOG_WARN() << "Order file doesn't exist. Ignoring."; - return false; - } - if (!orderFile.open(QFile::ReadOnly)) - { - QLOG_ERROR() << "Couldn't open" << orderFile.fileName() - << " for reading:" << orderFile.errorString(); - QLOG_WARN() << "Ignoring overriden order"; - return false; - } - - // 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 false; - } - // and then read it and process it if all above is true. - try - { - auto obj = MMCJson::ensureObject(doc); - // check order file version. - auto version = MMCJson::ensureInteger(obj.value("version"), "version"); - if (version != currentOrderFileVersion) - { - 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"; - order.clear(); - return false; - } - return true; } -bool VersionBuilder::writeOverrideOrders(OneSixInstance *instance, const PatchOrder &order) -{ - QJsonObject obj; - obj.insert("version", currentOrderFileVersion); - QJsonArray orderArray; - for(auto str: order) - { - orderArray.append(str); - } - obj.insert("order", orderArray); - 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 index 2f7e6b6b..b2d23da5 100644 --- a/logic/minecraft/VersionBuilder.h +++ b/logic/minecraft/VersionBuilder.h @@ -19,38 +19,25 @@ #include <QMap> #include "VersionFile.h" -class InstanceVersion; +class MinecraftProfile; class OneSixInstance; class QJsonObject; class QFileInfo; -typedef QStringList PatchOrder; - class VersionBuilder { VersionBuilder(); public: - static void build(InstanceVersion *version, OneSixInstance *instance, const QStringList &external); - static void readJsonAndApplyToVersion(InstanceVersion *version, const QJsonObject &obj); - static VersionFilePtr parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder, bool isFTB = false); - static VersionFilePtr parseBinaryJsonFile(const QFileInfo &fileInfo); - - bool readOverrideOrders(OneSixInstance *instance, PatchOrder &order); - static bool writeOverrideOrders(OneSixInstance *instance, const PatchOrder &order); + static void build(MinecraftProfile *version, OneSixInstance *instance); + static void readJsonAndApplyToVersion(MinecraftProfile *version, const QJsonObject &obj); private: - InstanceVersion *m_version; + MinecraftProfile *m_version; OneSixInstance *m_instance; - QStringList external_patches; - QDir instance_root; - + void buildInternal(); - void buildFromExternalPatches(); - void buildFromCustomJson(); - void buildFromVersionJson(); - void buildFromMultilayer(); - + void readInstancePatches(); - + void readJsonAndApply(const QJsonObject &obj); }; diff --git a/logic/minecraft/VersionFile.cpp b/logic/minecraft/VersionFile.cpp index 3e0648cc..97ce6535 100644 --- a/logic/minecraft/VersionFile.cpp +++ b/logic/minecraft/VersionFile.cpp @@ -6,7 +6,7 @@ #include "logic/minecraft/VersionFile.h" #include "logic/minecraft/OneSixLibrary.h" -#include "logic/minecraft/InstanceVersion.h" +#include "logic/minecraft/MinecraftProfile.h" #include "logic/minecraft/JarMod.h" #include "ParseUtils.h" @@ -256,8 +256,7 @@ QJsonDocument VersionFile::toJson(bool saveOrder) bool VersionFile::isMinecraftVersion() { - return (fileId == "org.multimc.version.json") || (fileId == "net.minecraft") || - (fileId == "org.multimc.custom.json"); + return fileId == "net.minecraft"; } bool VersionFile::hasJarMods() @@ -265,7 +264,7 @@ bool VersionFile::hasJarMods() return !jarMods.isEmpty(); } -void VersionFile::applyTo(InstanceVersion *version) +void VersionFile::applyTo(MinecraftProfile *version) { if (minimumLauncherVersion != -1) { diff --git a/logic/minecraft/VersionFile.h b/logic/minecraft/VersionFile.h index 96856891..ddc3f849 100644 --- a/logic/minecraft/VersionFile.h +++ b/logic/minecraft/VersionFile.h @@ -6,23 +6,23 @@ #include <memory> #include "logic/minecraft/OpSys.h" #include "logic/minecraft/OneSixRule.h" -#include "VersionPatch.h" +#include "ProfilePatch.h" #include "MMCError.h" #include "OneSixLibrary.h" #include "JarMod.h" -class InstanceVersion; +class MinecraftProfile; class VersionFile; typedef std::shared_ptr<VersionFile> VersionFilePtr; -class VersionFile : public VersionPatch +class VersionFile : public ProfilePatch { public: /* methods */ static VersionFilePtr fromJson(const QJsonDocument &doc, const QString &filename, const bool requireOrder, const bool isFTB = false); QJsonDocument toJson(bool saveOrder); - virtual void applyTo(InstanceVersion *version) override; + virtual void applyTo(MinecraftProfile *version) override; virtual bool isMinecraftVersion() override; virtual bool hasJarMods() override; virtual int getOrder() override diff --git a/logic/minecraft/VersionFilterData.cpp b/logic/minecraft/VersionFilterData.cpp new file mode 100644 index 00000000..ef8b049e --- /dev/null +++ b/logic/minecraft/VersionFilterData.cpp @@ -0,0 +1,72 @@ +#include "VersionFilterData.h" +#include "ParseUtils.h" + +VersionFilterData g_VersionFilterData = VersionFilterData(); + +VersionFilterData::VersionFilterData() +{ + // 1.3.* + auto libs13 = + QList<FMLlib>{{"argo-2.25.jar", "bb672829fde76cb163004752b86b0484bd0a7f4b", false}, + {"guava-12.0.1.jar", "b8e78b9af7bf45900e14c6f958486b6ca682195f", false}, + {"asm-all-4.0.jar", "98308890597acb64047f7e896638e0d98753ae82", false}}; + + fmlLibsMapping["1.3.2"] = libs13; + + // 1.4.* + auto libs14 = QList<FMLlib>{ + {"argo-2.25.jar", "bb672829fde76cb163004752b86b0484bd0a7f4b", false}, + {"guava-12.0.1.jar", "b8e78b9af7bf45900e14c6f958486b6ca682195f", false}, + {"asm-all-4.0.jar", "98308890597acb64047f7e896638e0d98753ae82", false}, + {"bcprov-jdk15on-147.jar", "b6f5d9926b0afbde9f4dbe3db88c5247be7794bb", false}}; + + fmlLibsMapping["1.4"] = libs14; + fmlLibsMapping["1.4.1"] = libs14; + fmlLibsMapping["1.4.2"] = libs14; + fmlLibsMapping["1.4.3"] = libs14; + fmlLibsMapping["1.4.4"] = libs14; + fmlLibsMapping["1.4.5"] = libs14; + fmlLibsMapping["1.4.6"] = libs14; + fmlLibsMapping["1.4.7"] = libs14; + + // 1.5 + fmlLibsMapping["1.5"] = QList<FMLlib>{ + {"argo-small-3.2.jar", "58912ea2858d168c50781f956fa5b59f0f7c6b51", false}, + {"guava-14.0-rc3.jar", "931ae21fa8014c3ce686aaa621eae565fefb1a6a", false}, + {"asm-all-4.1.jar", "054986e962b88d8660ae4566475658469595ef58", false}, + {"bcprov-jdk15on-148.jar", "960dea7c9181ba0b17e8bab0c06a43f0a5f04e65", true}, + {"deobfuscation_data_1.5.zip", "5f7c142d53776f16304c0bbe10542014abad6af8", false}, + {"scala-library.jar", "458d046151ad179c85429ed7420ffb1eaf6ddf85", true}}; + + // 1.5.1 + fmlLibsMapping["1.5.1"] = QList<FMLlib>{ + {"argo-small-3.2.jar", "58912ea2858d168c50781f956fa5b59f0f7c6b51", false}, + {"guava-14.0-rc3.jar", "931ae21fa8014c3ce686aaa621eae565fefb1a6a", false}, + {"asm-all-4.1.jar", "054986e962b88d8660ae4566475658469595ef58", false}, + {"bcprov-jdk15on-148.jar", "960dea7c9181ba0b17e8bab0c06a43f0a5f04e65", true}, + {"deobfuscation_data_1.5.1.zip", "22e221a0d89516c1f721d6cab056a7e37471d0a6", false}, + {"scala-library.jar", "458d046151ad179c85429ed7420ffb1eaf6ddf85", true}}; + + // 1.5.2 + fmlLibsMapping["1.5.2"] = QList<FMLlib>{ + {"argo-small-3.2.jar", "58912ea2858d168c50781f956fa5b59f0f7c6b51", false}, + {"guava-14.0-rc3.jar", "931ae21fa8014c3ce686aaa621eae565fefb1a6a", false}, + {"asm-all-4.1.jar", "054986e962b88d8660ae4566475658469595ef58", false}, + {"bcprov-jdk15on-148.jar", "960dea7c9181ba0b17e8bab0c06a43f0a5f04e65", true}, + {"deobfuscation_data_1.5.2.zip", "446e55cd986582c70fcf12cb27bc00114c5adfd9", false}, + {"scala-library.jar", "458d046151ad179c85429ed7420ffb1eaf6ddf85", true}}; + + // don't use installers for those. + forgeInstallerBlacklist = QSet<QString>({"1.5.2"}); + // these won't show up in version lists because they are extremely bad and dangerous + legacyBlacklist = QSet<QString>({"rd-160052"}); + /* + * nothing older than this will be accepted from Mojang servers + * (these versions need to be tested by us first) + */ + legacyCutoffDate = timeFromS3Time("2013-06-25T15:08:56+02:00"); + lwjglWhitelist = + QSet<QString>{"net.java.jinput:jinput", "net.java.jinput:jinput-platform", + "net.java.jutils:jutils", "org.lwjgl.lwjgl:lwjgl", + "org.lwjgl.lwjgl:lwjgl_util", "org.lwjgl.lwjgl:lwjgl-platform"}; +} diff --git a/logic/minecraft/VersionFilterData.h b/logic/minecraft/VersionFilterData.h new file mode 100644 index 00000000..98ecb36c --- /dev/null +++ b/logic/minecraft/VersionFilterData.h @@ -0,0 +1,28 @@ +#pragma once +#include <QMap> +#include <QString> +#include <QSet> +#include <QDateTime> + +struct FMLlib +{ + QString filename; + QString checksum; + bool ours; +}; + +struct VersionFilterData +{ + VersionFilterData(); + // mapping between minecraft versions and FML libraries required + QMap<QString, QList<FMLlib>> fmlLibsMapping; + // set of minecraft versions for which using forge installers is blacklisted + QSet<QString> forgeInstallerBlacklist; + // set of 'legacy' versions that will not show up in the version lists. + QSet<QString> legacyBlacklist; + // no new versions below this date will be accepted from Mojang servers + QDateTime legacyCutoffDate; + // Libraries that belong to LWJGL + QSet<QString> lwjglWhitelist; +}; +extern VersionFilterData g_VersionFilterData; |