From 82c87aa06f793b9f38e6cb42d284f00695f4bac5 Mon Sep 17 00:00:00 2001 From: Jan Dalheimer Date: Fri, 20 Dec 2013 14:47:26 +0100 Subject: Initial FTB support. Allows "tracking" of FTB instances. --- logic/lists/ForgeVersionList.cpp | 1 + logic/lists/InstanceList.cpp | 151 +++++++++++++++++++++++++++++---------- logic/lists/InstanceList.h | 14 ++-- 3 files changed, 123 insertions(+), 43 deletions(-) (limited to 'logic/lists') diff --git a/logic/lists/ForgeVersionList.cpp b/logic/lists/ForgeVersionList.cpp index b5e421af..d6d353da 100644 --- a/logic/lists/ForgeVersionList.cpp +++ b/logic/lists/ForgeVersionList.cpp @@ -159,6 +159,7 @@ ForgeListLoadTask::ForgeListLoadTask(ForgeVersionList *vlist) : Task() void ForgeListLoadTask::executeTask() { + setStatus(tr("Fetching Forge version list")); auto job = new NetJob("Version index"); // we do not care if the version is stale or not. auto forgeListEntry = MMC->metacache()->resolveEntry("minecraftforge", "list.json"); diff --git a/logic/lists/InstanceList.cpp b/logic/lists/InstanceList.cpp index 15fd10ba..539413d8 100644 --- a/logic/lists/InstanceList.cpp +++ b/logic/lists/InstanceList.cpp @@ -22,11 +22,14 @@ #include #include #include +#include +#include #include #include "MultiMC.h" #include "logic/lists/InstanceList.h" #include "logic/lists/IconList.h" +#include "logic/lists/MinecraftVersionList.h" #include "logic/BaseInstance.h" #include "logic/InstanceFactory.h" #include "logger/QsLog.h" @@ -42,6 +45,8 @@ InstanceList::InstanceList(const QString &instDir, QObject *parent) { QDir::current().mkpath(m_instDir); } + + connect(MMC->minecraftlist().get(), &MinecraftVersionList::modelReset, this, &InstanceList::loadList); } InstanceList::~InstanceList() @@ -285,57 +290,87 @@ InstanceList::InstListError InstanceList::loadList() beginResetModel(); m_instances.clear(); - QDir dir(m_instDir); - QDirIterator iter(m_instDir, QDir::Dirs | QDir::NoDot | QDir::NoDotDot | QDir::Readable, - QDirIterator::FollowSymlinks); - while (iter.hasNext()) + { - QString subDir = iter.next(); - if (!QFileInfo(PathCombine(subDir, "instance.cfg")).exists()) - continue; + QDirIterator iter(m_instDir, QDir::Dirs | QDir::NoDot | QDir::NoDotDot | QDir::Readable, + QDirIterator::FollowSymlinks); + while (iter.hasNext()) + { + QString subDir = iter.next(); + if (!QFileInfo(PathCombine(subDir, "instance.cfg")).exists()) + continue; - BaseInstance *instPtr = NULL; - auto &loader = InstanceFactory::get(); - auto error = loader.loadInstance(instPtr, subDir); + BaseInstance *instPtr = NULL; + auto error = InstanceFactory::get().loadInstance(instPtr, subDir); + continueProcessInstance(instPtr, error, subDir, groupMap); + } + } - if (error != InstanceFactory::NoLoadError && error != InstanceFactory::NotAnInstance) + if (MMC->settings()->get("TrackFTBInstances").toBool() && MMC->minecraftlist()->isLoaded()) + { + QDir dir = QDir(MMC->settings()->get("FTBLauncherRoot").toString()); + QDir dataDir = QDir(MMC->settings()->get("FTBRoot").toString()); + if (!dir.exists()) { - QString errorMsg = QString("Failed to load instance %1: ") - .arg(QFileInfo(subDir).baseName()) - .toUtf8(); - - switch (error) - { - default: - errorMsg += QString("Unknown instance loader error %1").arg(error); - break; - } - QLOG_ERROR() << errorMsg.toUtf8(); + QLOG_INFO() << "The FTB launcher directory specified does not exist. Please check your settings."; } - else if (!instPtr) + else if (!dataDir.exists()) { - QLOG_ERROR() << QString("Error loading instance %1. Instance loader returned null.") - .arg(QFileInfo(subDir).baseName()) - .toUtf8(); + QLOG_INFO() << "The FTB directory specified does not exist. Please check your settings"; } else { - std::shared_ptr inst(instPtr); - auto iter = groupMap.find(inst->id()); - if (iter != groupMap.end()) + dir.cd("ModPacks"); + QFile f(dir.absoluteFilePath("modpacks.xml")); + if (f.open(QFile::ReadOnly)) { - inst->setGroupInitial((*iter)); + QXmlStreamReader reader(&f); + while (!reader.atEnd()) + { + switch (reader.readNext()) + { + case QXmlStreamReader::StartElement: + { + if (reader.name() == "modpack") + { + QXmlStreamAttributes attrs = reader.attributes(); + const QDir instanceDir = QDir(dataDir.absoluteFilePath(attrs.value("dir").toString())); + if (instanceDir.exists()) + { + const QString name = attrs.value("name").toString(); + const QString iconKey = attrs.value("logo").toString().remove(QRegularExpression("\\..*")); + const QString mcVersion = attrs.value("mcVersion").toString(); + const QString notes = attrs.value("description").toString(); + QLOG_DEBUG() << dir.absoluteFilePath(attrs.value("logo").toString()); + MMC->icons()->addIcon(iconKey, iconKey, dir.absoluteFilePath(attrs.value("dir").toString() + QDir::separator() + attrs.value("logo").toString()), true); + + BaseInstance *instPtr = NULL; + auto error = InstanceFactory::get().createInstance(instPtr, MMC->minecraftlist()->findVersion(mcVersion), instanceDir.absolutePath(), InstanceFactory::FTBInstance); + if (instPtr && error == InstanceFactory::NoCreateError) + { + instPtr->setGroupInitial("FTB"); + instPtr->setName(name); + instPtr->setIconKey(iconKey); + instPtr->setIntendedVersionId(mcVersion); + instPtr->setNotes(notes); + } + continueProcessInstance(instPtr, error, instanceDir, groupMap); + } + } + break; + } + case QXmlStreamReader::EndElement: + break; + case QXmlStreamReader::Characters: + break; + default: + break; + } + } } - QLOG_INFO() << "Loaded instance " << inst->name(); - inst->setParent(this); - m_instances.append(inst); - connect(instPtr, SIGNAL(propertiesChanged(BaseInstance *)), this, - SLOT(propertiesChanged(BaseInstance *))); - connect(instPtr, SIGNAL(groupChanged()), this, SLOT(groupChanged())); - connect(instPtr, SIGNAL(nuked(BaseInstance *)), this, - SLOT(instanceNuked(BaseInstance *))); } } + endResetModel(); emit dataIsInvalid(); return NoError; @@ -409,6 +444,46 @@ int InstanceList::getInstIndex(BaseInstance *inst) const return -1; } +void InstanceList::continueProcessInstance(BaseInstance *instPtr, const int error, const QDir &dir, QMap &groupMap) +{ + if (error != InstanceFactory::NoLoadError && error != InstanceFactory::NotAnInstance) + { + QString errorMsg = QString("Failed to load instance %1: ") + .arg(QFileInfo(dir.absolutePath()).baseName()) + .toUtf8(); + + switch (error) + { + default: + errorMsg += QString("Unknown instance loader error %1").arg(error); + break; + } + QLOG_ERROR() << errorMsg.toUtf8(); + } + else if (!instPtr) + { + QLOG_ERROR() << QString("Error loading instance %1. Instance loader returned null.") + .arg(QFileInfo(dir.absolutePath()).baseName()) + .toUtf8(); + } + else + { + auto iter = groupMap.find(instPtr->id()); + if (iter != groupMap.end()) + { + instPtr->setGroupInitial((*iter)); + } + QLOG_INFO() << "Loaded instance " << instPtr->name(); + instPtr->setParent(this); + m_instances.append(std::shared_ptr(instPtr)); + connect(instPtr, SIGNAL(propertiesChanged(BaseInstance *)), this, + SLOT(propertiesChanged(BaseInstance *))); + connect(instPtr, SIGNAL(groupChanged()), this, SLOT(groupChanged())); + connect(instPtr, SIGNAL(nuked(BaseInstance *)), this, + SLOT(instanceNuked(BaseInstance *))); + } +} + void InstanceList::instanceNuked(BaseInstance *inst) { int i = getInstIndex(inst); diff --git a/logic/lists/InstanceList.h b/logic/lists/InstanceList.h index f23b7763..b3ee6cfe 100644 --- a/logic/lists/InstanceList.h +++ b/logic/lists/InstanceList.h @@ -25,6 +25,8 @@ class BaseInstance; +class QDir; + class InstanceList : public QAbstractListModel { Q_OBJECT @@ -65,11 +67,6 @@ public: return m_instDir; } - /*! - * \brief Loads the instance list. Triggers notifications. - */ - InstListError loadList(); - /*! * \brief Get the instance at index */ @@ -108,6 +105,11 @@ public slots: void on_InstFolderChanged(const Setting &setting, QVariant value); + /*! + * \brief Loads the instance list. Triggers notifications. + */ + InstListError loadList(); + private slots: void propertiesChanged(BaseInstance *inst); @@ -117,6 +119,8 @@ slots: private: int getInstIndex(BaseInstance *inst) const; + void continueProcessInstance(BaseInstance *instPtr, const int error, const QDir &dir, QMap &groupMap); + protected: QString m_instDir; QList m_instances; -- cgit From 74b5b5f535ec8d98ba93c629804c75fda9e32475 Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Sun, 22 Dec 2013 04:31:30 +0100 Subject: Make FTB instances behave better * Do not re-create on every reload * Use the version.json/custom.json logic properly * Should be offline-friendly * FTB instances can be copied, turn into normal instances --- logic/lists/InstanceList.cpp | 196 ++++++++++++++++++++++++++++--------------- logic/lists/InstanceList.h | 4 +- 2 files changed, 131 insertions(+), 69 deletions(-) (limited to 'logic/lists') diff --git a/logic/lists/InstanceList.cpp b/logic/lists/InstanceList.cpp index 539413d8..0ecb387d 100644 --- a/logic/lists/InstanceList.cpp +++ b/logic/lists/InstanceList.cpp @@ -46,7 +46,8 @@ InstanceList::InstanceList(const QString &instDir, QObject *parent) QDir::current().mkpath(m_instDir); } - connect(MMC->minecraftlist().get(), &MinecraftVersionList::modelReset, this, &InstanceList::loadList); + connect(MMC->minecraftlist().get(), &MinecraftVersionList::modelReset, this, + &InstanceList::loadList); } InstanceList::~InstanceList() @@ -281,6 +282,124 @@ void InstanceList::loadGroupList(QMap &groupMap) } } +struct FTBRecord +{ + QString dir; + QString name; + QString logo; + QString mcVersion; + QString description; +}; + +void InstanceList::loadForgeInstances(QMap groupMap) +{ + QList records; + QDir dir = QDir(MMC->settings()->get("FTBLauncherRoot").toString()); + QDir dataDir = QDir(MMC->settings()->get("FTBRoot").toString()); + if (!dir.exists()) + { + QLOG_INFO() << "The FTB launcher directory specified does not exist. Please check your " + "settings."; + return; + } + else if (!dataDir.exists()) + { + QLOG_INFO() << "The FTB directory specified does not exist. Please check your settings"; + return; + } + + dir.cd("ModPacks"); + QFile f(dir.absoluteFilePath("modpacks.xml")); + if (!f.open(QFile::ReadOnly)) + return; + + // read the FTB packs XML. + QXmlStreamReader reader(&f); + while (!reader.atEnd()) + { + switch (reader.readNext()) + { + case QXmlStreamReader::StartElement: + { + if (reader.name() == "modpack") + { + QXmlStreamAttributes attrs = reader.attributes(); + FTBRecord record; + record.dir = attrs.value("dir").toString(); + record.name = attrs.value("name").toString(); + record.logo = attrs.value("logo").toString(); + record.mcVersion = attrs.value("mcVersion").toString(); + record.description = attrs.value("description").toString(); + records.append(record); + } + break; + } + case QXmlStreamReader::EndElement: + break; + case QXmlStreamReader::Characters: + break; + default: + break; + } + } + f.close(); + + // process the records we acquired. + for (auto record : records) + { + auto instanceDir = dataDir.absoluteFilePath(record.dir); + auto templateDir = dir.absoluteFilePath(record.dir); + if (!QFileInfo(instanceDir).exists()) + { + continue; + } + + QString iconKey = record.logo; + iconKey.remove(QRegularExpression("\\..*")); + MMC->icons()->addIcon(iconKey, iconKey, PathCombine(templateDir, record.logo), true); + + if (!QFileInfo(PathCombine(instanceDir, "instance.cfg")).exists()) + { + BaseInstance *instPtr = NULL; + auto & factory = InstanceFactory::get(); + auto version = MMC->minecraftlist()->findVersion(record.mcVersion); + if (!version) + { + QLOG_ERROR() << "Can't load instance " << instanceDir + << " because minecraft version " << record.mcVersion + << " can't be resolved."; + continue; + } + auto error = factory.createInstance(instPtr, version, instanceDir, + InstanceFactory::FTBInstance); + + if (!instPtr || error != InstanceFactory::NoCreateError) + continue; + + instPtr->setGroupInitial("FTB"); + instPtr->setName(record.name); + instPtr->setIconKey(iconKey); + instPtr->setIntendedVersionId(record.mcVersion); + instPtr->setNotes(record.description); + continueProcessInstance(instPtr, error, instanceDir, groupMap); + } + else + { + BaseInstance *instPtr = NULL; + auto error = InstanceFactory::get().loadInstance(instPtr, instanceDir); + if (!instPtr || error != InstanceFactory::NoCreateError) + continue; + instPtr->setGroupInitial("FTB"); + instPtr->setName(record.name); + instPtr->setIconKey(iconKey); + if (instPtr->intendedVersionId() != record.mcVersion) + instPtr->setIntendedVersionId(record.mcVersion); + instPtr->setNotes(record.description); + continueProcessInstance(instPtr, error, instanceDir, groupMap); + } + } +} + InstanceList::InstListError InstanceList::loadList() { // load the instance groups @@ -306,69 +425,9 @@ InstanceList::InstListError InstanceList::loadList() } } - if (MMC->settings()->get("TrackFTBInstances").toBool() && MMC->minecraftlist()->isLoaded()) + if (MMC->settings()->get("TrackFTBInstances").toBool()) { - QDir dir = QDir(MMC->settings()->get("FTBLauncherRoot").toString()); - QDir dataDir = QDir(MMC->settings()->get("FTBRoot").toString()); - if (!dir.exists()) - { - QLOG_INFO() << "The FTB launcher directory specified does not exist. Please check your settings."; - } - else if (!dataDir.exists()) - { - QLOG_INFO() << "The FTB directory specified does not exist. Please check your settings"; - } - else - { - dir.cd("ModPacks"); - QFile f(dir.absoluteFilePath("modpacks.xml")); - if (f.open(QFile::ReadOnly)) - { - QXmlStreamReader reader(&f); - while (!reader.atEnd()) - { - switch (reader.readNext()) - { - case QXmlStreamReader::StartElement: - { - if (reader.name() == "modpack") - { - QXmlStreamAttributes attrs = reader.attributes(); - const QDir instanceDir = QDir(dataDir.absoluteFilePath(attrs.value("dir").toString())); - if (instanceDir.exists()) - { - const QString name = attrs.value("name").toString(); - const QString iconKey = attrs.value("logo").toString().remove(QRegularExpression("\\..*")); - const QString mcVersion = attrs.value("mcVersion").toString(); - const QString notes = attrs.value("description").toString(); - QLOG_DEBUG() << dir.absoluteFilePath(attrs.value("logo").toString()); - MMC->icons()->addIcon(iconKey, iconKey, dir.absoluteFilePath(attrs.value("dir").toString() + QDir::separator() + attrs.value("logo").toString()), true); - - BaseInstance *instPtr = NULL; - auto error = InstanceFactory::get().createInstance(instPtr, MMC->minecraftlist()->findVersion(mcVersion), instanceDir.absolutePath(), InstanceFactory::FTBInstance); - if (instPtr && error == InstanceFactory::NoCreateError) - { - instPtr->setGroupInitial("FTB"); - instPtr->setName(name); - instPtr->setIconKey(iconKey); - instPtr->setIntendedVersionId(mcVersion); - instPtr->setNotes(notes); - } - continueProcessInstance(instPtr, error, instanceDir, groupMap); - } - } - break; - } - case QXmlStreamReader::EndElement: - break; - case QXmlStreamReader::Characters: - break; - default: - break; - } - } - } - } + loadForgeInstances(groupMap); } endResetModel(); @@ -444,13 +503,14 @@ int InstanceList::getInstIndex(BaseInstance *inst) const return -1; } -void InstanceList::continueProcessInstance(BaseInstance *instPtr, const int error, const QDir &dir, QMap &groupMap) +void InstanceList::continueProcessInstance(BaseInstance *instPtr, const int error, + const QDir &dir, QMap &groupMap) { if (error != InstanceFactory::NoLoadError && error != InstanceFactory::NotAnInstance) { QString errorMsg = QString("Failed to load instance %1: ") - .arg(QFileInfo(dir.absolutePath()).baseName()) - .toUtf8(); + .arg(QFileInfo(dir.absolutePath()).baseName()) + .toUtf8(); switch (error) { @@ -463,8 +523,8 @@ void InstanceList::continueProcessInstance(BaseInstance *instPtr, const int erro else if (!instPtr) { QLOG_ERROR() << QString("Error loading instance %1. Instance loader returned null.") - .arg(QFileInfo(dir.absolutePath()).baseName()) - .toUtf8(); + .arg(QFileInfo(dir.absolutePath()).baseName()) + .toUtf8(); } else { diff --git a/logic/lists/InstanceList.h b/logic/lists/InstanceList.h index b3ee6cfe..0ce808e5 100644 --- a/logic/lists/InstanceList.h +++ b/logic/lists/InstanceList.h @@ -109,6 +109,7 @@ slots: * \brief Loads the instance list. Triggers notifications. */ InstListError loadList(); + void loadForgeInstances(QMap groupMap); private slots: @@ -119,7 +120,8 @@ slots: private: int getInstIndex(BaseInstance *inst) const; - void continueProcessInstance(BaseInstance *instPtr, const int error, const QDir &dir, QMap &groupMap); + void continueProcessInstance(BaseInstance *instPtr, const int error, const QDir &dir, + QMap &groupMap); protected: QString m_instDir; -- cgit From 7a07ed79407edcb2a543aa0dc80745a0b8c2e234 Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Sun, 22 Dec 2013 05:47:10 +0100 Subject: FTB fixage * Corrected an uninitialized variable that prevented forge list loadinf on Windows * Run the update step twice for FTB instances to ensure forge libs get downloaded --- logic/lists/ForgeVersionList.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'logic/lists') diff --git a/logic/lists/ForgeVersionList.h b/logic/lists/ForgeVersionList.h index bf9e87b2..f32975ed 100644 --- a/logic/lists/ForgeVersionList.h +++ b/logic/lists/ForgeVersionList.h @@ -80,7 +80,7 @@ public: protected: QList m_vlist; - bool m_loaded; + bool m_loaded = false; protected slots: -- cgit From 3841260ef1f4e6d7e30e68d1ccae09bfbf176ceb Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Sun, 22 Dec 2013 23:05:18 +0100 Subject: Fix Java checker leaving behind temporary jar files --- logic/lists/JavaVersionList.cpp | 11 ++++++----- logic/lists/JavaVersionList.h | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'logic/lists') diff --git a/logic/lists/JavaVersionList.cpp b/logic/lists/JavaVersionList.cpp index d2f0972c..c2886c67 100644 --- a/logic/lists/JavaVersionList.cpp +++ b/logic/lists/JavaVersionList.cpp @@ -177,9 +177,9 @@ void JavaListLoadTask::executeTask() JavaUtils ju; QList candidate_paths = ju.FindJavaPaths(); - auto job = new JavaCheckerJob("Java detection"); - connect(job, SIGNAL(finished(QList)), this, SLOT(javaCheckerFinished(QList))); - connect(job, SIGNAL(progress(int, int)), this, SLOT(checkerProgress(int, int))); + m_job = std::shared_ptr(new JavaCheckerJob("Java detection")); + connect(m_job.get(), SIGNAL(finished(QList)), this, SLOT(javaCheckerFinished(QList))); + connect(m_job.get(), SIGNAL(progress(int, int)), this, SLOT(checkerProgress(int, int))); QLOG_DEBUG() << "Probing the following Java paths: "; for(QString candidate : candidate_paths) @@ -188,10 +188,10 @@ void JavaListLoadTask::executeTask() auto candidate_checker = new JavaChecker(); candidate_checker->path = candidate; - job->addJavaCheckerAction(JavaCheckerPtr(candidate_checker)); + m_job->addJavaCheckerAction(JavaCheckerPtr(candidate_checker)); } - job->start(); + m_job->start(); } void JavaListLoadTask::checkerProgress(int current, int total) @@ -203,6 +203,7 @@ void JavaListLoadTask::checkerProgress(int current, int total) void JavaListLoadTask::javaCheckerFinished(QList results) { QList candidates; + m_job.reset(); QLOG_DEBUG() << "Found the following valid Java installations:"; for(JavaCheckResult result : results) diff --git a/logic/lists/JavaVersionList.h b/logic/lists/JavaVersionList.h index 879b2480..e6cc8e5f 100644 --- a/logic/lists/JavaVersionList.h +++ b/logic/lists/JavaVersionList.h @@ -90,6 +90,7 @@ public slots: void checkerProgress(int current, int total); protected: + std::shared_ptr m_job; JavaVersionList *m_list; JavaVersion *m_currentRecommended; }; -- cgit From 9e645f4a37e73857b1414a67700e9f3c4cf61d56 Mon Sep 17 00:00:00 2001 From: Jan Dalheimer Date: Mon, 23 Dec 2013 00:12:03 +0100 Subject: Support for the new forge gradle repo --- logic/lists/ForgeVersionList.cpp | 201 +++++++++++++++++++++++++++++++++------ logic/lists/ForgeVersionList.h | 12 ++- 2 files changed, 184 insertions(+), 29 deletions(-) (limited to 'logic/lists') diff --git a/logic/lists/ForgeVersionList.cpp b/logic/lists/ForgeVersionList.cpp index d6d353da..b6e06e77 100644 --- a/logic/lists/ForgeVersionList.cpp +++ b/logic/lists/ForgeVersionList.cpp @@ -24,6 +24,7 @@ #include "logger/QsLog.h" #define JSON_URL "http://files.minecraftforge.net/minecraftforge/json" +#define GRADLE_JSON_URL "http://files.minecraftforge.net/maven/net/minecraftforge/forge/json" ForgeVersionList::ForgeVersionList(QObject *parent) : BaseVersionList(parent) { @@ -163,41 +164,37 @@ void ForgeListLoadTask::executeTask() auto job = new NetJob("Version index"); // we do not care if the version is stale or not. auto forgeListEntry = MMC->metacache()->resolveEntry("minecraftforge", "list.json"); + auto gradleForgeListEntry = MMC->metacache()->resolveEntry("minecraftforge", "json"); // verify by poking the server. forgeListEntry->stale = true; + gradleForgeListEntry->stale = true; + + job->addNetAction(listDownload = CacheDownload::make(QUrl(JSON_URL), forgeListEntry)); + job->addNetAction(gradleListDownload = CacheDownload::make(QUrl(GRADLE_JSON_URL), gradleForgeListEntry)); + + connect(listDownload.get(), SIGNAL(failed(int)), SLOT(listFailed())); + connect(gradleListDownload.get(), SIGNAL(failed(int)), SLOT(gradleListFailed())); - job->addNetAction(CacheDownload::make(QUrl(JSON_URL), forgeListEntry)); listJob.reset(job); - connect(listJob.get(), SIGNAL(succeeded()), SLOT(list_downloaded())); - connect(listJob.get(), SIGNAL(failed()), SLOT(list_failed())); + connect(listJob.get(), SIGNAL(succeeded()), SLOT(listDownloaded())); connect(listJob.get(), SIGNAL(progress(qint64, qint64)), SIGNAL(progress(qint64, qint64))); listJob->start(); } -void ForgeListLoadTask::list_failed() -{ - auto DlJob = listJob->first(); - auto reply = DlJob->m_reply; - if (reply) - { - QLOG_ERROR() << "Getting forge version list failed: " << reply->errorString(); - } - else - QLOG_ERROR() << "Getting forge version list failed for reasons unknown."; -} - -void ForgeListLoadTask::list_downloaded() +bool ForgeListLoadTask::parseForgeList(QList &out) { QByteArray data; { - auto DlJob = listJob->first(); - auto filename = std::dynamic_pointer_cast(DlJob)->m_target_path; + auto dlJob = listDownload; + auto filename = std::dynamic_pointer_cast(dlJob)->m_target_path; QFile listFile(filename); if (!listFile.open(QIODevice::ReadOnly)) - return; + { + return false; + } data = listFile.readAll(); - DlJob.reset(); + dlJob.reset(); } QJsonParseError jsonError; @@ -206,13 +203,13 @@ void ForgeListLoadTask::list_downloaded() if (jsonError.error != QJsonParseError::NoError) { emitFailed("Error parsing version list JSON:" + jsonError.errorString()); - return; + return false; } if (!jsonDoc.isObject()) { - emitFailed("Error parsing version list JSON: jsonDoc is not an object"); - return; + emitFailed("Error parsing version list JSON: JSON root is not an object"); + return false; } QJsonObject root = jsonDoc.object(); @@ -222,11 +219,10 @@ void ForgeListLoadTask::list_downloaded() { emitFailed( "Error parsing version list JSON: version list object is missing 'builds' array"); - return; + return false; } QJsonArray builds = root.value("builds").toArray(); - QList tempList; for (int i = 0; i < builds.count(); i++) { // Load the version info. @@ -247,7 +243,9 @@ void ForgeListLoadTask::list_downloaded() for (int j = 0; j < files.count(); j++) { if (!files[j].isObject()) + { continue; + } QJsonObject file = files[j].toObject(); buildtype = file.value("buildtype").toString(); if ((buildtype == "client" || buildtype == "universal") && !valid) @@ -263,7 +261,9 @@ void ForgeListLoadTask::list_downloaded() { QString ext = file.value("ext").toString(); if (ext.isEmpty()) + { continue; + } changelog_url = file.value("url").toString(); } else if (buildtype == "installer") @@ -283,15 +283,162 @@ void ForgeListLoadTask::list_downloaded() fVersion->jobbuildver = jobbuildver; fVersion->mcver = mcver; if (installer_filename.isEmpty()) + { fVersion->filename = filename; + } else + { fVersion->filename = installer_filename; + } fVersion->m_buildnr = build_nr; - tempList.append(fVersion); + out.append(fVersion); + } + } + + return true; +} + +bool ForgeListLoadTask::parseForgeGradleList(QList &out) +{ + QByteArray data; + { + auto dlJob = gradleListDownload; + auto filename = std::dynamic_pointer_cast(dlJob)->m_target_path; + QFile listFile(filename); + if (!listFile.open(QIODevice::ReadOnly)) + { + return false; + } + data = listFile.readAll(); + dlJob.reset(); + } + + QJsonParseError jsonError; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); + + if (jsonError.error != QJsonParseError::NoError) + { + emitFailed("Error parsing gradle version list JSON:" + jsonError.errorString()); + return false; + } + + if (!jsonDoc.isObject()) + { + emitFailed("Error parsing gradle version list JSON: JSON root is not an object"); + return false; + } + + QJsonObject root = jsonDoc.object(); + + // we probably could hard code these, but it might still be worth doing it this way + const QString webpath = root.value("webpath").toString(); + const QString artifact = root.value("artifact").toString(); + + QJsonObject numbers = root.value("number").toObject(); + for (auto it = numbers.begin(); it != numbers.end(); ++it) + { + QJsonObject number = it.value().toObject(); + std::shared_ptr fVersion(new ForgeVersion()); + fVersion->m_buildnr = number.value("build").toDouble(); + fVersion->jobbuildver = number.value("version").toString(); + fVersion->mcver = number.value("mcversion").toString(); + fVersion->filename = ""; + QString filename, installer_filename; + QJsonArray files = number.value("files").toArray(); + for (auto fIt = files.begin(); fIt != files.end(); ++fIt) + { + // TODO with gradle we also get checksums, use them + QJsonArray file = (*fIt).toArray(); + if (file.size() < 3) + { + continue; + } + if (file.at(1).toString() == "installer") + { + fVersion->installer_url = + QString("%1/%2-%3/%4-%2-%3-installer.%5") + .arg(webpath, fVersion->mcver, fVersion->jobbuildver, artifact, file.at(0).toString()); + installer_filename = QString("%1-%2-%3-installer.%4") + .arg(artifact, fVersion->mcver, fVersion->jobbuildver, file.at(0).toString()); + } + else if (file.at(1).toString() == "universal") + { + fVersion->universal_url = + QString("%1/%2-%3/%4-%2-%3-universal.%5") + .arg(webpath, fVersion->mcver, fVersion->jobbuildver, artifact, file.at(0).toString()); + filename = QString("%1-%2-%3-universal.%4") + .arg(artifact, fVersion->mcver, fVersion->jobbuildver, file.at(0).toString()); + } + else if (file.at(1).toString() == "changelog") + { + fVersion->changelog_url = + QString("%1/%2-%3/%4-%2-%3-changelog.%5") + .arg(webpath, fVersion->mcver, fVersion->jobbuildver, artifact, file.at(0).toString()); + } } + if (fVersion->installer_url.isEmpty() && fVersion->universal_url.isEmpty()) + { + continue; + } + fVersion->filename = fVersion->installer_url.isEmpty() ? + filename : installer_filename; + out.append(fVersion); + } + + return true; +} + +void ForgeListLoadTask::listDownloaded() +{ + QList list; + bool ret = true; + if (!parseForgeList(list)) + { + ret = false; + } + if (!parseForgeGradleList(list)) + { + ret = false; + } + + if (!ret) + { + return; } - m_list->updateListData(tempList); + + qSort(list.begin(), list.end(), + [](const BaseVersionPtr &p1, const BaseVersionPtr &p2) { + // TODO better comparison (takes major/minor/build number into account) + return p1->name() > p2->name(); + }); + + m_list->updateListData(list); emitSucceeded(); return; } + +void ForgeListLoadTask::listFailed() +{ + auto reply = listDownload->m_reply; + if (reply) + { + QLOG_ERROR() << "Getting forge version list failed: " << reply->errorString(); + } + else + { + QLOG_ERROR() << "Getting forge version list failed for reasons unknown."; + } +} +void ForgeListLoadTask::gradleListFailed() +{ + auto reply = gradleListDownload->m_reply; + if (reply) + { + QLOG_ERROR() << "Getting forge version list failed: " << reply->errorString(); + } + else + { + QLOG_ERROR() << "Getting forge version list failed for reasons unknown."; + } +} diff --git a/logic/lists/ForgeVersionList.h b/logic/lists/ForgeVersionList.h index f32975ed..924084ae 100644 --- a/logic/lists/ForgeVersionList.h +++ b/logic/lists/ForgeVersionList.h @@ -98,10 +98,18 @@ public: protected slots: - void list_downloaded(); - void list_failed(); + void listDownloaded(); + void listFailed(); + void gradleListFailed(); protected: NetJobPtr listJob; ForgeVersionList *m_list; + + CacheDownloadPtr listDownload; + CacheDownloadPtr gradleListDownload; + +private: + bool parseForgeList(QList &out); + bool parseForgeGradleList(QList &out); }; -- cgit From f402001453c4053d1c8c56b63896796d63df0388 Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Mon, 23 Dec 2013 00:43:29 +0100 Subject: Use the central URL list for forge URLs --- logic/lists/ForgeVersionList.cpp | 43 ++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 22 deletions(-) (limited to 'logic/lists') diff --git a/logic/lists/ForgeVersionList.cpp b/logic/lists/ForgeVersionList.cpp index b6e06e77..78cb0de0 100644 --- a/logic/lists/ForgeVersionList.cpp +++ b/logic/lists/ForgeVersionList.cpp @@ -15,6 +15,7 @@ #include "ForgeVersionList.h" #include +#include #include "MultiMC.h" #include @@ -23,9 +24,6 @@ #include "logger/QsLog.h" -#define JSON_URL "http://files.minecraftforge.net/minecraftforge/json" -#define GRADLE_JSON_URL "http://files.minecraftforge.net/maven/net/minecraftforge/forge/json" - ForgeVersionList::ForgeVersionList(QObject *parent) : BaseVersionList(parent) { } @@ -170,8 +168,10 @@ void ForgeListLoadTask::executeTask() forgeListEntry->stale = true; gradleForgeListEntry->stale = true; - job->addNetAction(listDownload = CacheDownload::make(QUrl(JSON_URL), forgeListEntry)); - job->addNetAction(gradleListDownload = CacheDownload::make(QUrl(GRADLE_JSON_URL), gradleForgeListEntry)); + job->addNetAction(listDownload = CacheDownload::make(QUrl(URLConstants::FORGE_LEGACY_URL), + forgeListEntry)); + job->addNetAction(gradleListDownload = CacheDownload::make( + QUrl(URLConstants::FORGE_GRADLE_URL), gradleForgeListEntry)); connect(listDownload.get(), SIGNAL(failed(int)), SLOT(listFailed())); connect(gradleListDownload.get(), SIGNAL(failed(int)), SLOT(gradleListFailed())); @@ -355,33 +355,32 @@ bool ForgeListLoadTask::parseForgeGradleList(QList &out) } if (file.at(1).toString() == "installer") { - fVersion->installer_url = - QString("%1/%2-%3/%4-%2-%3-installer.%5") - .arg(webpath, fVersion->mcver, fVersion->jobbuildver, artifact, file.at(0).toString()); - installer_filename = QString("%1-%2-%3-installer.%4") - .arg(artifact, fVersion->mcver, fVersion->jobbuildver, file.at(0).toString()); + fVersion->installer_url = QString("%1/%2-%3/%4-%2-%3-installer.%5").arg( + webpath, fVersion->mcver, fVersion->jobbuildver, artifact, + file.at(0).toString()); + installer_filename = QString("%1-%2-%3-installer.%4").arg( + artifact, fVersion->mcver, fVersion->jobbuildver, file.at(0).toString()); } else if (file.at(1).toString() == "universal") { - fVersion->universal_url = - QString("%1/%2-%3/%4-%2-%3-universal.%5") - .arg(webpath, fVersion->mcver, fVersion->jobbuildver, artifact, file.at(0).toString()); - filename = QString("%1-%2-%3-universal.%4") - .arg(artifact, fVersion->mcver, fVersion->jobbuildver, file.at(0).toString()); + fVersion->universal_url = QString("%1/%2-%3/%4-%2-%3-universal.%5").arg( + webpath, fVersion->mcver, fVersion->jobbuildver, artifact, + file.at(0).toString()); + filename = QString("%1-%2-%3-universal.%4").arg( + artifact, fVersion->mcver, fVersion->jobbuildver, file.at(0).toString()); } else if (file.at(1).toString() == "changelog") { - fVersion->changelog_url = - QString("%1/%2-%3/%4-%2-%3-changelog.%5") - .arg(webpath, fVersion->mcver, fVersion->jobbuildver, artifact, file.at(0).toString()); + fVersion->changelog_url = QString("%1/%2-%3/%4-%2-%3-changelog.%5").arg( + webpath, fVersion->mcver, fVersion->jobbuildver, artifact, + file.at(0).toString()); } } if (fVersion->installer_url.isEmpty() && fVersion->universal_url.isEmpty()) { continue; } - fVersion->filename = fVersion->installer_url.isEmpty() ? - filename : installer_filename; + fVersion->filename = fVersion->installer_url.isEmpty() ? filename : installer_filename; out.append(fVersion); } @@ -406,8 +405,8 @@ void ForgeListLoadTask::listDownloaded() return; } - qSort(list.begin(), list.end(), - [](const BaseVersionPtr &p1, const BaseVersionPtr &p2) { + qSort(list.begin(), list.end(), [](const BaseVersionPtr & p1, const BaseVersionPtr & p2) + { // TODO better comparison (takes major/minor/build number into account) return p1->name() > p2->name(); }); -- cgit From 027aafc3c1fc5e78c91ee439cd38562387f7ed9f Mon Sep 17 00:00:00 2001 From: Sky Date: Mon, 23 Dec 2013 15:46:01 +0000 Subject: Tidy status messages a bit --- logic/lists/ForgeVersionList.cpp | 2 +- logic/lists/JavaVersionList.cpp | 2 +- logic/lists/MinecraftVersionList.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'logic/lists') diff --git a/logic/lists/ForgeVersionList.cpp b/logic/lists/ForgeVersionList.cpp index 78cb0de0..56eca744 100644 --- a/logic/lists/ForgeVersionList.cpp +++ b/logic/lists/ForgeVersionList.cpp @@ -158,7 +158,7 @@ ForgeListLoadTask::ForgeListLoadTask(ForgeVersionList *vlist) : Task() void ForgeListLoadTask::executeTask() { - setStatus(tr("Fetching Forge version list")); + setStatus(tr("Fetching Forge version lists...")); auto job = new NetJob("Version index"); // we do not care if the version is stale or not. auto forgeListEntry = MMC->metacache()->resolveEntry("minecraftforge", "list.json"); diff --git a/logic/lists/JavaVersionList.cpp b/logic/lists/JavaVersionList.cpp index c2886c67..e8c5acd0 100644 --- a/logic/lists/JavaVersionList.cpp +++ b/logic/lists/JavaVersionList.cpp @@ -172,7 +172,7 @@ JavaListLoadTask::~JavaListLoadTask() void JavaListLoadTask::executeTask() { - setStatus("Detecting Java installations..."); + setStatus(tr("Detecting Java installations...")); JavaUtils ju; QList candidate_paths = ju.FindJavaPaths(); diff --git a/logic/lists/MinecraftVersionList.cpp b/logic/lists/MinecraftVersionList.cpp index 523b81ac..91f86df0 100644 --- a/logic/lists/MinecraftVersionList.cpp +++ b/logic/lists/MinecraftVersionList.cpp @@ -139,7 +139,7 @@ MCVListLoadTask::~MCVListLoadTask() void MCVListLoadTask::executeTask() { - setStatus("Loading instance version list..."); + setStatus(tr("Loading instance version list...")); auto worker = MMC->qnam(); vlistReply = worker->get(QNetworkRequest(QUrl("http://" + URLConstants::AWS_DOWNLOAD_VERSIONS + "versions.json"))); connect(vlistReply, SIGNAL(finished()), this, SLOT(list_downloaded())); -- cgit From 952b63f68de93e8acf7aab81373661dae8d5098b Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Tue, 31 Dec 2013 01:24:28 +0100 Subject: Refactor icon lists heavily * Icon list now uses a filesystem watcher for updates * Icon folder is user-customizable * All the little details. ALL OF THEM. --- logic/lists/IconList.cpp | 271 ------------------------------------------- logic/lists/IconList.h | 54 --------- logic/lists/InstanceList.cpp | 7 +- 3 files changed, 4 insertions(+), 328 deletions(-) delete mode 100644 logic/lists/IconList.cpp delete mode 100644 logic/lists/IconList.h (limited to 'logic/lists') diff --git a/logic/lists/IconList.cpp b/logic/lists/IconList.cpp deleted file mode 100644 index ecfb8c3c..00000000 --- a/logic/lists/IconList.cpp +++ /dev/null @@ -1,271 +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 "IconList.h" -#include -#include -#include -#include -#include -#include -#define MAX_SIZE 1024 - -struct entry -{ - QString key; - QString name; - QIcon icon; - bool is_builtin; - QString filename; -}; - -class Private : public QObject -{ - Q_OBJECT -public: - QMap index; - QVector icons; - Private() - { - } -}; - -IconList::IconList() : QAbstractListModel(), d(new Private()) -{ - QDir instance_icons(":/icons/instances/"); - auto file_info_list = instance_icons.entryInfoList(QDir::Files, QDir::Name); - for (auto file_info : file_info_list) - { - QString key = file_info.baseName(); - addIcon(key, key, file_info.absoluteFilePath(), true); - } - - // FIXME: get from settings - ensureFolderPathExists("icons"); - QDir user_icons("icons"); - file_info_list = user_icons.entryInfoList(QDir::Files, QDir::Name); - for (auto file_info : file_info_list) - { - QString filename = file_info.absoluteFilePath(); - QString key = file_info.baseName(); - addIcon(key, key, filename); - } -} - -IconList::~IconList() -{ - delete d; - d = nullptr; -} - -QStringList IconList::mimeTypes() const -{ - QStringList types; - types << "text/uri-list"; - return types; -} -Qt::DropActions IconList::supportedDropActions() const -{ - return Qt::CopyAction; -} - -bool IconList::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, - const QModelIndex &parent) -{ - if (action == Qt::IgnoreAction) - return true; - // check if the action is supported - if (!data || !(action & supportedDropActions())) - return false; - - // files dropped from outside? - if (data->hasUrls()) - { - /* - bool was_watching = is_watching; - if(was_watching) - stopWatching(); - */ - auto urls = data->urls(); - QStringList iconFiles; - for (auto url : urls) - { - // only local files may be dropped... - if (!url.isLocalFile()) - continue; - iconFiles += url.toLocalFile(); - } - installIcons(iconFiles); - /* - if(was_watching) - startWatching(); - */ - return true; - } - return false; -} - -Qt::ItemFlags IconList::flags(const QModelIndex &index) const -{ - Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index); - if (index.isValid()) - return Qt::ItemIsDropEnabled | defaultFlags; - else - return Qt::ItemIsDropEnabled | defaultFlags; -} - -QVariant IconList::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - int row = index.row(); - - if (row < 0 || row >= d->icons.size()) - return QVariant(); - - switch (role) - { - case Qt::DecorationRole: - return d->icons[row].icon; - case Qt::DisplayRole: - return d->icons[row].name; - case Qt::UserRole: - return d->icons[row].key; - default: - return QVariant(); - } -} - -int IconList::rowCount(const QModelIndex &parent) const -{ - return d->icons.size(); -} - -void IconList::installIcons(QStringList iconFiles) -{ - for (QString file : iconFiles) - { - QFileInfo fileinfo(file); - if (!fileinfo.isReadable() || !fileinfo.isFile()) - continue; - QString target = PathCombine("icons", fileinfo.fileName()); - - QString suffix = fileinfo.suffix(); - if (suffix != "jpeg" && suffix != "png" && suffix != "jpg") - continue; - - if (!QFile::copy(file, target)) - continue; - - QString key = fileinfo.baseName(); - addIcon(key, key, target); - } -} - -bool IconList::deleteIcon(QString key) -{ - int iconIdx = getIconIndex(key); - if (iconIdx == -1) - return false; - auto &iconEntry = d->icons[iconIdx]; - if (iconEntry.is_builtin) - return false; - if (QFile::remove(iconEntry.filename)) - { - beginRemoveRows(QModelIndex(), iconIdx, iconIdx); - d->icons.remove(iconIdx); - reindex(); - endRemoveRows(); - } - return true; -} - -bool IconList::addIcon(QString key, QString name, QString path, bool is_builtin) -{ - auto iter = d->index.find(key); - if (iter != d->index.end()) - { - if (d->icons[*iter].is_builtin) - return false; - - QIcon icon(path); - if (icon.isNull()) - return false; - - auto &oldOne = d->icons[*iter]; - - if (!QFile::remove(oldOne.filename)) - return false; - - // replace the icon - oldOne = {key, name, icon, is_builtin, path}; - dataChanged(index(*iter), index(*iter)); - return true; - } - else - { - QIcon icon(path); - if (icon.isNull()) - return false; - - // add a new icon - beginInsertRows(QModelIndex(), d->icons.size(), d->icons.size()); - d->icons.push_back({key, name, icon, is_builtin, path}); - d->index[key] = d->icons.size() - 1; - endInsertRows(); - return true; - } -} - -void IconList::reindex() -{ - d->index.clear(); - int i = 0; - for (auto &iter : d->icons) - { - d->index[iter.key] = i; - i++; - } -} - -QIcon IconList::getIcon(QString key) -{ - int icon_index = getIconIndex(key); - - if (icon_index != -1) - return d->icons[icon_index].icon; - - // Fallback for icons that don't exist. - icon_index = getIconIndex("infinity"); - - if (icon_index != -1) - return d->icons[icon_index].icon; - return QIcon(); -} - -int IconList::getIconIndex(QString key) -{ - if (key == "default") - key = "infinity"; - - auto iter = d->index.find(key); - if (iter != d->index.end()) - return *iter; - - return -1; -} - -#include "IconList.moc" \ No newline at end of file diff --git a/logic/lists/IconList.h b/logic/lists/IconList.h deleted file mode 100644 index 40ad043b..00000000 --- a/logic/lists/IconList.h +++ /dev/null @@ -1,54 +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. - */ - -#pragma once - -#include -#include -#include - -class Private; - -class IconList : public QAbstractListModel -{ -public: - IconList(); - virtual ~IconList(); - - QIcon getIcon(QString key); - int getIconIndex(QString key); - - virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; - - bool addIcon(QString key, QString name, QString path, bool is_builtin = false); - bool deleteIcon(QString key); - - virtual QStringList mimeTypes() const; - virtual Qt::DropActions supportedDropActions() const; - virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, - const QModelIndex &parent); - virtual Qt::ItemFlags flags(const QModelIndex &index) const; - - void installIcons(QStringList iconFiles); - -private: - // hide copy constructor - IconList(const IconList &) = delete; - // hide assign op - IconList &operator=(const IconList &) = delete; - void reindex(); - Private *d; -}; diff --git a/logic/lists/InstanceList.cpp b/logic/lists/InstanceList.cpp index 0ecb387d..48a2865a 100644 --- a/logic/lists/InstanceList.cpp +++ b/logic/lists/InstanceList.cpp @@ -28,7 +28,7 @@ #include "MultiMC.h" #include "logic/lists/InstanceList.h" -#include "logic/lists/IconList.h" +#include "logic/icons/IconList.h" #include "logic/lists/MinecraftVersionList.h" #include "logic/BaseInstance.h" #include "logic/InstanceFactory.h" @@ -356,12 +356,13 @@ void InstanceList::loadForgeInstances(QMap groupMap) QString iconKey = record.logo; iconKey.remove(QRegularExpression("\\..*")); - MMC->icons()->addIcon(iconKey, iconKey, PathCombine(templateDir, record.logo), true); + MMC->icons()->addIcon(iconKey, iconKey, PathCombine(templateDir, record.logo), + MMCIcon::Transient); if (!QFileInfo(PathCombine(instanceDir, "instance.cfg")).exists()) { BaseInstance *instPtr = NULL; - auto & factory = InstanceFactory::get(); + auto &factory = InstanceFactory::get(); auto version = MMC->minecraftlist()->findVersion(record.mcVersion); if (!version) { -- cgit