Runnable 1.6 instances!

This commit is contained in:
Petr Mrázek
2013-08-05 03:29:50 +02:00
parent 005a010ee6
commit 183a735145
23 changed files with 502 additions and 214 deletions

View File

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

View File

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

View File

@ -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 ) {}

View File

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

View File

@ -134,6 +134,7 @@ void MinecraftProcess::finish(int code, ExitStatus status)
//TODO: error handling
}
}
m_instance->cleanupAfterRun();
emit ended();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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