diff options
Diffstat (limited to 'logic/minecraft/InstanceVersion.cpp')
-rw-r--r-- | logic/minecraft/InstanceVersion.cpp | 493 |
1 files changed, 493 insertions, 0 deletions
diff --git a/logic/minecraft/InstanceVersion.cpp b/logic/minecraft/InstanceVersion.cpp new file mode 100644 index 00000000..eb1eeae2 --- /dev/null +++ b/logic/minecraft/InstanceVersion.cpp @@ -0,0 +1,493 @@ +/* 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 <QDebug> +#include <QFile> +#include <QDir> +#include <QUuid> +#include <QJsonDocument> +#include <QJsonArray> +#include <pathutils.h> + +#include "logic/minecraft/InstanceVersion.h" +#include "logic/minecraft/VersionBuilder.h" +#include "logic/OneSixInstance.h" + +InstanceVersion::InstanceVersion(OneSixInstance *instance, QObject *parent) + : QAbstractListModel(parent), m_instance(instance) +{ + clear(); +} + +void InstanceVersion::reload(const QStringList &external) +{ + beginResetModel(); + VersionBuilder::build(this, m_instance, external); + reapply(true); + endResetModel(); +} + +void InstanceVersion::clear() +{ + id.clear(); + m_updateTimeString.clear(); + m_updateTime = QDateTime(); + m_releaseTimeString.clear(); + m_releaseTime = QDateTime(); + type.clear(); + assets.clear(); + processArguments.clear(); + minecraftArguments.clear(); + minimumLauncherVersion = 0xDEADBEAF; + mainClass.clear(); + appletClass.clear(); + libraries.clear(); + tweakers.clear(); + jarMods.clear(); + traits.clear(); +} + +bool InstanceVersion::canRemove(const int index) const +{ + return VersionPatches.at(index)->isMoveable(); +} + +bool InstanceVersion::preremove(VersionPatchPtr 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; +} + +bool InstanceVersion::remove(const int index) +{ + if (!canRemove(index)) + return false; + if(!preremove(VersionPatches[index])) + { + return false; + } + if(!QFile::remove(VersionPatches.at(index)->getPatchFilename())) + return false; + beginResetModel(); + VersionPatches.removeAt(index); + reapply(true); + endResetModel(); + return true; +} + +bool InstanceVersion::remove(const QString id) +{ + int i = 0; + for (auto patch : VersionPatches) + { + if (patch->getPatchID() == id) + { + return remove(i); + } + i++; + } + return false; +} + +QString InstanceVersion::versionFileId(const int index) const +{ + if (index < 0 || index >= VersionPatches.size()) + { + return QString(); + } + return VersionPatches.at(index)->getPatchID(); +} + +VersionPatchPtr InstanceVersion::versionPatch(const QString &id) +{ + for (auto file : VersionPatches) + { + if (file->getPatchID() == id) + { + return file; + } + } + return 0; +} + +VersionPatchPtr InstanceVersion::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() +{ + return remove("org.multimc.ftb.pack.json"); +} + +bool InstanceVersion::isVanilla() +{ + QDir patches(PathCombine(m_instance->instanceRoot(), "patches/")); + if(VersionPatches.size() > 1) + return false; + if(QFile::exists(PathCombine(m_instance->instanceRoot(), "custom.json"))) + return false; + return true; +} + +bool InstanceVersion::revertToVanilla() +{ + beginResetModel(); + auto it = VersionPatches.begin(); + while (it != VersionPatches.end()) + { + if ((*it)->isMoveable()) + { + if(!preremove(*it)) + { + endResetModel(); + return false; + } + if(!QFile::remove((*it)->getPatchFilename())) + { + endResetModel(); + return false; + } + it = VersionPatches.erase(it); + } + else + it++; + } + reapply(true); + endResetModel(); + return true; +} + +bool InstanceVersion::usesLegacyCustomJson() +{ + return QFile::exists(PathCombine(m_instance->instanceRoot(), "custom.json")); +} + +QList<std::shared_ptr<OneSixLibrary> > InstanceVersion::getActiveNormalLibs() +{ + QList<std::shared_ptr<OneSixLibrary> > output; + for (auto lib : libraries) + { + if (lib->isActive() && !lib->isNative()) + { + output.append(lib); + } + } + return output; +} +QList<std::shared_ptr<OneSixLibrary> > InstanceVersion::getActiveNativeLibs() +{ + QList<std::shared_ptr<OneSixLibrary> > output; + for (auto lib : libraries) + { + if (lib->isActive() && lib->isNative()) + { + output.append(lib); + } + } + return output; +} + +std::shared_ptr<InstanceVersion> InstanceVersion::fromJson(const QJsonObject &obj) +{ + std::shared_ptr<InstanceVersion> version(new InstanceVersion(0)); + try + { + VersionBuilder::readJsonAndApplyToVersion(version.get(), obj); + } + catch(MMCError & err) + { + return 0; + } + return version; +} + +QVariant InstanceVersion::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + int row = index.row(); + int column = index.column(); + + if (row < 0 || row >= VersionPatches.size()) + return QVariant(); + + if (role == Qt::DisplayRole) + { + switch (column) + { + case 0: + return VersionPatches.at(row)->getPatchName(); + case 1: + return VersionPatches.at(row)->getPatchVersion(); + default: + return QVariant(); + } + } + return QVariant(); +} +QVariant InstanceVersion::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal) + { + if (role == Qt::DisplayRole) + { + switch (section) + { + case 0: + return tr("Name"); + case 1: + return tr("Version"); + default: + return QVariant(); + } + } + } + return QVariant(); +} +Qt::ItemFlags InstanceVersion::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return Qt::NoItemFlags; + return Qt::ItemIsSelectable | Qt::ItemIsEnabled; +} + +int InstanceVersion::rowCount(const QModelIndex &parent) const +{ + return VersionPatches.size(); +} + +int InstanceVersion::columnCount(const QModelIndex &parent) const +{ + return 2; +} + +QMap<QString, int> InstanceVersion::getExistingOrder() const +{ + QMap<QString, int> order; + int index = 0; + // overriden + { + QMap<QString, int> overridenOrder = VersionBuilder::readOverrideOrders(m_instance); + for (auto id : order.keys()) + { + if (overridenOrder.contains(id)) + { + order[id] = overridenOrder[id]; + } + } + } + for(auto item: VersionPatches) + { + // things with fixed (negative) order. + if(!item->isMoveable()) + continue; + // the other things. + auto id = item->getPatchID(); + order[id] = index; + index++; + } + return order; +} + +void InstanceVersion::move(const int index, const MoveDirection direction) +{ + int theirIndex; + if (direction == MoveUp) + { + theirIndex = index - 1; + } + else + { + theirIndex = index + 1; + } + + if (index < 0 || index >= VersionPatches.size()) + return; + if (theirIndex >= rowCount()) + theirIndex = rowCount() - 1; + if (theirIndex == -1) + theirIndex = rowCount() - 1; + if (index == theirIndex) + return; + int togap = theirIndex > index ? theirIndex + 1 : theirIndex; + + auto from = versionPatch(index); + auto to = versionPatch(theirIndex); + + if (!from || !to || !to->isMoveable() || !from->isMoveable()) + { + return; + } + + beginMoveRows(QModelIndex(), index, index, QModelIndex(), togap); + VersionPatches.swap(index, theirIndex); + endMoveRows(); + reapply(); +} +void InstanceVersion::resetOrder() +{ + QDir(m_instance->instanceRoot()).remove("order.json"); + reapply(); +} + +void InstanceVersion::reapply(const bool alreadyReseting) +{ + clear(); + for(auto file: VersionPatches) + { + file->applyTo(this); + } + finalize(); +} + +void InstanceVersion::finalize() +{ + // HACK: deny april fools. my head hurts enough already. + QDate now = QDate::currentDate(); + bool isAprilFools = now.month() == 4 && now.day() == 1; + if (assets.endsWith("_af") && !isAprilFools) + { + assets = assets.left(assets.length() - 3); + } + if (assets.isEmpty()) + { + assets = "legacy"; + } + auto finalizeArguments = [&]( QString & minecraftArguments, const QString & processArguments ) -> void + { + if (!minecraftArguments.isEmpty()) + return; + QString toCompare = processArguments.toLower(); + if (toCompare == "legacy") + { + minecraftArguments = " ${auth_player_name} ${auth_session}"; + } + else if (toCompare == "username_session") + { + minecraftArguments = "--username ${auth_player_name} --session ${auth_session}"; + } + else if (toCompare == "username_session_version") + { + minecraftArguments = "--username ${auth_player_name} " + "--session ${auth_session} " + "--version ${profile_name}"; + } + }; + finalizeArguments(vanillaMinecraftArguments, vanillaProcessArguments); + finalizeArguments(minecraftArguments, processArguments); +} + +void InstanceVersion::installJarMods(QStringList selectedFiles) +{ + for(auto filename: selectedFiles) + { + installJarModByFilename(filename); + } +} + +void InstanceVersion::installJarModByFilename(QString filepath) +{ + 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(); + + QFile file(PathCombine(patchDir, target_id + ".json")); + 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(); +} + +int InstanceVersion::getFreeOrderNumber() +{ + int largest = 100; + // yes, I do realize this is dumb. The order thing itself is dumb. and to be removed next. + for(auto thing: VersionPatches) + { + int order = thing->getOrder(); + if(order > largest) + largest = order; + } + return largest + 1; +} |