diff options
author | Andrew <forkk@forkk.net> | 2013-03-08 13:56:26 -0600 |
---|---|---|
committer | Andrew <forkk@forkk.net> | 2013-03-08 13:56:26 -0600 |
commit | 2d6e785e4ee8a8b837fe84f83972ec23a09564af (patch) | |
tree | 6afdac6e06f1ba8ae5c29f62b5a4a9bc1b696b12 /plugins/stdinstance | |
parent | 69040f923b0344de214d6f1fc4553d223df7d2d6 (diff) | |
download | MultiMC-2d6e785e4ee8a8b837fe84f83972ec23a09564af.tar MultiMC-2d6e785e4ee8a8b837fe84f83972ec23a09564af.tar.gz MultiMC-2d6e785e4ee8a8b837fe84f83972ec23a09564af.tar.lz MultiMC-2d6e785e4ee8a8b837fe84f83972ec23a09564af.tar.xz MultiMC-2d6e785e4ee8a8b837fe84f83972ec23a09564af.zip |
Implemented version lists.
Diffstat (limited to 'plugins/stdinstance')
-rw-r--r-- | plugins/stdinstance/CMakeLists.txt | 7 | ||||
-rw-r--r-- | plugins/stdinstance/stdinstance.cpp | 7 | ||||
-rw-r--r-- | plugins/stdinstance/stdinstance.h | 2 | ||||
-rw-r--r-- | plugins/stdinstance/stdinstancetype.cpp | 6 | ||||
-rw-r--r-- | plugins/stdinstance/stdinstancetype.h | 3 | ||||
-rw-r--r-- | plugins/stdinstance/stdinstversion.cpp | 147 | ||||
-rw-r--r-- | plugins/stdinstance/stdinstversion.h | 82 | ||||
-rw-r--r-- | plugins/stdinstance/stdinstversionlist.cpp | 509 | ||||
-rw-r--r-- | plugins/stdinstance/stdinstversionlist.h | 99 |
9 files changed, 861 insertions, 1 deletions
diff --git a/plugins/stdinstance/CMakeLists.txt b/plugins/stdinstance/CMakeLists.txt index 7b1ff192..deebf812 100644 --- a/plugins/stdinstance/CMakeLists.txt +++ b/plugins/stdinstance/CMakeLists.txt @@ -5,6 +5,7 @@ ADD_DEFINITIONS(-DQT_PLUGIN) # Find Qt find_package(Qt5Core REQUIRED) find_package(Qt5Network REQUIRED) +find_package(Qt5Xml REQUIRED) # Include Qt headers. include_directories(${Qt5Base_INCLUDE_DIRS}) @@ -25,11 +26,15 @@ include_directories(${CMAKE_SOURCE_DIR}libinstance/include) SET(STDINST_HEADERS stdinstancetype.h stdinstance.h +stdinstversionlist.h +stdinstversion.h ) SET(STDINST_SOURCES stdinstancetype.cpp stdinstance.cpp +stdinstversionlist.cpp +stdinstversion.cpp ) add_library(stdinstance SHARED ${STDINST_SOURCES} ${STDINST_HEADERS}) @@ -41,7 +46,7 @@ IF(UNIX) set_target_properties(stdinstance PROPERTIES LIBRARY_OUTPUT_DIRECTORY "..") ENDIF() -qt5_use_modules(stdinstance Core Network) +qt5_use_modules(stdinstance Core Network Xml) target_link_libraries(stdinstance quazip patchlib diff --git a/plugins/stdinstance/stdinstance.cpp b/plugins/stdinstance/stdinstance.cpp index 077b6b15..e5d87d23 100644 --- a/plugins/stdinstance/stdinstance.cpp +++ b/plugins/stdinstance/stdinstance.cpp @@ -21,6 +21,8 @@ #include <javautils.h> +#include "stdinstversionlist.h" + StdInstance::StdInstance(const QString &rootDir, const InstanceTypeInterface *iType, QObject *parent) : Instance(rootDir, parent) { @@ -61,3 +63,8 @@ const InstanceTypeInterface *StdInstance::instanceType() const { return m_instType; } + +InstVersionList *StdInstance::versionList() const +{ + return &vList; +} diff --git a/plugins/stdinstance/stdinstance.h b/plugins/stdinstance/stdinstance.h index 9c4b6fd6..2058453b 100644 --- a/plugins/stdinstance/stdinstance.h +++ b/plugins/stdinstance/stdinstance.h @@ -30,6 +30,8 @@ public: virtual const InstanceTypeInterface *instanceType() const; + virtual InstVersionList *versionList() const; + ////// TIMESTAMPS ////// virtual qint64 lastVersionUpdate() { return settings().get("lastVersionUpdate").value<qint64>(); } virtual void setLastVersionUpdate(qint64 val) { settings().set("lastVersionUpdate", val); } diff --git a/plugins/stdinstance/stdinstancetype.cpp b/plugins/stdinstance/stdinstancetype.cpp index 93c5fd16..8ad7fd40 100644 --- a/plugins/stdinstance/stdinstancetype.cpp +++ b/plugins/stdinstance/stdinstancetype.cpp @@ -19,6 +19,7 @@ #include <QFileInfo> #include "stdinstance.h" +#include "stdinstversionlist.h" StdInstanceType::StdInstanceType(QObject *parent) : QObject(parent) @@ -26,6 +27,11 @@ StdInstanceType::StdInstanceType(QObject *parent) : } +InstVersionList *StdInstanceType::versionList() const +{ + return &vList; +} + InstanceLoader::InstTypeError StdInstanceType::createInstance(Instance *&inst, const QString &instDir) const { diff --git a/plugins/stdinstance/stdinstancetype.h b/plugins/stdinstance/stdinstancetype.h index b8382a97..4840ab51 100644 --- a/plugins/stdinstance/stdinstancetype.h +++ b/plugins/stdinstance/stdinstancetype.h @@ -34,6 +34,9 @@ public: virtual QString description() const { return "A standard Minecraft instance."; } + virtual InstVersionList *versionList() const; + +protected: virtual InstanceLoader::InstTypeError createInstance(Instance *&inst, const QString &instDir) const; virtual InstanceLoader::InstTypeError loadInstance(Instance *&inst, const QString &instDir) const; diff --git a/plugins/stdinstance/stdinstversion.cpp b/plugins/stdinstance/stdinstversion.cpp new file mode 100644 index 00000000..0e582ffc --- /dev/null +++ b/plugins/stdinstance/stdinstversion.cpp @@ -0,0 +1,147 @@ +/* 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 "stdinstversion.h" + +StdInstVersion::StdInstVersion(QString descriptor, + QString name, + qint64 timestamp, + QString dlUrl, + bool hasLWJGL, + QString etag, + InstVersionList *parent) : + InstVersion(parent), m_descriptor(descriptor), m_name(name), m_timestamp(timestamp), + m_dlUrl(dlUrl), m_hasLWJGL(hasLWJGL), m_etag(etag) +{ + m_linkedVersion = NULL; +} + +StdInstVersion::StdInstVersion(StdInstVersion *linkedVersion) +{ + m_linkedVersion = linkedVersion; +} + +StdInstVersion::StdInstVersion() +{ + m_timestamp = 0; + m_hasLWJGL = false; + m_linkedVersion = NULL; +} + +StdInstVersion *StdInstVersion::mcnVersion(QString rawName, QString niceName) +{ + StdInstVersion *version = new StdInstVersion; + version->m_descriptor = rawName; + version->m_name = niceName; + version->setVersionType(MCNostalgia); + return version; +} + +QString StdInstVersion::descriptor() const +{ + if (m_linkedVersion) + return m_linkedVersion->descriptor(); + return m_descriptor; +} + +QString StdInstVersion::name() const +{ + if (m_linkedVersion) + return m_linkedVersion->name(); + return m_name; +} + +QString StdInstVersion::type() const +{ + if (m_linkedVersion) + return m_linkedVersion->type(); + + switch (versionType()) + { + case OldSnapshot: + return "Old Snapshot"; + + case Stable: + return "Stable"; + + case CurrentStable: + return "Current Stable"; + + case Snapshot: + return "Snapshot"; + + case MCNostalgia: + return "MCNostalgia"; + + case MetaCustom: + // Not really sure what this does, but it was in the code for v4, + // so it must be important... Right? + return "Custom Meta Version"; + + case MetaLatestSnapshot: + return "Latest Snapshot"; + + case MetaLatestStable: + return "Latest Stable"; + + default: + return QString("Unknown Type %1").arg(versionType()); + } +} + +qint64 StdInstVersion::timestamp() const +{ + if (m_linkedVersion) + return m_linkedVersion->timestamp(); + return m_timestamp; +} + +QString StdInstVersion::downloadURL() const +{ + if (m_linkedVersion) + return m_linkedVersion->downloadURL(); + return m_dlUrl; +} + +bool StdInstVersion::hasLWJGL() const +{ + if (m_linkedVersion) + return m_linkedVersion->hasLWJGL(); + return m_hasLWJGL; +} + +QString StdInstVersion::etag() const +{ + if (m_linkedVersion) + return m_linkedVersion->etag(); + return m_etag; +} + +StdInstVersion::VersionType StdInstVersion::versionType() const +{ + return m_type; +} + +void StdInstVersion::setVersionType(StdInstVersion::VersionType type) +{ + m_type = type; +} + +bool StdInstVersion::isMeta() const +{ + return versionType() == MetaCustom || + versionType() == MetaLatestSnapshot || + versionType() == MetaLatestStable; +} diff --git a/plugins/stdinstance/stdinstversion.h b/plugins/stdinstance/stdinstversion.h new file mode 100644 index 00000000..3f03ae83 --- /dev/null +++ b/plugins/stdinstance/stdinstversion.h @@ -0,0 +1,82 @@ +/* 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 STDINSTVERSION_H +#define STDINSTVERSION_H + +#include "instversion.h" + +/*! + * \brief Implements a standard Minecraft instance version. + * This class also supports meta versions (i.e. versions that are essentially + * aliases of other versions). + */ +class StdInstVersion : public InstVersion +{ + Q_OBJECT +public: + explicit StdInstVersion(QString descriptor, + QString name, + qint64 timestamp, + QString dlUrl, + bool hasLWJGL, + QString etag, + InstVersionList *parent); + + explicit StdInstVersion(StdInstVersion *linkedVersion); + + StdInstVersion(); + + static StdInstVersion *mcnVersion(QString rawName, QString niceName); + + enum VersionType + { + OldSnapshot, + Stable, + CurrentStable, + Snapshot, + MCNostalgia, + MetaCustom, + MetaLatestSnapshot, + MetaLatestStable + }; + + virtual QString descriptor() const; + virtual QString name() const; + virtual QString type() const; + virtual qint64 timestamp() const; + virtual QString downloadURL() const; + virtual bool hasLWJGL() const; + virtual QString etag() const; + + virtual VersionType versionType() const; + virtual void setVersionType(VersionType type); + + virtual bool isMeta() const; + + +protected: + QString m_descriptor; + QString m_name; + qint64 m_timestamp; + QString m_dlUrl; + bool m_hasLWJGL; + QString m_etag; + VersionType m_type; + + StdInstVersion *m_linkedVersion; +}; + +#endif // STDINSTVERSION_H diff --git a/plugins/stdinstance/stdinstversionlist.cpp b/plugins/stdinstance/stdinstversionlist.cpp new file mode 100644 index 00000000..4ad4c52f --- /dev/null +++ b/plugins/stdinstance/stdinstversionlist.cpp @@ -0,0 +1,509 @@ +/* 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 "stdinstversionlist.h" + +#include <QNetworkAccessManager> +#include <QNetworkRequest> +#include <QNetworkReply> + +#include <QtXml/QDomDocument> + +#include <QJsonDocument> +#include <QJsonObject> +#include <QJsonArray> +#include <QJsonParseError> + +#include <QDateTime> +#include <QMap> +#include <QMapIterator> +#include <QStringList> +#include <QUrl> + +#include <QRegExp> + +#include <QDebug> + +#include <instversion.h> + +#include "stdinstversion.h" + +#define MCDL_URLBASE "http://assets.minecraft.net/" +#define ASSETS_URLBASE "http://s3.amazonaws.com/MinecraftDownload/" +#define MCN_URLBASE "http://sonicrules.org/mcnweb.py" + +// When this is defined, prints the entire version list to qDebug() after loading. +#define PRINT_VERSIONS + + +StdInstVersionList vList; + +StdInstVersionList::StdInstVersionList(QObject *parent) : + InstVersionList(parent) +{ + loaded = false; +} + +Task *StdInstVersionList::getLoadTask() +{ + return new StdInstVListLoadTask(this); +} + +bool StdInstVersionList::isLoaded() +{ + return loaded; +} + +const InstVersion *StdInstVersionList::at(int i) const +{ + return m_vlist.at(i); +} + +int StdInstVersionList::count() const +{ + return m_vlist.count(); +} + +void StdInstVersionList::printToStdOut() +{ + qDebug() << "---------------- Version List ----------------"; + + for (int i = 0; i < m_vlist.count(); i++) + { + StdInstVersion *version = qobject_cast<StdInstVersion *>(m_vlist.at(i)); + + if (!version) + continue; + + qDebug() << "Version " << version->name(); + qDebug() << "\tDownload: " << version->downloadURL(); + qDebug() << "\tTimestamp: " << version->timestamp(); + qDebug() << "\tType: " << version->type(); + qDebug() << "----------------------------------------------"; + } +} + + +StdInstVListLoadTask::StdInstVListLoadTask(StdInstVersionList *vlist) : + Task(vlist) +{ + m_list = vlist; + processedMCDLReply = false; + processedAssetsReply = false; + processedMCNReply = false; + + currentStable = NULL; + foundCurrentInAssets = false; +} + +void StdInstVListLoadTask::executeTask() +{ + setSubStatus(); + + // Initialize the network access manager. + QNetworkAccessManager netMgr; + + mcdlReply = netMgr.get(QNetworkRequest(QUrl(ASSETS_URLBASE))); + assetsReply = netMgr.get(QNetworkRequest(QUrl(MCDL_URLBASE))); + mcnReply = netMgr.get(QNetworkRequest(QUrl(QString(MCN_URLBASE) + "?pversion=1&list=True"))); + + connect(mcdlReply, SIGNAL(finished()), + SLOT(processMCDLReply())); + connect(mcnReply, SIGNAL(finished()), + SLOT(processMCNReply())); + + exec(); + finalize(); +} + +void StdInstVListLoadTask::finalize() +{ + // First, we need to do some cleanup. We loaded MCNostalgia versions into + // mcnList and all the others into tempList. MCNostalgia provides some versions + // that are on assets.minecraft.net and we want to ignore those, so we remove + // and delete them from mcnList. + + // To start, we get a list of the descriptors in tmpList. + QStringList tlistDescriptors; + for (int i = 0; i < tempList.count(); i++) + tlistDescriptors.append(tempList.at(i)->descriptor()); + + // Now, we go through our MCNostalgia version list and remove anything with + // a descriptor that matches one we already have in tempList. + // We'll need a list of items we're going to remove. + for (int i = 0; i < mcnList.count(); i++) + if (tlistDescriptors.contains(mcnList.at(i)->descriptor())) + delete mcnList.takeAt(i--); // We need to decrement here because we're removing an item. + + // Now that the duplicates are gone, we need to merge the two lists. This is + // simple enough. + tempList.append(mcnList); + + // We're done with mcnList now, but the items have been moved over to + // tempList, so we don't need to delete them. + + // Now we swap the list we loaded into the actual version list. + // This applies our changes to the version list immediately and still gives us + // access to the old list so that we can delete the objects in it and free their memory. + // By doing this, we cause the version list to update immediately. + m_list->m_vlist.swap(tempList); + + // We called swap, so all the data that was in the version list previously is now in + // tempList (and vice-versa). Now we just free the memory. + while (!tempList.isEmpty()) + delete tempList.takeFirst(); + +#ifdef PRINT_VERSIONS + m_list->printToStdOut(); +#endif +} + +inline QDomElement getDomElementByTagName(QDomElement parent, QString tagname) +{ + QDomNodeList elementList = parent.elementsByTagName(tagname); + if (elementList.count()) + return elementList.at(0).toElement(); + else + return QDomElement(); +} + +inline QDateTime timeFromS3Time(QString str) +{ + const QString fmt("yyyy-MM-dd'T'HH:mm:ss'.000Z'"); + return QDateTime::fromString(str, fmt); +} + +void StdInstVListLoadTask::processMCDLReply() +{ + switch (mcdlReply->error()) + { + case QNetworkReply::NoError: + { + // Get the XML string. + QString xmlString = mcdlReply->readAll(); + + QString xmlErrorMsg; + + QDomDocument doc; + if (!doc.setContent(xmlString, false, &xmlErrorMsg)) + { + // TODO: Display error message to the user. + qDebug(QString("Failed to process Minecraft download site. XML error: %s"). + arg(xmlErrorMsg).toUtf8()); + } + + QDomNodeList contents = doc.elementsByTagName("Contents"); + + for (int i = 0; i < contents.length(); i++) + { + QDomElement element = contents.at(i).toElement(); + + if (element.isNull()) + continue; + + QDomElement keyElement = getDomElementByTagName(element, "Key"); + QDomElement lastmodElement = getDomElementByTagName(element, "LastModified"); + QDomElement etagElement = getDomElementByTagName(element, "ETag"); + + if (keyElement.isNull() || lastmodElement.isNull() || etagElement.isNull()) + continue; + + QString key = keyElement.text(); + QString lastModStr = lastmodElement.text(); + QString etagStr = etagElement.text(); + QString dlUrl = "http://s3.amazonaws.com/MinecraftDownload/"; + + if (key != "minecraft.jar") + continue; + + QDateTime versionTimestamp = timeFromS3Time(lastModStr); + if (!versionTimestamp.isValid()) + { + qDebug(QString("Failed to parse timestamp for current stable version %1"). + arg(lastModStr).toUtf8()); + versionTimestamp = QDateTime::currentDateTime(); + } + + currentStable = new StdInstVersion("LatestStable", "Current", + versionTimestamp.toMSecsSinceEpoch(), + "http://s3.amazonaws.com/MinecraftDownload/", + true, etagStr, m_list); + + setSubStatus("Loaded latest version info."); + } + break; + } + + default: + // TODO: Network error handling. + break; + } + + if (!currentStable) + qDebug("Failed to get current stable version."); + + + processedMCDLReply = true; + updateStuff(); + + // If the assets request isn't finished yet, connect the slot to allow it + // to process when the request is done. Otherwise, simply call the + // processAssetsReply slot directly. + if (!assetsReply->isFinished()) + connect(assetsReply, SIGNAL(finished()), + SLOT(processAssetsReply())); + else if (!processedAssetsReply) + processAssetsReply(); +} + +void StdInstVListLoadTask::processAssetsReply() +{ + switch (assetsReply->error()) + { + case QNetworkReply::NoError: + { + // Get the XML string. + QString xmlString = assetsReply->readAll(); + + QString xmlErrorMsg; + + QDomDocument doc; + if (!doc.setContent(xmlString, false, &xmlErrorMsg)) + { + // TODO: Display error message to the user. + qDebug(QString("Failed to process assets.minecraft.net. XML error: %s"). + arg(xmlErrorMsg).toUtf8()); + } + + QDomNodeList contents = doc.elementsByTagName("Contents"); + + QRegExp mcRegex("/minecraft.jar$"); + QRegExp snapshotRegex("[0-9][0-9]w[0-9][0-9][a-z]|pre|rc"); + + for (int i = 0; i < contents.length(); i++) + { + QDomElement element = contents.at(i).toElement(); + + if (element.isNull()) + continue; + + QDomElement keyElement = getDomElementByTagName(element, "Key"); + QDomElement lastmodElement = getDomElementByTagName(element, "LastModified"); + QDomElement etagElement = getDomElementByTagName(element, "ETag"); + + if (keyElement.isNull() || lastmodElement.isNull() || etagElement.isNull()) + continue; + + QString key = keyElement.text(); + QString lastModStr = lastmodElement.text(); + QString etagStr = etagElement.text(); + + if (!key.contains(mcRegex)) + continue; + + QString versionDirName = key.left(key.length() - 14); + QString dlUrl = QString("http://assets.minecraft.net/%1/").arg(versionDirName); + + QString versionName = versionDirName.replace("_", "."); + + QDateTime versionTimestamp = timeFromS3Time(lastModStr); + if (!versionTimestamp.isValid()) + { + qDebug(QString("Failed to parse timestamp for version %1 %2"). + arg(versionName, lastModStr).toUtf8()); + versionTimestamp = QDateTime::currentDateTime(); + } + + if (currentStable) + { + if (etagStr == currentStable->etag()) + { + StdInstVersion *version = new StdInstVersion( + versionName, versionName, + versionTimestamp.toMSecsSinceEpoch(), + currentStable->downloadURL(), true, etagStr, m_list); + version->setVersionType(StdInstVersion::CurrentStable); + tempList.push_back(version); + foundCurrentInAssets = true; + } + else + { + bool older = versionTimestamp.toMSecsSinceEpoch() < currentStable->timestamp(); + bool newer = versionTimestamp.toMSecsSinceEpoch() > currentStable->timestamp(); + bool isSnapshot = versionName.contains(snapshotRegex); + + StdInstVersion *version = new StdInstVersion( + versionName, versionName, + versionTimestamp.toMSecsSinceEpoch(), + dlUrl, false, etagStr, m_list); + + if (newer) + { + version->setVersionType(StdInstVersion::Snapshot); + } + else if (older && isSnapshot) + { + version->setVersionType(StdInstVersion::OldSnapshot); + } + else if (older) + { + version->setVersionType(StdInstVersion::Stable); + } + else + { + // Shouldn't happen, but just in case... + version->setVersionType(StdInstVersion::CurrentStable); + } + + tempList.push_back(version); + } + } + else // If there isn't a current stable version. + { + bool isSnapshot = versionName.contains(snapshotRegex); + + StdInstVersion *version = new StdInstVersion( + versionName, versionName, + versionTimestamp.toMSecsSinceEpoch(), + dlUrl, false, etagStr, m_list); + version->setVersionType(isSnapshot? StdInstVersion::Snapshot : + StdInstVersion::Stable); + tempList.push_back(version); + } + } + + setSubStatus("Loaded assets.minecraft.net"); + break; + } + + default: + // TODO: Network error handling. + break; + } + + processedAssetsReply = true; + updateStuff(); +} + + +QString mcnToAssetsVersion(QString mcnVersion); + +void StdInstVListLoadTask::processMCNReply() +{ + switch (assetsReply->error()) + { + case QNetworkReply::NoError: + { + QJsonParseError pError; + QJsonDocument jsonDoc = QJsonDocument::fromJson(mcnReply->readAll(), &pError); + + if (pError.error != QJsonParseError::NoError) + { + // Handle errors. + qDebug() << "Failed to parse MCNostalgia response. JSON parser error: " << + pError.errorString(); + break; + } + + + // Load data. + QRegExp indevRegex("in(f)?dev"); + QJsonArray vlistArray = jsonDoc.object().value("order").toArray(); + + for (int i = 0; i < vlistArray.size(); i++) + { + QString rawVersion = vlistArray.at(i).toString(); + if (rawVersion.isEmpty() || rawVersion.contains(indevRegex)) + continue; + + QString niceVersion = mcnToAssetsVersion(rawVersion); + if (niceVersion.isEmpty()) + continue; + + StdInstVersion *version = StdInstVersion::mcnVersion(rawVersion, niceVersion); + mcnList.prepend(version); + } + + setSubStatus("Loaded MCNostalgia"); + break; + } + + default: + // TODO: Network error handling. + break; + } + + + processedMCNReply = true; + updateStuff(); +} + +void StdInstVListLoadTask::setSubStatus(const QString &msg) +{ + if (msg.isEmpty()) + setStatus("Loading instance version list..."); + else + setStatus("Loading instance version list: " + msg); +} + +void StdInstVListLoadTask::updateStuff() +{ + const int totalReqs = 3; + int reqsComplete = 0; + + if (processedMCDLReply) + reqsComplete++; + if (processedAssetsReply) + reqsComplete++; + if (processedMCNReply) + reqsComplete++; + + calcProgress(reqsComplete, totalReqs); + + if (reqsComplete >= totalReqs) + { + quit(); + } +} + +class MCNostalgiaVNameMap +{ +public: + QMap <QString, QString> mapping; + MCNostalgiaVNameMap() + { + // An empty string means that it should be ignored + mapping["1.4.6_pre"] = ""; + mapping["1.4.5_pre"] = ""; + mapping["1.4.3_pre"] = "1.4.3"; + mapping["1.4.2_pre"] = ""; + mapping["1.4.1_pre"] = "1.4.1"; + mapping["1.4_pre"] = "1.4"; + mapping["1.3.2_pre"] = ""; + mapping["1.3.1_pre"] = ""; + mapping["1.3_pre"] = ""; + mapping["1.2_pre"] = "1.2"; + } +} mcnVNMap; + +QString mcnToAssetsVersion(QString mcnVersion) +{ + QMap<QString, QString>::iterator iter = mcnVNMap.mapping.find(mcnVersion); + if (iter != mcnVNMap.mapping.end()) + { + return iter.value(); + } + return mcnVersion; +} diff --git a/plugins/stdinstance/stdinstversionlist.h b/plugins/stdinstance/stdinstversionlist.h new file mode 100644 index 00000000..1fad48c2 --- /dev/null +++ b/plugins/stdinstance/stdinstversionlist.h @@ -0,0 +1,99 @@ +/* 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 STDINSTVERSIONLIST_H +#define STDINSTVERSIONLIST_H + +#include <instversionlist.h> + +#include <task.h> + +class QNetworkReply; + +class StdInstVListLoadTask; +class StdInstVersion; + +class StdInstVersionList : public InstVersionList +{ + Q_OBJECT +public: + friend class StdInstVListLoadTask; + + explicit StdInstVersionList(QObject *parent = 0); + + virtual Task *getLoadTask(); + + virtual bool isLoaded(); + + virtual const InstVersion *at(int i) const; + + virtual int count() const; + + //! Prints the list to stdout. This is mainly for debugging. + virtual void printToStdOut(); + +protected: + QList<InstVersion *> m_vlist; + + bool loaded; +}; + +class StdInstVListLoadTask : public Task +{ +Q_OBJECT +public: + StdInstVListLoadTask(StdInstVersionList *vlist); + + virtual void executeTask(); + + //! Performs some final processing when the task is finished. + virtual void finalize(); + +protected slots: + //! Slot connected to the finished signal for mcdlReply. + virtual void processMCDLReply(); + + //! Slot connected to the finished signal for assetsReply. + virtual void processAssetsReply(); + + //! Slot connected to the finished signal for mcnReply. + virtual void processMCNReply(); + +protected: + void setSubStatus(const QString &msg = ""); + + StdInstVersionList *m_list; + QList<InstVersion *> tempList; //! < List of loaded versions. + QList<InstVersion *> mcnList; //! < List of MCNostalgia versions. + + QNetworkReply *assetsReply; //! < The reply from assets.minecraft.net + QNetworkReply *mcdlReply; //! < The reply from s3.amazonaws.com/MinecraftDownload + QNetworkReply *mcnReply; //! < The reply from MCNostalgia. + + bool processedAssetsReply; + bool processedMCDLReply; + bool processedMCNReply; + + //! Checks if the task is finished processing replies and, if so, exits the task's event loop. + void updateStuff(); + + StdInstVersion *currentStable; + + bool foundCurrentInAssets; +}; + +extern StdInstVersionList vList; + +#endif // STDINSTVERSIONLIST_H |