diff options
38 files changed, 198 insertions, 421 deletions
@@ -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/launcher/Application.cpp b/launcher/Application.cpp index a5b861d0..b605e54b 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -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 diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 21859cad..c49b68b2 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -221,11 +221,7 @@ set(MINECRAFT_SOURCES minecraft/auth/flows/Mojang.h minecraft/auth/flows/MSA.cpp minecraft/auth/flows/MSA.h - minecraft/auth/flows/Offline.cpp - minecraft/auth/flows/Offline.h - minecraft/auth/steps/OfflineStep.cpp - minecraft/auth/steps/OfflineStep.h minecraft/auth/steps/EntitlementsStep.cpp minecraft/auth/steps/EntitlementsStep.h minecraft/auth/steps/GetSkinStep.cpp @@ -773,8 +769,6 @@ SET(LAUNCHER_SOURCES ui/dialogs/LoginDialog.h ui/dialogs/MSALoginDialog.cpp ui/dialogs/MSALoginDialog.h - ui/dialogs/OfflineLoginDialog.cpp - ui/dialogs/OfflineLoginDialog.h ui/dialogs/NewComponentDialog.cpp ui/dialogs/NewComponentDialog.h ui/dialogs/NewInstanceDialog.cpp @@ -886,7 +880,6 @@ qt5_wrap_ui(LAUNCHER_UI ui/dialogs/ExportInstanceDialog.ui ui/dialogs/IconPickerDialog.ui ui/dialogs/MSALoginDialog.ui - ui/dialogs/OfflineLoginDialog.ui ui/dialogs/AboutDialog.ui ui/dialogs/LoginDialog.ui ui/dialogs/EditAccountDialog.ui diff --git a/launcher/LaunchController.cpp b/launcher/LaunchController.cpp index 32fc99cb..7750be1a 100644 --- a/launcher/LaunchController.cpp +++ b/launcher/LaunchController.cpp @@ -116,12 +116,6 @@ void LaunchController::login() { m_session->wants_online = m_online; m_accountToUse->fillSession(m_session); - // Launch immediately in true offline mode - if(m_accountToUse->isOffline()) { - launchInstance(); - return; - } - switch(m_accountToUse->accountState()) { case AccountState::Offline: { m_session->wants_online = false; 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/AccountData.cpp b/launcher/minecraft/auth/AccountData.cpp index 9b84fe1a..7526c951 100644 --- a/launcher/minecraft/auth/AccountData.cpp +++ b/launcher/minecraft/auth/AccountData.cpp @@ -314,8 +314,6 @@ bool AccountData::resumeStateFromV3(QJsonObject data) { type = AccountType::MSA; } else if (typeS == "Mojang") { type = AccountType::Mojang; - } else if (typeS == "Offline") { - type = AccountType::Offline; } else { qWarning() << "Failed to parse account data: type is not recognized."; return false; @@ -365,9 +363,6 @@ QJsonObject AccountData::saveState() const { tokenToJSONV3(output, xboxApiToken, "xrp-main"); tokenToJSONV3(output, mojangservicesToken, "xrp-mc"); } - else if (type == AccountType::Offline) { - output["type"] = "Offline"; - } tokenToJSONV3(output, yggdrasilToken, "ygg"); profileToJSONV3(output, minecraftProfile, "profile"); @@ -376,7 +371,7 @@ QJsonObject AccountData::saveState() const { } QString AccountData::userName() const { - if(type == AccountType::MSA) { + if(type != AccountType::Mojang) { return QString(); } return yggdrasilToken.extra["userName"].toString(); @@ -432,9 +427,6 @@ QString AccountData::accountDisplayString() const { case AccountType::Mojang: { return userName(); } - case AccountType::Offline: { - return userName(); - } case AccountType::MSA: { if(xboxApiToken.extra.contains("gtg")) { return xboxApiToken.extra["gtg"].toString(); diff --git a/launcher/minecraft/auth/AccountData.h b/launcher/minecraft/auth/AccountData.h index 606c1ad1..abf84e43 100644 --- a/launcher/minecraft/auth/AccountData.h +++ b/launcher/minecraft/auth/AccountData.h @@ -38,8 +38,7 @@ struct MinecraftProfile { enum class AccountType { MSA, - Mojang, - Offline + Mojang }; enum class AccountState { diff --git a/launcher/minecraft/auth/AccountList.cpp b/launcher/minecraft/auth/AccountList.cpp index 04470e1c..ef8b435d 100644 --- a/launcher/minecraft/auth/AccountList.cpp +++ b/launcher/minecraft/auth/AccountList.cpp @@ -302,7 +302,7 @@ QVariant AccountList::data(const QModelIndex &index, int role) const } case MigrationColumn: { - if(account->isMSA() || account->isOffline()) { + if(account->isMSA()) { return tr("N/A", "Can Migrate?"); } if (account->canMigrate()) { 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/MinecraftAccount.cpp b/launcher/minecraft/auth/MinecraftAccount.cpp index 6592be0f..ed9e945e 100644 --- a/launcher/minecraft/auth/MinecraftAccount.cpp +++ b/launcher/minecraft/auth/MinecraftAccount.cpp @@ -30,7 +30,6 @@ #include "flows/MSA.h" #include "flows/Mojang.h" -#include "flows/Offline.h" MinecraftAccount::MinecraftAccount(QObject* parent) : QObject(parent) { data.internalId = QUuid::createUuid().toString().remove(QRegExp("[{}-]")); @@ -69,23 +68,6 @@ MinecraftAccountPtr MinecraftAccount::createBlankMSA() return account; } -MinecraftAccountPtr MinecraftAccount::createOffline(const QString &username) -{ - MinecraftAccountPtr account = new MinecraftAccount(); - account->data.type = AccountType::Offline; - account->data.yggdrasilToken.token = "offline"; - account->data.yggdrasilToken.validity = Katabasis::Validity::Certain; - account->data.yggdrasilToken.issueInstant = QDateTime::currentDateTimeUtc(); - account->data.yggdrasilToken.extra["userName"] = username; - account->data.yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegExp("[{}-]")); - account->data.minecraftEntitlement.ownsMinecraft = true; - account->data.minecraftEntitlement.canPlayMinecraft = true; - account->data.minecraftProfile.id = QUuid::createUuid().toString().remove(QRegExp("[{}-]")); - account->data.minecraftProfile.name = username; - account->data.minecraftProfile.validity = Katabasis::Validity::Certain; - return account; -} - QJsonObject MinecraftAccount::saveToJson() const { @@ -129,16 +111,6 @@ shared_qobject_ptr<AccountTask> MinecraftAccount::loginMSA() { return m_currentTask; } -shared_qobject_ptr<AccountTask> MinecraftAccount::loginOffline() { - Q_ASSERT(m_currentTask.get() == nullptr); - - m_currentTask.reset(new OfflineLogin(&data)); - connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded())); - connect(m_currentTask.get(), SIGNAL(failed(QString)), SLOT(authFailed(QString))); - emit activityChanged(true); - return m_currentTask; -} - shared_qobject_ptr<AccountTask> MinecraftAccount::refresh() { if(m_currentTask) { return m_currentTask; @@ -147,9 +119,6 @@ shared_qobject_ptr<AccountTask> MinecraftAccount::refresh() { if(data.type == AccountType::MSA) { m_currentTask.reset(new MSASilent(&data)); } - if(data.type == AccountType::Offline) { - m_currentTask.reset(new OfflineRefresh(&data)); - } else { m_currentTask.reset(new MojangRefresh(&data)); } diff --git a/launcher/minecraft/auth/MinecraftAccount.h b/launcher/minecraft/auth/MinecraftAccount.h index 6592f9c0..7ab3c746 100644 --- a/launcher/minecraft/auth/MinecraftAccount.h +++ b/launcher/minecraft/auth/MinecraftAccount.h @@ -73,8 +73,6 @@ public: /* construction */ static MinecraftAccountPtr createBlankMSA(); - static MinecraftAccountPtr createOffline(const QString &username); - static MinecraftAccountPtr loadFromJsonV2(const QJsonObject &json); static MinecraftAccountPtr loadFromJsonV3(const QJsonObject &json); @@ -91,8 +89,6 @@ public: /* manipulation */ shared_qobject_ptr<AccountTask> loginMSA(); - shared_qobject_ptr<AccountTask> loginOffline(); - shared_qobject_ptr<AccountTask> refresh(); shared_qobject_ptr<AccountTask> currentTask(); @@ -132,10 +128,6 @@ public: /* queries */ return data.type == AccountType::MSA; } - bool isOffline() const { - return data.type == AccountType::Offline; - } - bool ownsMinecraft() const { return data.minecraftEntitlement.ownsMinecraft; } @@ -157,10 +149,6 @@ public: /* queries */ return "msa"; } break; - case AccountType::Offline: { - return "offline"; - } - break; default: { return "unknown"; } 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/flows/Offline.cpp b/launcher/minecraft/auth/flows/Offline.cpp deleted file mode 100644 index fc614a8c..00000000 --- a/launcher/minecraft/auth/flows/Offline.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "Offline.h" - -#include "minecraft/auth/steps/OfflineStep.h" - -OfflineRefresh::OfflineRefresh( - AccountData *data, - QObject *parent -) : AuthFlow(data, parent) { - m_steps.append(new OfflineStep(m_data)); -} - -OfflineLogin::OfflineLogin( - AccountData *data, - QObject *parent -) : AuthFlow(data, parent) { - m_steps.append(new OfflineStep(m_data)); -} diff --git a/launcher/minecraft/auth/flows/Offline.h b/launcher/minecraft/auth/flows/Offline.h deleted file mode 100644 index 5d1f83a4..00000000 --- a/launcher/minecraft/auth/flows/Offline.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include "AuthFlow.h" - -class OfflineRefresh : public AuthFlow -{ - Q_OBJECT -public: - explicit OfflineRefresh( - AccountData *data, - QObject *parent = 0 - ); -}; - -class OfflineLogin : public AuthFlow -{ - Q_OBJECT -public: - explicit OfflineLogin( - AccountData *data, - QObject *parent = 0 - ); -}; 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/minecraft/auth/steps/OfflineStep.cpp b/launcher/minecraft/auth/steps/OfflineStep.cpp deleted file mode 100644 index dc092bfd..00000000 --- a/launcher/minecraft/auth/steps/OfflineStep.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "OfflineStep.h" - -#include "Application.h" - -OfflineStep::OfflineStep(AccountData* data) : AuthStep(data) {} -OfflineStep::~OfflineStep() noexcept = default; - -QString OfflineStep::describe() { - return tr("Creating offline account."); -} - -void OfflineStep::rehydrate() { - // NOOP -} - -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 deleted file mode 100644 index 62addb1f..00000000 --- a/launcher/minecraft/auth/steps/OfflineStep.h +++ /dev/null @@ -1,20 +0,0 @@ - -#pragma once -#include <QObject> - -#include "QObjectPtr.h" -#include "minecraft/auth/AuthStep.h" - -#include <katabasis/DeviceFlow.h> - -class OfflineStep : public AuthStep { - Q_OBJECT -public: - explicit OfflineStep(AccountData *data); - virtual ~OfflineStep() noexcept; - - void perform() override; - void rehydrate() override; - - QString describe() override; -}; diff --git a/launcher/translations/TranslationsModel.cpp b/launcher/translations/TranslationsModel.cpp index 2e744007..0fa82e35 100644 --- a/launcher/translations/TranslationsModel.cpp +++ b/launcher/translations/TranslationsModel.cpp @@ -143,6 +143,11 @@ struct TranslationsModel::Private std::unique_ptr<POTranslator> m_po_translator; QFileSystemWatcher *watcher; + + const QString m_system_locale = QLocale::system().name(); + const QString m_system_language = m_system_locale.split('_').front(); + + bool no_language_set = false; }; TranslationsModel::TranslationsModel(QString path, QObject* parent): QAbstractListModel(parent) @@ -164,7 +169,10 @@ TranslationsModel::~TranslationsModel() void TranslationsModel::translationDirChanged(const QString& path) { qDebug() << "Dir changed:" << path; - reloadLocalFiles(); + if (!d->no_language_set) + { + reloadLocalFiles(); + } selectLanguage(selectedLanguage()); } @@ -172,7 +180,26 @@ void TranslationsModel::indexReceived() { qDebug() << "Got translations index!"; d->m_index_job.reset(); - if(d->m_selectedLanguage != defaultLangCode) + + if (d->no_language_set) + { + reloadLocalFiles(); + + auto language = d->m_system_locale; + if (!findLanguage(language)) + { + language = d->m_system_language; + } + selectLanguage(language); + if (selectedLanguage() != defaultLangCode) + { + updateLanguage(selectedLanguage()); + } + APPLICATION->settings()->set("Language", selectedLanguage()); + d->no_language_set = false; + } + + else if(d->m_selectedLanguage != defaultLangCode) { downloadTranslation(d->m_selectedLanguage); } @@ -319,8 +346,19 @@ void TranslationsModel::reloadLocalFiles() { d->m_languages.append(language); } - std::sort(d->m_languages.begin(), d->m_languages.end(), [](const Language& a, const Language& b) { - return a.key.compare(b.key) < 0; + std::sort(d->m_languages.begin(), d->m_languages.end(), [this](const Language& a, const Language& b) { + if (a.key != b.key) + { + if (a.key == d->m_system_locale || a.key == d->m_system_language) + { + return true; + } + if (b.key == d->m_system_locale || b.key == d->m_system_language) + { + return false; + } + } + return a.key < b.key; }); endInsertRows(); } @@ -439,6 +477,12 @@ bool TranslationsModel::selectLanguage(QString key) { QString &langCode = key; auto langPtr = findLanguage(key); + + if (langCode.isEmpty()) + { + d->no_language_set = true; + } + if(!langPtr) { qWarning() << "Selected invalid language" << key << ", defaulting to" << defaultLangCode; diff --git a/launcher/ui/dialogs/AboutDialog.cpp b/launcher/ui/dialogs/AboutDialog.cpp index 2ba34f1a..46d2f429 100644 --- a/launcher/ui/dialogs/AboutDialog.cpp +++ b/launcher/ui/dialogs/AboutDialog.cpp @@ -99,7 +99,7 @@ AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent), ui(new Ui::AboutDia QString urlText("<html><head/><body><p><a href=\"%1\">%1</a></p></body></html>"); ui->urlLabel->setText(urlText.arg(BuildConfig.LAUNCHER_GIT)); - QString copyText("© 2012-2021 %1"); + QString copyText("© 2021-2022 %1"); ui->copyLabel->setText(copyText.arg(BuildConfig.LAUNCHER_COPYRIGHT)); connect(ui->closeButton, SIGNAL(clicked()), SLOT(close())); diff --git a/launcher/ui/dialogs/MSALoginDialog.cpp b/launcher/ui/dialogs/MSALoginDialog.cpp index f46aa3b9..174ad46c 100644 --- a/launcher/ui/dialogs/MSALoginDialog.cpp +++ b/launcher/ui/dialogs/MSALoginDialog.cpp @@ -16,15 +16,19 @@ #include "MSALoginDialog.h" #include "ui_MSALoginDialog.h" +#include "DesktopServices.h" #include "minecraft/auth/AccountTask.h" #include <QtWidgets/QPushButton> #include <QUrl> +#include <QApplication> +#include <QClipboard> MSALoginDialog::MSALoginDialog(QWidget *parent) : QDialog(parent), ui(new Ui::MSALoginDialog) { ui->setupUi(this); ui->progressBar->setVisible(false); + ui->actionButton->setVisible(false); // ui->buttonBox->button(QDialogButtonBox::Cancel)->setEnabled(false); connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); @@ -81,10 +85,17 @@ void MSALoginDialog::showVerificationUriAndCode(const QUrl& uri, const QString& QString urlString = uri.toString(); QString linkString = QString("<a href=\"%1\">%2</a>").arg(urlString, urlString); ui->label->setText(tr("<p>Please open up %1 in a browser and put in the code <b>%2</b> to proceed with login.</p>").arg(linkString, code)); + ui->actionButton->setVisible(true); + connect(ui->actionButton, &QPushButton::clicked, [=]() { + DesktopServices::openUrl(uri); + QClipboard* cb = QApplication::clipboard(); + cb->setText(code); + }); } void MSALoginDialog::hideVerificationUriAndCode() { m_externalLoginTimer.stop(); + ui->actionButton->setVisible(false); } void MSALoginDialog::setUserInputsEnabled(bool enable) @@ -110,6 +121,7 @@ void MSALoginDialog::onTaskFailed(const QString &reason) // Re-enable user-interaction setUserInputsEnabled(true); ui->progressBar->setVisible(false); + ui->actionButton->setVisible(false); } void MSALoginDialog::onTaskSucceeded() diff --git a/launcher/ui/dialogs/MSALoginDialog.ui b/launcher/ui/dialogs/MSALoginDialog.ui index 78cbfb26..c18d01a1 100644 --- a/launcher/ui/dialogs/MSALoginDialog.ui +++ b/launcher/ui/dialogs/MSALoginDialog.ui @@ -49,14 +49,25 @@ aaaaa</string> </widget> </item> <item> - <widget class="QDialogButtonBox" name="buttonBox"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="standardButtons"> - <set>QDialogButtonBox::Cancel</set> - </property> - </widget> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QPushButton" name="actionButton"> + <property name="text"> + <string>Open page and copy code</string> + </property> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel</set> + </property> + </widget> + </item> + </layout> </item> </layout> </widget> diff --git a/launcher/ui/dialogs/OfflineLoginDialog.cpp b/launcher/ui/dialogs/OfflineLoginDialog.cpp deleted file mode 100644 index 345ed40a..00000000 --- a/launcher/ui/dialogs/OfflineLoginDialog.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "OfflineLoginDialog.h" -#include "ui_OfflineLoginDialog.h" - -#include "minecraft/auth/AccountTask.h" - -#include <QtWidgets/QPushButton> - -OfflineLoginDialog::OfflineLoginDialog(QWidget *parent) : QDialog(parent), ui(new Ui::OfflineLoginDialog) -{ - ui->setupUi(this); - ui->progressBar->setVisible(false); - ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); - - connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); - connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); -} - -OfflineLoginDialog::~OfflineLoginDialog() -{ - delete ui; -} - -// Stage 1: User interaction -void OfflineLoginDialog::accept() -{ - setUserInputsEnabled(false); - ui->progressBar->setVisible(true); - - // Setup the login task and start it - m_account = MinecraftAccount::createOffline(ui->userTextBox->text()); - m_loginTask = m_account->loginOffline(); - connect(m_loginTask.get(), &Task::failed, this, &OfflineLoginDialog::onTaskFailed); - connect(m_loginTask.get(), &Task::succeeded, this, &OfflineLoginDialog::onTaskSucceeded); - connect(m_loginTask.get(), &Task::status, this, &OfflineLoginDialog::onTaskStatus); - connect(m_loginTask.get(), &Task::progress, this, &OfflineLoginDialog::onTaskProgress); - m_loginTask->start(); -} - -void OfflineLoginDialog::setUserInputsEnabled(bool enable) -{ - ui->userTextBox->setEnabled(enable); - ui->buttonBox->setEnabled(enable); -} - -// Enable the OK button only when the textbox contains something. -void OfflineLoginDialog::on_userTextBox_textEdited(const QString &newText) -{ - ui->buttonBox->button(QDialogButtonBox::Ok) - ->setEnabled(!newText.isEmpty()); -} - -void OfflineLoginDialog::onTaskFailed(const QString &reason) -{ - // Set message - auto lines = reason.split('\n'); - QString processed; - for(auto line: lines) { - if(line.size()) { - processed += "<font color='red'>" + line + "</font><br />"; - } - else { - processed += "<br />"; - } - } - ui->label->setText(processed); - - // Re-enable user-interaction - setUserInputsEnabled(true); - ui->progressBar->setVisible(false); -} - -void OfflineLoginDialog::onTaskSucceeded() -{ - QDialog::accept(); -} - -void OfflineLoginDialog::onTaskStatus(const QString &status) -{ - ui->label->setText(status); -} - -void OfflineLoginDialog::onTaskProgress(qint64 current, qint64 total) -{ - ui->progressBar->setMaximum(total); - ui->progressBar->setValue(current); -} - -// Public interface -MinecraftAccountPtr OfflineLoginDialog::newAccount(QWidget *parent, QString msg) -{ - OfflineLoginDialog dlg(parent); - dlg.ui->label->setText(msg); - if (dlg.exec() == QDialog::Accepted) - { - return dlg.m_account; - } - return 0; -} diff --git a/launcher/ui/dialogs/OfflineLoginDialog.h b/launcher/ui/dialogs/OfflineLoginDialog.h deleted file mode 100644 index 5e608379..00000000 --- a/launcher/ui/dialogs/OfflineLoginDialog.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include <QtWidgets/QDialog> -#include <QtCore/QEventLoop> - -#include "minecraft/auth/MinecraftAccount.h" -#include "tasks/Task.h" - -namespace Ui -{ -class OfflineLoginDialog; -} - -class OfflineLoginDialog : public QDialog -{ - Q_OBJECT - -public: - ~OfflineLoginDialog(); - - static MinecraftAccountPtr newAccount(QWidget *parent, QString message); - -private: - explicit OfflineLoginDialog(QWidget *parent = 0); - - void setUserInputsEnabled(bool enable); - -protected -slots: - void accept(); - - void onTaskFailed(const QString &reason); - void onTaskSucceeded(); - void onTaskStatus(const QString &status); - void onTaskProgress(qint64 current, qint64 total); - - void on_userTextBox_textEdited(const QString &newText); - -private: - Ui::OfflineLoginDialog *ui; - MinecraftAccountPtr m_account; - Task::Ptr m_loginTask; -}; diff --git a/launcher/ui/dialogs/OfflineLoginDialog.ui b/launcher/ui/dialogs/OfflineLoginDialog.ui deleted file mode 100644 index 4577d361..00000000 --- a/launcher/ui/dialogs/OfflineLoginDialog.ui +++ /dev/null @@ -1,67 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>OfflineLoginDialog</class> - <widget class="QDialog" name="OfflineLoginDialog"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>500</width> - <height>250</height> - </rect> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="windowTitle"> - <string>Add Account</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QLabel" name="label"> - <property name="text"> - <string notr="true">Message label placeholder.</string> - </property> - <property name="textFormat"> - <enum>Qt::RichText</enum> - </property> - <property name="textInteractionFlags"> - <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="userTextBox"> - <property name="placeholderText"> - <string>Username</string> - </property> - </widget> - </item> - <item> - <widget class="QProgressBar" name="progressBar"> - <property name="value"> - <number>69</number> - </property> - <property name="textVisible"> - <bool>false</bool> - </property> - </widget> - </item> - <item> - <widget class="QDialogButtonBox" name="buttonBox"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="standardButtons"> - <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> - </property> - </widget> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> diff --git a/launcher/ui/pages/global/AccountListPage.cpp b/launcher/ui/pages/global/AccountListPage.cpp index ad88812a..b8da6c75 100644 --- a/launcher/ui/pages/global/AccountListPage.cpp +++ b/launcher/ui/pages/global/AccountListPage.cpp @@ -24,7 +24,6 @@ #include "net/NetJob.h" #include "ui/dialogs/ProgressDialog.h" -#include "ui/dialogs/OfflineLoginDialog.h" #include "ui/dialogs/LoginDialog.h" #include "ui/dialogs/MSALoginDialog.h" #include "ui/dialogs/CustomMessageBox.h" @@ -154,28 +153,6 @@ void AccountListPage::on_actionAddMicrosoft_triggered() } } -void AccountListPage::on_actionAddOffline_triggered() -{ - MinecraftAccountPtr account = OfflineLoginDialog::newAccount( - this, - tr("Please enter your desired username to add your offline account. <br>" - "<br>" - "It is required by Mojang that you own Minecraft BEFORE you may use offline mode. <br>" - "The PolyMC developers denounce piracy and take NO LIABILITY WHATSOEVER for <br>" - "any illegal activity that may occur in usage of the offline mode feature. <br>" - "<br>" - "By continuing you promise that you own a Minecraft account.") - ); - - if (account) - { - m_accounts->addAccount(account); - if (m_accounts->count() == 1) { - m_accounts->setDefaultAccount(account); - } - } -} - void AccountListPage::on_actionRemove_triggered() { QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes(); diff --git a/launcher/ui/pages/global/AccountListPage.h b/launcher/ui/pages/global/AccountListPage.h index 841c3fd2..1c65e708 100644 --- a/launcher/ui/pages/global/AccountListPage.h +++ b/launcher/ui/pages/global/AccountListPage.h @@ -62,7 +62,6 @@ public: public slots: void on_actionAddMojang_triggered(); void on_actionAddMicrosoft_triggered(); - void on_actionAddOffline_triggered(); void on_actionRemove_triggered(); void on_actionRefresh_triggered(); void on_actionSetDefault_triggered(); diff --git a/launcher/ui/pages/global/AccountListPage.ui b/launcher/ui/pages/global/AccountListPage.ui index d21a92e2..29738c02 100644 --- a/launcher/ui/pages/global/AccountListPage.ui +++ b/launcher/ui/pages/global/AccountListPage.ui @@ -54,7 +54,6 @@ </attribute> <addaction name="actionAddMicrosoft"/> <addaction name="actionAddMojang"/> - <addaction name="actionAddOffline"/> <addaction name="actionRefresh"/> <addaction name="actionRemove"/> <addaction name="actionSetDefault"/> @@ -104,11 +103,6 @@ <string>Add Microsoft</string> </property> </action> - <action name="actionAddOffline"> - <property name="text"> - <string>Add Offline</string> - </property> - </action> <action name="actionRefresh"> <property name="text"> <string>Refresh</string> diff --git a/launcher/ui/pages/global/LauncherPage.cpp b/launcher/ui/pages/global/LauncherPage.cpp index 4d4d4e89..81ecd58f 100644 --- a/launcher/ui/pages/global/LauncherPage.cpp +++ b/launcher/ui/pages/global/LauncherPage.cpp @@ -256,7 +256,7 @@ void LauncherPage::applySettings() s->set("IconTheme", "pe_blue"); break; case 4: - s->set("IconTheme", "pe_colored"); + s->set("IconTheme", "multimc"); break; case 5: s->set("IconTheme", "OSX"); @@ -272,7 +272,7 @@ void LauncherPage::applySettings() break; case 0: default: - s->set("IconTheme", "multimc"); + s->set("IconTheme", "pe_colored"); break; } diff --git a/launcher/ui/widgets/LanguageSelectionWidget.cpp b/launcher/ui/widgets/LanguageSelectionWidget.cpp index cf70c7b4..964d2b7c 100644 --- a/launcher/ui/widgets/LanguageSelectionWidget.cpp +++ b/launcher/ui/widgets/LanguageSelectionWidget.cpp @@ -6,6 +6,7 @@ #include <QLabel> #include "Application.h" #include "translations/TranslationsModel.h" +#include "settings/Setting.h" LanguageSelectionWidget::LanguageSelectionWidget(QWidget *parent) : QWidget(parent) @@ -37,6 +38,9 @@ LanguageSelectionWidget::LanguageSelectionWidget(QWidget *parent) : languageView->header()->setSectionResizeMode(0, QHeaderView::Stretch); connect(languageView->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &LanguageSelectionWidget::languageRowChanged); verticalLayout->setContentsMargins(0,0,0,0); + + auto language_setting = APPLICATION->settings()->getSetting("Language"); + connect(language_setting.get(), &Setting::SettingChanged, this, &LanguageSelectionWidget::languageSettingChanged); } QString LanguageSelectionWidget::getSelectedLanguageKey() const @@ -64,3 +68,10 @@ void LanguageSelectionWidget::languageRowChanged(const QModelIndex& current, con translations->selectLanguage(key); translations->updateLanguage(key); } + +void LanguageSelectionWidget::languageSettingChanged(const Setting &, const QVariant) +{ + auto translations = APPLICATION->translations(); + auto index = translations->selectedIndex(); + languageView->setCurrentIndex(index); +} diff --git a/launcher/ui/widgets/LanguageSelectionWidget.h b/launcher/ui/widgets/LanguageSelectionWidget.h index e65936db..4a88924c 100644 --- a/launcher/ui/widgets/LanguageSelectionWidget.h +++ b/launcher/ui/widgets/LanguageSelectionWidget.h @@ -20,6 +20,7 @@ class QVBoxLayout; class QTreeView; class QLabel; +class Setting; class LanguageSelectionWidget: public QWidget { @@ -33,6 +34,7 @@ public: protected slots: void languageRowChanged(const QModelIndex ¤t, const QModelIndex &previous); + void languageSettingChanged(const Setting &, const QVariant); private: QVBoxLayout *verticalLayout = nullptr; diff --git a/packages/rpm/polymc.spec b/packages/rpm/polymc.spec index f5a6fe07..259dc526 100644 --- a/packages/rpm/polymc.spec +++ b/packages/rpm/polymc.spec @@ -6,7 +6,7 @@ Name: polymc Version: 1.0.5 -Release: 1%{?dist} +Release: 2%{?dist} Summary: Minecraft launcher with ability to manage multiple instances # @@ -61,23 +61,18 @@ Source0: https://github.com/PolyMC/PolyMC/archive/%{version}/%{name}-%{ve Source1: https://github.com/MultiMC/libnbtplusplus/archive/%{libnbtplusplus_commit}/libnbtplusplus-%{libnbtplusplus_shortcommit}.tar.gz Source2: https://github.com/PolyMC/quazip/archive/%{quazip_commit}/quazip-%{quazip_shortcommit}.tar.gz -BuildRequires: cmake3 +BuildRequires: cmake BuildRequires: desktop-file-utils BuildRequires: gcc-c++ -# Fix warning: Could not complete Guile gdb module initialization from: -# /usr/share/gdb/guile/gdb/boot.scm -BuildRequires: gdb-headless - BuildRequires: java-devel -BuildRequires: pkgconfig(gl) -BuildRequires: pkgconfig(Qt5) -BuildRequires: pkgconfig(zlib) +BuildRequires: %{?suse_version:lib}qt5-qtbase-devel +BuildRequires: zlib-devel -Requires: java-headless -Requires: pkgconfig(gl) -Requires: pkgconfig(Qt5) -Requires: pkgconfig(zlib) +# Minecraft < 1.17 +Recommends: java-1.8.0-openjdk-headless +# Minecraft >= 1.17 +Recommends: java-17-openjdk-headless %description PolyMC is a free, open source launcher for Minecraft. It allows you to have @@ -105,7 +100,6 @@ mv -f libraries/libnbtplusplus-%{libnbtplusplus_commit} libraries/libnbtplusplus %cmake_build - %install %cmake_install @@ -115,8 +109,11 @@ echo "%{_libdir}/%{name}" > "%{buildroot}%{_sysconfdir}/ld.so.conf.d/%{name}-%{_ %check +# skip tests on systems that aren't officially supported +%if ! 0%{?suse_version} %ctest desktop-file-validate %{buildroot}%{_datadir}/applications/org.polymc.PolyMC.desktop +%endif %files @@ -132,6 +129,9 @@ desktop-file-validate %{buildroot}%{_datadir}/applications/org.polymc.PolyMC.des %changelog +* Mon Jan 24 2022 Jan Drögehoff <sentrycraft123@gmail.com> - 1.0.5-2 +- remove explicit dependencies, correct dependencies to work on OpenSuse + * Sun Jan 09 2022 Jan Drögehoff <sentrycraft123@gmail.com> - 1.0.5-1 - Update to 1.0.5 diff --git a/program_info/org.polymc.PolyMC.desktop.in b/program_info/org.polymc.PolyMC.desktop.in index 8bbdc505..5d982b38 100644 --- a/program_info/org.polymc.PolyMC.desktop.in +++ b/program_info/org.polymc.PolyMC.desktop.in @@ -10,3 +10,4 @@ Icon=org.polymc.PolyMC PrefersNonDefaultGPU=true Categories=Game; Keywords=game;minecraft;launcher; +StartupWMClass=PolyMC diff --git a/program_info/polymc-dark.png b/program_info/polymc-dark.png Binary files differdeleted file mode 100644 index cedf6cef..00000000 --- a/program_info/polymc-dark.png +++ /dev/null diff --git a/program_info/polymc-header-black.svg b/program_info/polymc-header-black.svg new file mode 100644 index 00000000..34cda4ab --- /dev/null +++ b/program_info/polymc-header-black.svg @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg width="1424" height="512" version="1.1" viewBox="0 0 376.77 135.47" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs> + <linearGradient id="linearGradient84726" x1="4.4979" x2="12.435" y1="3.8011" y2="9.5681" gradientUnits="userSpaceOnUse"> + <stop stop-color="#88b858" offset="0"/> + <stop stop-color="#72b147" offset=".5"/> + <stop stop-color="#5a9a30" offset="1"/> + </linearGradient> + </defs> + <g transform="matrix(6.95 0 0 6.9572 3.7759 1.0225)"> + <g> + <path d="m3.561 16.016s0-3.5642 4.9056-3.5642c4.9069 0 4.9056 3.5642 4.9056 3.5642z" fill="#765338"/> + <path d="m8.4667 12.452-4.9056 3.5642-3.0319-9.3311z" fill="#b7835a"/> + <path d="m8.4667 12.452 7.9375-5.7669-3.0319 9.3311z" fill="#5b422d"/> + <path d="m8.8308 12.716-0.36417 0.26458-0.36417-0.26458c0-0.26458 0.36417-0.26458 0.36417-0.26458s0.36417 0 0.36417 0.26458z" fill="#72b147"/> + <path d="m8.4667 12.452s-2e-7 -5.7669 7.9375-5.7669l-0.22507 0.69269-0.91853 1.1965-0.91853 0.13819-0.91853 1.1965-0.91853 0.13819-0.91853 1.1965-0.91853 0.13819-0.91853 1.1965-0.91853 0.13819z" fill="#5a9a30"/> + <path d="m8.1025 12.716-0.91853-0.13819-0.91853-1.1965-0.91853-0.13819-0.91853-1.1965-0.91853-0.13819-0.91853-1.1965-0.91853-0.13819-0.91853-1.1965-0.22507-0.69269c7.9375 1e-7 7.9375 5.7669 7.9375 5.7669z" fill="#88b858"/> + <path d="m0.52917 6.6846 7.9375 5.7669 7.9375-5.7669-7.9375-5.7669z" fill="url(#linearGradient84726)"/> + </g> + <path d="m0.75424 7.3773-0.22507-0.69269 7.9375 5.7669 7.9375-5.7669-0.22507 0.69269-7.7124 5.6034z" fill-opacity="0"/> + </g> + <g id="polymc-header-text" fill="black" transform="matrix(6.9306 0 0 6.9306 -702.9 -659.02)" stroke-width=".26458" aria-label="PolyMC"> + <path d="m120.51 108.48v2.7957h-1.3074v-7.5241h2.8784q1.2609 0 1.9999 0.65629 0.74414 0.65629 0.74414 1.7363 0 1.1059-0.72864 1.7208-0.72346 0.61495-2.0309 0.61495zm0-1.049h1.571q0.69763 0 1.0645-0.32556 0.3669-0.33073 0.3669-0.95084 0-0.60978-0.37207-0.97152-0.37207-0.3669-1.0232-0.37723h-1.6071z"/> + <path d="m125.55 108.43q0-0.82165 0.32556-1.4779 0.32556-0.66145 0.91467-1.0128 0.58911-0.35657 1.3539-0.35657 1.1317 0 1.8345 0.72864 0.70797 0.72863 0.76481 1.9327l5e-3 0.29455q0 0.82682-0.32039 1.478-0.31523 0.65112-0.9095 1.0077-0.58911 0.35657-1.3643 0.35657-1.1834 0-1.8965-0.78548-0.70796-0.79065-0.70796-2.1032zm1.2557 0.10852q0 0.863 0.35657 1.3539 0.35656 0.48576 0.99218 0.48576t0.98702-0.49609q0.35657-0.49609 0.35657-1.4521 0-0.84749-0.36691-1.3436-0.36173-0.49609-0.98701-0.49609-0.61495 0-0.97668 0.49092-0.36174 0.48576-0.36174 1.4573z"/> + <path d="m133.14 111.27h-1.2557v-7.9375h1.2557z"/> + <path d="m136.46 109.47 1.1369-3.793h1.3384l-2.2221 6.4389q-0.5116 1.4108-1.7363 1.4108-0.27388 0-0.60461-0.093v-0.97151l0.23771 0.0155q0.47542 0 0.71314-0.1757 0.24287-0.17053 0.3824-0.57877l0.18087-0.48059-1.9637-5.5655h1.3539z"/> + <path d="m141.48 103.75 2.1704 5.7671 2.1652-5.7671h1.6898v7.5241h-1.3022v-2.4805l0.12919-3.3176-2.2221 5.7981h-0.93534l-2.2169-5.7929 0.12919 3.3124v2.4805h-1.3022v-7.5241z"/> + <path d="m154.79 108.82q-0.11369 1.2041-0.88883 1.881-0.77515 0.67179-2.0619 0.67179-0.89916 0-1.5865-0.42375-0.68212-0.42891-1.0542-1.2144t-0.38758-1.8242v-0.7028q0-1.0645 0.37724-1.8758 0.37724-0.81131 1.08-1.2506 0.70797-0.43925 1.633-0.43925 1.2454 0 2.005 0.67696 0.75965 0.67696 0.88367 1.912h-1.3022q-0.093-0.81132-0.47543-1.1679-0.37723-0.36174-1.111-0.36174-0.85265 0-1.3126 0.62529-0.45475 0.62011-0.46509 1.8242v0.66662q0 1.2196 0.43408 1.8604 0.43925 0.64078 1.2816 0.64078 0.76998 0 1.1576-0.34623t0.49093-1.1524z"/> + </g> +</svg> diff --git a/program_info/polymc-header.svg b/program_info/polymc-header.svg new file mode 100644 index 00000000..a896787f --- /dev/null +++ b/program_info/polymc-header.svg @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg width="1424" height="512" version="1.1" viewBox="0 0 376.77 135.47" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs> + <linearGradient id="linearGradient84726" x1="4.4979" x2="12.435" y1="3.8011" y2="9.5681" gradientUnits="userSpaceOnUse"> + <stop stop-color="#88b858" offset="0"/> + <stop stop-color="#72b147" offset=".5"/> + <stop stop-color="#5a9a30" offset="1"/> + </linearGradient> + </defs> + <g transform="matrix(6.95 0 0 6.9572 3.7759 1.0225)"> + <g> + <path d="m3.561 16.016s0-3.5642 4.9056-3.5642c4.9069 0 4.9056 3.5642 4.9056 3.5642z" fill="#765338"/> + <path d="m8.4667 12.452-4.9056 3.5642-3.0319-9.3311z" fill="#b7835a"/> + <path d="m8.4667 12.452 7.9375-5.7669-3.0319 9.3311z" fill="#5b422d"/> + <path d="m8.8308 12.716-0.36417 0.26458-0.36417-0.26458c0-0.26458 0.36417-0.26458 0.36417-0.26458s0.36417 0 0.36417 0.26458z" fill="#72b147"/> + <path d="m8.4667 12.452s-2e-7 -5.7669 7.9375-5.7669l-0.22507 0.69269-0.91853 1.1965-0.91853 0.13819-0.91853 1.1965-0.91853 0.13819-0.91853 1.1965-0.91853 0.13819-0.91853 1.1965-0.91853 0.13819z" fill="#5a9a30"/> + <path d="m8.1025 12.716-0.91853-0.13819-0.91853-1.1965-0.91853-0.13819-0.91853-1.1965-0.91853-0.13819-0.91853-1.1965-0.91853-0.13819-0.91853-1.1965-0.22507-0.69269c7.9375 1e-7 7.9375 5.7669 7.9375 5.7669z" fill="#88b858"/> + <path d="m0.52917 6.6846 7.9375 5.7669 7.9375-5.7669-7.9375-5.7669z" fill="url(#linearGradient84726)"/> + </g> + <path d="m0.75424 7.3773-0.22507-0.69269 7.9375 5.7669 7.9375-5.7669-0.22507 0.69269-7.7124 5.6034z" fill-opacity="0"/> + </g> + <g id="polymc-header-text" fill="white" transform="matrix(6.9306 0 0 6.9306 -702.9 -659.02)" stroke-width=".26458" aria-label="PolyMC"> + <path d="m120.51 108.48v2.7957h-1.3074v-7.5241h2.8784q1.2609 0 1.9999 0.65629 0.74414 0.65629 0.74414 1.7363 0 1.1059-0.72864 1.7208-0.72346 0.61495-2.0309 0.61495zm0-1.049h1.571q0.69763 0 1.0645-0.32556 0.3669-0.33073 0.3669-0.95084 0-0.60978-0.37207-0.97152-0.37207-0.3669-1.0232-0.37723h-1.6071z"/> + <path d="m125.55 108.43q0-0.82165 0.32556-1.4779 0.32556-0.66145 0.91467-1.0128 0.58911-0.35657 1.3539-0.35657 1.1317 0 1.8345 0.72864 0.70797 0.72863 0.76481 1.9327l5e-3 0.29455q0 0.82682-0.32039 1.478-0.31523 0.65112-0.9095 1.0077-0.58911 0.35657-1.3643 0.35657-1.1834 0-1.8965-0.78548-0.70796-0.79065-0.70796-2.1032zm1.2557 0.10852q0 0.863 0.35657 1.3539 0.35656 0.48576 0.99218 0.48576t0.98702-0.49609q0.35657-0.49609 0.35657-1.4521 0-0.84749-0.36691-1.3436-0.36173-0.49609-0.98701-0.49609-0.61495 0-0.97668 0.49092-0.36174 0.48576-0.36174 1.4573z"/> + <path d="m133.14 111.27h-1.2557v-7.9375h1.2557z"/> + <path d="m136.46 109.47 1.1369-3.793h1.3384l-2.2221 6.4389q-0.5116 1.4108-1.7363 1.4108-0.27388 0-0.60461-0.093v-0.97151l0.23771 0.0155q0.47542 0 0.71314-0.1757 0.24287-0.17053 0.3824-0.57877l0.18087-0.48059-1.9637-5.5655h1.3539z"/> + <path d="m141.48 103.75 2.1704 5.7671 2.1652-5.7671h1.6898v7.5241h-1.3022v-2.4805l0.12919-3.3176-2.2221 5.7981h-0.93534l-2.2169-5.7929 0.12919 3.3124v2.4805h-1.3022v-7.5241z"/> + <path d="m154.79 108.82q-0.11369 1.2041-0.88883 1.881-0.77515 0.67179-2.0619 0.67179-0.89916 0-1.5865-0.42375-0.68212-0.42891-1.0542-1.2144t-0.38758-1.8242v-0.7028q0-1.0645 0.37724-1.8758 0.37724-0.81131 1.08-1.2506 0.70797-0.43925 1.633-0.43925 1.2454 0 2.005 0.67696 0.75965 0.67696 0.88367 1.912h-1.3022q-0.093-0.81132-0.47543-1.1679-0.37723-0.36174-1.111-0.36174-0.85265 0-1.3126 0.62529-0.45475 0.62011-0.46509 1.8242v0.66662q0 1.2196 0.43408 1.8604 0.43925 0.64078 1.2816 0.64078 0.76998 0 1.1576-0.34623t0.49093-1.1524z"/> + </g> +</svg> diff --git a/program_info/polymc-light.png b/program_info/polymc-light.png Binary files differdeleted file mode 100644 index d3899a1f..00000000 --- a/program_info/polymc-light.png +++ /dev/null |