Detect java bitness on launch, use appropriate libraries
Fixes problems with latest snapshot
This commit is contained in:
		| @@ -599,7 +599,7 @@ void MainWindow::doLogin(const QString &errorMsg) | ||||
|  | ||||
| void MainWindow::prepareLaunch(BaseInstance* instance, MojangAccountPtr account) | ||||
| { | ||||
| 	Task *updateTask = instance->doUpdate(); | ||||
| 	Task *updateTask = instance->doUpdate(true); | ||||
| 	if (!updateTask) | ||||
| 	{ | ||||
| 		launchInstance(instance, account); | ||||
|   | ||||
| @@ -93,7 +93,6 @@ public: | ||||
| 	 * \warning Don't change this value unless you know what you're doing. | ||||
| 	 */ | ||||
| 	virtual QString currentVersionId() const = 0; | ||||
| 	// virtual void setCurrentVersionId(QString val) = 0; | ||||
|  | ||||
| 	/*! | ||||
| 	 * Whether or not Minecraft should be downloaded when the instance is launched. | ||||
| @@ -151,7 +150,7 @@ public: | ||||
| 	virtual SettingsObject &settings() const; | ||||
|  | ||||
| 	/// returns a valid update task if update is needed, NULL otherwise | ||||
| 	virtual Task *doUpdate() = 0; | ||||
| 	virtual Task *doUpdate(bool prepare_for_launch) = 0; | ||||
|  | ||||
| 	/// returns a valid minecraft process, ready for launch with the given account. | ||||
| 	virtual MinecraftProcess *prepareForLaunch(MojangAccountPtr account) = 0; | ||||
|   | ||||
| @@ -44,10 +44,12 @@ LegacyInstance::LegacyInstance(const QString &rootDir, SettingsObject *settings, | ||||
| 	settings->registerSetting(new Setting("IntendedJarVersion", "")); | ||||
| } | ||||
|  | ||||
| Task *LegacyInstance::doUpdate() | ||||
| Task *LegacyInstance::doUpdate(bool prepare_for_launch) | ||||
| { | ||||
| 	// make sure the jar mods list is initialized by asking for it. | ||||
| 	auto list = jarModList(); | ||||
| 	return new LegacyUpdate(this, this); | ||||
| 	// create an update task | ||||
| 	return new LegacyUpdate(this, prepare_for_launch , this); | ||||
| } | ||||
|  | ||||
| MinecraftProcess *LegacyInstance::prepareForLaunch(MojangAccountPtr account) | ||||
| @@ -245,12 +247,6 @@ QString LegacyInstance::currentVersionId() const | ||||
| 	return d->m_settings->get("JarVersion").toString(); | ||||
| } | ||||
|  | ||||
| void LegacyInstance::setCurrentVersionId(QString val) | ||||
| { | ||||
| 	I_D(LegacyInstance); | ||||
| 	d->m_settings->set("JarVersion", val); | ||||
| } | ||||
|  | ||||
| QString LegacyInstance::lwjglVersion() const | ||||
| { | ||||
| 	I_D(LegacyInstance); | ||||
|   | ||||
| @@ -48,7 +48,7 @@ public: | ||||
| 	QString loaderModsDir() const; | ||||
| 	QString coreModsDir() const; | ||||
| 	QString resourceDir() const; | ||||
| 	virtual QString instanceConfigFolder() const; | ||||
| 	virtual QString instanceConfigFolder() const override; | ||||
|  | ||||
| 	/*! | ||||
| 	 * Whether or not the instance's minecraft.jar needs to be rebuilt. | ||||
| @@ -58,37 +58,35 @@ public: | ||||
| 	bool shouldRebuild() const; | ||||
| 	void setShouldRebuild(bool val); | ||||
|  | ||||
| 	virtual QString currentVersionId() const; | ||||
| 	virtual void setCurrentVersionId(QString val); | ||||
| 	virtual QString currentVersionId() const override; | ||||
|  | ||||
| 	//! The version of LWJGL that this instance uses. | ||||
| 	QString lwjglVersion() const; | ||||
| 	/// st the version of LWJGL libs this instance will use | ||||
| 	void setLWJGLVersion(QString val); | ||||
|  | ||||
| 	virtual QString intendedVersionId() const; | ||||
| 	virtual bool setIntendedVersionId(QString version); | ||||
| 	virtual QString intendedVersionId() const override; | ||||
| 	virtual bool setIntendedVersionId(QString version) override; | ||||
| 	// the `version' of Legacy instances is defined by the launcher code. | ||||
| 	// in contrast with OneSix, where `version' is described in a json file | ||||
| 	virtual bool versionIsCustom() override | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 	; | ||||
|  | ||||
| 	virtual bool shouldUpdate() const; | ||||
| 	virtual void setShouldUpdate(bool val); | ||||
| 	virtual Task *doUpdate(); | ||||
| 	virtual bool shouldUpdate() const override; | ||||
| 	virtual void setShouldUpdate(bool val) override; | ||||
| 	virtual Task *doUpdate(bool prepare_for_launch) override; | ||||
|  | ||||
| 	virtual MinecraftProcess *prepareForLaunch(MojangAccountPtr account); | ||||
| 	virtual void cleanupAfterRun(); | ||||
| 	virtual QDialog *createModEditDialog(QWidget *parent); | ||||
| 	virtual MinecraftProcess *prepareForLaunch(MojangAccountPtr account) override; | ||||
| 	virtual void cleanupAfterRun() override; | ||||
| 	virtual QDialog *createModEditDialog(QWidget *parent) override; | ||||
|  | ||||
| 	virtual QString defaultBaseJar() const; | ||||
| 	virtual QString defaultCustomBaseJar() const; | ||||
| 	virtual QString defaultBaseJar() const override; | ||||
| 	virtual QString defaultCustomBaseJar() const override; | ||||
|  | ||||
| 	bool menuActionEnabled(QString action_name) const; | ||||
| 	virtual QString getStatusbarDescription(); | ||||
| 	virtual QString getStatusbarDescription() override; | ||||
|  | ||||
| protected | ||||
| slots: | ||||
|   | ||||
| @@ -26,7 +26,8 @@ | ||||
| #include <JlCompress.h> | ||||
| #include "logger/QsLog.h" | ||||
|  | ||||
| LegacyUpdate::LegacyUpdate(BaseInstance *inst, QObject *parent) : Task(parent), m_inst(inst) | ||||
| LegacyUpdate::LegacyUpdate(BaseInstance *inst, bool prepare_for_launch, QObject *parent) | ||||
| 	: Task(parent), m_inst(inst), m_prepare_for_launch(prepare_for_launch) | ||||
| { | ||||
| } | ||||
|  | ||||
| @@ -361,7 +362,8 @@ void LegacyUpdate::ModTheJar() | ||||
| 		setStatus("Installing mods - backing up minecraft.jar..."); | ||||
| 		if (!baseJar.exists() && !QFile::copy(runnableJar.filePath(), baseJar.filePath())) | ||||
| 		{ | ||||
| 			emitFailed("It seems both the active and base jar are gone. A fresh base jar will be used on next run."); | ||||
| 			emitFailed("It seems both the active and base jar are gone. A fresh base jar will " | ||||
| 					   "be used on next run."); | ||||
| 			inst->setShouldRebuild(true); | ||||
| 			inst->setShouldUpdate(true); | ||||
| 			inst->setShouldUseCustomBaseJar(false); | ||||
|   | ||||
| @@ -31,7 +31,7 @@ class LegacyUpdate : public Task | ||||
| { | ||||
| 	Q_OBJECT | ||||
| public: | ||||
| 	explicit LegacyUpdate(BaseInstance *inst, QObject *parent = 0); | ||||
| 	explicit LegacyUpdate(BaseInstance *inst, bool prepare_for_launch, QObject *parent = 0); | ||||
| 	virtual void executeTask(); | ||||
|  | ||||
| private | ||||
| @@ -71,5 +71,6 @@ private: | ||||
|  | ||||
| private: | ||||
| 	NetJobPtr legacyDownloadJob; | ||||
| 	BaseInstance *m_inst; | ||||
| 	BaseInstance *m_inst = nullptr; | ||||
| 	bool m_prepare_for_launch = false; | ||||
| }; | ||||
|   | ||||
| @@ -37,9 +37,9 @@ OneSixInstance::OneSixInstance(const QString &rootDir, SettingsObject *setting_o | ||||
| 	reloadFullVersion(); | ||||
| } | ||||
|  | ||||
| Task *OneSixInstance::doUpdate() | ||||
| Task *OneSixInstance::doUpdate(bool prepare_for_launch) | ||||
| { | ||||
| 	return new OneSixUpdate(this); | ||||
| 	return new OneSixUpdate(this, prepare_for_launch); | ||||
| } | ||||
|  | ||||
| QString replaceTokensIn(QString text, QMap<QString, QString> with) | ||||
| @@ -108,34 +108,12 @@ QStringList OneSixInstance::processMinecraftArgs(MojangAccountPtr account) | ||||
| MinecraftProcess *OneSixInstance::prepareForLaunch(MojangAccountPtr account) | ||||
| { | ||||
| 	I_D(OneSixInstance); | ||||
| 	cleanupAfterRun(); | ||||
|  | ||||
| 	QString natives_dir_raw = PathCombine(instanceRoot(), "natives/"); | ||||
|  | ||||
| 	auto version = d->version; | ||||
| 	if (!version) | ||||
| 		return nullptr; | ||||
| 	auto libs_to_extract = version->getActiveNativeLibs(); | ||||
| 	QString natives_dir_raw = PathCombine(instanceRoot(), "natives/"); | ||||
| 	bool success = ensureFolderPathExists(natives_dir_raw); | ||||
| 	if (!success) | ||||
| 	{ | ||||
| 		// FIXME: handle errors | ||||
| 		return nullptr; | ||||
| 	} | ||||
|  | ||||
| 	for (auto lib : libs_to_extract) | ||||
| 	{ | ||||
| 		QString storage = lib->storagePath(); | ||||
| 		if(storage.contains("${arch}")) | ||||
| 		{ | ||||
| 			storage.replace("${arch}", "64"); | ||||
| 		} | ||||
| 		QString path = "libraries/" + lib->storagePath(); | ||||
| 		QLOG_INFO() << "Will extract " << path.toLocal8Bit(); | ||||
| 		if (JlCompress::extractWithExceptions(path, natives_dir_raw, lib->extract_excludes) | ||||
| 				.isEmpty()) | ||||
| 		{ | ||||
| 			return nullptr; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	QStringList args; | ||||
| 	args.append(Util::Commandline::splitArgs(settings().get("JvmArgs").toString())); | ||||
|   | ||||
| @@ -37,23 +37,22 @@ public: | ||||
| 	////// Directories ////// | ||||
| 	QString resourcePacksDir() const; | ||||
| 	QString loaderModsDir() const; | ||||
| 	virtual QString instanceConfigFolder() const; | ||||
| 	virtual QString instanceConfigFolder() const override; | ||||
|  | ||||
| 	virtual Task *doUpdate(); | ||||
| 	virtual MinecraftProcess *prepareForLaunch(MojangAccountPtr account); | ||||
| 	virtual Task *doUpdate(bool prepare_for_launch) override; | ||||
| 	virtual MinecraftProcess *prepareForLaunch(MojangAccountPtr account) override; | ||||
|  | ||||
| 	virtual void cleanupAfterRun(); | ||||
| 	virtual void cleanupAfterRun() override; | ||||
|  | ||||
| 	virtual QString intendedVersionId() const; | ||||
| 	virtual bool setIntendedVersionId(QString version); | ||||
| 	virtual QString intendedVersionId() const override; | ||||
| 	virtual bool setIntendedVersionId(QString version) override; | ||||
|  | ||||
| 	virtual QString currentVersionId() const; | ||||
| 	// virtual void setCurrentVersionId ( QString val ) {}; | ||||
| 	virtual QString currentVersionId() const override; | ||||
|  | ||||
| 	virtual bool shouldUpdate() const; | ||||
| 	virtual void setShouldUpdate(bool val); | ||||
| 	virtual bool shouldUpdate() const override; | ||||
| 	virtual void setShouldUpdate(bool val) override; | ||||
|  | ||||
| 	virtual QDialog *createModEditDialog(QWidget *parent); | ||||
| 	virtual QDialog *createModEditDialog(QWidget *parent) override; | ||||
|  | ||||
| 	/// reload the full version json file. return true on success! | ||||
| 	bool reloadFullVersion(); | ||||
| @@ -66,11 +65,11 @@ public: | ||||
| 	/// is the current version original, or custom? | ||||
| 	virtual bool versionIsCustom() override; | ||||
|  | ||||
| 	virtual QString defaultBaseJar() const; | ||||
| 	virtual QString defaultCustomBaseJar() const; | ||||
| 	virtual QString defaultBaseJar() const override; | ||||
| 	virtual QString defaultCustomBaseJar() const override; | ||||
|  | ||||
| 	virtual bool menuActionEnabled(QString action_name) const; | ||||
| 	virtual QString getStatusbarDescription(); | ||||
| 	virtual bool menuActionEnabled(QString action_name) const override; | ||||
| 	virtual QString getStatusbarDescription() override; | ||||
|  | ||||
| private: | ||||
| 	QStringList processMinecraftArgs(MojangAccountPtr account); | ||||
|   | ||||
| @@ -31,8 +31,10 @@ | ||||
| #include "net/ForgeMirrors.h" | ||||
|  | ||||
| #include "pathutils.h" | ||||
| #include <JlCompress.h> | ||||
|  | ||||
| OneSixUpdate::OneSixUpdate(BaseInstance *inst, QObject *parent) : Task(parent), m_inst(inst) | ||||
| OneSixUpdate::OneSixUpdate(BaseInstance *inst, bool prepare_for_launch, QObject *parent) | ||||
| 	: Task(parent), m_inst(inst), m_prepare_for_launch(prepare_for_launch) | ||||
| { | ||||
| } | ||||
|  | ||||
| @@ -48,28 +50,57 @@ void OneSixUpdate::executeTask() | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	// Get a pointer to the version object that corresponds to the instance's version. | ||||
| 	targetVersion = std::dynamic_pointer_cast<MinecraftVersion>( | ||||
| 		MMC->minecraftlist()->findVersion(intendedVersion)); | ||||
| 	if (targetVersion == nullptr) | ||||
| 	{ | ||||
| 		// don't do anything if it was invalid | ||||
| 		emitSucceeded(); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (m_inst->shouldUpdate()) | ||||
| 	{ | ||||
| 		// Get a pointer to the version object that corresponds to the instance's version. | ||||
| 		targetVersion = std::dynamic_pointer_cast<MinecraftVersion>( | ||||
| 			MMC->minecraftlist()->findVersion(intendedVersion)); | ||||
| 		if (targetVersion == nullptr) | ||||
| 		{ | ||||
| 			// don't do anything if it was invalid | ||||
| 			emitFailed("The specified Minecraft version is invalid. Choose a different one."); | ||||
| 			return; | ||||
| 		} | ||||
| 		versionFileStart(); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		checkJava(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void OneSixUpdate::checkJava() | ||||
| { | ||||
| 	QLOG_INFO() << m_inst->name() << ": checking java binary"; | ||||
| 	setStatus("Testing the Java installation."); | ||||
| 	// TODO: cache this so we don't have to run an extra java process every time. | ||||
| 	QString java_path = m_inst->settings().get("JavaPath").toString(); | ||||
|  | ||||
| 	checker.reset(new JavaChecker()); | ||||
| 	connect(checker.get(), SIGNAL(checkFinished(JavaCheckResult)), this, | ||||
| 			SLOT(checkFinished(JavaCheckResult))); | ||||
| 	checker->performCheck(java_path); | ||||
| } | ||||
|  | ||||
| void OneSixUpdate::checkFinished(JavaCheckResult result) | ||||
| { | ||||
| 	if (result.valid) | ||||
| 	{ | ||||
| 		QLOG_INFO() << m_inst->name() << ": java is " | ||||
| 					<< (result.is_64bit ? "64 bit" : "32 bit"); | ||||
| 		java_is_64bit = result.is_64bit; | ||||
| 		jarlibStart(); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		QLOG_INFO() << m_inst->name() << ": java isn't valid"; | ||||
| 		emitFailed("The java binary doesn't work. Check the settings and correct the problem"); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void OneSixUpdate::versionFileStart() | ||||
| { | ||||
| 	QLOG_INFO() << m_inst->name() << ": getting version file."; | ||||
| 	setStatus("Getting the version files from Mojang."); | ||||
|  | ||||
| 	QString urlstr("http://s3.amazonaws.com/Minecraft.Download/versions/"); | ||||
| @@ -129,7 +160,7 @@ void OneSixUpdate::versionFileFinished() | ||||
| 	} | ||||
| 	inst->reloadFullVersion(); | ||||
|  | ||||
| 	jarlibStart(); | ||||
| 	checkJava(); | ||||
| } | ||||
|  | ||||
| void OneSixUpdate::versionFileFailed() | ||||
| @@ -139,6 +170,8 @@ void OneSixUpdate::versionFileFailed() | ||||
|  | ||||
| void OneSixUpdate::jarlibStart() | ||||
| { | ||||
| 	setStatus("Getting the library files from Mojang."); | ||||
| 	QLOG_INFO() << m_inst->name() << ": downloading libraries"; | ||||
| 	OneSixInstance *inst = (OneSixInstance *)m_inst; | ||||
| 	bool successful = inst->reloadFullVersion(); | ||||
| 	if (!successful) | ||||
| @@ -170,26 +203,13 @@ void OneSixUpdate::jarlibStart() | ||||
| 	{ | ||||
| 		if (lib->hint() == "local") | ||||
| 			continue; | ||||
| 		QString subst = java_is_64bit ? "64" : "32"; | ||||
| 		QString storage = lib->storagePath(); | ||||
| 		QString dl = lib->downloadUrl(); | ||||
| 		if (lib->isNative() && storage.contains("${arch}")) | ||||
| 		{ | ||||
| 			auto storage64 = storage, storage32 = storage; | ||||
| 			auto dl64  = dl, dl32 = dl; | ||||
| 			storage64.replace("${arch}", "64"); | ||||
| 			storage32.replace("${arch}", "32"); | ||||
| 			dl32.replace("${arch}", "32"); | ||||
| 			dl64.replace("${arch}", "64"); | ||||
|  | ||||
| 			auto entry64 = metacache->resolveEntry("libraries", storage64); | ||||
| 			if (entry64->stale) | ||||
| 				jarlibDownloadJob->addNetAction(CacheDownload::make(dl64, entry64)); | ||||
| 		storage.replace("${arch}", subst); | ||||
| 		dl.replace("${arch}", subst); | ||||
|  | ||||
| 			auto entry32 = metacache->resolveEntry("libraries", storage32); | ||||
| 			if (entry32->stale) | ||||
| 				jarlibDownloadJob->addNetAction(CacheDownload::make(dl32, entry32)); | ||||
| 			continue; | ||||
| 		} | ||||
| 		auto entry = metacache->resolveEntry("libraries", storage); | ||||
| 		if (entry->stale) | ||||
| 		{ | ||||
| @@ -221,7 +241,10 @@ void OneSixUpdate::jarlibStart() | ||||
|  | ||||
| void OneSixUpdate::jarlibFinished() | ||||
| { | ||||
| 	emitSucceeded(); | ||||
| 	if (m_prepare_for_launch) | ||||
| 		prepareForLaunch(); | ||||
| 	else | ||||
| 		emitSucceeded(); | ||||
| } | ||||
|  | ||||
| void OneSixUpdate::jarlibFailed() | ||||
| @@ -231,3 +254,57 @@ void OneSixUpdate::jarlibFailed() | ||||
| 	emitFailed("Failed to download the following files:\n" + failed_all + | ||||
| 			   "\n\nPlease try again."); | ||||
| } | ||||
|  | ||||
| void OneSixUpdate::prepareForLaunch() | ||||
| { | ||||
| 	setStatus("Preparing for launch."); | ||||
| 	QLOG_INFO() << m_inst->name() << ": preparing for launch"; | ||||
| 	auto onesix_inst = (OneSixInstance *)m_inst; | ||||
|  | ||||
| 	// delete any leftovers, if they are present. | ||||
| 	onesix_inst->cleanupAfterRun(); | ||||
|  | ||||
| 	// Acquire swag | ||||
| 	QString natives_dir_raw = PathCombine(onesix_inst->instanceRoot(), "natives/"); | ||||
| 	auto version = onesix_inst->getFullVersion(); | ||||
| 	if (!version) | ||||
| 	{ | ||||
| 		emitFailed("The version information for this instance is not complete. Try re-creating " | ||||
| 				   "it or changing the version."); | ||||
| 		return; | ||||
| 	} | ||||
| 	auto libs_to_extract = version->getActiveNativeLibs(); | ||||
|  | ||||
| 	// Acquire bag | ||||
| 	bool success = ensureFolderPathExists(natives_dir_raw); | ||||
| 	if (!success) | ||||
| 	{ | ||||
| 		emitFailed("Could not create the native library folder:\n" + natives_dir_raw + | ||||
| 				   "\nMake sure MultiMC has appropriate permissions and there is enough space " | ||||
| 				   "on the storage device."); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	// Put swag in the bag | ||||
| 	QString subst = java_is_64bit ? "64" : "32"; | ||||
| 	for (auto lib : libs_to_extract) | ||||
| 	{ | ||||
| 		QString storage = lib->storagePath(); | ||||
| 		storage.replace("${arch}", subst); | ||||
|  | ||||
| 		QString path = "libraries/" + storage; | ||||
| 		QLOG_INFO() << "Will extract " << path.toLocal8Bit(); | ||||
| 		if (JlCompress::extractWithExceptions(path, natives_dir_raw, lib->extract_excludes) | ||||
| 				.isEmpty()) | ||||
| 		{ | ||||
| 			emitFailed( | ||||
| 				"Could not extract the native library:\n" + path + | ||||
| 				"\nMake sure MultiMC has appropriate permissions and there is enough space " | ||||
| 				"on the storage device."); | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Show them your war face! | ||||
| 	emitSucceeded(); | ||||
| } | ||||
|   | ||||
| @@ -21,6 +21,7 @@ | ||||
|  | ||||
| #include "logic/net/NetJob.h" | ||||
| #include "logic/tasks/Task.h" | ||||
| #include "logic/JavaChecker.h" | ||||
|  | ||||
| class MinecraftVersion; | ||||
| class BaseInstance; | ||||
| @@ -29,7 +30,7 @@ class OneSixUpdate : public Task | ||||
| { | ||||
| 	Q_OBJECT | ||||
| public: | ||||
| 	explicit OneSixUpdate(BaseInstance *inst, QObject *parent = 0); | ||||
| 	explicit OneSixUpdate(BaseInstance *inst, bool prepare_for_launch, QObject *parent = 0); | ||||
| 	virtual void executeTask(); | ||||
|  | ||||
| private | ||||
| @@ -42,11 +43,20 @@ slots: | ||||
| 	void jarlibFinished(); | ||||
| 	void jarlibFailed(); | ||||
|  | ||||
| 	void checkJava(); | ||||
| 	void checkFinished(JavaCheckResult result); | ||||
|  | ||||
| 	// extract the appropriate libraries | ||||
| 	void prepareForLaunch(); | ||||
| private: | ||||
| 	NetJobPtr specificVersionDownloadJob; | ||||
| 	NetJobPtr jarlibDownloadJob; | ||||
|  | ||||
| 	// target version, determined during this task | ||||
| 	std::shared_ptr<MinecraftVersion> targetVersion; | ||||
| 	BaseInstance *m_inst; | ||||
| 	BaseInstance *m_inst = nullptr; | ||||
| 	bool m_prepare_for_launch = false; | ||||
| 	std::shared_ptr<JavaChecker> checker; | ||||
|  | ||||
| 	bool java_is_64bit = false; | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user