summaryrefslogtreecommitdiffstats
path: root/logic/minecraft/InstanceVersion.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'logic/minecraft/InstanceVersion.cpp')
-rw-r--r--logic/minecraft/InstanceVersion.cpp493
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;
+}