diff --git a/backend/BaseInstance.h b/backend/BaseInstance.h index 7454c17ed..3a344ceae 100644 --- a/backend/BaseInstance.h +++ b/backend/BaseInstance.h @@ -25,6 +25,7 @@ #include "libmmc_config.h" +class BaseUpdate; class MinecraftProcess; class OneSixUpdate; class InstanceList; @@ -117,7 +118,7 @@ public: virtual SettingsObject &settings() const; /// returns a valid update task if update is needed, NULL otherwise - virtual OneSixUpdate* doUpdate() = 0; + virtual BaseUpdate* doUpdate() = 0; /// returns a valid minecraft process, ready for launch virtual MinecraftProcess* prepareForLaunch(QString user, QString session) = 0; diff --git a/backend/BaseUpdate.cpp b/backend/BaseUpdate.cpp new file mode 100644 index 000000000..8a4aced37 --- /dev/null +++ b/backend/BaseUpdate.cpp @@ -0,0 +1,18 @@ +#include "BaseUpdate.h" + +BaseUpdate::BaseUpdate ( BaseInstance* inst, QObject* parent ) : Task ( parent ) +{ + m_inst = inst; +} + +void BaseUpdate::error ( const QString& msg ) +{ + emit gameUpdateError(msg); +} + +void BaseUpdate::updateDownloadProgress(qint64 current, qint64 total) +{ + // The progress on the current file is current / total + float currentDLProgress = (float) current / (float) total; + setProgress((int)(currentDLProgress * 100)); // convert to percentage +} \ No newline at end of file diff --git a/backend/BaseUpdate.h b/backend/BaseUpdate.h new file mode 100644 index 000000000..83eb00892 --- /dev/null +++ b/backend/BaseUpdate.h @@ -0,0 +1,62 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include "net/DownloadJob.h" + +#include "tasks/Task.h" +#include "libmmc_config.h" + +class MinecraftVersion; +class BaseInstance; + +/*! + * The game update task is the task that handles downloading instances' files. + */ +class LIBMULTIMC_EXPORT BaseUpdate : public Task +{ + Q_OBJECT +public: + explicit BaseUpdate(BaseInstance *inst, QObject *parent = 0); + + virtual void executeTask() = 0; + +signals: + /*! + * \brief Signal emitted when the game update is complete. + */ + void gameUpdateComplete(); + + /*! + * \brief Signal emitted if an error occurrs during the update. + * \param errorMsg An error message to be displayed to the user. + */ + void gameUpdateError(const QString &errorMsg); + +protected slots: + virtual void error(const QString &msg); + void updateDownloadProgress(qint64 current, qint64 total); + +protected: + JobListQueue download_queue; + BaseInstance *m_inst; +}; + + diff --git a/backend/CMakeLists.txt b/backend/CMakeLists.txt index 4fbe7bedd..ea19fbbfd 100644 --- a/backend/CMakeLists.txt +++ b/backend/CMakeLists.txt @@ -24,13 +24,20 @@ libmmc_config.h InstanceVersion.h MinecraftVersion.h InstanceFactory.h +BaseUpdate.h BaseInstance.h BaseInstance_p.h MinecraftProcess.h +# network stuffs +net/DownloadJob.h +net/JobQueue.h +net/NetWorker.h + # legacy instances LegacyInstance.h LegacyInstance_p.h +LegacyUpdate.h # 1.6 instances OneSixAssets.h @@ -56,11 +63,17 @@ SET(LIBINST_SOURCES InstanceVersion.cpp MinecraftVersion.cpp InstanceFactory.cpp +BaseUpdate.cpp BaseInstance.cpp MinecraftProcess.cpp +# network stuffs +net/NetWorker.cpp +net/DownloadJob.cpp + # legacy instances LegacyInstance.cpp +LegacyUpdate.cpp # 1.6 instances OneSixAssets.cpp @@ -93,4 +106,3 @@ add_library(backend SHARED ${LIBINST_SOURCES} ${LIBINST_HEADERS}) qt5_use_modules(backend Core Network Xml) target_link_libraries(backend libUtil libSettings quazip) - diff --git a/backend/LegacyInstance.cpp b/backend/LegacyInstance.cpp index dc6cf0dbb..bf5c674b9 100644 --- a/backend/LegacyInstance.cpp +++ b/backend/LegacyInstance.cpp @@ -1,6 +1,7 @@ #include "LegacyInstance.h" #include "LegacyInstance_p.h" #include "MinecraftProcess.h" +#include "LegacyUpdate.h" #include #include #include @@ -16,7 +17,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", "Mojang")); + settings->registerSetting(new Setting("LwjglVersion", "2.9.0")); settings->registerSetting(new Setting("IntendedJarVersion", "")); } @@ -31,10 +32,9 @@ QString LegacyInstance::minecraftDir() const return mcDir.filePath(); } -OneSixUpdate* LegacyInstance::doUpdate() +BaseUpdate* LegacyInstance::doUpdate() { - // legacy instances no longer update - return nullptr; + return new LegacyUpdate(this, this); } MinecraftProcess* LegacyInstance::prepareForLaunch(QString user, QString session) @@ -224,6 +224,6 @@ bool LegacyInstance::setIntendedVersionId ( QString version ) } bool LegacyInstance::shouldUpdate() const { - return false; + return true; } void LegacyInstance::setShouldUpdate ( bool val ) {} diff --git a/backend/LegacyInstance.h b/backend/LegacyInstance.h index e4ab6f292..e7cf347c9 100644 --- a/backend/LegacyInstance.h +++ b/backend/LegacyInstance.h @@ -2,6 +2,8 @@ #include "BaseInstance.h" +class BaseUpdate; + class LIBMULTIMC_EXPORT LegacyInstance : public BaseInstance { Q_OBJECT @@ -77,7 +79,7 @@ public: virtual bool shouldUpdate() const; virtual void setShouldUpdate(bool val); - virtual OneSixUpdate* doUpdate(); + virtual BaseUpdate* doUpdate(); virtual MinecraftProcess* prepareForLaunch( QString user, QString session ); virtual void cleanupAfterRun(); diff --git a/backend/LegacyUpdate.cpp b/backend/LegacyUpdate.cpp new file mode 100644 index 000000000..533be4689 --- /dev/null +++ b/backend/LegacyUpdate.cpp @@ -0,0 +1,185 @@ +#include "LegacyUpdate.h" +#include "lists/LwjglVersionList.h" +#include "BaseInstance.h" +#include "LegacyInstance.h" +#include "net/NetWorker.h" +#include +#include +#include + + +LegacyUpdate::LegacyUpdate ( BaseInstance* inst, QObject* parent ) : BaseUpdate ( inst, parent ) {} + +void LegacyUpdate::executeTask() +{ + lwjglStart(); +} + +void LegacyUpdate::lwjglStart() +{ + LegacyInstance * inst = (LegacyInstance *) m_inst; + auto &list = LWJGLVersionList::get(); + if(!list.isLoaded()) + { + error("Too soon! Let the LWJGL list load :)"); + emitEnded(); + return; + } + QString lwjglVer = inst->lwjglVersion(); + auto version = list.getVersion(lwjglVer); + if(!version) + { + error("Game update failed: the selected LWJGL version is invalid."); + emitEnded(); + } + lwjglVersion = version->name(); + QString url = version->url(); + + auto &worker = NetWorker::spawn(); + QNetworkRequest req(url); + req.setRawHeader("Host", "sourceforge.net"); + req.setHeader(QNetworkRequest::UserAgentHeader, "Wget/1.14 (linux-gnu)"); + QNetworkReply * rep = worker.get ( req ); + + m_reply = QSharedPointer (rep, &QObject::deleteLater); + connect(rep, SIGNAL(downloadProgress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64))); + connect(&worker, SIGNAL(finished(QNetworkReply*)), SLOT(lwjglFinished(QNetworkReply*))); + //connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(downloadError(QNetworkReply::NetworkError))); +} + +void LegacyUpdate::lwjglFinished(QNetworkReply* reply) +{ + if(m_reply != reply) + { + return; + } + if(reply->error() != QNetworkReply::NoError) + { + error("Failed to download: " + reply->errorString() + "\nSometimes you have to wait a bit if you download many LWJGL versions in a row. YMMV"); + emitEnded(); + return; + } + auto &worker = NetWorker::spawn(); + //Here i check if there is a cookie for me in the reply and extract it + QList cookies = qvariant_cast>(reply->header(QNetworkRequest::SetCookieHeader)); + if(cookies.count() != 0) + { + //you must tell which cookie goes with which url + worker.cookieJar()->setCookiesFromUrl(cookies, QUrl("sourceforge.net")); + } + + //here you can check for the 302 or whatever other header i need + QVariant newLoc = reply->header(QNetworkRequest::LocationHeader); + if(newLoc.isValid()) + { + auto &worker = NetWorker::spawn(); + QString redirectedTo = reply->header(QNetworkRequest::LocationHeader).toString(); + QNetworkRequest req(redirectedTo); + req.setRawHeader("Host", "sourceforge.net"); + req.setHeader(QNetworkRequest::UserAgentHeader, "Wget/1.14 (linux-gnu)"); + QNetworkReply * rep = worker.get(req); + connect(rep, SIGNAL(downloadProgress(qint64,qint64)), SLOT(updateDownloadProgress(qint64,qint64))); + m_reply = QSharedPointer (rep, &QObject::deleteLater); + return; + } + QFile saveMe("lwjgl.zip"); + saveMe.open(QIODevice::WriteOnly); + saveMe.write(m_reply->readAll()); + saveMe.close(); + setStatus("Installing new LWJGL..."); + extractLwjgl(); +} +void LegacyUpdate::extractLwjgl() +{ + // make sure the directories are there + QString lwjgl_base = PathCombine("lwjgl", lwjglVersion ); + QString nativesPath = PathCombine( lwjgl_base, "natives/"); + bool success = ensurePathExists(nativesPath); + + if(!success) + { + error("Failed to extract the lwjgl libs - error when creating required folders."); + emitEnded(); + return; + } + + QuaZip zip("lwjgl.zip"); + if(!zip.open(QuaZip::mdUnzip)) + { + error("Failed to extract the lwjgl libs - not a valid archive."); + emitEnded(); + return; + } + + // and now we are going to access files inside it + QuaZipFile file(&zip); + const QString jarNames[] = { "jinput.jar", "lwjgl_util.jar", "lwjgl.jar" }; + for(bool more=zip.goToFirstFile(); more; more=zip.goToNextFile()) + { + if(!file.open(QIODevice::ReadOnly)) + { + zip.close(); + error("Failed to extract the lwjgl libs - error while reading archive."); + emitEnded(); + return; + } + QuaZipFileInfo info; + QString name = file.getActualFileName(); + if(name.endsWith('/')) + { + file.close(); + continue; + } + QString destFileName; + // Look for the jars + for (int i = 0; i < 3; i++) + { + if (name.endsWith(jarNames[i])) + { + destFileName = PathCombine(lwjgl_base, jarNames[i]); + } + } + // Not found? look for the natives + if(destFileName.isEmpty()) + { +#ifdef Q_OS_WIN32 + QString nativesDir = "windows"; +#elif Q_OS_MAC + QString nativesDir = "macosx"; +#else + QString nativesDir = "linux"; +#endif + if (name.contains(nativesDir)) + { + int lastSlash = name.lastIndexOf('/'); + int lastBackSlash = name.lastIndexOf('/'); + if(lastSlash != -1) + name = name.mid(lastSlash+1); + else if(lastBackSlash != -1) + name = name.mid(lastBackSlash+1); + destFileName = PathCombine(nativesPath, name); + } + } + // Now if destFileName is still empty, go to the next file. + if (!destFileName.isEmpty()) + { + setStatus("Installing new LWJGL - Extracting " + name); + QFile output(destFileName); + output.open(QIODevice::WriteOnly); + output.write(file.readAll()); // FIXME: wste of memory!? + output.close(); + } + file.close(); // do not forget to close! + } + zip.close(); + m_reply.clear(); + emit gameUpdateComplete(); + emitEnded(); +} + +void LegacyUpdate::lwjglFailed() +{ + error("Bad stuff happened while trying to get the lwjgl libs..."); + emitEnded(); +} + diff --git a/backend/LegacyUpdate.h b/backend/LegacyUpdate.h new file mode 100644 index 000000000..de5608d05 --- /dev/null +++ b/backend/LegacyUpdate.h @@ -0,0 +1,52 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include "net/DownloadJob.h" +#include "tasks/Task.h" +#include "libmmc_config.h" +#include "BaseUpdate.h" + +class MinecraftVersion; +class BaseInstance; + +class LIBMULTIMC_EXPORT LegacyUpdate : public BaseUpdate +{ + Q_OBJECT +public: + explicit LegacyUpdate(BaseInstance *inst, QObject *parent = 0); + virtual void executeTask(); + +private slots: + void lwjglStart(); + void lwjglFinished( QNetworkReply* ); + void lwjglFailed(); + void extractLwjgl(); +private: + + QSharedPointer m_reply; + + // target version, determined during this task + // MinecraftVersion *targetVersion; + QString lwjglURL; + QString lwjglVersion; +}; + + diff --git a/backend/MinecraftVersion.cpp b/backend/MinecraftVersion.cpp index d6e544047..fdaf0712c 100644 --- a/backend/MinecraftVersion.cpp +++ b/backend/MinecraftVersion.cpp @@ -51,6 +51,9 @@ QString MinecraftVersion::typeName() const case Snapshot: return "Snapshot"; + case Nostalgia: + return "Nostalgia"; + default: return QString("Unknown Type %1").arg(versionType()); } diff --git a/backend/MinecraftVersion.h b/backend/MinecraftVersion.h index 98b10f2d7..f5cf98055 100644 --- a/backend/MinecraftVersion.h +++ b/backend/MinecraftVersion.h @@ -39,6 +39,7 @@ public: Stable, CurrentStable, Snapshot, + Nostalgia }; virtual QString descriptor() const; diff --git a/backend/OneSixAssets.cpp b/backend/OneSixAssets.cpp index 409172b22..db9e7421a 100644 --- a/backend/OneSixAssets.cpp +++ b/backend/OneSixAssets.cpp @@ -2,7 +2,7 @@ #include #include #include "OneSixAssets.h" -#include "dlqueue.h" +#include "net/DownloadJob.h" inline QDomElement getDomElementByTagName(QDomElement parent, QString tagname) { @@ -138,7 +138,7 @@ void OneSixAssets::fetchFinished() QString trimmedEtag = etagStr.remove ( '"' ); nuke_whitelist.append ( keyStr ); if(trimmedEtag != client_etag) - job->add ( DownloadJob::create ( net_manager, QUrl ( prefix + keyStr ), filename ) ); + job->add ( DownloadJob::create ( QUrl ( prefix + keyStr ), filename ) ); } job->add ( JobPtr ( new NukeAndPaveJob ( fprefix, nuke_whitelist ) ) ); diff --git a/backend/OneSixAssets.h b/backend/OneSixAssets.h index 233f925a8..8c345daad 100644 --- a/backend/OneSixAssets.h +++ b/backend/OneSixAssets.h @@ -1,5 +1,5 @@ #pragma once -#include "dlqueue.h" +#include "net/DownloadJob.h" class Private; @@ -16,7 +16,6 @@ public slots: public: void start(); private: - QSharedPointer net_manager {new QNetworkAccessManager()}; JobListQueue dl; JobListPtr index_job; JobListPtr files_job; diff --git a/backend/OneSixInstance.cpp b/backend/OneSixInstance.cpp index 6df2b4712..bf8fd84e9 100644 --- a/backend/OneSixInstance.cpp +++ b/backend/OneSixInstance.cpp @@ -18,7 +18,7 @@ OneSixInstance::OneSixInstance ( const QString& rootDir, SettingsObject* setting reloadFullVersion(); } -OneSixUpdate* OneSixInstance::doUpdate() +BaseUpdate* OneSixInstance::doUpdate() { return new OneSixUpdate(this); } diff --git a/backend/OneSixInstance.h b/backend/OneSixInstance.h index 2e08554d7..12ad9e401 100644 --- a/backend/OneSixInstance.h +++ b/backend/OneSixInstance.h @@ -3,13 +3,14 @@ #include "BaseInstance.h" #include class FullVersion; +class BaseUpdate; class LIBMULTIMC_EXPORT OneSixInstance : public BaseInstance { Q_OBJECT public: explicit OneSixInstance(const QString &rootDir, SettingsObject * settings, QObject *parent = 0); - virtual OneSixUpdate* doUpdate(); + virtual BaseUpdate* doUpdate(); virtual MinecraftProcess* prepareForLaunch ( QString user, QString session ); virtual void cleanupAfterRun(); diff --git a/backend/OneSixUpdate.cpp b/backend/OneSixUpdate.cpp index db3b98640..84d8dfae0 100644 --- a/backend/OneSixUpdate.cpp +++ b/backend/OneSixUpdate.cpp @@ -33,11 +33,7 @@ #include "pathutils.h" -OneSixUpdate::OneSixUpdate(BaseInstance *inst, QObject *parent) : - Task(parent) -{ - m_inst = inst; -} +OneSixUpdate::OneSixUpdate(BaseInstance *inst, QObject *parent):BaseUpdate(inst, parent){} void OneSixUpdate::executeTask() { @@ -142,7 +138,7 @@ void OneSixUpdate::jarlibStart() { QString download_path = lib->downloadPath(); QString storage_path = "libraries/" + lib->storagePath(); - jarlibDownloadJob->add(DownloadJob::create(net_manager, download_path, storage_path)); + jarlibDownloadJob->add(DownloadJob::create(download_path, storage_path)); } connect(jarlibDownloadJob.data(), SIGNAL(finished()), SLOT(jarlibFinished())); connect(jarlibDownloadJob.data(), SIGNAL(failed()), SLOT(jarlibFailed())); @@ -163,15 +159,3 @@ void OneSixUpdate::jarlibFailed() emitEnded(); } -void OneSixUpdate::error(const QString &msg) -{ - emit gameUpdateError(msg); -} - -void OneSixUpdate::updateDownloadProgress(qint64 current, qint64 total) -{ - // The progress on the current file is current / total - float currentDLProgress = (float) current / (float) total; - setProgress((int)(currentDLProgress * 100)); // convert to percentage -} - diff --git a/backend/OneSixUpdate.h b/backend/OneSixUpdate.h index 3bab4ecae..31aed8baa 100644 --- a/backend/OneSixUpdate.h +++ b/backend/OneSixUpdate.h @@ -16,36 +16,25 @@ #pragma once #include - #include - -#include #include -#include "dlqueue.h" +#include "net/DownloadJob.h" #include "tasks/Task.h" #include "libmmc_config.h" +#include "BaseUpdate.h" class MinecraftVersion; class BaseInstance; -/*! - * The game update task is the task that handles downloading instances' files. - */ -class LIBMULTIMC_EXPORT OneSixUpdate : public Task +class LIBMULTIMC_EXPORT OneSixUpdate : public BaseUpdate { Q_OBJECT public: explicit OneSixUpdate(BaseInstance *inst, QObject *parent = 0); - virtual void executeTask(); -public slots: - virtual void error(const QString &msg); - private slots: - void updateDownloadProgress(qint64 current, qint64 total); - void versionFileStart(); void versionFileFinished(); void versionFileFailed(); @@ -54,25 +43,7 @@ private slots: void jarlibFinished(); void jarlibFailed(); - -signals: - /*! - * \brief Signal emitted when the game update is complete. - */ - void gameUpdateComplete(); - - /*! - * \brief Signal emitted if an error occurrs during the update. - * \param errorMsg An error message to be displayed to the user. - */ - void gameUpdateError(const QString &errorMsg); - private: - BaseInstance *m_inst; - - QString m_subStatusMsg; - - QSharedPointer net_manager {new QNetworkAccessManager()}; JobListPtr legacyDownloadJob; JobListPtr specificVersionDownloadJob; JobListPtr jarlibDownloadJob; diff --git a/backend/OneSixVersion.h b/backend/OneSixVersion.h index 160d0426c..1f8090abb 100644 --- a/backend/OneSixVersion.h +++ b/backend/OneSixVersion.h @@ -13,23 +13,14 @@ enum OpSys OpSys OpSys_fromString(QString); -#ifdef Q_OS_MAC - #define currentSystem Os_OSX -#endif - -#ifdef Q_OS_LINUX - #define currentSystem Os_Linux -#endif - #ifdef Q_OS_WIN32 #define currentSystem Os_Windows +#elif Q_OS_MAC + #define currentSystem Os_OSX +#else + #define currentSystem Os_Linux #endif -#ifndef currentSystem - #define currentSystem Os_Other -#endif - - enum RuleAction { Allow, diff --git a/backend/VersionFactory.cpp b/backend/VersionFactory.cpp index 7bec43701..a431ca26f 100644 --- a/backend/VersionFactory.cpp +++ b/backend/VersionFactory.cpp @@ -80,6 +80,16 @@ QSharedPointer FullVersionFactory::parse4(QJsonObject root, QShared fullVersion->minecraftArguments = minecraftArgsValue.toString(); } + auto minecraftTypeValue = root.value("type"); + if(minecraftTypeValue.isString()) + { + QString copy = fullVersion->type = minecraftTypeValue.toString(); + if(copy == "old_aplha" || copy == "old_beta") + { + fullVersion->isLegacy = true; + } + } + fullVersion->releaseTime = root.value("releaseTime").toString(); fullVersion->time = root.value("time").toString(); @@ -107,7 +117,7 @@ QSharedPointer FullVersionFactory::parse4(QJsonObject root, QShared auto urlVal = libObj.value("url"); if(urlVal.isString()) { - library->setBaseUrl(urlVal.toString()); + library->setBaseUrl(nameVal.toString()); } // Extract excludes (if any) @@ -175,19 +185,15 @@ QSharedPointer FullVersionFactory::parse(QByteArray data) } QJsonObject root = jsonDoc.object(); - readVersion->minimumLauncherVersion = root.value("minimumLauncherVersion").toDouble(); - switch(readVersion->minimumLauncherVersion) + int launcher_ver = readVersion->minimumLauncherVersion = root.value("minimumLauncherVersion").toDouble(); + // ADD MORE HERE :D + if(launcher_ver > 0 && launcher_ver <= 7) + return parse4(root, readVersion); + else { - case 1: - case 2: - case 3: - case 4: - return parse4(root, readVersion); - // ADD MORE HERE :D - default: - error_string = "Version file was for an unrecognized launcher version. RIP"; - m_error = FullVersionFactory::UnsupportedVersion; - return QSharedPointer(); + error_string = "Version file was for an unrecognized launcher version. RIP"; + m_error = FullVersionFactory::UnsupportedVersion; + return QSharedPointer(); } } diff --git a/backend/lists/LwjglVersionList.cpp b/backend/lists/LwjglVersionList.cpp index 824d09061..73a27a585 100644 --- a/backend/lists/LwjglVersionList.cpp +++ b/backend/lists/LwjglVersionList.cpp @@ -14,6 +14,7 @@ */ #include "LwjglVersionList.h" +#include #include @@ -53,7 +54,7 @@ QVariant LWJGLVersionList::data(const QModelIndex &index, int role) const return version->name(); case Qt::ToolTipRole: - return version->url().toString(); + return version->url(); default: return QVariant(); @@ -90,7 +91,8 @@ void LWJGLVersionList::loadList() Q_ASSERT_X(!m_loading, "loadList", "list is already loading (m_loading is true)"); setLoading(true); - reply = netMgr.get(QNetworkRequest(QUrl(RSS_URL))); + auto & worker = NetWorker::spawn(); + reply = worker.get(QNetworkRequest(QUrl(RSS_URL))); connect(reply, SIGNAL(finished()), SLOT(netRequestComplete())); } @@ -144,9 +146,9 @@ void LWJGLVersionList::netRequestComplete() // Make sure it's a download link. if (link.endsWith("/download") && link.contains(lwjglRegex)) { - QString name = link.mid(lwjglRegex.indexIn(link)); + QString name = link.mid(lwjglRegex.indexIn(link) + 6); // Subtract 4 here to remove the .zip file extension. - name = name.left(lwjglRegex.matchedLength() - 4); + name = name.left(lwjglRegex.matchedLength() - 10); QUrl url(link); if (!url.isValid()) @@ -179,7 +181,8 @@ const PtrLWJGLVersion LWJGLVersionList::getVersion(const QString &versionName) { for (int i = 0; i < count(); i++) { - if (at(i)->name() == versionName) + QString name = at(i)->name(); + if ( name == versionName) return at(i); } return PtrLWJGLVersion(); diff --git a/backend/lists/LwjglVersionList.h b/backend/lists/LwjglVersionList.h index f3e7799a8..2360f181f 100644 --- a/backend/lists/LwjglVersionList.h +++ b/backend/lists/LwjglVersionList.h @@ -20,7 +20,6 @@ #include #include -#include #include #include "libmmc_config.h" @@ -32,32 +31,22 @@ class LIBMULTIMC_EXPORT LWJGLVersion : public QObject { Q_OBJECT - /*! - * The name of the LWJGL version. - */ - Q_PROPERTY(QString name READ name) - - /*! - * The URL for this version of LWJGL. - */ - Q_PROPERTY(QUrl url READ url) - - LWJGLVersion(const QString &name, const QUrl &url, QObject *parent = 0) : + LWJGLVersion(const QString &name, const QString &url, QObject *parent = 0) : QObject(parent), m_name(name), m_url(url) { } public: - static PtrLWJGLVersion Create(const QString &name, const QUrl &url, QObject *parent = 0) + static PtrLWJGLVersion Create(const QString &name, const QString &url, QObject *parent = 0) { return PtrLWJGLVersion(new LWJGLVersion(name, url, parent)); }; QString name() const { return m_name; } - QUrl url() const { return m_url; } + QString url() const { return m_url; } protected: QString m_name; - QUrl m_url; + QString m_url; }; class LIBMULTIMC_EXPORT LWJGLVersionList : public QAbstractListModel @@ -112,8 +101,6 @@ private: QList m_vlist; QNetworkReply *m_netReply; - - QNetworkAccessManager netMgr; QNetworkReply *reply; bool m_loading; diff --git a/backend/lists/MinecraftVersionList.cpp b/backend/lists/MinecraftVersionList.cpp index 7f220086b..e14d7a256 100644 --- a/backend/lists/MinecraftVersionList.cpp +++ b/backend/lists/MinecraftVersionList.cpp @@ -14,6 +14,7 @@ */ #include "MinecraftVersionList.h" +#include #include @@ -29,8 +30,6 @@ #include -#include "netutils.h" - #define MCVLIST_URLBASE "http://s3.amazonaws.com/Minecraft.Download/versions/" #define ASSETS_URLBASE "http://assets.minecraft.net/" #define MCN_URLBASE "http://sonicrules.org/mcnweb.py" @@ -160,21 +159,18 @@ MCVListLoadTask::MCVListLoadTask(MinecraftVersionList *vlist) { m_list = vlist; m_currentStable = NULL; - netMgr = nullptr; vlistReply = nullptr; } MCVListLoadTask::~MCVListLoadTask() { - if(netMgr) - netMgr->deleteLater(); } void MCVListLoadTask::executeTask() { setStatus("Loading instance version list..."); - netMgr = new QNetworkAccessManager(); - vlistReply = netMgr->get(QNetworkRequest(QUrl(QString(MCVLIST_URLBASE) + "versions.json"))); + auto & worker = NetWorker::spawn(); + vlistReply = worker.get(QNetworkRequest(QUrl(QString(MCVLIST_URLBASE) + "versions.json"))); connect(vlistReply, SIGNAL(finished()), this, SLOT(list_downloaded())); } @@ -283,12 +279,18 @@ void MCVListLoadTask::list_downloaded() { versionType = MinecraftVersion::Snapshot; } + else if(versionTypeStr == "old_beta" || versionTypeStr == "old_alpha") + { + versionType = MinecraftVersion::Nostalgia; + } else { //FIXME: log this somewhere continue; } + //FIXME: detect if snapshots are old or not + // Get the download URL. QString dlUrl = QString(MCVLIST_URLBASE) + versionID + "/"; diff --git a/backend/lists/MinecraftVersionList.h b/backend/lists/MinecraftVersionList.h index 078c7c66e..8707016ae 100644 --- a/backend/lists/MinecraftVersionList.h +++ b/backend/lists/MinecraftVersionList.h @@ -24,7 +24,6 @@ #include "libmmc_config.h" class MCVListLoadTask; -class QNetworkAccessManager; class QNetworkReply; class LIBMULTIMC_EXPORT MinecraftVersionList : public InstVersionList @@ -76,7 +75,6 @@ protected: //! Loads versions from Mojang's official version list. bool loadFromVList(); - QNetworkAccessManager *netMgr; QNetworkReply *vlistReply; MinecraftVersionList *m_list; diff --git a/libutil/src/dlqueue.cpp b/backend/net/DownloadJob.cpp similarity index 79% rename from libutil/src/dlqueue.cpp rename to backend/net/DownloadJob.cpp index 65e0e31e4..ef842dfd8 100644 --- a/libutil/src/dlqueue.cpp +++ b/backend/net/DownloadJob.cpp @@ -1,5 +1,6 @@ -#include "include/dlqueue.h" -#include +#include "DownloadJob.h" +#include "pathutils.h" +#include "NetWorker.h" DownloadJob::DownloadJob (QUrl url, QString target_path, @@ -14,7 +15,6 @@ DownloadJob::DownloadJob (QUrl url, m_save_to_file = m_target_path.size(); m_status = Job_NotStarted; m_opened_for_saving = false; - m_manager.reset(new QNetworkAccessManager()); } JobPtr DownloadJob::create (QUrl url, @@ -24,31 +24,6 @@ JobPtr DownloadJob::create (QUrl url, return JobPtr ( new DownloadJob ( url, target_path, expected_md5 ) ); } -DownloadJob::DownloadJob (QSharedPointer net_mgr, - QUrl url, - QString target_path, - QString expected_md5 ) - :Job() -{ - m_url = url; - m_target_path = target_path; - m_expected_md5 = expected_md5; - - m_check_md5 = m_expected_md5.size(); - m_save_to_file = m_target_path.size(); - m_status = Job_NotStarted; - m_opened_for_saving = false; - m_manager = net_mgr; -} - -JobPtr DownloadJob::create (QSharedPointer net_mgr, - QUrl url, - QString target_path, - QString expected_md5 ) -{ - return JobPtr ( new DownloadJob ( net_mgr, url, target_path, expected_md5 ) ); -} - void DownloadJob::start() { if ( m_save_to_file ) @@ -82,7 +57,10 @@ void DownloadJob::start() qDebug() << "Downloading " << m_url.toString(); QNetworkRequest request ( m_url ); request.setRawHeader(QString("If-None-Match").toLatin1(), m_expected_md5.toLatin1()); - QNetworkReply * rep = m_manager->get ( request ); + + auto &worker = NetWorker::spawn(); + QNetworkReply * rep = worker.get ( request ); + m_reply = QSharedPointer ( rep, &QObject::deleteLater ); connect ( rep, SIGNAL ( downloadProgress ( qint64,qint64 ) ), SLOT ( downloadProgress ( qint64,qint64 ) ) ); connect ( rep, SIGNAL ( finished() ), SLOT ( downloadFinished() ) ); diff --git a/libutil/include/dlqueue.h b/backend/net/DownloadJob.h similarity index 74% rename from libutil/include/dlqueue.h rename to backend/net/DownloadJob.h index 015f4deeb..cbde3852f 100644 --- a/libutil/include/dlqueue.h +++ b/backend/net/DownloadJob.h @@ -1,5 +1,5 @@ #pragma once -#include "jobqueue.h" +#include "JobQueue.h" #include /** @@ -14,18 +14,6 @@ public: QString expected_md5 = QString() ); static JobPtr create(QUrl url, QString rel_target_path = QString(), QString expected_md5 = QString()); - - DownloadJob(QSharedPointer net_mgr, - QUrl url, - QString rel_target_path = QString(), - QString expected_md5 = QString() - ); - static JobPtr create(QSharedPointer net_mgr, - QUrl url, - QString rel_target_path = QString(), - QString expected_md5 = QString() - ); - public slots: virtual void start(); @@ -36,8 +24,6 @@ private slots: void downloadReadyRead(); public: - /// the associated network manager - QSharedPointer m_manager; /// the network reply QSharedPointer m_reply; /// source URL diff --git a/libutil/include/jobqueue.h b/backend/net/JobQueue.h similarity index 100% rename from libutil/include/jobqueue.h rename to backend/net/JobQueue.h diff --git a/backend/net/NetWorker.cpp b/backend/net/NetWorker.cpp new file mode 100644 index 000000000..1eef13d93 --- /dev/null +++ b/backend/net/NetWorker.cpp @@ -0,0 +1,12 @@ +#include "NetWorker.h" +#include + +NetWorker& NetWorker::spawn() +{ + static QThreadStorage storage; + if (!storage.hasLocalData()) + { + storage.setLocalData(new NetWorker()); + } + return *storage.localData(); +} diff --git a/backend/net/NetWorker.h b/backend/net/NetWorker.h new file mode 100644 index 000000000..98374e3bf --- /dev/null +++ b/backend/net/NetWorker.h @@ -0,0 +1,20 @@ +/* + _.ooo-._ + .OOOP _ '. + dOOOO (_) \ + OOOOOb | + OOOOOOb. | + OOOOOOOOb | + YOO(_)OOO / + 'OOOOOY _.' + '""""'' +*/ + +#pragma once +#include +class NetWorker : public QNetworkAccessManager +{ + Q_OBJECT +public: + static NetWorker &spawn(); +}; \ No newline at end of file diff --git a/backend/tasks/LoginTask.cpp b/backend/tasks/LoginTask.cpp index 30e97ca98..7a1d52622 100644 --- a/backend/tasks/LoginTask.cpp +++ b/backend/tasks/LoginTask.cpp @@ -14,27 +14,23 @@ */ #include "LoginTask.h" +#include #include -#include -#include -#include +#include +#include #include #include -LoginTask::LoginTask( const UserInfo& uInfo, QObject* parent ) : - Task(parent), uInfo(uInfo) -{ - netMgr.reset(new QNetworkAccessManager()); -} +LoginTask::LoginTask( const UserInfo& uInfo, QObject* parent ) : Task(parent), uInfo(uInfo){} void LoginTask::executeTask() { setStatus("Logging in..."); - - connect(netMgr.data(), SIGNAL(finished(QNetworkReply*)), this, SLOT(processNetReply(QNetworkReply*))); + auto & worker = NetWorker::spawn(); + connect(&worker, SIGNAL(finished(QNetworkReply*)), this, SLOT(processNetReply(QNetworkReply*))); QUrl loginURL("https://login.minecraft.net/"); QNetworkRequest netRequest(loginURL); @@ -45,11 +41,13 @@ void LoginTask::executeTask() params.addQueryItem("password", uInfo.password); params.addQueryItem("version", "13"); - netReply = netMgr->post(netRequest, params.query(QUrl::EncodeSpaces).toUtf8()); + netReply = worker.post(netRequest, params.query(QUrl::EncodeSpaces).toUtf8()); } void LoginTask::processNetReply(QNetworkReply *reply) { + if(netReply != reply) + return; // Check for errors. switch (reply->error()) { diff --git a/backend/tasks/LoginTask.h b/backend/tasks/LoginTask.h index e2f72f9e8..81d1b6cc7 100644 --- a/backend/tasks/LoginTask.h +++ b/backend/tasks/LoginTask.h @@ -33,7 +33,6 @@ struct LoginResponse qint64 latestVersion; }; -class QNetworkAccessManager; class QNetworkReply; class LIBMULTIMC_EXPORT LoginTask : public Task @@ -54,8 +53,6 @@ protected: QNetworkReply* netReply; UserInfo uInfo; -private: - QSharedPointer netMgr; }; #endif // LOGINTASK_H diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 259490423..309e41805 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -412,7 +412,7 @@ void MainWindow::onLoginComplete(LoginResponse response) return; m_activeLogin = LoginResponse(response); - OneSixUpdate *updateTask = m_activeInst->doUpdate(); + BaseUpdate *updateTask = m_activeInst->doUpdate(); if(!updateTask) { launchInstance(m_activeInst, m_activeLogin); diff --git a/gui/versionselectdialog.cpp b/gui/versionselectdialog.cpp index 9f1a86539..b3a14db1d 100644 --- a/gui/versionselectdialog.cpp +++ b/gui/versionselectdialog.cpp @@ -90,7 +90,7 @@ void VersionSelectDialog::updateFilterState() if (!ui->filterSnapshotsCheckbox->isChecked()) filteredTypes += "Snapshot"; if (!ui->filterMCNostalgiaCheckbox->isChecked()) - filteredTypes += "MCNostalgia"; + filteredTypes += "Nostalgia"; QString regexStr = "^.*$"; if (filteredTypes.length() > 0) diff --git a/gui/versionselectdialog.ui b/gui/versionselectdialog.ui index 2bdd4449e..5cb0ebad7 100644 --- a/gui/versionselectdialog.ui +++ b/gui/versionselectdialog.ui @@ -7,7 +7,7 @@ 0 0 400 - 300 + 347 @@ -38,20 +38,71 @@ + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + 0 + 0 + + Show &snapshots? + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + 0 + 0 + + - Show MC&Nostalgia? + Show &Nostalgia? + + + + Qt::Horizontal + + + + 40 + 20 + + + + diff --git a/libutil/CMakeLists.txt b/libutil/CMakeLists.txt index d3f90a1dd..7affb5ea6 100644 --- a/libutil/CMakeLists.txt +++ b/libutil/CMakeLists.txt @@ -20,7 +20,7 @@ find_package(Qt5Core REQUIRED) # Include Qt headers. include_directories(${Qt5Base_INCLUDE_DIRS}) -include_directories(${Qt5Network_INCLUDE_DIRS}) +# include_directories(${Qt5Network_INCLUDE_DIRS}) SET(LIBUTIL_HEADERS include/libutil_config.h @@ -31,9 +31,6 @@ include/pathutils.h include/osutils.h include/userutils.h include/cmdutils.h -include/netutils.h -include/jobqueue.h -include/dlqueue.h ) SET(LIBUTIL_SOURCES @@ -41,8 +38,6 @@ src/pathutils.cpp src/osutils.cpp src/userutils.cpp src/cmdutils.cpp -src/netutils.cpp -src/dlqueue.cpp ) # Set the include dir path. @@ -51,5 +46,6 @@ SET(LIBUTIL_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE) add_definitions(-DLIBUTIL_LIBRARY) add_library(libUtil SHARED ${LIBUTIL_SOURCES} ${LIBUTIL_HEADERS}) -qt5_use_modules(libUtil Core Network) +# qt5_use_modules(libUtil Core Network) +qt5_use_modules(libUtil Core) target_link_libraries(libUtil) diff --git a/libutil/include/netutils.h b/libutil/include/netutils.h deleted file mode 100644 index 0153693ba..000000000 --- a/libutil/include/netutils.h +++ /dev/null @@ -1,36 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef NETUTILS_H -#define NETUTILS_H - -#include - -#include -#include - -namespace NetUtils -{ - -inline void waitForNetRequest(QNetworkReply *netReply) -{ - QEventLoop loop; - loop.connect(netReply, SIGNAL(finished()), SLOT(quit())); - loop.exec(); -} - -} - -#endif // NETUTILS_H diff --git a/libutil/src/netutils.cpp b/libutil/src/netutils.cpp deleted file mode 100644 index 57eead9b5..000000000 --- a/libutil/src/netutils.cpp +++ /dev/null @@ -1,16 +0,0 @@ -/* Copyright 2013 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "include/netutils.h"