From 87db723008727b32681f5a2a39b20497bc5fb34e Mon Sep 17 00:00:00 2001 From: Tayou Date: Tue, 18 Apr 2023 20:25:45 +0200 Subject: [PATCH 01/72] add global .editorconfig for doxygen comment style Signed-off-by: Tayou --- .editorconfig | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..a6521c873 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +# Visual Studio generated .editorconfig file with C++ settings. +root = true + +[*.{c++,cc,cpp,cppm,cxx,h,h++,hh,hpp,hxx,inl,ipp,ixx,tlh,tli}] + +# Visual C++ Code Style settings + +cpp_generate_documentation_comments = doxygen_triple_slash From c0f9ccc5b5fc943c033fd52af5eca1ddadcc1be0 Mon Sep 17 00:00:00 2001 From: Tayou <31988415+TayouVR@users.noreply.github.com> Date: Sun, 28 May 2023 19:57:08 +0200 Subject: [PATCH 02/72] Use slash_star comment style in .editorconfig Signed-off-by: Tayou <31988415+TayouVR@users.noreply.github.com> --- .editorconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.editorconfig b/.editorconfig index a6521c873..56166b207 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,8 +1,8 @@ -# Visual Studio generated .editorconfig file with C++ settings. +# EditorConfig specs and documentation: https://EditorConfig.org + +# top-most EditorConfig file root = true +# C++ Code Style settings [*.{c++,cc,cpp,cppm,cxx,h,h++,hh,hpp,hxx,inl,ipp,ixx,tlh,tli}] - -# Visual C++ Code Style settings - -cpp_generate_documentation_comments = doxygen_triple_slash +cpp_generate_documentation_comments = doxygen_slash_star From 9d2516a199ae4c33f773ab00ce59ecb2a6dfd0a5 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 22 Jun 2023 16:00:45 +0300 Subject: [PATCH 03/72] Added ExportModsToStringTask Signed-off-by: Trial97 --- launcher/CMakeLists.txt | 3 + .../helpers/ExportModsToStringTask.cpp | 114 ++++++++++++++++++ .../helpers/ExportModsToStringTask.h | 33 +++++ 3 files changed, 150 insertions(+) create mode 100644 launcher/modplatform/helpers/ExportModsToStringTask.cpp create mode 100644 launcher/modplatform/helpers/ExportModsToStringTask.h diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index ce2771a49..c7efdad84 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -487,6 +487,9 @@ set(API_SOURCES modplatform/helpers/HashUtils.cpp modplatform/helpers/OverrideUtils.h modplatform/helpers/OverrideUtils.cpp + + modplatform/helpers/ExportModsToStringTask.h + modplatform/helpers/ExportModsToStringTask.cpp ) set(FTB_SOURCES diff --git a/launcher/modplatform/helpers/ExportModsToStringTask.cpp b/launcher/modplatform/helpers/ExportModsToStringTask.cpp new file mode 100644 index 000000000..a105fc352 --- /dev/null +++ b/launcher/modplatform/helpers/ExportModsToStringTask.cpp @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2023 Trial97 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "ExportModsToStringTask.h" +#include "modplatform/ModIndex.h" + +namespace ExportToString { +QString ExportModsToStringTask(QList mods, Formats format, OptionalData extraData) +{ + switch (format) { + case HTML: { + QStringList lines; + for (auto mod : mods) { + auto meta = mod->metadata(); + auto modName = mod->name(); + if (extraData & Url) { + auto url = mod->homeurl(); + if (meta != nullptr) { + url = (meta->provider == ModPlatform::ResourceProvider::FLAME ? "https://www.curseforge.com/minecraft/mc-mods/" + : "https://modrinth.com/mod/") + + meta->project_id.toString(); + } + if (!url.isEmpty()) + modName = QString("%2").arg(url, modName); + } + auto line = modName; + if (extraData & Version) { + auto ver = mod->version(); + if (ver.isEmpty() && meta != nullptr) + ver = meta->version().toString(); + if (!ver.isEmpty()) + line += QString("[%1]").arg(ver); + } + if (extraData & Authors && !mod->authors().isEmpty()) + line += " by " + mod->authors().join(", "); + lines.append(QString("
    %1
").arg(line)); + } + return QString("\n\t%1\n").arg(lines.join("\n\t")); + } + case MARKDOWN: { + QStringList lines; + for (auto mod : mods) { + auto meta = mod->metadata(); + auto modName = mod->name(); + if (extraData & Url) { + auto url = mod->homeurl(); + if (meta != nullptr) { + url = (meta->provider == ModPlatform::ResourceProvider::FLAME ? "https://www.curseforge.com/minecraft/mc-mods/" + : "https://modrinth.com/mod/") + + meta->project_id.toString(); + } + if (!url.isEmpty()) + modName = QString("[%1](%2)").arg(modName, url); + } + auto line = modName; + if (extraData & Version) { + auto ver = mod->version(); + if (ver.isEmpty() && meta != nullptr) + ver = meta->version().toString(); + if (!ver.isEmpty()) + line += QString("[%1]").arg(ver); + } + if (extraData & Authors && !mod->authors().isEmpty()) + line += " by " + mod->authors().join(", "); + lines << line; + } + return lines.join("\n"); + } + default: { + return QString("unknown format:%1").arg(format); + } + } +} + +QString ExportModsToStringTask(QList mods, QString lineTemplate) +{ + QStringList lines; + for (auto mod : mods) { + auto meta = mod->metadata(); + auto modName = mod->name(); + + auto url = mod->homeurl(); + if (meta != nullptr) { + url = (meta->provider == ModPlatform::ResourceProvider::FLAME ? "https://www.curseforge.com/minecraft/mc-mods/" + : "https://modrinth.com/mod/") + + meta->project_id.toString(); + } + auto ver = mod->version(); + if (ver.isEmpty() && meta != nullptr) + ver = meta->version().toString(); + auto authors = mod->authors().join(", "); + lines << QString(lineTemplate) + .replace("{name}", modName) + .replace("{url}", url) + .replace("{version}", ver) + .replace("{authors}", authors); + } + return lines.join("\n"); +} +} // namespace ExportToString \ No newline at end of file diff --git a/launcher/modplatform/helpers/ExportModsToStringTask.h b/launcher/modplatform/helpers/ExportModsToStringTask.h new file mode 100644 index 000000000..756c69f77 --- /dev/null +++ b/launcher/modplatform/helpers/ExportModsToStringTask.h @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2023 Trial97 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include +#include "minecraft/mod/Mod.h" + +namespace ExportToString { + +enum Formats { HTML, MARKDOWN }; +enum OptionalData { + Authors = 1 << 0, + Url = 1 << 1, + Version = 1 << 2, +}; +QString ExportModsToStringTask(QList mods, Formats format, OptionalData extraData); +QString ExportModsToStringTask(QList mods, QString lineTemplate); +} // namespace ExportToString From f7d502c68c530d66b385d530c838a9a6566828d0 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 22 Jun 2023 16:05:47 +0300 Subject: [PATCH 04/72] Added ExportModsToStringDialog Signed-off-by: Trial97 --- launcher/CMakeLists.txt | 3 + launcher/ui/MainWindow.cpp | 10 + launcher/ui/MainWindow.h | 1 + launcher/ui/MainWindow.ui | 8 + .../ui/dialogs/ExportModsToStringDialog.cpp | 119 ++++++++++++ .../ui/dialogs/ExportModsToStringDialog.h | 45 +++++ .../ui/dialogs/ExportModsToStringDialog.ui | 171 ++++++++++++++++++ 7 files changed, 357 insertions(+) create mode 100644 launcher/ui/dialogs/ExportModsToStringDialog.cpp create mode 100644 launcher/ui/dialogs/ExportModsToStringDialog.h create mode 100644 launcher/ui/dialogs/ExportModsToStringDialog.ui diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index c7efdad84..5ef97f422 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -911,6 +911,8 @@ SET(LAUNCHER_SOURCES ui/dialogs/ExportInstanceDialog.h ui/dialogs/ExportMrPackDialog.cpp ui/dialogs/ExportMrPackDialog.h + ui/dialogs/ExportModsToStringDialog.cpp + ui/dialogs/ExportModsToStringDialog.h ui/dialogs/IconPickerDialog.cpp ui/dialogs/IconPickerDialog.h ui/dialogs/ImportResourceDialog.cpp @@ -1058,6 +1060,7 @@ qt_wrap_ui(LAUNCHER_UI ui/dialogs/SkinUploadDialog.ui ui/dialogs/ExportInstanceDialog.ui ui/dialogs/ExportMrPackDialog.ui + ui/dialogs/ExportModsToStringDialog.ui ui/dialogs/IconPickerDialog.ui ui/dialogs/ImportResourceDialog.ui ui/dialogs/MSALoginDialog.ui diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index e04011cab..02ea30c36 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -43,6 +43,7 @@ #include "FileSystem.h" #include "MainWindow.h" +#include "ui/dialogs/ExportModsToStringDialog.h" #include "ui_MainWindow.h" #include @@ -205,6 +206,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi auto exportInstanceMenu = new QMenu(this); exportInstanceMenu->addAction(ui->actionExportInstanceZip); exportInstanceMenu->addAction(ui->actionExportInstanceMrPack); + exportInstanceMenu->addAction(ui->actionExportInstanceToString); ui->actionExportInstance->setMenu(exportInstanceMenu); } @@ -1416,6 +1418,14 @@ void MainWindow::on_actionExportInstanceMrPack_triggered() } } +void MainWindow::on_actionExportInstanceToString_triggered() +{ + if (m_selectedInstance) { + ExportModsToStringDialog dlg(m_selectedInstance, this); + dlg.exec(); + } +} + void MainWindow::on_actionRenameInstance_triggered() { if (m_selectedInstance) diff --git a/launcher/ui/MainWindow.h b/launcher/ui/MainWindow.h index 3bb20c4a4..9b38810f0 100644 --- a/launcher/ui/MainWindow.h +++ b/launcher/ui/MainWindow.h @@ -157,6 +157,7 @@ private slots: inline void on_actionExportInstance_triggered() { on_actionExportInstanceZip_triggered(); } void on_actionExportInstanceZip_triggered(); void on_actionExportInstanceMrPack_triggered(); + void on_actionExportInstanceToString_triggered(); void on_actionRenameInstance_triggered(); diff --git a/launcher/ui/MainWindow.ui b/launcher/ui/MainWindow.ui index f67fb1859..e6e52a912 100644 --- a/launcher/ui/MainWindow.ui +++ b/launcher/ui/MainWindow.ui @@ -479,6 +479,14 @@ Modrinth (mrpack) + + + + + + Text + + diff --git a/launcher/ui/dialogs/ExportModsToStringDialog.cpp b/launcher/ui/dialogs/ExportModsToStringDialog.cpp new file mode 100644 index 000000000..d08a4c70c --- /dev/null +++ b/launcher/ui/dialogs/ExportModsToStringDialog.cpp @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2023 Trial97 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ExportModsToStringDialog.h" +#include +#include +#include +#include "minecraft/MinecraftInstance.h" +#include "minecraft/mod/ModFolderModel.h" +#include "modplatform/helpers/ExportModsToStringTask.h" +#include "ui_ExportModsToStringDialog.h" + +#include +#include +#include +#include +#include + +ExportModsToStringDialog::ExportModsToStringDialog(InstancePtr instance, QWidget* parent) + : QDialog(parent), m_template_selected(false), ui(new Ui::ExportModsToStringDialog) +{ + ui->setupUi(this); + ui->templateGroup->setDisabled(true); + + MinecraftInstance* mcInstance = dynamic_cast(instance.get()); + if (mcInstance) { + mcInstance->loaderModList()->update(); + connect(mcInstance->loaderModList().get(), &ModFolderModel::updateFinished, this, [this, mcInstance]() { + m_allMods = mcInstance->loaderModList()->allMods(); + trigger(); + }); + } + + connect(ui->formatComboBox, &QComboBox::currentIndexChanged, this, &ExportModsToStringDialog::formatChanged); + connect(ui->authorsCheckBox, &QCheckBox::stateChanged, this, &ExportModsToStringDialog::trigger); + connect(ui->versionCheckBox, &QCheckBox::stateChanged, this, &ExportModsToStringDialog::trigger); + connect(ui->urlCheckBox, &QCheckBox::stateChanged, this, &ExportModsToStringDialog::trigger); + connect(ui->templateText, &QTextEdit::textChanged, this, &ExportModsToStringDialog::trigger); + connect(ui->copyButton, &QPushButton::clicked, this, [this]() { + this->ui->finalText->selectAll(); + this->ui->finalText->copy(); + }); +} + +ExportModsToStringDialog::~ExportModsToStringDialog() +{ + delete ui; +} + +void ExportModsToStringDialog::formatChanged(int index) +{ + switch (index) { + case 0: { + ui->templateGroup->setDisabled(true); + ui->optionsGroup->setDisabled(false); + break; + } + case 1: { + ui->templateGroup->setDisabled(true); + ui->optionsGroup->setDisabled(false); + break; + } + case 2: { + ui->templateGroup->setDisabled(false); + ui->optionsGroup->setDisabled(true); + break; + } + } + trigger(); +} + +void ExportModsToStringDialog::trigger() +{ + ExportToString::Formats format; + switch (ui->formatComboBox->currentIndex()) { + case 2: { + m_template_selected = true; + ui->finalText->setPlainText(ExportToString::ExportModsToStringTask(m_allMods, ui->templateText->toPlainText())); + return; + } + case 0: { + format = ExportToString::HTML; + break; + } + case 1: { + format = ExportToString::MARKDOWN; + break; + } + } + auto opt = 0; + if (ui->authorsCheckBox->isChecked()) + opt |= ExportToString::Authors; + if (ui->versionCheckBox->isChecked()) + opt |= ExportToString::Version; + if (ui->urlCheckBox->isChecked()) + opt |= ExportToString::Url; + ui->finalText->setPlainText(ExportToString::ExportModsToStringTask(m_allMods, format, static_cast(opt))); + if (!m_template_selected) { + auto exampleLine = format == ExportToString::HTML ? "
    {name}[{version}] by {authors}
" + : "[{name}]({url})[{version}] by {authors}"; + if (ui->templateText->toPlainText() != exampleLine) + ui->templateText->setPlainText(exampleLine); + } +} diff --git a/launcher/ui/dialogs/ExportModsToStringDialog.h b/launcher/ui/dialogs/ExportModsToStringDialog.h new file mode 100644 index 000000000..7fada4d54 --- /dev/null +++ b/launcher/ui/dialogs/ExportModsToStringDialog.h @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2023 Trial97 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include "BaseInstance.h" +#include "minecraft/mod/Mod.h" + +namespace Ui { +class ExportModsToStringDialog; +} + +class ExportModsToStringDialog : public QDialog { + Q_OBJECT + + public: + explicit ExportModsToStringDialog(InstancePtr instance, QWidget* parent = nullptr); + ~ExportModsToStringDialog(); + + protected slots: + void formatChanged(int index); + void trigger(); + + private: + QList m_allMods; + bool m_template_selected; + Ui::ExportModsToStringDialog* ui; +}; diff --git a/launcher/ui/dialogs/ExportModsToStringDialog.ui b/launcher/ui/dialogs/ExportModsToStringDialog.ui new file mode 100644 index 000000000..4451a2785 --- /dev/null +++ b/launcher/ui/dialogs/ExportModsToStringDialog.ui @@ -0,0 +1,171 @@ + + + ExportModsToStringDialog + + + + 0 + 0 + 650 + 446 + + + + Export Modrinth Pack + + + true + + + + + + + + Settings + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + 1 + + + Format + + + + + + + + HTML + + + + + Markdown + + + + + Custom + + + + + + + + Template + + + + + + + + + + + + Optional Info + + + + + + Version + + + + + + + Authors + + + + + + + URL + + + + + + + + + + + + + Result + + + + + + + 0 + 143 + + + + true + + + + + + + + + + + + + + Copy + + + + + + + QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + ExportModsToStringDialog + accept() + + + 334 + 435 + + + 324 + 206 + + + + + From b84dc8551a13ed87d09e6f8ca8b401c57d549f95 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 22 Jun 2023 16:49:19 +0300 Subject: [PATCH 05/72] Fixed trigger function Signed-off-by: Trial97 --- launcher/ui/dialogs/ExportModsToStringDialog.cpp | 12 ++++++------ launcher/ui/dialogs/ExportModsToStringDialog.h | 3 ++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/launcher/ui/dialogs/ExportModsToStringDialog.cpp b/launcher/ui/dialogs/ExportModsToStringDialog.cpp index d08a4c70c..ae793dcb3 100644 --- a/launcher/ui/dialogs/ExportModsToStringDialog.cpp +++ b/launcher/ui/dialogs/ExportModsToStringDialog.cpp @@ -42,16 +42,16 @@ ExportModsToStringDialog::ExportModsToStringDialog(InstancePtr instance, QWidget mcInstance->loaderModList()->update(); connect(mcInstance->loaderModList().get(), &ModFolderModel::updateFinished, this, [this, mcInstance]() { m_allMods = mcInstance->loaderModList()->allMods(); - trigger(); + triggerImp(); }); } - connect(ui->formatComboBox, &QComboBox::currentIndexChanged, this, &ExportModsToStringDialog::formatChanged); + connect(ui->formatComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &ExportModsToStringDialog::formatChanged); connect(ui->authorsCheckBox, &QCheckBox::stateChanged, this, &ExportModsToStringDialog::trigger); connect(ui->versionCheckBox, &QCheckBox::stateChanged, this, &ExportModsToStringDialog::trigger); connect(ui->urlCheckBox, &QCheckBox::stateChanged, this, &ExportModsToStringDialog::trigger); - connect(ui->templateText, &QTextEdit::textChanged, this, &ExportModsToStringDialog::trigger); - connect(ui->copyButton, &QPushButton::clicked, this, [this]() { + connect(ui->templateText, &QTextEdit::textChanged, this, &ExportModsToStringDialog::triggerImp); + connect(ui->copyButton, &QPushButton::clicked, this, [this](bool) { this->ui->finalText->selectAll(); this->ui->finalText->copy(); }); @@ -81,10 +81,10 @@ void ExportModsToStringDialog::formatChanged(int index) break; } } - trigger(); + triggerImp(); } -void ExportModsToStringDialog::trigger() +void ExportModsToStringDialog::triggerImp() { ExportToString::Formats format; switch (ui->formatComboBox->currentIndex()) { diff --git a/launcher/ui/dialogs/ExportModsToStringDialog.h b/launcher/ui/dialogs/ExportModsToStringDialog.h index 7fada4d54..d195d1cec 100644 --- a/launcher/ui/dialogs/ExportModsToStringDialog.h +++ b/launcher/ui/dialogs/ExportModsToStringDialog.h @@ -36,7 +36,8 @@ class ExportModsToStringDialog : public QDialog { protected slots: void formatChanged(int index); - void trigger(); + void triggerImp(); + void trigger(int) { triggerImp(); }; private: QList m_allMods; From 836e8d2e28b4ab63e6c4189410c38ad1a7fd2718 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 22 Jun 2023 17:39:57 +0300 Subject: [PATCH 06/72] Fixed code quality Signed-off-by: Trial97 --- launcher/ui/dialogs/ExportModsToStringDialog.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/launcher/ui/dialogs/ExportModsToStringDialog.cpp b/launcher/ui/dialogs/ExportModsToStringDialog.cpp index ae793dcb3..29d69918e 100644 --- a/launcher/ui/dialogs/ExportModsToStringDialog.cpp +++ b/launcher/ui/dialogs/ExportModsToStringDialog.cpp @@ -86,7 +86,7 @@ void ExportModsToStringDialog::formatChanged(int index) void ExportModsToStringDialog::triggerImp() { - ExportToString::Formats format; + auto format = ExportToString::HTML; switch (ui->formatComboBox->currentIndex()) { case 2: { m_template_selected = true; @@ -101,6 +101,9 @@ void ExportModsToStringDialog::triggerImp() format = ExportToString::MARKDOWN; break; } + default: { + return; + } } auto opt = 0; if (ui->authorsCheckBox->isChecked()) From da6f846a496f70dd5339ed1bdba35842feaa1286 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 22 Jun 2023 18:11:03 +0300 Subject: [PATCH 07/72] Use slug for url Signed-off-by: Trial97 --- launcher/modplatform/helpers/ExportModsToStringTask.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launcher/modplatform/helpers/ExportModsToStringTask.cpp b/launcher/modplatform/helpers/ExportModsToStringTask.cpp index a105fc352..c10560c1c 100644 --- a/launcher/modplatform/helpers/ExportModsToStringTask.cpp +++ b/launcher/modplatform/helpers/ExportModsToStringTask.cpp @@ -32,7 +32,7 @@ QString ExportModsToStringTask(QList mods, Formats format, OptionalData ex if (meta != nullptr) { url = (meta->provider == ModPlatform::ResourceProvider::FLAME ? "https://www.curseforge.com/minecraft/mc-mods/" : "https://modrinth.com/mod/") + - meta->project_id.toString(); + meta->slug.remove(".pw.toml"); } if (!url.isEmpty()) modName = QString("%2").arg(url, modName); @@ -61,7 +61,7 @@ QString ExportModsToStringTask(QList mods, Formats format, OptionalData ex if (meta != nullptr) { url = (meta->provider == ModPlatform::ResourceProvider::FLAME ? "https://www.curseforge.com/minecraft/mc-mods/" : "https://modrinth.com/mod/") + - meta->project_id.toString(); + meta->slug.remove(".pw.toml"); } if (!url.isEmpty()) modName = QString("[%1](%2)").arg(modName, url); From 3c9c39cb890252f94d0c50caa00de5439881d7f6 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 22 Jun 2023 20:04:06 +0300 Subject: [PATCH 08/72] Updated slug for url Signed-off-by: Trial97 --- launcher/modplatform/helpers/ExportModsToStringTask.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/modplatform/helpers/ExportModsToStringTask.cpp b/launcher/modplatform/helpers/ExportModsToStringTask.cpp index c10560c1c..e7be5ce13 100644 --- a/launcher/modplatform/helpers/ExportModsToStringTask.cpp +++ b/launcher/modplatform/helpers/ExportModsToStringTask.cpp @@ -97,7 +97,7 @@ QString ExportModsToStringTask(QList mods, QString lineTemplate) if (meta != nullptr) { url = (meta->provider == ModPlatform::ResourceProvider::FLAME ? "https://www.curseforge.com/minecraft/mc-mods/" : "https://modrinth.com/mod/") + - meta->project_id.toString(); + meta->slug.remove(".pw.toml"); } auto ver = mod->version(); if (ver.isEmpty() && meta != nullptr) From bf95cfb30eee52f23d0279284f70931b2c968dd3 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 23 Jun 2023 01:37:28 +0300 Subject: [PATCH 09/72] Added CatPacks Signed-off-by: Trial97 --- launcher/Application.cpp | 12 +- launcher/Application.h | 9 +- launcher/CMakeLists.txt | 2 + launcher/ui/MainWindow.cpp | 4 +- launcher/ui/setupwizard/ThemeWizardPage.cpp | 2 +- launcher/ui/themes/CatPack.cpp | 109 ++++++++++++++++++ launcher/ui/themes/CatPack.h | 98 ++++++++++++++++ launcher/ui/themes/ThemeManager.cpp | 82 ++++++++++--- launcher/ui/themes/ThemeManager.h | 15 ++- .../ui/widgets/ThemeCustomizationWidget.cpp | 17 ++- .../ui/widgets/ThemeCustomizationWidget.h | 34 +++--- 11 files changed, 331 insertions(+), 53 deletions(-) create mode 100644 launcher/ui/themes/CatPack.cpp create mode 100644 launcher/ui/themes/CatPack.h diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 724e6e44d..d8ac2168d 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -1173,7 +1173,17 @@ QIcon Application::getThemedIcon(const QString& name) return QIcon::fromTheme(name); } -bool Application::openJsonEditor(const QString &filename) +QList Application::getValidCatPacks() +{ + return m_themeManager->getValidCatPacks(); +} + +QString Application::getCatPack(QString catName) +{ + return m_themeManager->getCatPack(catName); +} + +bool Application::openJsonEditor(const QString& filename) { const QString file = QDir::current().absoluteFilePath(filename); if (m_settings->get("JsonEditor").toString().isEmpty()) diff --git a/launcher/Application.h b/launcher/Application.h index ced0af17d..55b01cd49 100644 --- a/launcher/Application.h +++ b/launcher/Application.h @@ -48,6 +48,7 @@ #include #include "minecraft/launch/MinecraftServerTarget.h" +#include "ui/themes/CatPack.h" class LaunchController; class LocalPeer; @@ -126,9 +127,11 @@ public: void setApplicationTheme(const QString& name); - shared_qobject_ptr updater() { - return m_updater; - } + QList getValidCatPacks(); + + QString getCatPack(QString catName = ""); + + shared_qobject_ptr updater() { return m_updater; } void triggerUpdateCheck(); diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index ce2771a49..4d0f7d06e 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -755,6 +755,8 @@ SET(LAUNCHER_SOURCES ui/themes/SystemTheme.h ui/themes/ThemeManager.cpp ui/themes/ThemeManager.h + ui/themes/CatPack.cpp + ui/themes/CatPack.h # Processes LaunchController.h diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index e04011cab..8e1b56136 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -924,14 +924,14 @@ void MainWindow::setCatBackground(bool enabled) view->setStyleSheet(QString(R"( InstanceView { - background-image: url(:/backgrounds/%1); + background-image: url(%1); background-attachment: fixed; background-clip: padding; background-position: bottom right; background-repeat: none; background-color:palette(base); })") - .arg(ThemeManager::getCatImage())); + .arg(APPLICATION->getCatPack())); } else { view->setStyleSheet(QString()); } diff --git a/launcher/ui/setupwizard/ThemeWizardPage.cpp b/launcher/ui/setupwizard/ThemeWizardPage.cpp index 42826aba1..282a01acb 100644 --- a/launcher/ui/setupwizard/ThemeWizardPage.cpp +++ b/launcher/ui/setupwizard/ThemeWizardPage.cpp @@ -61,7 +61,7 @@ void ThemeWizardPage::updateIcons() void ThemeWizardPage::updateCat() { qDebug() << "Setting Cat"; - ui->catImagePreviewButton->setIcon(QIcon(QString(R"(:/backgrounds/%1)").arg(ThemeManager::getCatImage()))); + ui->catImagePreviewButton->setIcon(QIcon(QString(R"(%1)").arg(APPLICATION->getCatPack()))); } void ThemeWizardPage::retranslate() diff --git a/launcher/ui/themes/CatPack.cpp b/launcher/ui/themes/CatPack.cpp new file mode 100644 index 000000000..e74b9709a --- /dev/null +++ b/launcher/ui/themes/CatPack.cpp @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2023 Trial97 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ui/themes/CatPack.h" +#include +#include +#include +#include +#include +#include +#include +#include "FileSystem.h" +#include "Json.h" +#include "ui/themes/ThemeManager.h" + +QString BasicCatPack::path() +{ + const QDateTime now = QDateTime::currentDateTime(); + const QDateTime birthday(QDate(now.date().year(), 11, 30), QTime(0, 0)); + const QDateTime xmas(QDate(now.date().year(), 12, 25), QTime(0, 0)); + const QDateTime halloween(QDate(now.date().year(), 10, 31), QTime(0, 0)); + + QString cat = QString(":/backgrounds/%1").arg(m_id); + if (std::abs(now.daysTo(xmas)) <= 4) { + cat += "-xmas"; + } else if (std::abs(now.daysTo(halloween)) <= 4) { + cat += "-spooky"; + } else if (std::abs(now.daysTo(birthday)) <= 12) { + cat += "-bday"; + } + return cat; +} + +JsonCatPack::JsonCatPack(QFileInfo& manifestInfo) : BasicCatPack(manifestInfo.dir().dirName()) +{ + QString path = FS::PathCombine("catpacks", m_id); + + if (!FS::ensureFolderPathExists(path)) { + themeWarningLog() << "couldn't create folder for catpack!"; + return; + } + + if (manifestInfo.exists() && manifestInfo.isFile()) { + try { + auto doc = Json::requireDocument(manifestInfo.absoluteFilePath(), "CatPack JSON file"); + const auto root = doc.object(); + m_name = Json::requireString(root, "name", "Catpack name"); + m_id = Json::requireString(root, "id", "Catpack ID"); + m_defaultPath = FS::PathCombine(path, Json::requireString(root, "default", "Deafult Cat")); + auto variants = Json::ensureArray(root, "variants", QJsonArray(), "Catpack Variants"); + for (auto v : variants) { + auto variant = Json::ensureObject(v, QJsonObject(), "Cat variant"); + m_variants << Variant{ FS::PathCombine(path, Json::requireString(variant, "path", "Variant path")), + date(Json::requireString(variant, "startTime", "Variant startTime")), + date(Json::requireString(variant, "endTime", "Variant endTime")) }; + } + + } catch (const Exception& e) { + themeWarningLog() << "Couldn't load catpack json: " << e.cause(); + return; + } + } else { + themeDebugLog() << "No catpack json present."; + } +} + +QString JsonCatPack::path() +{ + const QDateTime now = QDateTime::currentDateTime(); + for (auto var : m_variants) { + QDateTime startDate(QDate(now.date().year(), var.startTime.mounth, var.startTime.day), QTime(0, 0)); + QDateTime endDate(QDate(now.date().year(), var.endTime.mounth, var.endTime.day), QTime(0, 0)); + if (startDate.daysTo(now) > 0 && now.daysTo(endDate) > 0) + return var.path; + } + return m_defaultPath; +} diff --git a/launcher/ui/themes/CatPack.h b/launcher/ui/themes/CatPack.h new file mode 100644 index 000000000..d9010b8ea --- /dev/null +++ b/launcher/ui/themes/CatPack.h @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2023 Trial97 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +class CatPack { + public: + virtual ~CatPack() {} + virtual QString id() = 0; + virtual QString name() = 0; + virtual QString path() = 0; +}; + +class BasicCatPack : public CatPack { + public: + BasicCatPack(QString id, QString name) : m_id(id), m_name(name) {} + BasicCatPack(QString id) : BasicCatPack(id, id) {} + virtual QString id() { return m_id; }; + virtual QString name() { return m_name; }; + virtual QString path(); + + protected: + QString m_id; + QString m_name; +}; + +class FileCatPack : public BasicCatPack { + public: + FileCatPack(QString id, QFileInfo& fileInfo) : BasicCatPack(id), m_path(fileInfo.absoluteFilePath()) {} + FileCatPack(QFileInfo& fileInfo) : FileCatPack(fileInfo.baseName(), fileInfo) {} + virtual QString path() { return m_path; } + + private: + QString m_path; +}; + +class JsonCatPack : public BasicCatPack { + public: + struct date { + date(QString d) + { + auto sp = d.split("-"); + day = sp[0].toInt(); + if (sp.length() >= 2) + mounth = sp[1].length(); + } + int mounth; + int day; + }; + struct Variant { + QString path; + date startTime; + date endTime; + }; + JsonCatPack(QFileInfo& manifestInfo); + virtual QString path(); + + private: + QString m_defaultPath; + QList m_variants; +}; diff --git a/launcher/ui/themes/ThemeManager.cpp b/launcher/ui/themes/ThemeManager.cpp index 94ac8a245..bfd0550a8 100644 --- a/launcher/ui/themes/ThemeManager.cpp +++ b/launcher/ui/themes/ThemeManager.cpp @@ -22,6 +22,7 @@ #include #include #include "ui/themes/BrightTheme.h" +#include "ui/themes/CatPack.h" #include "ui/themes/CustomTheme.h" #include "ui/themes/DarkTheme.h" #include "ui/themes/SystemTheme.h" @@ -32,6 +33,7 @@ ThemeManager::ThemeManager(MainWindow* mainWindow) { m_mainWindow = mainWindow; initializeThemes(); + initializeCatPacks(); } /// @brief Adds the Theme to the list of themes @@ -111,6 +113,16 @@ QList ThemeManager::getValidApplicationThemes() return ret; } +QList ThemeManager::getValidCatPacks() +{ + QList ret; + ret.reserve(m_catPacks.size()); + for (auto&& [id, theme] : m_catPacks) { + ret.append(theme.get()); + } + return ret; +} + void ThemeManager::setIconTheme(const QString& name) { QIcon::setThemeName(name); @@ -137,19 +149,63 @@ void ThemeManager::setApplicationTheme(const QString& name, bool initial) } } -QString ThemeManager::getCatImage(QString catName) +QString ThemeManager::getCatPack(QString catName) { - QDateTime now = QDateTime::currentDateTime(); - QDateTime birthday(QDate(now.date().year(), 11, 30), QTime(0, 0)); - QDateTime xmas(QDate(now.date().year(), 12, 25), QTime(0, 0)); - QDateTime halloween(QDate(now.date().year(), 10, 31), QTime(0, 0)); - QString cat = !catName.isEmpty() ? catName : APPLICATION->settings()->get("BackgroundCat").toString(); - if (std::abs(now.daysTo(xmas)) <= 4) { - cat += "-xmas"; - } else if (std::abs(now.daysTo(halloween)) <= 4) { - cat += "-spooky"; - } else if (std::abs(now.daysTo(birthday)) <= 12) { - cat += "-bday"; + auto catIter = m_catPacks.find(!catName.isEmpty() ? catName : APPLICATION->settings()->get("BackgroundCat").toString()); + if (catIter != m_catPacks.end()) { + auto& catPack = catIter->second; + themeDebugLog() << "applying catpack" << catPack->id(); + return catPack->path(); + } else { + themeWarningLog() << "Tried to get invalid catPack:" << catName; + } + + return m_catPacks.begin()->second->path(); +} + +QString ThemeManager::addCatPack(std::unique_ptr catPack) +{ + QString id = catPack->id(); + m_catPacks.emplace(id, std::move(catPack)); + return id; +} + +void ThemeManager::initializeCatPacks() +{ + QList> defaultCats{ { "kitteh", QObject::tr("Background Cat (from MultiMC)") }, + { "rory", QObject::tr("Rory ID 11 (drawn by Ashtaka)") }, + { "rory-flat", QObject::tr("Rory ID 11 (flat edition, drawn by Ashtaka)") }, + { "teawie", QObject::tr("Teawie (drawn by SympathyTea)") } }; + for (auto [id, name] : defaultCats) { + addCatPack(std::unique_ptr(new BasicCatPack(id, name))); + } + QDir catpacksDir("./catpacks/"); + QString catpacksFolder = catpacksDir.absoluteFilePath(""); + themeDebugLog() << "CatPacks Folder Path: " << catpacksFolder; + + auto loadFiles = [this](QDir dir) { + // Load image files directly + QDirIterator ImageFileIterator(dir.absoluteFilePath(""), { "*.png", "*.gif", "*.jpg", "*.apng", "*.jxl", "*.avif" }, QDir::Files); + while (ImageFileIterator.hasNext()) { + QFile customCatFile(ImageFileIterator.next()); + QFileInfo customCatFileInfo(customCatFile); + themeDebugLog() << "Loading QSS Theme from:" << customCatFileInfo.absoluteFilePath(); + addCatPack(std::unique_ptr(new FileCatPack(customCatFileInfo))); + } + }; + + loadFiles(catpacksDir); + + QDirIterator directoryIterator(catpacksFolder, QDir::Dirs | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); + while (directoryIterator.hasNext()) { + QDir dir(directoryIterator.next()); + QFileInfo manifest(dir.absoluteFilePath("catpack.json")); + if (manifest.exists()) { + // Load background manifest + themeDebugLog() << "Loading background manifest from:" << manifest.absoluteFilePath(); + addCatPack(std::unique_ptr(new JsonCatPack(manifest))); + } else { + loadFiles(dir); + } } - return cat; } diff --git a/launcher/ui/themes/ThemeManager.h b/launcher/ui/themes/ThemeManager.h index 87f36d9c1..bc0d31cd0 100644 --- a/launcher/ui/themes/ThemeManager.h +++ b/launcher/ui/themes/ThemeManager.h @@ -20,6 +20,7 @@ #include #include "ui/MainWindow.h" +#include "ui/themes/CatPack.h" #include "ui/themes/ITheme.h" inline auto themeDebugLog() @@ -40,18 +41,20 @@ class ThemeManager { void applyCurrentlySelectedTheme(bool initial = false); void setApplicationTheme(const QString& name, bool initial = false); - /// - /// Returns the cat based on selected cat and with events (Birthday, XMas, etc.) - /// - /// Optional, if you need a specific cat. - /// - static QString getCatImage(QString catName = ""); + /// @brief Returns the background based on selected and with events (Birthday, XMas, etc.) + /// @param catName Optional, if you need a specific background. + /// @return + QString getCatPack(QString catName = ""); + QList getValidCatPacks(); private: std::map> m_themes; + std::map> m_catPacks; MainWindow* m_mainWindow; void initializeThemes(); + void initializeCatPacks(); QString addTheme(std::unique_ptr theme); ITheme* getTheme(QString themeId); + QString addCatPack(std::unique_ptr catPack); }; diff --git a/launcher/ui/widgets/ThemeCustomizationWidget.cpp b/launcher/ui/widgets/ThemeCustomizationWidget.cpp index dcf13303c..e2c5ce3d7 100644 --- a/launcher/ui/widgets/ThemeCustomizationWidget.cpp +++ b/launcher/ui/widgets/ThemeCustomizationWidget.cpp @@ -95,9 +95,14 @@ void ThemeCustomizationWidget::applyWidgetTheme(int index) { emit currentWidgetThemeChanged(index); } -void ThemeCustomizationWidget::applyCatTheme(int index) { +void ThemeCustomizationWidget::applyCatTheme(int index) +{ auto settings = APPLICATION->settings(); - settings->set("BackgroundCat", m_catOptions[index].first); + auto originalCat = settings->get("BackgroundCat").toString(); + auto newCat = ui->backgroundCatComboBox->currentData().toString(); + if (originalCat != newCat) { + settings->set("BackgroundCat", newCat); + } emit currentCatChanged(index); } @@ -135,10 +140,10 @@ void ThemeCustomizationWidget::loadSettings() } auto cat = settings->get("BackgroundCat").toString(); - for (auto& catFromList : m_catOptions) { - QIcon catIcon = QIcon(QString(":/backgrounds/%1").arg(ThemeManager::getCatImage(catFromList.first))); - ui->backgroundCatComboBox->addItem(catIcon, catFromList.second); - if (cat == catFromList.first) { + for (auto& catFromList : APPLICATION->getValidCatPacks()) { + QIcon catIcon = QIcon(QString("%1").arg(catFromList->path())); + ui->backgroundCatComboBox->addItem(catIcon, catFromList->name(), catFromList->id()); + if (cat == catFromList->id()) { ui->backgroundCatComboBox->setCurrentIndex(ui->backgroundCatComboBox->count() - 1); } } diff --git a/launcher/ui/widgets/ThemeCustomizationWidget.h b/launcher/ui/widgets/ThemeCustomizationWidget.h index d955a2665..be204e57c 100644 --- a/launcher/ui/widgets/ThemeCustomizationWidget.h +++ b/launcher/ui/widgets/ThemeCustomizationWidget.h @@ -53,25 +53,17 @@ class ThemeCustomizationWidget : public QWidget { private: Ui::ThemeCustomizationWidget* ui; - //TODO finish implementing - QList> m_iconThemeOptions{ - { "pe_colored", QObject::tr("Simple (Colored Icons)") }, - { "pe_light", QObject::tr("Simple (Light Icons)") }, - { "pe_dark", QObject::tr("Simple (Dark Icons)") }, - { "pe_blue", QObject::tr("Simple (Blue Icons)") }, - { "breeze_light", QObject::tr("Breeze Light") }, - { "breeze_dark", QObject::tr("Breeze Dark") }, - { "OSX", QObject::tr("OSX") }, - { "iOS", QObject::tr("iOS") }, - { "flat", QObject::tr("Flat") }, - { "flat_white", QObject::tr("Flat (White)") }, - { "multimc", QObject::tr("Legacy") }, - { "custom", QObject::tr("Custom") } - }; - QList> m_catOptions{ - { "kitteh", QObject::tr("Background Cat (from MultiMC)") }, - { "rory", QObject::tr("Rory ID 11 (drawn by Ashtaka)") }, - { "rory-flat", QObject::tr("Rory ID 11 (flat edition, drawn by Ashtaka)") }, - { "teawie", QObject::tr("Teawie (drawn by SympathyTea)") } - }; + // TODO finish implementing + QList> m_iconThemeOptions{ { "pe_colored", QObject::tr("Simple (Colored Icons)") }, + { "pe_light", QObject::tr("Simple (Light Icons)") }, + { "pe_dark", QObject::tr("Simple (Dark Icons)") }, + { "pe_blue", QObject::tr("Simple (Blue Icons)") }, + { "breeze_light", QObject::tr("Breeze Light") }, + { "breeze_dark", QObject::tr("Breeze Dark") }, + { "OSX", QObject::tr("OSX") }, + { "iOS", QObject::tr("iOS") }, + { "flat", QObject::tr("Flat") }, + { "flat_white", QObject::tr("Flat (White)") }, + { "multimc", QObject::tr("Legacy") }, + { "custom", QObject::tr("Custom") } }; }; From 718aca3d066fc24c03b7ac6d625d68829fcaa427 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 23 Jun 2023 09:24:18 +0300 Subject: [PATCH 10/72] Fixed date constructor Signed-off-by: Trial97 --- launcher/ui/themes/CatPack.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/themes/CatPack.h b/launcher/ui/themes/CatPack.h index d9010b8ea..9f288d3dd 100644 --- a/launcher/ui/themes/CatPack.h +++ b/launcher/ui/themes/CatPack.h @@ -79,7 +79,7 @@ class JsonCatPack : public BasicCatPack { auto sp = d.split("-"); day = sp[0].toInt(); if (sp.length() >= 2) - mounth = sp[1].length(); + mounth = sp[1].toInt(); } int mounth; int day; From f8adb508ab0152af76829e0fdee92b451dcc1acf Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 23 Jun 2023 11:44:40 +0300 Subject: [PATCH 11/72] Made catpack id optional in catpack.json Signed-off-by: Trial97 --- launcher/ui/themes/CatPack.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/launcher/ui/themes/CatPack.cpp b/launcher/ui/themes/CatPack.cpp index e74b9709a..2d5653a67 100644 --- a/launcher/ui/themes/CatPack.cpp +++ b/launcher/ui/themes/CatPack.cpp @@ -77,7 +77,8 @@ JsonCatPack::JsonCatPack(QFileInfo& manifestInfo) : BasicCatPack(manifestInfo.di auto doc = Json::requireDocument(manifestInfo.absoluteFilePath(), "CatPack JSON file"); const auto root = doc.object(); m_name = Json::requireString(root, "name", "Catpack name"); - m_id = Json::requireString(root, "id", "Catpack ID"); + auto id = Json::ensureString(root, "id", "", "Catpack ID"); + m_id = id.isEmpty() ? m_id : id; m_defaultPath = FS::PathCombine(path, Json::requireString(root, "default", "Deafult Cat")); auto variants = Json::ensureArray(root, "variants", QJsonArray(), "Catpack Variants"); for (auto v : variants) { From c5ea8367aaf9d61a6362427a55206d8891f40cda Mon Sep 17 00:00:00 2001 From: Alexandru Ionut Tripon Date: Fri, 23 Jun 2023 14:25:21 +0300 Subject: [PATCH 12/72] Update launcher/ui/themes/CatPack.cpp Co-authored-by: TheKodeToad Signed-off-by: Alexandru Ionut Tripon --- launcher/ui/themes/CatPack.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/launcher/ui/themes/CatPack.cpp b/launcher/ui/themes/CatPack.cpp index 2d5653a67..bee632029 100644 --- a/launcher/ui/themes/CatPack.cpp +++ b/launcher/ui/themes/CatPack.cpp @@ -78,7 +78,8 @@ JsonCatPack::JsonCatPack(QFileInfo& manifestInfo) : BasicCatPack(manifestInfo.di const auto root = doc.object(); m_name = Json::requireString(root, "name", "Catpack name"); auto id = Json::ensureString(root, "id", "", "Catpack ID"); - m_id = id.isEmpty() ? m_id : id; + if (!id.isEmpty()) + m_id = id; m_defaultPath = FS::PathCombine(path, Json::requireString(root, "default", "Deafult Cat")); auto variants = Json::ensureArray(root, "variants", QJsonArray(), "Catpack Variants"); for (auto v : variants) { From 84c63f4f017324b42c2470fb2e7a1ac5858fcaa0 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 25 Jun 2023 14:11:41 +0300 Subject: [PATCH 13/72] Added plantxt export Signed-off-by: Trial97 --- launcher/CMakeLists.txt | 10 +- launcher/minecraft/mod/Mod.cpp | 7 + launcher/minecraft/mod/Mod.h | 1 + launcher/modplatform/ModIndex.cpp | 8 +- launcher/modplatform/ModIndex.h | 1 + ...dsToStringTask.cpp => ExportToModList.cpp} | 60 +++--- ...rtModsToStringTask.h => ExportToModList.h} | 10 +- launcher/ui/MainWindow.cpp | 8 +- launcher/ui/MainWindow.h | 2 +- launcher/ui/MainWindow.ui | 4 +- .../ui/dialogs/ExportModsToStringDialog.cpp | 122 ------------- launcher/ui/dialogs/ExportToModListDialog.cpp | 171 ++++++++++++++++++ ...StringDialog.h => ExportToModListDialog.h} | 16 +- ...ringDialog.ui => ExportToModListDialog.ui} | 38 +++- 14 files changed, 282 insertions(+), 176 deletions(-) rename launcher/modplatform/helpers/{ExportModsToStringTask.cpp => ExportToModList.cpp} (67%) rename launcher/modplatform/helpers/{ExportModsToStringTask.h => ExportToModList.h} (77%) delete mode 100644 launcher/ui/dialogs/ExportModsToStringDialog.cpp create mode 100644 launcher/ui/dialogs/ExportToModListDialog.cpp rename launcher/ui/dialogs/{ExportModsToStringDialog.h => ExportToModListDialog.h} (71%) rename launcher/ui/dialogs/{ExportModsToStringDialog.ui => ExportToModListDialog.ui} (82%) diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index aab7e90d1..a4e82576f 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -490,8 +490,8 @@ set(API_SOURCES modplatform/helpers/OverrideUtils.h modplatform/helpers/OverrideUtils.cpp - modplatform/helpers/ExportModsToStringTask.h - modplatform/helpers/ExportModsToStringTask.cpp + modplatform/helpers/ExportToModList.h + modplatform/helpers/ExportToModList.cpp ) set(FTB_SOURCES @@ -913,8 +913,8 @@ SET(LAUNCHER_SOURCES ui/dialogs/ExportInstanceDialog.h ui/dialogs/ExportMrPackDialog.cpp ui/dialogs/ExportMrPackDialog.h - ui/dialogs/ExportModsToStringDialog.cpp - ui/dialogs/ExportModsToStringDialog.h + ui/dialogs/ExportToModListDialog.cpp + ui/dialogs/ExportToModListDialog.h ui/dialogs/IconPickerDialog.cpp ui/dialogs/IconPickerDialog.h ui/dialogs/ImportResourceDialog.cpp @@ -1062,7 +1062,7 @@ qt_wrap_ui(LAUNCHER_UI ui/dialogs/SkinUploadDialog.ui ui/dialogs/ExportInstanceDialog.ui ui/dialogs/ExportMrPackDialog.ui - ui/dialogs/ExportModsToStringDialog.ui + ui/dialogs/ExportToModListDialog.ui ui/dialogs/IconPickerDialog.ui ui/dialogs/ImportResourceDialog.ui ui/dialogs/MSALoginDialog.ui diff --git a/launcher/minecraft/mod/Mod.cpp b/launcher/minecraft/mod/Mod.cpp index e613ddeb7..d5b96badd 100644 --- a/launcher/minecraft/mod/Mod.cpp +++ b/launcher/minecraft/mod/Mod.cpp @@ -166,6 +166,13 @@ auto Mod::homeurl() const -> QString return details().homeurl; } +auto Mod::metaurl() const -> QString +{ + if (metadata() == nullptr) + return homeurl(); + return ModPlatform::getMetaURL(metadata()->provider, metadata()->project_id); +} + auto Mod::description() const -> QString { return details().description; diff --git a/launcher/minecraft/mod/Mod.h b/launcher/minecraft/mod/Mod.h index d4e419f4f..d6272f4d0 100644 --- a/launcher/minecraft/mod/Mod.h +++ b/launcher/minecraft/mod/Mod.h @@ -70,6 +70,7 @@ public: auto provider() const -> std::optional; auto licenses() const -> const QList&; auto issueTracker() const -> QString; + auto metaurl() const -> QString; /** Get the intneral path to the mod's icon file*/ QString iconPath() const { return m_local_details.icon_file; }; diff --git a/launcher/modplatform/ModIndex.cpp b/launcher/modplatform/ModIndex.cpp index 6a507caf4..a1c4d8917 100644 --- a/launcher/modplatform/ModIndex.cpp +++ b/launcher/modplatform/ModIndex.cpp @@ -70,11 +70,17 @@ auto ProviderCapabilities::hash(ResourceProvider p, QIODevice* device, QString t } QCryptographicHash hash(algo); - if(!hash.addData(device)) + if (!hash.addData(device)) qCritical() << "Failed to read JAR to create hash!"; Q_ASSERT(hash.result().length() == hash.hashLength(algo)); return { hash.result().toHex() }; } +QString getMetaURL(ResourceProvider provider, QVariant projectID) +{ + return ((provider == ModPlatform::ResourceProvider::FLAME) ? "https://www.curseforge.com/projects/" : "https://modrinth.com/mod/") + + projectID.toString(); +} + } // namespace ModPlatform diff --git a/launcher/modplatform/ModIndex.h b/launcher/modplatform/ModIndex.h index 3b0a03a18..3f51e700f 100644 --- a/launcher/modplatform/ModIndex.h +++ b/launcher/modplatform/ModIndex.h @@ -144,6 +144,7 @@ inline auto getOverrideDeps() -> QList { "qvIfYCYJ", "P7dR8mSH", "API", ModPlatform::ResourceProvider::MODRINTH }, { "lwVhp9o5", "Ha28R6CL", "KotlinLibraries", ModPlatform::ResourceProvider::MODRINTH } }; }; +QString getMetaURL(ResourceProvider provider, QVariant projectID); } // namespace ModPlatform diff --git a/launcher/modplatform/helpers/ExportModsToStringTask.cpp b/launcher/modplatform/helpers/ExportToModList.cpp similarity index 67% rename from launcher/modplatform/helpers/ExportModsToStringTask.cpp rename to launcher/modplatform/helpers/ExportToModList.cpp index e7be5ce13..5e01367f9 100644 --- a/launcher/modplatform/helpers/ExportModsToStringTask.cpp +++ b/launcher/modplatform/helpers/ExportToModList.cpp @@ -15,11 +15,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include "ExportModsToStringTask.h" -#include "modplatform/ModIndex.h" +#include "ExportToModList.h" -namespace ExportToString { -QString ExportModsToStringTask(QList mods, Formats format, OptionalData extraData) +namespace ExportToModList { +QString ExportToModList(QList mods, Formats format, OptionalData extraData) { switch (format) { case HTML: { @@ -28,12 +27,7 @@ QString ExportModsToStringTask(QList mods, Formats format, OptionalData ex auto meta = mod->metadata(); auto modName = mod->name(); if (extraData & Url) { - auto url = mod->homeurl(); - if (meta != nullptr) { - url = (meta->provider == ModPlatform::ResourceProvider::FLAME ? "https://www.curseforge.com/minecraft/mc-mods/" - : "https://modrinth.com/mod/") + - meta->slug.remove(".pw.toml"); - } + auto url = mod->metaurl(); if (!url.isEmpty()) modName = QString("%2").arg(url, modName); } @@ -49,7 +43,7 @@ QString ExportModsToStringTask(QList mods, Formats format, OptionalData ex line += " by " + mod->authors().join(", "); lines.append(QString("
    %1
