Merge branch 'develop' of https://github.com/PrismLauncher/PrismLauncher into feature/java-downloader

This commit is contained in:
Trial97
2024-03-17 20:57:53 +02:00
20 changed files with 199 additions and 105 deletions

View File

@@ -644,10 +644,11 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
m_settings->registerSetting("UseNativeGLFW", false);
m_settings->registerSetting("CustomGLFWPath", "");
// Peformance related options
// Performance related options
m_settings->registerSetting("EnableFeralGamemode", false);
m_settings->registerSetting("EnableMangoHud", false);
m_settings->registerSetting("UseDiscreteGpu", false);
m_settings->registerSetting("UseZink", false);
// Game time
m_settings->registerSetting("ShowGameTime", true);

View File

@@ -38,6 +38,7 @@
#include <QDir>
#include <QDirIterator>
#include <QFile>
#include <QFileInfo>
#include <QFileSystemWatcher>
#include <QJsonArray>
#include <QJsonDocument>
@@ -847,14 +848,16 @@ class InstanceStaging : public Task {
const unsigned maxBackoff = 16;
public:
InstanceStaging(InstanceList* parent, InstanceTask* child, QString stagingPath, InstanceName const& instanceName, QString groupName)
: m_parent(parent)
, backoff(minBackoff, maxBackoff)
, m_stagingPath(std::move(stagingPath))
, m_instance_name(std::move(instanceName))
, m_groupName(std::move(groupName))
InstanceStaging(InstanceList* parent, InstanceTask* child, SettingsObjectPtr settings)
: m_parent(parent), backoff(minBackoff, maxBackoff)
{
m_stagingPath = parent->getStagedInstancePath();
m_child.reset(child);
m_child->setStagingPath(m_stagingPath);
m_child->setParentSettings(std::move(settings));
connect(child, &Task::succeeded, this, &InstanceStaging::childSucceeded);
connect(child, &Task::failed, this, &InstanceStaging::childFailed);
connect(child, &Task::aborted, this, &InstanceStaging::childAborted);
@@ -866,7 +869,7 @@ class InstanceStaging : public Task {
connect(&m_backoffTimer, &QTimer::timeout, this, &InstanceStaging::childSucceeded);
}
virtual ~InstanceStaging(){};
virtual ~InstanceStaging() {}
// FIXME/TODO: add ability to abort during instance commit retries
bool abort() override
@@ -881,14 +884,22 @@ class InstanceStaging : public Task {
bool canAbort() const override { return (m_child && m_child->canAbort()); }
protected:
virtual void executeTask() override { m_child->start(); }
virtual void executeTask() override
{
if (m_stagingPath.isNull()) {
emitFailed(tr("Could not create staging folder"));
return;
}
m_child->start();
}
QStringList warnings() const override { return m_child->warnings(); }
private slots:
void childSucceeded()
{
unsigned sleepTime = backoff();
if (m_parent->commitStagedInstance(m_stagingPath, m_instance_name, m_groupName, *m_child.get())) {
if (m_parent->commitStagedInstance(m_stagingPath, *m_child.get(), m_child->group(), *m_child.get())) {
emitSucceeded();
return;
}
@@ -897,7 +908,7 @@ class InstanceStaging : public Task {
emitFailed(tr("Failed to commit instance, even after multiple retries. It is being blocked by something."));
return;
}
qDebug() << "Failed to commit instance" << m_instance_name.name() << "Initiating backoff:" << sleepTime;
qDebug() << "Failed to commit instance" << m_child->name() << "Initiating backoff:" << sleepTime;
m_backoffTimer.start(sleepTime * 500);
}
void childFailed(const QString& reason)
@@ -906,7 +917,11 @@ class InstanceStaging : public Task {
emitFailed(reason);
}
void childAborted() { emitAborted(); }
void childAborted()
{
m_parent->destroyStagingPath(m_stagingPath);
emitAborted();
}
private:
InstanceList* m_parent;
@@ -918,34 +933,35 @@ class InstanceStaging : public Task {
ExponentialSeries backoff;
QString m_stagingPath;
unique_qobject_ptr<InstanceTask> m_child;
InstanceName m_instance_name;
QString m_groupName;
QTimer m_backoffTimer;
};
Task* InstanceList::wrapInstanceTask(InstanceTask* task)
{
auto stagingPath = getStagedInstancePath();
task->setStagingPath(stagingPath);
task->setParentSettings(m_globalSettings);
return new InstanceStaging(this, task, stagingPath, *task, task->group());
return new InstanceStaging(this, task, m_globalSettings);
}
QString InstanceList::getStagedInstancePath()
{
QString key = QUuid::createUuid().toString(QUuid::WithoutBraces);
QString tempDir = ".LAUNCHER_TEMP/";
QString relPath = FS::PathCombine(tempDir, key);
QDir rootPath(m_instDir);
auto path = FS::PathCombine(m_instDir, relPath);
if (!rootPath.mkpath(relPath)) {
return QString();
}
const QString tempRoot = FS::PathCombine(m_instDir, ".tmp");
QString result;
int tries = 0;
do {
if (++tries > 256)
return {};
const QString key = QUuid::createUuid().toString(QUuid::Id128).left(6);
result = FS::PathCombine(tempRoot, key);
} while (QFileInfo::exists(result));
if (!QDir::current().mkpath(result))
return {};
#ifdef Q_OS_WIN32
auto tempPath = FS::PathCombine(m_instDir, tempDir);
SetFileAttributesA(tempPath.toStdString().c_str(), FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
SetFileAttributesA(tempRoot.toStdString().c_str(), FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
#endif
return path;
return result;
}
bool InstanceList::commitStagedInstance(const QString& path,

View File

@@ -463,7 +463,7 @@ auto ExportToZipTask::exportZip() -> ZipResult
auto absolute = file.absoluteFilePath();
auto relative = m_dir.relativeFilePath(absolute);
setStatus("Compresing: " + relative);
setStatus("Compressing: " + relative);
setProgress(m_progress + 1, m_progressTotal);
if (m_follow_symlinks) {
if (file.isSymLink())

View File

@@ -175,11 +175,12 @@ void MinecraftInstance::loadSpecificSettings()
m_settings->registerOverride(global_settings->getSetting("UseNativeGLFW"), nativeLibraryWorkaroundsOverride);
m_settings->registerOverride(global_settings->getSetting("CustomGLFWPath"), nativeLibraryWorkaroundsOverride);
// Peformance related options
// Performance related options
auto performanceOverride = m_settings->registerSetting("OverridePerformance", false);
m_settings->registerOverride(global_settings->getSetting("EnableFeralGamemode"), performanceOverride);
m_settings->registerOverride(global_settings->getSetting("EnableMangoHud"), performanceOverride);
m_settings->registerOverride(global_settings->getSetting("UseDiscreteGpu"), performanceOverride);
m_settings->registerOverride(global_settings->getSetting("UseZink"), performanceOverride);
// Miscellaneous
auto miscellaneousOverride = m_settings->registerSetting("OverrideMiscellaneous", false);
@@ -624,6 +625,13 @@ QProcessEnvironment MinecraftInstance::createLaunchEnvironment()
env.insert("__VK_LAYER_NV_optimus", "NVIDIA_only");
env.insert("__GLX_VENDOR_LIBRARY_NAME", "nvidia");
}
if (settings()->get("UseZink").toBool()) {
// taken from https://wiki.archlinux.org/title/OpenGL#OpenGL_over_Vulkan_(Zink)
env.insert("__GLX_VENDOR_LIBRARY_NAME", "mesa");
env.insert("MESA_LOADER_DRIVER_OVERRIDE", "zink");
env.insert("GALLIUM_DRIVER", "zink");
}
#endif
return env;
}

View File

@@ -287,16 +287,12 @@ QByteArray ModrinthPackExportTask::generateIndex()
env["client"] = "required";
env["server"] = "required";
}
switch (iterator->side) {
case Metadata::ModSide::ClientSide:
env["server"] = "unsupported";
break;
case Metadata::ModSide::ServerSide:
env["client"] = "unsupported";
break;
case Metadata::ModSide::UniversalSide:
break;
}
// a server side mod does not imply that the mod does not work on the client
// however, if a mrpack mod is marked as server-only it will not install on the client
if (iterator->side == Metadata::ModSide::ClientSide)
env["server"] = "unsupported";
fileOut["env"] = env;
fileOut["path"] = path;

View File

@@ -47,11 +47,18 @@ ExportPackDialog::ExportPackDialog(InstancePtr instance, QWidget* parent, ModPla
if (m_provider == ModPlatform::ResourceProvider::MODRINTH) {
setWindowTitle(tr("Export Modrinth Pack"));
ui->summary->setText(instance->settings()->get("ExportSummary").toString());
ui->authorLabel->hide();
ui->author->hide();
ui->summary->setPlainText(instance->settings()->get("ExportSummary").toString());
} else {
setWindowTitle(tr("Export CurseForge Pack"));
ui->summaryLabel->setText(tr("&Author"));
ui->summary->setText(instance->settings()->get("ExportAuthor").toString());
ui->summaryLabel->hide();
ui->summary->hide();
ui->author->setText(instance->settings()->get("ExportAuthor").toString());
}
// ensure a valid pack is generated
@@ -108,9 +115,13 @@ void ExportPackDialog::done(int result)
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 (m_provider == ModPlatform::ResourceProvider::MODRINTH)
settings->set("ExportSummary", ui->summary->toPlainText());
else
settings->set("ExportAuthor", ui->author->text());
if (result == Accepted) {
const QString name = ui->name->text().isEmpty() ? instance->name() : ui->name->text();
const QString filename = FS::RemoveInvalidFilenameChars(name);
@@ -134,10 +145,10 @@ void ExportPackDialog::done(int result)
Task* task;
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));
task = new ModrinthPackExportTask(name, ui->version->text(), ui->summary->toPlainText(), 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,
task = new FlamePackExportTask(name, ui->version->text(), ui->author->text(), ui->optionalFiles->isChecked(), instance, output,
std::bind(&FileIgnoreProxy::filterFile, proxy, std::placeholders::_1));
}

View File

@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>650</width>
<height>510</height>
<height>532</height>
</rect>
</property>
<property name="sizeGripEnabled">
@@ -19,21 +19,8 @@
<property name="title">
<string>&amp;Description</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="0">
<widget class="QLabel" name="summaryLabel">
<property name="text">
<string>&amp;Summary</string>
</property>
<property name="buddy">
<cstring>summary</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="summary"/>
</item>
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="nameLabel">
<property name="text">
<string>&amp;Name</string>
@@ -43,7 +30,10 @@
</property>
</widget>
</item>
<item row="1" column="0">
<item>
<widget class="QLineEdit" name="name"/>
</item>
<item>
<widget class="QLabel" name="versionLabel">
<property name="text">
<string>&amp;Version</string>
@@ -53,16 +43,43 @@
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="name"/>
</item>
<item row="1" column="1">
<item>
<widget class="QLineEdit" name="version">
<property name="text">
<string>1.0.0</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="summaryLabel">
<property name="text">
<string>&amp;Summary</string>
</property>
<property name="buddy">
<cstring>summary</cstring>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="summary">
<property name="tabChangesFocus">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="authorLabel">
<property name="text">
<string>&amp;Author</string>
</property>
<property name="buddy">
<cstring>author</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="author"/>
</item>
</layout>
</widget>
</item>
@@ -124,6 +141,7 @@
<tabstop>name</tabstop>
<tabstop>version</tabstop>
<tabstop>summary</tabstop>
<tabstop>author</tabstop>
<tabstop>files</tabstop>
<tabstop>optionalFiles</tabstop>
</tabstops>

View File

@@ -482,32 +482,42 @@ void InstanceView::paintEvent([[maybe_unused]] QPaintEvent* event)
if (model()->rowCount() == 0) {
painter.save();
const QString line1 = tr("Welcome!");
const QString line2 = tr("Click \"Add Instance\" to get started.");
auto rect = this->viewport()->rect();
auto font = option.font;
font.setPointSize(37);
painter.setFont(font);
auto fm = painter.fontMetrics();
QString emptyString = tr("Welcome!") + "\n" + tr("Click \"Add Instance\" to get started.");
if (rect.height() <= (fm.height() * 5) || rect.width() <= fm.horizontalAdvance(line2)) {
auto s = rect.height() / (5. * fm.height());
auto sx = rect.width() * 1. / fm.horizontalAdvance(line2);
if (s >= sx)
s = sx;
auto ps = font.pointSize() * s;
if (ps <= 0)
ps = 1;
font.setPointSize(ps);
painter.setFont(font);
fm = painter.fontMetrics();
// calculate the rect for the overlay
painter.setRenderHint(QPainter::Antialiasing, true);
QFont font("sans", 20);
font.setBold(true);
QRect bounds = viewport()->geometry();
bounds.moveTop(0);
auto innerBounds = bounds;
innerBounds.adjust(10, 10, -10, -10);
QColor background = QApplication::palette().color(QPalette::WindowText);
QColor foreground = QApplication::palette().color(QPalette::Base);
foreground.setAlpha(190);
painter.setFont(font);
auto fontMetrics = painter.fontMetrics();
auto textRect = fontMetrics.boundingRect(innerBounds, Qt::AlignHCenter | Qt::TextWordWrap, emptyString);
textRect.moveCenter(bounds.center());
auto wrapRect = textRect;
wrapRect.adjust(-10, -10, 10, 10);
// check if we are allowed to draw in our area
if (!event->rect().intersects(wrapRect)) {
return;
}
// text
rect.setTop(rect.top() + fm.height() * 1.5);
painter.drawText(rect, Qt::AlignHCenter, line1);
rect.setTop(rect.top() + fm.height());
painter.drawText(rect, Qt::AlignHCenter, line2);
painter.setBrush(QBrush(background));
painter.setPen(foreground);
painter.drawRoundedRect(wrapRect, 5.0, 5.0);
painter.setPen(foreground);
painter.setFont(font);
painter.drawText(textRect, Qt::AlignHCenter | Qt::TextWordWrap, emptyString);
painter.restore();
return;
}

View File

@@ -109,6 +109,7 @@ void MinecraftPage::applySettings()
s->set("EnableFeralGamemode", ui->enableFeralGamemodeCheck->isChecked());
s->set("EnableMangoHud", ui->enableMangoHud->isChecked());
s->set("UseDiscreteGpu", ui->useDiscreteGpuCheck->isChecked());
s->set("UseZink", ui->useZink->isChecked());
// Game time
s->set("ShowGameTime", ui->showGameTime->isChecked());
@@ -151,6 +152,7 @@ void MinecraftPage::loadSettings()
ui->enableFeralGamemodeCheck->setChecked(s->get("EnableFeralGamemode").toBool());
ui->enableMangoHud->setChecked(s->get("EnableMangoHud").toBool());
ui->useDiscreteGpuCheck->setChecked(s->get("UseDiscreteGpu").toBool());
ui->useZink->setChecked(s->get("UseZink").toBool());
#if !defined(Q_OS_LINUX)
ui->perfomanceGroupBox->setVisible(false);

View File

@@ -309,6 +309,16 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="useZink">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use Zink, a Mesa OpenGL driver that implements OpenGL on top of Vulkan. Performance may vary depending on the situation. Note: If no suitable Vulkan driver is found, software rendering will be used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Use Zink</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@@ -236,10 +236,13 @@ void InstanceSettingsPage::applySettings()
m_settings->set("EnableFeralGamemode", ui->enableFeralGamemodeCheck->isChecked());
m_settings->set("EnableMangoHud", ui->enableMangoHud->isChecked());
m_settings->set("UseDiscreteGpu", ui->useDiscreteGpuCheck->isChecked());
m_settings->set("UseZink", ui->useZink->isChecked());
} else {
m_settings->reset("EnableFeralGamemode");
m_settings->reset("EnableMangoHud");
m_settings->reset("UseDiscreteGpu");
m_settings->reset("UseZink");
}
// Game time
@@ -358,6 +361,7 @@ void InstanceSettingsPage::loadSettings()
ui->enableFeralGamemodeCheck->setChecked(m_settings->get("EnableFeralGamemode").toBool());
ui->enableMangoHud->setChecked(m_settings->get("EnableMangoHud").toBool());
ui->useDiscreteGpuCheck->setChecked(m_settings->get("UseDiscreteGpu").toBool());
ui->useZink->setChecked(m_settings->get("UseZink").toBool());
#if !defined(Q_OS_LINUX)
ui->settingsTabs->setTabVisible(ui->settingsTabs->indexOf(ui->performancePage), false);

View File

@@ -574,6 +574,16 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="useZink">
<property name="toolTip">
<string>Use Zink, a Mesa OpenGL driver that implements OpenGL on top of Vulkan. Performance may vary depending on the situation. Note: If no suitable Vulkan driver is found, software rendering will be used.</string>
</property>
<property name="text">
<string>Use Zink</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@@ -200,7 +200,9 @@ void ImportPage::setExtraInfo(const QMap<QString, QString>& extra_info)
void ImportPage::on_modpackBtn_clicked()
{
auto filter = QMimeDatabase().mimeTypeForName("application/zip").filterString();
const QMimeType zip = QMimeDatabase().mimeTypeForName("application/zip");
auto filter = tr("Supported files") + QString(" (%1 *.mrpack)").arg(zip.globPatterns().join(" "));
filter += ";;" + zip.filterString();
//: Option for filtering for *.mrpack files when importing
filter += ";;" + tr("Modrinth pack") + " (*.mrpack)";
const QUrl url = QFileDialog::getOpenFileUrl(this, tr("Choose modpack"), modpackUrl(), filter);