Merge branch 'develop' into feat/launcher-updater

Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
This commit is contained in:
TheKodeToad
2023-08-30 11:47:33 +01:00
committed by GitHub
115 changed files with 1296 additions and 793 deletions

View File

@ -44,8 +44,6 @@
#include <QPushButton>
#include <QScrollBar>
#include "ui/dialogs/CustomMessageBox.h"
#include "ui/dialogs/ProgressDialog.h"
#include "ui/widgets/PageContainer.h"
#include "InstancePageProvider.h"
@ -76,40 +74,44 @@ InstanceWindow::InstanceWindow(InstancePtr instance, QWidget* parent) : QMainWin
// Add custom buttons to the page container layout.
{
auto horizontalLayout = new QHBoxLayout();
auto horizontalLayout = new QHBoxLayout(this);
horizontalLayout->setObjectName(QStringLiteral("horizontalLayout"));
horizontalLayout->setContentsMargins(6, -1, 6, -1);
auto btnHelp = new QPushButton();
auto btnHelp = new QPushButton(this);
btnHelp->setText(tr("Help"));
horizontalLayout->addWidget(btnHelp);
connect(btnHelp, SIGNAL(clicked(bool)), m_container, SLOT(help()));
connect(btnHelp, &QPushButton::clicked, m_container, &PageContainer::help);
auto spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
horizontalLayout->addSpacerItem(spacer);
m_killButton = new QPushButton();
m_launchButton = new QToolButton(this);
m_launchButton->setText(tr("&Launch"));
m_launchButton->setToolTip(tr("Launch the instance"));
m_launchButton->setPopupMode(QToolButton::MenuButtonPopup);
m_launchButton->setMinimumWidth(80); // HACK!!
horizontalLayout->addWidget(m_launchButton);
connect(m_launchButton, &QPushButton::clicked, this, [this] { APPLICATION->launch(m_instance); });
m_killButton = new QPushButton(this);
m_killButton->setText(tr("&Kill"));
m_killButton->setToolTip(tr("Kill the running instance"));
m_killButton->setShortcut(QKeySequence(tr("Ctrl+K")));
horizontalLayout->addWidget(m_killButton);
connect(m_killButton, SIGNAL(clicked(bool)), SLOT(on_btnKillMinecraft_clicked()));
connect(m_killButton, &QPushButton::clicked, this, [this] { APPLICATION->kill(m_instance); });
m_launchOfflineButton = new QPushButton();
horizontalLayout->addWidget(m_launchOfflineButton);
m_launchOfflineButton->setText(tr("Launch Offline"));
updateButtons();
m_launchDemoButton = new QPushButton();
horizontalLayout->addWidget(m_launchDemoButton);
m_launchDemoButton->setText(tr("Launch Demo"));
updateLaunchButtons();
connect(m_launchOfflineButton, SIGNAL(clicked(bool)), SLOT(on_btnLaunchMinecraftOffline_clicked()));
connect(m_launchDemoButton, SIGNAL(clicked(bool)), SLOT(on_btnLaunchMinecraftDemo_clicked()));
m_closeButton = new QPushButton();
m_closeButton = new QPushButton(this);
m_closeButton->setText(tr("Close"));
horizontalLayout->addWidget(m_closeButton);
connect(m_closeButton, SIGNAL(clicked(bool)), SLOT(on_closeButton_clicked()));
connect(m_closeButton, &QPushButton::clicked, this, &QMainWindow::close);
m_container->addButtons(horizontalLayout);
connect(m_instance.get(), &BaseInstance::profilerChanged, this, &InstanceWindow::updateButtons);
connect(APPLICATION, &Application::globalSettingsClosed, this, &InstanceWindow::updateButtons);
}
// restore window state
@ -149,47 +151,18 @@ void InstanceWindow::on_instanceStatusChanged(BaseInstance::Status, BaseInstance
}
}
void InstanceWindow::updateLaunchButtons()
void InstanceWindow::updateButtons()
{
if (m_instance->isRunning()) {
m_launchOfflineButton->setEnabled(false);
m_launchDemoButton->setEnabled(false);
m_killButton->setText(tr("Kill"));
m_killButton->setObjectName("killButton");
m_killButton->setToolTip(tr("Kill the running instance"));
} else if (!m_instance->canLaunch()) {
m_launchOfflineButton->setEnabled(false);
m_launchDemoButton->setEnabled(false);
m_killButton->setText(tr("Launch"));
m_killButton->setObjectName("launchButton");
m_killButton->setToolTip(tr("Launch the instance"));
m_killButton->setEnabled(false);
} else {
m_launchOfflineButton->setEnabled(true);
m_launchButton->setEnabled(m_instance->canLaunch());
m_killButton->setEnabled(m_instance->isRunning());
// Disable demo-mode if not available.
auto instance = dynamic_cast<MinecraftInstance*>(m_instance.get());
if (instance) {
m_launchDemoButton->setEnabled(instance->supportsDemo());
}
m_killButton->setText(tr("Launch"));
m_killButton->setObjectName("launchButton");
m_killButton->setToolTip(tr("Launch the instance"));
}
// NOTE: this is a hack to force the button to recalculate its style
m_killButton->setStyleSheet("/* */");
m_killButton->setStyleSheet(QString());
}
void InstanceWindow::on_btnLaunchMinecraftOffline_clicked()
{
APPLICATION->launch(m_instance, false, false, nullptr);
}
void InstanceWindow::on_btnLaunchMinecraftDemo_clicked()
{
APPLICATION->launch(m_instance, false, true, nullptr);
QMenu* launchMenu = m_launchButton->menu();
if (launchMenu)
launchMenu->clear();
else
launchMenu = new QMenu(this);
m_instance->populateLaunchMenu(launchMenu);
m_launchButton->setMenu(launchMenu);
}
void InstanceWindow::instanceLaunchTaskChanged(shared_qobject_ptr<LaunchTask> proc)
@ -199,18 +172,13 @@ void InstanceWindow::instanceLaunchTaskChanged(shared_qobject_ptr<LaunchTask> pr
void InstanceWindow::runningStateChanged(bool running)
{
updateLaunchButtons();
updateButtons();
m_container->refreshContainer();
if (running) {
selectPage("log");
}
}
void InstanceWindow::on_closeButton_clicked()
{
close();
}
void InstanceWindow::closeEvent(QCloseEvent* event)
{
bool proceed = true;
@ -233,15 +201,6 @@ bool InstanceWindow::saveAll()
return m_container->saveAll();
}
void InstanceWindow::on_btnKillMinecraft_clicked()
{
if (m_instance->isRunning()) {
APPLICATION->kill(m_instance);
} else {
APPLICATION->launch(m_instance, true, false, nullptr);
}
}
QString InstanceWindow::instanceId()
{
return m_instance->id();
@ -252,17 +211,15 @@ bool InstanceWindow::selectPage(QString pageId)
return m_container->selectPage(pageId);
}
BasePage* InstanceWindow::selectedPage() const
{
return m_container->selectedPage();
}
void InstanceWindow::refreshContainer()
{
m_container->refreshContainer();
}
InstanceWindow::~InstanceWindow() {}
BasePage* InstanceWindow::selectedPage() const
{
return m_container->selectedPage();
}
bool InstanceWindow::requestClose()
{

View File

@ -38,6 +38,7 @@
#include <QMainWindow>
#include <QSystemTrayIcon>
#include <QToolButton>
#include "LaunchController.h"
#include "launch/LaunchTask.h"
@ -53,7 +54,7 @@ class InstanceWindow : public QMainWindow, public BasePageContainer {
public:
explicit InstanceWindow(InstancePtr proc, QWidget* parent = 0);
virtual ~InstanceWindow();
virtual ~InstanceWindow() = default;
bool selectPage(QString pageId) override;
BasePage* selectedPage() const override;
@ -71,11 +72,6 @@ class InstanceWindow : public QMainWindow, public BasePageContainer {
void isClosing();
private slots:
void on_closeButton_clicked();
void on_btnKillMinecraft_clicked();
void on_btnLaunchMinecraftOffline_clicked();
void on_btnLaunchMinecraftDemo_clicked();
void instanceLaunchTaskChanged(shared_qobject_ptr<LaunchTask> proc);
void runningStateChanged(bool running);
void on_instanceStatusChanged(BaseInstance::Status, BaseInstance::Status newStatus);
@ -84,7 +80,7 @@ class InstanceWindow : public QMainWindow, public BasePageContainer {
void closeEvent(QCloseEvent*) override;
private:
void updateLaunchButtons();
void updateButtons();
private:
shared_qobject_ptr<LaunchTask> m_proc;
@ -92,7 +88,6 @@ class InstanceWindow : public QMainWindow, public BasePageContainer {
bool m_doNotSave = false;
PageContainer* m_container = nullptr;
QPushButton* m_closeButton = nullptr;
QToolButton* m_launchButton = nullptr;
QPushButton* m_killButton = nullptr;
QPushButton* m_launchOfflineButton = nullptr;
QPushButton* m_launchDemoButton = nullptr;
};

View File

@ -43,7 +43,6 @@
#include "FileSystem.h"
#include "MainWindow.h"
#include "ui/dialogs/ExportToModListDialog.h"
#include "ui_MainWindow.h"
#include <QDir>
@ -85,22 +84,19 @@
#include <launch/LaunchTask.h>
#include <minecraft/MinecraftInstance.h>
#include <minecraft/auth/AccountList.h>
#include <net/Download.h>
#include <net/ApiDownload.h>
#include <net/NetJob.h>
#include <news/NewsChecker.h>
#include <tools/BaseProfiler.h>
#include <updater/ExternalUpdater.h>
#include "InstancePageProvider.h"
#include "InstanceWindow.h"
#include "JavaCommon.h"
#include "LaunchController.h"
#include "ui/dialogs/AboutDialog.h"
#include "ui/dialogs/CopyInstanceDialog.h"
#include "ui/dialogs/CustomMessageBox.h"
#include "ui/dialogs/EditAccountDialog.h"
#include "ui/dialogs/ExportInstanceDialog.h"
#include "ui/dialogs/ExportPackDialog.h"
#include "ui/dialogs/ExportToModListDialog.h"
#include "ui/dialogs/IconPickerDialog.h"
#include "ui/dialogs/ImportResourceDialog.h"
#include "ui/dialogs/NewInstanceDialog.h"
@ -113,15 +109,24 @@
#include "ui/themes/ThemeManager.h"
#include "ui/widgets/LabeledToolButton.h"
#include "minecraft/PackProfile.h"
#include "minecraft/VersionFile.h"
#include "minecraft/WorldList.h"
#include "minecraft/mod/ModFolderModel.h"
#include "minecraft/mod/ResourcePackFolderModel.h"
#include "minecraft/mod/ShaderPackFolderModel.h"
#include "minecraft/mod/TexturePackFolderModel.h"
#include "minecraft/mod/tasks/LocalResourceParse.h"
#include "modplatform/ModIndex.h"
#include "modplatform/flame/FlameAPI.h"
#include "modplatform/flame/FlameModIndex.h"
#include "KonamiCode.h"
#include "InstanceCopyTask.h"
#include "InstanceImportTask.h"
#include "Json.h"
#include "MMCTime.h"
@ -549,71 +554,15 @@ void MainWindow::updateMainToolBar()
ui->mainToolBar->setVisible(ui->menuBar->isNativeMenuBar() || !APPLICATION->settings()->get("MenuBarInsteadOfToolBar").toBool());
}
void MainWindow::updateToolsMenu()
void MainWindow::updateLaunchButton()
{
bool currentInstanceRunning = m_selectedInstance && m_selectedInstance->isRunning();
ui->actionLaunchInstance->setDisabled(!m_selectedInstance || currentInstanceRunning);
ui->actionLaunchInstanceOffline->setDisabled(!m_selectedInstance || currentInstanceRunning);
ui->actionLaunchInstanceDemo->setDisabled(!m_selectedInstance || currentInstanceRunning);
QMenu* launchMenu = ui->actionLaunchInstance->menu();
if (launchMenu) {
if (launchMenu)
launchMenu->clear();
} else {
else
launchMenu = new QMenu(this);
}
QAction* normalLaunch = launchMenu->addAction(tr("Launch"));
normalLaunch->setShortcut(QKeySequence::Open);
QAction* normalLaunchOffline = launchMenu->addAction(tr("Launch Offline"));
normalLaunchOffline->setShortcut(QKeySequence(tr("Ctrl+Shift+O")));
QAction* normalLaunchDemo = launchMenu->addAction(tr("Launch Demo"));
normalLaunchDemo->setShortcut(QKeySequence(tr("Ctrl+Alt+O")));
if (m_selectedInstance) {
normalLaunch->setEnabled(m_selectedInstance->canLaunch());
normalLaunchOffline->setEnabled(m_selectedInstance->canLaunch());
normalLaunchDemo->setEnabled(m_selectedInstance->canLaunch());
connect(normalLaunch, &QAction::triggered, [this]() { APPLICATION->launch(m_selectedInstance, true, false); });
connect(normalLaunchOffline, &QAction::triggered, [this]() { APPLICATION->launch(m_selectedInstance, false, false); });
connect(normalLaunchDemo, &QAction::triggered, [this]() { APPLICATION->launch(m_selectedInstance, false, true); });
} else {
normalLaunch->setDisabled(true);
normalLaunchOffline->setDisabled(true);
normalLaunchDemo->setDisabled(true);
}
// Disable demo-mode if not available.
auto instance = dynamic_cast<MinecraftInstance*>(m_selectedInstance.get());
if (instance) {
normalLaunchDemo->setEnabled(instance->supportsDemo());
}
QString profilersTitle = tr("Profilers");
launchMenu->addSeparator()->setText(profilersTitle);
for (auto profiler : APPLICATION->profilers().values()) {
QAction* profilerAction = launchMenu->addAction(profiler->name());
QAction* profilerOfflineAction = launchMenu->addAction(tr("%1 Offline").arg(profiler->name()));
QString error;
if (!profiler->check(&error)) {
profilerAction->setDisabled(true);
profilerOfflineAction->setDisabled(true);
QString profilerToolTip = tr("Profiler not setup correctly. Go into settings, \"External Tools\".");
profilerAction->setToolTip(profilerToolTip);
profilerOfflineAction->setToolTip(profilerToolTip);
} else if (m_selectedInstance) {
profilerAction->setEnabled(m_selectedInstance->canLaunch());
profilerOfflineAction->setEnabled(m_selectedInstance->canLaunch());
connect(profilerAction, &QAction::triggered,
[this, profiler]() { APPLICATION->launch(m_selectedInstance, true, false, profiler.get()); });
connect(profilerOfflineAction, &QAction::triggered,
[this, profiler]() { APPLICATION->launch(m_selectedInstance, false, false, profiler.get()); });
} else {
profilerAction->setDisabled(true);
profilerOfflineAction->setDisabled(true);
}
}
if (m_selectedInstance)
m_selectedInstance->populateLaunchMenu(launchMenu);
ui->actionLaunchInstance->setMenu(launchMenu);
}
@ -924,13 +873,13 @@ void MainWindow::finalizeInstance(InstancePtr inst)
} else {
CustomMessageBox::selectable(this, tr("Error"),
tr("The launcher cannot download Minecraft or update instances unless you have at least "
"one account added.\nPlease add your Mojang or Minecraft account."),
"one account added.\nPlease add your Microsoft or Mojang account."),
QMessageBox::Warning)
->show();
}
}
void MainWindow::addInstance(QString url)
void MainWindow::addInstance(const QString& url, const QMap<QString, QString>& extra_info)
{
QString groupName;
do {
@ -950,7 +899,7 @@ void MainWindow::addInstance(QString url)
groupName = APPLICATION->settings()->get("LastUsedGroupForNewInstance").toString();
}
NewInstanceDialog newInstDlg(groupName, url, this);
NewInstanceDialog newInstDlg(groupName, url, extra_info, this);
if (!newInstDlg.exec())
return;
@ -977,18 +926,105 @@ void MainWindow::processURLs(QList<QUrl> urls)
if (url.scheme().isEmpty())
url.setScheme("file");
if (!url.isLocalFile()) { // probably instance/modpack
addInstance(url.toString());
break;
ModPlatform::IndexedVersion version;
QMap<QString, QString> extra_info;
QUrl local_url;
if (!url.isLocalFile()) { // download the remote resource and identify
QUrl dl_url;
if (url.scheme() == "curseforge") {
// need to find the download link for the modpack / resource
// format of url curseforge://install?addonId=IDHERE&fileId=IDHERE
QUrlQuery query(url);
if (query.allQueryItemValues("addonId").isEmpty() || query.allQueryItemValues("fileId").isEmpty()) {
qDebug() << "Invalid curseforge link:" << url;
continue;
}
auto addonId = query.allQueryItemValues("addonId")[0];
auto fileId = query.allQueryItemValues("fileId")[0];
extra_info.insert("pack_id", addonId);
extra_info.insert("pack_version_id", fileId);
auto array = std::make_shared<QByteArray>();
auto api = FlameAPI();
auto job = api.getFile(addonId, fileId, array);
connect(job.get(), &Task::failed, this,
[this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show(); });
connect(job.get(), &Task::succeeded, this, [this, array, addonId, fileId, &dl_url, &version] {
qDebug() << "Returned CFURL Json:\n" << array->toStdString().c_str();
auto doc = Json::requireDocument(*array);
auto data = Json::ensureObject(Json::ensureObject(doc.object()), "data");
// No way to find out if it's a mod or a modpack before here
// And also we need to check if it ends with .zip, instead of any better way
version = FlameMod::loadIndexedPackVersion(data);
auto fileName = version.fileName;
// Have to use ensureString then use QUrl to get proper url encoding
dl_url = QUrl(version.downloadUrl);
if (!dl_url.isValid()) {
CustomMessageBox::selectable(
this, tr("Error"),
tr("The modpack, mod, or resource %1 is blocked for third-parties! Please download it manually.").arg(fileName),
QMessageBox::Critical)
->show();
return;
}
QFileInfo dl_file(dl_url.fileName());
});
{ // drop stack
ProgressDialog dlUrlDialod(this);
dlUrlDialod.setSkipButton(true, tr("Abort"));
dlUrlDialod.execWithTask(job.get());
}
} else {
dl_url = url;
}
if (!dl_url.isValid()) {
continue; // no valid url to download this resource
}
const QString path = dl_url.host() + '/' + dl_url.path();
auto entry = APPLICATION->metacache()->resolveEntry("general", path);
entry->setStale(true);
auto dl_job = unique_qobject_ptr<NetJob>(new NetJob(tr("Modpack download"), APPLICATION->network()));
dl_job->addNetAction(Net::ApiDownload::makeCached(dl_url, entry));
auto archivePath = entry->getFullPath();
bool dl_success = false;
connect(dl_job.get(), &Task::failed, this,
[this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show(); });
connect(dl_job.get(), &Task::succeeded, this, [&dl_success] { dl_success = true; });
{ // drop stack
ProgressDialog dlUrlDialod(this);
dlUrlDialod.setSkipButton(true, tr("Abort"));
dlUrlDialod.execWithTask(dl_job.get());
}
if (!dl_success) {
continue; // no local file to identify
}
local_url = QUrl::fromLocalFile(archivePath);
} else {
local_url = url;
}
auto localFileName = QDir::toNativeSeparators(url.toLocalFile());
auto localFileName = QDir::toNativeSeparators(local_url.toLocalFile());
QFileInfo localFileInfo(localFileName);
auto type = ResourceUtils::identify(localFileInfo);
if (ResourceUtils::ValidResourceTypes.count(type) == 0) { // probably instance/modpack
addInstance(localFileName);
addInstance(localFileName, extra_info);
continue;
}
@ -1013,7 +1049,7 @@ void MainWindow::processURLs(QList<QUrl> urls)
qWarning() << "Importing of Data Packs not supported at this time. Ignoring" << localFileName;
break;
case PackedResourceType::Mod:
minecraftInst->loaderModList()->installMod(localFileName);
minecraftInst->loaderModList()->installMod(localFileName, version);
break;
case PackedResourceType::ShaderPack:
minecraftInst->shaderPackList()->installResource(localFileName);
@ -1193,7 +1229,7 @@ void MainWindow::globalSettingsClosed()
proxymodel->invalidate();
proxymodel->sort(0);
updateMainToolBar();
updateToolsMenu();
updateLaunchButton();
updateThemeMenu();
updateStatusCenter();
// This needs to be done to prevent UI elements disappearing in the event the config is changed
@ -1323,10 +1359,11 @@ void MainWindow::on_actionDeleteInstance_triggered()
if (APPLICATION->instances()->trashInstance(id)) {
ui->actionUndoTrashInstance->setEnabled(APPLICATION->instances()->trashedSomething());
return;
} else {
APPLICATION->instances()->deleteInstance(id);
}
APPLICATION->instances()->deleteInstance(id);
APPLICATION->settings()->set("SelectedInstance", QString());
selectionBad();
}
void MainWindow::on_actionExportInstanceZip_triggered()
@ -1428,20 +1465,6 @@ void MainWindow::activateInstance(InstancePtr instance)
APPLICATION->launch(instance);
}
void MainWindow::on_actionLaunchInstanceOffline_triggered()
{
if (m_selectedInstance) {
APPLICATION->launch(m_selectedInstance, false);
}
}
void MainWindow::on_actionLaunchInstanceDemo_triggered()
{
if (m_selectedInstance) {
APPLICATION->launch(m_selectedInstance, false, true);
}
}
void MainWindow::on_actionKillInstance_triggered()
{
if (m_selectedInstance && m_selectedInstance->isRunning()) {
@ -1615,6 +1638,7 @@ void MainWindow::instanceChanged(const QModelIndex& current, [[maybe_unused]] co
}
if (m_selectedInstance) {
disconnect(m_selectedInstance.get(), &BaseInstance::runningStatusChanged, this, &MainWindow::refreshCurrentInstance);
disconnect(m_selectedInstance.get(), &BaseInstance::profilerChanged, this, &MainWindow::refreshCurrentInstance);
}
QString id = current.data(InstanceList::InstanceIDRole).toString();
m_selectedInstance = APPLICATION->instances()->getInstanceById(id);
@ -1622,14 +1646,6 @@ void MainWindow::instanceChanged(const QModelIndex& current, [[maybe_unused]] co
ui->instanceToolBar->setEnabled(true);
setInstanceActionsEnabled(true);
ui->actionLaunchInstance->setEnabled(m_selectedInstance->canLaunch());
ui->actionLaunchInstanceOffline->setEnabled(m_selectedInstance->canLaunch());
ui->actionLaunchInstanceDemo->setEnabled(m_selectedInstance->canLaunch());
// Disable demo-mode if not available.
auto instance = dynamic_cast<MinecraftInstance*>(m_selectedInstance.get());
if (instance) {
ui->actionLaunchInstanceDemo->setEnabled(instance->supportsDemo());
}
ui->actionKillInstance->setEnabled(m_selectedInstance->isRunning());
ui->actionExportInstance->setEnabled(m_selectedInstance->canExport());
@ -1638,18 +1654,13 @@ void MainWindow::instanceChanged(const QModelIndex& current, [[maybe_unused]] co
updateStatusCenter();
updateInstanceToolIcon(m_selectedInstance->iconKey());
updateToolsMenu();
updateLaunchButton();
APPLICATION->settings()->set("SelectedInstance", m_selectedInstance->id());
connect(m_selectedInstance.get(), &BaseInstance::runningStatusChanged, this, &MainWindow::refreshCurrentInstance);
connect(m_selectedInstance.get(), &BaseInstance::profilerChanged, this, &MainWindow::refreshCurrentInstance);
} else {
ui->instanceToolBar->setEnabled(false);
setInstanceActionsEnabled(false);
ui->actionLaunchInstance->setEnabled(false);
ui->actionLaunchInstanceOffline->setEnabled(false);
ui->actionLaunchInstanceDemo->setEnabled(false);
ui->actionKillInstance->setEnabled(false);
APPLICATION->settings()->set("SelectedInstance", QString());
selectionBad();
return;
@ -1674,11 +1685,12 @@ void MainWindow::selectionBad()
{
// start by reseting everything...
m_selectedInstance = nullptr;
m_statusLeft->setText(tr("No instance selected"));
statusBar()->clearMessage();
ui->instanceToolBar->setEnabled(false);
setInstanceActionsEnabled(false);
updateToolsMenu();
updateLaunchButton();
renameButton->setText(tr("Rename Instance"));
updateInstanceToolIcon("grass");
@ -1725,7 +1737,9 @@ void MainWindow::updateStatusCenter()
int timePlayed = APPLICATION->instances()->getTotalPlayTime();
if (timePlayed > 0) {
m_statusCenter->setText(tr("Total playtime: %1").arg(Time::prettifyDuration(timePlayed)));
m_statusCenter->setText(
tr("Total playtime: %1")
.arg(Time::prettifyDuration(timePlayed, APPLICATION->settings()->get("ShowGameTimeWithoutDays").toBool())));
}
}
// "Instance actions" are actions that require an instance to be selected (i.e. "new instance" is not here)
@ -1741,7 +1755,7 @@ void MainWindow::setInstanceActionsEnabled(bool enabled)
ui->actionCreateInstanceShortcut->setEnabled(enabled);
}
void MainWindow::refreshCurrentInstance([[maybe_unused]] bool running)
void MainWindow::refreshCurrentInstance()
{
auto current = view->selectionModel()->currentIndex();
instanceChanged(current, current);

View File

@ -144,10 +144,6 @@ class MainWindow : public QMainWindow {
void on_actionLaunchInstance_triggered();
void on_actionLaunchInstanceOffline_triggered();
void on_actionLaunchInstanceDemo_triggered();
void on_actionKillInstance_triggered();
void on_actionDeleteInstance_triggered();
@ -155,10 +151,7 @@ class MainWindow : public QMainWindow {
void deleteGroup();
void undoTrashInstance();
inline void on_actionExportInstance_triggered()
{
on_actionExportInstanceZip_triggered();
}
inline void on_actionExportInstance_triggered() { on_actionExportInstanceZip_triggered(); }
void on_actionExportInstanceZip_triggered();
void on_actionExportInstanceMrPack_triggered();
void on_actionExportInstanceFlamePack_triggered();
@ -181,7 +174,7 @@ class MainWindow : public QMainWindow {
void updateMainToolBar();
void updateToolsMenu();
void updateLaunchButton();
void updateThemeMenu();
@ -215,12 +208,12 @@ class MainWindow : public QMainWindow {
void keyReleaseEvent(QKeyEvent* event) override;
#endif
void refreshCurrentInstance(bool running);
void refreshCurrentInstance();
private:
void retranslateUi();
void addInstance(QString url = QString());
void addInstance(const QString& url = QString(), const QMap<QString, QString>& extra_info = {});
void activateInstance(InstancePtr instance);
void setCatBackground(bool enabled);
void updateInstanceToolIcon(QString new_icon);

View File

@ -440,22 +440,6 @@
<string>Ctrl+D</string>
</property>
</action>
<action name="actionLaunchInstanceOffline">
<property name="text">
<string>Launch &amp;Offline</string>
</property>
<property name="toolTip">
<string>Launch the selected instance in offline mode.</string>
</property>
</action>
<action name="actionLaunchInstanceDemo">
<property name="text">
<string>Launch &amp;Demo</string>
</property>
<property name="toolTip">
<string>Launch the selected instance in demo mode.</string>
</property>
</action>
<action name="actionExportInstance">
<property name="icon">
<iconset theme="export">

View File

@ -37,15 +37,21 @@
ExportPackDialog::ExportPackDialog(InstancePtr instance, QWidget* parent, ModPlatform::ResourceProvider provider)
: QDialog(parent), instance(instance), ui(new Ui::ExportPackDialog), m_provider(provider)
{
Q_ASSERT(m_provider == ModPlatform::ResourceProvider::MODRINTH || m_provider == ModPlatform::ResourceProvider::FLAME);
ui->setupUi(this);
ui->name->setText(instance->name());
ui->name->setPlaceholderText(instance->name());
ui->name->setText(instance->settings()->get("ExportName").toString());
ui->version->setText(instance->settings()->get("ExportVersion").toString());
ui->optionalFiles->setChecked(instance->settings()->get("ExportOptionalFiles").toBool());
if (m_provider == ModPlatform::ResourceProvider::MODRINTH) {
ui->summary->setText(instance->notes().split(QRegularExpression("\\r?\\n"))[0]);
setWindowTitle("Export Modrinth Pack");
setWindowTitle(tr("Export Modrinth Pack"));
ui->summary->setText(instance->settings()->get("ExportSummary").toString());
} else {
setWindowTitle("Export CurseForge Pack");
ui->version->setText("");
ui->summaryLabel->setText("Author");
setWindowTitle(tr("Export CurseForge Pack"));
ui->summaryLabel->setText(tr("&Author"));
ui->summary->setText(instance->settings()->get("ExportAuthor").toString());
}
// ensure a valid pack is generated
@ -75,20 +81,19 @@ ExportPackDialog::ExportPackDialog(InstancePtr instance, QWidget* parent, ModPla
MinecraftInstance* mcInstance = dynamic_cast<MinecraftInstance*>(instance.get());
if (mcInstance) {
mcInstance->loaderModList()->update();
const QDir index = mcInstance->loaderModList()->indexDir();
if (index.exists())
proxy->blockedPaths().insert(root.relativeFilePath(index.absolutePath()));
proxy->ignoreFilesWithPath().insert(root.relativeFilePath(index.absolutePath()));
}
ui->treeView->setModel(proxy);
ui->treeView->setRootIndex(proxy->mapFromSource(model->index(instance->gameRoot())));
ui->treeView->sortByColumn(0, Qt::AscendingOrder);
ui->files->setModel(proxy);
ui->files->setRootIndex(proxy->mapFromSource(model->index(instance->gameRoot())));
ui->files->sortByColumn(0, Qt::AscendingOrder);
model->setFilter(filter);
model->setRootPath(instance->gameRoot());
QHeaderView* headerView = ui->treeView->header();
QHeaderView* headerView = ui->files->header();
headerView->setSectionResizeMode(QHeaderView::ResizeToContents);
headerView->setSectionResizeMode(0, QHeaderView::Stretch);
}
@ -100,26 +105,41 @@ ExportPackDialog::~ExportPackDialog()
void ExportPackDialog::done(int result)
{
if (result == Accepted) {
const QString filename = FS::RemoveInvalidFilenameChars(ui->name->text());
QString output;
if (m_provider == ModPlatform::ResourceProvider::MODRINTH)
output = QFileDialog::getSaveFileName(this, tr("Export %1").arg(ui->name->text()),
FS::PathCombine(QDir::homePath(), filename + ".mrpack"), "Modrinth pack (*.mrpack *.zip)",
nullptr);
else
output = QFileDialog::getSaveFileName(this, tr("Export %1").arg(ui->name->text()),
FS::PathCombine(QDir::homePath(), filename + ".zip"), "CurseForge pack (*.zip)", nullptr);
auto settings = instance->settings();
settings->set("ExportName", ui->name->text());
settings->set("ExportVersion", ui->version->text());
settings->set(m_provider == ModPlatform::ResourceProvider::FLAME ? "ExportAuthor" : "ExportSummary", ui->summary->text());
settings->set("ExportOptionalFiles", ui->optionalFiles->isChecked());
if (result == Accepted) {
const QString name = ui->name->text().isEmpty() ? instance->name() : ui->name->text();
const QString filename = FS::RemoveInvalidFilenameChars(name);
QString output;
if (m_provider == ModPlatform::ResourceProvider::MODRINTH) {
output = QFileDialog::getSaveFileName(this, tr("Export %1").arg(name), FS::PathCombine(QDir::homePath(), filename + ".mrpack"),
"Modrinth pack (*.mrpack *.zip)", nullptr);
if (output.isEmpty())
return;
if (!(output.endsWith(".zip") || output.endsWith(".mrpack")))
output.append(".mrpack");
} else {
output = QFileDialog::getSaveFileName(this, tr("Export %1").arg(name), FS::PathCombine(QDir::homePath(), filename + ".zip"),
"CurseForge pack (*.zip)", nullptr);
if (output.isEmpty())
return;
if (!output.endsWith(".zip"))
output.append(".zip");
}
if (output.isEmpty())
return;
Task* task;
if (m_provider == ModPlatform::ResourceProvider::MODRINTH)
task = new ModrinthPackExportTask(ui->name->text(), ui->version->text(), ui->summary->text(), instance, output,
std::bind(&FileIgnoreProxy::filterFile, proxy, std::placeholders::_1));
else
task = new FlamePackExportTask(ui->name->text(), ui->version->text(), ui->summary->text(), instance, output,
if (m_provider == ModPlatform::ResourceProvider::MODRINTH) {
task = new ModrinthPackExportTask(name, ui->version->text(), ui->summary->text(), ui->optionalFiles->isChecked(), instance,
output, std::bind(&FileIgnoreProxy::filterFile, proxy, std::placeholders::_1));
} else {
task = new FlamePackExportTask(name, ui->version->text(), ui->summary->text(), ui->optionalFiles->isChecked(), instance, output,
std::bind(&FileIgnoreProxy::filterFile, proxy, std::placeholders::_1));
}
connect(task, &Task::failed,
[this](const QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show(); });
@ -140,7 +160,6 @@ void ExportPackDialog::done(int result)
void ExportPackDialog::validate()
{
const bool invalid =
ui->name->text().isEmpty() || ((m_provider == ModPlatform::ResourceProvider::MODRINTH) && ui->version->text().isEmpty());
ui->buttonBox->button(QDialogButtonBox::Ok)->setDisabled(invalid);
ui->buttonBox->button(QDialogButtonBox::Ok)
->setDisabled(m_provider == ModPlatform::ResourceProvider::MODRINTH && ui->version->text().isEmpty());
}

View File

@ -7,12 +7,9 @@
<x>0</x>
<y>0</y>
<width>650</width>
<height>413</height>
<height>510</height>
</rect>
</property>
<property name="windowTitle">
<string>Export Pack</string>
</property>
<property name="sizeGripEnabled">
<bool>true</bool>
</property>
@ -20,13 +17,16 @@
<item>
<widget class="QGroupBox" name="information">
<property name="title">
<string>Information</string>
<string>&amp;Description</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="0">
<widget class="QLabel" name="summaryLabel">
<property name="text">
<string>Summary</string>
<string>&amp;Summary</string>
</property>
<property name="buddy">
<cstring>summary</cstring>
</property>
</widget>
</item>
@ -36,14 +36,20 @@
<item row="0" column="0">
<widget class="QLabel" name="nameLabel">
<property name="text">
<string>Name</string>
<string>&amp;Name</string>
</property>
<property name="buddy">
<cstring>name</cstring>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="versionLabel">
<property name="text">
<string>Version</string>
<string>&amp;Version</string>
</property>
<property name="buddy">
<cstring>version</cstring>
</property>
</widget>
</item>
@ -57,31 +63,52 @@
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="filesLabel">
<property name="text">
<string>Files</string>
<widget class="QGroupBox" name="options">
<property name="title">
<string>&amp;Options</string>
</property>
</widget>
</item>
<item>
<widget class="QTreeView" name="treeView">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="headerStretchLastSection">
<bool>false</bool>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="filesLabel">
<property name="text">
<string>&amp;Files</string>
</property>
<property name="buddy">
<cstring>files</cstring>
</property>
</widget>
</item>
<item>
<widget class="QTreeView" name="files">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="headerStretchLastSection">
<bool>false</bool>
</attribute>
</widget>
</item>
<item>
<widget class="QCheckBox" name="optionalFiles">
<property name="text">
<string>&amp;Mark disabled files as optional</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
@ -97,7 +124,8 @@
<tabstop>name</tabstop>
<tabstop>version</tabstop>
<tabstop>summary</tabstop>
<tabstop>treeView</tabstop>
<tabstop>files</tabstop>
<tabstop>optionalFiles</tabstop>
</tabstops>
<resources/>
<connections>

View File

@ -129,7 +129,9 @@ InstallLoaderDialog::InstallLoaderDialog(std::shared_ptr<PackProfile> profile, c
QList<BasePage*> InstallLoaderDialog::getPages()
{
return { // Forge
return { // NeoForge
new InstallLoaderPage("net.neoforged", "neoforged", tr("NeoForge"), {}, profile),
// Forge
new InstallLoaderPage("net.minecraftforge", "forge", tr("Forge"), {}, profile),
// Fabric
new InstallLoaderPage("net.fabricmc.fabric-loader", "fabricmc", tr("Fabric"), Version("1.14"), profile),

View File

@ -5,8 +5,6 @@
#include "ScrollMessageBox.h"
#include "ui_ReviewMessageBox.h"
#include "FileSystem.h"
#include "Json.h"
#include "Markdown.h"
#include "tasks/ConcurrentTask.h"
@ -30,9 +28,9 @@ static std::list<Version> mcVersions(BaseInstance* inst)
return { static_cast<MinecraftInstance*>(inst)->getPackProfile()->getComponent("net.minecraft")->getVersion() };
}
static std::optional<ResourceAPI::ModLoaderTypes> mcLoaders(BaseInstance* inst)
static std::optional<ModPlatform::ModLoaderTypes> mcLoaders(BaseInstance* inst)
{
return { static_cast<MinecraftInstance*>(inst)->getPackProfile()->getModLoaders() };
return { static_cast<MinecraftInstance*>(inst)->getPackProfile()->getSupportedModLoaders() };
}
ModUpdateDialog::ModUpdateDialog(QWidget* parent,

View File

@ -62,8 +62,10 @@
#include "ui/pages/modplatform/modrinth/ModrinthPage.h"
#include "ui/pages/modplatform/technic/TechnicPage.h"
#include "ui/widgets/PageContainer.h"
NewInstanceDialog::NewInstanceDialog(const QString& initialGroup, const QString& url, QWidget* parent)
NewInstanceDialog::NewInstanceDialog(const QString& initialGroup,
const QString& url,
const QMap<QString, QString>& extra_info,
QWidget* parent)
: QDialog(parent), ui(new Ui::NewInstanceDialog)
{
ui->setupUi(this);
@ -125,6 +127,7 @@ NewInstanceDialog::NewInstanceDialog(const QString& initialGroup, const QString&
QUrl actualUrl(url);
m_container->selectPage("import");
importPage->setUrl(url);
importPage->setExtraInfo(extra_info);
}
updateDialogState();

View File

@ -53,7 +53,10 @@ class NewInstanceDialog : public QDialog, public BasePageProvider {
Q_OBJECT
public:
explicit NewInstanceDialog(const QString& initialGroup, const QString& url = QString(), QWidget* parent = 0);
explicit NewInstanceDialog(const QString& initialGroup,
const QString& url = QString(),
const QMap<QString, QString>& extra_info = {},
QWidget* parent = 0);
~NewInstanceDialog();
void updateDialogState();

View File

@ -279,7 +279,7 @@ QList<BasePage*> ModDownloadDialog::getPages()
{
QList<BasePage*> pages;
auto loaders = static_cast<MinecraftInstance*>(m_instance)->getPackProfile()->getModLoaders().value();
auto loaders = static_cast<MinecraftInstance*>(m_instance)->getPackProfile()->getSupportedModLoaders().value();
if (ModrinthAPI::validateModLoaders(loaders))
pages.append(ModrinthModPage::create(this, *m_instance));

View File

@ -35,12 +35,6 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>28</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Browse</string>
</property>

View File

@ -64,7 +64,8 @@ AccountListPage::AccountListPage(QWidget* parent) : QMainWindow(parent), ui(new
ui->setupUi(this);
ui->listView->setEmptyString(
tr("Welcome!\n"
"If you're new here, you can click the \"Add\" button to add your Mojang or Minecraft account."));
"If you're new here, you can select the \"Add Microsoft\" or \"Add Mojang\" buttons to link your Microsoft and/or Mojang "
"accounts."));
ui->listView->setEmptyMode(VersionListView::String);
ui->listView->setContextMenuPolicy(Qt::CustomContextMenu);
@ -85,6 +86,8 @@ AccountListPage::AccountListPage(QWidget* parent) : QMainWindow(parent), ui(new
connect(selectionModel, &QItemSelectionModel::selectionChanged,
[this]([[maybe_unused]] const QItemSelection& sel, [[maybe_unused]] const QItemSelection& dsel) { updateButtonStates(); });
connect(ui->listView, &VersionListView::customContextMenuRequested, this, &AccountListPage::ShowContextMenu);
connect(ui->listView, &VersionListView::activated, this,
[this](const QModelIndex& index) { m_accounts->setDefaultAccount(m_accounts->at(index.row())); });
connect(m_accounts.get(), &AccountList::listChanged, this, &AccountListPage::listChanged);
connect(m_accounts.get(), &AccountList::listActivityChanged, this, &AccountListPage::listChanged);

View File

@ -185,6 +185,7 @@ void JavaPage::updateThresholds()
{
auto sysMiB = Sys::getSystemRam() / Sys::mebibyte;
unsigned int maxMem = ui->maxMemSpinBox->value();
unsigned int minMem = ui->minMemSpinBox->value();
QString iconName;
@ -194,6 +195,9 @@ void JavaPage::updateThresholds()
} else if (maxMem > (sysMiB * 0.9)) {
iconName = "status-yellow";
ui->labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation approaches your system memory capacity."));
} else if (maxMem < minMem) {
iconName = "status-yellow";
ui->labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation is smaller than the minimum value"));
} else {
iconName = "status-good";
ui->labelMaxMemIcon->setToolTip("");

View File

@ -2,7 +2,6 @@
/*
* Prism Launcher - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
* Copyright (C) 2023 seth <getchoo at tuta dot io>
*
* 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,6 +34,7 @@
*/
#include "MinecraftPage.h"
#include "BuildConfig.h"
#include "ui_MinecraftPage.h"
#include <QDir>
@ -44,9 +44,15 @@
#include "Application.h"
#include "settings/SettingsObject.h"
#ifdef Q_OS_LINUX
#include "MangoHud.h"
#endif
MinecraftPage::MinecraftPage(QWidget* parent) : QWidget(parent), ui(new Ui::MinecraftPage)
{
ui->setupUi(this);
connect(ui->useNativeGLFWCheck, &QAbstractButton::toggled, this, &MinecraftPage::onUseNativeGLFWChanged);
connect(ui->useNativeOpenALCheck, &QAbstractButton::toggled, this, &MinecraftPage::onUseNativeOpenALChanged);
loadSettings();
updateCheckboxStuff();
}
@ -74,6 +80,16 @@ void MinecraftPage::on_maximizedCheckBox_clicked(bool checked)
updateCheckboxStuff();
}
void MinecraftPage::onUseNativeGLFWChanged(bool checked)
{
ui->lineEditGLFWPath->setEnabled(checked);
}
void MinecraftPage::onUseNativeOpenALChanged(bool checked)
{
ui->lineEditOpenALPath->setEnabled(checked);
}
void MinecraftPage::applySettings()
{
auto s = APPLICATION->settings();
@ -84,8 +100,10 @@ void MinecraftPage::applySettings()
s->set("MinecraftWinHeight", ui->windowHeightSpinBox->value());
// Native library workarounds
s->set("UseNativeOpenAL", ui->useNativeOpenALCheck->isChecked());
s->set("UseNativeGLFW", ui->useNativeGLFWCheck->isChecked());
s->set("CustomGLFWPath", ui->lineEditGLFWPath->text());
s->set("UseNativeOpenAL", ui->useNativeOpenALCheck->isChecked());
s->set("CustomOpenALPath", ui->lineEditOpenALPath->text());
// Peformance related options
s->set("EnableFeralGamemode", ui->enableFeralGamemodeCheck->isChecked());
@ -96,13 +114,11 @@ void MinecraftPage::applySettings()
s->set("ShowGameTime", ui->showGameTime->isChecked());
s->set("ShowGlobalGameTime", ui->showGlobalGameTime->isChecked());
s->set("RecordGameTime", ui->recordGameTime->isChecked());
s->set("ShowGameTimeWithoutDays", ui->showGameTimeWithoutDays->isChecked());
// 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()
@ -114,8 +130,20 @@ void MinecraftPage::loadSettings()
ui->windowWidthSpinBox->setValue(s->get("MinecraftWinWidth").toInt());
ui->windowHeightSpinBox->setValue(s->get("MinecraftWinHeight").toInt());
ui->useNativeOpenALCheck->setChecked(s->get("UseNativeOpenAL").toBool());
ui->useNativeGLFWCheck->setChecked(s->get("UseNativeGLFW").toBool());
ui->lineEditGLFWPath->setText(s->get("CustomGLFWPath").toString());
ui->lineEditGLFWPath->setPlaceholderText(tr("Path to %1 library file").arg(BuildConfig.GLFW_LIBRARY_NAME));
#ifdef Q_OS_LINUX
if (!APPLICATION->m_detectedGLFWPath.isEmpty())
ui->lineEditGLFWPath->setPlaceholderText(tr("Auto detected path: %1").arg(APPLICATION->m_detectedGLFWPath));
#endif
ui->useNativeOpenALCheck->setChecked(s->get("UseNativeOpenAL").toBool());
ui->lineEditOpenALPath->setText(s->get("CustomOpenALPath").toString());
ui->lineEditOpenALPath->setPlaceholderText(tr("Path to %1 library file").arg(BuildConfig.OPENAL_LIBRARY_NAME));
#ifdef Q_OS_LINUX
if (!APPLICATION->m_detectedOpenALPath.isEmpty())
ui->lineEditOpenALPath->setPlaceholderText(tr("Auto detected path: %1").arg(APPLICATION->m_detectedOpenALPath));
#endif
ui->enableFeralGamemodeCheck->setChecked(s->get("EnableFeralGamemode").toBool());
ui->enableMangoHud->setChecked(s->get("EnableMangoHud").toBool());
@ -138,11 +166,10 @@ void MinecraftPage::loadSettings()
ui->showGameTime->setChecked(s->get("ShowGameTime").toBool());
ui->showGlobalGameTime->setChecked(s->get("ShowGlobalGameTime").toBool());
ui->recordGameTime->setChecked(s->get("RecordGameTime").toBool());
ui->showGameTimeWithoutDays->setChecked(s->get("ShowGameTimeWithoutDays").toBool());
ui->closeAfterLaunchCheck->setChecked(s->get("CloseAfterLaunch").toBool());
ui->quitAfterGameStopCheck->setChecked(s->get("QuitAfterGameStop").toBool());
ui->disableQuiltBeaconCheckBox->setChecked(s->get("DisableQuiltBeacon").toBool());
}
void MinecraftPage::retranslate()

View File

@ -70,6 +70,9 @@ class MinecraftPage : public QWidget, public BasePage {
private slots:
void on_maximizedCheckBox_clicked(bool checked);
void onUseNativeGLFWChanged(bool checked);
void onUseNativeOpenALChanged(bool checked);
private:
Ui::MinecraftPage* ui;
};

View File

@ -138,6 +138,13 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="showGameTimeWithoutDays">
<property name="text">
<string>Show time spent playing in hours</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -190,45 +197,60 @@
<string>Tweaks</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_12">
<item>
<widget class="QGroupBox" name="modLoaderSettingsGroupBox">
<property name="title">
<string>Mod loader settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_13">
<item>
<widget class="QCheckBox" name="disableQuiltBeaconCheckBox">
<property name="text">
<string>Disable Quilt Loader Beacon</string>
</property>
<property name="toolTip">
<string>Disable Quilt loader's beacon for counting monthly active users</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="nativeLibWorkaroundGroupBox">
<property name="title">
<string>Native library workarounds</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_11">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QCheckBox" name="useNativeGLFWCheck">
<property name="text">
<string>Use system installation of &amp;GLFW</string>
</property>
</widget>
</item>
<item>
<item row="1" column="0">
<widget class="QLabel" name="labelGLFWPath">
<property name="text">
<string>&amp;GLFW library path</string>
</property>
<property name="buddy">
<cstring>lineEditGLFWPath</cstring>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="useNativeOpenALCheck">
<property name="text">
<string>Use system installation of &amp;OpenAL</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="labelOpenALPath">
<property name="text">
<string>&amp;OpenAL library path</string>
</property>
<property name="buddy">
<cstring>lineEditOpenALPath</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEditGLFWPath">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="lineEditOpenALPath">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@ -152,6 +152,7 @@ void ExternalResourcesPage::retranslate()
void ExternalResourcesPage::itemActivated(const QModelIndex&)
{
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
m_model->setResourceEnabled(selection.indexes(), EnableAction::TOGGLE);
}
void ExternalResourcesPage::filterTextChanged(const QString& newContents)

View File

@ -3,7 +3,6 @@
* Prism Launcher - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2023 seth <getchoo at tuta dot io>
*
* 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
@ -48,6 +47,7 @@
#include "ui/widgets/CustomCommands.h"
#include "Application.h"
#include "BuildConfig.h"
#include "JavaCommon.h"
#include "minecraft/auth/AccountList.h"
@ -66,6 +66,10 @@ InstanceSettingsPage::InstanceSettingsPage(BaseInstance* inst, QWidget* parent)
connect(APPLICATION, &Application::globalSettingsClosed, this, &InstanceSettingsPage::loadSettings);
connect(ui->instanceAccountSelector, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&InstanceSettingsPage::changeInstanceAccount);
connect(ui->useNativeGLFWCheck, &QAbstractButton::toggled, this, &InstanceSettingsPage::onUseNativeGLFWChanged);
connect(ui->useNativeOpenALCheck, &QAbstractButton::toggled, this, &InstanceSettingsPage::onUseNativeOpenALChanged);
loadSettings();
updateThresholds();
@ -198,11 +202,15 @@ void InstanceSettingsPage::applySettings()
bool workarounds = ui->nativeWorkaroundsGroupBox->isChecked();
m_settings->set("OverrideNativeWorkarounds", workarounds);
if (workarounds) {
m_settings->set("UseNativeOpenAL", ui->useNativeOpenALCheck->isChecked());
m_settings->set("UseNativeGLFW", ui->useNativeGLFWCheck->isChecked());
m_settings->set("CustomGLFWPath", ui->lineEditGLFWPath->text());
m_settings->set("UseNativeOpenAL", ui->useNativeOpenALCheck->isChecked());
m_settings->set("CustomOpenALPath", ui->lineEditOpenALPath->text());
} else {
m_settings->reset("UseNativeOpenAL");
m_settings->reset("UseNativeGLFW");
m_settings->reset("CustomGLFWPath");
m_settings->reset("UseNativeOpenAL");
m_settings->reset("CustomOpenALPath");
}
// Performance
@ -245,14 +253,6 @@ 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();
}
@ -312,7 +312,19 @@ void InstanceSettingsPage::loadSettings()
// Workarounds
ui->nativeWorkaroundsGroupBox->setChecked(m_settings->get("OverrideNativeWorkarounds").toBool());
ui->useNativeGLFWCheck->setChecked(m_settings->get("UseNativeGLFW").toBool());
ui->lineEditGLFWPath->setText(m_settings->get("CustomGLFWPath").toString());
#ifdef Q_OS_LINUX
ui->lineEditGLFWPath->setPlaceholderText(APPLICATION->m_detectedGLFWPath);
#else
ui->lineEditGLFWPath->setPlaceholderText(tr("Path to %1 library file").arg(BuildConfig.GLFW_LIBRARY_NAME));
#endif
ui->useNativeOpenALCheck->setChecked(m_settings->get("UseNativeOpenAL").toBool());
ui->lineEditOpenALPath->setText(m_settings->get("CustomOpenALPath").toString());
#ifdef Q_OS_LINUX
ui->lineEditOpenALPath->setPlaceholderText(APPLICATION->m_detectedOpenALPath);
#else
ui->lineEditGLFWPath->setPlaceholderText(tr("Path to %1 library file").arg(BuildConfig.OPENAL_LIBRARY_NAME));
#endif
// Performance
ui->perfomanceGroupBox->setChecked(m_settings->get("OverridePerformance").toBool());
@ -344,10 +356,6 @@ 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()
@ -408,6 +416,16 @@ void InstanceSettingsPage::on_javaTestBtn_clicked()
checker->run();
}
void InstanceSettingsPage::onUseNativeGLFWChanged(bool checked)
{
ui->lineEditGLFWPath->setEnabled(checked);
}
void InstanceSettingsPage::onUseNativeOpenALChanged(bool checked)
{
ui->lineEditOpenALPath->setEnabled(checked);
}
void InstanceSettingsPage::updateAccountsMenu()
{
ui->instanceAccountSelector->clear();
@ -460,6 +478,7 @@ void InstanceSettingsPage::updateThresholds()
{
auto sysMiB = Sys::getSystemRam() / Sys::mebibyte;
unsigned int maxMem = ui->maxMemSpinBox->value();
unsigned int minMem = ui->minMemSpinBox->value();
QString iconName;
@ -469,6 +488,9 @@ void InstanceSettingsPage::updateThresholds()
} else if (maxMem > (sysMiB * 0.9)) {
iconName = "status-yellow";
ui->labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation approaches your system memory capacity."));
} else if (maxMem < minMem) {
iconName = "status-yellow";
ui->labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation is smaller than the minimum value"));
} else {
iconName = "status-good";
ui->labelMaxMemIcon->setToolTip("");

View File

@ -71,6 +71,9 @@ class InstanceSettingsPage : public QWidget, public BasePage {
void on_javaBrowseBtn_clicked();
void on_maxMemSpinBox_valueChanged(int i);
void onUseNativeGLFWChanged(bool checked);
void onUseNativeOpenALChanged(bool checked);
void applySettings();
void loadSettings();

View File

@ -443,18 +443,52 @@
<property name="checked">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<layout class="QGridLayout" name="gridLayout_3">
<item row="2" column="0">
<widget class="QCheckBox" name="useNativeOpenALCheck">
<property name="text">
<string>Use system installation of OpenAL</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelGLFWPath">
<property name="text">
<string>&amp;GLFW library path</string>
</property>
<property name="buddy">
<cstring>lineEditGLFWPath</cstring>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="useNativeGLFWCheck">
<property name="text">
<string>Use system installation of GLFW</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="useNativeOpenALCheck">
<item row="1" column="1">
<widget class="QLineEdit" name="lineEditGLFWPath">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="labelOpenALPath">
<property name="text">
<string>Use system installation of OpenAL</string>
<string>&amp;OpenAL library path</string>
</property>
<property name="buddy">
<cstring>lineEditOpenALPath</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="lineEditOpenALPath">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
@ -549,31 +583,6 @@
<string>Miscellaneous</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QGroupBox" name="modLoaderSettingsGroupBox">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<property name="title">
<string>Mod loader settings</string>
</property>
<layout class="QVBoxLayout" name="VerticalLayout_16">
<item>
<widget class="QCheckBox" name="disableQuiltBeaconCheckBox">
<property name="text">
<string>Disable Quilt Loader Beacon</string>
</property>
<property name="toolTip">
<string>Disable Quilt loader's beacon for counting monthly active users</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gameTimeGroupBox">
<property name="enabled">

View File

@ -3,7 +3,7 @@
* Prism Launcher - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
* Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
*
* 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
@ -354,14 +354,8 @@ class ServersModel : public QAbstractListModel {
}
}
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override
{
return parent.isValid() ? 0 : m_servers.size();
}
int columnCount(const QModelIndex& parent) const override
{
return parent.isValid() ? 0 : COLUMN_COUNT;
}
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override { return parent.isValid() ? 0 : m_servers.size(); }
int columnCount(const QModelIndex& parent) const override { return parent.isValid() ? 0 : COLUMN_COUNT; }
Server* at(int index)
{
@ -445,10 +439,7 @@ class ServersModel : public QAbstractListModel {
qDebug() << "Changed:" << path;
load();
}
void fileChanged(const QString& path)
{
qDebug() << "Changed:" << path;
}
void fileChanged(const QString& path) { qDebug() << "Changed:" << path; }
private slots:
void save_internal()
@ -492,10 +483,7 @@ class ServersModel : public QAbstractListModel {
m_saveTimer.stop();
}
bool saveIsScheduled() const
{
return m_dirty;
}
bool saveIsScheduled() const { return m_dirty; }
void updateFSObserver()
{
@ -743,7 +731,7 @@ void ServersPage::on_actionMove_Down_triggered()
void ServersPage::on_actionJoin_triggered()
{
const auto& address = m_model->at(currentServer)->m_address;
APPLICATION->launch(m_inst, true, false, nullptr, std::make_shared<MinecraftServerTarget>(MinecraftServerTarget::parse(address)));
APPLICATION->launch(m_inst, true, false, std::make_shared<MinecraftServerTarget>(MinecraftServerTarget::parse(address)));
}
#include "ServersPage.moc"

View File

@ -166,14 +166,17 @@ VersionPage::VersionPage(MinecraftInstance* inst, QWidget* parent) : QMainWindow
ui->packageView->setSelectionMode(QAbstractItemView::SingleSelection);
ui->packageView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->packageView->selectionModel(), &QItemSelectionModel::currentChanged, this, &VersionPage::versionCurrent);
auto smodel = ui->packageView->selectionModel();
connect(smodel, &QItemSelectionModel::currentChanged, this, &VersionPage::versionCurrent);
connect(smodel, &QItemSelectionModel::currentChanged, this, &VersionPage::packageCurrent);
connect(m_profile.get(), &PackProfile::minecraftChanged, this, &VersionPage::updateVersionControls);
updateVersionControls();
preselect(0);
connect(ui->packageView, &ModListView::customContextMenuRequested, this, &VersionPage::showContextMenu);
connect(ui->packageView, &QAbstractItemView::activated, this, [this](const QModelIndex& index) {
auto component = m_profile->getComponent(index.row());
component->setEnabled(!component->isEnabled());
});
connect(ui->filterEdit, &QLineEdit::textChanged, this, &VersionPage::onFilterTextChanged);
}
@ -408,7 +411,7 @@ void VersionPage::on_actionDownload_All_triggered()
if (!APPLICATION->accounts()->anyAccountIsValid()) {
CustomMessageBox::selectable(this, tr("Error"),
tr("Cannot download Minecraft or update instances unless you have at least "
"one account added.\nPlease add your Mojang or Minecraft account."),
"one account added.\nPlease add your Microsoft or Mojang account."),
QMessageBox::Warning)
->show();
return;

View File

@ -127,6 +127,9 @@ void CustomPage::loaderFilterChanged()
ui->loaderVersionList->setEmptyString(tr("No mod loader is selected."));
ui->loaderVersionList->setEmptyMode(VersionListView::String);
return;
} else if (ui->neoForgeFilter->isChecked()) {
ui->loaderVersionList->setExactFilter(BaseVersionList::ParentVersionRole, minecraftVersion);
m_selectedLoader = "net.neoforged";
} else if (ui->forgeFilter->isChecked()) {
ui->loaderVersionList->setExactFilter(BaseVersionList::ParentVersionRole, minecraftVersion);
m_selectedLoader = "net.minecraftforge";

View File

@ -194,6 +194,16 @@
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="neoForgeFilter">
<property name="text">
<string>NeoForge</string>
</property>
<attribute name="buttonGroup">
<string notr="true">loaderBtnGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="forgeFilter">
<property name="text">

View File

@ -35,13 +35,21 @@
*/
#include "ImportPage.h"
#include "ui/dialogs/ProgressDialog.h"
#include "ui_ImportPage.h"
#include <QFileDialog>
#include <QValidator>
#include <utility>
#include "ui/dialogs/CustomMessageBox.h"
#include "ui/dialogs/NewInstanceDialog.h"
#include "modplatform/flame/FlameAPI.h"
#include "Json.h"
#include "InstanceImportTask.h"
class UrlValidator : public QValidator {
@ -106,10 +114,61 @@ void ImportPage::updateState()
bool isMRPack = fi.suffix() == "mrpack";
if (fi.exists() && (isZip || isMRPack)) {
QFileInfo file_info(url.fileName());
dialog->setSuggestedPack(file_info.completeBaseName(), new InstanceImportTask(url, this));
auto extra_info = QMap(m_extra_info);
qDebug() << "Pack Extra Info" << extra_info << m_extra_info;
dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(url, this, std::move(extra_info)));
dialog->setSuggestedIcon("default");
}
} else if (url.scheme() == "curseforge") {
// need to find the download link for the modpack
// format of url curseforge://install?addonId=IDHERE&fileId=IDHERE
QUrlQuery query(url);
auto addonId = query.allQueryItemValues("addonId")[0];
auto fileId = query.allQueryItemValues("fileId")[0];
auto array = std::make_shared<QByteArray>();
auto api = FlameAPI();
auto job = api.getFile(addonId, fileId, array);
connect(job.get(), &NetJob::failed, this,
[this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show(); });
connect(job.get(), &NetJob::succeeded, this, [this, array, addonId, fileId] {
qDebug() << "Returned CFURL Json:\n" << array->toStdString().c_str();
auto doc = Json::requireDocument(*array);
auto data = Json::ensureObject(Json::ensureObject(doc.object()), "data");
// No way to find out if it's a mod or a modpack before here
// And also we need to check if it ends with .zip, instead of any better way
auto fileName = Json::ensureString(data, "fileName");
if (fileName.endsWith(".zip")) {
// Have to use ensureString then use QUrl to get proper url encoding
auto dl_url = QUrl(Json::ensureString(data, "downloadUrl", "", "downloadUrl"));
if (!dl_url.isValid()) {
CustomMessageBox::selectable(
this, tr("Error"),
tr("The modpack %1 is blocked for third-parties! Please download it manually.").arg(fileName),
QMessageBox::Critical)
->show();
return;
}
QFileInfo dl_file(dl_url.fileName());
QString pack_name = Json::ensureString(data, "displayName", dl_file.completeBaseName(), "displayName");
QMap<QString, QString> extra_info;
extra_info.insert("pack_id", addonId);
extra_info.insert("pack_version_id", fileId);
dialog->setSuggestedPack(pack_name, new InstanceImportTask(dl_url, this, std::move(extra_info)));
dialog->setSuggestedIcon("default");
} else {
CustomMessageBox::selectable(this, tr("Error"), tr("This url isn't a valid modpack !"), QMessageBox::Critical)->show();
}
});
ProgressDialog dlUrlDialod(this);
dlUrlDialod.setSkipButton(true, tr("Abort"));
dlUrlDialod.execWithTask(job.get());
return;
} else {
if (input.endsWith("?client=y")) {
input.chop(9);
@ -118,7 +177,8 @@ void ImportPage::updateState()
}
// hook, line and sinker.
QFileInfo fi(url.fileName());
dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(url, this));
auto extra_info = QMap(m_extra_info);
dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(url, this, std::move(extra_info)));
dialog->setSuggestedIcon("default");
}
} else {
@ -132,6 +192,12 @@ void ImportPage::setUrl(const QString& url)
updateState();
}
void ImportPage::setExtraInfo(const QMap<QString, QString>& extra_info)
{
m_extra_info = extra_info;
updateState();
}
void ImportPage::on_modpackBtn_clicked()
{
auto filter = QMimeDatabase().mimeTypeForName("application/zip").filterString();

View File

@ -62,7 +62,7 @@ class ImportPage : public QWidget, public BasePage {
void setUrl(const QString& url);
void openedImpl() override;
void setExtraInfo(const QMap<QString, QString>& extra_info);
private slots:
void on_modpackBtn_clicked();
void updateState();
@ -73,4 +73,5 @@ class ImportPage : public QWidget, public BasePage {
private:
Ui::ImportPage* ui = nullptr;
NewInstanceDialog* dialog = nullptr;
QMap<QString, QString> m_extra_info = {};
};

View File

@ -40,7 +40,7 @@
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>- CurseForge modpacks (ZIP)</string>
<string>- CurseForge modpacks (ZIP / curseforge:// URL)</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>

View File

@ -33,7 +33,7 @@ ResourceAPI::SearchArgs ModModel::createSearchArguments()
auto sort = getCurrentSortingMethodByIndex();
return { ModPlatform::ResourceType::MOD, m_next_search_offset, m_search_term, sort, profile->getModLoaders(), versions };
return { ModPlatform::ResourceType::MOD, m_next_search_offset, m_search_term, sort, profile->getSupportedModLoaders(), versions };
}
ResourceAPI::VersionSearchArgs ModModel::createVersionsArguments(QModelIndex& entry)
@ -48,7 +48,7 @@ ResourceAPI::VersionSearchArgs ModModel::createVersionsArguments(QModelIndex& en
if (!m_filter->versions.empty())
versions = m_filter->versions;
return { pack, versions, profile->getModLoaders() };
return { pack, versions, profile->getSupportedModLoaders() };
}
ResourceAPI::ProjectInfoArgs ModModel::createInfoArguments(QModelIndex& entry)

View File

@ -124,8 +124,7 @@ void ModPage::updateVersionList()
auto version = current_pack->versions[i];
bool valid = false;
for (auto& mcVer : m_filter->versions) {
// NOTE: Flame doesn't care about loader, so passing it changes nothing.
if (validateVersion(version, mcVer.toString(), packProfile->getModLoaders())) {
if (validateVersion(version, mcVer.toString(), packProfile->getSupportedModLoaders())) {
valid = true;
break;
}

View File

@ -55,7 +55,7 @@ class ModPage : public ResourcePage {
virtual auto validateVersion(ModPlatform::IndexedVersion& ver,
QString mineVer,
std::optional<ResourceAPI::ModLoaderTypes> loaders = {}) const -> bool = 0;
std::optional<ModPlatform::ModLoaderTypes> loaders = {}) const -> bool = 0;
[[nodiscard]] bool supportsFiltering() const override { return true; };
auto getFilter() const -> const std::shared_ptr<ModFilterWidget::Filter> { return m_filter; }

View File

@ -3,6 +3,7 @@
// SPDX-License-Identifier: GPL-3.0-only
#include "ShaderPackPage.h"
#include "modplatform/ModIndex.h"
#include "ui_ResourcePage.h"
#include "ShaderPackModel.h"
@ -48,7 +49,7 @@ void ShaderPackResourcePage::addResourceToPage(ModPlatform::IndexedPack::Ptr pac
const std::shared_ptr<ResourceFolderModel> base_model)
{
QString custom_target_folder;
if (version.loaders.contains(QStringLiteral("canvas")))
if (version.loaders & ModPlatform::Cauldron)
custom_target_folder = QStringLiteral("resourcepacks");
m_model->addPack(pack, version, base_model, false, custom_target_folder);
}

View File

@ -31,7 +31,7 @@ void FlameModModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonAr
auto FlameModModel::loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion
{
return FlameMod::loadDependencyVersions(m, arr);
return FlameMod::loadDependencyVersions(m, arr, &m_base_instance);
}
auto FlameModModel::documentToArray(QJsonDocument& obj) const -> QJsonArray

View File

@ -68,10 +68,10 @@ FlameModPage::FlameModPage(ModDownloadDialog* dialog, BaseInstance& instance) :
auto FlameModPage::validateVersion(ModPlatform::IndexedVersion& ver,
QString mineVer,
std::optional<ResourceAPI::ModLoaderTypes> loaders) const -> bool
std::optional<ModPlatform::ModLoaderTypes> loaders) const -> bool
{
Q_UNUSED(loaders);
return ver.mcVersion.contains(mineVer) && !ver.downloadUrl.isEmpty();
return ver.mcVersion.contains(mineVer) && !ver.downloadUrl.isEmpty() &&
(!loaders.has_value() || !ver.loaders || loaders.value() & ver.loaders);
}
bool FlameModPage::optedOut(ModPlatform::IndexedVersion& ver) const

View File

@ -95,7 +95,7 @@ class FlameModPage : public ModPage {
bool validateVersion(ModPlatform::IndexedVersion& ver,
QString mineVer,
std::optional<ResourceAPI::ModLoaderTypes> loaders = {}) const override;
std::optional<ModPlatform::ModLoaderTypes> loaders = {}) const override;
bool optedOut(ModPlatform::IndexedVersion& ver) const override;
void openUrl(const QUrl& url) override;

View File

@ -39,12 +39,12 @@ void ModrinthModModel::loadExtraPackInfo(ModPlatform::IndexedPack& m, QJsonObjec
void ModrinthModModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr)
{
::Modrinth::loadIndexedPackVersions(m, arr, APPLICATION->network(), &m_base_instance);
::Modrinth::loadIndexedPackVersions(m, arr, &m_base_instance);
}
auto ModrinthModModel::loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion
{
return ::Modrinth::loadDependencyVersions(m, arr);
return ::Modrinth::loadDependencyVersions(m, arr, &m_base_instance);
}
auto ModrinthModModel::documentToArray(QJsonDocument& obj) const -> QJsonArray
@ -66,7 +66,7 @@ void ModrinthResourcePackModel::loadExtraPackInfo(ModPlatform::IndexedPack& m, Q
void ModrinthResourcePackModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr)
{
::Modrinth::loadIndexedPackVersions(m, arr, APPLICATION->network(), &m_base_instance);
::Modrinth::loadIndexedPackVersions(m, arr, &m_base_instance);
}
auto ModrinthResourcePackModel::documentToArray(QJsonDocument& obj) const -> QJsonArray
@ -88,7 +88,7 @@ void ModrinthTexturePackModel::loadExtraPackInfo(ModPlatform::IndexedPack& m, QJ
void ModrinthTexturePackModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr)
{
::Modrinth::loadIndexedPackVersions(m, arr, APPLICATION->network(), &m_base_instance);
::Modrinth::loadIndexedPackVersions(m, arr, &m_base_instance);
}
auto ModrinthTexturePackModel::documentToArray(QJsonDocument& obj) const -> QJsonArray
@ -110,7 +110,7 @@ void ModrinthShaderPackModel::loadExtraPackInfo(ModPlatform::IndexedPack& m, QJs
void ModrinthShaderPackModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr)
{
::Modrinth::loadIndexedPackVersions(m, arr, APPLICATION->network(), &m_base_instance);
::Modrinth::loadIndexedPackVersions(m, arr, &m_base_instance);
}
auto ModrinthShaderPackModel::documentToArray(QJsonDocument& obj) const -> QJsonArray

View File

@ -65,21 +65,9 @@ ModrinthModPage::ModrinthModPage(ModDownloadDialog* dialog, BaseInstance& instan
auto ModrinthModPage::validateVersion(ModPlatform::IndexedVersion& ver,
QString mineVer,
std::optional<ResourceAPI::ModLoaderTypes> loaders) const -> bool
std::optional<ModPlatform::ModLoaderTypes> loaders) const -> bool
{
auto loaderCompatible = !loaders.has_value();
if (!loaderCompatible) {
auto loaderStrings = ModrinthAPI::getModLoaderStrings(loaders.value());
for (auto remoteLoader : ver.loaders) {
if (loaderStrings.contains(remoteLoader)) {
loaderCompatible = true;
break;
}
}
}
return ver.mcVersion.contains(mineVer) && loaderCompatible;
return ver.mcVersion.contains(mineVer) && (!loaders.has_value() || !ver.loaders || loaders.value() & ver.loaders);
}
ModrinthResourcePackPage::ModrinthResourcePackPage(ResourcePackDownloadDialog* dialog, BaseInstance& instance)

View File

@ -93,7 +93,7 @@ class ModrinthModPage : public ModPage {
[[nodiscard]] inline auto helpPage() const -> QString override { return "Mod-platform"; }
auto validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, std::optional<ResourceAPI::ModLoaderTypes> loaders = {}) const
auto validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, std::optional<ModPlatform::ModLoaderTypes> loaders = {}) const
-> bool override;
};

View File

@ -186,12 +186,20 @@ QString JavaSettingsWidget::javaPath() const
int JavaSettingsWidget::maxHeapSize() const
{
return m_maxMemSpinBox->value();
auto min = m_minMemSpinBox->value();
auto max = m_maxMemSpinBox->value();
if (max < min)
max = min;
return max;
}
int JavaSettingsWidget::minHeapSize() const
{
return m_minMemSpinBox->value();
auto min = m_minMemSpinBox->value();
auto max = m_maxMemSpinBox->value();
if (min > max)
min = max;
return min;
}
bool JavaSettingsWidget::permGenEnabled() const
@ -214,17 +222,9 @@ void JavaSettingsWidget::memoryValueChanged(int)
if (obj == m_minMemSpinBox && min != observedMinMemory) {
observedMinMemory = min;
actuallyChanged = true;
if (min > max) {
observedMaxMemory = min;
m_maxMemSpinBox->setValue(min);
}
} else if (obj == m_maxMemSpinBox && max != observedMaxMemory) {
observedMaxMemory = max;
actuallyChanged = true;
if (min > max) {
observedMinMemory = max;
m_minMemSpinBox->setValue(max);
}
} else if (obj == m_permGenSpinBox && permgen != observedPermGenMemory) {
observedPermGenMemory = permgen;
actuallyChanged = true;
@ -361,8 +361,8 @@ void JavaSettingsWidget::checkJavaPath(const QString& path)
setJavaStatus(JavaStatus::Pending);
m_checker.reset(new JavaChecker());
m_checker->m_path = path;
m_checker->m_minMem = m_minMemSpinBox->value();
m_checker->m_maxMem = m_maxMemSpinBox->value();
m_checker->m_minMem = minHeapSize();
m_checker->m_maxMem = maxHeapSize();
if (m_permGenSpinBox->isVisible()) {
m_checker->m_permGen = m_permGenSpinBox->value();
}
@ -415,6 +415,9 @@ void JavaSettingsWidget::updateThresholds()
} else if (observedMaxMemory > (m_availableMemory * 0.9)) {
iconName = "status-yellow";
m_labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation approaches your system memory capacity."));
} else if (observedMaxMemory < observedMinMemory) {
iconName = "status-yellow";
m_labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation is smaller than the minimum value"));
} else {
iconName = "status-good";
m_labelMaxMemIcon->setToolTip("");