Detect java bitness on launch, use appropriate libraries

Fixes problems with latest snapshot
This commit is contained in:
Petr Mrázek 2013-11-25 00:46:52 +01:00
parent 82225a21e1
commit 088b039cf7
10 changed files with 163 additions and 103 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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:

View File

@ -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);

View File

@ -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;
};

View File

@ -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()));

View File

@ -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);

View File

@ -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;
}
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
emitSucceeded();
emitFailed("The specified Minecraft version is invalid. Choose a different one.");
return;
}
if (m_inst->shouldUpdate())
{
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,6 +241,9 @@ void OneSixUpdate::jarlibStart()
void OneSixUpdate::jarlibFinished()
{
if (m_prepare_for_launch)
prepareForLaunch();
else
emitSucceeded();
}
@ -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();
}

View File

@ -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;
};