diff options
43 files changed, 334 insertions, 750 deletions
@@ -47,16 +47,25 @@ If everything works correctly, the .deb will be next to the build script, in `Po ### Building a .rpm -You don't need to install the build dependencies, as the script will use `dnf` to install them for you. +Build dependencies are automatically installed using `dnf`, but you do need the `rpmdevtools` package (on Fedora) +in order to fetch sources and setup your tree. ``` +cd ~ +# setup your ~/rpmbuild directory, required for rpmbuild to work. +rpmdev-setuptree +# note: submodules are not needed here, as the spec file will download the tarball instead git clone https://github.com/PolyMC/PolyMC.git -cd packages/rpm -sudo dnf builddep ./polymec.spec -rpmbuild -bb ./polymec.spec +cd PolyMC/packages/rpm +# install build dependencies +sudo dnf builddep polymc.spec +# download build sources +spectool -g -R polymc.spec +# now build! +rpmbuild -bb polymc.spec ``` -The path to the rpm packages will be printed at the end of building +The path to the rpm packages will be printed when the build is complete. ### Building from command line You need a source folder, a build folder and an install folder. diff --git a/CMakeLists.txt b/CMakeLists.txt index 2af0aa71..6a9511b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,9 +45,6 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_DEPRECATED_WARNINGS=Y") ##################################### Set Application options ##################################### -######## Set URLs ######## -set(Launcher_NEWS_RSS_URL "https://multimc.org/rss.xml" CACHE STRING "URL to fetch Launcher's news RSS feed from.") - ######## Set version numbers ######## set(Launcher_VERSION_MAJOR 1) set(Launcher_VERSION_MINOR 0) @@ -66,10 +63,7 @@ set(Launcher_UPDATER_BASE "" CACHE STRING "Base URL for the updater.") set(Launcher_NOTIFICATION_URL "" CACHE STRING "URL for checking for notifications.") # The metadata server -set(Launcher_META_URL "https://meta.multimc.org/v1/" CACHE STRING "URL to fetch Launcher's meta files from.") - -# paste.ee API key -set(Launcher_PASTE_EE_API_KEY "utLvciUouSURFzfjPxLBf5W4ISsUX4pwBDF7N1AfZ" CACHE STRING "API key you can get from paste.ee when you register an account") +set(Launcher_META_URL "https://meta.polymc.org/v1/" CACHE STRING "URL to fetch Launcher's meta files from.") # Imgur API Client ID set(Launcher_IMGUR_CLIENT_ID "5b97b0713fba4a3" CACHE STRING "Client ID you can get from Imgur when you register an application") @@ -1,7 +1,7 @@ # PolyMC Copyright (C) 2012-2021 MultiMC Contributors - Copyright (C) 2021 PolyMC Contributors + Copyright (C) 2021-2022 PolyMC Contributors 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 @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. - + # Launcher (https://github.com/MultiMC/Launcher) Copyright 2012-2021 MultiMC Contributors Licensed under the Apache License, Version 2.0 (the "License"); @@ -1,8 +1,9 @@ <p align="center"> - <img src="/program_info/polymc-light.png#gh-light-mode-only" alt="PolyMC logo"/> - <img src="/program_info/polymc-dark.png#gh-dark-mode-only" alt="PolyMC logo"/> + <img src="./program_info/polymc-header-black.svg#gh-light-mode-only" alt="PolyMC logo"/> + <img src="./program_info/polymc-header.svg#gh-dark-mode-only" alt="PolyMC logo"/> </p> <br> + PolyMC is a custom launcher for Minecraft that focuses on predictability, long term stability and simplicity. This is a **fork** of the MultiMC Launcher and not endorsed by MultiMC. The PolyMC community felt that the maintainer was not acting in the spirit of Free Software so this fork was made. Read "[Why was this fork made?](https://github.com/PolyMC/PolyMC/wiki/FAQ)" on the wiki for more details. @@ -23,6 +24,7 @@ Several source build packages are available, along with experimental pre-built g - [Windows (32-bit)](https://packages.polymc.org/latest/win32/win32.zip) ([SHA256](https://packages.polymc.org/latest/win32/win32.zip.sha256)) - this is a portable package, you can extract it anywhere and run it. This package needs testing. - [Debian (AMD64)](https://packages.polymc.org/latest/deb/polymc-amd64.deb) ([SHA256](https://packages.polymc.org/latest/deb/polymc-amd64.deb.sha256)) - this is intended to be installed with `dpkg -i`. Alternatively, you may build the `.deb` yourself, by going to `packages/debian` and running `./makedeb.sh`. - [AppImage (AMD64)](https://packages.polymc.org/latest/appimage/PolyMC-latest-x86_64.AppImage) ([SHA256](https://packages.polymc.org/latest/appimage/PolyMC-latest-x86_64.AppImage.sha256)) - `chmod +x` must be run on this file before usage. This should work on any distribution. +- [Arch Linux (AMD64)](https://packages.polymc.org/latest/arch/polymc-bin-latest-1-x86_64.pkg.tar.zst) ([SHA256](https://packages.polymc.org/latest/arch/polymc-bin-latest-1-x86_64.pkg.tar.zst.sha256)) - this is intended to be installed with `pacman -U`. This is an alternative if building the AUR package is not desired. - MacOS currently does not have any packages. We are still working on setting up MacOS packaging. ## Development diff --git a/buildconfig/BuildConfig.cpp.in b/buildconfig/BuildConfig.cpp.in index af8845dc..2595f78b 100644 --- a/buildconfig/BuildConfig.cpp.in +++ b/buildconfig/BuildConfig.cpp.in @@ -42,7 +42,6 @@ Config::Config() VERSION_STR = "@Launcher_VERSION_STRING@"; NEWS_RSS_URL = "@Launcher_NEWS_RSS_URL@"; - PASTE_EE_KEY = "@Launcher_PASTE_EE_API_KEY@"; IMGUR_CLIENT_ID = "@Launcher_IMGUR_CLIENT_ID@"; MSA_CLIENT_ID = "@Launcher_MSA_CLIENT_ID@"; META_URL = "@Launcher_META_URL@"; diff --git a/buildconfig/BuildConfig.h b/buildconfig/BuildConfig.h index 009fb2bc..d09d5288 100644 --- a/buildconfig/BuildConfig.h +++ b/buildconfig/BuildConfig.h @@ -68,11 +68,6 @@ public: QString NEWS_RSS_URL; /** - * API key you can get from paste.ee when you register an account - */ - QString PASTE_EE_KEY; - - /** * Client ID you can get from Imgur when you register an application */ QString IMGUR_CLIENT_ID; diff --git a/launcher/Application.cpp b/launcher/Application.cpp index a3e2c44f..b605e54b 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -14,7 +14,7 @@ #include "ui/pages/global/ProxyPage.h" #include "ui/pages/global/ExternalToolsPage.h" #include "ui/pages/global/AccountListPage.h" -#include "ui/pages/global/PasteEEPage.h" +#include "ui/pages/global/PastePage.h" #include "ui/pages/global/CustomCommandsPage.h" #include "ui/themes/ITheme.h" @@ -595,7 +595,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) m_settings->registerSetting("AutoUpdate", true); // Theming - m_settings->registerSetting("IconTheme", QString("multimc")); + m_settings->registerSetting("IconTheme", QString("pe_colored")); m_settings->registerSetting("ApplicationTheme", QString("system")); // Notifications @@ -662,7 +662,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) // Memory m_settings->registerSetting({"MinMemAlloc", "MinMemoryAlloc"}, 512); - m_settings->registerSetting({"MaxMemAlloc", "MaxMemoryAlloc"}, 1024); + m_settings->registerSetting({"MaxMemAlloc", "MaxMemoryAlloc"}, 4096); m_settings->registerSetting("PermGen", 128); // Java Settings @@ -714,8 +714,8 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) m_settings->registerSetting("UpdateDialogGeometry", ""); - // paste.ee API key - m_settings->registerSetting("PasteEEAPIKey", "multimc"); + // pastebin URL + m_settings->registerSetting("PastebinURL", "https://0x0.st"); // Init page provider { @@ -728,7 +728,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) m_globalSettingsProvider->addPage<ProxyPage>(); m_globalSettingsProvider->addPage<ExternalToolsPage>(); m_globalSettingsProvider->addPage<AccountListPage>(); - m_globalSettingsProvider->addPage<PasteEEPage>(); + m_globalSettingsProvider->addPage<PastePage>(); } qDebug() << "<> Settings loaded."; } diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index a1aae524..8d8b4d02 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -181,15 +181,6 @@ set(NOTIFICATIONS_SOURCES notifications/NotificationChecker.cpp ) -# Backend for the news bar... there's usually no news. -set(NEWS_SOURCES - # News System - news/NewsChecker.h - news/NewsChecker.cpp - news/NewsEntry.h - news/NewsEntry.cpp -) - # Icon interface set(ICONS_SOURCES # Icons System and related code @@ -719,8 +710,8 @@ SET(LAUNCHER_SOURCES ui/pages/global/LauncherPage.h ui/pages/global/ProxyPage.cpp ui/pages/global/ProxyPage.h - ui/pages/global/PasteEEPage.cpp - ui/pages/global/PasteEEPage.h + ui/pages/global/PastePage.cpp + ui/pages/global/PastePage.h # GUI - platform pages ui/pages/modplatform/VanillaPage.cpp @@ -865,7 +856,7 @@ qt5_wrap_ui(LAUNCHER_UI ui/pages/global/AccountListPage.ui ui/pages/global/JavaPage.ui ui/pages/global/LauncherPage.ui - ui/pages/global/PasteEEPage.ui + ui/pages/global/PastePage.ui ui/pages/global/ProxyPage.ui ui/pages/global/MinecraftPage.ui ui/pages/global/ExternalToolsPage.ui diff --git a/launcher/Launcher.in b/launcher/Launcher.in index b79b276b..5e5e2c2b 100755 --- a/launcher/Launcher.in +++ b/launcher/Launcher.in @@ -14,7 +14,7 @@ if [[ $EUID -eq 0 ]]; then fi -LAUNCHER_NAME=@Launcher_Name@ +LAUNCHER_NAME=@Launcher_APP_BINARY_NAME@ LAUNCHER_DIR="$(dirname "$(readlink -f "$0")")" echo "Launcher Dir: ${LAUNCHER_DIR}" diff --git a/launcher/java/JavaChecker.cpp b/launcher/java/JavaChecker.cpp index 80c599cc..35ddc35c 100644 --- a/launcher/java/JavaChecker.cpp +++ b/launcher/java/JavaChecker.cpp @@ -103,11 +103,15 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status) for(QString line : lines) { line = line.trimmed(); + // NOTE: workaround for GH-4125, where garbage is getting printed into stdout on bedrock linux + if (line.contains("/bedrock/strata")) { + continue; + } auto parts = line.split('=', QString::SkipEmptyParts); if(parts.size() != 2 || parts[0].isEmpty() || parts[1].isEmpty()) { - success = false; + continue; } else { diff --git a/launcher/minecraft/auth/AuthRequest.cpp b/launcher/minecraft/auth/AuthRequest.cpp index 459d2354..feface80 100644 --- a/launcher/minecraft/auth/AuthRequest.cpp +++ b/launcher/minecraft/auth/AuthRequest.cpp @@ -44,7 +44,7 @@ void AuthRequest::onRequestFinished() { if (reply_ != qobject_cast<QNetworkReply *>(sender())) { return; } - httpStatus_ = 200; + httpStatus_ = reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); finish(); } diff --git a/launcher/minecraft/auth/Parsers.cpp b/launcher/minecraft/auth/Parsers.cpp index ed31e934..2dd36562 100644 --- a/launcher/minecraft/auth/Parsers.cpp +++ b/launcher/minecraft/auth/Parsers.cpp @@ -94,7 +94,7 @@ bool parseXTokenResponse(QByteArray & data, Katabasis::Token &output, QString na return false; } if(!getString(obj.value("Token"), output.token)) { - qWarning() << "User Token is not a timestamp"; + qWarning() << "User Token is not a string"; return false; } auto arrayVal = obj.value("DisplayClaims").toObject().value("xui"); diff --git a/launcher/minecraft/auth/steps/MinecraftProfileStep.cpp b/launcher/minecraft/auth/steps/MinecraftProfileStep.cpp index 9fef99b0..add91659 100644 --- a/launcher/minecraft/auth/steps/MinecraftProfileStep.cpp +++ b/launcher/minecraft/auth/steps/MinecraftProfileStep.cpp @@ -56,6 +56,14 @@ void MinecraftProfileStep::onRequestDone( return; } if (error != QNetworkReply::NoError) { + qWarning() << "Error getting profile:"; + qWarning() << " HTTP Status: " << requestor->httpStatus_; + qWarning() << " Internal error no.: " << error; + qWarning() << " Error string: " << requestor->errorString_; + + qWarning() << " Response:"; + qWarning() << QString::fromUtf8(data); + emit finished( AccountTaskState::STATE_FAILED_SOFT, tr("Minecraft Java profile acquisition failed.") diff --git a/launcher/net/PasteUpload.cpp b/launcher/net/PasteUpload.cpp index 4b69b68a..52b82a0e 100644 --- a/launcher/net/PasteUpload.cpp +++ b/launcher/net/PasteUpload.cpp @@ -8,44 +8,34 @@ #include <QJsonDocument> #include <QFile> -PasteUpload::PasteUpload(QWidget *window, QString text, QString key) : m_window(window) +PasteUpload::PasteUpload(QWidget *window, QString text, QString url) : m_window(window), m_uploadUrl(url), m_text(text.toUtf8()) { - m_key = key; - QByteArray temp; - QJsonObject topLevelObj; - QJsonObject sectionObject; - sectionObject.insert("contents", text); - QJsonArray sectionArray; - sectionArray.append(sectionObject); - topLevelObj.insert("description", "Log Upload"); - topLevelObj.insert("sections", sectionArray); - QJsonDocument docOut; - docOut.setObject(topLevelObj); - m_jsonContent = docOut.toJson(); } PasteUpload::~PasteUpload() { } -bool PasteUpload::validateText() -{ - return m_jsonContent.size() <= maxSize(); -} - void PasteUpload::executeTask() { - QNetworkRequest request(QUrl("https://api.paste.ee/v1/pastes")); + QNetworkRequest request{QUrl(m_uploadUrl)}; request.setHeader(QNetworkRequest::UserAgentHeader, BuildConfig.USER_AGENT_UNCACHED); - request.setRawHeader("Content-Type", "application/json"); - request.setRawHeader("Content-Length", QByteArray::number(m_jsonContent.size())); - request.setRawHeader("X-Auth-Token", m_key.toStdString().c_str()); + QHttpMultiPart *multiPart = new QHttpMultiPart{QHttpMultiPart::FormDataType}; + + QHttpPart filePart; + filePart.setBody(m_text); + filePart.setHeader(QNetworkRequest::ContentTypeHeader, "text/plain"); + filePart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"file\"; filename=\"log.txt\""); - QNetworkReply *rep = APPLICATION->network()->post(request, m_jsonContent); + multiPart->append(filePart); + + QNetworkReply *rep = APPLICATION->network()->post(request, multiPart); + multiPart->setParent(rep); m_reply = std::shared_ptr<QNetworkReply>(rep); - setStatus(tr("Uploading to paste.ee")); + setStatus(tr("Uploading to %1").arg(m_uploadUrl)); + connect(rep, &QNetworkReply::uploadProgress, this, &Task::setProgress); connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(downloadError(QNetworkReply::NetworkError))); connect(rep, SIGNAL(finished()), this, SLOT(downloadFinished())); @@ -61,45 +51,23 @@ void PasteUpload::downloadError(QNetworkReply::NetworkError error) void PasteUpload::downloadFinished() { QByteArray data = m_reply->readAll(); - // if the download succeeded - if (m_reply->error() == QNetworkReply::NetworkError::NoError) + int statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + if (m_reply->error() != QNetworkReply::NetworkError::NoError) { + emitFailed(tr("Network error: %1").arg(m_reply->errorString())); m_reply.reset(); - QJsonParseError jsonError; - QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError); - if (jsonError.error != QJsonParseError::NoError) - { - emitFailed(jsonError.errorString()); - return; - } - if (!parseResult(doc)) - { - emitFailed(tr("paste.ee returned an error. Please consult the logs for more information")); - return; - } + return; } - // else the download failed - else + else if (statusCode != 200 && statusCode != 201) { - emitFailed(QString("Network error: %1").arg(m_reply->errorString())); + QString reasonPhrase = m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString(); + emitFailed(tr("Error: %1 returned unexpected status code %2 %3").arg(m_uploadUrl).arg(statusCode).arg(reasonPhrase)); + qCritical() << m_uploadUrl << " returned unexpected status code " << statusCode << " with body: " << data; m_reply.reset(); return; } - emitSucceeded(); -} -bool PasteUpload::parseResult(QJsonDocument doc) -{ - auto object = doc.object(); - auto status = object.value("success").toBool(); - if (!status) - { - qCritical() << "paste.ee reported error:" << QString(object.value("error").toString()); - return false; - } - m_pasteLink = object.value("link").toString(); - m_pasteID = object.value("id").toString(); - qDebug() << m_pasteLink; - return true; + m_pasteLink = QString::fromUtf8(data).trimmed(); + emitSucceeded(); } - diff --git a/launcher/net/PasteUpload.h b/launcher/net/PasteUpload.h index 5514e058..62b2dc36 100644 --- a/launcher/net/PasteUpload.h +++ b/launcher/net/PasteUpload.h @@ -8,37 +8,21 @@ class PasteUpload : public Task { Q_OBJECT public: - PasteUpload(QWidget *window, QString text, QString key = "public"); + PasteUpload(QWidget *window, QString text, QString url); virtual ~PasteUpload(); QString pasteLink() { return m_pasteLink; } - QString pasteID() - { - return m_pasteID; - } - int maxSize() - { - // 2MB for paste.ee - public - if(m_key == "public") - return 1024*1024*2; - // 12MB for paste.ee - with actual key - return 1024*1024*12; - } - bool validateText(); protected: virtual void executeTask(); private: - bool parseResult(QJsonDocument doc); - QString m_error; QWidget *m_window; - QString m_pasteID; QString m_pasteLink; - QString m_key; - QByteArray m_jsonContent; + QString m_uploadUrl; + QByteArray m_text; std::shared_ptr<QNetworkReply> m_reply; public slots: diff --git a/launcher/news/NewsChecker.cpp b/launcher/news/NewsChecker.cpp deleted file mode 100644 index 4f4359b8..00000000 --- a/launcher/news/NewsChecker.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* 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 "NewsChecker.h" - -#include <QByteArray> -#include <QDomDocument> - -#include <QDebug> - -NewsChecker::NewsChecker(shared_qobject_ptr<QNetworkAccessManager> network, const QString& feedUrl) -{ - m_network = network; - m_feedUrl = feedUrl; -} - -void NewsChecker::reloadNews() -{ - // Start a netjob to download the RSS feed and call rssDownloadFinished() when it's done. - if (isLoadingNews()) - { - qDebug() << "Ignored request to reload news. Currently reloading already."; - return; - } - - qDebug() << "Reloading news."; - - NetJob* job = new NetJob("News RSS Feed", m_network); - job->addNetAction(Net::Download::makeByteArray(m_feedUrl, &newsData)); - QObject::connect(job, &NetJob::succeeded, this, &NewsChecker::rssDownloadFinished); - QObject::connect(job, &NetJob::failed, this, &NewsChecker::rssDownloadFailed); - m_newsNetJob.reset(job); - job->start(); -} - -void NewsChecker::rssDownloadFinished() -{ - // Parse the XML file and process the RSS feed entries. - qDebug() << "Finished loading RSS feed."; - - m_newsNetJob.reset(); - QDomDocument doc; - { - // Stuff to store error info in. - QString errorMsg = "Unknown error."; - int errorLine = -1; - int errorCol = -1; - - // Parse the XML. - if (!doc.setContent(newsData, false, &errorMsg, &errorLine, &errorCol)) - { - QString fullErrorMsg = QString("Error parsing RSS feed XML. %s at %d:%d.").arg(errorMsg, errorLine, errorCol); - fail(fullErrorMsg); - newsData.clear(); - return; - } - newsData.clear(); - } - - // If the parsing succeeded, read it. - QDomNodeList items = doc.elementsByTagName("item"); - m_newsEntries.clear(); - for (int i = 0; i < items.length(); i++) - { - QDomElement element = items.at(i).toElement(); - NewsEntryPtr entry; - entry.reset(new NewsEntry()); - QString errorMsg = "An unknown error occurred."; - if (NewsEntry::fromXmlElement(element, entry.get(), &errorMsg)) - { - qDebug() << "Loaded news entry" << entry->title; - m_newsEntries.append(entry); - } - else - { - qWarning() << "Failed to load news entry at index" << i << ":" << errorMsg; - } - } - - succeed(); -} - -void NewsChecker::rssDownloadFailed(QString reason) -{ - // Set an error message and fail. - fail(tr("Failed to load news RSS feed:\n%1").arg(reason)); -} - - -QList<NewsEntryPtr> NewsChecker::getNewsEntries() const -{ - return m_newsEntries; -} - -bool NewsChecker::isLoadingNews() const -{ - return m_newsNetJob.get() != nullptr; -} - -QString NewsChecker::getLastLoadErrorMsg() const -{ - return m_lastLoadError; -} - -void NewsChecker::succeed() -{ - m_lastLoadError = ""; - qDebug() << "News loading succeeded."; - m_newsNetJob.reset(); - emit newsLoaded(); -} - -void NewsChecker::fail(const QString& errorMsg) -{ - m_lastLoadError = errorMsg; - qDebug() << "Failed to load news:" << errorMsg; - m_newsNetJob.reset(); - emit newsLoadingFailed(errorMsg); -} - diff --git a/launcher/news/NewsChecker.h b/launcher/news/NewsChecker.h deleted file mode 100644 index 8467a541..00000000 --- a/launcher/news/NewsChecker.h +++ /dev/null @@ -1,105 +0,0 @@ -/* Copyright 2013-2021 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in complia |
