All of the broken legacy things work.
This commit is contained in:
		| @@ -479,6 +479,8 @@ SET(MULTIMC_SOURCES | ||||
| 	logic/minecraft/OneSixRule.h | ||||
| 	logic/minecraft/OpSys.cpp | ||||
| 	logic/minecraft/OpSys.h | ||||
| 	logic/minecraft/ParseUtils.cpp | ||||
| 	logic/minecraft/ParseUtils.h | ||||
| 	logic/minecraft/RawLibrary.cpp | ||||
| 	logic/minecraft/RawLibrary.h | ||||
| 	logic/minecraft/VersionBuilder.cpp | ||||
| @@ -489,10 +491,6 @@ SET(MULTIMC_SOURCES | ||||
| 	logic/minecraft/VersionFinal.h | ||||
| 	logic/minecraft/VersionPatch.h | ||||
|  | ||||
| 	# Trivial operating system utilities | ||||
| 	logic/minecraft/OpSys.h | ||||
| 	logic/minecraft/OpSys.cpp | ||||
|  | ||||
| 	# Various base classes | ||||
| 	logic/BaseInstaller.h | ||||
| 	logic/BaseInstaller.cpp | ||||
|   | ||||
| @@ -24,6 +24,7 @@ import java.awt.BorderLayout; | ||||
| import java.awt.Graphics; | ||||
| import java.applet.Applet; | ||||
| import java.applet.AppletStub; | ||||
| import java.net.MalformedURLException; | ||||
|  | ||||
| public class Launcher extends Applet implements AppletStub | ||||
| { | ||||
| @@ -130,13 +131,23 @@ public class Launcher extends Applet implements AppletStub | ||||
|  | ||||
| 	@Override | ||||
| 	public URL getCodeBase() { | ||||
| 		return wrappedApplet.getCodeBase(); | ||||
| 		try { | ||||
| 			return new URL("http://www.minecraft.net/game/"); | ||||
| 		} catch (MalformedURLException e) { | ||||
| 			e.printStackTrace(); | ||||
| 		} | ||||
| 		return null; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public URL getDocumentBase() | ||||
| 	{ | ||||
| 		return documentBase; | ||||
| 		try { | ||||
| 			return new URL("http://www.minecraft.net/game/"); | ||||
| 		} catch (MalformedURLException e) { | ||||
| 			e.printStackTrace(); | ||||
| 		} | ||||
| 		return null; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
|   | ||||
| @@ -53,7 +53,7 @@ public class OneSixLauncher implements Launcher | ||||
| 	{ | ||||
| 		libraries = params.all("cp"); | ||||
| 		extlibs = params.all("ext"); | ||||
| 		mcparams = params.all("param"); | ||||
| 		mcparams = params.allSafe("param", new ArrayList<String>() ); | ||||
| 		mainClass = params.firstSafe("mainClass", "net.minecraft.client.Minecraft"); | ||||
| 		appletClass = params.firstSafe("appletClass", "net.minecraft.client.MinecraftApplet"); | ||||
| 		mods = params.allSafe("mods", new ArrayList<String>()); | ||||
|   | ||||
| @@ -47,7 +47,7 @@ NewInstanceDialog::NewInstanceDialog(QWidget *parent) | ||||
| 		taskDlg->exec(loadTask); | ||||
| 	} | ||||
| 	*/ | ||||
| 	setSelectedVersion(MMC->minecraftlist()->getLatestStable()); | ||||
| 	setSelectedVersion(MMC->minecraftlist()->getLatestStable(), true); | ||||
| 	InstIconKey = "infinity"; | ||||
| 	ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey)); | ||||
| } | ||||
| @@ -63,13 +63,17 @@ void NewInstanceDialog::updateDialogState() | ||||
| 		->setEnabled(!instName().isEmpty() && m_selectedVersion); | ||||
| } | ||||
|  | ||||
| void NewInstanceDialog::setSelectedVersion(BaseVersionPtr version) | ||||
| void NewInstanceDialog::setSelectedVersion(BaseVersionPtr version, bool initial) | ||||
| { | ||||
| 	m_selectedVersion = version; | ||||
|  | ||||
| 	if (m_selectedVersion) | ||||
| 	{ | ||||
| 		ui->versionTextBox->setText(version->name()); | ||||
| 		if(ui->instNameTextBox->text().isEmpty() && !initial) | ||||
| 		{ | ||||
| 			ui->instNameTextBox->setText(version->name()); | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
|   | ||||
| @@ -33,7 +33,7 @@ public: | ||||
|  | ||||
| 	void updateDialogState(); | ||||
|  | ||||
| 	void setSelectedVersion(BaseVersionPtr version); | ||||
| 	void setSelectedVersion(BaseVersionPtr version, bool initial = false); | ||||
|  | ||||
| 	void loadVersionList(); | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -495,6 +495,7 @@ | ||||
| 		"releaseTime": "2010-07-13T00:00:00+02:00", | ||||
| 		"type": "old_alpha", | ||||
| 		"processArguments": "legacy", | ||||
| 		"mainClass": "y", | ||||
| 		"+traits": ["legacyLaunch"] | ||||
| 	}, | ||||
| 	{ | ||||
| @@ -502,6 +503,7 @@ | ||||
| 		"releaseTime": "2010-07-09T00:00:00+02:00", | ||||
| 		"type": "old_alpha", | ||||
| 		"processArguments": "legacy", | ||||
| 		"mainClass": "ax", | ||||
| 		"+traits": ["legacyLaunch"] | ||||
| 	}, | ||||
| 	{ | ||||
| @@ -509,6 +511,8 @@ | ||||
| 		"releaseTime": "2010-06-16T00:00:00+02:00", | ||||
| 		"type": "old_alpha", | ||||
| 		"processArguments": "legacy", | ||||
| 		"mainClass": "net.minecraft.client.d", | ||||
| 		"appletClass": "net.minecraft.client.MinecraftApplet", | ||||
| 		"+traits": ["legacyLaunch"] | ||||
| 	}, | ||||
| 	{ | ||||
| @@ -516,6 +520,8 @@ | ||||
| 		"releaseTime": "2009-12-22T00:00:00+02:00", | ||||
| 		"type": "old_alpha", | ||||
| 		"processArguments": "legacy", | ||||
| 		"mainClass": "com.mojang.minecraft.l", | ||||
| 		"appletClass": "com.mojang.minecraft.MinecraftApplet", | ||||
| 		"+traits": ["legacyLaunch"] | ||||
| 	}, | ||||
| 	{ | ||||
| @@ -523,6 +529,8 @@ | ||||
| 		"releaseTime": "2009-05-22T00:00:00+02:00", | ||||
| 		"type": "old_alpha", | ||||
| 		"processArguments": "legacy", | ||||
| 		"mainClass": "com.mojang.minecraft.c", | ||||
| 		"appletClass": "com.mojang.minecraft.MinecraftApplet", | ||||
| 		"+traits": ["legacyLaunch"] | ||||
| 	}, | ||||
| 	{ | ||||
| @@ -530,6 +538,8 @@ | ||||
| 		"releaseTime": "2009-05-31T00:00:00+02:00", | ||||
| 		"type": "old_alpha", | ||||
| 		"processArguments": "legacy", | ||||
| 		"mainClass": "com.mojang.minecraft.Minecraft", | ||||
| 		"appletClass": "com.mojang.minecraft.MinecraftApplet", | ||||
| 		"+traits": ["legacyLaunch"] | ||||
| 	}, | ||||
| 	{ | ||||
| @@ -537,6 +547,8 @@ | ||||
| 		"releaseTime": "2009-05-17T00:00:00+02:00", | ||||
| 		"type": "old_alpha", | ||||
| 		"processArguments": "legacy", | ||||
| 		"mainClass": "com.mojang.minecraft.Minecraft", | ||||
| 		"appletClass": "com.mojang.minecraft.MinecraftApplet", | ||||
| 		"+traits": ["legacyLaunch"] | ||||
| 	}, | ||||
| 	{ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user