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

View File

@ -26,8 +26,6 @@ public:
QString expected_md5 = QString()
);
public:
static bool ensurePathExists(QString filenamepath);
public slots:
virtual void start();

View File

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

View File

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

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

View File

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

View File

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