aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYING.md4
-rw-r--r--README.md6
-rw-r--r--launcher/Application.cpp2
-rw-r--r--launcher/CMakeLists.txt7
-rw-r--r--launcher/LaunchController.cpp6
-rwxr-xr-xlauncher/Launcher.in2
-rw-r--r--launcher/java/JavaChecker.cpp6
-rw-r--r--launcher/minecraft/auth/AccountData.cpp10
-rw-r--r--launcher/minecraft/auth/AccountData.h3
-rw-r--r--launcher/minecraft/auth/AccountList.cpp2
-rw-r--r--launcher/minecraft/auth/AuthRequest.cpp2
-rw-r--r--launcher/minecraft/auth/MinecraftAccount.cpp31
-rw-r--r--launcher/minecraft/auth/MinecraftAccount.h12
-rw-r--r--launcher/minecraft/auth/Parsers.cpp2
-rw-r--r--launcher/minecraft/auth/flows/Offline.cpp17
-rw-r--r--launcher/minecraft/auth/flows/Offline.h22
-rw-r--r--launcher/minecraft/auth/steps/MinecraftProfileStep.cpp8
-rw-r--r--launcher/minecraft/auth/steps/OfflineStep.cpp18
-rw-r--r--launcher/minecraft/auth/steps/OfflineStep.h20
-rw-r--r--launcher/translations/TranslationsModel.cpp52
-rw-r--r--launcher/ui/dialogs/AboutDialog.cpp2
-rw-r--r--launcher/ui/dialogs/MSALoginDialog.cpp12
-rw-r--r--launcher/ui/dialogs/MSALoginDialog.ui27
-rw-r--r--launcher/ui/dialogs/OfflineLoginDialog.cpp98
-rw-r--r--launcher/ui/dialogs/OfflineLoginDialog.h43
-rw-r--r--launcher/ui/dialogs/OfflineLoginDialog.ui67
-rw-r--r--launcher/ui/pages/global/AccountListPage.cpp23
-rw-r--r--launcher/ui/pages/global/AccountListPage.h1
-rw-r--r--launcher/ui/pages/global/AccountListPage.ui6
-rw-r--r--launcher/ui/pages/global/LauncherPage.cpp4
-rw-r--r--launcher/ui/widgets/LanguageSelectionWidget.cpp11
-rw-r--r--launcher/ui/widgets/LanguageSelectionWidget.h2
-rw-r--r--packages/rpm/polymc.spec28
-rw-r--r--program_info/org.polymc.PolyMC.desktop.in1
-rw-r--r--program_info/polymc-dark.pngbin50722 -> 0 bytes
-rw-r--r--program_info/polymc-header-black.svg31
-rw-r--r--program_info/polymc-header.svg31
-rw-r--r--program_info/polymc-light.pngbin48991 -> 0 bytes
38 files changed, 198 insertions, 421 deletions
diff --git a/COPYING.md b/COPYING.md
index 4205d441..1ac6d5cb 100644
--- a/COPYING.md
+++ b/COPYING.md
@@ -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");
diff --git a/README.md b/README.md
index d9d414e7..778a2d96 100644
--- a/README.md
+++ b/README.md
@@ -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 &current, 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
deleted file mode 100644
index cedf6cef..00000000
--- a/program_info/polymc-dark.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index d3899a1f..00000000
--- a/program_info/polymc-light.png
+++ /dev/null
Binary files differ