diff options
author | Sefa Eyeoglu <contact@scrumplex.net> | 2023-08-02 18:35:35 +0200 |
---|---|---|
committer | Sefa Eyeoglu <contact@scrumplex.net> | 2023-08-02 18:35:35 +0200 |
commit | 1d468ac35ad88d8c77cc83f25e3704d9bd7df01b (patch) | |
tree | 8644b1574c947a1a87c5c7b2567f746cfe17882f /launcher/minecraft | |
parent | ce2ca1381519a2e261d7f76dffa874d559d979c2 (diff) | |
download | PrismLauncher-1d468ac35ad88d8c77cc83f25e3704d9bd7df01b.tar.gz PrismLauncher-1d468ac35ad88d8c77cc83f25e3704d9bd7df01b.tar.bz2 PrismLauncher-1d468ac35ad88d8c77cc83f25e3704d9bd7df01b.zip |
chore: reformat
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
Diffstat (limited to 'launcher/minecraft')
156 files changed, 3540 insertions, 5101 deletions
diff --git a/launcher/minecraft/Agent.h b/launcher/minecraft/Agent.h index 374e6e94..8958521e 100644 --- a/launcher/minecraft/Agent.h +++ b/launcher/minecraft/Agent.h @@ -9,28 +9,21 @@ class Agent; typedef std::shared_ptr<Agent> AgentPtr; class Agent { -public: - Agent(LibraryPtr library, const QString &argument) + public: + Agent(LibraryPtr library, const QString& argument) { m_library = library; m_argument = argument; } -public: /* methods */ - - LibraryPtr library() { - return m_library; - } - QString argument() { - return m_argument; - } - -protected: /* data */ + public: /* methods */ + LibraryPtr library() { return m_library; } + QString argument() { return m_argument; } + protected: /* data */ /// The library pointing to the jar this Java agent is contained within LibraryPtr m_library; /// The argument to the Java agent, passed after an = if present QString m_argument; - }; diff --git a/launcher/minecraft/AssetsUtils.cpp b/launcher/minecraft/AssetsUtils.cpp index 16fdfdb1..32b48aed 100644 --- a/launcher/minecraft/AssetsUtils.cpp +++ b/launcher/minecraft/AssetsUtils.cpp @@ -33,21 +33,21 @@ * limitations under the License. */ -#include <QFileInfo> +#include <QCryptographicHash> +#include <QDebug> #include <QDir> #include <QDirIterator> -#include <QCryptographicHash> -#include <QJsonParseError> +#include <QFileInfo> #include <QJsonDocument> #include <QJsonObject> +#include <QJsonParseError> #include <QVariant> -#include <QDebug> #include "AssetsUtils.h" +#include "BuildConfig.h" #include "FileSystem.h" -#include "net/Download.h" #include "net/ChecksumValidator.h" -#include "BuildConfig.h" +#include "net/Download.h" #include "Application.h" @@ -56,37 +56,32 @@ QSet<QString> collectPathsFromDir(QString dirPath) { QFileInfo dirInfo(dirPath); - if (!dirInfo.exists()) - { + if (!dirInfo.exists()) { return {}; } QSet<QString> out; QDirIterator iter(dirPath, QDirIterator::Subdirectories); - while (iter.hasNext()) - { + while (iter.hasNext()) { QString value = iter.next(); QFileInfo info(value); - if(info.isFile()) - { + if (info.isFile()) { out.insert(value); qDebug() << value; } } return out; } -} +} // namespace - -namespace AssetsUtils -{ +namespace AssetsUtils { /* * Returns true on success, with index populated * index is undefined otherwise */ -bool loadAssetsIndexJson(const QString &assetsId, const QString &path, AssetsIndex& index) +bool loadAssetsIndexJson(const QString& assetsId, const QString& path, AssetsIndex& index) { /* { @@ -105,8 +100,7 @@ bool loadAssetsIndexJson(const QString &assetsId, const QString &path, AssetsInd // Try to open the file and fail if we can't. // TODO: We should probably report this error to the user. - if (!file.open(QIODevice::ReadOnly)) - { + if (!file.open(QIODevice::ReadOnly)) { qCritical() << "Failed to read assets index file" << path; return false; } @@ -120,16 +114,14 @@ bool loadAssetsIndexJson(const QString &assetsId, const QString &path, AssetsInd QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &parseError); // Fail if the JSON is invalid. - if (parseError.error != QJsonParseError::NoError) - { - qCritical() << "Failed to parse assets index file:" << parseError.errorString() - << "at offset " << QString::number(parseError.offset); + if (parseError.error != QJsonParseError::NoError) { + qCritical() << "Failed to parse assets index file:" << parseError.errorString() << "at offset " + << QString::number(parseError.offset); return false; } // Make sure the root is an object. - if (!jsonDoc.isObject()) - { + if (!jsonDoc.isObject()) { qCritical() << "Invalid assets index JSON: Root should be an array."; return false; } @@ -137,22 +129,19 @@ bool loadAssetsIndexJson(const QString &assetsId, const QString &path, AssetsInd QJsonObject root = jsonDoc.object(); QJsonValue isVirtual = root.value("virtual"); - if (!isVirtual.isUndefined()) - { + if (!isVirtual.isUndefined()) { index.isVirtual = isVirtual.toBool(false); } QJsonValue mapToResources = root.value("map_to_resources"); - if (!mapToResources.isUndefined()) - { + if (!mapToResources.isUndefined()) { index.mapToResources = mapToResources.toBool(false); } QJsonValue objects = root.value("objects"); QVariantMap map = objects.toVariant().toMap(); - for (QVariantMap::const_iterator iter = map.begin(); iter != map.end(); ++iter) - { + for (QVariantMap::const_iterator iter = map.begin(); iter != map.end(); ++iter) { // qDebug() << iter.key(); QVariant variant = iter.value(); @@ -160,19 +149,14 @@ bool loadAssetsIndexJson(const QString &assetsId, const QString &path, AssetsInd AssetObject object; - for (QVariantMap::const_iterator nested_iter = nested_objects.begin(); - nested_iter != nested_objects.end(); ++nested_iter) - { + for (QVariantMap::const_iterator nested_iter = nested_objects.begin(); nested_iter != nested_objects.end(); ++nested_iter) { // qDebug() << nested_iter.key() << nested_iter.value().toString(); QString key = nested_iter.key(); QVariant value = nested_iter.value(); - if (key == "hash") - { + if (key == "hash") { object.hash = value.toString(); - } - else if (key == "size") - { + } else if (key == "size") { object.size = value.toDouble(); } } @@ -184,7 +168,7 @@ bool loadAssetsIndexJson(const QString &assetsId, const QString &path, AssetsInd } // FIXME: ugly code duplication -QDir getAssetsDir(const QString &assetsId, const QString &resourcesFolder) +QDir getAssetsDir(const QString& assetsId, const QString& resourcesFolder) { QDir assetsDir = QDir("assets/"); QDir indexDir = QDir(FS::PathCombine(assetsDir.path(), "indexes")); @@ -195,26 +179,21 @@ QDir getAssetsDir(const QString &assetsId, const QString &resourcesFolder) QFile indexFile(indexPath); QDir virtualRoot(FS::PathCombine(virtualDir.path(), assetsId)); - if (!indexFile.exists()) - { + if (!indexFile.exists()) { qCritical() << "No assets index file" << indexPath << "; can't determine assets path!"; return virtualRoot; } AssetsIndex index; - if(!AssetsUtils::loadAssetsIndexJson(assetsId, indexPath, index)) - { + if (!AssetsUtils::loadAssetsIndexJson(assetsId, indexPath, index)) { qCritical() << "Failed to load asset index file" << indexPath << "; can't determine assets path!"; return virtualRoot; } QString targetPath; - if(index.isVirtual) - { + if (index.isVirtual) { return virtualRoot; - } - else if(index.mapToResources) - { + } else if (index.mapToResources) { return QDir(resourcesFolder); } return virtualRoot; @@ -232,8 +211,7 @@ bool reconstructAssets(QString assetsId, QString resourcesFolder) QFile indexFile(indexPath); QDir virtualRoot(FS::PathCombine(virtualDir.path(), assetsId)); - if (!indexFile.exists()) - { + if (!indexFile.exists()) { qCritical() << "No assets index file" << indexPath << "; can't reconstruct assets!"; return false; } @@ -241,31 +219,25 @@ bool reconstructAssets(QString assetsId, QString resourcesFolder) qDebug() << "reconstructAssets" << assetsDir.path() << indexDir.path() << objectDir.path() << virtualDir.path() << virtualRoot.path(); AssetsIndex index; - if(!AssetsUtils::loadAssetsIndexJson(assetsId, indexPath, index)) - { + if (!AssetsUtils::loadAssetsIndexJson(assetsId, indexPath, index)) { qCritical() << "Failed to load asset index file" << indexPath << "; can't reconstruct assets!"; return false; } QString targetPath; bool removeLeftovers = false; - if(index.isVirtual) - { + if (index.isVirtual) { targetPath = virtualRoot.path(); removeLeftovers = true; qDebug() << "Reconstructing virtual assets folder at" << targetPath; - } - else if(index.mapToResources) - { + } else if (index.mapToResources) { targetPath = resourcesFolder; qDebug() << "Reconstructing resources folder at" << targetPath; } - if (!targetPath.isNull()) - { + if (!targetPath.isNull()) { auto presentFiles = collectPathsFromDir(targetPath); - for (QString map : index.objects.keys()) - { + for (QString map : index.objects.keys()) { AssetObject asset_object = index.objects.value(map); QString target_path = FS::PathCombine(targetPath, map); QFile target(target_path); @@ -279,8 +251,7 @@ bool reconstructAssets(QString assetsId, QString resourcesFolder) presentFiles.remove(target_path); - if (!target.exists()) - { + if (!target.exists()) { QFileInfo info(target_path); QDir target_dir = info.dir(); @@ -293,10 +264,8 @@ bool reconstructAssets(QString assetsId, QString resourcesFolder) } // TODO: Write last used time to virtualRoot/.lastused - if(removeLeftovers) - { - for(auto & file: presentFiles) - { + if (removeLeftovers) { + for (auto& file : presentFiles) { qDebug() << "Would remove" << file; } } @@ -304,16 +273,14 @@ bool reconstructAssets(QString assetsId, QString resourcesFolder) return true; } -} +} // namespace AssetsUtils NetAction::Ptr AssetObject::getDownloadAction() { QFileInfo objectFile(getLocalPath()); - if ((!objectFile.isFile()) || (objectFile.size() != size)) - { + if ((!objectFile.isFile()) || (objectFile.size() != size)) { auto objectDL = Net::Download::makeFile(getUrl(), objectFile.filePath()); - if(hash.size()) - { + if (hash.size()) { auto rawHash = QByteArray::fromHex(hash.toLatin1()); objectDL->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawHash)); } @@ -341,15 +308,13 @@ QString AssetObject::getRelPath() NetJob::Ptr AssetsIndex::getDownloadJob() { auto job = makeShared<NetJob>(QObject::tr("Assets for %1").arg(id), APPLICATION->network()); - for (auto &object : objects.values()) - { + for (auto& object : objects.values()) { auto dl = object.getDownloadAction(); - if(dl) - { + if (dl) { job->addNetAction(dl); } } - if(job->size()) + if (job->size()) return job; return nullptr; } diff --git a/launcher/minecraft/AssetsUtils.h b/launcher/minecraft/AssetsUtils.h index 3dbf19ed..87956e57 100644 --- a/launcher/minecraft/AssetsUtils.h +++ b/launcher/minecraft/AssetsUtils.h @@ -15,13 +15,12 @@ #pragma once -#include <QString> #include <QMap> +#include <QString> #include "net/NetAction.h" #include "net/NetJob.h" -struct AssetObject -{ +struct AssetObject { QString getRelPath(); QUrl getUrl(); QString getLocalPath(); @@ -31,8 +30,7 @@ struct AssetObject qint64 size; }; -struct AssetsIndex -{ +struct AssetsIndex { NetJob::Ptr getDownloadJob(); QString id; @@ -42,12 +40,11 @@ struct AssetsIndex }; /// FIXME: this is absolutely horrendous. REDO!!!! -namespace AssetsUtils -{ -bool loadAssetsIndexJson(const QString &id, const QString &file, AssetsIndex& index); +namespace AssetsUtils { +bool loadAssetsIndexJson(const QString& id, const QString& file, AssetsIndex& index); -QDir getAssetsDir(const QString &assetsId, const QString &resourcesFolder); +QDir getAssetsDir(const QString& assetsId, const QString& resourcesFolder); /// Reconstruct a virtual assets folder for the given assets ID and return the folder bool reconstructAssets(QString assetsId, QString resourcesFolder); -} +} // namespace AssetsUtils diff --git a/launcher/minecraft/Component.cpp b/launcher/minecraft/Component.cpp index ff81fcbb..96d67a05 100644 --- a/launcher/minecraft/Component.cpp +++ b/launcher/minecraft/Component.cpp @@ -33,22 +33,22 @@ * limitations under the License. */ -#include <meta/VersionList.h> -#include <meta/Index.h> #include "Component.h" +#include <meta/Index.h> +#include <meta/VersionList.h> #include <QSaveFile> -#include "meta/Version.h" -#include "VersionFile.h" -#include "minecraft/PackProfile.h" +#include "Application.h" #include "FileSystem.h" #include "OneSixVersionFormat.h" -#include "Application.h" +#include "VersionFile.h" +#include "meta/Version.h" +#include "minecraft/PackProfile.h" #include <assert.h> -Component::Component(PackProfile * parent, const QString& uid) +Component::Component(PackProfile* parent, const QString& uid) { assert(parent); m_parent = parent; @@ -56,7 +56,7 @@ Component::Component(PackProfile * parent, const QString& uid) m_uid = uid; } -Component::Component(PackProfile * parent, std::shared_ptr<Meta::Version> version) +Component::Component(PackProfile* parent, std::shared_ptr<Meta::Version> version) { assert(parent); m_parent = parent; @@ -68,7 +68,7 @@ Component::Component(PackProfile * parent, std::shared_ptr<Meta::Version> versio m_loaded = version->isLoaded(); } -Component::Component(PackProfile * parent, const QString& uid, std::shared_ptr<VersionFile> file) +Component::Component(PackProfile* parent, const QString& uid, std::shared_ptr<VersionFile> file) { assert(parent); m_parent = parent; @@ -88,33 +88,25 @@ std::shared_ptr<Meta::Version> Component::getMeta() void Component::applyTo(LaunchProfile* profile) { // do not apply disabled components - if(!isEnabled()) - { + if (!isEnabled()) { return; } auto vfile = getVersionFile(); - if(vfile) - { + if (vfile) { vfile->applyTo(profile, m_parent->runtimeContext()); - } - else - { + } else { profile->applyProblemSeverity(getProblemSeverity()); } } std::shared_ptr<class VersionFile> Component::getVersionFile() const { - if(m_metaVersion) - { - if(!m_metaVersion->isLoaded()) - { + if (m_metaVersion) { + if (!m_metaVersion->isLoaded()) { m_metaVersion->load(Net::Mode::Online); } return m_metaVersion->data(); - } - else - { + } else { return m_file; } } @@ -122,8 +114,7 @@ std::shared_ptr<class VersionFile> Component::getVersionFile() const std::shared_ptr<class Meta::VersionList> Component::getVersionList() const { // FIXME: what if the metadata index isn't loaded yet? - if(APPLICATION->metadataIndex()->hasUid(m_uid)) - { + if (APPLICATION->metadataIndex()->hasUid(m_uid)) { return APPLICATION->metadataIndex()->get(m_uid); } return nullptr; @@ -131,12 +122,11 @@ std::shared_ptr<class Meta::VersionList> Component::getVersionList() const int Component::getOrder() { - if(m_orderOverride) + if (m_orderOverride) return m_order; auto vfile = getVersionFile(); - if(vfile) - { + if (vfile) { return vfile->order; } return 0; @@ -166,13 +156,11 @@ QString Component::getFilename() } QDateTime Component::getReleaseDateTime() { - if(m_metaVersion) - { + if (m_metaVersion) { return m_metaVersion->time(); } auto vfile = getVersionFile(); - if(vfile) - { + if (vfile) { return vfile->releaseTime; } // FIXME: fake @@ -192,12 +180,10 @@ bool Component::canBeDisabled() bool Component::setEnabled(bool state) { bool intendedDisabled = !state; - if (!canBeDisabled()) - { + if (!canBeDisabled()) { intendedDisabled = false; } - if(intendedDisabled != m_disabled) - { + if (intendedDisabled != m_disabled) { m_disabled = intendedDisabled; emit dataChanged(); return true; @@ -212,10 +198,8 @@ bool Component::isCustom() bool Component::isCustomizable() { - if(m_metaVersion) - { - if(getVersionFile()) - { + if (m_metaVersion) { + if (getVersionFile()) { return true; } } @@ -227,10 +211,8 @@ bool Component::isRemovable() } bool Component::isRevertible() { - if (isCustom()) - { - if(APPLICATION->metadataIndex()->hasUid(m_uid)) - { + if (isCustom()) { + if (APPLICATION->metadataIndex()->hasUid(m_uid)) { return true; } } @@ -244,10 +226,8 @@ bool Component::isMoveable() bool Component::isVersionChangeable() { auto list = getVersionList(); - if(list) - { - if(!list->isLoaded()) - { + if (list) { + if (!list->isLoaded()) { list->load(Net::Mode::Online); } return list->count() != 0; @@ -257,8 +237,7 @@ bool Component::isVersionChangeable() void Component::setImportant(bool state) { - if(m_important != state) - { + if (m_important != state) { m_important = state; emit dataChanged(); } @@ -267,8 +246,7 @@ void Component::setImportant(bool state) ProblemSeverity Component::getProblemSeverity() const { auto file = getVersionFile(); - if(file) - { + if (file) { return file->getProblemSeverity(); } return ProblemSeverity::Error; @@ -277,49 +255,38 @@ ProblemSeverity Component::getProblemSeverity() const const QList<PatchProblem> Component::getProblems() const { auto file = getVersionFile(); - if(file) - { + if (file) { return file->getProblems(); } - return {{ProblemSeverity::Error, QObject::tr("Patch is not loaded yet.")}}; + return { { ProblemSeverity::Error, QObject::tr("Patch is not loaded yet.") } }; } void Component::setVersion(const QString& version) { - if(version == m_version) - { + if (version == m_version) { return; } m_version = version; - if(m_loaded) - { + if (m_loaded) { // we are loaded and potentially have state to invalidate - if(m_file) - { + if (m_file) { // we have a file... explicit version has been changed and there is nothing else to do. - } - else - { + } else { // we don't have a file, therefore we are loaded with metadata m_cachedVersion = version; // see if the meta version is loaded auto metaVersion = APPLICATION->metadataIndex()->get(m_uid, version); - if(metaVersion->isLoaded()) - { + if (metaVersion->isLoaded()) { // if yes, we can continue with that. m_metaVersion = metaVersion; - } - else - { + } else { // if not, we need loading m_metaVersion.reset(); m_loaded = false; } updateCachedData(); } - } - else - { + } else { // not loaded... assume it will be sorted out later by the update task } emit dataChanged(); @@ -327,41 +294,33 @@ void Component::setVersion(const QString& version) bool Component::customize() { - if(isCustom()) - { + if (isCustom()) { return false; } auto filename = getFilename(); - if(!FS::ensureFilePathExists(filename)) - { + if (!FS::ensureFilePathExists(filename)) { return false; } // FIXME: get rid of this try-catch. - try - { + try { QSaveFile jsonFile(filename); - if(!jsonFile.open(QIODevice::WriteOnly)) - { + if (!jsonFile.open(QIODevice::WriteOnly)) { return false; } auto vfile = getVersionFile(); - if(!vfile) - { + if (!vfile) { return false; } auto document = OneSixVersionFormat::versionFileToJson(vfile); jsonFile.write(document.toJson()); - if(!jsonFile.commit()) - { + if (!jsonFile.commit()) { return false; } m_file = vfile; m_metaVersion.reset(); emit dataChanged(); - } - catch (const Exception &error) - { + } catch (const Exception& error) { qWarning() << "Version could not be loaded:" << error.cause(); } return true; @@ -369,31 +328,25 @@ bool Component::customize() bool Component::revert() { - if(!isCustom()) - { + if (!isCustom()) { // already not custom return true; } auto filename = getFilename(); bool result = true; // just kill the file and reload - if(QFile::exists(filename)) - { + if (QFile::exists(filename)) { result = QFile::remove(filename); } - if(result) - { + if (result) { // file gone... m_file.reset(); // check local cache for metadata... auto version = APPLICATION->metadataIndex()->get(m_uid, m_version); - if(version->isLoaded()) - { + if (version->isLoaded()) { m_metaVersion = version; - } - else - { + } else { m_metaVersion.reset(); m_loaded = false; } @@ -407,23 +360,19 @@ bool Component::revert() * By default, only uids are compared for set operations. * This compares all fields of the Require structs in the sets. */ -static bool deepCompare(const std::set<Meta::Require> & a, const std::set<Meta::Require> & b) +static bool deepCompare(const std::set<Meta::Require>& a, const std::set<Meta::Require>& b) { // NOTE: this needs to be rewritten if the type of Meta::RequireSet changes - if(a.size() != b.size()) - { + if (a.size() != b.size()) { return false; } - for(const auto & reqA :a) - { - const auto &iter2 = b.find(reqA); - if(iter2 == b.cend()) - { + for (const auto& reqA : a) { + const auto& iter2 = b.find(reqA); + if (iter2 == b.cend()) { return false; } - const auto & reqB = *iter2; - if(!reqA.deepEquals(reqB)) - { + const auto& reqB = *iter2; + if (!reqA.deepEquals(reqB)) { return false; } } @@ -433,41 +382,32 @@ static bool deepCompare(const std::set<Meta::Require> & a, const std::set<Meta:: void Component::updateCachedData() { auto file = getVersionFile(); - if(file) - { + if (file) { bool changed = false; - if(m_cachedName != file->name) - { + if (m_cachedName != file->name) { m_cachedName = file->name; changed = true; } - if(m_cachedVersion != file->version) - { + if (m_cachedVersion != file->version) { m_cachedVersion = file->version; changed = true; } - if(m_cachedVolatile != file->m_volatile) - { + if (m_cachedVolatile != file->m_volatile) { m_cachedVolatile = file->m_volatile; changed = true; } - if(!deepCompare(m_cachedRequires, file->m_requires)) - { + if (!deepCompare(m_cachedRequires, file->m_requires)) { m_cachedRequires = file->m_requires; changed = true; } - if(!deepCompare(m_cachedConflicts, file->conflicts)) - { + if (!deepCompare(m_cachedConflicts, file->conflicts)) { m_cachedConflicts = file->conflicts; changed = true; } - if(changed) - { + if (changed) { emit dataChanged(); } - } - else - { + } else { // in case we removed all the metadata m_cachedRequires.clear(); m_cachedConflicts.clear(); diff --git a/launcher/minecraft/Component.h b/launcher/minecraft/Component.h index ef7c9947..00a912d6 100644 --- a/launcher/minecraft/Component.h +++ b/launcher/minecraft/Component.h @@ -1,37 +1,35 @@ #pragma once -#include <memory> -#include <QList> -#include <QJsonDocument> #include <QDateTime> -#include "meta/JsonFormat.h" +#include <QJsonDocument> +#include <QList> +#include <memory> #include "ProblemProvider.h" #include "QObjectPtr.h" +#include "meta/JsonFormat.h" class PackProfile; class LaunchProfile; -namespace Meta -{ - class Version; - class VersionList; -} +namespace Meta { +class Version; +class VersionList; +} // namespace Meta class VersionFile; -class Component : public QObject, public ProblemProvider -{ -Q_OBJECT -public: - Component(PackProfile * parent, const QString &uid); +class Component : public QObject, public ProblemProvider { + Q_OBJECT + public: + Component(PackProfile* parent, const QString& uid); // DEPRECATED: remove these constructors? - Component(PackProfile * parent, std::shared_ptr<Meta::Version> version); - Component(PackProfile * parent, const QString & uid, std::shared_ptr<VersionFile> file); + Component(PackProfile* parent, std::shared_ptr<Meta::Version> version); + Component(PackProfile* parent, const QString& uid, std::shared_ptr<VersionFile> file); virtual ~Component(){}; - void applyTo(LaunchProfile *profile); + void applyTo(LaunchProfile* profile); bool isEnabled(); - bool setEnabled (bool state); + bool setEnabled(bool state); bool canBeDisabled(); bool isMoveable(); @@ -56,23 +54,22 @@ public: std::shared_ptr<class VersionFile> getVersionFile() const; std::shared_ptr<class Meta::VersionList> getVersionList() const; - void setImportant (bool state); - + void setImportant(bool state); const QList<PatchProblem> getProblems() const override; ProblemSeverity getProblemSeverity() const override; - void setVersion(const QString & version); + void setVersion(const QString& version); bool customize(); bool revert(); void updateCachedData(); -signals: + signals: void dataChanged(); -public: /* data */ - PackProfile * m_parent; + public: /* data */ + PackProfile* m_parent; // BEGIN: persistent component list properties /// ID of the component diff --git a/launcher/minecraft/ComponentUpdateTask.cpp b/launcher/minecraft/ComponentUpdateTask.cpp index d55bc17f..0b85b81a 100644 --- a/launcher/minecraft/ComponentUpdateTask.cpp +++ b/launcher/minecraft/ComponentUpdateTask.cpp @@ -1,16 +1,16 @@ #include "ComponentUpdateTask.h" -#include "PackProfile_p.h" -#include "PackProfile.h" #include "Component.h" -#include "meta/Index.h" -#include "meta/VersionList.h" -#include "meta/Version.h" #include "ComponentUpdateTask_p.h" -#include "cassert" +#include "OneSixVersionFormat.h" +#include "PackProfile.h" +#include "PackProfile_p.h" #include "Version.h" +#include "cassert" +#include "meta/Index.h" +#include "meta/Version.h" +#include "meta/VersionList.h" #include "net/Mode.h" -#include "OneSixVersionFormat.h" #include "Application.h" @@ -32,8 +32,7 @@ * If the component list changes, start over. */ -ComponentUpdateTask::ComponentUpdateTask(Mode mode, Net::Mode netmode, PackProfile* list, QObject* parent) - : Task(parent) +ComponentUpdateTask::ComponentUpdateTask(Mode mode, Net::Mode netmode, PackProfile* list, QObject* parent) : Task(parent) { d.reset(new ComponentUpdateTaskData); d->m_list = list; @@ -41,9 +40,7 @@ ComponentUpdateTask::ComponentUpdateTask(Mode mode, Net::Mode netmode, PackProfi d->netmode = netmode; } -ComponentUpdateTask::~ComponentUpdateTask() -{ -} +ComponentUpdateTask::~ComponentUpdateTask() {} void ComponentUpdateTask::executeTask() { @@ -51,19 +48,12 @@ void ComponentUpdateTask::executeTask() loadComponents(); } -namespace -{ -enum class LoadResult -{ - LoadedLocal, - RequiresRemote, - Failed -}; +namespace { +enum class LoadResult { LoadedLocal, RequiresRemote, Failed }; LoadResult composeLoadResult(LoadResult a, LoadResult b) { - if (a < b) - { + if (a < b) { return b; } return a; @@ -71,28 +61,24 @@ LoadResult composeLoadResult(LoadResult a, LoadResult b) static LoadResult loadComponent(ComponentPtr component, Task::Ptr& loadTask, Net::Mode netmode) { - if(component->m_loaded) - { + if (component->m_loaded) { qDebug() << component->getName() << "is already loaded"; return LoadResult::LoadedLocal; } LoadResult result = LoadResult::Failed; auto customPatchFilename = component->getFilename(); - if(QFile::exists(customPatchFilename)) - { + if (QFile::exists(customPatchFilename)) { // if local file exists... // check for uid problems inside... bool fileChanged = false; auto file = ProfileUtils::parseJsonFile(QFileInfo(customPatchFilename), false); - if(file->uid != component->m_uid) - { + if (file->uid != component->m_uid) { file->uid = component->m_uid; fileChanged = true; } - if(fileChanged) - { + if (fileChanged) { // FIXME: @QUALITY do not ignore return value ProfileUtils::saveJsonFile(OneSixVersionFormat::versionFileToJson(file), customPatchFilename); } @@ -100,21 +86,16 @@ static LoadResult loadComponent(ComponentPtr component, Task::Ptr& loadTask, Net component->m_file = file; component->m_loaded = true; result = LoadResult::LoadedLocal; - } - else - { + } else { auto metaVersion = APPLICATION->metadataIndex()->get(component->m_uid, component->m_version); component->m_metaVersion = metaVersion; - if(metaVersion->isLoaded()) - { + if (metaVersion->isLoaded()) { component->m_loaded = true; result = LoadResult::LoadedLocal; - } - else - { + } else { metaVersion->load(netmode); loadTask = metaVersion->getCurrentTask(); - if(loadTask) + if (loadTask) result = LoadResult::RequiresRemote; else if (metaVersion->isLoaded()) result = LoadResult::LoadedLocal; @@ -155,21 +136,19 @@ static LoadResult loadPackProfile(ComponentPtr component, Task::Ptr& loadTask, N static LoadResult loadIndex(Task::Ptr& loadTask, Net::Mode netmode) { // FIXME: DECIDE. do we want to run the update task anyway? - if(APPLICATION->metadataIndex()->isLoaded()) - { + if (APPLICATION->metadataIndex()->isLoaded()) { qDebug() << "Index is already loaded"; return LoadResult::LoadedLocal; } APPLICATION->metadataIndex()->load(netmode); loadTask = APPLICATION->metadataIndex()->getCurrentTask(); - if(loadTask) - { + if (loadTask) { return LoadResult::RequiresRemote; } // FIXME: this is assuming the load succeeded... did it really? return LoadResult::LoadedLocal; } -} +} // namespace void ComponentUpdateTask::loadComponents() { @@ -183,34 +162,24 @@ void ComponentUpdateTask::loadComponents() Task::Ptr indexLoadTask; auto singleResult = loadIndex(indexLoadTask, d->netmode); result = composeLoadResult(result, singleResult); - if(indexLoadTask) - { + if (indexLoadTask) { qDebug() << "Remote loading is being run for metadata index"; RemoteLoadStatus status; status.type = RemoteLoadStatus::Type::Index; d->remoteLoadStatusList.append(status); - connect(indexLoadTask.get(), &Task::succeeded, [=]() - { - remoteLoadSucceeded(taskIndex); - }); - connect(indexLoadTask.get(), &Task::failed, [=](const QString & error) - { - remoteLoadFailed(taskIndex, error); - }); - connect(indexLoadTask.get(), &Task::aborted, [=]() - { - remoteLoadFailed(taskIndex, tr("Aborted")); - }); + connect(indexLoadTask.get(), &Task::succeeded, [=]() { remoteLoadSucceeded(taskIndex); }); + connect(indexLoadTask.get(), &Task::failed, [=](const QString& error) { remoteLoadFailed(taskIndex, error); }); + connect(indexLoadTask.get(), &Task::aborted, [=]() { remoteLoadFailed(taskIndex, tr("Aborted")); }); taskIndex++; } } // load all the components OR their lists... - for (auto component: d->m_list->d->components) - { + for (auto component : d->m_list->d->components) { Task::Ptr loadTask; LoadResult singleResult; RemoteLoadStatus::Type loadType; - // FIXME: to do this right, we need to load the lists and decide on which versions to use during dependency resolution. For now, ignore all that... + // FIXME: to do this right, we need to load the lists and decide on which versions to use during dependency resolution. For now, + // ignore all that... #if 0 switch(d->mode) { @@ -231,26 +200,15 @@ void ComponentUpdateTask::loadComponents() singleResult = loadComponent(component, loadTask, d->netmode); loadType = RemoteLoadStatus::Type::Version; #endif - if(singleResult == LoadResult::LoadedLocal) - { + if (singleResult == LoadResult::LoadedLocal) { component->updateCachedData(); } result = composeLoadResult(result, singleResult); - if (loadTask) - { + if (loadTask) { qDebug() << "Remote loading is being run for" << component->getName(); - connect(loadTask.get(), &Task::succeeded, [=]() - { - remoteLoadSucceeded(taskIndex); - }); - connect(loadTask.get(), &Task::failed, [=](const QString & error) - { - remoteLoadFailed(taskIndex, error); - }); - connect(loadTask.get(), &Task::aborted, [=]() - { - remoteLoadFailed(taskIndex, tr("Aborted")); - }); + connect(loadTask.get(), &Task::succeeded, [=]() { remoteLoadSucceeded(taskIndex); }); + connect(loadTask.get(), &Task::failed, [=](const QString& error) { remoteLoadFailed(taskIndex, error); }); + connect(loadTask.get(), &Task::aborted, [=]() { remoteLoadFailed(taskIndex, tr("Aborted")); }); RemoteLoadStatus status; status.type = loadType; status.PackProfileIndex = componentIndex; @@ -260,95 +218,73 @@ void ComponentUpdateTask::loadComponents() componentIndex++; } d->remoteTasksInProgress = taskIndex; - switch(result) - { - case LoadResult::LoadedLocal: - { + switch (result) { + case LoadResult::LoadedLocal: { // Everything got loaded. Advance to dependency resolution. resolveDependencies(d->mode == Mode::Launch || d->netmode == Net::Mode::Offline); break; } - case LoadResult::RequiresRemote: - { + case LoadResult::RequiresRemote: { // we wait for signals. break; } - case LoadResult::Failed: - { + case LoadResult::Failed: { emitFailed(tr("Some component metadata load tasks failed.")); break; } } } -namespace -{ - struct RequireEx : public Meta::Require - { - size_t indexOfFirstDependee = 0; - }; - struct RequireCompositionResult - { - bool ok; - RequireEx outcome; - }; - using RequireExSet = std::set<RequireEx>; -} +namespace { +struct RequireEx : public Meta::Require { + size_t indexOfFirstDependee = 0; +}; +struct RequireCompositionResult { + bool ok; + RequireEx outcome; +}; +using RequireExSet = std::set<RequireEx>; +} // namespace -static RequireCompositionResult composeRequirement(const RequireEx & a, const RequireEx & b) +static RequireCompositionResult composeRequirement(const RequireEx& a, const RequireEx& b) { assert(a.uid == b.uid); RequireEx out; out.uid = a.uid; out.indexOfFirstDependee = std::min(a.indexOfFirstDependee, b.indexOfFirstDependee); - if(a.equalsVersion.isEmpty()) - { + if (a.equalsVersion.isEmpty()) { out.equalsVersion = b.equalsVersion; - } - else if (b.equalsVersion.isEmpty()) - { + } else if (b.equalsVersion.isEmpty()) { out.equalsVersion = a.equalsVersion; - } - else if (a.equalsVersion == b.equalsVersion) - { + } else if (a.equalsVersion == b.equalsVersion) { out.equalsVersion = a.equalsVersion; - } - else - { + } else { // FIXME: mark error as explicit version conflict - return {false, out}; + return { false, out }; } - if(a.suggests.isEmpty()) - { + if (a.suggests.isEmpty()) { out.suggests = b.suggests; - } - else if (b.suggests.isEmpty()) - { + } else if (b.suggests.isEmpty()) { out.suggests = a.suggests; - } - else - { + } else { Version aVer(a.suggests); Version bVer(b.suggests); out.suggests = (aVer < bVer ? b.suggests : a.suggests); } - return {true, out}; + return { true, out }; } // gather the requirements from all components, finding any obvious conflicts -static bool gatherRequirementsFromComponents(const ComponentContainer & input, RequireExSet & output) +static bool gatherRequirementsFromComponents(const ComponentContainer& input, RequireExSet& output) { bool succeeded = true; size_t componentNum = 0; - for(auto component: input) - { - auto &componentRequires = component->m_cachedRequires; - for(const auto & componentRequire: componentRequires) - { - auto found = std::find_if(output.cbegin(), output.cend(), [componentRequire](const Meta::Require & req){ - return req.uid == componentRequire.uid; - }); + for (auto component : input) { + auto& componentRequires = component->m_cachedRequires; + for (const auto& componentRequire : componentRequires) { + auto found = std::find_if(output.cbegin(), output.cend(), + [componentRequire](const Meta::Require& req) { return req.uid == componentRequire.uid; }); RequireEx componenRequireEx; componenRequireEx.uid = componentRequire.uid; @@ -356,29 +292,18 @@ static bool gatherRequirementsFromComponents(const ComponentContainer & input, R componenRequireEx.equalsVersion = componentRequire.equalsVersion; componenRequireEx.indexOfFirstDependee = componentNum; - if(found != output.cend()) - { + if (found != output.cend()) { // found... process it further auto result = composeRequirement(componenRequireEx, *found); - if(result.ok) - { + if (result.ok) { output.erase(componenRequireEx); output.insert(result.outcome); - } - else - { - qCritical() - << "Conflicting requirements:" - << componentRequire.uid - << "versions:" - << componentRequire.equalsVersion - << ";" - << (*found).equalsVersion; + } else { + qCritical() << "Conflicting requirements:" << componentRequire.uid << "versions:" << componentRequire.equalsVersion + << ";" << (*found).equalsVersion; } succeeded &= result.ok; - } - else - { + } else { // not found, accumulate output.insert(componenRequireEx); } @@ -389,19 +314,17 @@ static bool gatherRequirementsFromComponents(const ComponentContainer & input, R } /// Get list of uids that can be trivially removed because nothing is depending on them anymore (and they are installed as deps) -static void getTrivialRemovals(const ComponentContainer & components, const RequireExSet & reqs, QStringList &toRemove) +static void getTrivialRemovals(const ComponentContainer& components, const RequireExSet& reqs, QStringList& toRemove) { - for(const auto & component: components) - { - if(!component->m_dependencyOnly) + for (const auto& component : components) { + if (!component->m_dependencyOnly) continue; - if(!component->m_cachedVolatile) + if (!component->m_cachedVolatile) continue; RequireEx reqNeedle; reqNeedle.uid = component->m_uid; const auto iter = reqs.find(reqNeedle); - if(iter == reqs.cend()) - { + if (iter == reqs.cend()) { toRemove.append(component->m_uid); } } @@ -415,60 +338,40 @@ static void getTrivialRemovals(const ComponentContainer & components, const Requ * toAdd - set of requirements than mean adding a new component * toChange - set of requirements that mean changing version of an existing component */ -static bool getTrivialComponentChanges(const ComponentIndex & index, const RequireExSet & input, RequireExSet & toAdd, RequireExSet & toChange) +static bool getTrivialComponentChanges(const ComponentIndex& index, const RequireExSet& input, RequireExSet& toAdd, RequireExSet& toChange) { - enum class Decision - { - Undetermined, - Met, - Missing, - VersionNotSame, - LockedVersionNotSame - } decision = Decision::Undetermined; + enum class Decision { Undetermined, Met, Missing, VersionNotSame, LockedVersionNotSame } decision = Decision::Undetermined; QString reqStr; bool succeeded = true; // list the composed requirements and say if they are met or unmet - for(auto & req: input) - { - do - { - if(req.equalsVersion.isEmpty()) - { + for (auto& req : input) { + do { + if (req.equalsVersion.isEmpty()) { reqStr = QString("Req: %1").arg(req.uid); - if(index.contains(req.uid)) - { + if (index.contains(req.uid)) { decision = Decision::Met; - } - else - { + } else { toAdd.insert(req); decision = Decision::Missing; } break; - } - else - { + } else { reqStr = QString("Req: %1 == %2").arg(req.uid, req.equalsVersion); - const auto & compIter = index.find(req.uid); - if(compIter == index.cend()) - { + const auto& compIter = index.find(req.uid); + if (compIter == index.cend()) { toAdd.insert(req); decision = Decision::Missing; break; } - auto & comp = (*compIter); - if(comp->getVersion() != req.equalsVersion) - { - if(comp->isCustom()) { + auto& comp = (*compIter); + if (comp->getVersion() != req.equalsVersion) { + if (comp->isCustom()) { decision = Decision::LockedVersionNotSame; } else { - if(comp->m_dependencyOnly) - { + if (comp->m_dependencyOnly) { decision = Decision::VersionNotSame; - } - else - { + } else { decision = Decision::LockedVersionNotSame; } } @@ -476,9 +379,8 @@ static bool getTrivialComponentChanges(const ComponentIndex & index, const Requi } decision = Decision::Met; } - } while(false); - switch(decision) - { + } while (false); + switch (decision) { case Decision::Undetermined: qCritical() << "No decision for" << reqStr; succeeded = false; @@ -520,26 +422,22 @@ void ComponentUpdateTask::resolveDependencies(bool checkOnly) * * NOTE: this is a placeholder and should eventually be replaced with something 'serious' */ - auto & components = d->m_list->d->components; - auto & componentIndex = d->m_list->d->componentIndex; + auto& components = d->m_list->d->components; + auto& componentIndex = d->m_list->d->componentIndex; RequireExSet allRequires; QStringList toRemove; - do - { + do { allRequires.clear(); toRemove.clear(); - if(!gatherRequirementsFromComponents(components, allRequires)) - { + if (!gatherRequirementsFromComponents(components, allRequires)) { emitFailed(tr("Conflicting requirements detected during dependency checking!")); return; } getTrivialRemovals(components, allRequires, toRemove); - if(!toRemove.isEmpty()) - { + if (!toRemove.isEmpty()) { qDebug() << "Removing obsolete components..."; - for(auto & remove : toRemove) - { + for (auto& remove : toRemove) { qDebug() << "Removing" << remove; d->m_list->remove(remove); } @@ -548,69 +446,50 @@ void ComponentUpdateTask::resolveDependencies(bool checkOnly) RequireExSet toAdd; RequireExSet toChange; bool succeeded = getTrivialComponentChanges(componentIndex, allRequires, toAdd, toChange); - if(!succeeded) - { + if (!succeeded) { emitFailed(tr("Instance has conflicting dependencies.")); return; } - if(checkOnly) - { - if(toAdd.size() || toChange.size()) - { + if (checkOnly) { + if (toAdd.size() || toChange.size()) { emitFailed(tr("Instance has unresolved dependencies while loading/checking for launch.")); - } - else - { + } else { emitSucceeded(); } return; } bool recursionNeeded = false; - if(toAdd.size()) - { + if (toAdd.size()) { // add stuff... - for(auto &add: toAdd) - { + for (auto& add : toAdd) { auto component = makeShared<Component>(d->m_list, add.uid); - if(!add.equalsVersion.isEmpty()) - { + if (!add.equalsVersion.isEmpty()) { // exact version qDebug() << "Adding" << add.uid << "version" << add.equalsVersion << "at position" << add.indexOfFirstDependee; component->m_version = add.equalsVersion; - } - else - { + } else { // version needs to be decided qDebug() << "Adding" << add.uid << "at position" << add.indexOfFirstDependee; -// ############################################################################################################ -// HACK HACK HACK HACK FIXME: this is a placeholder for deciding what version to use. For now, it is hardcoded. - if(!add.suggests.isEmpty()) - { + // ############################################################################################################ + // HACK HACK HACK HACK FIXME: this is a placeholder for deciding what version to use. For now, it is hardcoded. + if (!add.suggests.isEmpty()) { component->m_version = add.suggests; - } - else - { - if(add.uid == "org.lwjgl") - { + } else { + if (add.uid == "org.lwjgl") { component->m_version = "2.9.1"; - } - else if (add.uid == "org.lwjgl3") - { + } else if (add.uid == "org.lwjgl3") { component->m_version = "3.1.2"; - } - else if (add.uid == "net.fabricmc.intermediary" || add.uid == "org.quiltmc.hashed") - { - auto minecraft = std::find_if(components.begin(), components.end(), [](ComponentPtr & cmp){ - return cmp->getID() == "net.minecraft"; - }); - if(minecraft != components.end()) { + } else if (add.uid == "net.fabricmc.intermediary" || add.uid == "org.quiltmc.hashed") { + auto minecraft = std::find_if(components.begin(), components.end(), + [](ComponentPtr& cmp) { return cmp->getID() == "net.minecraft"; }); + if (minecraft != components.end()) { component->m_version = (*minecraft)->getVersion(); } } } -// HACK HACK HACK HACK FIXME: this is a placeholder for deciding what version to use. For now, it is hardcoded. -// ############################################################################################################ + // HACK HACK HACK HACK FIXME: this is a placeholder for deciding what version to use. For now, it is hardcoded. + // ############################################################################################################ } component->m_dependencyOnly = true; // FIXME: this should not work directly with the component list @@ -619,11 +498,9 @@ void ComponentUpdateTask::resolveDependencies(bool checkOnly) } recursionNeeded = true; } - if(toChange.size()) - { + if (toChange.size()) { // change a version of something that exists - for(auto &change: toChange) - { + for (auto& change : toChange) { // FIXME: this should not work directly with the component list qDebug() << "Setting version of " << change.uid << "to" << change.equalsVersion; auto component = componentIndex[change.uid]; @@ -632,31 +509,26 @@ void ComponentUpdateTask::resolveDependencies(bool checkOnly) recursionNeeded = true; } - if(recursionNeeded) - { + if (recursionNeeded) { loadComponents(); - } - else - { + } else { emitSucceeded(); } } void ComponentUpdateTask::remoteLoadSucceeded(size_t taskIndex) { - auto &taskSlot = d->remoteLoadStatusList[taskIndex]; - if(taskSlot.finished) - { + auto& taskSlot = d->remoteLoadStatusList[taskIndex]; + if (taskSlot.finished) { qWarning() << "Got multiple results from remote load task" << taskIndex; return; } qDebug() << "Remote task" << taskIndex << "succeeded"; taskSlot.succeeded = false; taskSlot.finished = true; - d->remoteTasksInProgress --; + d->remoteTasksInProgress--; // update the cached data of the component from the downloaded version file. - if (taskSlot.type == RemoteLoadStatus::Type::Version) - { + if (taskSlot.type == RemoteLoadStatus::Type::Version) { auto component = d->m_list->getComponent(taskSlot.PackProfileIndex); component->m_loaded = true; component->updateCachedData(); @@ -664,12 +536,10 @@ void ComponentUpdateTask::remoteLoadSucceeded(size_t taskIndex) checkIfAllFinished(); } - void ComponentUpdateTask::remoteLoadFailed(size_t taskIndex, const QString& msg) { - auto &taskSlot = d->remoteLoadStatusList[taskIndex]; - if(taskSlot.finished) - { + auto& taskSlot = d->remoteLoadStatusList[taskIndex]; + if (taskSlot.finished) { qWarning() << "Got multiple results from remote load task" << taskIndex; return; } @@ -678,31 +548,25 @@ void ComponentUpdateTask::remoteLoadFailed(size_t taskIndex, const QString& msg) taskSlot.succeeded = false; taskSlot.finished = true; taskSlot.error = msg; - d->remoteTasksInProgress --; + d->remoteTasksInProgress--; checkIfAllFinished(); } void ComponentUpdateTask::checkIfAllFinished() { - if(d->remoteTasksInProgress) - { + if (d->remoteTasksInProgress) { // not yet... return; } - if(d->remoteLoadSuccessful) - { + if (d->remoteLoadSuccessful) { // nothing bad happened... clear the temp load status and proceed with looking at dependencies d->remoteLoadStatusList.clear(); resolveDependencies(d->mode == Mode::Launch); - } - else - { + } else { // remote load failed... report error and bail QStringList allErrorsList; - for(auto & item: d->remoteLoadStatusList) - { - if(!item.succeeded) - { + for (auto& item : d->remoteLoadStatusList) { + if (!item.succeeded) { allErrorsList.append(item.error); } } diff --git a/launcher/minecraft/ComponentUpdateTask.h b/launcher/minecraft/ComponentUpdateTask.h index 4274cabb..2f396a04 100644 --- a/launcher/minecraft/ComponentUpdateTask.h +++ b/launcher/minecraft/ComponentUpdateTask.h @@ -1,37 +1,32 @@ #pragma once -#include "tasks/Task.h" #include "net/Mode.h" +#include "tasks/Task.h" #include <memory> class PackProfile; struct ComponentUpdateTaskData; -class ComponentUpdateTask : public Task -{ +class ComponentUpdateTask : public Task { Q_OBJECT -public: - enum class Mode - { - Launch, - Resolution - }; - -public: - explicit ComponentUpdateTask(Mode mode, Net::Mode netmode, PackProfile * list, QObject *parent = 0); + public: + enum class Mode { Launch, Resolution }; + + public: + explicit ComponentUpdateTask(Mode mode, Net::Mode netmode, PackProfile* list, QObject* parent = 0); virtual ~ComponentUpdateTask(); -protected: + protected: void executeTask(); -private: + private: void loadComponents(); void resolveDependencies(bool checkOnly); void remoteLoadSucceeded(size_t index); - void remoteLoadFailed(size_t index, const QString &msg); + void remoteLoadFailed(size_t index, const QString& msg); void checkIfAllFinished(); -private: + private: std::unique_ptr<ComponentUpdateTaskData> d; }; diff --git a/launcher/minecraft/ComponentUpdateTask_p.h b/launcher/minecraft/ComponentUpdateTask_p.h index 5b02431b..00e8f2fb 100644 --- a/launcher/minecraft/ComponentUpdateTask_p.h +++ b/launcher/minecraft/ComponentUpdateTask_p.h @@ -1,29 +1,22 @@ #pragma once -#include <cstddef> -#include <QString> #include <QList> +#include <QString> +#include <cstddef> #include "net/Mode.h" class PackProfile; -struct RemoteLoadStatus -{ - enum class Type - { - Index, - List, - Version - } type = Type::Version; +struct RemoteLoadStatus { + enum class Type { Index, List, Version } type = Type::Version; size_t PackProfileIndex = 0; bool finished = false; bool succeeded = false; QString error; }; -struct ComponentUpdateTaskData -{ - PackProfile * m_list = nullptr; +struct ComponentUpdateTaskData { + PackProfile* m_list = nullptr; QList<RemoteLoadStatus> remoteLoadStatusList; bool remoteLoadSuccessful = true; size_t remoteTasksInProgress = 0; diff --git a/launcher/minecraft/GradleSpecifier.h b/launcher/minecraft/GradleSpecifier.h index 27514ab9..53c31e8e 100644 --- a/launcher/minecraft/GradleSpecifier.h +++ b/launcher/minecraft/GradleSpecifier.h @@ -35,22 +35,15 @@ #pragma once +#include <QRegularExpression> #include <QString> #include <QStringList> -#include <QRegularExpression> #include "DefaultVariable.h" -struct GradleSpecifier -{ - GradleSpecifier() - { - m_valid = false; - } - GradleSpecifier(QString value) - { - operator=(value); - } - GradleSpecifier & operator =(const QString & value) +struct GradleSpecifier { + GradleSpecifier() { m_valid = false; } + GradleSpecifier(QString value) { operator=(value); } + GradleSpecifier& operator=(const QString& value) { /* org.gradle.test.classifiers : service : 1.0 : jdk15 @ jar @@ -61,10 +54,13 @@ struct GradleSpecifier 4 "jdk15" 5 "jar" */ - QRegularExpression matcher(QRegularExpression::anchoredPattern("([^:@]+):([^:@]+):([^:@]+)" "(?::([^:@]+))?" "(?:@([^:@]+))?")); + QRegularExpression matcher( + QRegularExpression::anchoredPattern("([^:@]+):([^:@]+):([^:@]+)" + "(?::([^:@]+))?" + "(?:@([^:@]+))?")); QRegularExpressionMatch match = matcher.match(value); m_valid = match.hasMatch(); - if(!m_valid) { + if (!m_valid) { m_invalidValue = value; return *this; } @@ -73,53 +69,46 @@ struct GradleSpecifier m_artifactId = match.captured(2); m_version = match.captured(3); m_classifier = match.captured(4); - if(match.lastCapturedIndex() >= 5) - { + if (match.lastCapturedIndex() >= 5) { m_extension = match.captured(5); } return *this; } QString serialize() const { - if(!m_valid) { + if (!m_valid) { return m_invalidValue; } QString retval = m_groupId + ":" + m_artifactId + ":" + m_version; - if(!m_classifier.isEmpty()) - { + if (!m_classifier.isEmpty()) { retval += ":" + m_classifier; } - if(m_extension.isExplicit()) - { + if (m_extension.isExplicit()) { retval += "@" + m_extension; } return retval; } QString getFileName() const { - if(!m_valid) { + if (!m_valid) { return QString(); } QString filename = m_artifactId + '-' + m_version; - if(!m_classifier.isEmpty()) - { + if (!m_classifier.isEmpty()) { filename += "-" + m_classifier; } filename += "." + m_extension; return filename; } - QString toPath(const QString & filenameOverride = QString()) const + QString toPath(const QString& filenameOverride = QString()) const { - if(!m_valid) { + if (!m_valid) { return QString(); } QString filename; - if(filenameOverride.isEmpty()) - { + if (filenameOverride.isEmpty()) { filename = getFileName(); - } - else - { + } else { filename = filenameOverride; } QString path = m_groupId; @@ -127,57 +116,34 @@ struct GradleSpecifier path += '/' + m_artifactId + '/' + m_version + '/' + filename; return path; } - inline bool valid() const - { - return m_valid; - } - inline QString version() const - { - return m_version; - } - inline QString groupId() const - { - return m_groupId; - } - inline QString artifactId() const - { - return m_artifactId; - } - inline void setClassifier(const QString & classifier) - { - m_classifier = classifier; - } - inline QString classifier() const - { - return m_classifier; - } - inline QString extension() const - { - return m_extension; - } - inline QString artifactPrefix() const - { - return m_groupId + ":" + m_artifactId; - } - bool matchName(const GradleSpecifier & other) const + inline bool valid() const { return m_valid; } + inline QString version() const { return m_version; } + inline QString groupId() const { return m_groupId; } + inline QString artifactId() const { return m_artifactId; } + inline void setClassifier(const QString& classifier) { m_classifier = classifier; } + inline QString classifier() const { return m_classifier; } + inline QString extension() const { return m_extension; } + inline QString artifactPrefix() const { return m_groupId + ":" + m_artifactId; } + bool matchName(const GradleSpecifier& other) const { return other.artifactId() == artifactId() && other.groupId() == groupId() && other.classifier() == classifier(); } - bool operator==(const GradleSpecifier & other) const + bool operator==(const GradleSpecifier& other) const { - if(m_groupId != other.m_groupId) + if (m_groupId != other.m_groupId) return false; - if(m_artifactId != other.m_artifactId) + if (m_artifactId != other.m_artifactId) return false; - if(m_version != other.m_version) + if (m_version != other.m_version) return false; - if(m_classifier != other.m_classifier) + if (m_classifier != other.m_classifier) return false; - if(m_extension != other.m_extension) + if (m_extension != other.m_extension) return false; return true; } -private: + + private: QString m_invalidValue; QString m_groupId; QString m_artifactId; diff --git a/launcher/minecraft/LaunchProfile.cpp b/launcher/minecraft/LaunchProfile.cpp index 9a6cea11..013c78ae 100644 --- a/launcher/minecraft/LaunchProfile.cpp +++ b/launcher/minecraft/LaunchProfile.cpp @@ -55,9 +55,9 @@ void LaunchProfile::clear() m_problemSeverity = ProblemSeverity::None; } -static void applyString(const QString & from, QString & to) +static void applyString(const QString& from, QString& to) { - if(from.isEmpty()) + if (from.isEmpty()) return; to = from; } @@ -94,8 +94,7 @@ void LaunchProfile::applyMinecraftVersionType(const QString& type) void LaunchProfile::applyMinecraftAssets(MojangAssetIndexInfo::Ptr assets) { - if(assets) - { + if (assets) { m_minecraftAssets = assets; } } @@ -109,10 +108,8 @@ void LaunchProfile::applyTweakers(const QStringList& tweakers) { // if the applied tweakers override an existing one, skip it. this effectively moves it later in the sequence QStringList newTweakers; - for(auto & tweaker: m_tweakers) - { - if (tweakers.contains(tweaker)) - { + for (auto& tweaker : m_tweakers) { + if (tweakers.contains(tweaker)) { continue; } newTweakers.append(tweaker); @@ -127,13 +124,11 @@ void LaunchProfile::applyJarMods(const QList<LibraryPtr>& jarMods) this->m_jarMods.append(jarMods); } -static int findLibraryByName(QList<LibraryPtr> *haystack, const GradleSpecifier &needle) +static int findLibraryByName(QList<LibraryPtr>* haystack, const GradleSpecifier& needle) { int retval = -1; - for (int i = 0; i < haystack->size(); ++i) - { - if (haystack->at(i)->rawName().matchName(needle)) - { + for (int i = 0; i < haystack->size(); ++i) { + if (haystack->at(i)->rawName().matchName(needle)) { // only one is allowed. if (retval != -1) return -1; @@ -145,24 +140,21 @@ static int findLibraryByName(QList<LibraryPtr> *haystack, const GradleSpecifier void LaunchProfile::applyMods(const QList<LibraryPtr>& mods) { - QList<LibraryPtr> * list = &m_mods; - for(auto & mod: mods) - { + QList<LibraryPtr>* list = &m_mods; + for (auto& mod : mods) { auto modCopy = Library::limitedCopy(mod); // find the mod by name. const int index = findLibraryByName(list, mod->rawName()); // mod not found? just add it. - if (index < 0) - { + if (index < 0) { list->append(modCopy); return; } auto existingLibrary = list->at(index); // if we are higher it means we should update - if (Version(mod->version()) > Version(existingLibrary->version())) - { + if (Version(mod->version()) > Version(existingLibrary->version())) { list->replace(index, modCopy); } } @@ -173,16 +165,14 @@ void LaunchProfile::applyCompatibleJavaMajors(QList<int>& javaMajor) m_compatibleJavaMajors.append(javaMajor); } -void LaunchProfile::applyLibrary(LibraryPtr library, const RuntimeContext & runtimeContext) +void LaunchProfile::applyLibrary(LibraryPtr library, const RuntimeContext& runtimeContext) { - if(!library->isActive(runtimeContext)) - { + if (!library->isActive(runtimeContext)) { return; } - QList<LibraryPtr> * list = &m_libraries; - if(library->isNative()) - { + QList<LibraryPtr>* list = &m_libraries; + if (library->isNative()) { list = &m_nativeLibraries; } @@ -191,29 +181,25 @@ void LaunchProfile::applyLibrary(LibraryPtr library, const RuntimeContext & runt // find the library by name. const int index = findLibraryByName(list, library->rawName()); // library not found? just add it. - if (index < 0) - { + if (index < 0) { list->append(libraryCopy); return; } auto existingLibrary = list->at(index); // if we are higher it means we should update - if (Version(library->version()) > Version(existingLibrary->version())) - { + if (Version(library->version()) > Version(existingLibrary->version())) { list->replace(index, libraryCopy); } } -void LaunchProfile::applyMavenFile(LibraryPtr mavenFile, const RuntimeContext & runtimeContext) +void LaunchProfile::applyMavenFile(LibraryPtr mavenFile, const RuntimeContext& runtimeContext) { - if(!mavenFile->isActive(runtimeContext)) - { + if (!mavenFile->isActive(runtimeContext)) { return; } - if(mavenFile->isNative()) - { + if (mavenFile->isNative()) { return; } @@ -221,16 +207,14 @@ void LaunchProfile::applyMavenFile(LibraryPtr mavenFile, const RuntimeContext & m_mavenFiles.append(Library::limitedCopy(mavenFile)); } -void LaunchProfile::applyAgent(AgentPtr agent, const RuntimeContext & runtimeContext) +void LaunchProfile::applyAgent(AgentPtr agent, const RuntimeContext& runtimeContext) { auto lib = agent->library(); - if(!lib->isActive(runtimeContext)) - { + if (!lib->isActive(runtimeContext)) { return; } - if(lib->isNative()) - { + if (lib->isNative()) { return; } @@ -244,16 +228,14 @@ const LibraryPtr LaunchProfile::getMainJar() const void LaunchProfile::applyMainJar(LibraryPtr jar) { - if(jar) - { + if (jar) { m_mainJar = jar; } } void LaunchProfile::applyProblemSeverity(ProblemSeverity severity) { - if (m_problemSeverity < severity) - { + if (m_problemSeverity < severity) { m_problemSeverity = severity; } } @@ -279,12 +261,12 @@ QString LaunchProfile::getMainClass() const return m_mainClass; } -const QSet<QString> &LaunchProfile::getTraits() const +const QSet<QString>& LaunchProfile::getTraits() const { return m_traits; } -const QStringList & LaunchProfile::getTweakers() const +const QStringList& LaunchProfile::getTweakers() const { return m_tweakers; } @@ -306,8 +288,7 @@ QString LaunchProfile::getMinecraftVersionType() const std::shared_ptr<MojangAssetIndexInfo> LaunchProfile::getMinecraftAssets() const { - if(!m_minecraftAssets) - { + if (!m_minecraftAssets) { return std::make_shared<MojangAssetIndexInfo>("legacy"); } return m_minecraftAssets; @@ -318,80 +299,69 @@ QString LaunchProfile::getMinecraftArguments() const return m_minecraftArguments; } -const QStringList & LaunchProfile::getAddnJvmArguments() const +const QStringList& LaunchProfile::getAddnJvmArguments() const { return m_addnJvmArguments; } -const QList<LibraryPtr> & LaunchProfile::getJarMods() const +const QList<LibraryPtr>& LaunchProfile::getJarMods() const { return m_jarMods; } -const QList<LibraryPtr> & LaunchProfile::getLibraries() const +const QList<LibraryPtr>& LaunchProfile::getLibraries() const { return m_libraries; } -const QList<LibraryPtr> & LaunchProfile::getNativeLibraries() const +const QList<LibraryPtr>& LaunchProfile::getNativeLibraries() const { return m_nativeLibraries; } -const QList<LibraryPtr> & LaunchProfile::getMavenFiles() const +const QList<LibraryPtr>& LaunchProfile::getMavenFiles() const { return m_mavenFiles; } -const QList<AgentPtr> & LaunchProfile::getAgents() const +const QList<AgentPtr>& LaunchProfile::getAgents() const { return m_agents; } -const QList<int> & LaunchProfile::getCompatibleJavaMajors() const +const QList<int>& LaunchProfile::getCompatibleJavaMajors() const { return m_compatibleJavaMajors; } -void LaunchProfile::getLibraryFiles( - const RuntimeContext & runtimeContext, - QStringList& jars, - QStringList& nativeJars, - const QString& overridePath, - const QString& tempPath -) const +void LaunchProfile::getLibraryFiles(const RuntimeContext& runtimeContext, + QStringList& jars, + QStringList& nativeJars, + const QString& overridePath, + const QString& tempPath) const { QStringList native32, native64; jars.clear(); nativeJars.clear(); - for (auto lib : getLibraries()) - { + for (auto lib : getLibraries()) { lib->getApplicableFiles(runtimeContext, jars, nativeJars, native32, native64, overridePath); } // NOTE: order is important here, add main jar last to the lists - if(m_mainJar) - { + if (m_mainJar) { // FIXME: HACK!! jar modding is weird and unsystematic! - if(m_jarMods.size()) - { + if (m_jarMods.size()) { QDir tempDir(tempPath); jars.append(tempDir.absoluteFilePath("minecraft.jar")); - } - else - { + } else { m_mainJar->getApplicableFiles(runtimeContext, jars, nativeJars, native32, native64, overridePath); } } - for (auto lib : getNativeLibraries()) - { + for (auto lib : getNativeLibraries()) { lib->getApplicableFiles(runtimeContext, jars, nativeJars, native32, native64, overridePath); } - if(runtimeContext.javaArchitecture == "32") - { + if (runtimeContext.javaArchitecture == "32") { nativeJars.append(native32); - } - else if(runtimeContext.javaArchitecture == "64") - { + } else if (runtimeContext.javaArchitecture == "64") { nativeJars.append(native64); } } diff --git a/launcher/minecraft/LaunchProfile.h b/launcher/minecraft/LaunchProfile.h index 49c1217d..797631f3 100644 --- a/launcher/minecraft/LaunchProfile.h +++ b/launcher/minecraft/LaunchProfile.h @@ -34,17 +34,16 @@ */ #pragma once +#include <ProblemProvider.h> #include <QString> -#include "Library.h" #include "Agent.h" -#include <ProblemProvider.h> +#include "Library.h" -class LaunchProfile: public ProblemProvider -{ -public: - virtual ~LaunchProfile() {}; +class LaunchProfile : public ProblemProvider { + public: + virtual ~LaunchProfile(){}; -public: /* application of profile variables from patches */ + public: /* application of profile variables from patches */ void applyMinecraftVersion(const QString& id); void applyMainClass(const QString& mainClass); void applyAppletClass(const QString& appletClass); @@ -52,48 +51,46 @@ public: /* application of profile variables from patches */ void applyAddnJvmArguments(const QStringList& minecraftArguments); void applyMinecraftVersionType(const QString& type); void applyMinecraftAssets(MojangAssetIndexInfo::Ptr assets); - void applyTraits(const QSet<QString> &traits); - void applyTweakers(const QStringList &tweakers); - void applyJarMods(const QList<LibraryPtr> &jarMods); - void applyMods(const QList<LibraryPtr> &jarMods); - void applyLibrary(LibraryPtr library, const RuntimeContext & runtimeContext); - void applyMavenFile(LibraryPtr library, const RuntimeContext & runtimeContext); - void applyAgent(AgentPtr agent, const RuntimeContext & runtimeContext); + void applyTraits(const QSet<QString>& traits); + void applyTweakers(const QStringList& tweakers); + void applyJarMods(const QList<LibraryPtr>& jarMods); + void applyMods(const QList<LibraryPtr>& jarMods); + void applyLibrary(LibraryPtr library, const RuntimeContext& runtimeContext); + void applyMavenFile(LibraryPtr library, const RuntimeContext& runtimeContext); + void applyAgent(AgentPtr agent, const RuntimeContext& runtimeContext); void applyCompatibleJavaMajors(QList<int>& javaMajor); void applyMainJar(LibraryPtr jar); void applyProblemSeverity(ProblemSeverity severity); /// clear the profile void clear(); -public: /* getters for profile variables */ + public: /* getters for profile variables */ QString getMinecraftVersion() const; QString getMainClass() const; QString getAppletClass() const; QString getMinecraftVersionType() const; MojangAssetIndexInfo::Ptr getMinecraftAssets() const; QString getMinecraftArguments() const; - const QStringList & getAddnJvmArguments() const; - const QSet<QString> & getTraits() const; - const QStringList & getTweakers() const; - const QList<LibraryPtr> & getJarMods() const; - const QList<LibraryPtr> & getLibraries() const; - const QList<LibraryPtr> & getNativeLibraries() const; - const QList<LibraryPtr> & getMavenFiles() const; - const QList<AgentPtr> & getAgents() const; - const QList<int> & getCompatibleJavaMajors() const; + const QStringList& getAddnJvmArguments() const; + const QSet<QString>& getTraits() const; + const QStringList& getTweakers() const; + const QList<LibraryPtr>& getJarMods() const; + const QList<LibraryPtr>& getLibraries() const; + const QList<LibraryPtr>& getNativeLibraries() const; + const QList<LibraryPtr>& getMavenFiles() const; + const QList<AgentPtr>& getAgents() const; + const QList<int>& getCompatibleJavaMajors() const; const LibraryPtr getMainJar() const; - void getLibraryFiles( - const RuntimeContext & runtimeContext, - QStringList & jars, - QStringList & nativeJars, - const QString & overridePath, - const QString & tempPath - ) const; - bool hasTrait(const QString & trait) const; + void getLibraryFiles(const RuntimeContext& runtimeContext, + QStringList& jars, + QStringList& nativeJars, + const QString& overridePath, + const QString& tempPath) const; + bool hasTrait(const QString& trait) const; ProblemSeverity getProblemSeverity() const override; const QList<PatchProblem> getProblems() const override; -private: + private: /// the version of Minecraft - jar to use QString m_minecraftVersion; @@ -154,5 +151,4 @@ private: QList<int> m_compatibleJavaMajors; ProblemSeverity m_problemSeverity = ProblemSeverity::None; - }; diff --git a/launcher/minecraft/Library.cpp b/launcher/minecraft/Library.cpp index cb2b5254..53c285d8 100644 --- a/launcher/minecraft/Library.cpp +++ b/launcher/minecraft/Library.cpp @@ -36,106 +36,90 @@ #include "Library.h" #include "MinecraftInstance.h" -#include <net/Download.h> -#include <net/ChecksumValidator.h> -#include <FileSystem.h> #include <BuildConfig.h> +#include <FileSystem.h> +#include <net/ChecksumValidator.h> +#include <net/Download.h> - -void Library::getApplicableFiles(const RuntimeContext & runtimeContext, QStringList& jar, QStringList& native, QStringList& native32, - QStringList& native64, const QString &overridePath) const +void Library::getApplicableFiles(const RuntimeContext& runtimeContext, + QStringList& jar, + QStringList& native, + QStringList& native32, + QStringList& native64, + const QString& overridePath) const { bool local = isLocal(); - auto actualPath = [&](QString relPath) - { + auto actualPath = [&](QString relPath) { QFileInfo out(FS::PathCombine(storagePrefix(), relPath)); - if(local && !overridePath.isEmpty()) - { + if (local && !overridePath.isEmpty()) { QString fileName = out.fileName(); return QFileInfo(FS::PathCombine(overridePath, fileName)).absoluteFilePath(); } return out.absoluteFilePath(); }; QString raw_storage = storageSuffix(runtimeContext); - if(isNative()) - { - if (raw_storage.contains("${arch}")) - { + if (isNative()) { + if (raw_storage.contains("${arch}")) { auto nat32Storage = raw_storage; nat32Storage.replace("${arch}", "32"); auto nat64Storage = raw_storage; nat64Storage.replace("${arch}", "64"); native32 += actualPath(nat32Storage); native64 += actualPath(nat64Storage); - } - else - { + } else { native += actualPath(raw_storage); } - } - else - { + } else { jar += actualPath(raw_storage); } } -QList<NetAction::Ptr> Library::getDownloads( - const RuntimeContext & runtimeContext, - class HttpMetaCache* cache, - QStringList& failedLocalFiles, - const QString & overridePath -) const +QList<NetAction::Ptr> Library::getDownloads(const RuntimeContext& runtimeContext, + class HttpMetaCache* cache, + QStringList& failedLocalFiles, + const QString& overridePath) const { QList<NetAction::Ptr> out; bool stale = isAlwaysStale(); bool local = isLocal(); - auto check_local_file = [&](QString storage) - { + auto check_local_file = [&](QString storage) { QFileInfo fileinfo(storage); QString fileName = fileinfo.fileName(); auto fullPath = FS::PathCombine(overridePath, fileName); QFileInfo localFileInfo(fullPath); - if(!localFileInfo.exists()) - { + if (!localFileInfo.exists()) { failedLocalFiles.append(localFileInfo.filePath()); return false; } return true; }; - auto add_download = [&](QString storage, QString url, QString sha1) - { - if(local) - { + auto add_download = [&](QString storage, QString url, QString sha1) { + if (local) { return check_local_file(storage); } auto entry = cache->resolveEntry("libraries", storage); - if(stale) - { + if (stale) { entry->setStale(true); } if (!entry->isStale()) return true; Net::Download::Options options; - if(stale) - { + if (stale) { options |= Net::Download::Option::AcceptLocalFiles; } // Don't add a time limit for the libraries cache entry validity options |= Net::Download::Option::MakeEternal; - if(sha1.size()) - { + if (sha1.size()) { auto rawSha1 = QByteArray::fromHex(sha1.toLatin1()); auto dl = Net::Download::makeCached(url, entry, options); dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawSha1)); qDebug() << "Checksummed Download for:" << rawName().serialize() << "storage:" << storage << "url:" << url; out.append(dl); - } - else - { + } else { out.append(Net::Download::makeCached(url, entry, options)); qDebug() << "Download for:" << rawName().serialize() << "storage:" << storage << "url:" << url; } @@ -143,121 +127,89 @@ QList<NetAction::Ptr> Library::getDownloads( }; QString raw_storage = storageSuffix(runtimeContext); - if(m_mojangDownloads) - { - if(isNative()) - { + if (m_mojangDownloads) { + if (isNative()) { auto nativeClassifier = getCompatibleNative(runtimeContext); - if(!nativeClassifier.isNull()) - { - if(nativeClassifier.contains("${arch}")) - { + if (!nativeClassifier.isNull()) { + if (nativeClassifier.contains("${arch}")) { auto nat32Classifier = nativeClassifier; nat32Classifier.replace("${arch}", "32"); auto nat64Classifier = nativeClassifier; nat64Classifier.replace("${arch}", "64"); auto nat32info = m_mojangDownloads->getDownloadInfo(nat32Classifier); - if(nat32info) - { + if (nat32info) { auto cooked_storage = raw_storage; cooked_storage.replace("${arch}", "32"); add_download(cooked_storage, nat32info->url, nat32info->sha1); } auto nat64info = m_mojangDownloads->getDownloadInfo(nat64Classifier); - if(nat64info) - { + if (nat64info) { auto cooked_storage = raw_storage; cooked_storage.replace("${arch}", "64"); add_download(cooked_storage, nat64info->url, nat64info->sha1); } - } - else - { + } else { auto info = m_mojangDownloads->getDownloadInfo(nativeClassifier); - if(info) - { + if (info) { add_download(raw_storage, info->url, info->sha1); } } - } - else - { + } else { qDebug() << "Ignoring native library" << m_name.serialize() << "because it has no classifier for current OS"; } - } - else - { - if(m_mojangDownloads->artifact) - { + } else { + if (m_mojangDownloads->artifact) { auto artifact = m_mojangDownloads->artifact; add_download(raw_storage, artifact->url, artifact->sha1); - } - else - { + } else { qDebug() << "Ignoring java library" << m_name.serialize() << "because it has no artifact"; } } - } - else - { - auto raw_dl = [&]() - { - if (!m_absoluteURL.isEmpty()) - { + } else { + auto raw_dl = [&]() { + if (!m_absoluteURL.isEmpty()) { return m_absoluteURL; } - if (m_repositoryURL.isEmpty()) - { + if (m_repositoryURL.isEmpty()) { return BuildConfig.LIBRARY_BASE + raw_storage; } - if(m_repositoryURL.endsWith('/')) - { + if (m_repositoryURL.endsWith('/')) { return m_repositoryURL + raw_storage; - } - else - { + } else { return m_repositoryURL + QChar('/') + raw_storage; } }(); - if (raw_storage.contains("${arch}")) - { + if (raw_storage.contains("${arch}")) { QString cooked_storage = raw_storage; QString cooked_dl = raw_dl; add_download(cooked_storage.replace("${arch}", "32"), cooked_dl.replace("${arch}", "32"), QString()); cooked_storage = raw_storage; cooked_dl = raw_dl; add_download(cooked_storage.replace("${arch}", "64"), cooked_dl.replace("${arch}", "64"), QString()); - } - else - { + } else { add_download(raw_storage, raw_dl, QString()); } } return out; } -bool Library::isActive(const RuntimeContext & runtimeContext) const +bool Library::isActive(const RuntimeContext& runtimeContext) const { bool result = true; - if (m_rules.empty()) - { + if (m_rules.empty()) { result = true; - } - else - { + } else { RuleAction ruleResult = Disallow; - for (auto rule : m_rules) - { + for (auto rule : m_rules) { RuleAction temp = rule->apply(this, runtimeContext); if (temp != Defer) ruleResult = temp; } result = result && (ruleResult == Allow); } - if (isNative()) - { + if (isNative()) { result = result && !getCompatibleNative(runtimeContext).isNull(); } return result; @@ -273,7 +225,8 @@ bool Library::isAlwaysStale() const return m_hint == "always-stale"; } -QString Library::getCompatibleNative(const RuntimeContext & runtimeContext) const { +QString Library::getCompatibleNative(const RuntimeContext& runtimeContext) const +{ // try to match precise classifier "[os]-[arch]" auto entry = m_nativeClassifiers.constFind(runtimeContext.getClassifier()); // try to match imprecise classifier on legacy architectures "[os]" @@ -298,63 +251,53 @@ QString Library::defaultStoragePrefix() QString Library::storagePrefix() const { - if(m_storagePrefix.isEmpty()) - { + if (m_storagePrefix.isEmpty()) { return defaultStoragePrefix(); } return m_storagePrefix; } -QString Library::filename(const RuntimeContext & runtimeContext) const +QString Library::filename(const RuntimeContext& runtimeContext) const { - if(!m_filename.isEmpty()) - { + if (!m_filename.isEmpty()) { return m_filename; } // non-native? use only the gradle specifier - if (!isNative()) - { + if (!isNative()) { return m_name.getFileName(); } // otherwise native, override classifiers. Mojang HACK! GradleSpecifier nativeSpec = m_name; QString nativeClassifier = getCompatibleNative(runtimeContext); - if (!nativeClassifier.isNull()) - { + if (!nativeClassifier.isNull()) { nativeSpec.setClassifier(nativeClassifier); - } - else - { + } else { nativeSpec.setClassifier("INVALID"); } return nativeSpec.getFileName(); } -QString Library::displayName(const RuntimeContext & runtimeContext) const +QString Library::displayName(const RuntimeContext& runtimeContext) const { - if(!m_displayname.isEmpty()) + if (!m_displayname.isEmpty()) return m_displayname; return filename(runtimeContext); } -QString Library::storageSuffix(const RuntimeContext & runtimeContext) const +QString Library::storageSuffix(const RuntimeContext& runtimeContext) const { // non-native? use only the gradle specifier - if (!isNative()) - { + if (!isNative()) { return m_name.toPath(m_filename); } // otherwise native, override classifiers. Mojang HACK! GradleSpecifier nativeSpec = m_name; QString nativeClassifier = getCompatibleNative(runtimeContext); - if (!nativeClassifier.isNull()) - { + if (!nativeClassifier.isNull()) { nativeSpec.setClassifier(nativeClassifier); - } - else - { + } else { nativeSpec.setClassifier("INVALID"); } return nativeSpec.toPath(m_filename); diff --git a/launcher/minecraft/Library.h b/launcher/minecraft/Library.h index 26dbf962..a24c1121 100644 --- a/launcher/minecraft/Library.h +++ b/launcher/minecraft/Library.h @@ -34,20 +34,19 @@ */ #pragma once -#include <QString> #include <net/NetAction.h> -#include <QPair> +#include <QDir> #include <QList> +#include <QMap> +#include <QPair> #include <QString> #include <QStringList> -#include <QMap> -#include <QDir> #include <QUrl> #include <memory> -#include "Rule.h" #include "GradleSpecifier.h" #include "MojangDownloadInfo.h" +#include "Rule.h" #include "RuntimeContext.h" class Library; @@ -55,19 +54,14 @@ class MinecraftInstance; typedef std::shared_ptr<Library> LibraryPtr; -class Library -{ +class Library { friend class OneSixVersionFormat; friend class MojangVersionFormat; friend class LibraryTest; -public: - Library() - { - } - Library(const QString &name) - { - m_name = name; - } + + public: + Library() {} + Library(const QString& name) { m_name = name; } /// limited copy without some data. TODO: why? static LibraryPtr limitedCopy(LibraryPtr base) { @@ -85,98 +79,60 @@ public: return newlib; } -public: /* methods */ + public: /* methods */ /// Returns the raw name field - const GradleSpecifier & rawName() const - { - return m_name; - } + const GradleSpecifier& rawName() const { return m_name; } - void setRawName(const GradleSpecifier & spec) - { - m_name = spec; - } + void setRawName(const GradleSpecifier& spec) { m_name = spec; } - void setClassifier(const QString & spec) - { - m_name.setClassifier(spec); - } + void setClassifier(const QString& spec) { m_name.setClassifier(spec); } /// returns the full group and artifact prefix - QString artifactPrefix() const - { - return m_name.artifactPrefix(); - } + QString artifactPrefix() const { return m_name.artifactPrefix(); } /// get the artifact ID - QString artifactId() const - { - return m_name.artifactId(); - } + QString artifactId() const { return m_name.artifactId(); } /// get the artifact version - QString version() const - { - return m_name.version(); - } + QString version() const { return m_name.version(); } /// Returns true if the library is native - bool isNative() const - { - return m_nativeClassifiers.size() != 0; - } + bool isNative() const { return m_nativeClassifiers.size() != 0; } void setStoragePrefix(QString prefix = QString()); /// Set the url base for downloads - void setRepositoryURL(const QString &base_url) - { - m_repositoryURL = base_url; - } + void setRepositoryURL(const QString& base_url) { m_repositoryURL = base_url; } - void getApplicableFiles(const RuntimeContext & runtimeContext, QStringList & jar, QStringList & native, - QStringList & native32, QStringList & native64, const QString & overridePath) const; + void getApplicableFiles(const RuntimeContext& runtimeContext, + QStringList& jar, + QStringList& native, + QStringList& native32, + QStringList& native64, + const QString& overridePath) const; - void setAbsoluteUrl(const QString &absolute_url) - { - m_absoluteURL = absolute_url; - } + void setAbsoluteUrl(const QString& absolute_url) { m_absoluteURL = absolute_url; } - void setFilename(const QString &filename) - { - m_filename = filename; - } + void setFilename(const QString& filename) { m_filename = filename; } /// Get the file name of the library - QString filename(const RuntimeContext & runtimeContext) const; + QString filename(const RuntimeContext& runtimeContext) const; // DEPRECATED: set a display name, used by jar mods only - void setDisplayName(const QString & displayName) - { - m_displayname = displayName; - } + void setDisplayName(const QString& displayName) { m_displayname = displayName; } /// Get the file name of the library - QString displayName(const RuntimeContext & runtimeContext) const; + QString displayName(const RuntimeContext& runtimeContext) const; - void setMojangDownloadInfo(MojangLibraryDownloadInfo::Ptr info) - { - m_mojangDownloads = info; - } + void setMojangDownloadInfo(MojangLibraryDownloadInfo::Ptr info) { m_mojangDownloads = info; } - void setHint(const QString &hint) - { - m_hint = hint; - } + void setHint(const QString& hint) { m_hint = hint; } /// Set the load rules - void setRules(QList<std::shared_ptr<Rule>> rules) - { - m_rules = rules; - } + void setRules(QList<std::shared_ptr<Rule>> rules) { m_rules = rules; } /// Returns true if the library should be loaded (or extracted, in case of natives) - bool isActive(const RuntimeContext & runtimeContext) const; + bool isActive(const RuntimeContext& runtimeContext) const; /// Returns true if the library is contained in an instance and false if it is shared bool isLocal() const; @@ -188,12 +144,14 @@ public: /* methods */ bool isForge() const; // Get a list of downloads for this library - QList<NetAction::Ptr> getDownloads(const RuntimeContext & runtimeContext, class HttpMetaCache * cache, - QStringList & failedLocalFiles, const QString & overridePath) const; + QList<NetAction::Ptr> getDownloads(const RuntimeContext& runtimeContext, + class HttpMetaCache* cache, + QStringList& failedLocalFiles, + const QString& overridePath) const; - QString getCompatibleNative(const RuntimeContext & runtimeContext) const; + QString getCompatibleNative(const RuntimeContext& runtimeContext) const; -private: /* methods */ + private: /* methods */ /// the default storage prefix used by Prism Launcher static QString defaultStoragePrefix(); @@ -201,14 +159,11 @@ private: /* methods */ QString storagePrefix() const; /// Get the relative file path where the library should be saved - QString storageSuffix(const RuntimeContext & runtimeContext) const; + QString storageSuffix(const RuntimeContext& runtimeContext) const; - QString hint() const - { - return m_hint; - } + QString hint() const { return m_hint; } -protected: /* data */ + protected: /* data */ /// the basic gradle dependency specifier. GradleSpecifier m_name; @@ -253,4 +208,3 @@ protected: /* data */ /// MOJANG: container with Mojang style download info MojangLibraryDownloadInfo::Ptr m_mojangDownloads; }; - diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index 07ed04f9..305bff67 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -37,32 +37,32 @@ */ #include "MinecraftInstance.h" +#include "Application.h" #include "BuildConfig.h" #include "minecraft/launch/CreateGameFolders.h" #include "minecraft/launch/ExtractNatives.h" #include "minecraft/launch/PrintInstanceInfo.h" #include "settings/Setting.h" #include "settings/SettingsObject.h" -#include "Application.h" -#include "pathmatcher/RegexpMatcher.h" -#include "pathmatcher/MultiMatcher.h" #include "FileSystem.h" -#include "java/JavaVersion.h" #include "MMCTime.h" +#include "java/JavaVersion.h" +#include "pathmatcher/MultiMatcher.h" +#include "pathmatcher/RegexpMatcher.h" #include "launch/LaunchTask.h" +#include "launch/steps/CheckJava.h" #include "launch/steps/LookupServerAddress.h" #include "launch/steps/PostLaunchCommand.h" -#include "launch/steps/Update.h" #include "launch/steps/PreLaunchCommand.h" -#include "launch/steps/TextPrint.h" -#include "launch/steps/CheckJava.h" #include "launch/steps/QuitAfterGameStop.h" +#include "launch/steps/TextPrint.h" +#include "launch/steps/Update.h" +#include "minecraft/launch/ClaimAccount.h" #include "minecraft/launch/LauncherPartLaunch.h" #include "minecraft/launch/ModMinecraftJar.h" -#include "minecraft/launch/ClaimAccount.h" #include "minecraft/launch/ReconstructAssets.h" #include "minecraft/launch/ScanModFolders.h" #include "minecraft/launch/VerifyJavaInstall.h" @@ -81,10 +81,10 @@ #include "WorldList.h" -#include "PackProfile.h" #include "AssetsUtils.h" -#include "MinecraftUpdate.h" #include "MinecraftLoadAndCheck.h" +#include "MinecraftUpdate.h" +#include "PackProfile.h" #include "minecraft/gameoptions/GameOptions.h" #include "minecraft/update/FoldersTask.h" @@ -96,14 +96,10 @@ // all of this because keeping things compatible with deprecated old settings // if either of the settings {a, b} is true, this also resolves to true -class OrSetting : public Setting -{ +class OrSetting : public Setting { Q_OBJECT -public: - OrSetting(QString id, std::shared_ptr<Setting> a, std::shared_ptr<Setting> b) - :Setting({id}, false), m_a(a), m_b(b) - { - } + public: + OrSetting(QString id, std::shared_ptr<Setting> a, std::shared_ptr<Setting> b) : Setting({ id }, false), m_a(a), m_b(b) {} virtual QVariant get() const { bool a = m_a->get().toBool(); @@ -112,12 +108,13 @@ public: } virtual void reset() {} virtual void set(QVariant value) {} -private: + + private: std::shared_ptr<Setting> m_a; std::shared_ptr<Setting> m_b; }; -MinecraftInstance::MinecraftInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir) +MinecraftInstance::MinecraftInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString& rootDir) : BaseInstance(globalSettings, settings, rootDir) { m_components.reset(new PackProfile(this)); @@ -222,14 +219,12 @@ std::shared_ptr<PackProfile> MinecraftInstance::getPackProfile() const QSet<QString> MinecraftInstance::traits() const { auto components = getPackProfile(); - if (!components) - { - return {"version-incomplete"}; + if (!components) { + return { "version-incomplete" }; } auto profile = components->getProfile(); - if (!profile) - { - return {"version-incomplete"}; + if (!profile) { + return { "version-incomplete" }; } return profile->getTraits(); } @@ -264,7 +259,7 @@ QString MinecraftInstance::getLocalLibraryPath() const bool MinecraftInstance::supportsDemo() const { - Version instance_ver { getPackProfile()->getComponentVersion("net.minecraft") }; + Version instance_ver{ getPackProfile()->getComponentVersion("net.minecraft") }; // Demo mode was introduced in 1.3.1: https://minecraft.fandom.com/wiki/Demo_mode#History // FIXME: Due to Version constraints atm, this can't handle well non-release versions return instance_ver >= Version("1.3.1"); @@ -375,21 +370,18 @@ QStringList MinecraftInstance::extraArguments() if (!version) return list; auto jarMods = getJarMods(); - if (!jarMods.isEmpty()) - { - list.append({"-Dfml.ignoreInvalidMinecraftCertificates=true", - "-Dfml.ignorePatchDiscrepancies=true"}); + if (!jarMods.isEmpty()) { + list.append({ "-Dfml.ignoreInvalidMinecraftCertificates=true", "-Dfml.ignorePatchDiscrepancies=true" }); } auto addn = m_components->getProfile()->getAddnJvmArguments(); if (!addn.isEmpty()) { list.append(addn); } auto agents = m_components->getProfile()->getAgents(); - for (auto agent : agents) - { + for (auto agent : agents) { QStringList jar, temp1, temp2, temp3; agent->library()->getApplicableFiles(runtimeContext(), jar, temp1, temp2, temp3, getLocalLibraryPath()); - list.append("-javaagent:"+jar[0]+(agent->argument().isEmpty() ? "" : "="+agent->argument())); + list.append("-javaagent:" + jar[0] + (agent->argument().isEmpty() ? "" : "=" + agent->argument())); } { @@ -416,38 +408,33 @@ QStringList MinecraftInstance::javaArguments() // HACK: fix issues on macOS with 1.13 snapshots // NOTE: Oracle Java option. if there are alternate jvm implementations, this would be the place to customize this for them #ifdef Q_OS_MAC - if(traits_.contains("FirstThreadOnMacOS")) - { + if (traits_.contains("FirstThreadOnMacOS")) { args << QString("-XstartOnFirstThread"); } #endif // HACK: Stupid hack for Intel drivers. See: https://mojang.atlassian.net/browse/MCL-767 #ifdef Q_OS_WIN32 - args << QString("-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_" - "minecraft.exe.heapdump"); + args << QString( + "-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_" + "minecraft.exe.heapdump"); #endif int min = settings()->get("MinMemAlloc").toInt(); int max = settings()->get("MaxMemAlloc").toInt(); - if(min < max) - { + if (min < max) { args << QString("-Xms%1m").arg(min); args << QString("-Xmx%1m").arg(max); - } - else - { + } else { args << QString("-Xms%1m").arg(max); args << QString("-Xmx%1m").arg(min); } // No PermGen in newer java. JavaVersion javaVersion = getJavaVersion(); - if(javaVersion.requiresPermGen()) - { + if (javaVersion.requiresPermGen()) { auto permgen = settings()->get("PermGen").toInt(); - if (permgen != 64) - { + if (permgen != 64) { args << QString("-XX:PermSize=%1m").arg(permgen); } } @@ -487,8 +474,7 @@ QProcessEnvironment MinecraftInstance::createEnvironment() // export some infos auto variables = getVariables(); - for (auto it = variables.begin(); it != variables.end(); ++it) - { + for (auto it = variables.begin(); it != variables.end(); ++it) { env.insert(it.key(), it.value()); } return env; @@ -500,15 +486,12 @@ QProcessEnvironment MinecraftInstance::createLaunchEnvironment() QProcessEnvironment env = createEnvironment(); #ifdef Q_OS_LINUX - if (settings()->get("EnableMangoHud").toBool() && APPLICATION->capabilities() & Application::SupportsMangoHud) - { - + if (settings()->get("EnableMangoHud").toBool() && APPLICATION->capabilities() & Application::SupportsMangoHud) { auto preloadList = env.value("LD_PRELOAD").split(QLatin1String(":")); auto libPaths = env.value("LD_LIBRARY_PATH").split(QLatin1String(":")); auto mangoHudLibString = MangoHud::getLibraryString(); - if (!mangoHudLibString.isEmpty()) - { + if (!mangoHudLibString.isEmpty()) { QFileInfo mangoHudLib(mangoHudLibString); // dlsym variant is only needed for OpenGL and not included in the vulkan layer @@ -521,8 +504,7 @@ QProcessEnvironment MinecraftInstance::createLaunchEnvironment() env.insert("MANGOHUD", "1"); } - if (settings()->get("UseDiscreteGpu").toBool()) - { + if (settings()->get("UseDiscreteGpu").toBool()) { // Open Source Drivers env.insert("DRI_PRIME", "1"); // Proprietary Nvidia Drivers @@ -543,14 +525,12 @@ static QString replaceTokensIn(QString text, QMap<QString, QString> with) QStringList list; QRegularExpressionMatchIterator i = token_regexp.globalMatch(text); int lastCapturedEnd = 0; - while (i.hasNext()) - { + while (i.hasNext()) { QRegularExpressionMatch match = i.next(); result.append(text.mid(lastCapturedEnd, match.capturedStart())); QString key = match.captured(1); auto iter = with.find(key); - if (iter != with.end()) - { + if (iter != with.end()) { result.append(*iter); } lastCapturedEnd = match.capturedEnd(); @@ -559,25 +539,22 @@ static QString replaceTokensIn(QString text, QMap<QString, QString> with) return result; } -QStringList MinecraftInstance::processMinecraftArgs( - AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) const +QStringList MinecraftInstance::processMinecraftArgs(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) const { auto profile = m_components->getProfile(); QString args_pattern = profile->getMinecraftArguments(); - for (auto tweaker : profile->getTweakers()) - { + for (auto tweaker : profile->getTweakers()) { args_pattern += " --tweakClass " + tweaker; } - if (serverToJoin && !serverToJoin->address.isEmpty()) - { + if (serverToJoin && !serverToJoin->address.isEmpty()) { args_pattern += " --server " + serverToJoin->address; args_pattern += " --port " + QString::number(serverToJoin->port); } QMap<QString, QString> token_mapping; // yggdrasil! - if(session) { + if (session) { // token_mapping["auth_username"] = session->username; token_mapping["auth_session"] = session->session; token_mapping["auth_access_token"] = session->access_token; @@ -585,7 +562,7 @@ QStringList MinecraftInstance::processMinecraftArgs( token_mapping["auth_uuid"] = session->uuid; token_mapping["user_properties"] = session->serializeUserProperties(); token_mapping["user_type"] = session->user_type; - if(session->demo) { + if (session->demo) { args_pattern += " --demo"; } } @@ -609,8 +586,7 @@ QStringList MinecraftInstance::processMinecraftArgs( #else QStringList parts = args_pattern.split(' ', QString::SkipEmptyParts); #endif - for (int i = 0; i < parts.length(); i++) - { + for (int i = 0; i < parts.length(); i++) { parts[i] = replaceTokensIn(parts[i], token_mapping); } return parts; @@ -623,32 +599,26 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftS if (!m_components) return QString(); auto profile = m_components->getProfile(); - if(!profile) + if (!profile) return QString(); auto mainClass = getMainClass(); - if (!mainClass.isEmpty()) - { + if (!mainClass.isEmpty()) { launchScript += "mainClass " + mainClass + "\n"; } auto appletClass = profile->getAppletClass(); - if (!appletClass.isEmpty()) - { + if (!appletClass.isEmpty()) { launchScript += "appletClass " + appletClass + "\n"; } - if (serverToJoin && !serverToJoin->address.isEmpty()) - { + if (serverToJoin && !serverToJoin->address.isEmpty()) { launchScript += "serverAddress " + serverToJoin->address + "\n"; launchScript += "serverPort " + QString::number(serverToJoin->port) + "\n"; } // generic minecraft params - for (auto param : processMinecraftArgs( - session, - nullptr /* When using a launch script, the server parameters are handled by it*/ - )) - { + for (auto param : processMinecraftArgs(session, nullptr /* When using a launch script, the server parameters are handled by it*/ + )) { launchScript += "param " + param + "\n"; } @@ -658,22 +628,19 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftS if (settings()->get("LaunchMaximized").toBool()) windowParams = "max"; else - windowParams = QString("%1x%2") - .arg(settings()->get("MinecraftWinWidth").toInt()) - .arg(settings()->get("MinecraftWinHeight").toInt()); + windowParams = + QString("%1x%2").arg(settings()->get("MinecraftWinWidth").toInt()).arg(settings()->get("MinecraftWinHeight").toInt()); launchScript += "windowTitle " + windowTitle() + "\n"; launchScript += "windowParams " + windowParams + "\n"; } // legacy auth - if(session) - { + if (session) { launchScript += "userName " + session->player_name + "\n"; launchScript += "sessionId " + session->session + "\n"; } - for (auto trait : profile->getTraits()) - { + for (auto trait : profile->getTraits()) { launchScript += "traits " + trait + "\n"; } @@ -686,17 +653,17 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftS QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) { QStringList out; - out << "Main Class:" << " " + getMainClass() << ""; - out << "Native path:" << " " + getNativePath() << ""; + out << "Main Class:" + << " " + getMainClass() << ""; + out << "Native path:" + << " " + getNativePath() << ""; auto profile = m_components->getProfile(); auto alltraits = traits(); - if(alltraits.size()) - { + if (alltraits.size()) { out << "Traits:"; - for (auto trait : alltraits) - { + for (auto trait : alltraits) { out << "traits " + trait; } out << ""; @@ -705,8 +672,7 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr auto settings = this->settings(); bool nativeOpenAL = settings->get("UseNativeOpenAL").toBool(); bool nativeGLFW = settings->get("UseNativeGLFW").toBool(); - if (nativeOpenAL || nativeGLFW) - { + if (nativeOpenAL || nativeGLFW) { if (nativeOpenAL) out << "Using system OpenAL."; if (nativeGLFW) @@ -719,34 +685,27 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr out << "Libraries:"; QStringList jars, nativeJars; profile->getLibraryFiles(runtimeContext(), jars, nativeJars, getLocalLibraryPath(), binRoot()); - auto printLibFile = [&](const QString & path) - { + auto printLibFile = [&](const QString& path) { QFileInfo info(path); - if(info.exists()) - { + if (info.exists()) { out << " " + path; - } - else - { + } else { out << " " + path + " (missing)"; } }; - for(auto file: jars) - { + for (auto file : jars) { printLibFile(file); } out << ""; out << "Native libraries:"; - for(auto file: nativeJars) - { + for (auto file : nativeJars) { printLibFile(file); } out << ""; } - auto printModList = [&](const QString & label, ModFolderModel & model) { - if(model.size()) - { + auto printModList = [&](const QString& label, ModFolderModel& model) { + if (model.size()) { out << QString("%1:").arg(label); auto modList = model.allMods(); std::sort(modList.begin(), modList.end(), [](auto a, auto b) { @@ -754,21 +713,17 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr auto bName = b->fileinfo().completeBaseName(); return aName.localeAwareCompare(bName) < 0; }); - for(auto mod: modList) - { - if(mod->type() == ResourceType::FOLDER) - { + for (auto mod : modList) { + if (mod->type() == ResourceType::FOLDER) { out << u8" [🖿] " + mod->fileinfo().completeBaseName() + " (folder)"; continue; } - if(mod->enabled()) { + if (mod->enabled()) { out << u8" [✔] " + mod->fileinfo().completeBaseName(); - } - else { + } else { out << u8" [✘] " + mod->fileinfo().completeBaseName() + " (disabled)"; } - } out << ""; } @@ -777,20 +732,15 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr printModList("Mods", *(loaderModList().get())); printModList("Core Mods", *(coreModList().get())); - auto & jarMods = profile->getJarMods(); - if(jarMods.size()) - { + auto& jarMods = profile->getJarMods(); + if (jarMods.size()) { out << "Jar Mods:"; - for(auto & jarmod: jarMods) - { + for (auto& jarmod : jarMods) { auto displayname = jarmod->displayName(runtimeContext()); auto realname = jarmod->filename(runtimeContext()); - if(displayname != realname) - { + if (displayname != realname) { out << " " + displayname + " (" + realname + ")"; - } - else - { + } else { out << " " + realname; } } @@ -803,12 +753,9 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr out << ""; QString windowParams; - if (settings->get("LaunchMaximized").toBool()) - { + if (settings->get("LaunchMaximized").toBool()) { out << "Window size: max (if available)"; - } - else - { + } else { auto width = settings->get("MinecraftWinWidth").toInt(); auto height = settings->get("MinecraftWinHeight").toInt(); out << "Window size: " + QString::number(width) + " x " + QString::number(height); @@ -821,27 +768,23 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr QMap<QString, QString> MinecraftInstance::createCensorFilterFromSession(AuthSessionPtr session) { - if(!session) - { + if (!session) { return QMap<QString, QString>(); } - auto & sessionRef = *session.get(); + auto& sessionRef = *session.get(); QMap<QString, QString> filter; - auto addToFilter = [&filter](QString key, QString value) - { - if(key.trimmed().size()) - { + auto addToFilter = [&filter](QString key, QString value) { + if (key.trimmed().size()) { filter[key] = value; } }; - if (sessionRef.session != "-") - { + if (sessionRef.session != "-") { addToFilter(sessionRef.session, tr("<SESSION ID>")); } if (sessionRef.access_token != "0") { addToFilter(sessionRef.access_token, tr("<ACCESS TOKEN>")); } - if(sessionRef.client_token.size()) { + if (sessionRef.client_token.size()) { addToFilter(sessionRef.client_token, tr("<CLIENT TOKEN>")); } addToFilter(sessionRef.uuid, tr("<PROFILE ID>")); @@ -849,31 +792,28 @@ QMap<QString, QString> MinecraftInstance::createCensorFilterFromSession(AuthSess return filter; } -MessageLevel::Enum MinecraftInstance::guessLevel(const QString &line, MessageLevel::Enum level) +MessageLevel::Enum MinecraftInstance::guessLevel(const QString& line, MessageLevel::Enum level) { QRegularExpression re("\\[(?<timestamp>[0-9:]+)\\] \\[[^/]+/(?<level>[^\\]]+)\\]"); auto match = re.match(line); - if(match.hasMatch()) - { + if (match.hasMatch()) { // New style logs from log4j QString timestamp = match.captured("timestamp"); QString levelStr = match.captured("level"); - if(levelStr == "INFO") + if (levelStr == "INFO") level = MessageLevel::Message; - if(levelStr == "WARN") + if (levelStr == "WARN") level = MessageLevel::Warning; - if(levelStr == "ERROR") + if (levelStr == "ERROR") level = MessageLevel::Error; - if(levelStr == "FATAL") + if (levelStr == "FATAL") level = MessageLevel::Fatal; - if(levelStr == "TRACE" || levelStr == "DEBUG") + if (levelStr == "TRACE" || levelStr == "DEBUG") level = MessageLevel::Debug; - } - else - { + } else { // Old style forge logs - if (line.contains("[INFO]") || line.contains("[CONFIG]") || line.contains("[FINE]") || - line.contains("[FINER]") || line.contains("[FINEST]")) + if (line.contains("[INFO]") || line.contains("[CONFIG]") || line.contains("[FINE]") || line.contains("[FINER]") || + line.contains("[FINEST]")) level = MessageLevel::Message; if (line.contains("[SEVERE]") || line.contains("[STDERR]")) level = MessageLevel::Error; @@ -884,14 +824,12 @@ MessageLevel::Enum MinecraftInstance::guessLevel(const QString &line, MessageLev } if (line.contains("overwriting existing")) return MessageLevel::Fatal; - //NOTE: this diverges from the real regexp. no unicode, the first section is + instead of * + // NOTE: this diverges from the real regexp. no unicode, the first section is + instead of * static const QString javaSymbol = "([a-zA-Z_$][a-zA-Z\\d_$]*\\.)+[a-zA-Z_$][a-zA-Z\\d_$]*"; - if (line.contains("Exception in thread") - || line.contains(QRegularExpression("\\s+at " + javaSymbol)) - || line.contains(QRegularExpression("Caused by: " + javaSymbol)) - || line.contains(QRegularExpression("([a-zA-Z_$][a-zA-Z\\d_$]*\\.)+[a-zA-Z_$]?[a-zA-Z\\d_$]*(Exception|Error|Throwable)")) - || line.contains(QRegularExpression("... \\d+ more$")) - ) + if (line.contains("Exception in thread") || line.contains(QRegularExpression("\\s+at " + javaSymbol)) || + line.contains(QRegularExpression("Caused by: " + javaSymbol)) || + line.contains(QRegularExpression("([a-zA-Z_$][a-zA-Z\\d_$]*\\.)+[a-zA-Z_$]?[a-zA-Z\\d_$]*(Exception|Error|Throwable)")) || + line.contains(QRegularExpression("... \\d+ more$"))) return MessageLevel::Error; return level; } @@ -914,14 +852,12 @@ QString MinecraftInstance::getLogFileRoot() QString MinecraftInstance::getStatusbarDescription() { QStringList traits; - if (hasVersionBroken()) - { + if (hasVersionBroken()) { traits.append(tr("broken")); } QString mcVersion = m_components->getComponentVersion("net.minecraft"); - if (mcVersion.isEmpty()) - { + if (mcVersion.isEmpty()) { // Load component info if needed m_components->reload(Net::Mode::Offline); mcVersion = m_components->getComponentVersion("net.minecraft"); @@ -929,8 +865,7 @@ QString MinecraftInstance::getStatusbarDescription() QString description; description.append(tr("Minecraft %1").arg(mcVersion)); - if(m_settings->get("ShowGameTime").toBool()) - { + if (m_settings->get("ShowGameTime").toBool()) { if (lastTimePlayed() > 0) { QDateTime lastLaunchTime = QDateTime::fromMSecsSinceEpoch(lastLaunch()); description.append(tr(", last played on %1 for %2") @@ -942,8 +877,7 @@ QString MinecraftInstance::getStatusbarDescription() description.append(tr(", total played for %1").arg(Time::prettifyDuration(totalTimePlayed()))); } } - if(hasCrashed()) - { + if (hasCrashed()) { description.append(tr(", has crashed.")); } return description; @@ -952,14 +886,11 @@ QString MinecraftInstance::getStatusbarDescription() Task::Ptr MinecraftInstance::createUpdateTask(Net::Mode mode) { updateRuntimeContext(); - switch (mode) - { - case Net::Mode::Offline: - { + switch (mode) { + case Net::Mode::Offline: { return Task::Ptr(new MinecraftLoadAndCheck(this)); } - case Net::Mode::Online: - { + case Net::Mode::Online: { return Task::Ptr(new MinecraftUpdate(this)); } } @@ -990,14 +921,12 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt process->appendStep(makeShared<CreateGameFolders>(pptr)); } - if (!serverToJoin && settings()->get("JoinServerOnLaunch").toBool()) - { + if (!serverToJoin && settings()->get("JoinServerOnLaunch").toBool()) { QString fullAddress = settings()->get("JoinServerOnLaunchAddress").toString(); serverToJoin.reset(new MinecraftServerTarget(MinecraftServerTarget::parse(fullAddress))); } - if(serverToJoin && serverToJoin->port == 25565) - { + if (serverToJoin && serverToJoin->port == 25565) { // Resolve server address to join on launch auto step = makeShared<LookupServerAddress>(pptr); step->setLookupAddress(serverToJoin->address); @@ -1006,23 +935,19 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt } // run pre-launch command if that's needed - if(getPreLaunchCommand().size()) - { + if (getPreLaunchCommand().size()) { auto step = makeShared<PreLaunchCommand>(pptr); step->setWorkingDirectory(gameRoot()); process->appendStep(step); } // if we aren't in offline mode,. - if(session->status != AuthSession::PlayableOffline) - { - if(!session->demo) { + if (session->status != AuthSession::PlayableOffline) { + if (!session->demo) { process->appendStep(makeShared<ClaimAccount>(pptr, session)); } process->appendStep(makeShared<Update>(pptr, Net::Mode::Online)); - } - else - { + } else { process->appendStep(makeShared<Update>(pptr, Net::Mode::Offline)); } @@ -1066,18 +991,15 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt } // run post-exit command if that's needed - if(getPostExitCommand().size()) - { + if (getPostExitCommand().size()) { auto step = makeShared<PostLaunchCommand>(pptr); step->setWorkingDirectory(gameRoot()); process->appendStep(step); } - if (session) - { + if (session) { process->setCensorFilter(createCensorFilterFromSession(session)); } - if(m_settings->get("QuitAfterGameStop").toBool()) - { + if (m_settings->get("QuitAfterGameStop").toBool()) { process->appendStep(makeShared<QuitAfterGameStop>(pptr)); } m_launchProcess = process; @@ -1119,8 +1041,7 @@ std::shared_ptr<ModFolderModel> MinecraftInstance::nilModList() std::shared_ptr<ResourcePackFolderModel> MinecraftInstance::resourcePackList() { - if (!m_resource_pack_list) - { + if (!m_resource_pack_list) { m_resource_pack_list.reset(new ResourcePackFolderModel(resourcePacksDir(), this)); } return m_resource_pack_list; @@ -1128,8 +1049,7 @@ std::shared_ptr<ResourcePackFolderModel> MinecraftInstance::resourcePackList() std::shared_ptr<TexturePackFolderModel> MinecraftInstance::texturePackList() { - if (!m_texture_pack_list) - { + if (!m_texture_pack_list) { m_texture_pack_list.reset(new TexturePackFolderModel(texturePacksDir(), this)); } return m_texture_pack_list; @@ -1137,8 +1057,7 @@ std::shared_ptr<TexturePackFolderModel> MinecraftInstance::texturePackList() std::shared_ptr<ShaderPackFolderModel> MinecraftInstance::shaderPackList() { - if (!m_shader_pack_list) - { + if (!m_shader_pack_list) { m_shader_pack_list.reset(new ShaderPackFolderModel(shaderPacksDir(), this)); } return m_shader_pack_list; @@ -1146,8 +1065,7 @@ std::shared_ptr<ShaderPackFolderModel> MinecraftInstance::shaderPackList() std::shared_ptr<WorldList> MinecraftInstance::worldList() { - if (!m_world_list) - { + if (!m_world_list) { m_world_list.reset(new WorldList(worldDir(), this)); } return m_world_list; @@ -1155,8 +1073,7 @@ std::shared_ptr<WorldList> MinecraftInstance::worldList() std::shared_ptr<GameOptions> MinecraftInstance::gameOptionsModel() { - if (!m_game_options) - { + if (!m_game_options) { m_game_options.reset(new GameOptions(FS::PathCombine(gameRoot(), "options.txt"))); } return m_game_options; @@ -1166,8 +1083,7 @@ QList<Mod*> MinecraftInstance::getJarMods() const { auto profile = m_components->getProfile(); QList<Mod*> mods; - for (auto jarmod : profile->getJarMods()) - { + for (auto jarmod : profile->getJarMods()) { QStringList jar, temp1, temp2, temp3; jarmod->getApplicableFiles(runtimeContext(), jar, temp1, temp2, temp3, jarmodsPath().absolutePath()); // QString filePath = jarmodsPath().absoluteFilePath(jarmod->filename(currentSystem)); @@ -1176,5 +1092,4 @@ QList<Mod*> MinecraftInstance::getJarMods() const return mods; } - #include "MinecraftInstance.moc" diff --git a/launcher/minecraft/MinecraftInstance.h b/launcher/minecraft/MinecraftInstance.h index 4afcf04b..c331cc6f 100644 --- a/launcher/minecraft/MinecraftInstance.h +++ b/launcher/minecraft/MinecraftInstance.h @@ -35,12 +35,12 @@ */ #pragma once -#include "BaseInstance.h" #include <java/JavaVersion.h> -#include "minecraft/mod/Mod.h" -#include <QProcess> #include <QDir> +#include <QProcess> +#include "BaseInstance.h" #include "minecraft/launch/MinecraftServerTarget.h" +#include "minecraft/mod/Mod.h" class ModFolderModel; class ResourceFolderModel; @@ -52,12 +52,11 @@ class GameOptions; class LaunchStep; class PackProfile; -class MinecraftInstance: public BaseInstance -{ +class MinecraftInstance : public BaseInstance { Q_OBJECT -public: - MinecraftInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir); - virtual ~MinecraftInstance() {}; + public: + MinecraftInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString& rootDir); + virtual ~MinecraftInstance(){}; virtual void saveNow() override; void loadSpecificSettings() override; @@ -67,15 +66,9 @@ public: // FIXME: remove QSet<QString> traits() const override; - bool canEdit() const override - { - return true; - } + bool canEdit() const override { return true; } - bool canExport() const override - { - return true; - } + bool canExport() const override { return true; } ////// Directories and files ////// QString jarModsDir() const; @@ -143,7 +136,7 @@ public: QProcessEnvironment createLaunchEnvironment() override; /// guess log level from a line of minecraft log - MessageLevel::Enum guessLevel(const QString &line, MessageLevel::Enum level) override; + MessageLevel::Enum guessLevel(const QString& line, MessageLevel::Enum level) override; IPathMatcher::Ptr getLogFileMatcher() override; @@ -163,10 +156,10 @@ public: virtual JavaVersion getJavaVersion(); -protected: + protected: QMap<QString, QString> createCensorFilterFromSession(AuthSessionPtr session); -protected: // data + protected: // data std::shared_ptr<PackProfile> m_components; mutable std::shared_ptr<ModFolderModel> m_loader_mod_list; mutable std::shared_ptr<ModFolderModel> m_core_mod_list; diff --git a/launcher/minecraft/MinecraftLoadAndCheck.cpp b/launcher/minecraft/MinecraftLoadAndCheck.cpp index 2a369879..818e90cf 100644 --- a/launcher/minecraft/MinecraftLoadAndCheck.cpp +++ b/launcher/minecraft/MinecraftLoadAndCheck.cpp @@ -2,9 +2,7 @@ #include "MinecraftInstance.h" #include "PackProfile.h" -MinecraftLoadAndCheck::MinecraftLoadAndCheck(MinecraftInstance *inst, QObject *parent) : Task(parent), m_inst(inst) -{ -} +MinecraftLoadAndCheck::MinecraftLoadAndCheck(MinecraftInstance* inst, QObject* parent) : Task(parent), m_inst(inst) {} void MinecraftLoadAndCheck::executeTask() { @@ -13,14 +11,13 @@ void MinecraftLoadAndCheck::executeTask() components->reload(Net::Mode::Offline); m_task = components->getCurrentTask(); - if(!m_task) - { + if (!m_task) { emitSucceeded(); return; } connect(m_task.get(), &Task::succeeded, this, &MinecraftLoadAndCheck::subtaskSucceeded); connect(m_task.get(), &Task::failed, this, &MinecraftLoadAndCheck::subtaskFailed); - connect(m_task.get(), &Task::aborted, this, [this]{ subtaskFailed(tr("Aborted")); }); + connect(m_task.get(), &Task::aborted, this, [this] { subtaskFailed(tr("Aborted")); }); connect(m_task.get(), &Task::progress, this, &MinecraftLoadAndCheck::progress); connect(m_task.get(), &Task::stepProgress, this, &MinecraftLoadAndCheck::propagateStepProgress); connect(m_task.get(), &Task::status, this, &MinecraftLoadAndCheck::setStatus); @@ -28,8 +25,7 @@ void MinecraftLoadAndCheck::executeTask() void MinecraftLoadAndCheck::subtaskSucceeded() { - if(isFinished()) - { + if (isFinished()) { qCritical() << "MinecraftUpdate: Subtask" << sender() << "succeeded, but work was already done!"; return; } @@ -38,8 +34,7 @@ void MinecraftLoadAndCheck::subtaskSucceeded() void MinecraftLoadAndCheck::subtaskFailed(QString error) { - if(isFinished()) - { + if (isFinished()) { qCritical() << "MinecraftUpdate: Subtask" << sender() << "failed, but work was already done!"; return; } diff --git a/launcher/minecraft/MinecraftLoadAndCheck.h b/launcher/minecraft/MinecraftLoadAndCheck.h index d9af3ace..9556c1d6 100644 --- a/launcher/minecraft/MinecraftLoadAndCheck.h +++ b/launcher/minecraft/MinecraftLoadAndCheck.h @@ -15,34 +15,32 @@ #pragma once -#include <QObject> #include <QList> +#include <QObject> #include <QUrl> -#include "tasks/Task.h" #include <quazip/quazip.h> +#include "tasks/Task.h" #include "QObjectPtr.h" class MinecraftVersion; class MinecraftInstance; -class MinecraftLoadAndCheck : public Task -{ +class MinecraftLoadAndCheck : public Task { Q_OBJECT -public: - explicit MinecraftLoadAndCheck(MinecraftInstance *inst, QObject *parent = 0); - virtual ~MinecraftLoadAndCheck() {}; + public: + explicit MinecraftLoadAndCheck(MinecraftInstance* inst, QObject* parent = 0); + virtual ~MinecraftLoadAndCheck(){}; void executeTask() override; -private slots: + private slots: void subtaskSucceeded(); void subtaskFailed(QString error); -private: - MinecraftInstance *m_inst = nullptr; + private: + MinecraftInstance* m_inst = nullptr; Task::Ptr m_task; QString m_preFailure; QString m_fail_reason; }; - diff --git a/launcher/minecraft/MinecraftUpdate.cpp b/launcher/minecraft/MinecraftUpdate.cpp index 236d0224..c009317a 100644 --- a/launcher/minecraft/MinecraftUpdate.cpp +++ b/launcher/minecraft/MinecraftUpdate.cpp @@ -16,27 +16,25 @@ #include "MinecraftUpdate.h" #include "MinecraftInstance.h" +#include <QDataStream> #include <QFile> #include <QFileInfo> #include <QTextStream> -#include <QDataStream> +#include <FileSystem.h> #include "BaseInstance.h" -#include "minecraft/PackProfile.h" #include "minecraft/Library.h" -#include <FileSystem.h> +#include "minecraft/PackProfile.h" +#include "update/AssetUpdateTask.h" +#include "update/FMLLibrariesTask.h" #include "update/FoldersTask.h" #include "update/LibrariesTask.h" -#include "update/FMLLibrariesTask.h" -#include "update/AssetUpdateTask.h" #include <meta/Index.h> #include <meta/Version.h> -MinecraftUpdate::MinecraftUpdate(MinecraftInstance *inst, QObject *parent) : Task(parent), m_inst(inst) -{ -} +MinecraftUpdate::MinecraftUpdate(MinecraftInstance* inst, QObject* parent) : Task(parent), m_inst(inst) {} void MinecraftUpdate::executeTask() { @@ -51,8 +49,7 @@ void MinecraftUpdate::executeTask() auto components = m_inst->getPackProfile(); components->reload(Net::Mode::Online); auto task = components->getCurrentTask(); - if(task) - { + if (task) { m_tasks.append(task); } } @@ -72,8 +69,7 @@ void MinecraftUpdate::executeTask() m_tasks.append(makeShared<AssetUpdateTask>(m_inst)); } - if(!m_preFailure.isEmpty()) - { + if (!m_preFailure.isEmpty()) { emitFailed(m_preFailure); return; } @@ -82,19 +78,16 @@ void MinecraftUpdate::executeTask() void MinecraftUpdate::next() { - if(m_abort) - { + if (m_abort) { emitFailed(tr("Aborted by user.")); return; } - if(m_failed_out_of_order) - { + if (m_failed_out_of_order) { emitFailed(m_fail_reason); return; } - m_currentTask ++; - if(m_currentTask > 0) - { + m_currentTask++; + if (m_currentTask > 0) { auto task = m_tasks[m_currentTask - 1]; disconnect(task.get(), &Task::succeeded, this, &MinecraftUpdate::subtaskSucceeded); disconnect(task.get(), &Task::failed, this, &MinecraftUpdate::subtaskFailed); @@ -104,15 +97,13 @@ void MinecraftUpdate::next() disconnect(task.get(), &Task::status, this, &MinecraftUpdate::setStatus); disconnect(task.get(), &Task::details, this, &MinecraftUpdate::setDetails); } - if(m_currentTask == m_tasks.size()) - { + if (m_currentTask == m_tasks.size()) { emitSucceeded(); return; } auto task = m_tasks[m_currentTask]; // if the task is already finished by the time we look at it, skip it - if(task->isFinished()) - { + if (task->isFinished()) { qCritical() << "MinecraftUpdate: Skipping finished subtask" << m_currentTask << ":" << task.get(); next(); } @@ -124,23 +115,20 @@ void MinecraftUpdate::next() connect(task.get(), &Task::status, this, &MinecraftUpdate::setStatus); connect(task.get(), &Task::details, this, &MinecraftUpdate::setDetails); // if the task is already running, do not start it again - if(!task->isRunning()) - { + if (!task->isRunning()) { task->start(); } } void MinecraftUpdate::subtaskSucceeded() { - if(isFinished()) - { + if (isFinished()) { qCritical() << "MinecraftUpdate: Subtask" << sender() << "succeeded, but work was already done!"; return; } auto senderTask = QObject::sender(); auto currentTask = m_tasks[m_currentTask].get(); - if(senderTask != currentTask) - { + if (senderTask != currentTask) { qDebug() << "MinecraftUpdate: Subtask" << sender() << "succeeded out of order."; return; } @@ -149,15 +137,13 @@ void MinecraftUpdate::subtaskSucceeded() void MinecraftUpdate::subtaskFailed(QString error) { - if(isFinished()) - { + if (isFinished()) { qCritical() << "MinecraftUpdate: Subtask" << sender() << "failed, but work was already done!"; return; } auto senderTask = QObject::sender(); auto currentTask = m_tasks[m_currentTask].get(); - if(senderTask != currentTask) - { + if (senderTask != currentTask) { qDebug() << "MinecraftUpdate: Subtask" << sender() << "failed out of order."; m_failed_out_of_order = true; m_fail_reason = error; @@ -166,15 +152,12 @@ void MinecraftUpdate::subtaskFailed(QString error) emitFailed(error); } - bool MinecraftUpdate::abort() { - if(!m_abort) - { + if (!m_abort) { m_abort = true; auto task = m_tasks[m_currentTask]; - if(task->canAbort()) - { + if (task->canAbort()) { return task->abort(); } } diff --git a/launcher/minecraft/MinecraftUpdate.h b/launcher/minecraft/MinecraftUpdate.h index c9cf8624..9c41d7f5 100644 --- a/launcher/minecraft/MinecraftUpdate.h +++ b/launcher/minecraft/MinecraftUpdate.h @@ -15,41 +15,39 @@ #pragma once -#include <QObject> #include <QList> +#include <QObject> #include <QUrl> +#include <quazip/quazip.h> +#include "minecraft/VersionFilterData.h" #include "net/NetJob.h" #include "tasks/Task.h" -#include "minecraft/VersionFilterData.h" -#include <quazip/quazip.h> class MinecraftVersion; class MinecraftInstance; // FIXME: This looks very similar to a SequentialTask. Maybe we can reduce code duplications? :^) -class MinecraftUpdate : public Task -{ +class MinecraftUpdate : public Task { Q_OBJECT -public: - explicit MinecraftUpdate(MinecraftInstance *inst, QObject *parent = 0); - virtual ~MinecraftUpdate() {}; + public: + explicit MinecraftUpdate(MinecraftInstance* inst, QObject* parent = 0); + virtual ~MinecraftUpdate(){}; void executeTask() override; bool canAbort() const override; -private -slots: + private slots: bool abort() override; void subtaskSucceeded(); void subtaskFailed(QString error); -private: + private: void next(); -private: - MinecraftInstance *m_inst = nullptr; + private: + MinecraftInstance* m_inst = nullptr; QList<Task::Ptr> m_tasks; QString m_preFailure; int m_currentTask = -1; diff --git a/launcher/minecraft/MojangDownloadInfo.h b/launcher/minecraft/MojangDownloadInfo.h index 13e27e15..b98a0168 100644 --- a/launcher/minecraft/MojangDownloadInfo.h +++ b/launcher/minecraft/MojangDownloadInfo.h @@ -1,10 +1,9 @@ #pragma once -#include <QString> #include <QMap> +#include <QString> #include <memory> -struct MojangDownloadInfo -{ +struct MojangDownloadInfo { // types typedef std::shared_ptr<MojangDownloadInfo> Ptr; @@ -19,24 +18,20 @@ struct MojangDownloadInfo int size; }; - - -struct MojangLibraryDownloadInfo -{ - MojangLibraryDownloadInfo(MojangDownloadInfo::Ptr artifact): artifact(artifact) {}; - MojangLibraryDownloadInfo() {}; +struct MojangLibraryDownloadInfo { + MojangLibraryDownloadInfo(MojangDownloadInfo::Ptr artifact) : artifact(artifact){}; + MojangLibraryDownloadInfo(){}; // types typedef std::shared_ptr<MojangLibraryDownloadInfo> Ptr; // methods - MojangDownloadInfo *getDownloadInfo(QString classifier) + MojangDownloadInfo* getDownloadInfo(QString classifier) { - if (classifier.isNull()) - { + if (classifier.isNull()) { return artifact.get(); } - + return classifiers[classifier].get(); } @@ -45,17 +40,12 @@ struct MojangLibraryDownloadInfo QMap<QString, MojangDownloadInfo::Ptr> classifiers; }; - - -struct MojangAssetIndexInfo : public MojangDownloadInfo -{ +struct MojangAssetIndexInfo : public MojangDownloadInfo { // types typedef std::shared_ptr<MojangAssetIndexInfo> Ptr; // methods - MojangAssetIndexInfo() - { - } + MojangAssetIndexInfo() {} MojangAssetIndexInfo(QString id) { @@ -63,13 +53,11 @@ struct MojangAssetIndexInfo : public MojangDownloadInfo // HACK: ignore assets from other version files than Minecraft // workaround for stupid assets issue caused by amazon: // https://www.theregister.co.uk/2017/02/28/aws_is_awol_as_s3_goes_haywire/ - if(id == "legacy") - { + if (id == "legacy") { url = "https://piston-meta.mojang.com/mc/assets/legacy/c0fd82e8ce9fbc93119e40d96d5a4e62cfa3f729/legacy.json"; } // HACK - else - { + else { url = "https://s3.amazonaws.com/Minecraft.Download/indexes/" + id + ".json"; } known = false; diff --git a/launcher/minecraft/MojangVersionFormat.cpp b/launcher/minecraft/MojangVersionFormat.cpp index 623dcdfa..d7393cf4 100644 --- a/launcher/minecraft/MojangVersionFormat.cpp +++ b/launcher/minecraft/MojangVersionFormat.cpp @@ -34,34 +34,32 @@ */ #include "MojangVersionFormat.h" -#include "OneSixVersionFormat.h" #include "MojangDownloadInfo.h" +#include "OneSixVersionFormat.h" #include "Json.h" using namespace Json; -#include "ParseUtils.h" #include <BuildConfig.h> +#include "ParseUtils.h" static const int CURRENT_MINIMUM_LAUNCHER_VERSION = 18; -static MojangAssetIndexInfo::Ptr assetIndexFromJson (const QJsonObject &obj); -static MojangDownloadInfo::Ptr downloadInfoFromJson (const QJsonObject &obj); -static MojangLibraryDownloadInfo::Ptr libDownloadInfoFromJson (const QJsonObject &libObj); -static QJsonObject assetIndexToJson (MojangAssetIndexInfo::Ptr assetidxinfo); -static QJsonObject libDownloadInfoToJson (MojangLibraryDownloadInfo::Ptr libinfo); -static QJsonObject downloadInfoToJson (MojangDownloadInfo::Ptr info); +static MojangAssetIndexInfo::Ptr assetIndexFromJson(const QJsonObject& obj); +static MojangDownloadInfo::Ptr downloadInfoFromJson(const QJsonObject& obj); +static MojangLibraryDownloadInfo::Ptr libDownloadInfoFromJson(const QJsonObject& libObj); +static QJsonObject assetIndexToJson(MojangAssetIndexInfo::Ptr assetidxinfo); +static QJsonObject libDownloadInfoToJson(MojangLibraryDownloadInfo::Ptr libinfo); +static QJsonObject downloadInfoToJson(MojangDownloadInfo::Ptr info); -namespace Bits -{ -static void readString(const QJsonObject &root, const QString &key, QString &variable) +namespace Bits { +static void readString(const QJsonObject& root, const QString& key, QString& variable) { - if (root.contains(key)) - { + if (root.contains(key)) { variable = requireString(root.value(key)); } } -static void readDownloadInfo(MojangDownloadInfo::Ptr out, const QJsonObject &obj) +static void readDownloadInfo(MojangDownloadInfo::Ptr out, const QJsonObject& obj) { // optional, not used readString(obj, "path", out->path); @@ -71,22 +69,22 @@ static void readDownloadInfo(MojangDownloadInfo::Ptr out, const QJsonObject &obj out->size = requireInteger(obj, "size"); } -static void readAssetIndex(MojangAssetIndexInfo::Ptr out, const QJsonObject &obj) +static void readAssetIndex(MojangAssetIndexInfo::Ptr out, const QJsonObject& obj) { out->totalSize = requireInteger(obj, "totalSize"); out->id = requireString(obj, "id"); // out->known = true; } -} +} // namespace Bits -MojangDownloadInfo::Ptr downloadInfoFromJson(const QJsonObject &obj) +MojangDownloadInfo::Ptr downloadInfoFromJson(const QJsonObject& obj) { auto out = std::make_shared<MojangDownloadInfo>(); Bits::readDownloadInfo(out, obj); return out; } -MojangAssetIndexInfo::Ptr assetIndexFromJson(const QJsonObject &obj) +MojangAssetIndexInfo::Ptr assetIndexFromJson(const QJsonObject& obj) { auto out = std::make_shared<MojangAssetIndexInfo>(); Bits::readDownloadInfo(out, obj); @@ -97,8 +95,7 @@ MojangAssetIndexInfo::Ptr assetIndexFromJson(const QJsonObject &obj) QJsonObject downloadInfoToJson(MojangDownloadInfo::Ptr info) { QJsonObject out; - if(!info->path.isNull()) - { + if (!info->path.isNull()) { out.insert("path", info->path); } out.insert("sha1", info->sha1); @@ -107,19 +104,16 @@ QJsonObject downloadInfoToJson(MojangDownloadInfo::Ptr info) return out; } -MojangLibraryDownloadInfo::Ptr libDownloadInfoFromJson(const QJsonObject &libObj) +MojangLibraryDownloadInfo::Ptr libDownloadInfoFromJson(const QJsonObject& libObj) { auto out = std::make_shared<MojangLibraryDownloadInfo>(); auto dlObj = requireObject(libObj.value("downloads")); - if(dlObj.contains("artifact")) - { + if (dlObj.contains("artifact")) { out->artifact = downloadInfoFromJson(requireObject(dlObj, "artifact")); } - if(dlObj.contains("classifiers")) - { + if (dlObj.contains("classifiers")) { auto classifiersObj = requireObject(dlObj, "classifiers"); - for(auto iter = classifiersObj.begin(); iter != classifiersObj.end(); iter++) - { + for (auto iter = classifiersObj.begin(); iter != classifiersObj.end(); iter++) { auto classifier = iter.key(); auto classifierObj = requireObject(iter.value()); out->classifiers[classifier] = downloadInfoFromJson(classifierObj); @@ -131,15 +125,12 @@ MojangLibraryDownloadInfo::Ptr libDownloadInfoFromJson(const QJsonObject &libObj QJsonObject libDownloadInfoToJson(MojangLibraryDownloadInfo::Ptr libinfo) { QJsonObject out; - if(libinfo->artifact) - { + if (libinfo->artifact) { out.insert("artifact", downloadInfoToJson(libinfo->artifact)); } - if(!libinfo->classifiers.isEmpty()) - { + if (!libinfo->classifiers.isEmpty()) { QJsonObject classifiersOut; - for(auto iter = libinfo->classifiers.begin(); iter != libinfo->classifiers.end(); iter++) - { + for (auto iter = libinfo->classifiers.begin(); iter != libinfo->classifiers.end(); iter++) { classifiersOut.insert(iter.key(), downloadInfoToJson(iter.value())); } out.insert("classifiers", classifiersOut); @@ -150,8 +141,7 @@ QJsonObject libDownloadInfoToJson(MojangLibraryDownloadInfo::Ptr libinfo) QJsonObject assetIndexToJson(MojangAssetIndexInfo::Ptr info) { QJsonObject out; - if(!info->path.isNull()) - { + if (!info->path.isNull()) { out.insert("path", info->path); } out.insert("sha1", info->sha1); @@ -162,76 +152,57 @@ QJsonObject assetIndexToJson(MojangAssetIndexInfo::Ptr info) return out; } -void MojangVersionFormat::readVersionProperties(const QJsonObject &in, VersionFile *out) +void MojangVersionFormat::readVersionProperties(const QJsonObject& in, VersionFile* out) { Bits::readString(in, "id", out->minecraftVersion); Bits::readString(in, "mainClass", out->mainClass); Bits::readString(in, "minecraftArguments", out->minecraftArguments); - if(out->minecraftArguments.isEmpty()) - { + if (out->minecraftArguments.isEmpty()) { QString processArguments; Bits::readString(in, "processArguments", processArguments); QString toCompare = processArguments.toLower(); - if (toCompare == "legacy") - { + if (toCompare == "legacy") { out->minecraftArguments = " ${auth_player_name} ${auth_session}"; - } - else if (toCompare == "username_session") - { + } else if (toCompare == "username_session") { out->minecraftArguments = "--username ${auth_player_name} --session ${auth_session}"; - } - else if (toCompare == "username_session_version") - { + } else if (toCompare == "username_session_version") { out->minecraftArguments = "--username ${auth_player_name} --session ${auth_session} --version ${profile_name}"; - } - else if (!toCompare.isEmpty()) - { + } else if (!toCompare.isEmpty()) { out->addProblem(ProblemSeverity::Error, QObject::tr("processArguments is set to unknown value '%1'").arg(processArguments)); } } Bits::readString(in, "type", out->type); Bits::readString(in, "assets", out->assets); - if(in.contains("assetIndex")) - { + if (in.contains("assetIndex")) { out->mojangAssetIndex = assetIndexFromJson(requireObject(in, "assetIndex")); - } - else if (!out->assets.isNull()) - { + } else if (!out->assets.isNull()) { out->mojangAssetIndex = std::make_shared<MojangAssetIndexInfo>(out->assets); } out->releaseTime = timeFromS3Time(in.value("releaseTime").toString("")); out->updateTime = timeFromS3Time(in.value("time").toString("")); - if (in.contains("minimumLauncherVersion")) - { + if (in.contains("minimumLauncherVersion")) { out->minimumLauncherVersion = requireInteger(in.value("minimumLauncherVersion")); - if (out->minimumLauncherVersion > CURRENT_MINIMUM_LAUNCHER_VERSION) - { - out->addProblem( - ProblemSeverity::Warning, - QObject::tr("The 'minimumLauncherVersion' value of this version (%1) is higher than supported by %3 (%2). It might not work properly!") - .arg(out->minimumLauncherVersion) - .arg(CURRENT_MINIMUM_LAUNCHER_VERSION) - .arg(BuildConfig.LAUNCHER_DISPLAYNAME) - ); + if (out->minimumLauncherVersion > CURRENT_MINIMUM_LAUNCHER_VERSION) { + out->addProblem(ProblemSeverity::Warning, QObject::tr("The 'minimumLauncherVersion' value of this version (%1) is higher than " + "supported by %3 (%2). It might not work properly!") + .arg(out->minimumLauncherVersion) + .arg(CURRENT_MINIMUM_LAUNCHER_VERSION) + .arg(BuildConfig.LAUNCHER_DISPLAYNAME)); } } - if (in.contains("compatibleJavaMajors")) - { - for (auto compatible : requireArray(in.value("compatibleJavaMajors"))) - { + if (in.contains("compatibleJavaMajors")) { + for (auto compatible : requireArray(in.value("compatibleJavaMajors"))) { out->compatibleJavaMajors.append(requireInteger(compatible)); } } - if(in.contains("downloads")) - { + if (in.contains("downloads")) { auto downloadsObj = requireObject(in, "downloads"); - for(auto iter = downloadsObj.begin(); iter != downloadsObj.end(); iter++) - { + for (auto iter = downloadsObj.begin(); iter != downloadsObj.end(); iter++) { auto classifier = iter.key(); auto classifierObj = requireObject(iter.value()); out->mojangDownloads[classifier] = downloadInfoFromJson(classifierObj); @@ -239,15 +210,13 @@ void MojangVersionFormat::readVersionProperties(const QJsonObject &in, VersionFi } } -VersionFilePtr MojangVersionFormat::versionFileFromJson(const QJsonDocument &doc, const QString &filename) +VersionFilePtr MojangVersionFormat::versionFileFromJson(const QJsonDocument& doc, const QString& filename) { VersionFilePtr out(new VersionFile()); - if (doc.isEmpty() || doc.isNull()) - { + if (doc.isEmpty() || doc.isNull()) { throw JSONValidationError(filename + " is empty or null"); } - if (!doc.isObject()) - { + if (!doc.isObject()) { throw JSONValidationError(filename + " is not an object"); } @@ -260,11 +229,8 @@ VersionFilePtr MojangVersionFormat::versionFileFromJson(const QJsonDocument &doc out->version = out->minecraftVersion; // out->filename = filename; - - if (root.contains("libraries")) - { - for (auto libVal : requireArray(root.value("libraries"))) - { + if (root.contains("libraries")) { + for (auto libVal : requireArray(root.value("libraries"))) { auto libObj = requireObject(libVal); auto lib = MojangVersionFormat::libraryFromJson(*out, libObj, filename); @@ -280,52 +246,42 @@ void MojangVersionFormat::writeVersionProperties(const VersionFile* in, QJsonObj writeString(out, "mainClass", in->mainClass); writeString(out, "minecraftArguments", in->minecraftArguments); writeString(out, "type", in->type); - if(!in->releaseTime.isNull()) - { + if (!in->releaseTime.isNull()) { writeString(out, "releaseTime", timeToS3Time(in->releaseTime)); } - if(!in->updateTime.isNull()) - { + if (!in->updateTime.isNull()) { writeString(out, "time", timeToS3Time(in->updateTime)); } - if(in->minimumLauncherVersion != -1) - { + if (in->minimumLauncherVersion != -1) { out.insert("minimumLauncherVersion", in->minimumLauncherVersion); } writeString(out, "assets", in->assets); - if(in->mojangAssetIndex && in->mojangAssetIndex->known) - { + if (in->mojangAssetIndex && in->mojangAssetIndex->known) { out.insert("assetIndex", assetIndexToJson(in->mojangAssetIndex)); } - if(!in->mojangDownloads.isEmpty()) - { + if (!in->mojangDownloads.isEmpty()) { QJsonObject downloadsOut; - for(auto iter = in->mojangDownloads.begin(); iter != in->mojangDownloads.end(); iter++) - { + for (auto iter = in->mojangDownloads.begin(); iter != in->mojangDownloads.end(); iter++) { downloadsOut.insert(iter.key(), downloadInfoToJson(iter.value())); } out.insert("downloads", downloadsOut); } - if(!in->compatibleJavaMajors.isEmpty()) - { + if (!in->compatibleJavaMajors.isEmpty()) { QJsonArray compatibleJavaMajorsOut; - for(auto compatibleJavaMajor : in->compatibleJavaMajors) - { + for (auto compatibleJavaMajor : in->compatibleJavaMajors) { compatibleJavaMajorsOut.append(compatibleJavaMajor); } out.insert("compatibleJavaMajors", compatibleJavaMajorsOut); } } -QJsonDocument MojangVersionFormat::versionFileToJson(const VersionFilePtr &patch) +QJsonDocument MojangVersionFormat::versionFileToJson(const VersionFilePtr& patch) { QJsonObject root; writeVersionProperties(patch.get(), root); - if (!patch->libraries.isEmpty()) - { + if (!patch->libraries.isEmpty()) { QJsonArray array; - for (auto value: patch->libraries) - { + for (auto value : patch->libraries) { array.append(MojangVersionFormat::libraryToJson(value.get())); } root.insert("libraries", array); @@ -339,96 +295,80 @@ QJsonDocument MojangVersionFormat::versionFileToJson(const VersionFilePtr &patch } } -LibraryPtr MojangVersionFormat::libraryFromJson(ProblemContainer & problems, const QJsonObject &libObj, const QString &filename) +LibraryPtr MojangVersionFormat::libraryFromJson(ProblemContainer& problems, const QJsonObject& libObj, const QString& filename) { LibraryPtr out(new Library()); - if (!libObj.contains("name")) - { + if (!libObj.contains("name")) { throw JSONValidationError(filename + "contains a library that doesn't have a 'name' field"); } auto rawName = libObj.value("name").toString(); out->m_name = rawName; - if(!out->m_name.valid()) { + if (!out->m_name.valid()) { problems.addProblem(ProblemSeverity::Error, QObject::tr("Library %1 name is broken and cannot be processed.").arg(rawName)); } Bits::readString(libObj, "url", out->m_repositoryURL); - if (libObj.contains("extract")) - { + if (libObj.contains("extract")) { out->m_hasExcludes = true; auto extractObj = requireObject(libObj.value("extract")); - for (auto excludeVal : requireArray(extractObj.value("exclude"))) - { + for (auto excludeVal : requireArray(extractObj.value("exclude"))) { out->m_extractExcludes.append(requireString(excludeVal)); } } - if (libObj.contains("natives")) - { + if (libObj.contains("natives")) { QJsonObject nativesObj = requireObject(libObj.value("natives")); - for (auto it = nativesObj.begin(); it != nativesObj.end(); ++it) - { - if (!it.value().isString()) - { + for (auto it = nativesObj.begin(); it != nativesObj.end(); ++it) { + if (!it.value().isString()) { qWarning() << filename << "contains an invalid native (skipping)"; } // FIXME: Skip unknown platforms out->m_nativeClassifiers[it.key()] = it.value().toString(); } } - if (libObj.contains("rules")) - { + if (libObj.contains("rules")) { out->applyRules = true; out->m_rules = rulesFromJsonV4(libObj); } - if (libObj.contains("downloads")) - { + if (libObj.contains("downloads")) { out->m_mojangDownloads = libDownloadInfoFromJson(libObj); } return out; } -QJsonObject MojangVersionFormat::libraryToJson(Library *library) +QJsonObject MojangVersionFormat::libraryToJson(Library* library) { QJsonObject libRoot; libRoot.insert("name", library->m_name.serialize()); - if (!library->m_repositoryURL.isEmpty()) - { + if (!library->m_repositoryURL.isEmpty()) { libRoot.insert("url", library->m_repositoryURL); } - if (library->isNative()) - { + if (library->isNative()) { QJsonObject nativeList; auto iter = library->m_nativeClassifiers.begin(); - while (iter != library->m_nativeClassifiers.end()) - { + while (iter != library->m_nativeClassifiers.end()) { nativeList.insert(iter.key(), iter.value()); iter++; } libRoot.insert("natives", nativeList); - if (!library->m_extractExcludes.isEmpty()) - { + if (!library->m_extractExcludes.isEmpty()) { QJsonArray excludes; QJsonObject extract; - for (auto exclude : library->m_extractExcludes) - { + for (auto exclude : library->m_extractExcludes) { excludes.append(exclude); } extract.insert("exclude", excludes); libRoot.insert("extract", extract); } } - if (!library->m_rules.isEmpty()) - { + if (!library->m_rules.isEmpty()) { QJsonArray allRules; - for (auto &rule : library->m_rules) - { + for (auto& rule : library->m_rules) { QJsonObject ruleObj = rule->toJson(); allRules.append(ruleObj); } libRoot.insert("rules", allRules); } - if(library->m_mojangDownloads) - { + if (library->m_mojangDownloads) { auto downloadsObj = libDownloadInfoToJson(library->m_mojangDownloads); libRoot.insert("downloads", downloadsObj); } diff --git a/launcher/minecraft/MojangVersionFormat.h b/launcher/minecraft/MojangVersionFormat.h index d38f0a2f..88d8a206 100644 --- a/launcher/minecraft/MojangVersionFormat.h +++ b/launcher/minecraft/MojangVersionFormat.h @@ -1,24 +1,25 @@ #pragma once -#include <minecraft/VersionFile.h> +#include <ProblemProvider.h> #include <minecraft/Library.h> +#include <minecraft/VersionFile.h> #include <QJsonDocument> -#include <ProblemProvider.h> -class MojangVersionFormat -{ -friend class OneSixVersionFormat; -protected: +class MojangVersionFormat { + friend class OneSixVersionFormat; + + protected: // does not include libraries static void readVersionProperties(const QJsonObject& in, VersionFile* out); // does not include libraries static void writeVersionProperties(const VersionFile* in, QJsonObject& out); -public: + + public: // version files / profile patches - static VersionFilePtr versionFileFromJson(const QJsonDocument &doc, const QString &filename); - static QJsonDocument versionFileToJson(const VersionFilePtr &patch); + static VersionFilePtr versionFileFromJson(const QJsonDocument& doc, const QString& filename); + static QJsonDocument versionFileToJson(const VersionFilePtr& patch); // libraries - static LibraryPtr libraryFromJson(ProblemContainer & problems, const QJsonObject &libObj, const QString &filename); - static QJsonObject libraryToJson(Library *library); + static LibraryPtr libraryFromJson(ProblemContainer& problems, const QJsonObject& libObj, const QString& filename); + static QJsonObject libraryToJson(Library* library); }; diff --git a/launcher/minecraft/OneSixVersionFormat.cpp b/launcher/minecraft/OneSixVersionFormat.cpp index b586198b..22c2c997 100644 --- a/launcher/minecraft/OneSixVersionFormat.cpp +++ b/launcher/minecraft/OneSixVersionFormat.cpp @@ -35,23 +35,22 @@ #include "OneSixVersionFormat.h" #include <Json.h> +#include <minecraft/MojangVersionFormat.h> #include "minecraft/Agent.h" #include "minecraft/ParseUtils.h" -#include <minecraft/MojangVersionFormat.h> #include <QRegularExpression> using namespace Json; -static void readString(const QJsonObject &root, const QString &key, QString &variable) +static void readString(const QJsonObject& root, const QString& key, QString& variable) { - if (root.contains(key)) - { + if (root.contains(key)) { variable = requireString(root.value(key)); } } -LibraryPtr OneSixVersionFormat::libraryFromJson(ProblemContainer & problems, const QJsonObject &libObj, const QString &filename) +LibraryPtr OneSixVersionFormat::libraryFromJson(ProblemContainer& problems, const QJsonObject& libObj, const QString& filename) { LibraryPtr out = MojangVersionFormat::libraryFromJson(problems, libObj, filename); readString(libObj, "MMC-hint", out->m_hint); @@ -62,7 +61,7 @@ LibraryPtr OneSixVersionFormat::libraryFromJson(ProblemContainer & problems, con return out; } -QJsonObject OneSixVersionFormat::libraryToJson(Library *library) +QJsonObject OneSixVersionFormat::libraryToJson(Library* library) { QJsonObject libRoot = MojangVersionFormat::libraryToJson(library); if (!library->m_absoluteURL.isEmpty()) @@ -76,37 +75,30 @@ QJsonObject OneSixVersionFormat::libraryToJson(Library *library) return libRoot; } -VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc, const QString &filename, const bool requireOrder) +VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument& doc, const QString& filename, const bool requireOrder) { VersionFilePtr out(new VersionFile()); - if (doc.isEmpty() || doc.isNull()) - { + if (doc.isEmpty() || doc.isNull()) { throw JSONValidationError(filename + " is empty or null"); } - if (!doc.isObject()) - { + if (!doc.isObject()) { throw JSONValidationError(filename + " is not an object"); } QJsonObject root = doc.object(); Meta::MetadataVersion formatVersion = Meta::parseFormatVersion(root, false); - switch(formatVersion) - { + switch (formatVersion) { case Meta::MetadataVersion::InitialRelease: break; case Meta::MetadataVersion::Invalid: throw JSONValidationError(filename + " does not contain a recognizable version of the metadata format."); } - if (requireOrder) - { - if (root.contains("order")) - { + if (requireOrder) { + if (root.contains("order")) { out->order = requireInteger(root.value("order")); - } - else - { + } else { // FIXME: evaluate if we don't want to throw exceptions here instead qCritical() << filename << "doesn't contain an order field"; } @@ -114,22 +106,18 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc out->name = root.value("name").toString(); - if(root.contains("uid")) - { + if (root.contains("uid")) { out->uid = root.value("uid").toString(); - } - else - { + } else { out->uid = root.value("fileId").toString(); } - const QRegularExpression valid_uid_regex{ QRegularExpression::anchoredPattern(QStringLiteral(R"([a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]+)*)")) }; + const QRegularExpression valid_uid_regex{ QRegularExpression::anchoredPattern( + QStringLiteral(R"([a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]+)*)")) }; if (!valid_uid_regex.match(out->uid).hasMatch()) { qCritical() << "The component's 'uid' contains illegal characters! UID:" << out->uid; - out->addProblem( - ProblemSeverity::Error, - QObject::tr("The component's 'uid' contains illegal characters! This can cause security issues.") - ); + out->addProblem(ProblemSeverity::Error, + QObject::tr("The component's 'uid' contains illegal characters! This can cause security issues.")); } out->version = root.value("version").toString(); @@ -139,46 +127,35 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc // added for legacy Minecraft window embedding, TODO: remove readString(root, "appletClass", out->appletClass); - if (root.contains("+tweakers")) - { - for (auto tweakerVal : requireArray(root.value("+tweakers"))) - { + if (root.contains("+tweakers")) { + for (auto tweakerVal : requireArray(root.value("+tweakers"))) { out->addTweakers.append(requireString(tweakerVal)); } } - if (root.contains("+traits")) - { - for (auto tweakerVal : requireArray(root.value("+traits"))) - { + if (root.contains("+traits")) { + for (auto tweakerVal : requireArray(root.value("+traits"))) { out->traits.insert(requireString(tweakerVal)); } } - if (root.contains("+jvmArgs")) - { - for (auto arg : requireArray(root.value("+jvmArgs"))) - { + if (root.contains("+jvmArgs")) { + for (auto arg : requireArray(root.value("+jvmArgs"))) { out->addnJvmArguments.append(requireString(arg)); } } - - if (root.contains("jarMods")) - { - for (auto libVal : requireArray(root.value("jarMods"))) - { + if (root.contains("jarMods")) { + for (auto libVal : requireArray(root.value("jarMods"))) { QJsonObject libObj = requireObject(libVal); // parse the jarmod auto lib = OneSixVersionFormat::jarModFromJson(*out, libObj, filename); // and add to jar mods out->jarMods.append(lib); } - } - else if (root.contains("+jarMods")) // DEPRECATED: old style '+jarMods' are only here for backwards compatibility + } else if (root.contains("+jarMods")) // DEPRECATED: old style '+jarMods' are only here for backwards compatibility { - for (auto libVal : requireArray(root.value("+jarMods"))) - { + for (auto libVal : requireArray(root.value("+jarMods"))) { QJsonObject libObj = requireObject(libVal); // parse the jarmod auto lib = OneSixVersionFormat::plusJarModFromJson(*out, libObj, filename, out->name); @@ -187,10 +164,8 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc } } - if (root.contains("mods")) - { - for (auto libVal : requireArray(root.value("mods"))) - { + if (root.contains("mods")) { + for (auto libVal : requireArray(root.value("mods"))) { QJsonObject libObj = requireObject(libVal); // parse the jarmod auto lib = OneSixVersionFormat::modFromJson(*out, libObj, filename); @@ -199,10 +174,8 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc } } - auto readLibs = [&](const char * which, QList<LibraryPtr> & outList) - { - for (auto libVal : requireArray(root.value(which))) - { + auto readLibs = [&](const char* which, QList<LibraryPtr>& outList) { + for (auto libVal : requireArray(root.value(which))) { QJsonObject libObj = requireObject(libVal); // parse the library auto lib = libraryFromJson(*out, libObj, filename); @@ -211,29 +184,23 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc }; bool hasPlusLibs = root.contains("+libraries"); bool hasLibs = root.contains("libraries"); - if (hasPlusLibs && hasLibs) - { + if (hasPlusLibs && hasLibs) { out->addProblem(ProblemSeverity::Warning, QObject::tr("Version file has both '+libraries' and 'libraries'. This is no longer supported.")); readLibs("libraries", out->libraries); readLibs("+libraries", out->libraries); - } - else if (hasLibs) - { + } else if (hasLibs) { readLibs("libraries", out->libraries); - } - else if(hasPlusLibs) - { + } else if (hasPlusLibs) { readLibs("+libraries", out->libraries); } - if(root.contains("mavenFiles")) { + if (root.contains("mavenFiles")) { readLibs("mavenFiles", out->mavenFiles); } - if(root.contains("+agents")) { - for (auto agentVal : requireArray(root.value("+agents"))) - { + if (root.contains("+agents")) { + for (auto agentVal : requireArray(root.value("+agents"))) { QJsonObject agentObj = requireObject(agentVal); auto lib = libraryFromJson(*out, agentObj, filename); @@ -246,83 +213,68 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc } // if we have mainJar, just use it - if(root.contains("mainJar")) - { + if (root.contains("mainJar")) { QJsonObject libObj = requireObject(root, "mainJar"); out->mainJar = libraryFromJson(*out, libObj, filename); } // else reconstruct it from downloads and id ... if that's available - else if(!out->minecraftVersion.isEmpty()) - { + else if (!out->minecraftVersion.isEmpty()) { auto lib = std::make_shared<Library>(); lib->setRawName(GradleSpecifier(QString("com.mojang:minecraft:%1:client").arg(out->minecraftVersion))); // we have a reliable client download, use it. - if(out->mojangDownloads.contains("client")) - { + if (out->mojangDownloads.contains("client")) { auto LibDLInfo = std::make_shared<MojangLibraryDownloadInfo>(); LibDLInfo->artifact = out->mojangDownloads["client"]; lib->setMojangDownloadInfo(LibDLInfo); } // we got nothing... - else - { + else { out->addProblem( ProblemSeverity::Error, - QObject::tr("URL for the main jar could not be determined - Mojang removed the server that we used as fallback.") - ); + QObject::tr("URL for the main jar could not be determined - Mojang removed the server that we used as fallback.")); } out->mainJar = lib; } - if (root.contains("requires")) - { + if (root.contains("requires")) { Meta::parseRequires(root, &out->m_requires); } QString dependsOnMinecraftVersion = root.value("mcVersion").toString(); - if(!dependsOnMinecraftVersion.isEmpty()) - { + if (!dependsOnMinecraftVersion.isEmpty()) { Meta::Require mcReq; mcReq.uid = "net.minecraft"; mcReq.equalsVersion = dependsOnMinecraftVersion; - if (out->m_requires.count(mcReq) == 0) - { + if (out->m_requires.count(mcReq) == 0) { out->m_requires.insert(mcReq); } } - if (root.contains("conflicts")) - { + if (root.contains("conflicts")) { Meta::parseRequires(root, &out->conflicts); } - if (root.contains("volatile")) - { + if (root.contains("volatile")) { out->m_volatile = requireBoolean(root, "volatile"); } /* removed features that shouldn't be used */ - if (root.contains("tweakers")) - { + if (root.contains("tweakers")) { out->addProblem(ProblemSeverity::Error, QObject::tr("Version file contains unsupported element 'tweakers'")); } - if (root.contains("-libraries")) - { + if (root.contains("-libraries")) { out->addProblem(ProblemSeverity::Error, QObject::tr("Version file contains unsupported element '-libraries'")); } - if (root.contains("-tweakers")) - { + if (root.contains("-tweakers")) { out->addProblem(ProblemSeverity::Error, QObject::tr("Version file contains unsupported element '-tweakers'")); } - if (root.contains("-minecraftArguments")) - { + if (root.contains("-minecraftArguments")) { out->addProblem(ProblemSeverity::Error, QObject::tr("Version file contains unsupported element '-minecraftArguments'")); } - if (root.contains("+minecraftArguments")) - { + if (root.contains("+minecraftArguments")) { out->addProblem(ProblemSeverity::Error, QObject::tr("Version file contains unsupported element '+minecraftArguments'")); } return out; } -QJsonDocument OneSixVersionFormat::versionFileToJson(const VersionFilePtr &patch) +QJsonDocument OneSixVersionFormat::versionFileToJson(const VersionFilePtr& patch) { QJsonObject root; writeString(root, "name", patch->name); @@ -335,19 +287,16 @@ QJsonDocument OneSixVersionFormat::versionFileToJson(const VersionFilePtr &patch MojangVersionFormat::writeVersionProperties(patch.get(), root); - if(patch->mainJar) - { + if (patch->mainJar) { root.insert("mainJar", libraryToJson(patch->mainJar.get())); } writeString(root, "appletClass", patch->appletClass); writeStringList(root, "+tweakers", patch->addTweakers); writeStringList(root, "+traits", patch->traits.values()); writeStringList(root, "+jvmArgs", patch->addnJvmArguments); - if (!patch->agents.isEmpty()) - { + if (!patch->agents.isEmpty()) { QJsonArray array; - for (auto value: patch->agents) - { + for (auto value : patch->agents) { QJsonObject agentOut = OneSixVersionFormat::libraryToJson(value->library().get()); if (!value->argument().isEmpty()) agentOut.insert("argument", value->argument()); @@ -356,52 +305,41 @@ QJsonDocument OneSixVersionFormat::versionFileToJson(const VersionFilePtr &patch } root.insert("+agents", array); } - if (!patch->libraries.isEmpty()) - { + if (!patch->libraries.isEmpty()) { QJsonArray array; - for (auto value: patch->libraries) - { + for (auto value : patch->libraries) { array.append(OneSixVersionFormat::libraryToJson(value.get())); } root.insert("libraries", array); } - if (!patch->mavenFiles.isEmpty()) - { + if (!patch->mavenFiles.isEmpty()) { QJsonArray array; - for (auto value: patch->mavenFiles) - { + for (auto value : patch->mavenFiles) { array.append(OneSixVersionFormat::libraryToJson(value.get())); } root.insert("mavenFiles", array); } - if (!patch->jarMods.isEmpty()) - { + if (!patch->jarMods.isEmpty()) { QJsonArray array; - for (auto value: patch->jarMods) - { + for (auto value : patch->jarMods) { array.append(OneSixVersionFormat::jarModtoJson(value.get())); } root.insert("jarMods", array); } - if (!patch->mods.isEmpty()) - { + if (!patch->mods.isEmpty()) { QJsonArray array; - for (auto value: patch->jarMods) - { + for (auto value : patch->jarMods) { array.append(OneSixVersionFormat::modtoJson(value.get())); } root.insert("mods", array); } - if(!patch->m_requires.empty()) - { + if (!patch->m_requires.empty()) { Meta::serializeRequires(root, &patch->m_requires, "requires"); } - if(!patch->conflicts.empty()) - { + if (!patch->conflicts.empty()) { Meta::serializeRequires(root, &patch->conflicts, "conflicts"); } - if(patch->m_volatile) - { + if (patch->m_volatile) { root.insert("volatile", true); } // write the contents to a json document. @@ -412,17 +350,14 @@ QJsonDocument OneSixVersionFormat::versionFileToJson(const VersionFilePtr &patch } } -LibraryPtr OneSixVersionFormat::plusJarModFromJson( - ProblemContainer & problems, - const QJsonObject &libObj, - const QString &filename, - const QString &originalName -) { +LibraryPtr OneSixVersionFormat::plusJarModFromJson(ProblemContainer& problems, + const QJsonObject& libObj, + const QString& filename, + const QString& originalName) +{ LibraryPtr out(new Library()); - if (!libObj.contains("name")) - { - throw JSONValidationError(filename + - "contains a jarmod that doesn't have a 'name' field"); + if (!libObj.contains("name")) { + throw JSONValidationError(filename + "contains a jarmod that doesn't have a 'name' field"); } // just make up something unique on the spot for the library name. @@ -439,36 +374,32 @@ LibraryPtr OneSixVersionFormat::plusJarModFromJson( // read the original name if present - some versions did not set it // it is the original jar mod filename before it got renamed at the point of addition auto displayName = libObj.value("originalName").toString(); - if(displayName.isEmpty()) - { + if (displayName.isEmpty()) { auto fixed = originalName; fixed.remove(" (jar mod)"); out->setDisplayName(fixed); - } - else - { + } else { out->setDisplayName(displayName); } return out; } -LibraryPtr OneSixVersionFormat::jarModFromJson(ProblemContainer & problems, const QJsonObject& libObj, const QString& filename) +LibraryPtr OneSixVersionFormat::jarModFromJson(ProblemContainer& problems, const QJsonObject& libObj, const QString& filename) { return libraryFromJson(problems, libObj, filename); } - -QJsonObject OneSixVersionFormat::jarModtoJson(Library *jarmod) +QJsonObject OneSixVersionFormat::jarModtoJson(Library* jarmod) { return libraryToJson(jarmod); } -LibraryPtr OneSixVersionFormat::modFromJson(ProblemContainer & problems, const QJsonObject& libObj, const QString& filename) +LibraryPtr OneSixVersionFormat::modFromJson(ProblemContainer& problems, const QJsonObject& libObj, const QString& filename) { - return libraryFromJson(problems, libObj, filename); + return libraryFromJson(problems, libObj, filename); } -QJsonObject OneSixVersionFormat::modtoJson(Library *jarmod) +QJsonObject OneSixVersionFormat::modtoJson(Library* jarmod) { return libraryToJson(jarmod); } diff --git a/launcher/minecraft/OneSixVersionFormat.h b/launcher/minecraft/OneSixVersionFormat.h index 1a091d88..9bdc4a4a 100644 --- a/launcher/minecraft/OneSixVersionFormat.h +++ b/launcher/minecraft/OneSixVersionFormat.h @@ -1,30 +1,32 @@ #pragma once -#include <minecraft/VersionFile.h> -#include <minecraft/PackProfile.h> +#include <ProblemProvider.h> #include <minecraft/Library.h> +#include <minecraft/PackProfile.h> +#include <minecraft/VersionFile.h> #include <QJsonDocument> -#include <ProblemProvider.h> -class OneSixVersionFormat -{ -public: +class OneSixVersionFormat { + public: // version files / profile patches - static VersionFilePtr versionFileFromJson(const QJsonDocument &doc, const QString &filename, const bool requireOrder); - static QJsonDocument versionFileToJson(const VersionFilePtr &patch); + static VersionFilePtr versionFileFromJson(const QJsonDocument& doc, const QString& filename, const bool requireOrder); + static QJsonDocument versionFileToJson(const VersionFilePtr& patch); // libraries - static LibraryPtr libraryFromJson(ProblemContainer & problems, const QJsonObject &libObj, const QString &filename); - static QJsonObject libraryToJson(Library *library); + static LibraryPtr libraryFromJson(ProblemContainer& problems, const QJsonObject& libObj, const QString& filename); + static QJsonObject libraryToJson(Library* library); // DEPRECATED: old 'plus' jar mods generated by the application - static LibraryPtr plusJarModFromJson(ProblemContainer & problems, const QJsonObject &libObj, const QString &filename, const QString &originalName); + static LibraryPtr plusJarModFromJson(ProblemContainer& problems, + const QJsonObject& libObj, + const QString& filename, + const QString& originalName); // new jar mods derived from libraries - static LibraryPtr jarModFromJson(ProblemContainer & problems, const QJsonObject &libObj, const QString &filename); - static QJsonObject jarModtoJson(Library * jarmod); + static LibraryPtr jarModFromJson(ProblemContainer& problems, const QJsonObject& libObj, const QString& filename); + static QJsonObject jarModtoJson(Library* jarmod); // mods, also derived from libraries - static LibraryPtr modFromJson(ProblemContainer & problems, const QJsonObject &libObj, const QString &filename); - static QJsonObject modtoJson(Library * jarmod); + static LibraryPtr modFromJson(ProblemContainer& problems, const QJsonObject& libObj, const QString& filename); + static QJsonObject modtoJson(Library* jarmod); }; diff --git a/launcher/minecraft/PackProfile.cpp b/launcher/minecraft/PackProfile.cpp index 7cdd47ae..82fc779e 100644 --- a/launcher/minecraft/PackProfile.cpp +++ b/launcher/minecraft/PackProfile.cpp @@ -37,40 +37,37 @@ * limitations under the License. */ -#include <QFile> -#include <QCryptographicHash> #include <Version.h> +#include <QCryptographicHash> +#include <QDebug> #include <QDir> -#include <QJsonDocument> +#include <QFile> #include <QJsonArray> -#include <QDebug> +#include <QJsonDocument> #include <QSaveFile> -#include <QUuid> #include <QTimer> +#include <QUuid> #include "Exception.h" -#include "minecraft/OneSixVersionFormat.h" #include "FileSystem.h" +#include "Json.h" #include "minecraft/MinecraftInstance.h" +#include "minecraft/OneSixVersionFormat.h" #include "minecraft/ProfileUtils.h" -#include "Json.h" +#include "ComponentUpdateTask.h" #include "PackProfile.h" #include "PackProfile_p.h" -#include "ComponentUpdateTask.h" #include "Application.h" #include "modplatform/ResourceAPI.h" -static const QMap<QString, ResourceAPI::ModLoaderType> modloaderMapping{ - {"net.minecraftforge", ResourceAPI::Forge}, - {"net.fabricmc.fabric-loader", ResourceAPI::Fabric}, - {"org.quiltmc.quilt-loader", ResourceAPI::Quilt}, - {"com.mumfrey.liteloader", ResourceAPI::LiteLoader} -}; +static const QMap<QString, ResourceAPI::ModLoaderType> modloaderMapping{ { "net.minecraftforge", ResourceAPI::Forge }, + { "net.fabricmc.fabric-loader", ResourceAPI::Fabric }, + { "org.quiltmc.quilt-loader", ResourceAPI::Quilt }, + { "com.mumfrey.liteloader", ResourceAPI::LiteLoader } }; -PackProfile::PackProfile(MinecraftInstance * instance) - : QAbstractListModel() +PackProfile::PackProfile(MinecraftInstance* instance) : QAbstractListModel() { d.reset(new PackProfileData); d->m_instance = instance; @@ -95,42 +92,35 @@ static QJsonObject componentToJsonV1(ComponentPtr component) QJsonObject obj; // critical obj.insert("uid", component->m_uid); - if(!component->m_version.isEmpty()) - { + if (!component->m_version.isEmpty()) { obj.insert("version", component->m_version); } - if(component->m_dependencyOnly) - { + if (component->m_dependencyOnly) { obj.insert("dependencyOnly", true); } - if(component->m_important) - { + if (component->m_important) { obj.insert("important", true); } - if(component->m_disabled) - { + if (component->m_disabled) { obj.insert("disabled", true); } // cached - if(!component->m_cachedVersion.isEmpty()) - { + if (!component->m_cachedVersion.isEmpty()) { obj.insert("cachedVersion", component->m_cachedVersion); } - if(!component->m_cachedName.isEmpty()) - { + if (!component->m_cachedName.isEmpty()) { obj.insert("cachedName", component->m_cachedName); } Meta::serializeRequires(obj, &component->m_cachedRequires, "cachedRequires"); Meta::serializeRequires(obj, &component->m_cachedConflicts, "cachedConflicts"); - if(component->m_cachedVolatile) - { + if (component->m_cachedVolatile) { obj.insert("cachedVolatile", true); } return obj; } -static ComponentPtr componentFromJsonV1(PackProfile * parent, const QString & componentJsonPattern, const QJsonObject &obj) +static ComponentPtr componentFromJsonV1(PackProfile* parent, const QString& componentJsonPattern, const QJsonObject& obj) { // critical auto uid = Json::requireString(obj.value("uid")); @@ -153,51 +143,44 @@ static ComponentPtr componentFromJsonV1(PackProfile * parent, const QString & co } // Save the given component container data to a file -static bool savePackProfile(const QString & filename, const ComponentContainer & container) +static bool savePackProfile(const QString& filename, const ComponentContainer& container) { QJsonObject obj; obj.insert("formatVersion", currentComponentsFileVersion); QJsonArray orderArray; - for(auto component: container) - { + for (auto component : container) { orderArray.append(componentToJsonV1(component)); } obj.insert("components", orderArray); QSaveFile outFile(filename); - if (!outFile.open(QFile::WriteOnly)) - { - qCritical() << "Couldn't open" << outFile.fileName() - << "for writing:" << outFile.errorString(); + if (!outFile.open(QFile::WriteOnly)) { + qCritical() << "Couldn't open" << outFile.fileName() << "for writing:" << outFile.errorString(); return false; } auto data = QJsonDocument(obj).toJson(QJsonDocument::Indented); - if(outFile.write(data) != data.size()) - { - qCritical() << "Couldn't write all the data into" << outFile.fileName() - << "because:" << outFile.errorString(); + if (outFile.write(data) != data.size()) { + qCritical() << "Couldn't write all the data into" << outFile.fileName() << "because:" << outFile.errorString(); return false; } - if(!outFile.commit()) - { - qCritical() << "Couldn't save" << outFile.fileName() - << "because:" << outFile.errorString(); + if (!outFile.commit()) { + qCritical() << "Couldn't save" << outFile.fileName() << "because:" << outFile.errorString(); } return true; } // Read the given file into component containers -static bool loadPackProfile(PackProfile * parent, const QString & filename, const QString & componentJsonPattern, ComponentContainer & container) +static bool loadPackProfile(PackProfile* parent, + const QString& filename, + const QString& componentJsonPattern, + ComponentContainer& container) { QFile componentsFile(filename); - if (!componentsFile.exists()) - { + if (!componentsFile.exists()) { qWarning() << "Components file doesn't exist. This should never happen."; return false; } - if (!componentsFile.open(QFile::ReadOnly)) - { - qCritical() << "Couldn't open" << componentsFile.fileName() - << " for reading:" << componentsFile.errorString(); + if (!componentsFile.open(QFile::ReadOnly)) { + qCritical() << "Couldn't open" << componentsFile.fileName() << " for reading:" << componentsFile.errorString(); qWarning() << "Ignoring overriden order"; return false; } @@ -205,33 +188,26 @@ static bool loadPackProfile(PackProfile * parent, const QString & filename, cons // and it's valid JSON QJsonParseError error; QJsonDocument doc = QJsonDocument::fromJson(componentsFile.readAll(), &error); - if (error.error != QJsonParseError::NoError) - { + if (error.error != QJsonParseError::NoError) { qCritical() << "Couldn't parse" << componentsFile.fileName() << ":" << error.errorString(); qWarning() << "Ignoring overriden order"; return false; } // and then read it and process it if all above is true. - try - { + try { auto obj = Json::requireObject(doc); // check order file version. auto version = Json::requireInteger(obj.value("formatVersion")); - if (version != currentComponentsFileVersion) - { - throw JSONValidationError(QObject::tr("Invalid component file version, expected %1") - .arg(currentComponentsFileVersion)); + if (version != currentComponentsFileVersion) { + throw JSONValidationError(QObject::tr("Invalid component file version, expected %1").arg(currentComponentsFileVersion)); } auto orderArray = Json::requireArray(obj.value("components")); - for(auto item: orderArray) - { + for (auto item : orderArray) { auto obj = Json::requireObject(item, "Component must be an object."); container.append(componentFromJsonV1(parent, componentJsonPattern, obj)); } - } - catch (const JSONValidationError &err) - { + } catch (const JSONValidationError& err) { qCritical() << "Couldn't parse" << componentsFile.fileName() << ": bad file format"; container.clear(); return false; @@ -245,8 +221,7 @@ static bool loadPackProfile(PackProfile * parent, const QString & filename, cons void PackProfile::saveNow() { - if(saveIsScheduled()) - { + if (saveIsScheduled()) { d->m_saveTimer.stop(); save_internal(); } @@ -265,13 +240,11 @@ void PackProfile::buildingFromScratch() void PackProfile::scheduleSave() { - if(!d->loaded) - { + if (!d->loaded) { qDebug() << "Component list should never save if it didn't successfully load, instance:" << d->m_instance->name(); return; } - if(!d->dirty) - { + if (!d->dirty) { d->dirty = true; qDebug() << "Component list save is scheduled for" << d->m_instance->name(); } @@ -312,26 +285,20 @@ bool PackProfile::load() // load the new component list and swap it with the current one... ComponentContainer newComponents; - if(!loadPackProfile(this, filename, patchesPattern(), newComponents)) - { + if (!loadPackProfile(this, filename, patchesPattern(), newComponents)) { qCritical() << "Failed to load the component config for instance" << d->m_instance->name(); return false; - } - else - { + } else { // FIXME: actually use fine-grained updates, not this... beginResetModel(); // disconnect all the old components - for(auto component: d->components) - { + for (auto component : d->components) { disconnect(component.get(), &Component::dataChanged, this, &PackProfile::componentDataChanged); } d->components.clear(); d->componentIndex.clear(); - for(auto component: newComponents) - { - if(d->componentIndex.contains(component->m_uid)) - { + for (auto component : newComponents) { + if (d->componentIndex.contains(component->m_uid)) { qWarning() << "Ignoring duplicate component entry" << component->m_uid; continue; } @@ -348,8 +315,7 @@ bool PackProfile::load() void PackProfile::reload(Net::Mode netmode) { // Do not reload when the update/resolve task is running. It is in control. - if(d->m_updateTask) - { + if (d->m_updateTask) { return; } @@ -359,8 +325,7 @@ void PackProfile::reload(Net::Mode netmode) // FIXME: differentiate when a reapply is required by propagating state from components invalidateLaunchProfile(); - if(load()) - { + if (load()) { resolve(netmode); } } @@ -376,11 +341,10 @@ void PackProfile::resolve(Net::Mode netmode) d->m_updateTask.reset(updateTask); connect(updateTask, &ComponentUpdateTask::succeeded, this, &PackProfile::updateSucceeded); connect(updateTask, &ComponentUpdateTask::failed, this, &PackProfile::updateFailed); - connect(updateTask, &ComponentUpdateTask::aborted, this, [this]{ updateFailed(tr("Aborted")); }); + connect(updateTask, &ComponentUpdateTask::aborted, this, [this] { updateFailed(tr("Aborted")); }); d->m_updateTask->start(); } - void PackProfile::updateSucceeded() { qDebug() << "Component list update/resolve task succeeded for" << d->m_instance->name(); @@ -405,13 +369,11 @@ void PackProfile::appendComponent(ComponentPtr component) void PackProfile::insertComponent(size_t index, ComponentPtr component) { auto id = component->getID(); - if(id.isEmpty()) - { + if (id.isEmpty()) { qWarning() << "Attempt to add a component with empty ID!"; return; } - if(d->componentIndex.contains(id)) - { + if (d->componentIndex.contains(id)) { qWarning() << "Attempt to add a component that is already present!"; return; } @@ -425,21 +387,18 @@ void PackProfile::insertComponent(size_t index, ComponentPtr component) void PackProfile::componentDataChanged() { - auto objPtr = qobject_cast<Component *>(sender()); - if(!objPtr) - { + auto objPtr = qobject_cast<Component*>(sender()); + if (!objPtr) { qWarning() << "PackProfile got dataChenged signal from a non-Component!"; return; } - if(objPtr->getID() == "net.minecraft") { + if (objPtr->getID() == "net.minecraft") { emit minecraftChanged(); } // figure out which one is it... in a seriously dumb way. int index = 0; - for (auto component: d->components) - { - if(component.get() == objPtr) - { + for (auto component : d->components) { + if (component.get() == objPtr) { emit dataChanged(createIndex(index, 0), createIndex(index, columnCount(QModelIndex()) - 1)); scheduleSave(); return; @@ -452,14 +411,12 @@ void PackProfile::componentDataChanged() bool PackProfile::remove(const int index) { auto patch = getComponent(index); - if (!patch->isRemovable()) - { + if (!patch->isRemovable()) { qWarning() << "Patch" << patch->getID() << "is non-removable"; return false; } - if(!removeComponent_internal(patch)) - { + if (!removeComponent_internal(patch)) { qCritical() << "Patch" << patch->getID() << "could not be removed"; return false; } @@ -476,10 +433,8 @@ bool PackProfile::remove(const int index) bool PackProfile::remove(const QString id) { int i = 0; - for (auto patch : d->components) - { - if (patch->getID() == id) - { + for (auto patch : d->components) { + if (patch->getID() == id) { return remove(i); } i++; @@ -490,13 +445,11 @@ bool PackProfile::remove(const QString id) bool PackProfile::customize(int index) { auto patch = getComponent(index); - if (!patch->isCustomizable()) - { + if (!patch->isCustomizable()) { qDebug() << "Patch" << patch->getID() << "is not customizable"; return false; } - if(!patch->customize()) - { + if (!patch->customize()) { qCritical() << "Patch" << patch->getID() << "could not be customized"; return false; } @@ -508,13 +461,11 @@ bool PackProfile::customize(int index) bool PackProfile::revertToBase(int index) { auto patch = getComponent(index); - if (!patch->isRevertible()) - { + if (!patch->isRevertible()) { qDebug() << "Patch" << patch->getID() << "is not revertible"; return false; } - if(!patch->revert()) - { + if (!patch->revert()) { qCritical() << "Patch" << patch->getID() << "could not be reverted"; return false; } @@ -523,11 +474,10 @@ bool PackProfile::revertToBase(int index) return true; } -ComponentPtr PackProfile::getComponent(const QString &id) +ComponentPtr PackProfile::getComponent(const QString& id) { auto iter = d->componentIndex.find(id); - if (iter == d->componentIndex.end()) - { + if (iter == d->componentIndex.end()) { return nullptr; } return (*iter); @@ -535,14 +485,13 @@ ComponentPtr PackProfile::getComponent(const QString &id) ComponentPtr PackProfile::getComponent(int index) { - if(index < 0 || index >= d->components.size()) - { + if (index < 0 || index >= d->components.size()) { return nullptr; } return d->components[index]; } -QVariant PackProfile::data(const QModelIndex &index, int role) const +QVariant PackProfile::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); @@ -555,72 +504,58 @@ QVariant PackProfile::data(const QModelIndex &index, int role) const auto patch = d->components.at(row); - switch (role) - { - case Qt::CheckStateRole: - { - switch (column) - { - case NameColumn: { - return patch->isEnabled() ? Qt::Checked : Qt::Unchecked; - } - default: - return QVariant(); - } - } - case Qt::DisplayRole: - { - switch (column) - { - case NameColumn: - return patch->getName(); - case VersionColumn: - { - if(patch->isCustom()) - { - return QString("%1 (Custom)").arg(patch->getVersion()); - } - else - { - return patch->getVersion(); + switch (role) { + case Qt::CheckStateRole: { + switch (column) { + case NameColumn: { + return patch->isEnabled() ? Qt::Checked : Qt::Unchecked; + } + default: + return QVariant(); } } - default: - return QVariant(); - } - } - case Qt::DecorationRole: - { - if (column == NameColumn) { - auto severity = patch->getProblemSeverity(); - switch (severity) - { - case ProblemSeverity::Warning: - return "warning"; - case ProblemSeverity::Error: - return "error"; + case Qt::DisplayRole: { + switch (column) { + case NameColumn: + return patch->getName(); + case VersionColumn: { + if (patch->isCustom()) { + return QString("%1 (Custom)").arg(patch->getVersion()); + } else { + return patch->getVersion(); + } + } default: return QVariant(); } } - return QVariant(); - } + case Qt::DecorationRole: { + if (column == NameColumn) { + auto severity = patch->getProblemSeverity(); + switch (severity) { + case ProblemSeverity::Warning: + return "warning"; + case ProblemSeverity::Error: + return "error"; + default: + return QVariant(); + } + } + return QVariant(); + } } return QVariant(); } bool PackProfile::setData(const QModelIndex& index, const QVariant& value, int role) { - if (!index.isValid() || index.row() < 0 || index.row() >= rowCount(index.parent())) - { + if (!index.isValid() || index.row() < 0 || index.row() >= rowCount(index.parent())) { return false; } - if (role == Qt::CheckStateRole) - { + if (role == Qt::CheckStateRole) { auto component = d->components[index.row()]; - if (component->setEnabled(!component->isEnabled())) - { + if (component->setEnabled(!component->isEnabled())) { return true; } } @@ -629,18 +564,15 @@ bool PackProfile::setData(const QModelIndex& index, const QVariant& value, int r QVariant PackProfile::headerData(int section, Qt::Orientation orientation, int role) const { - if (orientation == Qt::Horizontal) - { - if (role == Qt::DisplayRole) - { - switch (section) - { - case NameColumn: - return tr("Name"); - case VersionColumn: - return tr("Version"); - default: - return QVariant(); + if (orientation == Qt::Horizontal) { + if (role == Qt::DisplayRole) { + switch (section) { + case NameColumn: + return tr("Name"); + case VersionColumn: + return tr("Version"); + default: + return QVariant(); } } } @@ -648,7 +580,7 @@ QVariant PackProfile::headerData(int section, Qt::Orientation orientation, int r } // FIXME: zero precision mess -Qt::ItemFlags PackProfile::flags(const QModelIndex &index) const +Qt::ItemFlags PackProfile::flags(const QModelIndex& index) const { if (!index.isValid()) { return Qt::NoItemFlags; @@ -664,19 +596,18 @@ Qt::ItemFlags PackProfile::flags(const QModelIndex &index) const auto patch = d->components.at(row); // TODO: this will need fine-tuning later... - if(patch->canBeDisabled() && !d->interactionDisabled) - { + if (patch->canBeDisabled() && !d->interactionDisabled) { outFlags |= Qt::ItemIsUserCheckable; } return outFlags; } -int PackProfile::rowCount(const QModelIndex &parent) const +int PackProfile::rowCount(const QModelIndex& parent) const { return parent.isValid() ? 0 : d->components.size(); } -int PackProfile::columnCount(const QModelIndex &parent) const +int PackProfile::columnCount(const QModelIndex& parent) const { return parent.isValid() ? 0 : NUM_COLUMNS; } @@ -684,12 +615,9 @@ int PackProfile::columnCount(const QModelIndex &parent) const void PackProfile::move(const int index, const MoveDirection direction) { int theirIndex; - if (direction == MoveUp) - { + if (direction == MoveUp) { theirIndex = index - 1; - } - else - { + } else { theirIndex = index + 1; } @@ -706,8 +634,7 @@ void PackProfile::move(const int index, const MoveDirection direction) auto from = getComponent(index); auto to = getComponent(theirIndex); - if (!from || !to || !to->isMoveable() || !from->isMoveable()) - { + if (!from || !to || !to->isMoveable() || !from->isMoveable()) { return; } beginMoveRows(QModelIndex(), index, index, QModelIndex(), togap); @@ -775,8 +702,7 @@ void PackProfile::installAgents(QStringList selectedFiles) bool PackProfile::installEmpty(const QString& uid, const QString& name) { QString patchDir = FS::PathCombine(d->m_instance->instanceRoot(), "patches"); - if(!FS::ensureFolderPathExists(patchDir)) - { + if (!FS::ensureFolderPathExists(patchDir)) { return false; } auto f = std::make_shared<VersionFile>(); @@ -785,10 +711,8 @@ bool PackProfile::installEmpty(const QString& uid, const QString& name) f->version = "1"; QString patchFileName = FS::PathCombine(patchDir, uid + ".json"); QFile file(patchFileName); - if (!file.open(QFile::WriteOnly)) - { - qCritical() << "Error opening" << file.fileName() - << "for reading:" << file.errorString(); + if (!file.open(QFile::WriteOnly)) { + qCritical() << "Error opening" << file.fileName() << "for reading:" << file.errorString(); return false; } file.write(OneSixVersionFormat::versionFileToJson(f).toJson()); @@ -805,31 +729,25 @@ bool PackProfile::removeComponent_internal(ComponentPtr patch) bool ok = true; // first, remove the patch file. this ensures it's not used anymore auto fileName = patch->getFilename(); - if(fileName.size()) - { + if (fileName.size()) { QFile patchFile(fileName); - if(patchFile.exists() && !patchFile.remove()) - { + if (patchFile.exists() && !patchFile.remove()) { qCritical() << "File" << fileName << "could not be removed because:" << patchFile.errorString(); return false; } } // FIXME: we need a generic way of removing local resources, not just jar mods... - auto preRemoveJarMod = [&](LibraryPtr jarMod) -> bool - { - if (!jarMod->isLocal()) - { + auto preRemoveJarMod = [&](LibraryPtr jarMod) -> bool { + if (!jarMod->isLocal()) { return true; } QStringList jar, temp1, temp2, temp3; jarMod->getApplicableFiles(d->m_instance->runtimeContext(), jar, temp1, temp2, temp3, d->m_instance->jarmodsPath().absolutePath()); - QFileInfo finfo (jar[0]); - if(finfo.exists()) - { + QFileInfo finfo(jar[0]); + if (finfo.exists()) { QFile jarModFile(jar[0]); - if(!jarModFile.remove()) - { + if (!jarModFile.remove()) { qCritical() << "File" << jar[0] << "could not be removed because:" << jarModFile.errorString(); return false; } @@ -839,11 +757,9 @@ bool PackProfile::removeComponent_internal(ComponentPtr patch) }; auto vFile = patch->getVersionFile(); - if(vFile) - { - auto &jarMods = vFile->jarMods; - for(auto &jarmod: jarMods) - { + if (vFile) { + auto& jarMods = vFile->jarMods; + for (auto& jarmod : jarMods) { ok &= preRemoveJarMod(jarmod); } } @@ -853,18 +769,15 @@ bool PackProfile::removeComponent_internal(ComponentPtr patch) bool PackProfile::installJarMods_internal(QStringList filepaths) { QString patchDir = FS::PathCombine(d->m_instance->instanceRoot(), "patches"); - if(!FS::ensureFolderPathExists(patchDir)) - { + if (!FS::ensureFolderPathExists(patchDir)) { return false; } - if (!FS::ensureFolderPathExists(d->m_instance->jarModsDir())) - { + if (!FS::ensureFolderPathExists(d->m_instance->jarModsDir())) { return false; } - for(auto filepath:filepaths) - { + for (auto filepath : filepaths) { QFileInfo sourceInfo(filepath); QString id = QUuid::createUuid().toString(QUuid::WithoutBraces); QString target_filename = id + ".jar"; @@ -875,8 +788,7 @@ bool PackProfile::installJarMods_internal(QStringList filepaths) QFileInfo targetInfo(finalPath); Q_ASSERT(!targetInfo.exists()); - if (!QFile::copy(sourceInfo.absoluteFilePath(),QFileInfo(finalPath).absoluteFilePath())) - { + if (!QFile::copy(sourceInfo.absoluteFilePath(), QFileInfo(finalPath).absoluteFilePath())) { return false; } @@ -892,10 +804,8 @@ bool PackProfile::installJarMods_internal(QStringList filepaths) QString patchFileName = FS::PathCombine(patchDir, target_id + ".json"); QFile file(patchFileName); - if (!file.open(QFile::WriteOnly)) - { - qCritical() << "Error opening" << file.fileName() - << "for reading:" << file.errorString(); + if (!file.open(QFile::WriteOnly)) { + qCritical() << "Error opening" << file.fileName() << "for reading:" << file.errorString(); return false; } file.write(OneSixVersionFormat::versionFileToJson(f).toJson()); @@ -911,14 +821,12 @@ bool PackProfile::installJarMods_internal(QStringList filepaths) bool PackProfile::installCustomJar_internal(QString filepath) { QString patchDir = FS::PathCombine(d->m_instance->instanceRoot(), "patches"); - if(!FS::ensureFolderPathExists(patchDir)) - { + if (!FS::ensureFolderPathExists(patchDir)) { return false; } QString libDir = d->m_instance->getLocalLibraryPath(); - if (!FS::ensureFolderPathExists(libDir)) - { + if (!FS::ensureFolderPathExists(libDir)) { return false; } @@ -930,15 +838,12 @@ bool PackProfile::installCustomJar_internal(QString filepath) QString finalPath = FS::PathCombine(libDir, target_filename); QFileInfo jarInfo(finalPath); - if (jarInfo.exists()) - { - if(!QFile::remove(finalPath)) - { + if (jarInfo.exists()) { + if (!QFile::remove(finalPath)) { return false; } } - if (!QFile::copy(filepath, finalPath)) - { + if (!QFile::copy(filepath, finalPath)) { return false; } @@ -953,10 +858,8 @@ bool PackProfile::installCustomJar_internal(QString filepath) QString patchFileName = FS::PathCombine(patchDir, target_id + ".json"); QFile file(patchFileName); - if (!file.open(QFile::WriteOnly)) - { - qCritical() << "Error opening" << file.fileName() - << "for reading:" << file.errorString(); + if (!file.open(QFile::WriteOnly)) { + qCritical() << "Error opening" << file.fileName() << "for reading:" << file.errorString(); return false; } file.write(OneSixVersionFormat::versionFileToJson(f).toJson()); @@ -1029,20 +932,15 @@ bool PackProfile::installAgents_internal(QStringList filepaths) std::shared_ptr<LaunchProfile> PackProfile::getProfile() const { - if(!d->m_profile) - { - try - { + if (!d->m_profile) { + try { auto profile = std::make_shared<LaunchProfile>(); - for(auto file: d->components) - { + for (auto file : d->components) { qDebug() << "Applying" << file->getID() << (file->getProblemSeverity() == ProblemSeverity::Error ? "ERROR" : "GOOD"); file->applyTo(profile.get()); } d->m_profile = profile; - } - catch (const Exception &error) - { + } catch (const Exception& error) { qWarning() << "Couldn't apply profile patches because: " << error.cause(); } } @@ -1052,20 +950,16 @@ std::shared_ptr<LaunchProfile> PackProfile::getProfile() const bool PackProfile::setComponentVersion(const QString& uid, const QString& version, bool important) { auto iter = d->componentIndex.find(uid); - if(iter != d->componentIndex.end()) - { + if (iter != d->componentIndex.end()) { ComponentPtr component = *iter; // set existing - if(component->revert()) - { + if (component->revert()) { component->setVersion(version); component->setImportant(important); return true; } return false; - } - else - { + } else { // add new auto component = makeShared<Component>(this, uid); component->m_version = version; @@ -1078,8 +972,7 @@ bool PackProfile::setComponentVersion(const QString& uid, const QString& version QString PackProfile::getComponentVersion(const QString& uid) const { const auto iter = d->componentIndex.find(uid); - if (iter != d->componentIndex.end()) - { + if (iter != d->componentIndex.end()) { return (*iter)->getVersion(); } return QString(); @@ -1087,10 +980,10 @@ QString PackProfile::getComponentVersion(const QString& uid) const void PackProfile::disableInteraction(bool disable) { - if(d->interactionDisabled != disable) { + if (d->interactionDisabled != disable) { d->interactionDisabled = disable; auto size = d->components.size(); - if(size) { + if (size) { emit dataChanged(index(0), index(size - 1)); } } diff --git a/launcher/minecraft/PackProfile.h b/launcher/minecraft/PackProfile.h index d144d875..a5e5cb1a 100644 --- a/launcher/minecraft/PackProfile.h +++ b/launcher/minecraft/PackProfile.h @@ -41,44 +41,39 @@ #include <QAbstractListModel> -#include <QString> #include <QList> +#include <QString> #include <memory> -#include "Library.h" -#include "LaunchProfile.h" -#include "Component.h" -#include "ProfileUtils.h" #include "BaseVersion.h" +#include "Component.h" +#include "LaunchProfile.h" +#include "Library.h" #include "MojangDownloadInfo.h" -#include "net/Mode.h" +#include "ProfileUtils.h" #include "modplatform/ResourceAPI.h" +#include "net/Mode.h" class MinecraftInstance; struct PackProfileData; class ComponentUpdateTask; -class PackProfile : public QAbstractListModel -{ +class PackProfile : public QAbstractListModel { Q_OBJECT friend ComponentUpdateTask; -public: - enum Columns - { - NameColumn = 0, - VersionColumn, - NUM_COLUMNS - }; - - explicit PackProfile(MinecraftInstance * instance); + + public: + enum Columns { NameColumn = 0, VersionColumn, NUM_COLUMNS }; + + explicit PackProfile(MinecraftInstance* instance); virtual ~PackProfile(); - virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override; - virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; - virtual int columnCount(const QModelIndex &parent) const override; - virtual Qt::ItemFlags flags(const QModelIndex &index) const override; + virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override; + virtual int columnCount(const QModelIndex& parent) const override; + virtual Qt::ItemFlags flags(const QModelIndex& index) const override; /// call this to explicitly mark the component list as loaded - this is used to build a new component list from scratch. void buildingFromScratch(); @@ -121,15 +116,15 @@ public: std::shared_ptr<LaunchProfile> getProfile() const; // NOTE: used ONLY by MinecraftInstance to provide legacy version mappings from instance config - void setOldConfigVersion(const QString &uid, const QString &version); + void setOldConfigVersion(const QString& uid, const QString& version); - QString getComponentVersion(const QString &uid) const; + QString getComponentVersion(const QString& uid) const; - bool setComponentVersion(const QString &uid, const QString &version, bool important = false); + bool setComponentVersion(const QString& uid, const QString& version, bool important = false); - bool installEmpty(const QString &uid, const QString &name); + bool installEmpty(const QString& uid, const QString& name); - QString patchFilePathForUid(const QString &uid) const; + QString patchFilePathForUid(const QString& uid) const; /// if there is a save scheduled, do it now. void saveNow(); @@ -137,12 +132,12 @@ public: /// helper method, returns RuntimeContext of instance RuntimeContext runtimeContext(); -signals: + signals: void minecraftChanged(); -public: + public: /// get the profile component by id - ComponentPtr getComponent(const QString &id); + ComponentPtr getComponent(const QString& id); /// get the profile component by index ComponentPtr getComponent(int index); @@ -153,7 +148,7 @@ public: std::optional<ResourceAPI::ModLoaderTypes> getModLoaders(); -private: + private: void scheduleSave(); bool saveIsScheduled() const; @@ -166,21 +161,20 @@ private: QString componentsFilePath() const; QString patchesPattern() const; -private slots: + private slots: void save_internal(); void updateSucceeded(); - void updateFailed(const QString & error); + void updateFailed(const QString& error); void componentDataChanged(); void disableInteraction(bool disable); -private: + private: bool load(); bool installJarMods_internal(QStringList filepaths); bool installCustomJar_internal(QString filepath); bool installAgents_internal(QStringList filepaths); bool removeComponent_internal(ComponentPtr patch); -private: /* data */ - + private: /* data */ std::unique_ptr<PackProfileData> d; }; diff --git a/launcher/minecraft/PackProfile_p.h b/launcher/minecraft/PackProfile_p.h index 715e0460..0cd4fb83 100644 --- a/launcher/minecraft/PackProfile_p.h +++ b/launcher/minecraft/PackProfile_p.h @@ -1,19 +1,18 @@ #pragma once -#include "Component.h" -#include <map> -#include <QTimer> #include <QList> #include <QMap> +#include <QTimer> +#include <map> +#include "Component.h" class MinecraftInstance; using ComponentContainer = QList<ComponentPtr>; using ComponentIndex = QMap<QString, ComponentPtr>; -struct PackProfileData -{ +struct PackProfileData { // the instance this belongs to - MinecraftInstance *m_instance; + MinecraftInstance* m_instance; // the launch profile (volatile, temporary thing created on demand) std::shared_ptr<LaunchProfile> m_profile; @@ -27,4 +26,3 @@ struct PackProfileData bool loaded = false; bool interactionDisabled = true; }; - diff --git a/launcher/minecraft/ParseUtils.cpp b/launcher/minecraft/ParseUtils.cpp index c9640e77..fabc57a6 100644 --- a/launcher/minecraft/ParseUtils.cpp +++ b/launcher/minecraft/ParseUtils.cpp @@ -1,7 +1,7 @@ -#include <QDateTime> -#include <QString> #include "ParseUtils.h" +#include <QDateTime> #include <QDebug> +#include <QString> #include <cstdlib> QDateTime timeFromS3Time(QString str) @@ -22,7 +22,7 @@ QString timeToS3Time(QDateTime time) int offsetMinutes = offsetAbs % 3600; offsetAbs -= offsetMinutes; offsetMinutes /= 60; - + int offsetHours = offsetAbs / 3600; QString raw = time.toString("yyyy-MM-ddTHH:mm:ss"); diff --git a/launcher/minecraft/ParseUtils.h b/launcher/minecraft/ParseUtils.h index aad82748..c81d8f8b 100644 --- a/launcher/minecraft/ParseUtils.h +++ b/launcher/minecraft/ParseUtils.h @@ -1,6 +1,6 @@ #pragma once -#include <QString> #include <QDateTime> +#include <QString> /// take the timestamp used by S3 and turn it into QDateTime QDateTime timeFromS3Time(QString str); diff --git a/launcher/minecraft/ProfileUtils.cpp b/launcher/minecraft/ProfileUtils.cpp index 03f8c198..666ebcfc 100644 --- a/launcher/minecraft/ProfileUtils.cpp +++ b/launcher/minecraft/ProfileUtils.cpp @@ -34,33 +34,29 @@ */ #include "ProfileUtils.h" -#include "minecraft/VersionFilterData.h" -#include "minecraft/OneSixVersionFormat.h" -#include "Json.h" #include <QDebug> +#include "Json.h" +#include "minecraft/OneSixVersionFormat.h" +#include "minecraft/VersionFilterData.h" -#include <QJsonDocument> #include <QJsonArray> +#include <QJsonDocument> #include <QRegularExpression> #include <QSaveFile> -namespace ProfileUtils -{ +namespace ProfileUtils { static const int currentOrderFileVersion = 1; -bool readOverrideOrders(QString path, PatchOrder &order) +bool readOverrideOrders(QString path, PatchOrder& order) { QFile orderFile(path); - if (!orderFile.exists()) - { + if (!orderFile.exists()) { qWarning() << "Order file doesn't exist. Ignoring."; return false; } - if (!orderFile.open(QFile::ReadOnly)) - { - qCritical() << "Couldn't open" << orderFile.fileName() - << " for reading:" << orderFile.errorString(); + if (!orderFile.open(QFile::ReadOnly)) { + qCritical() << "Couldn't open" << orderFile.fileName() << " for reading:" << orderFile.errorString(); qWarning() << "Ignoring overriden order"; return false; } @@ -68,32 +64,25 @@ bool readOverrideOrders(QString path, PatchOrder &order) // and it's valid JSON QJsonParseError error; QJsonDocument doc = QJsonDocument::fromJson(orderFile.readAll(), &error); - if (error.error != QJsonParseError::NoError) - { + if (error.error != QJsonParseError::NoError) { qCritical() << "Couldn't parse" << orderFile.fileName() << ":" << error.errorString(); qWarning() << "Ignoring overriden order"; return false; } // and then read it and process it if all above is true. - try - { + try { auto obj = Json::requireObject(doc); // check order file version. auto version = Json::requireInteger(obj.value("version")); - if (version != currentOrderFileVersion) - { - throw JSONValidationError(QObject::tr("Invalid order file version, expected %1") - .arg(currentOrderFileVersion)); + if (version != currentOrderFileVersion) { + throw JSONValidationError(QObject::tr("Invalid order file version, expected %1").arg(currentOrderFileVersion)); } auto orderArray = Json::requireArray(obj.value("order")); - for(auto item: orderArray) - { + for (auto item : orderArray) { order.append(Json::requireString(item)); } - } - catch (const JSONValidationError &err) - { + } catch (const JSONValidationError& err) { qCritical() << "Couldn't parse" << orderFile.fileName() << ": bad file format"; qWarning() << "Ignoring overriden order"; order.clear(); @@ -111,23 +100,19 @@ static VersionFilePtr createErrorVersionFile(QString fileId, QString filepath, Q return outError; } -static VersionFilePtr guardedParseJson(const QJsonDocument & doc,const QString &fileId,const QString &filepath,const bool &requireOrder) +static VersionFilePtr guardedParseJson(const QJsonDocument& doc, const QString& fileId, const QString& filepath, const bool& requireOrder) { - try - { + try { return OneSixVersionFormat::versionFileFromJson(doc, filepath, requireOrder); - } - catch (const Exception &e) - { + } catch (const Exception& e) { return createErrorVersionFile(fileId, filepath, e.cause()); } } -VersionFilePtr parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder) +VersionFilePtr parseJsonFile(const QFileInfo& fileInfo, const bool requireOrder) { QFile file(fileInfo.absoluteFilePath()); - if (!file.open(QFile::ReadOnly)) - { + if (!file.open(QFile::ReadOnly)) { auto errorStr = QObject::tr("Unable to open the version file %1: %2.").arg(fileInfo.fileName(), file.errorString()); return createErrorVersionFile(fileInfo.completeBaseName(), fileInfo.absoluteFilePath(), errorStr); } @@ -135,14 +120,11 @@ VersionFilePtr parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder) auto data = file.readAll(); QJsonDocument doc = QJsonDocument::fromJson(data, &error); file.close(); - if (error.error != QJsonParseError::NoError) - { + if (error.error != QJsonParseError::NoError) { int line = 1; int column = 0; - for(int i = 0; i < error.offset; i++) - { - if(data[i] == '\n') - { + for (int i = 0; i < error.offset; i++) { + if (data[i] == '\n') { line++; column = 0; continue; @@ -150,26 +132,25 @@ VersionFilePtr parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder) column++; } auto errorStr = QObject::tr("Unable to process the version file %1: %2 at line %3 column %4.") - .arg(fileInfo.fileName(), error.errorString()) - .arg(line).arg(column); + .arg(fileInfo.fileName(), error.errorString()) + .arg(line) + .arg(column); return createErrorVersionFile(fileInfo.completeBaseName(), fileInfo.absoluteFilePath(), errorStr); } return guardedParseJson(doc, fileInfo.completeBaseName(), fileInfo.absoluteFilePath(), requireOrder); } -bool saveJsonFile(const QJsonDocument doc, const QString & filename) +bool saveJsonFile(const QJsonDocument doc, const QString& filename) { auto data = doc.toJson(); QSaveFile jsonFile(filename); - if(!jsonFile.open(QIODevice::WriteOnly)) - { + if (!jsonFile.open(QIODevice::WriteOnly)) { jsonFile.cancelWriting(); qWarning() << "Couldn't open" << filename << "for writing"; return false; } jsonFile.write(data); - if(!jsonFile.commit()) - { + if (!jsonFile.commit()) { qWarning() << "Couldn't save" << filename; return false; } @@ -178,13 +159,10 @@ bool saveJsonFile(const QJsonDocument doc, const QString & filename) void removeLwjglFromPatch(VersionFilePtr patch) { - auto filter = [](QList<LibraryPtr>& libs) - { + auto filter = [](QList<LibraryPtr>& libs) { QList<LibraryPtr> filteredLibs; - for (auto lib : libs) - { - if (!g_VersionFilterData.lwjglWhitelist.contains(lib->artifactPrefix())) - { + for (auto lib : libs) { + if (!g_VersionFilterData.lwjglWhitelist.contains(lib->artifactPrefix())) { filteredLibs.append(lib); } } @@ -192,4 +170,4 @@ void removeLwjglFromPatch(VersionFilePtr patch) }; filter(patch->libraries); } -} +} // namespace ProfileUtils diff --git a/launcher/minecraft/ProfileUtils.h b/launcher/minecraft/ProfileUtils.h index 5b938784..93cc3da0 100644 --- a/launcher/minecraft/ProfileUtils.h +++ b/launcher/minecraft/ProfileUtils.h @@ -37,24 +37,22 @@ #include "Library.h" #include "VersionFile.h" -namespace ProfileUtils -{ +namespace ProfileUtils { typedef QStringList PatchOrder; /// Read and parse a OneSix format order file -bool readOverrideOrders(QString path, PatchOrder &order); +bool readOverrideOrders(QString path, PatchOrder& order); /// Write a OneSix format order file -bool writeOverrideOrders(QString path, const PatchOrder &order); - +bool writeOverrideOrders(QString path, const PatchOrder& order); /// Parse a version file in JSON format -VersionFilePtr parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder); +VersionFilePtr parseJsonFile(const QFileInfo& fileInfo, const bool requireOrder); /// Save a JSON file (in any format) -bool saveJsonFile(const QJsonDocument doc, const QString & filename); +bool saveJsonFile(const QJsonDocument doc, const QString& filename); /// Remove LWJGL from a patch file. This is applied to all Mojang-like profile files. void removeLwjglFromPatch(VersionFilePtr patch); -} +} // namespace ProfileUtils diff --git a/launcher/minecraft/Rule.cpp b/launcher/minecraft/Rule.cpp index ff3d75f2..74c12a0d 100644 --- a/launcher/minecraft/Rule.cpp +++ b/launcher/minecraft/Rule.cpp @@ -33,8 +33,8 @@ * limitations under the License. */ -#include <QJsonObject> #include <QJsonArray> +#include <QJsonObject> #include "Rule.h" @@ -47,7 +47,7 @@ RuleAction RuleAction_fromString(QString name) return Defer; } -QList<std::shared_ptr<Rule>> rulesFromJsonV4(const QJsonObject &objectWithRules) +QList<std::shared_ptr<Rule>> rulesFromJsonV4(const QJsonObject& objectWithRules) { QList<std::shared_ptr<Rule>> rules; auto rulesVal = objectWithRules.value("rules"); @@ -55,8 +55,7 @@ QList<std::shared_ptr<Rule>> rulesFromJsonV4(const QJsonObject &objectWithRules) return rules; QJsonArray ruleList = rulesVal.toArray(); - for (auto ruleVal : ruleList) - { + for (auto ruleVal : ruleList) { std::shared_ptr<Rule> rule; if (!ruleVal.isObject()) continue; @@ -69,8 +68,7 @@ QList<std::shared_ptr<Rule>> rulesFromJsonV4(const QJsonObject &objectWithRules) continue; auto osVal = ruleObj.value("os"); - if (!osVal.isObject()) - { + if (!osVal.isObject()) { // add a new implicit action rule rules.append(ImplicitRule::create(action)); continue; @@ -102,12 +100,10 @@ QJsonObject OsRule::toJson() QJsonObject osObj; { osObj.insert("name", m_system); - if(!m_version_regexp.isEmpty()) - { + if (!m_version_regexp.isEmpty()) { osObj.insert("version", m_version_regexp); } } ruleObj.insert("os", osObj); return ruleObj; } - diff --git a/launcher/minecraft/Rule.h b/launcher/minecraft/Rule.h index 846e8e42..0ece6ae2 100644 --- a/launcher/minecraft/Rule.h +++ b/launcher/minecraft/Rule.h @@ -35,37 +35,29 @@ #pragma once -#include <QString> -#include <QList> #include <QJsonObject> +#include <QList> +#include <QString> #include <memory> #include "RuntimeContext.h" class Library; class Rule; -enum RuleAction -{ - Allow, - Disallow, - Defer -}; +enum RuleAction { Allow, Disallow, Defer }; -QList<std::shared_ptr<Rule>> rulesFromJsonV4(const QJsonObject &objectWithRules); +QList<std::shared_ptr<Rule>> rulesFromJsonV4(const QJsonObject& objectWithRules); -class Rule -{ -protected: +class Rule { + protected: RuleAction m_result; - virtual bool applies(const Library *parent, const RuntimeContext & runtimeContext) = 0; + virtual bool applies(const Library* parent, const RuntimeContext& runtimeContext) = 0; -public: - Rule(RuleAction result) : m_result(result) - { - } - virtual ~Rule() {}; + public: + Rule(RuleAction result) : m_result(result) {} + virtual ~Rule(){}; virtual QJsonObject toJson() = 0; - RuleAction apply(const Library *parent, const RuntimeContext & runtimeContext) + RuleAction apply(const Library* parent, const RuntimeContext& runtimeContext) { if (applies(parent, runtimeContext)) return m_result; @@ -74,48 +66,31 @@ public: } }; -class OsRule : public Rule -{ -private: +class OsRule : public Rule { + private: // the OS QString m_system; // the OS version regexp QString m_version_regexp; -protected: - virtual bool applies(const Library *, const RuntimeContext & runtimeContext) - { - return runtimeContext.classifierMatches(m_system); - } - OsRule(RuleAction result, QString system, QString version_regexp) - : Rule(result), m_system(system), m_version_regexp(version_regexp) - { - } + protected: + virtual bool applies(const Library*, const RuntimeContext& runtimeContext) { return runtimeContext.classifierMatches(m_system); } + OsRule(RuleAction result, QString system, QString version_regexp) : Rule(result), m_system(system), m_version_regexp(version_regexp) {} -public: + public: virtual QJsonObject toJson(); - static std::shared_ptr<OsRule> create(RuleAction result, QString system, - QString version_regexp) + static std::shared_ptr<OsRule> create(RuleAction result, QString system, QString version_regexp) { return std::shared_ptr<OsRule>(new OsRule(result, system, version_regexp)); } }; -class ImplicitRule : public Rule -{ -protected: - virtual bool applies(const Library *, [[maybe_unused]] const RuntimeContext & runtimeContext) - { - return true; - } - ImplicitRule(RuleAction result) : Rule(result) - { - } +class ImplicitRule : public Rule { + protected: + virtual bool applies(const Library*, [[maybe_unused]] const RuntimeContext& runtimeContext) { return true; } + ImplicitRule(RuleAction result) : Rule(result) {} -public: + public: virtual QJsonObject toJson(); - static std::shared_ptr<ImplicitRule> create(RuleAction result) - { - return std::shared_ptr<ImplicitRule>(new ImplicitRule(result)); - } + static std::shared_ptr<ImplicitRule> create(RuleAction result) { return std::shared_ptr<ImplicitRule>(new ImplicitRule(result)); } }; diff --git a/launcher/minecraft/VanillaInstanceCreationTask.cpp b/launcher/minecraft/VanillaInstanceCreationTask.cpp index 0bb92e87..ccbd8c67 100644 --- a/launcher/minecraft/VanillaInstanceCreationTask.cpp +++ b/launcher/minecraft/VanillaInstanceCreationTask.cpp @@ -8,7 +8,11 @@ #include "settings/INISettingsObject.h" VanillaCreationTask::VanillaCreationTask(BaseVersion::Ptr version, QString loader, BaseVersion::Ptr loader_version) - : InstanceCreationTask(), m_version(std::move(version)), m_using_loader(true), m_loader(std::move(loader)), m_loader_version(std::move(loader_version)) + : InstanceCreationTask() + , m_version(std::move(version)) + , m_using_loader(true) + , m_loader(std::move(loader)) + , m_loader_version(std::move(loader_version)) {} bool VanillaCreationTask::createInstance() @@ -22,7 +26,7 @@ bool VanillaCreationTask::createInstance() auto components = inst.getPackProfile(); components->buildingFromScratch(); components->setComponentVersion("net.minecraft", m_version->descriptor(), true); - if(m_using_loader) + if (m_using_loader) components->setComponentVersion(m_loader, m_loader_version->descriptor()); inst.setName(name()); diff --git a/launcher/minecraft/VersionFile.cpp b/launcher/minecraft/VersionFile.cpp index 76f41600..b8aaee90 100644 --- a/launcher/minecraft/VersionFile.cpp +++ b/launcher/minecraft/VersionFile.cpp @@ -39,23 +39,22 @@ #include <QDebug> -#include "minecraft/VersionFile.h" +#include "ParseUtils.h" #include "minecraft/Library.h" #include "minecraft/PackProfile.h" -#include "ParseUtils.h" +#include "minecraft/VersionFile.h" #include <Version.h> -static bool isMinecraftVersion(const QString &uid) +static bool isMinecraftVersion(const QString& uid) { return uid == "net.minecraft"; } -void VersionFile::applyTo(LaunchProfile *profile, const RuntimeContext & runtimeContext) +void VersionFile::applyTo(LaunchProfile* profile, const RuntimeContext& runtimeContext) { // Only real Minecraft can set those. Don't let anything override them. - if (isMinecraftVersion(uid)) - { + if (isMinecraftVersion(uid)) { profile->applyMinecraftVersion(version); profile->applyMinecraftVersionType(type); // HACK: ignore assets from other version files than Minecraft @@ -75,16 +74,13 @@ void VersionFile::applyTo(LaunchProfile *profile, const RuntimeContext & runtime profile->applyTraits(traits); profile->applyCompatibleJavaMajors(compatibleJavaMajors); - for (auto library : libraries) - { + for (auto library : libraries) { profile->applyLibrary(library, runtimeContext); } - for (auto mavenFile : mavenFiles) - { + for (auto mavenFile : mavenFiles) { profile->applyMavenFile(mavenFile, runtimeContext); } - for (auto agent : agents) - { + for (auto agent : agents) { profile->applyAgent(agent, runtimeContext); } profile->applyProblemSeverity(getProblemSeverity()); diff --git a/launcher/minecraft/VersionFile.h b/launcher/minecraft/VersionFile.h index 8e9dd167..d8984a29 100644 --- a/launcher/minecraft/VersionFile.h +++ b/launcher/minecraft/VersionFile.h @@ -35,17 +35,17 @@ #pragma once -#include <QString> -#include <QStringList> #include <QDateTime> #include <QSet> +#include <QString> +#include <QStringList> +#include <meta/JsonFormat.h> #include <memory> -#include "minecraft/Rule.h" -#include "ProblemProvider.h" -#include "Library.h" #include "Agent.h" -#include <meta/JsonFormat.h> +#include "Library.h" +#include "ProblemProvider.h" +#include "minecraft/Rule.h" class PackProfile; class VersionFile; @@ -54,14 +54,14 @@ struct MojangDownloadInfo; struct MojangAssetIndexInfo; using VersionFilePtr = std::shared_ptr<VersionFile>; -class VersionFile : public ProblemContainer -{ +class VersionFile : public ProblemContainer { friend class MojangVersionFormat; friend class OneSixVersionFormat; -public: /* methods */ - void applyTo(LaunchProfile* profile, const RuntimeContext & runtimeContext); -public: /* data */ + public: /* methods */ + void applyTo(LaunchProfile* profile, const RuntimeContext& runtimeContext); + + public: /* data */ /// Prism Launcher: order hint for this version file if no explicit order is set int order = 0; @@ -149,11 +149,10 @@ public: /* data */ /// is volatile -- may be removed as soon as it is no longer needed by something else bool m_volatile = false; -public: + public: // Mojang: DEPRECATED list of 'downloads' - client jar, server jar, windows server exe, maybe more. - QMap <QString, std::shared_ptr<MojangDownloadInfo>> mojangDownloads; + QMap<QString, std::shared_ptr<MojangDownloadInfo>> mojangDownloads; // Mojang: extended asset index download information std::shared_ptr<MojangAssetIndexInfo> mojangAssetIndex; }; - diff --git a/launcher/minecraft/VersionFilterData.cpp b/launcher/minecraft/VersionFilterData.cpp index c286d266..3924e598 100644 --- a/launcher/minecraft/VersionFilterData.cpp +++ b/launcher/minecraft/VersionFilterData.cpp @@ -6,19 +6,17 @@ VersionFilterData g_VersionFilterData = VersionFilterData(); VersionFilterData::VersionFilterData() { // 1.3.* - auto libs13 = - QList<FMLlib>{{"argo-2.25.jar", "bb672829fde76cb163004752b86b0484bd0a7f4b"}, - {"guava-12.0.1.jar", "b8e78b9af7bf45900e14c6f958486b6ca682195f"}, - {"asm-all-4.0.jar", "98308890597acb64047f7e896638e0d98753ae82"}}; + auto libs13 = QList<FMLlib>{ { "argo-2.25.jar", "bb672829fde76cb163004752b86b0484bd0a7f4b" }, + { "guava-12.0.1.jar", "b8e78b9af7bf45900e14c6f958486b6ca682195f" }, + { "asm-all-4.0.jar", "98308890597acb64047f7e896638e0d98753ae82" } }; fmlLibsMapping["1.3.2"] = libs13; // 1.4.* - auto libs14 = QList<FMLlib>{ - {"argo-2.25.jar", "bb672829fde76cb163004752b86b0484bd0a7f4b"}, - {"guava-12.0.1.jar", "b8e78b9af7bf45900e14c6f958486b6ca682195f"}, - {"asm-all-4.0.jar", "98308890597acb64047f7e896638e0d98753ae82"}, - {"bcprov-jdk15on-147.jar", "b6f5d9926b0afbde9f4dbe3db88c5247be7794bb"}}; + auto libs14 = QList<FMLlib>{ { "argo-2.25.jar", "bb672829fde76cb163004752b86b0484bd0a7f4b" }, + { "guava-12.0.1.jar", "b8e78b9af7bf45900e14c6f958486b6ca682195f" }, + { "asm-all-4.0.jar", "98308890597acb64047f7e896638e0d98753ae82" }, + { "bcprov-jdk15on-147.jar", "b6f5d9926b0afbde9f4dbe3db88c5247be7794bb" } }; fmlLibsMapping["1.4"] = libs14; fmlLibsMapping["1.4.1"] = libs14; @@ -30,43 +28,38 @@ VersionFilterData::VersionFilterData() fmlLibsMapping["1.4.7"] = libs14; // 1.5 - fmlLibsMapping["1.5"] = QList<FMLlib>{ - {"argo-small-3.2.jar", "58912ea2858d168c50781f956fa5b59f0f7c6b51"}, - {"guava-14.0-rc3.jar", "931ae21fa8014c3ce686aaa621eae565fefb1a6a"}, - {"asm-all-4.1.jar", "054986e962b88d8660ae4566475658469595ef58"}, - {"bcprov-jdk15on-148.jar", "960dea7c9181ba0b17e8bab0c06a43f0a5f04e65"}, - {"deobfuscation_data_1.5.zip", "5f7c142d53776f16304c0bbe10542014abad6af8"}, - {"scala-library.jar", "458d046151ad179c85429ed7420ffb1eaf6ddf85"}}; + fmlLibsMapping["1.5"] = QList<FMLlib>{ { "argo-small-3.2.jar", "58912ea2858d168c50781f956fa5b59f0f7c6b51" }, + { "guava-14.0-rc3.jar", "931ae21fa8014c3ce686aaa621eae565fefb1a6a" }, + { "asm-all-4.1.jar", "054986e962b88d8660ae4566475658469595ef58" }, + { "bcprov-jdk15on-148.jar", "960dea7c9181ba0b17e8bab0c06a43f0a5f04e65" }, + { "deobfuscation_data_1.5.zip", "5f7c142d53776f16304c0bbe10542014abad6af8" }, + { "scala-library.jar", "458d046151ad179c85429ed7420ffb1eaf6ddf85" } }; // 1.5.1 - fmlLibsMapping["1.5.1"] = QList<FMLlib>{ - {"argo-small-3.2.jar", "58912ea2858d168c50781f956fa5b59f0f7c6b51"}, - {"guava-14.0-rc3.jar", "931ae21fa8014c3ce686aaa621eae565fefb1a6a"}, - {"asm-all-4.1.jar", "054986e962b88d8660ae4566475658469595ef58"}, - {"bcprov-jdk15on-148.jar", "960dea7c9181ba0b17e8bab0c06a43f0a5f04e65"}, - {"deobfuscation_data_1.5.1.zip", "22e221a0d89516c1f721d6cab056a7e37471d0a6"}, - {"scala-library.jar", "458d046151ad179c85429ed7420ffb1eaf6ddf85"}}; + fmlLibsMapping["1.5.1"] = QList<FMLlib>{ { "argo-small-3.2.jar", "58912ea2858d168c50781f956fa5b59f0f7c6b51" }, + { "guava-14.0-rc3.jar", "931ae21fa8014c3ce686aaa621eae565fefb1a6a" }, + { "asm-all-4.1.jar", "054986e962b88d8660ae4566475658469595ef58" }, + { "bcprov-jdk15on-148.jar", "960dea7c9181ba0b17e8bab0c06a43f0a5f04e65" }, + { "deobfuscation_data_1.5.1.zip", "22e221a0d89516c1f721d6cab056a7e37471d0a6" }, + { "scala-library.jar", "458d046151ad179c85429ed7420ffb1eaf6ddf85" } }; // 1.5.2 - fmlLibsMapping["1.5.2"] = QList<FMLlib>{ - {"argo-small-3.2.jar", "58912ea2858d168c50781f956fa5b59f0f7c6b51"}, - {"guava-14.0-rc3.jar", "931ae21fa8014c3ce686aaa621eae565fefb1a6a"}, - {"asm-all-4.1.jar", "054986e962b88d8660ae4566475658469595ef58"}, - {"bcprov-jdk15on-148.jar", "960dea7c9181ba0b17e8bab0c06a43f0a5f04e65"}, - {"deobfuscation_data_1.5.2.zip", "446e55cd986582c70fcf12cb27bc00114c5adfd9"}, - {"scala-library.jar", "458d046151ad179c85429ed7420ffb1eaf6ddf85"}}; + fmlLibsMapping["1.5.2"] = QList<FMLlib>{ { "argo-small-3.2.jar", "58912ea2858d168c50781f956fa5b59f0f7c6b51" }, + { "guava-14.0-rc3.jar", "931ae21fa8014c3ce686aaa621eae565fefb1a6a" }, + { "asm-all-4.1.jar", "054986e962b88d8660ae4566475658469595ef58" }, + { "bcprov-jdk15on-148.jar", "960dea7c9181ba0b17e8bab0c06a43f0a5f04e65" }, + { "deobfuscation_data_1.5.2.zip", "446e55cd986582c70fcf12cb27bc00114c5adfd9" }, + { "scala-library.jar", "458d046151ad179c85429ed7420ffb1eaf6ddf85" } }; // don't use installers for those. - forgeInstallerBlacklist = QSet<QString>({"1.5.2"}); + forgeInstallerBlacklist = QSet<QString>({ "1.5.2" }); // FIXME: remove, used for deciding when core mods should display legacyCutoffDate = timeFromS3Time("2013-06-25T15:08:56+02:00"); - lwjglWhitelist = - QSet<QString>{"net.java.jinput:jinput", "net.java.jinput:jinput-platform", - "net.java.jutils:jutils", "org.lwjgl.lwjgl:lwjgl", - "org.lwjgl.lwjgl:lwjgl_util", "org.lwjgl.lwjgl:lwjgl-platform"}; + lwjglWhitelist = QSet<QString>{ "net.java.jinput:jinput", "net.java.jinput:jinput-platform", "net.java.jutils:jutils", + "org.lwjgl.lwjgl:lwjgl", "org.lwjgl.lwjgl:lwjgl_util", "org.lwjgl.lwjgl:lwjgl-platform" }; - java8BeginsDate = timeFromS3Time("2017-03-30T09:32:19+00:00"); + java8BeginsDate = timeFromS3Time("2017-03-30T09:32:19+00:00"); java16BeginsDate = timeFromS3Time("2021-05-12T11:19:15+00:00"); java17BeginsDate = timeFromS3Time("2021-11-16T17:04:48+00:00"); } diff --git a/launcher/minecraft/VersionFilterData.h b/launcher/minecraft/VersionFilterData.h index 13445a51..bcd329b6 100644 --- a/launcher/minecraft/VersionFilterData.h +++ b/launcher/minecraft/VersionFilterData.h @@ -1,17 +1,15 @@ #pragma once +#include <QDateTime> #include <QMap> -#include <QString> #include <QSet> -#include <QDateTime> +#include <QString> -struct FMLlib -{ +struct FMLlib { QString filename; QString checksum; }; -struct VersionFilterData -{ +struct VersionFilterData { VersionFilterData(); // mapping between minecraft versions and FML libraries required QMap<QString, QList<FMLlib>> fmlLibsMapping; diff --git a/launcher/minecraft/World.cpp b/launcher/minecraft/World.cpp index 54fb9434..62e0279a 100644 --- a/launcher/minecraft/World.cpp +++ b/launcher/minecraft/World.cpp @@ -34,23 +34,23 @@ * limitations under the License. */ -#include <QDir> -#include <QString> +#include "World.h" #include <QDebug> -#include <QSaveFile> +#include <QDir> #include <QDirIterator> -#include "World.h" +#include <QSaveFile> +#include <QString> -#include "GZip.h" -#include <MMCZip.h> #include <FileSystem.h> -#include <sstream> +#include <MMCZip.h> #include <io/stream_reader.h> -#include <tag_string.h> -#include <tag_primitive.h> #include <quazip/quazip.h> -#include <quazip/quazipfile.h> #include <quazip/quazipdir.h> +#include <quazip/quazipfile.h> +#include <tag_primitive.h> +#include <tag_string.h> +#include <sstream> +#include "GZip.h" #include <QCoreApplication> @@ -58,16 +58,15 @@ #include "FileSystem.h" -using std::optional; using std::nullopt; +using std::optional; -GameType::GameType(std::optional<int> original): - original(original) +GameType::GameType(std::optional<int> original) : original(original) { - if(!original) { + if (!original) { return; } - switch(*original) { + switch (*original) { case 0: type = GameType::Survival; break; @@ -87,8 +86,7 @@ GameType::GameType(std::optional<int> original): QString GameType::toTranslatedString() const { - switch (type) - { + switch (type) { case GameType::Survival: return QCoreApplication::translate("GameType", "Survival"); case GameType::Creative: @@ -100,7 +98,7 @@ QString GameType::toTranslatedString() const default: break; } - if(original) { + if (original) { return QCoreApplication::translate("GameType", "Unknown (%1)").arg(*original); } return QCoreApplication::translate("GameType", "Undefined"); @@ -108,8 +106,7 @@ QString GameType::toTranslatedString() const QString GameType::toLogString() const { - switch (type) - { + switch (type) { case GameType::Survival: return "Survival"; case GameType::Creative: @@ -121,108 +118,94 @@ QString GameType::toLogString() const default: break; } - if(original) { + if (original) { return QString("Unknown (%1)").arg(*original); } return "Undefined"; } -std::unique_ptr <nbt::tag_compound> parseLevelDat(QByteArray data) +std::unique_ptr<nbt::tag_compound> parseLevelDat(QByteArray data) { QByteArray output; - if(!GZip::unzip(data, output)) - { + if (!GZip::unzip(data, output)) { return nullptr; } std::istringstream foo(std::string(output.constData(), output.size())); try { auto pair = nbt::io::read_compound(foo); - if(pair.first != "") + if (pair.first != "") return nullptr; - if(pair.second == nullptr) + if (pair.second == nullptr) return nullptr; return std::move(pair.second); - } - catch (const nbt::io::input_error &e) - { + } catch (const nbt::io::input_error& e) { qWarning() << "Unable to parse level.dat:" << e.what(); return nullptr; } } -QByteArray serializeLevelDat(nbt::tag_compound * levelInfo) +QByteArray serializeLevelDat(nbt::tag_compound* levelInfo) { std::ostringstream s; nbt::io::write_tag("", *levelInfo, s); - QByteArray val( s.str().data(), (int) s.str().size() ); + QByteArray val(s.str().data(), (int)s.str().size()); return val; } -QString getLevelDatFromFS(const QFileInfo &file) +QString getLevelDatFromFS(const QFileInfo& file) { QDir worldDir(file.filePath()); - if(!file.isDir() || !worldDir.exists("level.dat")) - { + if (!file.isDir() || !worldDir.exists("level.dat")) { return QString(); } return worldDir.absoluteFilePath("level.dat"); } -QByteArray getLevelDatDataFromFS(const QFileInfo &file) +QByteArray getLevelDatDataFromFS(const QFileInfo& file) { auto fullFilePath = getLevelDatFromFS(file); - if(fullFilePath.isNull()) - { + if (fullFilePath.isNull()) { return QByteArray(); } QFile f(fullFilePath); - if(!f.open(QIODevice::ReadOnly)) - { + if (!f.open(QIODevice::ReadOnly)) { return QByteArray(); } return f.readAll(); } -bool putLevelDatDataToFS(const QFileInfo &file, QByteArray & data) +bool putLevelDatDataToFS(const QFileInfo& file, QByteArray& data) { - auto fullFilePath = getLevelDatFromFS(file); - if(fullFilePath.isNull()) - { + auto fullFilePath = getLevelDatFromFS(file); + if (fullFilePath.isNull()) { return false; } QSaveFile f(fullFilePath); - if(!f.open(QIODevice::WriteOnly)) - { + if (!f.open(QIODevice::WriteOnly)) { return false; } QByteArray compressed; - if(!GZip::zip(data, compressed)) - { + if (!GZip::zip(data, compressed)) { return false; } - if(f.write(compressed) != compressed.size()) - { + if (f.write(compressed) != compressed.size()) { f.cancelWriting(); return false; } return f.commit(); } -int64_t calculateWorldSize(const QFileInfo &file) +int64_t calculateWorldSize(const QFileInfo& file) { - if (file.isFile() && file.suffix() == "zip") - { + if (file.isFile() && file.suffix() == "zip") { return file.size(); - } - else if(file.isDir()) - { + } else if (file.isDir()) { QDirIterator it(file.absoluteFilePath(), QDir::Files, QDirIterator::Subdirectories); int64_t total = 0; - while (it.hasNext()) - { + while (it.hasNext()) { total += it.fileInfo().size(); it.next(); } @@ -231,25 +214,22 @@ int64_t calculateWorldSize(const QFileInfo &file) return -1; } -World::World(const QFileInfo &file) +World::World(const QFileInfo& file) { repath(file); } -void World::repath(const QFileInfo &file) +void World::repath(const QFileInfo& file) { m_containerFile = file; m_folderName = file.fileName(); m_size = calculateWorldSize(file); - if(file.isFile() && file.suffix() == "zip") - { + if (file.isFile() && file.suffix() == "zip") { m_iconFile = QString(); readFromZip(file); - } - else if(file.isDir()) - { + } else if (file.isDir()) { QFileInfo assumedIconPath(file.absoluteFilePath() + "/icon.png"); - if(assumedIconPath.exists()) { + if (assumedIconPath.exists()) { m_iconFile = assumedIconPath.absoluteFilePath(); } readFromFS(file); @@ -258,21 +238,20 @@ void World::repath(const QFileInfo &file) bool World::resetIcon() { - if(m_iconFile.isNull()) { + if (m_iconFile.isNull()) { return false; } - if(QFile(m_iconFile).remove()) { + if (QFile(m_iconFile).remove()) { m_iconFile = QString(); return true; } return false; } -void World::readFromFS(const QFileInfo &file) +void World::readFromFS(const QFileInfo& file) { auto bytes = getLevelDatDataFromFS(file); - if(bytes.isEmpty()) - { + if (bytes.isEmpty()) { is_valid = false; return; } @@ -280,104 +259,88 @@ void World::readFromFS(const QFileInfo &file) levelDatTime = file.lastModified(); } -void World::readFromZip(const QFileInfo &file) +void World::readFromZip(const QFileInfo& file) { QuaZip zip(file.absoluteFilePath()); is_valid = zip.open(QuaZip::mdUnzip); - if (!is_valid) - { + if (!is_valid) { return; } auto location = MMCZip::findFolderOfFileInZip(&zip, "level.dat"); is_valid = !location.isEmpty(); - if (!is_valid) - { + if (!is_valid) { return; } m_containerOffsetPath = location; QuaZipFile zippedFile(&zip); // read the install profile is_valid = zip.setCurrentFile(location + "level.dat"); - if (!is_valid) - { + if (!is_valid) { return; } is_valid = zippedFile.open(QIODevice::ReadOnly); QuaZipFileInfo64 levelDatInfo; zippedFile.getFileInfo(&levelDatInfo); auto modTime = levelDatInfo.getNTFSmTime(); - if(!modTime.isValid()) - { + if (!modTime.isValid()) { modTime = levelDatInfo.dateTime; } levelDatTime = modTime; - if (!is_valid) - { + if (!is_valid) { return; } loadFromLevelDat(zippedFile.readAll()); zippedFile.close(); } -bool World::install(const QString &to, const QString &name) +bool World::install(const QString& to, const QString& name) { auto finalPath = FS::PathCombine(to, FS::DirNameFromString(m_actualName, to)); - if(!FS::ensureFolderPathExists(finalPath)) - { + if (!FS::ensureFolderPathExists(finalPath)) { return false; } bool ok = false; - if(m_containerFile.isFile()) - { + if (m_containerFile.isFile()) { QuaZip zip(m_containerFile.absoluteFilePath()); - if (!zip.open(QuaZip::mdUnzip)) - { + if (!zip.open(QuaZip::mdUnzip)) { return false; } ok = !MMCZip::extractSubDir(&zip, m_containerOffsetPath, finalPath); - } - else if(m_containerFile.isDir()) - { + } else if (m_containerFile.isDir()) { QString from = m_containerFile.filePath(); ok = FS::copy(from, finalPath)(); } - if(ok && !name.isEmpty() && m_actualName != name) - { + if (ok && !name.isEmpty() && m_actualName != name) { QFileInfo finalPathInfo(finalPath); World newWorld(finalPathInfo); - if(newWorld.isValid()) - { + if (newWorld.isValid()) { newWorld.rename(name); } } return ok; } -bool World::rename(const QString &newName) +bool World::rename(const QString& newName) { - if(m_containerFile.isFile()) - { + if (m_containerFile.isFile()) { return false; } auto data = getLevelDatDataFromFS(m_containerFile); - if(data.isEmpty()) - { + if (data.isEmpty()) { return false; } auto worldData = parseLevelDat(data); - if(!worldData) - { + if (!worldData) { return false; } - auto &val = worldData->at("Data"); - if(val.get_type() != nbt::tag_type::Compound) - { + auto& val = worldData->at("Data"); + if (val.get_type() != nbt::tag_type::Compound) { return false; } - auto &dataCompound = val.as<nbt::tag_compound>(); + auto& dataCompound = val.as<nbt::tag_compound>(); dataCompound.put("LevelName", nbt::value_initializer(newName.toUtf8().data())); data = serializeLevelDat(worldData.get()); @@ -396,112 +359,93 @@ bool World::rename(const QString &newName) namespace { -optional<QString> read_string (nbt::value& parent, const char * name) +optional<QString> read_string(nbt::value& parent, const char* name) { - try - { - auto &namedValue = parent.at(name); - if(namedValue.get_type() != nbt::tag_type::String) - { + try { + auto& namedValue = parent.at(name); + if (namedValue.get_type() != nbt::tag_type::String) { return nullopt; } - auto & tag_str = namedValue.as<nbt::tag_string>(); + auto& tag_str = namedValue.as<nbt::tag_string>(); return QString::fromStdString(tag_str.get()); - } - catch (const std::out_of_range &e) - { + } catch (const std::out_of_range& e) { // fallback for old world formats qWarning() << "String NBT tag" << name << "could not be found."; return nullopt; - } - catch (const std::bad_cast &e) - { + } catch (const std::bad_cast& e) { // type mismatch qWarning() << "NBT tag" << name << "could not be converted to string."; return nullopt; } } -optional<int64_t> read_long (nbt::value& parent, const char * name) +optional<int64_t> read_long(nbt::value& parent, const char* name) { - try - { - auto &namedValue = parent.at(name); - if(namedValue.get_type() != nbt::tag_type::Long) - { + try { + auto& namedValue = parent.at(name); + if (namedValue.get_type() != nbt::tag_type::Long) { return nullopt; } - auto & tag_str = namedValue.as<nbt::tag_long>(); + auto& tag_str = namedValue.as<nbt::tag_long>(); return tag_str.get(); - } - catch (const std::out_of_range &e) - { + } catch (const std::out_of_range& e) { // fallback for old world formats qWarning() << "Long NBT tag" << name << "could not be found."; return nullopt; - } - catch (const std::bad_cast &e) - { + } catch (const std::bad_cast& e) { // type mismatch qWarning() << "NBT tag" << name << "could not be converted to long."; return nullopt; } } -optional<int> read_int (nbt::value& parent, const char * name) +optional<int> read_int(nbt::value& parent, const char* name) { - try - { - auto &namedValue = parent.at(name); - if(namedValue.get_type() != nbt::tag_type::Int) - { + try { + auto& namedValue = parent.at(name); + if (namedValue.get_type() != nbt::tag_type::Int) { return nullopt; } - auto & tag_str = namedValue.as<nbt::tag_int>(); + auto& tag_str = namedValue.as<nbt::tag_int>(); return tag_str.get(); - } - catch (const std::out_of_range &e) - { + } catch (const std::out_of_range& e) { // fallback for old world formats qWarning() << "Int NBT tag" << name << "could not be found."; return nullopt; - } - catch (const std::bad_cast &e) - { + } catch (const std::bad_cast& e) { // type mismatch qWarning() << "NBT tag" << name << "could not be converted to int."; return nullopt; } } -GameType read_gametype(nbt::value& parent, const char * name) { +GameType read_gametype(nbt::value& parent, const char* name) +{ return GameType(read_int(parent, name)); } -} +} // namespace void World::loadFromLevelDat(QByteArray data) { auto levelData = parseLevelDat(data); - if(!levelData) - { + if (!levelData) { is_valid = false; return; } - nbt::value * valPtr = nullptr; + nbt::value* valPtr = nullptr; try { valPtr = &levelData->at("Data"); - } - catch (const std::out_of_range &e) { + } catch (const std::out_of_range& e) { qWarning() << "Unable to read NBT tags from " << m_folderName << ":" << e.what(); is_valid = false; return; } - nbt::value &val = *valPtr; + nbt::value& val = *valPtr; is_valid = val.get_type() == nbt::tag_type::Compound; - if(!is_valid) + if (!is_valid) return; auto name = read_string(val, "LevelName"); @@ -514,31 +458,30 @@ void World::loadFromLevelDat(QByteArray data) optional<int64_t> randomSeed; try { - auto &WorldGen_val = val.at("WorldGenSettings"); + auto& WorldGen_val = val.at("WorldGenSettings"); randomSeed = read_long(WorldGen_val, "seed"); + } catch (const std::out_of_range&) { } - catch (const std::out_of_range &) {} - if(!randomSeed) { + if (!randomSeed) { randomSeed = read_long(val, "RandomSeed"); } m_randomSeed = randomSeed ? *randomSeed : 0; qDebug() << "World Name:" << m_actualName; qDebug() << "Last Played:" << m_lastPlayed.toString(); - if(randomSeed) { + if (randomSeed) { qDebug() << "Seed:" << *randomSeed; } qDebug() << "Size:" << m_size; qDebug() << "GameType:" << m_gameType.toLogString(); } -bool World::replace(World &with) +bool World::replace(World& with) { if (!destroy()) return false; bool success = FS::copy(with.m_containerFile.filePath(), m_containerFile.path())(); - if (success) - { + if (success) { m_folderName = with.m_folderName; m_containerFile.refresh(); } @@ -547,25 +490,23 @@ bool World::replace(World &with) bool World::destroy() { - if(!is_valid) return false; + if (!is_valid) + return false; if (FS::trash(m_containerFile.filePath())) return true; - if (m_containerFile.isDir()) - { + if (m_containerFile.isDir()) { QDir d(m_containerFile.filePath()); return d.removeRecursively(); - } - else if(m_containerFile.isFile()) - { + } else if (m_containerFile.isFile()) { QFile file(m_containerFile.absoluteFilePath()); return file.remove(); } return true; } -bool World::operator==(const World &other) const +bool World::operator==(const World& other) const { return is_valid == other.is_valid && folderName() == other.folderName(); } @@ -585,8 +526,7 @@ bool World::isSymLinkUnder(const QString& instPath) const bool World::isMoreThanOneHardLink() const { - if (m_containerFile.isDir()) - { + if (m_containerFile.isDir()) { return FS::hardLinkCount(QDir(m_containerFile.absoluteFilePath()).filePath("level.dat")) > 1; } return FS::hardLinkCount(m_containerFile.absoluteFilePath()) > 1; diff --git a/launcher/minecraft/World.h b/launcher/minecraft/World.h index dc3733d5..4303dc55 100644 --- a/launcher/minecraft/World.h +++ b/launcher/minecraft/World.h @@ -14,95 +14,57 @@ */ #pragma once -#include <QFileInfo> #include <QDateTime> +#include <QFileInfo> #include <optional> struct GameType { GameType() = default; - GameType (std::optional<int> original); + GameType(std::optional<int> original); QString toTranslatedString() const; QString toLogString() const; - enum - { - Unknown = -1, - Survival, - Creative, - Adventure, - Spectator - } type = Unknown; + enum { Unknown = -1, Survival, Creative, Adventure, Spectator } type = Unknown; std::optional<int> original; }; -class World -{ -public: - World(const QFileInfo &file); - QString folderName() const - { - return m_folderName; - } - QString name() const - { - return m_actualName; - } - QString iconFile() const - { - return m_iconFile; - } - int64_t bytes() const - { - return m_size; - } - QDateTime lastPlayed() const - { - return m_lastPlayed; - } - GameType gameType() const - { - return m_gameType; - } - int64_t seed() const - { - return m_randomSeed; - } - bool isValid() const - { - return is_valid; - } - bool isOnFS() const - { - return m_containerFile.isDir(); - } - QFileInfo container() const - { - return m_containerFile; - } +class World { + public: + World(const QFileInfo& file); + QString folderName() const { return m_folderName; } + QString name() const { return m_actualName; } + QString iconFile() const { return m_iconFile; } + int64_t bytes() const { return m_size; } + QDateTime lastPlayed() const { return m_lastPlayed; } + GameType gameType() const { return m_gameType; } + int64_t seed() const { return m_randomSeed; } + bool isValid() const { return is_valid; } + bool isOnFS() const { return m_containerFile.isDir(); } + QFileInfo container() const { return m_containerFile; } // delete all the files of this world bool destroy(); // replace this world with a copy of the other - bool replace(World &with); + bool replace(World& with); // change the world's filesystem path (used by world lists for *MAGIC* purposes) - void repath(const QFileInfo &file); + void repath(const QFileInfo& file); // remove the icon file, if any bool resetIcon(); - bool rename(const QString &to); - bool install(const QString &to, const QString &name= QString()); + bool rename(const QString& to); + bool install(const QString& to, const QString& name = QString()); // WEAK compare operator - used for replacing worlds - bool operator==(const World &other) const; + bool operator==(const World& other) const; - [[nodiscard]] auto isSymLink() const -> bool{ return m_containerFile.isSymLink(); } + [[nodiscard]] auto isSymLink() const -> bool { return m_containerFile.isSymLink(); } /** * @brief Take a instance path, checks if the file pointed to by the resource is a symlink or under a symlink in that instance - * + * * @param instPath path to an instance directory - * @return true - * @return false + * @return true + * @return false */ [[nodiscard]] bool isSymLinkUnder(const QString& instPath) const; @@ -110,13 +72,12 @@ public: QString canonicalFilePath() const { return m_containerFile.canonicalFilePath(); } -private: - void readFromZip(const QFileInfo &file); - void readFromFS(const QFileInfo &file); + private: + void readFromZip(const QFileInfo& file); + void readFromFS(const QFileInfo& file); void loadFromLevelDat(QByteArray data); -protected: - + protected: QFileInfo m_containerFile; QString m_containerOffsetPath; QString m_folderName; diff --git a/launcher/minecraft/WorldList.cpp b/launcher/minecraft/WorldList.cpp index 0feee299..c55742eb 100644 --- a/launcher/minecraft/WorldList.cpp +++ b/launcher/minecraft/WorldList.cpp @@ -35,18 +35,17 @@ #include "WorldList.h" -#include "Application.h" #include <FileSystem.h> -#include <Qt> +#include <QDebug> +#include <QFileSystemWatcher> #include <QMimeData> +#include <QString> #include <QUrl> #include <QUuid> -#include <QString> -#include <QFileSystemWatcher> -#include <QDebug> +#include <Qt> +#include "Application.h" -WorldList::WorldList(const QString &dir, BaseInstance* instance) - : QAbstractListModel(), m_instance(instance), m_dir(dir) +WorldList::WorldList(const QString& dir, BaseInstance* instance) : QAbstractListModel(), m_instance(instance), m_dir(dir) { FS::ensureFolderPathExists(m_dir.absolutePath()); m_dir.setFilter(QDir::Readable | QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); @@ -58,35 +57,27 @@ WorldList::WorldList(const QString &dir, BaseInstance* instance) void WorldList::startWatching() { - if(is_watching) - { + if (is_watching) { return; } update(); is_watching = m_watcher->addPath(m_dir.absolutePath()); - if (is_watching) - { + if (is_watching) { qDebug() << "Started watching " << m_dir.absolutePath(); - } - else - { + } else { qDebug() << "Failed to start watching " << m_dir.absolutePath(); } } void WorldList::stopWatching() { - if(!is_watching) - { + if (!is_watching) { return; } is_watching = !m_watcher->removePath(m_dir.absolutePath()); - if (!is_watching) - { + if (!is_watching) { qDebug() << "Stopped watching " << m_dir.absolutePath(); - } - else - { + } else { qDebug() << "Failed to stop watching " << m_dir.absolutePath(); } } @@ -100,14 +91,12 @@ bool WorldList::update() m_dir.refresh(); auto folderContents = m_dir.entryInfoList(); // if there are any untracked files... - for (QFileInfo entry : folderContents) - { - if(!entry.isDir()) + for (QFileInfo entry : folderContents) { + if (!entry.isDir()) continue; World w(entry); - if(w.isValid()) - { + if (w.isValid()) { newWorlds.append(w); } } @@ -127,7 +116,8 @@ bool WorldList::isValid() return m_dir.exists() && m_dir.isReadable(); } -QString WorldList::instDirPath() const { +QString WorldList::instDirPath() const +{ return QFileInfo(m_instance->instanceRoot()).absoluteFilePath(); } @@ -135,9 +125,8 @@ bool WorldList::deleteWorld(int index) { if (index >= worlds.size() || index < 0) return false; - World &m = worlds[index]; - if (m.destroy()) - { + World& m = worlds[index]; + if (m.destroy()) { beginRemoveRows(QModelIndex(), index, index); worlds.removeAt(index); endRemoveRows(); @@ -149,9 +138,8 @@ bool WorldList::deleteWorld(int index) bool WorldList::deleteWorlds(int first, int last) { - for (int i = first; i <= last; i++) - { - World &m = worlds[i]; + for (int i = first; i <= last; i++) { + World& m = worlds[i]; m.destroy(); } beginRemoveRows(QModelIndex(), first, last); @@ -165,21 +153,20 @@ bool WorldList::resetIcon(int row) { if (row >= worlds.size() || row < 0) return false; - World &m = worlds[row]; - if(m.resetIcon()) { - emit dataChanged(index(row), index(row), {WorldList::IconFileRole}); + World& m = worlds[row]; + if (m.resetIcon()) { + emit dataChanged(index(row), index(row), { WorldList::IconFileRole }); return true; } return false; } - -int WorldList::columnCount(const QModelIndex &parent) const +int WorldList::columnCount(const QModelIndex& parent) const { - return parent.isValid()? 0 : 5; + return parent.isValid() ? 0 : 5; } -QVariant WorldList::data(const QModelIndex &index, int role) const +QVariant WorldList::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); @@ -192,133 +179,120 @@ QVariant WorldList::data(const QModelIndex &index, int role) const QLocale locale; - auto & world = worlds[row]; - switch (role) - { - case Qt::DisplayRole: - switch (column) - { - case NameColumn: - return world.name(); - - case GameModeColumn: - return world.gameType().toTranslatedString(); - - case LastPlayedColumn: - return world.lastPlayed(); + auto& world = worlds[row]; + switch (role) { + case Qt::DisplayRole: + switch (column) { + case NameColumn: + return world.name(); + + case GameModeColumn: + return world.gameType().toTranslatedString(); + + case LastPlayedColumn: + return world.lastPlayed(); + + case SizeColumn: + return locale.formattedDataSize(world.bytes()); + + case InfoColumn: + if (world.isSymLinkUnder(instDirPath())) { + return tr("This world is symbolically linked from elsewhere."); + } + if (world.isMoreThanOneHardLink()) { + return tr("\nThis world is hard linked elsewhere."); + } + return ""; + default: + return QVariant(); + } - case SizeColumn: - return locale.formattedDataSize(world.bytes()); + case Qt::UserRole: + switch (column) { + case SizeColumn: + return QVariant::fromValue<qlonglong>(world.bytes()); - case InfoColumn: - if (world.isSymLinkUnder(instDirPath())) { - return tr("This world is symbolically linked from elsewhere."); + default: + return data(index, Qt::DisplayRole); } - if (world.isMoreThanOneHardLink()) { - return tr("\nThis world is hard linked elsewhere."); + + case Qt::ToolTipRole: { + if (column == InfoColumn) { + if (world.isSymLinkUnder(instDirPath())) { + return tr("Warning: This world is symbolically linked from elsewhere. Editing it will also change the original." + "\nCanonical Path: %1") + .arg(world.canonicalFilePath()); + } + if (world.isMoreThanOneHardLink()) { + return tr("Warning: This world is hard linked elsewhere. Editing it will also change the original."); + } } - return ""; - default: - return QVariant(); + return world.folderName(); } - - case Qt::UserRole: - switch (column) - { - case SizeColumn: - return QVariant::fromValue<qlonglong>(world.bytes()); - - default: - return data(index, Qt::DisplayRole); + case ObjectRole: { + return QVariant::fromValue<void*>((void*)&world); } - - case Qt::ToolTipRole: - { - if (column == InfoColumn) { - if (world.isSymLinkUnder(instDirPath())) { - return tr("Warning: This world is symbolically linked from elsewhere. Editing it will also change the original." - "\nCanonical Path: %1").arg(world.canonicalFilePath()); - } - if (world.isMoreThanOneHardLink()) { - return tr("Warning: This world is hard linked elsewhere. Editing it will also change the original."); - } + case FolderRole: { + return QDir::toNativeSeparators(dir().absoluteFilePath(world.folderName())); } - return world.folderName(); - } - case ObjectRole: - { - return QVariant::fromValue<void *>((void *)&world); - } - case FolderRole: - { - return QDir::toNativeSeparators(dir().absoluteFilePath(world.folderName())); - } - case SeedRole: - { - return QVariant::fromValue<qlonglong>(world.seed()); - } - case NameRole: - { - return world.name(); - } - case LastPlayedRole: - { - return world.lastPlayed(); - } - case SizeRole: - { - return QVariant::fromValue<qlonglong>(world.bytes()); - } - case IconFileRole: - { - return world.iconFile(); - } - default: - return QVariant(); + case SeedRole: { + return QVariant::fromValue<qlonglong>(world.seed()); + } + case NameRole: { + return world.name(); + } + case LastPlayedRole: { + return world.lastPlayed(); + } + case SizeRole: { + return QVariant::fromValue<qlonglong>(world.bytes()); + } + case IconFileRole: { + return world.iconFile(); + } + default: + return QVariant(); } } QVariant WorldList::headerData(int section, Qt::Orientation orientation, int role) const { - switch (role) - { - case Qt::DisplayRole: - switch (section) - { - case NameColumn: - return tr("Name"); - case GameModeColumn: - return tr("Game Mode"); - case LastPlayedColumn: - return tr("Last Played"); - case SizeColumn: - //: World size on disk - return tr("Size"); - case InfoColumn: - //: special warnings? - return tr("Info"); - default: - return QVariant(); - } + switch (role) { + case Qt::DisplayRole: + switch (section) { + case NameColumn: + return tr("Name"); + case GameModeColumn: + return tr("Game Mode"); + case LastPlayedColumn: + return tr("Last Played"); + case SizeColumn: + //: World size on disk + return tr("Size"); + case InfoColumn: + //: special warnings? + return tr("Info"); + default: + return QVariant(); + } - case Qt::ToolTipRole: - switch (section) - { - case NameColumn: - return tr("The name of the world."); - case GameModeColumn: - return tr("Game mode of the world."); - case LastPlayedColumn: - return tr("Date and time the world was last played."); - case SizeColumn: - return tr("Size of the world on disk."); - case InfoColumn: - return tr("Information and warnings about the world."); + case Qt::ToolTipRole: + switch (section) { + case NameColumn: + return tr("The name of the world."); + case GameModeColumn: + return tr("Game mode of the world."); + case LastPlayedColumn: + return tr("Date and time the world was last played."); + case SizeColumn: + return tr("Size of the world on disk."); + case InfoColumn: + return tr("Information and warnings about the world."); + default: + return QVariant(); + } default: return QVariant(); - } - default: - return QVariant(); } return QVariant(); } @@ -330,32 +304,23 @@ QStringList WorldList::mimeTypes() const return types; } -class WorldMimeData : public QMimeData -{ -Q_OBJECT - -public: - WorldMimeData(QList<World> worlds) - { - m_worlds = worlds; +class WorldMimeData : public QMimeData { + Q_OBJECT - } - QStringList formats() const - { - return QMimeData::formats() << "text/uri-list"; - } + public: + WorldMimeData(QList<World> worlds) { m_worlds = worlds; } + QStringList formats() const { return QMimeData::formats() << "text/uri-list"; } -protected: + protected: #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - QVariant retrieveData(const QString &mimetype, QMetaType type) const + QVariant retrieveData(const QString& mimetype, QMetaType type) const #else - QVariant retrieveData(const QString &mimetype, QVariant::Type type) const + QVariant retrieveData(const QString& mimetype, QVariant::Type type) const #endif { QList<QUrl> urls; - for(auto &world: m_worlds) - { - if(!world.isValid() || !world.isOnFS()) + for (auto& world : m_worlds) { + if (!world.isValid() || !world.isOnFS()) continue; QString worldPath = world.container().absoluteFilePath(); qDebug() << worldPath; @@ -364,38 +329,36 @@ protected: const_cast<WorldMimeData*>(this)->setUrls(urls); return QMimeData::retrieveData(mimetype, type); } -private: + + private: QList<World> m_worlds; }; -QMimeData *WorldList::mimeData(const QModelIndexList &indexes) const +QMimeData* WorldList::mimeData(const QModelIndexList& indexes) const { if (indexes.size() == 0) return new QMimeData(); QList<World> worlds; - for(auto idx : indexes) - { - if(idx.column() != 0) + for (auto idx : indexes) { + if (idx.column() != 0) continue; int row = idx.row(); if (row < 0 || row >= this->worlds.size()) continue; worlds.append(this->worlds[row]); } - if(!worlds.size()) - { + if (!worlds.size()) { return new QMimeData(); } return new WorldMimeData(worlds); } -Qt::ItemFlags WorldList::flags(const QModelIndex &index) const +Qt::ItemFlags WorldList::flags(const QModelIndex& index) const { Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index); if (index.isValid()) - return Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | - defaultFlags; + return Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags; else return Qt::ItemIsDropEnabled | defaultFlags; } @@ -416,15 +379,17 @@ void WorldList::installWorld(QFileInfo filename) { qDebug() << "installing: " << filename.absoluteFilePath(); World w(filename); - if(!w.isValid()) - { + if (!w.isValid()) { return; } w.install(m_dir.absolutePath()); } -bool WorldList::dropMimeData(const QMimeData *data, Qt::DropAction action, [[maybe_unused]] int row, [[maybe_unused]] int column, - [[maybe_unused]] const QModelIndex &parent) +bool WorldList::dropMimeData(const QMimeData* data, + Qt::DropAction action, + [[maybe_unused]] int row, + [[maybe_unused]] int column, + [[maybe_unused]] const QModelIndex& parent) { if (action == Qt::IgnoreAction) return true; @@ -432,14 +397,12 @@ bool WorldList::dropMimeData(const QMimeData *data, Qt::DropAction action, [[may if (!data || !(action & supportedDropActions())) return false; // files dropped from outside? - if (data->hasUrls()) - { + if (data->hasUrls()) { bool was_watching = is_watching; if (was_watching) stopWatching(); auto urls = data->urls(); - for (auto url : urls) - { + for (auto url : urls) { // only local files may be dropped... if (!url.isLocalFile()) continue; @@ -447,8 +410,7 @@ bool WorldList::dropMimeData(const QMimeData *data, Qt::DropAction action, [[may QFileInfo worldInfo(filename); - if(!m_dir.entryInfoList().contains(worldInfo)) - { + if (!m_dir.entryInfoList().contains(worldInfo)) { installWorld(worldInfo); } } diff --git a/launcher/minecraft/WorldList.h b/launcher/minecraft/WorldList.h index 96b64193..bea24bb9 100644 --- a/launcher/minecraft/WorldList.h +++ b/launcher/minecraft/WorldList.h @@ -15,65 +15,34 @@ #pragma once -#include <QList> -#include <QString> -#include <QDir> #include <QAbstractListModel> +#include <QDir> +#include <QList> #include <QMimeData> -#include "minecraft/World.h" +#include <QString> #include "BaseInstance.h" +#include "minecraft/World.h" class QFileSystemWatcher; -class WorldList : public QAbstractListModel -{ +class WorldList : public QAbstractListModel { Q_OBJECT -public: - enum Columns - { - NameColumn, - GameModeColumn, - LastPlayedColumn, - SizeColumn, - InfoColumn - }; - - enum Roles - { - ObjectRole = Qt::UserRole + 1, - FolderRole, - SeedRole, - NameRole, - GameModeRole, - LastPlayedRole, - SizeRole, - IconFileRole - }; - - WorldList(const QString &dir, BaseInstance* instance); - - virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - - virtual int rowCount(const QModelIndex &parent = QModelIndex()) const - { - return parent.isValid() ? 0 : static_cast<int>(size()); - }; - virtual QVariant headerData(int section, Qt::Orientation orientation, - int role = Qt::DisplayRole) const; - virtual int columnCount(const QModelIndex &parent) const; - - size_t size() const - { - return worlds.size(); - }; - bool empty() const - { - return size() == 0; - } - World &operator[](size_t index) - { - return worlds[index]; - } + public: + enum Columns { NameColumn, GameModeColumn, LastPlayedColumn, SizeColumn, InfoColumn }; + + enum Roles { ObjectRole = Qt::UserRole + 1, FolderRole, SeedRole, NameRole, GameModeRole, LastPlayedRole, SizeRole, IconFileRole }; + + WorldList(const QString& dir, BaseInstance* instance); + + virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; + + virtual int rowCount(const QModelIndex& parent = QModelIndex()) const { return parent.isValid() ? 0 : static_cast<int>(size()); }; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + virtual int columnCount(const QModelIndex& parent) const; + + size_t size() const { return worlds.size(); }; + bool empty() const { return size() == 0; } + World& operator[](size_t index) { return worlds[index]; } /// Reloads the mod list and returns true if the list changed. virtual bool update(); @@ -91,13 +60,13 @@ public: virtual bool deleteWorlds(int first, int last); /// flags, mostly to support drag&drop - virtual Qt::ItemFlags flags(const QModelIndex &index) const; + virtual Qt::ItemFlags flags(const QModelIndex& index) const; /// get data for drag action - virtual QMimeData *mimeData(const QModelIndexList &indexes) const; + virtual QMimeData* mimeData(const QModelIndexList& indexes) const; /// get the supported mime types virtual QStringList mimeTypes() const; /// process data from drop action - virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); + virtual bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent); /// what drag actions do we support? virtual Qt::DropActions supportedDragActions() const; @@ -109,27 +78,21 @@ public: virtual bool isValid(); - QDir dir() const - { - return m_dir; - } + QDir dir() const { return m_dir; } QString instDirPath() const; - const QList<World> &allWorlds() const - { - return worlds; - } + const QList<World>& allWorlds() const { return worlds; } -private slots: + private slots: void directoryChanged(QString path); -signals: + signals: void changed(); -protected: + protected: BaseInstance* m_instance; - QFileSystemWatcher *m_watcher; + QFileSystemWatcher* m_watcher; bool is_watching; QDir m_dir; QList<World> worlds; diff --git a/launcher/minecraft/auth/AccountData.cpp b/launcher/minecraft/auth/AccountData.cpp index 0b78cb0c..b621a68c 100644 --- a/launcher/minecraft/auth/AccountData.cpp +++ b/launcher/minecraft/auth/AccountData.cpp @@ -34,87 +34,90 @@ */ #include "AccountData.h" +#include <QDebug> +#include <QJsonArray> #include <QJsonDocument> #include <QJsonObject> -#include <QJsonArray> -#include <QDebug> -#include <QUuid> #include <QRegularExpression> +#include <QUuid> namespace { -void tokenToJSONV3(QJsonObject &parent, Katabasis::Token t, const char * tokenName) { - if(!t.persistent) { +void tokenToJSONV3(QJsonObject& parent, Katabasis::Token t, const char* tokenName) +{ + if (!t.persistent) { return; } QJsonObject out; - if(t.issueInstant.isValid()) { + if (t.issueInstant.isValid()) { out["iat"] = QJsonValue(t.issueInstant.toMSecsSinceEpoch() / 1000); } - if(t.notAfter.isValid()) { + if (t.notAfter.isValid()) { out["exp"] = QJsonValue(t.notAfter.toMSecsSinceEpoch() / 1000); } bool save = false; - if(!t.token.isEmpty()) { + if (!t.token.isEmpty()) { out["token"] = QJsonValue(t.token); save = true; } - if(!t.refresh_token.isEmpty()) { + if (!t.refresh_token.isEmpty()) { out["refresh_token"] = QJsonValue(t.refresh_token); save = true; } - if(t.extra.size()) { + if (t.extra.size()) { out["extra"] = QJsonObject::fromVariantMap(t.extra); save = true; } - if(save) { + if (save) { parent[tokenName] = out; } } -Katabasis::Token tokenFromJSONV3(const QJsonObject &parent, const char * tokenName) { +Katabasis::Token tokenFromJSONV3(const QJsonObject& parent, const char* tokenName) +{ Katabasis::Token out; auto tokenObject = parent.value(tokenName).toObject(); - if(tokenObject.isEmpty()) { + if (tokenObject.isEmpty()) { return out; } auto issueInstant = tokenObject.value("iat"); - if(issueInstant.isDouble()) { - out.issueInstant = QDateTime::fromMSecsSinceEpoch(((int64_t) issueInstant.toDouble()) * 1000); + if (issueInstant.isDouble()) { + out.issueInstant = QDateTime::fromMSecsSinceEpoch(((int64_t)issueInstant.toDouble()) * 1000); } auto notAfter = tokenObject.value("exp"); - if(notAfter.isDouble()) { - out.notAfter = QDateTime::fromMSecsSinceEpoch(((int64_t) notAfter.toDouble()) * 1000); + if (notAfter.isDouble()) { + out.notAfter = QDateTime::fromMSecsSinceEpoch(((int64_t)notAfter.toDouble()) * 1000); } auto token = tokenObject.value("token"); - if(token.isString()) { + if (token.isString()) { out.token = token.toString(); out.validity = Katabasis::Validity::Assumed; } auto refresh_token = tokenObject.value("refresh_token"); - if(refresh_token.isString()) { + if (refresh_token.isString()) { out.refresh_token = refresh_token.toString(); } auto extra = tokenObject.value("extra"); - if(extra.isObject()) { + if (extra.isObject()) { out.extra = extra.toObject().toVariantMap(); } return out; } -void profileToJSONV3(QJsonObject &parent, MinecraftProfile p, const char * tokenName) { - if(p.id.isEmpty()) { +void profileToJSONV3(QJsonObject& parent, MinecraftProfile p, const char* tokenName) +{ + if (p.id.isEmpty()) { return; } QJsonObject out; out["id"] = QJsonValue(p.id); out["name"] = QJsonValue(p.name); - if(!p.currentCape.isEmpty()) { + if (!p.currentCape.isEmpty()) { out["cape"] = p.currentCape; } @@ -123,19 +126,19 @@ void profileToJSONV3(QJsonObject &parent, MinecraftProfile p, const char * token skinObj["id"] = p.skin.id; skinObj["url"] = p.skin.url; skinObj["variant"] = p.skin.variant; - if(p.skin.data.size()) { + if (p.skin.data.size()) { skinObj["data"] = QString::fromLatin1(p.skin.data.toBase64()); } out["skin"] = skinObj; } QJsonArray capesArray; - for(auto & cape: p.capes) { + for (auto& cape : p.capes) { QJsonObject capeObj; capeObj["id"] = cape.id; capeObj["url"] = cape.url; capeObj["alias"] = cape.alias; - if(cape.data.size()) { + if (cape.data.size()) { capeObj["data"] = QString::fromLatin1(cape.data.toBase64()); } capesArray.push_back(capeObj); @@ -144,16 +147,17 @@ void profileToJSONV3(QJsonObject &parent, MinecraftProfile p, const char * token parent[tokenName] = out; } -MinecraftProfile profileFromJSONV3(const QJsonObject &parent, const char * tokenName) { +MinecraftProfile profileFromJSONV3(const QJsonObject& parent, const char* tokenName) +{ MinecraftProfile out; auto tokenObject = parent.value(tokenName).toObject(); - if(tokenObject.isEmpty()) { + if (tokenObject.isEmpty()) { return out; } { auto idV = tokenObject.value("id"); auto nameV = tokenObject.value("name"); - if(!idV.isString() || !nameV.isString()) { + if (!idV.isString() || !nameV.isString()) { qWarning() << "mandatory profile attributes are missing or of unexpected type"; return MinecraftProfile(); } @@ -163,7 +167,7 @@ MinecraftProfile profileFromJSONV3(const QJsonObject &parent, const char * token { auto skinV = tokenObject.value("skin"); - if(!skinV.isObject()) { + if (!skinV.isObject()) { qWarning() << "skin is missing"; return MinecraftProfile(); } @@ -171,7 +175,7 @@ MinecraftProfile profileFromJSONV3(const QJsonObject &parent, const char * token auto idV = skinObj.value("id"); auto urlV = skinObj.value("url"); auto variantV = skinObj.value("variant"); - if(!idV.isString() || !urlV.isString() || !variantV.isString()) { + if (!idV.isString() || !urlV.isString() || !variantV.isString()) { qWarning() << "mandatory skin attributes are missing or of unexpected type"; return MinecraftProfile(); } @@ -181,11 +185,10 @@ MinecraftProfile profileFromJSONV3(const QJsonObject &parent, const char * token // data for skin is optional auto dataV = skinObj.value("data"); - if(dataV.isString()) { + if (dataV.isString()) { // TODO: validate base64 out.skin.data = QByteArray::fromBase64(dataV.toString().toLatin1()); - } - else if (!dataV.isUndefined()) { + } else if (!dataV.isUndefined()) { qWarning() << "skin data is something unexpected"; return MinecraftProfile(); } @@ -193,13 +196,13 @@ MinecraftProfile profileFromJSONV3(const QJsonObject &parent, const char * token { auto capesV = tokenObject.value("capes"); - if(!capesV.isArray()) { + if (!capesV.isArray()) { qWarning() << "capes is not an array!"; return MinecraftProfile(); } auto capesArray = capesV.toArray(); - for(auto capeV: capesArray) { - if(!capeV.isObject()) { + for (auto capeV : capesArray) { + if (!capeV.isObject()) { qWarning() << "cape is not an object!"; return MinecraftProfile(); } @@ -207,7 +210,7 @@ MinecraftProfile profileFromJSONV3(const QJsonObject &parent, const char * token auto idV = capeObj.value("id"); auto urlV = capeObj.value("url"); auto aliasV = capeObj.value("alias"); - if(!idV.isString() || !urlV.isString() || !aliasV.isString()) { + if (!idV.isString() || !urlV.isString() || !aliasV.isString()) { qWarning() << "mandatory skin attributes are missing or of unexpected type"; return MinecraftProfile(); } @@ -218,11 +221,10 @@ MinecraftProfile profileFromJSONV3(const QJsonObject &parent, const char * token // data for cape is optional. auto dataV = capeObj.value("data"); - if(dataV.isString()) { + if (dataV.isString()) { // TODO: validate base64 cape.data = QByteArray::fromBase64(dataV.toString().toLatin1()); - } - else if (!dataV.isUndefined()) { + } else if (!dataV.isUndefined()) { qWarning() << "cape data is something unexpected"; return MinecraftProfile(); } @@ -232,9 +234,9 @@ MinecraftProfile profileFromJSONV3(const QJsonObject &parent, const char * token // current cape { auto capeV = tokenObject.value("cape"); - if(capeV.isString()) { + if (capeV.isString()) { auto currentCape = capeV.toString(); - if(out.capes.contains(currentCape)) { + if (out.capes.contains(currentCape)) { out.currentCape = currentCape; } } @@ -243,8 +245,9 @@ MinecraftProfile profileFromJSONV3(const QJsonObject &parent, const char * token return out; } -void entitlementToJSONV3(QJsonObject &parent, MinecraftEntitlement p) { - if(p.validity == Katabasis::Validity::None) { +void entitlementToJSONV3(QJsonObject& parent, MinecraftEntitlement p) +{ + if (p.validity == Katabasis::Validity::None) { return; } QJsonObject out; @@ -253,15 +256,16 @@ void entitlementToJSONV3(QJsonObject &parent, MinecraftEntitlement p) { parent["entitlement"] = out; } -bool entitlementFromJSONV3(const QJsonObject &parent, MinecraftEntitlement & out) { +bool entitlementFromJSONV3(const QJsonObject& parent, MinecraftEntitlement& out) +{ auto entitlementObject = parent.value("entitlement").toObject(); - if(entitlementObject.isEmpty()) { + if (entitlementObject.isEmpty()) { return false; } { auto ownsMinecraftV = entitlementObject.value("ownsMinecraft"); auto canPlayMinecraftV = entitlementObject.value("canPlayMinecraft"); - if(!ownsMinecraftV.isBool() || !canPlayMinecraftV.isBool()) { + if (!ownsMinecraftV.isBool() || !canPlayMinecraftV.isBool()) { qWarning() << "mandatory attributes are missing or of unexpected type"; return false; } @@ -272,12 +276,12 @@ bool entitlementFromJSONV3(const QJsonObject &parent, MinecraftEntitlement & out return true; } -} +} // namespace -bool AccountData::resumeStateFromV2(QJsonObject data) { +bool AccountData::resumeStateFromV2(QJsonObject data) +{ // The JSON object must at least have a username for it to be valid. - if (!data.value("username").isString()) - { + if (!data.value("username").isString()) { qCritical() << "Can't load Mojang account info from JSON object. Username field is missing or of the wrong type."; return false; } @@ -287,14 +291,12 @@ bool AccountData::resumeStateFromV2(QJsonObject data) { QString accessToken = data.value("accessToken").toString(""); QJsonArray profileArray = data.value("profiles").toArray(); - if (profileArray.size() < 1) - { + if (profileArray.size() < 1) { qCritical() << "Can't load Mojang account with username \"" << userName << "\". No profiles found."; return false; } - struct AccountProfile - { + struct AccountProfile { QString id; QString name; bool legacy; @@ -304,24 +306,22 @@ bool AccountData::resumeStateFromV2(QJsonObject data) { int currentProfileIndex = 0; int index = -1; QString currentProfile = data.value("activeProfile").toString(""); - for (QJsonValue profileVal : profileArray) - { + for (QJsonValue profileVal : profileArray) { index++; QJsonObject profileObject = profileVal.toObject(); QString id = profileObject.value("id").toString(""); QString name = profileObject.value("name").toString(""); bool legacy = profileObject.value("legacy").toBool(false); - if (id.isEmpty() || name.isEmpty()) - { + if (id.isEmpty() || name.isEmpty()) { qWarning() << "Unable to load a profile" << name << "because it was missing an ID or a name."; continue; } - if(id == currentProfile) { + if (id == currentProfile) { currentProfileIndex = index; } - profiles.append({id, name, legacy}); + profiles.append({ id, name, legacy }); } - auto & profile = profiles[currentProfileIndex]; + auto& profile = profiles[currentProfileIndex]; type = AccountType::Mojang; legacy = profile.legacy; @@ -339,14 +339,15 @@ bool AccountData::resumeStateFromV2(QJsonObject data) { return true; } -bool AccountData::resumeStateFromV3(QJsonObject data) { +bool AccountData::resumeStateFromV3(QJsonObject data) +{ auto typeV = data.value("type"); - if(!typeV.isString()) { + if (!typeV.isString()) { qWarning() << "Failed to parse account data: type is missing."; return false; } auto typeS = typeV.toString(); - if(typeS == "MSA") { + if (typeS == "MSA") { type = AccountType::MSA; } else if (typeS == "Mojang") { type = AccountType::Mojang; @@ -357,16 +358,16 @@ bool AccountData::resumeStateFromV3(QJsonObject data) { return false; } - if(type == AccountType::Mojang) { + if (type == AccountType::Mojang) { legacy = data.value("legacy").toBool(false); canMigrateToMSA = data.value("canMigrateToMSA").toBool(false); } - if(type == AccountType::MSA) { + if (type == AccountType::MSA) { auto clientIDV = data.value("msa-client-id"); if (clientIDV.isString()) { msaClientID = clientIDV.toString(); - } // leave msaClientID empty if it doesn't exist or isn't a string + } // leave msaClientID empty if it doesn't exist or isn't a string msaToken = tokenFromJSONV3(data, "msa"); userToken = tokenFromJSONV3(data, "utoken"); xboxApiToken = tokenFromJSONV3(data, "xrp-main"); @@ -379,8 +380,8 @@ bool AccountData::resumeStateFromV3(QJsonObject data) { yggdrasilToken.token = "0"; minecraftProfile = profileFromJSONV3(data, "profile"); - if(!entitlementFromJSONV3(data, minecraftEntitlement)) { - if(minecraftProfile.validity != Katabasis::Validity::None) { + if (!entitlementFromJSONV3(data, minecraftEntitlement)) { + if (minecraftProfile.validity != Katabasis::Validity::None) { minecraftEntitlement.canPlayMinecraft = true; minecraftEntitlement.ownsMinecraft = true; minecraftEntitlement.validity = Katabasis::Validity::Assumed; @@ -391,26 +392,25 @@ bool AccountData::resumeStateFromV3(QJsonObject data) { return true; } -QJsonObject AccountData::saveState() const { +QJsonObject AccountData::saveState() const +{ QJsonObject output; - if(type == AccountType::Mojang) { + if (type == AccountType::Mojang) { output["type"] = "Mojang"; - if(legacy) { + if (legacy) { output["legacy"] = true; } - if(canMigrateToMSA) { + if (canMigrateToMSA) { output["canMigrateToMSA"] = true; } - } - else if (type == AccountType::MSA) { + } else if (type == AccountType::MSA) { output["type"] = "MSA"; output["msa-client-id"] = msaClientID; tokenToJSONV3(output, msaToken, "msa"); tokenToJSONV3(output, userToken, "utoken"); tokenToJSONV3(output, xboxApiToken, "xrp-main"); tokenToJSONV3(output, mojangservicesToken, "xrp-mc"); - } - else if (type == AccountType::Offline) { + } else if (type == AccountType::Offline) { output["type"] = "Offline"; } @@ -420,60 +420,68 @@ QJsonObject AccountData::saveState() const { return output; } -QString AccountData::userName() const { - if(type == AccountType::MSA) { +QString AccountData::userName() const +{ + if (type == AccountType::MSA) { return QString(); } return yggdrasilToken.extra["userName"].toString(); } -QString AccountData::accessToken() const { +QString AccountData::accessToken() const +{ return yggdrasilToken.token; } -QString AccountData::clientToken() const { - if(type != AccountType::Mojang) { +QString AccountData::clientToken() const +{ + if (type != AccountType::Mojang) { return QString(); } return yggdrasilToken.extra["clientToken"].toString(); } -void AccountData::setClientToken(QString clientToken) { - if(type != AccountType::Mojang) { +void AccountData::setClientToken(QString clientToken) +{ + if (type != AccountType::Mojang) { return; } yggdrasilToken.extra["clientToken"] = clientToken; } -void AccountData::generateClientTokenIfMissing() { - if(yggdrasilToken.extra.contains("clientToken")) { +void AccountData::generateClientTokenIfMissing() +{ + if (yggdrasilToken.extra.contains("clientToken")) { return; } invalidateClientToken(); } -void AccountData::invalidateClientToken() { - if(type != AccountType::Mojang) { +void AccountData::invalidateClientToken() +{ + if (type != AccountType::Mojang) { return; } yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegularExpression("[{-}]")); } -QString AccountData::profileId() const { +QString AccountData::profileId() const +{ return minecraftProfile.id; } -QString AccountData::profileName() const { - if(minecraftProfile.name.size() == 0) { +QString AccountData::profileName() const +{ + if (minecraftProfile.name.size() == 0) { return QObject::tr("No profile (%1)").arg(accountDisplayString()); - } - else { + } else { return minecraftProfile.name; } } -QString AccountData::accountDisplayString() const { - switch(type) { +QString AccountData::accountDisplayString() const +{ + switch (type) { case AccountType::Mojang: { return userName(); } @@ -481,7 +489,7 @@ QString AccountData::accountDisplayString() const { return QObject::tr("<Offline>"); } case AccountType::MSA: { - if(xboxApiToken.extra.contains("gtg")) { + if (xboxApiToken.extra.contains("gtg")) { return xboxApiToken.extra["gtg"].toString(); } return "Xbox profile missing"; @@ -492,6 +500,7 @@ QString AccountData::accountDisplayString() const { } } -QString AccountData::lastError() const { +QString AccountData::lastError() const +{ return errorString; } diff --git a/launcher/minecraft/auth/AccountData.h b/launcher/minecraft/auth/AccountData.h index 092e1691..38e3c3c9 100644 --- a/launcher/minecraft/auth/AccountData.h +++ b/launcher/minecraft/auth/AccountData.h @@ -34,11 +34,11 @@ */ #pragma once -#include <QString> -#include <QByteArray> -#include <QVector> #include <katabasis/Bits.h> +#include <QByteArray> #include <QJsonObject> +#include <QString> +#include <QVector> struct Skin { QString id; @@ -71,22 +71,9 @@ struct MinecraftProfile { Katabasis::Validity validity = Katabasis::Validity::None; }; -enum class AccountType { - MSA, - Mojang, - Offline -}; +enum class AccountType { MSA, Mojang, Offline }; -enum class AccountState { - Unchecked, - Offline, - Working, - Online, - Disabled, - Errored, - Expired, - Gone -}; +enum class AccountState { Unchecked, Offline, Working, Online, Disabled, Errored, Expired, Gone }; struct AccountData { QJsonObject saveState() const; diff --git a/launcher/minecraft/auth/AccountList.cpp b/launcher/minecraft/auth/AccountList.cpp index d6f42b75..609eaa55 100644 --- a/launcher/minecraft/auth/AccountList.cpp +++ b/launcher/minecraft/auth/AccountList.cpp @@ -37,14 +37,14 @@ #include "AccountData.h" #include "AccountTask.h" -#include <QIODevice> +#include <QDir> #include <QFile> -#include <QTextStream> -#include <QJsonDocument> +#include <QIODevice> #include <QJsonArray> +#include <QJsonDocument> #include <QJsonObject> #include <QJsonParseError> -#include <QDir> +#include <QTextStream> #include <QTimer> #include <QDebug> @@ -54,12 +54,10 @@ #include <chrono> -enum AccountListVersion { - MojangOnly = 2, - MojangMSA = 3 -}; +enum AccountListVersion { MojangOnly = 2, MojangMSA = 3 }; -AccountList::AccountList(QObject *parent) : QAbstractListModel(parent) { +AccountList::AccountList(QObject* parent) : QAbstractListModel(parent) +{ m_refreshTimer = new QTimer(this); m_refreshTimer->setSingleShot(true); connect(m_refreshTimer, &QTimer::timeout, this, &AccountList::fillQueue); @@ -70,7 +68,8 @@ AccountList::AccountList(QObject *parent) : QAbstractListModel(parent) { AccountList::~AccountList() noexcept {} -int AccountList::findAccountByProfileId(const QString& profileId) const { +int AccountList::findAccountByProfileId(const QString& profileId) const +{ for (int i = 0; i < count(); i++) { MinecraftAccountPtr account = at(i); if (account->profileId() == profileId) { @@ -80,7 +79,8 @@ int AccountList::findAccountByProfileId(const QString& profileId) const { return -1; } -MinecraftAccountPtr AccountList::getAccountByProfileName(const QString& profileName) const { +MinecraftAccountPtr AccountList::getAccountByProfileName(const QString& profileName) const +{ for (int i = 0; i < count(); i++) { MinecraftAccountPtr account = at(i); if (account->profileName() == profileName) { @@ -95,11 +95,12 @@ const MinecraftAccountPtr AccountList::at(int i) const return MinecraftAccountPtr(m_accounts.at(i)); } -QStringList AccountList::profileNames() const { +QStringList AccountList::profileNames() const +{ QStringList out; - for(auto & account: m_accounts) { - auto profileName = account->profileName(); - if(profileName.isEmpty()) { + for (auto& account : m_accounts) { + auto profileName = account->profileName(); + if (profileName.isEmpty()) { continue; } out.append(profileName); @@ -122,14 +123,14 @@ void AccountList::addAccount(const MinecraftAccountPtr account) // override/replace existing account with the same profileId auto profileId = account->profileId(); - if(profileId.size()) { + if (profileId.size()) { auto existingAccount = findAccountByProfileId(profileId); - if(existingAccount != -1) { + if (existingAccount != -1) { qDebug() << "Replacing old account with a new one with the same profile ID!"; MinecraftAccountPtr existingAccountPtr = m_accounts[existingAccount]; m_accounts[existingAccount] = account; - if(m_defaultAccount == existingAccountPtr) { + if (m_defaultAccount == existingAccountPtr) { m_defaultAccount = account; } // disconnect notifications for changes in the account being replaced @@ -154,11 +155,9 @@ void AccountList::addAccount(const MinecraftAccountPtr account) void AccountList::removeAccount(QModelIndex index) { int row = index.row(); - if(index.isValid() && row >= 0 && row < m_accounts.size()) - { - auto & account = m_accounts[row]; - if(account == m_defaultAccount) - { + if (index.isValid() && row >= 0 && row < m_accounts.size()) { + auto& account = m_accounts[row]; + if (account == m_defaultAccount) { m_defaultAccount = nullptr; onDefaultAccountChanged(); } @@ -178,43 +177,34 @@ MinecraftAccountPtr AccountList::defaultAccount() const void AccountList::setDefaultAccount(MinecraftAccountPtr newAccount) { - if (!newAccount && m_defaultAccount) - { + if (!newAccount && m_defaultAccount) { int idx = 0; auto previousDefaultAccount = m_defaultAccount; m_defaultAccount = nullptr; - for (MinecraftAccountPtr account : m_accounts) - { - if (account == previousDefaultAccount) - { + for (MinecraftAccountPtr account : m_accounts) { + if (account == previousDefaultAccount) { emit dataChanged(index(idx), index(idx, columnCount(QModelIndex()) - 1)); } - idx ++; + idx++; } onDefaultAccountChanged(); - } - else - { + } else { auto currentDefaultAccount = m_defaultAccount; int currentDefaultAccountIdx = -1; auto newDefaultAccount = m_defaultAccount; int newDefaultAccountIdx = -1; int idx = 0; - for (MinecraftAccountPtr account : m_accounts) - { - if (account == newAccount) - { + for (MinecraftAccountPtr account : m_accounts) { + if (account == newAccount) { newDefaultAccount = account; newDefaultAccountIdx = idx; } - if(currentDefaultAccount == account) - { + if (currentDefaultAccount == account) { currentDefaultAccountIdx = idx; } idx++; } - if(currentDefaultAccount != newDefaultAccount) - { + if (currentDefaultAccount != newDefaultAccount) { emit dataChanged(index(currentDefaultAccountIdx), index(currentDefaultAccountIdx, columnCount(QModelIndex()) - 1)); emit dataChanged(index(newDefaultAccountIdx), index(newDefaultAccountIdx, columnCount(QModelIndex()) - 1)); m_defaultAccount = newDefaultAccount; @@ -231,27 +221,25 @@ void AccountList::accountChanged() void AccountList::accountActivityChanged(bool active) { - MinecraftAccount *account = qobject_cast<MinecraftAccount *>(sender()); + MinecraftAccount* account = qobject_cast<MinecraftAccount*>(sender()); bool found = false; for (int i = 0; i < count(); i++) { if (at(i).get() == account) { - emit dataChanged(index(i), index(i, columnCount(QModelIndex()) - 1)); + emit dataChanged(index(i), index(i, columnCount(QModelIndex()) - 1)); found = true; break; } } - if(found) { + if (found) { emit listActivityChanged(); - if(active) { + if (active) { beginActivity(); - } - else { + } else { endActivity(); } } } - void AccountList::onListChanged() { if (m_autosave) @@ -274,7 +262,7 @@ int AccountList::count() const return m_accounts.count(); } -QVariant AccountList::data(const QModelIndex &index, int role) const +QVariant AccountList::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); @@ -284,70 +272,67 @@ QVariant AccountList::data(const QModelIndex &index, int role) const MinecraftAccountPtr account = at(index.row()); - switch (role) - { + switch (role) { case Qt::DisplayRole: - switch (index.column()) - { - case ProfileNameColumn: { - return account->profileName(); - } + switch (index.column()) { + case ProfileNameColumn: { + return account->profileName(); + } - case NameColumn: - return account->accountDisplayString(); + case NameColumn: + return account->accountDisplayString(); - case TypeColumn: { - auto typeStr = account->typeString(); - typeStr[0] = typeStr[0].toUpper(); - return typeStr; - } + case TypeColumn: { + auto typeStr = account->typeString(); + typeStr[0] = typeStr[0].toUpper(); + return typeStr; + } - case StatusColumn: { - switch(account->accountState()) { - case AccountState::Unchecked: { - return tr("Unchecked", "Account status"); - } - case AccountState::Offline: { - return tr("Offline", "Account status"); - } - case AccountState::Online: { - return tr("Ready", "Account status"); - } - case AccountState::Working: { - return tr("Working", "Account status"); - } - case AccountState::Errored: { - return tr("Errored", "Account status"); - } - case AccountState::Expired: { - return tr("Expired", "Account status"); - } - case AccountState::Disabled: { - return tr("Disabled", "Account status"); - } - case AccountState::Gone: { - return tr("Gone", "Account status"); - } - default: { - return tr("Unknown", "Account status"); + case StatusColumn: { + switch (account->accountState()) { + case AccountState::Unchecked: { + return tr("Unchecked", "Account status"); + } + case AccountState::Offline: { + return tr("Offline", "Account status"); + } + case AccountState::Online: { + return tr("Ready", "Account status"); + } + case AccountState::Working: { + return tr("Working", "Account status"); + } + case AccountState::Errored: { + return tr("Errored", "Account status"); + } + case AccountState::Expired: { + return tr("Expired", "Account status"); + } + case AccountState::Disabled: { + return tr("Disabled", "Account status"); + } + case AccountState::Gone: { + return tr("Gone", "Account status"); + } + default: { + return tr("Unknown", "Account status"); + } } } - } - case MigrationColumn: { - if(account->isMSA() || account->isOffline()) { - return tr("N/A", "Can Migrate"); - } - if (account->canMigrate()) { - return tr("Yes", "Can Migrate"); - } - else { - return tr("No", "Can Migrate"); + case MigrationColumn: { + if (account->isMSA() || account->isOffline()) { + return tr("N/A", "Can Migrate"); + } + if (account->canMigrate()) { + return tr("Yes", "Can Migrate"); + } else { + return tr("No", "Can Migrate"); + } } - } - default: - return QVariant(); + default: + return QVariant(); } case Qt::ToolTipRole: @@ -362,7 +347,6 @@ QVariant AccountList::data(const QModelIndex &index, int role) const } else { return QVariant(); } - default: return QVariant(); @@ -371,79 +355,72 @@ QVariant AccountList::data(const QModelIndex &index, int role) const QVariant AccountList::headerData(int section, Qt::Orientation orientation, int role) const { - switch (role) - { - case Qt::DisplayRole: - switch (section) - { - case ProfileNameColumn: - return tr("Username"); - case NameColumn: - return tr("Account"); - case TypeColumn: - return tr("Type"); - case StatusColumn: - return tr("Status"); - case MigrationColumn: - return tr("Can Migrate?"); - default: - return QVariant(); - } + switch (role) { + case Qt::DisplayRole: + switch (section) { + case ProfileNameColumn: + return tr("Username"); + case NameColumn: + return tr("Account"); + case TypeColumn: + return tr("Type"); + case StatusColumn: + return tr("Status"); + case MigrationColumn: + return tr("Can Migrate?"); + default: + return QVariant(); + } + + case Qt::ToolTipRole: + switch (section) { + case ProfileNameColumn: + return tr("Minecraft username associated with the account."); + case NameColumn: + return tr("User name of the account."); + case TypeColumn: + return tr("Type of the account - Mojang or MSA."); + case StatusColumn: + return tr("Current status of the account."); + case MigrationColumn: + return tr("Can this account migrate to a Microsoft account?"); + default: + return QVariant(); + } - case Qt::ToolTipRole: - switch (section) - { - case ProfileNameColumn: - return tr("Minecraft username associated with the account."); - case NameColumn: - return tr("User name of the account."); - case TypeColumn: - return tr("Type of the account - Mojang or MSA."); - case StatusColumn: - return tr("Current status of the account."); - case MigrationColumn: - return tr("Can this account migrate to a Microsoft account?"); default: return QVariant(); - } - - default: - return QVariant(); } } -int AccountList::rowCount(const QModelIndex &parent) const +int AccountList::rowCount(const QModelIndex& parent) const { // Return count return parent.isValid() ? 0 : count(); } -int AccountList::columnCount(const QModelIndex &parent) const +int AccountList::columnCount(const QModelIndex& parent) const { return parent.isValid() ? 0 : NUM_COLUMNS; } -Qt::ItemFlags AccountList::flags(const QModelIndex &index) const +Qt::ItemFlags AccountList::flags(const QModelIndex& index) const { - if (index.row() < 0 || index.row() >= rowCount(index.parent()) || !index.isValid()) - { + if (index.row() < 0 || index.row() >= rowCount(index.parent()) || !index.isValid()) { return Qt::NoItemFlags; } return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; } -bool AccountList::setData(const QModelIndex &idx, const QVariant &value, int role) +bool AccountList::setData(const QModelIndex& idx, const QVariant& value, int role) { - if (idx.row() < 0 || idx.row() >= rowCount(idx) || !idx.isValid()) - { + if (idx.row() < 0 || idx.row() >= rowCount(idx) || !idx.isValid()) { return false; } - if(role == Qt::CheckStateRole) - { - if(value == Qt::Checked) - { + if (role == Qt::CheckStateRole) { + if (value == Qt::Checked) { MinecraftAccountPtr account = at(idx.row()); setDefaultAccount(account); } @@ -455,8 +432,7 @@ bool AccountList::setData(const QModelIndex &idx, const QVariant &value, int rol bool AccountList::loadList() { - if (m_listFilePath.isEmpty()) - { + if (m_listFilePath.isEmpty()) { qCritical() << "Can't load Mojang account list. No file path given and no default set."; return false; } @@ -465,8 +441,7 @@ bool AccountList::loadList() // Try to open the file and fail if we can't. // TODO: We should probably report this error to the user. - if (!file.open(QIODevice::ReadOnly)) - { + if (!file.open(QIODevice::ReadOnly)) { qCritical() << QString("Failed to read the account list file (%1).").arg(m_listFilePath).toUtf8(); return false; } @@ -479,17 +454,15 @@ bool AccountList::loadList() QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &parseError); // Fail if the JSON is invalid. - if (parseError.error != QJsonParseError::NoError) - { + if (parseError.error != QJsonParseError::NoError) { qCritical() << QString("Failed to parse account list file: %1 at offset %2") - .arg(parseError.errorString(), QString::number(parseError.offset)) - .toUtf8(); + .arg(parseError.errorString(), QString::number(parseError.offset)) + .toUtf8(); return false; } // Make sure the root is an object. - if (!jsonDoc.isObject()) - { + if (!jsonDoc.isObject()) { qCritical() << "Invalid account list JSON: Root should be an array."; return false; } @@ -498,15 +471,13 @@ bool AccountList::loadList() // Make sure the format version matches. auto listVersion = root.value("formatVersion").toVariant().toInt(); - switch(listVersion) { + switch (listVersion) { case AccountListVersion::MojangOnly: { return loadV2(root); - } - break; + } break; case AccountListVersion::MojangMSA: { return loadV3(root); - } - break; + } break; default: { QString newName = "accounts-old.json"; qWarning() << "Unknown format version when loading account list. Existing one will be renamed to" << newName; @@ -517,21 +488,20 @@ bool AccountList::loadList() } } -bool AccountList::loadV2(QJsonObject& root) { +bool AccountList::loadV2(QJsonObject& root) +{ beginResetModel(); auto defaultUserName = root.value("activeAccount").toString(""); QJsonArray accounts = root.value("accounts").toArray(); - for (QJsonValue accountVal : accounts) - { + for (QJsonValue accountVal : accounts) { QJsonObject accountObj = accountVal.toObject(); MinecraftAccountPtr account = MinecraftAccount::loadFromJsonV2(accountObj); - if (account.get() != nullptr) - { + if (account.get() != nullptr) { auto profileId = account->profileId(); - if(!profileId.size()) { + if (!profileId.size()) { continue; } - if(findAccountByProfileId(profileId) != -1) { + if (findAccountByProfileId(profileId) != -1) { continue; } connect(account.get(), &MinecraftAccount::changed, this, &AccountList::accountChanged); @@ -540,9 +510,7 @@ bool AccountList::loadV2(QJsonObject& root) { if (defaultUserName.size() && account->mojangUserName() == defaultUserName) { m_defaultAccount = account; } - } - else - { + } else { qWarning() << "Failed to load an account."; } } @@ -550,30 +518,27 @@ bool AccountList::loadV2(QJsonObject& root) { return true; } -bool AccountList::loadV3(QJsonObject& root) { +bool AccountList::loadV3(QJsonObject& root) +{ beginResetModel(); QJsonArray accounts = root.value("accounts").toArray(); - for (QJsonValue accountVal : accounts) - { + for (QJsonValue accountVal : accounts) { QJsonObject accountObj = accountVal.toObject(); MinecraftAccountPtr account = MinecraftAccount::loadFromJsonV3(accountObj); - if (account.get() != nullptr) - { + if (account.get() != nullptr) { auto profileId = account->profileId(); - if(profileId.size()) { - if(findAccountByProfileId(profileId) != -1) { + if (profileId.size()) { + if (findAccountByProfileId(profileId) != -1) { continue; } } connect(account.get(), &MinecraftAccount::changed, this, &AccountList::accountChanged); connect(account.get(), &MinecraftAccount::activityChanged, this, &AccountList::accountActivityChanged); m_accounts.append(account); - if(accountObj.value("active").toBool(false)) { + if (accountObj.value("active").toBool(false)) { m_defaultAccount = account; } - } - else - { + } else { qWarning() << "Failed to load an account."; } } @@ -581,23 +546,20 @@ bool AccountList::loadV3(QJsonObject& root) { return true; } - bool AccountList::saveList() { - if (m_listFilePath.isEmpty()) - { + if (m_listFilePath.isEmpty()) { qCritical() << "Can't save Mojang account list. No file path given and no default set."; return false; } // make sure the parent folder exists - if(!FS::ensureFilePathExists(m_listFilePath)) + if (!FS::ensureFilePathExists(m_listFilePath)) return false; // make sure the file wasn't overwritten with a folder before (fixes a bug) QFileInfo finfo(m_listFilePath); - if(finfo.isDir()) - { + if (finfo.isDir()) { QDir badDir(m_listFilePath); badDir.removeRecursively(); } @@ -613,10 +575,9 @@ bool AccountList::saveList() // Build a list of accounts. qDebug() << "Building account array."; QJsonArray accounts; - for (MinecraftAccountPtr account : m_accounts) - { + for (MinecraftAccountPtr account : m_accounts) { QJsonObject accountObj = account->saveToJson(); - if(m_defaultAccount == account) { + if (m_defaultAccount == account) { accountObj["active"] = true; } accounts.append(accountObj); @@ -634,20 +595,18 @@ bool AccountList::saveList() // Try to open the file and fail if we can't. // TODO: We should probably report this error to the user. - if (!file.open(QIODevice::WriteOnly)) - { + if (!file.open(QIODevice::WriteOnly)) { qCritical() << QString("Failed to read the account list file (%1).").arg(m_listFilePath).toUtf8(); return false; } // Write the JSON to the file. file.write(doc.toJson()); - file.setPermissions(QFile::ReadOwner|QFile::WriteOwner|QFile::ReadUser|QFile::WriteUser); - if(file.commit()) { + file.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ReadUser | QFile::WriteUser); + if (file.commit()) { qDebug() << "Saved account list to" << m_listFilePath; return true; - } - else { + } else { qDebug() << "Failed to save accounts to" << m_listFilePath; return false; } @@ -661,30 +620,29 @@ void AccountList::setListFilePath(QString path, bool autosave) bool AccountList::anyAccountIsValid() { - for(auto account: m_accounts) - { - if(account->ownsMinecraft()) { + for (auto account : m_accounts) { + if (account->ownsMinecraft()) { return true; } } return false; } -void AccountList::fillQueue() { - - if(m_defaultAccount && m_defaultAccount->shouldRefresh()) { +void AccountList::fillQueue() +{ + if (m_defaultAccount && m_defaultAccount->shouldRefresh()) { auto idToRefresh = m_defaultAccount->internalId(); m_refreshQueue.push_back(idToRefresh); qDebug() << "AccountList: Queued default account with internal ID " << idToRefresh << " to refresh first"; } - for(int i = 0; i < count(); i++) { + for (int i = 0; i < count(); i++) { auto account = at(i); - if(account == m_defaultAccount) { + if (account == m_defaultAccount) { continue; } - if(account->shouldRefresh()) { + if (account->shouldRefresh()) { auto idToRefresh = account->internalId(); queueRefresh(idToRefresh); } @@ -692,40 +650,43 @@ void AccountList::fillQueue() { tryNext(); } -void AccountList::requestRefresh(QString accountId) { +void AccountList::requestRefresh(QString accountId) +{ auto index = m_refreshQueue.indexOf(accountId); - if(index != -1) { + if (index != -1) { m_refreshQueue.removeAt(index); } m_refreshQueue.push_front(accountId); qDebug() << "AccountList: Pushed account with internal ID " << accountId << " to the front of the queue"; - if(!isActive()) { + if (!isActive()) { tryNext(); } } -void AccountList::queueRefresh(QString accountId) { - if(m_refreshQueue.indexOf(accountId) != -1) { +void AccountList::queueRefresh(QString accountId) +{ + if (m_refreshQueue.indexOf(accountId) != -1) { return; } m_refreshQueue.push_back(accountId); qDebug() << "AccountList: Queued account with internal ID " << accountId << " to refresh"; } - -void AccountList::tryNext() { +void AccountList::tryNext() +{ while (m_refreshQueue.length()) { auto accountId = m_refreshQueue.front(); m_refreshQueue.pop_front(); - for(int i = 0; i < count(); i++) { + for (int i = 0; i < count(); i++) { auto account = at(i); - if(account->internalId() == accountId) { + if (account->internalId() == accountId) { m_currentTask = account->refresh(); - if(m_currentTask) { + if (m_currentTask) { connect(m_currentTask.get(), &AccountTask::succeeded, this, &AccountList::authSucceeded); connect(m_currentTask.get(), &AccountTask::failed, this, &AccountList::authFailed); m_currentTask->start(); - qDebug() << "RefreshSchedule: Processing account " << account->accountDisplayString() << " with internal ID " << accountId; + qDebug() << "RefreshSchedule: Processing account " << account->accountDisplayString() << " with internal ID " + << accountId; return; } } @@ -736,38 +697,43 @@ void AccountList::tryNext() { m_refreshTimer->start(1000 * 3600); } -void AccountList::authSucceeded() { +void AccountList::authSucceeded() +{ qDebug() << "RefreshSchedule: Background account refresh succeeded"; m_currentTask.reset(); m_nextTimer->start(1000 * 20); } -void AccountList::authFailed(QString reason) { +void AccountList::authFailed(QString reason) +{ qDebug() << "RefreshSchedule: Background account refresh failed: " << reason; m_currentTask.reset(); m_nextTimer->start(1000 * 20); } -bool AccountList::isActive() const { +bool AccountList::isActive() const +{ return m_activityCount != 0; } -void AccountList::beginActivity() { +void AccountList::beginActivity() +{ bool activating = m_activityCount == 0; m_activityCount++; - if(activating) { + if (activating) { emit activityChanged(true); } } -void AccountList::endActivity() { - if(m_activityCount == 0) { +void AccountList::endActivity() +{ + if (m_activityCount == 0) { qWarning() << m_name << " - Activity count would become below zero"; return; } bool deactivating = m_activityCount == 1; m_activityCount--; - if(deactivating) { + if (deactivating) { emit activityChanged(false); } } diff --git a/launcher/minecraft/auth/AccountList.h b/launcher/minecraft/auth/AccountList.h index a8c3529a..30926d13 100644 --- a/launcher/minecraft/auth/AccountList.h +++ b/launcher/minecraft/auth/AccountList.h @@ -37,26 +37,21 @@ #include "MinecraftAccount.h" -#include <QObject> -#include <QVariant> #include <QAbstractListModel> +#include <QObject> #include <QSharedPointer> +#include <QVariant> /*! * List of available Mojang accounts. * This should be loaded in the background by Prism Launcher on startup. */ -class AccountList : public QAbstractListModel -{ +class AccountList : public QAbstractListModel { Q_OBJECT -public: - enum ModelRoles - { - PointerRole = 0x34B1CB48 - }; + public: + enum ModelRoles { PointerRole = 0x34B1CB48 }; - enum VListColumns - { + enum VListColumns { // TODO: Add icon column. ProfileNameColumn = 0, NameColumn, @@ -67,24 +62,24 @@ public: NUM_COLUMNS }; - explicit AccountList(QObject *parent = 0); + explicit AccountList(QObject* parent = 0); virtual ~AccountList() noexcept; const MinecraftAccountPtr at(int i) const; int count() const; //////// List Model Functions //////// - QVariant data(const QModelIndex &index, int role) const override; + QVariant data(const QModelIndex& index, int role) const override; virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override; - virtual int rowCount(const QModelIndex &parent) const override; - virtual int columnCount(const QModelIndex &parent) const override; - virtual Qt::ItemFlags flags(const QModelIndex &index) const override; - virtual bool setData(const QModelIndex &index, const QVariant &value, int role) override; + virtual int rowCount(const QModelIndex& parent) const override; + virtual int columnCount(const QModelIndex& parent) const override; + virtual Qt::ItemFlags flags(const QModelIndex& index) const override; + virtual bool setData(const QModelIndex& index, const QVariant& value, int role) override; void addAccount(const MinecraftAccountPtr account); void removeAccount(QModelIndex index); - int findAccountByProfileId(const QString &profileId) const; - MinecraftAccountPtr getAccountByProfileName(const QString &profileName) const; + int findAccountByProfileId(const QString& profileId) const; + MinecraftAccountPtr getAccountByProfileName(const QString& profileName) const; QStringList profileNames() const; // requesting a refresh pushes it to the front of the queue @@ -102,8 +97,8 @@ public: void setListFilePath(QString path, bool autosave = false); bool loadList(); - bool loadV2(QJsonObject &root); - bool loadV3(QJsonObject &root); + bool loadV2(QJsonObject& root); + bool loadV3(QJsonObject& root); bool saveList(); MinecraftAccountPtr defaultAccount() const; @@ -112,20 +107,20 @@ public: bool isActive() const; -protected: + protected: void beginActivity(); void endActivity(); -private: + private: const char* m_name; uint32_t m_activityCount = 0; -signals: + signals: void listChanged(); void listActivityChanged(); void defaultAccountChanged(); void activityChanged(bool active); -public slots: + public slots: /** * This is called when one of the accounts changes and the list needs to be updated */ @@ -141,16 +136,16 @@ public slots: */ void fillQueue(); -private slots: + private slots: void tryNext(); void authSucceeded(); void authFailed(QString reason); -protected: + protected: QList<QString> m_refreshQueue; - QTimer *m_refreshTimer; - QTimer *m_nextTimer; + QTimer* m_refreshTimer; + QTimer* m_nextTimer; shared_qobject_ptr<AccountTask> m_currentTask; /*! @@ -178,4 +173,3 @@ protected: */ bool m_autosave = false; }; - diff --git a/launcher/minecraft/auth/AccountTask.cpp b/launcher/minecraft/auth/AccountTask.cpp index 4118c3c5..89660719 100644 --- a/launcher/minecraft/auth/AccountTask.cpp +++ b/launcher/minecraft/auth/AccountTask.cpp @@ -36,43 +36,41 @@ #include "AccountTask.h" #include "MinecraftAccount.h" -#include <QObject> -#include <QString> -#include <QJsonObject> +#include <QByteArray> #include <QJsonDocument> +#include <QJsonObject> #include <QNetworkReply> -#include <QByteArray> +#include <QObject> +#include <QString> #include <QDebug> -AccountTask::AccountTask(AccountData *data, QObject *parent) - : Task(parent), m_data(data) +AccountTask::AccountTask(AccountData* data, QObject* parent) : Task(parent), m_data(data) { changeState(AccountTaskState::STATE_CREATED); } QString AccountTask::getStateMessage() const { - switch (m_taskState) - { - case AccountTaskState::STATE_CREATED: - return "Waiting..."; - case AccountTaskState::STATE_WORKING: - return tr("Sending request to auth servers..."); - case AccountTaskState::STATE_SUCCEEDED: - return tr("Authentication task succeeded."); - case AccountTaskState::STATE_OFFLINE: - return tr("Failed to contact the authentication server."); - case AccountTaskState::STATE_DISABLED: - return tr("Client ID has changed. New session needs to be created."); - case AccountTaskState::STATE_FAILED_SOFT: - return tr("Encountered an error during authentication."); - case AccountTaskState::STATE_FAILED_HARD: - return tr("Failed to authenticate. The session has expired."); - case AccountTaskState::STATE_FAILED_GONE: - return tr("Failed to authenticate. The account no longer exists."); - default: - return tr("..."); + switch (m_taskState) { + case AccountTaskState::STATE_CREATED: + return "Waiting..."; + case AccountTaskState::STATE_WORKING: + return tr("Sending request to auth servers..."); + case AccountTaskState::STATE_SUCCEEDED: + return tr("Authentication task succeeded."); + case AccountTaskState::STATE_OFFLINE: + return tr("Failed to contact the authentication server."); + case AccountTaskState::STATE_DISABLED: + return tr("Client ID has changed. New session needs to be created."); + case AccountTaskState::STATE_FAILED_SOFT: + return tr("Encountered an error during authentication."); + case AccountTaskState::STATE_FAILED_HARD: + return tr("Failed to authenticate. The session has expired."); + case AccountTaskState::STATE_FAILED_GONE: + return tr("Failed to authenticate. The account no longer exists."); + default: + return tr("..."); } } @@ -82,7 +80,7 @@ bool AccountTask::changeState(AccountTaskState newState, QString reason) // FIXME: virtual method invoked in constructor. // We want that behavior, but maybe make it less weird? setStatus(getStateMessage()); - switch(newState) { + switch (newState) { case AccountTaskState::STATE_CREATED: { m_data->errorString.clear(); return true; diff --git a/launcher/minecraft/auth/AccountTask.h b/launcher/minecraft/auth/AccountTask.h index 1bd6c59f..68bbfe5f 100644 --- a/launcher/minecraft/auth/AccountTask.h +++ b/launcher/minecraft/auth/AccountTask.h @@ -37,10 +37,10 @@ #include <tasks/Task.h> -#include <QString> +#include <qsslerror.h> #include <QJsonObject> +#include <QString> #include <QTimer> -#include <qsslerror.h> #include "MinecraftAccount.h" @@ -50,37 +50,32 @@ class QNetworkReply; * Enum for describing the state of the current task. * Used by the getStateMessage function to determine what the status message should be. */ -enum class AccountTaskState -{ +enum class AccountTaskState { STATE_CREATED, STATE_WORKING, STATE_SUCCEEDED, - STATE_DISABLED, //!< MSA Client ID has changed. Tell user to reloginn - STATE_FAILED_SOFT, //!< soft failure. authentication went through partially - STATE_FAILED_HARD, //!< hard failure. main tokens are invalid - STATE_FAILED_GONE, //!< hard failure. main tokens are invalid, and the account no longer exists - STATE_OFFLINE //!< soft failure. authentication failed in the first step in a 'soft' way + STATE_DISABLED, //!< MSA Client ID has changed. Tell user to reloginn + STATE_FAILED_SOFT, //!< soft failure. authentication went through partially + STATE_FAILED_HARD, //!< hard failure. main tokens are invalid + STATE_FAILED_GONE, //!< hard failure. main tokens are invalid, and the account no longer exists + STATE_OFFLINE //!< soft failure. authentication failed in the first step in a 'soft' way }; -class AccountTask : public Task -{ +class AccountTask : public Task { Q_OBJECT -public: - explicit AccountTask(AccountData * data, QObject *parent = 0); - virtual ~AccountTask() {}; + public: + explicit AccountTask(AccountData* data, QObject* parent = 0); + virtual ~AccountTask(){}; AccountTaskState m_taskState = AccountTaskState::STATE_CREATED; - AccountTaskState taskState() { - return m_taskState; - } + AccountTaskState taskState() { return m_taskState; } -signals: - void showVerificationUriAndCode(const QUrl &uri, const QString &code, int expiresIn); + signals: + void showVerificationUriAndCode(const QUrl& uri, const QString& code, int expiresIn); void hideVerificationUriAndCode(); -protected: - + protected: /** * Returns the state message for the given state. * Used to set the status message for the task. @@ -88,10 +83,10 @@ protected: */ virtual QString getStateMessage() const; -protected slots: + protected slots: // NOTE: true -> non-terminal state, false -> terminal state bool changeState(AccountTaskState newState, QString reason = QString()); -protected: - AccountData *m_data = nullptr; + protected: + AccountData* m_data = nullptr; }; diff --git a/launcher/minecraft/auth/AuthRequest.cpp b/launcher/minecraft/auth/AuthRequest.cpp index a21634b7..bd48a059 100644 --- a/launcher/minecraft/auth/AuthRequest.cpp +++ b/launcher/minecraft/auth/AuthRequest.cpp @@ -35,44 +35,44 @@ #include <cassert> +#include <QBuffer> #include <QDebug> #include <QTimer> -#include <QBuffer> #include <QUrlQuery> #include "Application.h" #include "AuthRequest.h" #include "katabasis/Globals.h" -AuthRequest::AuthRequest(QObject *parent): QObject(parent) { -} +AuthRequest::AuthRequest(QObject* parent) : QObject(parent) {} -AuthRequest::~AuthRequest() { -} +AuthRequest::~AuthRequest() {} -void AuthRequest::get(const QNetworkRequest &req, int timeout/* = 60*1000*/) { +void AuthRequest::get(const QNetworkRequest& req, int timeout /* = 60*1000*/) +{ setup(req, QNetworkAccessManager::GetOperation); reply_ = APPLICATION->network()->get(request_); status_ = Requesting; timedReplies_.add(new Katabasis::Reply(reply_, timeout)); -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15 +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15 connect(reply_, &QNetworkReply::errorOccurred, this, &AuthRequest::onRequestError); -#else // &QNetworkReply::error SIGNAL depricated +#else // &QNetworkReply::error SIGNAL depricated connect(reply_, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), this, &AuthRequest::onRequestError); #endif connect(reply_, &QNetworkReply::finished, this, &AuthRequest::onRequestFinished); connect(reply_, &QNetworkReply::sslErrors, this, &AuthRequest::onSslErrors); } -void AuthRequest::post(const QNetworkRequest &req, const QByteArray &data, int timeout/* = 60*1000*/) { +void AuthRequest::post(const QNetworkRequest& req, const QByteArray& data, int timeout /* = 60*1000*/) +{ setup(req, QNetworkAccessManager::PostOperation); data_ = data; status_ = Requesting; reply_ = APPLICATION->network()->post(request_, data_); timedReplies_.add(new Katabasis::Reply(reply_, timeout)); -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15 +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15 connect(reply_, &QNetworkReply::errorOccurred, this, &AuthRequest::onRequestError); -#else // &QNetworkReply::error SIGNAL depricated +#else // &QNetworkReply::error SIGNAL depricated connect(reply_, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), this, &AuthRequest::onRequestError); #endif connect(reply_, &QNetworkReply::finished, this, &AuthRequest::onRequestFinished); @@ -80,35 +80,39 @@ void AuthRequest::post(const QNetworkRequest &req, const QByteArray &data, int t connect(reply_, &QNetworkReply::uploadProgress, this, &AuthRequest::onUploadProgress); } -void AuthRequest::onRequestFinished() { +void AuthRequest::onRequestFinished() +{ if (status_ == Idle) { return; } - if (reply_ != qobject_cast<QNetworkReply *>(sender())) { + if (reply_ != qobject_cast<QNetworkReply*>(sender())) { return; } httpStatus_ = reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); finish(); } -void AuthRequest::onRequestError(QNetworkReply::NetworkError error) { +void AuthRequest::onRequestError(QNetworkReply::NetworkError error) +{ qWarning() << "AuthRequest::onRequestError: Error" << (int)error; if (status_ == Idle) { return; } - if (reply_ != qobject_cast<QNetworkReply *>(sender())) { + if (reply_ != qobject_cast<QNetworkReply*>(sender())) { return; } errorString_ = reply_->errorString(); httpStatus_ = reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); error_ = error; qWarning() << "AuthRequest::onRequestError: Error string: " << errorString_; - qWarning() << "AuthRequest::onRequestError: HTTP status" << httpStatus_ << reply_->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString(); + qWarning() << "AuthRequest::onRequestError: HTTP status" << httpStatus_ + << reply_->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString(); // QTimer::singleShot(10, this, SLOT(finish())); } -void AuthRequest::onSslErrors(QList<QSslError> errors) { +void AuthRequest::onSslErrors(QList<QSslError> errors) +{ int i = 1; for (auto error : errors) { qCritical() << "LOGIN SSL Error #" << i << " : " << error.errorString(); @@ -118,23 +122,25 @@ void AuthRequest::onSslErrors(QList<QSslError> errors) { } } -void AuthRequest::onUploadProgress(qint64 uploaded, qint64 total) { +void AuthRequest::onUploadProgress(qint64 uploaded, qint64 total) +{ if (status_ == Idle) { qWarning() << "AuthRequest::onUploadProgress: No pending request"; return; } - if (reply_ != qobject_cast<QNetworkReply *>(sender())) { + if (reply_ != qobject_cast<QNetworkReply*>(sender())) { return; } // Restart timeout because request in progress - Katabasis::Reply *o2Reply = timedReplies_.find(reply_); - if(o2Reply) { + Katabasis::Reply* o2Reply = timedReplies_.find(reply_); + if (o2Reply) { o2Reply->start(); } emit uploadProgress(uploaded, total); } -void AuthRequest::setup(const QNetworkRequest &req, QNetworkAccessManager::Operation operation, const QByteArray &verb) { +void AuthRequest::setup(const QNetworkRequest& req, QNetworkAccessManager::Operation operation, const QByteArray& verb) +{ request_ = req; operation_ = operation; url_ = req.url(); @@ -152,7 +158,8 @@ void AuthRequest::setup(const QNetworkRequest &req, QNetworkAccessManager::Opera httpStatus_ = 0; } -void AuthRequest::finish() { +void AuthRequest::finish() +{ QByteArray data; if (status_ == Idle) { qWarning() << "AuthRequest::finish: No pending request"; diff --git a/launcher/minecraft/auth/AuthRequest.h b/launcher/minecraft/auth/AuthRequest.h index 89f7a123..84d2a7d6 100644 --- a/launcher/minecraft/auth/AuthRequest.h +++ b/launcher/minecraft/auth/AuthRequest.h @@ -1,27 +1,26 @@ #pragma once -#include <QObject> -#include <QNetworkRequest> -#include <QNetworkReply> +#include <QByteArray> #include <QNetworkAccessManager> +#include <QNetworkReply> +#include <QNetworkRequest> +#include <QObject> #include <QUrl> -#include <QByteArray> #include "katabasis/Reply.h" /// Makes authentication requests. -class AuthRequest: public QObject { +class AuthRequest : public QObject { Q_OBJECT -public: - explicit AuthRequest(QObject *parent = 0); + public: + explicit AuthRequest(QObject* parent = 0); ~AuthRequest(); -public slots: - void get(const QNetworkRequest &req, int timeout = 60*1000); - void post(const QNetworkRequest &req, const QByteArray &data, int timeout = 60*1000); - + public slots: + void get(const QNetworkRequest& req, int timeout = 60 * 1000); + void post(const QNetworkRequest& req, const QByteArray& data, int timeout = 60 * 1000); -signals: + signals: /// Emitted when a request has been completed or failed. void finished(QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers); @@ -29,7 +28,7 @@ signals: /// Emitted when an upload has progressed. void uploadProgress(qint64 bytesSent, qint64 bytesTotal); -protected slots: + protected slots: /// Handle request finished. void onRequestFinished(); @@ -46,25 +45,23 @@ protected slots: /// Handle upload progress. void onUploadProgress(qint64 uploaded, qint64 total); -public: + public: QNetworkReply::NetworkError error_; int httpStatus_ = 0; QString errorString_; -protected: - void setup(const QNetworkRequest &request, QNetworkAccessManager::Operation operation, const QByteArray &verb = QByteArray()); + protected: + void setup(const QNetworkRequest& request, QNetworkAccessManager::Operation operation, const QByteArray& verb = QByteArray()); - enum Status { - Idle, Requesting, ReRequesting - }; + enum Status { Idle, Requesting, ReRequesting }; QNetworkRequest request_; QByteArray data_; - QNetworkReply *reply_; + QNetworkReply* reply_; Status status_; QNetworkAccessManager::Operation operation_; QUrl url_; Katabasis::ReplyList timedReplies_; - QTimer *timer_; + QTimer* timer_; }; diff --git a/launcher/minecraft/auth/AuthSession.cpp b/launcher/minecraft/auth/AuthSession.cpp index 2c06beaa..37534f98 100644 --- a/launcher/minecraft/auth/AuthSession.cpp +++ b/launcher/minecraft/auth/AuthSession.cpp @@ -1,7 +1,7 @@ #include "AuthSession.h" -#include <QJsonObject> #include <QJsonArray> #include <QJsonDocument> +#include <QJsonObject> #include <QStringList> QString AuthSession::serializeUserProperties() @@ -16,13 +16,11 @@ QString AuthSession::serializeUserProperties() */ QJsonDocument value(userAttrs); return value.toJson(QJsonDocument::Compact); - } bool AuthSession::MakeOffline(QString offline_playername) { - if (status != PlayableOffline && status != PlayableOnline) - { + if (status != PlayableOffline && status != PlayableOnline) { return false; } session = "-"; @@ -32,7 +30,8 @@ bool AuthSession::MakeOffline(QString offline_playername) return true; } -void AuthSession::MakeDemo() { +void AuthSession::MakeDemo() +{ player_name = "Player"; demo = true; } diff --git a/launcher/minecraft/auth/AuthSession.h b/launcher/minecraft/auth/AuthSession.h index a75df506..40519476 100644 --- a/launcher/minecraft/auth/AuthSession.h +++ b/launcher/minecraft/auth/AuthSession.h @@ -1,22 +1,20 @@ #pragma once -#include <QString> #include <QMultiMap> +#include <QString> #include <memory> #include "QObjectPtr.h" class MinecraftAccount; class QNetworkAccessManager; -struct AuthSession -{ +struct AuthSession { bool MakeOffline(QString offline_playername); void MakeDemo(); QString serializeUserProperties(); - enum Status - { + enum Status { Undetermined, RequiresOAuth, RequiresPassword, @@ -45,7 +43,7 @@ struct AuthSession // Did the user request online mode? bool wants_online = true; - //Is this a demo session? + // Is this a demo session? bool demo = false; }; diff --git a/launcher/minecraft/auth/AuthStep.cpp b/launcher/minecraft/auth/AuthStep.cpp index ffa2581b..6240cc54 100644 --- a/launcher/minecraft/auth/AuthStep.cpp +++ b/launcher/minecraft/auth/AuthStep.cpp @@ -1,7 +1,5 @@ #include "AuthStep.h" -AuthStep::AuthStep(AccountData *data) : QObject(nullptr), m_data(data) { -} +AuthStep::AuthStep(AccountData* data) : QObject(nullptr), m_data(data) {} AuthStep::~AuthStep() noexcept = default; - diff --git a/launcher/minecraft/auth/AuthStep.h b/launcher/minecraft/auth/AuthStep.h index 2a8dc2ca..becd9b0c 100644 --- a/launcher/minecraft/auth/AuthStep.h +++ b/launcher/minecraft/auth/AuthStep.h @@ -1,33 +1,33 @@ #pragma once -#include <QObject> #include <QList> #include <QNetworkReply> +#include <QObject> +#include "AccountTask.h" #include "QObjectPtr.h" #include "minecraft/auth/AccountData.h" -#include "AccountTask.h" class AuthStep : public QObject { Q_OBJECT -public: + public: using Ptr = shared_qobject_ptr<AuthStep>; -public: - explicit AuthStep(AccountData *data); + public: + explicit AuthStep(AccountData* data); virtual ~AuthStep() noexcept; virtual QString describe() = 0; -public slots: + public slots: virtual void perform() = 0; virtual void rehydrate() = 0; -signals: + signals: void finished(AccountTaskState resultingState, QString message); - void showVerificationUriAndCode(const QUrl &uri, const QString &code, int expiresIn); + void showVerificationUriAndCode(const QUrl& uri, const QString& code, int expiresIn); void hideVerificationUriAndCode(); -protected: - AccountData *m_data; + protected: + AccountData* m_data; }; diff --git a/launcher/minecraft/auth/MinecraftAccount.cpp b/launcher/minecraft/auth/MinecraftAccount.cpp index 5d279af1..e8422a6f 100644 --- a/launcher/minecraft/auth/MinecraftAccount.cpp +++ b/launcher/minecraft/auth/MinecraftAccount.cpp @@ -38,12 +38,12 @@ #include "MinecraftAccount.h" #include <QCryptographicHash> -#include <QUuid> -#include <QJsonObject> #include <QJsonArray> +#include <QJsonDocument> +#include <QJsonObject> #include <QRegularExpression> #include <QStringList> -#include <QJsonDocument> +#include <QUuid> #include <QDebug> @@ -53,28 +53,30 @@ #include "flows/Mojang.h" #include "flows/Offline.h" -MinecraftAccount::MinecraftAccount(QObject* parent) : QObject(parent) { +MinecraftAccount::MinecraftAccount(QObject* parent) : QObject(parent) +{ data.internalId = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]")); } - -MinecraftAccountPtr MinecraftAccount::loadFromJsonV2(const QJsonObject& json) { +MinecraftAccountPtr MinecraftAccount::loadFromJsonV2(const QJsonObject& json) +{ MinecraftAccountPtr account(new MinecraftAccount()); - if(account->data.resumeStateFromV2(json)) { + if (account->data.resumeStateFromV2(json)) { return account; } return nullptr; } -MinecraftAccountPtr MinecraftAccount::loadFromJsonV3(const QJsonObject& json) { +MinecraftAccountPtr MinecraftAccount::loadFromJsonV3(const QJsonObject& json) +{ MinecraftAccountPtr account(new MinecraftAccount()); - if(account->data.resumeStateFromV3(json)) { + if (account->data.resumeStateFromV3(json)) { return account; } return nullptr; } -MinecraftAccountPtr MinecraftAccount::createFromUsername(const QString &username) +MinecraftAccountPtr MinecraftAccount::createFromUsername(const QString& username) { auto account = makeShared<MinecraftAccount>(); account->data.type = AccountType::Mojang; @@ -90,7 +92,7 @@ MinecraftAccountPtr MinecraftAccount::createBlankMSA() return account; } -MinecraftAccountPtr MinecraftAccount::createOffline(const QString &username) +MinecraftAccountPtr MinecraftAccount::createOffline(const QString& username) { auto account = makeShared<MinecraftAccount>(); account->data.type = AccountType::Offline; @@ -107,19 +109,20 @@ MinecraftAccountPtr MinecraftAccount::createOffline(const QString &username) return account; } - QJsonObject MinecraftAccount::saveToJson() const { return data.saveState(); } -AccountState MinecraftAccount::accountState() const { +AccountState MinecraftAccount::accountState() const +{ return data.accountState; } -QPixmap MinecraftAccount::getFace() const { +QPixmap MinecraftAccount::getFace() const +{ QPixmap skinTexture; - if(!skinTexture.loadFromData(data.minecraftProfile.skin.data, "PNG")) { + if (!skinTexture.loadFromData(data.minecraftProfile.skin.data, "PNG")) { return QPixmap(); } QPixmap skin = QPixmap(8, 8); @@ -129,67 +132,68 @@ QPixmap MinecraftAccount::getFace() const { return skin.scaled(64, 64, Qt::KeepAspectRatio); } - -shared_qobject_ptr<AccountTask> MinecraftAccount::login(QString password) { +shared_qobject_ptr<AccountTask> MinecraftAccount::login(QString password) +{ Q_ASSERT(m_currentTask.get() == nullptr); m_currentTask.reset(new MojangLogin(&data, password)); connect(m_currentTask.get(), &Task::succeeded, this, &MinecraftAccount::authSucceeded); connect(m_currentTask.get(), &Task::failed, this, &MinecraftAccount::authFailed); - connect(m_currentTask.get(), &Task::aborted, this, [this]{ authFailed(tr("Aborted")); }); + connect(m_currentTask.get(), &Task::aborted, this, [this] { authFailed(tr("Aborted")); }); emit activityChanged(true); return m_currentTask; } -shared_qobject_ptr<AccountTask> MinecraftAccount::loginMSA() { +shared_qobject_ptr<AccountTask> MinecraftAccount::loginMSA() +{ Q_ASSERT(m_currentTask.get() == nullptr); m_currentTask.reset(new MSAInteractive(&data)); connect(m_currentTask.get(), &Task::succeeded, this, &MinecraftAccount::authSucceeded); connect(m_currentTask.get(), &Task::failed, this, &MinecraftAccount::authFailed); - connect(m_currentTask.get(), &Task::aborted, this, [this]{ authFailed(tr("Aborted")); }); + connect(m_currentTask.get(), &Task::aborted, this, [this] { authFailed(tr("Aborted")); }); emit activityChanged(true); return m_currentTask; } -shared_qobject_ptr<AccountTask> MinecraftAccount::loginOffline() { +shared_qobject_ptr<AccountTask> MinecraftAccount::loginOffline() +{ Q_ASSERT(m_currentTask.get() == nullptr); m_currentTask.reset(new OfflineLogin(&data)); connect(m_currentTask.get(), &Task::succeeded, this, &MinecraftAccount::authSucceeded); connect(m_currentTask.get(), &Task::failed, this, &MinecraftAccount::authFailed); - connect(m_currentTask.get(), &Task::aborted, this, [this]{ authFailed(tr("Aborted")); }); + connect(m_currentTask.get(), &Task::aborted, this, [this] { authFailed(tr("Aborted")); }); emit activityChanged(true); return m_currentTask; } -shared_qobject_ptr<AccountTask> MinecraftAccount::refresh() { - if(m_currentTask) { +shared_qobject_ptr<AccountTask> MinecraftAccount::refresh() +{ + if (m_currentTask) { return m_currentTask; } - if(data.type == AccountType::MSA) { + if (data.type == AccountType::MSA) { m_currentTask.reset(new MSASilent(&data)); - } - else if(data.type == AccountType::Offline) { + } else if (data.type == AccountType::Offline) { m_currentTask.reset(new OfflineRefresh(&data)); - } - else { + } else { m_currentTask.reset(new MojangRefresh(&data)); } connect(m_currentTask.get(), &Task::succeeded, this, &MinecraftAccount::authSucceeded); connect(m_currentTask.get(), &Task::failed, this, &MinecraftAccount::authFailed); - connect(m_currentTask.get(), &Task::aborted, this, [this]{ authFailed(tr("Aborted")); }); + connect(m_currentTask.get(), &Task::aborted, this, [this] { authFailed(tr("Aborted")); }); emit activityChanged(true); return m_currentTask; } -shared_qobject_ptr<AccountTask> MinecraftAccount::currentTask() { +shared_qobject_ptr<AccountTask> MinecraftAccount::currentTask() +{ return m_currentTask; } - void MinecraftAccount::authSucceeded() { m_currentTask.reset(); @@ -206,28 +210,24 @@ void MinecraftAccount::authFailed(QString reason) } case AccountTaskState::STATE_FAILED_SOFT: { // NOTE: this doesn't do much. There was an error of some sort. - } - break; + } break; case AccountTaskState::STATE_FAILED_HARD: { - if(isMSA()) { + if (isMSA()) { data.msaToken.token = QString(); data.msaToken.refresh_token = QString(); data.msaToken.validity = Katabasis::Validity::None; data.validity_ = Katabasis::Validity::None; - } - else { + } else { data.yggdrasilToken.token = QString(); data.yggdrasilToken.validity = Katabasis::Validity::None; data.validity_ = Katabasis::Validity::None; } emit changed(); - } - break; + } break; case AccountTaskState::STATE_FAILED_GONE: { data.validity_ = Katabasis::Validity::None; emit changed(); - } - break; + } break; case AccountTaskState::STATE_CREATED: case AccountTaskState::STATE_WORKING: case AccountTaskState::STATE_SUCCEEDED: { @@ -238,21 +238,23 @@ void MinecraftAccount::authFailed(QString reason) emit activityChanged(false); } -bool MinecraftAccount::isActive() const { +bool MinecraftAccount::isActive() const +{ return !m_currentTask.isNull(); } -bool MinecraftAccount::shouldRefresh() const { +bool MinecraftAccount::shouldRefresh() const +{ /* * Never refresh accounts that are being used by the game, it breaks the game session. * Always refresh accounts that have not been refreshed yet during this session. * Don't refresh broken accounts. * Refresh accounts that would expire in the next 12 hours (fresh token validity is 24 hours). */ - if(isInUse()) { + if (isInUse()) { return false; } - switch(data.validity_) { + switch (data.validity_) { case Katabasis::Validity::Certain: { break; } @@ -267,7 +269,7 @@ bool MinecraftAccount::shouldRefresh() const { auto issuedTimestamp = data.yggdrasilToken.issueInstant; auto expiresTimestamp = data.yggdrasilToken.notAfter; - if(!expiresTimestamp.isValid()) { + if (!expiresTimestamp.isValid()) { expiresTimestamp = issuedTimestamp.addSecs(24 * 3600); } if (now.secsTo(expiresTimestamp) < (12 * 3600)) { @@ -278,14 +280,12 @@ bool MinecraftAccount::shouldRefresh() const { void MinecraftAccount::fillSession(AuthSessionPtr session) { - if(ownsMinecraft() && !hasProfile()) { + if (ownsMinecraft() && !hasProfile()) { session->status = AuthSession::RequiresProfileSetup; - } - else { - if(session->wants_online) { + } else { + if (session->wants_online) { session->status = AuthSession::PlayableOnline; - } - else { + } else { session->status = AuthSession::PlayableOffline; } } @@ -303,12 +303,9 @@ void MinecraftAccount::fillSession(AuthSessionPtr session) session->uuid = data.profileId(); // 'legacy' or 'mojang', depending on account type session->user_type = typeString(); - if (!session->access_token.isEmpty()) - { + if (!session->access_token.isEmpty()) { session->session = "token:" + data.accessToken() + ":" + data.profileId(); - } - else - { + } else { session->session = "-"; } } @@ -316,8 +313,7 @@ void MinecraftAccount::fillSession(AuthSessionPtr session) void MinecraftAccount::decrementUses() { Usable::decrementUses(); - if(!isInUse()) - { + if (!isInUse()) { emit changed(); // FIXME: we now need a better way to identify accounts... qWarning() << "Profile" << data.profileId() << "is no longer in use."; @@ -328,39 +324,31 @@ void MinecraftAccount::incrementUses() { bool wasInUse = isInUse(); Usable::incrementUses(); - if(!wasInUse) - { + if (!wasInUse) { emit changed(); // FIXME: we now need a better way to identify accounts... qWarning() << "Profile" << data.profileId() << "is now in use."; } } -QUuid MinecraftAccount::uuidFromUsername(QString username) { +QUuid MinecraftAccount::uuidFromUsername(QString username) +{ auto input = QString("OfflinePlayer:%1").arg(username).toUtf8(); // basically a reimplementation of Java's UUID#nameUUIDFromBytes QByteArray digest = QCryptographicHash::hash(input, QCryptographicHash::Md5); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - auto bOr = [](QByteArray& array, int index, char value) { - array[index] = array.at(index) | value; - }; - auto bAnd = [](QByteArray& array, int index, char value) { - array[index] = array.at(index) & value; - }; + auto bOr = [](QByteArray& array, int index, char value) { array[index] = array.at(index) | value; }; + auto bAnd = [](QByteArray& array, int index, char value) { array[index] = array.at(index) & value; }; #else - auto bOr = [](QByteArray& array, qsizetype index, char value) { - array[index] |= value; - }; - auto bAnd = [](QByteArray& array, qsizetype index, char value) { - array[index] &= value; - }; + auto bOr = [](QByteArray& array, qsizetype index, char value) { array[index] |= value; }; + auto bAnd = [](QByteArray& array, qsizetype index, char value) { array[index] &= value; }; #endif - bAnd(digest, 6, (char) 0x0f); // clear version - bOr(digest, 6, (char) 0x30); // set to version 3 - bAnd(digest, 8, (char) 0x3f); // clear variant - bOr(digest, 8, (char) 0x80); // set to IETF variant + bAnd(digest, 6, (char)0x0f); // clear version + bOr(digest, 6, (char)0x30); // set to version 3 + bAnd(digest, 8, (char)0x3f); // clear variant + bOr(digest, 8, (char)0x80); // set to IETF variant return QUuid::fromRfc4122(digest); } diff --git a/launcher/minecraft/auth/MinecraftAccount.h b/launcher/minecraft/auth/MinecraftAccount.h index 67623a5a..395ca549 100644 --- a/launcher/minecraft/auth/MinecraftAccount.h +++ b/launcher/minecraft/auth/MinecraftAccount.h @@ -35,20 +35,20 @@ #pragma once -#include <QObject> -#include <QString> -#include <QList> #include <QJsonObject> -#include <QPair> +#include <QList> #include <QMap> +#include <QObject> +#include <QPair> #include <QPixmap> +#include <QString> #include <memory> -#include "AuthSession.h" -#include "Usable.h" #include "AccountData.h" +#include "AuthSession.h" #include "QObjectPtr.h" +#include "Usable.h" class Task; class AccountTask; @@ -64,8 +64,7 @@ Q_DECLARE_METATYPE(MinecraftAccountPtr) * but we might as well add some things for it in Prism Launcher right now so * we don't have to rip the code to pieces to add it later. */ -struct AccountProfile -{ +struct AccountProfile { QString id; QString name; bool legacy; @@ -77,34 +76,30 @@ struct AccountProfile * Said information may include things such as that account's username, client token, and access * token if the user chose to stay logged in. */ -class MinecraftAccount : - public QObject, - public Usable -{ +class MinecraftAccount : public QObject, public Usable { Q_OBJECT -public: /* construction */ + public: /* construction */ //! Do not copy accounts. ever. - explicit MinecraftAccount(const MinecraftAccount &other, QObject *parent) = delete; + explicit MinecraftAccount(const MinecraftAccount& other, QObject* parent) = delete; //! Default constructor - explicit MinecraftAccount(QObject *parent = 0); + explicit MinecraftAccount(QObject* parent = 0); - static MinecraftAccountPtr createFromUsername(const QString &username); + static MinecraftAccountPtr createFromUsername(const QString& username); static MinecraftAccountPtr createBlankMSA(); - static MinecraftAccountPtr createOffline(const QString &username); + static MinecraftAccountPtr createOffline(const QString& username); - static MinecraftAccountPtr loadFromJsonV2(const QJsonObject &json); - static MinecraftAccountPtr loadFromJsonV3(const QJsonObject &json); + static MinecraftAccountPtr loadFromJsonV2(const QJsonObject& json); + static MinecraftAccountPtr loadFromJsonV3(const QJsonObject& json); static QUuid uuidFromUsername(QString username); //! Saves a MinecraftAccount to a JSON object and returns it. QJsonObject saveToJson() const; -public: /* manipulation */ - + public: /* manipulation */ /** * Attempt to login. Empty password means we use the token. * If the attempt fails because we already are performing some task, it returns false. @@ -119,70 +114,46 @@ public: /* manipulation */ shared_qobject_ptr<AccountTask> currentTask(); -public: /* queries */ - QString internalId() const { - return data.internalId; - } + public: /* queries */ + QString internalId() const { return data.internalId; } - QString accountDisplayString() const { - return data.accountDisplayString(); - } + QString accountDisplayString() const { return data.accountDisplayString(); } - QString mojangUserName() const { - return data.userName(); - } + QString mojangUserName() const { return data.userName(); } - QString accessToken() const { - return data.accessToken(); - } + QString accessToken() const { return data.accessToken(); } - QString profileId() const { - return data.profileId(); - } + QString profileId() const { return data.profileId(); } - QString profileName() const { - return data.profileName(); - } + QString profileName() const { return data.profileName(); } bool isActive() const; - bool canMigrate() const { - return data.canMigrateToMSA; - } + bool canMigrate() const { return data.canMigrateToMSA; } - bool isMSA() const { - return data.type == AccountType::MSA; - } + bool isMSA() const { return data.type == AccountType::MSA; } - bool isOffline() const { - return data.type == AccountType::Offline; - } + bool isOffline() const { return data.type == AccountType::Offline; } - bool ownsMinecraft() const { - return data.minecraftEntitlement.ownsMinecraft; - } + bool ownsMinecraft() const { return data.minecraftEntitlement.ownsMinecraft; } - bool hasProfile() const { - return data.profileId().size() != 0; - } + bool hasProfile() const { return data.profileId().size() != 0; } - QString typeString() const { - switch(data.type) { + QString typeString() const + { + switch (data.type) { case AccountType::Mojang: { - if(data.legacy) { + if (data.legacy) { return "legacy"; } return "mojang"; - } - break; + } break; case AccountType::MSA: { return "msa"; - } - break; + } break; case AccountType::Offline: { return "offline"; - } - break; + } break; default: { return "unknown"; } @@ -194,19 +165,15 @@ public: /* queries */ //! Returns the current state of the account AccountState accountState() const; - AccountData * accountData() { - return &data; - } + AccountData* accountData() { return &data; } bool shouldRefresh() const; void fillSession(AuthSessionPtr session); - QString lastError() const { - return data.lastError(); - } + QString lastError() const { return data.lastError(); } -signals: + signals: /** * This signal is emitted when the account changes */ @@ -216,20 +183,17 @@ signals: // TODO: better signalling for the various possible state changes - especially errors -protected: /* variables */ + protected: /* variables */ AccountData data; // current task we are executing here shared_qobject_ptr<AccountTask> m_currentTask; -protected: /* methods */ - + protected: /* methods */ void incrementUses() override; void decrementUses() override; -private -slots: + private slots: void authSucceeded(); void authFailed(QString reason); }; - diff --git a/launcher/minecraft/auth/Parsers.cpp b/launcher/minecraft/auth/Parsers.cpp index f3d9ad56..8dbe446a 100644 --- a/launcher/minecraft/auth/Parsers.cpp +++ b/launcher/minecraft/auth/Parsers.cpp @@ -2,46 +2,51 @@ #include "Json.h" #include "Logging.h" -#include <QJsonDocument> -#include <QJsonArray> #include <QDebug> +#include <QJsonArray> +#include <QJsonDocument> namespace Parsers { -bool getDateTime(QJsonValue value, QDateTime & out) { - if(!value.isString()) { +bool getDateTime(QJsonValue value, QDateTime& out) +{ + if (!value.isString()) { return false; } out = QDateTime::fromString(value.toString(), Qt::ISODate); return out.isValid(); } -bool getString(QJsonValue value, QString & out) { - if(!value.isString()) { +bool getString(QJsonValue value, QString& out) +{ + if (!value.isString()) { return false; } out = value.toString(); return true; } -bool getNumber(QJsonValue value, double & out) { - if(!value.isDouble()) { +bool getNumber(QJsonValue value, double& out) +{ + if (!value.isDouble()) { return false; } out = value.toDouble(); return true; } -bool getNumber(QJsonValue value, int64_t & out) { - if(!value.isDouble()) { +bool getNumber(QJsonValue value, int64_t& out) +{ + if (!value.isDouble()) { return false; } - out = (int64_t) value.toDouble(); + out = (int64_t)value.toDouble(); return true; } -bool getBool(QJsonValue value, bool & out) { - if(!value.isBool()) { +bool getBool(QJsonValue value, bool& out) +{ + if (!value.isBool()) { return false; } out = value.toBool(); @@ -74,49 +79,50 @@ bool getBool(QJsonValue value, bool & out) { // 2148916238 = child account not linked to a family */ -bool parseXTokenResponse(QByteArray & data, Katabasis::Token &output, QString name) { - qDebug() << "Parsing" << name <<":"; +bool parseXTokenResponse(QByteArray& data, Katabasis::Token& output, QString name) +{ + qDebug() << "Parsing" << name << ":"; qCDebug(authCredentials()) << data; QJsonParseError jsonError; QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError); - if(jsonError.error) { + if (jsonError.error) { qWarning() << "Failed to parse response from user.auth.xboxlive.com as JSON: " << jsonError.errorString(); return false; } auto obj = doc.object(); - if(!getDateTime(obj.value("IssueInstant"), output.issueInstant)) { + if (!getDateTime(obj.value("IssueInstant"), output.issueInstant)) { qWarning() << "User IssueInstant is not a timestamp"; return false; } - if(!getDateTime(obj.value("NotAfter"), output.notAfter)) { + if (!getDateTime(obj.value("NotAfter"), output.notAfter)) { qWarning() << "User NotAfter is not a timestamp"; return false; } - if(!getString(obj.value("Token"), output.token)) { + if (!getString(obj.value("Token"), output.token)) { qWarning() << "User Token is not a string"; return false; } auto arrayVal = obj.value("DisplayClaims").toObject().value("xui"); - if(!arrayVal.isArray()) { + if (!arrayVal.isArray()) { qWarning() << "Missing xui claims array"; return false; } bool foundUHS = false; - for(auto item: arrayVal.toArray()) { - if(!item.isObject()) { + for (auto item : arrayVal.toArray()) { + if (!item.isObject()) { continue; } auto obj = item.toObject(); - if(obj.contains("uhs")) { + if (obj.contains("uhs")) { foundUHS = true; } else { continue; } // consume all 'display claims' ... whatever that means - for(auto iter = obj.begin(); iter != obj.end(); iter++) { + for (auto iter = obj.begin(); iter != obj.end(); iter++) { QString claim; - if(!getString(obj.value(iter.key()), claim)) { + if (!getString(obj.value(iter.key()), claim)) { qWarning() << "display claim " << iter.key() << " is not a string..."; return false; } @@ -125,7 +131,7 @@ bool parseXTokenResponse(QByteArray & data, Katabasis::Token &output, QString na break; } - if(!foundUHS) { + if (!foundUHS) { qWarning() << "Missing uhs"; return false; } @@ -134,46 +140,47 @@ bool parseXTokenResponse(QByteArray & data, Katabasis::Token &output, QString na return true; } -bool parseMinecraftProfile(QByteArray & data, MinecraftProfile &output) { +bool parseMinecraftProfile(QByteArray& data, MinecraftProfile& output) +{ qDebug() << "Parsing Minecraft profile..."; qCDebug(authCredentials()) << data; QJsonParseError jsonError; QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError); - if(jsonError.error) { + if (jsonError.error) { qWarning() << "Failed to parse response from user.auth.xboxlive.com as JSON: " << jsonError.errorString(); return false; } auto obj = doc.object(); - if(!getString(obj.value("id"), output.id)) { + if (!getString(obj.value("id"), output.id)) { qWarning() << "Minecraft profile id is not a string"; return false; } - if(!getString(obj.value("name"), output.name)) { + if (!getString(obj.value("name"), output.name)) { qWarning() << "Minecraft profile name is not a string"; return false; } auto skinsArray = obj.value("skins").toArray(); - for(auto skin: skinsArray) { + for (auto skin : skinsArray) { auto skinObj = skin.toObject(); Skin skinOut; - if(!getString(skinObj.value("id"), skinOut.id)) { + if (!getString(skinObj.value("id"), skinOut.id)) { continue; } QString state; - if(!getString(skinObj.value("state"), state)) { + if (!getString(skinObj.value("state"), state)) { continue; } - if(state != "ACTIVE") { + if (state != "ACTIVE") { continue; } - if(!getString(skinObj.value("url"), skinOut.url)) { + if (!getString(skinObj.value("url"), skinOut.url)) { continue; } - if(!getString(skinObj.value("variant"), skinOut.variant)) { + if (!getString(skinObj.value("variant"), skinOut.variant)) { continue; } // we deal with only the active skin @@ -183,23 +190,23 @@ bool parseMinecraftProfile(QByteArray & data, MinecraftProfile &output) { auto capesArray = obj.value("capes").toArray(); QString currentCape; - for(auto cape: capesArray) { + for (auto cape : capesArray) { auto capeObj = cape.toObject(); Cape capeOut; - if(!getString(capeObj.value("id"), capeOut.id)) { + if (!getString(capeObj.value("id"), capeOut.id)) { continue; } QString state; - if(!getString(capeObj.value("state"), state)) { + if (!getString(capeObj.value("state"), state)) { continue; } - if(state == "ACTIVE") { + if (state == "ACTIVE") { currentCape = capeOut.id; } - if(!getString(capeObj.value("url"), capeOut.url)) { + if (!getString(capeObj.value("url"), capeOut.url)) { continue; } - if(!getString(capeObj.value("alias"), capeOut.alias)) { + if (!getString(capeObj.value("alias"), capeOut.alias)) { continue; } @@ -211,30 +218,33 @@ bool parseMinecraftProfile(QByteArray & data, MinecraftProfile &output) { } namespace { - // these skin URLs are for the MHF_Steve and MHF_Alex accounts (made by a Mojang employee) - // they are needed because the session server doesn't return skin urls for default skins - static const QString SKIN_URL_STEVE = "http://textures.minecraft.net/texture/1a4af718455d4aab528e7a61f86fa25e6a369d1768dcb13f7df319a713eb810b"; - static const QString SKIN_URL_ALEX = "http://textures.minecraft.net/texture/83cee5ca6afcdb171285aa00e8049c297b2dbeba0efb8ff970a5677a1b644032"; - - bool isDefaultModelSteve(QString uuid) { - // need to calculate *Java* hashCode of UUID - // if number is even, skin/model is steve, otherwise it is alex - - // just in case dashes are in the id - uuid.remove('-'); +// these skin URLs are for the MHF_Steve and MHF_Alex accounts (made by a Mojang employee) +// they are needed because the session server doesn't return skin urls for default skins +static const QString SKIN_URL_STEVE = + "http://textures.minecraft.net/texture/1a4af718455d4aab528e7a61f86fa25e6a369d1768dcb13f7df319a713eb810b"; +static const QString SKIN_URL_ALEX = + "http://textures.minecraft.net/texture/83cee5ca6afcdb171285aa00e8049c297b2dbeba0efb8ff970a5677a1b644032"; + +bool isDefaultModelSteve(QString uuid) +{ + // need to calculate *Java* hashCode of UUID + // if number is even, skin/model is steve, otherwise it is alex - if (uuid.size() != 32) { - return true; - } + // just in case dashes are in the id + uuid.remove('-'); - // qulonglong is guaranteed to be 64 bits - // we need to use unsigned numbers to guarantee truncation below - qulonglong most = uuid.left(16).toULongLong(nullptr, 16); - qulonglong least = uuid.right(16).toULongLong(nullptr, 16); - qulonglong xored = most ^ least; - return ((static_cast<quint32>(xored >> 32)) ^ static_cast<quint32>(xored)) % 2 == 0; + if (uuid.size() != 32) { + return true; } + + // qulonglong is guaranteed to be 64 bits + // we need to use unsigned numbers to guarantee truncation below + qulonglong most = uuid.left(16).toULongLong(nullptr, 16); + qulonglong least = uuid.right(16).toULongLong(nullptr, 16); + qulonglong xored = most ^ least; + return ((static_cast<quint32>(xored >> 32)) ^ static_cast<quint32>(xored)) % 2 == 0; } +} // namespace /** Uses session server for skin/cape lookup instead of profile, @@ -270,31 +280,32 @@ decoded base64 "value": } */ -bool parseMinecraftProfileMojang(QByteArray & data, MinecraftProfile &output) { +bool parseMinecraftProfileMojang(QByteArray& data, MinecraftProfile& output) +{ qDebug() << "Parsing Minecraft profile..."; qCDebug(authCredentials()) << data; QJsonParseError jsonError; QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError); - if(jsonError.error) { + if (jsonError.error) { qWarning() << "Failed to parse response as JSON: " << jsonError.errorString(); return false; } auto obj = Json::requireObject(doc, "mojang minecraft profile"); - if(!getString(obj.value("id"), output.id)) { + if (!getString(obj.value("id"), output.id)) { qWarning() << "Minecraft profile id is not a string"; return false; } - if(!getString(obj.value("name"), output.name)) { + if (!getString(obj.value("name"), output.name)) { qWarning() << "Minecraft profile name is not a string"; return false; } auto propsArray = obj.value("properties").toArray(); QByteArray texturePayload; - for( auto p : propsArray) { + for (auto p : propsArray) { auto pObj = p.toObject(); auto name = pObj.value("name"); if (!name.isString() || name.toString() != "textures") { @@ -321,7 +332,7 @@ bool parseMinecraftProfileMojang(QByteArray & data, MinecraftProfile &output) { } doc = QJsonDocument::fromJson(texturePayload, &jsonError); - if(jsonError.error) { + if (jsonError.error) { qWarning() << "Failed to parse response as JSON: " << jsonError.errorString(); return false; } @@ -357,8 +368,7 @@ bool parseMinecraftProfileMojang(QByteArray & data, MinecraftProfile &output) { // might not be present getString(meta.value("model"), skinOut.variant); } - } - else if (idx.key() == "CAPE") { + } else if (idx.key() == "CAPE") { auto cape = idx->toObject(); if (!getString(cape.value("url"), capeOut.url)) { qWarning() << "Cape url is not a string"; @@ -374,7 +384,7 @@ bool parseMinecraftProfileMojang(QByteArray & data, MinecraftProfile &output) { output.skin = skinOut; if (capeOut.alias == "cape") { - output.capes = QMap<QString, Cape>({{capeOut.alias, capeOut}}); + output.capes = QMap<QString, Cape>({ { capeOut.alias, capeOut } }); output.currentCape = capeOut.alias; } @@ -382,13 +392,14 @@ bool parseMinecraftProfileMojang(QByteArray & data, MinecraftProfile &output) { return true; } -bool parseMinecraftEntitlements(QByteArray & data, MinecraftEntitlement &output) { +bool parseMinecraftEntitlements(QByteArray& data, MinecraftEntitlement& output) +{ qDebug() << "Parsing Minecraft entitlements..."; qCDebug(authCredentials()) << data; QJsonParseError jsonError; QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError); - if(jsonError.error) { + if (jsonError.error) { qWarning() << "Failed to parse response from user.auth.xboxlive.com as JSON: " << jsonError.errorString(); return false; } @@ -398,16 +409,16 @@ bool parseMinecraftEntitlements(QByteArray & data, MinecraftEntitlement &output) output.ownsMinecraft = false; auto itemsArray = obj.value("items").toArray(); - for(auto item: itemsArray) { + for (auto item : itemsArray) { auto itemObj = item.toObject(); QString name; - if(!getString(itemObj.value("name"), name)) { + if (!getString(itemObj.value("name"), name)) { continue; } - if(name == "game_minecraft") { + if (name == "game_minecraft") { output.canPlayMinecraft = true; } - if(name == "product_minecraft") { + if (name == "product_minecraft") { output.ownsMinecraft = true; } } @@ -415,47 +426,50 @@ bool parseMinecraftEntitlements(QByteArray & data, MinecraftEntitlement &output) return true; } -bool parseRolloutResponse(QByteArray & data, bool& result) { +bool parseRolloutResponse(QByteArray& data, bool& result) +{ qDebug() << "Parsing Rollout response..."; qCDebug(authCredentials()) << data; QJsonParseError jsonError; QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError); - if(jsonError.error) { - qWarning() << "Failed to parse response from https://api.minecraftservices.com/rollout/v1/msamigration as JSON: " << jsonError.errorString(); + if (jsonError.error) { + qWarning() << "Failed to parse response from https://api.minecraftservices.com/rollout/v1/msamigration as JSON: " + << jsonError.errorString(); return false; } auto obj = doc.object(); QString feature; - if(!getString(obj.value("feature"), feature)) { + if (!getString(obj.value("feature"), feature)) { qWarning() << "Rollout feature is not a string"; return false; } - if(feature != "msamigration") { + if (feature != "msamigration") { qWarning() << "Rollout feature is not what we expected (msamigration), but is instead \"" << feature << "\""; return false; } - if(!getBool(obj.value("rollout"), result)) { + if (!getBool(obj.value("rollout"), result)) { qWarning() << "Rollout feature is not a string"; return false; } return true; } -bool parseMojangResponse(QByteArray & data, Katabasis::Token &output) { +bool parseMojangResponse(QByteArray& data, Katabasis::Token& output) +{ QJsonParseError jsonError; qDebug() << "Parsing Mojang response..."; qCDebug(authCredentials()) << data; QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError); - if(jsonError.error) { + if (jsonError.error) { qWarning() << "Failed to parse response from api.minecraftservices.com/launcher/login as JSON: " << jsonError.errorString(); return false; } auto obj = doc.object(); double expires_in = 0; - if(!getNumber(obj.value("expires_in"), expires_in)) { + if (!getNumber(obj.value("expires_in"), expires_in)) { qWarning() << "expires_in is not a valid number"; return false; } @@ -464,13 +478,13 @@ bool parseMojangResponse(QByteArray & data, Katabasis::Token &output) { output.notAfter = currentTime.addSecs(expires_in); QString username; - if(!getString(obj.value("username"), username)) { + if (!getString(obj.value("username"), username)) { qWarning() << "username is not valid"; return false; } // TODO: it's a JWT... validate it? - if(!getString(obj.value("access_token"), output.token)) { + if (!getString(obj.value("access_token"), output.token)) { qWarning() << "access_token is not valid"; return false; } @@ -479,4 +493,4 @@ bool parseMojangResponse(QByteArray & data, Katabasis::Token &output) { return true; } -} +} // namespace Parsers diff --git a/launcher/minecraft/auth/Parsers.h b/launcher/minecraft/auth/Parsers.h index 2666d890..d073f999 100644 --- a/launcher/minecraft/auth/Parsers.h +++ b/launcher/minecraft/auth/Parsers.h @@ -2,19 +2,18 @@ #include "AccountData.h" -namespace Parsers -{ - bool getDateTime(QJsonValue value, QDateTime & out); - bool getString(QJsonValue value, QString & out); - bool getNumber(QJsonValue value, double & out); - bool getNumber(QJsonValue value, int64_t & out); - bool getBool(QJsonValue value, bool & out); +namespace Parsers { +bool getDateTime(QJsonValue value, QDateTime& out); +bool getString(QJsonValue value, QString& out); +bool getNumber(QJsonValue value, double& out); +bool getNumber(QJsonValue value, int64_t& out); +bool getBool(QJsonValue value, bool& out); - bool parseXTokenResponse(QByteArray &data, Katabasis::Token &output, QString name); - bool parseMojangResponse(QByteArray &data, Katabasis::Token &output); +bool parseXTokenResponse(QByteArray& data, Katabasis::Token& output, QString name); +bool parseMojangResponse(QByteArray& data, Katabasis::Token& output); - bool parseMinecraftProfile(QByteArray &data, MinecraftProfile &output); - bool parseMinecraftProfileMojang(QByteArray &data, MinecraftProfile &output); - bool parseMinecraftEntitlements(QByteArray &data, MinecraftEntitlement &output); - bool parseRolloutResponse(QByteArray &data, bool& result); -} +bool parseMinecraftProfile(QByteArray& data, MinecraftProfile& output); +bool parseMinecraftProfileMojang(QByteArray& data, MinecraftProfile& output); +bool parseMinecraftEntitlements(QByteArray& data, MinecraftEntitlement& output); +bool parseRolloutResponse(QByteArray& data, bool& result); +} // namespace Parsers diff --git a/launcher/minecraft/auth/Yggdrasil.cpp b/launcher/minecraft/auth/Yggdrasil.cpp index d3e7ccdd..97f2a78d 100644 --- a/launcher/minecraft/auth/Yggdrasil.cpp +++ b/launcher/minecraft/auth/Yggdrasil.cpp @@ -16,24 +16,24 @@ #include "Yggdrasil.h" #include "AccountData.h" -#include <QObject> -#include <QString> -#include <QJsonObject> +#include <QByteArray> #include <QJsonDocument> +#include <QJsonObject> #include <QNetworkReply> -#include <QByteArray> +#include <QObject> +#include <QString> #include <QDebug> #include "Application.h" -Yggdrasil::Yggdrasil(AccountData *data, QObject *parent) - : AccountTask(data, parent) +Yggdrasil::Yggdrasil(AccountData* data, QObject* parent) : AccountTask(data, parent) { changeState(AccountTaskState::STATE_CREATED); } -void Yggdrasil::sendRequest(QUrl endpoint, QByteArray content) { +void Yggdrasil::sendRequest(QUrl endpoint, QByteArray content) +{ changeState(AccountTaskState::STATE_WORKING); QNetworkRequest netRequest(endpoint); @@ -52,10 +52,10 @@ void Yggdrasil::sendRequest(QUrl endpoint, QByteArray content) { connect(&counter, &QTimer::timeout, this, &Yggdrasil::heartbeat); } -void Yggdrasil::executeTask() { -} +void Yggdrasil::executeTask() {} -void Yggdrasil::refresh() { +void Yggdrasil::refresh() +{ start(); /* * { @@ -90,7 +90,8 @@ void Yggdrasil::refresh() { sendRequest(reqUrl, requestData); } -void Yggdrasil::login(QString password) { +void Yggdrasil::login(QString password) +{ start(); /* * { @@ -136,20 +137,21 @@ void Yggdrasil::login(QString password) { sendRequest(reqUrl, requestData); } - - -void Yggdrasil::refreshTimers(qint64, qint64) { +void Yggdrasil::refreshTimers(qint64, qint64) +{ timeout_keeper.stop(); timeout_keeper.start(timeout_max); progress(count = 0, timeout_max); } -void Yggdrasil::heartbeat() { +void Yggdrasil::heartbeat() +{ count += time_step; progress(count, timeout_max); } -bool Yggdrasil::abort() { +bool Yggdrasil::abort() +{ progress(timeout_max, timeout_max); // TODO: actually use this in a meaningful way m_aborted = Yggdrasil::BY_USER; @@ -157,14 +159,16 @@ bool Yggdrasil::abort() { return true; } -void Yggdrasil::abortByTimeout() { +void Yggdrasil::abortByTimeout() +{ progress(timeout_max, timeout_max); // TODO: actually use this in a meaningful way m_aborted = Yggdrasil::BY_TIMEOUT; m_netReply->abort(); } -void Yggdrasil::sslErrors(QList<QSslError> errors) { +void Yggdrasil::sslErrors(QList<QSslError> errors) +{ int i = 1; for (auto error : errors) { qCritical() << "LOGIN SSL Error #" << i << " : " << error.errorString(); @@ -174,7 +178,8 @@ void Yggdrasil::sslErrors(QList<QSslError> errors) { } } -void Yggdrasil::processResponse(QJsonObject responseData) { +void Yggdrasil::processResponse(QJsonObject responseData) +{ // Read the response data. We need to get the client token, access token, and the selected // profile. qDebug() << "Processing authentication response."; @@ -188,11 +193,11 @@ void Yggdrasil::processResponse(QJsonObject responseData) { changeState(AccountTaskState::STATE_FAILED_HARD, tr("Authentication server didn't send a client token.")); return; } - if(m_data->clientToken().isEmpty()) { + if (m_data->clientToken().isEmpty()) { m_data->setClientToken(clientToken); - } - else if(clientToken != m_data->clientToken()) { - changeState(AccountTaskState::STATE_FAILED_HARD, tr("Authentication server attempted to change the client token. This isn't supported.")); + } else if (clientToken != m_data->clientToken()) { + changeState(AccountTaskState::STATE_FAILED_HARD, + tr("Authentication server attempted to change the client token. This isn't supported.")); return; } @@ -220,8 +225,7 @@ void Yggdrasil::processResponse(QJsonObject responseData) { for (auto i = profileObj.constBegin(); i != profileObj.constEnd(); ++i) { if (i.key() == "name" && i.value().isString()) { m_data->minecraftProfile.name = i->toString(); - } - else if (i.key() == "id" && i.value().isString()) { + } else if (i.key() == "id" && i.value().isString()) { m_data->minecraftProfile.id = i->toString(); } } @@ -237,50 +241,43 @@ void Yggdrasil::processResponse(QJsonObject responseData) { changeState(AccountTaskState::STATE_SUCCEEDED); } -void Yggdrasil::processReply() { +void Yggdrasil::processReply() +{ changeState(AccountTaskState::STATE_WORKING); - switch (m_netReply->error()) - { - case QNetworkReply::NoError: - break; - case QNetworkReply::TimeoutError: - changeState(AccountTaskState::STATE_FAILED_SOFT, tr("Authentication operation timed out.")); - return; - case QNetworkReply::OperationCanceledError: - changeState(AccountTaskState::STATE_FAILED_SOFT, tr("Authentication operation cancelled.")); - return; - case QNetworkReply::SslHandshakeFailedError: - changeState( - AccountTaskState::STATE_FAILED_SOFT, - tr( - "<b>SSL Handshake failed.</b><br/>There might be a few causes for it:<br/>" - "<ul>" - "<li>You use Windows and need to update your root certificates, please install any outstanding updates.</li>" - "<li>Some device on your network is interfering with SSL traffic. In that case, " - "you have bigger worries than Minecraft not starting.</li>" - "<li>Possibly something else. Check the log file for details</li>" - "</ul>" - ) - ); - return; - // used for invalid credentials and similar errors. Fall through. - case QNetworkReply::ContentAccessDenied: - case QNetworkReply::ContentOperationNotPermittedError: - break; - case QNetworkReply::ContentGoneError: { - changeState( - AccountTaskState::STATE_FAILED_GONE, - tr("The Mojang account no longer exists. It may have been migrated to a Microsoft account.") - ); - return; - } - default: - changeState( - AccountTaskState::STATE_FAILED_SOFT, - tr("Authentication operation failed due to a network error: %1 (%2)").arg(m_netReply->errorString()).arg(m_netReply->error()) - ); - return; + switch (m_netReply->error()) { + case QNetworkReply::NoError: + break; + case QNetworkReply::TimeoutError: + changeState(AccountTaskState::STATE_FAILED_SOFT, tr("Authentication operation timed out.")); + return; + case QNetworkReply::OperationCanceledError: + changeState(AccountTaskState::STATE_FAILED_SOFT, tr("Authentication operation cancelled.")); + return; + case QNetworkReply::SslHandshakeFailedError: + changeState(AccountTaskState::STATE_FAILED_SOFT, + tr("<b>SSL Handshake failed.</b><br/>There might be a few causes for it:<br/>" + "<ul>" + "<li>You use Windows and need to update your root certificates, please install any outstanding updates.</li>" + "<li>Some device on your network is interfering with SSL traffic. In that case, " + "you have bigger worries than Minecraft not starting.</li>" + "<li>Possibly something else. Check the log file for details</li>" + "</ul>")); + return; + // used for invalid credentials and similar errors. Fall through. + case QNetworkReply::ContentAccessDenied: + case QNetworkReply::ContentOperationNotPermittedError: + break; + case QNetworkReply::ContentGoneError: { + changeState(AccountTaskState::STATE_FAILED_GONE, + tr("The Mojang account no longer exists. It may have been migrated to a Microsoft account.")); + return; + } + default: + changeState(AccountTaskState::STATE_FAILED_SOFT, tr("Authentication operation failed due to a network error: %1 (%2)") + .arg(m_netReply->errorString()) + .arg(m_netReply->error())); + return; } // Try to parse the response regardless of the response code. @@ -299,12 +296,11 @@ void Yggdrasil::processReply() { if (jsonError.error == QJsonParseError::NoError || replyData.size() == 0) { processResponse(replyData.size() > 0 ? doc.object() : QJsonObject()); return; - } - else { - changeState( - AccountTaskState::STATE_FAILED_SOFT, - tr("Failed to parse authentication server response JSON response: %1 at offset %2.").arg(jsonError.errorString()).arg(jsonError.offset) - ); + } else { + changeState(AccountTaskState::STATE_FAILED_SOFT, + tr("Failed to parse authentication server response JSON response: %1 at offset %2.") + .arg(jsonError.errorString()) + .arg(jsonError.offset)); qCritical() << replyData; } return; @@ -320,34 +316,26 @@ void Yggdrasil::processReply() { // stuff there. qDebug() << "The request failed, but the server gave us an error message. Processing error."; processError(doc.object()); - } - else { + } else { // The server didn't say anything regarding the error. Give the user an unknown // error. qDebug() << "The request failed and the server gave no error message. Unknown error."; changeState( AccountTaskState::STATE_FAILED_SOFT, - tr("An unknown error occurred when trying to communicate with the authentication server: %1").arg(m_netReply->errorString()) - ); + tr("An unknown error occurred when trying to communicate with the authentication server: %1").arg(m_netReply->errorString())); } } -void Yggdrasil::processError(QJsonObject responseData) { +void Yggdrasil::processError(QJsonObject responseData) +{ QJsonValue errorVal = responseData.value("error"); QJsonValue errorMessageValue = responseData.value("errorMessage"); QJsonValue causeVal = responseData.value("cause"); if (errorVal.isString() && errorMessageValue.isString()) { - m_error = std::shared_ptr<Error>( - new Error { - errorVal.toString(""), - errorMessageValue.toString(""), - causeVal.toString("") - } - ); + m_error = std::shared_ptr<Error>(new Error{ errorVal.toString(""), errorMessageValue.toString(""), causeVal.toString("") }); changeState(AccountTaskState::STATE_FAILED_HARD, m_error->m_errorMessageVerbose); - } - else { + } else { // Error is not in standard format. Don't set m_error and return unknown error. changeState(AccountTaskState::STATE_FAILED_HARD, tr("An unknown Yggdrasil error occurred.")); } diff --git a/launcher/minecraft/auth/Yggdrasil.h b/launcher/minecraft/auth/Yggdrasil.h index 4f52a04c..560d7fb8 100644 --- a/launcher/minecraft/auth/Yggdrasil.h +++ b/launcher/minecraft/auth/Yggdrasil.h @@ -17,10 +17,10 @@ #include "AccountTask.h" -#include <QString> +#include <qsslerror.h> #include <QJsonObject> +#include <QString> #include <QTimer> -#include <qsslerror.h> #include "MinecraftAccount.h" @@ -30,35 +30,25 @@ class QNetworkReply; /** * A Yggdrasil task is a task that performs an operation on a given mojang account. */ -class Yggdrasil : public AccountTask -{ +class Yggdrasil : public AccountTask { Q_OBJECT -public: - explicit Yggdrasil( - AccountData *data, - QObject *parent = 0 - ); + public: + explicit Yggdrasil(AccountData* data, QObject* parent = 0); virtual ~Yggdrasil() = default; void refresh(); void login(QString password); - struct Error - { + struct Error { QString m_errorMessageShort; QString m_errorMessageVerbose; QString m_cause; }; std::shared_ptr<Error> m_error; - enum AbortedBy - { - BY_NOTHING, - BY_USER, - BY_TIMEOUT - } m_aborted = BY_NOTHING; + enum AbortedBy { BY_NOTHING, BY_USER, BY_TIMEOUT } m_aborted = BY_NOTHING; -protected: + protected: void executeTask() override; /** @@ -78,24 +68,24 @@ protected: */ virtual void processError(QJsonObject responseData); -protected slots: + protected slots: void processReply(); void refreshTimers(qint64, qint64); void heartbeat(); void sslErrors(QList<QSslError>); void abortByTimeout(); -public slots: + public slots: virtual bool abort() override; -private: + private: void sendRequest(QUrl endpoint, QByteArray content); -protected: - QNetworkReply *m_netReply = nullptr; + protected: + QNetworkReply* m_netReply = nullptr; QTimer timeout_keeper; QTimer counter; - int count = 0; // num msec since time reset + int count = 0; // num msec since time reset const int timeout_max = 30000; const int time_step = 50; diff --git a/launcher/minecraft/auth/flows/AuthFlow.cpp b/launcher/minecraft/auth/flows/AuthFlow.cpp index 4f78e8c3..c51839a8 100644 --- a/launcher/minecraft/auth/flows/AuthFlow.cpp +++ b/launcher/minecraft/auth/flows/AuthFlow.cpp @@ -1,36 +1,33 @@ +#include <QDebug> #include <QNetworkAccessManager> -#include <QNetworkRequest> #include <QNetworkReply> -#include <QDebug> +#include <QNetworkRequest> #include "AuthFlow.h" #include "katabasis/Globals.h" #include <Application.h> -AuthFlow::AuthFlow(AccountData * data, QObject *parent) : - AccountTask(data, parent) -{ -} +AuthFlow::AuthFlow(AccountData* data, QObject* parent) : AccountTask(data, parent) {} -void AuthFlow::succeed() { +void AuthFlow::succeed() +{ m_data->validity_ = Katabasis::Validity::Certain; - changeState( - AccountTaskState::STATE_SUCCEEDED, - tr("Finished all authentication steps") - ); + changeState(AccountTaskState::STATE_SUCCEEDED, tr("Finished all authentication steps")); } -void AuthFlow::executeTask() { - if(m_currentStep) { +void AuthFlow::executeTask() +{ + if (m_currentStep) { return; } changeState(AccountTaskState::STATE_WORKING, tr("Initializing")); nextStep(); } -void AuthFlow::nextStep() { - if(m_steps.size() == 0) { +void AuthFlow::nextStep() +{ + if (m_steps.size() == 0) { // we got to the end without an incident... assume this is all. m_currentStep.reset(); succeed(); @@ -46,15 +43,13 @@ void AuthFlow::nextStep() { m_currentStep->perform(); } - -QString AuthFlow::getStateMessage() const { - switch (m_taskState) - { +QString AuthFlow::getStateMessage() const +{ + switch (m_taskState) { case AccountTaskState::STATE_WORKING: { - if(m_currentStep) { + if (m_currentStep) { return m_currentStep->describe(); - } - else { + } else { return tr("Working..."); } } @@ -64,8 +59,9 @@ QString AuthFlow::getStateMessage() const { } } -void AuthFlow::stepFinished(AccountTaskState resultingState, QString message) { - if(changeState(resultingState, message)) { +void AuthFlow::stepFinished(AccountTaskState resultingState, QString message) +{ + if (changeState(resultingState, message)) { nextStep(); } } diff --git a/launcher/minecraft/auth/flows/AuthFlow.h b/launcher/minecraft/auth/flows/AuthFlow.h index e067cc99..c2c412ab 100644 --- a/launcher/minecraft/auth/flows/AuthFlow.h +++ b/launcher/minecraft/auth/flows/AuthFlow.h @@ -1,45 +1,42 @@ #pragma once -#include <QObject> +#include <QImage> #include <QList> -#include <QVector> -#include <QSet> #include <QNetworkReply> -#include <QImage> +#include <QObject> +#include <QSet> +#include <QVector> #include <katabasis/DeviceFlow.h> -#include "minecraft/auth/Yggdrasil.h" #include "minecraft/auth/AccountData.h" #include "minecraft/auth/AccountTask.h" #include "minecraft/auth/AuthStep.h" +#include "minecraft/auth/Yggdrasil.h" -class AuthFlow : public AccountTask -{ +class AuthFlow : public AccountTask { Q_OBJECT -public: - explicit AuthFlow(AccountData * data, QObject *parent = 0); + public: + explicit AuthFlow(AccountData* data, QObject* parent = 0); - Katabasis::Validity validity() { - return m_data->validity_; - }; + Katabasis::Validity validity() { return m_data->validity_; }; QString getStateMessage() const override; void executeTask() override; -signals: + signals: void activityChanged(Katabasis::Activity activity); -private slots: + private slots: void stepFinished(AccountTaskState resultingState, QString message); -protected: + protected: void succeed(); void nextStep(); -protected: + protected: QList<AuthStep::Ptr> m_steps; AuthStep::Ptr m_currentStep; }; diff --git a/launcher/minecraft/auth/flows/MSA.cpp b/launcher/minecraft/auth/flows/MSA.cpp index f1987e0c..f0399342 100644 --- a/launcher/minecraft/auth/flows/MSA.cpp +++ b/launcher/minecraft/auth/flows/MSA.cpp @@ -1,15 +1,16 @@ #include "MSA.h" +#include "minecraft/auth/steps/EntitlementsStep.h" +#include "minecraft/auth/steps/GetSkinStep.h" +#include "minecraft/auth/steps/LauncherLoginStep.h" #include "minecraft/auth/steps/MSAStep.h" -#include "minecraft/auth/steps/XboxUserStep.h" +#include "minecraft/auth/steps/MinecraftProfileStep.h" #include "minecraft/auth/steps/XboxAuthorizationStep.h" -#include "minecraft/auth/steps/LauncherLoginStep.h" #include "minecraft/auth/steps/XboxProfileStep.h" -#include "minecraft/auth/steps/EntitlementsStep.h" -#include "minecraft/auth/steps/MinecraftProfileStep.h" -#include "minecraft/auth/steps/GetSkinStep.h" +#include "minecraft/auth/steps/XboxUserStep.h" -MSASilent::MSASilent(AccountData* data, QObject* parent) : AuthFlow(data, parent) { +MSASilent::MSASilent(AccountData* data, QObject* parent) : AuthFlow(data, parent) +{ m_steps.append(makeShared<MSAStep>(m_data, MSAStep::Action::Refresh)); m_steps.append(makeShared<XboxUserStep>(m_data)); m_steps.append(makeShared<XboxAuthorizationStep>(m_data, &m_data->xboxApiToken, "http://xboxlive.com", "Xbox")); @@ -21,10 +22,8 @@ MSASilent::MSASilent(AccountData* data, QObject* parent) : AuthFlow(data, parent m_steps.append(makeShared<GetSkinStep>(m_data)); } -MSAInteractive::MSAInteractive( - AccountData* data, - QObject* parent -) : AuthFlow(data, parent) { +MSAInteractive::MSAInteractive(AccountData* data, QObject* parent) : AuthFlow(data, parent) +{ m_steps.append(makeShared<MSAStep>(m_data, MSAStep::Action::Login)); m_steps.append(makeShared<XboxUserStep>(m_data)); m_steps.append(makeShared<XboxAuthorizationStep>(m_data, &m_data->xboxApiToken, "http://xboxlive.com", "Xbox")); diff --git a/launcher/minecraft/auth/flows/MSA.h b/launcher/minecraft/auth/flows/MSA.h index 14a4ff43..e403d530 100644 --- a/launcher/minecraft/auth/flows/MSA.h +++ b/launcher/minecraft/auth/flows/MSA.h @@ -1,22 +1,14 @@ #pragma once #include "AuthFlow.h" -class MSAInteractive : public AuthFlow -{ +class MSAInteractive : public AuthFlow { Q_OBJECT -public: - explicit MSAInteractive( - AccountData *data, - QObject *parent = 0 - ); + public: + explicit MSAInteractive(AccountData* data, QObject* parent = 0); }; -class MSASilent : public AuthFlow -{ +class MSASilent : public AuthFlow { Q_OBJECT -public: - explicit MSASilent( - AccountData * data, - QObject *parent = 0 - ); + public: + explicit MSASilent(AccountData* data, QObject* parent = 0); }; diff --git a/launcher/minecraft/auth/flows/Mojang.cpp b/launcher/minecraft/auth/flows/Mojang.cpp index 5900ea98..7e2db16f 100644 --- a/launcher/minecraft/auth/flows/Mojang.cpp +++ b/launcher/minecraft/auth/flows/Mojang.cpp @@ -1,25 +1,20 @@ #include "Mojang.h" -#include "minecraft/auth/steps/YggdrasilStep.h" -#include "minecraft/auth/steps/MinecraftProfileStepMojang.h" -#include "minecraft/auth/steps/MigrationEligibilityStep.h" #include "minecraft/auth/steps/GetSkinStep.h" +#include "minecraft/auth/steps/MigrationEligibilityStep.h" +#include "minecraft/auth/steps/MinecraftProfileStepMojang.h" +#include "minecraft/auth/steps/YggdrasilStep.h" -MojangRefresh::MojangRefresh( - AccountData *data, - QObject *parent -) : AuthFlow(data, parent) { +MojangRefresh::MojangRefresh(AccountData* data, QObject* parent) : AuthFlow(data, parent) +{ m_steps.append(makeShared<YggdrasilStep>(m_data, QString())); m_steps.append(makeShared<MinecraftProfileStepMojang>(m_data)); m_steps.append(makeShared<MigrationEligibilityStep>(m_data)); m_steps.append(makeShared<GetSkinStep>(m_data)); } -MojangLogin::MojangLogin( - AccountData *data, - QString password, - QObject *parent -): AuthFlow(data, parent), m_password(password) { +MojangLogin::MojangLogin(AccountData* data, QString password, QObject* parent) : AuthFlow(data, parent), m_password(password) +{ m_steps.append(makeShared<YggdrasilStep>(m_data, m_password)); m_steps.append(makeShared<MinecraftProfileStepMojang>(m_data)); m_steps.append(makeShared<MigrationEligibilityStep>(m_data)); diff --git a/launcher/minecraft/auth/flows/Mojang.h b/launcher/minecraft/auth/flows/Mojang.h index c09c81a8..779ca7e3 100644 --- a/launcher/minecraft/auth/flows/Mojang.h +++ b/launcher/minecraft/auth/flows/Mojang.h @@ -1,26 +1,17 @@ #pragma once #include "AuthFlow.h" -class MojangRefresh : public AuthFlow -{ +class MojangRefresh : public AuthFlow { Q_OBJECT -public: - explicit MojangRefresh( - AccountData *data, - QObject *parent = 0 - ); + public: + explicit MojangRefresh(AccountData* data, QObject* parent = 0); }; -class MojangLogin : public AuthFlow -{ +class MojangLogin : public AuthFlow { Q_OBJECT -public: - explicit MojangLogin( - AccountData *data, - QString password, - QObject *parent = 0 - ); + public: + explicit MojangLogin(AccountData* data, QString password, QObject* parent = 0); -private: + private: QString m_password; }; diff --git a/launcher/minecraft/auth/flows/Offline.cpp b/launcher/minecraft/auth/flows/Offline.cpp index d5c63271..3770b869 100644 --- a/launcher/minecraft/auth/flows/Offline.cpp +++ b/launcher/minecraft/auth/flows/Offline.cpp @@ -2,16 +2,12 @@ #include "minecraft/auth/steps/OfflineStep.h" -OfflineRefresh::OfflineRefresh( - AccountData *data, - QObject *parent -) : AuthFlow(data, parent) { +OfflineRefresh::OfflineRefresh(AccountData* data, QObject* parent) : AuthFlow(data, parent) +{ m_steps.append(makeShared<OfflineStep>(m_data)); } -OfflineLogin::OfflineLogin( - AccountData *data, - QObject *parent -) : AuthFlow(data, parent) { +OfflineLogin::OfflineLogin(AccountData* data, QObject* parent) : AuthFlow(data, parent) +{ m_steps.append(makeShared<OfflineStep>(m_data)); } diff --git a/launcher/minecraft/auth/flows/Offline.h b/launcher/minecraft/auth/flows/Offline.h index 5d1f83a4..2bc9c761 100644 --- a/launcher/minecraft/auth/flows/Offline.h +++ b/launcher/minecraft/auth/flows/Offline.h @@ -1,22 +1,14 @@ #pragma once #include "AuthFlow.h" -class OfflineRefresh : public AuthFlow -{ +class OfflineRefresh : public AuthFlow { Q_OBJECT -public: - explicit OfflineRefresh( - AccountData *data, - QObject *parent = 0 - ); + public: + explicit OfflineRefresh(AccountData* data, QObject* parent = 0); }; -class OfflineLogin : public AuthFlow -{ +class OfflineLogin : public AuthFlow { Q_OBJECT -public: - explicit OfflineLogin( - AccountData *data, - QObject *parent = 0 - ); + public: + explicit OfflineLogin(AccountData* data, QObject* parent = 0); }; diff --git a/launcher/minecraft/auth/steps/EntitlementsStep.cpp b/launcher/minecraft/auth/steps/EntitlementsStep.cpp index bd604292..e942db52 100644 --- a/launcher/minecraft/auth/steps/EntitlementsStep.cpp +++ b/launcher/minecraft/auth/steps/EntitlementsStep.cpp @@ -11,12 +11,13 @@ EntitlementsStep::EntitlementsStep(AccountData* data) : AuthStep(data) {} EntitlementsStep::~EntitlementsStep() noexcept = default; -QString EntitlementsStep::describe() { +QString EntitlementsStep::describe() +{ return tr("Determining game ownership."); } - -void EntitlementsStep::perform() { +void EntitlementsStep::perform() +{ auto uuid = QUuid::createUuid(); m_entitlementsRequestId = uuid.toString().remove('{').remove('}'); auto url = "https://api.minecraftservices.com/entitlements/license?requestId=" + m_entitlementsRequestId; @@ -24,22 +25,20 @@ void EntitlementsStep::perform() { request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); request.setRawHeader("Accept", "application/json"); request.setRawHeader("Authorization", QString("Bearer %1").arg(m_data->yggdrasilToken.token).toUtf8()); - AuthRequest *requestor = new AuthRequest(this); + AuthRequest* requestor = new AuthRequest(this); connect(requestor, &AuthRequest::finished, this, &EntitlementsStep::onRequestDone); requestor->get(request); qDebug() << "Getting entitlements..."; } -void EntitlementsStep::rehydrate() { +void EntitlementsStep::rehydrate() +{ // NOOP, for now. We only save bools and there's nothing to check. } -void EntitlementsStep::onRequestDone( - QNetworkReply::NetworkError error, - QByteArray data, - QList<QNetworkReply::RawHeaderPair> headers -) { - auto requestor = qobject_cast<AuthRequest *>(QObject::sender()); +void EntitlementsStep::onRequestDone(QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers) +{ + auto requestor = qobject_cast<AuthRequest*>(QObject::sender()); requestor->deleteLater(); qCDebug(authCredentials()) << data; diff --git a/launcher/minecraft/auth/steps/EntitlementsStep.h b/launcher/minecraft/auth/steps/EntitlementsStep.h index 9412ae79..be16bda1 100644 --- a/launcher/minecraft/auth/steps/EntitlementsStep.h +++ b/launcher/minecraft/auth/steps/EntitlementsStep.h @@ -4,12 +4,11 @@ #include "QObjectPtr.h" #include "minecraft/auth/AuthStep.h" - class EntitlementsStep : public AuthStep { Q_OBJECT -public: - explicit EntitlementsStep(AccountData *data); + public: + explicit EntitlementsStep(AccountData* data); virtual ~EntitlementsStep() noexcept; void perform() override; @@ -17,9 +16,9 @@ public: QString describe() override; -private slots: + private slots: void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>); -private: + private: QString m_entitlementsRequestId; }; diff --git a/launcher/minecraft/auth/steps/GetSkinStep.cpp b/launcher/minecraft/auth/steps/GetSkinStep.cpp index 3521f8dc..52087702 100644 --- a/launcher/minecraft/auth/steps/GetSkinStep.cpp +++ b/launcher/minecraft/auth/steps/GetSkinStep.cpp @@ -6,34 +6,32 @@ #include "minecraft/auth/AuthRequest.h" #include "minecraft/auth/Parsers.h" -GetSkinStep::GetSkinStep(AccountData* data) : AuthStep(data) { - -} +GetSkinStep::GetSkinStep(AccountData* data) : AuthStep(data) {} GetSkinStep::~GetSkinStep() noexcept = default; -QString GetSkinStep::describe() { +QString GetSkinStep::describe() +{ return tr("Getting skin."); } -void GetSkinStep::perform() { +void GetSkinStep::perform() +{ auto url = QUrl(m_data->minecraftProfile.skin.url); QNetworkRequest request = QNetworkRequest(url); - AuthRequest *requestor = new AuthRequest(this); + AuthRequest* requestor = new AuthRequest(this); connect(requestor, &AuthRequest::finished, this, &GetSkinStep::onRequestDone); requestor->get(request); } -void GetSkinStep::rehydrate() { +void GetSkinStep::rehydrate() +{ // NOOP, for now. } -void GetSkinStep::onRequestDone( - QNetworkReply::NetworkError error, - QByteArray data, - QList<QNetworkReply::RawHeaderPair> headers -) { - auto requestor = qobject_cast<AuthRequest *>(QObject::sender()); +void GetSkinStep::onRequestDone(QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers) +{ + auto requestor = qobject_cast<AuthRequest*>(QObject::sender()); requestor->deleteLater(); if (error == QNetworkReply::NoError) { diff --git a/launcher/minecraft/auth/steps/GetSkinStep.h b/launcher/minecraft/auth/steps/GetSkinStep.h index 6b97371e..105e497d 100644 --- a/launcher/minecraft/auth/steps/GetSkinStep.h +++ b/launcher/minecraft/auth/steps/GetSkinStep.h @@ -4,12 +4,11 @@ #include "QObjectPtr.h" #include "minecraft/auth/AuthStep.h" - class GetSkinStep : public AuthStep { Q_OBJECT -public: - explicit GetSkinStep(AccountData *data); + public: + explicit GetSkinStep(AccountData* data); virtual ~GetSkinStep() noexcept; void perform() override; @@ -17,6 +16,6 @@ public: QString describe() override; -private slots: + private slots: void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>); }; diff --git a/launcher/minecraft/auth/steps/LauncherLoginStep.cpp b/launcher/minecraft/auth/steps/LauncherLoginStep.cpp index 8a26cbe7..c57f5111 100644 --- a/launcher/minecraft/auth/steps/LauncherLoginStep.cpp +++ b/launcher/minecraft/auth/steps/LauncherLoginStep.cpp @@ -8,17 +8,17 @@ #include "minecraft/auth/Parsers.h" #include "net/NetUtils.h" -LauncherLoginStep::LauncherLoginStep(AccountData* data) : AuthStep(data) { - -} +LauncherLoginStep::LauncherLoginStep(AccountData* data) : AuthStep(data) {} LauncherLoginStep::~LauncherLoginStep() noexcept = default; -QString LauncherLoginStep::describe() { +QString LauncherLoginStep::describe() +{ return tr("Accessing Mojang services."); } -void LauncherLoginStep::perform() { +void LauncherLoginStep::perform() +{ auto requestURL = "https://api.minecraftservices.com/launcher/login"; auto uhs = m_data->mojangservicesToken.extra["uhs"].toString(); auto xToken = m_data->mojangservicesToken.token; @@ -34,22 +34,20 @@ void LauncherLoginStep::perform() { QNetworkRequest request = QNetworkRequest(QUrl(requestURL)); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); request.setRawHeader("Accept", "application/json"); - AuthRequest *requestor = new AuthRequest(this); + AuthRequest* requestor = new AuthRequest(this); connect(requestor, &AuthRequest::finished, this, &LauncherLoginStep::onRequestDone); requestor->post(request, requestBody.toUtf8()); qDebug() << "Getting Minecraft access token..."; } -void LauncherLoginStep::rehydrate() { +void LauncherLoginStep::rehydrate() +{ // TODO: check the token validity } -void LauncherLoginStep::onRequestDone( - QNetworkReply::NetworkError error, - QByteArray data, - QList<QNetworkReply::RawHeaderPair> headers -) { - auto requestor = qobject_cast<AuthRequest *>(QObject::sender()); +void LauncherLoginStep::onRequestDone(QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers) +{ + auto requestor = qobject_cast<AuthRequest*>(QObject::sender()); requestor->deleteLater(); qCDebug(authCredentials()) << data; @@ -57,27 +55,17 @@ void LauncherLoginStep::onRequestDone( qWarning() << "Reply error:" << error; qCDebug(authCredentials()) << data; if (Net::isApplicationError(error)) { - emit finished( - AccountTaskState::STATE_FAILED_SOFT, - tr("Failed to get Minecraft access token: %1").arg(requestor->errorString_) - ); - } - else { - emit finished( - AccountTaskState::STATE_OFFLINE, - tr("Failed to get Minecraft access token: %1").arg(requestor->errorString_) - ); + emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("Failed to get Minecraft access token: %1").arg(requestor->errorString_)); + } else { + emit finished(AccountTaskState::STATE_OFFLINE, tr("Failed to get Minecraft access token: %1").arg(requestor->errorString_)); } return; } - if(!Parsers::parseMojangResponse(data, m_data->yggdrasilToken)) { + if (!Parsers::parseMojangResponse(data, m_data->yggdrasilToken)) { qWarning() << "Could not parse login_with_xbox response..."; qCDebug(authCredentials()) << data; - emit finished( - AccountTaskState::STATE_FAILED_SOFT, - tr("Failed to parse the Minecraft access token response.") - ); + emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("Failed to parse the Minecraft access token response.")); return; } emit finished(AccountTaskState::STATE_WORKING, tr("")); diff --git a/launcher/minecraft/auth/steps/LauncherLoginStep.h b/launcher/minecraft/auth/steps/LauncherLoginStep.h index e06a306f..30c18e67 100644 --- a/launcher/minecraft/auth/steps/LauncherLoginStep.h +++ b/launcher/minecraft/auth/steps/LauncherLoginStep.h @@ -4,12 +4,11 @@ #include "QObjectPtr.h" #include "minecraft/auth/AuthStep.h" - class LauncherLoginStep : public AuthStep { Q_OBJECT -public: - explicit LauncherLoginStep(AccountData *data); + public: + explicit LauncherLoginStep(AccountData* data); virtual ~LauncherLoginStep() noexcept; void perform() override; @@ -17,6 +16,6 @@ public: QString describe() override; -private slots: + private slots: void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>); }; diff --git a/launcher/minecraft/auth/steps/MSAStep.cpp b/launcher/minecraft/auth/steps/MSAStep.cpp index 6fc8d468..66a9a0e8 100644 --- a/launcher/minecraft/auth/steps/MSAStep.cpp +++ b/launcher/minecraft/auth/steps/MSAStep.cpp @@ -47,7 +47,8 @@ using OAuth2 = Katabasis::DeviceFlow; using Activity = Katabasis::Activity; -MSAStep::MSAStep(AccountData* data, Action action) : AuthStep(data), m_action(action) { +MSAStep::MSAStep(AccountData* data, Action action) : AuthStep(data), m_action(action) +{ m_clientId = APPLICATION->getMSAClientID(); OAuth2::Options opts; opts.scope = "XboxLive.signin offline_access"; @@ -64,13 +65,14 @@ MSAStep::MSAStep(AccountData* data, Action action) : AuthStep(data), m_action(ac MSAStep::~MSAStep() noexcept = default; -QString MSAStep::describe() { +QString MSAStep::describe() +{ return tr("Logging in with Microsoft account."); } - -void MSAStep::rehydrate() { - switch(m_action) { +void MSAStep::rehydrate() +{ + switch (m_action) { case Refresh: { // TODO: check the tokens and see if they are old (older than a day) return; @@ -82,12 +84,14 @@ void MSAStep::rehydrate() { } } -void MSAStep::perform() { - switch(m_action) { +void MSAStep::perform() +{ + switch (m_action) { case Refresh: { if (m_data->msaClientID != m_clientId) { emit hideVerificationUriAndCode(); - emit finished(AccountTaskState::STATE_DISABLED, tr("Microsoft user authentication failed - client identification has changed.")); + emit finished(AccountTaskState::STATE_DISABLED, + tr("Microsoft user authentication failed - client identification has changed.")); } m_oauth2->refresh(); return; @@ -105,8 +109,9 @@ void MSAStep::perform() { } } -void MSAStep::onOAuthActivityChanged(Katabasis::Activity activity) { - switch(activity) { +void MSAStep::onOAuthActivityChanged(Katabasis::Activity activity) +{ + switch (activity) { case Katabasis::Activity::Idle: case Katabasis::Activity::LoggingIn: case Katabasis::Activity::Refreshing: diff --git a/launcher/minecraft/auth/steps/MSAStep.h b/launcher/minecraft/auth/steps/MSAStep.h index e9a1524e..fc070ff6 100644 --- a/launcher/minecraft/auth/steps/MSAStep.h +++ b/launcher/minecraft/auth/steps/MSAStep.h @@ -43,13 +43,11 @@ class MSAStep : public AuthStep { Q_OBJECT -public: - enum Action { - Refresh, - Login - }; -public: - explicit MSAStep(AccountData *data, Action action); + public: + enum Action { Refresh, Login }; + + public: + explicit MSAStep(AccountData* data, Action action); virtual ~MSAStep() noexcept; void perform() override; @@ -57,11 +55,11 @@ public: QString describe() override; -private slots: + private slots: void onOAuthActivityChanged(Katabasis::Activity activity); -private: - Katabasis::DeviceFlow *m_oauth2 = nullptr; + private: + Katabasis::DeviceFlow* m_oauth2 = nullptr; Action m_action; QString m_clientId; }; diff --git a/launcher/minecraft/auth/steps/MigrationEligibilityStep.cpp b/launcher/minecraft/auth/steps/MigrationEligibilityStep.cpp index f5b5637a..5ce953df 100644 --- a/launcher/minecraft/auth/steps/MigrationEligibilityStep.cpp +++ b/launcher/minecraft/auth/steps/MigrationEligibilityStep.cpp @@ -5,37 +5,37 @@ #include "minecraft/auth/AuthRequest.h" #include "minecraft/auth/Parsers.h" -MigrationEligibilityStep::MigrationEligibilityStep(AccountData* data) : AuthStep(data) { - -} +MigrationEligibilityStep::MigrationEligibilityStep(AccountData* data) : AuthStep(data) {} MigrationEligibilityStep::~MigrationEligibilityStep() noexcept = default; -QString MigrationEligibilityStep::describe() { +QString MigrationEligibilityStep::describe() +{ return tr("Checking for migration eligibility."); } -void MigrationEligibilityStep::perform() { +void MigrationEligibilityStep::perform() +{ auto url = QUrl("https://api.minecraftservices.com/rollout/v1/msamigration"); QNetworkRequest request = QNetworkRequest(url); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); request.setRawHeader("Authorization", QString("Bearer %1").arg(m_data->yggdrasilToken.token).toUtf8()); - AuthRequest *requestor = new AuthRequest(this); + AuthRequest* requestor = new AuthRequest(this); connect(requestor, &AuthRequest::finished, this, &MigrationEligibilityStep::onRequestDone); requestor->get(request); } -void MigrationEligibilityStep::rehydrate() { +void MigrationEligibilityStep::rehydrate() +{ // NOOP, for now. We only save bools and there's nothing to check. } -void MigrationEligibilityStep::onRequestDone( - QNetworkReply::NetworkError error, - QByteArray data, - QList<QNetworkReply::RawHeaderPair> headers -) { - auto requestor = qobject_cast<AuthRequest *>(QObject::sender()); +void MigrationEligibilityStep::onRequestDone(QNetworkReply::NetworkError error, + QByteArray data, + QList<QNetworkReply::RawHeaderPair> headers) +{ + auto requestor = qobject_cast<AuthRequest*>(QObject::sender()); requestor->deleteLater(); if (error == QNetworkReply::NoError) { diff --git a/launcher/minecraft/auth/steps/MigrationEligibilityStep.h b/launcher/minecraft/auth/steps/MigrationEligibilityStep.h index b1bf9cbf..8638975d 100644 --- a/launcher/minecraft/auth/steps/MigrationEligibilityStep.h +++ b/launcher/minecraft/auth/steps/MigrationEligibilityStep.h @@ -4,12 +4,11 @@ #include "QObjectPtr.h" #include "minecraft/auth/AuthStep.h" - class MigrationEligibilityStep : public AuthStep { Q_OBJECT -public: - explicit MigrationEligibilityStep(AccountData *data); + public: + explicit MigrationEligibilityStep(AccountData* data); virtual ~MigrationEligibilityStep() noexcept; void perform() override; @@ -17,6 +16,6 @@ public: QString describe() override; -private slots: + private slots: void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>); }; diff --git a/launcher/minecraft/auth/steps/MinecraftProfileStep.cpp b/launcher/minecraft/auth/steps/MinecraftProfileStep.cpp index 6cfa7c1c..7cdce23f 100644 --- a/launcher/minecraft/auth/steps/MinecraftProfileStep.cpp +++ b/launcher/minecraft/auth/steps/MinecraftProfileStep.cpp @@ -7,52 +7,46 @@ #include "minecraft/auth/Parsers.h" #include "net/NetUtils.h" -MinecraftProfileStep::MinecraftProfileStep(AccountData* data) : AuthStep(data) { - -} +MinecraftProfileStep::MinecraftProfileStep(AccountData* data) : AuthStep(data) {} MinecraftProfileStep::~MinecraftProfileStep() noexcept = default; -QString MinecraftProfileStep::describe() { +QString MinecraftProfileStep::describe() +{ return tr("Fetching the Minecraft profile."); } - -void MinecraftProfileStep::perform() { +void MinecraftProfileStep::perform() +{ auto url = QUrl("https://api.minecraftservices.com/minecraft/profile"); QNetworkRequest request = QNetworkRequest(url); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); request.setRawHeader("Authorization", QString("Bearer %1").arg(m_data->yggdrasilToken.token).toUtf8()); - AuthRequest *requestor = new AuthRequest(this); + AuthRequest* requestor = new AuthRequest(this); connect(requestor, &AuthRequest::finished, this, &MinecraftProfileStep::onRequestDone); requestor->get(request); } -void MinecraftProfileStep::rehydrate() { +void MinecraftProfileStep::rehydrate() +{ // NOOP, for now. We only save bools and there's nothing to check. } -void MinecraftProfileStep::onRequestDone( - QNetworkReply::NetworkError error, - QByteArray data, - QList<QNetworkReply::RawHeaderPair> headers -) { - auto requestor = qobject_cast<AuthRequest *>(QObject::sender()); +void MinecraftProfileStep::onRequestDone(QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers) +{ + auto requestor = qobject_cast<AuthRequest*>(QObject::sender()); requestor->deleteLater(); qCDebug(authCredentials()) << data; if (error == QNetworkReply::ContentNotFoundError) { // NOTE: Succeed even if we do not have a profile. This is a valid account state. - if(m_data->type == AccountType::Mojang) { + if (m_data->type == AccountType::Mojang) { m_data->minecraftEntitlement.canPlayMinecraft = false; m_data->minecraftEntitlement.ownsMinecraft = false; } m_data->minecraftProfile = MinecraftProfile(); - emit finished( - AccountTaskState::STATE_SUCCEEDED, - tr("Account has no Minecraft profile.") - ); + emit finished(AccountTaskState::STATE_SUCCEEDED, tr("Account has no Minecraft profile.")); return; } if (error != QNetworkReply::NoError) { @@ -65,35 +59,24 @@ void MinecraftProfileStep::onRequestDone( qWarning() << QString::fromUtf8(data); if (Net::isApplicationError(error)) { - emit finished( - AccountTaskState::STATE_FAILED_SOFT, - tr("Minecraft Java profile acquisition failed: %1").arg(requestor->errorString_) - ); - } - else { - emit finished( - AccountTaskState::STATE_OFFLINE, - tr("Minecraft Java profile acquisition failed: %1").arg(requestor->errorString_) - ); + emit finished(AccountTaskState::STATE_FAILED_SOFT, + tr("Minecraft Java profile acquisition failed: %1").arg(requestor->errorString_)); + } else { + emit finished(AccountTaskState::STATE_OFFLINE, + tr("Minecraft Java profile acquisition failed: %1").arg(requestor->errorString_)); } return; } - if(!Parsers::parseMinecraftProfile(data, m_data->minecraftProfile)) { + if (!Parsers::parseMinecraftProfile(data, m_data->minecraftProfile)) { m_data->minecraftProfile = MinecraftProfile(); - emit finished( - AccountTaskState::STATE_FAILED_SOFT, - tr("Minecraft Java profile response could not be parsed") - ); + emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("Minecraft Java profile response could not be parsed")); return; } - if(m_data->type == AccountType::Mojang) { + if (m_data->type == AccountType::Mojang) { auto validProfile = m_data->minecraftProfile.validity == Katabasis::Validity::Certain; m_data->minecraftEntitlement.canPlayMinecraft = validProfile; m_data->minecraftEntitlement.ownsMinecraft = validProfile; } - emit finished( - AccountTaskState::STATE_WORKING, - tr("Minecraft Java profile acquisition succeeded.") - ); + emit finished(AccountTaskState::STATE_WORKING, tr("Minecraft Java profile acquisition succeeded.")); } diff --git a/launcher/minecraft/auth/steps/MinecraftProfileStep.h b/launcher/minecraft/auth/steps/MinecraftProfileStep.h index 8ef3395c..cb30dab2 100644 --- a/launcher/minecraft/auth/steps/MinecraftProfileStep.h +++ b/launcher/minecraft/auth/steps/MinecraftProfileStep.h @@ -4,12 +4,11 @@ #include "QObjectPtr.h" #include "minecraft/auth/AuthStep.h" - class MinecraftProfileStep : public AuthStep { Q_OBJECT -public: - explicit MinecraftProfileStep(AccountData *data); + public: + explicit MinecraftProfileStep(AccountData* data); virtual ~MinecraftProfileStep() noexcept; void perform() override; @@ -17,6 +16,6 @@ public: QString describe() override; -private slots: + private slots: void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>); }; diff --git a/launcher/minecraft/auth/steps/MinecraftProfileStepMojang.cpp b/launcher/minecraft/auth/steps/MinecraftProfileStepMojang.cpp index 8c378588..d035e39a 100644 --- a/launcher/minecraft/auth/steps/MinecraftProfileStepMojang.cpp +++ b/launcher/minecraft/auth/steps/MinecraftProfileStepMojang.cpp @@ -7,18 +7,17 @@ #include "minecraft/auth/Parsers.h" #include "net/NetUtils.h" -MinecraftProfileStepMojang::MinecraftProfileStepMojang(AccountData* data) : AuthStep(data) { - -} +MinecraftProfileStepMojang::MinecraftProfileStepMojang(AccountData* data) : AuthStep(data) {} MinecraftProfileStepMojang::~MinecraftProfileStepMojang() noexcept = default; -QString MinecraftProfileStepMojang::describe() { +QString MinecraftProfileStepMojang::describe() +{ return tr("Fetching the Minecraft profile."); } - -void MinecraftProfileStepMojang::perform() { +void MinecraftProfileStepMojang::perform() +{ if (m_data->minecraftProfile.id.isEmpty()) { emit finished(AccountTaskState::STATE_FAILED_HARD, tr("A UUID is required to get the profile.")); return; @@ -27,35 +26,32 @@ void MinecraftProfileStepMojang::perform() { // use session server instead of profile due to profile endpoint being locked for locked Mojang accounts QUrl url = QUrl("https://sessionserver.mojang.com/session/minecraft/profile/" + m_data->minecraftProfile.id); QNetworkRequest req = QNetworkRequest(url); - AuthRequest *request = new AuthRequest(this); + AuthRequest* request = new AuthRequest(this); connect(request, &AuthRequest::finished, this, &MinecraftProfileStepMojang::onRequestDone); request->get(req); } -void MinecraftProfileStepMojang::rehydrate() { +void MinecraftProfileStepMojang::rehydrate() +{ // NOOP, for now. We only save bools and there's nothing to check. } -void MinecraftProfileStepMojang::onRequestDone( - QNetworkReply::NetworkError error, - QByteArray data, - QList<QNetworkReply::RawHeaderPair> headers -) { - auto requestor = qobject_cast<AuthRequest *>(QObject::sender()); +void MinecraftProfileStepMojang::onRequestDone(QNetworkReply::NetworkError error, + QByteArray data, + QList<QNetworkReply::RawHeaderPair> headers) +{ + auto requestor = qobject_cast<AuthRequest*>(QObject::sender()); requestor->deleteLater(); qCDebug(authCredentials()) << data; if (error == QNetworkReply::ContentNotFoundError) { // NOTE: Succeed even if we do not have a profile. This is a valid account state. - if(m_data->type == AccountType::Mojang) { + if (m_data->type == AccountType::Mojang) { m_data->minecraftEntitlement.canPlayMinecraft = false; m_data->minecraftEntitlement.ownsMinecraft = false; } m_data->minecraftProfile = MinecraftProfile(); - emit finished( - AccountTaskState::STATE_SUCCEEDED, - tr("Account has no Minecraft profile.") - ); + emit finished(AccountTaskState::STATE_SUCCEEDED, tr("Account has no Minecraft profile.")); return; } if (error != QNetworkReply::NoError) { @@ -68,35 +64,24 @@ void MinecraftProfileStepMojang::onRequestDone( qWarning() << QString::fromUtf8(data); if (Net::isApplicationError(error)) { - emit finished( - AccountTaskState::STATE_FAILED_SOFT, - tr("Minecraft Java profile acquisition failed: %1").arg(requestor->errorString_) - ); - } - else { - emit finished( - AccountTaskState::STATE_OFFLINE, - tr("Minecraft Java profile acquisition failed: %1").arg(requestor->errorString_) - ); + emit finished(AccountTaskState::STATE_FAILED_SOFT, + tr("Minecraft Java profile acquisition failed: %1").arg(requestor->errorString_)); + } else { + emit finished(AccountTaskState::STATE_OFFLINE, + tr("Minecraft Java profile acquisition failed: %1").arg(requestor->errorString_)); } return; } - if(!Parsers::parseMinecraftProfileMojang(data, m_data->minecraftProfile)) { + if (!Parsers::parseMinecraftProfileMojang(data, m_data->minecraftProfile)) { m_data->minecraftProfile = MinecraftProfile(); - emit finished( - AccountTaskState::STATE_FAILED_SOFT, - tr("Minecraft Java profile response could not be parsed") - ); + emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("Minecraft Java profile response could not be parsed")); return; } - if(m_data->type == AccountType::Mojang) { + if (m_data->type == AccountType::Mojang) { auto validProfile = m_data->minecraftProfile.validity == Katabasis::Validity::Certain; m_data->minecraftEntitlement.canPlayMinecraft = validProfile; m_data->minecraftEntitlement.ownsMinecraft = validProfile; } - emit finished( - AccountTaskState::STATE_WORKING, - tr("Minecraft Java profile acquisition succeeded.") - ); + emit finished(AccountTaskState::STATE_WORKING, tr("Minecraft Java profile acquisition succeeded.")); } diff --git a/launcher/minecraft/auth/steps/MinecraftProfileStepMojang.h b/launcher/minecraft/auth/steps/MinecraftProfileStepMojang.h index e06b30ab..730ec3f6 100644 --- a/launcher/minecraft/auth/steps/MinecraftProfileStepMojang.h +++ b/launcher/minecraft/auth/steps/MinecraftProfileStepMojang.h @@ -4,12 +4,11 @@ #include "QObjectPtr.h" #include "minecraft/auth/AuthStep.h" - class MinecraftProfileStepMojang : public AuthStep { Q_OBJECT -public: - explicit MinecraftProfileStepMojang(AccountData *data); + public: + explicit MinecraftProfileStepMojang(AccountData* data); virtual ~MinecraftProfileStepMojang() noexcept; void perform() override; @@ -17,6 +16,6 @@ public: QString describe() override; -private slots: + private slots: void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>); }; diff --git a/launcher/minecraft/auth/steps/OfflineStep.cpp b/launcher/minecraft/auth/steps/OfflineStep.cpp index dc092bfd..bf111abe 100644 --- a/launcher/minecraft/auth/steps/OfflineStep.cpp +++ b/launcher/minecraft/auth/steps/OfflineStep.cpp @@ -5,14 +5,17 @@ OfflineStep::OfflineStep(AccountData* data) : AuthStep(data) {} OfflineStep::~OfflineStep() noexcept = default; -QString OfflineStep::describe() { +QString OfflineStep::describe() +{ return tr("Creating offline account."); } -void OfflineStep::rehydrate() { +void OfflineStep::rehydrate() +{ // NOOP } -void OfflineStep::perform() { +void OfflineStep::perform() +{ emit finished(AccountTaskState::STATE_WORKING, tr("Created offline account.")); } diff --git a/launcher/minecraft/auth/steps/OfflineStep.h b/launcher/minecraft/auth/steps/OfflineStep.h index 436597cd..3bf123d6 100644 --- a/launcher/minecraft/auth/steps/OfflineStep.h +++ b/launcher/minecraft/auth/steps/OfflineStep.h @@ -8,8 +8,8 @@ class OfflineStep : public AuthStep { Q_OBJECT -public: - explicit OfflineStep(AccountData *data); + public: + explicit OfflineStep(AccountData* data); virtual ~OfflineStep() noexcept; void perform() override; diff --git a/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp b/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp index b397b734..c33d7e62 100644 --- a/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp +++ b/launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp @@ -1,33 +1,32 @@ #include "XboxAuthorizationStep.h" -#include <QNetworkRequest> -#include <QJsonParseError> #include <QJsonDocument> +#include <QJsonParseError> +#include <QNetworkRequest> #include "Logging.h" #include "minecraft/auth/AuthRequest.h" #include "minecraft/auth/Parsers.h" #include "net/NetUtils.h" -XboxAuthorizationStep::XboxAuthorizationStep(AccountData* data, Katabasis::Token *token, QString relyingParty, QString authorizationKind): - AuthStep(data), - m_token(token), - m_relyingParty(relyingParty), - m_authorizationKind(authorizationKind) -{ -} +XboxAuthorizationStep::XboxAuthorizationStep(AccountData* data, Katabasis::Token* token, QString relyingParty, QString authorizationKind) + : AuthStep(data), m_token(token), m_relyingParty(relyingParty), m_authorizationKind(authorizationKind) +{} XboxAuthorizationStep::~XboxAuthorizationStep() noexcept = default; -QString XboxAuthorizationStep::describe() { +QString XboxAuthorizationStep::describe() +{ return tr("Getting authorization to access %1 services.").arg(m_authorizationKind); } -void XboxAuthorizationStep::rehydrate() { +void XboxAuthorizationStep::rehydrate() +{ // FIXME: check if the tokens are good? } -void XboxAuthorizationStep::perform() { +void XboxAuthorizationStep::perform() +{ QString xbox_auth_template = R"XXX( { "Properties": { @@ -41,129 +40,98 @@ void XboxAuthorizationStep::perform() { } )XXX"; auto xbox_auth_data = xbox_auth_template.arg(m_data->userToken.token, m_relyingParty); -// http://xboxlive.com + // http://xboxlive.com QNetworkRequest request = QNetworkRequest(QUrl("https://xsts.auth.xboxlive.com/xsts/authorize")); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); request.setRawHeader("Accept", "application/json"); - AuthRequest *requestor = new AuthRequest(this); + AuthRequest* requestor = new AuthRequest(this); connect(requestor, &AuthRequest::finished, this, &XboxAuthorizationStep::onRequestDone); requestor->post(request, xbox_auth_data.toUtf8()); qDebug() << "Getting authorization token for " << m_relyingParty; } -void XboxAuthorizationStep::onRequestDone( - QNetworkReply::NetworkError error, - QByteArray data, - QList<QNetworkReply::RawHeaderPair> headers -) { - auto requestor = qobject_cast<AuthRequest *>(QObject::sender()); +void XboxAuthorizationStep::onRequestDone(QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers) +{ + auto requestor = qobject_cast<AuthRequest*>(QObject::sender()); requestor->deleteLater(); qCDebug(authCredentials()) << data; if (error != QNetworkReply::NoError) { qWarning() << "Reply error:" << error; if (Net::isApplicationError(error)) { - if(!processSTSError(error, data, headers)) { - emit finished( - AccountTaskState::STATE_FAILED_SOFT, - tr("Failed to get authorization for %1 services. Error %2.").arg(m_authorizationKind, error) - ); - } - else { - emit finished( - AccountTaskState::STATE_FAILED_SOFT, - tr("Unknown STS error for %1 services: %2").arg(m_authorizationKind, requestor->errorString_) - ); + if (!processSTSError(error, data, headers)) { + emit finished(AccountTaskState::STATE_FAILED_SOFT, + tr("Failed to get authorization for %1 services. Error %2.").arg(m_authorizationKind, error)); + } else { + emit finished(AccountTaskState::STATE_FAILED_SOFT, + tr("Unknown STS error for %1 services: %2").arg(m_authorizationKind, requestor->errorString_)); } - } - else { - emit finished( - AccountTaskState::STATE_OFFLINE, - tr("Failed to get authorization for %1 services: %2").arg(m_authorizationKind, requestor->errorString_) - ); + } else { + emit finished(AccountTaskState::STATE_OFFLINE, + tr("Failed to get authorization for %1 services: %2").arg(m_authorizationKind, requestor->errorString_)); } return; } Katabasis::Token temp; - if(!Parsers::parseXTokenResponse(data, temp, m_authorizationKind)) { - emit finished( - AccountTaskState::STATE_FAILED_SOFT, - tr("Could not parse authorization response for access to %1 services.").arg(m_authorizationKind) - ); + if (!Parsers::parseXTokenResponse(data, temp, m_authorizationKind)) { + emit finished(AccountTaskState::STATE_FAILED_SOFT, + tr("Could not parse authorization response for access to %1 services.").arg(m_authorizationKind)); return; } - if(temp.extra["uhs"] != m_data->userToken.extra["uhs"]) { - emit finished( - AccountTaskState::STATE_FAILED_SOFT, - tr("Server has changed %1 authorization user hash in the reply. Something is wrong.").arg(m_authorizationKind) - ); + if (temp.extra["uhs"] != m_data->userToken.extra["uhs"]) { + emit finished(AccountTaskState::STATE_FAILED_SOFT, + tr("Server has changed %1 authorization user hash in the reply. Something is wrong.").arg(m_authorizationKind)); return; } - auto & token = *m_token; + auto& token = *m_token; token = temp; emit finished(AccountTaskState::STATE_WORKING, tr("Got authorization to access %1").arg(m_relyingParty)); } - -bool XboxAuthorizationStep::processSTSError( - QNetworkReply::NetworkError error, - QByteArray data, - QList<QNetworkReply::RawHeaderPair> headers -) { - if(error == QNetworkReply::AuthenticationRequiredError) { +bool XboxAuthorizationStep::processSTSError(QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers) +{ + if (error == QNetworkReply::AuthenticationRequiredError) { QJsonParseError jsonError; QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError); - if(jsonError.error) { + if (jsonError.error) { qWarning() << "Cannot parse error XSTS response as JSON: " << jsonError.errorString(); - emit finished( - AccountTaskState::STATE_FAILED_SOFT, - tr("Cannot parse %1 authorization error response as JSON: %2").arg(m_authorizationKind, jsonError.errorString()) - ); + emit finished(AccountTaskState::STATE_FAILED_SOFT, + tr("Cannot parse %1 authorization error response as JSON: %2").arg(m_authorizationKind, jsonError.errorString())); return true; } int64_t errorCode = -1; auto obj = doc.object(); - if(!Parsers::getNumber(obj.value("XErr"), errorCode)) { - emit finished( - AccountTaskState::STATE_FAILED_SOFT, - tr("XErr element is missing from %1 authorization error response.").arg(m_authorizationKind) - ); + if (!Parsers::getNumber(obj.value("XErr"), errorCode)) { + emit finished(AccountTaskState::STATE_FAILED_SOFT, + tr("XErr element is missing from %1 authorization error response.").arg(m_authorizationKind)); return true; } - switch(errorCode) { - case 2148916233:{ - emit finished( - AccountTaskState::STATE_FAILED_SOFT, - tr("This Microsoft account does not have an XBox Live profile. Buy the game on %1 first.") - .arg("<a href=\"https://www.minecraft.net/en-us/store/minecraft-java-edition\">minecraft.net</a>") - ); + switch (errorCode) { + case 2148916233: { + emit finished(AccountTaskState::STATE_FAILED_SOFT, + tr("This Microsoft account does not have an XBox Live profile. Buy the game on %1 first.") + .arg("<a href=\"https://www.minecraft.net/en-us/store/minecraft-java-edition\">minecraft.net</a>")); return true; } case 2148916235: { // NOTE: this is the Grulovia error - emit finished( - AccountTaskState::STATE_FAILED_SOFT, - tr("XBox Live is not available in your country. You've been blocked.") - ); + emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("XBox Live is not available in your country. You've been blocked.")); return true; } case 2148916238: { emit finished( AccountTaskState::STATE_FAILED_SOFT, tr("This Microsoft account is underaged and is not linked to a family.\n\nPlease set up your account according to %1.") - .arg("<a href=\"https://help.minecraft.net/hc/en-us/articles/4403181904525\">help.minecraft.net</a>") - ); + .arg("<a href=\"https://help.minecraft.net/hc/en-us/articles/4403181904525\">help.minecraft.net</a>")); return true; } default: { - emit finished( - AccountTaskState::STATE_FAILED_SOFT, - tr("XSTS authentication ended with unrecognized error(s):\n\n%1").arg(errorCode) - ); + emit finished(AccountTaskState::STATE_FAILED_SOFT, + tr("XSTS authentication ended with unrecognized error(s):\n\n%1").arg(errorCode)); return true; } } diff --git a/launcher/minecraft/auth/steps/XboxAuthorizationStep.h b/launcher/minecraft/auth/steps/XboxAuthorizationStep.h index 31e43bf0..dee24c95 100644 --- a/launcher/minecraft/auth/steps/XboxAuthorizationStep.h +++ b/launcher/minecraft/auth/steps/XboxAuthorizationStep.h @@ -4,12 +4,11 @@ #include "QObjectPtr.h" #include "minecraft/auth/AuthStep.h" - class XboxAuthorizationStep : public AuthStep { Q_OBJECT -public: - explicit XboxAuthorizationStep(AccountData *data, Katabasis::Token *token, QString relyingParty, QString authorizationKind); + public: + explicit XboxAuthorizationStep(AccountData* data, Katabasis::Token* token, QString relyingParty, QString authorizationKind); virtual ~XboxAuthorizationStep() noexcept; void perform() override; @@ -17,18 +16,14 @@ public: QString describe() override; -private: - bool processSTSError( - QNetworkReply::NetworkError error, - QByteArray data, - QList<QNetworkReply::RawHeaderPair> headers - ); + private: + bool processSTSError(QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers); -private slots: + private slots: void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>); -private: - Katabasis::Token *m_token; + private: + Katabasis::Token* m_token; QString m_relyingParty; QString m_authorizationKind; }; diff --git a/launcher/minecraft/auth/steps/XboxProfileStep.cpp b/launcher/minecraft/auth/steps/XboxProfileStep.cpp index 644c419b..fd2b32cc 100644 --- a/launcher/minecraft/auth/steps/XboxProfileStep.cpp +++ b/launcher/minecraft/auth/steps/XboxProfileStep.cpp @@ -8,66 +8,56 @@ #include "minecraft/auth/Parsers.h" #include "net/NetUtils.h" -XboxProfileStep::XboxProfileStep(AccountData* data) : AuthStep(data) { - -} +XboxProfileStep::XboxProfileStep(AccountData* data) : AuthStep(data) {} XboxProfileStep::~XboxProfileStep() noexcept = default; -QString XboxProfileStep::describe() { +QString XboxProfileStep::describe() +{ return tr("Fetching Xbox profile."); } -void XboxProfileStep::rehydrate() { +void XboxProfileStep::rehydrate() +{ // NOOP, for now. We only save bools and there's nothing to check. } -void XboxProfileStep::perform() { +void XboxProfileStep::perform() +{ auto url = QUrl("https://profile.xboxlive.com/users/me/profile/settings"); QUrlQuery q; - q.addQueryItem( - "settings", - "GameDisplayName,AppDisplayName,AppDisplayPicRaw,GameDisplayPicRaw," - "PublicGamerpic,ShowUserAsAvatar,Gamerscore,Gamertag,ModernGamertag,ModernGamertagSuffix," - "UniqueModernGamertag,AccountTier,TenureLevel,XboxOneRep," - "PreferredColor,Location,Bio,Watermarks," - "RealName,RealNameOverride,IsQuarantined" - ); + q.addQueryItem("settings", + "GameDisplayName,AppDisplayName,AppDisplayPicRaw,GameDisplayPicRaw," + "PublicGamerpic,ShowUserAsAvatar,Gamerscore,Gamertag,ModernGamertag,ModernGamertagSuffix," + "UniqueModernGamertag,AccountTier,TenureLevel,XboxOneRep," + "PreferredColor,Location,Bio,Watermarks," + "RealName,RealNameOverride,IsQuarantined"); url.setQuery(q); QNetworkRequest request = QNetworkRequest(url); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); request.setRawHeader("Accept", "application/json"); request.setRawHeader("x-xbl-contract-version", "3"); - request.setRawHeader("Authorization", QString("XBL3.0 x=%1;%2").arg(m_data->userToken.extra["uhs"].toString(), m_data->xboxApiToken.token).toUtf8()); - AuthRequest *requestor = new AuthRequest(this); + request.setRawHeader("Authorization", + QString("XBL3.0 x=%1;%2").arg(m_data->userToken.extra["uhs"].toString(), m_data->xboxApiToken.token).toUtf8()); + AuthRequest* requestor = new AuthRequest(this); connect(requestor, &AuthRequest::finished, this, &XboxProfileStep::onRequestDone); requestor->get(request); qDebug() << "Getting Xbox profile..."; } -void XboxProfileStep::onRequestDone( - QNetworkReply::NetworkError error, - QByteArray data, - QList<QNetworkReply::RawHeaderPair> headers -) { - auto requestor = qobject_cast<AuthRequest *>(QObject::sender()); +void XboxProfileStep::onRequestDone(QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers) +{ + auto requestor = qobject_cast<AuthRequest*>(QObject::sender()); requestor->deleteLater(); if (error != QNetworkReply::NoError) { qWarning() << "Reply error:" << error; qCDebug(authCredentials()) << data; if (Net::isApplicationError(error)) { - emit finished( - AccountTaskState::STATE_FAILED_SOFT, - tr("Failed to retrieve the Xbox profile: %1").arg(requestor->errorString_) - ); - } - else { - emit finished( - AccountTaskState::STATE_OFFLINE, - tr("Failed to retrieve the Xbox profile: %1").arg(requestor->errorString_) - ); + emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("Failed to retrieve the Xbox profile: %1").arg(requestor->errorString_)); + } else { + emit finished(AccountTaskState::STATE_OFFLINE, tr("Failed to retrieve the Xbox profile: %1").arg(requestor->errorString_)); } return; } diff --git a/launcher/minecraft/auth/steps/XboxProfileStep.h b/launcher/minecraft/auth/steps/XboxProfileStep.h index 7a0c5873..b8494b6e 100644 --- a/launcher/minecraft/auth/steps/XboxProfileStep.h +++ b/launcher/minecraft/auth/steps/XboxProfileStep.h @@ -4,12 +4,11 @@ #include "QObjectPtr.h" #include "minecraft/auth/AuthStep.h" - class XboxProfileStep : public AuthStep { Q_OBJECT -public: - explicit XboxProfileStep(AccountData *data); + public: + explicit XboxProfileStep(AccountData* data); virtual ~XboxProfileStep() noexcept; void perform() override; @@ -17,6 +16,6 @@ public: QString describe() override; -private slots: + private slots: void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>); }; diff --git a/launcher/minecraft/auth/steps/XboxUserStep.cpp b/launcher/minecraft/auth/steps/XboxUserStep.cpp index 842eb60f..61c33a18 100644 --- a/launcher/minecraft/auth/steps/XboxUserStep.cpp +++ b/launcher/minecraft/auth/steps/XboxUserStep.cpp @@ -6,22 +6,22 @@ #include "minecraft/auth/Parsers.h" #include "net/NetUtils.h" -XboxUserStep::XboxUserStep(AccountData* data) : AuthStep(data) { - -} +XboxUserStep::XboxUserStep(AccountData* data) : AuthStep(data) {} XboxUserStep::~XboxUserStep() noexcept = default; -QString XboxUserStep::describe() { +QString XboxUserStep::describe() +{ return tr("Logging in as an Xbox user."); } - -void XboxUserStep::rehydrate() { +void XboxUserStep::rehydrate() +{ // NOOP, for now. We only save bools and there's nothing to check. } -void XboxUserStep::perform() { +void XboxUserStep::perform() +{ QString xbox_auth_template = R"XXX( { "Properties": { @@ -40,40 +40,31 @@ void XboxUserStep::perform() { request.setRawHeader("Accept", "application/json"); // set contract-verison header (prevent err 400 bad-request?) // https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/reference/live/rest/additional/httpstandardheaders - request.setRawHeader("x-xbl-contract-version", "1"); + request.setRawHeader("x-xbl-contract-version", "1"); - auto *requestor = new AuthRequest(this); + auto* requestor = new AuthRequest(this); connect(requestor, &AuthRequest::finished, this, &XboxUserStep::onRequestDone); requestor->post(request, xbox_auth_data.toUtf8()); qDebug() << "First layer of XBox auth ... commencing."; } -void XboxUserStep::onRequestDone( - QNetworkReply::NetworkError error, - QByteArray data, - QList<QNetworkReply::RawHeaderPair> headers -) { - auto requestor = qobject_cast<AuthRequest *>(QObject::sender()); +void XboxUserStep::onRequestDone(QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers) +{ + auto requestor = qobject_cast<AuthRequest*>(QObject::sender()); requestor->deleteLater(); if (error != QNetworkReply::NoError) { qWarning() << "Reply error:" << error; if (Net::isApplicationError(error)) { - emit finished(AccountTaskState::STATE_FAILED_SOFT, - tr("XBox user authentication failed: %1").arg(requestor->errorString_) - ); - } - else { - emit finished( - AccountTaskState::STATE_OFFLINE, - tr("XBox user authentication failed: %1").arg(requestor->errorString_) - ); + emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("XBox user authentication failed: %1").arg(requestor->errorString_)); + } else { + emit finished(AccountTaskState::STATE_OFFLINE, tr("XBox user authentication failed: %1").arg(requestor->errorString_)); } return; } Katabasis::Token temp; - if(!Parsers::parseXTokenResponse(data, temp, "UToken")) { + if (!Parsers::parseXTokenResponse(data, temp, "UToken")) { qWarning() << "Could not parse user authentication response..."; emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("XBox user authentication response could not be understood.")); return; diff --git a/launcher/minecraft/auth/steps/XboxUserStep.h b/launcher/minecraft/auth/steps/XboxUserStep.h index 83e9405f..e92727a4 100644 --- a/launcher/minecraft/auth/steps/XboxUserStep.h +++ b/launcher/minecraft/auth/steps/XboxUserStep.h @@ -4,12 +4,11 @@ #include "QObjectPtr.h" #include "minecraft/auth/AuthStep.h" - class XboxUserStep : public AuthStep { Q_OBJECT -public: - explicit XboxUserStep(AccountData *data); + public: + explicit XboxUserStep(AccountData* data); virtual ~XboxUserStep() noexcept; void perform() override; @@ -17,6 +16,6 @@ public: QString describe() override; -private slots: + private slots: void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>); }; diff --git a/launcher/minecraft/auth/steps/YggdrasilStep.cpp b/launcher/minecraft/auth/steps/YggdrasilStep.cpp index e1d33172..fdcaa0d6 100644 --- a/launcher/minecraft/auth/steps/YggdrasilStep.cpp +++ b/launcher/minecraft/auth/steps/YggdrasilStep.cpp @@ -4,7 +4,8 @@ #include "minecraft/auth/Parsers.h" #include "minecraft/auth/Yggdrasil.h" -YggdrasilStep::YggdrasilStep(AccountData* data, QString password) : AuthStep(data), m_password(password) { +YggdrasilStep::YggdrasilStep(AccountData* data, QString password) : AuthStep(data), m_password(password) +{ m_yggdrasil = new Yggdrasil(m_data, this); connect(m_yggdrasil, &Task::failed, this, &YggdrasilStep::onAuthFailed); @@ -14,28 +15,32 @@ YggdrasilStep::YggdrasilStep(AccountData* data, QString password) : AuthStep(dat YggdrasilStep::~YggdrasilStep() noexcept = default; -QString YggdrasilStep::describe() { +QString YggdrasilStep::describe() +{ return tr("Logging in with Mojang account."); } -void YggdrasilStep::rehydrate() { +void YggdrasilStep::rehydrate() +{ // NOOP, for now. } -void YggdrasilStep::perform() { - if(m_password.size()) { +void YggdrasilStep::perform() +{ + if (m_password.size()) { m_yggdrasil->login(m_password); - } - else { + } else { m_yggdrasil->refresh(); } } -void YggdrasilStep::onAuthSucceeded() { +void YggdrasilStep::onAuthSucceeded() +{ emit finished(AccountTaskState::STATE_WORKING, tr("Logged in with Mojang")); } -void YggdrasilStep::onAuthFailed() { +void YggdrasilStep::onAuthFailed() +{ // TODO: hook these in again, expand to MSA // m_error = m_yggdrasil->m_error; // m_aborted = m_yggdrasil->m_aborted; @@ -44,7 +49,7 @@ void YggdrasilStep::onAuthFailed() { QString errorMessage = tr("Mojang user authentication failed."); // NOTE: soft error in the first step means 'offline' - if(state == AccountTaskState::STATE_FAILED_SOFT) { + if (state == AccountTaskState::STATE_FAILED_SOFT) { state = AccountTaskState::STATE_OFFLINE; errorMessage = tr("Mojang user authentication ended with a network error."); } diff --git a/launcher/minecraft/auth/steps/YggdrasilStep.h b/launcher/minecraft/auth/steps/YggdrasilStep.h index ebafb8e5..ef31f34d 100644 --- a/launcher/minecraft/auth/steps/YggdrasilStep.h +++ b/launcher/minecraft/auth/steps/YggdrasilStep.h @@ -9,8 +9,8 @@ class Yggdrasil; class YggdrasilStep : public AuthStep { Q_OBJECT -public: - explicit YggdrasilStep(AccountData *data, QString password); + public: + explicit YggdrasilStep(AccountData* data, QString password); virtual ~YggdrasilStep() noexcept; void perform() override; @@ -18,11 +18,11 @@ public: QString describe() override; -private slots: + private slots: void onAuthSucceeded(); void onAuthFailed(); -private: - Yggdrasil *m_yggdrasil = nullptr; + private: + Yggdrasil* m_yggdrasil = nullptr; QString m_password; }; diff --git a/launcher/minecraft/gameoptions/GameOptions.cpp b/launcher/minecraft/gameoptions/GameOptions.cpp index e547b32a..443525ae 100644 --- a/launcher/minecraft/gameoptions/GameOptions.cpp +++ b/launcher/minecraft/gameoptions/GameOptions.cpp @@ -1,59 +1,51 @@ #include "GameOptions.h" -#include "FileSystem.h" #include <QDebug> #include <QSaveFile> +#include "FileSystem.h" namespace { -bool load(const QString& path, std::vector<GameOptionItem> &contents, int & version) +bool load(const QString& path, std::vector<GameOptionItem>& contents, int& version) { contents.clear(); QFile file(path); - if (!file.open(QFile::ReadOnly)) - { + if (!file.open(QFile::ReadOnly)) { qWarning() << "Failed to read options file."; return false; } version = 0; - while(!file.atEnd()) - { + while (!file.atEnd()) { auto line = file.readLine(); - if(line.endsWith('\n')) - { + if (line.endsWith('\n')) { line.chop(1); } auto separatorIndex = line.indexOf(':'); - if(separatorIndex == -1) - { + if (separatorIndex == -1) { continue; } auto key = QString::fromUtf8(line.data(), separatorIndex); auto value = QString::fromUtf8(line.data() + separatorIndex + 1, line.size() - 1 - separatorIndex); qDebug() << "!!" << key << "!!"; - if(key == "version") - { + if (key == "version") { version = value.toInt(); continue; } - contents.emplace_back(GameOptionItem{key, value}); + contents.emplace_back(GameOptionItem{ key, value }); } qDebug() << "Loaded" << path << "with version:" << version; return true; } -bool save(const QString& path, std::vector<GameOptionItem> &mapping, int version) +bool save(const QString& path, std::vector<GameOptionItem>& mapping, int version) { QSaveFile out(path); - if(!out.open(QIODevice::WriteOnly)) - { + if (!out.open(QIODevice::WriteOnly)) { return false; } - if(version != 0) - { + if (version != 0) { QString versionLine = QString("version:%1\n").arg(version); out.write(versionLine.toUtf8()); } auto iter = mapping.begin(); - while (iter != mapping.end()) - { + while (iter != mapping.end()) { out.write(iter->key.toUtf8()); out.write(":"); out.write(iter->value.toUtf8()); @@ -62,22 +54,19 @@ bool save(const QString& path, std::vector<GameOptionItem> &mapping, int version } return out.commit(); } -} +} // namespace -GameOptions::GameOptions(const QString& path): - path(path) +GameOptions::GameOptions(const QString& path) : path(path) { reload(); } QVariant GameOptions::headerData(int section, Qt::Orientation orientation, int role) const { - if(role != Qt::DisplayRole) - { + if (role != Qt::DisplayRole) { return QAbstractListModel::headerData(section, orientation, role); } - switch(section) - { + switch (section) { case 0: return tr("Key"); case 1: @@ -98,19 +87,15 @@ QVariant GameOptions::data(const QModelIndex& index, int role) const if (row < 0 || row >= int(contents.size())) return QVariant(); - switch (role) - { - case Qt::DisplayRole: - if(column == 0) - { - return contents[row].key; - } - else - { - return contents[row].value; - } - default: - return QVariant(); + switch (role) { + case Qt::DisplayRole: + if (column == 0) { + return contents[row].key; + } else { + return contents[row].value; + } + default: + return QVariant(); } return QVariant(); } diff --git a/launcher/minecraft/gameoptions/GameOptions.h b/launcher/minecraft/gameoptions/GameOptions.h index c6d25492..ae031efb 100644 --- a/launcher/minecraft/gameoptions/GameOptions.h +++ b/launcher/minecraft/gameoptions/GameOptions.h @@ -1,32 +1,30 @@ #pragma once -#include <map> -#include <QString> #include <QAbstractListModel> +#include <QString> +#include <map> -struct GameOptionItem -{ +struct GameOptionItem { QString key; QString value; }; -class GameOptions : public QAbstractListModel -{ +class GameOptions : public QAbstractListModel { Q_OBJECT -public: + public: explicit GameOptions(const QString& path); virtual ~GameOptions() = default; - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - int columnCount(const QModelIndex & parent) const override; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + int columnCount(const QModelIndex& parent) const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; bool isLoaded() const; bool reload(); bool save(); -private: + private: std::vector<GameOptionItem> contents; bool loaded = false; QString path; diff --git a/launcher/minecraft/launch/ClaimAccount.cpp b/launcher/minecraft/launch/ClaimAccount.cpp index 1cd7c0da..a3de1516 100644 --- a/launcher/minecraft/launch/ClaimAccount.cpp +++ b/launcher/minecraft/launch/ClaimAccount.cpp @@ -4,10 +4,9 @@ #include "Application.h" #include "minecraft/auth/AccountList.h" -ClaimAccount::ClaimAccount(LaunchTask* parent, AuthSessionPtr session): LaunchStep(parent) +ClaimAccount::ClaimAccount(LaunchTask* parent, AuthSessionPtr session) : LaunchStep(parent) { - if(session->status == AuthSession::Status::PlayableOnline && !session->demo) - { + if (session->status == AuthSession::Status::PlayableOnline && !session->demo) { auto accounts = APPLICATION->accounts(); m_account = accounts->getAccountByProfileName(session->player_name); } @@ -15,8 +14,7 @@ ClaimAccount::ClaimAccount(LaunchTask* parent, AuthSessionPtr session): LaunchSt void ClaimAccount::executeTask() { - if(m_account) - { + if (m_account) { lock.reset(new UseLock(m_account)); emitSucceeded(); } diff --git a/launcher/minecraft/launch/ClaimAccount.h b/launcher/minecraft/launch/ClaimAccount.h index cb4de23f..3d47539a 100644 --- a/launcher/minecraft/launch/ClaimAccount.h +++ b/launcher/minecraft/launch/ClaimAccount.h @@ -18,20 +18,17 @@ #include <launch/LaunchStep.h> #include <minecraft/auth/MinecraftAccount.h> -class ClaimAccount: public LaunchStep -{ +class ClaimAccount : public LaunchStep { Q_OBJECT -public: - explicit ClaimAccount(LaunchTask *parent, AuthSessionPtr session); - virtual ~ClaimAccount() {}; + public: + explicit ClaimAccount(LaunchTask* parent, AuthSessionPtr session); + virtual ~ClaimAccount(){}; void executeTask() override; void finalize() override; - bool canAbort() const override - { - return false; - } -private: + bool canAbort() const override { return false; } + + private: std::unique_ptr<UseLock> lock; MinecraftAccountPtr m_account; }; diff --git a/launcher/minecraft/launch/CreateGameFolders.cpp b/launcher/minecraft/launch/CreateGameFolders.cpp index 4081e72e..36f5e640 100644 --- a/launcher/minecraft/launch/CreateGameFolders.cpp +++ b/launcher/minecraft/launch/CreateGameFolders.cpp @@ -1,27 +1,23 @@ #include "CreateGameFolders.h" -#include "minecraft/MinecraftInstance.h" -#include "launch/LaunchTask.h" #include "FileSystem.h" +#include "launch/LaunchTask.h" +#include "minecraft/MinecraftInstance.h" -CreateGameFolders::CreateGameFolders(LaunchTask* parent): LaunchStep(parent) -{ -} +CreateGameFolders::CreateGameFolders(LaunchTask* parent) : LaunchStep(parent) {} void CreateGameFolders::executeTask() { auto instance = m_parent->instance(); std::shared_ptr<MinecraftInstance> minecraftInstance = std::dynamic_pointer_cast<MinecraftInstance>(instance); - if(!FS::ensureFolderPathExists(minecraftInstance->gameRoot())) - { + if (!FS::ensureFolderPathExists(minecraftInstance->gameRoot())) { emit logLine("Couldn't create the main game folder", MessageLevel::Error); emitFailed(tr("Couldn't create the main game folder")); return; } // HACK: this is a workaround for MCL-3732 - 'server-resource-packs' folder is created. - if(!FS::ensureFolderPathExists(FS::PathCombine(minecraftInstance->gameRoot(), "server-resource-packs"))) - { + if (!FS::ensureFolderPathExists(FS::PathCombine(minecraftInstance->gameRoot(), "server-resource-packs"))) { emit logLine("Couldn't create the 'server-resource-packs' folder", MessageLevel::Error); } emitSucceeded(); diff --git a/launcher/minecraft/launch/CreateGameFolders.h b/launcher/minecraft/launch/CreateGameFolders.h index 9c7d3c94..44524ded 100644 --- a/launcher/minecraft/launch/CreateGameFolders.h +++ b/launcher/minecraft/launch/CreateGameFolders.h @@ -15,23 +15,17 @@ #pragma once -#include <launch/LaunchStep.h> #include <LoggedProcess.h> +#include <launch/LaunchStep.h> #include <minecraft/auth/AuthSession.h> // Create the main .minecraft for the instance and any other necessary folders -class CreateGameFolders: public LaunchStep -{ +class CreateGameFolders : public LaunchStep { Q_OBJECT -public: - explicit CreateGameFolders(LaunchTask *parent); - virtual ~CreateGameFolders() {}; + public: + explicit CreateGameFolders(LaunchTask* parent); + virtual ~CreateGameFolders(){}; virtual void executeTask(); - virtual bool canAbort() const - { - return false; - } + virtual bool canAbort() const { return false; } }; - - diff --git a/launcher/minecraft/launch/ExtractNatives.cpp b/launcher/minecraft/launch/ExtractNatives.cpp index 7d5f4179..cebeaedd 100644 --- a/launcher/minecraft/launch/ExtractNatives.cpp +++ b/launcher/minecraft/launch/ExtractNatives.cpp @@ -14,26 +14,25 @@ */ #include "ExtractNatives.h" -#include <minecraft/MinecraftInstance.h> #include <launch/LaunchTask.h> +#include <minecraft/MinecraftInstance.h> #include <quazip/quazip.h> #include <quazip/quazipdir.h> -#include "MMCZip.h" -#include "FileSystem.h" #include <QDir> +#include "FileSystem.h" +#include "MMCZip.h" #ifdef major - #undef major +#undef major #endif #ifdef minor - #undef minor +#undef minor #endif -static QString replaceSuffix (QString target, const QString &suffix, const QString &replacement) +static QString replaceSuffix(QString target, const QString& suffix, const QString& replacement) { - if (!target.endsWith(suffix)) - { + if (!target.endsWith(suffix)) { return target; } target.resize(target.length() - suffix.length()); @@ -43,17 +42,14 @@ static QString replaceSuffix (QString target, const QString &suffix, const QStri static bool unzipNatives(QString source, QString targetFolder, bool applyJnilibHack, bool nativeOpenAL, bool nativeGLFW) { QuaZip zip(source); - if(!zip.open(QuaZip::mdUnzip)) - { + if (!zip.open(QuaZip::mdUnzip)) { return false; } QDir directory(targetFolder); - if (!zip.goToFirstFile()) - { + if (!zip.goToFirstFile()) { return false; } - do - { + do { QString name = zip.getCurrentFileName(); auto lowercase = name.toLower(); if (nativeGLFW && name.contains("glfw")) { @@ -62,19 +58,16 @@ static bool unzipNatives(QString source, QString targetFolder, bool applyJnilibH if (nativeOpenAL && name.contains("openal")) { continue; } - if(applyJnilibHack) - { + if (applyJnilibHack) { name = replaceSuffix(name, ".jnilib", ".dylib"); } QString absFilePath = directory.absoluteFilePath(name); - if (!JlCompress::extractFile(&zip, "", absFilePath)) - { + if (!JlCompress::extractFile(&zip, "", absFilePath)) { return false; } } while (zip.goToNextFile()); zip.close(); - if(zip.getZipError()!=0) - { + if (zip.getZipError() != 0) { return false; } return true; @@ -85,8 +78,7 @@ void ExtractNatives::executeTask() auto instance = m_parent->instance(); std::shared_ptr<MinecraftInstance> minecraftInstance = std::dynamic_pointer_cast<MinecraftInstance>(instance); auto toExtract = minecraftInstance->getNativeJars(); - if(toExtract.isEmpty()) - { + if (toExtract.isEmpty()) { emitSucceeded(); return; } @@ -94,14 +86,12 @@ void ExtractNatives::executeTask() bool nativeOpenAL = settings->get("UseNativeOpenAL").toBool(); bool nativeGLFW = settings->get("UseNativeGLFW").toBool(); - auto outputPath = minecraftInstance->getNativePath(); + auto outputPath = minecraftInstance->getNativePath(); auto javaVersion = minecraftInstance->getJavaVersion(); bool jniHackEnabled = javaVersion.major() >= 8; - for(const auto &source: toExtract) - { - if(!unzipNatives(source, outputPath, jniHackEnabled, nativeOpenAL, nativeGLFW)) - { - const char *reason = QT_TR_NOOP("Couldn't extract native jar '%1' to destination '%2'"); + for (const auto& source : toExtract) { + if (!unzipNatives(source, outputPath, jniHackEnabled, nativeOpenAL, nativeGLFW)) { + const char* reason = QT_TR_NOOP("Couldn't extract native jar '%1' to destination '%2'"); emit logLine(QString(reason).arg(source, outputPath), MessageLevel::Fatal); emitFailed(tr(reason).arg(source, outputPath)); } diff --git a/launcher/minecraft/launch/ExtractNatives.h b/launcher/minecraft/launch/ExtractNatives.h index 094fcd6b..2ab8816b 100644 --- a/launcher/minecraft/launch/ExtractNatives.h +++ b/launcher/minecraft/launch/ExtractNatives.h @@ -20,19 +20,13 @@ #include "minecraft/auth/AuthSession.h" // FIXME: temporary wrapper for existing task. -class ExtractNatives: public LaunchStep -{ +class ExtractNatives : public LaunchStep { Q_OBJECT -public: - explicit ExtractNatives(LaunchTask *parent) : LaunchStep(parent){}; + public: + explicit ExtractNatives(LaunchTask* parent) : LaunchStep(parent){}; virtual ~ExtractNatives(){}; void executeTask() override; - bool canAbort() const override - { - return false; - } + bool canAbort() const override { return false; } void finalize() override; }; - - diff --git a/launcher/minecraft/launch/LauncherPartLaunch.cpp b/launcher/minecraft/launch/LauncherPartLaunch.cpp index 8ecf715d..e5f919d7 100644 --- a/launcher/minecraft/launch/LauncherPartLaunch.cpp +++ b/launcher/minecraft/launch/LauncherPartLaunch.cpp @@ -35,29 +35,27 @@ #include "LauncherPartLaunch.h" -#include <QStandardPaths> #include <QRegularExpression> +#include <QStandardPaths> +#include "Application.h" +#include "Commandline.h" +#include "FileSystem.h" #include "launch/LaunchTask.h" #include "minecraft/MinecraftInstance.h" -#include "FileSystem.h" -#include "Commandline.h" -#include "Application.h" #ifdef Q_OS_LINUX #include "gamemode_client.h" #endif -LauncherPartLaunch::LauncherPartLaunch(LaunchTask *parent) : LaunchStep(parent) +LauncherPartLaunch::LauncherPartLaunch(LaunchTask* parent) : LaunchStep(parent) { auto instance = parent->instance(); - if (instance->settings()->get("CloseAfterLaunch").toBool()) - { - std::shared_ptr<QMetaObject::Connection> connection{new QMetaObject::Connection}; + if (instance->settings()->get("CloseAfterLaunch").toBool()) { + std::shared_ptr<QMetaObject::Connection> connection{ new QMetaObject::Connection }; *connection = connect(&m_process, &LoggedProcess::log, this, [=](QStringList lines, MessageLevel::Enum level) { qDebug() << lines; - if (lines.filter(QRegularExpression(".*Setting user.+", QRegularExpression::CaseInsensitiveOption)).length() != 0) - { + if (lines.filter(QRegularExpression(".*Setting user.+", QRegularExpression::CaseInsensitiveOption)).length() != 0) { APPLICATION->closeAllWindows(); disconnect(*connection); } @@ -71,7 +69,7 @@ LauncherPartLaunch::LauncherPartLaunch(LaunchTask *parent) : LaunchStep(parent) #ifdef Q_OS_WIN // returns 8.3 file format from long path #include <windows.h> -QString shortPathName(const QString & file) +QString shortPathName(const QString& file) { auto input = file.toStdWString(); std::wstring output; @@ -81,15 +79,15 @@ QString shortPathName(const QString & file) // when it succeeds, it returns length excluding null character // See: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364989(v=vs.85).aspx output.resize(length); - GetShortPathNameW(input.c_str(),(LPWSTR)output.c_str(),length); - output.resize(length-1); + GetShortPathNameW(input.c_str(), (LPWSTR)output.c_str(), length); + output.resize(length - 1); QString ret = QString::fromStdWString(output); return ret; } #endif // if the string survives roundtrip through local 8bit encoding... -bool fitsInLocal8bit(const QString & string) +bool fitsInLocal8bit(const QString& string) { return string == QString::fromLocal8Bit(string.toLocal8Bit()); } @@ -97,9 +95,8 @@ bool fitsInLocal8bit(const QString & string) void LauncherPartLaunch::executeTask() { QString jarPath = APPLICATION->getJarPath("NewLaunch.jar"); - if (jarPath.isEmpty()) - { - const char *reason = QT_TR_NOOP("Launcher library could not be found. Please check your installation."); + if (jarPath.isEmpty()) { + const char* reason = QT_TR_NOOP("Launcher library could not be found. Please check your installation."); emit logLine(tr(reason), MessageLevel::Fatal); emitFailed(tr(reason)); return; @@ -125,12 +122,9 @@ void LauncherPartLaunch::executeTask() auto natPath = minecraftInstance->getNativePath(); #ifdef Q_OS_WIN - if (!fitsInLocal8bit(natPath)) - { + if (!fitsInLocal8bit(natPath)) { args << "-Djava.library.path=" + shortPathName(natPath); - } - else - { + } else { args << "-Djava.library.path=" + natPath; } #else @@ -140,14 +134,10 @@ void LauncherPartLaunch::executeTask() args << "-cp"; #ifdef Q_OS_WIN QStringList processed; - for(auto & item: classPath) - { - if (!fitsInLocal8bit(item)) - { + for (auto& item : classPath) { + if (!fitsInLocal8bit(item)) { processed << shortPathName(item); - } - else - { + } else { processed << item; } } @@ -160,14 +150,12 @@ void LauncherPartLaunch::executeTask() qDebug() << args.join(' '); QString wrapperCommandStr = instance->getWrapperCommand().trimmed(); - if(!wrapperCommandStr.isEmpty()) - { + if (!wrapperCommandStr.isEmpty()) { auto wrapperArgs = Commandline::splitArgs(wrapperCommandStr); auto wrapperCommand = wrapperArgs.takeFirst(); auto realWrapperCommand = QStandardPaths::findExecutable(wrapperCommand); - if (realWrapperCommand.isEmpty()) - { - const char *reason = QT_TR_NOOP("The wrapper command \"%1\" couldn't be found."); + if (realWrapperCommand.isEmpty()) { + const char* reason = QT_TR_NOOP("The wrapper command \"%1\" couldn't be found."); emit logLine(QString(reason).arg(wrapperCommand), MessageLevel::Fatal); emitFailed(tr(reason).arg(wrapperCommand)); return; @@ -175,18 +163,14 @@ void LauncherPartLaunch::executeTask() emit logLine("Wrapper command is:\n" + wrapperCommandStr + "\n\n", MessageLevel::Launcher); args.prepend(javaPath); m_process.start(wrapperCommand, wrapperArgs + args); - } - else - { + } else { m_process.start(javaPath, args); } #ifdef Q_OS_LINUX - if (instance->settings()->get("EnableFeralGamemode").toBool() && APPLICATION->capabilities() & Application::SupportsGameMode) - { + if (instance->settings()->get("EnableFeralGamemode").toBool() && APPLICATION->capabilities() & Application::SupportsGameMode) { auto pid = m_process.processId(); - if (pid) - { + if (pid) { gamemode_request_start_for(pid); } } @@ -195,25 +179,21 @@ void LauncherPartLaunch::executeTask() void LauncherPartLaunch::on_state(LoggedProcess::State state) { - switch(state) - { - case LoggedProcess::FailedToStart: - { + switch (state) { + case LoggedProcess::FailedToStart: { //: Error message displayed if instace can't start - const char *reason = QT_TR_NOOP("Could not launch Minecraft!"); + const char* reason = QT_TR_NOOP("Could not launch Minecraft!"); emit logLine(reason, MessageLevel::Fatal); emitFailed(tr(reason)); return; } case LoggedProcess::Aborted: - case LoggedProcess::Crashed: - { + case LoggedProcess::Crashed: { m_parent->setPid(-1); emitFailed(tr("Game crashed.")); return; } - case LoggedProcess::Finished: - { + case LoggedProcess::Finished: { auto instance = m_parent->instance(); if (instance->settings()->get("CloseAfterLaunch").toBool()) APPLICATION->showMainWindow(); @@ -221,14 +201,13 @@ void LauncherPartLaunch::on_state(LoggedProcess::State state) m_parent->setPid(-1); // if the exit code wasn't 0, report this as a crash auto exitCode = m_process.exitCode(); - if(exitCode != 0) - { + if (exitCode != 0) { emitFailed(tr("Game crashed.")); return; } - //FIXME: make this work again - // m_postlaunchprocess.processEnvironment().insert("INST_EXITCODE", QString(exitCode)); - // run post-exit + // FIXME: make this work again + // m_postlaunchprocess.processEnvironment().insert("INST_EXITCODE", QString(exitCode)); + // run post-exit emitSucceeded(); break; } @@ -247,15 +226,14 @@ void LauncherPartLaunch::on_state(LoggedProcess::State state) } } -void LauncherPartLaunch::setWorkingDirectory(const QString &wd) +void LauncherPartLaunch::setWorkingDirectory(const QString& wd) { m_process.setWorkingDirectory(wd); } void LauncherPartLaunch::proceed() { - if(mayProceed) - { + if (mayProceed) { QString launchString("launch\n"); m_process.write(launchString.toUtf8()); mayProceed = false; @@ -264,17 +242,13 @@ void LauncherPartLaunch::proceed() bool LauncherPartLaunch::abort() { - if(mayProceed) - { + if (mayProceed) { mayProceed = false; QString launchString("abort\n"); m_process.write(launchString.toUtf8()); - } - else - { + } else { auto state = m_process.state(); - if (state == LoggedProcess::Running || state == LoggedProcess::Starting) - { + if (state == LoggedProcess::Running || state == LoggedProcess::Starting) { m_process.kill(); } } diff --git a/launcher/minecraft/launch/LauncherPartLaunch.h b/launcher/minecraft/launch/LauncherPartLaunch.h index 6a7ee0e5..9f6ca1e7 100644 --- a/launcher/minecraft/launch/LauncherPartLaunch.h +++ b/launcher/minecraft/launch/LauncherPartLaunch.h @@ -15,41 +15,31 @@ #pragma once -#include <launch/LaunchStep.h> #include <LoggedProcess.h> +#include <launch/LaunchStep.h> #include <minecraft/auth/AuthSession.h> #include "MinecraftServerTarget.h" -class LauncherPartLaunch: public LaunchStep -{ +class LauncherPartLaunch : public LaunchStep { Q_OBJECT -public: - explicit LauncherPartLaunch(LaunchTask *parent); - virtual ~LauncherPartLaunch() {}; + public: + explicit LauncherPartLaunch(LaunchTask* parent); + virtual ~LauncherPartLaunch(){}; virtual void executeTask(); virtual bool abort(); virtual void proceed(); - virtual bool canAbort() const - { - return true; - } - void setWorkingDirectory(const QString &wd); - void setAuthSession(AuthSessionPtr session) - { - m_session = session; - } - - void setServerToJoin(MinecraftServerTargetPtr serverToJoin) - { - m_serverToJoin = std::move(serverToJoin); - } - -private slots: + virtual bool canAbort() const { return true; } + void setWorkingDirectory(const QString& wd); + void setAuthSession(AuthSessionPtr session) { m_session = session; } + + void setServerToJoin(MinecraftServerTargetPtr serverToJoin) { m_serverToJoin = std::move(serverToJoin); } + + private slots: void on_state(LoggedProcess::State state); -private: + private: LoggedProcess m_process; QString m_command; AuthSessionPtr m_session; diff --git a/launcher/minecraft/launch/MinecraftServerTarget.cpp b/launcher/minecraft/launch/MinecraftServerTarget.cpp index a3383ec0..e201efab 100644 --- a/launcher/minecraft/launch/MinecraftServerTarget.cpp +++ b/launcher/minecraft/launch/MinecraftServerTarget.cpp @@ -18,50 +18,43 @@ #include <QStringList> // FIXME: the way this is written, it can't ever do any sort of validation and can accept total junk -MinecraftServerTarget MinecraftServerTarget::parse(const QString &fullAddress) { +MinecraftServerTarget MinecraftServerTarget::parse(const QString& fullAddress) +{ QStringList split = fullAddress.split(":"); // The logic below replicates the exact logic minecraft uses for parsing server addresses. // While the conversion is not lossless and eats errors, it ensures the same behavior // within Minecraft and Prism Launcher when entering server addresses. - if (fullAddress.startsWith("[")) - { + if (fullAddress.startsWith("[")) { int bracket = fullAddress.indexOf("]"); - if (bracket > 0) - { + if (bracket > 0) { QString ipv6 = fullAddress.mid(1, bracket - 1); QString port = fullAddress.mid(bracket + 1).trimmed(); - if (port.startsWith(":") && !ipv6.isEmpty()) - { + if (port.startsWith(":") && !ipv6.isEmpty()) { port = port.mid(1); split = QStringList({ ipv6, port }); - } - else - { - split = QStringList({ipv6}); + } else { + split = QStringList({ ipv6 }); } } } - if (split.size() > 2) - { - split = QStringList({fullAddress}); + if (split.size() > 2) { + split = QStringList({ fullAddress }); } QString realAddress = split[0]; quint16 realPort = 25565; - if (split.size() > 1) - { + if (split.size() > 1) { bool ok; realPort = split[1].toUInt(&ok); - if (!ok) - { + if (!ok) { realPort = 25565; } } - return MinecraftServerTarget { realAddress, realPort }; + return MinecraftServerTarget{ realAddress, realPort }; } diff --git a/launcher/minecraft/launch/MinecraftServerTarget.h b/launcher/minecraft/launch/MinecraftServerTarget.h index a402421a..af8d6550 100644 --- a/launcher/minecraft/launch/MinecraftServerTarget.h +++ b/launcher/minecraft/launch/MinecraftServerTarget.h @@ -23,7 +23,7 @@ struct MinecraftServerTarget { QString address; quint16 port; - static MinecraftServerTarget parse(const QString &fullAddress); + static MinecraftServerTarget parse(const QString& fullAddress); }; typedef std::shared_ptr<MinecraftServerTarget> MinecraftServerTargetPtr; diff --git a/launcher/minecraft/launch/ModMinecraftJar.cpp b/launcher/minecraft/launch/ModMinecraftJar.cpp index 1d6eecf2..f858dd74 100644 --- a/launcher/minecraft/launch/ModMinecraftJar.cpp +++ b/launcher/minecraft/launch/ModMinecraftJar.cpp @@ -34,9 +34,9 @@ */ #include "ModMinecraftJar.h" -#include "launch/LaunchTask.h" -#include "MMCZip.h" #include "FileSystem.h" +#include "MMCZip.h" +#include "launch/LaunchTask.h" #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" @@ -44,20 +44,17 @@ void ModMinecraftJar::executeTask() { auto m_inst = std::dynamic_pointer_cast<MinecraftInstance>(m_parent->instance()); - if(!m_inst->getJarMods().size()) - { + if (!m_inst->getJarMods().size()) { emitSucceeded(); return; } // nuke obsolete stripped jar(s) if needed - if(!FS::ensureFolderPathExists(m_inst->binRoot())) - { + if (!FS::ensureFolderPathExists(m_inst->binRoot())) { emitFailed(tr("Couldn't create the bin folder for Minecraft.jar")); } auto finalJarPath = QDir(m_inst->binRoot()).absoluteFilePath("minecraft.jar"); - if(!removeJar()) - { + if (!removeJar()) { emitFailed(tr("Couldn't remove stale jar file: %1").arg(finalJarPath)); } @@ -65,14 +62,12 @@ void ModMinecraftJar::executeTask() auto components = m_inst->getPackProfile(); auto profile = components->getProfile(); auto jarMods = m_inst->getJarMods(); - if(jarMods.size()) - { + if (jarMods.size()) { auto mainJar = profile->getMainJar(); QStringList jars, temp1, temp2, temp3, temp4; mainJar->getApplicableFiles(m_inst->runtimeContext(), jars, temp1, temp2, temp3, m_inst->getLocalLibraryPath()); auto sourceJarPath = jars[0]; - if(!MMCZip::createModdedJar(sourceJarPath, finalJarPath, jarMods)) - { + if (!MMCZip::createModdedJar(sourceJarPath, finalJarPath, jarMods)) { emitFailed(tr("Failed to create the custom Minecraft jar file.")); return; } @@ -90,10 +85,8 @@ bool ModMinecraftJar::removeJar() auto m_inst = std::dynamic_pointer_cast<MinecraftInstance>(m_parent->instance()); auto finalJarPath = QDir(m_inst->binRoot()).absoluteFilePath("minecraft.jar"); QFile finalJar(finalJarPath); - if(finalJar.exists()) - { - if(!finalJar.remove()) - { + if (finalJar.exists()) { + if (!finalJar.remove()) { return false; } } diff --git a/launcher/minecraft/launch/ModMinecraftJar.h b/launcher/minecraft/launch/ModMinecraftJar.h index 081c6a91..12e73b5f 100644 --- a/launcher/minecraft/launch/ModMinecraftJar.h +++ b/launcher/minecraft/launch/ModMinecraftJar.h @@ -18,19 +18,16 @@ #include <launch/LaunchStep.h> #include <memory> -class ModMinecraftJar: public LaunchStep -{ +class ModMinecraftJar : public LaunchStep { Q_OBJECT -public: - explicit ModMinecraftJar(LaunchTask *parent) : LaunchStep(parent) {}; + public: + explicit ModMinecraftJar(LaunchTask* parent) : LaunchStep(parent){}; virtual ~ModMinecraftJar(){}; virtual void executeTask() override; - virtual bool canAbort() const override - { - return false; - } + virtual bool canAbort() const override { return false; } void finalize() override; -private: + + private: bool removeJar(); }; diff --git a/launcher/minecraft/launch/PrintInstanceInfo.cpp b/launcher/minecraft/launch/PrintInstanceInfo.cpp index e8fbcb9b..e3a45b03 100644 --- a/launcher/minecraft/launch/PrintInstanceInfo.cpp +++ b/launcher/minecraft/launch/PrintInstanceInfo.cpp @@ -16,50 +16,44 @@ #include <fstream> #include <string> -#include "PrintInstanceInfo.h" #include <launch/LaunchTask.h> +#include "PrintInstanceInfo.h" #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) namespace { #if defined(Q_OS_LINUX) -void probeProcCpuinfo(QStringList &log) +void probeProcCpuinfo(QStringList& log) { std::ifstream cpuin("/proc/cpuinfo"); - for (std::string line; std::getline(cpuin, line);) - { - if (strncmp(line.c_str(), "model name", 10) == 0) - { + for (std::string line; std::getline(cpuin, line);) { + if (strncmp(line.c_str(), "model name", 10) == 0) { log << QString::fromStdString(line.substr(13, std::string::npos)); break; } } } -void runLspci(QStringList &log) +void runLspci(QStringList& log) { // FIXME: fixed size buffers... char buff[512]; int gpuline = -1; int cline = 0; - FILE * lspci = popen("lspci -k", "r"); + FILE* lspci = popen("lspci -k", "r"); if (!lspci) return; - while (fgets(buff, 512, lspci) != NULL) - { + while (fgets(buff, 512, lspci) != NULL) { std::string str(buff); if (str.length() < 9) continue; - if (str.substr(8, 3) == "VGA") - { + if (str.substr(8, 3) == "VGA") { gpuline = cline; log << QString::fromStdString(str.substr(35, std::string::npos)); } - if (gpuline > -1 && gpuline != cline) - { - if (cline - gpuline < 3) - { + if (gpuline > -1 && gpuline != cline) { + if (cline - gpuline < 3) { log << QString::fromStdString(str.substr(1, std::string::npos)); } } @@ -68,54 +62,47 @@ void runLspci(QStringList &log) pclose(lspci); } #elif defined(Q_OS_FREEBSD) -void runSysctlHwModel(QStringList &log) +void runSysctlHwModel(QStringList& log) { char buff[512]; - FILE *hwmodel = popen("sysctl hw.model", "r"); - while (fgets(buff, 512, hwmodel) != NULL) - { - log << QString::fromUtf8(buff); - break; + FILE* hwmodel = popen("sysctl hw.model", "r"); + while (fgets(buff, 512, hwmodel) != NULL) { + log << QString::fromUtf8(buff); + break; } pclose(hwmodel); } -void runPciconf(QStringList &log) +void runPciconf(QStringList& log) { char buff[512]; std::string strcard; - FILE *pciconf = popen("pciconf -lv -a vgapci0", "r"); - while (fgets(buff, 512, pciconf) != NULL) - { - if (strncmp(buff, " vendor", 10) == 0) - { - std::string str(buff); - strcard.append(str.substr(str.find_first_of("'") + 1, str.find_last_not_of("'") - (str.find_first_of("'") + 2))); - strcard.append(" "); - } - else if (strncmp(buff, " device", 10) == 0) - { - std::string str2(buff); - strcard.append(str2.substr(str2.find_first_of("'") + 1, str2.find_last_not_of("'") - (str2.find_first_of("'") + 2))); - } - log << QString::fromStdString(strcard); - break; + FILE* pciconf = popen("pciconf -lv -a vgapci0", "r"); + while (fgets(buff, 512, pciconf) != NULL) { + if (strncmp(buff, " vendor", 10) == 0) { + std::string str(buff); + strcard.append(str.substr(str.find_first_of("'") + 1, str.find_last_not_of("'") - (str.find_first_of("'") + 2))); + strcard.append(" "); + } else if (strncmp(buff, " device", 10) == 0) { + std::string str2(buff); + strcard.append(str2.substr(str2.find_first_of("'") + 1, str2.find_last_not_of("'") - (str2.find_first_of("'") + 2))); + } + log << QString::fromStdString(strcard); + break; } pclose(pciconf); } #endif -void runGlxinfo(QStringList & log) +void runGlxinfo(QStringList& log) { // FIXME: fixed size buffers... char buff[512]; - FILE *glxinfo = popen("glxinfo", "r"); + FILE* glxinfo = popen("glxinfo", "r"); if (!glxinfo) return; - while (fgets(buff, 512, glxinfo) != NULL) - { - if (strncmp(buff, "OpenGL version string:", 22) == 0) - { + while (fgets(buff, 512, glxinfo) != NULL) { + if (strncmp(buff, "OpenGL version string:", 22) == 0) { log << QString::fromUtf8(buff); break; } @@ -123,7 +110,7 @@ void runGlxinfo(QStringList & log) pclose(glxinfo); } -} +} // namespace #endif void PrintInstanceInfo::executeTask() diff --git a/launcher/minecraft/launch/PrintInstanceInfo.h b/launcher/minecraft/launch/PrintInstanceInfo.h index fdc30f31..8e1c41b6 100644 --- a/launcher/minecraft/launch/PrintInstanceInfo.h +++ b/launcher/minecraft/launch/PrintInstanceInfo.h @@ -21,21 +21,17 @@ #include "minecraft/launch/MinecraftServerTarget.h" // FIXME: temporary wrapper for existing task. -class PrintInstanceInfo: public LaunchStep -{ +class PrintInstanceInfo : public LaunchStep { Q_OBJECT -public: - explicit PrintInstanceInfo(LaunchTask *parent, AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) : - LaunchStep(parent), m_session(session), m_serverToJoin(serverToJoin) {}; + public: + explicit PrintInstanceInfo(LaunchTask* parent, AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) + : LaunchStep(parent), m_session(session), m_serverToJoin(serverToJoin){}; virtual ~PrintInstanceInfo(){}; virtual void executeTask(); - virtual bool canAbort() const - { - return false; - } -private: + virtual bool canAbort() const { return false; } + + private: AuthSessionPtr m_session; MinecraftServerTargetPtr m_serverToJoin; }; - diff --git a/launcher/minecraft/launch/ReconstructAssets.cpp b/launcher/minecraft/launch/ReconstructAssets.cpp index 4d206665..843ccc55 100644 --- a/launcher/minecraft/launch/ReconstructAssets.cpp +++ b/launcher/minecraft/launch/ReconstructAssets.cpp @@ -14,10 +14,10 @@ */ #include "ReconstructAssets.h" +#include "launch/LaunchTask.h" +#include "minecraft/AssetsUtils.h" #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" -#include "minecraft/AssetsUtils.h" -#include "launch/LaunchTask.h" void ReconstructAssets::executeTask() { @@ -27,8 +27,7 @@ void ReconstructAssets::executeTask() auto profile = components->getProfile(); auto assets = profile->getMinecraftAssets(); - if(!AssetsUtils::reconstructAssets(assets->id, minecraftInstance->resourcesDir())) - { + if (!AssetsUtils::reconstructAssets(assets->id, minecraftInstance->resourcesDir())) { emit logLine("Failed to reconstruct Minecraft assets.", MessageLevel::Error); } diff --git a/launcher/minecraft/launch/ReconstructAssets.h b/launcher/minecraft/launch/ReconstructAssets.h index 58d7febd..bd867c8d 100644 --- a/launcher/minecraft/launch/ReconstructAssets.h +++ b/launcher/minecraft/launch/ReconstructAssets.h @@ -18,16 +18,12 @@ #include <launch/LaunchStep.h> #include <memory> -class ReconstructAssets: public LaunchStep -{ +class ReconstructAssets : public LaunchStep { Q_OBJECT -public: - explicit ReconstructAssets(LaunchTask *parent) : LaunchStep(parent){}; + public: + explicit ReconstructAssets(LaunchTask* parent) : LaunchStep(parent){}; virtual ~ReconstructAssets(){}; void executeTask() override; - bool canAbort() const override - { - return false; - } + bool canAbort() const override { return false; } }; diff --git a/launcher/minecraft/launch/ScanModFolders.cpp b/launcher/minecraft/launch/ScanModFolders.cpp index 71e7638c..04d82066 100644 --- a/launcher/minecraft/launch/ScanModFolders.cpp +++ b/launcher/minecraft/launch/ScanModFolders.cpp @@ -34,9 +34,9 @@ */ #include "ScanModFolders.h" -#include "launch/LaunchTask.h" -#include "MMCZip.h" #include "FileSystem.h" +#include "MMCZip.h" +#include "launch/LaunchTask.h" #include "minecraft/MinecraftInstance.h" #include "minecraft/mod/ModFolderModel.h" @@ -46,19 +46,19 @@ void ScanModFolders::executeTask() auto loaders = m_inst->loaderModList(); connect(loaders.get(), &ModFolderModel::updateFinished, this, &ScanModFolders::modsDone); - if(!loaders->update()) { + if (!loaders->update()) { m_modsDone = true; } auto cores = m_inst->coreModList(); connect(cores.get(), &ModFolderModel::updateFinished, this, &ScanModFolders::coreModsDone); - if(!cores->update()) { + if (!cores->update()) { m_coreModsDone = true; } auto nils = m_inst->nilModList(); connect(nils.get(), &ModFolderModel::updateFinished, this, &ScanModFolders::nilModsDone); - if(!nils->update()) { + if (!nils->update()) { m_nilModsDone = true; } checkDone(); @@ -84,7 +84,7 @@ void ScanModFolders::nilModsDone() void ScanModFolders::checkDone() { - if(m_modsDone && m_coreModsDone && m_nilModsDone) { + if (m_modsDone && m_coreModsDone && m_nilModsDone) { emitSucceeded(); } } diff --git a/launcher/minecraft/launch/ScanModFolders.h b/launcher/minecraft/launch/ScanModFolders.h index 111a5850..a5b75825 100644 --- a/launcher/minecraft/launch/ScanModFolders.h +++ b/launcher/minecraft/launch/ScanModFolders.h @@ -18,26 +18,23 @@ #include <launch/LaunchStep.h> #include <memory> -class ScanModFolders: public LaunchStep -{ +class ScanModFolders : public LaunchStep { Q_OBJECT -public: - explicit ScanModFolders(LaunchTask *parent) : LaunchStep(parent) {}; + public: + explicit ScanModFolders(LaunchTask* parent) : LaunchStep(parent){}; virtual ~ScanModFolders(){}; virtual void executeTask() override; - virtual bool canAbort() const override - { - return false; - } -private slots: + virtual bool canAbort() const override { return false; } + private slots: void coreModsDone(); void modsDone(); void nilModsDone(); -private: + + private: void checkDone(); -private: // DATA + private: // DATA bool m_modsDone = false; bool m_nilModsDone = false; bool m_coreModsDone = false; diff --git a/launcher/minecraft/launch/VerifyJavaInstall.cpp b/launcher/minecraft/launch/VerifyJavaInstall.cpp index 6ae666b4..03831d17 100644 --- a/launcher/minecraft/launch/VerifyJavaInstall.cpp +++ b/launcher/minecraft/launch/VerifyJavaInstall.cpp @@ -36,10 +36,11 @@ #include "VerifyJavaInstall.h" #include "java/JavaVersion.h" -#include "minecraft/PackProfile.h" #include "minecraft/MinecraftInstance.h" +#include "minecraft/PackProfile.h" -void VerifyJavaInstall::executeTask() { +void VerifyJavaInstall::executeTask() +{ auto instance = std::dynamic_pointer_cast<MinecraftInstance>(m_parent->instance()); auto packProfile = instance->getPackProfile(); auto settings = instance->settings(); @@ -50,28 +51,27 @@ void VerifyJavaInstall::executeTask() { JavaVersion javaVersion(storedVersion); - if (compatibleMajors.isEmpty() || compatibleMajors.contains(javaVersion.major())) - { + if (compatibleMajors.isEmpty() || compatibleMajors.contains(javaVersion.major())) { emitSucceeded(); return; } - - if (ignoreCompatibility) - { + if (ignoreCompatibility) { emit logLine(tr("Java major version is incompatible. Things might break."), MessageLevel::Warning); emitSucceeded(); return; } emit logLine(tr("This instance is not compatible with Java version %1.\n" - "Please switch to one of the following Java versions for this instance:").arg(javaVersion.major()), + "Please switch to one of the following Java versions for this instance:") + .arg(javaVersion.major()), MessageLevel::Error); - for (auto major : compatibleMajors) - { + for (auto major : compatibleMajors) { emit logLine(tr("Java version %1").arg(major), MessageLevel::Error); } - emit logLine(tr("Go to instance Java settings to change your Java version or disable the Java compatibility check if you know what you're doing."), MessageLevel::Error); + emit logLine(tr("Go to instance Java settings to change your Java version or disable the Java compatibility check if you know what " + "you're doing."), + MessageLevel::Error); emitFailed(QString("Incompatible Java major version")); } diff --git a/launcher/minecraft/launch/VerifyJavaInstall.h b/launcher/minecraft/launch/VerifyJavaInstall.h index 9139c0fa..edf6015a 100644 --- a/launcher/minecraft/launch/VerifyJavaInstall.h +++ b/launcher/minecraft/launch/VerifyJavaInstall.h @@ -41,13 +41,10 @@ class VerifyJavaInstall : public LaunchStep { Q_OBJECT -public: - explicit VerifyJavaInstall(LaunchTask *parent) : LaunchStep(parent) { - }; + public: + explicit VerifyJavaInstall(LaunchTask* parent) : LaunchStep(parent){}; ~VerifyJavaInstall() override = default; void executeTask() override; - bool canAbort() const override { - return false; - } + bool canAbort() const override { return false; } }; diff --git a/launcher/minecraft/mod/DataPack.cpp b/launcher/minecraft/mod/DataPack.cpp index c5754638..7bf5a311 100644 --- a/launcher/minecraft/mod/DataPack.cpp +++ b/launcher/minecraft/mod/DataPack.cpp @@ -30,10 +30,10 @@ // Values taken from: // https://minecraft.fandom.com/wiki/Tutorials/Creating_a_data_pack#%22pack_format%22 static const QMap<int, std::pair<Version, Version>> s_pack_format_versions = { - { 4, { Version("1.13"), Version("1.14.4") } }, { 5, { Version("1.15"), Version("1.16.1") } }, - { 6, { Version("1.16.2"), Version("1.16.5") } }, { 7, { Version("1.17"), Version("1.17.1") } }, - { 8, { Version("1.18"), Version("1.18.1") } }, { 9, { Version("1.18.2"), Version("1.18.2") } }, - { 10, { Version("1.19"), Version("1.19.3") } }, { 11, { Version("23w03a"), Version("23w05a") } }, + { 4, { Version("1.13"), Version("1.14.4") } }, { 5, { Version("1.15"), Version("1.16.1") } }, + { 6, { Version("1.16.2"), Version("1.16.5") } }, { 7, { Version("1.17"), Version("1.17.1") } }, + { 8, { Version("1.18"), Version("1.18.1") } }, { 9, { Version("1.18.2"), Version("1.18.2") } }, + { 10, { Version("1.19"), Version("1.19.3") } }, { 11, { Version("23w03a"), Version("23w05a") } }, { 12, { Version("1.19.4"), Version("1.19.4") } }, { 13, { Version("23w12a"), Version("23w14a") } }, { 14, { Version("23w16a"), Version("23w17a") } }, { 15, { Version("1.20"), Version("1.20") } }, }; diff --git a/launcher/minecraft/mod/MetadataHandler.h b/launcher/minecraft/mod/MetadataHandler.h index 39723b49..ea9078e0 100644 --- a/launcher/minecraft/mod/MetadataHandler.h +++ b/launcher/minecraft/mod/MetadataHandler.h @@ -1,20 +1,20 @@ // SPDX-License-Identifier: GPL-3.0-only /* -* PolyMC - Minecraft Launcher -* Copyright (c) 2022 flowln <flowlnlnln@gmail.com> -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, version 3. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ + * PolyMC - Minecraft Launcher + * Copyright (c) 2022 flowln <flowlnlnln@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ #pragma once @@ -42,28 +42,13 @@ class Metadata { return Packwiz::V1::createModFormat(index_dir, internal_mod, mod_slug); } - static void update(QDir& index_dir, ModStruct& mod) - { - Packwiz::V1::updateModIndex(index_dir, mod); - } + static void update(QDir& index_dir, ModStruct& mod) { Packwiz::V1::updateModIndex(index_dir, mod); } - static void remove(QDir& index_dir, QString mod_slug) - { - Packwiz::V1::deleteModIndex(index_dir, mod_slug); - } + static void remove(QDir& index_dir, QString mod_slug) { Packwiz::V1::deleteModIndex(index_dir, mod_slug); } - static void remove(QDir& index_dir, QVariant& mod_id) - { - Packwiz::V1::deleteModIndex(index_dir, mod_id); - } + static void remove(QDir& index_dir, QVariant& mod_id) { Packwiz::V1::deleteModIndex(index_dir, mod_id); } - static auto get(QDir& index_dir, QString mod_slug) -> ModStruct - { - return Packwiz::V1::getIndexForMod(index_dir, mod_slug); - } + static auto get(QDir& index_dir, QString mod_slug) -> ModStruct { return Packwiz::V1::getIndexForMod(index_dir, mod_slug); } - static auto get(QDir& index_dir, QVariant& mod_id) -> ModStruct - { - return Packwiz::V1::getIndexForMod(index_dir, mod_id); - } + static auto get(QDir& index_dir, QVariant& mod_id) -> ModStruct { return Packwiz::V1::getIndexForMod(index_dir, mod_id); } }; diff --git a/launcher/minecraft/mod/Mod.cpp b/launcher/minecraft/mod/Mod.cpp index 880dacb1..46509cde 100644 --- a/launcher/minecraft/mod/Mod.cpp +++ b/launcher/minecraft/mod/Mod.cpp @@ -1,45 +1,45 @@ // SPDX-License-Identifier: GPL-3.0-only /* -* PolyMC - Minecraft Launcher -* Copyright (c) 2022 flowln <flowlnlnln@gmail.com> -* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, version 3. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <https://www.gnu.org/licenses/>. -* -* This file incorporates work covered by the following copyright and -* permission notice: -* -* Copyright 2013-2021 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. -*/ + * PolyMC - Minecraft Launcher + * Copyright (c) 2022 flowln <flowlnlnln@gmail.com> + * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 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 "Mod.h" #include <QDebug> #include <QDir> -#include <QString> #include <QRegularExpression> +#include <QString> #include "MTPixmapCache.h" #include "MetadataHandler.h" @@ -54,8 +54,7 @@ Mod::Mod(const QFileInfo& file) : Resource(file), m_local_details() m_enabled = (file.suffix() != "disabled"); } -Mod::Mod(const QDir& mods_dir, const Metadata::ModStruct& metadata) - : Mod(mods_dir.absoluteFilePath(metadata.filename)) +Mod::Mod(const QDir& mods_dir, const Metadata::ModStruct& metadata) : Mod(mods_dir.absoluteFilePath(metadata.filename)) { m_name = metadata.name; m_local_details.metadata = std::make_shared<Metadata::ModStruct>(std::move(metadata)); @@ -73,7 +72,8 @@ void Mod::setMetadata(std::shared_ptr<Metadata::ModStruct>&& metadata) m_local_details.metadata = metadata; } -void Mod::setDetails(const ModDetails& details) { +void Mod::setDetails(const ModDetails& details) +{ m_local_details = details; } @@ -103,7 +103,8 @@ std::pair<int, bool> Mod::compare(const Resource& other, SortType type) const break; } case SortType::PROVIDER: { - auto compare_result = QString::compare(provider().value_or("Unknown"), cast_other->provider().value_or("Unknown"), Qt::CaseInsensitive); + auto compare_result = + QString::compare(provider().value_or("Unknown"), cast_other->provider().value_or("Unknown"), Qt::CaseInsensitive); if (compare_result != 0) return { compare_result, type == SortType::PROVIDER }; break; @@ -230,7 +231,7 @@ auto Mod::licenses() const -> const QList<ModLicense>& return details().licenses; } - auto Mod::issueTracker() const -> QString +auto Mod::issueTracker() const -> QString { return details().issue_tracker; } @@ -245,7 +246,7 @@ void Mod::setIcon(QImage new_image) const PixmapCache::remove(m_pack_image_cache_key.key); // scale the image to avoid flooding the pixmapcache - auto pixmap = QPixmap::fromImage(new_image.scaled({64, 64}, Qt::AspectRatioMode::KeepAspectRatioByExpanding)); + auto pixmap = QPixmap::fromImage(new_image.scaled({ 64, 64 }, Qt::AspectRatioMode::KeepAspectRatioByExpanding)); m_pack_image_cache_key.key = PixmapCache::insert(pixmap); m_pack_image_cache_key.was_ever_used = true; diff --git a/launcher/minecraft/mod/Mod.h b/launcher/minecraft/mod/Mod.h index b67bd465..51c42028 100644 --- a/launcher/minecraft/mod/Mod.h +++ b/launcher/minecraft/mod/Mod.h @@ -1,76 +1,75 @@ // SPDX-License-Identifier: GPL-3.0-only /* -* PolyMC - Minecraft Launcher -* Copyright (c) 2022 flowln <flowlnlnln@gmail.com> -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, version 3. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <https://www.gnu.org/licenses/>. -* -* This file incorporates work covered by the following copyright and -* permission notice: -* -* Copyright 2013-2021 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. -*/ + * PolyMC - Minecraft Launcher + * Copyright (c) 2022 flowln <flowlnlnln@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 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 <QDateTime> #include <QFileInfo> -#include <QList> #include <QImage> +#include <QList> #include <QMutex> #include <QPixmap> #include <QPixmapCache> #include <optional> -#include "Resource.h" #include "ModDetails.h" +#include "Resource.h" -class Mod : public Resource -{ +class Mod : public Resource { Q_OBJECT -public: + public: using Ptr = shared_qobject_ptr<Mod>; using WeakPtr = QPointer<Mod>; Mod() = default; - Mod(const QFileInfo &file); + Mod(const QFileInfo& file); Mod(const QDir& mods_dir, const Metadata::ModStruct& metadata); Mod(QString file_path) : Mod(QFileInfo(file_path)) {} - auto details() const -> const ModDetails&; - auto name() const -> QString override; - auto version() const -> QString; - auto homeurl() const -> QString; + auto details() const -> const ModDetails&; + auto name() const -> QString override; + auto version() const -> QString; + auto homeurl() const -> QString; auto description() const -> QString; - auto authors() const -> QStringList; - auto status() const -> ModStatus; - auto provider() const -> std::optional<QString>; - auto licenses() const -> const QList<ModLicense>&; + auto authors() const -> QStringList; + auto status() const -> ModStatus; + auto provider() const -> std::optional<QString>; + auto licenses() const -> const QList<ModLicense>&; auto issueTracker() const -> QString; - auto metaurl() const -> QString; + auto metaurl() const -> QString; /** Get the intneral path to the mod's icon file*/ QString iconPath() const { return m_local_details.icon_file; }; @@ -97,7 +96,7 @@ public: void finishResolvingWithDetails(ModDetails&& details); -protected: + protected: ModDetails m_local_details; mutable QMutex m_data_lock; @@ -107,5 +106,4 @@ protected: bool was_ever_used = false; bool was_read_attempt = false; } mutable m_pack_image_cache_key; - }; diff --git a/launcher/minecraft/mod/ModDetails.h b/launcher/minecraft/mod/ModDetails.h index b4e59d52..60099496 100644 --- a/launcher/minecraft/mod/ModDetails.h +++ b/launcher/minecraft/mod/ModDetails.h @@ -1,37 +1,37 @@ // SPDX-License-Identifier: GPL-3.0-only /* -* PolyMC - Minecraft Launcher -* Copyright (c) 2022 flowln <flowlnlnln@gmail.com> -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, version 3. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <https://www.gnu.org/licenses/>. -* -* This file incorporates work covered by the following copyright and -* permission notice: -* -* Copyright 2013-2021 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. -*/ + * PolyMC - Minecraft Launcher + * Copyright (c) 2022 flowln <flowlnlnln@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 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 @@ -44,10 +44,10 @@ #include "minecraft/mod/MetadataHandler.h" enum class ModStatus { - Installed, // Both JAR and Metadata are present - NotInstalled, // Only the Metadata is present - NoMetadata, // Only the JAR is present - Unknown, // Default status + Installed, // Both JAR and Metadata are present + NotInstalled, // Only the Metadata is present + NoMetadata, // Only the JAR is present + Unknown, // Default status }; struct ModLicense { @@ -58,11 +58,12 @@ struct ModLicense { ModLicense() {} - ModLicense(const QString license) { - // FIXME: come up with a better license parseing. + ModLicense(const QString license) + { + // FIXME: come up with a better license parseing. // handle SPDX identifiers? https://spdx.org/licenses/ auto parts = license.split(' '); - QStringList notNameParts = {}; + QStringList notNameParts = {}; for (auto part : parts) { auto url = QUrl(part); if (part.startsWith("(") && part.endsWith(")")) @@ -78,7 +79,7 @@ struct ModLicense { for (auto part : notNameParts) { parts.removeOne(part); } - + auto licensePart = parts.join(' '); this->name = licensePart; this->description = licensePart; @@ -86,22 +87,17 @@ struct ModLicense { if (parts.size() == 1) { this->id = parts.first(); } - } - ModLicense(const QString name, const QString id, const QString url, const QString description) { + ModLicense(const QString name, const QString id, const QString url, const QString description) + { this->name = name; this->id = id; this->url = url; this->description = description; } - ModLicense(const ModLicense& other) - : name(other.name) - , id(other.id) - , url(other.url) - , description(other.description) - {} + ModLicense(const ModLicense& other) : name(other.name), id(other.id), url(other.url), description(other.description) {} ModLicense& operator=(const ModLicense& other) { @@ -123,28 +119,25 @@ struct ModLicense { return *this; } - bool isEmpty() { - return this->name.isEmpty() && this->id.isEmpty() && this->url.isEmpty() && this->description.isEmpty(); - } + bool isEmpty() { return this->name.isEmpty() && this->id.isEmpty() && this->url.isEmpty() && this->description.isEmpty(); } }; -struct ModDetails -{ +struct ModDetails { /* Mod ID as defined in the ModLoader-specific metadata */ QString mod_id = {}; - + /* Human-readable name */ QString name = {}; - + /* Human-readable mod version */ QString version = {}; - + /* Human-readable minecraft version */ QString mcversion = {}; - + /* URL for mod's home page */ QString homeurl = {}; - + /* Human-readable description */ QString description = {}; diff --git a/launcher/minecraft/mod/ModFolderModel.cpp b/launcher/minecraft/mod/ModFolderModel.cpp index 51383edf..69028199 100644 --- a/launcher/minecraft/mod/ModFolderModel.cpp +++ b/launcher/minecraft/mod/ModFolderModel.cpp @@ -1,38 +1,38 @@ // SPDX-License-Identifier: GPL-3.0-only /* -* PolyMC - Minecraft Launcher -* Copyright (c) 2022 flowln <flowlnlnln@gmail.com> -* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, version 3. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <https://www.gnu.org/licenses/>. -* -* This file incorporates work covered by the following copyright and -* permission notice: -* -* Copyright 2013-2021 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. -*/ + * PolyMC - Minecraft Launcher + * Copyright (c) 2022 flowln <flowlnlnln@gmail.com> + * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 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 "ModFolderModel.h" @@ -59,11 +59,12 @@ ModFolderModel::ModFolderModel(const QString& dir, BaseInstance* instance, bool { m_column_names = QStringList({ "Enable", "Image", "Name", "Version", "Last Modified", "Provider" }); m_column_names_translated = QStringList({ tr("Enable"), tr("Image"), tr("Name"), tr("Version"), tr("Last Modified"), tr("Provider") }); - m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::NAME , SortType::VERSION, SortType::DATE, SortType::PROVIDER}; - m_column_resize_modes = { QHeaderView::ResizeToContents, QHeaderView::Interactive, QHeaderView::Stretch, QHeaderView::ResizeToContents, QHeaderView::ResizeToContents, QHeaderView::ResizeToContents}; + m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::NAME, SortType::VERSION, SortType::DATE, SortType::PROVIDER }; + m_column_resize_modes = { QHeaderView::ResizeToContents, QHeaderView::Interactive, QHeaderView::Stretch, + QHeaderView::ResizeToContents, QHeaderView::ResizeToContents, QHeaderView::ResizeToContents }; } -QVariant ModFolderModel::data(const QModelIndex &index, int role) const +QVariant ModFolderModel::data(const QModelIndex& index, int role) const { if (!validateIndex(index)) return {}; @@ -71,115 +72,109 @@ QVariant ModFolderModel::data(const QModelIndex &index, int role) const int row = index.row(); int column = index.column(); - switch (role) - { - case Qt::DisplayRole: - switch (column) - { - case NameColumn: - return m_resources[row]->name(); - case VersionColumn: { - switch(m_resources[row]->type()) { - case ResourceType::FOLDER: - return tr("Folder"); - case ResourceType::SINGLEFILE: - return tr("File"); + switch (role) { + case Qt::DisplayRole: + switch (column) { + case NameColumn: + return m_resources[row]->name(); + case VersionColumn: { + switch (m_resources[row]->type()) { + case ResourceType::FOLDER: + return tr("Folder"); + case ResourceType::SINGLEFILE: + return tr("File"); + default: + break; + } + return at(row)->version(); + } + case DateColumn: + return m_resources[row]->dateTimeChanged(); + case ProviderColumn: { + auto provider = at(row)->provider(); + if (!provider.has_value()) { + //: Unknown mod provider (i.e. not Modrinth, CurseForge, etc...) + return tr("Unknown"); + } + + return provider.value(); + } default: - break; - } - return at(row)->version(); - } - case DateColumn: - return m_resources[row]->dateTimeChanged(); - case ProviderColumn: { - auto provider = at(row)->provider(); - if (!provider.has_value()) { - //: Unknown mod provider (i.e. not Modrinth, CurseForge, etc...) - return tr("Unknown"); + return QVariant(); } - return provider.value(); - } - default: - return QVariant(); - } - - case Qt::ToolTipRole: - if (column == NAME_COLUMN) { - if (at(row)->isSymLinkUnder(instDirPath())) { - return m_resources[row]->internal_id() + - tr("\nWarning: This resource is symbolically linked from elsewhere. Editing it will also change the original." - "\nCanonical Path: %1") - .arg(at(row)->fileinfo().canonicalFilePath()); + case Qt::ToolTipRole: + if (column == NAME_COLUMN) { + if (at(row)->isSymLinkUnder(instDirPath())) { + return m_resources[row]->internal_id() + + tr("\nWarning: This resource is symbolically linked from elsewhere. Editing it will also change the original." + "\nCanonical Path: %1") + .arg(at(row)->fileinfo().canonicalFilePath()); + } + if (at(row)->isMoreThanOneHardLink()) { + return m_resources[row]->internal_id() + + tr("\nWarning: This resource is hard linked elsewhere. Editing it will also change the original."); + } } - if (at(row)->isMoreThanOneHardLink()) { - return m_resources[row]->internal_id() + - tr("\nWarning: This resource is hard linked elsewhere. Editing it will also change the original."); + return m_resources[row]->internal_id(); + case Qt::DecorationRole: { + if (column == NAME_COLUMN && (at(row)->isSymLinkUnder(instDirPath()) || at(row)->isMoreThanOneHardLink())) + return APPLICATION->getThemedIcon("status-yellow"); + if (column == ImageColumn) { + return at(row)->icon({ 32, 32 }, Qt::AspectRatioMode::KeepAspectRatioByExpanding); } + return {}; } - return m_resources[row]->internal_id(); - case Qt::DecorationRole: { - if (column == NAME_COLUMN && (at(row)->isSymLinkUnder(instDirPath()) || at(row)->isMoreThanOneHardLink())) - return APPLICATION->getThemedIcon("status-yellow"); - if (column == ImageColumn) { - return at(row)->icon({32, 32}, Qt::AspectRatioMode::KeepAspectRatioByExpanding); - } - return {}; - } - case Qt::CheckStateRole: - switch (column) - { - case ActiveColumn: - return at(row)->enabled() ? Qt::Checked : Qt::Unchecked; + case Qt::CheckStateRole: + switch (column) { + case ActiveColumn: + return at(row)->enabled() ? Qt::Checked : Qt::Unchecked; + default: + return QVariant(); + } default: return QVariant(); - } - default: - return QVariant(); } } QVariant ModFolderModel::headerData(int section, Qt::Orientation orientation, int role) const { - switch (role) - { - case Qt::DisplayRole: - switch (section) - { - case ActiveColumn: - case NameColumn: - case VersionColumn: - case DateColumn: - case ProviderColumn: - case ImageColumn: - return columnNames().at(section); - default: - return QVariant(); - } + switch (role) { + case Qt::DisplayRole: + switch (section) { + case ActiveColumn: + case NameColumn: + case VersionColumn: + case DateColumn: + case ProviderColumn: + case ImageColumn: + return columnNames().at(section); + default: + return QVariant(); + } - case Qt::ToolTipRole: - switch (section) - { - case ActiveColumn: - return tr("Is the mod enabled?"); - case NameColumn: - return tr("The name of the mod."); - case VersionColumn: - return tr("The version of the mod."); - case DateColumn: - return tr("The date and time this mod was last changed (or added)."); - case ProviderColumn: - return tr("Where the mod was downloaded from."); + case Qt::ToolTipRole: + switch (section) { + case ActiveColumn: + return tr("Is the mod enabled?"); + case NameColumn: + return tr("The name of the mod."); + case VersionColumn: + return tr("The version of the mod."); + case DateColumn: + return tr("The date and time this mod was last changed (or added)."); + case ProviderColumn: + return tr("Where the mod was downloaded from."); + default: + return QVariant(); + } default: return QVariant(); - } - default: - return QVariant(); } return QVariant(); } -int ModFolderModel::columnCount(const QModelIndex &parent) const +int ModFolderModel::columnCount(const QModelIndex& parent) const { return parent.isValid() ? 0 : NUM_COLUMNS; } @@ -199,8 +194,8 @@ Task* ModFolderModel::createParseTask(Resource& resource) bool ModFolderModel::uninstallMod(const QString& filename, bool preserve_metadata) { - for(auto mod : allMods()) { - if(mod->fileinfo().fileName() == filename) { + for (auto mod : allMods()) { + if (mod->fileinfo().fileName() == filename) { auto index_dir = indexDir(); mod->destroy(index_dir, preserve_metadata, false); @@ -253,7 +248,7 @@ auto ModFolderModel::selectedMods(QModelIndexList& indexes) -> QList<Mod*> { QList<Mod*> selected_resources; for (auto i : indexes) { - if(i.column() != 0) + if (i.column() != 0) continue; selected_resources.push_back(at(i.row())); diff --git a/launcher/minecraft/mod/ModFolderModel.h b/launcher/minecraft/mod/ModFolderModel.h index 6ccaba23..f1f40a81 100644 --- a/launcher/minecraft/mod/ModFolderModel.h +++ b/launcher/minecraft/mod/ModFolderModel.h @@ -1,53 +1,53 @@ // SPDX-License-Identifier: GPL-3.0-only /* -* PolyMC - Minecraft Launcher -* Copyright (c) 2022 flowln <flowlnlnln@gmail.com> -* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, version 3. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <https://www.gnu.org/licenses/>. -* -* This file incorporates work covered by the following copyright and -* permission notice: -* -* Copyright 2013-2021 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. -*/ + * PolyMC - Minecraft Launcher + * Copyright (c) 2022 flowln <flowlnlnln@gmail.com> + * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 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 <QAbstractListModel> +#include <QDir> #include <QList> #include <QMap> #include <QSet> #include <QString> -#include <QDir> -#include <QAbstractListModel> #include "Mod.h" #include "ResourceFolderModel.h" -#include "minecraft/mod/tasks/ModFolderLoadTask.h" #include "minecraft/mod/tasks/LocalModParseTask.h" +#include "minecraft/mod/tasks/ModFolderLoadTask.h" class LegacyInstance; class BaseInstance; @@ -57,33 +57,19 @@ class QFileSystemWatcher; * A legacy mod list. * Backed by a folder. */ -class ModFolderModel : public ResourceFolderModel -{ +class ModFolderModel : public ResourceFolderModel { Q_OBJECT -public: - enum Columns - { - ActiveColumn = 0, - ImageColumn, - NameColumn, - VersionColumn, - DateColumn, - ProviderColumn, - NUM_COLUMNS - }; - enum ModStatusAction { - Disable, - Enable, - Toggle - }; - ModFolderModel(const QString &dir, BaseInstance* instance, bool is_indexed = false, bool create_dir = true); + public: + enum Columns { ActiveColumn = 0, ImageColumn, NameColumn, VersionColumn, DateColumn, ProviderColumn, NUM_COLUMNS }; + enum ModStatusAction { Disable, Enable, Toggle }; + ModFolderModel(const QString& dir, BaseInstance* instance, bool is_indexed = false, bool create_dir = true); virtual QString id() const override { return "mods"; } - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; - int columnCount(const QModelIndex &parent) const override; + int columnCount(const QModelIndex& parent) const override; [[nodiscard]] Task* createUpdateTask() override; [[nodiscard]] Task* createParseTask(Resource&) override; @@ -92,7 +78,7 @@ public: bool uninstallMod(const QString& filename, bool preserve_metadata = false); /// Deletes all the selected mods - bool deleteMods(const QModelIndexList &indexes); + bool deleteMods(const QModelIndexList& indexes); bool isValid(); @@ -106,12 +92,11 @@ public: RESOURCE_HELPERS(Mod) -private -slots: + private slots: void onUpdateSucceeded() override; void onParseSucceeded(int ticket, QString resource_id) override; -protected: + protected: bool m_is_indexed; bool m_first_folder_load = true; }; diff --git a/launcher/minecraft/mod/Resource.cpp b/launcher/minecraft/mod/Resource.cpp index 098a617f..da806f0f 100644 --- a/launcher/minecraft/mod/Resource.cpp +++ b/launcher/minecraft/mod/Resource.cpp @@ -1,8 +1,7 @@ #include "Resource.h" - -#include <QRegularExpression> #include <QFileInfo> +#include <QRegularExpression> #include "FileSystem.h" @@ -105,7 +104,6 @@ bool Resource::enable(EnableAction action) if (m_type == ResourceType::UNKNOWN || m_type == ResourceType::FOLDER) return false; - QString path = m_file_info.absoluteFilePath(); QFile file(path); @@ -154,7 +152,7 @@ bool Resource::destroy(bool attemptTrash) return (attemptTrash && FS::trash(m_file_info.filePath())) || FS::deletePath(m_file_info.filePath()); } -bool Resource::isSymLinkUnder(const QString& instPath) const +bool Resource::isSymLinkUnder(const QString& instPath) const { if (isSymLink()) return true; @@ -167,7 +165,7 @@ bool Resource::isSymLinkUnder(const QString& instPath) const return relAbsPath != relCanonPath; } -bool Resource::isMoreThanOneHardLink() const +bool Resource::isMoreThanOneHardLink() const { return FS::hardLinkCount(m_file_info.absoluteFilePath()) > 1; } diff --git a/launcher/minecraft/mod/Resource.h b/launcher/minecraft/mod/Resource.h index 94f3160c..c1ed4946 100644 --- a/launcher/minecraft/mod/Resource.h +++ b/launcher/minecraft/mod/Resource.h @@ -15,20 +15,9 @@ enum class ResourceType { LITEMOD, //!< The resource is a litemod }; -enum class SortType { - NAME, - DATE, - VERSION, - ENABLED, - PACK_FORMAT, - PROVIDER -}; +enum class SortType { NAME, DATE, VERSION, ENABLED, PACK_FORMAT, PROVIDER }; -enum class EnableAction { - ENABLE, - DISABLE, - TOGGLE -}; +enum class EnableAction { ENABLE, DISABLE, TOGGLE }; /** General class for managed resources. It mirrors a file in disk, with some more info * for display and house-keeping purposes. @@ -98,10 +87,10 @@ class Resource : public QObject { /** * @brief Take a instance path, checks if the file pointed to by the resource is a symlink or under a symlink in that instance - * + * * @param instPath path to an instance directory - * @return true - * @return false + * @return true + * @return false */ [[nodiscard]] bool isSymLinkUnder(const QString& instPath) const; diff --git a/launcher/minecraft/mod/ResourceFolderModel.cpp b/launcher/minecraft/mod/ResourceFolderModel.cpp index 39a61067..0106d5c9 100644 --- a/launcher/minecraft/mod/ResourceFolderModel.cpp +++ b/launcher/minecraft/mod/ResourceFolderModel.cpp @@ -515,25 +515,25 @@ void ResourceFolderModel::setupHeaderAction(QAction* act, int column) void ResourceFolderModel::saveHiddenColumn(int column, bool hidden) { auto const setting_name = QString("UI/%1_Page/HiddenColumns").arg(id()); - auto setting = (m_instance->settings()->contains(setting_name)) ? - m_instance->settings()->getSetting(setting_name) : m_instance->settings()->registerSetting(setting_name); + auto setting = (m_instance->settings()->contains(setting_name)) ? m_instance->settings()->getSetting(setting_name) + : m_instance->settings()->registerSetting(setting_name); auto hiddenColumns = setting->get().toStringList(); auto name = columnNames(false).at(column); auto index = hiddenColumns.indexOf(name); if (index >= 0 && !hidden) { hiddenColumns.removeAt(index); - } else if ( index < 0 && hidden) { + } else if (index < 0 && hidden) { hiddenColumns.append(name); } setting->set(hiddenColumns); } -void ResourceFolderModel::loadHiddenColumns(QTreeView *tree) +void ResourceFolderModel::loadHiddenColumns(QTreeView* tree) { auto const setting_name = QString("UI/%1_Page/HiddenColumns").arg(id()); - auto setting = (m_instance->settings()->contains(setting_name)) ? - m_instance->settings()->getSetting(setting_name) : m_instance->settings()->registerSetting(setting_name); + auto setting = (m_instance->settings()->contains(setting_name)) ? m_instance->settings()->getSetting(setting_name) + : m_instance->settings()->registerSetting(setting_name); auto hiddenColumns = setting->get().toStringList(); auto col_names = columnNames(false); @@ -542,7 +542,6 @@ void ResourceFolderModel::loadHiddenColumns(QTreeView *tree) if (index >= 0) tree->setColumnHidden(index, true); } - } QMenu* ResourceFolderModel::createHeaderContextMenu(QTreeView* tree) @@ -558,9 +557,9 @@ QMenu* ResourceFolderModel::createHeaderContextMenu(QTreeView* tree) act->setCheckable(true); act->setChecked(!tree->isColumnHidden(col)); - connect(act, &QAction::toggled, tree, [this, col, tree](bool toggled){ + connect(act, &QAction::toggled, tree, [this, col, tree](bool toggled) { tree->setColumnHidden(col, !toggled); - for(int c = 0; c < columnCount(); ++c) { + for (int c = 0; c < columnCount(); ++c) { if (m_column_resize_modes.at(c) == QHeaderView::ResizeToContents) tree->resizeColumnToContents(c); } @@ -568,7 +567,6 @@ QMenu* ResourceFolderModel::createHeaderContextMenu(QTreeView* tree) }); menu->addAction(act); - } return menu; diff --git a/launcher/minecraft/mod/ResourceFolderModel.h b/launcher/minecraft/mod/ResourceFolderModel.h index 454b84c3..595b9762 100644 --- a/launcher/minecraft/mod/ResourceFolderModel.h +++ b/launcher/minecraft/mod/ResourceFolderModel.h @@ -1,14 +1,14 @@ #pragma once -#include <QHeaderView> -#include <QAction> -#include <QTreeView> #include <QAbstractListModel> +#include <QAction> #include <QDir> #include <QFileSystemWatcher> +#include <QHeaderView> #include <QMutex> #include <QSet> #include <QSortFilterProxyModel> +#include <QTreeView> #include "Resource.h" @@ -120,7 +120,7 @@ class ResourceFolderModel : public QAbstractListModel { void saveHiddenColumn(int column, bool hidden); void loadHiddenColumns(QTreeView* tree); QMenu* createHeaderContextMenu(QTreeView* tree); - + /** This creates a proxy model to filter / sort the model for a UI. * * The actual comparisons and filtering are done directly by the Resource, so to modify behavior go there instead! @@ -199,9 +199,10 @@ class ResourceFolderModel : public QAbstractListModel { // Represents the relationship between a column's index (represented by the list index), and it's sorting key. // As such, the order in with they appear is very important! QList<SortType> m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::DATE }; - QStringList m_column_names = {"Enable", "Name", "Last Modified"}; - QStringList m_column_names_translated = {tr("Enable"), tr("Name"), tr("Last Modified")}; - QList<QHeaderView::ResizeMode> m_column_resize_modes = { QHeaderView::ResizeToContents, QHeaderView::Stretch, QHeaderView::ResizeToContents }; + QStringList m_column_names = { "Enable", "Name", "Last Modified" }; + QStringList m_column_names_translated = { tr("Enable"), tr("Name"), tr("Last Modified") }; + QList<QHeaderView::ResizeMode> m_column_resize_modes = { QHeaderView::ResizeToContents, QHeaderView::Stretch, + QHeaderView::ResizeToContents }; QDir m_dir; BaseInstance* m_instance; diff --git a/launcher/minecraft/mod/ResourcePack.cpp b/launcher/minecraft/mod/ResourcePack.cpp index 6d5978d4..dab0f6d6 100644 --- a/launcher/minecraft/mod/ResourcePack.cpp +++ b/launcher/minecraft/mod/ResourcePack.cpp @@ -50,7 +50,7 @@ void ResourcePack::setImage(QImage new_image) const PixmapCache::instance().remove(m_pack_image_cache_key.key); // scale the image to avoid flooding the pixmapcache - auto pixmap = QPixmap::fromImage(new_image.scaled({64, 64}, Qt::AspectRatioMode::KeepAspectRatioByExpanding)); + auto pixmap = QPixmap::fromImage(new_image.scaled({ 64, 64 }, Qt::AspectRatioMode::KeepAspectRatioByExpanding)); m_pack_image_cache_key.key = PixmapCache::instance().insert(pixmap); m_pack_image_cache_key.was_ever_used = true; diff --git a/launcher/minecraft/mod/ResourcePackFolderModel.cpp b/launcher/minecraft/mod/ResourcePackFolderModel.cpp index 41455599..0e2981ef 100644 --- a/launcher/minecraft/mod/ResourcePackFolderModel.cpp +++ b/launcher/minecraft/mod/ResourcePackFolderModel.cpp @@ -47,14 +47,13 @@ #include "minecraft/mod/tasks/BasicFolderLoadTask.h" #include "minecraft/mod/tasks/LocalResourcePackParseTask.h" -ResourcePackFolderModel::ResourcePackFolderModel(const QString& dir, BaseInstance* instance) - : ResourceFolderModel(QDir(dir), instance) +ResourcePackFolderModel::ResourcePackFolderModel(const QString& dir, BaseInstance* instance) : ResourceFolderModel(QDir(dir), instance) { m_column_names = QStringList({ "Enable", "Image", "Name", "Pack Format", "Last Modified" }); m_column_names_translated = QStringList({ tr("Enable"), tr("Image"), tr("Name"), tr("Pack Format"), tr("Last Modified") }); - m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::NAME, SortType::PACK_FORMAT, SortType::DATE}; - m_column_resize_modes = { QHeaderView::ResizeToContents, QHeaderView::Interactive, QHeaderView::Stretch, QHeaderView::ResizeToContents, QHeaderView::ResizeToContents }; - + m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::NAME, SortType::PACK_FORMAT, SortType::DATE }; + m_column_resize_modes = { QHeaderView::ResizeToContents, QHeaderView::Interactive, QHeaderView::Stretch, QHeaderView::ResizeToContents, + QHeaderView::ResizeToContents }; } QVariant ResourcePackFolderModel::data(const QModelIndex& index, int role) const @@ -93,7 +92,7 @@ QVariant ResourcePackFolderModel::data(const QModelIndex& index, int role) const if (column == NameColumn && (at(row)->isSymLinkUnder(instDirPath()) || at(row)->isMoreThanOneHardLink())) return APPLICATION->getThemedIcon("status-yellow"); if (column == ImageColumn) { - return at(row)->image({32, 32}, Qt::AspectRatioMode::KeepAspectRatioByExpanding); + return at(row)->image({ 32, 32 }, Qt::AspectRatioMode::KeepAspectRatioByExpanding); } return {}; } @@ -105,13 +104,14 @@ QVariant ResourcePackFolderModel::data(const QModelIndex& index, int role) const if (column == NameColumn) { if (at(row)->isSymLinkUnder(instDirPath())) { return m_resources[row]->internal_id() + - tr("\nWarning: This resource is symbolically linked from elsewhere. Editing it will also change the original." - "\nCanonical Path: %1") - .arg(at(row)->fileinfo().canonicalFilePath());; + tr("\nWarning: This resource is symbolically linked from elsewhere. Editing it will also change the original." + "\nCanonical Path: %1") + .arg(at(row)->fileinfo().canonicalFilePath()); + ; } if (at(row)->isMoreThanOneHardLink()) { return m_resources[row]->internal_id() + - tr("\nWarning: This resource is hard linked elsewhere. Editing it will also change the original."); + tr("\nWarning: This resource is hard linked elsewhere. Editing it will also change the original."); } } return m_resources[row]->internal_id(); @@ -159,7 +159,7 @@ QVariant ResourcePackFolderModel::headerData(int section, Qt::Orientation orient } case Qt::SizeHintRole: if (section == ImageColumn) { - return QSize(64,0); + return QSize(64, 0); } return {}; default: diff --git a/launcher/minecraft/mod/ResourcePackFolderModel.h b/launcher/minecraft/mod/ResourcePackFolderModel.h index 531d8192..29c2c599 100644 --- a/launcher/minecraft/mod/ResourcePackFolderModel.h +++ b/launcher/minecraft/mod/ResourcePackFolderModel.h @@ -4,28 +4,19 @@ #include "ResourcePack.h" -class ResourcePackFolderModel : public ResourceFolderModel -{ +class ResourcePackFolderModel : public ResourceFolderModel { Q_OBJECT -public: - enum Columns - { - ActiveColumn = 0, - ImageColumn, - NameColumn, - PackFormatColumn, - DateColumn, - NUM_COLUMNS - }; - - explicit ResourcePackFolderModel(const QString &dir, BaseInstance* instance); + public: + enum Columns { ActiveColumn = 0, ImageColumn, NameColumn, PackFormatColumn, DateColumn, NUM_COLUMNS }; + + explicit ResourcePackFolderModel(const QString& dir, BaseInstance* instance); virtual QString id() const override { return "resourcepacks"; } - [[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + [[nodiscard]] QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; [[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; - [[nodiscard]] int columnCount(const QModelIndex &parent) const override; + [[nodiscard]] int columnCount(const QModelIndex& parent) const override; [[nodiscard]] Task* createUpdateTask() override; [[nodiscard]] Task* createParseTask(Resource&) override; diff --git a/launcher/minecraft/mod/ShaderPackFolderModel.h b/launcher/minecraft/mod/ShaderPackFolderModel.h index f8249962..44ed37a4 100644 --- a/launcher/minecraft/mod/ShaderPackFolderModel.h +++ b/launcher/minecraft/mod/ShaderPackFolderModel.h @@ -6,9 +6,7 @@ class ShaderPackFolderModel : public ResourceFolderModel { Q_OBJECT public: - explicit ShaderPackFolderModel(const QString& dir, BaseInstance* instance) - : ResourceFolderModel(QDir(dir), instance) - {} - + explicit ShaderPackFolderModel(const QString& dir, BaseInstance* instance) : ResourceFolderModel(QDir(dir), instance) {} + virtual QString id() const override { return "shaderpacks"; } }; diff --git a/launcher/minecraft/mod/TexturePack.cpp b/launcher/minecraft/mod/TexturePack.cpp index c7a50a97..fbc716c4 100644 --- a/launcher/minecraft/mod/TexturePack.cpp +++ b/launcher/minecraft/mod/TexturePack.cpp @@ -44,7 +44,7 @@ void TexturePack::setImage(QImage new_image) const PixmapCache::remove(m_pack_image_cache_key.key); // scale the image to avoid flooding the pixmapcache - auto pixmap = QPixmap::fromImage(new_image.scaled({64, 64}, Qt::AspectRatioMode::KeepAspectRatioByExpanding)); + auto pixmap = QPixmap::fromImage(new_image.scaled({ 64, 64 }, Qt::AspectRatioMode::KeepAspectRatioByExpanding)); m_pack_image_cache_key.key = PixmapCache::insert(pixmap); m_pack_image_cache_key.was_ever_used = true; diff --git a/launcher/minecraft/mod/TexturePackFolderModel.cpp b/launcher/minecraft/mod/TexturePackFolderModel.cpp index 531a7023..869fbe2e 100644 --- a/launcher/minecraft/mod/TexturePackFolderModel.cpp +++ b/launcher/minecraft/mod/TexturePackFolderModel.cpp @@ -42,14 +42,13 @@ #include "minecraft/mod/tasks/BasicFolderLoadTask.h" #include "minecraft/mod/tasks/LocalTexturePackParseTask.h" -TexturePackFolderModel::TexturePackFolderModel(const QString& dir, BaseInstance* instance) - : ResourceFolderModel(QDir(dir), instance) +TexturePackFolderModel::TexturePackFolderModel(const QString& dir, BaseInstance* instance) : ResourceFolderModel(QDir(dir), instance) { m_column_names = QStringList({ "Enable", "Image", "Name", "Last Modified" }); m_column_names_translated = QStringList({ tr("Enable"), tr("Image"), tr("Name"), tr("Last Modified") }); m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::NAME, SortType::DATE }; - m_column_resize_modes = { QHeaderView::ResizeToContents, QHeaderView::Interactive, QHeaderView::Stretch, QHeaderView::ResizeToContents}; - + m_column_resize_modes = { QHeaderView::ResizeToContents, QHeaderView::Interactive, QHeaderView::Stretch, + QHeaderView::ResizeToContents }; } Task* TexturePackFolderModel::createUpdateTask() @@ -62,7 +61,6 @@ Task* TexturePackFolderModel::createParseTask(Resource& resource) return new LocalTexturePackParseTask(m_next_resolution_ticket, static_cast<TexturePack&>(resource)); } - QVariant TexturePackFolderModel::data(const QModelIndex& index, int role) const { if (!validateIndex(index)) @@ -85,28 +83,29 @@ QVariant TexturePackFolderModel::data(const QModelIndex& index, int role) const if (column == NameColumn) { if (at(row)->isSymLinkUnder(instDirPath())) { return m_resources[row]->internal_id() + - tr("\nWarning: This resource is symbolically linked from elsewhere. Editing it will also change the original." - "\nCanonical Path: %1") - .arg(at(row)->fileinfo().canonicalFilePath());; + tr("\nWarning: This resource is symbolically linked from elsewhere. Editing it will also change the original." + "\nCanonical Path: %1") + .arg(at(row)->fileinfo().canonicalFilePath()); + ; } if (at(row)->isMoreThanOneHardLink()) { return m_resources[row]->internal_id() + - tr("\nWarning: This resource is hard linked elsewhere. Editing it will also change the original."); + tr("\nWarning: This resource is hard linked elsewhere. Editing it will also change the original."); } } - + return m_resources[row]->internal_id(); case Qt::DecorationRole: { if (column == NameColumn && (at(row)->isSymLinkUnder(instDirPath()) || at(row)->isMoreThanOneHardLink())) return APPLICATION->getThemedIcon("status-yellow"); if (column == ImageColumn) { - return at(row)->image({32, 32}, Qt::AspectRatioMode::KeepAspectRatioByExpanding); + return at(row)->image({ 32, 32 }, Qt::AspectRatioMode::KeepAspectRatioByExpanding); } return {}; } case Qt::CheckStateRole: if (column == ActiveColumn) { - return m_resources[row]->enabled() ? Qt::Checked : Qt::Unchecked; + return m_resources[row]->enabled() ? Qt::Checked : Qt::Unchecked; } return {}; default: @@ -153,4 +152,3 @@ int TexturePackFolderModel::columnCount(const QModelIndex& parent) const { return parent.isValid() ? 0 : NUM_COLUMNS; } - diff --git a/launcher/minecraft/mod/TexturePackFolderModel.h b/launcher/minecraft/mod/TexturePackFolderModel.h index 71a8bdd1..ccc634da 100644 --- a/launcher/minecraft/mod/TexturePackFolderModel.h +++ b/launcher/minecraft/mod/TexturePackFolderModel.h @@ -40,31 +40,22 @@ #include "TexturePack.h" -class TexturePackFolderModel : public ResourceFolderModel -{ +class TexturePackFolderModel : public ResourceFolderModel { Q_OBJECT -public: + public: + enum Columns { ActiveColumn = 0, ImageColumn, NameColumn, DateColumn, NUM_COLUMNS }; - enum Columns - { - ActiveColumn = 0, - ImageColumn, - NameColumn, - DateColumn, - NUM_COLUMNS - }; - - explicit TexturePackFolderModel(const QString &dir, std::shared_ptr<const BaseInstance> instance); + explicit TexturePackFolderModel(const QString& dir, std::shared_ptr<const BaseInstance> instance); virtual QString id() const override { return "texturepacks"; } - [[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + [[nodiscard]] QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; [[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; - [[nodiscard]] int columnCount(const QModelIndex &parent) const override; + [[nodiscard]] int columnCount(const QModelIndex& parent) const override; - explicit TexturePackFolderModel(const QString &dir, BaseInstance* instance); + explicit TexturePackFolderModel(const QString& dir, BaseInstance* instance); [[nodiscard]] Task* createUpdateTask() override; [[nodiscard]] Task* createParseTask(Resource&) override; diff --git a/launcher/minecraft/mod/tasks/BasicFolderLoadTask.h b/launcher/minecraft/mod/tasks/BasicFolderLoadTask.h index 3ee7e2e0..23a2b649 100644 --- a/launcher/minecraft/mod/tasks/BasicFolderLoadTask.h +++ b/launcher/minecraft/mod/tasks/BasicFolderLoadTask.h @@ -26,12 +26,14 @@ class BasicFolderLoadTask : public Task { public: BasicFolderLoadTask(QDir dir) : Task(nullptr, false), m_dir(dir), m_result(new Result), m_thread_to_spawn_into(thread()) { - m_create_func = [](QFileInfo const& entry) -> Resource::Ptr { - return makeShared<Resource>(entry); - }; + m_create_func = [](QFileInfo const& entry) -> Resource::Ptr { return makeShared<Resource>(entry); }; } BasicFolderLoadTask(QDir dir, std::function<Resource::Ptr(QFileInfo const&)> create_function) - : Task(nullptr, false), m_dir(dir), m_result(new Result), m_create_func(std::move(create_function)), m_thread_to_spawn_into(thread()) + : Task(nullptr, false) + , m_dir(dir) + , m_result(new Result) + , m_create_func(std::move(create_function)) + , m_thread_to_spawn_into(thread()) {} [[nodiscard]] bool canAbort() const override { return true; } @@ -59,7 +61,7 @@ class BasicFolderLoadTask : public Task { emitSucceeded(); } -private: + private: QDir m_dir; ResultPtr m_result; diff --git a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp index 60389753..75bb6d25 100644 --- a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp @@ -181,7 +181,7 @@ ModDetails ReadMCModTOML(QByteArray contents) QString license = ""; if (auto licenseDatum = tomlData["license"].as_string()) { license = QString::fromStdString(licenseDatum->get()); - } else if (auto licenseDatum =(*modsTable)["license"].as_string()) { + } else if (auto licenseDatum = (*modsTable)["license"].as_string()) { license = QString::fromStdString(licenseDatum->get()); } if (!license.isEmpty()) @@ -190,7 +190,7 @@ ModDetails ReadMCModTOML(QByteArray contents) QString logoFile = ""; if (auto logoFileDatum = tomlData["logoFile"].as_string()) { logoFile = QString::fromStdString(logoFileDatum->get()); - } else if (auto logoFileDatum =(*modsTable)["logoFile"].as_string()) { + } else if (auto logoFileDatum = (*modsTable)["logoFile"].as_string()) { logoFile = QString::fromStdString(logoFileDatum->get()); } details.icon_file = logoFile; @@ -271,7 +271,7 @@ ModDetails ReadFabricModInfo(QByteArray contents) if (largest > 0) { auto key = QString::number(largest) + "x" + QString::number(largest); details.icon_file = obj.value(key).toString(); - } else { // parsing the sizes failed + } else { // parsing the sizes failed // take the first for (auto i : obj) { details.icon_file = i.toString(); @@ -358,7 +358,7 @@ ModDetails ReadQuiltModInfo(QByteArray contents) if (largest > 0) { auto key = QString::number(largest) + "x" + QString::number(largest); details.icon_file = obj.value(key).toString(); - } else { // parsing the sizes failed + } else { // parsing the sizes failed // take the first for (auto i : obj) { details.icon_file = i.toString(); @@ -658,7 +658,8 @@ bool processIconPNG(const Mod& mod, QByteArray&& raw_data) return true; } -bool loadIconFile(const Mod& mod) { +bool loadIconFile(const Mod& mod) +{ if (mod.iconPath().isEmpty()) { qWarning() << "No Iconfile set, be sure to parse the mod first"; return false; @@ -670,15 +671,14 @@ bool loadIconFile(const Mod& mod) { }; switch (mod.type()) { - case ResourceType::FOLDER: - { + case ResourceType::FOLDER: { QFileInfo icon_info(FS::PathCombine(mod.fileinfo().filePath(), mod.iconPath())); if (icon_info.exists() && icon_info.isFile()) { QFile icon(icon_info.filePath()); if (!icon.open(QIODevice::ReadOnly)) return false; auto data = icon.readAll(); - + bool icon_result = ModUtils::processIconPNG(mod, std::move(data)); icon.close(); @@ -688,8 +688,7 @@ bool loadIconFile(const Mod& mod) { } } } - case ResourceType::ZIPFILE: - { + case ResourceType::ZIPFILE: { QuaZip zip(mod.fileinfo().filePath()); if (!zip.open(QuaZip::mdUnzip)) return false; @@ -715,9 +714,8 @@ bool loadIconFile(const Mod& mod) { return png_invalid(); // could not set icon as current file. } } - case ResourceType::LITEMOD: - { - return false; // can lightmods even have icons? + case ResourceType::LITEMOD: { + return false; // can lightmods even have icons? } default: qWarning() << "Invalid type for mod, can not load icon."; diff --git a/launcher/minecraft/mod/tasks/LocalModUpdateTask.h b/launcher/minecraft/mod/tasks/LocalModUpdateTask.h index 1d2f06a6..31f919b8 100644 --- a/launcher/minecraft/mod/tasks/LocalModUpdateTask.h +++ b/launcher/minecraft/mod/tasks/LocalModUpdateTask.h @@ -1,20 +1,20 @@ // SPDX-License-Identifier: GPL-3.0-only /* -* PolyMC - Minecraft Launcher -* Copyright (c) 2022 flowln <flowlnlnln@gmail.com> -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, version 3. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ + * PolyMC - Minecraft Launcher + * Copyright (c) 2022 flowln <flowlnlnln@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ #pragma once diff --git a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp index a67c56a8..7440e6aa 100644 --- a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp @@ -207,15 +207,14 @@ bool processPackPNG(const ResourcePack& pack, QByteArray&& raw_data) } bool processPackPNG(const ResourcePack& pack) -{ +{ auto png_invalid = [&pack]() { qWarning() << "Resource pack at" << pack.fileinfo().filePath() << "does not have a valid pack.png"; return false; }; switch (pack.type()) { - case ResourceType::FOLDER: - { + case ResourceType::FOLDER: { QFileInfo image_file_info(FS::PathCombine(pack.fileinfo().filePath(), "pack.png")); if (image_file_info.exists() && image_file_info.isFile()) { QFile pack_png_file(image_file_info.filePath()); @@ -234,8 +233,7 @@ bool processPackPNG(const ResourcePack& pack) return png_invalid(); // pack.png does not exists or is not a valid file. } } - case ResourceType::ZIPFILE: - { + case ResourceType::ZIPFILE: { Q_ASSERT(pack.type() == ResourceType::ZIPFILE); QuaZip zip(pack.fileinfo().filePath()); diff --git a/launcher/minecraft/mod/tasks/LocalResourceParse.cpp b/launcher/minecraft/mod/tasks/LocalResourceParse.cpp index 0894049c..d5a09083 100644 --- a/launcher/minecraft/mod/tasks/LocalResourceParse.cpp +++ b/launcher/minecraft/mod/tasks/LocalResourceParse.cpp @@ -19,7 +19,7 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -#include <QObject> +#include <QObject> #include "LocalResourceParse.h" @@ -30,19 +30,17 @@ #include "LocalTexturePackParseTask.h" #include "LocalWorldSaveParseTask.h" - -static const QMap<PackedResourceType, QString> s_packed_type_names = { - {PackedResourceType::ResourcePack, QObject::tr("resource pack")}, - {PackedResourceType::TexturePack, QObject::tr("texture pack")}, - {PackedResourceType::DataPack, QObject::tr("data pack")}, - {PackedResourceType::ShaderPack, QObject::tr("shader pack")}, - {PackedResourceType::WorldSave, QObject::tr("world save")}, - {PackedResourceType::Mod , QObject::tr("mod")}, - {PackedResourceType::UNKNOWN, QObject::tr("unknown")} -}; +static const QMap<PackedResourceType, QString> s_packed_type_names = { { PackedResourceType::ResourcePack, QObject::tr("resource pack") }, + { PackedResourceType::TexturePack, QObject::tr("texture pack") }, + { PackedResourceType::DataPack, QObject::tr("data pack") }, + { PackedResourceType::ShaderPack, QObject::tr("shader pack") }, + { PackedResourceType::WorldSave, QObject::tr("world save") }, + { PackedResourceType::Mod, QObject::tr("mod") }, + { PackedResourceType::UNKNOWN, QObject::tr("unknown") } }; namespace ResourceUtils { -PackedResourceType identify(QFileInfo file){ +PackedResourceType identify(QFileInfo file) +{ if (file.exists() && file.isFile()) { if (ModUtils::validate(file)) { // mods can contain resource and data packs so they must be tested first @@ -64,7 +62,7 @@ PackedResourceType identify(QFileInfo file){ qDebug() << file.fileName() << "is a shader pack"; return PackedResourceType::ShaderPack; } else { - qDebug() << "Can't Identify" << file.fileName() ; + qDebug() << "Can't Identify" << file.fileName(); } } else { qDebug() << "Can't find" << file.absolutePath(); @@ -72,8 +70,9 @@ PackedResourceType identify(QFileInfo file){ return PackedResourceType::UNKNOWN; } -QString getPackedTypeName(PackedResourceType type) { +QString getPackedTypeName(PackedResourceType type) +{ return s_packed_type_names.constFind(type).value(); } -} +} // namespace ResourceUtils diff --git a/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp index a72e8115..817b0ea9 100644 --- a/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalTexturePackParseTask.cpp @@ -161,15 +161,14 @@ bool processPackPNG(const TexturePack& pack, QByteArray&& raw_data) } bool processPackPNG(const TexturePack& pack) -{ +{ auto png_invalid = [&pack]() { qWarning() << "Texture pack at" << pack.fileinfo().filePath() << "does not have a valid pack.png"; return false; }; switch (pack.type()) { - case ResourceType::FOLDER: - { + case ResourceType::FOLDER: { QFileInfo image_file_info(FS::PathCombine(pack.fileinfo().filePath(), "pack.png")); if (image_file_info.exists() && image_file_info.isFile()) { QFile pack_png_file(image_file_info.filePath()); @@ -188,8 +187,7 @@ bool processPackPNG(const TexturePack& pack) return png_invalid(); // pack.png does not exists or is not a valid file. } } - case ResourceType::ZIPFILE: - { + case ResourceType::ZIPFILE: { Q_ASSERT(pack.type() == ResourceType::ZIPFILE); QuaZip zip(pack.fileinfo().filePath()); @@ -232,8 +230,7 @@ bool validate(QFileInfo file) } // namespace TexturePackUtils -LocalTexturePackParseTask::LocalTexturePackParseTask(int token, TexturePack& rp) - : Task(nullptr, false), m_token(token), m_texture_pack(rp) +LocalTexturePackParseTask::LocalTexturePackParseTask(int token, TexturePack& rp) : Task(nullptr, false), m_token(token), m_texture_pack(rp) {} bool LocalTexturePackParseTask::abort() diff --git a/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.cpp b/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.cpp index cbc8f8ce..9d564ddb 100644 --- a/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.cpp @@ -50,8 +50,8 @@ bool process(WorldSave& pack, ProcessingLevel level) /// @param dir the path to check /// @param saves used in recursive call if a "saves" dir was found /// @return std::tuple of ( -/// bool <found level.dat>, -/// QString <name of folder containing level.dat>, +/// bool <found level.dat>, +/// QString <name of folder containing level.dat>, /// bool <saves folder found> /// ) static std::tuple<bool, QString, bool> contains_level_dat(QDir dir, bool saves = false) @@ -101,8 +101,8 @@ bool processFolder(WorldSave& save, ProcessingLevel level) /// @brief checks a folder structure to see if it contains a level.dat /// @param zip the zip file to check /// @return std::tuple of ( -/// bool <found level.dat>, -/// QString <name of folder containing level.dat>, +/// bool <found level.dat>, +/// QString <name of folder containing level.dat>, /// bool <saves folder found> /// ) static std::tuple<bool, QString, bool> contains_level_dat(QuaZip& zip) diff --git a/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.h b/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.h index 9dcdca2b..12f677b0 100644 --- a/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.h +++ b/launcher/minecraft/mod/tasks/LocalWorldSaveParseTask.h @@ -39,7 +39,7 @@ bool processFolder(WorldSave& pack, ProcessingLevel level = ProcessingLevel::Ful bool validate(QFileInfo file); -} // namespace WorldSaveUtils +} // namespace WorldSaveUtils class LocalWorldSaveParseTask : public Task { Q_OBJECT diff --git a/launcher/minecraft/mod/tasks/ModFolderLoadTask.cpp b/launcher/minecraft/mod/tasks/ModFolderLoadTask.cpp index ef353c70..4a19a8eb 100644 --- a/launcher/minecraft/mod/tasks/ModFolderLoadTask.cpp +++ b/launcher/minecraft/mod/tasks/ModFolderLoadTask.cpp @@ -1,38 +1,38 @@ // SPDX-License-Identifier: GPL-3.0-only /* -* PolyMC - Minecraft Launcher -* Copyright (c) 2022 flowln <flowlnlnln@gmail.com> -* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, version 3. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <https://www.gnu.org/licenses/>. -* -* This file incorporates work covered by the following copyright and -* permission notice: -* -* Copyright 2013-2021 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. -*/ + * PolyMC - Minecraft Launcher + * Copyright (c) 2022 flowln <flowlnlnln@gmail.com> + * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 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 "ModFolderLoadTask.h" @@ -70,13 +70,11 @@ void ModFolderLoadTask::executeTask() m_result->mods[mod->internal_id()]->setStatus(ModStatus::Installed); // Delete the object we just created, since a valid one is already in the mods list. delete mod; - } - else { + } else { m_result->mods[mod->internal_id()].reset(std::move(mod)); m_result->mods[mod->internal_id()]->setStatus(ModStatus::NoMetadata); } - } - else { + } else { QString chopped_id = mod->internal_id().chopped(9); if (m_result->mods.contains(chopped_id)) { m_result->mods[mod->internal_id()].reset(std::move(mod)); @@ -88,8 +86,7 @@ void ModFolderLoadTask::executeTask() m_result->mods[mod->internal_id()]->setStatus(ModStatus::Installed); m_result->mods.remove(chopped_id); } - } - else { + } else { m_result->mods[mod->internal_id()].reset(std::move(mod)); m_result->mods[mod->internal_id()]->setStatus(ModStatus::NoMetadata); } @@ -124,7 +121,7 @@ void ModFolderLoadTask::getFromMetadata() for (auto entry : m_index_dir.entryList(QDir::Files)) { auto metadata = Metadata::get(m_index_dir, entry); - if(!metadata.isValid()){ + if (!metadata.isValid()) { return; } diff --git a/launcher/minecraft/mod/tasks/ModFolderLoadTask.h b/launcher/minecraft/mod/tasks/ModFolderLoadTask.h index af5f58a5..7ce13cfa 100644 --- a/launcher/minecraft/mod/tasks/ModFolderLoadTask.h +++ b/launcher/minecraft/mod/tasks/ModFolderLoadTask.h @@ -1,38 +1,38 @@ // SPDX-License-Identifier: GPL-3.0-only /* -* PolyMC - Minecraft Launcher -* Copyright (c) 2022 flowln <flowlnlnln@gmail.com> -* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, version 3. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <https://www.gnu.org/licenses/>. -* -* This file incorporates work covered by the following copyright and -* permission notice: -* -* Copyright 2013-2021 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. -*/ + * PolyMC - Minecraft Launcher + * Copyright (c) 2022 flowln <flowlnlnln@gmail.com> + * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 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 @@ -44,19 +44,16 @@ #include "minecraft/mod/Mod.h" #include "tasks/Task.h" -class ModFolderLoadTask : public Task -{ +class ModFolderLoadTask : public Task { Q_OBJECT -public: + public: struct Result { QMap<QString, Mod::Ptr> mods; }; using ResultPtr = std::shared_ptr<Result>; - ResultPtr result() const { - return m_result; - } + ResultPtr result() const { return m_result; } -public: + public: ModFolderLoadTask(QDir mods_dir, QDir index_dir, bool is_indexed, bool clean_orphan = false); [[nodiscard]] bool canAbort() const override { return true; } @@ -66,13 +63,12 @@ public: return true; } - void executeTask() override; -private: + private: void getFromMetadata(); -private: + private: QDir m_mods_dir, m_index_dir; bool m_is_indexed; bool m_clean_orphan; diff --git a/launcher/minecraft/services/CapeChange.cpp b/launcher/minecraft/services/CapeChange.cpp index 1d5ea36d..cb6ed1a4 100644 --- a/launcher/minecraft/services/CapeChange.cpp +++ b/launcher/minecraft/services/CapeChange.cpp @@ -35,27 +35,25 @@ #include "CapeChange.h" -#include <QNetworkRequest> #include <QHttpMultiPart> +#include <QNetworkRequest> #include "Application.h" -CapeChange::CapeChange(QObject *parent, QString token, QString cape) - : Task(parent), m_capeId(cape), m_token(token) -{ -} +CapeChange::CapeChange(QObject* parent, QString token, QString cape) : Task(parent), m_capeId(cape), m_token(token) {} -void CapeChange::setCape(QString& cape) { +void CapeChange::setCape(QString& cape) +{ QNetworkRequest request(QUrl("https://api.minecraftservices.com/minecraft/profile/capes/active")); auto requestString = QString("{\"capeId\":\"%1\"}").arg(m_capeId); request.setRawHeader("Authorization", QString("Bearer %1").arg(m_token).toLocal8Bit()); - QNetworkReply *rep = APPLICATION->network()->put(request, requestString.toUtf8()); + QNetworkReply* rep = APPLICATION->network()->put(request, requestString.toUtf8()); setStatus(tr("Equipping cape")); m_reply = shared_qobject_ptr<QNetworkReply>(rep); connect(rep, &QNetworkReply::uploadProgress, this, &CapeChange::setProgress); -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15 +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15 connect(rep, &QNetworkReply::errorOccurred, this, &CapeChange::downloadError); #else connect(rep, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), this, &CapeChange::downloadError); @@ -64,17 +62,18 @@ void CapeChange::setCape(QString& cape) { connect(rep, &QNetworkReply::finished, this, &CapeChange::downloadFinished); } -void CapeChange::clearCape() { +void CapeChange::clearCape() +{ QNetworkRequest request(QUrl("https://api.minecraftservices.com/minecraft/profile/capes/active")); auto requestString = QString("{\"capeId\":\"%1\"}").arg(m_capeId); request.setRawHeader("Authorization", QString("Bearer %1").arg(m_token).toLocal8Bit()); - QNetworkReply *rep = APPLICATION->network()->deleteResource(request); + QNetworkReply* rep = APPLICATION->network()->deleteResource(request); setStatus(tr("Removing cape")); m_reply = shared_qobject_ptr<QNetworkReply>(rep); connect(rep, &QNetworkReply::uploadProgress, this, &CapeChange::setProgress); -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15 +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15 connect(rep, &QNetworkReply::errorOccurred, this, &CapeChange::downloadError); #else connect(rep, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), this, &CapeChange::downloadError); @@ -83,13 +82,11 @@ void CapeChange::clearCape() { connect(rep, &QNetworkReply::finished, this, &CapeChange::downloadFinished); } - void CapeChange::executeTask() { - if(m_capeId.isEmpty()) { + if (m_capeId.isEmpty()) { clearCape(); - } - else { + } else { setCape(m_capeId); } } @@ -115,8 +112,7 @@ void CapeChange::sslErrors(const QList<QSslError>& errors) void CapeChange::downloadFinished() { // if the download failed - if (m_reply->error() != QNetworkReply::NetworkError::NoError) - { + if (m_reply->error() != QNetworkReply::NetworkError::NoError) { emitFailed(QString("Network error: %1").arg(m_reply->errorString())); m_reply.reset(); return; diff --git a/launcher/minecraft/services/CapeChange.h b/launcher/minecraft/services/CapeChange.h index 38069f90..d0c893c4 100644 --- a/launcher/minecraft/services/CapeChange.h +++ b/launcher/minecraft/services/CapeChange.h @@ -3,31 +3,29 @@ #include <QFile> #include <QtNetwork/QtNetwork> #include <memory> -#include "tasks/Task.h" #include "QObjectPtr.h" +#include "tasks/Task.h" -class CapeChange : public Task -{ +class CapeChange : public Task { Q_OBJECT -public: - CapeChange(QObject *parent, QString token, QString capeId); + public: + CapeChange(QObject* parent, QString token, QString capeId); virtual ~CapeChange() {} -private: - void setCape(QString & cape); + private: + void setCape(QString& cape); void clearCape(); -private: + private: QString m_capeId; QString m_token; shared_qobject_ptr<QNetworkReply> m_reply; -protected: + protected: virtual void executeTask(); -public slots: + public slots: void downloadError(QNetworkReply::NetworkError); void sslErrors(const QList<QSslError>& errors); void downloadFinished(); }; - diff --git a/launcher/minecraft/services/SkinDelete.cpp b/launcher/minecraft/services/SkinDelete.cpp index fbaaeacb..3737a5af 100644 --- a/launcher/minecraft/services/SkinDelete.cpp +++ b/launcher/minecraft/services/SkinDelete.cpp @@ -35,26 +35,23 @@ #include "SkinDelete.h" -#include <QNetworkRequest> #include <QHttpMultiPart> +#include <QNetworkRequest> #include "Application.h" -SkinDelete::SkinDelete(QObject *parent, QString token) - : Task(parent), m_token(token) -{ -} +SkinDelete::SkinDelete(QObject* parent, QString token) : Task(parent), m_token(token) {} void SkinDelete::executeTask() { QNetworkRequest request(QUrl("https://api.minecraftservices.com/minecraft/profile/skins/active")); request.setRawHeader("Authorization", QString("Bearer %1").arg(m_token).toLocal8Bit()); - QNetworkReply *rep = APPLICATION->network()->deleteResource(request); + QNetworkReply* rep = APPLICATION->network()->deleteResource(request); m_reply = shared_qobject_ptr<QNetworkReply>(rep); setStatus(tr("Deleting skin")); connect(rep, &QNetworkReply::uploadProgress, this, &SkinDelete::setProgress); -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15 +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15 connect(rep, &QNetworkReply::errorOccurred, this, &SkinDelete::downloadError); #else connect(rep, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), this, &SkinDelete::downloadError); @@ -84,12 +81,10 @@ void SkinDelete::sslErrors(const QList<QSslError>& errors) void SkinDelete::downloadFinished() { // if the download failed - if (m_reply->error() != QNetworkReply::NetworkError::NoError) - { + if (m_reply->error() != QNetworkReply::NetworkError::NoError) { emitFailed(QString("Network error: %1").arg(m_reply->errorString())); m_reply.reset(); return; } emitSucceeded(); } - diff --git a/launcher/minecraft/services/SkinDelete.h b/launcher/minecraft/services/SkinDelete.h index b9a1c9d3..d5b2e63d 100644 --- a/launcher/minecraft/services/SkinDelete.h +++ b/launcher/minecraft/services/SkinDelete.h @@ -6,21 +6,20 @@ typedef shared_qobject_ptr<class SkinDelete> SkinDeletePtr; -class SkinDelete : public Task -{ +class SkinDelete : public Task { Q_OBJECT -public: - SkinDelete(QObject *parent, QString token); + public: + SkinDelete(QObject* parent, QString token); virtual ~SkinDelete() = default; -private: + private: QString m_token; shared_qobject_ptr<QNetworkReply> m_reply; -protected: + protected: virtual void executeTask(); -public slots: + public slots: void downloadError(QNetworkReply::NetworkError); void sslErrors(const QList<QSslError>& errors); void downloadFinished(); diff --git a/launcher/minecraft/services/SkinUpload.cpp b/launcher/minecraft/services/SkinUpload.cpp index 711f8739..29960881 100644 --- a/launcher/minecraft/services/SkinUpload.cpp +++ b/launcher/minecraft/services/SkinUpload.cpp @@ -35,12 +35,13 @@ #include "SkinUpload.h" -#include <QNetworkRequest> #include <QHttpMultiPart> +#include <QNetworkRequest> #include "Application.h" -QByteArray getVariant(SkinUpload::Model model) { +QByteArray getVariant(SkinUpload::Model model) +{ switch (model) { default: qDebug() << "Unknown skin type!"; @@ -51,16 +52,15 @@ QByteArray getVariant(SkinUpload::Model model) { } } -SkinUpload::SkinUpload(QObject *parent, QString token, QByteArray skin, SkinUpload::Model model) +SkinUpload::SkinUpload(QObject* parent, QString token, QByteArray skin, SkinUpload::Model model) : Task(parent), m_model(model), m_skin(skin), m_token(token) -{ -} +{} void SkinUpload::executeTask() { QNetworkRequest request(QUrl("https://api.minecraftservices.com/minecraft/profile/skins")); request.setRawHeader("Authorization", QString("Bearer %1").arg(m_token).toLocal8Bit()); - QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); + QHttpMultiPart* multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); QHttpPart skin; skin.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/png")); @@ -74,12 +74,12 @@ void SkinUpload::executeTask() multiPart->append(skin); multiPart->append(model); - QNetworkReply *rep = APPLICATION->network()->post(request, multiPart); + QNetworkReply* rep = APPLICATION->network()->post(request, multiPart); m_reply = shared_qobject_ptr<QNetworkReply>(rep); setStatus(tr("Uploading skin")); connect(rep, &QNetworkReply::uploadProgress, this, &SkinUpload::setProgress); -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15 +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15 connect(rep, &QNetworkReply::errorOccurred, this, &SkinUpload::downloadError); #else connect(rep, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), this, &SkinUpload::downloadError); @@ -109,8 +109,7 @@ void SkinUpload::sslErrors(const QList<QSslError>& errors) void SkinUpload::downloadFinished() { // if the download failed - if (m_reply->error() != QNetworkReply::NetworkError::NoError) - { + if (m_reply->error() != QNetworkReply::NetworkError::NoError) { emitFailed(QString("Network error: %1").arg(m_reply->errorString())); m_reply.reset(); return; diff --git a/launcher/minecraft/services/SkinUpload.h b/launcher/minecraft/services/SkinUpload.h index ac8c5b36..5716aa99 100644 --- a/launcher/minecraft/services/SkinUpload.h +++ b/launcher/minecraft/services/SkinUpload.h @@ -7,29 +7,25 @@ typedef shared_qobject_ptr<class SkinUpload> SkinUploadPtr; -class SkinUpload : public Task -{ +class SkinUpload : public Task { Q_OBJECT -public: - enum Model - { - STEVE, - ALEX - }; + public: + enum Model { STEVE, ALEX }; // Note this class takes ownership of the file. - SkinUpload(QObject *parent, QString token, QByteArray skin, Model model = STEVE); + SkinUpload(QObject* parent, QString token, QByteArray skin, Model model = STEVE); virtual ~SkinUpload() {} -private: + private: Model m_model; QByteArray m_skin; QString m_token; shared_qobject_ptr<QNetworkReply> m_reply; -protected: + + protected: virtual void executeTask(); -public slots: + public slots: void downloadError(QNetworkReply::NetworkError); void sslErrors(const QList<QSslError>& errors); diff --git a/launcher/minecraft/update/AssetUpdateTask.cpp b/launcher/minecraft/update/AssetUpdateTask.cpp index fda85ba8..7043d987 100644 --- a/launcher/minecraft/update/AssetUpdateTask.cpp +++ b/launcher/minecraft/update/AssetUpdateTask.cpp @@ -1,20 +1,18 @@ #include "AssetUpdateTask.h" +#include "minecraft/AssetsUtils.h" #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" #include "net/ChecksumValidator.h" -#include "minecraft/AssetsUtils.h" #include "Application.h" -AssetUpdateTask::AssetUpdateTask(MinecraftInstance * inst) +AssetUpdateTask::AssetUpdateTask(MinecraftInstance* inst) { m_inst = inst; } -AssetUpdateTask::~AssetUpdateTask() -{ -} +AssetUpdateTask::~AssetUpdateTask() {} void AssetUpdateTask::executeTask() { @@ -24,10 +22,7 @@ void AssetUpdateTask::executeTask() auto assets = profile->getMinecraftAssets(); QUrl indexUrl = assets->url; QString localPath = assets->id + ".json"; - auto job = makeShared<NetJob>( - tr("Asset index for %1").arg(m_inst->name()), - APPLICATION->network() - ); + auto job = makeShared<NetJob>(tr("Asset index for %1").arg(m_inst->name()), APPLICATION->network()); auto metacache = APPLICATION->metacache(); auto entry = metacache->resolveEntry("asset_indexes", localPath); @@ -43,7 +38,7 @@ void AssetUpdateTask::executeTask() connect(downloadJob.get(), &NetJob::succeeded, this, &AssetUpdateTask::assetIndexFinished); connect(downloadJob.get(), &NetJob::failed, this, &AssetUpdateTask::assetIndexFailed); - connect(downloadJob.get(), &NetJob::aborted, this, [this]{ emitFailed(tr("Aborted")); }); + connect(downloadJob.get(), &NetJob::aborted, this, [this] { emitFailed(tr("Aborted")); }); connect(downloadJob.get(), &NetJob::progress, this, &AssetUpdateTask::progress); connect(downloadJob.get(), &NetJob::stepProgress, this, &AssetUpdateTask::propagateStepProgress); @@ -67,8 +62,7 @@ void AssetUpdateTask::assetIndexFinished() QString asset_fname = "assets/indexes/" + assets->id + ".json"; // FIXME: this looks like a job for a generic validator based on json schema? - if (!AssetsUtils::loadAssetsIndexJson(assets->id, asset_fname, index)) - { + if (!AssetsUtils::loadAssetsIndexJson(assets->id, asset_fname, index)) { auto metacache = APPLICATION->metacache(); auto entry = metacache->resolveEntry("asset_indexes", assets->id + ".json"); metacache->evictEntry(entry); @@ -76,13 +70,12 @@ void AssetUpdateTask::assetIndexFinished() } auto job = index.getDownloadJob(); - if(job) - { + if (job) { setStatus(tr("Getting the assets files from Mojang...")); downloadJob = job; connect(downloadJob.get(), &NetJob::succeeded, this, &AssetUpdateTask::emitSucceeded); connect(downloadJob.get(), &NetJob::failed, this, &AssetUpdateTask::assetsFailed); - connect(downloadJob.get(), &NetJob::aborted, this, [this]{ emitFailed(tr("Aborted")); }); + connect(downloadJob.get(), &NetJob::aborted, this, [this] { emitFailed(tr("Aborted")); }); connect(downloadJob.get(), &NetJob::progress, this, &AssetUpdateTask::progress); connect(downloadJob.get(), &NetJob::stepProgress, this, &AssetUpdateTask::propagateStepProgress); downloadJob->start(); @@ -104,12 +97,9 @@ void AssetUpdateTask::assetsFailed(QString reason) bool AssetUpdateTask::abort() { - if(downloadJob) - { + if (downloadJob) { return downloadJob->abort(); - } - else - { + } else { qWarning() << "Prematurely aborted AssetUpdateTask"; } return true; diff --git a/launcher/minecraft/update/AssetUpdateTask.h b/launcher/minecraft/update/AssetUpdateTask.h index 6d7356f3..6f053a54 100644 --- a/launcher/minecraft/update/AssetUpdateTask.h +++ b/launcher/minecraft/update/AssetUpdateTask.h @@ -1,28 +1,27 @@ #pragma once -#include "tasks/Task.h" #include "net/NetJob.h" +#include "tasks/Task.h" class MinecraftInstance; -class AssetUpdateTask : public Task -{ +class AssetUpdateTask : public Task { Q_OBJECT -public: - AssetUpdateTask(MinecraftInstance * inst); + public: + AssetUpdateTask(MinecraftInstance* inst); virtual ~AssetUpdateTask(); void executeTask() override; bool canAbort() const override; -private slots: + private slots: void assetIndexFinished(); void assetIndexFailed(QString reason); void assetsFailed(QString reason); -public slots: + public slots: bool abort() override; -private: - MinecraftInstance *m_inst; + private: + MinecraftInstance* m_inst; NetJob::Ptr downloadJob; }; diff --git a/launcher/minecraft/update/FMLLibrariesTask.cpp b/launcher/minecraft/update/FMLLibrariesTask.cpp index d9fa0595..a6ca2102 100644 --- a/launcher/minecraft/update/FMLLibrariesTask.cpp +++ b/launcher/minecraft/update/FMLLibrariesTask.cpp @@ -1,51 +1,47 @@ #include "FMLLibrariesTask.h" #include "FileSystem.h" -#include "minecraft/VersionFilterData.h" #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" +#include "minecraft/VersionFilterData.h" -#include "BuildConfig.h" #include "Application.h" +#include "BuildConfig.h" -FMLLibrariesTask::FMLLibrariesTask(MinecraftInstance * inst) +FMLLibrariesTask::FMLLibrariesTask(MinecraftInstance* inst) { m_inst = inst; } void FMLLibrariesTask::executeTask() { // Get the mod list - MinecraftInstance *inst = (MinecraftInstance *)m_inst; + MinecraftInstance* inst = (MinecraftInstance*)m_inst; auto components = inst->getPackProfile(); auto profile = components->getProfile(); - if (!profile->hasTrait("legacyFML")) - { + if (!profile->hasTrait("legacyFML")) { emitSucceeded(); return; } QString version = components->getComponentVersion("net.minecraft"); - auto &fmlLibsMapping = g_VersionFilterData.fmlLibsMapping; - if (!fmlLibsMapping.contains(version)) - { + auto& fmlLibsMapping = g_VersionFilterData.fmlLibsMapping; + if (!fmlLibsMapping.contains(version)) { emitSucceeded(); return; } - auto &libList = fmlLibsMapping[version]; + auto& libList = fmlLibsMapping[version]; // determine if we need some libs for FML or forge setStatus(tr("Checking for FML libraries...")); - if(!components->getComponent("net.minecraftforge")) - { + if (!components->getComponent("net.minecraftforge")) { emitSucceeded(); return; } // now check the lib folder inside the instance for files. - for (auto &lib : libList) - { + for (auto& lib : libList) { QFileInfo libInfo(FS::PathCombine(inst->libDir(), lib.filename)); if (libInfo.exists()) continue; @@ -53,8 +49,7 @@ void FMLLibrariesTask::executeTask() } // if everything is in place, there's nothing to do here... - if (fmlLibsToProcess.isEmpty()) - { + if (fmlLibsToProcess.isEmpty()) { emitSucceeded(); return; } @@ -64,8 +59,7 @@ void FMLLibrariesTask::executeTask() NetJob::Ptr dljob{ new NetJob("FML libraries", APPLICATION->network()) }; auto metacache = APPLICATION->metacache(); Net::Download::Options options = Net::Download::Option::MakeEternal; - for (auto &lib : fmlLibsToProcess) - { + for (auto& lib : fmlLibsToProcess) { auto entry = metacache->resolveEntry("fmllibs", lib.filename); QString urlString = BuildConfig.FMLLIBS_BASE_URL + lib.filename; dljob->addNetAction(Net::Download::makeCached(QUrl(urlString), entry, options)); @@ -73,7 +67,7 @@ void FMLLibrariesTask::executeTask() connect(dljob.get(), &NetJob::succeeded, this, &FMLLibrariesTask::fmllibsFinished); connect(dljob.get(), &NetJob::failed, this, &FMLLibrariesTask::fmllibsFailed); - connect(dljob.get(), &NetJob::aborted, this, [this]{ emitFailed(tr("Aborted")); }); + connect(dljob.get(), &NetJob::aborted, this, [this] { emitFailed(tr("Aborted")); }); connect(dljob.get(), &NetJob::progress, this, &FMLLibrariesTask::progress); connect(dljob.get(), &NetJob::stepProgress, this, &FMLLibrariesTask::propagateStepProgress); downloadJob.reset(dljob); @@ -88,24 +82,20 @@ bool FMLLibrariesTask::canAbort() const void FMLLibrariesTask::fmllibsFinished() { downloadJob.reset(); - if (!fmlLibsToProcess.isEmpty()) - { + if (!fmlLibsToProcess.isEmpty()) { setStatus(tr("Copying FML libraries into the instance...")); - MinecraftInstance *inst = (MinecraftInstance *)m_inst; + MinecraftInstance* inst = (MinecraftInstance*)m_inst; auto metacache = APPLICATION->metacache(); int index = 0; - for (auto &lib : fmlLibsToProcess) - { + for (auto& lib : fmlLibsToProcess) { progress(index, fmlLibsToProcess.size()); auto entry = metacache->resolveEntry("fmllibs", lib.filename); auto path = FS::PathCombine(inst->libDir(), lib.filename); - if (!FS::ensureFilePathExists(path)) - { + if (!FS::ensureFilePathExists(path)) { emitFailed(tr("Failed creating FML library folder inside the instance.")); return; } - if (!QFile::copy(entry->getFullPath(), FS::PathCombine(inst->libDir(), lib.filename))) - { + if (!QFile::copy(entry->getFullPath(), FS::PathCombine(inst->libDir(), lib.filename))) { emitFailed(tr("Failed copying Forge/FML library: %1.").arg(lib.filename)); return; } @@ -124,12 +114,9 @@ void FMLLibrariesTask::fmllibsFailed(QString reason) bool FMLLibrariesTask::abort() { - if(downloadJob) - { + if (downloadJob) { return downloadJob->abort(); - } - else - { + } else { qWarning() << "Prematurely aborted FMLLibrariesTask"; } return true; diff --git a/launcher/minecraft/update/FMLLibrariesTask.h b/launcher/minecraft/update/FMLLibrariesTask.h index 2e5ad83a..9d0102be 100644 --- a/launcher/minecraft/update/FMLLibrariesTask.h +++ b/launcher/minecraft/update/FMLLibrariesTask.h @@ -1,31 +1,29 @@ #pragma once -#include "tasks/Task.h" -#include "net/NetJob.h" #include "minecraft/VersionFilterData.h" +#include "net/NetJob.h" +#include "tasks/Task.h" class MinecraftInstance; -class FMLLibrariesTask : public Task -{ +class FMLLibrariesTask : public Task { Q_OBJECT -public: - FMLLibrariesTask(MinecraftInstance * inst); - virtual ~FMLLibrariesTask() {}; + public: + FMLLibrariesTask(MinecraftInstance* inst); + virtual ~FMLLibrariesTask(){}; void executeTask() override; bool canAbort() const override; -private slots: + private slots: void fmllibsFinished(); void fmllibsFailed(QString reason); -public slots: + public slots: bool abort() override; -private: - MinecraftInstance *m_inst; + private: + MinecraftInstance* m_inst; NetJob::Ptr downloadJob; QList<FMLlib> fmlLibsToProcess; }; - diff --git a/launcher/minecraft/update/FoldersTask.cpp b/launcher/minecraft/update/FoldersTask.cpp index b9ee9d98..3cbc309d 100644 --- a/launcher/minecraft/update/FoldersTask.cpp +++ b/launcher/minecraft/update/FoldersTask.cpp @@ -34,11 +34,10 @@ */ #include "FoldersTask.h" -#include "minecraft/MinecraftInstance.h" #include <QDir> +#include "minecraft/MinecraftInstance.h" -FoldersTask::FoldersTask(MinecraftInstance * inst) - :Task() +FoldersTask::FoldersTask(MinecraftInstance* inst) : Task() { m_inst = inst; } @@ -47,8 +46,7 @@ void FoldersTask::executeTask() { // Make directories QDir mcDir(m_inst->gameRoot()); - if (!mcDir.exists() && !mcDir.mkpath(".")) - { + if (!mcDir.exists() && !mcDir.mkpath(".")) { emitFailed(tr("Failed to create folder for Minecraft binaries.")); return; } diff --git a/launcher/minecraft/update/FoldersTask.h b/launcher/minecraft/update/FoldersTask.h index f6ed5e6d..2d2954b2 100644 --- a/launcher/minecraft/update/FoldersTask.h +++ b/launcher/minecraft/update/FoldersTask.h @@ -3,15 +3,14 @@ #include "tasks/Task.h" class MinecraftInstance; -class FoldersTask : public Task -{ +class FoldersTask : public Task { Q_OBJECT -public: - FoldersTask(MinecraftInstance * inst); - virtual ~FoldersTask() {}; + public: + FoldersTask(MinecraftInstance* inst); + virtual ~FoldersTask(){}; void executeTask() override; -private: - MinecraftInstance *m_inst; -}; + private: + MinecraftInstance* m_inst; +}; diff --git a/launcher/minecraft/update/LibrariesTask.cpp b/launcher/minecraft/update/LibrariesTask.cpp index 9d1c0295..1581b32e 100644 --- a/launcher/minecraft/update/LibrariesTask.cpp +++ b/launcher/minecraft/update/LibrariesTask.cpp @@ -5,7 +5,7 @@ #include "Application.h" -LibrariesTask::LibrariesTask(MinecraftInstance * inst) +LibrariesTask::LibrariesTask(MinecraftInstance* inst) { m_inst = inst; } @@ -14,7 +14,7 @@ void LibrariesTask::executeTask() { setStatus(tr("Downloading required library files...")); qDebug() << m_inst->name() << ": downloading libraries"; - MinecraftInstance *inst = (MinecraftInstance *)m_inst; + MinecraftInstance* inst = (MinecraftInstance*)m_inst; // Build a list of URLs that will need to be downloaded. auto components = inst->getPackProfile(); @@ -25,18 +25,14 @@ void LibrariesTask::executeTask() auto metacache = APPLICATION->metacache(); - auto processArtifactPool = [&](const QList<LibraryPtr> & pool, QStringList & errors, const QString & localPath) - { - for (auto lib : pool) - { - if(!lib) - { + auto processArtifactPool = [&](const QList<LibraryPtr>& pool, QStringList& errors, const QString& localPath) { + for (auto lib : pool) { + if (!lib) { emitFailed(tr("Null jar is specified in the metadata, aborting.")); return false; } auto dls = lib->getDownloads(inst->runtimeContext(), metacache.get(), errors, localPath); - for(auto dl : dls) - { + for (auto dl : dls) { downloadJob->addNetAction(dl); } } @@ -48,8 +44,7 @@ void LibrariesTask::executeTask() libArtifactPool.append(profile->getLibraries()); libArtifactPool.append(profile->getNativeLibraries()); libArtifactPool.append(profile->getMavenFiles()); - for (auto agent : profile->getAgents()) - { + for (auto agent : profile->getAgents()) { libArtifactPool.append(agent->library()); } libArtifactPool.append(profile->getMainJar()); @@ -58,17 +53,18 @@ void LibrariesTask::executeTask() QStringList failedLocalJarMods; processArtifactPool(profile->getJarMods(), failedLocalJarMods, inst->jarModsDir()); - if (!failedLocalJarMods.empty() || !failedLocalLibraries.empty()) - { + if (!failedLocalJarMods.empty() || !failedLocalLibraries.empty()) { downloadJob.reset(); QString failed_all = (failedLocalLibraries + failedLocalJarMods).join("\n"); - emitFailed(tr("Some artifacts marked as 'local' are missing their files:\n%1\n\nYou need to either add the files, or removed the packages that require them.\nYou'll have to correct this problem manually.").arg(failed_all)); + emitFailed(tr("Some artifacts marked as 'local' are missing their files:\n%1\n\nYou need to either add the files, or removed the " + "packages that require them.\nYou'll have to correct this problem manually.") + .arg(failed_all)); return; } connect(downloadJob.get(), &NetJob::succeeded, this, &LibrariesTask::emitSucceeded); connect(downloadJob.get(), &NetJob::failed, this, &LibrariesTask::jarlibFailed); - connect(downloadJob.get(), &NetJob::aborted, this, [this]{ emitFailed(tr("Aborted")); }); + connect(downloadJob.get(), &NetJob::aborted, this, [this] { emitFailed(tr("Aborted")); }); connect(downloadJob.get(), &NetJob::progress, this, &LibrariesTask::progress); connect(downloadJob.get(), &NetJob::stepProgress, this, &LibrariesTask::propagateStepProgress); @@ -87,12 +83,9 @@ void LibrariesTask::jarlibFailed(QString reason) bool LibrariesTask::abort() { - if(downloadJob) - { + if (downloadJob) { return downloadJob->abort(); - } - else - { + } else { qWarning() << "Prematurely aborted LibrariesTask"; } return true; diff --git a/launcher/minecraft/update/LibrariesTask.h b/launcher/minecraft/update/LibrariesTask.h index b966ad6c..c969e74d 100644 --- a/launcher/minecraft/update/LibrariesTask.h +++ b/launcher/minecraft/update/LibrariesTask.h @@ -1,26 +1,25 @@ #pragma once -#include "tasks/Task.h" #include "net/NetJob.h" +#include "tasks/Task.h" class MinecraftInstance; -class LibrariesTask : public Task -{ +class LibrariesTask : public Task { Q_OBJECT -public: - LibrariesTask(MinecraftInstance * inst); - virtual ~LibrariesTask() {}; + public: + LibrariesTask(MinecraftInstance* inst); + virtual ~LibrariesTask(){}; void executeTask() override; bool canAbort() const override; -private slots: + private slots: void jarlibFailed(QString reason); -public slots: + public slots: bool abort() override; -private: - MinecraftInstance *m_inst; + private: + MinecraftInstance* m_inst; NetJob::Ptr downloadJob; }; |