All of the broken legacy things work.
This commit is contained in:
		@@ -224,7 +224,10 @@ bool OneSixInstance::prepareForLaunch(AuthSessionPtr account, QString &launchScr
 | 
			
		||||
		}
 | 
			
		||||
		launchScript += "cp " + versionsPath().absoluteFilePath(minecraftjarpath) + "\n";
 | 
			
		||||
	}
 | 
			
		||||
	launchScript += "mainClass " + version->mainClass + "\n";
 | 
			
		||||
	if(!version->mainClass.isEmpty())
 | 
			
		||||
	{
 | 
			
		||||
		launchScript += "mainClass " + version->mainClass + "\n";
 | 
			
		||||
	}
 | 
			
		||||
	if(!version->appletClass.isEmpty())
 | 
			
		||||
	{
 | 
			
		||||
		launchScript += "appletClass " + version->appletClass + "\n";
 | 
			
		||||
 
 | 
			
		||||
@@ -62,12 +62,14 @@ void OneSixUpdate::executeTask()
 | 
			
		||||
			emitFailed(tr("The specified Minecraft version is invalid. Choose a different one."));
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		versionFileStart();
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		jarlibStart();
 | 
			
		||||
		// builtins need no updates, so only update for Mojang
 | 
			
		||||
		if(targetVersion->m_versionSource == MinecraftVersion::Mojang)
 | 
			
		||||
		{
 | 
			
		||||
			versionFileStart();
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	jarlibStart();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OneSixUpdate::versionFileStart()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,2 +1,95 @@
 | 
			
		||||
#include "MinecraftVersion.h"
 | 
			
		||||
#include "VersionFinal.h"
 | 
			
		||||
 | 
			
		||||
bool MinecraftVersion::usesLegacyLauncher()
 | 
			
		||||
{
 | 
			
		||||
	return m_traits.contains("legacyLaunch") || m_traits.contains("aplhaLaunch");
 | 
			
		||||
}
 | 
			
		||||
QString MinecraftVersion::descriptor()
 | 
			
		||||
{
 | 
			
		||||
	return m_descriptor;
 | 
			
		||||
}
 | 
			
		||||
QString MinecraftVersion::name()
 | 
			
		||||
{
 | 
			
		||||
	return m_name;
 | 
			
		||||
}
 | 
			
		||||
QString MinecraftVersion::typeString() const
 | 
			
		||||
{
 | 
			
		||||
	if (is_latest && is_snapshot)
 | 
			
		||||
	{
 | 
			
		||||
		return QObject::tr("Latest snapshot");
 | 
			
		||||
	}
 | 
			
		||||
	else if (is_latest)
 | 
			
		||||
	{
 | 
			
		||||
		return QObject::tr("Latest release");
 | 
			
		||||
	}
 | 
			
		||||
	else if (is_snapshot)
 | 
			
		||||
	{
 | 
			
		||||
		return QObject::tr("Snapshot");
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		return QObject::tr("Regular release");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
bool MinecraftVersion::hasJarMods()
 | 
			
		||||
{
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
bool MinecraftVersion::isVanilla()
 | 
			
		||||
{
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MinecraftVersion::applyTo(VersionFinal *version)
 | 
			
		||||
{
 | 
			
		||||
	// FIXME: make this work.
 | 
			
		||||
	if(m_versionSource != Builtin)
 | 
			
		||||
	{
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	if (!m_descriptor.isNull())
 | 
			
		||||
	{
 | 
			
		||||
		version->id = m_descriptor;
 | 
			
		||||
	}
 | 
			
		||||
	if (!m_mainClass.isNull())
 | 
			
		||||
	{
 | 
			
		||||
		version->mainClass = m_mainClass;
 | 
			
		||||
	}
 | 
			
		||||
	if (!m_appletClass.isNull())
 | 
			
		||||
	{
 | 
			
		||||
		version->appletClass = m_appletClass;
 | 
			
		||||
	}
 | 
			
		||||
	if (!m_processArguments.isNull())
 | 
			
		||||
	{
 | 
			
		||||
		version->vanillaProcessArguments = m_processArguments;
 | 
			
		||||
		version->processArguments = m_processArguments;
 | 
			
		||||
	}
 | 
			
		||||
	if (!m_type.isNull())
 | 
			
		||||
	{
 | 
			
		||||
		version->type = m_type;
 | 
			
		||||
	}
 | 
			
		||||
	if (!m_releaseTimeString.isNull())
 | 
			
		||||
	{
 | 
			
		||||
		version->m_releaseTimeString = m_releaseTimeString;
 | 
			
		||||
		version->m_releaseTime = m_releaseTime;
 | 
			
		||||
	}
 | 
			
		||||
	if (!m_updateTimeString.isNull())
 | 
			
		||||
	{
 | 
			
		||||
		version->m_updateTimeString = m_updateTimeString;
 | 
			
		||||
		version->m_updateTime = m_updateTime;
 | 
			
		||||
	}
 | 
			
		||||
	version->traits.unite(m_traits);
 | 
			
		||||
}
 | 
			
		||||
int MinecraftVersion::getOrder()
 | 
			
		||||
{
 | 
			
		||||
	return order;
 | 
			
		||||
}
 | 
			
		||||
void MinecraftVersion::setOrder(int order)
 | 
			
		||||
{
 | 
			
		||||
	this->order = order;
 | 
			
		||||
}
 | 
			
		||||
QList<JarmodPtr> MinecraftVersion::getJarMods()
 | 
			
		||||
{
 | 
			
		||||
	return QList<JarmodPtr>();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -15,16 +15,18 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "logic/BaseVersion.h"
 | 
			
		||||
#include "VersionPatch.h"
 | 
			
		||||
#include <QStringList>
 | 
			
		||||
#include <QSet>
 | 
			
		||||
#include <QDateTime>
 | 
			
		||||
 | 
			
		||||
#include "logic/BaseVersion.h"
 | 
			
		||||
#include "VersionPatch.h"
 | 
			
		||||
#include "VersionFile.h"
 | 
			
		||||
 | 
			
		||||
class VersionFinal;
 | 
			
		||||
 | 
			
		||||
struct MinecraftVersion : public BaseVersion, public VersionPatch
 | 
			
		||||
{
 | 
			
		||||
	/// The version's timestamp - this is primarily used for sorting versions in a list.
 | 
			
		||||
	qint64 timestamp;
 | 
			
		||||
 | 
			
		||||
	/// The URL that this version will be downloaded from. maybe.
 | 
			
		||||
	QString download_url;
 | 
			
		||||
 | 
			
		||||
@@ -34,16 +36,20 @@ struct MinecraftVersion : public BaseVersion, public VersionPatch
 | 
			
		||||
	/// is this a snapshot?
 | 
			
		||||
	bool is_snapshot = false;
 | 
			
		||||
 | 
			
		||||
	/// is this a built-in version that comes with MultiMC?
 | 
			
		||||
	bool is_builtin = false;
 | 
			
		||||
	
 | 
			
		||||
	/// where is this from?
 | 
			
		||||
	enum VersionSource
 | 
			
		||||
	{
 | 
			
		||||
		Builtin,
 | 
			
		||||
		Mojang
 | 
			
		||||
	} m_versionSource = Builtin;
 | 
			
		||||
 | 
			
		||||
	/// the human readable version name
 | 
			
		||||
	QString m_name;
 | 
			
		||||
 | 
			
		||||
	/// the version ID.
 | 
			
		||||
	QString m_descriptor;
 | 
			
		||||
 | 
			
		||||
	/// version traits. generally launcher business...
 | 
			
		||||
	/// version traits. added by MultiMC
 | 
			
		||||
	QSet<QString> m_traits;
 | 
			
		||||
 | 
			
		||||
	/// The main class this version uses (if any, can be empty).
 | 
			
		||||
@@ -52,57 +58,47 @@ struct MinecraftVersion : public BaseVersion, public VersionPatch
 | 
			
		||||
	/// The applet class this version uses (if any, can be empty).
 | 
			
		||||
	QString m_appletClass;
 | 
			
		||||
 | 
			
		||||
	bool usesLegacyLauncher()
 | 
			
		||||
	/// The process arguments used by this version
 | 
			
		||||
	QString m_processArguments;
 | 
			
		||||
 | 
			
		||||
	/// The type of this release
 | 
			
		||||
	QString m_type;
 | 
			
		||||
 | 
			
		||||
	/// the time this version was actually released by Mojang, as string and as QDateTime
 | 
			
		||||
	QString m_releaseTimeString;
 | 
			
		||||
	QDateTime m_releaseTime;
 | 
			
		||||
 | 
			
		||||
	/// the time this version was last updated by Mojang, as string and as QDateTime
 | 
			
		||||
	QString m_updateTimeString;
 | 
			
		||||
	QDateTime m_updateTime;
 | 
			
		||||
 | 
			
		||||
	/// order of this file... default = -2
 | 
			
		||||
	int order = -2;
 | 
			
		||||
 | 
			
		||||
	bool usesLegacyLauncher();
 | 
			
		||||
	virtual QString descriptor() override;
 | 
			
		||||
	virtual QString name() override;
 | 
			
		||||
	virtual QString typeString() const override;
 | 
			
		||||
	virtual bool hasJarMods() override;
 | 
			
		||||
	virtual bool isVanilla() override;
 | 
			
		||||
	virtual void applyTo(VersionFinal *version) override;
 | 
			
		||||
	virtual int getOrder();
 | 
			
		||||
	virtual void setOrder(int order);
 | 
			
		||||
	virtual QList<JarmodPtr> getJarMods() override;
 | 
			
		||||
	virtual QString getPatchID()
 | 
			
		||||
	{
 | 
			
		||||
		return m_traits.contains("legacyLaunch") || m_traits.contains("aplhaLaunch");
 | 
			
		||||
		return "net.minecraft";
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	virtual QString descriptor() override
 | 
			
		||||
	virtual QString getPatchVersion()
 | 
			
		||||
	{
 | 
			
		||||
		return m_descriptor;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	virtual QString name() override
 | 
			
		||||
	virtual QString getPatchName()
 | 
			
		||||
	{
 | 
			
		||||
		return m_name;
 | 
			
		||||
		return "Minecraft";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	virtual QString typeString() const override
 | 
			
		||||
	virtual QString getPatchFilename()
 | 
			
		||||
	{
 | 
			
		||||
		if (is_latest && is_snapshot)
 | 
			
		||||
		{
 | 
			
		||||
			return QObject::tr("Latest snapshot");
 | 
			
		||||
		}
 | 
			
		||||
		else if(is_latest)
 | 
			
		||||
		{
 | 
			
		||||
			return QObject::tr("Latest release");
 | 
			
		||||
		}
 | 
			
		||||
		else if(is_snapshot)
 | 
			
		||||
		{
 | 
			
		||||
			return QObject::tr("Snapshot");
 | 
			
		||||
		}
 | 
			
		||||
		else if(is_builtin)
 | 
			
		||||
		{
 | 
			
		||||
			return QObject::tr("Museum piece");
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			return QObject::tr("Regular release");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	virtual bool hasJarMods() override
 | 
			
		||||
	{
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	virtual bool isVanilla() override
 | 
			
		||||
	{
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	virtual void applyTo(VersionFinal *version)
 | 
			
		||||
	{
 | 
			
		||||
		// umm... what now?
 | 
			
		||||
	}
 | 
			
		||||
		return QString();
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,8 @@
 | 
			
		||||
#include "MinecraftVersionList.h"
 | 
			
		||||
#include "MultiMC.h"
 | 
			
		||||
#include "logic/net/URLConstants.h"
 | 
			
		||||
#include <logic/MMCJson.h>
 | 
			
		||||
#include "logic/MMCJson.h"
 | 
			
		||||
#include "ParseUtils.h"
 | 
			
		||||
 | 
			
		||||
#include <QtXml>
 | 
			
		||||
 | 
			
		||||
@@ -30,11 +31,6 @@
 | 
			
		||||
 | 
			
		||||
#include <QtNetwork>
 | 
			
		||||
 | 
			
		||||
inline QDateTime timeFromS3Time(QString str)
 | 
			
		||||
{
 | 
			
		||||
	return QDateTime::fromString(str, Qt::ISODate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MinecraftVersionList::MinecraftVersionList(QObject *parent) : BaseVersionList(parent)
 | 
			
		||||
{
 | 
			
		||||
	loadBuiltinList();
 | 
			
		||||
@@ -64,7 +60,7 @@ static bool cmpVersions(BaseVersionPtr first, BaseVersionPtr second)
 | 
			
		||||
{
 | 
			
		||||
	auto left = std::dynamic_pointer_cast<MinecraftVersion>(first);
 | 
			
		||||
	auto right = std::dynamic_pointer_cast<MinecraftVersion>(second);
 | 
			
		||||
	return left->timestamp > right->timestamp;
 | 
			
		||||
	return left->m_releaseTime > right->m_releaseTime;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MinecraftVersionList::sortInternal()
 | 
			
		||||
@@ -79,55 +75,55 @@ void MinecraftVersionList::loadBuiltinList()
 | 
			
		||||
	QFile filez(versionList.absoluteFilePath());
 | 
			
		||||
	filez.open(QIODevice::ReadOnly);
 | 
			
		||||
	auto data = filez.readAll();
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	// parse the data as json
 | 
			
		||||
	QJsonParseError jsonError;
 | 
			
		||||
	QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
 | 
			
		||||
	QJsonObject root = jsonDoc.object();
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	// parse all the versions
 | 
			
		||||
	for (const auto version : MMCJson::ensureArray(root.value("versions")))
 | 
			
		||||
	{
 | 
			
		||||
		QJsonObject versionObj = version.toObject();
 | 
			
		||||
		QString versionID = versionObj.value("id").toString("");
 | 
			
		||||
		QString versionTimeStr = versionObj.value("releaseTime").toString("");
 | 
			
		||||
		QString versionTypeStr = versionObj.value("type").toString("");
 | 
			
		||||
		QSet<QString> traits;
 | 
			
		||||
		if (versionObj.contains("+traits"))
 | 
			
		||||
		if (versionID.isEmpty() || versionTypeStr.isEmpty())
 | 
			
		||||
		{
 | 
			
		||||
			for (auto traitVal : MMCJson::ensureArray(versionObj.value("+traits")))
 | 
			
		||||
			{
 | 
			
		||||
				traits.insert(MMCJson::ensureString(traitVal));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (versionID.isEmpty() || versionTimeStr.isEmpty() || versionTypeStr.isEmpty())
 | 
			
		||||
		{
 | 
			
		||||
			// FIXME: log this somewhere
 | 
			
		||||
			QLOG_ERROR() << "Parsed version is missing ID or type";
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		// Parse the timestamp.
 | 
			
		||||
		QDateTime versionTime = timeFromS3Time(versionTimeStr);
 | 
			
		||||
		if (!versionTime.isValid())
 | 
			
		||||
		{
 | 
			
		||||
			// FIXME: log this somewhere
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		// Get the download URL.
 | 
			
		||||
		QString dlUrl = "http://" + URLConstants::AWS_DOWNLOAD_VERSIONS + versionID + "/";
 | 
			
		||||
 | 
			
		||||
		// main class and applet class
 | 
			
		||||
		QString mainClass = versionObj.value("type").toString("");
 | 
			
		||||
		QString appletClass = versionObj.value("type").toString("");
 | 
			
		||||
 | 
			
		||||
		// Now, we construct the version object and add it to the list.
 | 
			
		||||
		std::shared_ptr<MinecraftVersion> mcVersion(new MinecraftVersion());
 | 
			
		||||
		mcVersion->m_name = mcVersion->m_descriptor = versionID;
 | 
			
		||||
		mcVersion->timestamp = versionTime.toMSecsSinceEpoch();
 | 
			
		||||
		mcVersion->download_url = dlUrl;
 | 
			
		||||
		mcVersion->is_builtin = true;
 | 
			
		||||
		mcVersion->m_appletClass = appletClass;
 | 
			
		||||
		mcVersion->m_mainClass = mainClass;
 | 
			
		||||
		mcVersion->m_traits = traits;
 | 
			
		||||
 | 
			
		||||
		// Parse the timestamp.
 | 
			
		||||
		try
 | 
			
		||||
		{
 | 
			
		||||
			parse_timestamp(versionObj.value("releaseTime").toString(""),
 | 
			
		||||
							mcVersion->m_releaseTimeString, mcVersion->m_releaseTime);
 | 
			
		||||
		}
 | 
			
		||||
		catch (MMCError &e)
 | 
			
		||||
		{
 | 
			
		||||
			QLOG_ERROR() << "Error while parsing version" << versionID << ":" << e.cause();
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Get the download URL.
 | 
			
		||||
		mcVersion->download_url =
 | 
			
		||||
			"http://" + URLConstants::AWS_DOWNLOAD_VERSIONS + versionID + "/";
 | 
			
		||||
 | 
			
		||||
		mcVersion->m_versionSource = MinecraftVersion::Builtin;
 | 
			
		||||
		mcVersion->m_appletClass = versionObj.value("appletClass").toString("");
 | 
			
		||||
		mcVersion->m_mainClass = versionObj.value("mainClass").toString("");
 | 
			
		||||
		mcVersion->m_processArguments = versionObj.value("processArguments").toString("legacy");
 | 
			
		||||
		if (versionObj.contains("+traits"))
 | 
			
		||||
		{
 | 
			
		||||
			for (auto traitVal : MMCJson::ensureArray(versionObj.value("+traits")))
 | 
			
		||||
			{
 | 
			
		||||
				mcVersion->m_traits.insert(MMCJson::ensureString(traitVal));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		m_vlist.append(mcVersion);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -265,50 +261,14 @@ void MCVListLoadTask::list_downloaded()
 | 
			
		||||
		// Load the version info.
 | 
			
		||||
		if (!version.isObject())
 | 
			
		||||
		{
 | 
			
		||||
			// FIXME: log this somewhere
 | 
			
		||||
			QLOG_ERROR() << "Error while parsing version list : invalid JSON structure";
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		QJsonObject versionObj = version.toObject();
 | 
			
		||||
		QString versionID = versionObj.value("id").toString("");
 | 
			
		||||
		QString versionTimeStr = versionObj.value("releaseTime").toString("");
 | 
			
		||||
		QString versionTypeStr = versionObj.value("type").toString("");
 | 
			
		||||
		if (versionID.isEmpty() || versionTimeStr.isEmpty() || versionTypeStr.isEmpty())
 | 
			
		||||
		if (versionID.isEmpty())
 | 
			
		||||
		{
 | 
			
		||||
			// FIXME: log this somewhere
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Parse the timestamp.
 | 
			
		||||
		QDateTime versionTime = timeFromS3Time(versionTimeStr);
 | 
			
		||||
		if (!versionTime.isValid())
 | 
			
		||||
		{
 | 
			
		||||
			// FIXME: log this somewhere
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		// OneSix or Legacy. use filter to determine type
 | 
			
		||||
		if (versionTypeStr == "release")
 | 
			
		||||
		{
 | 
			
		||||
			is_latest = (versionID == latestReleaseID);
 | 
			
		||||
			is_snapshot = false;
 | 
			
		||||
		}
 | 
			
		||||
		else if (versionTypeStr == "snapshot") // It's a snapshot... yay
 | 
			
		||||
		{
 | 
			
		||||
			is_latest = (versionID == latestSnapshotID);
 | 
			
		||||
			is_snapshot = true;
 | 
			
		||||
		}
 | 
			
		||||
		else if (versionTypeStr == "old_alpha")
 | 
			
		||||
		{
 | 
			
		||||
			is_latest = false;
 | 
			
		||||
			is_snapshot = false;
 | 
			
		||||
		}
 | 
			
		||||
		else if (versionTypeStr == "old_beta")
 | 
			
		||||
		{
 | 
			
		||||
			is_latest = false;
 | 
			
		||||
			is_snapshot = false;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			// FIXME: log this somewhere
 | 
			
		||||
			QLOG_ERROR() << "Error while parsing version : version ID is missing";
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		// Get the download URL.
 | 
			
		||||
@@ -317,10 +277,61 @@ void MCVListLoadTask::list_downloaded()
 | 
			
		||||
		// Now, we construct the version object and add it to the list.
 | 
			
		||||
		std::shared_ptr<MinecraftVersion> mcVersion(new MinecraftVersion());
 | 
			
		||||
		mcVersion->m_name = mcVersion->m_descriptor = versionID;
 | 
			
		||||
		mcVersion->timestamp = versionTime.toMSecsSinceEpoch();
 | 
			
		||||
 | 
			
		||||
		try
 | 
			
		||||
		{
 | 
			
		||||
			// Parse the timestamps.
 | 
			
		||||
			parse_timestamp(versionObj.value("releaseTime").toString(""),
 | 
			
		||||
							mcVersion->m_releaseTimeString, mcVersion->m_releaseTime);
 | 
			
		||||
 | 
			
		||||
			parse_timestamp(versionObj.value("time").toString(""),
 | 
			
		||||
							mcVersion->m_updateTimeString, mcVersion->m_updateTime);
 | 
			
		||||
		}
 | 
			
		||||
		catch (MMCError &e)
 | 
			
		||||
		{
 | 
			
		||||
			QLOG_ERROR() << "Error while parsing version" << versionID << ":" << e.cause();
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		mcVersion->m_versionSource = MinecraftVersion::Builtin;
 | 
			
		||||
		mcVersion->download_url = dlUrl;
 | 
			
		||||
		mcVersion->is_latest = is_latest;
 | 
			
		||||
		mcVersion->is_snapshot = is_snapshot;
 | 
			
		||||
		{
 | 
			
		||||
			QString versionTypeStr = versionObj.value("type").toString("");
 | 
			
		||||
			if (versionTypeStr.isEmpty())
 | 
			
		||||
			{
 | 
			
		||||
				// FIXME: log this somewhere
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			// OneSix or Legacy. use filter to determine type
 | 
			
		||||
			if (versionTypeStr == "release")
 | 
			
		||||
			{
 | 
			
		||||
				is_latest = (versionID == latestReleaseID);
 | 
			
		||||
				is_snapshot = false;
 | 
			
		||||
			}
 | 
			
		||||
			else if (versionTypeStr == "snapshot") // It's a snapshot... yay
 | 
			
		||||
			{
 | 
			
		||||
				is_latest = (versionID == latestSnapshotID);
 | 
			
		||||
				is_snapshot = true;
 | 
			
		||||
			}
 | 
			
		||||
			else if (versionTypeStr == "old_alpha")
 | 
			
		||||
			{
 | 
			
		||||
				is_latest = false;
 | 
			
		||||
				is_snapshot = false;
 | 
			
		||||
			}
 | 
			
		||||
			else if (versionTypeStr == "old_beta")
 | 
			
		||||
			{
 | 
			
		||||
				is_latest = false;
 | 
			
		||||
				is_snapshot = false;
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				// FIXME: log this somewhere
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			mcVersion->m_type = versionTypeStr;
 | 
			
		||||
			mcVersion->is_latest = is_latest;
 | 
			
		||||
			mcVersion->is_snapshot = is_snapshot;
 | 
			
		||||
		}
 | 
			
		||||
		tempList.append(mcVersion);
 | 
			
		||||
	}
 | 
			
		||||
	m_list->updateListData(tempList);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										23
									
								
								logic/minecraft/ParseUtils.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								logic/minecraft/ParseUtils.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
#include <QDateTime>
 | 
			
		||||
#include <QString>
 | 
			
		||||
#include "ParseUtils.h"
 | 
			
		||||
#include <logic/MMCJson.h>
 | 
			
		||||
 | 
			
		||||
QDateTime timeFromS3Time(QString str)
 | 
			
		||||
{
 | 
			
		||||
	return QDateTime::fromString(str, Qt::ISODate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void parse_timestamp (const QString & raw, QString & save_here, QDateTime & parse_here)
 | 
			
		||||
{
 | 
			
		||||
	save_here = raw;
 | 
			
		||||
	if (save_here.isEmpty())
 | 
			
		||||
	{
 | 
			
		||||
		throw JSONValidationError("The timestamp is empty!");
 | 
			
		||||
	}
 | 
			
		||||
	parse_here = timeFromS3Time(save_here);
 | 
			
		||||
	if (!parse_here.isValid())
 | 
			
		||||
	{
 | 
			
		||||
		throw JSONValidationError("The timestamp not a valid timestamp!");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								logic/minecraft/ParseUtils.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								logic/minecraft/ParseUtils.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include <QString>
 | 
			
		||||
#include <QDateTime>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * parse the S3 timestamp in 'raw' and fill the forwarded variables.
 | 
			
		||||
 * return true/false for success/failure
 | 
			
		||||
 */
 | 
			
		||||
void parse_timestamp (const QString &raw, QString &save_here, QDateTime &parse_here);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * take the timestamp used by S3 and turn it into QDateTime
 | 
			
		||||
 */
 | 
			
		||||
QDateTime timeFromS3Time(QString str);
 | 
			
		||||
							
								
								
									
										58
									
								
								logic/minecraft/VersionBuildError.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								logic/minecraft/VersionBuildError.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
#include "MMCError.h"
 | 
			
		||||
 | 
			
		||||
class VersionBuildError : public MMCError
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	VersionBuildError(QString cause) : MMCError(cause) {};
 | 
			
		||||
	virtual ~VersionBuildError() noexcept
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * the base version file was meant for a newer version of the vanilla launcher than we support
 | 
			
		||||
 */
 | 
			
		||||
class LauncherVersionError : public VersionBuildError
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	LauncherVersionError(int actual, int supported)
 | 
			
		||||
		: VersionBuildError(QObject::tr(
 | 
			
		||||
			  "The base version file of this instance was meant for a newer (%1) "
 | 
			
		||||
			  "version of the vanilla launcher than this version of MultiMC supports (%2).")
 | 
			
		||||
								.arg(actual)
 | 
			
		||||
								.arg(supported)) {};
 | 
			
		||||
	virtual ~LauncherVersionError() noexcept
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * some patch was intended for a different version of minecraft
 | 
			
		||||
 */
 | 
			
		||||
class MinecraftVersionMismatch : public VersionBuildError
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	MinecraftVersionMismatch(QString fileId, QString mcVersion, QString parentMcVersion)
 | 
			
		||||
		: VersionBuildError(QObject::tr("The patch %1 is for a different version of Minecraft "
 | 
			
		||||
										"(%2) than that of the instance (%3).")
 | 
			
		||||
								.arg(fileId)
 | 
			
		||||
								.arg(mcVersion)
 | 
			
		||||
								.arg(parentMcVersion)) {};
 | 
			
		||||
	virtual ~MinecraftVersionMismatch() noexcept
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * files required for the version are not (yet?) present
 | 
			
		||||
 */
 | 
			
		||||
class VersionIncomplete : public VersionBuildError
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	VersionIncomplete(QString missingPatch)
 | 
			
		||||
		: VersionBuildError(QObject::tr("Version is incomplete: missing %1.")
 | 
			
		||||
								.arg(missingPatch)) {};
 | 
			
		||||
	virtual ~VersionIncomplete() noexcept
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
@@ -23,12 +23,17 @@
 | 
			
		||||
#include <QObject>
 | 
			
		||||
#include <QDir>
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
#include <qresource.h>
 | 
			
		||||
#include <modutils.h>
 | 
			
		||||
 | 
			
		||||
#include "MultiMC.h"
 | 
			
		||||
#include "logic/minecraft/VersionBuilder.h"
 | 
			
		||||
#include "logic/minecraft/VersionFinal.h"
 | 
			
		||||
#include "logic/minecraft/OneSixRule.h"
 | 
			
		||||
#include "logic/minecraft/VersionPatch.h"
 | 
			
		||||
#include "logic/minecraft/VersionFile.h"
 | 
			
		||||
#include "VersionBuildError.h"
 | 
			
		||||
#include "MinecraftVersionList.h"
 | 
			
		||||
 | 
			
		||||
#include "logic/OneSixInstance.h"
 | 
			
		||||
#include "logic/MMCJson.h"
 | 
			
		||||
@@ -39,16 +44,17 @@ VersionBuilder::VersionBuilder()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VersionBuilder::build(VersionFinal *version, OneSixInstance *instance, const QStringList &external)
 | 
			
		||||
void VersionBuilder::build(VersionFinal *version, OneSixInstance *instance,
 | 
			
		||||
						   const QStringList &external)
 | 
			
		||||
{
 | 
			
		||||
	VersionBuilder builder;
 | 
			
		||||
	builder.m_version = version;
 | 
			
		||||
	builder.m_instance = instance;
 | 
			
		||||
	builder.buildInternal(external);
 | 
			
		||||
	builder.external_patches = external;
 | 
			
		||||
	builder.buildInternal();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VersionBuilder::readJsonAndApplyToVersion(VersionFinal *version,
 | 
			
		||||
													 const QJsonObject &obj)
 | 
			
		||||
void VersionBuilder::readJsonAndApplyToVersion(VersionFinal *version, const QJsonObject &obj)
 | 
			
		||||
{
 | 
			
		||||
	VersionBuilder builder;
 | 
			
		||||
	builder.m_version = version;
 | 
			
		||||
@@ -56,88 +62,143 @@ void VersionBuilder::readJsonAndApplyToVersion(VersionFinal *version,
 | 
			
		||||
	builder.readJsonAndApply(obj);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VersionBuilder::buildInternal(const QStringList &external)
 | 
			
		||||
void VersionBuilder::buildFromCustomJson()
 | 
			
		||||
{
 | 
			
		||||
	m_version->versionFiles.clear();
 | 
			
		||||
	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);
 | 
			
		||||
	// QObject::tr("The version descriptors of this instance are not compatible with the
 | 
			
		||||
	// current version of MultiMC"));
 | 
			
		||||
	// QObject::tr("Error while applying %1. Please check MultiMC-0.log for more info.")
 | 
			
		||||
	// some final touches
 | 
			
		||||
	m_version->finalize();
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	QDir root(m_instance->instanceRoot());
 | 
			
		||||
	QDir patches(root.absoluteFilePath("patches/"));
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
	// if we do external files, do just those.
 | 
			
		||||
	if (!external.isEmpty())
 | 
			
		||||
	{
 | 
			
		||||
		int externalOrder = -1;
 | 
			
		||||
		for (auto fileName : external)
 | 
			
		||||
		{
 | 
			
		||||
			QLOG_INFO() << "Reading" << fileName;
 | 
			
		||||
			auto file =
 | 
			
		||||
				parseJsonFile(QFileInfo(fileName), false, fileName.endsWith("pack.json"));
 | 
			
		||||
			file->name = QFileInfo(fileName).fileName();
 | 
			
		||||
			file->fileId = "org.multimc.external." + file->name;
 | 
			
		||||
			file->order = (externalOrder += 1);
 | 
			
		||||
			file->version = QString();
 | 
			
		||||
			file->mcVersion = QString();
 | 
			
		||||
			m_version->versionFiles.append(file);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// else, if there's custom json, we just do that.
 | 
			
		||||
	else if (QFile::exists(root.absoluteFilePath("custom.json")))
 | 
			
		||||
	{
 | 
			
		||||
		QLOG_INFO() << "Reading custom.json";
 | 
			
		||||
		auto file = parseJsonFile(QFileInfo(root.absoluteFilePath("custom.json")), false);
 | 
			
		||||
		file->name = "custom.json";
 | 
			
		||||
		file->filename = "custom.json";
 | 
			
		||||
		file->fileId = "org.multimc.custom.json";
 | 
			
		||||
		file->order = -1;
 | 
			
		||||
		file->version = QString();
 | 
			
		||||
		m_version->versionFiles.append(file);
 | 
			
		||||
		// QObject::tr("The version descriptors of this instance are not compatible with the
 | 
			
		||||
		// current version of MultiMC"));
 | 
			
		||||
		// QObject::tr("Error while applying %1. Please check MultiMC-0.log for more info.")
 | 
			
		||||
	}
 | 
			
		||||
	// version.json -> patches/*.json -> user.json
 | 
			
		||||
	else
 | 
			
		||||
		do
 | 
			
		||||
		{
 | 
			
		||||
			// version.json
 | 
			
		||||
			QLOG_INFO() << "Reading version.json";
 | 
			
		||||
			auto file = parseJsonFile(QFileInfo(root.absoluteFilePath("version.json")), false);
 | 
			
		||||
			file->name = "Minecraft";
 | 
			
		||||
			file->fileId = "org.multimc.version.json";
 | 
			
		||||
			file->order = -1;
 | 
			
		||||
			file->version = m_instance->intendedVersionId();
 | 
			
		||||
			file->mcVersion = m_instance->intendedVersionId();
 | 
			
		||||
			m_version->versionFiles.append(file);
 | 
			
		||||
			// QObject::tr("Error while applying %1. Please check MultiMC-0.log for more
 | 
			
		||||
			// info.").arg(root.absoluteFilePath("version.json")));
 | 
			
		||||
 | 
			
		||||
			// patches/
 | 
			
		||||
			// load all, put into map for ordering, apply in the right order
 | 
			
		||||
 | 
			
		||||
			QMap<int, QPair<QString, VersionFilePtr>> files;
 | 
			
		||||
			for (auto info : patches.entryInfoList(QStringList() << "*.json", QDir::Files))
 | 
			
		||||
			{
 | 
			
		||||
				QLOG_INFO() << "Reading" << info.fileName();
 | 
			
		||||
				auto file = parseJsonFile(info, true);
 | 
			
		||||
				if (files.contains(file->order))
 | 
			
		||||
				{
 | 
			
		||||
					throw VersionBuildError(QObject::tr("%1 has the same order as %2").arg(
 | 
			
		||||
						file->fileId, files[file->order].second->fileId));
 | 
			
		||||
				}
 | 
			
		||||
				files.insert(file->order, qMakePair(info.fileName(), file));
 | 
			
		||||
			}
 | 
			
		||||
			for (auto order : files.keys())
 | 
			
		||||
			{
 | 
			
		||||
				auto &filePair = files[order];
 | 
			
		||||
				m_version->versionFiles.append(filePair.second);
 | 
			
		||||
			}
 | 
			
		||||
		} while (0);
 | 
			
		||||
	// load all patches, put into map for ordering, apply in the right order
 | 
			
		||||
	readInstancePatches();
 | 
			
		||||
 | 
			
		||||
	// some final touches
 | 
			
		||||
	m_version->finalize();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VersionBuilder::readInstancePatches()
 | 
			
		||||
{
 | 
			
		||||
	QDir patches(instance_root.absoluteFilePath("patches/"));
 | 
			
		||||
	QMap<int, QPair<QString, VersionFilePtr>> files;
 | 
			
		||||
	for (auto info : patches.entryInfoList(QStringList() << "*.json", QDir::Files))
 | 
			
		||||
	{
 | 
			
		||||
		QLOG_INFO() << "Reading" << info.fileName();
 | 
			
		||||
		auto file = parseJsonFile(info, true);
 | 
			
		||||
		if(file->fileId == "net.minecraft")
 | 
			
		||||
			continue;
 | 
			
		||||
		if(file->fileId == "org.lwjgl")
 | 
			
		||||
			continue;
 | 
			
		||||
		if (files.contains(file->order))
 | 
			
		||||
		{
 | 
			
		||||
			throw VersionBuildError(QObject::tr("%1 has the same order as %2")
 | 
			
		||||
										.arg(file->fileId, files[file->order].second->fileId));
 | 
			
		||||
		}
 | 
			
		||||
		files.insert(file->order, qMakePair(info.fileName(), file));
 | 
			
		||||
	}
 | 
			
		||||
	for (auto order : files.keys())
 | 
			
		||||
	{
 | 
			
		||||
		auto &filePair = files[order];
 | 
			
		||||
		m_version->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);
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
	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)
 | 
			
		||||
{
 | 
			
		||||
@@ -147,14 +208,14 @@ void VersionBuilder::readJsonAndApply(const QJsonObject &obj)
 | 
			
		||||
	// QObject::tr("Error while reading. Please check MultiMC-0.log for more info."));
 | 
			
		||||
 | 
			
		||||
	file->applyTo(m_version);
 | 
			
		||||
	m_version->versionFiles.append(file);
 | 
			
		||||
	m_version->VersionPatches.append(file);
 | 
			
		||||
	// QObject::tr("Error while applying. Please check MultiMC-0.log for more info."));
 | 
			
		||||
	// QObject::tr("The version descriptors of this instance are not compatible with the current
 | 
			
		||||
	// version of MultiMC"));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VersionFilePtr VersionBuilder::parseJsonFile(const QFileInfo &fileInfo,
 | 
			
		||||
												   const bool requireOrder, bool isFTB)
 | 
			
		||||
VersionFilePtr VersionBuilder::parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder,
 | 
			
		||||
											 bool isFTB)
 | 
			
		||||
{
 | 
			
		||||
	QFile file(fileInfo.absoluteFilePath());
 | 
			
		||||
	if (!file.open(QFile::ReadOnly))
 | 
			
		||||
@@ -166,9 +227,10 @@ VersionFilePtr VersionBuilder::parseJsonFile(const QFileInfo &fileInfo,
 | 
			
		||||
	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));
 | 
			
		||||
		throw JSONValidationError(
 | 
			
		||||
			QObject::tr("Unable to process the version file %1: %2 at %3.")
 | 
			
		||||
				.arg(fileInfo.fileName(), error.errorString())
 | 
			
		||||
				.arg(error.offset));
 | 
			
		||||
	}
 | 
			
		||||
	return VersionFile::fromJson(doc, file.fileName(), requireOrder, isFTB);
 | 
			
		||||
	// QObject::tr("Error while reading %1. Please check MultiMC-0.log for more
 | 
			
		||||
@@ -226,7 +288,7 @@ QMap<QString, int> VersionBuilder::readOverrideOrders(OneSixInstance *instance)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool VersionBuilder::writeOverrideOrders(const QMap<QString, int> &order,
 | 
			
		||||
											   OneSixInstance *instance)
 | 
			
		||||
										 OneSixInstance *instance)
 | 
			
		||||
{
 | 
			
		||||
	QJsonObject obj;
 | 
			
		||||
	for (auto it = order.cbegin(); it != order.cend(); ++it)
 | 
			
		||||
 
 | 
			
		||||
@@ -37,8 +37,17 @@ public:
 | 
			
		||||
private:
 | 
			
		||||
	VersionFinal *m_version;
 | 
			
		||||
	OneSixInstance *m_instance;
 | 
			
		||||
 | 
			
		||||
	void buildInternal(const QStringList& external);
 | 
			
		||||
	QStringList external_patches;
 | 
			
		||||
	QDir instance_root;
 | 
			
		||||
	
 | 
			
		||||
	void buildInternal();
 | 
			
		||||
	void buildFromExternalPatches();
 | 
			
		||||
	void buildFromCustomJson();
 | 
			
		||||
	void buildFromVersionJson();
 | 
			
		||||
	void buildFromMultilayer();
 | 
			
		||||
	
 | 
			
		||||
	void readInstancePatches();
 | 
			
		||||
	
 | 
			
		||||
	void readJsonAndApply(const QJsonObject &obj);
 | 
			
		||||
 | 
			
		||||
	VersionFilePtr parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder,
 | 
			
		||||
 
 | 
			
		||||
@@ -8,10 +8,13 @@
 | 
			
		||||
#include "logic/minecraft/OneSixLibrary.h"
 | 
			
		||||
#include "logic/minecraft/VersionFinal.h"
 | 
			
		||||
#include "logic/minecraft/JarMod.h"
 | 
			
		||||
#include "ParseUtils.h"
 | 
			
		||||
 | 
			
		||||
#include "logic/MMCJson.h"
 | 
			
		||||
using namespace MMCJson;
 | 
			
		||||
 | 
			
		||||
#include "VersionBuildError.h"
 | 
			
		||||
 | 
			
		||||
#define CURRENT_MINIMUM_LAUNCHER_VERSION 14
 | 
			
		||||
 | 
			
		||||
int findLibrary(QList<OneSixLibraryPtr> haystack, const QString &needle)
 | 
			
		||||
@@ -23,7 +26,7 @@ int findLibrary(QList<OneSixLibraryPtr> haystack, const QString &needle)
 | 
			
		||||
		if (QRegExp(needle, Qt::CaseSensitive, QRegExp::WildcardUnix).indexIn(chunk) != -1)
 | 
			
		||||
		{
 | 
			
		||||
			// only one is allowed.
 | 
			
		||||
			if(retval != -1)
 | 
			
		||||
			if (retval != -1)
 | 
			
		||||
				return -1;
 | 
			
		||||
			retval = i;
 | 
			
		||||
		}
 | 
			
		||||
@@ -32,7 +35,7 @@ int findLibrary(QList<OneSixLibraryPtr> haystack, const QString &needle)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VersionFilePtr VersionFile::fromJson(const QJsonDocument &doc, const QString &filename,
 | 
			
		||||
								  const bool requireOrder, const bool isFTB)
 | 
			
		||||
									 const bool requireOrder, const bool isFTB)
 | 
			
		||||
{
 | 
			
		||||
	VersionFilePtr out(new VersionFile());
 | 
			
		||||
	if (doc.isEmpty() || doc.isNull())
 | 
			
		||||
@@ -41,7 +44,6 @@ VersionFilePtr VersionFile::fromJson(const QJsonDocument &doc, const QString &fi
 | 
			
		||||
	}
 | 
			
		||||
	if (!doc.isObject())
 | 
			
		||||
	{
 | 
			
		||||
		throw JSONValidationError("The root of " + filename + " is not an object");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	QJsonObject root = doc.object();
 | 
			
		||||
@@ -65,7 +67,7 @@ VersionFilePtr VersionFile::fromJson(const QJsonDocument &doc, const QString &fi
 | 
			
		||||
	out->mcVersion = root.value("mcVersion").toString();
 | 
			
		||||
	out->filename = filename;
 | 
			
		||||
 | 
			
		||||
	auto readString = [root, filename](const QString & key, QString & variable)
 | 
			
		||||
	auto readString = [root](const QString & key, QString & variable)
 | 
			
		||||
	{
 | 
			
		||||
		if (root.contains(key))
 | 
			
		||||
		{
 | 
			
		||||
@@ -73,6 +75,16 @@ VersionFilePtr VersionFile::fromJson(const QJsonDocument &doc, const QString &fi
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	auto readStringRet = [root](const QString & key)->QString
 | 
			
		||||
	{
 | 
			
		||||
		if (root.contains(key))
 | 
			
		||||
		{
 | 
			
		||||
			return ensureString(root.value(key));
 | 
			
		||||
		}
 | 
			
		||||
		return QString();
 | 
			
		||||
	}
 | 
			
		||||
	;
 | 
			
		||||
 | 
			
		||||
	// FIXME: This should be ignored when applying.
 | 
			
		||||
	if (!isFTB)
 | 
			
		||||
	{
 | 
			
		||||
@@ -86,8 +98,14 @@ VersionFilePtr VersionFile::fromJson(const QJsonDocument &doc, const QString &fi
 | 
			
		||||
	readString("+minecraftArguments", out->addMinecraftArguments);
 | 
			
		||||
	readString("-minecraftArguments", out->removeMinecraftArguments);
 | 
			
		||||
	readString("type", out->type);
 | 
			
		||||
	readString("releaseTime", out->versionReleaseTime);
 | 
			
		||||
	readString("time", out->versionFileUpdateTime);
 | 
			
		||||
	if (out->isVanilla())
 | 
			
		||||
	{
 | 
			
		||||
		parse_timestamp(readStringRet("releaseTime"), out->m_releaseTimeString,
 | 
			
		||||
						out->m_releaseTime);
 | 
			
		||||
		parse_timestamp(readStringRet("time"), out->m_updateTimeString, out->m_updateTime);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	readStringRet("time");
 | 
			
		||||
	readString("assets", out->assets);
 | 
			
		||||
 | 
			
		||||
	if (root.contains("minimumLauncherVersion"))
 | 
			
		||||
@@ -284,7 +302,8 @@ void VersionFile::applyTo(VersionFinal *version)
 | 
			
		||||
	{
 | 
			
		||||
		if (minimumLauncherVersion > CURRENT_MINIMUM_LAUNCHER_VERSION)
 | 
			
		||||
		{
 | 
			
		||||
			throw LauncherVersionError(minimumLauncherVersion, CURRENT_MINIMUM_LAUNCHER_VERSION);
 | 
			
		||||
			throw LauncherVersionError(minimumLauncherVersion,
 | 
			
		||||
									   CURRENT_MINIMUM_LAUNCHER_VERSION);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -311,23 +330,28 @@ void VersionFile::applyTo(VersionFinal *version)
 | 
			
		||||
	}
 | 
			
		||||
	if (!processArguments.isNull())
 | 
			
		||||
	{
 | 
			
		||||
		if(isVanilla())
 | 
			
		||||
		if (isVanilla())
 | 
			
		||||
		{
 | 
			
		||||
			version->vanillaProcessArguments = processArguments;
 | 
			
		||||
		}
 | 
			
		||||
		version->processArguments = processArguments;
 | 
			
		||||
	}
 | 
			
		||||
	if (!type.isNull())
 | 
			
		||||
	if(isVanilla())
 | 
			
		||||
	{
 | 
			
		||||
		version->type = type;
 | 
			
		||||
	}
 | 
			
		||||
	if (!versionReleaseTime.isNull())
 | 
			
		||||
	{
 | 
			
		||||
		version->versionReleaseTime = versionReleaseTime;
 | 
			
		||||
	}
 | 
			
		||||
	if (!versionFileUpdateTime.isNull())
 | 
			
		||||
	{
 | 
			
		||||
		version->time = versionFileUpdateTime;
 | 
			
		||||
		if (!type.isNull())
 | 
			
		||||
		{
 | 
			
		||||
			version->type = type;
 | 
			
		||||
		}
 | 
			
		||||
		if (!m_releaseTimeString.isNull())
 | 
			
		||||
		{
 | 
			
		||||
			version->m_releaseTimeString = m_releaseTimeString;
 | 
			
		||||
			version->m_releaseTime = m_releaseTime;
 | 
			
		||||
		}
 | 
			
		||||
		if (!m_updateTimeString.isNull())
 | 
			
		||||
		{
 | 
			
		||||
			version->m_updateTimeString = m_updateTimeString;
 | 
			
		||||
			version->m_updateTime = m_updateTime;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (!assets.isNull())
 | 
			
		||||
	{
 | 
			
		||||
@@ -335,11 +359,12 @@ void VersionFile::applyTo(VersionFinal *version)
 | 
			
		||||
	}
 | 
			
		||||
	if (minimumLauncherVersion >= 0)
 | 
			
		||||
	{
 | 
			
		||||
		version->minimumLauncherVersion = minimumLauncherVersion;
 | 
			
		||||
		if(version->minimumLauncherVersion < minimumLauncherVersion)
 | 
			
		||||
			version->minimumLauncherVersion = minimumLauncherVersion;
 | 
			
		||||
	}
 | 
			
		||||
	if (!overwriteMinecraftArguments.isNull())
 | 
			
		||||
	{
 | 
			
		||||
		if(isVanilla())
 | 
			
		||||
		if (isVanilla())
 | 
			
		||||
		{
 | 
			
		||||
			version->vanillaMinecraftArguments = overwriteMinecraftArguments;
 | 
			
		||||
		}
 | 
			
		||||
@@ -374,7 +399,7 @@ void VersionFile::applyTo(VersionFinal *version)
 | 
			
		||||
		{
 | 
			
		||||
			libs.append(createLibrary(lib));
 | 
			
		||||
		}
 | 
			
		||||
		if(isVanilla())
 | 
			
		||||
		if (isVanilla())
 | 
			
		||||
			version->vanillaLibraries = libs;
 | 
			
		||||
		version->libraries = libs;
 | 
			
		||||
	}
 | 
			
		||||
@@ -498,7 +523,7 @@ void VersionFile::applyTo(VersionFinal *version)
 | 
			
		||||
		case RawLibrary::Replace:
 | 
			
		||||
		{
 | 
			
		||||
			QString toReplace;
 | 
			
		||||
			if(lib->insertData.isEmpty())
 | 
			
		||||
			if (lib->insertData.isEmpty())
 | 
			
		||||
			{
 | 
			
		||||
				const int startOfVersion = lib->name.lastIndexOf(':') + 1;
 | 
			
		||||
				toReplace = QString(lib->name).replace(startOfVersion, INT_MAX, '*');
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
 | 
			
		||||
#include <QString>
 | 
			
		||||
#include <QStringList>
 | 
			
		||||
#include <QDateTime>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include "logic/minecraft/OpSys.h"
 | 
			
		||||
#include "logic/minecraft/OneSixRule.h"
 | 
			
		||||
@@ -11,46 +12,8 @@
 | 
			
		||||
#include "JarMod.h"
 | 
			
		||||
 | 
			
		||||
class VersionFinal;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VersionBuildError : public MMCError
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	VersionBuildError(QString cause) : MMCError(cause) {};
 | 
			
		||||
	virtual ~VersionBuildError() noexcept {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * the base version file was meant for a newer version of the vanilla launcher than we support
 | 
			
		||||
 */
 | 
			
		||||
class LauncherVersionError : public VersionBuildError
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	LauncherVersionError(int actual, int supported)
 | 
			
		||||
		: VersionBuildError(QObject::tr(
 | 
			
		||||
			  "The base version file of this instance was meant for a newer (%1) "
 | 
			
		||||
			  "version of the vanilla launcher than this version of MultiMC supports (%2).")
 | 
			
		||||
								.arg(actual)
 | 
			
		||||
								.arg(supported)) {};
 | 
			
		||||
	virtual ~LauncherVersionError() noexcept {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * some patch was intended for a different version of minecraft
 | 
			
		||||
 */
 | 
			
		||||
class MinecraftVersionMismatch : public VersionBuildError
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	MinecraftVersionMismatch(QString fileId, QString mcVersion, QString parentMcVersion)
 | 
			
		||||
		: VersionBuildError(QObject::tr("The patch %1 is for a different version of Minecraft "
 | 
			
		||||
										"(%2) than that of the instance (%3).")
 | 
			
		||||
								.arg(fileId)
 | 
			
		||||
								.arg(mcVersion)
 | 
			
		||||
								.arg(parentMcVersion)) {};
 | 
			
		||||
	virtual ~MinecraftVersionMismatch() noexcept {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct VersionFile;
 | 
			
		||||
 | 
			
		||||
typedef std::shared_ptr<VersionFile> VersionFilePtr;
 | 
			
		||||
class VersionFile : public VersionPatch
 | 
			
		||||
{
 | 
			
		||||
@@ -62,7 +25,35 @@ public: /* methods */
 | 
			
		||||
	virtual void applyTo(VersionFinal *version) override;
 | 
			
		||||
	virtual bool isVanilla() override;
 | 
			
		||||
	virtual bool hasJarMods() override;
 | 
			
		||||
	
 | 
			
		||||
	virtual int getOrder() override
 | 
			
		||||
	{
 | 
			
		||||
		return order;
 | 
			
		||||
	}
 | 
			
		||||
	virtual void setOrder(int order) override
 | 
			
		||||
	{
 | 
			
		||||
		this->order = order;
 | 
			
		||||
	}
 | 
			
		||||
	virtual QList<JarmodPtr> getJarMods() override
 | 
			
		||||
	{
 | 
			
		||||
		return jarMods;
 | 
			
		||||
	}
 | 
			
		||||
	virtual QString getPatchID() override
 | 
			
		||||
	{
 | 
			
		||||
		return fileId;
 | 
			
		||||
	}
 | 
			
		||||
	virtual QString getPatchName() override
 | 
			
		||||
	{
 | 
			
		||||
		return name;
 | 
			
		||||
	}
 | 
			
		||||
	virtual QString getPatchVersion() override
 | 
			
		||||
	{
 | 
			
		||||
		return version;
 | 
			
		||||
	}
 | 
			
		||||
	virtual QString getPatchFilename() override
 | 
			
		||||
	{
 | 
			
		||||
		return filename;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
public: /* data */
 | 
			
		||||
	int order = 0;
 | 
			
		||||
	QString name;
 | 
			
		||||
@@ -81,8 +72,16 @@ public: /* data */
 | 
			
		||||
	QString removeMinecraftArguments;
 | 
			
		||||
	QString processArguments;
 | 
			
		||||
	QString type;
 | 
			
		||||
	QString versionReleaseTime;
 | 
			
		||||
	QString versionFileUpdateTime;
 | 
			
		||||
 | 
			
		||||
	/// the time this version was actually released by Mojang, as string and as QDateTime
 | 
			
		||||
	QString m_releaseTimeString;
 | 
			
		||||
	QDateTime m_releaseTime;
 | 
			
		||||
 | 
			
		||||
	/// the time this version was last updated by Mojang, as string and as QDateTime
 | 
			
		||||
	QString m_updateTimeString;
 | 
			
		||||
	QDateTime m_updateTime;
 | 
			
		||||
 | 
			
		||||
	/// asset group used by this ... thing.
 | 
			
		||||
	QString assets;
 | 
			
		||||
	int minimumLauncherVersion = -1;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -39,8 +39,10 @@ void VersionFinal::reload(const QStringList &external)
 | 
			
		||||
void VersionFinal::clear()
 | 
			
		||||
{
 | 
			
		||||
	id.clear();
 | 
			
		||||
	time.clear();
 | 
			
		||||
	versionReleaseTime.clear();
 | 
			
		||||
	m_updateTimeString.clear();
 | 
			
		||||
	m_updateTime = QDateTime();
 | 
			
		||||
	m_releaseTimeString.clear();
 | 
			
		||||
	m_releaseTime = QDateTime();
 | 
			
		||||
	type.clear();
 | 
			
		||||
	assets.clear();
 | 
			
		||||
	processArguments.clear();
 | 
			
		||||
@@ -56,17 +58,13 @@ void VersionFinal::clear()
 | 
			
		||||
 | 
			
		||||
bool VersionFinal::canRemove(const int index) const
 | 
			
		||||
{
 | 
			
		||||
	if (index < versionFiles.size())
 | 
			
		||||
	{
 | 
			
		||||
		return versionFiles.at(index)->fileId != "org.multimc.version.json";
 | 
			
		||||
	}
 | 
			
		||||
	return false;
 | 
			
		||||
	return VersionPatches.at(index)->isMoveable();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool VersionFinal::preremove(VersionFilePtr versionfile)
 | 
			
		||||
bool VersionFinal::preremove(VersionPatchPtr patch)
 | 
			
		||||
{
 | 
			
		||||
	bool ok = true;
 | 
			
		||||
	for(auto & jarmod: versionfile->jarMods)
 | 
			
		||||
	for(auto & jarmod: patch->getJarMods())
 | 
			
		||||
	{
 | 
			
		||||
		QString fullpath =PathCombine(m_instance->jarModsDir(), jarmod->name);
 | 
			
		||||
		QFileInfo finfo (fullpath);
 | 
			
		||||
@@ -80,14 +78,14 @@ bool VersionFinal::remove(const int index)
 | 
			
		||||
{
 | 
			
		||||
	if (!canRemove(index))
 | 
			
		||||
		return false;
 | 
			
		||||
	if(!preremove(versionFiles[index]))
 | 
			
		||||
	if(!preremove(VersionPatches[index]))
 | 
			
		||||
	{
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	if(!QFile::remove(versionFiles.at(index)->filename))
 | 
			
		||||
	if(!QFile::remove(VersionPatches.at(index)->getPatchFilename()))
 | 
			
		||||
		return false;
 | 
			
		||||
	beginResetModel();
 | 
			
		||||
	versionFiles.removeAt(index);
 | 
			
		||||
	VersionPatches.removeAt(index);
 | 
			
		||||
	reapply(true);
 | 
			
		||||
	endResetModel();
 | 
			
		||||
	return true;
 | 
			
		||||
@@ -96,9 +94,9 @@ bool VersionFinal::remove(const int index)
 | 
			
		||||
bool VersionFinal::remove(const QString id)
 | 
			
		||||
{
 | 
			
		||||
	int i = 0;
 | 
			
		||||
	for (auto file : versionFiles)
 | 
			
		||||
	for (auto patch : VersionPatches)
 | 
			
		||||
	{
 | 
			
		||||
		if (file->fileId == id)
 | 
			
		||||
		if (patch->getPatchID() == id)
 | 
			
		||||
		{
 | 
			
		||||
			return remove(i);
 | 
			
		||||
		}
 | 
			
		||||
@@ -109,18 +107,18 @@ bool VersionFinal::remove(const QString id)
 | 
			
		||||
 | 
			
		||||
QString VersionFinal::versionFileId(const int index) const
 | 
			
		||||
{
 | 
			
		||||
	if (index < 0 || index >= versionFiles.size())
 | 
			
		||||
	if (index < 0 || index >= VersionPatches.size())
 | 
			
		||||
	{
 | 
			
		||||
		return QString();
 | 
			
		||||
	}
 | 
			
		||||
	return versionFiles.at(index)->fileId;
 | 
			
		||||
	return VersionPatches.at(index)->getPatchID();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VersionFilePtr VersionFinal::versionPatch(const QString &id)
 | 
			
		||||
VersionPatchPtr VersionFinal::versionPatch(const QString &id)
 | 
			
		||||
{
 | 
			
		||||
	for (auto file : versionFiles)
 | 
			
		||||
	for (auto file : VersionPatches)
 | 
			
		||||
	{
 | 
			
		||||
		if (file->fileId == id)
 | 
			
		||||
		if (file->getPatchID() == id)
 | 
			
		||||
		{
 | 
			
		||||
			return file;
 | 
			
		||||
		}
 | 
			
		||||
@@ -128,6 +126,14 @@ VersionFilePtr VersionFinal::versionPatch(const QString &id)
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VersionPatchPtr VersionFinal::versionPatch(int index)
 | 
			
		||||
{
 | 
			
		||||
	if(index < 0 || index >= VersionPatches.size())
 | 
			
		||||
		return 0;
 | 
			
		||||
	return VersionPatches[index];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool VersionFinal::hasJarMods()
 | 
			
		||||
{
 | 
			
		||||
	return !jarMods.isEmpty();
 | 
			
		||||
@@ -146,7 +152,7 @@ bool VersionFinal::removeFtbPack()
 | 
			
		||||
bool VersionFinal::isVanilla()
 | 
			
		||||
{
 | 
			
		||||
	QDir patches(PathCombine(m_instance->instanceRoot(), "patches/"));
 | 
			
		||||
	if(versionFiles.size() > 1)
 | 
			
		||||
	if(VersionPatches.size() > 1)
 | 
			
		||||
		return false;
 | 
			
		||||
	if(QFile::exists(PathCombine(m_instance->instanceRoot(), "custom.json")))
 | 
			
		||||
		return false;
 | 
			
		||||
@@ -156,22 +162,22 @@ bool VersionFinal::isVanilla()
 | 
			
		||||
bool VersionFinal::revertToVanilla()
 | 
			
		||||
{
 | 
			
		||||
	beginResetModel();
 | 
			
		||||
	auto it = versionFiles.begin();
 | 
			
		||||
	while (it != versionFiles.end())
 | 
			
		||||
	auto it = VersionPatches.begin();
 | 
			
		||||
	while (it != VersionPatches.end())
 | 
			
		||||
	{
 | 
			
		||||
		if ((*it)->fileId != "org.multimc.version.json")
 | 
			
		||||
		if ((*it)->isMoveable())
 | 
			
		||||
		{
 | 
			
		||||
			if(!preremove(*it))
 | 
			
		||||
			{
 | 
			
		||||
				endResetModel();
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			if(!QFile::remove((*it)->filename))
 | 
			
		||||
			if(!QFile::remove((*it)->getPatchFilename()))
 | 
			
		||||
			{
 | 
			
		||||
				endResetModel();
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			it = versionFiles.erase(it);
 | 
			
		||||
			it = VersionPatches.erase(it);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
			it++;
 | 
			
		||||
@@ -233,7 +239,7 @@ QVariant VersionFinal::data(const QModelIndex &index, int role) const
 | 
			
		||||
	int row = index.row();
 | 
			
		||||
	int column = index.column();
 | 
			
		||||
 | 
			
		||||
	if (row < 0 || row >= versionFiles.size())
 | 
			
		||||
	if (row < 0 || row >= VersionPatches.size())
 | 
			
		||||
		return QVariant();
 | 
			
		||||
 | 
			
		||||
	if (role == Qt::DisplayRole)
 | 
			
		||||
@@ -241,9 +247,9 @@ QVariant VersionFinal::data(const QModelIndex &index, int role) const
 | 
			
		||||
		switch (column)
 | 
			
		||||
		{
 | 
			
		||||
		case 0:
 | 
			
		||||
			return versionFiles.at(row)->name;
 | 
			
		||||
			return VersionPatches.at(row)->getPatchName();
 | 
			
		||||
		case 1:
 | 
			
		||||
			return versionFiles.at(row)->version;
 | 
			
		||||
			return VersionPatches.at(row)->getPatchVersion();
 | 
			
		||||
		default:
 | 
			
		||||
			return QVariant();
 | 
			
		||||
		}
 | 
			
		||||
@@ -278,7 +284,7 @@ Qt::ItemFlags VersionFinal::flags(const QModelIndex &index) const
 | 
			
		||||
 | 
			
		||||
int VersionFinal::rowCount(const QModelIndex &parent) const
 | 
			
		||||
{
 | 
			
		||||
	return versionFiles.size();
 | 
			
		||||
	return VersionPatches.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int VersionFinal::columnCount(const QModelIndex &parent) const
 | 
			
		||||
@@ -288,13 +294,12 @@ int VersionFinal::columnCount(const QModelIndex &parent) const
 | 
			
		||||
 | 
			
		||||
QMap<QString, int> VersionFinal::getExistingOrder() const
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	QMap<QString, int> order;
 | 
			
		||||
	// default
 | 
			
		||||
	{
 | 
			
		||||
		for (auto file : versionFiles)
 | 
			
		||||
		for (auto file : VersionPatches)
 | 
			
		||||
		{
 | 
			
		||||
			order.insert(file->fileId, file->order);
 | 
			
		||||
			order.insert(file->getPatchID(), file->getOrder());
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// overriden
 | 
			
		||||
@@ -314,39 +319,37 @@ QMap<QString, int> VersionFinal::getExistingOrder() const
 | 
			
		||||
void VersionFinal::move(const int index, const MoveDirection direction)
 | 
			
		||||
{
 | 
			
		||||
	int theirIndex;
 | 
			
		||||
	int theirIndex_qt;
 | 
			
		||||
	if (direction == MoveUp)
 | 
			
		||||
	{
 | 
			
		||||
		theirIndex = index - 1;
 | 
			
		||||
		theirIndex_qt = theirIndex = index - 1;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		theirIndex = index + 1;
 | 
			
		||||
		theirIndex_qt = index + 2;
 | 
			
		||||
	}
 | 
			
		||||
	if (theirIndex < 0 || theirIndex >= versionFiles.size())
 | 
			
		||||
	{
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	const QString ourId = versionFileId(index);
 | 
			
		||||
	const QString theirId = versionFileId(theirIndex);
 | 
			
		||||
	if (ourId.isNull() || ourId.startsWith("org.multimc.") ||
 | 
			
		||||
			theirId.isNull() || theirId.startsWith("org.multimc."))
 | 
			
		||||
	auto from = versionPatch(index);
 | 
			
		||||
	auto to = versionPatch(theirIndex);
 | 
			
		||||
	
 | 
			
		||||
	if (!from || !to || !from->isMoveable() || !from->isMoveable())
 | 
			
		||||
	{
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	if(direction == MoveDown)
 | 
			
		||||
	{
 | 
			
		||||
		beginMoveRows(QModelIndex(), index, index, QModelIndex(), theirIndex+1);
 | 
			
		||||
		beginMoveRows(QModelIndex(), index, index, QModelIndex(), theirIndex_qt);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		beginMoveRows(QModelIndex(), index, index, QModelIndex(), theirIndex);
 | 
			
		||||
		beginMoveRows(QModelIndex(), index, index, QModelIndex(), theirIndex_qt);
 | 
			
		||||
	}
 | 
			
		||||
	versionFiles.swap(index, theirIndex);
 | 
			
		||||
	VersionPatches.swap(index, theirIndex);
 | 
			
		||||
	endMoveRows();
 | 
			
		||||
 | 
			
		||||
	auto order = getExistingOrder();
 | 
			
		||||
	order[ourId] = theirIndex;
 | 
			
		||||
	order[theirId] = index;
 | 
			
		||||
	order[from->getPatchID()] = theirIndex;
 | 
			
		||||
	order[to->getPatchID()] = index;
 | 
			
		||||
 | 
			
		||||
	if (!VersionBuilder::writeOverrideOrders(order, m_instance))
 | 
			
		||||
	{
 | 
			
		||||
@@ -375,14 +378,14 @@ void VersionFinal::reapply(const bool alreadyReseting)
 | 
			
		||||
	auto existingOrders = getExistingOrder();
 | 
			
		||||
	QList<int> orders = existingOrders.values();
 | 
			
		||||
	std::sort(orders.begin(), orders.end());
 | 
			
		||||
	QList<VersionFilePtr> newVersionFiles;
 | 
			
		||||
	QList<VersionPatchPtr> newVersionFiles;
 | 
			
		||||
	for (auto order : orders)
 | 
			
		||||
	{
 | 
			
		||||
		auto file = versionPatch(existingOrders.key(order));
 | 
			
		||||
		newVersionFiles.append(file);
 | 
			
		||||
		file->applyTo(this);
 | 
			
		||||
	}
 | 
			
		||||
	versionFiles.swap(newVersionFiles);
 | 
			
		||||
	VersionPatches.swap(newVersionFiles);
 | 
			
		||||
	finalize();
 | 
			
		||||
	if (!alreadyReseting)
 | 
			
		||||
	{
 | 
			
		||||
 
 | 
			
		||||
@@ -83,16 +83,21 @@ public:
 | 
			
		||||
	static std::shared_ptr<VersionFinal> fromJson(const QJsonObject &obj);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	bool preremove(VersionFilePtr);
 | 
			
		||||
	bool preremove(VersionPatchPtr patch);
 | 
			
		||||
	
 | 
			
		||||
	// data members
 | 
			
		||||
public:
 | 
			
		||||
	/// the ID - determines which jar to use! ACTUALLY IMPORTANT!
 | 
			
		||||
	QString id;
 | 
			
		||||
	/// Last updated time - as a string
 | 
			
		||||
	QString time;
 | 
			
		||||
	/// Release time - as a string
 | 
			
		||||
	QString versionReleaseTime;
 | 
			
		||||
 | 
			
		||||
	/// the time this version was actually released by Mojang, as string and as QDateTime
 | 
			
		||||
	QString m_releaseTimeString;
 | 
			
		||||
	QDateTime m_releaseTime;
 | 
			
		||||
 | 
			
		||||
	/// the time this version was last updated by Mojang, as string and as QDateTime
 | 
			
		||||
	QString m_updateTimeString;
 | 
			
		||||
	QDateTime m_updateTime;
 | 
			
		||||
 | 
			
		||||
	/// Release type - "release" or "snapshot"
 | 
			
		||||
	QString type;
 | 
			
		||||
	/// Assets type - "legacy" or a version ID
 | 
			
		||||
@@ -164,8 +169,9 @@ public:
 | 
			
		||||
	*/
 | 
			
		||||
	// QList<Rule> rules;
 | 
			
		||||
 | 
			
		||||
	QList<VersionFilePtr> versionFiles;
 | 
			
		||||
	VersionFilePtr versionPatch(const QString &id);
 | 
			
		||||
	QList<VersionPatchPtr> VersionPatches;
 | 
			
		||||
	VersionPatchPtr versionPatch(const QString &id);
 | 
			
		||||
	VersionPatchPtr versionPatch(int index);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	OneSixInstance *m_instance;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,8 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <QList>
 | 
			
		||||
#include "JarMod.h"
 | 
			
		||||
 | 
			
		||||
class VersionFinal;
 | 
			
		||||
class VersionPatch
 | 
			
		||||
@@ -8,8 +10,22 @@ class VersionPatch
 | 
			
		||||
public:
 | 
			
		||||
	virtual ~VersionPatch(){};
 | 
			
		||||
	virtual void applyTo(VersionFinal *version) = 0;
 | 
			
		||||
	
 | 
			
		||||
	virtual bool isVanilla() = 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;
 | 
			
		||||
	virtual QString getPatchFilename() = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef std::shared_ptr<VersionPatch> VersionPatchPtr;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user