Prepare for rework of instance launch/update
Added missing licenses Added a Java functionality checker (detects 32/64bit java) Refactor of *Update - no longer based on BaseUpdate, but Task directly Fixed runner script to not derp up on 32bit linux. Could add more detection and error reporting there. Resources are now split into graphics and generated. Generated resources are placed in the build tree and included from there. Used the Java checker in the main settings dialog (TODO: instance settings). Partial support for ${arch}-using libraries - both 32 and 64 variants of ${arch} are downloaded.
This commit is contained in:
@ -25,7 +25,7 @@
|
||||
#include "net/LoginTask.h"
|
||||
|
||||
class QDialog;
|
||||
class BaseUpdate;
|
||||
class Task;
|
||||
class MinecraftProcess;
|
||||
class OneSixUpdate;
|
||||
class InstanceList;
|
||||
@ -151,7 +151,7 @@ public:
|
||||
virtual SettingsObject &settings() const;
|
||||
|
||||
/// returns a valid update task if update is needed, NULL otherwise
|
||||
virtual BaseUpdate *doUpdate() = 0;
|
||||
virtual Task *doUpdate() = 0;
|
||||
|
||||
/// returns a valid minecraft process, ready for launch
|
||||
virtual MinecraftProcess *prepareForLaunch(LoginResponse response) = 0;
|
||||
|
@ -1,26 +0,0 @@
|
||||
/* Copyright 2013 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 "BaseUpdate.h"
|
||||
|
||||
BaseUpdate::BaseUpdate(BaseInstance *inst, QObject *parent) : Task(parent)
|
||||
{
|
||||
m_inst = inst;
|
||||
}
|
||||
|
||||
void BaseUpdate::updateDownloadProgress(qint64 current, qint64 total)
|
||||
{
|
||||
emit progress(current, total);
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
/* Copyright 2013 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 <QObject>
|
||||
#include <QList>
|
||||
#include <QUrl>
|
||||
|
||||
#include "net/NetJob.h"
|
||||
|
||||
#include "tasks/Task.h"
|
||||
|
||||
class MinecraftVersion;
|
||||
class BaseInstance;
|
||||
|
||||
/*!
|
||||
* The game update task is the task that handles downloading instances' files.
|
||||
*/
|
||||
class BaseUpdate : public Task
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit BaseUpdate(BaseInstance *inst, QObject *parent = 0);
|
||||
|
||||
virtual void executeTask() = 0;
|
||||
|
||||
protected
|
||||
slots:
|
||||
// virtual void error(const QString &msg);
|
||||
void updateDownloadProgress(qint64 current, qint64 total);
|
||||
|
||||
protected:
|
||||
BaseInstance *m_inst;
|
||||
};
|
89
logic/JavaChecker.cpp
Normal file
89
logic/JavaChecker.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
#include "JavaChecker.h"
|
||||
#include <QFile>
|
||||
#include <QProcess>
|
||||
|
||||
#define CHECKER_FILE "JavaChecker.jar"
|
||||
|
||||
JavaChecker::JavaChecker(QObject *parent) : QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
int JavaChecker::performCheck(QString path)
|
||||
{
|
||||
if(QFile::exists(CHECKER_FILE))
|
||||
{
|
||||
QFile::remove(CHECKER_FILE);
|
||||
}
|
||||
// extract the checker
|
||||
QFile(":/java/checker.jar").copy(CHECKER_FILE);
|
||||
|
||||
QStringList args = {"-jar", CHECKER_FILE};
|
||||
|
||||
process.reset(new QProcess());
|
||||
process->setArguments(args);
|
||||
process->setProgram(path);
|
||||
process->setProcessChannelMode(QProcess::SeparateChannels);
|
||||
|
||||
connect(process.get(), SIGNAL(finished(int, QProcess::ExitStatus)), this,
|
||||
SLOT(finished(int, QProcess::ExitStatus)));
|
||||
connect(process.get(), SIGNAL(error(QProcess::ProcessError)), this,
|
||||
SLOT(error(QProcess::ProcessError)));
|
||||
connect(&killTimer, SIGNAL(timeout()), SLOT(timeout()));
|
||||
killTimer.setSingleShot(true);
|
||||
killTimer.start(5000);
|
||||
process->start();
|
||||
}
|
||||
|
||||
void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
|
||||
{
|
||||
killTimer.stop();
|
||||
QProcessPtr _process;
|
||||
_process.swap(process);
|
||||
|
||||
if (status == QProcess::CrashExit || exitcode == 1)
|
||||
{
|
||||
emit checkFinished({});
|
||||
return;
|
||||
}
|
||||
|
||||
QString p_stdout = _process->readAllStandardOutput();
|
||||
auto parts = p_stdout.split('=', QString::SkipEmptyParts);
|
||||
if (parts.size() != 2 || parts[0] != "os.arch")
|
||||
{
|
||||
emit checkFinished({});
|
||||
return;
|
||||
}
|
||||
|
||||
auto os_arch = parts[1].remove('\n').remove('\r');
|
||||
bool is_64 = os_arch == "x86_64" || os_arch == "amd64";
|
||||
|
||||
JavaCheckResult result;
|
||||
{
|
||||
result.valid = true;
|
||||
result.is_64bit = is_64;
|
||||
result.mojangPlatform = is_64 ? "64" : "32";
|
||||
result.realPlatform = os_arch;
|
||||
}
|
||||
emit checkFinished(result);
|
||||
}
|
||||
|
||||
void JavaChecker::error(QProcess::ProcessError err)
|
||||
{
|
||||
if(err == QProcess::FailedToStart)
|
||||
{
|
||||
killTimer.stop();
|
||||
emit checkFinished({});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void JavaChecker::timeout()
|
||||
{
|
||||
// NO MERCY. NO ABUSE.
|
||||
if(process)
|
||||
{
|
||||
process->kill();
|
||||
process.reset();
|
||||
emit checkFinished({});
|
||||
}
|
||||
}
|
32
logic/JavaChecker.h
Normal file
32
logic/JavaChecker.h
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
#include <QProcess>
|
||||
#include <QTimer>
|
||||
#include <memory>
|
||||
|
||||
struct JavaCheckResult
|
||||
{
|
||||
QString mojangPlatform;
|
||||
QString realPlatform;
|
||||
bool valid = false;
|
||||
bool is_64bit = false;
|
||||
};
|
||||
typedef std::shared_ptr<QProcess> QProcessPtr;
|
||||
|
||||
class JavaChecker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit JavaChecker(QObject *parent = 0);
|
||||
int performCheck(QString path);
|
||||
|
||||
signals:
|
||||
void checkFinished(JavaCheckResult result);
|
||||
private:
|
||||
QProcessPtr process;
|
||||
QTimer killTimer;
|
||||
public
|
||||
slots:
|
||||
void timeout();
|
||||
void finished(int exitcode, QProcess::ExitStatus);
|
||||
void error(QProcess::ProcessError);
|
||||
};
|
@ -33,7 +33,6 @@ public:
|
||||
|
||||
QList<JavaVersionPtr> FindJavaPaths();
|
||||
JavaVersionPtr GetDefaultJava();
|
||||
|
||||
private:
|
||||
|
||||
#if WINDOWS
|
||||
|
@ -44,7 +44,7 @@ LegacyInstance::LegacyInstance(const QString &rootDir, SettingsObject *settings,
|
||||
settings->registerSetting(new Setting("IntendedJarVersion", ""));
|
||||
}
|
||||
|
||||
BaseUpdate *LegacyInstance::doUpdate()
|
||||
Task *LegacyInstance::doUpdate()
|
||||
{
|
||||
auto list = jarModList();
|
||||
return new LegacyUpdate(this, this);
|
||||
@ -59,7 +59,7 @@ MinecraftProcess *LegacyInstance::prepareForLaunch(LoginResponse response)
|
||||
pixmap.save(PathCombine(minecraftRoot(), "icon.png"), "PNG");
|
||||
|
||||
// extract the legacy launcher
|
||||
QFile(":/launcher/launcher.jar").copy(PathCombine(minecraftRoot(), LAUNCHER_FILE));
|
||||
QFile(":/java/launcher.jar").copy(PathCombine(minecraftRoot(), LAUNCHER_FILE));
|
||||
|
||||
// set the process arguments
|
||||
{
|
||||
@ -108,11 +108,11 @@ MinecraftProcess *LegacyInstance::prepareForLaunch(LoginResponse response)
|
||||
args << windowTitle;
|
||||
args << windowSize;
|
||||
args << lwjgl;
|
||||
proc->setMinecraftArguments(args);
|
||||
proc->setArguments(args);
|
||||
}
|
||||
|
||||
// set the process work path
|
||||
proc->setMinecraftWorkdir(minecraftRoot());
|
||||
proc->setWorkdir(minecraftRoot());
|
||||
|
||||
return proc;
|
||||
}
|
||||
@ -227,56 +227,18 @@ QString LegacyInstance::instanceConfigFolder() const
|
||||
return PathCombine(minecraftRoot(), "config");
|
||||
}
|
||||
|
||||
/*
|
||||
bool LegacyInstance::shouldUpdateCurrentVersion() const
|
||||
{
|
||||
QFileInfo jar(runnableJar());
|
||||
return jar.lastModified().toUTC().toMSecsSinceEpoch() != lastCurrentVersionUpdate();
|
||||
}
|
||||
|
||||
void LegacyInstance::updateCurrentVersion(bool keepCurrent)
|
||||
{
|
||||
QFileInfo jar(runnableJar());
|
||||
|
||||
if(!jar.exists())
|
||||
{
|
||||
setLastCurrentVersionUpdate(0);
|
||||
setCurrentVersionId("Unknown");
|
||||
return;
|
||||
}
|
||||
|
||||
qint64 time = jar.lastModified().toUTC().toMSecsSinceEpoch();
|
||||
|
||||
setLastCurrentVersionUpdate(time);
|
||||
if (!keepCurrent)
|
||||
{
|
||||
// TODO: Implement GetMinecraftJarVersion function.
|
||||
QString newVersion =
|
||||
"Unknown";//javautils::GetMinecraftJarVersion(jar.absoluteFilePath());
|
||||
setCurrentVersionId(newVersion);
|
||||
}
|
||||
}
|
||||
qint64 LegacyInstance::lastCurrentVersionUpdate() const
|
||||
{
|
||||
I_D(LegacyInstance);
|
||||
return d->m_settings->get ( "lastVersionUpdate" ).value<qint64>();
|
||||
}
|
||||
void LegacyInstance::setLastCurrentVersionUpdate ( qint64 val )
|
||||
{
|
||||
I_D(LegacyInstance);
|
||||
d->m_settings->set ( "lastVersionUpdate", val );
|
||||
}
|
||||
*/
|
||||
bool LegacyInstance::shouldRebuild() const
|
||||
{
|
||||
I_D(LegacyInstance);
|
||||
return d->m_settings->get("NeedsRebuild").toBool();
|
||||
}
|
||||
|
||||
void LegacyInstance::setShouldRebuild(bool val)
|
||||
{
|
||||
I_D(LegacyInstance);
|
||||
d->m_settings->set("NeedsRebuild", val);
|
||||
}
|
||||
|
||||
QString LegacyInstance::currentVersionId() const
|
||||
{
|
||||
I_D(LegacyInstance);
|
||||
@ -294,22 +256,26 @@ QString LegacyInstance::lwjglVersion() const
|
||||
I_D(LegacyInstance);
|
||||
return d->m_settings->get("LwjglVersion").toString();
|
||||
}
|
||||
|
||||
void LegacyInstance::setLWJGLVersion(QString val)
|
||||
{
|
||||
I_D(LegacyInstance);
|
||||
d->m_settings->set("LwjglVersion", val);
|
||||
}
|
||||
|
||||
QString LegacyInstance::intendedVersionId() const
|
||||
{
|
||||
I_D(LegacyInstance);
|
||||
return d->m_settings->get("IntendedJarVersion").toString();
|
||||
}
|
||||
|
||||
bool LegacyInstance::setIntendedVersionId(QString version)
|
||||
{
|
||||
settings().set("IntendedJarVersion", version);
|
||||
setShouldUpdate(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LegacyInstance::shouldUpdate() const
|
||||
{
|
||||
I_D(LegacyInstance);
|
||||
@ -320,6 +286,7 @@ bool LegacyInstance::shouldUpdate() const
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void LegacyInstance::setShouldUpdate(bool val)
|
||||
{
|
||||
settings().set("ShouldUpdate", val);
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include "BaseInstance.h"
|
||||
|
||||
class ModList;
|
||||
class BaseUpdate;
|
||||
class Task;
|
||||
|
||||
class LegacyInstance : public BaseInstance
|
||||
{
|
||||
@ -78,7 +78,7 @@ public:
|
||||
|
||||
virtual bool shouldUpdate() const;
|
||||
virtual void setShouldUpdate(bool val);
|
||||
virtual BaseUpdate *doUpdate();
|
||||
virtual Task *doUpdate();
|
||||
|
||||
virtual MinecraftProcess *prepareForLaunch(LoginResponse response);
|
||||
virtual void cleanupAfterRun();
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include <JlCompress.h>
|
||||
#include "logger/QsLog.h"
|
||||
|
||||
LegacyUpdate::LegacyUpdate(BaseInstance *inst, QObject *parent) : BaseUpdate(inst, parent)
|
||||
LegacyUpdate::LegacyUpdate(BaseInstance *inst, QObject *parent) : Task(parent), m_inst(inst)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -21,14 +21,13 @@
|
||||
|
||||
#include "logic/net/NetJob.h"
|
||||
#include "logic/tasks/Task.h"
|
||||
#include "logic/BaseUpdate.h"
|
||||
|
||||
class MinecraftVersion;
|
||||
class BaseInstance;
|
||||
class QuaZip;
|
||||
class Mod;
|
||||
|
||||
class LegacyUpdate : public BaseUpdate
|
||||
class LegacyUpdate : public Task
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@ -72,4 +71,5 @@ private:
|
||||
|
||||
private:
|
||||
NetJobPtr legacyDownloadJob;
|
||||
BaseInstance *m_inst;
|
||||
};
|
||||
|
@ -59,12 +59,12 @@ MinecraftProcess::MinecraftProcess(BaseInstance *inst) : m_instance(inst)
|
||||
connect(this, SIGNAL(readyReadStandardOutput()), SLOT(on_stdOut()));
|
||||
}
|
||||
|
||||
void MinecraftProcess::setMinecraftArguments(QStringList args)
|
||||
void MinecraftProcess::setArguments(QStringList args)
|
||||
{
|
||||
m_args = args;
|
||||
}
|
||||
|
||||
void MinecraftProcess::setMinecraftWorkdir(QString path)
|
||||
void MinecraftProcess::setWorkdir(QString path)
|
||||
{
|
||||
QDir mcDir(path);
|
||||
this->setWorkingDirectory(mcDir.absolutePath());
|
||||
|
@ -63,9 +63,9 @@ public:
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
void setMinecraftWorkdir(QString path);
|
||||
void setWorkdir(QString path);
|
||||
|
||||
void setMinecraftArguments(QStringList args);
|
||||
void setArguments(QStringList args);
|
||||
|
||||
void killMinecraft();
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "OneSixUpdate.h"
|
||||
#include "MinecraftProcess.h"
|
||||
#include "OneSixVersion.h"
|
||||
#include "JavaChecker.h"
|
||||
|
||||
#include <setting.h>
|
||||
#include <pathutils.h>
|
||||
@ -36,7 +37,7 @@ OneSixInstance::OneSixInstance(const QString &rootDir, SettingsObject *setting_o
|
||||
reloadFullVersion();
|
||||
}
|
||||
|
||||
BaseUpdate *OneSixInstance::doUpdate()
|
||||
Task *OneSixInstance::doUpdate()
|
||||
{
|
||||
return new OneSixUpdate(this);
|
||||
}
|
||||
@ -122,6 +123,11 @@ MinecraftProcess *OneSixInstance::prepareForLaunch(LoginResponse response)
|
||||
|
||||
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)
|
||||
@ -188,8 +194,8 @@ MinecraftProcess *OneSixInstance::prepareForLaunch(LoginResponse response)
|
||||
|
||||
// create the process and set its parameters
|
||||
MinecraftProcess *proc = new MinecraftProcess(this);
|
||||
proc->setMinecraftArguments(args);
|
||||
proc->setMinecraftWorkdir(minecraftRoot());
|
||||
proc->setArguments(args);
|
||||
proc->setWorkdir(minecraftRoot());
|
||||
return proc;
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "BaseInstance.h"
|
||||
|
||||
class OneSixVersion;
|
||||
class BaseUpdate;
|
||||
class Task;
|
||||
class ModList;
|
||||
|
||||
class OneSixInstance : public BaseInstance
|
||||
@ -39,7 +39,7 @@ public:
|
||||
QString loaderModsDir() const;
|
||||
virtual QString instanceConfigFolder() const;
|
||||
|
||||
virtual BaseUpdate *doUpdate();
|
||||
virtual Task *doUpdate();
|
||||
virtual MinecraftProcess *prepareForLaunch(LoginResponse response);
|
||||
virtual void cleanupAfterRun();
|
||||
|
||||
|
@ -32,7 +32,7 @@
|
||||
|
||||
#include "pathutils.h"
|
||||
|
||||
OneSixUpdate::OneSixUpdate(BaseInstance *inst, QObject *parent) : BaseUpdate(inst, parent)
|
||||
OneSixUpdate::OneSixUpdate(BaseInstance *inst, QObject *parent) : Task(parent), m_inst(inst)
|
||||
{
|
||||
}
|
||||
|
||||
@ -143,7 +143,7 @@ void OneSixUpdate::jarlibStart()
|
||||
bool successful = inst->reloadFullVersion();
|
||||
if (!successful)
|
||||
{
|
||||
emitFailed("Failed to load the version description file (version.json). It might be "
|
||||
emitFailed("Failed to load the version description file. It might be "
|
||||
"corrupted, missing or simply too new.");
|
||||
return;
|
||||
}
|
||||
@ -170,16 +170,36 @@ void OneSixUpdate::jarlibStart()
|
||||
{
|
||||
if (lib->hint() == "local")
|
||||
continue;
|
||||
auto entry = metacache->resolveEntry("libraries", lib->storagePath());
|
||||
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));
|
||||
|
||||
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)
|
||||
{
|
||||
if (lib->hint() == "forge-pack-xz")
|
||||
{
|
||||
ForgeLibs.append(ForgeXzDownload::make(lib->storagePath(), entry));
|
||||
ForgeLibs.append(ForgeXzDownload::make(storage, entry));
|
||||
}
|
||||
else
|
||||
{
|
||||
jarlibDownloadJob->addNetAction(CacheDownload::make(lib->downloadUrl(), entry));
|
||||
jarlibDownloadJob->addNetAction(CacheDownload::make(dl, entry));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,12 +21,11 @@
|
||||
|
||||
#include "logic/net/NetJob.h"
|
||||
#include "logic/tasks/Task.h"
|
||||
#include "logic/BaseUpdate.h"
|
||||
|
||||
class MinecraftVersion;
|
||||
class BaseInstance;
|
||||
|
||||
class OneSixUpdate : public BaseUpdate
|
||||
class OneSixUpdate : public Task
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@ -49,4 +48,5 @@ private:
|
||||
|
||||
// target version, determined during this task
|
||||
std::shared_ptr<MinecraftVersion> targetVersion;
|
||||
BaseInstance *m_inst;
|
||||
};
|
||||
|
Reference in New Issue
Block a user