mirror of
https://github.com/MultiMC/MultiMC5.git
synced 2024-09-02 21:19:25 +00:00
Runnable 1.6 instances!
This commit is contained in:
parent
005a010ee6
commit
183a735145
@ -69,8 +69,23 @@ public:
|
||||
QString group() const;
|
||||
void setGroup(QString val);
|
||||
|
||||
virtual QString intendedVersionId() const = 0;
|
||||
virtual bool setIntendedVersionId(QString version) = 0;
|
||||
virtual QString intendedVersionId() = 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;
|
||||
//virtual void setCurrentVersionId(QString val) = 0;
|
||||
|
||||
/*!
|
||||
* Whether or not Minecraft should be downloaded when the instance is launched.
|
||||
*/
|
||||
virtual bool shouldUpdate() const = 0;
|
||||
virtual void setShouldUpdate(bool val) = 0;
|
||||
|
||||
/**
|
||||
* Gets the time that the instance was last launched.
|
||||
@ -107,6 +122,8 @@ public:
|
||||
/// returns a valid minecraft process, ready for launch
|
||||
virtual MinecraftProcess* prepareForLaunch(QString user, QString session) = 0;
|
||||
|
||||
/// do any necessary cleanups after the instance finishes. also runs before 'prepareForLaunch'
|
||||
virtual void cleanupAfterRun() = 0;
|
||||
signals:
|
||||
/*!
|
||||
* \brief Signal emitted when properties relevant to the instance view change
|
||||
|
@ -91,6 +91,6 @@ add_definitions(-DLIBMULTIMC_LIBRARY)
|
||||
|
||||
add_library(backend SHARED ${LIBINST_SOURCES} ${LIBINST_HEADERS})
|
||||
qt5_use_modules(backend Core Network Xml)
|
||||
target_link_libraries(backend libUtil libSettings)
|
||||
target_link_libraries(backend libUtil libSettings quazip)
|
||||
|
||||
|
||||
|
@ -16,7 +16,7 @@ LegacyInstance::LegacyInstance(const QString& rootDir, SettingsObject* settings,
|
||||
settings->registerSetting(new Setting("NeedsRebuild", true));
|
||||
settings->registerSetting(new Setting("ShouldUpdate", false));
|
||||
settings->registerSetting(new Setting("JarVersion", "Unknown"));
|
||||
settings->registerSetting(new Setting("LwjglVersion", "2.9.0"));
|
||||
settings->registerSetting(new Setting("LwjglVersion", "Mojang"));
|
||||
settings->registerSetting(new Setting("IntendedJarVersion", ""));
|
||||
}
|
||||
|
||||
@ -93,6 +93,11 @@ MinecraftProcess* LegacyInstance::prepareForLaunch(QString user, QString session
|
||||
return proc;
|
||||
}
|
||||
|
||||
void LegacyInstance::cleanupAfterRun()
|
||||
{
|
||||
//FIXME: delete the launcher and icons and whatnot.
|
||||
}
|
||||
|
||||
|
||||
QString LegacyInstance::instModsDir() const
|
||||
{
|
||||
@ -152,7 +157,7 @@ void LegacyInstance::updateCurrentVersion(bool keepCurrent)
|
||||
if(!jar.exists())
|
||||
{
|
||||
setLastCurrentVersionUpdate(0);
|
||||
setCurrentVersion("Unknown");
|
||||
setCurrentVersionId("Unknown");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -163,7 +168,7 @@ void LegacyInstance::updateCurrentVersion(bool keepCurrent)
|
||||
{
|
||||
// TODO: Implement GetMinecraftJarVersion function.
|
||||
QString newVersion = "Unknown";//javautils::GetMinecraftJarVersion(jar.absoluteFilePath());
|
||||
setCurrentVersion(newVersion);
|
||||
setCurrentVersionId(newVersion);
|
||||
}
|
||||
}
|
||||
qint64 LegacyInstance::lastCurrentVersionUpdate() const
|
||||
@ -186,16 +191,18 @@ void LegacyInstance::setShouldRebuild ( bool val )
|
||||
I_D(LegacyInstance);
|
||||
d->m_settings->set ( "NeedsRebuild", val );
|
||||
}
|
||||
QString LegacyInstance::currentVersion() const
|
||||
QString LegacyInstance::currentVersionId() const
|
||||
{
|
||||
I_D(LegacyInstance);
|
||||
return d->m_settings->get ( "JarVersion" ).toString();
|
||||
}
|
||||
void LegacyInstance::setCurrentVersion ( QString val )
|
||||
|
||||
void LegacyInstance::setCurrentVersionId ( QString val )
|
||||
{
|
||||
I_D(LegacyInstance);
|
||||
d->m_settings->set ( "JarVersion", val );
|
||||
}
|
||||
|
||||
QString LegacyInstance::lwjglVersion() const
|
||||
{
|
||||
I_D(LegacyInstance);
|
||||
@ -206,36 +213,17 @@ void LegacyInstance::setLWJGLVersion ( QString val )
|
||||
I_D(LegacyInstance);
|
||||
d->m_settings->set ( "LwjglVersion", val );
|
||||
}
|
||||
QString LegacyInstance::intendedVersionId()
|
||||
QString LegacyInstance::intendedVersionId() const
|
||||
{
|
||||
I_D(LegacyInstance);
|
||||
return d->m_settings->get ( "IntendedJarVersion" ).toString();
|
||||
}
|
||||
bool LegacyInstance::setIntendedVersionId ( QString version )
|
||||
{
|
||||
/*
|
||||
I_D(LegacyInstance);
|
||||
d->m_settings->set ( "IntendedJarVersion", val );
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
bool LegacyInstance::shouldUpdate() const
|
||||
{
|
||||
/*
|
||||
I_D(LegacyInstance);
|
||||
QVariant var = d->m_settings->get ( "ShouldUpdate" );
|
||||
if ( !var.isValid() || var.toBool() == false )
|
||||
{
|
||||
return intendedVersionId() != currentVersion();
|
||||
}
|
||||
return true;
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
void LegacyInstance::setShouldUpdate ( bool val )
|
||||
{
|
||||
/*
|
||||
I_D(LegacyInstance);
|
||||
d->m_settings->set ( "ShouldUpdate", val );
|
||||
*/
|
||||
}
|
||||
void LegacyInstance::setShouldUpdate ( bool val ) {}
|
||||
|
@ -56,7 +56,6 @@ public:
|
||||
qint64 lastCurrentVersionUpdate() const;
|
||||
void setLastCurrentVersionUpdate(qint64 val);
|
||||
|
||||
|
||||
/*!
|
||||
* Whether or not the instance's minecraft.jar needs to be rebuilt.
|
||||
* If this is true, when the instance launches, its jar mods will be
|
||||
@ -65,39 +64,21 @@ public:
|
||||
bool shouldRebuild() const;
|
||||
void setShouldRebuild(bool val);
|
||||
|
||||
virtual QString currentVersionId() const;
|
||||
virtual void setCurrentVersionId(QString val);
|
||||
|
||||
/*!
|
||||
* 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.
|
||||
*/
|
||||
QString currentVersion() const;
|
||||
void setCurrentVersion(QString val);
|
||||
|
||||
//! 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);
|
||||
|
||||
/*!
|
||||
* The version that the user has set for this instance to use.
|
||||
* If this is not the same as currentVersion, the instance's game updater
|
||||
* will be run on launch.
|
||||
*/
|
||||
virtual QString intendedVersionId();
|
||||
virtual QString intendedVersionId() const;
|
||||
virtual bool setIntendedVersionId ( QString version );
|
||||
|
||||
/*!
|
||||
* Whether or not Minecraft should be downloaded when the instance is launched.
|
||||
* This returns true if shouldForceUpdate game is true or if the intended and
|
||||
* current versions don't match.
|
||||
*/
|
||||
bool shouldUpdate() const;
|
||||
void setShouldUpdate(bool val);
|
||||
|
||||
/// return a valid GameUpdateTask if an update is needed, return NULL otherwise
|
||||
virtual bool shouldUpdate() const;
|
||||
virtual void setShouldUpdate(bool val);
|
||||
virtual OneSixUpdate* doUpdate();
|
||||
|
||||
/// prepare the instance for launch and return a constructed MinecraftProcess instance
|
||||
virtual MinecraftProcess* prepareForLaunch( QString user, QString session );
|
||||
virtual void cleanupAfterRun();
|
||||
};
|
@ -134,6 +134,7 @@ void MinecraftProcess::finish(int code, ExitStatus status)
|
||||
//TODO: error handling
|
||||
}
|
||||
}
|
||||
m_instance->cleanupAfterRun();
|
||||
emit ended();
|
||||
}
|
||||
|
||||
|
@ -2,13 +2,20 @@
|
||||
#include "OneSixInstance_p.h"
|
||||
#include "OneSixUpdate.h"
|
||||
#include "MinecraftProcess.h"
|
||||
#include "VersionFactory.h"
|
||||
|
||||
#include <setting.h>
|
||||
#include <pathutils.h>
|
||||
#include <cmdutils.h>
|
||||
#include <JlCompress.h>
|
||||
|
||||
OneSixInstance::OneSixInstance ( const QString& rootDir, SettingsObject* setting_obj, QObject* parent )
|
||||
: BaseInstance ( new OneSixInstancePrivate(), rootDir, setting_obj, parent )
|
||||
{
|
||||
I_D(OneSixInstance);
|
||||
d->m_settings->registerSetting(new Setting("IntendedVersion", ""));
|
||||
d->m_settings->registerSetting(new Setting("ShouldUpdate", false));
|
||||
reloadFullVersion();
|
||||
}
|
||||
|
||||
OneSixUpdate* OneSixInstance::doUpdate()
|
||||
@ -16,17 +23,188 @@ OneSixUpdate* OneSixInstance::doUpdate()
|
||||
return 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( QString user, QString session )
|
||||
{
|
||||
I_D(OneSixInstance);
|
||||
auto version = d->version;
|
||||
QString args_pattern = version->minecraftArguments;
|
||||
|
||||
QMap<QString, QString> token_mapping;
|
||||
token_mapping["auth_username"] = user;
|
||||
token_mapping["auth_session"] = session;
|
||||
//FIXME: user and player name are DIFFERENT!
|
||||
token_mapping["auth_player_name"] = user;
|
||||
//FIXME: WTF is this. I just plugged in a random UUID here.
|
||||
token_mapping["auth_uuid"] = "7d4bacf0-fd62-11e2-b778-0800200c9a66"; // obviously fake.
|
||||
|
||||
// this is for offline:
|
||||
/*
|
||||
map["auth_player_name"] = "Player";
|
||||
map["auth_player_name"] = "00000000-0000-0000-0000-000000000000";
|
||||
*/
|
||||
|
||||
token_mapping["profile_name"] = name();
|
||||
token_mapping["version_name"] = version->id;
|
||||
|
||||
QString absRootDir = QDir(rootDir()).absolutePath();
|
||||
token_mapping["game_directory"] = absRootDir;
|
||||
QString absAssetsDir = QDir("assets/").absolutePath();
|
||||
token_mapping["game_assets"] = absAssetsDir;
|
||||
|
||||
QStringList parts = args_pattern.split(' ',QString::SkipEmptyParts);
|
||||
for (int i = 0; i < parts.length(); i++)
|
||||
{
|
||||
parts[i] = replaceTokensIn(parts[i], token_mapping);
|
||||
}
|
||||
return parts;
|
||||
}
|
||||
|
||||
MinecraftProcess* OneSixInstance::prepareForLaunch ( QString user, QString session )
|
||||
{
|
||||
return nullptr;
|
||||
I_D(OneSixInstance);
|
||||
cleanupAfterRun();
|
||||
auto version = d->version;
|
||||
if(!version)
|
||||
return nullptr;
|
||||
auto libs_to_extract = version->getActiveNativeLibs();
|
||||
QString natives_dir_raw = PathCombine(rootDir(), "natives/");
|
||||
bool success = ensurePathExists(natives_dir_raw);
|
||||
if(!success)
|
||||
{
|
||||
// FIXME: handle errors
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for(auto lib: libs_to_extract)
|
||||
{
|
||||
QString path = "libraries/" + lib->storagePath();
|
||||
qDebug() << "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()));
|
||||
args << QString("-Xms%1m").arg(settings().get("MinMemAlloc").toInt());
|
||||
args << QString("-Xmx%1m").arg(settings().get("MaxMemAlloc").toInt());
|
||||
QDir natives_dir(natives_dir_raw);
|
||||
args << QString("-Djava.library.path=%1").arg( natives_dir.absolutePath() );
|
||||
QString classPath;
|
||||
{
|
||||
auto libs = version->getActiveNormalLibs();
|
||||
for (auto lib: libs)
|
||||
{
|
||||
QFileInfo fi(QString("libraries/") + lib->storagePath());
|
||||
classPath.append(fi.absoluteFilePath());
|
||||
//FIXME: make separator tweakable
|
||||
classPath.append(':');
|
||||
}
|
||||
QString targetstr = "versions/" + version->id + "/" + version->id + ".jar";
|
||||
QFileInfo fi(targetstr);
|
||||
classPath.append(fi.absoluteFilePath());
|
||||
}
|
||||
if(classPath.size())
|
||||
{
|
||||
args << "-cp";
|
||||
args << classPath;
|
||||
}
|
||||
args << version->mainClass;
|
||||
args.append(processMinecraftArgs(user, session));
|
||||
|
||||
// create the process and set its parameters
|
||||
MinecraftProcess * proc = new MinecraftProcess(this);
|
||||
proc->setMinecraftArguments(args);
|
||||
proc->setMinecraftWorkdir(rootDir());
|
||||
return proc;
|
||||
}
|
||||
|
||||
void OneSixInstance::cleanupAfterRun()
|
||||
{
|
||||
QString target_dir = PathCombine(rootDir(), "natives/");
|
||||
QDir dir(target_dir);
|
||||
dir.removeRecursively();
|
||||
}
|
||||
|
||||
bool OneSixInstance::setIntendedVersionId ( QString version )
|
||||
{
|
||||
settings().set("IntendedVersion", version);
|
||||
setShouldUpdate(true);
|
||||
}
|
||||
|
||||
QString OneSixInstance::intendedVersionId()
|
||||
QString OneSixInstance::intendedVersionId() const
|
||||
{
|
||||
return settings().get("IntendedVersion").toString();
|
||||
}
|
||||
|
||||
void OneSixInstance::setShouldUpdate ( bool val )
|
||||
{
|
||||
settings().set ( "ShouldUpdate", val );
|
||||
}
|
||||
|
||||
bool OneSixInstance::shouldUpdate() const
|
||||
{
|
||||
I_D(OneSixInstance);
|
||||
QVariant var = settings().get ( "ShouldUpdate" );
|
||||
if ( !var.isValid() || var.toBool() == false )
|
||||
{
|
||||
return intendedVersionId() != currentVersionId();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QString OneSixInstance::currentVersionId() const
|
||||
{
|
||||
return intendedVersionId();
|
||||
}
|
||||
|
||||
bool OneSixInstance::reloadFullVersion()
|
||||
{
|
||||
I_D(OneSixInstance);
|
||||
|
||||
QString verpath = PathCombine(rootDir(), "version.json");
|
||||
QFile versionfile(verpath);
|
||||
if(versionfile.exists() && versionfile.open(QIODevice::ReadOnly))
|
||||
{
|
||||
FullVersionFactory fvf;
|
||||
auto version = fvf.parse(versionfile.readAll());
|
||||
versionfile.close();
|
||||
if(version)
|
||||
{
|
||||
d->version = version;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
return false;
|
||||
}
|
||||
|
||||
QSharedPointer< FullVersion > OneSixInstance::getFullVersion()
|
||||
{
|
||||
I_D(OneSixInstance);
|
||||
return d->version;
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "BaseInstance.h"
|
||||
#include <QStringList>
|
||||
class FullVersion;
|
||||
|
||||
class LIBMULTIMC_EXPORT OneSixInstance : public BaseInstance
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -8,8 +11,21 @@ public:
|
||||
explicit OneSixInstance(const QString &rootDir, SettingsObject * settings, QObject *parent = 0);
|
||||
virtual OneSixUpdate* doUpdate();
|
||||
virtual MinecraftProcess* prepareForLaunch ( QString user, QString session );
|
||||
virtual void cleanupAfterRun();
|
||||
|
||||
virtual QString intendedVersionId() const;
|
||||
virtual bool setIntendedVersionId ( QString version );
|
||||
virtual QString intendedVersionId();
|
||||
|
||||
virtual QString currentVersionId() const;
|
||||
// virtual void setCurrentVersionId ( QString val ) {};
|
||||
|
||||
virtual bool shouldUpdate() const;
|
||||
virtual void setShouldUpdate(bool val);
|
||||
|
||||
/// reload the full version json file. return true on success!
|
||||
bool reloadFullVersion();
|
||||
/// get the current full version info
|
||||
QSharedPointer<FullVersion> getFullVersion();
|
||||
private:
|
||||
QStringList processMinecraftArgs( QString user, QString session );
|
||||
};
|
@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
#include <QString>
|
||||
#include <settingsobject.h>
|
||||
|
||||
#include "BaseInstance_p.h"
|
||||
#include "OneSixVersion.h"
|
||||
|
||||
struct OneSixInstancePrivate: public BaseInstancePrivate
|
||||
{
|
||||
QSharedPointer<FullVersion> version;
|
||||
};
|
@ -28,6 +28,7 @@
|
||||
#include "lists/MinecraftVersionList.h"
|
||||
#include "VersionFactory.h"
|
||||
#include "OneSixVersion.h"
|
||||
#include "OneSixInstance.h"
|
||||
|
||||
#include "pathutils.h"
|
||||
|
||||
@ -40,14 +41,28 @@ OneSixUpdate::OneSixUpdate(BaseInstance *inst, QObject *parent) :
|
||||
|
||||
void OneSixUpdate::executeTask()
|
||||
{
|
||||
QString intendedVersion = m_inst->intendedVersionId();
|
||||
// Get a pointer to the version object that corresponds to the instance's version.
|
||||
targetVersion = (MinecraftVersion *)MinecraftVersionList::getMainList().findVersion(m_inst->intendedVersionId());
|
||||
if(targetVersion == NULL)
|
||||
targetVersion = (MinecraftVersion *)MinecraftVersionList::getMainList().findVersion(intendedVersion);
|
||||
if(targetVersion == nullptr)
|
||||
{
|
||||
// don't do anything if it was invalid
|
||||
emit gameUpdateComplete();
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_inst->shouldUpdate())
|
||||
{
|
||||
versionFileStart();
|
||||
}
|
||||
else
|
||||
{
|
||||
jarlibStart();
|
||||
}
|
||||
}
|
||||
|
||||
void OneSixUpdate::versionFileStart()
|
||||
{
|
||||
setStatus("Getting the version files from Mojang.");
|
||||
|
||||
QString urlstr("http://s3.amazonaws.com/Minecraft.Download/versions/");
|
||||
@ -59,71 +74,93 @@ void OneSixUpdate::executeTask()
|
||||
connect(specificVersionDownloadJob.data(), SIGNAL(failed()), SLOT(versionFileFailed()));
|
||||
connect(specificVersionDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64)));
|
||||
download_queue.enqueue(specificVersionDownloadJob);
|
||||
|
||||
QEventLoop loop;
|
||||
loop.exec();
|
||||
}
|
||||
|
||||
void OneSixUpdate::versionFileFinished()
|
||||
{
|
||||
JobPtr firstJob = specificVersionDownloadJob->getFirstJob();
|
||||
auto DlJob = firstJob.dynamicCast<DownloadJob>();
|
||||
FullVersionFactory parser;
|
||||
auto version = parser.parse(DlJob->m_data);
|
||||
|
||||
if(!version)
|
||||
{
|
||||
error(parser.error_string);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// save the version file in $instanceId/version.json and versions/$version/$version.json
|
||||
QString version_id = targetVersion->descriptor();
|
||||
QString inst_dir = m_inst->rootDir();
|
||||
QString version1 = PathCombine(inst_dir, "/version.json");
|
||||
QString version2 = QString("versions/") + version_id + "/" + version_id + ".json";
|
||||
DownloadJob::ensurePathExists(version1);
|
||||
DownloadJob::ensurePathExists(version2);
|
||||
QFile vfile1 (version1);
|
||||
QFile vfile2 (version2);
|
||||
vfile1.open(QIODevice::Truncate | QIODevice::WriteOnly );
|
||||
vfile2.open(QIODevice::Truncate | QIODevice::WriteOnly );
|
||||
vfile1.write(DlJob->m_data);
|
||||
vfile2.write(DlJob->m_data);
|
||||
vfile1.close();
|
||||
vfile2.close();
|
||||
// save the version file in $instanceId/version.json
|
||||
{
|
||||
QString version1 = PathCombine(inst_dir, "/version.json");
|
||||
ensurePathExists(version1);
|
||||
QFile vfile1 (version1);
|
||||
vfile1.open(QIODevice::Truncate | QIODevice::WriteOnly );
|
||||
vfile1.write(DlJob->m_data);
|
||||
vfile1.close();
|
||||
}
|
||||
|
||||
// download the right jar, save it in versions/$version/$version.jar
|
||||
QString urlstr("http://s3.amazonaws.com/Minecraft.Download/versions/");
|
||||
urlstr += targetVersion->descriptor() + "/" + targetVersion->descriptor() + ".jar";
|
||||
QString targetstr ("versions/");
|
||||
targetstr += targetVersion->descriptor() + "/" + targetVersion->descriptor() + ".jar";
|
||||
auto dljob = DownloadJob::create(QUrl(urlstr), targetstr);
|
||||
// save the version file in versions/$version/$version.json
|
||||
/*
|
||||
//QString version2 = QString("versions/") + version_id + "/" + version_id + ".json";
|
||||
//ensurePathExists(version2);
|
||||
//QFile vfile2 (version2);
|
||||
//vfile2.open(QIODevice::Truncate | QIODevice::WriteOnly );
|
||||
//vfile2.write(DlJob->m_data);
|
||||
//vfile2.close();
|
||||
*/
|
||||
|
||||
jarlibDownloadJob.reset(new JobList());
|
||||
jarlibDownloadJob->add(dljob);
|
||||
connect(jarlibDownloadJob.data(), SIGNAL(finished()), SLOT(jarlibFinished()));
|
||||
connect(jarlibDownloadJob.data(), SIGNAL(failed()), SLOT(jarlibFailed()));
|
||||
connect(jarlibDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64)));
|
||||
// determine and download all the libraries, save them in libraries/whatever...
|
||||
download_queue.enqueue(jarlibDownloadJob);
|
||||
}
|
||||
|
||||
void OneSixUpdate::jarlibFinished()
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void OneSixUpdate::jarlibFailed()
|
||||
{
|
||||
error("Failed to download the binary garbage. Try again. Maybe. IF YOU DARE");
|
||||
exit(0);
|
||||
jarlibStart();
|
||||
}
|
||||
|
||||
void OneSixUpdate::versionFileFailed()
|
||||
{
|
||||
error("Failed to download the version description. Try again.");
|
||||
exit(0);
|
||||
emitEnded();
|
||||
}
|
||||
|
||||
void OneSixUpdate::jarlibStart()
|
||||
{
|
||||
OneSixInstance * inst = (OneSixInstance *) m_inst;
|
||||
bool successful = inst->reloadFullVersion();
|
||||
if(!successful)
|
||||
{
|
||||
error("Failed to load the version description file (version.json). It might be corrupted, missing or simply too new.");
|
||||
emitEnded();
|
||||
return;
|
||||
}
|
||||
|
||||
QSharedPointer<FullVersion> version = inst->getFullVersion();
|
||||
|
||||
// download the right jar, save it in versions/$version/$version.jar
|
||||
QString urlstr("http://s3.amazonaws.com/Minecraft.Download/versions/");
|
||||
urlstr += version->id + "/" + version->id + ".jar";
|
||||
QString targetstr ("versions/");
|
||||
targetstr += version->id + "/" + version->id + ".jar";
|
||||
|
||||
auto dljob = DownloadJob::create(QUrl(urlstr), targetstr);
|
||||
jarlibDownloadJob.reset(new JobList());
|
||||
jarlibDownloadJob->add(dljob);
|
||||
|
||||
auto libs = version->getActiveNativeLibs();
|
||||
libs.append(version->getActiveNormalLibs());
|
||||
|
||||
for(auto lib: libs)
|
||||
{
|
||||
QString download_path = lib->downloadPath();
|
||||
QString storage_path = "libraries/" + lib->storagePath();
|
||||
jarlibDownloadJob->add(DownloadJob::create(net_manager, download_path, storage_path));
|
||||
}
|
||||
connect(jarlibDownloadJob.data(), SIGNAL(finished()), SLOT(jarlibFinished()));
|
||||
connect(jarlibDownloadJob.data(), SIGNAL(failed()), SLOT(jarlibFailed()));
|
||||
connect(jarlibDownloadJob.data(), SIGNAL(progress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64)));
|
||||
|
||||
download_queue.enqueue(jarlibDownloadJob);
|
||||
}
|
||||
|
||||
void OneSixUpdate::jarlibFinished()
|
||||
{
|
||||
emit gameUpdateComplete();
|
||||
emitEnded();
|
||||
}
|
||||
|
||||
void OneSixUpdate::jarlibFailed()
|
||||
{
|
||||
error("Failed to download the binary garbage. Try again. Maybe. IF YOU DARE");
|
||||
emitEnded();
|
||||
}
|
||||
|
||||
void OneSixUpdate::error(const QString &msg)
|
||||
|
@ -46,16 +46,18 @@ public slots:
|
||||
private slots:
|
||||
void updateDownloadProgress(qint64 current, qint64 total);
|
||||
|
||||
void versionFileStart();
|
||||
void versionFileFinished();
|
||||
void versionFileFailed();
|
||||
|
||||
void jarlibStart();
|
||||
void jarlibFinished();
|
||||
void jarlibFailed();
|
||||
|
||||
|
||||
signals:
|
||||
/*!
|
||||
* \brief Signal emitted when the game update is complete.
|
||||
* \param response The login response received from login task.
|
||||
*/
|
||||
void gameUpdateComplete();
|
||||
|
||||
@ -70,6 +72,7 @@ private:
|
||||
|
||||
QString m_subStatusMsg;
|
||||
|
||||
QSharedPointer<QNetworkAccessManager> net_manager {new QNetworkAccessManager()};
|
||||
JobListPtr legacyDownloadJob;
|
||||
JobListPtr specificVersionDownloadJob;
|
||||
JobListPtr jarlibDownloadJob;
|
||||
|
@ -64,12 +64,51 @@ void Library::finalize()
|
||||
}
|
||||
}
|
||||
|
||||
void Library::setName ( QString name )
|
||||
{
|
||||
m_name = name;
|
||||
}
|
||||
void Library::setBaseUrl ( QString base_url )
|
||||
{
|
||||
m_base_url = base_url;
|
||||
}
|
||||
void Library::setIsNative()
|
||||
{
|
||||
m_is_native = true;
|
||||
}
|
||||
void Library::addNative ( OpSys os, QString suffix )
|
||||
{
|
||||
m_is_native = true;
|
||||
m_native_suffixes[os] = suffix;
|
||||
}
|
||||
void Library::setRules ( QList< QSharedPointer< Rule > > rules )
|
||||
{
|
||||
m_rules = rules;
|
||||
}
|
||||
bool Library::isActive()
|
||||
{
|
||||
return m_is_active;
|
||||
}
|
||||
bool Library::isNative()
|
||||
{
|
||||
return m_is_native;
|
||||
}
|
||||
QString Library::downloadPath()
|
||||
{
|
||||
return m_download_path;
|
||||
}
|
||||
QString Library::storagePath()
|
||||
{
|
||||
return m_storage_path;
|
||||
}
|
||||
|
||||
|
||||
QList<QSharedPointer<Library> > FullVersion::getActiveNormalLibs()
|
||||
{
|
||||
QList<QSharedPointer<Library> > output;
|
||||
for ( auto lib: libraries )
|
||||
{
|
||||
if (lib->getIsActive() && !lib->getIsNative())
|
||||
if (lib->isActive() && !lib->isNative())
|
||||
{
|
||||
output.append(lib);
|
||||
}
|
||||
@ -82,10 +121,12 @@ QList<QSharedPointer<Library> > FullVersion::getActiveNativeLibs()
|
||||
QList<QSharedPointer<Library> > output;
|
||||
for ( auto lib: libraries )
|
||||
{
|
||||
if (lib->getIsActive() && lib->getIsNative())
|
||||
if (lib->isActive() && lib->isNative())
|
||||
{
|
||||
output.append(lib);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
|
@ -107,11 +107,11 @@ private:
|
||||
QString m_storage_path;
|
||||
/// where to download the lib from
|
||||
QString m_download_path;
|
||||
/// is this lib actuall active on the current OS?
|
||||
/// is this lib actually active on the current OS?
|
||||
bool m_is_active;
|
||||
|
||||
// native lib?
|
||||
/// is the library a native?
|
||||
bool m_is_native;
|
||||
/// native suffixes per OS
|
||||
QMap<OpSys, QString> m_native_suffixes;
|
||||
public:
|
||||
QStringList extract_excludes;
|
||||
@ -133,62 +133,25 @@ public:
|
||||
*/
|
||||
void finalize();
|
||||
|
||||
|
||||
/**
|
||||
* Set the library composite name
|
||||
*/
|
||||
void setName(QString name)
|
||||
{
|
||||
m_name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the url base for downloads
|
||||
*/
|
||||
void setBaseUrl(QString base_url)
|
||||
{
|
||||
m_base_url = base_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this to mark the library as 'native' (it's a zip archive with DLLs)
|
||||
*/
|
||||
void setIsNative()
|
||||
{
|
||||
m_is_native = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach a name suffix to the specified OS native
|
||||
*/
|
||||
void addNative(OpSys os, QString suffix)
|
||||
{
|
||||
m_is_native = true;
|
||||
m_native_suffixes[os] = suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the load rules
|
||||
*/
|
||||
void setRules(QList<QSharedPointer<Rule> > rules)
|
||||
{
|
||||
m_rules = rules;
|
||||
}
|
||||
/// Set the library composite name
|
||||
void setName(QString name);
|
||||
/// Set the url base for downloads
|
||||
void setBaseUrl(QString base_url);
|
||||
/// Call this to mark the library as 'native' (it's a zip archive with DLLs)
|
||||
void setIsNative();
|
||||
/// Attach a name suffix to the specified OS native
|
||||
void addNative(OpSys os, QString suffix);
|
||||
/// Set the load rules
|
||||
void setRules(QList<QSharedPointer<Rule> > rules);
|
||||
|
||||
/**
|
||||
* Returns true if the library should be loaded (or extracted, in case of natives)
|
||||
*/
|
||||
bool getIsActive()
|
||||
{
|
||||
return m_is_active;
|
||||
}
|
||||
/**
|
||||
* Returns true if the library is native
|
||||
*/
|
||||
bool getIsNative()
|
||||
{
|
||||
return m_is_native;
|
||||
}
|
||||
/// Returns true if the library should be loaded (or extracted, in case of natives)
|
||||
bool isActive();
|
||||
/// Returns true if the library is native
|
||||
bool isNative();
|
||||
/// Get the URL to download the library from
|
||||
QString downloadPath();
|
||||
/// Get the relative path where the library should be saved
|
||||
QString storagePath();
|
||||
};
|
||||
|
||||
|
||||
|
@ -172,24 +172,21 @@ MCVListLoadTask::~MCVListLoadTask()
|
||||
|
||||
void MCVListLoadTask::executeTask()
|
||||
{
|
||||
// NOTE: this executes in the QThread
|
||||
setStatus("Loading instance version list...");
|
||||
netMgr = new QNetworkAccessManager();
|
||||
vlistReply = netMgr->get(QNetworkRequest(QUrl(QString(MCVLIST_URLBASE) + "versions.json")));
|
||||
connect(vlistReply, SIGNAL(finished()), this, SLOT(list_downloaded()));
|
||||
exec();
|
||||
}
|
||||
|
||||
|
||||
void MCVListLoadTask::list_downloaded()
|
||||
{
|
||||
// NOTE: this executes in the main thread
|
||||
|
||||
if(vlistReply->error() != QNetworkReply::QNetworkReply::NoError)
|
||||
{
|
||||
qDebug() << "Failed to load Minecraft main version list" << vlistReply->errorString();
|
||||
vlistReply->deleteLater();
|
||||
exit(0);
|
||||
emitEnded();
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonParseError jsonError;
|
||||
@ -199,13 +196,15 @@ void MCVListLoadTask::list_downloaded()
|
||||
if (jsonError.error != QJsonParseError::NoError)
|
||||
{
|
||||
qDebug() << "Error parsing version list JSON:" << jsonError.errorString();
|
||||
exit(0);
|
||||
emitEnded();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!jsonDoc.isObject())
|
||||
{
|
||||
qDebug() << "Error parsing version list JSON: " << "jsonDoc is not an object";
|
||||
exit(0);
|
||||
emitEnded();
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject root = jsonDoc.object();
|
||||
@ -214,7 +213,8 @@ void MCVListLoadTask::list_downloaded()
|
||||
if(!root.value("latest").isObject())
|
||||
{
|
||||
qDebug() << "Error parsing version list JSON: " << "version list is missing 'latest' object";
|
||||
exit(0);
|
||||
emitEnded();
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject latest = root.value("latest").toObject();
|
||||
@ -224,19 +224,22 @@ void MCVListLoadTask::list_downloaded()
|
||||
if(latestReleaseID.isEmpty())
|
||||
{
|
||||
qDebug() << "Error parsing version list JSON: " << "latest release field is missing";
|
||||
exit(0);
|
||||
emitEnded();
|
||||
return;
|
||||
}
|
||||
if(latestSnapshotID.isEmpty())
|
||||
{
|
||||
qDebug() << "Error parsing version list JSON: " << "latest snapshot field is missing";
|
||||
exit(0);
|
||||
emitEnded();
|
||||
return;
|
||||
}
|
||||
|
||||
// Now, get the array of versions.
|
||||
if(!root.value("versions").isArray())
|
||||
{
|
||||
qDebug() << "Error parsing version list JSON: " << "version list object is missing 'versions' array";
|
||||
exit(0);
|
||||
emitEnded();
|
||||
return;
|
||||
}
|
||||
QJsonArray versions = root.value("versions").toArray();
|
||||
|
||||
@ -303,7 +306,8 @@ void MCVListLoadTask::list_downloaded()
|
||||
#ifdef PRINT_VERSIONS
|
||||
m_list->printToStdOut();
|
||||
#endif
|
||||
exit(1);
|
||||
emitEnded();
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: we should have a local cache of the version list and a local cache of version data
|
||||
|
@ -27,16 +27,14 @@
|
||||
LoginTask::LoginTask( const UserInfo& uInfo, QObject* parent ) :
|
||||
Task(parent), uInfo(uInfo)
|
||||
{
|
||||
|
||||
netMgr.reset(new QNetworkAccessManager());
|
||||
}
|
||||
|
||||
void LoginTask::executeTask()
|
||||
{
|
||||
setStatus("Logging in...");
|
||||
|
||||
QNetworkAccessManager netMgr;
|
||||
connect(&netMgr, SIGNAL(finished(QNetworkReply*)),
|
||||
SLOT(processNetReply(QNetworkReply*)));
|
||||
connect(netMgr.data(), SIGNAL(finished(QNetworkReply*)), this, SLOT(processNetReply(QNetworkReply*)));
|
||||
|
||||
QUrl loginURL("https://login.minecraft.net/");
|
||||
QNetworkRequest netRequest(loginURL);
|
||||
@ -47,8 +45,7 @@ void LoginTask::executeTask()
|
||||
params.addQueryItem("password", uInfo.password);
|
||||
params.addQueryItem("version", "13");
|
||||
|
||||
netReply = netMgr.post(netRequest, params.query(QUrl::EncodeSpaces).toUtf8());
|
||||
exec();
|
||||
netReply = netMgr->post(netRequest, params.query(QUrl::EncodeSpaces).toUtf8());
|
||||
}
|
||||
|
||||
void LoginTask::processNetReply(QNetworkReply *reply)
|
||||
@ -115,6 +112,5 @@ void LoginTask::processNetReply(QNetworkReply *reply)
|
||||
emit loginFailed("Login failed: " + reply->errorString());
|
||||
break;
|
||||
}
|
||||
|
||||
quit();
|
||||
emitEnded();
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
#define LOGINTASK_H
|
||||
|
||||
#include "Task.h"
|
||||
|
||||
#include <QSharedPointer>
|
||||
#include "libmmc_config.h"
|
||||
|
||||
struct UserInfo
|
||||
@ -33,7 +33,7 @@ struct LoginResponse
|
||||
qint64 latestVersion;
|
||||
};
|
||||
|
||||
//class QNetworkAccessManager;
|
||||
class QNetworkAccessManager;
|
||||
class QNetworkReply;
|
||||
|
||||
class LIBMULTIMC_EXPORT LoginTask : public Task
|
||||
@ -54,6 +54,8 @@ protected:
|
||||
|
||||
QNetworkReply* netReply;
|
||||
UserInfo uInfo;
|
||||
private:
|
||||
QSharedPointer<QNetworkAccessManager> netMgr;
|
||||
};
|
||||
|
||||
#endif // LOGINTASK_H
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include "Task.h"
|
||||
|
||||
Task::Task(QObject *parent) :
|
||||
QThread(parent)
|
||||
QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
@ -49,29 +49,31 @@ void Task::setProgress(int progress)
|
||||
}
|
||||
|
||||
void Task::startTask()
|
||||
{
|
||||
start();
|
||||
}
|
||||
|
||||
void Task::run()
|
||||
{
|
||||
emitStarted();
|
||||
executeTask();
|
||||
emitEnded();
|
||||
}
|
||||
|
||||
void Task::emitStarted()
|
||||
{
|
||||
running = true;
|
||||
emit started();
|
||||
emit started(this);
|
||||
}
|
||||
|
||||
void Task::emitEnded()
|
||||
{
|
||||
running = false;
|
||||
emit ended();
|
||||
emit ended(this);
|
||||
}
|
||||
|
||||
bool Task::isRunning() const
|
||||
{
|
||||
return running;
|
||||
}
|
||||
|
||||
|
||||
void Task::emitStatusChange(const QString &status)
|
||||
{
|
||||
emit statusChanged(status);
|
||||
|
@ -17,12 +17,11 @@
|
||||
#define TASK_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <QString>
|
||||
|
||||
#include "libmmc_config.h"
|
||||
|
||||
class LIBMULTIMC_EXPORT Task : public QThread
|
||||
class LIBMULTIMC_EXPORT Task : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@ -34,6 +33,8 @@ public:
|
||||
QString getStatus() const;
|
||||
int getProgress() const;
|
||||
|
||||
bool isRunning() const;
|
||||
|
||||
/*!
|
||||
* \brief Calculates and sets the task's progress based on the number of parts completed out of the total number to complete.
|
||||
* This is essentially just shorthand for setProgress((parts / whole) * 100);
|
||||
@ -43,7 +44,7 @@ public:
|
||||
*/
|
||||
void calcProgress(int parts, int whole);
|
||||
|
||||
public slots:
|
||||
protected slots:
|
||||
void setStatus(const QString& status);
|
||||
void setProgress(int progress);
|
||||
|
||||
@ -54,7 +55,6 @@ signals:
|
||||
void started();
|
||||
void ended();
|
||||
|
||||
|
||||
void statusChanged(Task* task, const QString& status);
|
||||
void progressChanged(Task* task, int progress);
|
||||
|
||||
@ -62,7 +62,6 @@ signals:
|
||||
void progressChanged(int progress);
|
||||
|
||||
protected:
|
||||
virtual void run();
|
||||
virtual void executeTask() = 0;
|
||||
|
||||
virtual void emitStarted();
|
||||
@ -73,6 +72,7 @@ protected:
|
||||
|
||||
QString status;
|
||||
int progress;
|
||||
bool running = false;
|
||||
};
|
||||
|
||||
#endif // TASK_H
|
||||
|
@ -26,8 +26,6 @@ public:
|
||||
QString expected_md5 = QString()
|
||||
);
|
||||
|
||||
public:
|
||||
static bool ensurePathExists(QString filenamepath);
|
||||
public slots:
|
||||
virtual void start();
|
||||
|
||||
|
@ -29,4 +29,6 @@ LIBUTIL_EXPORT QString RemoveInvalidFilenameChars(QString string, QChar replaceW
|
||||
|
||||
LIBUTIL_EXPORT QString DirNameFromString(QString string, QString inDir = ".");
|
||||
|
||||
LIBUTIL_EXPORT bool ensurePathExists(QString filenamepath);
|
||||
|
||||
#endif // PATHUTILS_H
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "include/dlqueue.h"
|
||||
#include <include/pathutils.h>
|
||||
|
||||
DownloadJob::DownloadJob (QUrl url,
|
||||
QString target_path,
|
||||
@ -48,13 +49,6 @@ JobPtr DownloadJob::create (QSharedPointer<QNetworkAccessManager> net_mgr,
|
||||
return JobPtr ( new DownloadJob ( net_mgr, url, target_path, expected_md5 ) );
|
||||
}
|
||||
|
||||
bool DownloadJob::ensurePathExists(QString filenamepath)
|
||||
{
|
||||
QFileInfo a ( filenamepath );
|
||||
QDir dir;
|
||||
return (dir.mkpath ( a.path() ));
|
||||
}
|
||||
|
||||
void DownloadJob::start()
|
||||
{
|
||||
if ( m_save_to_file )
|
||||
|
@ -65,3 +65,11 @@ QString DirNameFromString(QString string, QString inDir)
|
||||
}
|
||||
return dirName;
|
||||
}
|
||||
|
||||
bool ensurePathExists(QString filenamepath)
|
||||
{
|
||||
QFileInfo a ( filenamepath );
|
||||
QDir dir;
|
||||
return (dir.mkpath ( a.path() ));
|
||||
}
|
||||
|
||||
|
@ -384,6 +384,53 @@ QStringList JlCompress::extractFiles(QString fileCompressed, QStringList files,
|
||||
return extracted;
|
||||
}
|
||||
|
||||
QStringList JlCompress::extractWithExceptions(QString fileCompressed, QString dir, QStringList exceptions)
|
||||
{
|
||||
QuaZip zip(fileCompressed);
|
||||
if(!zip.open(QuaZip::mdUnzip))
|
||||
{
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
QDir directory(dir);
|
||||
QStringList extracted;
|
||||
if (!zip.goToFirstFile())
|
||||
{
|
||||
return QStringList();
|
||||
}
|
||||
do
|
||||
{
|
||||
QString name = zip.getCurrentFileName();
|
||||
bool ok = true;
|
||||
for(auto str: exceptions)
|
||||
{
|
||||
if(name.startsWith(str))
|
||||
{
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!ok)
|
||||
continue;
|
||||
QString absFilePath = directory.absoluteFilePath(name);
|
||||
if (!JlCompress::extractFile(&zip, "", absFilePath))
|
||||
{
|
||||
JlCompress::removeFile(extracted);
|
||||
return QStringList();
|
||||
}
|
||||
extracted.append(absFilePath);
|
||||
} while (zip.goToNextFile());
|
||||
|
||||
zip.close();
|
||||
if(zip.getZipError()!=0)
|
||||
{
|
||||
JlCompress::removeFile(extracted);
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
return extracted;
|
||||
}
|
||||
|
||||
/**OK
|
||||
* Estrae il file fileCompressed nella cartella dir.
|
||||
* Se dir = "" allora il file viene estratto nella cartella corrente.
|
||||
|
@ -102,6 +102,15 @@ public:
|
||||
\return The list of the full paths of the files extracted, empty on failure.
|
||||
*/
|
||||
static QStringList extractDir(QString fileCompressed, QString dir = QString());
|
||||
/// Extract a whole archive, with a list of exceptions (prefixes to ignore).
|
||||
/**
|
||||
\param fileCompressed The name of the archive.
|
||||
\param dir The directory to extract to, the current directory if
|
||||
left empty.
|
||||
\param exceptions The list of exception prefixes
|
||||
\return The list of the full paths of the files extracted, empty on failure.
|
||||
*/
|
||||
static QStringList extractWithExceptions(QString fileCompressed, QString dir, QStringList exceptions);
|
||||
/// Get the file list.
|
||||
/**
|
||||
\return The list of the files in the archive, or, more precisely, the
|
||||
|
Loading…
Reference in New Issue
Block a user