NOISSUE merging of strategy into profile, onesix into minecraft
This commit is contained in:
		| @@ -16,19 +16,19 @@ | |||||||
| #include <QFile> | #include <QFile> | ||||||
|  |  | ||||||
| #include "BaseInstaller.h" | #include "BaseInstaller.h" | ||||||
| #include "minecraft/onesix/OneSixInstance.h" | #include "minecraft/MinecraftInstance.h" | ||||||
|  |  | ||||||
| BaseInstaller::BaseInstaller() | BaseInstaller::BaseInstaller() | ||||||
| { | { | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| bool BaseInstaller::isApplied(OneSixInstance *on) | bool BaseInstaller::isApplied(MinecraftInstance *on) | ||||||
| { | { | ||||||
| 	return QFile::exists(filename(on->instanceRoot())); | 	return QFile::exists(filename(on->instanceRoot())); | ||||||
| } | } | ||||||
|  |  | ||||||
| bool BaseInstaller::add(OneSixInstance *to) | bool BaseInstaller::add(MinecraftInstance *to) | ||||||
| { | { | ||||||
| 	if (!patchesDir(to->instanceRoot()).exists()) | 	if (!patchesDir(to->instanceRoot()).exists()) | ||||||
| 	{ | 	{ | ||||||
| @@ -46,7 +46,7 @@ bool BaseInstaller::add(OneSixInstance *to) | |||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| bool BaseInstaller::remove(OneSixInstance *from) | bool BaseInstaller::remove(MinecraftInstance *from) | ||||||
| { | { | ||||||
| 	return QFile::remove(filename(from->instanceRoot())); | 	return QFile::remove(filename(from->instanceRoot())); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ | |||||||
|  |  | ||||||
| #include "multimc_logic_export.h" | #include "multimc_logic_export.h" | ||||||
|  |  | ||||||
| class OneSixInstance; | class MinecraftInstance; | ||||||
| class QDir; | class QDir; | ||||||
| class QString; | class QString; | ||||||
| class QObject; | class QObject; | ||||||
| @@ -32,12 +32,12 @@ class MULTIMC_LOGIC_EXPORT BaseInstaller | |||||||
| public: | public: | ||||||
| 	BaseInstaller(); | 	BaseInstaller(); | ||||||
| 	virtual ~BaseInstaller(){}; | 	virtual ~BaseInstaller(){}; | ||||||
| 	bool isApplied(OneSixInstance *on); | 	bool isApplied(MinecraftInstance *on); | ||||||
|  |  | ||||||
| 	virtual bool add(OneSixInstance *to); | 	virtual bool add(MinecraftInstance *to); | ||||||
| 	virtual bool remove(OneSixInstance *from); | 	virtual bool remove(MinecraftInstance *from); | ||||||
|  |  | ||||||
| 	virtual Task *createInstallTask(OneSixInstance *instance, BaseVersionPtr version, QObject *parent) = 0; | 	virtual Task *createInstallTask(MinecraftInstance *instance, BaseVersionPtr version, QObject *parent) = 0; | ||||||
|  |  | ||||||
| protected: | protected: | ||||||
| 	virtual QString id() const = 0; | 	virtual QString id() const = 0; | ||||||
|   | |||||||
| @@ -279,6 +279,7 @@ QString BaseInstance::windowTitle() const | |||||||
| 	return "MultiMC: " + name(); | 	return "MultiMC: " + name(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // FIXME: why is this here? move it to MinecraftInstance!!! | ||||||
| QStringList BaseInstance::extraArguments() const | QStringList BaseInstance::extraArguments() const | ||||||
| { | { | ||||||
| 	return Commandline::splitArgs(settings()->get("JvmArgs").toString()); | 	return Commandline::splitArgs(settings()->get("JvmArgs").toString()); | ||||||
|   | |||||||
| @@ -129,23 +129,6 @@ public: | |||||||
|  |  | ||||||
| 	virtual QStringList extraArguments() const; | 	virtual QStringList extraArguments() const; | ||||||
|  |  | ||||||
| 	virtual QString intendedVersionId() const = 0; |  | ||||||
| 	virtual bool setIntendedVersionId(QString version) = 0; |  | ||||||
|  |  | ||||||
| 	/*! |  | ||||||
| 	 * The instance's current version. |  | ||||||
| 	 * This value represents the instance's current version. If this value is |  | ||||||
| 	 * different from the intendedVersion, the instance should be updated. |  | ||||||
| 	 * \warning Don't change this value unless you know what you're doing. |  | ||||||
| 	 */ |  | ||||||
| 	virtual QString currentVersionId() const = 0; |  | ||||||
|  |  | ||||||
| 	/*! |  | ||||||
| 	 * Whether or not 'the game' should be downloaded when the instance is launched. |  | ||||||
| 	 */ |  | ||||||
| 	virtual bool shouldUpdate() const = 0; |  | ||||||
| 	virtual void setShouldUpdate(bool val) = 0; |  | ||||||
|  |  | ||||||
| 	/// Traits. Normally inside the version, depends on instance implementation. | 	/// Traits. Normally inside the version, depends on instance implementation. | ||||||
| 	virtual QSet <QString> traits() = 0; | 	virtual QSet <QString> traits() = 0; | ||||||
|  |  | ||||||
| @@ -159,12 +142,6 @@ public: | |||||||
|  |  | ||||||
| 	InstancePtr getSharedPtr(); | 	InstancePtr getSharedPtr(); | ||||||
|  |  | ||||||
| 	/*! |  | ||||||
| 	 * \brief Gets a pointer to this instance's version list. |  | ||||||
| 	 * \return A pointer to the available version list for this instance. |  | ||||||
| 	 */ |  | ||||||
| 	virtual std::shared_ptr<BaseVersionList> versionList() const = 0; |  | ||||||
|  |  | ||||||
| 	/*! | 	/*! | ||||||
| 	 * \brief Gets this instance's settings object. | 	 * \brief Gets this instance's settings object. | ||||||
| 	 * This settings object stores instance-specific settings. | 	 * This settings object stores instance-specific settings. | ||||||
| @@ -181,12 +158,6 @@ public: | |||||||
| 	/// returns the current launch task (if any) | 	/// returns the current launch task (if any) | ||||||
| 	std::shared_ptr<LaunchTask> getLaunchTask(); | 	std::shared_ptr<LaunchTask> getLaunchTask(); | ||||||
|  |  | ||||||
| 	/*! |  | ||||||
| 	 * Returns a task that should be done right before launch |  | ||||||
| 	 * This task should do any extra preparations needed |  | ||||||
| 	 */ |  | ||||||
| 	virtual std::shared_ptr<Task> createJarModdingTask() = 0; |  | ||||||
|  |  | ||||||
| 	/*! | 	/*! | ||||||
| 	 * Create envrironment variables for running the instance | 	 * Create envrironment variables for running the instance | ||||||
| 	 */ | 	 */ | ||||||
|   | |||||||
| @@ -206,22 +206,14 @@ set(MINECRAFT_SOURCES | |||||||
| 	minecraft/auth/flows/RefreshTask.cpp | 	minecraft/auth/flows/RefreshTask.cpp | ||||||
| 	minecraft/auth/flows/ValidateTask.h | 	minecraft/auth/flows/ValidateTask.h | ||||||
| 	minecraft/auth/flows/ValidateTask.cpp | 	minecraft/auth/flows/ValidateTask.cpp | ||||||
| 	minecraft/onesix/OneSixUpdate.h | 	minecraft/update/AssetUpdateTask.h | ||||||
| 	minecraft/onesix/OneSixUpdate.cpp | 	minecraft/update/AssetUpdateTask.cpp | ||||||
| 	minecraft/onesix/OneSixInstance.h | 	minecraft/update/FMLLibrariesTask.cpp | ||||||
| 	minecraft/onesix/OneSixInstance.cpp | 	minecraft/update/FMLLibrariesTask.h | ||||||
| 	minecraft/onesix/OneSixProfileStrategy.cpp | 	minecraft/update/FoldersTask.cpp | ||||||
| 	minecraft/onesix/OneSixProfileStrategy.h | 	minecraft/update/FoldersTask.h | ||||||
| 	minecraft/onesix/OneSixVersionFormat.cpp | 	minecraft/update/LibrariesTask.cpp | ||||||
| 	minecraft/onesix/OneSixVersionFormat.h | 	minecraft/update/LibrariesTask.h | ||||||
| 	minecraft/onesix/update/AssetUpdateTask.h |  | ||||||
| 	minecraft/onesix/update/AssetUpdateTask.cpp |  | ||||||
| 	minecraft/onesix/update/FMLLibrariesTask.cpp |  | ||||||
| 	minecraft/onesix/update/FMLLibrariesTask.h |  | ||||||
| 	minecraft/onesix/update/FoldersTask.cpp |  | ||||||
| 	minecraft/onesix/update/FoldersTask.h |  | ||||||
| 	minecraft/onesix/update/LibrariesTask.cpp |  | ||||||
| 	minecraft/onesix/update/LibrariesTask.h |  | ||||||
| 	minecraft/launch/ClaimAccount.cpp | 	minecraft/launch/ClaimAccount.cpp | ||||||
| 	minecraft/launch/ClaimAccount.h | 	minecraft/launch/ClaimAccount.h | ||||||
| 	minecraft/launch/CreateServerResourcePacksFolder.cpp | 	minecraft/launch/CreateServerResourcePacksFolder.cpp | ||||||
| @@ -237,21 +229,24 @@ set(MINECRAFT_SOURCES | |||||||
| 	minecraft/launch/PrintInstanceInfo.cpp | 	minecraft/launch/PrintInstanceInfo.cpp | ||||||
| 	minecraft/launch/PrintInstanceInfo.h | 	minecraft/launch/PrintInstanceInfo.h | ||||||
| 	minecraft/GradleSpecifier.h | 	minecraft/GradleSpecifier.h | ||||||
| 	minecraft/MinecraftProfile.cpp |  | ||||||
| 	minecraft/MinecraftProfile.h |  | ||||||
| 	minecraft/MojangVersionFormat.cpp |  | ||||||
| 	minecraft/MojangVersionFormat.h |  | ||||||
| 	minecraft/MinecraftInstance.cpp | 	minecraft/MinecraftInstance.cpp | ||||||
| 	minecraft/MinecraftInstance.h | 	minecraft/MinecraftInstance.h | ||||||
|  | 	minecraft/MinecraftProfile.cpp | ||||||
|  | 	minecraft/MinecraftProfile.h | ||||||
|  | 	minecraft/MinecraftUpdate.h | ||||||
|  | 	minecraft/MinecraftUpdate.cpp | ||||||
|  | 	minecraft/MojangVersionFormat.cpp | ||||||
|  | 	minecraft/MojangVersionFormat.h | ||||||
| 	minecraft/Rule.cpp | 	minecraft/Rule.cpp | ||||||
| 	minecraft/Rule.h | 	minecraft/Rule.h | ||||||
|  | 	minecraft/OneSixVersionFormat.cpp | ||||||
|  | 	minecraft/OneSixVersionFormat.h | ||||||
| 	minecraft/OpSys.cpp | 	minecraft/OpSys.cpp | ||||||
| 	minecraft/OpSys.h | 	minecraft/OpSys.h | ||||||
| 	minecraft/ParseUtils.cpp | 	minecraft/ParseUtils.cpp | ||||||
| 	minecraft/ParseUtils.h | 	minecraft/ParseUtils.h | ||||||
| 	minecraft/ProfileUtils.cpp | 	minecraft/ProfileUtils.cpp | ||||||
| 	minecraft/ProfileUtils.h | 	minecraft/ProfileUtils.h | ||||||
| 	minecraft/ProfileStrategy.h |  | ||||||
| 	minecraft/Library.cpp | 	minecraft/Library.cpp | ||||||
| 	minecraft/Library.h | 	minecraft/Library.h | ||||||
| 	minecraft/MojangDownloadInfo.h | 	minecraft/MojangDownloadInfo.h | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| #include "FolderInstanceProvider.h" | #include "FolderInstanceProvider.h" | ||||||
| #include "settings/INISettingsObject.h" | #include "settings/INISettingsObject.h" | ||||||
| #include "FileSystem.h" | #include "FileSystem.h" | ||||||
| #include "minecraft/onesix/OneSixInstance.h" | #include "minecraft/MinecraftInstance.h" | ||||||
| #include "NullInstance.h" | #include "NullInstance.h" | ||||||
|  |  | ||||||
| #include <QDir> | #include <QDir> | ||||||
| @@ -88,7 +88,7 @@ InstancePtr FolderInstanceProvider::loadInstance(const InstanceId& id) | |||||||
|  |  | ||||||
| 	if (inst_type == "OneSix" || inst_type == "Nostalgia") | 	if (inst_type == "OneSix" || inst_type == "Nostalgia") | ||||||
| 	{ | 	{ | ||||||
| 		inst.reset(new OneSixInstance(m_globalSettings, instanceSettings, instanceRoot)); | 		inst.reset(new MinecraftInstance(m_globalSettings, instanceSettings, instanceRoot)); | ||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ | |||||||
| #include "FileSystem.h" | #include "FileSystem.h" | ||||||
|  |  | ||||||
| //FIXME: remove this | //FIXME: remove this | ||||||
| #include "minecraft/onesix/OneSixInstance.h" | #include "minecraft/MinecraftInstance.h" | ||||||
|  |  | ||||||
| InstanceCreationTask::InstanceCreationTask(SettingsObjectPtr settings, const QString & stagingPath, BaseVersionPtr version, | InstanceCreationTask::InstanceCreationTask(SettingsObjectPtr settings, const QString & stagingPath, BaseVersionPtr version, | ||||||
| 	const QString& instName, const QString& instIcon, const QString& instGroup) | 	const QString& instName, const QString& instIcon, const QString& instGroup) | ||||||
| @@ -25,11 +25,11 @@ void InstanceCreationTask::executeTask() | |||||||
| 		instanceSettings->suspendSave(); | 		instanceSettings->suspendSave(); | ||||||
| 		instanceSettings->registerSetting("InstanceType", "Legacy"); | 		instanceSettings->registerSetting("InstanceType", "Legacy"); | ||||||
| 		instanceSettings->set("InstanceType", "OneSix"); | 		instanceSettings->set("InstanceType", "OneSix"); | ||||||
| 		OneSixInstance inst(m_globalSettings, instanceSettings, m_stagingPath); | 		auto inst = new MinecraftInstance(m_globalSettings, instanceSettings, m_stagingPath); | ||||||
| 		inst.setIntendedVersionId(m_version->descriptor()); | 		inst->setComponentVersion("net.minecraft", m_version->descriptor()); | ||||||
| 		inst.setName(m_instName); | 		inst->setName(m_instName); | ||||||
| 		inst.setIconKey(m_instIcon); | 		inst->setIconKey(m_instIcon); | ||||||
| 		inst.init(); | 		inst->init(); | ||||||
| 		instanceSettings->resumeSave(); | 		instanceSettings->resumeSave(); | ||||||
| 	} | 	} | ||||||
| 	emitSucceeded(); | 	emitSucceeded(); | ||||||
|   | |||||||
| @@ -1,5 +1,3 @@ | |||||||
| #include "minecraft/onesix/OneSixInstance.h" |  | ||||||
|  |  | ||||||
| #include "InstanceImportTask.h" | #include "InstanceImportTask.h" | ||||||
| #include "BaseInstance.h" | #include "BaseInstance.h" | ||||||
| #include "BaseInstanceProvider.h" | #include "BaseInstanceProvider.h" | ||||||
| @@ -12,6 +10,8 @@ | |||||||
| #include <QtConcurrentRun> | #include <QtConcurrentRun> | ||||||
|  |  | ||||||
| // FIXME: this does not belong here, it's Minecraft/Flame specific | // FIXME: this does not belong here, it's Minecraft/Flame specific | ||||||
|  | #include "minecraft/MinecraftInstance.h" | ||||||
|  | #include "minecraft/MinecraftProfile.h" | ||||||
| #include "minecraft/flame/FileResolvingTask.h" | #include "minecraft/flame/FileResolvingTask.h" | ||||||
| #include "minecraft/flame/PackManifest.h" | #include "minecraft/flame/PackManifest.h" | ||||||
| #include "Json.h" | #include "Json.h" | ||||||
| @@ -225,7 +225,7 @@ void InstanceImportTask::processFlame() | |||||||
| 	auto instanceSettings = std::make_shared<INISettingsObject>(configPath); | 	auto instanceSettings = std::make_shared<INISettingsObject>(configPath); | ||||||
| 	instanceSettings->registerSetting("InstanceType", "Legacy"); | 	instanceSettings->registerSetting("InstanceType", "Legacy"); | ||||||
| 	instanceSettings->set("InstanceType", "OneSix"); | 	instanceSettings->set("InstanceType", "OneSix"); | ||||||
| 	OneSixInstance instance(m_globalSettings, instanceSettings, m_stagingPath); | 	MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath); | ||||||
| 	auto mcVersion = pack.minecraft.version; | 	auto mcVersion = pack.minecraft.version; | ||||||
| 	// Hack to correct some 'special sauce'... | 	// Hack to correct some 'special sauce'... | ||||||
| 	if(mcVersion.endsWith('.')) | 	if(mcVersion.endsWith('.')) | ||||||
|   | |||||||
| @@ -10,18 +10,6 @@ public: | |||||||
| 		setVersionBroken(true); | 		setVersionBroken(true); | ||||||
| 	} | 	} | ||||||
| 	virtual ~NullInstance() {}; | 	virtual ~NullInstance() {}; | ||||||
| 	virtual bool setIntendedVersionId(QString) override |  | ||||||
| 	{ |  | ||||||
| 		return false; |  | ||||||
| 	} |  | ||||||
| 	virtual QString currentVersionId() const override |  | ||||||
| 	{ |  | ||||||
| 		return "Null"; |  | ||||||
| 	}; |  | ||||||
| 	virtual QString intendedVersionId() const override |  | ||||||
| 	{ |  | ||||||
| 		return "Null"; |  | ||||||
| 	}; |  | ||||||
| 	virtual void init() override | 	virtual void init() override | ||||||
| 	{ | 	{ | ||||||
| 	}; | 	}; | ||||||
| @@ -29,10 +17,6 @@ public: | |||||||
| 	{ | 	{ | ||||||
| 		return tr("Unknown instance type"); | 		return tr("Unknown instance type"); | ||||||
| 	}; | 	}; | ||||||
| 	virtual bool shouldUpdate() const override |  | ||||||
| 	{ |  | ||||||
| 		return false; |  | ||||||
| 	}; |  | ||||||
| 	virtual QSet< QString > traits() override | 	virtual QSet< QString > traits() override | ||||||
| 	{ | 	{ | ||||||
| 		return {}; | 		return {}; | ||||||
| @@ -49,17 +33,6 @@ public: | |||||||
| 	{ | 	{ | ||||||
| 		return nullptr; | 		return nullptr; | ||||||
| 	} | 	} | ||||||
| 	virtual std::shared_ptr<Task> createJarModdingTask() override |  | ||||||
| 	{ |  | ||||||
| 		return nullptr; |  | ||||||
| 	} |  | ||||||
| 	virtual void setShouldUpdate(bool) override |  | ||||||
| 	{ |  | ||||||
| 	}; |  | ||||||
| 	virtual std::shared_ptr< BaseVersionList > versionList() const override |  | ||||||
| 	{ |  | ||||||
| 		return nullptr; |  | ||||||
| 	}; |  | ||||||
| 	virtual QProcessEnvironment createEnvironment() override | 	virtual QProcessEnvironment createEnvironment() override | ||||||
| 	{ | 	{ | ||||||
| 		return QProcessEnvironment(); | 		return QProcessEnvironment(); | ||||||
|   | |||||||
| @@ -16,7 +16,7 @@ | |||||||
| #include "JsonFormat.h" | #include "JsonFormat.h" | ||||||
|  |  | ||||||
| // FIXME: remove this from here... somehow | // FIXME: remove this from here... somehow | ||||||
| #include "minecraft/onesix/OneSixVersionFormat.h" | #include "minecraft/OneSixVersionFormat.h" | ||||||
| #include "Json.h" | #include "Json.h" | ||||||
|  |  | ||||||
| #include "Index.h" | #include "Index.h" | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
| #include "TestUtil.h" | #include "TestUtil.h" | ||||||
|  |  | ||||||
| #include "minecraft/MojangVersionFormat.h" | #include "minecraft/MojangVersionFormat.h" | ||||||
| #include "minecraft/onesix/OneSixVersionFormat.h" | #include "minecraft/OneSixVersionFormat.h" | ||||||
| #include "minecraft/Library.h" | #include "minecraft/Library.h" | ||||||
| #include "net/HttpMetaCache.h" | #include "net/HttpMetaCache.h" | ||||||
| #include "FileSystem.h" | #include "FileSystem.h" | ||||||
|   | |||||||
| @@ -17,16 +17,23 @@ | |||||||
| #include "launch/steps/PreLaunchCommand.h" | #include "launch/steps/PreLaunchCommand.h" | ||||||
| #include "launch/steps/TextPrint.h" | #include "launch/steps/TextPrint.h" | ||||||
| #include "minecraft/launch/LauncherPartLaunch.h" | #include "minecraft/launch/LauncherPartLaunch.h" | ||||||
|  | #include "minecraft/launch/DirectJavaLaunch.h" | ||||||
| #include "minecraft/launch/ModMinecraftJar.h" | #include "minecraft/launch/ModMinecraftJar.h" | ||||||
| #include "minecraft/launch/ClaimAccount.h" | #include "minecraft/launch/ClaimAccount.h" | ||||||
| #include "java/launch/CheckJava.h" | #include "java/launch/CheckJava.h" | ||||||
| #include "java/JavaUtils.h" | #include "java/JavaUtils.h" | ||||||
| #include <meta/Index.h> | #include "meta/Index.h" | ||||||
| #include <meta/VersionList.h> | #include "meta/VersionList.h" | ||||||
|  |  | ||||||
| #include <icons/IIconList.h> | #include "ModList.h" | ||||||
|  | #include "WorldList.h" | ||||||
|  |  | ||||||
|  | #include "icons/IIconList.h" | ||||||
|  |  | ||||||
| #include <QCoreApplication> | #include <QCoreApplication> | ||||||
|  | #include "MinecraftProfile.h" | ||||||
|  | #include "AssetsUtils.h" | ||||||
|  | #include "MinecraftUpdate.h" | ||||||
|  |  | ||||||
| #define IBUS "@im=ibus" | #define IBUS "@im=ibus" | ||||||
|  |  | ||||||
| @@ -56,6 +63,12 @@ private: | |||||||
| MinecraftInstance::MinecraftInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir) | MinecraftInstance::MinecraftInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir) | ||||||
| 	: BaseInstance(globalSettings, settings, rootDir) | 	: BaseInstance(globalSettings, settings, rootDir) | ||||||
| { | { | ||||||
|  | 	// FIXME: remove these | ||||||
|  | 	m_settings->registerSetting({"IntendedVersion", "MinecraftVersion"}, ""); | ||||||
|  | 	m_settings->registerSetting("LWJGLVersion", "2.9.1"); | ||||||
|  | 	m_settings->registerSetting("ForgeVersion", ""); | ||||||
|  | 	m_settings->registerSetting("LiteloaderVersion", ""); | ||||||
|  |  | ||||||
| 	// Java Settings | 	// Java Settings | ||||||
| 	auto javaOverride = m_settings->registerSetting("OverrideJava", false); | 	auto javaOverride = m_settings->registerSetting("OverrideJava", false); | ||||||
| 	auto locationOverride = m_settings->registerSetting("OverrideJavaLocation", false); | 	auto locationOverride = m_settings->registerSetting("OverrideJavaLocation", false); | ||||||
| @@ -90,6 +103,70 @@ MinecraftInstance::MinecraftInstance(SettingsObjectPtr globalSettings, SettingsO | |||||||
| 	m_settings->registerOverride(globalSettings->getSetting("MCLaunchMethod"), launchMethodOverride); | 	m_settings->registerOverride(globalSettings->getSetting("MCLaunchMethod"), launchMethodOverride); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void MinecraftInstance::init() | ||||||
|  | { | ||||||
|  | 	createProfile(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString MinecraftInstance::typeName() const | ||||||
|  | { | ||||||
|  | 	return "Minecraft"; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bool MinecraftInstance::reload() | ||||||
|  | { | ||||||
|  | 	if (BaseInstance::reload()) | ||||||
|  | 	{ | ||||||
|  | 		try | ||||||
|  | 		{ | ||||||
|  | 			reloadProfile(); | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  | 		catch (...) | ||||||
|  | 		{ | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MinecraftInstance::createProfile() | ||||||
|  | { | ||||||
|  | 	m_profile.reset(new MinecraftProfile(this)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MinecraftInstance::reloadProfile() | ||||||
|  | { | ||||||
|  | 	m_profile->reload(); | ||||||
|  | 	setVersionBroken(m_profile->getProblemSeverity() == ProblemSeverity::Error); | ||||||
|  | 	emit versionReloaded(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MinecraftInstance::clearProfile() | ||||||
|  | { | ||||||
|  | 	m_profile->clear(); | ||||||
|  | 	emit versionReloaded(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::shared_ptr<MinecraftProfile> MinecraftInstance::getMinecraftProfile() const | ||||||
|  | { | ||||||
|  | 	return m_profile; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QSet<QString> MinecraftInstance::traits() | ||||||
|  | { | ||||||
|  | 	auto version = getMinecraftProfile(); | ||||||
|  | 	if (!version) | ||||||
|  | 	{ | ||||||
|  | 		return {"version-incomplete"}; | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		return version->getTraits(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| QString MinecraftInstance::minecraftRoot() const | QString MinecraftInstance::minecraftRoot() const | ||||||
| { | { | ||||||
| 	QFileInfo mcDir(FS::PathCombine(instanceRoot(), "minecraft")); | 	QFileInfo mcDir(FS::PathCombine(instanceRoot(), "minecraft")); | ||||||
| @@ -106,9 +183,107 @@ QString MinecraftInstance::binRoot() const | |||||||
| 	return FS::PathCombine(minecraftRoot(), "bin"); | 	return FS::PathCombine(minecraftRoot(), "bin"); | ||||||
| } | } | ||||||
|  |  | ||||||
| std::shared_ptr< BaseVersionList > MinecraftInstance::versionList() const | QString MinecraftInstance::getNativePath() const | ||||||
| { | { | ||||||
| 	return ENV.metadataIndex()->get("net.minecraft"); | 	QDir natives_dir(FS::PathCombine(instanceRoot(), "natives/")); | ||||||
|  | 	return natives_dir.absolutePath(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString MinecraftInstance::getLocalLibraryPath() const | ||||||
|  | { | ||||||
|  | 	QDir libraries_dir(FS::PathCombine(instanceRoot(), "libraries/")); | ||||||
|  | 	return libraries_dir.absolutePath(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString MinecraftInstance::loaderModsDir() const | ||||||
|  | { | ||||||
|  | 	return FS::PathCombine(minecraftRoot(), "mods"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString MinecraftInstance::coreModsDir() const | ||||||
|  | { | ||||||
|  | 	return FS::PathCombine(minecraftRoot(), "coremods"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString MinecraftInstance::resourcePacksDir() const | ||||||
|  | { | ||||||
|  | 	return FS::PathCombine(minecraftRoot(), "resourcepacks"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString MinecraftInstance::texturePacksDir() const | ||||||
|  | { | ||||||
|  | 	return FS::PathCombine(minecraftRoot(), "texturepacks"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString MinecraftInstance::instanceConfigFolder() const | ||||||
|  | { | ||||||
|  | 	return FS::PathCombine(minecraftRoot(), "config"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString MinecraftInstance::jarModsDir() const | ||||||
|  | { | ||||||
|  | 	return FS::PathCombine(instanceRoot(), "jarmods"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString MinecraftInstance::libDir() const | ||||||
|  | { | ||||||
|  | 	return FS::PathCombine(minecraftRoot(), "lib"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString MinecraftInstance::worldDir() const | ||||||
|  | { | ||||||
|  | 	return FS::PathCombine(minecraftRoot(), "saves"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QDir MinecraftInstance::librariesPath() const | ||||||
|  | { | ||||||
|  | 	return QDir::current().absoluteFilePath("libraries"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QDir MinecraftInstance::jarmodsPath() const | ||||||
|  | { | ||||||
|  | 	return QDir(jarModsDir()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QDir MinecraftInstance::versionsPath() const | ||||||
|  | { | ||||||
|  | 	return QDir::current().absoluteFilePath("versions"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QStringList MinecraftInstance::getClassPath() const | ||||||
|  | { | ||||||
|  | 	QStringList jars, nativeJars; | ||||||
|  | 	auto javaArchitecture = settings()->get("JavaArchitecture").toString(); | ||||||
|  | 	m_profile->getLibraryFiles(javaArchitecture, jars, nativeJars, getLocalLibraryPath(), binRoot()); | ||||||
|  | 	return jars; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString MinecraftInstance::getMainClass() const | ||||||
|  | { | ||||||
|  | 	return m_profile->getMainClass(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QStringList MinecraftInstance::getNativeJars() const | ||||||
|  | { | ||||||
|  | 	QStringList jars, nativeJars; | ||||||
|  | 	auto javaArchitecture = settings()->get("JavaArchitecture").toString(); | ||||||
|  | 	m_profile->getLibraryFiles(javaArchitecture, jars, nativeJars, getLocalLibraryPath(), binRoot()); | ||||||
|  | 	return nativeJars; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QStringList MinecraftInstance::extraArguments() const | ||||||
|  | { | ||||||
|  | 	auto list = BaseInstance::extraArguments(); | ||||||
|  | 	auto version = getMinecraftProfile(); | ||||||
|  | 	if (!version) | ||||||
|  | 		return list; | ||||||
|  | 	auto jarMods = getJarMods(); | ||||||
|  | 	if (!jarMods.isEmpty()) | ||||||
|  | 	{ | ||||||
|  | 		list.append({"-Dfml.ignoreInvalidMinecraftCertificates=true", | ||||||
|  | 					 "-Dfml.ignorePatchDiscrepancies=true"}); | ||||||
|  | 	} | ||||||
|  | 	return list; | ||||||
| } | } | ||||||
|  |  | ||||||
| QStringList MinecraftInstance::javaArguments() const | QStringList MinecraftInstance::javaArguments() const | ||||||
| @@ -193,6 +368,270 @@ QProcessEnvironment MinecraftInstance::createEnvironment() | |||||||
| 	return env; | 	return env; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static QString replaceTokensIn(QString text, QMap<QString, QString> with) | ||||||
|  | { | ||||||
|  | 	QString result; | ||||||
|  | 	QRegExp token_regexp("\\$\\{(.+)\\}"); | ||||||
|  | 	token_regexp.setMinimal(true); | ||||||
|  | 	QStringList list; | ||||||
|  | 	int tail = 0; | ||||||
|  | 	int head = 0; | ||||||
|  | 	while ((head = token_regexp.indexIn(text, head)) != -1) | ||||||
|  | 	{ | ||||||
|  | 		result.append(text.mid(tail, head - tail)); | ||||||
|  | 		QString key = token_regexp.cap(1); | ||||||
|  | 		auto iter = with.find(key); | ||||||
|  | 		if (iter != with.end()) | ||||||
|  | 		{ | ||||||
|  | 			result.append(*iter); | ||||||
|  | 		} | ||||||
|  | 		head += token_regexp.matchedLength(); | ||||||
|  | 		tail = head; | ||||||
|  | 	} | ||||||
|  | 	result.append(text.mid(tail)); | ||||||
|  | 	return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QStringList MinecraftInstance::processMinecraftArgs(AuthSessionPtr session) const | ||||||
|  | { | ||||||
|  | 	QString args_pattern = m_profile->getMinecraftArguments(); | ||||||
|  | 	for (auto tweaker : m_profile->getTweakers()) | ||||||
|  | 	{ | ||||||
|  | 		args_pattern += " --tweakClass " + tweaker; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	QMap<QString, QString> token_mapping; | ||||||
|  | 	// yggdrasil! | ||||||
|  | 	if(session) | ||||||
|  | 	{ | ||||||
|  | 		token_mapping["auth_username"] = session->username; | ||||||
|  | 		token_mapping["auth_session"] = session->session; | ||||||
|  | 		token_mapping["auth_access_token"] = session->access_token; | ||||||
|  | 		token_mapping["auth_player_name"] = session->player_name; | ||||||
|  | 		token_mapping["auth_uuid"] = session->uuid; | ||||||
|  | 		token_mapping["user_properties"] = session->serializeUserProperties(); | ||||||
|  | 		token_mapping["user_type"] = session->user_type; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// blatant self-promotion. | ||||||
|  | 	token_mapping["profile_name"] = token_mapping["version_name"] = "MultiMC5"; | ||||||
|  | 	if(m_profile->isVanilla()) | ||||||
|  | 	{ | ||||||
|  | 		token_mapping["version_type"] = m_profile->getMinecraftVersionType(); | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		token_mapping["version_type"] = "custom"; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	QString absRootDir = QDir(minecraftRoot()).absolutePath(); | ||||||
|  | 	token_mapping["game_directory"] = absRootDir; | ||||||
|  | 	QString absAssetsDir = QDir("assets/").absolutePath(); | ||||||
|  | 	auto assets = m_profile->getMinecraftAssets(); | ||||||
|  | 	// FIXME: this is wrong and should be run as an async task | ||||||
|  | 	token_mapping["game_assets"] = AssetsUtils::reconstructAssets(assets->id).absolutePath(); | ||||||
|  |  | ||||||
|  | 	// 1.7.3+ assets tokens | ||||||
|  | 	token_mapping["assets_root"] = absAssetsDir; | ||||||
|  | 	token_mapping["assets_index_name"] = assets->id; | ||||||
|  |  | ||||||
|  | 	QStringList parts = args_pattern.split(' ', QString::SkipEmptyParts); | ||||||
|  | 	for (int i = 0; i < parts.length(); i++) | ||||||
|  | 	{ | ||||||
|  | 		parts[i] = replaceTokensIn(parts[i], token_mapping); | ||||||
|  | 	} | ||||||
|  | 	return parts; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString MinecraftInstance::createLaunchScript(AuthSessionPtr session) | ||||||
|  | { | ||||||
|  | 	QString launchScript; | ||||||
|  |  | ||||||
|  | 	if (!m_profile) | ||||||
|  | 		return nullptr; | ||||||
|  |  | ||||||
|  | 	auto mainClass = getMainClass(); | ||||||
|  | 	if (!mainClass.isEmpty()) | ||||||
|  | 	{ | ||||||
|  | 		launchScript += "mainClass " + mainClass + "\n"; | ||||||
|  | 	} | ||||||
|  | 	auto appletClass = m_profile->getAppletClass(); | ||||||
|  | 	if (!appletClass.isEmpty()) | ||||||
|  | 	{ | ||||||
|  | 		launchScript += "appletClass " + appletClass + "\n"; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// generic minecraft params | ||||||
|  | 	for (auto param : processMinecraftArgs(session)) | ||||||
|  | 	{ | ||||||
|  | 		launchScript += "param " + param + "\n"; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// window size, title and state, legacy | ||||||
|  | 	{ | ||||||
|  | 		QString windowParams; | ||||||
|  | 		if (settings()->get("LaunchMaximized").toBool()) | ||||||
|  | 			windowParams = "max"; | ||||||
|  | 		else | ||||||
|  | 			windowParams = QString("%1x%2") | ||||||
|  | 							   .arg(settings()->get("MinecraftWinWidth").toInt()) | ||||||
|  | 							   .arg(settings()->get("MinecraftWinHeight").toInt()); | ||||||
|  | 		launchScript += "windowTitle " + windowTitle() + "\n"; | ||||||
|  | 		launchScript += "windowParams " + windowParams + "\n"; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// legacy auth | ||||||
|  | 	if(session) | ||||||
|  | 	{ | ||||||
|  | 		launchScript += "userName " + session->player_name + "\n"; | ||||||
|  | 		launchScript += "sessionId " + session->session + "\n"; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// libraries and class path. | ||||||
|  | 	{ | ||||||
|  | 		QStringList jars, nativeJars; | ||||||
|  | 		auto javaArchitecture = settings()->get("JavaArchitecture").toString(); | ||||||
|  | 		m_profile->getLibraryFiles(javaArchitecture, jars, nativeJars, getLocalLibraryPath(), binRoot()); | ||||||
|  | 		for(auto file: jars) | ||||||
|  | 		{ | ||||||
|  | 			launchScript += "cp " + file + "\n"; | ||||||
|  | 		} | ||||||
|  | 		for(auto file: nativeJars) | ||||||
|  | 		{ | ||||||
|  | 			launchScript += "ext " + file + "\n"; | ||||||
|  | 		} | ||||||
|  | 		launchScript += "natives " + getNativePath() + "\n"; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for (auto trait : m_profile->getTraits()) | ||||||
|  | 	{ | ||||||
|  | 		launchScript += "traits " + trait + "\n"; | ||||||
|  | 	} | ||||||
|  | 	launchScript += "launcher onesix\n"; | ||||||
|  | 	return launchScript; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session) | ||||||
|  | { | ||||||
|  | 	QStringList out; | ||||||
|  | 	out << "Main Class:" << "  " + getMainClass() << ""; | ||||||
|  | 	out << "Native path:" << "  " + getNativePath() << ""; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	auto alltraits = traits(); | ||||||
|  | 	if(alltraits.size()) | ||||||
|  | 	{ | ||||||
|  | 		out << "Traits:"; | ||||||
|  | 		for (auto trait : alltraits) | ||||||
|  | 		{ | ||||||
|  | 			out << "traits " + trait; | ||||||
|  | 		} | ||||||
|  | 		out << ""; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// libraries and class path. | ||||||
|  | 	{ | ||||||
|  | 		out << "Libraries:"; | ||||||
|  | 		QStringList jars, nativeJars; | ||||||
|  | 		auto javaArchitecture = settings()->get("JavaArchitecture").toString(); | ||||||
|  | 		m_profile->getLibraryFiles(javaArchitecture, jars, nativeJars, getLocalLibraryPath(), binRoot()); | ||||||
|  | 		auto printLibFile = [&](const QString & path) | ||||||
|  | 		{ | ||||||
|  | 			QFileInfo info(path); | ||||||
|  | 			if(info.exists()) | ||||||
|  | 			{ | ||||||
|  | 				out << "  " + path; | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				out << "  " + path + " (missing)"; | ||||||
|  | 			} | ||||||
|  | 		}; | ||||||
|  | 		for(auto file: jars) | ||||||
|  | 		{ | ||||||
|  | 			printLibFile(file); | ||||||
|  | 		} | ||||||
|  | 		out << ""; | ||||||
|  | 		out << "Native libraries:"; | ||||||
|  | 		for(auto file: nativeJars) | ||||||
|  | 		{ | ||||||
|  | 			printLibFile(file); | ||||||
|  | 		} | ||||||
|  | 		out << ""; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if(loaderModList()->size()) | ||||||
|  | 	{ | ||||||
|  | 		out << "Mods:"; | ||||||
|  | 		for(auto & mod: loaderModList()->allMods()) | ||||||
|  | 		{ | ||||||
|  | 			if(!mod.enabled()) | ||||||
|  | 				continue; | ||||||
|  | 			if(mod.type() == Mod::MOD_FOLDER) | ||||||
|  | 				continue; | ||||||
|  | 			// TODO: proper implementation would need to descend into folders. | ||||||
|  |  | ||||||
|  | 			out << "  " + mod.filename().completeBaseName(); | ||||||
|  | 		} | ||||||
|  | 		out << ""; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if(coreModList()->size()) | ||||||
|  | 	{ | ||||||
|  | 		out << "Core Mods:"; | ||||||
|  | 		for(auto & coremod: coreModList()->allMods()) | ||||||
|  | 		{ | ||||||
|  | 			if(!coremod.enabled()) | ||||||
|  | 				continue; | ||||||
|  | 			if(coremod.type() == Mod::MOD_FOLDER) | ||||||
|  | 				continue; | ||||||
|  | 			// TODO: proper implementation would need to descend into folders. | ||||||
|  |  | ||||||
|  | 			out << "  " + coremod.filename().completeBaseName(); | ||||||
|  | 		} | ||||||
|  | 		out << ""; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	auto & jarMods = m_profile->getJarMods(); | ||||||
|  | 	if(jarMods.size()) | ||||||
|  | 	{ | ||||||
|  | 		out << "Jar Mods:"; | ||||||
|  | 		for(auto & jarmod: jarMods) | ||||||
|  | 		{ | ||||||
|  | 			auto displayname = jarmod->displayName(currentSystem); | ||||||
|  | 			auto realname = jarmod->filename(currentSystem); | ||||||
|  | 			if(displayname != realname) | ||||||
|  | 			{ | ||||||
|  | 				out << "  " + displayname + " (" + realname + ")"; | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				out << "  " + realname; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		out << ""; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	auto params = processMinecraftArgs(nullptr); | ||||||
|  | 	out << "Params:"; | ||||||
|  | 	out << "  " + params.join(' '); | ||||||
|  | 	out << ""; | ||||||
|  |  | ||||||
|  | 	QString windowParams; | ||||||
|  | 	if (settings()->get("LaunchMaximized").toBool()) | ||||||
|  | 	{ | ||||||
|  | 		out << "Window size: max (if available)"; | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		auto width = settings()->get("MinecraftWinWidth").toInt(); | ||||||
|  | 		auto height = settings()->get("MinecraftWinHeight").toInt(); | ||||||
|  | 		out << "Window size: " + QString::number(width) + " x " + QString::number(height); | ||||||
|  | 	} | ||||||
|  | 	out << ""; | ||||||
|  | 	return out; | ||||||
|  | } | ||||||
|  |  | ||||||
| QMap<QString, QString> MinecraftInstance::createCensorFilterFromSession(AuthSessionPtr session) | QMap<QString, QString> MinecraftInstance::createCensorFilterFromSession(AuthSessionPtr session) | ||||||
| { | { | ||||||
| 	if(!session) | 	if(!session) | ||||||
| @@ -321,7 +760,7 @@ QString MinecraftInstance::getStatusbarDescription() | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	QString description; | 	QString description; | ||||||
| 	description.append(tr("Minecraft %1 (%2)").arg(intendedVersionId()).arg(typeName())); | 	description.append(tr("Minecraft %1 (%2)").arg(getComponentVersion("net.minecraft")).arg(typeName())); | ||||||
| 	if(totalTimePlayed() > 0) | 	if(totalTimePlayed() > 0) | ||||||
| 	{ | 	{ | ||||||
| 		description.append(tr(", played for %1").arg(prettifyTimeDuration(totalTimePlayed()))); | 		description.append(tr(", played for %1").arg(prettifyTimeDuration(totalTimePlayed()))); | ||||||
| @@ -333,6 +772,11 @@ QString MinecraftInstance::getStatusbarDescription() | |||||||
| 	return description; | 	return description; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | shared_qobject_ptr<Task> MinecraftInstance::createUpdateTask() | ||||||
|  | { | ||||||
|  | 	return shared_qobject_ptr<Task>(new OneSixUpdate(this)); | ||||||
|  | } | ||||||
|  |  | ||||||
| std::shared_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPtr session) | std::shared_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPtr session) | ||||||
| { | { | ||||||
| 	auto process = LaunchTask::create(std::dynamic_pointer_cast<MinecraftInstance>(getSharedPtr())); | 	auto process = LaunchTask::create(std::dynamic_pointer_cast<MinecraftInstance>(getSharedPtr())); | ||||||
| @@ -352,7 +796,7 @@ std::shared_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPtr s | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// check launch method | 	// check launch method | ||||||
| 	QStringList validMethods = validLaunchMethods(); | 	QStringList validMethods = {"LauncherPart", "DirectJava"}; | ||||||
| 	QString method = launchMethod(); | 	QString method = launchMethod(); | ||||||
| 	if(!validMethods.contains(method)) | 	if(!validMethods.contains(method)) | ||||||
| 	{ | 	{ | ||||||
| @@ -402,8 +846,21 @@ std::shared_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPtr s | |||||||
|  |  | ||||||
| 	{ | 	{ | ||||||
| 		// actually launch the game | 		// actually launch the game | ||||||
| 		auto step = createMainLaunchStep(pptr, session); | 		auto method = launchMethod(); | ||||||
| 		process->appendStep(step); | 		if(method == "LauncherPart") | ||||||
|  | 		{ | ||||||
|  | 			auto step = std::make_shared<LauncherPartLaunch>(pptr); | ||||||
|  | 			step->setWorkingDirectory(minecraftRoot()); | ||||||
|  | 			step->setAuthSession(session); | ||||||
|  | 			process->appendStep(step); | ||||||
|  | 		} | ||||||
|  | 		else if (method == "DirectJava") | ||||||
|  | 		{ | ||||||
|  | 			auto step = std::make_shared<DirectJavaLaunch>(pptr); | ||||||
|  | 			step->setWorkingDirectory(minecraftRoot()); | ||||||
|  | 			step->setAuthSession(session); | ||||||
|  | 			process->appendStep(step); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// run post-exit command if that's needed | 	// run post-exit command if that's needed | ||||||
| @@ -432,5 +889,114 @@ JavaVersion MinecraftInstance::getJavaVersion() const | |||||||
| 	return JavaVersion(settings()->get("JavaVersion").toString()); | 	return JavaVersion(settings()->get("JavaVersion").toString()); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | bool MinecraftInstance::setComponentVersion(const QString& uid, const QString& version) | ||||||
|  | { | ||||||
|  | 	if(uid == "net.minecraft") | ||||||
|  | 	{ | ||||||
|  | 		settings()->set("IntendedVersion", version); | ||||||
|  | 	} | ||||||
|  | 	else if (uid == "org.lwjgl") | ||||||
|  | 	{ | ||||||
|  | 		settings()->set("LWJGLVersion", version); | ||||||
|  | 	} | ||||||
|  | 	else if (uid == "net.minecraftforge") | ||||||
|  | 	{ | ||||||
|  | 		settings()->set("ForgeVersion", version); | ||||||
|  | 	} | ||||||
|  | 	else if (uid == "com.mumfrey.liteloader") | ||||||
|  | 	{ | ||||||
|  | 		settings()->set("LiteloaderVersion", version); | ||||||
|  | 	} | ||||||
|  | 	if(getMinecraftProfile()) | ||||||
|  | 	{ | ||||||
|  | 		clearProfile(); | ||||||
|  | 	} | ||||||
|  | 	emit propertiesChanged(this); | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QString MinecraftInstance::getComponentVersion(const QString& uid) const | ||||||
|  | { | ||||||
|  | 	if(uid == "net.minecraft") | ||||||
|  | 	{ | ||||||
|  | 		return settings()->get("IntendedVersion").toString(); | ||||||
|  | 	} | ||||||
|  | 	else if(uid == "org.lwjgl") | ||||||
|  | 	{ | ||||||
|  | 		return settings()->get("LWJGLVersion").toString(); | ||||||
|  | 	} | ||||||
|  | 	else if(uid == "net.minecraftforge") | ||||||
|  | 	{ | ||||||
|  | 		return settings()->get("ForgeVersion").toString(); | ||||||
|  | 	} | ||||||
|  | 	else if(uid == "com.mumfrey.liteloader") | ||||||
|  | 	{ | ||||||
|  | 		return settings()->get("LiteloaderVersion").toString(); | ||||||
|  | 	} | ||||||
|  | 	return QString(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::shared_ptr<ModList> MinecraftInstance::loaderModList() const | ||||||
|  | { | ||||||
|  | 	if (!m_loader_mod_list) | ||||||
|  | 	{ | ||||||
|  | 		m_loader_mod_list.reset(new ModList(loaderModsDir())); | ||||||
|  | 	} | ||||||
|  | 	m_loader_mod_list->update(); | ||||||
|  | 	return m_loader_mod_list; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::shared_ptr<ModList> MinecraftInstance::coreModList() const | ||||||
|  | { | ||||||
|  | 	if (!m_core_mod_list) | ||||||
|  | 	{ | ||||||
|  | 		m_core_mod_list.reset(new ModList(coreModsDir())); | ||||||
|  | 	} | ||||||
|  | 	m_core_mod_list->update(); | ||||||
|  | 	return m_core_mod_list; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::shared_ptr<ModList> MinecraftInstance::resourcePackList() const | ||||||
|  | { | ||||||
|  | 	if (!m_resource_pack_list) | ||||||
|  | 	{ | ||||||
|  | 		m_resource_pack_list.reset(new ModList(resourcePacksDir())); | ||||||
|  | 	} | ||||||
|  | 	m_resource_pack_list->update(); | ||||||
|  | 	return m_resource_pack_list; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::shared_ptr<ModList> MinecraftInstance::texturePackList() const | ||||||
|  | { | ||||||
|  | 	if (!m_texture_pack_list) | ||||||
|  | 	{ | ||||||
|  | 		m_texture_pack_list.reset(new ModList(texturePacksDir())); | ||||||
|  | 	} | ||||||
|  | 	m_texture_pack_list->update(); | ||||||
|  | 	return m_texture_pack_list; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::shared_ptr<WorldList> MinecraftInstance::worldList() const | ||||||
|  | { | ||||||
|  | 	if (!m_world_list) | ||||||
|  | 	{ | ||||||
|  | 		m_world_list.reset(new WorldList(worldDir())); | ||||||
|  | 	} | ||||||
|  | 	return m_world_list; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | QList< Mod > MinecraftInstance::getJarMods() const | ||||||
|  | { | ||||||
|  | 	QList<Mod> mods; | ||||||
|  | 	for (auto jarmod : m_profile->getJarMods()) | ||||||
|  | 	{ | ||||||
|  | 		QStringList jar, temp1, temp2, temp3; | ||||||
|  | 		jarmod->getApplicableFiles(currentSystem, jar, temp1, temp2, temp3, jarmodsPath().absolutePath()); | ||||||
|  | 		// QString filePath = jarmodsPath().absoluteFilePath(jarmod->filename(currentSystem)); | ||||||
|  | 		mods.push_back(Mod(QFileInfo(jar[0]))); | ||||||
|  | 	} | ||||||
|  | 	return mods; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "MinecraftInstance.moc" | #include "MinecraftInstance.moc" | ||||||
|   | |||||||
| @@ -3,88 +3,117 @@ | |||||||
| #include <java/JavaVersion.h> | #include <java/JavaVersion.h> | ||||||
| #include "minecraft/Mod.h" | #include "minecraft/Mod.h" | ||||||
| #include <QProcess> | #include <QProcess> | ||||||
|  | #include <QDir> | ||||||
| #include "multimc_logic_export.h" | #include "multimc_logic_export.h" | ||||||
|  |  | ||||||
| class ModList; | class ModList; | ||||||
| class WorldList; | class WorldList; | ||||||
| class LaunchStep; | class LaunchStep; | ||||||
|  | class MinecraftProfile; | ||||||
|  |  | ||||||
| class MULTIMC_LOGIC_EXPORT MinecraftInstance: public BaseInstance | class MULTIMC_LOGIC_EXPORT MinecraftInstance: public BaseInstance | ||||||
| { | { | ||||||
|  | 	Q_OBJECT | ||||||
| public: | public: | ||||||
| 	MinecraftInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir); | 	MinecraftInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir); | ||||||
| 	virtual ~MinecraftInstance() {}; | 	virtual ~MinecraftInstance() {}; | ||||||
|  | 	virtual void init() override; | ||||||
|  |  | ||||||
| 	/// Path to the instance's minecraft directory. | 	QString typeName() const override; | ||||||
| 	QString minecraftRoot() const; | 	QSet<QString> traits() override; | ||||||
|  | 	bool canExport() const override | ||||||
|  | 	{ | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	////// Directories and files ////// | ||||||
|  | 	QString jarModsDir() const; | ||||||
|  | 	QString resourcePacksDir() const; | ||||||
|  | 	QString texturePacksDir() const; | ||||||
|  | 	QString loaderModsDir() const; | ||||||
|  | 	QString coreModsDir() const; | ||||||
|  | 	QString libDir() const; | ||||||
|  | 	QString worldDir() const; | ||||||
|  | 	QDir jarmodsPath() const; | ||||||
|  | 	QDir librariesPath() const; | ||||||
|  | 	QDir versionsPath() const; | ||||||
|  | 	QString instanceConfigFolder() const override; | ||||||
|  | 	QString minecraftRoot() const; // Path to the instance's minecraft directory. | ||||||
|  | 	QString binRoot() const; // Path to the instance's minecraft bin directory. | ||||||
|  | 	QString getNativePath() const; // where to put the natives during/before launch | ||||||
|  | 	QString getLocalLibraryPath() const; // where the instance-local libraries should be | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	//////  Profile management ////// | ||||||
|  | 	void createProfile(); | ||||||
|  | 	std::shared_ptr<MinecraftProfile> getMinecraftProfile() const; | ||||||
|  | 	void reloadProfile(); | ||||||
|  | 	void clearProfile(); | ||||||
|  | 	bool reload() override; | ||||||
|  |  | ||||||
| 	/// Path to the instance's minecraft/bin directory. |  | ||||||
| 	QString binRoot() const; |  | ||||||
|  |  | ||||||
| 	//////  Mod Lists  ////// | 	//////  Mod Lists  ////// | ||||||
| 	virtual std::shared_ptr<ModList> resourcePackList() const | 	std::shared_ptr<ModList> loaderModList() const; | ||||||
| 	{ | 	std::shared_ptr<ModList> coreModList() const; | ||||||
| 		return nullptr; | 	std::shared_ptr<ModList> resourcePackList() const; | ||||||
| 	} | 	std::shared_ptr<ModList> texturePackList() const; | ||||||
| 	virtual std::shared_ptr<ModList> texturePackList() const | 	std::shared_ptr<WorldList> worldList() const; | ||||||
| 	{ |  | ||||||
| 		return nullptr; |  | ||||||
| 	} |  | ||||||
| 	virtual std::shared_ptr<WorldList> worldList() const |  | ||||||
| 	{ |  | ||||||
| 		return nullptr; |  | ||||||
| 	} |  | ||||||
| 	/// get all jar mods applicable to this instance's jar |  | ||||||
| 	virtual QList<Mod> getJarMods() const |  | ||||||
| 	{ |  | ||||||
| 		return QList<Mod>(); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	virtual std::shared_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account) override; |  | ||||||
| 	virtual QString createLaunchScript(AuthSessionPtr session) = 0; |  | ||||||
|  |  | ||||||
| 	//FIXME: nuke? |  | ||||||
| 	virtual std::shared_ptr<BaseVersionList> versionList() const override; |  | ||||||
|  |  | ||||||
|  | 	//////  Launch stuff ////// | ||||||
|  | 	shared_qobject_ptr<Task> createUpdateTask() override; | ||||||
|  | 	std::shared_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account) override; | ||||||
|  | 	QStringList extraArguments() const override; | ||||||
|  | 	QStringList verboseDescription(AuthSessionPtr session) override; | ||||||
|  | 	QList<Mod> getJarMods() const; | ||||||
|  | 	QString createLaunchScript(AuthSessionPtr session); | ||||||
| 	/// get arguments passed to java | 	/// get arguments passed to java | ||||||
| 	QStringList javaArguments() const; | 	QStringList javaArguments() const; | ||||||
|  |  | ||||||
| 	/// get variables for launch command variable substitution/environment | 	/// get variables for launch command variable substitution/environment | ||||||
| 	virtual QMap<QString, QString> getVariables() const override; | 	QMap<QString, QString> getVariables() const override; | ||||||
|  |  | ||||||
| 	/// create an environment for launching processes | 	/// create an environment for launching processes | ||||||
| 	virtual QProcessEnvironment createEnvironment() override; | 	QProcessEnvironment createEnvironment() override; | ||||||
|  |  | ||||||
| 	/// guess log level from a line of minecraft log | 	/// guess log level from a line of minecraft log | ||||||
| 	virtual MessageLevel::Enum guessLevel(const QString &line, MessageLevel::Enum level) override; | 	MessageLevel::Enum guessLevel(const QString &line, MessageLevel::Enum level) override; | ||||||
|  |  | ||||||
| 	virtual IPathMatcher::Ptr getLogFileMatcher() override; | 	IPathMatcher::Ptr getLogFileMatcher() override; | ||||||
|  |  | ||||||
| 	virtual QString getLogFileRoot() override; | 	QString getLogFileRoot() override; | ||||||
|  |  | ||||||
| 	virtual QString getStatusbarDescription() override; | 	QString getStatusbarDescription() override; | ||||||
|  |  | ||||||
| 	virtual QStringList getClassPath() const = 0; | 	virtual QStringList getClassPath() const; | ||||||
| 	virtual QStringList getNativeJars() const = 0; | 	virtual QStringList getNativeJars() const; | ||||||
|  | 	virtual QString getMainClass() const; | ||||||
|  |  | ||||||
| 	virtual QString getMainClass() const = 0; | 	virtual QStringList processMinecraftArgs(AuthSessionPtr account) const; | ||||||
|  |  | ||||||
| 	virtual QString getNativePath() const = 0; |  | ||||||
|  |  | ||||||
| 	virtual QString getLocalLibraryPath() const = 0; |  | ||||||
|  |  | ||||||
| 	virtual QStringList processMinecraftArgs(AuthSessionPtr account) const = 0; |  | ||||||
|  |  | ||||||
| 	virtual JavaVersion getJavaVersion() const; | 	virtual JavaVersion getJavaVersion() const; | ||||||
|  |  | ||||||
|  | 	QString getComponentVersion(const QString &uid) const; | ||||||
|  | 	bool setComponentVersion(const QString &uid, const QString &version); | ||||||
|  |  | ||||||
|  | signals: | ||||||
|  | 	void versionReloaded(); | ||||||
|  |  | ||||||
| protected: | protected: | ||||||
| 	QMap<QString, QString> createCensorFilterFromSession(AuthSessionPtr session); | 	QMap<QString, QString> createCensorFilterFromSession(AuthSessionPtr session); | ||||||
| 	virtual QStringList validLaunchMethods() = 0; | 	QStringList validLaunchMethods(); | ||||||
| 	virtual QString launchMethod(); | 	QString launchMethod(); | ||||||
| 	virtual std::shared_ptr<LaunchStep> createMainLaunchStep(LaunchTask *parent, AuthSessionPtr session) = 0; |  | ||||||
| private: | private: | ||||||
| 	QString prettifyTimeDuration(int64_t duration); | 	QString prettifyTimeDuration(int64_t duration); | ||||||
|  |  | ||||||
|  | protected: // data | ||||||
|  | 	std::shared_ptr<MinecraftProfile> m_profile; | ||||||
|  | 	mutable std::shared_ptr<ModList> m_loader_mod_list; | ||||||
|  | 	mutable std::shared_ptr<ModList> m_core_mod_list; | ||||||
|  | 	mutable std::shared_ptr<ModList> m_resource_pack_list; | ||||||
|  | 	mutable std::shared_ptr<ModList> m_texture_pack_list; | ||||||
|  | 	mutable std::shared_ptr<WorldList> m_world_list; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| typedef std::shared_ptr<MinecraftInstance> MinecraftInstancePtr; | typedef std::shared_ptr<MinecraftInstance> MinecraftInstancePtr; | ||||||
|   | |||||||
| @@ -22,47 +22,30 @@ | |||||||
| #include <QDebug> | #include <QDebug> | ||||||
|  |  | ||||||
| #include "minecraft/MinecraftProfile.h" | #include "minecraft/MinecraftProfile.h" | ||||||
| #include "ProfileUtils.h" |  | ||||||
| #include "ProfileStrategy.h" |  | ||||||
| #include "Exception.h" | #include "Exception.h" | ||||||
|  | #include <minecraft/OneSixVersionFormat.h> | ||||||
|  | #include <FileSystem.h> | ||||||
|  | #include <QSaveFile> | ||||||
|  | #include <Env.h> | ||||||
|  | #include <meta/Index.h> | ||||||
|  | #include <minecraft/MinecraftInstance.h> | ||||||
|  | #include <QUuid> | ||||||
|  |  | ||||||
| MinecraftProfile::MinecraftProfile(ProfileStrategy *strategy) | MinecraftProfile::MinecraftProfile(MinecraftInstance * instance) | ||||||
| 	: QAbstractListModel() | 	: QAbstractListModel() | ||||||
| { | { | ||||||
| 	setStrategy(strategy); | 	m_instance = instance; | ||||||
| 	clear(); | 	clear(); | ||||||
| } | } | ||||||
|  |  | ||||||
| MinecraftProfile::~MinecraftProfile() | MinecraftProfile::~MinecraftProfile() | ||||||
| { | { | ||||||
| 	if(m_strategy) |  | ||||||
| 	{ |  | ||||||
| 		delete m_strategy; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void MinecraftProfile::setStrategy(ProfileStrategy* strategy) |  | ||||||
| { |  | ||||||
| 	Q_ASSERT(strategy != nullptr); |  | ||||||
|  |  | ||||||
| 	if(m_strategy != nullptr) |  | ||||||
| 	{ |  | ||||||
| 		delete m_strategy; |  | ||||||
| 		m_strategy = nullptr; |  | ||||||
| 	} |  | ||||||
| 	m_strategy = strategy; |  | ||||||
| 	m_strategy->profile = this; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| ProfileStrategy* MinecraftProfile::strategy() |  | ||||||
| { |  | ||||||
| 	return m_strategy; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void MinecraftProfile::reload() | void MinecraftProfile::reload() | ||||||
| { | { | ||||||
| 	beginResetModel(); | 	beginResetModel(); | ||||||
| 	m_strategy->load(); | 	load_internal(); | ||||||
| 	reapplyPatches(); | 	reapplyPatches(); | ||||||
| 	endResetModel(); | 	endResetModel(); | ||||||
| } | } | ||||||
| @@ -107,7 +90,7 @@ bool MinecraftProfile::remove(const int index) | |||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if(!m_strategy->removePatch(patch)) | 	if(!removePatch_internal(patch)) | ||||||
| 	{ | 	{ | ||||||
| 		qCritical() << "Patch" << patch->getID() << "could not be removed"; | 		qCritical() << "Patch" << patch->getID() << "could not be removed"; | ||||||
| 		return false; | 		return false; | ||||||
| @@ -143,7 +126,7 @@ bool MinecraftProfile::customize(int index) | |||||||
| 		qDebug() << "Patch" << patch->getID() << "is not customizable"; | 		qDebug() << "Patch" << patch->getID() << "is not customizable"; | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| 	if(!m_strategy->customizePatch(patch)) | 	if(!customizePatch_internal(patch)) | ||||||
| 	{ | 	{ | ||||||
| 		qCritical() << "Patch" << patch->getID() << "could not be customized"; | 		qCritical() << "Patch" << patch->getID() << "could not be customized"; | ||||||
| 		return false; | 		return false; | ||||||
| @@ -163,7 +146,7 @@ bool MinecraftProfile::revertToBase(int index) | |||||||
| 		qDebug() << "Patch" << patch->getID() << "is not revertible"; | 		qDebug() << "Patch" << patch->getID() << "is not revertible"; | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| 	if(!m_strategy->revertPatch(patch)) | 	if(!revertPatch_internal(patch)) | ||||||
| 	{ | 	{ | ||||||
| 		qCritical() << "Patch" << patch->getID() << "could not be reverted"; | 		qCritical() << "Patch" << patch->getID() << "could not be reverted"; | ||||||
| 		return false; | 		return false; | ||||||
| @@ -334,7 +317,7 @@ void MinecraftProfile::saveCurrentOrder() const | |||||||
| 			continue; | 			continue; | ||||||
| 		order.append(item->getID()); | 		order.append(item->getID()); | ||||||
| 	} | 	} | ||||||
| 	m_strategy->saveOrder(order); | 	saveOrder_internal(order); | ||||||
| } | } | ||||||
|  |  | ||||||
| void MinecraftProfile::move(const int index, const MoveDirection direction) | void MinecraftProfile::move(const int index, const MoveDirection direction) | ||||||
| @@ -374,7 +357,7 @@ void MinecraftProfile::move(const int index, const MoveDirection direction) | |||||||
| } | } | ||||||
| void MinecraftProfile::resetOrder() | void MinecraftProfile::resetOrder() | ||||||
| { | { | ||||||
| 	m_strategy->resetOrder(); | 	resetOrder_internal(); | ||||||
| 	reload(); | 	reload(); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -661,12 +644,12 @@ void MinecraftProfile::getLibraryFiles(const QString& architecture, QStringList& | |||||||
|  |  | ||||||
| void MinecraftProfile::installJarMods(QStringList selectedFiles) | void MinecraftProfile::installJarMods(QStringList selectedFiles) | ||||||
| { | { | ||||||
| 	m_strategy->installJarMods(selectedFiles); | 	installJarMods_internal(selectedFiles); | ||||||
| } | } | ||||||
|  |  | ||||||
| void MinecraftProfile::installCustomJar(QString selectedFile) | void MinecraftProfile::installCustomJar(QString selectedFile) | ||||||
| { | { | ||||||
| 	m_strategy->installCustomJar(selectedFile); | 	installCustomJar_internal(selectedFile); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -685,3 +668,389 @@ int MinecraftProfile::getFreeOrderNumber() | |||||||
| 	} | 	} | ||||||
| 	return largest + 1; | 	return largest + 1; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void MinecraftProfile::loadDefaultBuiltinPatches_internal() | ||||||
|  | { | ||||||
|  | 	auto addBuiltinPatch = [&](const QString &uid, const QString intendedVersion, int order) | ||||||
|  | 	{ | ||||||
|  | 		auto jsonFilePath = FS::PathCombine(m_instance->instanceRoot(), "patches" , uid + ".json"); | ||||||
|  | 		// load up the base minecraft patch | ||||||
|  | 		ProfilePatchPtr profilePatch; | ||||||
|  | 		if(QFile::exists(jsonFilePath)) | ||||||
|  | 		{ | ||||||
|  | 			auto file = ProfileUtils::parseJsonFile(QFileInfo(jsonFilePath), false); | ||||||
|  | 			if(file->version.isEmpty()) | ||||||
|  | 			{ | ||||||
|  | 				file->version = intendedVersion; | ||||||
|  | 			} | ||||||
|  | 			profilePatch = std::make_shared<ProfilePatch>(file, jsonFilePath); | ||||||
|  | 			profilePatch->setVanilla(false); | ||||||
|  | 			profilePatch->setRevertible(true); | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			auto metaVersion = ENV.metadataIndex()->get(uid, intendedVersion); | ||||||
|  | 			profilePatch = std::make_shared<ProfilePatch>(metaVersion); | ||||||
|  | 			profilePatch->setVanilla(true); | ||||||
|  | 		} | ||||||
|  | 		profilePatch->setOrder(order); | ||||||
|  | 		appendPatch(profilePatch); | ||||||
|  | 	}; | ||||||
|  | 	addBuiltinPatch("net.minecraft", m_instance->getComponentVersion("net.minecraft"), -2); | ||||||
|  | 	addBuiltinPatch("org.lwjgl", m_instance->getComponentVersion("org.lwjgl"), -1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MinecraftProfile::loadUserPatches_internal() | ||||||
|  | { | ||||||
|  | 	// first, collect all patches (that are not builtins of OneSix) and load them | ||||||
|  | 	QMap<QString, ProfilePatchPtr> loadedPatches; | ||||||
|  | 	QDir patchesDir(FS::PathCombine(m_instance->instanceRoot(),"patches")); | ||||||
|  | 	for (auto info : patchesDir.entryInfoList(QStringList() << "*.json", QDir::Files)) | ||||||
|  | 	{ | ||||||
|  | 		// parse the file | ||||||
|  | 		qDebug() << "Reading" << info.fileName(); | ||||||
|  | 		auto file = ProfileUtils::parseJsonFile(info, true); | ||||||
|  | 		// ignore builtins | ||||||
|  | 		if (file->uid == "net.minecraft") | ||||||
|  | 			continue; | ||||||
|  | 		if (file->uid == "org.lwjgl") | ||||||
|  | 			continue; | ||||||
|  | 		auto patch = std::make_shared<ProfilePatch>(file, info.filePath()); | ||||||
|  | 		patch->setRemovable(true); | ||||||
|  | 		patch->setMovable(true); | ||||||
|  | 		if(ENV.metadataIndex()->hasUid(file->uid)) | ||||||
|  | 		{ | ||||||
|  | 			// FIXME: requesting a uid/list creates it in the index... this allows reverting to possibly invalid versions... | ||||||
|  | 			patch->setRevertible(true); | ||||||
|  | 		} | ||||||
|  | 		loadedPatches[file->uid] = patch; | ||||||
|  | 	} | ||||||
|  | 	// these are 'special'... if not already loaded from instance files, grab them from the metadata repo. | ||||||
|  | 	auto loadSpecial = [&](const QString & uid, int order) | ||||||
|  | 	{ | ||||||
|  | 		auto patchVersion = m_instance->getComponentVersion(uid); | ||||||
|  | 		if(!patchVersion.isEmpty() && !loadedPatches.contains(uid)) | ||||||
|  | 		{ | ||||||
|  | 			auto patch = std::make_shared<ProfilePatch>(ENV.metadataIndex()->get(uid, patchVersion)); | ||||||
|  | 			patch->setOrder(order); | ||||||
|  | 			patch->setVanilla(true); | ||||||
|  | 			patch->setRemovable(true); | ||||||
|  | 			patch->setMovable(true); | ||||||
|  | 			loadedPatches[uid] = patch; | ||||||
|  | 		} | ||||||
|  | 	}; | ||||||
|  | 	loadSpecial("net.minecraftforge", 5); | ||||||
|  | 	loadSpecial("com.mumfrey.liteloader", 10); | ||||||
|  |  | ||||||
|  | 	// now add all the patches by user sort order | ||||||
|  | 	ProfileUtils::PatchOrder userOrder; | ||||||
|  | 	ProfileUtils::readOverrideOrders(FS::PathCombine(m_instance->instanceRoot(), "order.json"), userOrder); | ||||||
|  | 	for (auto uid : userOrder) | ||||||
|  | 	{ | ||||||
|  | 		// ignore builtins | ||||||
|  | 		if (uid == "net.minecraft") | ||||||
|  | 			continue; | ||||||
|  | 		if (uid == "org.lwjgl") | ||||||
|  | 			continue; | ||||||
|  | 		// ordering has a patch that is gone? | ||||||
|  | 		if(!loadedPatches.contains(uid)) | ||||||
|  | 		{ | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  | 		appendPatch(loadedPatches.take(uid)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// is there anything left to sort? | ||||||
|  | 	if(loadedPatches.isEmpty()) | ||||||
|  | 	{ | ||||||
|  | 		// TODO: save the order here? | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// inserting into multimap by order number as key sorts the patches and detects duplicates | ||||||
|  | 	QMultiMap<int, ProfilePatchPtr> files; | ||||||
|  | 	auto iter = loadedPatches.begin(); | ||||||
|  | 	while(iter != loadedPatches.end()) | ||||||
|  | 	{ | ||||||
|  | 		files.insert((*iter)->getOrder(), *iter); | ||||||
|  | 		iter++; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// then just extract the patches and put them in the list | ||||||
|  | 	for (auto order : files.keys()) | ||||||
|  | 	{ | ||||||
|  | 		const auto &values = files.values(order); | ||||||
|  | 		for(auto &value: values) | ||||||
|  | 		{ | ||||||
|  | 			// TODO: put back the insertion of problem messages here, so the user knows about the id duplication | ||||||
|  | 			appendPatch(value); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	// TODO: save the order here? | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void MinecraftProfile::load_internal() | ||||||
|  | { | ||||||
|  | 	clearPatches(); | ||||||
|  | 	loadDefaultBuiltinPatches_internal(); | ||||||
|  | 	loadUserPatches_internal(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool MinecraftProfile::saveOrder_internal(ProfileUtils::PatchOrder order) const | ||||||
|  | { | ||||||
|  | 	return ProfileUtils::writeOverrideOrders(FS::PathCombine(m_instance->instanceRoot(), "order.json"), order); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool MinecraftProfile::resetOrder_internal() | ||||||
|  | { | ||||||
|  | 	return QDir(m_instance->instanceRoot()).remove("order.json"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool MinecraftProfile::removePatch_internal(ProfilePatchPtr patch) | ||||||
|  | { | ||||||
|  | 	bool ok = true; | ||||||
|  | 	// first, remove the patch file. this ensures it's not used anymore | ||||||
|  | 	auto fileName = patch->getFilename(); | ||||||
|  | 	if(fileName.size()) | ||||||
|  | 	{ | ||||||
|  | 		QFile patchFile(fileName); | ||||||
|  | 		if(patchFile.exists() && !patchFile.remove()) | ||||||
|  | 		{ | ||||||
|  | 			qCritical() << "File" << fileName << "could not be removed because:" << patchFile.errorString(); | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if(!m_instance->getComponentVersion(patch->getID()).isEmpty()) | ||||||
|  | 	{ | ||||||
|  | 		m_instance->setComponentVersion(patch->getID(), QString()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// FIXME: we need a generic way of removing local resources, not just jar mods... | ||||||
|  | 	auto preRemoveJarMod = [&](LibraryPtr jarMod) -> bool | ||||||
|  | 	{ | ||||||
|  | 		if (!jarMod->isLocal()) | ||||||
|  | 		{ | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  | 		QStringList jar, temp1, temp2, temp3; | ||||||
|  | 		jarMod->getApplicableFiles(currentSystem, jar, temp1, temp2, temp3, m_instance->jarmodsPath().absolutePath()); | ||||||
|  | 		QFileInfo finfo (jar[0]); | ||||||
|  | 		if(finfo.exists()) | ||||||
|  | 		{ | ||||||
|  | 			QFile jarModFile(jar[0]); | ||||||
|  | 			if(!jarModFile.remove()) | ||||||
|  | 			{ | ||||||
|  | 				qCritical() << "File" << jar[0] << "could not be removed because:" << jarModFile.errorString(); | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  | 		return true; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	auto &jarMods = patch->getVersionFile()->jarMods; | ||||||
|  | 	for(auto &jarmod: jarMods) | ||||||
|  | 	{ | ||||||
|  | 		ok &= preRemoveJarMod(jarmod); | ||||||
|  | 	} | ||||||
|  | 	return ok; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool MinecraftProfile::customizePatch_internal(ProfilePatchPtr patch) | ||||||
|  | { | ||||||
|  | 	if(patch->isCustom()) | ||||||
|  | 	{ | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	auto filename = FS::PathCombine(m_instance->instanceRoot(), "patches" , patch->getID() + ".json"); | ||||||
|  | 	if(!FS::ensureFilePathExists(filename)) | ||||||
|  | 	{ | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 	// FIXME: get rid of this try-catch. | ||||||
|  | 	try | ||||||
|  | 	{ | ||||||
|  | 		QSaveFile jsonFile(filename); | ||||||
|  | 		if(!jsonFile.open(QIODevice::WriteOnly)) | ||||||
|  | 		{ | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 		auto vfile = patch->getVersionFile(); | ||||||
|  | 		if(!vfile) | ||||||
|  | 		{ | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 		auto document = OneSixVersionFormat::versionFileToJson(vfile, true); | ||||||
|  | 		jsonFile.write(document.toJson()); | ||||||
|  | 		if(!jsonFile.commit()) | ||||||
|  | 		{ | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 		load_internal(); | ||||||
|  | 	} | ||||||
|  | 	catch (Exception &error) | ||||||
|  | 	{ | ||||||
|  | 		qWarning() << "Version could not be loaded:" << error.cause(); | ||||||
|  | 	} | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool MinecraftProfile::revertPatch_internal(ProfilePatchPtr patch) | ||||||
|  | { | ||||||
|  | 	if(!patch->isCustom()) | ||||||
|  | 	{ | ||||||
|  | 		// already not custom | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  | 	auto filename = patch->getFilename(); | ||||||
|  | 	if(!QFile::exists(filename)) | ||||||
|  | 	{ | ||||||
|  | 		// already gone / not custom | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  | 	// just kill the file and reload | ||||||
|  | 	bool result = QFile::remove(filename); | ||||||
|  | 	// FIXME: get rid of this try-catch. | ||||||
|  | 	try | ||||||
|  | 	{ | ||||||
|  | 		load_internal(); | ||||||
|  | 	} | ||||||
|  | 	catch (Exception &error) | ||||||
|  | 	{ | ||||||
|  | 		qWarning() << "Version could not be loaded:" << error.cause(); | ||||||
|  | 	} | ||||||
|  | 	return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool MinecraftProfile::installJarMods_internal(QStringList filepaths) | ||||||
|  | { | ||||||
|  | 	QString patchDir = FS::PathCombine(m_instance->instanceRoot(), "patches"); | ||||||
|  | 	if(!FS::ensureFolderPathExists(patchDir)) | ||||||
|  | 	{ | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (!FS::ensureFolderPathExists(m_instance->jarModsDir())) | ||||||
|  | 	{ | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for(auto filepath:filepaths) | ||||||
|  | 	{ | ||||||
|  | 		QFileInfo sourceInfo(filepath); | ||||||
|  | 		auto uuid = QUuid::createUuid(); | ||||||
|  | 		QString id = uuid.toString().remove('{').remove('}'); | ||||||
|  | 		QString target_filename = id + ".jar"; | ||||||
|  | 		QString target_id = "org.multimc.jarmod." + id; | ||||||
|  | 		QString target_name = sourceInfo.completeBaseName() + " (jar mod)"; | ||||||
|  | 		QString finalPath = FS::PathCombine(m_instance->jarModsDir(), target_filename); | ||||||
|  |  | ||||||
|  | 		QFileInfo targetInfo(finalPath); | ||||||
|  | 		if(targetInfo.exists()) | ||||||
|  | 		{ | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (!QFile::copy(sourceInfo.absoluteFilePath(),QFileInfo(finalPath).absoluteFilePath())) | ||||||
|  | 		{ | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		auto f = std::make_shared<VersionFile>(); | ||||||
|  | 		auto jarMod = std::make_shared<Library>(); | ||||||
|  | 		jarMod->setRawName(GradleSpecifier("org.multimc.jarmods:" + id + ":1")); | ||||||
|  | 		jarMod->setFilename(target_filename); | ||||||
|  | 		jarMod->setDisplayName(sourceInfo.completeBaseName()); | ||||||
|  | 		jarMod->setHint("local"); | ||||||
|  | 		f->jarMods.append(jarMod); | ||||||
|  | 		f->name = target_name; | ||||||
|  | 		f->uid = target_id; | ||||||
|  | 		f->order = getFreeOrderNumber(); | ||||||
|  | 		QString patchFileName = FS::PathCombine(patchDir, target_id + ".json"); | ||||||
|  |  | ||||||
|  | 		QFile file(patchFileName); | ||||||
|  | 		if (!file.open(QFile::WriteOnly)) | ||||||
|  | 		{ | ||||||
|  | 			qCritical() << "Error opening" << file.fileName() | ||||||
|  | 						<< "for reading:" << file.errorString(); | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 		file.write(OneSixVersionFormat::versionFileToJson(f, true).toJson()); | ||||||
|  | 		file.close(); | ||||||
|  |  | ||||||
|  | 		auto patch = std::make_shared<ProfilePatch>(f, patchFileName); | ||||||
|  | 		patch->setMovable(true); | ||||||
|  | 		patch->setRemovable(true); | ||||||
|  | 		appendPatch(patch); | ||||||
|  | 	} | ||||||
|  | 	saveCurrentOrder(); | ||||||
|  | 	reapplyPatches(); | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool MinecraftProfile::installCustomJar_internal(QString filepath) | ||||||
|  | { | ||||||
|  | 	QString patchDir = FS::PathCombine(m_instance->instanceRoot(), "patches"); | ||||||
|  | 	if(!FS::ensureFolderPathExists(patchDir)) | ||||||
|  | 	{ | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	QString libDir = m_instance->getLocalLibraryPath(); | ||||||
|  | 	if (!FS::ensureFolderPathExists(libDir)) | ||||||
|  | 	{ | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	auto specifier = GradleSpecifier("org.multimc:customjar:1"); | ||||||
|  | 	QFileInfo sourceInfo(filepath); | ||||||
|  | 	QString target_filename = specifier.getFileName(); | ||||||
|  | 	QString target_id = specifier.artifactId(); | ||||||
|  | 	QString target_name = sourceInfo.completeBaseName() + " (custom jar)"; | ||||||
|  | 	QString finalPath = FS::PathCombine(libDir, target_filename); | ||||||
|  |  | ||||||
|  | 	QFileInfo jarInfo(finalPath); | ||||||
|  | 	if (jarInfo.exists()) | ||||||
|  | 	{ | ||||||
|  | 		if(!QFile::remove(finalPath)) | ||||||
|  | 		{ | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if (!QFile::copy(filepath, finalPath)) | ||||||
|  | 	{ | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	auto f = std::make_shared<VersionFile>(); | ||||||
|  | 	auto jarMod = std::make_shared<Library>(); | ||||||
|  | 	jarMod->setRawName(specifier); | ||||||
|  | 	jarMod->setDisplayName(sourceInfo.completeBaseName()); | ||||||
|  | 	jarMod->setHint("local"); | ||||||
|  | 	f->mainJar = jarMod; | ||||||
|  | 	f->name = target_name; | ||||||
|  | 	f->uid = target_id; | ||||||
|  | 	f->order = getFreeOrderNumber(); | ||||||
|  | 	QString patchFileName = FS::PathCombine(patchDir, target_id + ".json"); | ||||||
|  |  | ||||||
|  | 	QFile file(patchFileName); | ||||||
|  | 	if (!file.open(QFile::WriteOnly)) | ||||||
|  | 	{ | ||||||
|  | 		qCritical() << "Error opening" << file.fileName() | ||||||
|  | 					<< "for reading:" << file.errorString(); | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 	file.write(OneSixVersionFormat::versionFileToJson(f, true).toJson()); | ||||||
|  | 	file.close(); | ||||||
|  |  | ||||||
|  | 	auto patch = std::make_shared<ProfilePatch>(f, patchFileName); | ||||||
|  | 	patch->setMovable(true); | ||||||
|  | 	patch->setRemovable(true); | ||||||
|  | 	appendPatch(patch); | ||||||
|  |  | ||||||
|  | 	saveCurrentOrder(); | ||||||
|  | 	reapplyPatches(); | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
| @@ -23,13 +23,13 @@ | |||||||
|  |  | ||||||
| #include "Library.h" | #include "Library.h" | ||||||
| #include "ProfilePatch.h" | #include "ProfilePatch.h" | ||||||
|  | #include "ProfileUtils.h" | ||||||
| #include "BaseVersion.h" | #include "BaseVersion.h" | ||||||
| #include "MojangDownloadInfo.h" | #include "MojangDownloadInfo.h" | ||||||
|  |  | ||||||
| #include "multimc_logic_export.h" | #include "multimc_logic_export.h" | ||||||
|  |  | ||||||
| class ProfileStrategy; | class MinecraftInstance; | ||||||
| class OneSixInstance; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class MULTIMC_LOGIC_EXPORT MinecraftProfile : public QAbstractListModel | class MULTIMC_LOGIC_EXPORT MinecraftProfile : public QAbstractListModel | ||||||
| @@ -37,12 +37,9 @@ class MULTIMC_LOGIC_EXPORT MinecraftProfile : public QAbstractListModel | |||||||
| 	Q_OBJECT | 	Q_OBJECT | ||||||
|  |  | ||||||
| public: | public: | ||||||
| 	explicit MinecraftProfile(ProfileStrategy *strategy); | 	explicit MinecraftProfile(MinecraftInstance * instance); | ||||||
| 	virtual ~MinecraftProfile(); | 	virtual ~MinecraftProfile(); | ||||||
|  |  | ||||||
| 	void setStrategy(ProfileStrategy * strategy); |  | ||||||
| 	ProfileStrategy *strategy(); |  | ||||||
|  |  | ||||||
| 	virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; | 	virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; | ||||||
| 	virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override; | 	virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override; | ||||||
| 	virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; | 	virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; | ||||||
| @@ -138,6 +135,19 @@ public: | |||||||
| 	/// Add the patch object to the internal list of patches | 	/// Add the patch object to the internal list of patches | ||||||
| 	void appendPatch(ProfilePatchPtr patch); | 	void appendPatch(ProfilePatchPtr patch); | ||||||
|  |  | ||||||
|  | private: | ||||||
|  | 	void load_internal(); | ||||||
|  | 	bool resetOrder_internal(); | ||||||
|  | 	bool saveOrder_internal(ProfileUtils::PatchOrder order) const; | ||||||
|  | 	bool installJarMods_internal(QStringList filepaths); | ||||||
|  |     bool installCustomJar_internal(QString filepath); | ||||||
|  | 	bool removePatch_internal(ProfilePatchPtr patch); | ||||||
|  | 	bool customizePatch_internal(ProfilePatchPtr patch); | ||||||
|  | 	bool revertPatch_internal(ProfilePatchPtr patch); | ||||||
|  | 	void loadDefaultBuiltinPatches_internal(); | ||||||
|  | 	void loadUserPatches_internal(); | ||||||
|  | 	void upgradeDeprecatedFiles_internal(); | ||||||
|  |  | ||||||
| private: /* data */ | private: /* data */ | ||||||
| 	/// the version of Minecraft - jar to use | 	/// the version of Minecraft - jar to use | ||||||
| 	QString m_minecraftVersion; | 	QString m_minecraftVersion; | ||||||
| @@ -185,30 +195,9 @@ private: /* data */ | |||||||
|  |  | ||||||
| 	ProblemSeverity m_problemSeverity = ProblemSeverity::None; | 	ProblemSeverity m_problemSeverity = ProblemSeverity::None; | ||||||
|  |  | ||||||
| 	/* |  | ||||||
| 	FIXME: add support for those rules here? Looks like a pile of quick hacks to me though. |  | ||||||
|  |  | ||||||
| 	"rules": [ |  | ||||||
| 		{ |  | ||||||
| 		"action": "allow" |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 		"action": "disallow", |  | ||||||
| 		"os": { |  | ||||||
| 			"name": "osx", |  | ||||||
| 			"version": "^10\\.5\\.\\d$" |  | ||||||
| 		} |  | ||||||
| 		} |  | ||||||
| 	], |  | ||||||
| 	"incompatibilityReason": "There is a bug in LWJGL which makes it incompatible with OSX |  | ||||||
| 	10.5.8. Please go to New Profile and use 1.5.2 for now. Sorry!" |  | ||||||
| 	} |  | ||||||
| 	*/ |  | ||||||
| 	// QList<Rule> rules; |  | ||||||
|  |  | ||||||
| 	/// list of attached profile patches | 	/// list of attached profile patches | ||||||
| 	QList<ProfilePatchPtr> m_patches; | 	QList<ProfilePatchPtr> m_patches; | ||||||
|  |  | ||||||
| 	/// strategy used for profile operations | 	// the instance this belongs to | ||||||
| 	ProfileStrategy *m_strategy = nullptr; | 	MinecraftInstance *m_instance; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -15,8 +15,8 @@ | |||||||
| 
 | 
 | ||||||
| #include "Env.h" | #include "Env.h" | ||||||
| #include <minecraft/forge/ForgeXzDownload.h> | #include <minecraft/forge/ForgeXzDownload.h> | ||||||
| #include "OneSixUpdate.h" | #include "MinecraftUpdate.h" | ||||||
| #include "OneSixInstance.h" | #include "MinecraftInstance.h" | ||||||
| 
 | 
 | ||||||
| #include <QFile> | #include <QFile> | ||||||
| #include <QFileInfo> | #include <QFileInfo> | ||||||
| @@ -37,7 +37,7 @@ | |||||||
| #include <meta/Index.h> | #include <meta/Index.h> | ||||||
| #include <meta/Version.h> | #include <meta/Version.h> | ||||||
| 
 | 
 | ||||||
| OneSixUpdate::OneSixUpdate(OneSixInstance *inst, QObject *parent) : Task(parent), m_inst(inst) | OneSixUpdate::OneSixUpdate(MinecraftInstance *inst, QObject *parent) : Task(parent), m_inst(inst) | ||||||
| { | { | ||||||
| 	// create folders
 | 	// create folders
 | ||||||
| 	{ | 	{ | ||||||
| @@ -25,13 +25,13 @@ | |||||||
| #include <quazip.h> | #include <quazip.h> | ||||||
| 
 | 
 | ||||||
| class MinecraftVersion; | class MinecraftVersion; | ||||||
| class OneSixInstance; | class MinecraftInstance; | ||||||
| 
 | 
 | ||||||
| class OneSixUpdate : public Task | class OneSixUpdate : public Task | ||||||
| { | { | ||||||
| 	Q_OBJECT | 	Q_OBJECT | ||||||
| public: | public: | ||||||
| 	explicit OneSixUpdate(OneSixInstance *inst, QObject *parent = 0); | 	explicit OneSixUpdate(MinecraftInstance *inst, QObject *parent = 0); | ||||||
| 	void executeTask() override; | 	void executeTask() override; | ||||||
| 	bool canAbort() const override; | 	bool canAbort() const override; | ||||||
| 
 | 
 | ||||||
| @@ -45,7 +45,7 @@ private: | |||||||
| 	void next(); | 	void next(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| 	OneSixInstance *m_inst = nullptr; | 	MinecraftInstance *m_inst = nullptr; | ||||||
| 	QList<std::shared_ptr<Task>> m_tasks; | 	QList<std::shared_ptr<Task>> m_tasks; | ||||||
| 	QString m_preFailure; | 	QString m_preFailure; | ||||||
| 	int m_currentTask = -1; | 	int m_currentTask = -1; | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| #include "MojangVersionFormat.h" | #include "MojangVersionFormat.h" | ||||||
| #include "onesix/OneSixVersionFormat.h" | #include "OneSixVersionFormat.h" | ||||||
| #include "MojangDownloadInfo.h" | #include "MojangDownloadInfo.h" | ||||||
|  |  | ||||||
| #include "Json.h" | #include "Json.h" | ||||||
|   | |||||||
| @@ -1,39 +0,0 @@ | |||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include "ProfileUtils.h" |  | ||||||
| #include "ProfilePatch.h" |  | ||||||
|  |  | ||||||
| class MinecraftProfile; |  | ||||||
|  |  | ||||||
| class ProfileStrategy |  | ||||||
| { |  | ||||||
| 	friend class MinecraftProfile; |  | ||||||
| public: |  | ||||||
| 	virtual ~ProfileStrategy(){}; |  | ||||||
|  |  | ||||||
| 	/// load the patch files into the profile |  | ||||||
| 	virtual void load() = 0; |  | ||||||
|  |  | ||||||
| 	/// reset the order of patches |  | ||||||
| 	virtual bool resetOrder() = 0; |  | ||||||
|  |  | ||||||
| 	/// save the order of patches, given the order |  | ||||||
| 	virtual bool saveOrder(ProfileUtils::PatchOrder order) = 0; |  | ||||||
|  |  | ||||||
| 	/// install a list of jar mods into the instance |  | ||||||
| 	virtual bool installJarMods(QStringList filepaths) = 0; |  | ||||||
|  |  | ||||||
| 	/// install a custom jar (replaces the one from the Minecraft component) |  | ||||||
| 	virtual bool installCustomJar(QString filepath) = 0; |  | ||||||
|  |  | ||||||
| 	/// remove any files or records that constitute the version patch |  | ||||||
| 	virtual bool removePatch(ProfilePatchPtr jarMod) = 0; |  | ||||||
|  |  | ||||||
| 	/// make the patch custom, if possible |  | ||||||
| 	virtual bool customizePatch(ProfilePatchPtr patch) = 0; |  | ||||||
|  |  | ||||||
| 	/// revert the custom patch to 'vanilla', if possible |  | ||||||
| 	virtual bool revertPatch(ProfilePatchPtr patch) = 0; |  | ||||||
| protected: |  | ||||||
| 	MinecraftProfile *profile; |  | ||||||
| }; |  | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| #include "ProfileUtils.h" | #include "ProfileUtils.h" | ||||||
| #include "minecraft/VersionFilterData.h" | #include "minecraft/VersionFilterData.h" | ||||||
| #include "minecraft/onesix/OneSixVersionFormat.h" | #include "minecraft/OneSixVersionFormat.h" | ||||||
| #include "Json.h" | #include "Json.h" | ||||||
| #include <QDebug> | #include <QDebug> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -14,31 +14,47 @@ | |||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include "ModMinecraftJar.h" | #include "ModMinecraftJar.h" | ||||||
| #include <launch/LaunchTask.h> | #include "launch/LaunchTask.h" | ||||||
| #include <QStandardPaths> | #include "MMCZip.h" | ||||||
|  | #include "minecraft/OpSys.h" | ||||||
|  | #include "FileSystem.h" | ||||||
|  | #include "minecraft/MinecraftInstance.h" | ||||||
|  | #include "minecraft/MinecraftProfile.h" | ||||||
|  |  | ||||||
| void ModMinecraftJar::executeTask() | void ModMinecraftJar::executeTask() | ||||||
| { | { | ||||||
| 	m_jarModTask = m_parent->instance()->createJarModdingTask(); | 	auto m_inst = std::dynamic_pointer_cast<MinecraftInstance>(m_parent->instance()); | ||||||
| 	if(m_jarModTask) |  | ||||||
|  | 	// nuke obsolete stripped jar(s) if needed | ||||||
|  | 	if(!FS::ensureFolderPathExists(m_inst->binRoot())) | ||||||
| 	{ | 	{ | ||||||
| 		connect(m_jarModTask.get(), SIGNAL(finished()), this, SLOT(jarModdingFinished())); | 		emitFailed(tr("Couldn't create the bin folder for Minecraft.jar")); | ||||||
| 		m_jarModTask->start(); | 	} | ||||||
| 		return; | 	auto finalJarPath = QDir(m_inst->binRoot()).absoluteFilePath("minecraft.jar"); | ||||||
|  | 	QFile finalJar(finalJarPath); | ||||||
|  | 	if(finalJar.exists()) | ||||||
|  | 	{ | ||||||
|  | 		if(!finalJar.remove()) | ||||||
|  | 		{ | ||||||
|  | 			emitFailed(tr("Couldn't remove stale jar file: %1").arg(finalJarPath)); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// create temporary modded jar, if needed | ||||||
|  | 	auto profile = m_inst->getMinecraftProfile(); | ||||||
|  | 	auto jarMods = m_inst->getJarMods(); | ||||||
|  | 	if(jarMods.size()) | ||||||
|  | 	{ | ||||||
|  | 		auto mainJar = profile->getMainJar(); | ||||||
|  | 		QStringList jars, temp1, temp2, temp3, temp4; | ||||||
|  | 		mainJar->getApplicableFiles(currentSystem, jars, temp1, temp2, temp3, m_inst->getLocalLibraryPath()); | ||||||
|  | 		auto sourceJarPath = jars[0]; | ||||||
|  | 		if(!MMCZip::createModdedJar(sourceJarPath, finalJarPath, jarMods)) | ||||||
|  | 		{ | ||||||
|  | 			emitFailed(tr("Failed to create the custom Minecraft jar file.")); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	emitSucceeded(); | 	emitSucceeded(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void ModMinecraftJar::jarModdingFinished() |  | ||||||
| { |  | ||||||
| 	if(m_jarModTask->wasSuccessful()) |  | ||||||
| 	{ |  | ||||||
| 		emitSucceeded(); |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 	{ |  | ||||||
| 		QString reason = tr("jar modding failed because: %1.\n\n").arg(m_jarModTask->failReason()); |  | ||||||
| 		emit logLine(reason, MessageLevel::Fatal); |  | ||||||
| 		emitFailed(reason); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -18,7 +18,6 @@ | |||||||
| #include <launch/LaunchStep.h> | #include <launch/LaunchStep.h> | ||||||
| #include <memory> | #include <memory> | ||||||
|  |  | ||||||
| // FIXME: temporary wrapper for existing task. |  | ||||||
| class ModMinecraftJar: public LaunchStep | class ModMinecraftJar: public LaunchStep | ||||||
| { | { | ||||||
| 	Q_OBJECT | 	Q_OBJECT | ||||||
| @@ -31,9 +30,4 @@ public: | |||||||
| 	{ | 	{ | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| private slots: |  | ||||||
| 	void jarModdingFinished(); |  | ||||||
|  |  | ||||||
| private: |  | ||||||
| 	std::shared_ptr<Task> m_jarModTask; |  | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -1,706 +0,0 @@ | |||||||
| /* Copyright 2013-2017 MultiMC Contributors |  | ||||||
|  * |  | ||||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); |  | ||||||
|  * you may not use this file except in compliance with the License. |  | ||||||
|  * You may obtain a copy of the License at |  | ||||||
|  * |  | ||||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 |  | ||||||
|  * |  | ||||||
|  * Unless required by applicable law or agreed to in writing, software |  | ||||||
|  * distributed under the License is distributed on an "AS IS" BASIS, |  | ||||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |  | ||||||
|  * See the License for the specific language governing permissions and |  | ||||||
|  * limitations under the License. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include <QDebug> |  | ||||||
| #include <minecraft/launch/DirectJavaLaunch.h> |  | ||||||
| #include <minecraft/launch/LauncherPartLaunch.h> |  | ||||||
| #include <Env.h> |  | ||||||
|  |  | ||||||
| #include "OneSixInstance.h" |  | ||||||
| #include "OneSixUpdate.h" |  | ||||||
| #include "OneSixProfileStrategy.h" |  | ||||||
|  |  | ||||||
| #include "minecraft/MinecraftProfile.h" |  | ||||||
| #include "minecraft/launch/ModMinecraftJar.h" |  | ||||||
| #include "MMCZip.h" |  | ||||||
|  |  | ||||||
| #include "minecraft/AssetsUtils.h" |  | ||||||
| #include "minecraft/WorldList.h" |  | ||||||
| #include <FileSystem.h> |  | ||||||
|  |  | ||||||
| OneSixInstance::OneSixInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir) |  | ||||||
| 	: MinecraftInstance(globalSettings, settings, rootDir) |  | ||||||
| { |  | ||||||
| 	// set explicitly during instance creation |  | ||||||
| 	m_settings->registerSetting({"IntendedVersion", "MinecraftVersion"}, ""); |  | ||||||
|  |  | ||||||
| 	// defaults to the version we've been using for years (2.9.1) |  | ||||||
| 	m_settings->registerSetting("LWJGLVersion", "2.9.1"); |  | ||||||
|  |  | ||||||
| 	// optionals |  | ||||||
| 	m_settings->registerSetting("ForgeVersion", ""); |  | ||||||
| 	m_settings->registerSetting("LiteloaderVersion", ""); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void OneSixInstance::init() |  | ||||||
| { |  | ||||||
| 	createProfile(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void OneSixInstance::createProfile() |  | ||||||
| { |  | ||||||
| 	m_profile.reset(new MinecraftProfile(new OneSixProfileStrategy(this))); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QSet<QString> OneSixInstance::traits() |  | ||||||
| { |  | ||||||
| 	auto version = getMinecraftProfile(); |  | ||||||
| 	if (!version) |  | ||||||
| 	{ |  | ||||||
| 		return {"version-incomplete"}; |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 	{ |  | ||||||
| 		return version->getTraits(); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| shared_qobject_ptr<Task> OneSixInstance::createUpdateTask() |  | ||||||
| { |  | ||||||
| 	return shared_qobject_ptr<Task>(new OneSixUpdate(this)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QString replaceTokensIn(QString text, QMap<QString, QString> with) |  | ||||||
| { |  | ||||||
| 	QString result; |  | ||||||
| 	QRegExp token_regexp("\\$\\{(.+)\\}"); |  | ||||||
| 	token_regexp.setMinimal(true); |  | ||||||
| 	QStringList list; |  | ||||||
| 	int tail = 0; |  | ||||||
| 	int head = 0; |  | ||||||
| 	while ((head = token_regexp.indexIn(text, head)) != -1) |  | ||||||
| 	{ |  | ||||||
| 		result.append(text.mid(tail, head - tail)); |  | ||||||
| 		QString key = token_regexp.cap(1); |  | ||||||
| 		auto iter = with.find(key); |  | ||||||
| 		if (iter != with.end()) |  | ||||||
| 		{ |  | ||||||
| 			result.append(*iter); |  | ||||||
| 		} |  | ||||||
| 		head += token_regexp.matchedLength(); |  | ||||||
| 		tail = head; |  | ||||||
| 	} |  | ||||||
| 	result.append(text.mid(tail)); |  | ||||||
| 	return result; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QStringList OneSixInstance::processMinecraftArgs(AuthSessionPtr session) const |  | ||||||
| { |  | ||||||
| 	QString args_pattern = m_profile->getMinecraftArguments(); |  | ||||||
| 	for (auto tweaker : m_profile->getTweakers()) |  | ||||||
| 	{ |  | ||||||
| 		args_pattern += " --tweakClass " + tweaker; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	QMap<QString, QString> token_mapping; |  | ||||||
| 	// yggdrasil! |  | ||||||
| 	if(session) |  | ||||||
| 	{ |  | ||||||
| 		token_mapping["auth_username"] = session->username; |  | ||||||
| 		token_mapping["auth_session"] = session->session; |  | ||||||
| 		token_mapping["auth_access_token"] = session->access_token; |  | ||||||
| 		token_mapping["auth_player_name"] = session->player_name; |  | ||||||
| 		token_mapping["auth_uuid"] = session->uuid; |  | ||||||
| 		token_mapping["user_properties"] = session->serializeUserProperties(); |  | ||||||
| 		token_mapping["user_type"] = session->user_type; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// blatant self-promotion. |  | ||||||
| 	token_mapping["profile_name"] = token_mapping["version_name"] = "MultiMC5"; |  | ||||||
| 	if(m_profile->isVanilla()) |  | ||||||
| 	{ |  | ||||||
| 		token_mapping["version_type"] = m_profile->getMinecraftVersionType(); |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 	{ |  | ||||||
| 		token_mapping["version_type"] = "custom"; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	QString absRootDir = QDir(minecraftRoot()).absolutePath(); |  | ||||||
| 	token_mapping["game_directory"] = absRootDir; |  | ||||||
| 	QString absAssetsDir = QDir("assets/").absolutePath(); |  | ||||||
| 	auto assets = m_profile->getMinecraftAssets(); |  | ||||||
| 	token_mapping["game_assets"] = AssetsUtils::reconstructAssets(assets->id).absolutePath(); |  | ||||||
|  |  | ||||||
| 	// 1.7.3+ assets tokens |  | ||||||
| 	token_mapping["assets_root"] = absAssetsDir; |  | ||||||
| 	token_mapping["assets_index_name"] = assets->id; |  | ||||||
|  |  | ||||||
| 	QStringList parts = args_pattern.split(' ', QString::SkipEmptyParts); |  | ||||||
| 	for (int i = 0; i < parts.length(); i++) |  | ||||||
| 	{ |  | ||||||
| 		parts[i] = replaceTokensIn(parts[i], token_mapping); |  | ||||||
| 	} |  | ||||||
| 	return parts; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QString OneSixInstance::getNativePath() const |  | ||||||
| { |  | ||||||
| 	QDir natives_dir(FS::PathCombine(instanceRoot(), "natives/")); |  | ||||||
| 	return natives_dir.absolutePath(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QString OneSixInstance::getLocalLibraryPath() const |  | ||||||
| { |  | ||||||
| 	QDir libraries_dir(FS::PathCombine(instanceRoot(), "libraries/")); |  | ||||||
| 	return libraries_dir.absolutePath(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QString OneSixInstance::createLaunchScript(AuthSessionPtr session) |  | ||||||
| { |  | ||||||
| 	QString launchScript; |  | ||||||
|  |  | ||||||
| 	if (!m_profile) |  | ||||||
| 		return nullptr; |  | ||||||
|  |  | ||||||
| 	auto mainClass = getMainClass(); |  | ||||||
| 	if (!mainClass.isEmpty()) |  | ||||||
| 	{ |  | ||||||
| 		launchScript += "mainClass " + mainClass + "\n"; |  | ||||||
| 	} |  | ||||||
| 	auto appletClass = m_profile->getAppletClass(); |  | ||||||
| 	if (!appletClass.isEmpty()) |  | ||||||
| 	{ |  | ||||||
| 		launchScript += "appletClass " + appletClass + "\n"; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// generic minecraft params |  | ||||||
| 	for (auto param : processMinecraftArgs(session)) |  | ||||||
| 	{ |  | ||||||
| 		launchScript += "param " + param + "\n"; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// window size, title and state, legacy |  | ||||||
| 	{ |  | ||||||
| 		QString windowParams; |  | ||||||
| 		if (settings()->get("LaunchMaximized").toBool()) |  | ||||||
| 			windowParams = "max"; |  | ||||||
| 		else |  | ||||||
| 			windowParams = QString("%1x%2") |  | ||||||
| 							   .arg(settings()->get("MinecraftWinWidth").toInt()) |  | ||||||
| 							   .arg(settings()->get("MinecraftWinHeight").toInt()); |  | ||||||
| 		launchScript += "windowTitle " + windowTitle() + "\n"; |  | ||||||
| 		launchScript += "windowParams " + windowParams + "\n"; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// legacy auth |  | ||||||
| 	if(session) |  | ||||||
| 	{ |  | ||||||
| 		launchScript += "userName " + session->player_name + "\n"; |  | ||||||
| 		launchScript += "sessionId " + session->session + "\n"; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// libraries and class path. |  | ||||||
| 	{ |  | ||||||
| 		QStringList jars, nativeJars; |  | ||||||
| 		auto javaArchitecture = settings()->get("JavaArchitecture").toString(); |  | ||||||
| 		m_profile->getLibraryFiles(javaArchitecture, jars, nativeJars, getLocalLibraryPath(), binRoot()); |  | ||||||
| 		for(auto file: jars) |  | ||||||
| 		{ |  | ||||||
| 			launchScript += "cp " + file + "\n"; |  | ||||||
| 		} |  | ||||||
| 		for(auto file: nativeJars) |  | ||||||
| 		{ |  | ||||||
| 			launchScript += "ext " + file + "\n"; |  | ||||||
| 		} |  | ||||||
| 		launchScript += "natives " + getNativePath() + "\n"; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for (auto trait : m_profile->getTraits()) |  | ||||||
| 	{ |  | ||||||
| 		launchScript += "traits " + trait + "\n"; |  | ||||||
| 	} |  | ||||||
| 	launchScript += "launcher onesix\n"; |  | ||||||
| 	return launchScript; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QStringList OneSixInstance::verboseDescription(AuthSessionPtr session) |  | ||||||
| { |  | ||||||
| 	QStringList out; |  | ||||||
| 	out << "Main Class:" << "  " + getMainClass() << ""; |  | ||||||
| 	out << "Native path:" << "  " + getNativePath() << ""; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	auto alltraits = traits(); |  | ||||||
| 	if(alltraits.size()) |  | ||||||
| 	{ |  | ||||||
| 		out << "Traits:"; |  | ||||||
| 		for (auto trait : alltraits) |  | ||||||
| 		{ |  | ||||||
| 			out << "traits " + trait; |  | ||||||
| 		} |  | ||||||
| 		out << ""; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// libraries and class path. |  | ||||||
| 	{ |  | ||||||
| 		out << "Libraries:"; |  | ||||||
| 		QStringList jars, nativeJars; |  | ||||||
| 		auto javaArchitecture = settings()->get("JavaArchitecture").toString(); |  | ||||||
| 		m_profile->getLibraryFiles(javaArchitecture, jars, nativeJars, getLocalLibraryPath(), binRoot()); |  | ||||||
| 		auto printLibFile = [&](const QString & path) |  | ||||||
| 		{ |  | ||||||
| 			QFileInfo info(path); |  | ||||||
| 			if(info.exists()) |  | ||||||
| 			{ |  | ||||||
| 				out << "  " + path; |  | ||||||
| 			} |  | ||||||
| 			else |  | ||||||
| 			{ |  | ||||||
| 				out << "  " + path + " (missing)"; |  | ||||||
| 			} |  | ||||||
| 		}; |  | ||||||
| 		for(auto file: jars) |  | ||||||
| 		{ |  | ||||||
| 			printLibFile(file); |  | ||||||
| 		} |  | ||||||
| 		out << ""; |  | ||||||
| 		out << "Native libraries:"; |  | ||||||
| 		for(auto file: nativeJars) |  | ||||||
| 		{ |  | ||||||
| 			printLibFile(file); |  | ||||||
| 		} |  | ||||||
| 		out << ""; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if(loaderModList()->size()) |  | ||||||
| 	{ |  | ||||||
| 		out << "Mods:"; |  | ||||||
| 		for(auto & mod: loaderModList()->allMods()) |  | ||||||
| 		{ |  | ||||||
| 			if(!mod.enabled()) |  | ||||||
| 				continue; |  | ||||||
| 			if(mod.type() == Mod::MOD_FOLDER) |  | ||||||
| 				continue; |  | ||||||
| 			// TODO: proper implementation would need to descend into folders. |  | ||||||
|  |  | ||||||
| 			out << "  " + mod.filename().completeBaseName(); |  | ||||||
| 		} |  | ||||||
| 		out << ""; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if(coreModList()->size()) |  | ||||||
| 	{ |  | ||||||
| 		out << "Core Mods:"; |  | ||||||
| 		for(auto & coremod: coreModList()->allMods()) |  | ||||||
| 		{ |  | ||||||
| 			if(!coremod.enabled()) |  | ||||||
| 				continue; |  | ||||||
| 			if(coremod.type() == Mod::MOD_FOLDER) |  | ||||||
| 				continue; |  | ||||||
| 			// TODO: proper implementation would need to descend into folders. |  | ||||||
|  |  | ||||||
| 			out << "  " + coremod.filename().completeBaseName(); |  | ||||||
| 		} |  | ||||||
| 		out << ""; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	auto & jarMods = m_profile->getJarMods(); |  | ||||||
| 	if(jarMods.size()) |  | ||||||
| 	{ |  | ||||||
| 		out << "Jar Mods:"; |  | ||||||
| 		for(auto & jarmod: jarMods) |  | ||||||
| 		{ |  | ||||||
| 			auto displayname = jarmod->displayName(currentSystem); |  | ||||||
| 			auto realname = jarmod->filename(currentSystem); |  | ||||||
| 			if(displayname != realname) |  | ||||||
| 			{ |  | ||||||
| 				out << "  " + displayname + " (" + realname + ")"; |  | ||||||
| 			} |  | ||||||
| 			else |  | ||||||
| 			{ |  | ||||||
| 				out << "  " + realname; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		out << ""; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	auto params = processMinecraftArgs(nullptr); |  | ||||||
| 	out << "Params:"; |  | ||||||
| 	out << "  " + params.join(' '); |  | ||||||
| 	out << ""; |  | ||||||
|  |  | ||||||
| 	QString windowParams; |  | ||||||
| 	if (settings()->get("LaunchMaximized").toBool()) |  | ||||||
| 	{ |  | ||||||
| 		out << "Window size: max (if available)"; |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 	{ |  | ||||||
| 		auto width = settings()->get("MinecraftWinWidth").toInt(); |  | ||||||
| 		auto height = settings()->get("MinecraftWinHeight").toInt(); |  | ||||||
| 		out << "Window size: " + QString::number(width) + " x " + QString::number(height); |  | ||||||
| 	} |  | ||||||
| 	out << ""; |  | ||||||
| 	return out; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| std::shared_ptr<LaunchStep> OneSixInstance::createMainLaunchStep(LaunchTask * parent, AuthSessionPtr session) |  | ||||||
| { |  | ||||||
| 	auto method = launchMethod(); |  | ||||||
| 	if(method == "LauncherPart") |  | ||||||
| 	{ |  | ||||||
| 		auto step = std::make_shared<LauncherPartLaunch>(parent); |  | ||||||
| 		step->setAuthSession(session); |  | ||||||
| 		step->setWorkingDirectory(minecraftRoot()); |  | ||||||
| 		return step; |  | ||||||
| 	} |  | ||||||
| 	else if (method == "DirectJava") |  | ||||||
| 	{ |  | ||||||
| 		auto step = std::make_shared<DirectJavaLaunch>(parent); |  | ||||||
| 		step->setWorkingDirectory(minecraftRoot()); |  | ||||||
| 		step->setAuthSession(session); |  | ||||||
| 		return step; |  | ||||||
| 	} |  | ||||||
| 	return nullptr; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| class JarModTask : public Task |  | ||||||
| { |  | ||||||
| 	Q_OBJECT |  | ||||||
| public: |  | ||||||
| 	explicit JarModTask(std::shared_ptr<OneSixInstance> inst) : Task(nullptr), m_inst(inst) |  | ||||||
| 	{ |  | ||||||
| 	} |  | ||||||
| 	virtual void executeTask() |  | ||||||
| 	{ |  | ||||||
| 		auto profile = m_inst->getMinecraftProfile(); |  | ||||||
| 		// nuke obsolete stripped jar(s) if needed |  | ||||||
| 		QString version_id = profile->getMinecraftVersion(); |  | ||||||
| 		if(!FS::ensureFolderPathExists(m_inst->binRoot())) |  | ||||||
| 		{ |  | ||||||
| 			emitFailed(tr("Couldn't create the bin folder for Minecraft.jar")); |  | ||||||
| 		} |  | ||||||
| 		auto finalJarPath = QDir(m_inst->binRoot()).absoluteFilePath("minecraft.jar"); |  | ||||||
| 		QFile finalJar(finalJarPath); |  | ||||||
| 		if(finalJar.exists()) |  | ||||||
| 		{ |  | ||||||
| 			if(!finalJar.remove()) |  | ||||||
| 			{ |  | ||||||
| 				emitFailed(tr("Couldn't remove stale jar file: %1").arg(finalJarPath)); |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// create temporary modded jar, if needed |  | ||||||
| 		auto jarMods = m_inst->getJarMods(); |  | ||||||
| 		if(jarMods.size()) |  | ||||||
| 		{ |  | ||||||
| 			auto mainJar = profile->getMainJar(); |  | ||||||
| 			QStringList jars, temp1, temp2, temp3, temp4; |  | ||||||
| 			mainJar->getApplicableFiles(currentSystem, jars, temp1, temp2, temp3, m_inst->getLocalLibraryPath()); |  | ||||||
| 			auto sourceJarPath = jars[0]; |  | ||||||
| 			if(!MMCZip::createModdedJar(sourceJarPath, finalJarPath, jarMods)) |  | ||||||
| 			{ |  | ||||||
| 				emitFailed(tr("Failed to create the custom Minecraft jar file.")); |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		emitSucceeded(); |  | ||||||
| 	} |  | ||||||
| 	std::shared_ptr<OneSixInstance> m_inst; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| std::shared_ptr<Task> OneSixInstance::createJarModdingTask() |  | ||||||
| { |  | ||||||
| 	return std::make_shared<JarModTask>(std::dynamic_pointer_cast<OneSixInstance>(shared_from_this())); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::shared_ptr<ModList> OneSixInstance::loaderModList() const |  | ||||||
| { |  | ||||||
| 	if (!m_loader_mod_list) |  | ||||||
| 	{ |  | ||||||
| 		m_loader_mod_list.reset(new ModList(loaderModsDir())); |  | ||||||
| 	} |  | ||||||
| 	m_loader_mod_list->update(); |  | ||||||
| 	return m_loader_mod_list; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::shared_ptr<ModList> OneSixInstance::coreModList() const |  | ||||||
| { |  | ||||||
| 	if (!m_core_mod_list) |  | ||||||
| 	{ |  | ||||||
| 		m_core_mod_list.reset(new ModList(coreModsDir())); |  | ||||||
| 	} |  | ||||||
| 	m_core_mod_list->update(); |  | ||||||
| 	return m_core_mod_list; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::shared_ptr<ModList> OneSixInstance::resourcePackList() const |  | ||||||
| { |  | ||||||
| 	if (!m_resource_pack_list) |  | ||||||
| 	{ |  | ||||||
| 		m_resource_pack_list.reset(new ModList(resourcePacksDir())); |  | ||||||
| 	} |  | ||||||
| 	m_resource_pack_list->update(); |  | ||||||
| 	return m_resource_pack_list; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::shared_ptr<ModList> OneSixInstance::texturePackList() const |  | ||||||
| { |  | ||||||
| 	if (!m_texture_pack_list) |  | ||||||
| 	{ |  | ||||||
| 		m_texture_pack_list.reset(new ModList(texturePacksDir())); |  | ||||||
| 	} |  | ||||||
| 	m_texture_pack_list->update(); |  | ||||||
| 	return m_texture_pack_list; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::shared_ptr<WorldList> OneSixInstance::worldList() const |  | ||||||
| { |  | ||||||
| 	if (!m_world_list) |  | ||||||
| 	{ |  | ||||||
| 		m_world_list.reset(new WorldList(worldDir())); |  | ||||||
| 	} |  | ||||||
| 	return m_world_list; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool OneSixInstance::setIntendedVersionId(QString version) |  | ||||||
| { |  | ||||||
| 	return setComponentVersion("net.minecraft", version); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QString OneSixInstance::intendedVersionId() const |  | ||||||
| { |  | ||||||
| 	return getComponentVersion("net.minecraft"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool OneSixInstance::setComponentVersion(const QString& uid, const QString& version) |  | ||||||
| { |  | ||||||
| 	if(uid == "net.minecraft") |  | ||||||
| 	{ |  | ||||||
| 		settings()->set("IntendedVersion", version); |  | ||||||
| 	} |  | ||||||
| 	else if (uid == "org.lwjgl") |  | ||||||
| 	{ |  | ||||||
| 		settings()->set("LWJGLVersion", version); |  | ||||||
| 	} |  | ||||||
| 	else if (uid == "net.minecraftforge") |  | ||||||
| 	{ |  | ||||||
| 		settings()->set("ForgeVersion", version); |  | ||||||
| 	} |  | ||||||
| 	else if (uid == "com.mumfrey.liteloader") |  | ||||||
| 	{ |  | ||||||
| 		settings()->set("LiteloaderVersion", version); |  | ||||||
| 	} |  | ||||||
| 	if(getMinecraftProfile()) |  | ||||||
| 	{ |  | ||||||
| 		clearProfile(); |  | ||||||
| 	} |  | ||||||
| 	emit propertiesChanged(this); |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QString OneSixInstance::getComponentVersion(const QString& uid) const |  | ||||||
| { |  | ||||||
| 	if(uid == "net.minecraft") |  | ||||||
| 	{ |  | ||||||
| 		return settings()->get("IntendedVersion").toString(); |  | ||||||
| 	} |  | ||||||
| 	else if(uid == "org.lwjgl") |  | ||||||
| 	{ |  | ||||||
| 		return settings()->get("LWJGLVersion").toString(); |  | ||||||
| 	} |  | ||||||
| 	else if(uid == "net.minecraftforge") |  | ||||||
| 	{ |  | ||||||
| 		return settings()->get("ForgeVersion").toString(); |  | ||||||
| 	} |  | ||||||
| 	else if(uid == "com.mumfrey.liteloader") |  | ||||||
| 	{ |  | ||||||
| 		return settings()->get("LiteloaderVersion").toString(); |  | ||||||
| 	} |  | ||||||
| 	return QString(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QList< Mod > OneSixInstance::getJarMods() const |  | ||||||
| { |  | ||||||
| 	QList<Mod> mods; |  | ||||||
| 	for (auto jarmod : m_profile->getJarMods()) |  | ||||||
| 	{ |  | ||||||
| 		QStringList jar, temp1, temp2, temp3; |  | ||||||
| 		jarmod->getApplicableFiles(currentSystem, jar, temp1, temp2, temp3, jarmodsPath().absolutePath()); |  | ||||||
| 		// QString filePath = jarmodsPath().absoluteFilePath(jarmod->filename(currentSystem)); |  | ||||||
| 		mods.push_back(Mod(QFileInfo(jar[0]))); |  | ||||||
| 	} |  | ||||||
| 	return mods; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void OneSixInstance::setShouldUpdate(bool) |  | ||||||
| { |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool OneSixInstance::shouldUpdate() const |  | ||||||
| { |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QString OneSixInstance::currentVersionId() const |  | ||||||
| { |  | ||||||
| 	return intendedVersionId(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void OneSixInstance::reloadProfile() |  | ||||||
| { |  | ||||||
| 	m_profile->reload(); |  | ||||||
| 	setVersionBroken(m_profile->getProblemSeverity() == ProblemSeverity::Error); |  | ||||||
| 	emit versionReloaded(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void OneSixInstance::clearProfile() |  | ||||||
| { |  | ||||||
| 	m_profile->clear(); |  | ||||||
| 	emit versionReloaded(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::shared_ptr<MinecraftProfile> OneSixInstance::getMinecraftProfile() const |  | ||||||
| { |  | ||||||
| 	return m_profile; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QDir OneSixInstance::librariesPath() const |  | ||||||
| { |  | ||||||
| 	return QDir::current().absoluteFilePath("libraries"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QDir OneSixInstance::jarmodsPath() const |  | ||||||
| { |  | ||||||
| 	return QDir(jarModsDir()); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QDir OneSixInstance::versionsPath() const |  | ||||||
| { |  | ||||||
| 	return QDir::current().absoluteFilePath("versions"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool OneSixInstance::providesVersionFile() const |  | ||||||
| { |  | ||||||
| 	return false; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool OneSixInstance::reload() |  | ||||||
| { |  | ||||||
| 	if (BaseInstance::reload()) |  | ||||||
| 	{ |  | ||||||
| 		try |  | ||||||
| 		{ |  | ||||||
| 			reloadProfile(); |  | ||||||
| 			return true; |  | ||||||
| 		} |  | ||||||
| 		catch (...) |  | ||||||
| 		{ |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return false; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QString OneSixInstance::loaderModsDir() const |  | ||||||
| { |  | ||||||
| 	return FS::PathCombine(minecraftRoot(), "mods"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QString OneSixInstance::coreModsDir() const |  | ||||||
| { |  | ||||||
| 	return FS::PathCombine(minecraftRoot(), "coremods"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QString OneSixInstance::resourcePacksDir() const |  | ||||||
| { |  | ||||||
| 	return FS::PathCombine(minecraftRoot(), "resourcepacks"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QString OneSixInstance::texturePacksDir() const |  | ||||||
| { |  | ||||||
| 	return FS::PathCombine(minecraftRoot(), "texturepacks"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QString OneSixInstance::instanceConfigFolder() const |  | ||||||
| { |  | ||||||
| 	return FS::PathCombine(minecraftRoot(), "config"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QString OneSixInstance::jarModsDir() const |  | ||||||
| { |  | ||||||
| 	return FS::PathCombine(instanceRoot(), "jarmods"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QString OneSixInstance::FMLlibDir() const |  | ||||||
| { |  | ||||||
| 	return FS::PathCombine(minecraftRoot(), "lib"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QString OneSixInstance::customLibrariesDir() const |  | ||||||
| { |  | ||||||
| 	return FS::PathCombine(instanceRoot(), "libraries"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QString OneSixInstance::worldDir() const |  | ||||||
| { |  | ||||||
| 	return FS::PathCombine(minecraftRoot(), "saves"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QStringList OneSixInstance::extraArguments() const |  | ||||||
| { |  | ||||||
| 	auto list = BaseInstance::extraArguments(); |  | ||||||
| 	auto version = getMinecraftProfile(); |  | ||||||
| 	if (!version) |  | ||||||
| 		return list; |  | ||||||
| 	auto jarMods = getJarMods(); |  | ||||||
| 	if (!jarMods.isEmpty()) |  | ||||||
| 	{ |  | ||||||
| 		list.append({"-Dfml.ignoreInvalidMinecraftCertificates=true", |  | ||||||
| 					 "-Dfml.ignorePatchDiscrepancies=true"}); |  | ||||||
| 	} |  | ||||||
| 	return list; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::shared_ptr<OneSixInstance> OneSixInstance::getSharedPtr() |  | ||||||
| { |  | ||||||
| 	return std::dynamic_pointer_cast<OneSixInstance>(BaseInstance::getSharedPtr()); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QString OneSixInstance::typeName() const |  | ||||||
| { |  | ||||||
| 	return tr("OneSix"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QStringList OneSixInstance::validLaunchMethods() |  | ||||||
| { |  | ||||||
| 	return {"LauncherPart", "DirectJava"}; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QStringList OneSixInstance::getClassPath() const |  | ||||||
| { |  | ||||||
| 	QStringList jars, nativeJars; |  | ||||||
| 	auto javaArchitecture = settings()->get("JavaArchitecture").toString(); |  | ||||||
| 	m_profile->getLibraryFiles(javaArchitecture, jars, nativeJars, getLocalLibraryPath(), binRoot()); |  | ||||||
| 	return jars; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QString OneSixInstance::getMainClass() const |  | ||||||
| { |  | ||||||
| 	return m_profile->getMainClass(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| QStringList OneSixInstance::getNativeJars() const |  | ||||||
| { |  | ||||||
| 	QStringList jars, nativeJars; |  | ||||||
| 	auto javaArchitecture = settings()->get("JavaArchitecture").toString(); |  | ||||||
| 	m_profile->getLibraryFiles(javaArchitecture, jars, nativeJars, getLocalLibraryPath(), binRoot()); |  | ||||||
| 	return nativeJars; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #include "OneSixInstance.moc" |  | ||||||
| @@ -1,128 +0,0 @@ | |||||||
| /* Copyright 2013-2017 MultiMC Contributors |  | ||||||
|  * |  | ||||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); |  | ||||||
|  * you may not use this file except in compliance with the License. |  | ||||||
|  * You may obtain a copy of the License at |  | ||||||
|  * |  | ||||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 |  | ||||||
|  * |  | ||||||
|  * Unless required by applicable law or agreed to in writing, software |  | ||||||
|  * distributed under the License is distributed on an "AS IS" BASIS, |  | ||||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |  | ||||||
|  * See the License for the specific language governing permissions and |  | ||||||
|  * limitations under the License. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include "minecraft/MinecraftInstance.h" |  | ||||||
|  |  | ||||||
| #include "minecraft/MinecraftProfile.h" |  | ||||||
| #include "minecraft/ModList.h" |  | ||||||
|  |  | ||||||
| #include "multimc_logic_export.h" |  | ||||||
|  |  | ||||||
| class MULTIMC_LOGIC_EXPORT OneSixInstance : public MinecraftInstance |  | ||||||
| { |  | ||||||
| 	Q_OBJECT |  | ||||||
| public: |  | ||||||
| 	explicit OneSixInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir); |  | ||||||
| 	virtual ~OneSixInstance(){}; |  | ||||||
|  |  | ||||||
| 	virtual void init() override; |  | ||||||
|  |  | ||||||
| 	//////  Mod Lists  ////// |  | ||||||
| 	std::shared_ptr<ModList> loaderModList() const; |  | ||||||
| 	std::shared_ptr<ModList> coreModList() const; |  | ||||||
| 	std::shared_ptr<ModList> resourcePackList() const override; |  | ||||||
| 	std::shared_ptr<ModList> texturePackList() const override; |  | ||||||
| 	std::shared_ptr<WorldList> worldList() const override; |  | ||||||
| 	virtual QList<Mod> getJarMods() const override; |  | ||||||
| 	virtual void createProfile(); |  | ||||||
|  |  | ||||||
| 	virtual QSet<QString> traits() override; |  | ||||||
|  |  | ||||||
| 	////// Directories and files ////// |  | ||||||
| 	QString jarModsDir() const; |  | ||||||
| 	QString resourcePacksDir() const; |  | ||||||
| 	QString texturePacksDir() const; |  | ||||||
| 	QString loaderModsDir() const; |  | ||||||
| 	QString coreModsDir() const; |  | ||||||
| 	QString FMLlibDir() const; |  | ||||||
| 	QString customLibrariesDir() const; |  | ||||||
| 	QString worldDir() const; |  | ||||||
| 	virtual QString instanceConfigFolder() const override; |  | ||||||
|  |  | ||||||
| 	virtual shared_qobject_ptr<Task> createUpdateTask() override; |  | ||||||
| 	virtual std::shared_ptr<Task> createJarModdingTask() override; |  | ||||||
| 	virtual QString createLaunchScript(AuthSessionPtr session) override; |  | ||||||
| 	QStringList verboseDescription(AuthSessionPtr session) override; |  | ||||||
|  |  | ||||||
| 	virtual QString intendedVersionId() const override; |  | ||||||
| 	virtual bool setIntendedVersionId(QString version) override; |  | ||||||
| 	virtual QString currentVersionId() const override; |  | ||||||
|  |  | ||||||
| 	QString getComponentVersion(const QString &uid) const; |  | ||||||
| 	bool setComponentVersion(const QString &uid, const QString &version); |  | ||||||
|  |  | ||||||
| 	virtual bool shouldUpdate() const override; |  | ||||||
| 	virtual void setShouldUpdate(bool val) override; |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * reload the profile, including version json files. |  | ||||||
| 	 * |  | ||||||
| 	 * throws various exceptions :3 |  | ||||||
| 	 */ |  | ||||||
| 	void reloadProfile(); |  | ||||||
|  |  | ||||||
| 	/// clears all version information in preparation for an update |  | ||||||
| 	void clearProfile(); |  | ||||||
|  |  | ||||||
| 	/// get the current full version info |  | ||||||
| 	std::shared_ptr<MinecraftProfile> getMinecraftProfile() const; |  | ||||||
|  |  | ||||||
| 	virtual QDir jarmodsPath() const; |  | ||||||
| 	virtual QDir librariesPath() const; |  | ||||||
| 	virtual QDir versionsPath() const; |  | ||||||
| 	virtual bool providesVersionFile() const; |  | ||||||
|  |  | ||||||
| 	bool reload() override; |  | ||||||
|  |  | ||||||
| 	virtual QStringList extraArguments() const override; |  | ||||||
|  |  | ||||||
| 	std::shared_ptr<OneSixInstance> getSharedPtr(); |  | ||||||
|  |  | ||||||
| 	virtual QString typeName() const override; |  | ||||||
|  |  | ||||||
| 	bool canExport() const override |  | ||||||
| 	{ |  | ||||||
| 		return true; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	QStringList getClassPath() const override; |  | ||||||
| 	QString getMainClass() const override; |  | ||||||
|  |  | ||||||
| 	QStringList getNativeJars() const override; |  | ||||||
| 	QString getNativePath() const override; |  | ||||||
|  |  | ||||||
| 	QString getLocalLibraryPath() const override; |  | ||||||
|  |  | ||||||
| 	QStringList processMinecraftArgs(AuthSessionPtr account) const override; |  | ||||||
|  |  | ||||||
| protected: |  | ||||||
| 	std::shared_ptr<LaunchStep> createMainLaunchStep(LaunchTask *parent, AuthSessionPtr session) override; |  | ||||||
| 	QStringList validLaunchMethods() override; |  | ||||||
|  |  | ||||||
| signals: |  | ||||||
| 	void versionReloaded(); |  | ||||||
|  |  | ||||||
| protected: |  | ||||||
| 	std::shared_ptr<MinecraftProfile> m_profile; |  | ||||||
| 	mutable std::shared_ptr<ModList> m_loader_mod_list; |  | ||||||
| 	mutable std::shared_ptr<ModList> m_core_mod_list; |  | ||||||
| 	mutable std::shared_ptr<ModList> m_resource_pack_list; |  | ||||||
| 	mutable std::shared_ptr<ModList> m_texture_pack_list; |  | ||||||
| 	mutable std::shared_ptr<WorldList> m_world_list; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| Q_DECLARE_METATYPE(std::shared_ptr<OneSixInstance>) |  | ||||||
| @@ -1,471 +0,0 @@ | |||||||
| #include "OneSixProfileStrategy.h" |  | ||||||
| #include "OneSixInstance.h" |  | ||||||
| #include "OneSixVersionFormat.h" |  | ||||||
|  |  | ||||||
| #include "Env.h" |  | ||||||
| #include <FileSystem.h> |  | ||||||
|  |  | ||||||
| #include <QDir> |  | ||||||
| #include <QUuid> |  | ||||||
| #include <QJsonDocument> |  | ||||||
| #include <QJsonArray> |  | ||||||
| #include <QSaveFile> |  | ||||||
| #include <QResource> |  | ||||||
| #include <meta/Index.h> |  | ||||||
| #include <meta/Version.h> |  | ||||||
|  |  | ||||||
| #include <tuple> |  | ||||||
|  |  | ||||||
| OneSixProfileStrategy::OneSixProfileStrategy(OneSixInstance* instance) |  | ||||||
| { |  | ||||||
| 	m_instance = instance; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void OneSixProfileStrategy::upgradeDeprecatedFiles() |  | ||||||
| { |  | ||||||
| 	auto versionJsonPath = FS::PathCombine(m_instance->instanceRoot(), "version.json"); |  | ||||||
| 	auto customJsonPath = FS::PathCombine(m_instance->instanceRoot(), "custom.json"); |  | ||||||
| 	auto mcJson = FS::PathCombine(m_instance->instanceRoot(), "patches" , "net.minecraft.json"); |  | ||||||
|  |  | ||||||
| 	QString sourceFile; |  | ||||||
| 	QString renameFile; |  | ||||||
|  |  | ||||||
| 	// convert old crap. |  | ||||||
| 	if(QFile::exists(customJsonPath)) |  | ||||||
| 	{ |  | ||||||
| 		sourceFile = customJsonPath; |  | ||||||
| 		renameFile = versionJsonPath; |  | ||||||
| 	} |  | ||||||
| 	else if(QFile::exists(versionJsonPath)) |  | ||||||
| 	{ |  | ||||||
| 		sourceFile = versionJsonPath; |  | ||||||
| 	} |  | ||||||
| 	if(!sourceFile.isEmpty() && !QFile::exists(mcJson)) |  | ||||||
| 	{ |  | ||||||
| 		if(!FS::ensureFilePathExists(mcJson)) |  | ||||||
| 		{ |  | ||||||
| 			qWarning() << "Couldn't create patches folder for" << m_instance->name(); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
| 		if(!renameFile.isEmpty() && QFile::exists(renameFile)) |  | ||||||
| 		{ |  | ||||||
| 			if(!QFile::rename(renameFile, renameFile + ".old")) |  | ||||||
| 			{ |  | ||||||
| 				qWarning() << "Couldn't rename" << renameFile << "to" << renameFile + ".old" << "in" << m_instance->name(); |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		auto file = ProfileUtils::parseJsonFile(QFileInfo(sourceFile), false); |  | ||||||
| 		ProfileUtils::removeLwjglFromPatch(file); |  | ||||||
| 		file->uid = "net.minecraft"; |  | ||||||
| 		file->version = file->minecraftVersion; |  | ||||||
| 		file->name = "Minecraft"; |  | ||||||
| 		auto data = OneSixVersionFormat::versionFileToJson(file, false).toJson(); |  | ||||||
| 		QSaveFile newPatchFile(mcJson); |  | ||||||
| 		if(!newPatchFile.open(QIODevice::WriteOnly)) |  | ||||||
| 		{ |  | ||||||
| 			newPatchFile.cancelWriting(); |  | ||||||
| 			qWarning() << "Couldn't open main patch for writing in" << m_instance->name(); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
| 		newPatchFile.write(data); |  | ||||||
| 		if(!newPatchFile.commit()) |  | ||||||
| 		{ |  | ||||||
| 			qWarning() << "Couldn't save main patch in" << m_instance->name(); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
| 		if(!QFile::rename(sourceFile, sourceFile + ".old")) |  | ||||||
| 		{ |  | ||||||
| 			qWarning() << "Couldn't rename" << sourceFile << "to" << sourceFile + ".old" << "in" << m_instance->name(); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void OneSixProfileStrategy::loadDefaultBuiltinPatches() |  | ||||||
| { |  | ||||||
| 	auto addBuiltinPatch = [&](const QString &uid, const QString intendedVersion, int order) |  | ||||||
| 	{ |  | ||||||
| 		auto jsonFilePath = FS::PathCombine(m_instance->instanceRoot(), "patches" , uid + ".json"); |  | ||||||
| 		// load up the base minecraft patch |  | ||||||
| 		ProfilePatchPtr profilePatch; |  | ||||||
| 		if(QFile::exists(jsonFilePath)) |  | ||||||
| 		{ |  | ||||||
| 			auto file = ProfileUtils::parseJsonFile(QFileInfo(jsonFilePath), false); |  | ||||||
| 			if(file->version.isEmpty()) |  | ||||||
| 			{ |  | ||||||
| 				file->version = intendedVersion; |  | ||||||
| 			} |  | ||||||
| 			profilePatch = std::make_shared<ProfilePatch>(file, jsonFilePath); |  | ||||||
| 			profilePatch->setVanilla(false); |  | ||||||
| 			profilePatch->setRevertible(true); |  | ||||||
| 		} |  | ||||||
| 		else |  | ||||||
| 		{ |  | ||||||
| 			auto metaVersion = ENV.metadataIndex()->get(uid, intendedVersion); |  | ||||||
| 			profilePatch = std::make_shared<ProfilePatch>(metaVersion); |  | ||||||
| 			profilePatch->setVanilla(true); |  | ||||||
| 		} |  | ||||||
| 		profilePatch->setOrder(order); |  | ||||||
| 		profile->appendPatch(profilePatch); |  | ||||||
| 	}; |  | ||||||
| 	addBuiltinPatch("net.minecraft", m_instance->getComponentVersion("net.minecraft"), -2); |  | ||||||
| 	addBuiltinPatch("org.lwjgl", m_instance->getComponentVersion("org.lwjgl"), -1); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void OneSixProfileStrategy::loadUserPatches() |  | ||||||
| { |  | ||||||
| 	// first, collect all patches (that are not builtins of OneSix) and load them |  | ||||||
| 	QMap<QString, ProfilePatchPtr> loadedPatches; |  | ||||||
| 	QDir patchesDir(FS::PathCombine(m_instance->instanceRoot(),"patches")); |  | ||||||
| 	for (auto info : patchesDir.entryInfoList(QStringList() << "*.json", QDir::Files)) |  | ||||||
| 	{ |  | ||||||
| 		// parse the file |  | ||||||
| 		qDebug() << "Reading" << info.fileName(); |  | ||||||
| 		auto file = ProfileUtils::parseJsonFile(info, true); |  | ||||||
| 		// ignore builtins |  | ||||||
| 		if (file->uid == "net.minecraft") |  | ||||||
| 			continue; |  | ||||||
| 		if (file->uid == "org.lwjgl") |  | ||||||
| 			continue; |  | ||||||
| 		auto patch = std::make_shared<ProfilePatch>(file, info.filePath()); |  | ||||||
| 		patch->setRemovable(true); |  | ||||||
| 		patch->setMovable(true); |  | ||||||
| 		if(ENV.metadataIndex()->hasUid(file->uid)) |  | ||||||
| 		{ |  | ||||||
| 			// FIXME: requesting a uid/list creates it in the index... this allows reverting to possibly invalid versions... |  | ||||||
| 			patch->setRevertible(true); |  | ||||||
| 		} |  | ||||||
| 		loadedPatches[file->uid] = patch; |  | ||||||
| 	} |  | ||||||
| 	// these are 'special'... if not already loaded from instance files, grab them from the metadata repo. |  | ||||||
| 	auto loadSpecial = [&](const QString & uid, int order) |  | ||||||
| 	{ |  | ||||||
| 		auto patchVersion = m_instance->getComponentVersion(uid); |  | ||||||
| 		if(!patchVersion.isEmpty() && !loadedPatches.contains(uid)) |  | ||||||
| 		{ |  | ||||||
| 			auto patch = std::make_shared<ProfilePatch>(ENV.metadataIndex()->get(uid, patchVersion)); |  | ||||||
| 			patch->setOrder(order); |  | ||||||
| 			patch->setVanilla(true); |  | ||||||
| 			patch->setRemovable(true); |  | ||||||
| 			patch->setMovable(true); |  | ||||||
| 			loadedPatches[uid] = patch; |  | ||||||
| 		} |  | ||||||
| 	}; |  | ||||||
| 	loadSpecial("net.minecraftforge", 5); |  | ||||||
| 	loadSpecial("com.mumfrey.liteloader", 10); |  | ||||||
|  |  | ||||||
| 	// now add all the patches by user sort order |  | ||||||
| 	ProfileUtils::PatchOrder userOrder; |  | ||||||
| 	ProfileUtils::readOverrideOrders(FS::PathCombine(m_instance->instanceRoot(), "order.json"), userOrder); |  | ||||||
| 	for (auto uid : userOrder) |  | ||||||
| 	{ |  | ||||||
| 		// ignore builtins |  | ||||||
| 		if (uid == "net.minecraft") |  | ||||||
| 			continue; |  | ||||||
| 		if (uid == "org.lwjgl") |  | ||||||
| 			continue; |  | ||||||
| 		// ordering has a patch that is gone? |  | ||||||
| 		if(!loadedPatches.contains(uid)) |  | ||||||
| 		{ |  | ||||||
| 			continue; |  | ||||||
| 		} |  | ||||||
| 		profile->appendPatch(loadedPatches.take(uid)); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// is there anything left to sort? |  | ||||||
| 	if(loadedPatches.isEmpty()) |  | ||||||
| 	{ |  | ||||||
| 		// TODO: save the order here? |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// inserting into multimap by order number as key sorts the patches and detects duplicates |  | ||||||
| 	QMultiMap<int, ProfilePatchPtr> files; |  | ||||||
| 	auto iter = loadedPatches.begin(); |  | ||||||
| 	while(iter != loadedPatches.end()) |  | ||||||
| 	{ |  | ||||||
| 		files.insert((*iter)->getOrder(), *iter); |  | ||||||
| 		iter++; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// then just extract the patches and put them in the list |  | ||||||
| 	for (auto order : files.keys()) |  | ||||||
| 	{ |  | ||||||
| 		const auto &values = files.values(order); |  | ||||||
| 		for(auto &value: values) |  | ||||||
| 		{ |  | ||||||
| 			// TODO: put back the insertion of problem messages here, so the user knows about the id duplication |  | ||||||
| 			profile->appendPatch(value); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	// TODO: save the order here? |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| void OneSixProfileStrategy::load() |  | ||||||
| { |  | ||||||
| 	profile->clearPatches(); |  | ||||||
|  |  | ||||||
| 	upgradeDeprecatedFiles(); |  | ||||||
| 	loadDefaultBuiltinPatches(); |  | ||||||
| 	loadUserPatches(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool OneSixProfileStrategy::saveOrder(ProfileUtils::PatchOrder order) |  | ||||||
| { |  | ||||||
| 	return ProfileUtils::writeOverrideOrders(FS::PathCombine(m_instance->instanceRoot(), "order.json"), order); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool OneSixProfileStrategy::resetOrder() |  | ||||||
| { |  | ||||||
| 	return QDir(m_instance->instanceRoot()).remove("order.json"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool OneSixProfileStrategy::removePatch(ProfilePatchPtr patch) |  | ||||||
| { |  | ||||||
| 	bool ok = true; |  | ||||||
| 	// first, remove the patch file. this ensures it's not used anymore |  | ||||||
| 	auto fileName = patch->getFilename(); |  | ||||||
| 	if(fileName.size()) |  | ||||||
| 	{ |  | ||||||
| 		QFile patchFile(fileName); |  | ||||||
| 		if(patchFile.exists() && !patchFile.remove()) |  | ||||||
| 		{ |  | ||||||
| 			qCritical() << "File" << fileName << "could not be removed because:" << patchFile.errorString(); |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	if(!m_instance->getComponentVersion(patch->getID()).isEmpty()) |  | ||||||
| 	{ |  | ||||||
| 		m_instance->setComponentVersion(patch->getID(), QString()); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// FIXME: we need a generic way of removing local resources, not just jar mods... |  | ||||||
| 	auto preRemoveJarMod = [&](LibraryPtr jarMod) -> bool |  | ||||||
| 	{ |  | ||||||
| 		if (!jarMod->isLocal()) |  | ||||||
| 		{ |  | ||||||
| 			return true; |  | ||||||
| 		} |  | ||||||
| 		QStringList jar, temp1, temp2, temp3; |  | ||||||
| 		jarMod->getApplicableFiles(currentSystem, jar, temp1, temp2, temp3, m_instance->jarmodsPath().absolutePath()); |  | ||||||
| 		QFileInfo finfo (jar[0]); |  | ||||||
| 		if(finfo.exists()) |  | ||||||
| 		{ |  | ||||||
| 			QFile jarModFile(jar[0]); |  | ||||||
| 			if(!jarModFile.remove()) |  | ||||||
| 			{ |  | ||||||
| 				qCritical() << "File" << jar[0] << "could not be removed because:" << jarModFile.errorString(); |  | ||||||
| 				return false; |  | ||||||
| 			} |  | ||||||
| 			return true; |  | ||||||
| 		} |  | ||||||
| 		return true; |  | ||||||
| 	}; |  | ||||||
|  |  | ||||||
| 	auto &jarMods = patch->getVersionFile()->jarMods; |  | ||||||
| 	for(auto &jarmod: jarMods) |  | ||||||
| 	{ |  | ||||||
| 		ok &= preRemoveJarMod(jarmod); |  | ||||||
| 	} |  | ||||||
| 	return ok; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool OneSixProfileStrategy::customizePatch(ProfilePatchPtr patch) |  | ||||||
| { |  | ||||||
| 	if(patch->isCustom()) |  | ||||||
| 	{ |  | ||||||
| 		return false; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	auto filename = FS::PathCombine(m_instance->instanceRoot(), "patches" , patch->getID() + ".json"); |  | ||||||
| 	if(!FS::ensureFilePathExists(filename)) |  | ||||||
| 	{ |  | ||||||
| 		return false; |  | ||||||
| 	} |  | ||||||
| 	// FIXME: get rid of this try-catch. |  | ||||||
| 	try |  | ||||||
| 	{ |  | ||||||
| 		QSaveFile jsonFile(filename); |  | ||||||
| 		if(!jsonFile.open(QIODevice::WriteOnly)) |  | ||||||
| 		{ |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
| 		auto vfile = patch->getVersionFile(); |  | ||||||
| 		if(!vfile) |  | ||||||
| 		{ |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
| 		auto document = OneSixVersionFormat::versionFileToJson(vfile, true); |  | ||||||
| 		jsonFile.write(document.toJson()); |  | ||||||
| 		if(!jsonFile.commit()) |  | ||||||
| 		{ |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
| 		load(); |  | ||||||
| 	} |  | ||||||
| 	catch (Exception &error) |  | ||||||
| 	{ |  | ||||||
| 		qWarning() << "Version could not be loaded:" << error.cause(); |  | ||||||
| 	} |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool OneSixProfileStrategy::revertPatch(ProfilePatchPtr patch) |  | ||||||
| { |  | ||||||
| 	if(!patch->isCustom()) |  | ||||||
| 	{ |  | ||||||
| 		// already not custom |  | ||||||
| 		return true; |  | ||||||
| 	} |  | ||||||
| 	auto filename = patch->getFilename(); |  | ||||||
| 	if(!QFile::exists(filename)) |  | ||||||
| 	{ |  | ||||||
| 		// already gone / not custom |  | ||||||
| 		return true; |  | ||||||
| 	} |  | ||||||
| 	// just kill the file and reload |  | ||||||
| 	bool result = QFile::remove(filename); |  | ||||||
| 	// FIXME: get rid of this try-catch. |  | ||||||
| 	try |  | ||||||
| 	{ |  | ||||||
| 		load(); |  | ||||||
| 	} |  | ||||||
| 	catch (Exception &error) |  | ||||||
| 	{ |  | ||||||
| 		qWarning() << "Version could not be loaded:" << error.cause(); |  | ||||||
| 	} |  | ||||||
| 	return result; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool OneSixProfileStrategy::installJarMods(QStringList filepaths) |  | ||||||
| { |  | ||||||
| 	QString patchDir = FS::PathCombine(m_instance->instanceRoot(), "patches"); |  | ||||||
| 	if(!FS::ensureFolderPathExists(patchDir)) |  | ||||||
| 	{ |  | ||||||
| 		return false; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (!FS::ensureFolderPathExists(m_instance->jarModsDir())) |  | ||||||
| 	{ |  | ||||||
| 		return false; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for(auto filepath:filepaths) |  | ||||||
| 	{ |  | ||||||
| 		QFileInfo sourceInfo(filepath); |  | ||||||
| 		auto uuid = QUuid::createUuid(); |  | ||||||
| 		QString id = uuid.toString().remove('{').remove('}'); |  | ||||||
| 		QString target_filename = id + ".jar"; |  | ||||||
| 		QString target_id = "org.multimc.jarmod." + id; |  | ||||||
| 		QString target_name = sourceInfo.completeBaseName() + " (jar mod)"; |  | ||||||
| 		QString finalPath = FS::PathCombine(m_instance->jarModsDir(), target_filename); |  | ||||||
|  |  | ||||||
| 		QFileInfo targetInfo(finalPath); |  | ||||||
| 		if(targetInfo.exists()) |  | ||||||
| 		{ |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (!QFile::copy(sourceInfo.absoluteFilePath(),QFileInfo(finalPath).absoluteFilePath())) |  | ||||||
| 		{ |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		auto f = std::make_shared<VersionFile>(); |  | ||||||
| 		auto jarMod = std::make_shared<Library>(); |  | ||||||
| 		jarMod->setRawName(GradleSpecifier("org.multimc.jarmods:" + id + ":1")); |  | ||||||
| 		jarMod->setFilename(target_filename); |  | ||||||
| 		jarMod->setDisplayName(sourceInfo.completeBaseName()); |  | ||||||
| 		jarMod->setHint("local"); |  | ||||||
| 		f->jarMods.append(jarMod); |  | ||||||
| 		f->name = target_name; |  | ||||||
| 		f->uid = target_id; |  | ||||||
| 		f->order = profile->getFreeOrderNumber(); |  | ||||||
| 		QString patchFileName = FS::PathCombine(patchDir, target_id + ".json"); |  | ||||||
|  |  | ||||||
| 		QFile file(patchFileName); |  | ||||||
| 		if (!file.open(QFile::WriteOnly)) |  | ||||||
| 		{ |  | ||||||
| 			qCritical() << "Error opening" << file.fileName() |  | ||||||
| 						<< "for reading:" << file.errorString(); |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
| 		file.write(OneSixVersionFormat::versionFileToJson(f, true).toJson()); |  | ||||||
| 		file.close(); |  | ||||||
|  |  | ||||||
| 		auto patch = std::make_shared<ProfilePatch>(f, patchFileName); |  | ||||||
| 		patch->setMovable(true); |  | ||||||
| 		patch->setRemovable(true); |  | ||||||
| 		profile->appendPatch(patch); |  | ||||||
| 	} |  | ||||||
| 	profile->saveCurrentOrder(); |  | ||||||
| 	profile->reapplyPatches(); |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool OneSixProfileStrategy::installCustomJar(QString filepath) |  | ||||||
| { |  | ||||||
| 	QString patchDir = FS::PathCombine(m_instance->instanceRoot(), "patches"); |  | ||||||
| 	if(!FS::ensureFolderPathExists(patchDir)) |  | ||||||
| 	{ |  | ||||||
| 		return false; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	QString libDir = m_instance->customLibrariesDir(); |  | ||||||
| 	if (!FS::ensureFolderPathExists(libDir)) |  | ||||||
| 	{ |  | ||||||
| 		return false; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	auto specifier = GradleSpecifier("org.multimc:customjar:1"); |  | ||||||
| 	QFileInfo sourceInfo(filepath); |  | ||||||
| 	QString target_filename = specifier.getFileName(); |  | ||||||
| 	QString target_id = specifier.artifactId(); |  | ||||||
| 	QString target_name = sourceInfo.completeBaseName() + " (custom jar)"; |  | ||||||
| 	QString finalPath = FS::PathCombine(libDir, target_filename); |  | ||||||
|  |  | ||||||
| 	QFileInfo jarInfo(finalPath); |  | ||||||
| 	if (jarInfo.exists()) |  | ||||||
| 	{ |  | ||||||
| 		if(!QFile::remove(finalPath)) |  | ||||||
| 		{ |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	if (!QFile::copy(filepath, finalPath)) |  | ||||||
| 	{ |  | ||||||
| 		return false; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	auto f = std::make_shared<VersionFile>(); |  | ||||||
| 	auto jarMod = std::make_shared<Library>(); |  | ||||||
| 	jarMod->setRawName(specifier); |  | ||||||
| 	jarMod->setDisplayName(sourceInfo.completeBaseName()); |  | ||||||
| 	jarMod->setHint("local"); |  | ||||||
| 	f->mainJar = jarMod; |  | ||||||
| 	f->name = target_name; |  | ||||||
| 	f->uid = target_id; |  | ||||||
| 	f->order = profile->getFreeOrderNumber(); |  | ||||||
| 	QString patchFileName = FS::PathCombine(patchDir, target_id + ".json"); |  | ||||||
|  |  | ||||||
| 	QFile file(patchFileName); |  | ||||||
| 	if (!file.open(QFile::WriteOnly)) |  | ||||||
| 	{ |  | ||||||
| 		qCritical() << "Error opening" << file.fileName() |  | ||||||
| 					<< "for reading:" << file.errorString(); |  | ||||||
| 		return false; |  | ||||||
| 	} |  | ||||||
| 	file.write(OneSixVersionFormat::versionFileToJson(f, true).toJson()); |  | ||||||
| 	file.close(); |  | ||||||
|  |  | ||||||
| 	auto patch = std::make_shared<ProfilePatch>(f, patchFileName); |  | ||||||
| 	patch->setMovable(true); |  | ||||||
| 	patch->setRemovable(true); |  | ||||||
| 	profile->appendPatch(patch); |  | ||||||
|  |  | ||||||
| 	profile->saveCurrentOrder(); |  | ||||||
| 	profile->reapplyPatches(); |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
| @@ -1,27 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include "minecraft/ProfileStrategy.h" |  | ||||||
|  |  | ||||||
| class OneSixInstance; |  | ||||||
|  |  | ||||||
| class OneSixProfileStrategy : public ProfileStrategy |  | ||||||
| { |  | ||||||
| public: |  | ||||||
| 	OneSixProfileStrategy(OneSixInstance * instance); |  | ||||||
| 	virtual ~OneSixProfileStrategy() {}; |  | ||||||
| 	void load() override; |  | ||||||
| 	bool resetOrder() override; |  | ||||||
| 	bool saveOrder(ProfileUtils::PatchOrder order) override; |  | ||||||
| 	bool installJarMods(QStringList filepaths) override; |  | ||||||
| 	bool installCustomJar(QString filepath) override; |  | ||||||
| 	bool removePatch(ProfilePatchPtr patch) override; |  | ||||||
| 	bool customizePatch(ProfilePatchPtr patch) override; |  | ||||||
| 	bool revertPatch(ProfilePatchPtr patch) override; |  | ||||||
|  |  | ||||||
| protected: |  | ||||||
| 	virtual void loadDefaultBuiltinPatches(); |  | ||||||
| 	virtual void loadUserPatches(); |  | ||||||
| 	void upgradeDeprecatedFiles(); |  | ||||||
|  |  | ||||||
| protected: |  | ||||||
| 	OneSixInstance *m_instance; |  | ||||||
| }; |  | ||||||
| @@ -1,10 +1,11 @@ | |||||||
| #include "Env.h" | #include "Env.h" | ||||||
| #include "AssetUpdateTask.h" | #include "AssetUpdateTask.h" | ||||||
| #include "minecraft/onesix/OneSixInstance.h" | #include "minecraft/MinecraftInstance.h" | ||||||
|  | #include "minecraft/MinecraftProfile.h" | ||||||
| #include "net/ChecksumValidator.h" | #include "net/ChecksumValidator.h" | ||||||
| #include "minecraft/AssetsUtils.h" | #include "minecraft/AssetsUtils.h" | ||||||
| 
 | 
 | ||||||
| AssetUpdateTask::AssetUpdateTask(OneSixInstance * inst) | AssetUpdateTask::AssetUpdateTask(MinecraftInstance * inst) | ||||||
| { | { | ||||||
| 	m_inst = inst; | 	m_inst = inst; | ||||||
| } | } | ||||||
| @@ -1,13 +1,13 @@ | |||||||
| #pragma once | #pragma once | ||||||
| #include "tasks/Task.h" | #include "tasks/Task.h" | ||||||
| #include "net/NetJob.h" | #include "net/NetJob.h" | ||||||
| class OneSixInstance; | class MinecraftInstance; | ||||||
| 
 | 
 | ||||||
| class AssetUpdateTask : public Task | class AssetUpdateTask : public Task | ||||||
| { | { | ||||||
| 	Q_OBJECT | 	Q_OBJECT | ||||||
| public: | public: | ||||||
| 	AssetUpdateTask(OneSixInstance * inst); | 	AssetUpdateTask(MinecraftInstance * inst); | ||||||
| 	void executeTask() override; | 	void executeTask() override; | ||||||
| 
 | 
 | ||||||
| 	bool canAbort() const override; | 	bool canAbort() const override; | ||||||
| @@ -21,6 +21,6 @@ public slots: | |||||||
| 	bool abort() override; | 	bool abort() override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| 	OneSixInstance *m_inst; | 	MinecraftInstance *m_inst; | ||||||
| 	NetJobPtr downloadJob; | 	NetJobPtr downloadJob; | ||||||
| }; | }; | ||||||
| @@ -2,17 +2,17 @@ | |||||||
| #include <FileSystem.h> | #include <FileSystem.h> | ||||||
| #include <minecraft/VersionFilterData.h> | #include <minecraft/VersionFilterData.h> | ||||||
| #include "FMLLibrariesTask.h" | #include "FMLLibrariesTask.h" | ||||||
| #include "minecraft/onesix/OneSixInstance.h" | #include "minecraft/MinecraftInstance.h" | ||||||
|  | #include "minecraft/MinecraftProfile.h" | ||||||
| 
 | 
 | ||||||
| 
 | FMLLibrariesTask::FMLLibrariesTask(MinecraftInstance * inst) | ||||||
| FMLLibrariesTask::FMLLibrariesTask(OneSixInstance * inst) |  | ||||||
| { | { | ||||||
| 	m_inst = inst; | 	m_inst = inst; | ||||||
| } | } | ||||||
| void FMLLibrariesTask::executeTask() | void FMLLibrariesTask::executeTask() | ||||||
| { | { | ||||||
| 	// Get the mod list
 | 	// Get the mod list
 | ||||||
| 	OneSixInstance *inst = (OneSixInstance *)m_inst; | 	MinecraftInstance *inst = (MinecraftInstance *)m_inst; | ||||||
| 	std::shared_ptr<MinecraftProfile> profile = inst->getMinecraftProfile(); | 	std::shared_ptr<MinecraftProfile> profile = inst->getMinecraftProfile(); | ||||||
| 	bool forge_present = false; | 	bool forge_present = false; | ||||||
| 
 | 
 | ||||||
| @@ -22,7 +22,7 @@ void FMLLibrariesTask::executeTask() | |||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	QString version = inst->intendedVersionId(); | 	QString version = inst->getComponentVersion("net.minecraft"); | ||||||
| 	auto &fmlLibsMapping = g_VersionFilterData.fmlLibsMapping; | 	auto &fmlLibsMapping = g_VersionFilterData.fmlLibsMapping; | ||||||
| 	if (!fmlLibsMapping.contains(version)) | 	if (!fmlLibsMapping.contains(version)) | ||||||
| 	{ | 	{ | ||||||
| @@ -45,7 +45,7 @@ void FMLLibrariesTask::executeTask() | |||||||
| 	// now check the lib folder inside the instance for files.
 | 	// now check the lib folder inside the instance for files.
 | ||||||
| 	for (auto &lib : libList) | 	for (auto &lib : libList) | ||||||
| 	{ | 	{ | ||||||
| 		QFileInfo libInfo(FS::PathCombine(inst->FMLlibDir(), lib.filename)); | 		QFileInfo libInfo(FS::PathCombine(inst->libDir(), lib.filename)); | ||||||
| 		if (libInfo.exists()) | 		if (libInfo.exists()) | ||||||
| 			continue; | 			continue; | ||||||
| 		fmlLibsToProcess.append(lib); | 		fmlLibsToProcess.append(lib); | ||||||
| @@ -88,20 +88,20 @@ void FMLLibrariesTask::fmllibsFinished() | |||||||
| 	if (!fmlLibsToProcess.isEmpty()) | 	if (!fmlLibsToProcess.isEmpty()) | ||||||
| 	{ | 	{ | ||||||
| 		setStatus(tr("Copying FML libraries into the instance...")); | 		setStatus(tr("Copying FML libraries into the instance...")); | ||||||
| 		OneSixInstance *inst = (OneSixInstance *)m_inst; | 		MinecraftInstance *inst = (MinecraftInstance *)m_inst; | ||||||
| 		auto metacache = ENV.metacache(); | 		auto metacache = ENV.metacache(); | ||||||
| 		int index = 0; | 		int index = 0; | ||||||
| 		for (auto &lib : fmlLibsToProcess) | 		for (auto &lib : fmlLibsToProcess) | ||||||
| 		{ | 		{ | ||||||
| 			progress(index, fmlLibsToProcess.size()); | 			progress(index, fmlLibsToProcess.size()); | ||||||
| 			auto entry = metacache->resolveEntry("fmllibs", lib.filename); | 			auto entry = metacache->resolveEntry("fmllibs", lib.filename); | ||||||
| 			auto path = FS::PathCombine(inst->FMLlibDir(), lib.filename); | 			auto path = FS::PathCombine(inst->libDir(), lib.filename); | ||||||
| 			if (!FS::ensureFilePathExists(path)) | 			if (!FS::ensureFilePathExists(path)) | ||||||
| 			{ | 			{ | ||||||
| 				emitFailed(tr("Failed creating FML library folder inside the instance.")); | 				emitFailed(tr("Failed creating FML library folder inside the instance.")); | ||||||
| 				return; | 				return; | ||||||
| 			} | 			} | ||||||
| 			if (!QFile::copy(entry->getFullPath(), FS::PathCombine(inst->FMLlibDir(), lib.filename))) | 			if (!QFile::copy(entry->getFullPath(), FS::PathCombine(inst->libDir(), lib.filename))) | ||||||
| 			{ | 			{ | ||||||
| 				emitFailed(tr("Failed copying Forge/FML library: %1.").arg(lib.filename)); | 				emitFailed(tr("Failed copying Forge/FML library: %1.").arg(lib.filename)); | ||||||
| 				return; | 				return; | ||||||
| @@ -1,13 +1,13 @@ | |||||||
| #pragma once | #pragma once | ||||||
| #include "tasks/Task.h" | #include "tasks/Task.h" | ||||||
| #include "net/NetJob.h" | #include "net/NetJob.h" | ||||||
| class OneSixInstance; | class MinecraftInstance; | ||||||
| 
 | 
 | ||||||
| class FMLLibrariesTask : public Task | class FMLLibrariesTask : public Task | ||||||
| { | { | ||||||
| 	Q_OBJECT | 	Q_OBJECT | ||||||
| public: | public: | ||||||
| 	FMLLibrariesTask(OneSixInstance * inst); | 	FMLLibrariesTask(MinecraftInstance * inst); | ||||||
| 
 | 
 | ||||||
| 	void executeTask() override; | 	void executeTask() override; | ||||||
| 
 | 
 | ||||||
| @@ -21,7 +21,7 @@ public slots: | |||||||
| 	bool abort() override; | 	bool abort() override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| 	OneSixInstance *m_inst; | 	MinecraftInstance *m_inst; | ||||||
| 	NetJobPtr downloadJob; | 	NetJobPtr downloadJob; | ||||||
| 	QList<FMLlib> fmlLibsToProcess; | 	QList<FMLlib> fmlLibsToProcess; | ||||||
| }; | }; | ||||||
| @@ -1,8 +1,8 @@ | |||||||
| #include "FoldersTask.h" | #include "FoldersTask.h" | ||||||
| #include "minecraft/onesix/OneSixInstance.h" | #include "minecraft/MinecraftInstance.h" | ||||||
| #include <QDir> | #include <QDir> | ||||||
| 
 | 
 | ||||||
| FoldersTask::FoldersTask(OneSixInstance * inst) | FoldersTask::FoldersTask(MinecraftInstance * inst) | ||||||
| 	:Task() | 	:Task() | ||||||
| { | { | ||||||
| 	m_inst = inst; | 	m_inst = inst; | ||||||
| @@ -2,14 +2,14 @@ | |||||||
| 
 | 
 | ||||||
| #include "tasks/Task.h" | #include "tasks/Task.h" | ||||||
| 
 | 
 | ||||||
| class OneSixInstance; | class MinecraftInstance; | ||||||
| class FoldersTask : public Task | class FoldersTask : public Task | ||||||
| { | { | ||||||
| 	Q_OBJECT | 	Q_OBJECT | ||||||
| public: | public: | ||||||
| 	FoldersTask(OneSixInstance * inst); | 	FoldersTask(MinecraftInstance * inst); | ||||||
| 	void executeTask() override; | 	void executeTask() override; | ||||||
| private: | private: | ||||||
| 	OneSixInstance *m_inst; | 	MinecraftInstance *m_inst; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @@ -1,8 +1,9 @@ | |||||||
| #include "Env.h" | #include "Env.h" | ||||||
| #include "LibrariesTask.h" | #include "LibrariesTask.h" | ||||||
| #include "minecraft/onesix/OneSixInstance.h" | #include "minecraft/MinecraftInstance.h" | ||||||
|  | #include "minecraft/MinecraftProfile.h" | ||||||
| 
 | 
 | ||||||
| LibrariesTask::LibrariesTask(OneSixInstance * inst) | LibrariesTask::LibrariesTask(MinecraftInstance * inst) | ||||||
| { | { | ||||||
| 	m_inst = inst; | 	m_inst = inst; | ||||||
| } | } | ||||||
| @@ -11,7 +12,7 @@ void LibrariesTask::executeTask() | |||||||
| { | { | ||||||
| 	setStatus(tr("Getting the library files from Mojang...")); | 	setStatus(tr("Getting the library files from Mojang...")); | ||||||
| 	qDebug() << m_inst->name() << ": downloading libraries"; | 	qDebug() << m_inst->name() << ": downloading libraries"; | ||||||
| 	OneSixInstance *inst = (OneSixInstance *)m_inst; | 	MinecraftInstance *inst = (MinecraftInstance *)m_inst; | ||||||
| 	inst->reloadProfile(); | 	inst->reloadProfile(); | ||||||
| 	if(inst->hasVersionBroken()) | 	if(inst->hasVersionBroken()) | ||||||
| 	{ | 	{ | ||||||
| @@ -1,13 +1,13 @@ | |||||||
| #pragma once | #pragma once | ||||||
| #include "tasks/Task.h" | #include "tasks/Task.h" | ||||||
| #include "net/NetJob.h" | #include "net/NetJob.h" | ||||||
| class OneSixInstance; | class MinecraftInstance; | ||||||
| 
 | 
 | ||||||
| class LibrariesTask : public Task | class LibrariesTask : public Task | ||||||
| { | { | ||||||
| 	Q_OBJECT | 	Q_OBJECT | ||||||
| public: | public: | ||||||
| 	LibrariesTask(OneSixInstance * inst); | 	LibrariesTask(MinecraftInstance * inst); | ||||||
| 
 | 
 | ||||||
| 	void executeTask() override; | 	void executeTask() override; | ||||||
| 
 | 
 | ||||||
| @@ -20,6 +20,6 @@ public slots: | |||||||
| 	bool abort() override; | 	bool abort() override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| 	OneSixInstance *m_inst; | 	MinecraftInstance *m_inst; | ||||||
| 	NetJobPtr downloadJob; | 	NetJobPtr downloadJob; | ||||||
| }; | }; | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| #pragma once | #pragma once | ||||||
| #include "minecraft/onesix/OneSixInstance.h" | #include "minecraft/MinecraftInstance.h" | ||||||
| #include <FileSystem.h> | #include <FileSystem.h> | ||||||
| #include "pages/BasePage.h" | #include "pages/BasePage.h" | ||||||
| #include "pages/LogPage.h" | #include "pages/LogPage.h" | ||||||
| @@ -29,7 +29,7 @@ public: | |||||||
| 	{ | 	{ | ||||||
| 		QList<BasePage *> values; | 		QList<BasePage *> values; | ||||||
| 		values.append(new LogPage(inst)); | 		values.append(new LogPage(inst)); | ||||||
| 		std::shared_ptr<OneSixInstance> onesix = std::dynamic_pointer_cast<OneSixInstance>(inst); | 		std::shared_ptr<MinecraftInstance> onesix = std::dynamic_pointer_cast<MinecraftInstance>(inst); | ||||||
| 		if(onesix) | 		if(onesix) | ||||||
| 		{ | 		{ | ||||||
| 			values.append(new VersionPage(onesix.get())); | 			values.append(new VersionPage(onesix.get())); | ||||||
|   | |||||||
| @@ -28,6 +28,7 @@ | |||||||
| #include "minecraft/ModList.h" | #include "minecraft/ModList.h" | ||||||
| #include "minecraft/Mod.h" | #include "minecraft/Mod.h" | ||||||
| #include "minecraft/VersionFilterData.h" | #include "minecraft/VersionFilterData.h" | ||||||
|  | #include "minecraft/MinecraftProfile.h" | ||||||
| #include <DesktopServices.h> | #include <DesktopServices.h> | ||||||
|  |  | ||||||
| ModFolderPage::ModFolderPage(BaseInstance *inst, std::shared_ptr<ModList> mods, QString id, | ModFolderPage::ModFolderPage(BaseInstance *inst, std::shared_ptr<ModList> mods, QString id, | ||||||
| @@ -99,7 +100,7 @@ bool CoreModFolderPage::shouldDisplay() const | |||||||
| { | { | ||||||
| 	if (ModFolderPage::shouldDisplay()) | 	if (ModFolderPage::shouldDisplay()) | ||||||
| 	{ | 	{ | ||||||
| 		auto inst = dynamic_cast<OneSixInstance *>(m_inst); | 		auto inst = dynamic_cast<MinecraftInstance *>(m_inst); | ||||||
| 		if (!inst) | 		if (!inst) | ||||||
| 			return true; | 			return true; | ||||||
| 		auto version = inst->getMinecraftProfile(); | 		auto version = inst->getMinecraftProfile(); | ||||||
|   | |||||||
| @@ -17,7 +17,7 @@ | |||||||
|  |  | ||||||
| #include <QWidget> | #include <QWidget> | ||||||
|  |  | ||||||
| #include "minecraft/onesix/OneSixInstance.h" | #include "minecraft/MinecraftInstance.h" | ||||||
| #include "BasePage.h" | #include "BasePage.h" | ||||||
| #include <MultiMC.h> | #include <MultiMC.h> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -50,13 +50,13 @@ class IconProxy : public QIdentityProxyModel | |||||||
| { | { | ||||||
| 	Q_OBJECT | 	Q_OBJECT | ||||||
| public: | public: | ||||||
| 	 |  | ||||||
| 	IconProxy(QWidget *parentWidget) : QIdentityProxyModel(parentWidget) | 	IconProxy(QWidget *parentWidget) : QIdentityProxyModel(parentWidget) | ||||||
| 	{ | 	{ | ||||||
| 		connect(parentWidget, &QObject::destroyed, this, &IconProxy::widgetGone); | 		connect(parentWidget, &QObject::destroyed, this, &IconProxy::widgetGone); | ||||||
| 		m_parentWidget = parentWidget; | 		m_parentWidget = parentWidget; | ||||||
| 	} | 	} | ||||||
| 	 |  | ||||||
| 	virtual QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const override | 	virtual QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const override | ||||||
| 	{ | 	{ | ||||||
| 		QVariant var = QIdentityProxyModel::data(mapToSource(proxyIndex), role); | 		QVariant var = QIdentityProxyModel::data(mapToSource(proxyIndex), role); | ||||||
| @@ -103,7 +103,7 @@ void VersionPage::setParentContainer(BasePageContainer * container) | |||||||
| 	m_container = container; | 	m_container = container; | ||||||
| } | } | ||||||
|  |  | ||||||
| VersionPage::VersionPage(OneSixInstance *inst, QWidget *parent) | VersionPage::VersionPage(MinecraftInstance *inst, QWidget *parent) | ||||||
| 	: QWidget(parent), ui(new Ui::VersionPage), m_inst(inst) | 	: QWidget(parent), ui(new Ui::VersionPage), m_inst(inst) | ||||||
| { | { | ||||||
| 	ui->setupUi(this); | 	ui->setupUi(this); | ||||||
| @@ -130,7 +130,7 @@ VersionPage::VersionPage(OneSixInstance *inst, QWidget *parent) | |||||||
| 	{ | 	{ | ||||||
| 		disableVersionControls(); | 		disableVersionControls(); | ||||||
| 	} | 	} | ||||||
| 	connect(m_inst, &OneSixInstance::versionReloaded, this, | 	connect(m_inst, &MinecraftInstance::versionReloaded, this, | ||||||
| 			&VersionPage::updateVersionControls); | 			&VersionPage::updateVersionControls); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -381,8 +381,8 @@ void VersionPage::on_forgeBtn_clicked() | |||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 	VersionSelectDialog vselect(vlist.get(), tr("Select Forge version"), this); | 	VersionSelectDialog vselect(vlist.get(), tr("Select Forge version"), this); | ||||||
| 	vselect.setExactFilter(BaseVersionList::ParentVersionRole, m_inst->currentVersionId()); | 	vselect.setExactFilter(BaseVersionList::ParentVersionRole, m_inst->getComponentVersion("net.minecraft")); | ||||||
| 	vselect.setEmptyString(tr("No Forge versions are currently available for Minecraft ") + m_inst->currentVersionId()); | 	vselect.setEmptyString(tr("No Forge versions are currently available for Minecraft ") + m_inst->getComponentVersion("net.minecraft")); | ||||||
| 	vselect.setEmptyErrorString(tr("Couldn't load or download the Forge version lists!")); | 	vselect.setEmptyErrorString(tr("Couldn't load or download the Forge version lists!")); | ||||||
| 	if (vselect.exec() && vselect.selectedVersion()) | 	if (vselect.exec() && vselect.selectedVersion()) | ||||||
| 	{ | 	{ | ||||||
| @@ -403,8 +403,8 @@ void VersionPage::on_liteloaderBtn_clicked() | |||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 	VersionSelectDialog vselect(vlist.get(), tr("Select LiteLoader version"), this); | 	VersionSelectDialog vselect(vlist.get(), tr("Select LiteLoader version"), this); | ||||||
| 	vselect.setExactFilter(BaseVersionList::ParentVersionRole, m_inst->currentVersionId()); | 	vselect.setExactFilter(BaseVersionList::ParentVersionRole, m_inst->getComponentVersion("net.minecraft")); | ||||||
| 	vselect.setEmptyString(tr("No LiteLoader versions are currently available for Minecraft ") + m_inst->currentVersionId()); | 	vselect.setEmptyString(tr("No LiteLoader versions are currently available for Minecraft ") + m_inst->getComponentVersion("net.minecraft")); | ||||||
| 	vselect.setEmptyErrorString(tr("Couldn't load or download the LiteLoader version lists!")); | 	vselect.setEmptyErrorString(tr("Couldn't load or download the LiteLoader version lists!")); | ||||||
| 	if (vselect.exec() && vselect.selectedVersion()) | 	if (vselect.exec() && vselect.selectedVersion()) | ||||||
| 	{ | 	{ | ||||||
| @@ -548,3 +548,4 @@ void VersionPage::on_revertBtn_clicked() | |||||||
| } | } | ||||||
|  |  | ||||||
| #include "VersionPage.moc" | #include "VersionPage.moc" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -17,7 +17,8 @@ | |||||||
|  |  | ||||||
| #include <QWidget> | #include <QWidget> | ||||||
|  |  | ||||||
| #include "minecraft/onesix/OneSixInstance.h" | #include "minecraft/MinecraftInstance.h" | ||||||
|  | #include "minecraft/MinecraftProfile.h" | ||||||
| #include "BasePage.h" | #include "BasePage.h" | ||||||
|  |  | ||||||
| namespace Ui | namespace Ui | ||||||
| @@ -30,7 +31,7 @@ class VersionPage : public QWidget, public BasePage | |||||||
| 	Q_OBJECT | 	Q_OBJECT | ||||||
|  |  | ||||||
| public: | public: | ||||||
| 	explicit VersionPage(OneSixInstance *inst, QWidget *parent = 0); | 	explicit VersionPage(MinecraftInstance *inst, QWidget *parent = 0); | ||||||
| 	virtual ~VersionPage(); | 	virtual ~VersionPage(); | ||||||
| 	virtual QString displayName() const override | 	virtual QString displayName() const override | ||||||
| 	{ | 	{ | ||||||
| @@ -82,7 +83,7 @@ protected: | |||||||
| private: | private: | ||||||
| 	Ui::VersionPage *ui; | 	Ui::VersionPage *ui; | ||||||
| 	std::shared_ptr<MinecraftProfile> m_profile; | 	std::shared_ptr<MinecraftProfile> m_profile; | ||||||
| 	OneSixInstance *m_inst; | 	MinecraftInstance *m_inst; | ||||||
| 	int currentIdx = 0; | 	int currentIdx = 0; | ||||||
| 	BasePageContainer * m_container = nullptr; | 	BasePageContainer * m_container = nullptr; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -17,7 +17,7 @@ | |||||||
|  |  | ||||||
| #include <QWidget> | #include <QWidget> | ||||||
|  |  | ||||||
| #include "minecraft/onesix/OneSixInstance.h" | #include "minecraft/MinecraftInstance.h" | ||||||
| #include "BasePage.h" | #include "BasePage.h" | ||||||
| #include <MultiMC.h> | #include <MultiMC.h> | ||||||
| #include <LoggedProcess.h> | #include <LoggedProcess.h> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user