").arg(line)); } - return QString("\n\t%1\n").arg(lines.join("\n\t")); + return QString("
  • \n\t%1\n
  • ").arg(lines.join("\n\t")); } case MARKDOWN: { QStringList lines; @@ -57,12 +51,7 @@ QString ExportModsToStringTask(QList mods, Formats format, OptionalData ex auto meta = mod->metadata(); auto modName = mod->name(); if (extraData & Url) { - auto url = mod->homeurl(); - if (meta != nullptr) { - url = (meta->provider == ModPlatform::ResourceProvider::FLAME ? "https://www.curseforge.com/minecraft/mc-mods/" - : "https://modrinth.com/mod/") + - meta->slug.remove(".pw.toml"); - } + auto url = mod->metaurl(); if (!url.isEmpty()) modName = QString("[%1](%2)").arg(modName, url); } @@ -76,6 +65,31 @@ QString ExportModsToStringTask(QList mods, Formats format, OptionalData ex } if (extraData & Authors && !mod->authors().isEmpty()) line += " by " + mod->authors().join(", "); + lines << "- " + line; + } + return lines.join("\n"); + } + case PLAINTXT: { + QStringList lines; + for (auto mod : mods) { + auto meta = mod->metadata(); + auto modName = mod->name(); + + auto line = "name: " + modName + ";"; + if (extraData & Url) { + auto url = mod->metaurl(); + if (!url.isEmpty()) + line += " url: " + url + ";"; + } + if (extraData & Version) { + auto ver = mod->version(); + if (ver.isEmpty() && meta != nullptr) + ver = meta->version().toString(); + if (!ver.isEmpty()) + line += " version: " + QString("[%1]").arg(ver) + ";"; + } + if (extraData & Authors && !mod->authors().isEmpty()) + line += " authors " + mod->authors().join(", ") + ";"; lines << line; } return lines.join("\n"); @@ -86,19 +100,13 @@ QString ExportModsToStringTask(QList mods, Formats format, OptionalData ex } } -QString ExportModsToStringTask(QList mods, QString lineTemplate) +QString ExportToModList(QList mods, QString lineTemplate) { QStringList lines; for (auto mod : mods) { auto meta = mod->metadata(); auto modName = mod->name(); - - auto url = mod->homeurl(); - if (meta != nullptr) { - url = (meta->provider == ModPlatform::ResourceProvider::FLAME ? "https://www.curseforge.com/minecraft/mc-mods/" - : "https://modrinth.com/mod/") + - meta->slug.remove(".pw.toml"); - } + auto url = mod->metaurl(); auto ver = mod->version(); if (ver.isEmpty() && meta != nullptr) ver = meta->version().toString(); @@ -111,4 +119,4 @@ QString ExportModsToStringTask(QList mods, QString lineTemplate) } return lines.join("\n"); } -} // namespace ExportToString \ No newline at end of file +} // namespace ExportToModList \ No newline at end of file diff --git a/launcher/modplatform/helpers/ExportModsToStringTask.h b/launcher/modplatform/helpers/ExportToModList.h similarity index 77% rename from launcher/modplatform/helpers/ExportModsToStringTask.h rename to launcher/modplatform/helpers/ExportToModList.h index 756c69f77..9ff8d25a1 100644 --- a/launcher/modplatform/helpers/ExportModsToStringTask.h +++ b/launcher/modplatform/helpers/ExportToModList.h @@ -20,14 +20,14 @@ #include #include "minecraft/mod/Mod.h" -namespace ExportToString { +namespace ExportToModList { -enum Formats { HTML, MARKDOWN }; +enum Formats { HTML, MARKDOWN, PLAINTXT, CUSTOM }; enum OptionalData { Authors = 1 << 0, Url = 1 << 1, Version = 1 << 2, }; -QString ExportModsToStringTask(QList mods, Formats format, OptionalData extraData); -QString ExportModsToStringTask(QList mods, QString lineTemplate); -} // namespace ExportToString +QString ExportToModList(QList mods, Formats format, OptionalData extraData); +QString ExportToModList(QList mods, QString lineTemplate); +} // namespace ExportToModList diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index 02ea30c36..37f4d4ed5 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -43,7 +43,7 @@ #include "FileSystem.h" #include "MainWindow.h" -#include "ui/dialogs/ExportModsToStringDialog.h" +#include "ui/dialogs/ExportToModListDialog.h" #include "ui_MainWindow.h" #include @@ -206,7 +206,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi auto exportInstanceMenu = new QMenu(this); exportInstanceMenu->addAction(ui->actionExportInstanceZip); exportInstanceMenu->addAction(ui->actionExportInstanceMrPack); - exportInstanceMenu->addAction(ui->actionExportInstanceToString); + exportInstanceMenu->addAction(ui->actionExportInstanceToModList); ui->actionExportInstance->setMenu(exportInstanceMenu); } @@ -1418,10 +1418,10 @@ void MainWindow::on_actionExportInstanceMrPack_triggered() } } -void MainWindow::on_actionExportInstanceToString_triggered() +void MainWindow::on_actionExportInstanceToModList_triggered() { if (m_selectedInstance) { - ExportModsToStringDialog dlg(m_selectedInstance, this); + ExportToModListDialog dlg(m_selectedInstance, this); dlg.exec(); } } diff --git a/launcher/ui/MainWindow.h b/launcher/ui/MainWindow.h index 9b38810f0..f62e39e15 100644 --- a/launcher/ui/MainWindow.h +++ b/launcher/ui/MainWindow.h @@ -157,7 +157,7 @@ private slots: inline void on_actionExportInstance_triggered() { on_actionExportInstanceZip_triggered(); } void on_actionExportInstanceZip_triggered(); void on_actionExportInstanceMrPack_triggered(); - void on_actionExportInstanceToString_triggered(); + void on_actionExportInstanceToModList_triggered(); void on_actionRenameInstance_triggered(); diff --git a/launcher/ui/MainWindow.ui b/launcher/ui/MainWindow.ui index ecc7e2362..027742ba4 100644 --- a/launcher/ui/MainWindow.ui +++ b/launcher/ui/MainWindow.ui @@ -479,12 +479,12 @@ Modrinth (mrpack)
    - + - Text + ModList (txt) diff --git a/launcher/ui/dialogs/ExportModsToStringDialog.cpp b/launcher/ui/dialogs/ExportModsToStringDialog.cpp deleted file mode 100644 index 29d69918e..000000000 --- a/launcher/ui/dialogs/ExportModsToStringDialog.cpp +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -/* - * Prism Launcher - Minecraft Launcher - * Copyright (c) 2023 Trial97 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "ExportModsToStringDialog.h" -#include -#include -#include -#include "minecraft/MinecraftInstance.h" -#include "minecraft/mod/ModFolderModel.h" -#include "modplatform/helpers/ExportModsToStringTask.h" -#include "ui_ExportModsToStringDialog.h" - -#include -#include -#include -#include -#include - -ExportModsToStringDialog::ExportModsToStringDialog(InstancePtr instance, QWidget* parent) - : QDialog(parent), m_template_selected(false), ui(new Ui::ExportModsToStringDialog) -{ - ui->setupUi(this); - ui->templateGroup->setDisabled(true); - - MinecraftInstance* mcInstance = dynamic_cast(instance.get()); - if (mcInstance) { - mcInstance->loaderModList()->update(); - connect(mcInstance->loaderModList().get(), &ModFolderModel::updateFinished, this, [this, mcInstance]() { - m_allMods = mcInstance->loaderModList()->allMods(); - triggerImp(); - }); - } - - connect(ui->formatComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &ExportModsToStringDialog::formatChanged); - connect(ui->authorsCheckBox, &QCheckBox::stateChanged, this, &ExportModsToStringDialog::trigger); - connect(ui->versionCheckBox, &QCheckBox::stateChanged, this, &ExportModsToStringDialog::trigger); - connect(ui->urlCheckBox, &QCheckBox::stateChanged, this, &ExportModsToStringDialog::trigger); - connect(ui->templateText, &QTextEdit::textChanged, this, &ExportModsToStringDialog::triggerImp); - connect(ui->copyButton, &QPushButton::clicked, this, [this](bool) { - this->ui->finalText->selectAll(); - this->ui->finalText->copy(); - }); -} - -ExportModsToStringDialog::~ExportModsToStringDialog() -{ - delete ui; -} - -void ExportModsToStringDialog::formatChanged(int index) -{ - switch (index) { - case 0: { - ui->templateGroup->setDisabled(true); - ui->optionsGroup->setDisabled(false); - break; - } - case 1: { - ui->templateGroup->setDisabled(true); - ui->optionsGroup->setDisabled(false); - break; - } - case 2: { - ui->templateGroup->setDisabled(false); - ui->optionsGroup->setDisabled(true); - break; - } - } - triggerImp(); -} - -void ExportModsToStringDialog::triggerImp() -{ - auto format = ExportToString::HTML; - switch (ui->formatComboBox->currentIndex()) { - case 2: { - m_template_selected = true; - ui->finalText->setPlainText(ExportToString::ExportModsToStringTask(m_allMods, ui->templateText->toPlainText())); - return; - } - case 0: { - format = ExportToString::HTML; - break; - } - case 1: { - format = ExportToString::MARKDOWN; - break; - } - default: { - return; - } - } - auto opt = 0; - if (ui->authorsCheckBox->isChecked()) - opt |= ExportToString::Authors; - if (ui->versionCheckBox->isChecked()) - opt |= ExportToString::Version; - if (ui->urlCheckBox->isChecked()) - opt |= ExportToString::Url; - ui->finalText->setPlainText(ExportToString::ExportModsToStringTask(m_allMods, format, static_cast(opt))); - if (!m_template_selected) { - auto exampleLine = format == ExportToString::HTML ? "
      {name}[{version}] by {authors}
    " - : "[{name}]({url})[{version}] by {authors}"; - if (ui->templateText->toPlainText() != exampleLine) - ui->templateText->setPlainText(exampleLine); - } -} diff --git a/launcher/ui/dialogs/ExportToModListDialog.cpp b/launcher/ui/dialogs/ExportToModListDialog.cpp new file mode 100644 index 000000000..0550725f6 --- /dev/null +++ b/launcher/ui/dialogs/ExportToModListDialog.cpp @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2023 Trial97 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ExportToModListDialog.h" +#include +#include +#include +#include "FileSystem.h" +#include "minecraft/MinecraftInstance.h" +#include "minecraft/mod/ModFolderModel.h" +#include "modplatform/helpers/ExportToModList.h" +#include "ui_ExportToModListDialog.h" + +#include +#include +#include +#include +#include + +ExportToModListDialog::ExportToModListDialog(InstancePtr instance, QWidget* parent) + : QDialog(parent), m_template_selected(false), name(instance->name()), ui(new Ui::ExportToModListDialog) +{ + ui->setupUi(this); + ui->templateGroup->setDisabled(true); + + MinecraftInstance* mcInstance = dynamic_cast(instance.get()); + if (mcInstance) { + mcInstance->loaderModList()->update(); + connect(mcInstance->loaderModList().get(), &ModFolderModel::updateFinished, this, [this, mcInstance]() { + m_allMods = mcInstance->loaderModList()->allMods(); + triggerImp(); + }); + } + + connect(ui->formatComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &ExportToModListDialog::formatChanged); + connect(ui->authorsCheckBox, &QCheckBox::stateChanged, this, &ExportToModListDialog::trigger); + connect(ui->versionCheckBox, &QCheckBox::stateChanged, this, &ExportToModListDialog::trigger); + connect(ui->urlCheckBox, &QCheckBox::stateChanged, this, &ExportToModListDialog::trigger); + connect(ui->templateText, &QTextEdit::textChanged, this, &ExportToModListDialog::triggerImp); + connect(ui->copyButton, &QPushButton::clicked, this, [this](bool) { + this->ui->finalText->selectAll(); + this->ui->finalText->copy(); + }); +} + +ExportToModListDialog::~ExportToModListDialog() +{ + delete ui; +} + +void ExportToModListDialog::formatChanged(int index) +{ + switch (index) { + case 0: { + ui->templateGroup->setDisabled(true); + ui->optionsGroup->setDisabled(false); + ui->resultText->show(); + format = ExportToModList::HTML; + break; + } + case 1: { + ui->templateGroup->setDisabled(true); + ui->optionsGroup->setDisabled(false); + ui->resultText->show(); + format = ExportToModList::MARKDOWN; + break; + } + case 2: { + ui->templateGroup->setDisabled(true); + ui->optionsGroup->setDisabled(false); + ui->resultText->hide(); + format = ExportToModList::PLAINTXT; + break; + } + case 3: { + ui->templateGroup->setDisabled(false); + ui->optionsGroup->setDisabled(true); + ui->resultText->hide(); + format = ExportToModList::CUSTOM; + break; + } + } + triggerImp(); +} + +void ExportToModListDialog::triggerImp() +{ + if (format == ExportToModList::CUSTOM) { + m_template_selected = true; + ui->finalText->setPlainText(ExportToModList::ExportToModList(m_allMods, ui->templateText->toPlainText())); + return; + } + auto opt = 0; + if (ui->authorsCheckBox->isChecked()) + opt |= ExportToModList::Authors; + if (ui->versionCheckBox->isChecked()) + opt |= ExportToModList::Version; + if (ui->urlCheckBox->isChecked()) + opt |= ExportToModList::Url; + auto txt = ExportToModList::ExportToModList(m_allMods, format, static_cast(opt)); + ui->finalText->setPlainText(txt); + QString exampleLine; + switch (format) { + case ExportToModList::HTML: { + exampleLine = "
      {name}[{version}] by {authors}
    "; + ui->resultText->setHtml(txt); + break; + } + case ExportToModList::MARKDOWN: { + exampleLine = "[{name}]({url})[{version}] by {authors}"; + ui->resultText->setMarkdown(txt); + break; + } + case ExportToModList::PLAINTXT: { + exampleLine = "name: {name}; url: {url}; version: {version}; authors: {authors};"; + break; + } + case ExportToModList::CUSTOM: + return; + } + if (!m_template_selected) { + if (ui->templateText->toPlainText() != exampleLine) + ui->templateText->setPlainText(exampleLine); + } +} + +void ExportToModListDialog::done(int result) +{ + if (result == Accepted) { + const QString filename = FS::RemoveInvalidFilenameChars(name); + const QString output = + QFileDialog::getSaveFileName(this, tr("Export %1").arg(name), FS::PathCombine(QDir::homePath(), filename + extension()), + "File (*.txt *.html *.md)", nullptr); + + if (output.isEmpty()) + return; + FS::write(output, ui->finalText->toPlainText().toUtf8()); + } + + QDialog::done(result); +} + +QString ExportToModListDialog::extension() +{ + switch (format) { + case ExportToModList::HTML: + return ".html"; + case ExportToModList::MARKDOWN: + return ".md"; + case ExportToModList::PLAINTXT: + return ".txt"; + case ExportToModList::CUSTOM: + return ".txt"; + } + return ".txt"; +} diff --git a/launcher/ui/dialogs/ExportModsToStringDialog.h b/launcher/ui/dialogs/ExportToModListDialog.h similarity index 71% rename from launcher/ui/dialogs/ExportModsToStringDialog.h rename to launcher/ui/dialogs/ExportToModListDialog.h index d195d1cec..a7a6bcdce 100644 --- a/launcher/ui/dialogs/ExportModsToStringDialog.h +++ b/launcher/ui/dialogs/ExportToModListDialog.h @@ -22,17 +22,20 @@ #include #include "BaseInstance.h" #include "minecraft/mod/Mod.h" +#include "modplatform/helpers/ExportToModList.h" namespace Ui { -class ExportModsToStringDialog; +class ExportToModListDialog; } -class ExportModsToStringDialog : public QDialog { +class ExportToModListDialog : public QDialog { Q_OBJECT public: - explicit ExportModsToStringDialog(InstancePtr instance, QWidget* parent = nullptr); - ~ExportModsToStringDialog(); + explicit ExportToModListDialog(InstancePtr instance, QWidget* parent = nullptr); + ~ExportToModListDialog(); + + void done(int result) override; protected slots: void formatChanged(int index); @@ -40,7 +43,10 @@ class ExportModsToStringDialog : public QDialog { void trigger(int) { triggerImp(); }; private: + QString extension(); QList m_allMods; bool m_template_selected; - Ui::ExportModsToStringDialog* ui; + QString name; + ExportToModList::Formats format = ExportToModList::Formats::HTML; + Ui::ExportToModListDialog* ui; }; diff --git a/launcher/ui/dialogs/ExportModsToStringDialog.ui b/launcher/ui/dialogs/ExportToModListDialog.ui similarity index 82% rename from launcher/ui/dialogs/ExportModsToStringDialog.ui rename to launcher/ui/dialogs/ExportToModListDialog.ui index 4451a2785..640b17665 100644 --- a/launcher/ui/dialogs/ExportModsToStringDialog.ui +++ b/launcher/ui/dialogs/ExportToModListDialog.ui @@ -1,7 +1,7 @@ - ExportModsToStringDialog - + ExportToModListDialog + 0 @@ -11,7 +11,7 @@ - Export Modrinth Pack + Export Pack to ModList true @@ -53,6 +53,11 @@ Markdown + + + Plaintext + + Custom @@ -124,6 +129,13 @@ + + + + true + + + @@ -141,7 +153,7 @@ - QDialogButtonBox::Ok + QDialogButtonBox::Cancel|QDialogButtonBox::Save @@ -154,7 +166,7 @@ buttonBox accepted() - ExportModsToStringDialog + ExportToModListDialog accept() @@ -167,5 +179,21 @@ + + buttonBox + rejected() + ExportToModListDialog + reject() + + + 324 + 390 + + + 324 + 206 + + + From 8d3bc6b6b94ff5fb2dba0c06bf6d108794af7d8f Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 25 Jun 2023 14:58:54 +0300 Subject: [PATCH 14/72] Added markdown QT version check Signed-off-by: Trial97 --- launcher/ui/dialogs/ExportToModListDialog.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/launcher/ui/dialogs/ExportToModListDialog.cpp b/launcher/ui/dialogs/ExportToModListDialog.cpp index 0550725f6..715a62c34 100644 --- a/launcher/ui/dialogs/ExportToModListDialog.cpp +++ b/launcher/ui/dialogs/ExportToModListDialog.cpp @@ -76,7 +76,11 @@ void ExportToModListDialog::formatChanged(int index) case 1: { ui->templateGroup->setDisabled(true); ui->optionsGroup->setDisabled(false); +#if QT_VERSION >= QT_VERSION_CHECK(6, 1, 0) ui->resultText->show(); +#else + ui->resultText->hide(); +#endif format = ExportToModList::MARKDOWN; break; } @@ -123,7 +127,9 @@ void ExportToModListDialog::triggerImp() } case ExportToModList::MARKDOWN: { exampleLine = "[{name}]({url})[{version}] by {authors}"; +#if QT_VERSION >= QT_VERSION_CHECK(6, 1, 0) ui->resultText->setMarkdown(txt); +#endif break; } case ExportToModList::PLAINTXT: { From 3546f57a42eb23053772eb5b84cb864f9c83b166 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 25 Jun 2023 15:17:09 +0300 Subject: [PATCH 15/72] Use internal markdown implementation Signed-off-by: Trial97 --- launcher/ui/dialogs/ExportToModListDialog.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/launcher/ui/dialogs/ExportToModListDialog.cpp b/launcher/ui/dialogs/ExportToModListDialog.cpp index 715a62c34..57ee44537 100644 --- a/launcher/ui/dialogs/ExportToModListDialog.cpp +++ b/launcher/ui/dialogs/ExportToModListDialog.cpp @@ -21,6 +21,7 @@ #include #include #include "FileSystem.h" +#include "Markdown.h" #include "minecraft/MinecraftInstance.h" #include "minecraft/mod/ModFolderModel.h" #include "modplatform/helpers/ExportToModList.h" @@ -76,11 +77,7 @@ void ExportToModListDialog::formatChanged(int index) case 1: { ui->templateGroup->setDisabled(true); ui->optionsGroup->setDisabled(false); -#if QT_VERSION >= QT_VERSION_CHECK(6, 1, 0) ui->resultText->show(); -#else - ui->resultText->hide(); -#endif format = ExportToModList::MARKDOWN; break; } @@ -127,9 +124,7 @@ void ExportToModListDialog::triggerImp() } case ExportToModList::MARKDOWN: { exampleLine = "[{name}]({url})[{version}] by {authors}"; -#if QT_VERSION >= QT_VERSION_CHECK(6, 1, 0) - ui->resultText->setMarkdown(txt); -#endif + ui->resultText->setHtml(markdownToHTML(txt)); break; } case ExportToModList::PLAINTXT: { From f2015eee8059fa68af4ca9415cc8a11f13b65922 Mon Sep 17 00:00:00 2001 From: Alexandru Ionut Tripon Date: Mon, 26 Jun 2023 11:44:47 +0300 Subject: [PATCH 16/72] Update launcher/ui/MainWindow.ui Co-authored-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com> Signed-off-by: Alexandru Ionut Tripon --- launcher/ui/MainWindow.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/MainWindow.ui b/launcher/ui/MainWindow.ui index 027742ba4..22721fcdb 100644 --- a/launcher/ui/MainWindow.ui +++ b/launcher/ui/MainWindow.ui @@ -484,7 +484,7 @@ - ModList (txt) + Mod List
    From cf5c01a5b1a9a91d41fb343d2d2abc9bac07f1ec Mon Sep 17 00:00:00 2001 From: Alexandru Ionut Tripon Date: Mon, 26 Jun 2023 11:44:55 +0300 Subject: [PATCH 17/72] Update launcher/ui/dialogs/ExportToModListDialog.cpp Co-authored-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com> Signed-off-by: Alexandru Ionut Tripon --- launcher/ui/dialogs/ExportToModListDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/dialogs/ExportToModListDialog.cpp b/launcher/ui/dialogs/ExportToModListDialog.cpp index 57ee44537..d53e8db3a 100644 --- a/launcher/ui/dialogs/ExportToModListDialog.cpp +++ b/launcher/ui/dialogs/ExportToModListDialog.cpp @@ -118,7 +118,7 @@ void ExportToModListDialog::triggerImp() QString exampleLine; switch (format) { case ExportToModList::HTML: { - exampleLine = "
      {name}[{version}] by {authors}
    "; + exampleLine = "
      {name} [{version}] by {authors}
    "; ui->resultText->setHtml(txt); break; } From d82ae31fc1dc75693e3a6270f0b733fcf7bdaadd Mon Sep 17 00:00:00 2001 From: Alexandru Ionut Tripon Date: Mon, 26 Jun 2023 11:45:05 +0300 Subject: [PATCH 18/72] Update launcher/ui/dialogs/ExportToModListDialog.cpp Co-authored-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com> Signed-off-by: Alexandru Ionut Tripon --- launcher/ui/dialogs/ExportToModListDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/dialogs/ExportToModListDialog.cpp b/launcher/ui/dialogs/ExportToModListDialog.cpp index d53e8db3a..b399dc178 100644 --- a/launcher/ui/dialogs/ExportToModListDialog.cpp +++ b/launcher/ui/dialogs/ExportToModListDialog.cpp @@ -123,7 +123,7 @@ void ExportToModListDialog::triggerImp() break; } case ExportToModList::MARKDOWN: { - exampleLine = "[{name}]({url})[{version}] by {authors}"; + exampleLine = "[{name}]({url}) [{version}] by {authors}"; ui->resultText->setHtml(markdownToHTML(txt)); break; } From 22bb260ae3ccdc17840047cbef49f0af09b809bd Mon Sep 17 00:00:00 2001 From: Alexandru Ionut Tripon Date: Mon, 26 Jun 2023 11:45:26 +0300 Subject: [PATCH 19/72] Update launcher/ui/dialogs/ExportToModListDialog.cpp Co-authored-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com> Signed-off-by: Alexandru Ionut Tripon --- launcher/ui/dialogs/ExportToModListDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/dialogs/ExportToModListDialog.cpp b/launcher/ui/dialogs/ExportToModListDialog.cpp index b399dc178..149f6b358 100644 --- a/launcher/ui/dialogs/ExportToModListDialog.cpp +++ b/launcher/ui/dialogs/ExportToModListDialog.cpp @@ -128,7 +128,7 @@ void ExportToModListDialog::triggerImp() break; } case ExportToModList::PLAINTXT: { - exampleLine = "name: {name}; url: {url}; version: {version}; authors: {authors};"; + exampleLine = "{name} ({url}) [{version}] by {authors}"; break; } case ExportToModList::CUSTOM: From 0aaec9ae4fb8a2f9e00d81acf85ab66e60ad2639 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Mon, 26 Jun 2023 11:53:14 +0200 Subject: [PATCH 20/72] chore: remove obsolete macOS warning We don't support that macOS version. This check also never worked, as we never set the platform to that value. Signed-off-by: Sefa Eyeoglu --- buildconfig/BuildConfig.cpp.in | 2 +- buildconfig/BuildConfig.h | 2 +- launcher/ui/pages/global/AccountListPage.cpp | 13 ------------- 3 files changed, 2 insertions(+), 15 deletions(-) diff --git a/buildconfig/BuildConfig.cpp.in b/buildconfig/BuildConfig.cpp.in index 8a412b7ff..140731fe0 100644 --- a/buildconfig/BuildConfig.cpp.in +++ b/buildconfig/BuildConfig.cpp.in @@ -65,7 +65,7 @@ Config::Config() MAC_SPARKLE_PUB_KEY = "@MACOSX_SPARKLE_UPDATE_PUBLIC_KEY@"; MAC_SPARKLE_APPCAST_URL = "@MACOSX_SPARKLE_UPDATE_FEED_URL@"; - if (BUILD_PLATFORM == "macOS" && !MAC_SPARKLE_PUB_KEY.isEmpty() && !MAC_SPARKLE_APPCAST_URL.isEmpty()) + if (!MAC_SPARKLE_PUB_KEY.isEmpty() && !MAC_SPARKLE_APPCAST_URL.isEmpty()) { UPDATER_ENABLED = true; } diff --git a/buildconfig/BuildConfig.h b/buildconfig/BuildConfig.h index 8543d7241..11773d887 100644 --- a/buildconfig/BuildConfig.h +++ b/buildconfig/BuildConfig.h @@ -68,7 +68,7 @@ class Config { bool UPDATER_ENABLED = false; - /// A short string identifying this build's platform. For example, "lin64" or "win32". + /// A short string identifying this build's platform or distribution. QString BUILD_PLATFORM; /// A string containing the build timestamp diff --git a/launcher/ui/pages/global/AccountListPage.cpp b/launcher/ui/pages/global/AccountListPage.cpp index 278f45c49..fced5ff4a 100644 --- a/launcher/ui/pages/global/AccountListPage.cpp +++ b/launcher/ui/pages/global/AccountListPage.cpp @@ -159,19 +159,6 @@ void AccountListPage::on_actionAddMojang_triggered() void AccountListPage::on_actionAddMicrosoft_triggered() { - if(BuildConfig.BUILD_PLATFORM == "osx64") { - CustomMessageBox::selectable( - this, - tr("Microsoft Accounts not available"), - //: %1 refers to the launcher itself - tr( - "Microsoft accounts are only usable on macOS 10.13 or newer, with fully updated %1.\n\n" - "Please update both your operating system and %1." - ).arg(BuildConfig.LAUNCHER_DISPLAYNAME), - QMessageBox::Warning - )->exec(); - return; - } MinecraftAccountPtr account = MSALoginDialog::newAccount( this, tr("Please enter your Mojang account email and password to add your account.") From f5e4171df4f8990955b10d538809730abded32f8 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Mon, 26 Jun 2023 11:54:22 +0200 Subject: [PATCH 21/72] feat: print build platform in log Signed-off-by: Sefa Eyeoglu --- launcher/LaunchController.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/launcher/LaunchController.cpp b/launcher/LaunchController.cpp index 070ee283c..8fadf446c 100644 --- a/launcher/LaunchController.cpp +++ b/launcher/LaunchController.cpp @@ -390,7 +390,10 @@ void LaunchController::launchInstance() m_launcher->prependStep(makeShared(m_launcher.get(), "Launched instance in " + online_mode + " mode\n", MessageLevel::Launcher)); // Prepend Version - m_launcher->prependStep(makeShared(m_launcher.get(), BuildConfig.LAUNCHER_DISPLAYNAME + " version: " + BuildConfig.printableVersionString() + "\n\n", MessageLevel::Launcher)); + { + auto versionString = QString("%1 version: %2 (%3)").arg(BuildConfig.LAUNCHER_DISPLAYNAME, BuildConfig.printableVersionString(), BuildConfig.BUILD_PLATFORM); + m_launcher->prependStep(makeShared(m_launcher.get(), versionString + "\n\n", MessageLevel::Launcher)); + } m_launcher->start(); } From fce000206f9a866b70c50f2b6ea860bded19383b Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Mon, 26 Jun 2023 11:55:23 +0200 Subject: [PATCH 22/72] feat: print build platform in application log Signed-off-by: Sefa Eyeoglu --- launcher/Application.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 1d97a5f2e..45e340260 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -471,6 +471,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) qDebug() << BuildConfig.LAUNCHER_DISPLAYNAME << ", (c) 2013-2021 " << BuildConfig.LAUNCHER_COPYRIGHT; qDebug() << "Version : " << BuildConfig.printableVersionString(); + qDebug() << "Platform : " << BuildConfig.BUILD_PLATFORM; qDebug() << "Git commit : " << BuildConfig.GIT_COMMIT; qDebug() << "Git refspec : " << BuildConfig.GIT_REFSPEC; if (adjustedBy.size()) From 63acf0a7b4492334ad2d5b8c623a5ae6a54bb13d Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Mon, 26 Jun 2023 11:55:48 +0200 Subject: [PATCH 23/72] fix: set default platform to "unknown" Signed-off-by: Sefa Eyeoglu --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 70a553190..48995bedf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -146,7 +146,7 @@ set(Launcher_VERSION_NAME4 "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}. set(Launcher_VERSION_NAME4_COMMA "${Launcher_VERSION_MAJOR},${Launcher_VERSION_MINOR},0,0") # Build platform. -set(Launcher_BUILD_PLATFORM "" CACHE STRING "A short string identifying the platform that this build was built for. Only used to display in the about dialog.") +set(Launcher_BUILD_PLATFORM "unknown" CACHE STRING "A short string identifying the platform that this build was built for. Only used to display in the about dialog.") # Channel list URL set(Launcher_UPDATER_BASE "" CACHE STRING "Base URL for the updater.") From 40fb387185527db5eb03be34ea35f24d3e7bedcd Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Mon, 26 Jun 2023 11:58:47 +0200 Subject: [PATCH 24/72] fix(actions): set all build platforms to official Signed-off-by: Sefa Eyeoglu --- .github/workflows/build.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c2966abe7..bbfe4ab44 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -264,23 +264,23 @@ jobs: - name: Configure CMake (macOS) if: runner.os == 'macOS' && matrix.qt_ver == 6 run: | - cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=${{ matrix.name }} -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -G Ninja + cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -G Ninja - name: Configure CMake (macOS-Legacy) if: runner.os == 'macOS' && matrix.qt_ver == 5 run: | - cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=${{ matrix.name }} -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DMACOSX_SPARKLE_UPDATE_PUBLIC_KEY="" -DMACOSX_SPARKLE_UPDATE_FEED_URL="" -G Ninja + cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DMACOSX_SPARKLE_UPDATE_PUBLIC_KEY="" -DMACOSX_SPARKLE_UPDATE_FEED_URL="" -G Ninja - name: Configure CMake (Windows MinGW-w64) if: runner.os == 'Windows' && matrix.msystem != '' shell: msys2 {0} run: | - cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=${{ matrix.name }} -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=6 -DCMAKE_OBJDUMP=/mingw64/bin/objdump.exe -G Ninja + cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=6 -DCMAKE_OBJDUMP=/mingw64/bin/objdump.exe -G Ninja - name: Configure CMake (Windows MSVC) if: runner.os == 'Windows' && matrix.msystem == '' run: | - cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=${{ matrix.name }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_MSVC_RUNTIME_LIBRARY="MultiThreadedDLL" -A${{ matrix.architecture}} -DLauncher_FORCE_BUNDLED_LIBS=ON + cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_MSVC_RUNTIME_LIBRARY="MultiThreadedDLL" -A${{ matrix.architecture}} -DLauncher_FORCE_BUNDLED_LIBS=ON # https://github.com/ccache/ccache/wiki/MS-Visual-Studio (I coudn't figure out the compiler prefix) if ("${{ env.CCACHE_VAR }}") { @@ -295,7 +295,7 @@ jobs: - name: Configure CMake (Linux) if: runner.os == 'Linux' run: | - cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=Linux -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -G Ninja + cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -G Ninja ## # BUILD From 7033e2857268a314971ea9a29a5dbc83d3b2d978 Mon Sep 17 00:00:00 2001 From: Tayou Date: Wed, 28 Jun 2023 18:00:40 +0200 Subject: [PATCH 25/72] update instance group header to more modern style Signed-off-by: Tayou --- launcher/ui/instanceview/VisualGroup.cpp | 136 ++++++----------------- 1 file changed, 34 insertions(+), 102 deletions(-) diff --git a/launcher/ui/instanceview/VisualGroup.cpp b/launcher/ui/instanceview/VisualGroup.cpp index e6bca17d6..f2d1ca14a 100644 --- a/launcher/ui/instanceview/VisualGroup.cpp +++ b/launcher/ui/instanceview/VisualGroup.cpp @@ -157,133 +157,65 @@ VisualGroup::HitResults VisualGroup::hitScan(const QPoint &pos) const void VisualGroup::drawHeader(QPainter *painter, const QStyleOptionViewItem &option) { - painter->setRenderHint(QPainter::Antialiasing); - const QRect optRect = option.rect; QFont font(QApplication::font()); font.setBold(true); const QFontMetrics fontMetrics = QFontMetrics(font); - QColor outlineColor = option.palette.text().color(); - outlineColor.setAlphaF(0.35); + int centerHeight = option.rect.top() + fontMetrics.height()/2; - //BEGIN: top left corner - { - painter->save(); - painter->setPen(outlineColor); - const QPointF topLeft(optRect.topLeft()); - QRectF arc(topLeft, QSizeF(4, 4)); - arc.translate(0.5, 0.5); - painter->drawArc(arc, 1440, 1440); - painter->restore(); - } - //END: top left corner + QPen pen; + pen.setWidth(2); + QColor penColor = option.palette.text().color(); + penColor.setAlphaF(0.6); + pen.setColor(penColor); + painter->setPen(pen); - //BEGIN: left vertical line + //BEGIN: arrow { - QPoint start(optRect.topLeft()); - start.ry() += 3; - QPoint verticalGradBottom(optRect.topLeft()); - verticalGradBottom.ry() += fontMetrics.height() + 5; - QLinearGradient gradient(start, verticalGradBottom); - gradient.setColorAt(0, outlineColor); - gradient.setColorAt(1, Qt::transparent); - painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient); - } - //END: left vertical line - - //BEGIN: horizontal line - { - QPoint start(optRect.topLeft()); - start.rx() += 3; - QPoint horizontalGradTop(optRect.topLeft()); - horizontalGradTop.rx() += optRect.width() - 6; - painter->fillRect(QRect(start, QSize(optRect.width() - 6, 1)), outlineColor); - } - //END: horizontal line - - //BEGIN: top right corner - { - painter->save(); - painter->setPen(outlineColor); - QPointF topRight(optRect.topRight()); - topRight.rx() -= 4; - QRectF arc(topRight, QSizeF(4, 4)); - arc.translate(0.5, 0.5); - painter->drawArc(arc, 0, 1440); - painter->restore(); - } - //END: top right corner - - //BEGIN: right vertical line - { - QPoint start(optRect.topRight()); - start.ry() += 3; - QPoint verticalGradBottom(optRect.topRight()); - verticalGradBottom.ry() += fontMetrics.height() + 5; - QLinearGradient gradient(start, verticalGradBottom); - gradient.setColorAt(0, outlineColor); - gradient.setColorAt(1, Qt::transparent); - painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient); - } - //END: right vertical line - - //BEGIN: checkboxy thing - { - painter->save(); painter->setRenderHint(QPainter::Antialiasing, false); - painter->setFont(font); - QColor penColor(option.palette.text().color()); - penColor.setAlphaF(0.6); - painter->setPen(penColor); - QRect iconSubRect(option.rect); - iconSubRect.setTop(iconSubRect.top() + 7); - iconSubRect.setLeft(iconSubRect.left() + 7); + painter->save(); - int sizing = fontMetrics.height(); - int even = ( (sizing - 1) % 2 ); + int offsetLeft = fontMetrics.height()/2; + int offsetTop = centerHeight; + int arrowSize = 6; - iconSubRect.setHeight(sizing - even); - iconSubRect.setWidth(sizing - even); - painter->drawRect(iconSubRect); - - - /* - if(collapsed) - painter->drawText(iconSubRect, Qt::AlignHCenter | Qt::AlignVCenter, "+"); - else - painter->drawText(iconSubRect, Qt::AlignHCenter | Qt::AlignVCenter, "-"); - */ - painter->setBrush(option.palette.text()); - painter->fillRect(iconSubRect.x(), iconSubRect.y() + iconSubRect.height() / 2, - iconSubRect.width(), 2, penColor); - if (collapsed) - { - painter->fillRect(iconSubRect.x() + iconSubRect.width() / 2, iconSubRect.y(), 2, - iconSubRect.height(), penColor); + QPolygon polygon; + if (collapsed) { + polygon << QPoint(offsetLeft - arrowSize/2, offsetTop - arrowSize) << QPoint(offsetLeft + arrowSize/2, offsetTop) << QPoint(offsetLeft - arrowSize/2, offsetTop + arrowSize); + painter->drawPolyline(polygon); + } else { + polygon << QPoint(offsetLeft - arrowSize, offsetTop - arrowSize/2) << QPoint(offsetLeft, offsetTop + arrowSize/2) << QPoint(offsetLeft + arrowSize, offsetTop - arrowSize/2); + painter->drawPolyline(polygon); } - - painter->restore(); } - //END: checkboxy thing + //END: arrow //BEGIN: text { + painter->setRenderHint(QPainter::Antialiasing); QRect textRect(option.rect); - textRect.setTop(textRect.top() + 7); - textRect.setLeft(textRect.left() + 7 + fontMetrics.height() + 7); + textRect.setTop(textRect.top()); + textRect.setLeft(textRect.left() + fontMetrics.height()); textRect.setHeight(fontMetrics.height()); textRect.setRight(textRect.right() - 7); painter->save(); painter->setFont(font); - QColor penColor(option.palette.text().color()); - penColor.setAlphaF(0.6); - painter->setPen(penColor); painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text); - painter->restore(); } //END: text + + //BEGIN: horizontal line + { + // startPoint is left + arrow + text + space + int startPoint = optRect.left() + fontMetrics.height() + fontMetrics.size(Qt::AlignLeft | Qt::AlignVCenter, text).width() + 7; + painter->setRenderHint(QPainter::Antialiasing, false); + QPolygon polygon; + polygon << QPoint(startPoint, centerHeight) << QPoint(optRect.right() - 3, centerHeight); + painter->drawPolyline(polygon); + } + //END: horizontal line } int VisualGroup::totalHeight() const From 66461ac500ded75d1d3f4df580296936b85e08b2 Mon Sep 17 00:00:00 2001 From: Tayou Date: Wed, 28 Jun 2023 18:42:49 +0200 Subject: [PATCH 26/72] some positioning adjustments, deleted the line Signed-off-by: Tayou --- launcher/ui/instanceview/VisualGroup.cpp | 34 +++++++++--------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/launcher/ui/instanceview/VisualGroup.cpp b/launcher/ui/instanceview/VisualGroup.cpp index f2d1ca14a..f544c3dc7 100644 --- a/launcher/ui/instanceview/VisualGroup.cpp +++ b/launcher/ui/instanceview/VisualGroup.cpp @@ -157,12 +157,13 @@ VisualGroup::HitResults VisualGroup::hitScan(const QPoint &pos) const void VisualGroup::drawHeader(QPainter *painter, const QStyleOptionViewItem &option) { - const QRect optRect = option.rect; + QRect optRect = option.rect; + optRect.setTop(optRect.top() + 7); QFont font(QApplication::font()); font.setBold(true); const QFontMetrics fontMetrics = QFontMetrics(font); - int centerHeight = option.rect.top() + fontMetrics.height()/2; + int centerHeight = optRect.top() + fontMetrics.height()/2; QPen pen; pen.setWidth(2); @@ -171,21 +172,21 @@ void VisualGroup::drawHeader(QPainter *painter, const QStyleOptionViewItem &opti pen.setColor(penColor); painter->setPen(pen); + int arrowOffsetLeft = fontMetrics.height()/2 + 7; + int textOffsetLeft = arrowOffsetLeft *2; + int arrowSize = 6; + //BEGIN: arrow { painter->setRenderHint(QPainter::Antialiasing, false); painter->save(); - int offsetLeft = fontMetrics.height()/2; - int offsetTop = centerHeight; - int arrowSize = 6; - QPolygon polygon; if (collapsed) { - polygon << QPoint(offsetLeft - arrowSize/2, offsetTop - arrowSize) << QPoint(offsetLeft + arrowSize/2, offsetTop) << QPoint(offsetLeft - arrowSize/2, offsetTop + arrowSize); + polygon << QPoint(arrowOffsetLeft - arrowSize/2, centerHeight - arrowSize) << QPoint(arrowOffsetLeft + arrowSize/2, centerHeight) << QPoint(arrowOffsetLeft - arrowSize/2, centerHeight + arrowSize); painter->drawPolyline(polygon); } else { - polygon << QPoint(offsetLeft - arrowSize, offsetTop - arrowSize/2) << QPoint(offsetLeft, offsetTop + arrowSize/2) << QPoint(offsetLeft + arrowSize, offsetTop - arrowSize/2); + polygon << QPoint(arrowOffsetLeft - arrowSize, centerHeight - arrowSize/2) << QPoint(arrowOffsetLeft, centerHeight + arrowSize/2) << QPoint(arrowOffsetLeft + arrowSize, centerHeight - arrowSize/2); painter->drawPolyline(polygon); } } @@ -194,9 +195,9 @@ void VisualGroup::drawHeader(QPainter *painter, const QStyleOptionViewItem &opti //BEGIN: text { painter->setRenderHint(QPainter::Antialiasing); - QRect textRect(option.rect); + QRect textRect(optRect); textRect.setTop(textRect.top()); - textRect.setLeft(textRect.left() + fontMetrics.height()); + textRect.setLeft(textOffsetLeft); textRect.setHeight(fontMetrics.height()); textRect.setRight(textRect.right() - 7); @@ -205,22 +206,11 @@ void VisualGroup::drawHeader(QPainter *painter, const QStyleOptionViewItem &opti painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text); } //END: text - - //BEGIN: horizontal line - { - // startPoint is left + arrow + text + space - int startPoint = optRect.left() + fontMetrics.height() + fontMetrics.size(Qt::AlignLeft | Qt::AlignVCenter, text).width() + 7; - painter->setRenderHint(QPainter::Antialiasing, false); - QPolygon polygon; - polygon << QPoint(startPoint, centerHeight) << QPoint(optRect.right() - 3, centerHeight); - painter->drawPolyline(polygon); - } - //END: horizontal line } int VisualGroup::totalHeight() const { - return headerHeight() + 5 + contentHeight(); // FIXME: wtf is that '5'? + return headerHeight() + contentHeight(); } int VisualGroup::headerHeight() const From 6b3b119db07b229e22e33313a92a0c81a530f45c Mon Sep 17 00:00:00 2001 From: Tayou Date: Wed, 28 Jun 2023 18:50:44 +0200 Subject: [PATCH 27/72] give ungrouped instances a group header Signed-off-by: Tayou --- launcher/ui/instanceview/VisualGroup.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/launcher/ui/instanceview/VisualGroup.cpp b/launcher/ui/instanceview/VisualGroup.cpp index f544c3dc7..9d8dd2b9e 100644 --- a/launcher/ui/instanceview/VisualGroup.cpp +++ b/launcher/ui/instanceview/VisualGroup.cpp @@ -189,6 +189,7 @@ void VisualGroup::drawHeader(QPainter *painter, const QStyleOptionViewItem &opti polygon << QPoint(arrowOffsetLeft - arrowSize, centerHeight - arrowSize/2) << QPoint(arrowOffsetLeft, centerHeight + arrowSize/2) << QPoint(arrowOffsetLeft + arrowSize, centerHeight - arrowSize/2); painter->drawPolyline(polygon); } + painter->restore(); } //END: arrow @@ -203,7 +204,8 @@ void VisualGroup::drawHeader(QPainter *painter, const QStyleOptionViewItem &opti painter->save(); painter->setFont(font); - painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text); + painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text != "" ? text : QObject::tr("Ungrouped")); + painter->restore(); } //END: text } From 54d88e4dbf058fe32e92becb5af7eab8c1eb051c Mon Sep 17 00:00:00 2001 From: Tayou Date: Wed, 28 Jun 2023 18:57:10 +0200 Subject: [PATCH 28/72] use QString.isEmpty() oops Signed-off-by: Tayou --- launcher/ui/instanceview/VisualGroup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/instanceview/VisualGroup.cpp b/launcher/ui/instanceview/VisualGroup.cpp index 9d8dd2b9e..edf487f19 100644 --- a/launcher/ui/instanceview/VisualGroup.cpp +++ b/launcher/ui/instanceview/VisualGroup.cpp @@ -204,7 +204,7 @@ void VisualGroup::drawHeader(QPainter *painter, const QStyleOptionViewItem &opti painter->save(); painter->setFont(font); - painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text != "" ? text : QObject::tr("Ungrouped")); + painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, !text.isEmpty() ? text : QObject::tr("Ungrouped")); painter->restore(); } //END: text From 534d156b1239aed19c9d36a88ff23d84127ac002 Mon Sep 17 00:00:00 2001 From: Tayou Date: Wed, 28 Jun 2023 20:06:17 +0200 Subject: [PATCH 29/72] format VisualGroup.cpp file Signed-off-by: Tayou --- launcher/ui/instanceview/VisualGroup.cpp | 94 ++++++++++-------------- 1 file changed, 39 insertions(+), 55 deletions(-) diff --git a/launcher/ui/instanceview/VisualGroup.cpp b/launcher/ui/instanceview/VisualGroup.cpp index edf487f19..9b2189b85 100644 --- a/launcher/ui/instanceview/VisualGroup.cpp +++ b/launcher/ui/instanceview/VisualGroup.cpp @@ -35,22 +35,17 @@ #include "VisualGroup.h" +#include +#include #include #include #include -#include -#include #include "InstanceView.h" -VisualGroup::VisualGroup(const QString &text, InstanceView *view) : view(view), text(text), collapsed(false) -{ -} +VisualGroup::VisualGroup(const QString& text, InstanceView* view) : view(view), text(text), collapsed(false) {} -VisualGroup::VisualGroup(const VisualGroup *other) - : view(other->view), text(other->text), collapsed(other->collapsed) -{ -} +VisualGroup::VisualGroup(const VisualGroup* other) : view(other->view), text(other->text), collapsed(other->collapsed) {} void VisualGroup::update() { @@ -64,13 +59,11 @@ void VisualGroup::update() int positionInRow = 0; int currentRow = 0; int offsetFromTop = 0; - for (auto item: temp_items) - { - if(positionInRow == itemsPerRow) - { + for (auto item : temp_items) { + if (positionInRow == itemsPerRow) { rows[currentRow].height = maxRowHeight; rows[currentRow].top = offsetFromTop; - currentRow ++; + currentRow++; offsetFromTop += maxRowHeight + 5; positionInRow = 0; maxRowHeight = 0; @@ -83,8 +76,7 @@ void VisualGroup::update() #endif auto itemHeight = view->itemDelegate()->sizeHint(viewItemOption, item).height(); - if(itemHeight > maxRowHeight) - { + if (itemHeight > maxRowHeight) { maxRowHeight = itemHeight; } rows[currentRow].items.append(item); @@ -94,16 +86,13 @@ void VisualGroup::update() rows[currentRow].top = offsetFromTop; } -QPair VisualGroup::positionOf(const QModelIndex &index) const +QPair VisualGroup::positionOf(const QModelIndex& index) const { int y = 0; - for (auto & row: rows) - { - for(auto x = 0; x < row.items.size(); x++) - { - if(row.items[x] == index) - { - return qMakePair(x,y); + for (auto& row : rows) { + for (auto x = 0; x < row.items.size(); x++) { + if (row.items[x] == index) { + return qMakePair(x, y); } } y++; @@ -112,50 +101,44 @@ QPair VisualGroup::positionOf(const QModelIndex &index) const return qMakePair(0, 0); } -int VisualGroup::rowTopOf(const QModelIndex &index) const +int VisualGroup::rowTopOf(const QModelIndex& index) const { auto position = positionOf(index); return rows[position.second].top; } -int VisualGroup::rowHeightOf(const QModelIndex &index) const +int VisualGroup::rowHeightOf(const QModelIndex& index) const { auto position = positionOf(index); return rows[position.second].height; } -VisualGroup::HitResults VisualGroup::hitScan(const QPoint &pos) const +VisualGroup::HitResults VisualGroup::hitScan(const QPoint& pos) const { VisualGroup::HitResults results = VisualGroup::NoHit; int y_start = verticalPosition(); int body_start = y_start + headerHeight(); - int body_end = body_start + contentHeight() + 5; // FIXME: wtf is this 5? + int body_end = body_start + contentHeight() + 5; // FIXME: wtf is this 5? int y = pos.y(); // int x = pos.x(); - if (y < y_start) - { + if (y < y_start) { results = VisualGroup::NoHit; - } - else if (y < body_start) - { + } else if (y < body_start) { results = VisualGroup::HeaderHit; int collapseSize = headerHeight() - 4; // the icon QRect iconRect = QRect(view->m_leftMargin + 2, 2 + y_start, collapseSize, collapseSize); - if (iconRect.contains(pos)) - { + if (iconRect.contains(pos)) { results |= VisualGroup::CheckboxHit; } - } - else if (y < body_end) - { + } else if (y < body_end) { results |= VisualGroup::BodyHit; } return results; } -void VisualGroup::drawHeader(QPainter *painter, const QStyleOptionViewItem &option) +void VisualGroup::drawHeader(QPainter* painter, const QStyleOptionViewItem& option) { QRect optRect = option.rect; optRect.setTop(optRect.top() + 7); @@ -163,7 +146,7 @@ void VisualGroup::drawHeader(QPainter *painter, const QStyleOptionViewItem &opti font.setBold(true); const QFontMetrics fontMetrics = QFontMetrics(font); - int centerHeight = optRect.top() + fontMetrics.height()/2; + int centerHeight = optRect.top() + fontMetrics.height() / 2; QPen pen; pen.setWidth(2); @@ -172,28 +155,32 @@ void VisualGroup::drawHeader(QPainter *painter, const QStyleOptionViewItem &opti pen.setColor(penColor); painter->setPen(pen); - int arrowOffsetLeft = fontMetrics.height()/2 + 7; - int textOffsetLeft = arrowOffsetLeft *2; + int arrowOffsetLeft = fontMetrics.height() / 2 + 7; + int textOffsetLeft = arrowOffsetLeft * 2; int arrowSize = 6; - //BEGIN: arrow + // BEGIN: arrow { painter->setRenderHint(QPainter::Antialiasing, false); painter->save(); QPolygon polygon; if (collapsed) { - polygon << QPoint(arrowOffsetLeft - arrowSize/2, centerHeight - arrowSize) << QPoint(arrowOffsetLeft + arrowSize/2, centerHeight) << QPoint(arrowOffsetLeft - arrowSize/2, centerHeight + arrowSize); + polygon << QPoint(arrowOffsetLeft - arrowSize / 2, centerHeight - arrowSize) + << QPoint(arrowOffsetLeft + arrowSize / 2, centerHeight) + << QPoint(arrowOffsetLeft - arrowSize / 2, centerHeight + arrowSize); painter->drawPolyline(polygon); } else { - polygon << QPoint(arrowOffsetLeft - arrowSize, centerHeight - arrowSize/2) << QPoint(arrowOffsetLeft, centerHeight + arrowSize/2) << QPoint(arrowOffsetLeft + arrowSize, centerHeight - arrowSize/2); + polygon << QPoint(arrowOffsetLeft - arrowSize, centerHeight - arrowSize / 2) + << QPoint(arrowOffsetLeft, centerHeight + arrowSize / 2) + << QPoint(arrowOffsetLeft + arrowSize, centerHeight - arrowSize / 2); painter->drawPolyline(polygon); } painter->restore(); } - //END: arrow + // END: arrow - //BEGIN: text + // BEGIN: text { painter->setRenderHint(QPainter::Antialiasing); QRect textRect(optRect); @@ -207,7 +194,7 @@ void VisualGroup::drawHeader(QPainter *painter, const QStyleOptionViewItem &opti painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, !text.isEmpty() ? text : QObject::tr("Ungrouped")); painter->restore(); } - //END: text + // END: text } int VisualGroup::totalHeight() const @@ -222,7 +209,7 @@ int VisualGroup::headerHeight() const QFontMetrics fontMetrics(font); const int height = fontMetrics.height() + 1 /* 1 pixel-width gradient */ - + 11 /* top and bottom separation */; + + 11 /* top and bottom separation */; return height; /* int raw = view->viewport()->fontMetrics().height() + 4; @@ -235,8 +222,7 @@ int VisualGroup::headerHeight() const int VisualGroup::contentHeight() const { - if (collapsed) - { + if (collapsed) { return 0; } auto last = rows[numRows() - 1]; @@ -256,11 +242,9 @@ int VisualGroup::verticalPosition() const QList VisualGroup::items() const { QList indices; - for (int i = 0; i < view->model()->rowCount(); ++i) - { + for (int i = 0; i < view->model()->rowCount(); ++i) { const QModelIndex index = view->model()->index(i, 0); - if (index.data(InstanceViewRoles::GroupRole).toString() == text) - { + if (index.data(InstanceViewRoles::GroupRole).toString() == text) { indices.append(index); } } From 1dc7f800347d6b4e179a12de14af7f4ad87b7f27 Mon Sep 17 00:00:00 2001 From: Tayou Date: Wed, 28 Jun 2023 23:02:34 +0200 Subject: [PATCH 30/72] 4 clang-tidy changes, update copyright info while already at it I updated all my emails to use one from my domain Signed-off-by: Tayou --- launcher/Application.cpp | 2 +- launcher/Application.h | 2 +- launcher/ui/instanceview/VisualGroup.cpp | 12 +++-- launcher/ui/instanceview/VisualGroup.h | 48 +++++++++++++------ launcher/ui/pages/global/LauncherPage.cpp | 2 +- launcher/ui/setupwizard/ThemeWizardPage.cpp | 2 +- launcher/ui/setupwizard/ThemeWizardPage.h | 2 +- launcher/ui/themes/CustomTheme.cpp | 2 +- launcher/ui/themes/CustomTheme.h | 2 +- launcher/ui/themes/ITheme.cpp | 2 +- launcher/ui/themes/ITheme.h | 2 +- launcher/ui/themes/SystemTheme.cpp | 2 +- launcher/ui/themes/SystemTheme.h | 2 +- launcher/ui/themes/ThemeManager.cpp | 2 +- launcher/ui/themes/ThemeManager.h | 2 +- .../ui/widgets/ThemeCustomizationWidget.cpp | 2 +- .../ui/widgets/ThemeCustomizationWidget.h | 2 +- 17 files changed, 56 insertions(+), 34 deletions(-) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 1d97a5f2e..8e1d0cbdd 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -6,7 +6,7 @@ * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 Sefa Eyeoglu * Copyright (C) 2022 Lenny McLennington - * Copyright (C) 2022 Tayou + * Copyright (C) 2022 Tayou * Copyright (C) 2023 TheKodeToad * Copyright (C) 2023 Rachel Powers <508861+Ryex@users.noreply.github.com> * diff --git a/launcher/Application.h b/launcher/Application.h index ced0af17d..527c536b3 100644 --- a/launcher/Application.h +++ b/launcher/Application.h @@ -2,7 +2,7 @@ /* * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 Sefa Eyeoglu - * Copyright (C) 2022 Tayou + * Copyright (C) 2022 Tayou * Copyright (C) 2023 TheKodeToad * * This program is free software: you can redistribute it and/or modify diff --git a/launcher/ui/instanceview/VisualGroup.cpp b/launcher/ui/instanceview/VisualGroup.cpp index 9b2189b85..8663633b4 100644 --- a/launcher/ui/instanceview/VisualGroup.cpp +++ b/launcher/ui/instanceview/VisualGroup.cpp @@ -1,7 +1,8 @@ // SPDX-License-Identifier: GPL-3.0-only /* - * PolyMC - Minecraft Launcher + * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 Sefa Eyeoglu + * Copyright (C) 2023 Tayou * * 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 @@ -40,10 +41,11 @@ #include #include #include +#include #include "InstanceView.h" -VisualGroup::VisualGroup(const QString& text, InstanceView* view) : view(view), text(text), collapsed(false) {} +VisualGroup::VisualGroup(QString text, InstanceView* view) : view(view), text(std::move(text)), collapsed(false) {} VisualGroup::VisualGroup(const VisualGroup* other) : view(other->view), text(other->text), collapsed(other->collapsed) {} @@ -138,7 +140,7 @@ VisualGroup::HitResults VisualGroup::hitScan(const QPoint& pos) const return results; } -void VisualGroup::drawHeader(QPainter* painter, const QStyleOptionViewItem& option) +void VisualGroup::drawHeader(QPainter* painter, const QStyleOptionViewItem& option) const { QRect optRect = option.rect; optRect.setTop(optRect.top() + 7); @@ -202,7 +204,7 @@ int VisualGroup::totalHeight() const return headerHeight() + contentHeight(); } -int VisualGroup::headerHeight() const +int VisualGroup::headerHeight() { QFont font(QApplication::font()); font.setBold(true); @@ -231,7 +233,7 @@ int VisualGroup::contentHeight() const int VisualGroup::numRows() const { - return rows.size(); + return (int)rows.size(); } int VisualGroup::verticalPosition() const diff --git a/launcher/ui/instanceview/VisualGroup.h b/launcher/ui/instanceview/VisualGroup.h index 5a743aa18..697298c2d 100644 --- a/launcher/ui/instanceview/VisualGroup.h +++ b/launcher/ui/instanceview/VisualGroup.h @@ -1,16 +1,36 @@ -/* Copyright 2013-2021 MultiMC Contributors +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2023 Tayou * - * 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * 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. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #pragma once @@ -42,8 +62,8 @@ struct VisualRow struct VisualGroup { /* constructors */ - VisualGroup(const QString &text, InstanceView *view); - VisualGroup(const VisualGroup *other); + VisualGroup(QString text, InstanceView *view); + explicit VisualGroup(const VisualGroup *other); /* data */ InstanceView *view = nullptr; @@ -58,13 +78,13 @@ struct VisualGroup void update(); /// draw the header at y-position. - void drawHeader(QPainter *painter, const QStyleOptionViewItem &option); + void drawHeader(QPainter *painter, const QStyleOptionViewItem &option) const; /// height of the group, in total. includes a small bit of padding. int totalHeight() const; /// height of the group header, in pixels - int headerHeight() const; + static int headerHeight() ; /// height of the group content, in pixels int contentHeight() const; diff --git a/launcher/ui/pages/global/LauncherPage.cpp b/launcher/ui/pages/global/LauncherPage.cpp index 816dde723..2080b56f0 100644 --- a/launcher/ui/pages/global/LauncherPage.cpp +++ b/launcher/ui/pages/global/LauncherPage.cpp @@ -3,7 +3,7 @@ * Prism Launcher - Minecraft Launcher * Copyright (c) 2022 Jamie Mansfield * Copyright (c) 2022 dada513 - * Copyright (C) 2022 Tayou + * Copyright (C) 2022 Tayou * * 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 diff --git a/launcher/ui/setupwizard/ThemeWizardPage.cpp b/launcher/ui/setupwizard/ThemeWizardPage.cpp index 42826aba1..c3e0a5241 100644 --- a/launcher/ui/setupwizard/ThemeWizardPage.cpp +++ b/launcher/ui/setupwizard/ThemeWizardPage.cpp @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only /* * Prism Launcher - Minecraft Launcher - * Copyright (C) 2022 Tayou + * Copyright (C) 2022 Tayou * * 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 diff --git a/launcher/ui/setupwizard/ThemeWizardPage.h b/launcher/ui/setupwizard/ThemeWizardPage.h index 61a3d0c01..f3d40b6d8 100644 --- a/launcher/ui/setupwizard/ThemeWizardPage.h +++ b/launcher/ui/setupwizard/ThemeWizardPage.h @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only /* * Prism Launcher - Minecraft Launcher - * Copyright (C) 2022 Tayou + * Copyright (C) 2022 Tayou * * 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 diff --git a/launcher/ui/themes/CustomTheme.cpp b/launcher/ui/themes/CustomTheme.cpp index 198e76ba1..177edefad 100644 --- a/launcher/ui/themes/CustomTheme.cpp +++ b/launcher/ui/themes/CustomTheme.cpp @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only /* * Prism Launcher - Minecraft Launcher - * Copyright (C) 2022 Tayou + * Copyright (C) 2022 Tayou * * 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 diff --git a/launcher/ui/themes/CustomTheme.h b/launcher/ui/themes/CustomTheme.h index f2b1b06ed..3ec4cafa2 100644 --- a/launcher/ui/themes/CustomTheme.h +++ b/launcher/ui/themes/CustomTheme.h @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only /* * Prism Launcher - Minecraft Launcher - * Copyright (C) 2022 Tayou + * Copyright (C) 2022 Tayou * * 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 diff --git a/launcher/ui/themes/ITheme.cpp b/launcher/ui/themes/ITheme.cpp index 8f0757e1a..42d63b113 100644 --- a/launcher/ui/themes/ITheme.cpp +++ b/launcher/ui/themes/ITheme.cpp @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only /* * Prism Launcher - Minecraft Launcher - * Copyright (C) 2022 Tayou + * Copyright (C) 2022 Tayou * * 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 diff --git a/launcher/ui/themes/ITheme.h b/launcher/ui/themes/ITheme.h index a0a638bd0..d85e7f983 100644 --- a/launcher/ui/themes/ITheme.h +++ b/launcher/ui/themes/ITheme.h @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only /* * Prism Launcher - Minecraft Launcher - * Copyright (C) 2022 Tayou + * Copyright (C) 2022 Tayou * * 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 diff --git a/launcher/ui/themes/SystemTheme.cpp b/launcher/ui/themes/SystemTheme.cpp index 3a746d027..3b8cb24a4 100644 --- a/launcher/ui/themes/SystemTheme.cpp +++ b/launcher/ui/themes/SystemTheme.cpp @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only /* * Prism Launcher - Minecraft Launcher - * Copyright (C) 2022 Tayou + * Copyright (C) 2022 Tayou * * 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 diff --git a/launcher/ui/themes/SystemTheme.h b/launcher/ui/themes/SystemTheme.h index 05f31233e..4f7d83e57 100644 --- a/launcher/ui/themes/SystemTheme.h +++ b/launcher/ui/themes/SystemTheme.h @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only /* * Prism Launcher - Minecraft Launcher - * Copyright (C) 2022 Tayou + * Copyright (C) 2022 Tayou * * 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 diff --git a/launcher/ui/themes/ThemeManager.cpp b/launcher/ui/themes/ThemeManager.cpp index 94ac8a245..b50c6157f 100644 --- a/launcher/ui/themes/ThemeManager.cpp +++ b/launcher/ui/themes/ThemeManager.cpp @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only /* * Prism Launcher - Minecraft Launcher - * Copyright (C) 2022 Tayou + * Copyright (C) 2022 Tayou * * 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 diff --git a/launcher/ui/themes/ThemeManager.h b/launcher/ui/themes/ThemeManager.h index 87f36d9c1..d2a6fb70a 100644 --- a/launcher/ui/themes/ThemeManager.h +++ b/launcher/ui/themes/ThemeManager.h @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only /* * Prism Launcher - Minecraft Launcher - * Copyright (C) 2022 Tayou + * Copyright (C) 2022 Tayou * * 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 diff --git a/launcher/ui/widgets/ThemeCustomizationWidget.cpp b/launcher/ui/widgets/ThemeCustomizationWidget.cpp index dcf13303c..3bfcd8213 100644 --- a/launcher/ui/widgets/ThemeCustomizationWidget.cpp +++ b/launcher/ui/widgets/ThemeCustomizationWidget.cpp @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only /* * Prism Launcher - Minecraft Launcher - * Copyright (C) 2022 Tayou + * Copyright (C) 2022 Tayou * * 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 diff --git a/launcher/ui/widgets/ThemeCustomizationWidget.h b/launcher/ui/widgets/ThemeCustomizationWidget.h index d955a2665..6c33c3c50 100644 --- a/launcher/ui/widgets/ThemeCustomizationWidget.h +++ b/launcher/ui/widgets/ThemeCustomizationWidget.h @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only /* * Prism Launcher - Minecraft Launcher - * Copyright (C) 2022 Tayou + * Copyright (C) 2022 Tayou * * 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 From 8211befc29a4a5b05e1ff1bdd3e7fc2dfb90fc82 Mon Sep 17 00:00:00 2001 From: Tayou Date: Wed, 28 Jun 2023 23:24:57 +0200 Subject: [PATCH 31/72] removed magic 5, removed unnecessary QPainter function calls Signed-off-by: Tayou --- launcher/ui/instanceview/VisualGroup.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/launcher/ui/instanceview/VisualGroup.cpp b/launcher/ui/instanceview/VisualGroup.cpp index 8663633b4..7d52e4ad7 100644 --- a/launcher/ui/instanceview/VisualGroup.cpp +++ b/launcher/ui/instanceview/VisualGroup.cpp @@ -120,7 +120,7 @@ VisualGroup::HitResults VisualGroup::hitScan(const QPoint& pos) const VisualGroup::HitResults results = VisualGroup::NoHit; int y_start = verticalPosition(); int body_start = y_start + headerHeight(); - int body_end = body_start + contentHeight() + 5; // FIXME: wtf is this 5? + int body_end = body_start + contentHeight(); int y = pos.y(); // int x = pos.x(); if (y < y_start) { @@ -147,8 +147,7 @@ void VisualGroup::drawHeader(QPainter* painter, const QStyleOptionViewItem& opti QFont font(QApplication::font()); font.setBold(true); const QFontMetrics fontMetrics = QFontMetrics(font); - - int centerHeight = optRect.top() + fontMetrics.height() / 2; + painter->setFont(font); QPen pen; pen.setWidth(2); @@ -157,14 +156,15 @@ void VisualGroup::drawHeader(QPainter* painter, const QStyleOptionViewItem& opti pen.setColor(penColor); painter->setPen(pen); + // sizes and offsets, to keep things consistent below int arrowOffsetLeft = fontMetrics.height() / 2 + 7; int textOffsetLeft = arrowOffsetLeft * 2; int arrowSize = 6; + int centerHeight = optRect.top() + fontMetrics.height() / 2; // BEGIN: arrow { painter->setRenderHint(QPainter::Antialiasing, false); - painter->save(); QPolygon polygon; if (collapsed) { @@ -178,7 +178,6 @@ void VisualGroup::drawHeader(QPainter* painter, const QStyleOptionViewItem& opti << QPoint(arrowOffsetLeft + arrowSize, centerHeight - arrowSize / 2); painter->drawPolyline(polygon); } - painter->restore(); } // END: arrow @@ -191,10 +190,7 @@ void VisualGroup::drawHeader(QPainter* painter, const QStyleOptionViewItem& opti textRect.setHeight(fontMetrics.height()); textRect.setRight(textRect.right() - 7); - painter->save(); - painter->setFont(font); painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, !text.isEmpty() ? text : QObject::tr("Ungrouped")); - painter->restore(); } // END: text } From 7579fff532629643384d9b8011e885028ca9a8f0 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 2 Jul 2023 13:34:04 +0300 Subject: [PATCH 32/72] Added more options for variants planing Signed-off-by: Trial97 --- launcher/ui/themes/CatPack.cpp | 10 ++++++---- launcher/ui/themes/CatPack.h | 4 ++-- launcher/ui/themes/ThemeManager.cpp | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/launcher/ui/themes/CatPack.cpp b/launcher/ui/themes/CatPack.cpp index 2d5653a67..a0b06a600 100644 --- a/launcher/ui/themes/CatPack.cpp +++ b/launcher/ui/themes/CatPack.cpp @@ -99,11 +99,13 @@ JsonCatPack::JsonCatPack(QFileInfo& manifestInfo) : BasicCatPack(manifestInfo.di QString JsonCatPack::path() { - const QDateTime now = QDateTime::currentDateTime(); + const QDate now = QDate::currentDate(); for (auto var : m_variants) { - QDateTime startDate(QDate(now.date().year(), var.startTime.mounth, var.startTime.day), QTime(0, 0)); - QDateTime endDate(QDate(now.date().year(), var.endTime.mounth, var.endTime.day), QTime(0, 0)); - if (startDate.daysTo(now) > 0 && now.daysTo(endDate) > 0) + QDate startDate(now.year(), var.startTime.month, var.startTime.day); + QDate endDate(now.year(), var.endTime.month, var.endTime.day); + if (startDate.daysTo(endDate) < 0) // in this case end date should be next year + endDate = endDate.addYears(1); + if (startDate.daysTo(now) >= 0 && now.daysTo(endDate) >= 0) return var.path; } return m_defaultPath; diff --git a/launcher/ui/themes/CatPack.h b/launcher/ui/themes/CatPack.h index 9f288d3dd..e22df1f42 100644 --- a/launcher/ui/themes/CatPack.h +++ b/launcher/ui/themes/CatPack.h @@ -79,9 +79,9 @@ class JsonCatPack : public BasicCatPack { auto sp = d.split("-"); day = sp[0].toInt(); if (sp.length() >= 2) - mounth = sp[1].toInt(); + month = sp[1].toInt(); } - int mounth; + int month; int day; }; struct Variant { diff --git a/launcher/ui/themes/ThemeManager.cpp b/launcher/ui/themes/ThemeManager.cpp index bfd0550a8..d00b3a992 100644 --- a/launcher/ui/themes/ThemeManager.cpp +++ b/launcher/ui/themes/ThemeManager.cpp @@ -189,7 +189,7 @@ void ThemeManager::initializeCatPacks() while (ImageFileIterator.hasNext()) { QFile customCatFile(ImageFileIterator.next()); QFileInfo customCatFileInfo(customCatFile); - themeDebugLog() << "Loading QSS Theme from:" << customCatFileInfo.absoluteFilePath(); + themeDebugLog() << "Loading CatPack from:" << customCatFileInfo.absoluteFilePath(); addCatPack(std::unique_ptr(new FileCatPack(customCatFileInfo))); } }; From 81c0a1c4bd3b26c24a506e6d84c878b0786cf14a Mon Sep 17 00:00:00 2001 From: Tayou Date: Sun, 2 Jul 2023 14:01:56 +0200 Subject: [PATCH 33/72] antialiasing for all painting, make hitbox fullwidth Signed-off-by: Tayou --- launcher/ui/instanceview/VisualGroup.cpp | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/launcher/ui/instanceview/VisualGroup.cpp b/launcher/ui/instanceview/VisualGroup.cpp index 7d52e4ad7..aaf31941d 100644 --- a/launcher/ui/instanceview/VisualGroup.cpp +++ b/launcher/ui/instanceview/VisualGroup.cpp @@ -130,7 +130,7 @@ VisualGroup::HitResults VisualGroup::hitScan(const QPoint& pos) const int collapseSize = headerHeight() - 4; // the icon - QRect iconRect = QRect(view->m_leftMargin + 2, 2 + y_start, collapseSize, collapseSize); + QRect iconRect = QRect(view->m_leftMargin + 2, 2 + y_start, view->width() - 4, collapseSize); if (iconRect.contains(pos)) { results |= VisualGroup::CheckboxHit; } @@ -155,6 +155,7 @@ void VisualGroup::drawHeader(QPainter* painter, const QStyleOptionViewItem& opti penColor.setAlphaF(0.6); pen.setColor(penColor); painter->setPen(pen); + painter->setRenderHint(QPainter::Antialiasing); // sizes and offsets, to keep things consistent below int arrowOffsetLeft = fontMetrics.height() / 2 + 7; @@ -164,26 +165,23 @@ void VisualGroup::drawHeader(QPainter* painter, const QStyleOptionViewItem& opti // BEGIN: arrow { - painter->setRenderHint(QPainter::Antialiasing, false); - - QPolygon polygon; + QPolygon arrowPolygon; if (collapsed) { - polygon << QPoint(arrowOffsetLeft - arrowSize / 2, centerHeight - arrowSize) - << QPoint(arrowOffsetLeft + arrowSize / 2, centerHeight) - << QPoint(arrowOffsetLeft - arrowSize / 2, centerHeight + arrowSize); - painter->drawPolyline(polygon); + arrowPolygon << QPoint(arrowOffsetLeft - arrowSize / 2, centerHeight - arrowSize) + << QPoint(arrowOffsetLeft + arrowSize / 2, centerHeight) + << QPoint(arrowOffsetLeft - arrowSize / 2, centerHeight + arrowSize); + painter->drawPolyline(arrowPolygon); } else { - polygon << QPoint(arrowOffsetLeft - arrowSize, centerHeight - arrowSize / 2) - << QPoint(arrowOffsetLeft, centerHeight + arrowSize / 2) - << QPoint(arrowOffsetLeft + arrowSize, centerHeight - arrowSize / 2); - painter->drawPolyline(polygon); + arrowPolygon << QPoint(arrowOffsetLeft - arrowSize, centerHeight - arrowSize / 2) + << QPoint(arrowOffsetLeft, centerHeight + arrowSize / 2) + << QPoint(arrowOffsetLeft + arrowSize, centerHeight - arrowSize / 2); + painter->drawPolyline(arrowPolygon); } } // END: arrow // BEGIN: text { - painter->setRenderHint(QPainter::Antialiasing); QRect textRect(optRect); textRect.setTop(textRect.top()); textRect.setLeft(textOffsetLeft); From 5d5f1b86fdaa865bf8627acd86163469389ebb83 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Mon, 3 Jul 2023 09:21:25 +0300 Subject: [PATCH 34/72] fixed logic regarding range over multiple years Signed-off-by: Trial97 --- launcher/ui/themes/CatPack.cpp | 29 +++++++++++++++-------------- launcher/ui/themes/CatPack.h | 10 +++++----- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/launcher/ui/themes/CatPack.cpp b/launcher/ui/themes/CatPack.cpp index 4170febd7..435ccdb88 100644 --- a/launcher/ui/themes/CatPack.cpp +++ b/launcher/ui/themes/CatPack.cpp @@ -34,11 +34,7 @@ */ #include "ui/themes/CatPack.h" -#include -#include -#include -#include -#include +#include #include #include #include "FileSystem.h" @@ -47,10 +43,10 @@ QString BasicCatPack::path() { - const QDateTime now = QDateTime::currentDateTime(); - const QDateTime birthday(QDate(now.date().year(), 11, 30), QTime(0, 0)); - const QDateTime xmas(QDate(now.date().year(), 12, 25), QTime(0, 0)); - const QDateTime halloween(QDate(now.date().year(), 10, 31), QTime(0, 0)); + const auto now = QDate::currentDate(); + const auto birthday = QDate(now.year(), 11, 30); + const auto xmas = QDate(now.year(), 12, 25); + const auto halloween = QDate(now.year(), 10, 31); QString cat = QString(":/backgrounds/%1").arg(m_id); if (std::abs(now.daysTo(xmas)) <= 4) { @@ -85,8 +81,8 @@ JsonCatPack::JsonCatPack(QFileInfo& manifestInfo) : BasicCatPack(manifestInfo.di for (auto v : variants) { auto variant = Json::ensureObject(v, QJsonObject(), "Cat variant"); m_variants << Variant{ FS::PathCombine(path, Json::requireString(variant, "path", "Variant path")), - date(Json::requireString(variant, "startTime", "Variant startTime")), - date(Json::requireString(variant, "endTime", "Variant endTime")) }; + PartialDate(Json::requireString(variant, "startTime", "Variant startTime")), + PartialDate(Json::requireString(variant, "endTime", "Variant endTime")) }; } } catch (const Exception& e) { @@ -104,9 +100,14 @@ QString JsonCatPack::path() for (auto var : m_variants) { QDate startDate(now.year(), var.startTime.month, var.startTime.day); QDate endDate(now.year(), var.endTime.month, var.endTime.day); - if (startDate.daysTo(endDate) < 0) // in this case end date should be next year - endDate = endDate.addYears(1); - if (startDate.daysTo(now) >= 0 && now.daysTo(endDate) >= 0) + if (startDate > endDate) { // it's spans over multiple years + if (endDate <= now) // end date is in the past so jump one year into the future for endDate + endDate = endDate.addYears(1); + else // end date is in the future so jump one year into the past for startDate + startDate = startDate.addYears(-1); + } + + if (startDate >= now && now >= endDate) return var.path; } return m_defaultPath; diff --git a/launcher/ui/themes/CatPack.h b/launcher/ui/themes/CatPack.h index e22df1f42..20cb8f61e 100644 --- a/launcher/ui/themes/CatPack.h +++ b/launcher/ui/themes/CatPack.h @@ -35,7 +35,7 @@ #pragma once -#include +#include #include #include #include @@ -73,8 +73,8 @@ class FileCatPack : public BasicCatPack { class JsonCatPack : public BasicCatPack { public: - struct date { - date(QString d) + struct PartialDate { + PartialDate(QString d) { auto sp = d.split("-"); day = sp[0].toInt(); @@ -86,8 +86,8 @@ class JsonCatPack : public BasicCatPack { }; struct Variant { QString path; - date startTime; - date endTime; + PartialDate startTime; + PartialDate endTime; }; JsonCatPack(QFileInfo& manifestInfo); virtual QString path(); From 89aaedc06c3eb7a035d8be593a7bbe417cb2f712 Mon Sep 17 00:00:00 2001 From: seth Date: Wed, 12 Jul 2023 21:10:48 -0400 Subject: [PATCH 35/72] feat: add toggle for quilt beacon Signed-off-by: seth --- launcher/Application.cpp | 4 ++++ launcher/minecraft/MinecraftInstance.cpp | 10 ++++++++- launcher/ui/pages/global/MinecraftPage.cpp | 6 +++++ launcher/ui/pages/global/MinecraftPage.ui | 16 ++++++++++++++ .../pages/instance/InstanceSettingsPage.cpp | 15 ++++++++++++- .../ui/pages/instance/InstanceSettingsPage.ui | 22 +++++++++++++++++++ 6 files changed, 71 insertions(+), 2 deletions(-) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 5aa9efc4a..f98594292 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -9,6 +9,7 @@ * Copyright (C) 2022 Tayou * Copyright (C) 2023 TheKodeToad * Copyright (C) 2023 Rachel Powers <508861+Ryex@users.noreply.github.com> + * Copyright (C) 2023 seth * * 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 @@ -605,6 +606,9 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) m_settings->registerSetting("IgnoreJavaCompatibility", false); m_settings->registerSetting("IgnoreJavaWizard", false); + // Mod loader settings + m_settings->registerSetting("DisableQuiltBeacon", false); + // Native library workarounds m_settings->registerSetting("UseNativeOpenAL", false); m_settings->registerSetting("UseNativeGLFW", false); diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index 4867cc7a3..180838ad2 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -3,7 +3,8 @@ * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 Sefa Eyeoglu * Copyright (C) 2022 Jamie Mansfield - * Copyright (C) 2022 TheKodeToad + * Copyright (C) 2022 TheKodeToad \ + * Copyright (c) 2023 seth * * 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 @@ -186,6 +187,10 @@ void MinecraftInstance::loadSpecificSettings() m_settings->registerOverride(global_settings->getSetting("CloseAfterLaunch"), miscellaneousOverride); m_settings->registerOverride(global_settings->getSetting("QuitAfterGameStop"), miscellaneousOverride); + // Mod loader specific options + auto modLoaderSettings = m_settings->registerSetting("OverrideModLoaderSettings", false); + m_settings->registerOverride(global_settings->getSetting("DisableQuiltBeacon"), modLoaderSettings); + m_settings->set("InstanceType", "OneSix"); } @@ -391,6 +396,9 @@ QStringList MinecraftInstance::extraArguments() agent->library()->getApplicableFiles(runtimeContext(), jar, temp1, temp2, temp3, getLocalLibraryPath()); list.append("-javaagent:"+jar[0]+(agent->argument().isEmpty() ? "" : "="+agent->argument())); } + if (version->getModLoaders().value() & ResourceAPI::Quilt && settings()->get("DisableQuiltBeacon").toBool()) { + list.append("-Dloader.disable_beacon=true"); + } return list; } diff --git a/launcher/ui/pages/global/MinecraftPage.cpp b/launcher/ui/pages/global/MinecraftPage.cpp index eca3e8657..954823564 100644 --- a/launcher/ui/pages/global/MinecraftPage.cpp +++ b/launcher/ui/pages/global/MinecraftPage.cpp @@ -2,6 +2,7 @@ /* * PolyMC - Minecraft Launcher * Copyright (c) 2022 Jamie Mansfield + * Copyright (C) 2023 seth * * 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 @@ -99,6 +100,9 @@ void MinecraftPage::applySettings() // Miscellaneous s->set("CloseAfterLaunch", ui->closeAfterLaunchCheck->isChecked()); s->set("QuitAfterGameStop", ui->quitAfterGameStopCheck->isChecked()); + + // Mod loader settings + s->set("DisableQuiltBeacon", ui->disableQuiltBeaconCheckBox->isChecked()); } void MinecraftPage::loadSettings() @@ -137,6 +141,8 @@ void MinecraftPage::loadSettings() ui->closeAfterLaunchCheck->setChecked(s->get("CloseAfterLaunch").toBool()); ui->quitAfterGameStopCheck->setChecked(s->get("QuitAfterGameStop").toBool()); + + ui->disableQuiltBeaconCheckBox->setChecked(s->get("DisableQuiltBeacon").toBool()); } void MinecraftPage::retranslate() diff --git a/launcher/ui/pages/global/MinecraftPage.ui b/launcher/ui/pages/global/MinecraftPage.ui index 8f5de725d..7a8f107b0 100644 --- a/launcher/ui/pages/global/MinecraftPage.ui +++ b/launcher/ui/pages/global/MinecraftPage.ui @@ -190,6 +190,22 @@ Tweaks + + + + Mod loader settings + + + + + + Disable Quilt's Beacon + + + + + + diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.cpp b/launcher/ui/pages/instance/InstanceSettingsPage.cpp index 943ff17f1..25cc1a0de 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.cpp +++ b/launcher/ui/pages/instance/InstanceSettingsPage.cpp @@ -3,6 +3,7 @@ * PolyMC - Minecraft Launcher * Copyright (c) 2022 Jamie Mansfield * Copyright (C) 2022 Sefa Eyeoglu + * Copyright (C) 2023 seth * * 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 @@ -50,9 +51,9 @@ #include "Application.h" #include "minecraft/auth/AccountList.h" +#include "FileSystem.h" #include "java/JavaInstallList.h" #include "java/JavaUtils.h" -#include "FileSystem.h" InstanceSettingsPage::InstanceSettingsPage(BaseInstance *inst, QWidget *parent) : QWidget(parent), ui(new Ui::InstanceSettingsPage), m_instance(inst) @@ -280,6 +281,14 @@ void InstanceSettingsPage::applySettings() m_settings->reset("InstanceAccountId"); } + bool overrideModLoaderSettings = ui->modLoaderSettingsGroupBox->isChecked(); + m_settings->set("OverrideModLoaderSettings", overrideModLoaderSettings); + if (overrideModLoaderSettings) { + m_settings->set("DisableQuiltBeacon", ui->disableQuiltBeaconCheckBox->isChecked()); + } else { + m_settings->reset("DisableQuiltBeacon"); + } + // FIXME: This should probably be called by a signal instead m_instance->updateRuntimeContext(); } @@ -380,6 +389,10 @@ void InstanceSettingsPage::loadSettings() ui->instanceAccountGroupBox->setChecked(m_settings->get("UseAccountForInstance").toBool()); updateAccountsMenu(); + + // Mod loader specific settings + ui->modLoaderSettingsGroupBox->setChecked(m_settings->get("OverrideModLoaderSettings").toBool()); + ui->disableQuiltBeaconCheckBox->setChecked(m_settings->get("DisableQuiltBeacon").toBool()); } void InstanceSettingsPage::on_javaDetectBtn_clicked() diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.ui b/launcher/ui/pages/instance/InstanceSettingsPage.ui index 8427965de..5c6f74d47 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.ui +++ b/launcher/ui/pages/instance/InstanceSettingsPage.ui @@ -541,6 +541,28 @@ Miscellaneous + + + + true + + + false + + + Mod loader settings + + + + + + Disable Quilt's Beacon + + + + + + From fc4a1ef1935059b3c8e4f5d7bdac9fa2311485ac Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 14 Jul 2023 13:31:13 +0300 Subject: [PATCH 36/72] format Signed-off-by: Trial97 --- launcher/BaseVersion.h | 19 ++++++------------- launcher/java/JavaInstall.cpp | 14 ++++++-------- launcher/java/JavaInstall.h | 31 +++++++++---------------------- 3 files changed, 21 insertions(+), 43 deletions(-) diff --git a/launcher/BaseVersion.h b/launcher/BaseVersion.h index ca0e45027..c7cedbe10 100644 --- a/launcher/BaseVersion.h +++ b/launcher/BaseVersion.h @@ -15,16 +15,15 @@ #pragma once -#include -#include #include +#include +#include /*! * An abstract base class for versions. */ -class BaseVersion -{ -public: +class BaseVersion { + public: using Ptr = std::shared_ptr; virtual ~BaseVersion() {} /*! @@ -45,14 +44,8 @@ public: */ virtual QString typeString() const = 0; - virtual bool operator<(BaseVersion &a) - { - return name() < a.name(); - }; - virtual bool operator>(BaseVersion &a) - { - return name() > a.name(); - }; + virtual bool operator<(BaseVersion& a) { return name() < a.name(); }; + virtual bool operator>(BaseVersion& a) { return name() > a.name(); }; }; Q_DECLARE_METATYPE(BaseVersion::Ptr) diff --git a/launcher/java/JavaInstall.cpp b/launcher/java/JavaInstall.cpp index d5932bcb9..f095aa37f 100644 --- a/launcher/java/JavaInstall.cpp +++ b/launcher/java/JavaInstall.cpp @@ -2,28 +2,26 @@ #include "StringUtils.h" -bool JavaInstall::operator<(const JavaInstall &rhs) +bool JavaInstall::operator<(const JavaInstall& rhs) { auto archCompare = StringUtils::naturalCompare(arch, rhs.arch, Qt::CaseInsensitive); - if(archCompare != 0) + if (archCompare != 0) return archCompare < 0; - if(id < rhs.id) - { + if (id < rhs.id) { return true; } - if(id > rhs.id) - { + if (id > rhs.id) { return false; } return StringUtils::naturalCompare(path, rhs.path, Qt::CaseInsensitive) < 0; } -bool JavaInstall::operator==(const JavaInstall &rhs) +bool JavaInstall::operator==(const JavaInstall& rhs) { return arch == rhs.arch && id == rhs.id && path == rhs.path; } -bool JavaInstall::operator>(const JavaInstall &rhs) +bool JavaInstall::operator>(const JavaInstall& rhs) { return (!operator<(rhs)) && (!operator==(rhs)); } diff --git a/launcher/java/JavaInstall.h b/launcher/java/JavaInstall.h index 64be40d19..2d6e4d537 100644 --- a/launcher/java/JavaInstall.h +++ b/launcher/java/JavaInstall.h @@ -3,31 +3,18 @@ #include "BaseVersion.h" #include "JavaVersion.h" -struct JavaInstall : public BaseVersion -{ - JavaInstall(){} - JavaInstall(QString id, QString arch, QString path) - : id(id), arch(arch), path(path) - { - } - virtual QString descriptor() - { - return id.toString(); - } +struct JavaInstall : public BaseVersion { + JavaInstall() {} + JavaInstall(QString id, QString arch, QString path) : id(id), arch(arch), path(path) {} + virtual QString descriptor() { return id.toString(); } - virtual QString name() - { - return id.toString(); - } + virtual QString name() { return id.toString(); } - virtual QString typeString() const - { - return arch; - } + virtual QString typeString() const { return arch; } - bool operator<(const JavaInstall & rhs); - bool operator==(const JavaInstall & rhs); - bool operator>(const JavaInstall & rhs); + bool operator<(const JavaInstall& rhs); + bool operator==(const JavaInstall& rhs); + bool operator>(const JavaInstall& rhs); JavaVersion id; QString arch; From b0a21c9389dfb6962713b61cdb28fa0022c25eeb Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 14 Jul 2023 13:31:28 +0300 Subject: [PATCH 37/72] insert header Signed-off-by: Trial97 --- launcher/java/JavaInstall.cpp | 18 ++++++++++++++++++ launcher/java/JavaInstall.h | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/launcher/java/JavaInstall.cpp b/launcher/java/JavaInstall.cpp index f095aa37f..2931a0deb 100644 --- a/launcher/java/JavaInstall.cpp +++ b/launcher/java/JavaInstall.cpp @@ -1,3 +1,21 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2023 Trial97 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "JavaInstall.h" #include "StringUtils.h" diff --git a/launcher/java/JavaInstall.h b/launcher/java/JavaInstall.h index 2d6e4d537..aa673dad6 100644 --- a/launcher/java/JavaInstall.h +++ b/launcher/java/JavaInstall.h @@ -1,3 +1,21 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2023 Trial97 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #pragma once #include "BaseVersion.h" From 440afcedb02bd878deb2053d2905170763df673d Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 14 Jul 2023 13:32:18 +0300 Subject: [PATCH 38/72] fixed warning Signed-off-by: Trial97 --- launcher/java/JavaInstall.cpp | 19 +++++++++++++++++++ launcher/java/JavaInstall.h | 2 ++ 2 files changed, 21 insertions(+) diff --git a/launcher/java/JavaInstall.cpp b/launcher/java/JavaInstall.cpp index 2931a0deb..cfa471402 100644 --- a/launcher/java/JavaInstall.cpp +++ b/launcher/java/JavaInstall.cpp @@ -18,6 +18,7 @@ #include "JavaInstall.h" +#include "BaseVersion.h" #include "StringUtils.h" bool JavaInstall::operator<(const JavaInstall& rhs) @@ -43,3 +44,21 @@ bool JavaInstall::operator>(const JavaInstall& rhs) { return (!operator<(rhs)) && (!operator==(rhs)); } + +bool JavaInstall::operator<(BaseVersion& a) +{ + try { + return operator<(dynamic_cast(a)); + } catch (const std::bad_cast& e) { + return BaseVersion::operator<(a); + } +} + +bool JavaInstall::operator>(BaseVersion& a) +{ + try { + return operator>(dynamic_cast(a)); + } catch (const std::bad_cast& e) { + return BaseVersion::operator>(a); + } +} diff --git a/launcher/java/JavaInstall.h b/launcher/java/JavaInstall.h index aa673dad6..30815b5a8 100644 --- a/launcher/java/JavaInstall.h +++ b/launcher/java/JavaInstall.h @@ -30,6 +30,8 @@ struct JavaInstall : public BaseVersion { virtual QString typeString() const { return arch; } + virtual bool operator<(BaseVersion& a) override; + virtual bool operator>(BaseVersion& a) override; bool operator<(const JavaInstall& rhs); bool operator==(const JavaInstall& rhs); bool operator>(const JavaInstall& rhs); From 515197fba2da1d674dbe7bd17dae4e0f22f64097 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Mon, 26 Jun 2023 11:57:21 +0300 Subject: [PATCH 39/72] fix: html sintax for modlist export Signed-off-by: Trial97 --- launcher/modplatform/helpers/ExportToModList.cpp | 16 ++++++++-------- launcher/ui/dialogs/ExportToModListDialog.cpp | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/launcher/modplatform/helpers/ExportToModList.cpp b/launcher/modplatform/helpers/ExportToModList.cpp index 5e01367f9..d837fb0ba 100644 --- a/launcher/modplatform/helpers/ExportToModList.cpp +++ b/launcher/modplatform/helpers/ExportToModList.cpp @@ -37,13 +37,13 @@ QString ExportToModList(QList mods, Formats format, OptionalData extraData if (ver.isEmpty() && meta != nullptr) ver = meta->version().toString(); if (!ver.isEmpty()) - line += QString("[%1]").arg(ver); + line += QString(" [%1]").arg(ver); } if (extraData & Authors && !mod->authors().isEmpty()) line += " by " + mod->authors().join(", "); - lines.append(QString("
      %1
    ").arg(line)); + lines.append(QString("
  • %1
  • ").arg(line)); } - return QString("
  • \n\t%1\n
  • ").arg(lines.join("\n\t")); + return QString("
      \n\t%1\n
    ").arg(lines.join("\n\t")); } case MARKDOWN: { QStringList lines; @@ -61,7 +61,7 @@ QString ExportToModList(QList mods, Formats format, OptionalData extraData if (ver.isEmpty() && meta != nullptr) ver = meta->version().toString(); if (!ver.isEmpty()) - line += QString("[%1]").arg(ver); + line += QString(" [%1]").arg(ver); } if (extraData & Authors && !mod->authors().isEmpty()) line += " by " + mod->authors().join(", "); @@ -75,21 +75,21 @@ QString ExportToModList(QList mods, Formats format, OptionalData extraData auto meta = mod->metadata(); auto modName = mod->name(); - auto line = "name: " + modName + ";"; + auto line = modName; if (extraData & Url) { auto url = mod->metaurl(); if (!url.isEmpty()) - line += " url: " + url + ";"; + line += QString(" (%1)").arg(url); } if (extraData & Version) { auto ver = mod->version(); if (ver.isEmpty() && meta != nullptr) ver = meta->version().toString(); if (!ver.isEmpty()) - line += " version: " + QString("[%1]").arg(ver) + ";"; + line += QString(" [%1]").arg(ver); } if (extraData & Authors && !mod->authors().isEmpty()) - line += " authors " + mod->authors().join(", ") + ";"; + line += " by " + mod->authors().join(", "); lines << line; } return lines.join("\n"); diff --git a/launcher/ui/dialogs/ExportToModListDialog.cpp b/launcher/ui/dialogs/ExportToModListDialog.cpp index 149f6b358..700e7178a 100644 --- a/launcher/ui/dialogs/ExportToModListDialog.cpp +++ b/launcher/ui/dialogs/ExportToModListDialog.cpp @@ -118,7 +118,7 @@ void ExportToModListDialog::triggerImp() QString exampleLine; switch (format) { case ExportToModList::HTML: { - exampleLine = "
      {name} [{version}] by {authors}
    "; + exampleLine = "
  • {name} [{version}] by {authors}
  • "; ui->resultText->setHtml(txt); break; } From 9a3931dac6e75a79989f13b10604a142dbafcfbb Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 27 Jun 2023 16:57:30 +0300 Subject: [PATCH 40/72] Added json and csv format Signed-off-by: Trial97 --- .../modplatform/helpers/ExportToModList.cpp | 56 +++++++++++++++++++ .../modplatform/helpers/ExportToModList.h | 2 +- launcher/ui/dialogs/ExportToModListDialog.cpp | 26 ++++++++- launcher/ui/dialogs/ExportToModListDialog.ui | 10 ++++ 4 files changed, 92 insertions(+), 2 deletions(-) diff --git a/launcher/modplatform/helpers/ExportToModList.cpp b/launcher/modplatform/helpers/ExportToModList.cpp index d837fb0ba..86bb9c419 100644 --- a/launcher/modplatform/helpers/ExportToModList.cpp +++ b/launcher/modplatform/helpers/ExportToModList.cpp @@ -16,6 +16,9 @@ * along with this program. If not, see . */ #include "ExportToModList.h" +#include +#include +#include namespace ExportToModList { QString ExportToModList(QList mods, Formats format, OptionalData extraData) @@ -94,6 +97,59 @@ QString ExportToModList(QList mods, Formats format, OptionalData extraData } return lines.join("\n"); } + case JSON: { + QJsonArray lines; + for (auto mod : mods) { + auto meta = mod->metadata(); + auto modName = mod->name(); + QJsonObject line; + line["name"] = modName; + if (extraData & Url) { + auto url = mod->metaurl(); + if (!url.isEmpty()) + line["url"] = url; + } + if (extraData & Version) { + auto ver = mod->version(); + if (ver.isEmpty() && meta != nullptr) + ver = meta->version().toString(); + if (!ver.isEmpty()) + line["version"] = ver; + } + if (extraData & Authors && !mod->authors().isEmpty()) + line["authors"] = QJsonArray::fromStringList(mod->authors()); + lines << line; + } + QJsonDocument doc; + doc.setArray(lines); + return doc.toJson(); + } + case CSV: { + QStringList lines; + for (auto mod : mods) { + QStringList data; + auto meta = mod->metadata(); + auto modName = mod->name(); + + data << modName; + if (extraData & Url) { + auto url = mod->metaurl(); + if (!url.isEmpty()) + data << url; + } + if (extraData & Version) { + auto ver = mod->version(); + if (ver.isEmpty() && meta != nullptr) + ver = meta->version().toString(); + if (!ver.isEmpty()) + data << ver; + } + if (extraData & Authors && !mod->authors().isEmpty()) + data << QString("\"%1\"").arg(mod->authors().join(",")); + lines << data.join(","); + } + return lines.join("\n"); + } default: { return QString("unknown format:%1").arg(format); } diff --git a/launcher/modplatform/helpers/ExportToModList.h b/launcher/modplatform/helpers/ExportToModList.h index 9ff8d25a1..abd6e9bc6 100644 --- a/launcher/modplatform/helpers/ExportToModList.h +++ b/launcher/modplatform/helpers/ExportToModList.h @@ -22,7 +22,7 @@ namespace ExportToModList { -enum Formats { HTML, MARKDOWN, PLAINTXT, CUSTOM }; +enum Formats { HTML, MARKDOWN, PLAINTXT, JSON, CSV, CUSTOM }; enum OptionalData { Authors = 1 << 0, Url = 1 << 1, diff --git a/launcher/ui/dialogs/ExportToModListDialog.cpp b/launcher/ui/dialogs/ExportToModListDialog.cpp index 700e7178a..cfd28cf85 100644 --- a/launcher/ui/dialogs/ExportToModListDialog.cpp +++ b/launcher/ui/dialogs/ExportToModListDialog.cpp @@ -89,6 +89,20 @@ void ExportToModListDialog::formatChanged(int index) break; } case 3: { + ui->templateGroup->setDisabled(true); + ui->optionsGroup->setDisabled(false); + ui->resultText->hide(); + format = ExportToModList::JSON; + break; + } + case 4: { + ui->templateGroup->setDisabled(true); + ui->optionsGroup->setDisabled(false); + ui->resultText->hide(); + format = ExportToModList::CSV; + break; + } + case 5: { ui->templateGroup->setDisabled(false); ui->optionsGroup->setDisabled(true); ui->resultText->hide(); @@ -133,6 +147,12 @@ void ExportToModListDialog::triggerImp() } case ExportToModList::CUSTOM: return; + case ExportToModList::JSON: + exampleLine = "{\"name\":\"{name}\",\"url\":\"{url}\",\"version\":\"{version}\",\"authors\":\"{authors}\"},"; + break; + case ExportToModList::CSV: + exampleLine = "{name},{url},{version},\"{authors}\""; + break; } if (!m_template_selected) { if (ui->templateText->toPlainText() != exampleLine) @@ -146,7 +166,7 @@ void ExportToModListDialog::done(int result) const QString filename = FS::RemoveInvalidFilenameChars(name); const QString output = QFileDialog::getSaveFileName(this, tr("Export %1").arg(name), FS::PathCombine(QDir::homePath(), filename + extension()), - "File (*.txt *.html *.md)", nullptr); + "File (*.txt *.html *.md *.json *.csv)", nullptr); if (output.isEmpty()) return; @@ -167,6 +187,10 @@ QString ExportToModListDialog::extension() return ".txt"; case ExportToModList::CUSTOM: return ".txt"; + case ExportToModList::JSON: + return ".json"; + case ExportToModList::CSV: + return ".csv"; } return ".txt"; } diff --git a/launcher/ui/dialogs/ExportToModListDialog.ui b/launcher/ui/dialogs/ExportToModListDialog.ui index 640b17665..e0f138f9e 100644 --- a/launcher/ui/dialogs/ExportToModListDialog.ui +++ b/launcher/ui/dialogs/ExportToModListDialog.ui @@ -58,6 +58,16 @@ Plaintext
    + + + JSON + + + + + CSV + + Custom From 50dae9d4f38d84f168922552e9f87bf2d1130d98 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 27 Jun 2023 18:09:29 +0300 Subject: [PATCH 41/72] Moved to separate functions Signed-off-by: Trial97 --- .../modplatform/helpers/ExportToModList.cpp | 274 ++++++++++-------- 1 file changed, 148 insertions(+), 126 deletions(-) diff --git a/launcher/modplatform/helpers/ExportToModList.cpp b/launcher/modplatform/helpers/ExportToModList.cpp index 86bb9c419..a8a015e34 100644 --- a/launcher/modplatform/helpers/ExportToModList.cpp +++ b/launcher/modplatform/helpers/ExportToModList.cpp @@ -21,135 +21,157 @@ #include namespace ExportToModList { +QString toHTML(QList mods, OptionalData extraData) +{ + QStringList lines; + for (auto mod : mods) { + auto meta = mod->metadata(); + auto modName = mod->name(); + if (extraData & Url) { + auto url = mod->metaurl(); + if (!url.isEmpty()) + modName = QString("%2").arg(url, modName); + } + auto line = modName; + if (extraData & Version) { + auto ver = mod->version(); + if (ver.isEmpty() && meta != nullptr) + ver = meta->version().toString(); + if (!ver.isEmpty()) + line += QString(" [%1]").arg(ver); + } + if (extraData & Authors && !mod->authors().isEmpty()) + line += " by " + mod->authors().join(", "); + lines.append(QString("
  • %1
  • ").arg(line)); + } + return QString("
      \n\t%1\n
    ").arg(lines.join("\n\t")); +} + +QString toMARKDOWN(QList mods, OptionalData extraData) +{ + QStringList lines; + for (auto mod : mods) { + auto meta = mod->metadata(); + auto modName = mod->name(); + if (extraData & Url) { + auto url = mod->metaurl(); + if (!url.isEmpty()) + modName = QString("[%1](%2)").arg(modName, url); + } + auto line = modName; + if (extraData & Version) { + auto ver = mod->version(); + if (ver.isEmpty() && meta != nullptr) + ver = meta->version().toString(); + if (!ver.isEmpty()) + line += QString(" [%1]").arg(ver); + } + if (extraData & Authors && !mod->authors().isEmpty()) + line += " by " + mod->authors().join(", "); + lines << "- " + line; + } + return lines.join("\n"); +} + +QString toPLAINTXT(QList mods, OptionalData extraData) +{ + QStringList lines; + for (auto mod : mods) { + auto meta = mod->metadata(); + auto modName = mod->name(); + + auto line = modName; + if (extraData & Url) { + auto url = mod->metaurl(); + if (!url.isEmpty()) + line += QString(" (%1)").arg(url); + } + if (extraData & Version) { + auto ver = mod->version(); + if (ver.isEmpty() && meta != nullptr) + ver = meta->version().toString(); + if (!ver.isEmpty()) + line += QString(" [%1]").arg(ver); + } + if (extraData & Authors && !mod->authors().isEmpty()) + line += " by " + mod->authors().join(", "); + lines << line; + } + return lines.join("\n"); +} + +QString toJSON(QList mods, OptionalData extraData) +{ + QJsonArray lines; + for (auto mod : mods) { + auto meta = mod->metadata(); + auto modName = mod->name(); + QJsonObject line; + line["name"] = modName; + if (extraData & Url) { + auto url = mod->metaurl(); + if (!url.isEmpty()) + line["url"] = url; + } + if (extraData & Version) { + auto ver = mod->version(); + if (ver.isEmpty() && meta != nullptr) + ver = meta->version().toString(); + if (!ver.isEmpty()) + line["version"] = ver; + } + if (extraData & Authors && !mod->authors().isEmpty()) + line["authors"] = QJsonArray::fromStringList(mod->authors()); + lines << line; + } + QJsonDocument doc; + doc.setArray(lines); + return doc.toJson(); +} + +QString toCSV(QList mods, OptionalData extraData) +{ + QStringList lines; + for (auto mod : mods) { + QStringList data; + auto meta = mod->metadata(); + auto modName = mod->name(); + + data << modName; + if (extraData & Url) + data << mod->metaurl(); + if (extraData & Version) { + auto ver = mod->version(); + if (ver.isEmpty() && meta != nullptr) + ver = meta->version().toString(); + data << ver; + } + if (extraData & Authors) { + QString authors; + if (mod->authors().length() == 1) + authors = mod->authors().back(); + else if (mod->authors().length() > 1) + authors = QString("\"%1\"").arg(mod->authors().join(",")); + data << authors; + } + lines << data.join(","); + } + return lines.join("\n"); +} + QString ExportToModList(QList mods, Formats format, OptionalData extraData) { switch (format) { - case HTML: { - QStringList lines; - for (auto mod : mods) { - auto meta = mod->metadata(); - auto modName = mod->name(); - if (extraData & Url) { - auto url = mod->metaurl(); - if (!url.isEmpty()) - modName = QString("%2").arg(url, modName); - } - auto line = modName; - if (extraData & Version) { - auto ver = mod->version(); - if (ver.isEmpty() && meta != nullptr) - ver = meta->version().toString(); - if (!ver.isEmpty()) - line += QString(" [%1]").arg(ver); - } - if (extraData & Authors && !mod->authors().isEmpty()) - line += " by " + mod->authors().join(", "); - lines.append(QString("
  • %1
  • ").arg(line)); - } - return QString("
      \n\t%1\n
    ").arg(lines.join("\n\t")); - } - case MARKDOWN: { - QStringList lines; - for (auto mod : mods) { - auto meta = mod->metadata(); - auto modName = mod->name(); - if (extraData & Url) { - auto url = mod->metaurl(); - if (!url.isEmpty()) - modName = QString("[%1](%2)").arg(modName, url); - } - auto line = modName; - if (extraData & Version) { - auto ver = mod->version(); - if (ver.isEmpty() && meta != nullptr) - ver = meta->version().toString(); - if (!ver.isEmpty()) - line += QString(" [%1]").arg(ver); - } - if (extraData & Authors && !mod->authors().isEmpty()) - line += " by " + mod->authors().join(", "); - lines << "- " + line; - } - return lines.join("\n"); - } - case PLAINTXT: { - QStringList lines; - for (auto mod : mods) { - auto meta = mod->metadata(); - auto modName = mod->name(); - - auto line = modName; - if (extraData & Url) { - auto url = mod->metaurl(); - if (!url.isEmpty()) - line += QString(" (%1)").arg(url); - } - if (extraData & Version) { - auto ver = mod->version(); - if (ver.isEmpty() && meta != nullptr) - ver = meta->version().toString(); - if (!ver.isEmpty()) - line += QString(" [%1]").arg(ver); - } - if (extraData & Authors && !mod->authors().isEmpty()) - line += " by " + mod->authors().join(", "); - lines << line; - } - return lines.join("\n"); - } - case JSON: { - QJsonArray lines; - for (auto mod : mods) { - auto meta = mod->metadata(); - auto modName = mod->name(); - QJsonObject line; - line["name"] = modName; - if (extraData & Url) { - auto url = mod->metaurl(); - if (!url.isEmpty()) - line["url"] = url; - } - if (extraData & Version) { - auto ver = mod->version(); - if (ver.isEmpty() && meta != nullptr) - ver = meta->version().toString(); - if (!ver.isEmpty()) - line["version"] = ver; - } - if (extraData & Authors && !mod->authors().isEmpty()) - line["authors"] = QJsonArray::fromStringList(mod->authors()); - lines << line; - } - QJsonDocument doc; - doc.setArray(lines); - return doc.toJson(); - } - case CSV: { - QStringList lines; - for (auto mod : mods) { - QStringList data; - auto meta = mod->metadata(); - auto modName = mod->name(); - - data << modName; - if (extraData & Url) { - auto url = mod->metaurl(); - if (!url.isEmpty()) - data << url; - } - if (extraData & Version) { - auto ver = mod->version(); - if (ver.isEmpty() && meta != nullptr) - ver = meta->version().toString(); - if (!ver.isEmpty()) - data << ver; - } - if (extraData & Authors && !mod->authors().isEmpty()) - data << QString("\"%1\"").arg(mod->authors().join(",")); - lines << data.join(","); - } - return lines.join("\n"); - } + case HTML: + return toHTML(mods, extraData); + case MARKDOWN: + return toMARKDOWN(mods, extraData); + case PLAINTXT: + return toPLAINTXT(mods, extraData); + case JSON: + return toJSON(mods, extraData); + case CSV: + return toCSV(mods, extraData); default: { return QString("unknown format:%1").arg(format); } From 9b02c31f8dab0f36f3d0c30115ab323dabe21541 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 4 Jul 2023 17:48:20 +0300 Subject: [PATCH 42/72] escaped text for html export Signed-off-by: Trial97 --- launcher/modplatform/helpers/ExportToModList.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/launcher/modplatform/helpers/ExportToModList.cpp b/launcher/modplatform/helpers/ExportToModList.cpp index a8a015e34..e7bafac47 100644 --- a/launcher/modplatform/helpers/ExportToModList.cpp +++ b/launcher/modplatform/helpers/ExportToModList.cpp @@ -26,9 +26,9 @@ QString toHTML(QList mods, OptionalData extraData) QStringList lines; for (auto mod : mods) { auto meta = mod->metadata(); - auto modName = mod->name(); + auto modName = mod->name().toHtmlEscaped(); if (extraData & Url) { - auto url = mod->metaurl(); + auto url = mod->metaurl().toHtmlEscaped(); if (!url.isEmpty()) modName = QString("%2").arg(url, modName); } @@ -38,10 +38,10 @@ QString toHTML(QList mods, OptionalData extraData) if (ver.isEmpty() && meta != nullptr) ver = meta->version().toString(); if (!ver.isEmpty()) - line += QString(" [%1]").arg(ver); + line += QString(" [%1]").arg(ver.toHtmlEscaped()); } if (extraData & Authors && !mod->authors().isEmpty()) - line += " by " + mod->authors().join(", "); + line += " by " + mod->authors().join(", ").toHtmlEscaped(); lines.append(QString("
  • %1
  • ").arg(line)); } return QString("
      \n\t%1\n
    ").arg(lines.join("\n\t")); From 1495bfb73ead50b45942e94a8e3b18e111820b4b Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 11 Jul 2023 22:43:27 +0300 Subject: [PATCH 43/72] Made custom template enabled all time Signed-off-by: Trial97 --- .../modplatform/helpers/ExportToModList.h | 2 +- launcher/ui/dialogs/ExportToModListDialog.cpp | 59 +++++++++---------- launcher/ui/dialogs/ExportToModListDialog.h | 3 +- launcher/ui/dialogs/ExportToModListDialog.ui | 14 ++++- 4 files changed, 43 insertions(+), 35 deletions(-) diff --git a/launcher/modplatform/helpers/ExportToModList.h b/launcher/modplatform/helpers/ExportToModList.h index abd6e9bc6..49252fc4f 100644 --- a/launcher/modplatform/helpers/ExportToModList.h +++ b/launcher/modplatform/helpers/ExportToModList.h @@ -16,7 +16,7 @@ * along with this program. If not, see . */ #pragma once -#include +#include #include #include "minecraft/mod/Mod.h" diff --git a/launcher/ui/dialogs/ExportToModListDialog.cpp b/launcher/ui/dialogs/ExportToModListDialog.cpp index cfd28cf85..b86b10561 100644 --- a/launcher/ui/dialogs/ExportToModListDialog.cpp +++ b/launcher/ui/dialogs/ExportToModListDialog.cpp @@ -33,11 +33,19 @@ #include #include +const QHash ExportToModListDialog::exampleLines = { + { ExportToModList::HTML, "
  • {name} [{version}] by {authors}
  • " }, + { ExportToModList::MARKDOWN, "[{name}]({url}) [{version}] by {authors}" }, + { ExportToModList::PLAINTXT, "{name} ({url}) [{version}] by {authors}" }, + { ExportToModList::JSON, "{\"name\":\"{name}\",\"url\":\"{url}\",\"version\":\"{version}\",\"authors\":\"{authors}\"}," }, + { ExportToModList::CSV, "{name},{url},{version},\"{authors}\"" }, +}; + ExportToModListDialog::ExportToModListDialog(InstancePtr instance, QWidget* parent) - : QDialog(parent), m_template_selected(false), name(instance->name()), ui(new Ui::ExportToModListDialog) + : QDialog(parent), m_template_changed(false), name(instance->name()), ui(new Ui::ExportToModListDialog) { ui->setupUi(this); - ui->templateGroup->setDisabled(true); + ui->optionsGroup->setDisabled(false); MinecraftInstance* mcInstance = dynamic_cast(instance.get()); if (mcInstance) { @@ -52,7 +60,12 @@ ExportToModListDialog::ExportToModListDialog(InstancePtr instance, QWidget* pare connect(ui->authorsCheckBox, &QCheckBox::stateChanged, this, &ExportToModListDialog::trigger); connect(ui->versionCheckBox, &QCheckBox::stateChanged, this, &ExportToModListDialog::trigger); connect(ui->urlCheckBox, &QCheckBox::stateChanged, this, &ExportToModListDialog::trigger); - connect(ui->templateText, &QTextEdit::textChanged, this, &ExportToModListDialog::triggerImp); + connect(ui->templateText, &QTextEdit::textChanged, this, [this] { + if (ui->templateText->toPlainText() != exampleLines[format]) + ui->formatComboBox->setCurrentIndex(5); + else + triggerImp(); + }); connect(ui->copyButton, &QPushButton::clicked, this, [this](bool) { this->ui->finalText->selectAll(); this->ui->finalText->copy(); @@ -68,42 +81,37 @@ void ExportToModListDialog::formatChanged(int index) { switch (index) { case 0: { - ui->templateGroup->setDisabled(true); ui->optionsGroup->setDisabled(false); ui->resultText->show(); format = ExportToModList::HTML; break; } case 1: { - ui->templateGroup->setDisabled(true); ui->optionsGroup->setDisabled(false); ui->resultText->show(); format = ExportToModList::MARKDOWN; break; } case 2: { - ui->templateGroup->setDisabled(true); ui->optionsGroup->setDisabled(false); ui->resultText->hide(); format = ExportToModList::PLAINTXT; break; } case 3: { - ui->templateGroup->setDisabled(true); ui->optionsGroup->setDisabled(false); ui->resultText->hide(); format = ExportToModList::JSON; break; } case 4: { - ui->templateGroup->setDisabled(true); ui->optionsGroup->setDisabled(false); ui->resultText->hide(); format = ExportToModList::CSV; break; } case 5: { - ui->templateGroup->setDisabled(false); + m_template_changed = true; ui->optionsGroup->setDisabled(true); ui->resultText->hide(); format = ExportToModList::CUSTOM; @@ -116,7 +124,6 @@ void ExportToModListDialog::formatChanged(int index) void ExportToModListDialog::triggerImp() { if (format == ExportToModList::CUSTOM) { - m_template_selected = true; ui->finalText->setPlainText(ExportToModList::ExportToModList(m_allMods, ui->templateText->toPlainText())); return; } @@ -129,35 +136,25 @@ void ExportToModListDialog::triggerImp() opt |= ExportToModList::Url; auto txt = ExportToModList::ExportToModList(m_allMods, format, static_cast(opt)); ui->finalText->setPlainText(txt); - QString exampleLine; switch (format) { - case ExportToModList::HTML: { - exampleLine = "
  • {name} [{version}] by {authors}
  • "; - ui->resultText->setHtml(txt); - break; - } - case ExportToModList::MARKDOWN: { - exampleLine = "[{name}]({url}) [{version}] by {authors}"; - ui->resultText->setHtml(markdownToHTML(txt)); - break; - } - case ExportToModList::PLAINTXT: { - exampleLine = "{name} ({url}) [{version}] by {authors}"; - break; - } case ExportToModList::CUSTOM: return; + case ExportToModList::HTML: + ui->resultText->setHtml(txt); + break; + case ExportToModList::MARKDOWN: + ui->resultText->setHtml(markdownToHTML(txt)); + break; + case ExportToModList::PLAINTXT: + break; case ExportToModList::JSON: - exampleLine = "{\"name\":\"{name}\",\"url\":\"{url}\",\"version\":\"{version}\",\"authors\":\"{authors}\"},"; break; case ExportToModList::CSV: - exampleLine = "{name},{url},{version},\"{authors}\""; break; } - if (!m_template_selected) { - if (ui->templateText->toPlainText() != exampleLine) - ui->templateText->setPlainText(exampleLine); - } + auto exampleLine = exampleLines[format]; + if (!m_template_changed && ui->templateText->toPlainText() != exampleLine) + ui->templateText->setPlainText(exampleLine); } void ExportToModListDialog::done(int result) diff --git a/launcher/ui/dialogs/ExportToModListDialog.h b/launcher/ui/dialogs/ExportToModListDialog.h index a7a6bcdce..b8a83d830 100644 --- a/launcher/ui/dialogs/ExportToModListDialog.h +++ b/launcher/ui/dialogs/ExportToModListDialog.h @@ -45,8 +45,9 @@ class ExportToModListDialog : public QDialog { private: QString extension(); QList m_allMods; - bool m_template_selected; + bool m_template_changed; QString name; ExportToModList::Formats format = ExportToModList::Formats::HTML; Ui::ExportToModListDialog* ui; + static const QHash exampleLines; }; diff --git a/launcher/ui/dialogs/ExportToModListDialog.ui b/launcher/ui/dialogs/ExportToModListDialog.ui index e0f138f9e..90f179a63 100644 --- a/launcher/ui/dialogs/ExportToModListDialog.ui +++ b/launcher/ui/dialogs/ExportToModListDialog.ui @@ -18,7 +18,7 @@
    - + @@ -149,6 +149,16 @@
    + + + + This depends on the mods meta data. To ensure the meta data run at least one time the mods update on the selected instance(no need to update the mods). + + + true + + +
    @@ -189,7 +199,7 @@ - + buttonBox rejected() ExportToModListDialog From b9ed8283b7e22fff5920dcd81ae347822d31353a Mon Sep 17 00:00:00 2001 From: Trial97 Date: Thu, 13 Jul 2023 20:38:08 +0300 Subject: [PATCH 44/72] Added buttons Signed-off-by: Trial97 --- launcher/ui/dialogs/ExportToModListDialog.cpp | 44 ++++++++++++--- launcher/ui/dialogs/ExportToModListDialog.h | 2 + launcher/ui/dialogs/ExportToModListDialog.ui | 53 +++++++++++++------ 3 files changed, 76 insertions(+), 23 deletions(-) diff --git a/launcher/ui/dialogs/ExportToModListDialog.cpp b/launcher/ui/dialogs/ExportToModListDialog.cpp index b86b10561..a0f8ee7b0 100644 --- a/launcher/ui/dialogs/ExportToModListDialog.cpp +++ b/launcher/ui/dialogs/ExportToModListDialog.cpp @@ -45,7 +45,7 @@ ExportToModListDialog::ExportToModListDialog(InstancePtr instance, QWidget* pare : QDialog(parent), m_template_changed(false), name(instance->name()), ui(new Ui::ExportToModListDialog) { ui->setupUi(this); - ui->optionsGroup->setDisabled(false); + enableCustom(false); MinecraftInstance* mcInstance = dynamic_cast(instance.get()); if (mcInstance) { @@ -60,6 +60,9 @@ ExportToModListDialog::ExportToModListDialog(InstancePtr instance, QWidget* pare connect(ui->authorsCheckBox, &QCheckBox::stateChanged, this, &ExportToModListDialog::trigger); connect(ui->versionCheckBox, &QCheckBox::stateChanged, this, &ExportToModListDialog::trigger); connect(ui->urlCheckBox, &QCheckBox::stateChanged, this, &ExportToModListDialog::trigger); + connect(ui->authorsButton, &QPushButton::clicked, this, [this](bool) { addExtra(ExportToModList::Authors); }); + connect(ui->versionButton, &QPushButton::clicked, this, [this](bool) { addExtra(ExportToModList::Version); }); + connect(ui->urlButton, &QPushButton::clicked, this, [this](bool) { addExtra(ExportToModList::Url); }); connect(ui->templateText, &QTextEdit::textChanged, this, [this] { if (ui->templateText->toPlainText() != exampleLines[format]) ui->formatComboBox->setCurrentIndex(5); @@ -81,38 +84,38 @@ void ExportToModListDialog::formatChanged(int index) { switch (index) { case 0: { - ui->optionsGroup->setDisabled(false); + enableCustom(false); ui->resultText->show(); format = ExportToModList::HTML; break; } case 1: { - ui->optionsGroup->setDisabled(false); + enableCustom(false); ui->resultText->show(); format = ExportToModList::MARKDOWN; break; } case 2: { - ui->optionsGroup->setDisabled(false); + enableCustom(false); ui->resultText->hide(); format = ExportToModList::PLAINTXT; break; } case 3: { - ui->optionsGroup->setDisabled(false); + enableCustom(false); ui->resultText->hide(); format = ExportToModList::JSON; break; } case 4: { - ui->optionsGroup->setDisabled(false); + enableCustom(false); ui->resultText->hide(); format = ExportToModList::CSV; break; } case 5: { m_template_changed = true; - ui->optionsGroup->setDisabled(true); + enableCustom(true); ui->resultText->hide(); format = ExportToModList::CUSTOM; break; @@ -191,3 +194,30 @@ QString ExportToModListDialog::extension() } return ".txt"; } + +void ExportToModListDialog::addExtra(ExportToModList::OptionalData option) +{ + if (format != ExportToModList::CUSTOM) + return; + switch (option) { + case ExportToModList::Authors: + ui->templateText->insertPlainText("{authors}"); + break; + case ExportToModList::Url: + ui->templateText->insertPlainText("{url}"); + break; + case ExportToModList::Version: + ui->templateText->insertPlainText("{version}"); + break; + } +} +void ExportToModListDialog::enableCustom(bool enabled) +{ + ui->authorsCheckBox->setHidden(enabled); + ui->versionCheckBox->setHidden(enabled); + ui->urlCheckBox->setHidden(enabled); + + ui->authorsButton->setHidden(!enabled); + ui->versionButton->setHidden(!enabled); + ui->urlButton->setHidden(!enabled); +} diff --git a/launcher/ui/dialogs/ExportToModListDialog.h b/launcher/ui/dialogs/ExportToModListDialog.h index b8a83d830..9886ae5a0 100644 --- a/launcher/ui/dialogs/ExportToModListDialog.h +++ b/launcher/ui/dialogs/ExportToModListDialog.h @@ -41,9 +41,11 @@ class ExportToModListDialog : public QDialog { void formatChanged(int index); void triggerImp(); void trigger(int) { triggerImp(); }; + void addExtra(ExportToModList::OptionalData option); private: QString extension(); + void enableCustom(bool enabled); QList m_allMods; bool m_template_changed; QString name; diff --git a/launcher/ui/dialogs/ExportToModListDialog.ui b/launcher/ui/dialogs/ExportToModListDialog.ui index 90f179a63..fc72f9a99 100644 --- a/launcher/ui/dialogs/ExportToModListDialog.ui +++ b/launcher/ui/dialogs/ExportToModListDialog.ui @@ -25,22 +25,6 @@ Settings - - - - QFrame::NoFrame - - - QFrame::Plain - - - 1 - - - Format - - - @@ -114,9 +98,46 @@ + + + + Version + + + + + + + Authors + + + + + + + URL + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + 1 + + + Format + + + From 1ccfba13ebe11a1d6ea2897db45b47c2452931f5 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 14 Jul 2023 23:39:54 +0300 Subject: [PATCH 45/72] renames Signed-off-by: Trial97 --- launcher/modplatform/helpers/ExportToModList.cpp | 12 ++++++------ launcher/modplatform/helpers/ExportToModList.h | 4 ++-- launcher/ui/dialogs/ExportToModListDialog.cpp | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/launcher/modplatform/helpers/ExportToModList.cpp b/launcher/modplatform/helpers/ExportToModList.cpp index e7bafac47..1f01c4a89 100644 --- a/launcher/modplatform/helpers/ExportToModList.cpp +++ b/launcher/modplatform/helpers/ExportToModList.cpp @@ -47,7 +47,7 @@ QString toHTML(QList mods, OptionalData extraData) return QString("
      \n\t%1\n
    ").arg(lines.join("\n\t")); } -QString toMARKDOWN(QList mods, OptionalData extraData) +QString toMarkdown(QList mods, OptionalData extraData) { QStringList lines; for (auto mod : mods) { @@ -73,7 +73,7 @@ QString toMARKDOWN(QList mods, OptionalData extraData) return lines.join("\n"); } -QString toPLAINTXT(QList mods, OptionalData extraData) +QString toPlainTXT(QList mods, OptionalData extraData) { QStringList lines; for (auto mod : mods) { @@ -159,15 +159,15 @@ QString toCSV(QList mods, OptionalData extraData) return lines.join("\n"); } -QString ExportToModList(QList mods, Formats format, OptionalData extraData) +QString exportToModList(QList mods, Formats format, OptionalData extraData) { switch (format) { case HTML: return toHTML(mods, extraData); case MARKDOWN: - return toMARKDOWN(mods, extraData); + return toMarkdown(mods, extraData); case PLAINTXT: - return toPLAINTXT(mods, extraData); + return toPlainTXT(mods, extraData); case JSON: return toJSON(mods, extraData); case CSV: @@ -178,7 +178,7 @@ QString ExportToModList(QList mods, Formats format, OptionalData extraData } } -QString ExportToModList(QList mods, QString lineTemplate) +QString exportToModList(QList mods, QString lineTemplate) { QStringList lines; for (auto mod : mods) { diff --git a/launcher/modplatform/helpers/ExportToModList.h b/launcher/modplatform/helpers/ExportToModList.h index 49252fc4f..7ea4ba9c2 100644 --- a/launcher/modplatform/helpers/ExportToModList.h +++ b/launcher/modplatform/helpers/ExportToModList.h @@ -28,6 +28,6 @@ enum OptionalData { Url = 1 << 1, Version = 1 << 2, }; -QString ExportToModList(QList mods, Formats format, OptionalData extraData); -QString ExportToModList(QList mods, QString lineTemplate); +QString exportToModList(QList mods, Formats format, OptionalData extraData); +QString exportToModList(QList mods, QString lineTemplate); } // namespace ExportToModList diff --git a/launcher/ui/dialogs/ExportToModListDialog.cpp b/launcher/ui/dialogs/ExportToModListDialog.cpp index a0f8ee7b0..c811bfe6a 100644 --- a/launcher/ui/dialogs/ExportToModListDialog.cpp +++ b/launcher/ui/dialogs/ExportToModListDialog.cpp @@ -127,7 +127,7 @@ void ExportToModListDialog::formatChanged(int index) void ExportToModListDialog::triggerImp() { if (format == ExportToModList::CUSTOM) { - ui->finalText->setPlainText(ExportToModList::ExportToModList(m_allMods, ui->templateText->toPlainText())); + ui->finalText->setPlainText(ExportToModList::exportToModList(m_allMods, ui->templateText->toPlainText())); return; } auto opt = 0; @@ -137,7 +137,7 @@ void ExportToModListDialog::triggerImp() opt |= ExportToModList::Version; if (ui->urlCheckBox->isChecked()) opt |= ExportToModList::Url; - auto txt = ExportToModList::ExportToModList(m_allMods, format, static_cast(opt)); + auto txt = ExportToModList::exportToModList(m_allMods, format, static_cast(opt)); ui->finalText->setPlainText(txt); switch (format) { case ExportToModList::CUSTOM: From da87e825a154bc87a6017270d80e4afc1b3c2e64 Mon Sep 17 00:00:00 2001 From: Alexandru Ionut Tripon Date: Sat, 15 Jul 2023 15:59:19 +0300 Subject: [PATCH 46/72] Update launcher/ui/dialogs/ExportToModListDialog.ui Co-authored-by: TheKodeToad Signed-off-by: Alexandru Ionut Tripon --- launcher/ui/dialogs/ExportToModListDialog.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/dialogs/ExportToModListDialog.ui b/launcher/ui/dialogs/ExportToModListDialog.ui index fc72f9a99..25eb43429 100644 --- a/launcher/ui/dialogs/ExportToModListDialog.ui +++ b/launcher/ui/dialogs/ExportToModListDialog.ui @@ -173,7 +173,7 @@ - This depends on the mods meta data. To ensure the meta data run at least one time the mods update on the selected instance(no need to update the mods). + This depends on the mods' metadata. To ensure it is available, run an update on the instance. Installing the updates isn't necessary. true From a2a09ffe01fe8eb6cd1f557b0feb98ed0271151e Mon Sep 17 00:00:00 2001 From: seth Date: Thu, 13 Jul 2023 20:57:38 -0400 Subject: [PATCH 47/72] chore: better explain quilt loader beacon Signed-off-by: seth --- launcher/minecraft/MinecraftInstance.cpp | 2 +- launcher/ui/pages/global/MinecraftPage.ui | 5 ++++- launcher/ui/pages/instance/InstanceSettingsPage.ui | 5 ++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index 180838ad2..0833d5912 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -3,7 +3,7 @@ * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 Sefa Eyeoglu * Copyright (C) 2022 Jamie Mansfield - * Copyright (C) 2022 TheKodeToad \ + * Copyright (C) 2022 TheKodeToad * Copyright (c) 2023 seth * * This program is free software: you can redistribute it and/or modify diff --git a/launcher/ui/pages/global/MinecraftPage.ui b/launcher/ui/pages/global/MinecraftPage.ui index 7a8f107b0..a3188dccb 100644 --- a/launcher/ui/pages/global/MinecraftPage.ui +++ b/launcher/ui/pages/global/MinecraftPage.ui @@ -199,7 +199,10 @@ - Disable Quilt's Beacon + Disable Quilt Loader Beacon + + + Disable Quilt loader's beacon for counting monthly active users diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.ui b/launcher/ui/pages/instance/InstanceSettingsPage.ui index 5c6f74d47..323890b90 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.ui +++ b/launcher/ui/pages/instance/InstanceSettingsPage.ui @@ -556,7 +556,10 @@ - Disable Quilt's Beacon + Disable Quilt Loader Beacon + + + Disable Quilt loader's beacon for counting monthly active users From c346d875a2d26435f680efb07f785c43af5ad95a Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sat, 15 Jul 2023 23:26:52 +0300 Subject: [PATCH 48/72] make FileResolvingTask accept empty modlist Signed-off-by: Trial97 --- .../modplatform/flame/FileResolvingTask.cpp | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/launcher/modplatform/flame/FileResolvingTask.cpp b/launcher/modplatform/flame/FileResolvingTask.cpp index ce7a60551..34bd401d3 100644 --- a/launcher/modplatform/flame/FileResolvingTask.cpp +++ b/launcher/modplatform/flame/FileResolvingTask.cpp @@ -21,6 +21,10 @@ bool Flame::FileResolvingTask::abort() void Flame::FileResolvingTask::executeTask() { + if (m_toProcess.files.isEmpty()) { // no file to resolve so leave it empty and emit success immediately + emitSucceeded(); + return; + } setStatus(tr("Resolving mod IDs...")); setProgress(0, 3); m_dljob.reset(new NetJob("Mod id resolver", m_network)); @@ -128,12 +132,13 @@ void Flame::FileResolvingTask::netJobFinished() m_checkJob->start(); } -void Flame::FileResolvingTask::modrinthCheckFinished() { +void Flame::FileResolvingTask::modrinthCheckFinished() +{ setProgress(2, 3); qDebug() << "Finished with blocked mods : " << blockedProjects.size(); for (auto it = blockedProjects.keyBegin(); it != blockedProjects.keyEnd(); it++) { - auto &out = *it; + auto& out = *it; auto bytes = blockedProjects[out]; if (!out->resolved) { continue; @@ -153,15 +158,13 @@ void Flame::FileResolvingTask::modrinthCheckFinished() { out->resolved = false; } } - //copy to an output list and filter out projects found on modrinth + // copy to an output list and filter out projects found on modrinth auto block = std::make_shared>(); auto it = blockedProjects.keys(); - std::copy_if(it.begin(), it.end(), std::back_inserter(*block), [](File *f) { - return !f->resolved; - }); - //Display not found mods early + std::copy_if(it.begin(), it.end(), std::back_inserter(*block), [](File* f) { return !f->resolved; }); + // Display not found mods early if (!block->empty()) { - //blocked mods found, we need the slug for displaying.... we need another job :D ! + // blocked mods found, we need the slug for displaying.... we need another job :D ! m_slugJob.reset(new NetJob("Slug Job", m_network)); int index = 0; for (auto mod : *block) { @@ -173,8 +176,8 @@ void Flame::FileResolvingTask::modrinthCheckFinished() { QObject::connect(dl.get(), &Net::Download::succeeded, [block, index, output]() { auto mod = block->at(index); // use the shared_ptr so it is captured and only freed when we are done auto json = QJsonDocument::fromJson(*output); - auto base = Json::requireString(Json::requireObject(Json::requireObject(Json::requireObject(json),"data"),"links"), - "websiteUrl"); + auto base = + Json::requireString(Json::requireObject(Json::requireObject(Json::requireObject(json), "data"), "links"), "websiteUrl"); auto link = QString("%1/download/%2").arg(base, QString::number(mod->fileId)); mod->websiteUrl = link; }); From 06fc8358d9836a203cd31580fa57f055c9bcef05 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sat, 15 Jul 2023 23:57:32 +0300 Subject: [PATCH 49/72] auto focus search line on resource download Signed-off-by: Trial97 --- launcher/ui/pages/modplatform/ResourcePage.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/launcher/ui/pages/modplatform/ResourcePage.cpp b/launcher/ui/pages/modplatform/ResourcePage.cpp index aab2ee89a..48afbd900 100644 --- a/launcher/ui/pages/modplatform/ResourcePage.cpp +++ b/launcher/ui/pages/modplatform/ResourcePage.cpp @@ -104,6 +104,7 @@ void ResourcePage::openedImpl() updateSelectionButton(); triggerSearch(); + m_ui->searchEdit->setFocus(); } auto ResourcePage::eventFilter(QObject* watched, QEvent* event) -> bool From 6597a5c8604c580994958c2fff87ccbe90988df4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 16 Jul 2023 00:23:55 +0000 Subject: [PATCH 50/72] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'flake-parts': 'github:hercules-ci/flake-parts/267149c58a14d15f7f81b4d737308421de9d7152' (2023-07-01) → 'github:hercules-ci/flake-parts/8e8d955c22df93dbe24f19ea04f47a74adbdc5ec' (2023-07-04) • Updated input 'nixpkgs': 'github:nixos/nixpkgs/cd99c2b3c9f160cd004318e0697f90bbd5960825' (2023-07-01) → 'github:nixos/nixpkgs/46ed466081b9cad1125b11f11a2af5cc40b942c7' (2023-07-15) • Updated input 'pre-commit-hooks': 'github:cachix/pre-commit-hooks.nix/42587d3414d1747999a5f71e92a83cf6547b62da' (2023-07-03) → 'github:cachix/pre-commit-hooks.nix/5e28316db471d1ac234beb70031b635437421dd6' (2023-07-14) --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index 91a67f087..370250c4b 100644 --- a/flake.lock +++ b/flake.lock @@ -21,11 +21,11 @@ "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1688254665, - "narHash": "sha256-8FHEgBrr7gYNiS/NzCxIO3m4hvtLRW9YY1nYo1ivm3o=", + "lastModified": 1688466019, + "narHash": "sha256-VeM2akYrBYMsb4W/MmBo1zmaMfgbL4cH3Pu8PGyIwJ0=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "267149c58a14d15f7f81b4d737308421de9d7152", + "rev": "8e8d955c22df93dbe24f19ea04f47a74adbdc5ec", "type": "github" }, "original": { @@ -91,11 +91,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1688221086, - "narHash": "sha256-cdW6qUL71cNWhHCpMPOJjlw0wzSRP0pVlRn2vqX/VVg=", + "lastModified": 1689413807, + "narHash": "sha256-exuzOvOhGAEKWQKwDuZAL4N8a1I837hH5eocaTcIbLc=", "owner": "nixos", "repo": "nixpkgs", - "rev": "cd99c2b3c9f160cd004318e0697f90bbd5960825", + "rev": "46ed466081b9cad1125b11f11a2af5cc40b942c7", "type": "github" }, "original": { @@ -138,11 +138,11 @@ ] }, "locked": { - "lastModified": 1688386108, - "narHash": "sha256-Vffto9QaVonzYAcPlAzd0soqWYpPpKk60dfNLSIXcFA=", + "lastModified": 1689328505, + "narHash": "sha256-9B3+OeUn1a/CvzE3GW6nWNwS5J7PDHTyHGlpL3wV5oA=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "42587d3414d1747999a5f71e92a83cf6547b62da", + "rev": "5e28316db471d1ac234beb70031b635437421dd6", "type": "github" }, "original": { From 18ebc858fdebbd08703d9e5ddeaf23abcfceaa94 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Sun, 16 Jul 2023 11:47:47 +0200 Subject: [PATCH 51/72] feat(actions): add backport action Signed-off-by: Sefa Eyeoglu --- .github/workflows/backport.yml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .github/workflows/backport.yml diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml new file mode 100644 index 000000000..77c1a8802 --- /dev/null +++ b/.github/workflows/backport.yml @@ -0,0 +1,32 @@ +name: Backport +on: + pull_request_target: + types: [closed, labeled] + +# WARNING: +# When extending this action, be aware that $GITHUB_TOKEN allows write access to +# the GitHub repository. This means that it should not evaluate user input in a +# way that allows code injection. + +permissions: + contents: read + +jobs: + backport: + permissions: + contents: write # for korthout/backport-action to create branch + pull-requests: write # for korthout/backport-action to create PR to backport + name: Backport Pull Request + if: github.repository_owner == 'PrismLauncher' && github.event.pull_request.merged == true && (github.event_name != 'labeled' || startsWith('backport', github.event.label.name)) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + - name: Create backport PRs + uses: korthout/backport-action@v1.3.1 + with: + # Config README: https://github.com/korthout/backport-action#backport-action + pull_description: |- + Bot-based backport to `${target_branch}`, triggered by a label in #${pull_number}. + From 1e9a596908ba85dea974e6d041b53c675f8d7b78 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 16 Jul 2023 14:18:17 +0300 Subject: [PATCH 52/72] simplified code in cat packs Signed-off-by: Trial97 --- launcher/ui/themes/CatPack.cpp | 45 ++++++++++------------------- launcher/ui/themes/ThemeManager.cpp | 15 ++++++---- 2 files changed, 26 insertions(+), 34 deletions(-) diff --git a/launcher/ui/themes/CatPack.cpp b/launcher/ui/themes/CatPack.cpp index 435ccdb88..e1f2caf3c 100644 --- a/launcher/ui/themes/CatPack.cpp +++ b/launcher/ui/themes/CatPack.cpp @@ -61,36 +61,23 @@ QString BasicCatPack::path() JsonCatPack::JsonCatPack(QFileInfo& manifestInfo) : BasicCatPack(manifestInfo.dir().dirName()) { - QString path = FS::PathCombine("catpacks", m_id); - - if (!FS::ensureFolderPathExists(path)) { - themeWarningLog() << "couldn't create folder for catpack!"; - return; - } - - if (manifestInfo.exists() && manifestInfo.isFile()) { - try { - auto doc = Json::requireDocument(manifestInfo.absoluteFilePath(), "CatPack JSON file"); - const auto root = doc.object(); - m_name = Json::requireString(root, "name", "Catpack name"); - auto id = Json::ensureString(root, "id", "", "Catpack ID"); - if (!id.isEmpty()) - m_id = id; - m_defaultPath = FS::PathCombine(path, Json::requireString(root, "default", "Deafult Cat")); - auto variants = Json::ensureArray(root, "variants", QJsonArray(), "Catpack Variants"); - for (auto v : variants) { - auto variant = Json::ensureObject(v, QJsonObject(), "Cat variant"); - m_variants << Variant{ FS::PathCombine(path, Json::requireString(variant, "path", "Variant path")), - PartialDate(Json::requireString(variant, "startTime", "Variant startTime")), - PartialDate(Json::requireString(variant, "endTime", "Variant endTime")) }; - } - - } catch (const Exception& e) { - themeWarningLog() << "Couldn't load catpack json: " << e.cause(); - return; + QString path = manifestInfo.path(); + try { + auto doc = Json::requireDocument(manifestInfo.absoluteFilePath(), "CatPack JSON file"); + const auto root = doc.object(); + m_name = Json::requireString(root, "name", "Catpack name"); + m_defaultPath = FS::PathCombine(path, Json::requireString(root, "default", "Default Cat")); + auto variants = Json::ensureArray(root, "variants", QJsonArray(), "Catpack Variants"); + for (auto v : variants) { + auto variant = Json::ensureObject(v, QJsonObject(), "Cat variant"); + m_variants << Variant{ FS::PathCombine(path, Json::requireString(variant, "path", "Variant path")), + PartialDate(Json::requireString(variant, "startTime", "Variant startTime")), + PartialDate(Json::requireString(variant, "endTime", "Variant endTime")) }; } - } else { - themeDebugLog() << "No catpack json present."; + + } catch (const Exception& e) { + themeWarningLog() << "Couldn't load catpack json:" << e.cause(); + return; } } diff --git a/launcher/ui/themes/ThemeManager.cpp b/launcher/ui/themes/ThemeManager.cpp index d00b3a992..ba09f6276 100644 --- a/launcher/ui/themes/ThemeManager.cpp +++ b/launcher/ui/themes/ThemeManager.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "ui/themes/BrightTheme.h" #include "ui/themes/CatPack.h" #include "ui/themes/CustomTheme.h" @@ -179,13 +180,17 @@ void ThemeManager::initializeCatPacks() for (auto [id, name] : defaultCats) { addCatPack(std::unique_ptr(new BasicCatPack(id, name))); } - QDir catpacksDir("./catpacks/"); + QDir catpacksDir("catpacks"); QString catpacksFolder = catpacksDir.absoluteFilePath(""); - themeDebugLog() << "CatPacks Folder Path: " << catpacksFolder; + themeDebugLog() << "CatPacks Folder Path:" << catpacksFolder; - auto loadFiles = [this](QDir dir) { + QStringList supportedImageFormats; + for (auto format : QImageReader::supportedImageFormats()) { + supportedImageFormats.append("*." + format); + } + auto loadFiles = [this, supportedImageFormats](QDir dir) { // Load image files directly - QDirIterator ImageFileIterator(dir.absoluteFilePath(""), { "*.png", "*.gif", "*.jpg", "*.apng", "*.jxl", "*.avif" }, QDir::Files); + QDirIterator ImageFileIterator(dir.absoluteFilePath(""), supportedImageFormats, QDir::Files); while (ImageFileIterator.hasNext()) { QFile customCatFile(ImageFileIterator.next()); QFileInfo customCatFileInfo(customCatFile); @@ -200,7 +205,7 @@ void ThemeManager::initializeCatPacks() while (directoryIterator.hasNext()) { QDir dir(directoryIterator.next()); QFileInfo manifest(dir.absoluteFilePath("catpack.json")); - if (manifest.exists()) { + if (manifest.isFile()) { // Load background manifest themeDebugLog() << "Loading background manifest from:" << manifest.absoluteFilePath(); addCatPack(std::unique_ptr(new JsonCatPack(manifest))); From de30a72c4e1f051eef2a0bd389fc51e6a64d54c3 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 16 Jul 2023 15:16:16 +0300 Subject: [PATCH 53/72] made the date a object Signed-off-by: Trial97 --- launcher/ui/themes/CatPack.cpp | 58 ++++++++++++++++++----------- launcher/ui/themes/CatPack.h | 7 ---- launcher/ui/themes/ThemeManager.cpp | 21 ++++++++--- 3 files changed, 53 insertions(+), 33 deletions(-) diff --git a/launcher/ui/themes/CatPack.cpp b/launcher/ui/themes/CatPack.cpp index e1f2caf3c..ebb100a40 100644 --- a/launcher/ui/themes/CatPack.cpp +++ b/launcher/ui/themes/CatPack.cpp @@ -39,7 +39,6 @@ #include #include "FileSystem.h" #include "Json.h" -#include "ui/themes/ThemeManager.h" QString BasicCatPack::path() { @@ -59,39 +58,56 @@ QString BasicCatPack::path() return cat; } +JsonCatPack::PartialDate partialDate(QJsonObject date) +{ + auto month = Json::ensureInteger(date, "month", 1); + if (month > 12) + month = 12; + else if (month <= 0) + month = 1; + auto day = Json::ensureInteger(date, "day", 1); + if (day > 31) + day = 31; + else if (day <= 0) + day = 1; + return { month, day }; +}; + JsonCatPack::JsonCatPack(QFileInfo& manifestInfo) : BasicCatPack(manifestInfo.dir().dirName()) { QString path = manifestInfo.path(); - try { - auto doc = Json::requireDocument(manifestInfo.absoluteFilePath(), "CatPack JSON file"); - const auto root = doc.object(); - m_name = Json::requireString(root, "name", "Catpack name"); - m_defaultPath = FS::PathCombine(path, Json::requireString(root, "default", "Default Cat")); - auto variants = Json::ensureArray(root, "variants", QJsonArray(), "Catpack Variants"); - for (auto v : variants) { - auto variant = Json::ensureObject(v, QJsonObject(), "Cat variant"); - m_variants << Variant{ FS::PathCombine(path, Json::requireString(variant, "path", "Variant path")), - PartialDate(Json::requireString(variant, "startTime", "Variant startTime")), - PartialDate(Json::requireString(variant, "endTime", "Variant endTime")) }; - } - - } catch (const Exception& e) { - themeWarningLog() << "Couldn't load catpack json:" << e.cause(); - return; + auto doc = Json::requireDocument(manifestInfo.absoluteFilePath(), "CatPack JSON file"); + const auto root = doc.object(); + m_name = Json::requireString(root, "name", "Catpack name"); + m_defaultPath = FS::PathCombine(path, Json::requireString(root, "default", "Default Cat")); + auto variants = Json::ensureArray(root, "variants", QJsonArray(), "Catpack Variants"); + for (auto v : variants) { + auto variant = Json::ensureObject(v, QJsonObject(), "Cat variant"); + m_variants << Variant{ FS::PathCombine(path, Json::requireString(variant, "path", "Variant path")), + partialDate(Json::requireObject(variant, "startTime", "Variant startTime")), + partialDate(Json::requireObject(variant, "endTime", "Variant endTime")) }; } } +QDate ensureDay(int year, int month, int day) +{ + QDate date(year, month, 1); + if (day > date.daysInMonth()) + day = date.daysInMonth(); + return QDate(year, month, day); +} + QString JsonCatPack::path() { const QDate now = QDate::currentDate(); for (auto var : m_variants) { - QDate startDate(now.year(), var.startTime.month, var.startTime.day); - QDate endDate(now.year(), var.endTime.month, var.endTime.day); + QDate startDate = ensureDay(now.year(), var.startTime.month, var.startTime.day); + QDate endDate = ensureDay(now.year(), var.endTime.month, var.endTime.day); if (startDate > endDate) { // it's spans over multiple years if (endDate <= now) // end date is in the past so jump one year into the future for endDate - endDate = endDate.addYears(1); + endDate = ensureDay(now.year() + 1, var.endTime.month, var.endTime.day); else // end date is in the future so jump one year into the past for startDate - startDate = startDate.addYears(-1); + startDate = ensureDay(now.year() - 1, var.startTime.month, var.startTime.day); } if (startDate >= now && now >= endDate) diff --git a/launcher/ui/themes/CatPack.h b/launcher/ui/themes/CatPack.h index 20cb8f61e..b03a19f03 100644 --- a/launcher/ui/themes/CatPack.h +++ b/launcher/ui/themes/CatPack.h @@ -74,13 +74,6 @@ class FileCatPack : public BasicCatPack { class JsonCatPack : public BasicCatPack { public: struct PartialDate { - PartialDate(QString d) - { - auto sp = d.split("-"); - day = sp[0].toInt(); - if (sp.length() >= 2) - month = sp[1].toInt(); - } int month; int day; }; diff --git a/launcher/ui/themes/ThemeManager.cpp b/launcher/ui/themes/ThemeManager.cpp index ba09f6276..683642d79 100644 --- a/launcher/ui/themes/ThemeManager.cpp +++ b/launcher/ui/themes/ThemeManager.cpp @@ -22,6 +22,7 @@ #include #include #include +#include "Exception.h" #include "ui/themes/BrightTheme.h" #include "ui/themes/CatPack.h" #include "ui/themes/CustomTheme.h" @@ -43,7 +44,10 @@ ThemeManager::ThemeManager(MainWindow* mainWindow) QString ThemeManager::addTheme(std::unique_ptr theme) { QString id = theme->id(); - m_themes.emplace(id, std::move(theme)); + if (m_themes.find(id) == m_themes.end()) + m_themes.emplace(id, std::move(theme)); + else + themeWarningLog() << "Theme(" << id << ") not added to prevent id duplication"; return id; } @@ -167,7 +171,10 @@ QString ThemeManager::getCatPack(QString catName) QString ThemeManager::addCatPack(std::unique_ptr catPack) { QString id = catPack->id(); - m_catPacks.emplace(id, std::move(catPack)); + if (m_catPacks.find(id) == m_catPacks.end()) + m_catPacks.emplace(id, std::move(catPack)); + else + themeWarningLog() << "CatPack(" << id << ") not added to prevent id duplication"; return id; } @@ -206,9 +213,13 @@ void ThemeManager::initializeCatPacks() QDir dir(directoryIterator.next()); QFileInfo manifest(dir.absoluteFilePath("catpack.json")); if (manifest.isFile()) { - // Load background manifest - themeDebugLog() << "Loading background manifest from:" << manifest.absoluteFilePath(); - addCatPack(std::unique_ptr(new JsonCatPack(manifest))); + try { + // Load background manifest + themeDebugLog() << "Loading background manifest from:" << manifest.absoluteFilePath(); + addCatPack(std::unique_ptr(new JsonCatPack(manifest))); + } catch (const Exception& e) { + themeWarningLog() << "Couldn't load catpack json:" << e.cause(); + } } else { loadFiles(dir); } From 251055302eec0232a89f0466efe3e7e7f3fa7de3 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 16 Jul 2023 20:53:58 +0300 Subject: [PATCH 54/72] format Signed-off-by: Trial97 --- launcher/MMCZip.cpp | 148 +++++++--------- launcher/MMCZip.h | 174 +++++++++---------- launcher/ui/dialogs/ExportInstanceDialog.cpp | 70 +++----- launcher/ui/dialogs/ExportInstanceDialog.h | 22 ++- 4 files changed, 184 insertions(+), 230 deletions(-) diff --git a/launcher/MMCZip.cpp b/launcher/MMCZip.cpp index 1a336375b..4e932a768 100644 --- a/launcher/MMCZip.cpp +++ b/launcher/MMCZip.cpp @@ -33,56 +33,48 @@ * limitations under the License. */ +#include "MMCZip.h" #include #include #include -#include "MMCZip.h" #include "FileSystem.h" #include #include // ours -bool MMCZip::mergeZipFiles(QuaZip *into, QFileInfo from, QSet &contained, const FilterFunction filter) +bool MMCZip::mergeZipFiles(QuaZip* into, QFileInfo from, QSet& contained, const FilterFunction filter) { QuaZip modZip(from.filePath()); modZip.open(QuaZip::mdUnzip); QuaZipFile fileInsideMod(&modZip); QuaZipFile zipOutFile(into); - for (bool more = modZip.goToFirstFile(); more; more = modZip.goToNextFile()) - { + for (bool more = modZip.goToFirstFile(); more; more = modZip.goToNextFile()) { QString filename = modZip.getCurrentFileName(); - if (filter && !filter(filename)) - { - qDebug() << "Skipping file " << filename << " from " - << from.fileName() << " - filtered"; + if (filter && !filter(filename)) { + qDebug() << "Skipping file " << filename << " from " << from.fileName() << " - filtered"; continue; } - if (contained.contains(filename)) - { - qDebug() << "Skipping already contained file " << filename << " from " - << from.fileName(); + if (contained.contains(filename)) { + qDebug() << "Skipping already contained file " << filename << " from " << from.fileName(); continue; } contained.insert(filename); - if (!fileInsideMod.open(QIODevice::ReadOnly)) - { + if (!fileInsideMod.open(QIODevice::ReadOnly)) { qCritical() << "Failed to open " << filename << " from " << from.fileName(); return false; } QuaZipNewInfo info_out(fileInsideMod.getActualFileName()); - if (!zipOutFile.open(QIODevice::WriteOnly, info_out)) - { + if (!zipOutFile.open(QIODevice::WriteOnly, info_out)) { qCritical() << "Failed to open " << filename << " in the jar"; fileInsideMod.close(); return false; } - if (!JlCompress::copyData(fileInsideMod, zipOutFile)) - { + if (!JlCompress::copyData(fileInsideMod, zipOutFile)) { zipOutFile.close(); fileInsideMod.close(); qCritical() << "Failed to copy data of " << filename << " into the jar"; @@ -94,10 +86,11 @@ bool MMCZip::mergeZipFiles(QuaZip *into, QFileInfo from, QSet &containe return true; } -bool MMCZip::compressDirFiles(QuaZip *zip, QString dir, QFileInfoList files, bool followSymlinks) +bool MMCZip::compressDirFiles(QuaZip* zip, QString dir, QFileInfoList files, bool followSymlinks) { QDir directory(dir); - if (!directory.exists()) return false; + if (!directory.exists()) + return false; for (auto e : files) { auto filePath = directory.relativeFilePath(e.absoluteFilePath()); @@ -109,7 +102,8 @@ bool MMCZip::compressDirFiles(QuaZip *zip, QString dir, QFileInfoList files, boo srcPath = e.canonicalFilePath(); } } - if( !JlCompress::compressFile(zip, srcPath, filePath)) return false; + if (!JlCompress::compressFile(zip, srcPath, filePath)) + return false; } return true; @@ -119,7 +113,7 @@ bool MMCZip::compressDirFiles(QString fileCompressed, QString dir, QFileInfoList { QuaZip zip(fileCompressed); QDir().mkpath(QFileInfo(fileCompressed).absolutePath()); - if(!zip.open(QuaZip::mdCreate)) { + if (!zip.open(QuaZip::mdCreate)) { QFile::remove(fileCompressed); return false; } @@ -127,7 +121,7 @@ bool MMCZip::compressDirFiles(QString fileCompressed, QString dir, QFileInfoList auto result = compressDirFiles(&zip, dir, files, followSymlinks); zip.close(); - if(zip.getZipError()!=0) { + if (zip.getZipError() != 0) { QFile::remove(fileCompressed); return false; } @@ -139,8 +133,7 @@ bool MMCZip::compressDirFiles(QString fileCompressed, QString dir, QFileInfoList bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const QList& mods) { QuaZip zipOut(targetJarPath); - if (!zipOut.open(QuaZip::mdCreate)) - { + if (!zipOut.open(QuaZip::mdCreate)) { QFile::remove(targetJarPath); qCritical() << "Failed to open the minecraft.jar for modding"; return false; @@ -151,37 +144,29 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const // Modify the jar // This needs to be done in reverse-order to ensure we respect the loading order of components - for (auto i = mods.crbegin(); i != mods.crend(); i++) - { + for (auto i = mods.crbegin(); i != mods.crend(); i++) { const auto* mod = *i; // do not merge disabled mods. if (!mod->enabled()) continue; - if (mod->type() == ResourceType::ZIPFILE) - { - if (!mergeZipFiles(&zipOut, mod->fileinfo(), addedFiles)) - { + if (mod->type() == ResourceType::ZIPFILE) { + if (!mergeZipFiles(&zipOut, mod->fileinfo(), addedFiles)) { zipOut.close(); QFile::remove(targetJarPath); qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar."; return false; } - } - else if (mod->type() == ResourceType::SINGLEFILE) - { + } else if (mod->type() == ResourceType::SINGLEFILE) { // FIXME: buggy - does not work with addedFiles auto filename = mod->fileinfo(); - if (!JlCompress::compressFile(&zipOut, filename.absoluteFilePath(), filename.fileName())) - { + if (!JlCompress::compressFile(&zipOut, filename.absoluteFilePath(), filename.fileName())) { zipOut.close(); QFile::remove(targetJarPath); qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar."; return false; } addedFiles.insert(filename.fileName()); - } - else if (mod->type() == ResourceType::FOLDER) - { + } else if (mod->type() == ResourceType::FOLDER) { // untested, but seems to be unused / not possible to reach // FIXME: buggy - does not work with addedFiles auto filename = mod->fileinfo(); @@ -197,18 +182,14 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const files.removeAll(e); } - if (!MMCZip::compressDirFiles(&zipOut, parent_dir, files)) - { + if (!MMCZip::compressDirFiles(&zipOut, parent_dir, files)) { zipOut.close(); QFile::remove(targetJarPath); qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar."; return false; } - qDebug() << "Adding folder " << filename.fileName() << " from " - << filename.absoluteFilePath(); - } - else - { + qDebug() << "Adding folder " << filename.fileName() << " from " << filename.absoluteFilePath(); + } else { // Make sure we do not continue launching when something is missing or undefined... zipOut.close(); QFile::remove(targetJarPath); @@ -217,8 +198,7 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const } } - if (!mergeZipFiles(&zipOut, QFileInfo(sourceJarPath), addedFiles, [](const QString key){return !key.contains("META-INF");})) - { + if (!mergeZipFiles(&zipOut, QFileInfo(sourceJarPath), addedFiles, [](const QString key) { return !key.contains("META-INF"); })) { zipOut.close(); QFile::remove(targetJarPath); qCritical() << "Failed to insert minecraft.jar contents."; @@ -227,8 +207,7 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const // Recompress the jar zipOut.close(); - if (zipOut.getZipError() != 0) - { + if (zipOut.getZipError() != 0) { QFile::remove(targetJarPath); qCritical() << "Failed to finalize minecraft.jar!"; return false; @@ -261,27 +240,23 @@ QString MMCZip::findFolderOfFileInZip(QuaZip* zip, const QString& what, const QS } // ours -bool MMCZip::findFilesInZip(QuaZip * zip, const QString & what, QStringList & result, const QString &root) +bool MMCZip::findFilesInZip(QuaZip* zip, const QString& what, QStringList& result, const QString& root) { QuaZipDir rootDir(zip, root); - for(auto fileName: rootDir.entryList(QDir::Files)) - { - if(fileName == what) - { + for (auto fileName : rootDir.entryList(QDir::Files)) { + if (fileName == what) { result.append(root); return true; } } - for(auto fileName: rootDir.entryList(QDir::Dirs)) - { + for (auto fileName : rootDir.entryList(QDir::Dirs)) { findFilesInZip(zip, what, result, root + fileName); } return !result.isEmpty(); } - // ours -std::optional MMCZip::extractSubDir(QuaZip *zip, const QString & subdir, const QString &target) +std::optional MMCZip::extractSubDir(QuaZip* zip, const QString& subdir, const QString& target) { auto target_top_dir = QUrl::fromLocalFile(target); @@ -289,16 +264,13 @@ std::optional MMCZip::extractSubDir(QuaZip *zip, const QString & su qDebug() << "Extracting subdir" << subdir << "from" << zip->getZipName() << "to" << target; auto numEntries = zip->getEntriesCount(); - if(numEntries < 0) { + if (numEntries < 0) { qWarning() << "Failed to enumerate files in archive"; return std::nullopt; - } - else if(numEntries == 0) { + } else if (numEntries == 0) { qDebug() << "Extracting empty archives seems odd..."; return extracted; - } - else if (!zip->goToFirstFile()) - { + } else if (!zip->goToFirstFile()) { qWarning() << "Failed to seek to first file in zip"; return std::nullopt; } @@ -334,7 +306,8 @@ std::optional MMCZip::extractSubDir(QuaZip *zip, const QString & su } if (!target_top_dir.isParentOf(QUrl::fromLocalFile(target_file_path))) { - qWarning() << "Extracting" << relative_file_name << "was cancelled, because it was effectively outside of the target path" << target; + qWarning() << "Extracting" << relative_file_name << "was cancelled, because it was effectively outside of the target path" + << target; return std::nullopt; } @@ -345,7 +318,8 @@ std::optional MMCZip::extractSubDir(QuaZip *zip, const QString & su } extracted.append(target_file_path); - QFile::setPermissions(target_file_path, QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser | QFileDevice::Permission::ExeUser); + QFile::setPermissions(target_file_path, + QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser | QFileDevice::Permission::ExeUser); qDebug() << "Extracted file" << relative_file_name << "to" << target_file_path; } while (zip->goToNextFile()); @@ -354,7 +328,7 @@ std::optional MMCZip::extractSubDir(QuaZip *zip, const QString & su } // ours -bool MMCZip::extractRelFile(QuaZip *zip, const QString &file, const QString &target) +bool MMCZip::extractRelFile(QuaZip* zip, const QString& file, const QString& target) { return JlCompress::extractFile(zip, file, target); } @@ -363,14 +337,14 @@ bool MMCZip::extractRelFile(QuaZip *zip, const QString &file, const QString &tar std::optional MMCZip::extractDir(QString fileCompressed, QString dir) { QuaZip zip(fileCompressed); - if (!zip.open(QuaZip::mdUnzip)) - { + if (!zip.open(QuaZip::mdUnzip)) { // check if this is a minimum size empty zip file... QFileInfo fileInfo(fileCompressed); - if(fileInfo.size() == 22) { + if (fileInfo.size() == 22) { return QStringList(); } - qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError();; + qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError(); + ; return std::nullopt; } return MMCZip::extractSubDir(&zip, "", dir); @@ -380,14 +354,14 @@ std::optional MMCZip::extractDir(QString fileCompressed, QString di std::optional MMCZip::extractDir(QString fileCompressed, QString subdir, QString dir) { QuaZip zip(fileCompressed); - if (!zip.open(QuaZip::mdUnzip)) - { + if (!zip.open(QuaZip::mdUnzip)) { // check if this is a minimum size empty zip file... QFileInfo fileInfo(fileCompressed); - if(fileInfo.size() == 22) { + if (fileInfo.size() == 22) { return QStringList(); } - qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError();; + qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError(); + ; return std::nullopt; } return MMCZip::extractSubDir(&zip, subdir, dir); @@ -397,11 +371,10 @@ std::optional MMCZip::extractDir(QString fileCompressed, QString su bool MMCZip::extractFile(QString fileCompressed, QString file, QString target) { QuaZip zip(fileCompressed); - if (!zip.open(QuaZip::mdUnzip)) - { + if (!zip.open(QuaZip::mdUnzip)) { // check if this is a minimum size empty zip file... QFileInfo fileInfo(fileCompressed); - if(fileInfo.size() == 22) { + if (fileInfo.size() == 22) { return true; } qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError(); @@ -410,10 +383,14 @@ bool MMCZip::extractFile(QString fileCompressed, QString file, QString target) return MMCZip::extractRelFile(&zip, file, target); } -bool MMCZip::collectFileListRecursively(const QString& rootDir, const QString& subDir, QFileInfoList *files, - MMCZip::FilterFunction excludeFilter) { +bool MMCZip::collectFileListRecursively(const QString& rootDir, + const QString& subDir, + QFileInfoList* files, + MMCZip::FilterFunction excludeFilter) +{ QDir rootDirectory(rootDir); - if (!rootDirectory.exists()) return false; + if (!rootDirectory.exists()) + return false; QDir directory; if (subDir == nullptr) @@ -421,18 +398,19 @@ bool MMCZip::collectFileListRecursively(const QString& rootDir, const QString& s else directory = QDir(subDir); - if (!directory.exists()) return false; // shouldn't ever happen + if (!directory.exists()) + return false; // shouldn't ever happen // recurse directories QFileInfoList entries = directory.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::Hidden); - for (const auto& e: entries) { + for (const auto& e : entries) { if (!collectFileListRecursively(rootDir, e.filePath(), files, excludeFilter)) return false; } // collect files entries = directory.entryInfoList(QDir::Files); - for (const auto& e: entries) { + for (const auto& e : entries) { QString relativeFilePath = rootDirectory.relativeFilePath(e.absoluteFilePath()); if (excludeFilter && excludeFilter(relativeFilePath)) { qDebug() << "Skipping file " << relativeFilePath; diff --git a/launcher/MMCZip.h b/launcher/MMCZip.h index 2a78f830f..c7cabdc56 100644 --- a/launcher/MMCZip.h +++ b/launcher/MMCZip.h @@ -35,110 +35,108 @@ #pragma once -#include #include #include -#include "minecraft/mod/Mod.h" +#include #include +#include "minecraft/mod/Mod.h" #include #include -namespace MMCZip -{ - using FilterFunction = std::function; +namespace MMCZip { +using FilterFunction = std::function; - /** - * Merge two zip files, using a filter function - */ - bool mergeZipFiles(QuaZip *into, QFileInfo from, QSet &contained, - const FilterFunction filter = nullptr); +/** + * Merge two zip files, using a filter function + */ +bool mergeZipFiles(QuaZip* into, QFileInfo from, QSet& contained, const FilterFunction filter = nullptr); - /** - * Compress directory, by providing a list of files to compress - * \param zip target archive - * \param dir directory that will be compressed (to compress with relative paths) - * \param files list of files to compress - * \param followSymlinks should follow symlinks when compressing file data - * \return true for success or false for failure - */ - bool compressDirFiles(QuaZip *zip, QString dir, QFileInfoList files, bool followSymlinks = false); +/** + * Compress directory, by providing a list of files to compress + * \param zip target archive + * \param dir directory that will be compressed (to compress with relative paths) + * \param files list of files to compress + * \param followSymlinks should follow symlinks when compressing file data + * \return true for success or false for failure + */ +bool compressDirFiles(QuaZip* zip, QString dir, QFileInfoList files, bool followSymlinks = false); - /** - * Compress directory, by providing a list of files to compress - * \param fileCompressed target archive file - * \param dir directory that will be compressed (to compress with relative paths) - * \param files list of files to compress - * \param followSymlinks should follow symlinks when compressing file data - * \return true for success or false for failure - */ - bool compressDirFiles(QString fileCompressed, QString dir, QFileInfoList files, bool followSymlinks = false); +/** + * Compress directory, by providing a list of files to compress + * \param fileCompressed target archive file + * \param dir directory that will be compressed (to compress with relative paths) + * \param files list of files to compress + * \param followSymlinks should follow symlinks when compressing file data + * \return true for success or false for failure + */ +bool compressDirFiles(QString fileCompressed, QString dir, QFileInfoList files, bool followSymlinks = false); - /** - * take a source jar, add mods to it, resulting in target jar - */ - bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList& mods); +/** + * take a source jar, add mods to it, resulting in target jar + */ +bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList& mods); - /** - * Find a single file in archive by file name (not path) - * - * \param ignore_paths paths to skip when recursing the search - * - * \return the path prefix where the file is - */ - QString findFolderOfFileInZip(QuaZip * zip, const QString & what, const QStringList& ignore_paths = {}, const QString &root = QString("")); +/** + * Find a single file in archive by file name (not path) + * + * \param ignore_paths paths to skip when recursing the search + * + * \return the path prefix where the file is + */ +QString findFolderOfFileInZip(QuaZip* zip, const QString& what, const QStringList& ignore_paths = {}, const QString& root = QString("")); - /** - * Find a multiple files of the same name in archive by file name - * If a file is found in a path, no deeper paths are searched - * - * \return true if anything was found - */ - bool findFilesInZip(QuaZip * zip, const QString & what, QStringList & result, const QString &root = QString()); +/** + * Find a multiple files of the same name in archive by file name + * If a file is found in a path, no deeper paths are searched + * + * \return true if anything was found + */ +bool findFilesInZip(QuaZip* zip, const QString& what, QStringList& result, const QString& root = QString()); - /** - * Extract a subdirectory from an archive - */ - std::optional extractSubDir(QuaZip *zip, const QString & subdir, const QString &target); +/** + * Extract a subdirectory from an archive + */ +std::optional extractSubDir(QuaZip* zip, const QString& subdir, const QString& target); - bool extractRelFile(QuaZip *zip, const QString & file, const QString &target); +bool extractRelFile(QuaZip* zip, const QString& file, const QString& target); - /** - * Extract a whole archive. - * - * \param fileCompressed The name of the archive. - * \param dir The directory to extract to, the current directory if left empty. - * \return The list of the full paths of the files extracted, empty on failure. - */ - std::optional extractDir(QString fileCompressed, QString dir); +/** + * Extract a whole archive. + * + * \param fileCompressed The name of the archive. + * \param dir The directory to extract to, the current directory if left empty. + * \return The list of the full paths of the files extracted, empty on failure. + */ +std::optional extractDir(QString fileCompressed, QString dir); - /** - * Extract a subdirectory from an archive - * - * \param fileCompressed The name of the archive. - * \param subdir The directory within the archive to extract - * \param dir The directory to extract to, the current directory if left empty. - * \return The list of the full paths of the files extracted, empty on failure. - */ - std::optional extractDir(QString fileCompressed, QString subdir, QString dir); +/** + * Extract a subdirectory from an archive + * + * \param fileCompressed The name of the archive. + * \param subdir The directory within the archive to extract + * \param dir The directory to extract to, the current directory if left empty. + * \return The list of the full paths of the files extracted, empty on failure. + */ +std::optional extractDir(QString fileCompressed, QString subdir, QString dir); - /** - * Extract a single file from an archive into a directory - * - * \param fileCompressed The name of the archive. - * \param file The file within the archive to extract - * \param dir The directory to extract to, the current directory if left empty. - * \return true for success or false for failure - */ - bool extractFile(QString fileCompressed, QString file, QString dir); +/** + * Extract a single file from an archive into a directory + * + * \param fileCompressed The name of the archive. + * \param file The file within the archive to extract + * \param dir The directory to extract to, the current directory if left empty. + * \return true for success or false for failure + */ +bool extractFile(QString fileCompressed, QString file, QString dir); - /** - * Populate a QFileInfoList with a directory tree recursively, while allowing to excludeFilter what shouldn't be included. - * \param rootDir directory to start off - * \param subDir subdirectory, should be nullptr for first invocation - * \param files resulting list of QFileInfo - * \param excludeFilter function to excludeFilter which files shouldn't be included (returning true means to excude) - * \return true for success or false for failure - */ - bool collectFileListRecursively(const QString &rootDir, const QString &subDir, QFileInfoList *files, FilterFunction excludeFilter); -} +/** + * Populate a QFileInfoList with a directory tree recursively, while allowing to excludeFilter what shouldn't be included. + * \param rootDir directory to start off + * \param subDir subdirectory, should be nullptr for first invocation + * \param files resulting list of QFileInfo + * \param excludeFilter function to excludeFilter which files shouldn't be included (returning true means to excude) + * \return true for success or false for failure + */ +bool collectFileListRecursively(const QString& rootDir, const QString& subDir, QFileInfoList* files, FilterFunction excludeFilter); +} // namespace MMCZip diff --git a/launcher/ui/dialogs/ExportInstanceDialog.cpp b/launcher/ui/dialogs/ExportInstanceDialog.cpp index cc41c394d..379ec79f9 100644 --- a/launcher/ui/dialogs/ExportInstanceDialog.cpp +++ b/launcher/ui/dialogs/ExportInstanceDialog.cpp @@ -72,7 +72,7 @@ ExportInstanceDialog::ExportInstanceDialog(InstancePtr instance, QWidget* parent ui->treeView->setRootIndex(proxyModel->mapFromSource(model->index(root))); ui->treeView->sortByColumn(0, Qt::AscendingOrder); - connect(proxyModel, SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(rowsInserted(QModelIndex,int,int))); + connect(proxyModel, SIGNAL(rowsInserted(QModelIndex, int, int)), SLOT(rowsInserted(QModelIndex, int, int))); model->setFilter(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::AllDirs | QDir::Hidden); model->setRootPath(root); @@ -92,32 +92,26 @@ void SaveIcon(InstancePtr m_instance) auto iconKey = m_instance->iconKey(); auto iconList = APPLICATION->icons(); auto mmcIcon = iconList->icon(iconKey); - if(!mmcIcon || mmcIcon->isBuiltIn()) { + if (!mmcIcon || mmcIcon->isBuiltIn()) { return; } auto path = mmcIcon->getFilePath(); - if(!path.isNull()) { - QFileInfo inInfo (path); - FS::copy(path, FS::PathCombine(m_instance->instanceRoot(), inInfo.fileName())) (); + if (!path.isNull()) { + QFileInfo inInfo(path); + FS::copy(path, FS::PathCombine(m_instance->instanceRoot(), inInfo.fileName()))(); return; } - auto & image = mmcIcon->m_images[mmcIcon->type()]; - auto & icon = image.icon; + auto& image = mmcIcon->m_images[mmcIcon->type()]; + auto& icon = image.icon; auto sizes = icon.availableSizes(); - if(sizes.size() == 0) - { + if (sizes.size() == 0) { return; } - auto areaOf = [](QSize size) - { - return size.width() * size.height(); - }; + auto areaOf = [](QSize size) { return size.width() * size.height(); }; QSize largest = sizes[0]; // find variant with largest area - for(auto size: sizes) - { - if(areaOf(largest) < areaOf(size)) - { + for (auto size : sizes) { + if (areaOf(largest) < areaOf(size)) { largest = size; } } @@ -129,11 +123,9 @@ bool ExportInstanceDialog::doExport() { auto name = FS::RemoveInvalidFilenameChars(m_instance->name()); - const QString output = QFileDialog::getSaveFileName( - this, tr("Export %1").arg(m_instance->name()), - FS::PathCombine(QDir::homePath(), name + ".zip"), "Zip (*.zip)", nullptr); - if (output.isEmpty()) - { + const QString output = QFileDialog::getSaveFileName(this, tr("Export %1").arg(m_instance->name()), + FS::PathCombine(QDir::homePath(), name + ".zip"), "Zip (*.zip)", nullptr); + if (output.isEmpty()) { return false; } @@ -146,8 +138,7 @@ bool ExportInstanceDialog::doExport() return false; } - if (!MMCZip::compressDirFiles(output, m_instance->instanceRoot(), files, true)) - { + if (!MMCZip::compressDirFiles(output, m_instance->instanceRoot(), files, true)) { QMessageBox::warning(this, tr("Error"), tr("Unable to export instance")); return false; } @@ -157,15 +148,11 @@ bool ExportInstanceDialog::doExport() void ExportInstanceDialog::done(int result) { savePackIgnore(); - if (result == QDialog::Accepted) - { - if (doExport()) - { + if (result == QDialog::Accepted) { + if (doExport()) { QDialog::done(QDialog::Accepted); return; - } - else - { + } else { return; } } @@ -174,15 +161,12 @@ void ExportInstanceDialog::done(int result) void ExportInstanceDialog::rowsInserted(QModelIndex parent, int top, int bottom) { - //WARNING: possible off-by-one? - for(int i = top; i < bottom; i++) - { + // WARNING: possible off-by-one? + for (int i = top; i < bottom; i++) { auto node = proxyModel->index(i, 0, parent); - if(proxyModel->shouldExpand(node)) - { + if (proxyModel->shouldExpand(node)) { auto expNode = node.parent(); - if(!expNode.isValid()) - { + if (!expNode.isValid()) { continue; } ui->treeView->expand(node); @@ -199,8 +183,7 @@ void ExportInstanceDialog::loadPackIgnore() { auto filename = ignoreFileName(); QFile ignoreFile(filename); - if(!ignoreFile.open(QIODevice::ReadOnly)) - { + if (!ignoreFile.open(QIODevice::ReadOnly)) { return; } auto data = ignoreFile.readAll(); @@ -216,12 +199,9 @@ void ExportInstanceDialog::savePackIgnore() { auto data = proxyModel->blockedPaths().toStringList().join('\n').toUtf8(); auto filename = ignoreFileName(); - try - { + try { FS::write(filename, data); - } - catch (const Exception &e) - { + } catch (const Exception& e) { qWarning() << e.cause(); } } diff --git a/launcher/ui/dialogs/ExportInstanceDialog.h b/launcher/ui/dialogs/ExportInstanceDialog.h index 5e8018751..20a92807b 100644 --- a/launcher/ui/dialogs/ExportInstanceDialog.h +++ b/launcher/ui/dialogs/ExportInstanceDialog.h @@ -38,39 +38,37 @@ #include #include #include -#include "FileIgnoreProxy.h" #include "FastFileIconProvider.h" +#include "FileIgnoreProxy.h" class BaseInstance; typedef std::shared_ptr InstancePtr; -namespace Ui -{ +namespace Ui { class ExportInstanceDialog; } -class ExportInstanceDialog : public QDialog -{ +class ExportInstanceDialog : public QDialog { Q_OBJECT -public: - explicit ExportInstanceDialog(InstancePtr instance, QWidget *parent = 0); + public: + explicit ExportInstanceDialog(InstancePtr instance, QWidget* parent = 0); ~ExportInstanceDialog(); virtual void done(int result); -private: + private: bool doExport(); void loadPackIgnore(); void savePackIgnore(); QString ignoreFileName(); -private: - Ui::ExportInstanceDialog *ui; + private: + Ui::ExportInstanceDialog* ui; InstancePtr m_instance; - FileIgnoreProxy * proxyModel; + FileIgnoreProxy* proxyModel; FastFileIconProvider icons; -private slots: + private slots: void rowsInserted(QModelIndex parent, int top, int bottom); }; From cadb7142f0fe5eab16198ca8079d544456a977cc Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 16 Jul 2023 20:57:57 +0300 Subject: [PATCH 55/72] Added progress bar to Prism instance export Signed-off-by: Trial97 --- launcher/MMCZip.cpp | 87 +++++++++++++++----- launcher/MMCZip.h | 47 ++++++++++- launcher/ui/dialogs/ExportInstanceDialog.cpp | 38 +++++---- launcher/ui/dialogs/ExportInstanceDialog.h | 3 +- 4 files changed, 136 insertions(+), 39 deletions(-) diff --git a/launcher/MMCZip.cpp b/launcher/MMCZip.cpp index 4e932a768..f272bc031 100644 --- a/launcher/MMCZip.cpp +++ b/launcher/MMCZip.cpp @@ -2,6 +2,7 @@ /* * PolyMC - Minecraft Launcher * Copyright (C) 2022 Sefa Eyeoglu + * Copyright (c) 2023 Trial97 * * 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 @@ -41,9 +42,11 @@ #include #include +#include +namespace MMCZip { // ours -bool MMCZip::mergeZipFiles(QuaZip* into, QFileInfo from, QSet& contained, const FilterFunction filter) +bool mergeZipFiles(QuaZip* into, QFileInfo from, QSet& contained, const FilterFunction filter) { QuaZip modZip(from.filePath()); modZip.open(QuaZip::mdUnzip); @@ -86,7 +89,7 @@ bool MMCZip::mergeZipFiles(QuaZip* into, QFileInfo from, QSet& containe return true; } -bool MMCZip::compressDirFiles(QuaZip* zip, QString dir, QFileInfoList files, bool followSymlinks) +bool compressDirFiles(QuaZip* zip, QString dir, QFileInfoList files, bool followSymlinks) { QDir directory(dir); if (!directory.exists()) @@ -109,7 +112,7 @@ bool MMCZip::compressDirFiles(QuaZip* zip, QString dir, QFileInfoList files, boo return true; } -bool MMCZip::compressDirFiles(QString fileCompressed, QString dir, QFileInfoList files, bool followSymlinks) +bool compressDirFiles(QString fileCompressed, QString dir, QFileInfoList files, bool followSymlinks) { QuaZip zip(fileCompressed); QDir().mkpath(QFileInfo(fileCompressed).absolutePath()); @@ -130,7 +133,7 @@ bool MMCZip::compressDirFiles(QString fileCompressed, QString dir, QFileInfoList } // ours -bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const QList& mods) +bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList& mods) { QuaZip zipOut(targetJarPath); if (!zipOut.open(QuaZip::mdCreate)) { @@ -175,14 +178,14 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const dir.cdUp(); QString parent_dir = dir.absolutePath(); auto files = QFileInfoList(); - MMCZip::collectFileListRecursively(what_to_zip, nullptr, &files, nullptr); + collectFileListRecursively(what_to_zip, nullptr, &files, nullptr); for (auto e : files) { if (addedFiles.contains(e.filePath())) files.removeAll(e); } - if (!MMCZip::compressDirFiles(&zipOut, parent_dir, files)) { + if (!compressDirFiles(&zipOut, parent_dir, files)) { zipOut.close(); QFile::remove(targetJarPath); qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar."; @@ -216,7 +219,7 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const } // ours -QString MMCZip::findFolderOfFileInZip(QuaZip* zip, const QString& what, const QStringList& ignore_paths, const QString& root) +QString findFolderOfFileInZip(QuaZip* zip, const QString& what, const QStringList& ignore_paths, const QString& root) { QuaZipDir rootDir(zip, root); for (auto&& fileName : rootDir.entryList(QDir::Files)) { @@ -240,7 +243,7 @@ QString MMCZip::findFolderOfFileInZip(QuaZip* zip, const QString& what, const QS } // ours -bool MMCZip::findFilesInZip(QuaZip* zip, const QString& what, QStringList& result, const QString& root) +bool findFilesInZip(QuaZip* zip, const QString& what, QStringList& result, const QString& root) { QuaZipDir rootDir(zip, root); for (auto fileName : rootDir.entryList(QDir::Files)) { @@ -256,7 +259,7 @@ bool MMCZip::findFilesInZip(QuaZip* zip, const QString& what, QStringList& resul } // ours -std::optional MMCZip::extractSubDir(QuaZip* zip, const QString& subdir, const QString& target) +std::optional extractSubDir(QuaZip* zip, const QString& subdir, const QString& target) { auto target_top_dir = QUrl::fromLocalFile(target); @@ -328,13 +331,13 @@ std::optional MMCZip::extractSubDir(QuaZip* zip, const QString& sub } // ours -bool MMCZip::extractRelFile(QuaZip* zip, const QString& file, const QString& target) +bool extractRelFile(QuaZip* zip, const QString& file, const QString& target) { return JlCompress::extractFile(zip, file, target); } // ours -std::optional MMCZip::extractDir(QString fileCompressed, QString dir) +std::optional extractDir(QString fileCompressed, QString dir) { QuaZip zip(fileCompressed); if (!zip.open(QuaZip::mdUnzip)) { @@ -347,11 +350,11 @@ std::optional MMCZip::extractDir(QString fileCompressed, QString di ; return std::nullopt; } - return MMCZip::extractSubDir(&zip, "", dir); + return extractSubDir(&zip, "", dir); } // ours -std::optional MMCZip::extractDir(QString fileCompressed, QString subdir, QString dir) +std::optional extractDir(QString fileCompressed, QString subdir, QString dir) { QuaZip zip(fileCompressed); if (!zip.open(QuaZip::mdUnzip)) { @@ -364,11 +367,11 @@ std::optional MMCZip::extractDir(QString fileCompressed, QString su ; return std::nullopt; } - return MMCZip::extractSubDir(&zip, subdir, dir); + return extractSubDir(&zip, subdir, dir); } // ours -bool MMCZip::extractFile(QString fileCompressed, QString file, QString target) +bool extractFile(QString fileCompressed, QString file, QString target) { QuaZip zip(fileCompressed); if (!zip.open(QuaZip::mdUnzip)) { @@ -380,13 +383,10 @@ bool MMCZip::extractFile(QString fileCompressed, QString file, QString target) qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError(); return false; } - return MMCZip::extractRelFile(&zip, file, target); + return extractRelFile(&zip, file, target); } -bool MMCZip::collectFileListRecursively(const QString& rootDir, - const QString& subDir, - QFileInfoList* files, - MMCZip::FilterFunction excludeFilter) +bool collectFileListRecursively(const QString& rootDir, const QString& subDir, QFileInfoList* files, FilterFunction excludeFilter) { QDir rootDirectory(rootDir); if (!rootDirectory.exists()) @@ -417,7 +417,52 @@ bool MMCZip::collectFileListRecursively(const QString& rootDir, continue; } - files->append(e); // we want the original paths for MMCZip::compressDirFiles + files->append(e); // we want the original paths for compressDirFiles } return true; } + +void ExportToZipTask::executeTask() +{ + (void)QtConcurrent::run(QThreadPool::globalInstance(), [this]() { + setStatus("Adding files..."); + setProgress(0, m_files.length()); + if (!m_dir.exists()) { + emitFailed(tr("Folder doesn't exist")); + return; + } + if (!m_output->isOpen() && !m_output->open(QuaZip::mdCreate)) { + emitFailed(tr("Could not create file")); + return; + } + + for (const QFileInfo& file : m_files) { + if (!isRunning()) + return; + + auto absolute = file.absoluteFilePath(); + auto relative = m_dir.relativeFilePath(absolute); + setStatus("Compresing: " + relative); + setProgress(m_progress + 1, m_progressTotal); + if (m_followSymlinks) { + if (file.isSymLink()) + absolute = file.symLinkTarget(); + else + absolute = file.canonicalFilePath(); + } + + if (!JlCompress::compressFile(m_output, absolute, m_destinationPrefix + relative)) { + emitFailed(tr("Could not read and compress %1").arg(relative)); + return; + } + } + + m_output->close(); + if (m_output->getZipError() != 0) { + emitFailed(tr("A zip error occurred")); + return; + } + emitSucceeded(); + }); +} +} // namespace MMCZip \ No newline at end of file diff --git a/launcher/MMCZip.h b/launcher/MMCZip.h index c7cabdc56..728dd3c89 100644 --- a/launcher/MMCZip.h +++ b/launcher/MMCZip.h @@ -2,6 +2,7 @@ /* * PolyMC - Minecraft Launcher * Copyright (C) 2022 Sefa Eyeoglu + * Copyright (c) 2023 Trial97 * * 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 @@ -35,14 +36,16 @@ #pragma once +#include +#include +#include #include #include #include #include -#include "minecraft/mod/Mod.h" - -#include #include +#include "minecraft/mod/Mod.h" +#include "tasks/Task.h" namespace MMCZip { using FilterFunction = std::function; @@ -139,4 +142,42 @@ bool extractFile(QString fileCompressed, QString file, QString dir); * \return true for success or false for failure */ bool collectFileListRecursively(const QString& rootDir, const QString& subDir, QFileInfoList* files, FilterFunction excludeFilter); + +class ExportToZipTask : public Task { + public: + ExportToZipTask(QuaZip* output, + QDir dir, + QFileInfoList files, + QString destinationPrefix = "", + bool followSymlinks = false, + bool cleanUp = false) + : m_output(output) + , m_dir(dir) + , m_files(files) + , m_destinationPrefix(destinationPrefix) + , m_followSymlinks(followSymlinks) + , m_cleanUp(cleanUp) + { + setAbortable(true); + }; + ExportToZipTask(QString outputPath, QString dir, QFileInfoList files, QString destinationPrefix = "", bool followSymlinks = false) + : ExportToZipTask(new QuaZip(outputPath), QDir(dir), files, destinationPrefix, followSymlinks, true){}; + + virtual ~ExportToZipTask() + { + if (m_cleanUp) + delete m_output; + } + + protected: + virtual void executeTask() override; + + private: + QuaZip* m_output; + QDir m_dir; + QFileInfoList m_files; + QString m_destinationPrefix; + bool m_followSymlinks; + bool m_cleanUp; +}; } // namespace MMCZip diff --git a/launcher/ui/dialogs/ExportInstanceDialog.cpp b/launcher/ui/dialogs/ExportInstanceDialog.cpp index 379ec79f9..1a3f8cd41 100644 --- a/launcher/ui/dialogs/ExportInstanceDialog.cpp +++ b/launcher/ui/dialogs/ExportInstanceDialog.cpp @@ -3,6 +3,7 @@ * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 Sefa Eyeoglu * Copyright (C) 2023 TheKodeToad + * Copyright (c) 2023 Trial97 * * 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 @@ -41,6 +42,9 @@ #include #include #include "FileIgnoreProxy.h" +#include "QObjectPtr.h" +#include "ui/dialogs/CustomMessageBox.h" +#include "ui/dialogs/ProgressDialog.h" #include "ui_ExportInstanceDialog.h" #include @@ -119,14 +123,15 @@ void SaveIcon(InstancePtr m_instance) pixmap.save(FS::PathCombine(m_instance->instanceRoot(), iconKey + ".png")); } -bool ExportInstanceDialog::doExport() +void ExportInstanceDialog::doExport() { auto name = FS::RemoveInvalidFilenameChars(m_instance->name()); const QString output = QFileDialog::getSaveFileName(this, tr("Export %1").arg(m_instance->name()), FS::PathCombine(QDir::homePath(), name + ".zip"), "Zip (*.zip)", nullptr); if (output.isEmpty()) { - return false; + QDialog::done(QDialog::Rejected); + return; } SaveIcon(m_instance); @@ -135,26 +140,31 @@ bool ExportInstanceDialog::doExport() if (!MMCZip::collectFileListRecursively(m_instance->instanceRoot(), nullptr, &files, std::bind(&FileIgnoreProxy::filterFile, proxyModel, std::placeholders::_1))) { QMessageBox::warning(this, tr("Error"), tr("Unable to export instance")); - return false; + QDialog::done(QDialog::Rejected); + return; } - if (!MMCZip::compressDirFiles(output, m_instance->instanceRoot(), files, true)) { - QMessageBox::warning(this, tr("Error"), tr("Unable to export instance")); - return false; - } - return true; + auto task = makeShared(output, m_instance->instanceRoot(), files, "", true); + + connect(task.get(), &Task::failed, this, [this, output](QString reason) { + CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show(); + QFile::remove(output); + }); + connect(task.get(), &Task::aborted, this, [output] { QFile::remove(output); }); + connect(task.get(), &Task::finished, this, [task] { task->deleteLater(); }); + + ProgressDialog progress(this); + progress.setSkipButton(true, tr("Abort")); + auto result = progress.execWithTask(task.get()); + QDialog::done(result); } void ExportInstanceDialog::done(int result) { savePackIgnore(); if (result == QDialog::Accepted) { - if (doExport()) { - QDialog::done(QDialog::Accepted); - return; - } else { - return; - } + doExport(); + return; } QDialog::done(result); } diff --git a/launcher/ui/dialogs/ExportInstanceDialog.h b/launcher/ui/dialogs/ExportInstanceDialog.h index 20a92807b..02f38f63d 100644 --- a/launcher/ui/dialogs/ExportInstanceDialog.h +++ b/launcher/ui/dialogs/ExportInstanceDialog.h @@ -2,6 +2,7 @@ /* * Prism Launcher - Minecraft Launcher * Copyright (C) 2023 TheKodeToad + * Copyright (c) 2023 Trial97 * * 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 @@ -58,7 +59,7 @@ class ExportInstanceDialog : public QDialog { virtual void done(int result); private: - bool doExport(); + void doExport(); void loadPackIgnore(); void savePackIgnore(); QString ignoreFileName(); From 79222a56e38a696168dddcc92a970242e0f34053 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Sun, 16 Jul 2023 21:12:53 +0300 Subject: [PATCH 56/72] use shared pointer Signed-off-by: Trial97 use shared pointer --- launcher/MMCZip.cpp | 2 +- launcher/MMCZip.h | 24 +++++++----------------- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/launcher/MMCZip.cpp b/launcher/MMCZip.cpp index f272bc031..ec1c4b07d 100644 --- a/launcher/MMCZip.cpp +++ b/launcher/MMCZip.cpp @@ -451,7 +451,7 @@ void ExportToZipTask::executeTask() absolute = file.canonicalFilePath(); } - if (!JlCompress::compressFile(m_output, absolute, m_destinationPrefix + relative)) { + if (!JlCompress::compressFile(m_output.get(), absolute, m_destinationPrefix + relative)) { emitFailed(tr("Could not read and compress %1").arg(relative)); return; } diff --git a/launcher/MMCZip.h b/launcher/MMCZip.h index 728dd3c89..ded169cd9 100644 --- a/launcher/MMCZip.h +++ b/launcher/MMCZip.h @@ -43,6 +43,7 @@ #include #include #include +#include #include #include "minecraft/mod/Mod.h" #include "tasks/Task.h" @@ -145,39 +146,28 @@ bool collectFileListRecursively(const QString& rootDir, const QString& subDir, Q class ExportToZipTask : public Task { public: - ExportToZipTask(QuaZip* output, + ExportToZipTask(std::shared_ptr output, QDir dir, QFileInfoList files, QString destinationPrefix = "", - bool followSymlinks = false, - bool cleanUp = false) - : m_output(output) - , m_dir(dir) - , m_files(files) - , m_destinationPrefix(destinationPrefix) - , m_followSymlinks(followSymlinks) - , m_cleanUp(cleanUp) + bool followSymlinks = false) + : m_output(output), m_dir(dir), m_files(files), m_destinationPrefix(destinationPrefix), m_followSymlinks(followSymlinks) { setAbortable(true); }; ExportToZipTask(QString outputPath, QString dir, QFileInfoList files, QString destinationPrefix = "", bool followSymlinks = false) - : ExportToZipTask(new QuaZip(outputPath), QDir(dir), files, destinationPrefix, followSymlinks, true){}; + : ExportToZipTask(std::make_shared(outputPath), QDir(dir), files, destinationPrefix, followSymlinks){}; - virtual ~ExportToZipTask() - { - if (m_cleanUp) - delete m_output; - } + virtual ~ExportToZipTask() = default; protected: virtual void executeTask() override; private: - QuaZip* m_output; + std::shared_ptr m_output; QDir m_dir; QFileInfoList m_files; QString m_destinationPrefix; bool m_followSymlinks; - bool m_cleanUp; }; } // namespace MMCZip From 4df9df03ab2e6eddae08f95ec2d34b4e811158ed Mon Sep 17 00:00:00 2001 From: Alexandru Ionut Tripon Date: Sun, 16 Jul 2023 23:47:47 +0300 Subject: [PATCH 57/72] Update launcher/MMCZip.cpp Co-authored-by: Tayou <31988415+TayouVR@users.noreply.github.com> Signed-off-by: Alexandru Ionut Tripon --- launcher/MMCZip.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/MMCZip.cpp b/launcher/MMCZip.cpp index ec1c4b07d..0a334a83f 100644 --- a/launcher/MMCZip.cpp +++ b/launcher/MMCZip.cpp @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only /* - * PolyMC - Minecraft Launcher + * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 Sefa Eyeoglu * Copyright (c) 2023 Trial97 * From ec41252535d9432d0b15228dc301e3a57e1c281d Mon Sep 17 00:00:00 2001 From: Alexandru Ionut Tripon Date: Sun, 16 Jul 2023 23:47:54 +0300 Subject: [PATCH 58/72] Update launcher/MMCZip.h Co-authored-by: Tayou <31988415+TayouVR@users.noreply.github.com> Signed-off-by: Alexandru Ionut Tripon --- launcher/MMCZip.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/MMCZip.h b/launcher/MMCZip.h index ded169cd9..531f4a38a 100644 --- a/launcher/MMCZip.h +++ b/launcher/MMCZip.h @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only /* - * PolyMC - Minecraft Launcher + * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 Sefa Eyeoglu * Copyright (c) 2023 Trial97 * From ed2f680202316c2ecf33a8926866a47da17f44e2 Mon Sep 17 00:00:00 2001 From: seth Date: Sun, 16 Jul 2023 17:28:14 -0400 Subject: [PATCH 59/72] chore(docs): add backporting info to CONTRIBUTING.md Signed-off-by: seth --- CONTRIBUTING.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4bca126f8..b2795ce49 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -61,3 +61,10 @@ As a bonus, you can also [cryptographically sign your commits][gh-signing-commit [gh-signing-commits]: https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits [gh-vigilant-mode]: https://docs.github.com/en/authentication/managing-commit-signature-verification/displaying-verification-statuses-for-all-of-your-commits + + +## Backporting to Release Branches + +We use [automated backports](https://github.com/PrismLauncher/PrismLauncher/blob/develop/.github/workflows/backport.yml) to merge specific contributions from develop into `release` branches. + +This is done when pull requests are merged and have labels such as `backport release-7.x` - which should be added along with the milestone for the release. From ec32618e1158beba1cf5b4c91c3835a233eceeeb Mon Sep 17 00:00:00 2001 From: Trial97 Date: Mon, 17 Jul 2023 10:20:22 +0300 Subject: [PATCH 60/72] reveted back to add years Signed-off-by: Trial97 --- launcher/ui/themes/CatPack.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launcher/ui/themes/CatPack.cpp b/launcher/ui/themes/CatPack.cpp index ebb100a40..f0d8ddd55 100644 --- a/launcher/ui/themes/CatPack.cpp +++ b/launcher/ui/themes/CatPack.cpp @@ -105,9 +105,9 @@ QString JsonCatPack::path() QDate endDate = ensureDay(now.year(), var.endTime.month, var.endTime.day); if (startDate > endDate) { // it's spans over multiple years if (endDate <= now) // end date is in the past so jump one year into the future for endDate - endDate = ensureDay(now.year() + 1, var.endTime.month, var.endTime.day); + endDate = endDate.addYears(1); else // end date is in the future so jump one year into the past for startDate - startDate = ensureDay(now.year() - 1, var.startTime.month, var.startTime.day); + startDate = startDate.addYears(-1); } if (startDate >= now && now >= endDate) From 54a091ca597608e732f00eb7f086fe26448daea1 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Mon, 17 Jul 2023 10:09:01 +0200 Subject: [PATCH 61/72] fix: check if any modloader is installed Signed-off-by: Sefa Eyeoglu --- launcher/minecraft/MinecraftInstance.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index 0833d5912..83b50f0bd 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -396,8 +396,11 @@ QStringList MinecraftInstance::extraArguments() agent->library()->getApplicableFiles(runtimeContext(), jar, temp1, temp2, temp3, getLocalLibraryPath()); list.append("-javaagent:"+jar[0]+(agent->argument().isEmpty() ? "" : "="+agent->argument())); } - if (version->getModLoaders().value() & ResourceAPI::Quilt && settings()->get("DisableQuiltBeacon").toBool()) { - list.append("-Dloader.disable_beacon=true"); + + { + const auto& loaders = version->getModLoaders(); + if (loaders.has_value() && loaders.value() & ResourceAPI::Quilt && settings()->get("DisableQuiltBeacon").toBool()) + list.append("-Dloader.disable_beacon=true"); } return list; } From 2be630904f89c9308d3e0bab94eb9e5a4fa6ae03 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Mon, 17 Jul 2023 14:33:01 +0200 Subject: [PATCH 62/72] fix: don't take modloaders by reference Co-authored-by: TheKodeToad Signed-off-by: Sefa Eyeoglu --- launcher/minecraft/MinecraftInstance.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index 83b50f0bd..342e634f7 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -398,7 +398,7 @@ QStringList MinecraftInstance::extraArguments() } { - const auto& loaders = version->getModLoaders(); + const auto loaders = version->getModLoaders(); if (loaders.has_value() && loaders.value() & ResourceAPI::Quilt && settings()->get("DisableQuiltBeacon").toBool()) list.append("-Dloader.disable_beacon=true"); } From 2ea4a78541c5d6dc682ec76c2e0846fe11fe1cf9 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Mon, 17 Jul 2023 16:24:43 +0300 Subject: [PATCH 63/72] Upgraded ExportToZipTask Signed-off-by: Trial97 --- launcher/MMCZip.cpp | 95 ++++++++++++++++++++++++++------------------- launcher/MMCZip.h | 23 ++++++----- 2 files changed, 68 insertions(+), 50 deletions(-) diff --git a/launcher/MMCZip.cpp b/launcher/MMCZip.cpp index 0a334a83f..cc7491971 100644 --- a/launcher/MMCZip.cpp +++ b/launcher/MMCZip.cpp @@ -424,45 +424,60 @@ bool collectFileListRecursively(const QString& rootDir, const QString& subDir, Q void ExportToZipTask::executeTask() { - (void)QtConcurrent::run(QThreadPool::globalInstance(), [this]() { - setStatus("Adding files..."); - setProgress(0, m_files.length()); - if (!m_dir.exists()) { - emitFailed(tr("Folder doesn't exist")); - return; - } - if (!m_output->isOpen() && !m_output->open(QuaZip::mdCreate)) { - emitFailed(tr("Could not create file")); - return; - } - - for (const QFileInfo& file : m_files) { - if (!isRunning()) - return; - - auto absolute = file.absoluteFilePath(); - auto relative = m_dir.relativeFilePath(absolute); - setStatus("Compresing: " + relative); - setProgress(m_progress + 1, m_progressTotal); - if (m_followSymlinks) { - if (file.isSymLink()) - absolute = file.symLinkTarget(); - else - absolute = file.canonicalFilePath(); - } - - if (!JlCompress::compressFile(m_output.get(), absolute, m_destinationPrefix + relative)) { - emitFailed(tr("Could not read and compress %1").arg(relative)); - return; - } - } - - m_output->close(); - if (m_output->getZipError() != 0) { - emitFailed(tr("A zip error occurred")); - return; - } - emitSucceeded(); - }); + (void)QtConcurrent::run(QThreadPool::globalInstance(), [this]() { exportZip(); }); } + +void ExportToZipTask::exportZip() +{ + setStatus("Adding files..."); + setProgress(0, m_files.length()); + if (!m_dir.exists()) { + emitFailed(tr("Folder doesn't exist")); + return; + } + if (!m_output.isOpen() && !m_output.open(QuaZip::mdCreate)) { + emitFailed(tr("Could not create file")); + return; + } + + for (auto fileName : m_extra_files.keys()) { + if (!isRunning()) + return; + QuaZipFile indexFile(&m_output); + if (!indexFile.open(QIODevice::WriteOnly, QuaZipNewInfo(fileName))) { + emitFailed(tr("Could not create:") + fileName); + return; + } + indexFile.write(m_extra_files[fileName]); + } + + for (const QFileInfo& file : m_files) { + if (!isRunning()) + return; + + auto absolute = file.absoluteFilePath(); + auto relative = m_dir.relativeFilePath(absolute); + setStatus("Compresing: " + relative); + setProgress(m_progress + 1, m_progressTotal); + if (m_follow_symlinks) { + if (file.isSymLink()) + absolute = file.symLinkTarget(); + else + absolute = file.canonicalFilePath(); + } + + if (!m_exclude_files.contains(relative) && !JlCompress::compressFile(&m_output, absolute, m_destination_prefix + relative)) { + emitFailed(tr("Could not read and compress %1").arg(relative)); + return; + } + } + + m_output.close(); + if (m_output.getZipError() != 0) { + emitFailed(tr("A zip error occurred")); + return; + } + emitSucceeded(); +} + } // namespace MMCZip \ No newline at end of file diff --git a/launcher/MMCZip.h b/launcher/MMCZip.h index 531f4a38a..60b3490fe 100644 --- a/launcher/MMCZip.h +++ b/launcher/MMCZip.h @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -146,28 +147,30 @@ bool collectFileListRecursively(const QString& rootDir, const QString& subDir, Q class ExportToZipTask : public Task { public: - ExportToZipTask(std::shared_ptr output, - QDir dir, - QFileInfoList files, - QString destinationPrefix = "", - bool followSymlinks = false) - : m_output(output), m_dir(dir), m_files(files), m_destinationPrefix(destinationPrefix), m_followSymlinks(followSymlinks) + ExportToZipTask(QString outputPath, QDir dir, QFileInfoList files, QString destinationPrefix = "", bool followSymlinks = false) + : m_output(outputPath), m_dir(dir), m_files(files), m_destination_prefix(destinationPrefix), m_follow_symlinks(followSymlinks) { setAbortable(true); }; ExportToZipTask(QString outputPath, QString dir, QFileInfoList files, QString destinationPrefix = "", bool followSymlinks = false) - : ExportToZipTask(std::make_shared(outputPath), QDir(dir), files, destinationPrefix, followSymlinks){}; + : ExportToZipTask(outputPath, QDir(dir), files, destinationPrefix, followSymlinks){}; virtual ~ExportToZipTask() = default; + void setExcludeFiles(QStringList excludeFiles) { m_exclude_files = excludeFiles; } + void addExtraFile(QString fileName, QByteArray data) { m_extra_files.emplace(fileName, data); } + protected: virtual void executeTask() override; + void exportZip(); private: - std::shared_ptr m_output; + QuaZip m_output; QDir m_dir; QFileInfoList m_files; - QString m_destinationPrefix; - bool m_followSymlinks; + QString m_destination_prefix; + bool m_follow_symlinks; + QStringList m_exclude_files; + QHash m_extra_files; }; } // namespace MMCZip From fe73d696cb714d724948176f0bfbb356412b0f11 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Mon, 17 Jul 2023 16:57:52 +0300 Subject: [PATCH 64/72] replace emplace with insert Signed-off-by: Trial97 --- launcher/MMCZip.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/MMCZip.h b/launcher/MMCZip.h index 60b3490fe..ce76bc773 100644 --- a/launcher/MMCZip.h +++ b/launcher/MMCZip.h @@ -158,7 +158,7 @@ class ExportToZipTask : public Task { virtual ~ExportToZipTask() = default; void setExcludeFiles(QStringList excludeFiles) { m_exclude_files = excludeFiles; } - void addExtraFile(QString fileName, QByteArray data) { m_extra_files.emplace(fileName, data); } + void addExtraFile(QString fileName, QByteArray data) { m_extra_files.insert(fileName, data); } protected: virtual void executeTask() override; From b0940d696baa24ddcf29a5d3393196c1047dcd3f Mon Sep 17 00:00:00 2001 From: Trial97 Date: Mon, 17 Jul 2023 17:42:15 +0300 Subject: [PATCH 65/72] Added QFutureWatcher Signed-off-by: Trial97 abort forgot Signed-off-by: Trial97 --- launcher/MMCZip.cpp | 61 +++++++++++++------- launcher/MMCZip.h | 20 ++++++- launcher/ui/dialogs/ExportInstanceDialog.cpp | 7 +-- 3 files changed, 61 insertions(+), 27 deletions(-) diff --git a/launcher/MMCZip.cpp b/launcher/MMCZip.cpp index cc7491971..acd6bf7e4 100644 --- a/launcher/MMCZip.cpp +++ b/launcher/MMCZip.cpp @@ -423,37 +423,36 @@ bool collectFileListRecursively(const QString& rootDir, const QString& subDir, Q } void ExportToZipTask::executeTask() -{ - (void)QtConcurrent::run(QThreadPool::globalInstance(), [this]() { exportZip(); }); -} - -void ExportToZipTask::exportZip() { setStatus("Adding files..."); setProgress(0, m_files.length()); + m_build_zip_future = QtConcurrent::run(QThreadPool::globalInstance(), [this]() { return exportZip(); }); + connect(&m_build_zip_watcher, &QFutureWatcher::finished, this, &ExportToZipTask::finish); + m_build_zip_watcher.setFuture(m_build_zip_future); +} + +auto ExportToZipTask::exportZip() -> ZipResult +{ if (!m_dir.exists()) { - emitFailed(tr("Folder doesn't exist")); - return; + return ZipResult(tr("Folder doesn't exist")); } if (!m_output.isOpen() && !m_output.open(QuaZip::mdCreate)) { - emitFailed(tr("Could not create file")); - return; + return ZipResult(tr("Could not create file")); } for (auto fileName : m_extra_files.keys()) { - if (!isRunning()) - return; + if (m_build_zip_future.isCanceled()) + return ZipResult(); QuaZipFile indexFile(&m_output); if (!indexFile.open(QIODevice::WriteOnly, QuaZipNewInfo(fileName))) { - emitFailed(tr("Could not create:") + fileName); - return; + return ZipResult(tr("Could not create:") + fileName); } indexFile.write(m_extra_files[fileName]); } for (const QFileInfo& file : m_files) { - if (!isRunning()) - return; + if (m_build_zip_future.isCanceled()) + return ZipResult(); auto absolute = file.absoluteFilePath(); auto relative = m_dir.relativeFilePath(absolute); @@ -467,17 +466,39 @@ void ExportToZipTask::exportZip() } if (!m_exclude_files.contains(relative) && !JlCompress::compressFile(&m_output, absolute, m_destination_prefix + relative)) { - emitFailed(tr("Could not read and compress %1").arg(relative)); - return; + return ZipResult(tr("Could not read and compress %1").arg(relative)); } } m_output.close(); if (m_output.getZipError() != 0) { - emitFailed(tr("A zip error occurred")); - return; + return ZipResult(tr("A zip error occurred")); } - emitSucceeded(); + return ZipResult(); +} + +void ExportToZipTask::finish() +{ + if (m_build_zip_future.isCanceled()) { + QFile::remove(m_output_path); + emitAborted(); + } else if (auto result = m_build_zip_future.result(); result.has_value()) { + QFile::remove(m_output_path); + emitFailed(result.value()); + } else { + emitSucceeded(); + } +} + +bool ExportToZipTask::abort() +{ + if (m_build_zip_future.isRunning()) { + m_build_zip_future.cancel(); + // NOTE: Here we don't do `emitAborted()` because it will be done when `m_build_zip_future` actually cancels, which may not occur + // immediately. + return true; + } + return false; } } // namespace MMCZip \ No newline at end of file diff --git a/launcher/MMCZip.h b/launcher/MMCZip.h index ce76bc773..bc527ad1b 100644 --- a/launcher/MMCZip.h +++ b/launcher/MMCZip.h @@ -40,6 +40,8 @@ #include #include #include +#include +#include #include #include #include @@ -148,7 +150,12 @@ bool collectFileListRecursively(const QString& rootDir, const QString& subDir, Q class ExportToZipTask : public Task { public: ExportToZipTask(QString outputPath, QDir dir, QFileInfoList files, QString destinationPrefix = "", bool followSymlinks = false) - : m_output(outputPath), m_dir(dir), m_files(files), m_destination_prefix(destinationPrefix), m_follow_symlinks(followSymlinks) + : m_output_path(outputPath) + , m_output(outputPath) + , m_dir(dir) + , m_files(files) + , m_destination_prefix(destinationPrefix) + , m_follow_symlinks(followSymlinks) { setAbortable(true); }; @@ -160,11 +167,17 @@ class ExportToZipTask : public Task { void setExcludeFiles(QStringList excludeFiles) { m_exclude_files = excludeFiles; } void addExtraFile(QString fileName, QByteArray data) { m_extra_files.insert(fileName, data); } + typedef std::optional ZipResult; + protected: virtual void executeTask() override; - void exportZip(); + bool abort() override; + + ZipResult exportZip(); + void finish(); private: + QString m_output_path; QuaZip m_output; QDir m_dir; QFileInfoList m_files; @@ -172,5 +185,8 @@ class ExportToZipTask : public Task { bool m_follow_symlinks; QStringList m_exclude_files; QHash m_extra_files; + + QFuture m_build_zip_future; + QFutureWatcher m_build_zip_watcher; }; } // namespace MMCZip diff --git a/launcher/ui/dialogs/ExportInstanceDialog.cpp b/launcher/ui/dialogs/ExportInstanceDialog.cpp index 1a3f8cd41..d1a69b932 100644 --- a/launcher/ui/dialogs/ExportInstanceDialog.cpp +++ b/launcher/ui/dialogs/ExportInstanceDialog.cpp @@ -146,11 +146,8 @@ void ExportInstanceDialog::doExport() auto task = makeShared(output, m_instance->instanceRoot(), files, "", true); - connect(task.get(), &Task::failed, this, [this, output](QString reason) { - CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show(); - QFile::remove(output); - }); - connect(task.get(), &Task::aborted, this, [output] { QFile::remove(output); }); + connect(task.get(), &Task::failed, this, + [this, output](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show(); }); connect(task.get(), &Task::finished, this, [task] { task->deleteLater(); }); ProgressDialog progress(this); From 1fbb41f5e2c4426b1b1e469c78cfbc7e1c4d7999 Mon Sep 17 00:00:00 2001 From: Josiah Glosson Date: Mon, 17 Jul 2023 17:07:06 -0500 Subject: [PATCH 66/72] Make Launch Offline not launch online in 1.6+ Signed-off-by: Josiah Glosson --- launcher/minecraft/auth/AuthSession.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/launcher/minecraft/auth/AuthSession.cpp b/launcher/minecraft/auth/AuthSession.cpp index 6bea74a37..2c06beaa2 100644 --- a/launcher/minecraft/auth/AuthSession.cpp +++ b/launcher/minecraft/auth/AuthSession.cpp @@ -26,6 +26,7 @@ bool AuthSession::MakeOffline(QString offline_playername) return false; } session = "-"; + access_token = "0"; player_name = offline_playername; status = PlayableOffline; return true; From 2eff1de560c9b4ac76316d2c6d812438b4488222 Mon Sep 17 00:00:00 2001 From: Dallas Strouse Date: Mon, 17 Jul 2023 00:29:24 -0500 Subject: [PATCH 67/72] Update Flatpak manifest Signed-off-by: Dallas Strouse --- .gitmodules | 3 + flatpak/libdecor.json | 22 ++++ flatpak/org.prismlauncher.PrismLauncher.yml | 115 ++++++++++++++---- ...on-t-crash-on-calls-to-focus-or-icon.patch | 24 ++++ ...ning-about-being-an-unofficial-patch.patch | 17 +++ ...007-Platform-Prefer-Wayland-over-X11.patch | 20 +++ flatpak/patches/weird_libdecor.patch | 40 ++++++ flatpak/prismlauncher | 4 +- flatpak/shared-modules | 1 + 9 files changed, 222 insertions(+), 24 deletions(-) create mode 100644 flatpak/libdecor.json create mode 100644 flatpak/patches/0003-Don-t-crash-on-calls-to-focus-or-icon.patch create mode 100644 flatpak/patches/0005-Add-warning-about-being-an-unofficial-patch.patch create mode 100644 flatpak/patches/0007-Platform-Prefer-Wayland-over-X11.patch create mode 100644 flatpak/patches/weird_libdecor.patch create mode 160000 flatpak/shared-modules diff --git a/.gitmodules b/.gitmodules index 87703fee5..0f437d277 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,3 +19,6 @@ [submodule "libraries/cmark"] path = libraries/cmark url = https://github.com/commonmark/cmark.git +[submodule "flatpak/shared-modules"] + path = flatpak/shared-modules + url = https://github.com/flathub/shared-modules.git diff --git a/flatpak/libdecor.json b/flatpak/libdecor.json new file mode 100644 index 000000000..12afad69f --- /dev/null +++ b/flatpak/libdecor.json @@ -0,0 +1,22 @@ +{ + "name": "libdecor", + "buildsystem": "meson", + "config-opts": [ + "-Ddemo=false" + ], + "sources": [ + { + "type": "git", + "url": "https://gitlab.freedesktop.org/libdecor/libdecor.git", + "commit": "73260393a97291c887e1074ab7f318e031be0ac6" + }, + { + "type": "patch", + "path": "patches/weird_libdecor.patch" + } + ], + "cleanup": [ + "/include", + "/lib/pkgconfig" + ] +} diff --git a/flatpak/org.prismlauncher.PrismLauncher.yml b/flatpak/org.prismlauncher.PrismLauncher.yml index 0524946f0..a9b9762f5 100644 --- a/flatpak/org.prismlauncher.PrismLauncher.yml +++ b/flatpak/org.prismlauncher.PrismLauncher.yml @@ -5,13 +5,6 @@ sdk: org.kde.Sdk sdk-extensions: - org.freedesktop.Sdk.Extension.openjdk17 - org.freedesktop.Sdk.Extension.openjdk8 -add-extensions: - com.valvesoftware.Steam.Utility.gamescope: - version: stable - add-ld-path: lib - no-autodownload: true - autodelete: false - directory: utils/gamescope command: prismlauncher finish-args: @@ -26,21 +19,31 @@ finish-args: # Mod drag&drop - --filesystem=xdg-download:ro +cleanup: + - /lib/libGLU* + modules: + # Might be needed by some Controller mods (see https://github.com/isXander/Controlify/issues/31) + - shared-modules/libusb/libusb.json + + # Needed for proper Wayland support + - libdecor.json + - name: prismlauncher buildsystem: cmake-ninja + builddir: true config-opts: - -DLauncher_BUILD_PLATFORM=flatpak - - -DCMAKE_BUILD_TYPE=Debug + - -DCMAKE_BUILD_TYPE=RelWithDebInfo - -DLauncher_QT_VERSION_MAJOR=5 build-options: env: JAVA_HOME: /usr/lib/sdk/openjdk17/jvm/openjdk-17 JAVA_COMPILER: /usr/lib/sdk/openjdk17/jvm/openjdk-17/bin/javac sources: - - type: dir - path: ../ - builddir: true + - type: dir + path: ../ + - name: openjdk buildsystem: simple build-commands: @@ -49,14 +52,45 @@ modules: - mv /app/jre /app/jdk/17 - /usr/lib/sdk/openjdk8/install.sh - mv /app/jre /app/jdk/8 - cleanup: [/jre] + cleanup: + - /jre + + - name: glfw + buildsystem: cmake-ninja + config-opts: + - -DCMAKE_BUILD_TYPE=RelWithDebInfo + - -DBUILD_SHARED_LIBS:BOOL=ON + - -DGLFW_USE_WAYLAND=ON + sources: + - type: git + url: https://github.com/glfw/glfw.git + commit: 3fa2360720eeba1964df3c0ecf4b5df8648a8e52 + - type: patch + path: patches/0003-Don-t-crash-on-calls-to-focus-or-icon.patch + - type: patch + path: patches/0005-Add-warning-about-being-an-unofficial-patch.patch + - type: patch + path: patches/0007-Platform-Prefer-Wayland-over-X11.patch + cleanup: + - /include + - /lib/cmake + - /lib/pkgconfig + - name: xrandr buildsystem: autotools sources: - type: archive - url: https://xorg.freedesktop.org/archive/individual/app/xrandr-1.5.1.tar.xz - sha256: 7bc76daf9d72f8aff885efad04ce06b90488a1a169d118dea8a2b661832e8762 - cleanup: [/share/man, /bin/xkeystone] + url: https://xorg.freedesktop.org/archive/individual/app/xrandr-1.5.2.tar.xz + sha256: c8bee4790d9058bacc4b6246456c58021db58a87ddda1a9d0139bf5f18f1f240 + x-checker-data: + type: anitya + project-id: 14957 + stable-only: true + url-template: https://xorg.freedesktop.org/archive/individual/app/xrandr-$version.tar.xz + cleanup: + - /share/man + - /bin/xkeystone + - name: gamemode buildsystem: meson config-opts: @@ -67,19 +101,56 @@ modules: # post-install is running inside the build dir, we need it from the source though - install -Dm755 ../data/gamemoderun -t /app/bin sources: - - type: git - url: https://github.com/FeralInteractive/gamemode - tag: "1.7" - commit: 4dc99dff76218718763a6b07fc1900fa6d1dafd9 + - type: archive + archive-type: tar-gzip + url: https://api.github.com/repos/FeralInteractive/gamemode/tarball/1.7 + sha256: 57ce73ba605d1cf12f8d13725006a895182308d93eba0f69f285648449641803 + x-checker-data: + type: json + url: https://api.github.com/repos/FeralInteractive/gamemode/releases/latest + version-query: .tag_name + url-query: .tarball_url + timestamp-query: .published_at + cleanup: + - /include + - /lib/pkgconfig + - /lib/libgamemodeauto.a + + - name: glxinfo + buildsystem: meson + config-opts: + - --bindir=/app/mesa-demos + - -Degl=disabled + - -Dglut=disabled + - -Dosmesa=disabled + - -Dvulkan=disabled + - -Dwayland=disabled + post-install: + - mv -v /app/mesa-demos/glxinfo /app/bin + sources: + - type: archive + url: https://archive.mesa3d.org/demos/mesa-demos-9.0.0.tar.xz + sha256: 3046a3d26a7b051af7ebdd257a5f23bfeb160cad6ed952329cdff1e9f1ed496b + x-checker-data: + type: anitya + project-id: 16781 + stable-only: true + url-template: https://archive.mesa3d.org/demos/mesa-demos-$version.tar.xz + cleanup: + - /include + - /mesa-demos + - /share + modules: + - shared-modules/glu/glu-9.json + - name: enhance buildsystem: simple build-commands: - - mkdir -p /app/utils/gamescope - install -Dm755 prime-run /app/bin/prime-run - mv /app/bin/prismlauncher /app/bin/prismrun - install -Dm755 prismlauncher /app/bin/prismlauncher sources: - type: file - path: ../flatpak/prime-run + path: prime-run - type: file - path: ../flatpak/prismlauncher + path: prismlauncher diff --git a/flatpak/patches/0003-Don-t-crash-on-calls-to-focus-or-icon.patch b/flatpak/patches/0003-Don-t-crash-on-calls-to-focus-or-icon.patch new file mode 100644 index 000000000..9130e856c --- /dev/null +++ b/flatpak/patches/0003-Don-t-crash-on-calls-to-focus-or-icon.patch @@ -0,0 +1,24 @@ +diff --git a/src/wl_window.c b/src/wl_window.c +index 52d3b9eb..4ac4eb5d 100644 +--- a/src/wl_window.c ++++ b/src/wl_window.c +@@ -2117,8 +2117,7 @@ void _glfwSetWindowTitleWayland(_GLFWwindow* window, const char* title) + void _glfwSetWindowIconWayland(_GLFWwindow* window, + int count, const GLFWimage* images) + { +- _glfwInputError(GLFW_FEATURE_UNAVAILABLE, +- "Wayland: The platform does not support setting the window icon"); ++ fprintf(stderr, "!!! Ignoring Error: Wayland: The platform does not support setting the window icon\n"); + } + + void _glfwGetWindowPosWayland(_GLFWwindow* window, int* xpos, int* ypos) +@@ -2361,8 +2360,7 @@ void _glfwRequestWindowAttentionWayland(_GLFWwindow* window) + + void _glfwFocusWindowWayland(_GLFWwindow* window) + { +- _glfwInputError(GLFW_FEATURE_UNAVAILABLE, +- "Wayland: The platform does not support setting the input focus"); ++ fprintf(stderr, "!!! Ignoring Error: Wayland: The platform does not support setting the input focus\n"); + } + + void _glfwSetWindowMonitorWayland(_GLFWwindow* window, diff --git a/flatpak/patches/0005-Add-warning-about-being-an-unofficial-patch.patch b/flatpak/patches/0005-Add-warning-about-being-an-unofficial-patch.patch new file mode 100644 index 000000000..b031d739f --- /dev/null +++ b/flatpak/patches/0005-Add-warning-about-being-an-unofficial-patch.patch @@ -0,0 +1,17 @@ +diff --git a/src/init.c b/src/init.c +index 06dbb3f2..a7c6da86 100644 +--- a/src/init.c ++++ b/src/init.c +@@ -449,6 +449,12 @@ GLFWAPI int glfwInit(void) + _glfw.initialized = GLFW_TRUE; + + glfwDefaultWindowHints(); ++ ++ fprintf(stderr, "!!! Patched GLFW from https://github.com/Admicos/minecraft-wayland\n" ++ "!!! If any issues with the window, or some issues with rendering, occur, " ++ "first try with the built-in GLFW, and if that solves the issue, report there first.\n" ++ "!!! Use outside Minecraft is untested, and things might break.\n"); ++ + return GLFW_TRUE; + } + diff --git a/flatpak/patches/0007-Platform-Prefer-Wayland-over-X11.patch b/flatpak/patches/0007-Platform-Prefer-Wayland-over-X11.patch new file mode 100644 index 000000000..4eeb81309 --- /dev/null +++ b/flatpak/patches/0007-Platform-Prefer-Wayland-over-X11.patch @@ -0,0 +1,20 @@ +diff --git a/src/platform.c b/src/platform.c +index c5966ae7..3e7442f9 100644 +--- a/src/platform.c ++++ b/src/platform.c +@@ -49,12 +49,12 @@ static const struct + #if defined(_GLFW_COCOA) + { GLFW_PLATFORM_COCOA, _glfwConnectCocoa }, + #endif +-#if defined(_GLFW_X11) +- { GLFW_PLATFORM_X11, _glfwConnectX11 }, +-#endif + #if defined(_GLFW_WAYLAND) + { GLFW_PLATFORM_WAYLAND, _glfwConnectWayland }, + #endif ++#if defined(_GLFW_X11) ++ { GLFW_PLATFORM_X11, _glfwConnectX11 }, ++#endif + }; + + GLFWbool _glfwSelectPlatform(int desiredID, _GLFWplatform* platform) diff --git a/flatpak/patches/weird_libdecor.patch b/flatpak/patches/weird_libdecor.patch new file mode 100644 index 000000000..3a400b820 --- /dev/null +++ b/flatpak/patches/weird_libdecor.patch @@ -0,0 +1,40 @@ +diff --git a/src/libdecor.c b/src/libdecor.c +index a9c1106..1aa38b3 100644 +--- a/src/libdecor.c ++++ b/src/libdecor.c +@@ -1391,22 +1391,32 @@ calculate_priority(const struct libdecor_plugin_description *plugin_description) + static bool + check_symbol_conflicts(const struct libdecor_plugin_description *plugin_description) + { ++ bool ret = true; + char * const *symbol; ++ void* main_prog = dlopen(NULL, RTLD_LAZY); ++ if (!main_prog) { ++ fprintf(stderr, "Plugin \"%s\" couldn't check conflicting symbols: \"%s\".\n", ++ plugin_description->description, dlerror()); ++ return false; ++ } ++ + + symbol = plugin_description->conflicting_symbols; + while (*symbol) { + dlerror(); +- dlsym (RTLD_DEFAULT, *symbol); ++ dlsym (main_prog, *symbol); + if (!dlerror()) { + fprintf(stderr, "Plugin \"%s\" uses conflicting symbol \"%s\".\n", + plugin_description->description, *symbol); +- return false; ++ ret = false; ++ break; + } + + symbol++; + } + +- return true; ++ dlclose(main_prog); ++ return ret; + } + + static struct plugin_loader * diff --git a/flatpak/prismlauncher b/flatpak/prismlauncher index bb8767113..039d890d2 100644 --- a/flatpak/prismlauncher +++ b/flatpak/prismlauncher @@ -5,7 +5,7 @@ for i in {0..9}; do test -S "$XDG_RUNTIME_DIR"/discord-ipc-"$i" || ln -sf {app/com.discordapp.Discord,"$XDG_RUNTIME_DIR"}/discord-ipc-"$i"; done -export PATH="${PATH}${PATH:+:}/app/utils/gamescope/bin:/usr/lib/extensions/vulkan/MangoHud/bin" -export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}${LD_LIBRARY_PATH:+:}/usr/lib/extensions/vulkan/MangoHud/\$LIB/" +export PATH="${PATH}${PATH:+:}/usr/lib/extensions/vulkan/gamescope/bin:/usr/lib/extensions/vulkan/MangoHud/bin" +export VK_LAYER_PATH="/usr/lib/extensions/vulkan/share/vulkan/implicit_layer.d/" exec /app/bin/prismrun "$@" diff --git a/flatpak/shared-modules b/flatpak/shared-modules new file mode 160000 index 000000000..45094ca57 --- /dev/null +++ b/flatpak/shared-modules @@ -0,0 +1 @@ +Subproject commit 45094ca570be383d06df729b6972830ec63bd3df From f8fcb98c6837c0bf66c2175ea98198449c36b165 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Tue, 18 Jul 2023 09:06:49 +0200 Subject: [PATCH 68/72] fix: generate predictable UUIDs for offline accounts Signed-off-by: Sefa Eyeoglu --- launcher/minecraft/auth/MinecraftAccount.cpp | 32 +++++++++++++++++++- launcher/minecraft/auth/MinecraftAccount.h | 2 ++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/launcher/minecraft/auth/MinecraftAccount.cpp b/launcher/minecraft/auth/MinecraftAccount.cpp index 3b050ac0f..d7b061e5e 100644 --- a/launcher/minecraft/auth/MinecraftAccount.cpp +++ b/launcher/minecraft/auth/MinecraftAccount.cpp @@ -37,6 +37,7 @@ #include "MinecraftAccount.h" +#include #include #include #include @@ -100,7 +101,7 @@ MinecraftAccountPtr MinecraftAccount::createOffline(const QString &username) account->data.yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]")); account->data.minecraftEntitlement.ownsMinecraft = true; account->data.minecraftEntitlement.canPlayMinecraft = true; - account->data.minecraftProfile.id = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]")); + account->data.minecraftProfile.id = uuidFromUsername(username).toString().remove(QRegularExpression("[{}-]")); account->data.minecraftProfile.name = username; account->data.minecraftProfile.validity = Katabasis::Validity::Certain; return account; @@ -334,3 +335,32 @@ void MinecraftAccount::incrementUses() qWarning() << "Profile" << data.profileId() << "is now in use."; } } + +QUuid MinecraftAccount::uuidFromUsername(QString username) { + auto input = QString("OfflinePlayer:%1").arg(username).toUtf8(); + + // basically a reimplementation of Java's UUID#nameUUIDFromBytes + QByteArray digest = QCryptographicHash::hash(input, QCryptographicHash::Md5); + +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + auto bOr = [](QByteArray& array, int index, char value) { + array[index] = array.at(index) | value; + }; + auto bAnd = [](QByteArray& array, int index, char value) { + array[index] = array.at(index) & value; + }; +#else + auto bOr = [](QByteArray& array, qsizetype index, char value) { + array[index] |= value; + }; + auto bAnd = [](QByteArray& array, qsizetype index, char value) { + array[index] &= value; + }; +#endif + bAnd(digest, 6, (char) 0x0f); // clear version + bOr(digest, 6, (char) 0x30); // set to version 3 + bAnd(digest, 8, (char) 0x3f); // clear variant + bOr(digest, 8, (char) 0x80); // set to IETF variant + + return QUuid::fromRfc4122(digest); +} diff --git a/launcher/minecraft/auth/MinecraftAccount.h b/launcher/minecraft/auth/MinecraftAccount.h index 0dcaeb531..67623a5ab 100644 --- a/launcher/minecraft/auth/MinecraftAccount.h +++ b/launcher/minecraft/auth/MinecraftAccount.h @@ -98,6 +98,8 @@ public: /* construction */ static MinecraftAccountPtr loadFromJsonV2(const QJsonObject &json); static MinecraftAccountPtr loadFromJsonV3(const QJsonObject &json); + static QUuid uuidFromUsername(QString username); + //! Saves a MinecraftAccount to a JSON object and returns it. QJsonObject saveToJson() const; From 391497645ff2054dbc1eac48c8bc49133b86b319 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 18 Jul 2023 22:33:39 +0300 Subject: [PATCH 69/72] feat:made flame instace creation use metadata for recommended version Signed-off-by: Trial97 --- .../flame/FlameInstanceCreationTask.cpp | 116 ++++++++++++------ .../flame/FlameInstanceCreationTask.h | 6 +- 2 files changed, 80 insertions(+), 42 deletions(-) diff --git a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp index b57db288a..710ec06ac 100644 --- a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp +++ b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp @@ -57,15 +57,11 @@ #include #include +#include "meta/Index.h" +#include "meta/VersionList.h" #include "minecraft/World.h" #include "minecraft/mod/tasks/LocalResourceParse.h" - -const static QMap forgemap = { { "1.2.5", "3.4.9.171" }, - { "1.4.2", "6.0.1.355" }, - { "1.4.7", "6.6.2.534" }, - { "1.5.2", "7.8.1.737" } }; - static const FlameAPI api; bool FlameCreationTask::abort() @@ -259,6 +255,51 @@ bool FlameCreationTask::updateInstance() return false; } +QString FlameCreationTask::getVersionForLoader(QString uid, QString loaderType, QString version, QString mcVersion) +{ + if (version == "recommended") { + auto vlist = APPLICATION->metadataIndex()->get(uid); + if (!vlist) { + setError(tr("Failed to get local metadata index for %1").arg(uid)); + return Q_NULLPTR; + } + + if (!vlist->isLoaded()) { + vlist->load(Net::Mode::Online); + } + + for (int i = 0; i < vlist->versions().size(); i++) { + auto version = vlist->versions().at(i); + // first recommended build we find, we use. + if (!version->isRecommended()) + continue; + auto reqs = version->requiredSet(); + + // filter by minecraft version, if the loader depends on a certain version. + // not all mod loaders depend on a given Minecraft version, so we won't do this + // filtering for those loaders. + if (loaderType == "forge") { + auto iter = std::find_if(reqs.begin(), reqs.end(), [mcVersion](const Meta::Require& req) { + return req.uid == "net.minecraft" && req.equalsVersion == mcVersion; + }); + if (iter == reqs.end()) + continue; + } + return version->descriptor(); + } + + setError(tr("Failed to find version for %1 loader").arg(loaderType)); + return Q_NULLPTR; + } + + if (version == Q_NULLPTR || version.isEmpty()) { + emitFailed(tr("No loader version set for modpack!")); + return Q_NULLPTR; + } + + return version; +} + bool FlameCreationTask::createInstance() { QEventLoop loop; @@ -297,22 +338,29 @@ bool FlameCreationTask::createInstance() } } - QString forgeVersion; - QString fabricVersion; - // TODO: is Quilt relevant here? + QString loaderType; + QString loaderUid; + QString loaderVersion; + for (auto& loader : m_pack.minecraft.modLoaders) { auto id = loader.id; if (id.startsWith("forge-")) { id.remove("forge-"); - forgeVersion = id; - continue; - } - if (id.startsWith("fabric-")) { + loaderType = "forge"; + loaderUid = "net.minecraftforge"; + } else if (loaderType == "fabric") { id.remove("fabric-"); - fabricVersion = id; + loaderType = "fabric"; + loaderUid = "net.fabricmc.fabric-loader"; + } else if (loaderType == "quilt") { + id.remove("quilt-"); + loaderType = "quilt"; + loaderUid = "org.quiltmc.quilt-loader"; + } else { + logWarning(tr("Unknown mod loader in manifest: %1").arg(id)); continue; } - logWarning(tr("Unknown mod loader in manifest: %1").arg(id)); + loaderVersion = id; } QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg"); @@ -329,19 +377,12 @@ bool FlameCreationTask::createInstance() auto components = instance.getPackProfile(); components->buildingFromScratch(); components->setComponentVersion("net.minecraft", mcVersion, true); - if (!forgeVersion.isEmpty()) { - // FIXME: dirty, nasty, hack. Proper solution requires dependency resolution and knowledge of the metadata. - if (forgeVersion == "recommended") { - if (forgemap.contains(mcVersion)) { - forgeVersion = forgemap[mcVersion]; - } else { - logWarning(tr("Could not map recommended Forge version for Minecraft %1").arg(mcVersion)); - } - } - components->setComponentVersion("net.minecraftforge", forgeVersion); + if (!loaderType.isEmpty()) { + auto version = getVersionForLoader(loaderUid, loaderType, loaderVersion, mcVersion); + if (version == Q_NULLPTR || version.isEmpty()) + return false; + components->setComponentVersion(loaderUid, version); } - if (!fabricVersion.isEmpty()) - components->setComponentVersion("net.fabricmc.fabric-loader", fabricVersion); if (m_instIcon != "default") { instance.setIconKey(m_instIcon); @@ -502,7 +543,7 @@ void FlameCreationTask::setupDownloadJob(QEventLoop& loop) m_files_job.reset(); setError(reason); }); - connect(m_files_job.get(), &NetJob::progress, this, [this](qint64 current, qint64 total){ + connect(m_files_job.get(), &NetJob::progress, this, [this](qint64 current, qint64 total) { setDetails(tr("%1 out of %2 complete").arg(current).arg(total)); setProgress(current, total); }); @@ -545,7 +586,6 @@ void FlameCreationTask::copyBlockedMods(QList const& blocked_mods) setAbortable(true); } - void FlameCreationTask::validateZIPResouces() { qDebug() << "Validating whether resources stored as .zip are in the right place"; @@ -569,7 +609,7 @@ void FlameCreationTask::validateZIPResouces() return localPath; }; - auto installWorld = [this](QString worldPath){ + auto installWorld = [this](QString worldPath) { qDebug() << "Installing World from" << worldPath; QFileInfo worldFileInfo(worldPath); World w(worldFileInfo); @@ -586,29 +626,29 @@ void FlameCreationTask::validateZIPResouces() QString worldPath; switch (type) { - case PackedResourceType::Mod : + case PackedResourceType::Mod: validatePath(fileName, targetFolder, "mods"); break; - case PackedResourceType::ResourcePack : + case PackedResourceType::ResourcePack: validatePath(fileName, targetFolder, "resourcepacks"); break; - case PackedResourceType::TexturePack : + case PackedResourceType::TexturePack: validatePath(fileName, targetFolder, "texturepacks"); break; - case PackedResourceType::DataPack : + case PackedResourceType::DataPack: validatePath(fileName, targetFolder, "datapacks"); break; - case PackedResourceType::ShaderPack : + case PackedResourceType::ShaderPack: // in theroy flame API can't do this but who knows, that *may* change ? // better to handle it if it *does* occure in the future validatePath(fileName, targetFolder, "shaderpacks"); break; - case PackedResourceType::WorldSave : + case PackedResourceType::WorldSave: worldPath = validatePath(fileName, targetFolder, "saves"); installWorld(worldPath); break; - case PackedResourceType::UNKNOWN : - default : + case PackedResourceType::UNKNOWN: + default: qDebug() << "Can't Identify" << fileName << "at" << localPath << ", leaving it where it is."; break; } diff --git a/launcher/modplatform/flame/FlameInstanceCreationTask.h b/launcher/modplatform/flame/FlameInstanceCreationTask.h index 0ae4735bf..603d3693e 100644 --- a/launcher/modplatform/flame/FlameInstanceCreationTask.h +++ b/launcher/modplatform/flame/FlameInstanceCreationTask.h @@ -57,10 +57,7 @@ class FlameCreationTask final : public InstanceCreationTask { QString id, QString version_id, QString original_instance_id = {}) - : InstanceCreationTask() - , m_parent(parent) - , m_managed_id(std::move(id)) - , m_managed_version_id(std::move(version_id)) + : InstanceCreationTask(), m_parent(parent), m_managed_id(std::move(id)), m_managed_version_id(std::move(version_id)) { setStagingPath(staging_path); setParentSettings(global_settings); @@ -78,6 +75,7 @@ class FlameCreationTask final : public InstanceCreationTask { void setupDownloadJob(QEventLoop&); void copyBlockedMods(QList const& blocked_mods); void validateZIPResouces(); + QString getVersionForLoader(QString uid, QString loaderType, QString version, QString mcVersion); private: QWidget* m_parent = nullptr; From f393aa684e74ca870eb2108e2b74a7c93a70c366 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 18 Jul 2023 23:59:43 +0300 Subject: [PATCH 70/72] wait to load metadata Signed-off-by: Trial97 --- .../flame/FlameInstanceCreationTask.cpp | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp index 710ec06ac..e8453c603 100644 --- a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp +++ b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp @@ -255,17 +255,23 @@ bool FlameCreationTask::updateInstance() return false; } -QString FlameCreationTask::getVersionForLoader(QString uid, QString loaderType, QString version, QString mcVersion) +QString FlameCreationTask::getVersionForLoader(QString uid, QString loaderType, QString loaderVersion, QString mcVersion) { - if (version == "recommended") { + if (loaderVersion == "recommended") { auto vlist = APPLICATION->metadataIndex()->get(uid); if (!vlist) { setError(tr("Failed to get local metadata index for %1").arg(uid)); - return Q_NULLPTR; + return {}; } if (!vlist->isLoaded()) { - vlist->load(Net::Mode::Online); + QEventLoop loadVersionLoop; + auto task = vlist->getLoadTask(); + connect(task.get(), &Task::finished, &loadVersionLoop, &QEventLoop::quit); + if (!task->isRunning()) + task->start(); + + loadVersionLoop.exec(); } for (int i = 0; i < vlist->versions().size(); i++) { @@ -289,15 +295,15 @@ QString FlameCreationTask::getVersionForLoader(QString uid, QString loaderType, } setError(tr("Failed to find version for %1 loader").arg(loaderType)); - return Q_NULLPTR; + return {}; } - if (version == Q_NULLPTR || version.isEmpty()) { + if (loaderVersion.isEmpty()) { emitFailed(tr("No loader version set for modpack!")); - return Q_NULLPTR; + return {}; } - return version; + return loaderVersion; } bool FlameCreationTask::createInstance() @@ -379,7 +385,7 @@ bool FlameCreationTask::createInstance() components->setComponentVersion("net.minecraft", mcVersion, true); if (!loaderType.isEmpty()) { auto version = getVersionForLoader(loaderUid, loaderType, loaderVersion, mcVersion); - if (version == Q_NULLPTR || version.isEmpty()) + if (version.isEmpty()) return false; components->setComponentVersion(loaderUid, version); } From b7bccb905829eebea039a32edf93606f5fc5defa Mon Sep 17 00:00:00 2001 From: Trial97 Date: Wed, 19 Jul 2023 12:27:02 +0300 Subject: [PATCH 71/72] removed subdirectory flag Signed-off-by: Trial97 --- launcher/ui/themes/ThemeManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launcher/ui/themes/ThemeManager.cpp b/launcher/ui/themes/ThemeManager.cpp index 9ed8e1297..321f7db4a 100644 --- a/launcher/ui/themes/ThemeManager.cpp +++ b/launcher/ui/themes/ThemeManager.cpp @@ -84,7 +84,7 @@ void ThemeManager::initializeThemes() QString themeFolder = QDir("./themes/").absoluteFilePath(""); themeDebugLog() << "Theme Folder Path: " << themeFolder; - QDirIterator directoryIterator(themeFolder, QDir::Dirs | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); + QDirIterator directoryIterator(themeFolder, QDir::Dirs | QDir::NoDotAndDotDot); while (directoryIterator.hasNext()) { QDir dir(directoryIterator.next()); QFileInfo themeJson(dir.absoluteFilePath("theme.json")); @@ -208,7 +208,7 @@ void ThemeManager::initializeCatPacks() loadFiles(catpacksDir); - QDirIterator directoryIterator(catpacksFolder, QDir::Dirs | QDir::NoDotAndDotDot, QDirIterator::Subdirectories); + QDirIterator directoryIterator(catpacksFolder, QDir::Dirs | QDir::NoDotAndDotDot); while (directoryIterator.hasNext()) { QDir dir(directoryIterator.next()); QFileInfo manifest(dir.absoluteFilePath("catpack.json")); From f8d9cd9a0344d8afa806e7b3b73e8b3c59315d17 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Wed, 19 Jul 2023 23:08:16 +0300 Subject: [PATCH 72/72] use range for Signed-off-by: Trial97 --- launcher/modplatform/flame/FlameInstanceCreationTask.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp index e8453c603..29145d898 100644 --- a/launcher/modplatform/flame/FlameInstanceCreationTask.cpp +++ b/launcher/modplatform/flame/FlameInstanceCreationTask.cpp @@ -274,8 +274,7 @@ QString FlameCreationTask::getVersionForLoader(QString uid, QString loaderType, loadVersionLoop.exec(); } - for (int i = 0; i < vlist->versions().size(); i++) { - auto version = vlist->versions().at(i); + for (auto version : vlist->versions()) { // first recommended build we find, we use. if (!version->isRecommended()) continue;