From 094ed0bc81562606e2eff151d12205b64c2c284e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Mon, 29 Mar 2021 21:51:28 +0200 Subject: [PATCH 1/6] NOISSUE fix build issue with QJsonValueRef on macOS 11 This will remove support for macOS 10.7 and 10.8, but their numbers in analytics are 0 --- api/logic/modplatform/flame/PackManifest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/logic/modplatform/flame/PackManifest.cpp b/api/logic/modplatform/flame/PackManifest.cpp index 1db0a161..b928fd16 100644 --- a/api/logic/modplatform/flame/PackManifest.cpp +++ b/api/logic/modplatform/flame/PackManifest.cpp @@ -21,7 +21,7 @@ static void loadMinecraftV1(Flame::Minecraft & m, QJsonObject & minecraft) // intended use is likely hardcoded in the 'Flame' client, the manifest says nothing m.libraries = Json::ensureString(minecraft, QString("libraries"), QString()); auto arr = Json::ensureArray(minecraft, "modLoaders", QJsonArray()); - for (const auto & item : arr) + for (QJsonValueRef item : arr) { auto obj = Json::requireObject(item); Flame::Modloader loader; @@ -38,7 +38,7 @@ static void loadManifestV1(Flame::Manifest & m, QJsonObject & manifest) m.version = Json::ensureString(manifest, QString("version"), QString()); m.author = Json::ensureString(manifest, QString("author"), "Anonymous Coward"); auto arr = Json::ensureArray(manifest, "files", QJsonArray()); - for (const auto & item : arr) + for (QJsonValueRef item : arr) { auto obj = Json::requireObject(item); Flame::File file; From fbe9d158754bcdd12aa8889639bdbac4c125f1c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Mon, 29 Mar 2021 22:03:52 +0200 Subject: [PATCH 2/6] NOISSUE fix it some more in different file --- api/logic/modplatform/modpacksch/FTBPackManifest.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/api/logic/modplatform/modpacksch/FTBPackManifest.cpp b/api/logic/modplatform/modpacksch/FTBPackManifest.cpp index 35626cb8..fd99d332 100644 --- a/api/logic/modplatform/modpacksch/FTBPackManifest.cpp +++ b/api/logic/modplatform/modpacksch/FTBPackManifest.cpp @@ -60,7 +60,7 @@ void ModpacksCH::loadModpack(ModpacksCH::Modpack & m, QJsonObject & obj) m.updated = Json::requireInteger(obj, "updated"); m.refreshed = Json::requireInteger(obj, "refreshed"); auto artArr = Json::requireArray(obj, "art"); - for (const auto & artRaw : artArr) + for (QJsonValueRef artRaw : artArr) { auto artObj = Json::requireObject(artRaw); ModpacksCH::Art art; @@ -68,7 +68,7 @@ void ModpacksCH::loadModpack(ModpacksCH::Modpack & m, QJsonObject & obj) m.art.append(art); } auto authorArr = Json::requireArray(obj, "authors"); - for (const auto & authorRaw : authorArr) + for (QJsonValueRef authorRaw : authorArr) { auto authorObj = Json::requireObject(authorRaw); ModpacksCH::Author author; @@ -76,7 +76,7 @@ void ModpacksCH::loadModpack(ModpacksCH::Modpack & m, QJsonObject & obj) m.authors.append(author); } auto versionArr = Json::requireArray(obj, "versions"); - for (const auto & versionRaw : versionArr) + for (QJsonValueRef versionRaw : versionArr) { auto versionObj = Json::requireObject(versionRaw); ModpacksCH::VersionInfo version; @@ -84,7 +84,7 @@ void ModpacksCH::loadModpack(ModpacksCH::Modpack & m, QJsonObject & obj) m.versions.append(version); } auto tagArr = Json::requireArray(obj, "tags"); - for (const auto & tagRaw : tagArr) + for (QJsonValueRef tagRaw : tagArr) { auto tagObj = Json::requireObject(tagRaw); ModpacksCH::Tag tag; @@ -132,7 +132,7 @@ void ModpacksCH::loadVersion(ModpacksCH::Version & m, QJsonObject & obj) auto specs = Json::requireObject(obj, "specs"); loadSpecs(m.specs, specs); auto targetArr = Json::requireArray(obj, "targets"); - for (const auto & targetRaw : targetArr) + for (QJsonValueRef targetRaw : targetArr) { auto versionObj = Json::requireObject(targetRaw); ModpacksCH::VersionTarget target; @@ -140,7 +140,7 @@ void ModpacksCH::loadVersion(ModpacksCH::Version & m, QJsonObject & obj) m.targets.append(target); } auto fileArr = Json::requireArray(obj, "files"); - for (const auto & fileRaw : fileArr) + for (QJsonValueRef fileRaw : fileArr) { auto fileObj = Json::requireObject(fileRaw); ModpacksCH::VersionFile file; From 7246d8a77906d421de4eada95d90843b1b94326b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Thu, 1 Apr 2021 03:50:28 +0200 Subject: [PATCH 3/6] NOISSUE improve GradleSpecifier and handle broken library names --- api/logic/minecraft/GradleSpecifier.h | 42 ++++++++++++-------- api/logic/minecraft/GradleSpecifier_test.cpp | 5 ++- api/logic/minecraft/Library.cpp | 8 ++-- api/logic/minecraft/Library_test.cpp | 3 +- api/logic/minecraft/MojangVersionFormat.cpp | 12 ++++-- api/logic/minecraft/MojangVersionFormat.h | 3 +- api/logic/minecraft/OneSixVersionFormat.cpp | 34 +++++++++------- api/logic/minecraft/OneSixVersionFormat.h | 9 +++-- 8 files changed, 68 insertions(+), 48 deletions(-) diff --git a/api/logic/minecraft/GradleSpecifier.h b/api/logic/minecraft/GradleSpecifier.h index 959325c6..60e0a726 100644 --- a/api/logic/minecraft/GradleSpecifier.h +++ b/api/logic/minecraft/GradleSpecifier.h @@ -18,32 +18,35 @@ struct GradleSpecifier { /* org.gradle.test.classifiers : service : 1.0 : jdk15 @ jar - DEBUG 0 "org.gradle.test.classifiers:service:1.0:jdk15@jar" - DEBUG 1 "org.gradle.test.classifiers" - DEBUG 2 "service" - DEBUG 3 "1.0" - DEBUG 4 ":jdk15" - DEBUG 5 "jdk15" - DEBUG 6 "@jar" - DEBUG 7 "jar" + 0 "org.gradle.test.classifiers:service:1.0:jdk15@jar" + 1 "org.gradle.test.classifiers" + 2 "service" + 3 "1.0" + 4 "jdk15" + 5 "jar" */ - QRegExp matcher("([^:@]+):([^:@]+):([^:@]+)" "(:([^:@]+))?" "(@([^:@]+))?"); + QRegExp matcher("([^:@]+):([^:@]+):([^:@]+)" "(?::([^:@]+))?" "(?:@([^:@]+))?"); m_valid = matcher.exactMatch(value); + if(!m_valid) { + m_invalidValue = value; + return *this; + } auto elements = matcher.capturedTexts(); m_groupId = elements[1]; m_artifactId = elements[2]; m_version = elements[3]; - m_classifier = elements[5]; - if(!elements[7].isEmpty()) + m_classifier = elements[4]; + if(!elements[5].isEmpty()) { - m_extension = elements[7]; + m_extension = elements[5]; } return *this; } - operator QString() const + QString serialize() const { - if(!m_valid) - return "INVALID"; + if(!m_valid) { + return m_invalidValue; + } QString retval = m_groupId + ":" + m_artifactId + ":" + m_version; if(!m_classifier.isEmpty()) { @@ -57,6 +60,9 @@ struct GradleSpecifier } QString getFileName() const { + if(!m_valid) { + return QString(); + } QString filename = m_artifactId + '-' + m_version; if(!m_classifier.isEmpty()) { @@ -67,8 +73,9 @@ struct GradleSpecifier } QString toPath(const QString & filenameOverride = QString()) const { - if(!m_valid) - return "INVALID"; + if(!m_valid) { + return QString(); + } QString filename; if(filenameOverride.isEmpty()) { @@ -134,6 +141,7 @@ struct GradleSpecifier return true; } private: + QString m_invalidValue; QString m_groupId; QString m_artifactId; QString m_version; diff --git a/api/logic/minecraft/GradleSpecifier_test.cpp b/api/logic/minecraft/GradleSpecifier_test.cpp index f49ec718..0900c9d8 100644 --- a/api/logic/minecraft/GradleSpecifier_test.cpp +++ b/api/logic/minecraft/GradleSpecifier_test.cpp @@ -31,7 +31,7 @@ slots: { QFETCH(QString, through); - QString converted = GradleSpecifier(through); + QString converted = GradleSpecifier(through).serialize(); QCOMPARE(converted, through); } @@ -68,7 +68,8 @@ slots: GradleSpecifier spec(input); QVERIFY(!spec.valid()); - QCOMPARE(spec.operator QString(), QString("INVALID")); + QCOMPARE(spec.serialize(), input); + QCOMPARE(spec.toPath(), QString()); } }; diff --git a/api/logic/minecraft/Library.cpp b/api/logic/minecraft/Library.cpp index b3c7657c..f2293679 100644 --- a/api/logic/minecraft/Library.cpp +++ b/api/logic/minecraft/Library.cpp @@ -94,13 +94,13 @@ QList< std::shared_ptr< NetAction > > Library::getDownloads( 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() << "storage:" << storage << "url:" << url; + qDebug() << "Checksummed Download for:" << rawName().serialize() << "storage:" << storage << "url:" << url; out.append(dl); } else { out.append(Net::Download::makeCached(url, entry, options)); - qDebug() << "Download for:" << rawName() << "storage:" << storage << "url:" << url; + qDebug() << "Download for:" << rawName().serialize() << "storage:" << storage << "url:" << url; } return true; }; @@ -145,7 +145,7 @@ QList< std::shared_ptr< NetAction > > Library::getDownloads( } else { - qDebug() << "Ignoring native library" << m_name << "because it has no classifier for current OS"; + qDebug() << "Ignoring native library" << m_name.serialize() << "because it has no classifier for current OS"; } } else @@ -157,7 +157,7 @@ QList< std::shared_ptr< NetAction > > Library::getDownloads( } else { - qDebug() << "Ignoring java library" << m_name << "because it has no artifact"; + qDebug() << "Ignoring java library" << m_name.serialize() << "because it has no artifact"; } } } diff --git a/api/logic/minecraft/Library_test.cpp b/api/logic/minecraft/Library_test.cpp index c3d6150d..75bb4db1 100644 --- a/api/logic/minecraft/Library_test.cpp +++ b/api/logic/minecraft/Library_test.cpp @@ -18,7 +18,8 @@ private: jsonFile.open(QIODevice::ReadOnly); auto data = jsonFile.readAll(); jsonFile.close(); - return MojangVersionFormat::libraryFromJson(QJsonDocument::fromJson(data).object(), file); + ProblemContainer problems; + return MojangVersionFormat::libraryFromJson(problems, QJsonDocument::fromJson(data).object(), file); } // get absolute path to expected storage, assuming default cache prefix QStringList getStorage(QString relative) diff --git a/api/logic/minecraft/MojangVersionFormat.cpp b/api/logic/minecraft/MojangVersionFormat.cpp index 33d3c54c..f9cb2228 100644 --- a/api/logic/minecraft/MojangVersionFormat.cpp +++ b/api/logic/minecraft/MojangVersionFormat.cpp @@ -220,7 +220,7 @@ VersionFilePtr MojangVersionFormat::versionFileFromJson(const QJsonDocument &doc { auto libObj = requireObject(libVal); - auto lib = MojangVersionFormat::libraryFromJson(libObj, filename); + auto lib = MojangVersionFormat::libraryFromJson(*out, libObj, filename); out->libraries.append(lib); } } @@ -283,14 +283,18 @@ QJsonDocument MojangVersionFormat::versionFileToJson(const VersionFilePtr &patch } } -LibraryPtr MojangVersionFormat::libraryFromJson(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")) { throw JSONValidationError(filename + "contains a library that doesn't have a 'name' field"); } - out->m_name = libObj.value("name").toString(); + auto rawName = libObj.value("name").toString(); + out->m_name = rawName; + 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")) @@ -333,7 +337,7 @@ LibraryPtr MojangVersionFormat::libraryFromJson(const QJsonObject &libObj, const QJsonObject MojangVersionFormat::libraryToJson(Library *library) { QJsonObject libRoot; - libRoot.insert("name", (QString)library->m_name); + libRoot.insert("name", library->m_name.serialize()); if (!library->m_repositoryURL.isEmpty()) { libRoot.insert("url", library->m_repositoryURL); diff --git a/api/logic/minecraft/MojangVersionFormat.h b/api/logic/minecraft/MojangVersionFormat.h index 76c529e9..2871dae4 100644 --- a/api/logic/minecraft/MojangVersionFormat.h +++ b/api/logic/minecraft/MojangVersionFormat.h @@ -3,6 +3,7 @@ #include #include #include +#include #include "multimc_logic_export.h" @@ -20,6 +21,6 @@ public: static QJsonDocument versionFileToJson(const VersionFilePtr &patch); // libraries - static LibraryPtr libraryFromJson(const QJsonObject &libObj, const QString &filename); + static LibraryPtr libraryFromJson(ProblemContainer & problems, const QJsonObject &libObj, const QString &filename); static QJsonObject libraryToJson(Library *library); }; diff --git a/api/logic/minecraft/OneSixVersionFormat.cpp b/api/logic/minecraft/OneSixVersionFormat.cpp index 7ac9e2db..d6aaa790 100644 --- a/api/logic/minecraft/OneSixVersionFormat.cpp +++ b/api/logic/minecraft/OneSixVersionFormat.cpp @@ -13,9 +13,9 @@ static void readString(const QJsonObject &root, const QString &key, QString &var } } -LibraryPtr OneSixVersionFormat::libraryFromJson(const QJsonObject &libObj, const QString &filename) +LibraryPtr OneSixVersionFormat::libraryFromJson(ProblemContainer & problems, const QJsonObject &libObj, const QString &filename) { - LibraryPtr out = MojangVersionFormat::libraryFromJson(libObj, filename); + LibraryPtr out = MojangVersionFormat::libraryFromJson(problems, libObj, filename); readString(libObj, "MMC-hint", out->m_hint); readString(libObj, "MMC-absulute_url", out->m_absoluteURL); readString(libObj, "MMC-absoluteUrl", out->m_absoluteURL); @@ -115,7 +115,7 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc { QJsonObject libObj = requireObject(libVal); // parse the jarmod - auto lib = OneSixVersionFormat::jarModFromJson(libObj, filename); + auto lib = OneSixVersionFormat::jarModFromJson(*out, libObj, filename); // and add to jar mods out->jarMods.append(lib); } @@ -126,7 +126,7 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc { QJsonObject libObj = requireObject(libVal); // parse the jarmod - auto lib = OneSixVersionFormat::plusJarModFromJson(libObj, filename, out->name); + auto lib = OneSixVersionFormat::plusJarModFromJson(*out, libObj, filename, out->name); // and add to jar mods out->jarMods.append(lib); } @@ -138,20 +138,20 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc { QJsonObject libObj = requireObject(libVal); // parse the jarmod - auto lib = OneSixVersionFormat::modFromJson(libObj, filename); + auto lib = OneSixVersionFormat::modFromJson(*out, libObj, filename); // and add to jar mods out->mods.append(lib); } } - auto readLibs = [&](const char * which, QList & out) + auto readLibs = [&](const char * which, QList & outList) { for (auto libVal : requireArray(root.value(which))) { QJsonObject libObj = requireObject(libVal); // parse the library - auto lib = libraryFromJson(libObj, filename); - out.append(lib); + auto lib = libraryFromJson(*out, libObj, filename); + outList.append(lib); } }; bool hasPlusLibs = root.contains("+libraries"); @@ -180,7 +180,7 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc if(root.contains("mainJar")) { QJsonObject libObj = requireObject(root, "mainJar"); - out->mainJar = libraryFromJson(libObj, filename); + out->mainJar = libraryFromJson(*out, libObj, filename); } // else reconstruct it from downloads and id ... if that's available else if(!out->minecraftVersion.isEmpty()) @@ -330,8 +330,12 @@ QJsonDocument OneSixVersionFormat::versionFileToJson(const VersionFilePtr &patch } } -LibraryPtr OneSixVersionFormat::plusJarModFromJson(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")) { @@ -366,9 +370,9 @@ LibraryPtr OneSixVersionFormat::plusJarModFromJson(const QJsonObject &libObj, co return out; } -LibraryPtr OneSixVersionFormat::jarModFromJson(const QJsonObject& libObj, const QString& filename) +LibraryPtr OneSixVersionFormat::jarModFromJson(ProblemContainer & problems, const QJsonObject& libObj, const QString& filename) { - return libraryFromJson(libObj, filename); + return libraryFromJson(problems, libObj, filename); } @@ -377,9 +381,9 @@ QJsonObject OneSixVersionFormat::jarModtoJson(Library *jarmod) return libraryToJson(jarmod); } -LibraryPtr OneSixVersionFormat::modFromJson(const QJsonObject& libObj, const QString& filename) +LibraryPtr OneSixVersionFormat::modFromJson(ProblemContainer & problems, const QJsonObject& libObj, const QString& filename) { - return libraryFromJson(libObj, filename); + return libraryFromJson(problems, libObj, filename); } QJsonObject OneSixVersionFormat::modtoJson(Library *jarmod) diff --git a/api/logic/minecraft/OneSixVersionFormat.h b/api/logic/minecraft/OneSixVersionFormat.h index 14ae385c..1a091d88 100644 --- a/api/logic/minecraft/OneSixVersionFormat.h +++ b/api/logic/minecraft/OneSixVersionFormat.h @@ -4,6 +4,7 @@ #include #include #include +#include class OneSixVersionFormat { @@ -13,17 +14,17 @@ public: static QJsonDocument versionFileToJson(const VersionFilePtr &patch); // libraries - static LibraryPtr libraryFromJson(const QJsonObject &libObj, const QString &filename); + 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(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(const QJsonObject &libObj, const QString &filename); + static LibraryPtr jarModFromJson(ProblemContainer & problems, const QJsonObject &libObj, const QString &filename); static QJsonObject jarModtoJson(Library * jarmod); // mods, also derived from libraries - static LibraryPtr modFromJson(const QJsonObject &libObj, const QString &filename); + static LibraryPtr modFromJson(ProblemContainer & problems, const QJsonObject &libObj, const QString &filename); static QJsonObject modtoJson(Library * jarmod); }; From e5804b1279cd0588d9434f298675ccd89fe21fc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 4 Apr 2021 21:19:49 +0200 Subject: [PATCH 4/6] NOISSUE add some logging to the system theme determination logic --- application/themes/SystemTheme.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/application/themes/SystemTheme.cpp b/application/themes/SystemTheme.cpp index 00b2300d..49b1afaa 100644 --- a/application/themes/SystemTheme.cpp +++ b/application/themes/SystemTheme.cpp @@ -6,16 +6,19 @@ SystemTheme::SystemTheme() { + qDebug() << "Determining System Theme..."; const auto & style = QApplication::style(); systemPalette = style->standardPalette(); QString lowerThemeName = style->objectName(); - qDebug() << systemTheme; + qDebug() << "System theme seems to be:" << lowerThemeName; QStringList styles = QStyleFactory::keys(); for(auto &st: styles) { + qDebug() << "Considering theme from theme factory:" << st.toLower(); if(st.toLower() == lowerThemeName) { systemTheme = st; + qDebug() << "System theme has been determined to be:" << systemTheme; return; } } From f03600244d25a7ccd9e47c9297b671056fa7f34e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n?= <62727185+Sebastian-byte@users.noreply.github.com> Date: Mon, 5 Apr 2021 19:37:31 -0500 Subject: [PATCH 5/6] Update Windows download link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 35df2edd..01a01b4c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ This software is not related to MultiMC developers and provided without any warranty. Please don't bomb MultiMC developers if something gets wrong using this launcher. ## Pre-built binaries (experimental as for now): -- Windows x64: https://drive.google.com/file/d/1ENazMSvJM0MLh7CnPEX90k1CYYLqV4f4/view?usp=sharing +- Windows x64: https://drive.google.com/file/d/1XRSmNaDgZA6xL4UONxGMVagrEtW7IsLk/view?usp=sharing - Linux x64: https://drive.google.com/file/d/1jzcxDxRDliyAgjrohuaBgdmInIs4DnAM/view?usp=sharing - Mac OS X: https://drive.google.com/file/d/1QKjeghZecHH9foduy6dKEmpAH9AHbRTA/view?usp=sharing From b207fd8ca1e0fb45f62f9b26f2422f9ccd0388dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n?= <62727185+Sebastian-byte@users.noreply.github.com> Date: Tue, 6 Apr 2021 18:00:40 -0500 Subject: [PATCH 6/6] Fix Windows download link --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 01a01b4c..ff6f134e 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ This software is not related to MultiMC developers and provided without any warranty. Please don't bomb MultiMC developers if something gets wrong using this launcher. ## Pre-built binaries (experimental as for now): -- Windows x64: https://drive.google.com/file/d/1XRSmNaDgZA6xL4UONxGMVagrEtW7IsLk/view?usp=sharing +- Windows x64: https://drive.google.com/file/d/1erbFNd_BFZ5Wd9qZqp6mU9vl3tbNBiep/view?usp=sharing - Linux x64: https://drive.google.com/file/d/1jzcxDxRDliyAgjrohuaBgdmInIs4DnAM/view?usp=sharing -- Mac OS X: https://drive.google.com/file/d/1QKjeghZecHH9foduy6dKEmpAH9AHbRTA/view?usp=sharing +- MacOS: https://drive.google.com/file/d/1QKjeghZecHH9foduy6dKEmpAH9AHbRTA/view?usp=sharing Details about the original launcher below: