Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement GLFW/OpenAL override by defining and auto-detecting paths to library files #1392

Merged
merged 7 commits into from
Aug 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 12 additions & 0 deletions CMakeLists.txt
Scrumplex marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,18 @@ set(Launcher_SUBREDDIT_URL "https://prismlauncher.org/reddit" CACHE STRING "URL
set(Launcher_FORCE_BUNDLED_LIBS OFF CACHE BOOL "Prevent using system libraries, if they are available as submodules")
set(Launcher_QT_VERSION_MAJOR "6" CACHE STRING "Major Qt version to build against")

# Native libraries
if(UNIX AND APPLE)
set(Launcher_GLFW_LIBRARY_NAME "libglfw.dylib" CACHE STRING "Name of native glfw library")
set(Launcher_OPENAL_LIBRARY_NAME "libopenal.dylib" CACHE STRING "Name of native openal library")
elseif(UNIX)
set(Launcher_GLFW_LIBRARY_NAME "libglfw.so" CACHE STRING "Name of native glfw library")
set(Launcher_OPENAL_LIBRARY_NAME "libopenal.so" CACHE STRING "Name of native openal library")
Scrumplex marked this conversation as resolved.
Show resolved Hide resolved
elseif(WIN32)
set(Launcher_GLFW_LIBRARY_NAME "glfw.dll" CACHE STRING "Name of native glfw library")
set(Launcher_OPENAL_LIBRARY_NAME "OpenAL.dll" CACHE STRING "Name of native openal library")
endif()

# API Keys
# NOTE: These API keys are here for convenience. If you rebrand this software or intend to break the terms of service
# of these platforms, please change these API keys beforehand.
Expand Down
3 changes: 3 additions & 0 deletions buildconfig/BuildConfig.cpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ Config::Config()
FLAME_API_KEY = "@Launcher_CURSEFORGE_API_KEY@";
META_URL = "@Launcher_META_URL@";

GLFW_LIBRARY_NAME = "@Launcher_GLFW_LIBRARY_NAME@";
OPENAL_LIBRARY_NAME = "@Launcher_OPENAL_LIBRARY_NAME@";

BUG_TRACKER_URL = "@Launcher_BUG_TRACKER_URL@";
TRANSLATIONS_URL = "@Launcher_TRANSLATIONS_URL@";
MATRIX_URL = "@Launcher_MATRIX_URL@";
Expand Down
3 changes: 3 additions & 0 deletions buildconfig/BuildConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ class Config {
*/
QString META_URL;

QString GLFW_LIBRARY_NAME;
QString OPENAL_LIBRARY_NAME;

QString BUG_TRACKER_URL;
QString TRANSLATIONS_URL;
QString MATRIX_URL;
Expand Down
13 changes: 13 additions & 0 deletions launcher/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,9 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)

// Native library workarounds
m_settings->registerSetting("UseNativeOpenAL", false);
m_settings->registerSetting("CustomOpenALPath", "");
m_settings->registerSetting("UseNativeGLFW", false);
m_settings->registerSetting("CustomGLFWPath", "");

// Peformance related options
m_settings->registerSetting("EnableFeralGamemode", false);
Expand Down Expand Up @@ -842,6 +844,8 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)

updateCapabilities();

detectLibraries();

if (createSetupWizard()) {
return;
}
Expand Down Expand Up @@ -1412,6 +1416,15 @@ void Application::updateCapabilities()
#endif
}

void Application::detectLibraries()
{
#ifdef Q_OS_LINUX
m_detectedGLFWPath = MangoHud::findLibrary(BuildConfig.GLFW_LIBRARY_NAME);
m_detectedOpenALPath = MangoHud::findLibrary(BuildConfig.OPENAL_LIBRARY_NAME);
qDebug() << "Detected native libraries:" << m_detectedGLFWPath << m_detectedOpenALPath;
#endif
}

QString Application::getJarPath(QString jarFile)
{
QStringList potentialPaths = {
Expand Down
4 changes: 4 additions & 0 deletions launcher/Application.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ class Application : public QApplication {

void updateCapabilities();

void detectLibraries();

/*!
* Finds and returns the full path to a jar file.
* Returns a null-string if it could not be found.
Expand Down Expand Up @@ -275,6 +277,8 @@ class Application : public QApplication {
SetupWizard* m_setupWizard = nullptr;

public:
QString m_detectedGLFWPath;
QString m_detectedOpenALPath;
QString m_instanceIdToLaunch;
QString m_serverToJoin;
QString m_profileToUse;
Expand Down
43 changes: 43 additions & 0 deletions launcher/MangoHud.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#include <QDebug>
#include <QDir>
#include <QString>
#include <QStringList>
Expand All @@ -26,6 +27,15 @@
#include "Json.h"
#include "MangoHud.h"

#ifdef __GLIBC__
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#define UNDEF_GNU_SOURCE
#endif
#include <dlfcn.h>
#include <linux/limits.h>
#endif

namespace MangoHud {

QString getLibraryString()
Expand Down Expand Up @@ -106,4 +116,37 @@ QString getLibraryString()

return QString();
}

QString findLibrary(QString libName)
{
#ifdef __GLIBC__
const char* library = libName.toLocal8Bit().constData();

void* handle = dlopen(library, RTLD_NOW);
if (!handle) {
qCritical() << "dlopen() failed:" << dlerror();
return {};
}

char path[PATH_MAX];
if (dlinfo(handle, RTLD_DI_ORIGIN, path) == -1) {
qCritical() << "dlinfo() failed:" << dlerror();
dlclose(handle);
return {};
}

auto fullPath = FS::PathCombine(QString(path), libName);

dlclose(handle);
return fullPath;
#else
qWarning() << "MangoHud::findLibrary is not implemented on this platform";
return {};
#endif
}
TheKodeToad marked this conversation as resolved.
Show resolved Hide resolved
} // namespace MangoHud

#ifdef UNDEF_GNU_SOURCE
#undef _GNU_SOURCE
#undef UNDEF_GNU_SOURCE
#endif
4 changes: 3 additions & 1 deletion launcher/MangoHud.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@
namespace MangoHud {

QString getLibraryString();
}

QString findLibrary(QString libName);
} // namespace MangoHud
29 changes: 29 additions & 0 deletions launcher/minecraft/MinecraftInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,9 @@ void MinecraftInstance::loadSpecificSettings()
// Native library workarounds
auto nativeLibraryWorkaroundsOverride = m_settings->registerSetting("OverrideNativeWorkarounds", false);
m_settings->registerOverride(global_settings->getSetting("UseNativeOpenAL"), nativeLibraryWorkaroundsOverride);
m_settings->registerOverride(global_settings->getSetting("CustomOpenALPath"), nativeLibraryWorkaroundsOverride);
m_settings->registerOverride(global_settings->getSetting("UseNativeGLFW"), nativeLibraryWorkaroundsOverride);
m_settings->registerOverride(global_settings->getSetting("CustomGLFWPath"), nativeLibraryWorkaroundsOverride);

// Peformance related options
auto performanceOverride = m_settings->registerSetting("OverridePerformance", false);
Expand Down Expand Up @@ -389,6 +391,33 @@ QStringList MinecraftInstance::extraArguments()
if (loaders.has_value() && loaders.value() & ResourceAPI::Quilt && settings()->get("DisableQuiltBeacon").toBool())
list.append("-Dloader.disable_beacon=true");
}

{
QString openALPath;
QString glfwPath;

if (settings()->get("UseNativeOpenAL").toBool()) {
openALPath = APPLICATION->m_detectedOpenALPath;
auto customPath = settings()->get("CustomOpenALPath").toString();
if (!customPath.isEmpty())
openALPath = customPath;
}
if (settings()->get("UseNativeGLFW").toBool()) {
glfwPath = APPLICATION->m_detectedGLFWPath;
auto customPath = settings()->get("CustomGLFWPath").toString();
if (!customPath.isEmpty())
glfwPath = customPath;
}

QFileInfo openALInfo(openALPath);
QFileInfo glfwInfo(glfwPath);

if (!openALPath.isEmpty() && openALInfo.exists())
list.append("-Dorg.lwjgl.openal.libname=" + openALInfo.absoluteFilePath());
if (!glfwPath.isEmpty() && glfwInfo.exists())
list.append("-Dorg.lwjgl.glfw.libname=" + glfwInfo.absoluteFilePath());
}

return list;
}

Expand Down
12 changes: 2 additions & 10 deletions launcher/minecraft/launch/ExtractNatives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ static QString replaceSuffix(QString target, const QString& suffix, const QStrin
return target + replacement;
}

static bool unzipNatives(QString source, QString targetFolder, bool applyJnilibHack, bool nativeOpenAL, bool nativeGLFW)
static bool unzipNatives(QString source, QString targetFolder, bool applyJnilibHack)
{
QuaZip zip(source);
if (!zip.open(QuaZip::mdUnzip)) {
Expand All @@ -52,12 +52,6 @@ static bool unzipNatives(QString source, QString targetFolder, bool applyJnilibH
do {
QString name = zip.getCurrentFileName();
auto lowercase = name.toLower();
if (nativeGLFW && name.contains("glfw")) {
continue;
}
if (nativeOpenAL && name.contains("openal")) {
continue;
}
if (applyJnilibHack) {
name = replaceSuffix(name, ".jnilib", ".dylib");
}
Expand All @@ -83,14 +77,12 @@ void ExtractNatives::executeTask()
return;
}
auto settings = minecraftInstance->settings();
bool nativeOpenAL = settings->get("UseNativeOpenAL").toBool();
bool nativeGLFW = settings->get("UseNativeGLFW").toBool();

auto outputPath = minecraftInstance->getNativePath();
auto javaVersion = minecraftInstance->getJavaVersion();
bool jniHackEnabled = javaVersion.major() >= 8;
for (const auto& source : toExtract) {
if (!unzipNatives(source, outputPath, jniHackEnabled, nativeOpenAL, nativeGLFW)) {
if (!unzipNatives(source, outputPath, jniHackEnabled)) {
const char* reason = QT_TR_NOOP("Couldn't extract native jar '%1' to destination '%2'");
emit logLine(QString(reason).arg(source, outputPath), MessageLevel::Fatal);
emitFailed(tr(reason).arg(source, outputPath));
Expand Down
35 changes: 33 additions & 2 deletions launcher/ui/pages/global/MinecraftPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
*/

#include "MinecraftPage.h"
#include "BuildConfig.h"
#include "ui_MinecraftPage.h"

#include <QDir>
Expand All @@ -44,9 +45,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();
}
Expand Down Expand Up @@ -74,6 +81,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();
Expand All @@ -84,8 +101,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());
Expand Down Expand Up @@ -114,8 +133,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());
Expand Down
3 changes: 3 additions & 0 deletions launcher/ui/pages/global/MinecraftPage.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
40 changes: 37 additions & 3 deletions launcher/ui/pages/global/MinecraftPage.ui
Original file line number Diff line number Diff line change
Expand Up @@ -214,21 +214,55 @@
<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>
Scrumplex marked this conversation as resolved.
Show resolved Hide resolved
</layout>
</widget>
</item>
Expand Down