2023-10-11 18:01:30 -04:00
|
|
|
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
2023-10-11 14:30:21 -04:00
|
|
|
|
2023-10-11 18:01:30 -04:00
|
|
|
#include "gamerunner.h"
|
2023-10-11 14:30:21 -04:00
|
|
|
|
|
|
|
#ifdef ENABLE_GAMEMODE
|
|
|
|
#include <gamemode_client.h>
|
|
|
|
#endif
|
|
|
|
|
2024-07-30 19:15:37 -04:00
|
|
|
#include "astra_log.h"
|
2023-10-11 14:30:21 -04:00
|
|
|
#include "encryptedarg.h"
|
|
|
|
#include "launchercore.h"
|
|
|
|
#include "processlogger.h"
|
2024-07-30 19:15:37 -04:00
|
|
|
#include "processwatcher.h"
|
2023-10-11 14:30:21 -04:00
|
|
|
#include "utility.h"
|
|
|
|
|
2024-11-09 14:45:51 -05:00
|
|
|
#include <KProcessList>
|
|
|
|
|
2023-12-17 12:01:28 -05:00
|
|
|
using namespace Qt::StringLiterals;
|
|
|
|
|
2023-10-11 14:30:21 -04:00
|
|
|
GameRunner::GameRunner(LauncherCore &launcher, QObject *parent)
|
|
|
|
: QObject(parent)
|
|
|
|
, m_launcher(launcher)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2024-04-19 20:29:28 -04:00
|
|
|
void GameRunner::beginGameExecutable(Profile &profile, const std::optional<LoginAuth> &auth)
|
2023-10-11 14:30:21 -04:00
|
|
|
{
|
|
|
|
QString gameExectuable;
|
2024-03-23 12:51:48 -04:00
|
|
|
if (profile.directx9Enabled() && profile.hasDirectx9()) {
|
2023-10-11 14:30:21 -04:00
|
|
|
gameExectuable = profile.gamePath() + QStringLiteral("/game/ffxiv.exe");
|
|
|
|
} else {
|
|
|
|
gameExectuable = profile.gamePath() + QStringLiteral("/game/ffxiv_dx11.exe");
|
|
|
|
}
|
|
|
|
|
2024-06-27 16:38:18 -04:00
|
|
|
if (profile.dalamudShouldLaunch()) {
|
2023-10-11 14:30:21 -04:00
|
|
|
beginDalamudGame(gameExectuable, profile, auth);
|
|
|
|
} else {
|
|
|
|
beginVanillaGame(gameExectuable, profile, auth);
|
|
|
|
}
|
|
|
|
|
|
|
|
Q_EMIT m_launcher.successfulLaunch();
|
|
|
|
}
|
|
|
|
|
2024-04-19 20:29:28 -04:00
|
|
|
void GameRunner::beginVanillaGame(const QString &gameExecutablePath, Profile &profile, const std::optional<LoginAuth> &auth)
|
2023-10-11 14:30:21 -04:00
|
|
|
{
|
|
|
|
profile.setLoggedIn(true);
|
|
|
|
|
2024-07-04 20:53:06 -04:00
|
|
|
const auto gameProcess = new QProcess(this);
|
2023-10-11 14:30:21 -04:00
|
|
|
gameProcess->setProcessEnvironment(QProcessEnvironment::systemEnvironment());
|
2024-07-04 20:53:06 -04:00
|
|
|
connect(gameProcess, &QProcess::finished, this, [this, &profile](const int exitCode) {
|
2023-10-11 14:30:21 -04:00
|
|
|
profile.setLoggedIn(false);
|
|
|
|
Q_UNUSED(exitCode)
|
2024-07-30 19:47:26 -04:00
|
|
|
Q_EMIT m_launcher.gameClosed(&profile);
|
2023-10-11 14:30:21 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
auto args = getGameArgs(profile, auth);
|
|
|
|
|
2024-07-30 19:15:37 -04:00
|
|
|
new ProcessLogger(QStringLiteral("ffxiv"), gameProcess);
|
2023-10-11 14:30:21 -04:00
|
|
|
|
|
|
|
launchExecutable(profile, gameProcess, {gameExecutablePath, args}, true, true);
|
|
|
|
}
|
|
|
|
|
2024-04-19 20:29:28 -04:00
|
|
|
void GameRunner::beginDalamudGame(const QString &gameExecutablePath, Profile &profile, const std::optional<LoginAuth> &auth)
|
2023-10-11 14:30:21 -04:00
|
|
|
{
|
|
|
|
profile.setLoggedIn(true);
|
|
|
|
|
|
|
|
const QDir dataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
|
|
|
const QDir configDir = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
|
|
|
|
const QDir dalamudDir = dataDir.absoluteFilePath(QStringLiteral("dalamud"));
|
|
|
|
|
|
|
|
const QDir dalamudConfigDir = configDir.absoluteFilePath(QStringLiteral("dalamud"));
|
|
|
|
const QDir userDalamudConfigDir = dalamudConfigDir.absoluteFilePath(profile.account()->uuid());
|
|
|
|
|
|
|
|
const QDir dalamudBasePluginDir = dalamudDir.absoluteFilePath(QStringLiteral("plugins"));
|
|
|
|
const QDir dalamudUserPluginDir = dalamudBasePluginDir.absoluteFilePath(profile.account()->uuid());
|
|
|
|
|
|
|
|
// Some really dumb plugins check for "installedPlugins" in their assembly directory FOR SOME REASON,
|
|
|
|
// so we need to match typical XIVQuickLauncher behavior here. Why? I have no clue.
|
|
|
|
const QDir dalamudPluginDir = dalamudUserPluginDir.absoluteFilePath(QStringLiteral("installedPlugins"));
|
|
|
|
|
2024-07-30 19:15:37 -04:00
|
|
|
const QDir logDir = dataDir.absoluteFilePath(QStringLiteral("log"));
|
2023-12-17 12:01:28 -05:00
|
|
|
Utility::createPathIfNeeded(logDir);
|
2023-10-11 14:30:21 -04:00
|
|
|
|
|
|
|
const QDir dalamudRuntimeDir = dalamudDir.absoluteFilePath(QStringLiteral("runtime"));
|
|
|
|
const QDir dalamudAssetDir = dalamudDir.absoluteFilePath(QStringLiteral("assets"));
|
|
|
|
const QDir dalamudConfigPath = userDalamudConfigDir.absoluteFilePath(QStringLiteral("dalamud-config.json"));
|
|
|
|
|
|
|
|
const QDir dalamudInstallDir = dalamudDir.absoluteFilePath(profile.dalamudChannelName());
|
|
|
|
const QString dalamudInjector = dalamudInstallDir.absoluteFilePath(QStringLiteral("Dalamud.Injector.exe"));
|
|
|
|
|
2024-07-04 20:53:06 -04:00
|
|
|
const auto dalamudProcess = new QProcess(this);
|
2024-07-30 19:15:37 -04:00
|
|
|
connect(dalamudProcess, &QProcess::finished, this, [this, &profile, logDir](const int exitCode) {
|
2023-10-11 14:30:21 -04:00
|
|
|
Q_UNUSED(exitCode)
|
2024-07-30 19:15:37 -04:00
|
|
|
|
|
|
|
// So here's the kicker, we can't depend on Dalamud to give us an accurate finished signal for the game.
|
|
|
|
// finished() is called when the injector exits.
|
|
|
|
|
|
|
|
// so what we'll do instead is get the game PID from Dalamud first.
|
|
|
|
QFile logFile(logDir.absoluteFilePath(QStringLiteral("dalamud-initial-injection.log")));
|
|
|
|
logFile.open(QIODevice::ReadOnly);
|
|
|
|
|
|
|
|
const static QRegularExpression pidRegex(QStringLiteral("{\"pid\": (\\d*),"));
|
|
|
|
const QString log = QString::fromUtf8(logFile.readAll());
|
|
|
|
|
|
|
|
const auto match = pidRegex.match(log);
|
|
|
|
if (match.hasCaptured(1)) {
|
2024-11-09 14:45:51 -05:00
|
|
|
qint64 PID = match.captured(1).toInt();
|
2024-07-30 19:15:37 -04:00
|
|
|
if (PID > 0) {
|
|
|
|
qCInfo(ASTRA_LOG) << "Recieved PID from Dalamud:" << PID;
|
2024-11-09 14:45:51 -05:00
|
|
|
#if defined(Q_OS_LINUX) || defined(Q_OS_MAC)
|
|
|
|
// Dalamud gives us a Windows PID, but that's useless to us. We need to find the PID of the game now:
|
|
|
|
|
|
|
|
const auto info = KProcessList::processInfoList();
|
|
|
|
for (const auto &entry : info) {
|
|
|
|
if (entry.name().contains(QLatin1String("ffxiv"))) {
|
|
|
|
qCInfo(ASTRA_LOG) << "Using PID of" << entry.name() << "which is" << entry.pid();
|
|
|
|
PID = entry.pid();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
2024-07-30 19:15:37 -04:00
|
|
|
auto watcher = new ProcessWatcher(PID);
|
|
|
|
connect(watcher, &ProcessWatcher::finished, this, [this, &profile] {
|
|
|
|
profile.setLoggedIn(false);
|
2024-07-30 19:47:26 -04:00
|
|
|
Q_EMIT m_launcher.gameClosed(&profile);
|
2024-07-30 19:15:37 -04:00
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If Dalamud didn't give a valid PID, OK. Let's just do our previous status quo and inidcate we did log out.
|
|
|
|
profile.setLoggedIn(false);
|
2024-07-30 19:47:26 -04:00
|
|
|
Q_EMIT m_launcher.gameClosed(&profile);
|
2023-10-11 14:30:21 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
|
|
|
env.insert(QStringLiteral("DALAMUD_RUNTIME"), Utility::toWindowsPath(dalamudRuntimeDir));
|
|
|
|
|
|
|
|
#if defined(Q_OS_LINUX) || defined(Q_OS_MAC)
|
|
|
|
env.insert(QStringLiteral("XL_WINEONLINUX"), QStringLiteral("true"));
|
|
|
|
#endif
|
|
|
|
dalamudProcess->setProcessEnvironment(env);
|
|
|
|
|
2024-07-30 19:15:37 -04:00
|
|
|
new ProcessLogger(QStringLiteral("dalamud-initial-injection"), dalamudProcess);
|
2023-10-11 14:30:21 -04:00
|
|
|
|
|
|
|
const auto args = getGameArgs(profile, auth);
|
|
|
|
|
|
|
|
launchExecutable(profile,
|
|
|
|
dalamudProcess,
|
|
|
|
{Utility::toWindowsPath(dalamudInjector),
|
|
|
|
QStringLiteral("launch"),
|
|
|
|
QStringLiteral("-m"),
|
|
|
|
profile.dalamudInjectMethod() == Profile::DalamudInjectMethod::Entrypoint ? QStringLiteral("entrypoint") : QStringLiteral("inject"),
|
|
|
|
QStringLiteral("--game=") + Utility::toWindowsPath(gameExecutablePath),
|
|
|
|
QStringLiteral("--dalamud-configuration-path=") + Utility::toWindowsPath(dalamudConfigPath),
|
|
|
|
QStringLiteral("--dalamud-plugin-directory=") + Utility::toWindowsPath(dalamudPluginDir),
|
|
|
|
QStringLiteral("--dalamud-asset-directory=") + Utility::toWindowsPath(dalamudAssetDir),
|
|
|
|
QStringLiteral("--dalamud-client-language=") + QString::number(profile.account()->language()),
|
|
|
|
QStringLiteral("--dalamud-delay-initialize=") + QString::number(profile.dalamudInjectDelay()),
|
|
|
|
QStringLiteral("--logpath=") + Utility::toWindowsPath(logDir),
|
|
|
|
QStringLiteral("--"),
|
|
|
|
args},
|
|
|
|
true,
|
|
|
|
true);
|
|
|
|
}
|
|
|
|
|
2024-07-04 20:53:06 -04:00
|
|
|
QString GameRunner::getGameArgs(const Profile &profile, const std::optional<LoginAuth> &auth) const
|
2023-10-11 14:30:21 -04:00
|
|
|
{
|
2023-12-17 12:01:28 -05:00
|
|
|
QList<std::pair<QString, QString>> gameArgs;
|
2023-10-11 14:30:21 -04:00
|
|
|
|
2024-06-27 16:38:18 -04:00
|
|
|
if (profile.isBenchmark()) {
|
2024-04-19 20:29:28 -04:00
|
|
|
gameArgs.push_back({QStringLiteral("SYS.Language"), QString::number(1)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.Fps"), QString::number(0)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.WaterWet_DX11"), QString::number(1)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.OcclusionCulling_DX11"), QString::number(0)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.LodType_DX11"), QString::number(0)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.ReflectionType_DX11"), QString::number(3)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.AntiAliasing_DX11"), QString::number(1)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.TranslucentQuality_DX11"), QString::number(1)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.GrassQuality_DX11"), QString::number(3)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.ShadowLOD_DX11"), QString::number(0)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.ShadowVisibilityTypeSelf_DX11"), QString::number(1)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.ShadowVisibilityTypeOther_DX11"), QString::number(1)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.ShadowTextureSizeType_DX11"), QString::number(2)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.ShadowCascadeCountType_DX11"), QString::number(2)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.ShadowSoftShadowType_DX11"), QString::number(1)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.PhysicsTypeSelf_DX11"), QString::number(2)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.PhysicsTypeOther_DX11"), QString::number(2)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.TextureFilterQuality_DX11"), QString::number(2)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.TextureAnisotropicQuality_DX11"), QString::number(2)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.Vignetting_DX11"), QString::number(1)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.RadialBlur_DX11"), QString::number(1)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.SSAO_DX11"), QString::number(2)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.Glare_DX11"), QString::number(2)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.DepthOfField_DX11"), QString::number(1)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.ParallaxOcclusion_DX11"), QString::number(1)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.Tessellation_DX11"), QString::number(0)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.GlareRepresentation_DX11"), QString::number(1)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.DistortionWater_DX11"), QString::number(2)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.ScreenMode"), QString::number(0)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.ScreenWidth"), QString::number(1920)});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.ScreenHeight"), QString::number(1080)});
|
2024-06-27 16:38:18 -04:00
|
|
|
} else {
|
|
|
|
gameArgs.push_back({QStringLiteral("DEV.DataPathType"), QString::number(1)});
|
|
|
|
gameArgs.push_back({QStringLiteral("DEV.UseSqPack"), QString::number(1)});
|
|
|
|
gameArgs.push_back({QStringLiteral("ver"), profile.baseGameVersion()});
|
|
|
|
gameArgs.push_back({QStringLiteral("resetconfig"), QStringLiteral("0")});
|
|
|
|
gameArgs.push_back({QStringLiteral("language"), QString::number(profile.account()->language())});
|
|
|
|
gameArgs.push_back({QStringLiteral("UserPath"), Utility::toWindowsPath(profile.account()->getConfigDir().absolutePath())});
|
|
|
|
|
|
|
|
Utility::createPathIfNeeded(profile.account()->getConfigDir().absolutePath());
|
|
|
|
|
|
|
|
if (auth) {
|
|
|
|
gameArgs.push_back({QStringLiteral("DEV.MaxEntitledExpansionID"), QString::number(auth->maxExpansion)});
|
|
|
|
gameArgs.push_back({QStringLiteral("DEV.TestSID"), auth->SID});
|
|
|
|
gameArgs.push_back({QStringLiteral("SYS.Region"), QString::number(auth->region)});
|
|
|
|
} else {
|
|
|
|
// fallback just needed to get to the title screen
|
2024-06-27 20:31:41 -04:00
|
|
|
gameArgs.push_back({QStringLiteral("DEV.MaxEntitledExpansionID"), QString::number(2)});
|
|
|
|
gameArgs.push_back({QStringLiteral("DEV.TestSID"), QString::number(0)});
|
2024-06-27 16:38:18 -04:00
|
|
|
gameArgs.push_back({QStringLiteral("SYS.Region"), QString::number(1)});
|
|
|
|
}
|
2024-04-19 20:29:28 -04:00
|
|
|
}
|
2023-10-11 14:30:21 -04:00
|
|
|
|
|
|
|
// FIXME: this should belong somewhere else...
|
2024-05-18 14:30:07 -04:00
|
|
|
if (LauncherCore::needsCompatibilityTool())
|
|
|
|
Utility::createPathIfNeeded(profile.winePrefixPath());
|
2023-10-11 14:30:21 -04:00
|
|
|
|
2024-04-19 20:29:28 -04:00
|
|
|
if (auth) {
|
2025-03-08 13:51:26 -05:00
|
|
|
if (!auth->lobbyHost.isEmpty()) {
|
2024-04-19 20:29:28 -04:00
|
|
|
gameArgs.push_back({QStringLiteral("DEV.GMServerHost"), auth->frontierHost});
|
|
|
|
for (int i = 1; i < 9; i++) {
|
2025-03-08 13:51:26 -05:00
|
|
|
gameArgs.push_back({QStringLiteral("DEV.LobbyHost0%1").arg(QString::number(i)), auth->lobbyHost});
|
|
|
|
gameArgs.push_back({QStringLiteral("DEV.LobbyPort0%1").arg(QString::number(i)), QString::number(auth->lobbyHostPort)});
|
2024-04-19 20:29:28 -04:00
|
|
|
}
|
2023-10-11 14:30:21 -04:00
|
|
|
}
|
|
|
|
|
2024-04-19 20:29:28 -04:00
|
|
|
if (profile.account()->license() == Account::GameLicense::WindowsSteam) {
|
|
|
|
gameArgs.push_back({QStringLiteral("IsSteam"), QString::number(1)});
|
|
|
|
}
|
2023-10-11 14:30:21 -04:00
|
|
|
}
|
|
|
|
|
2024-04-19 20:29:28 -04:00
|
|
|
const QString argFormat = !profile.isBenchmark() && m_launcher.settings()->argumentsEncrypted() ? QStringLiteral(" /%1 =%2") : QStringLiteral(" %1=%2");
|
2023-10-11 14:30:21 -04:00
|
|
|
|
|
|
|
QString argJoined;
|
2023-12-17 12:01:28 -05:00
|
|
|
for (const auto &[key, value] : gameArgs) {
|
|
|
|
argJoined += argFormat.arg(key, value);
|
2023-10-11 14:30:21 -04:00
|
|
|
}
|
|
|
|
|
2024-04-19 20:29:28 -04:00
|
|
|
return !profile.isBenchmark() && m_launcher.settings()->argumentsEncrypted() ? encryptGameArg(argJoined) : argJoined;
|
2023-10-11 14:30:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void GameRunner::launchExecutable(const Profile &profile, QProcess *process, const QStringList &args, bool isGame, bool needsRegistrySetup)
|
|
|
|
{
|
|
|
|
QList<QString> arguments;
|
|
|
|
auto env = process->processEnvironment();
|
|
|
|
|
|
|
|
if (needsRegistrySetup) {
|
|
|
|
#if defined(Q_OS_LINUX) || defined(Q_OS_MAC)
|
2023-12-17 12:01:28 -05:00
|
|
|
// FFXIV detects this as a "macOS" build by checking if Wine shows up
|
2024-04-19 20:29:28 -04:00
|
|
|
if (!profile.isBenchmark()) {
|
|
|
|
const int value = profile.account()->license() == Account::GameLicense::macOS ? 0 : 1;
|
|
|
|
addRegistryKey(profile, QStringLiteral("HKEY_CURRENT_USER\\Software\\Wine"), QStringLiteral("HideWineExports"), QString::number(value));
|
|
|
|
}
|
2023-12-20 20:19:48 -05:00
|
|
|
|
2023-12-23 11:11:02 -05:00
|
|
|
setWindowsVersion(profile, QStringLiteral("win7"));
|
|
|
|
|
2023-12-31 17:19:29 -05:00
|
|
|
// TODO: band-aid fix to wait for wine to exit, otherwise gamescope will collide
|
|
|
|
QThread::sleep(2);
|
|
|
|
|
2023-12-20 20:19:48 -05:00
|
|
|
// copy DXVK
|
|
|
|
const QDir dataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
2023-12-20 20:20:20 -05:00
|
|
|
const QDir compatibilityToolDir = dataDir.absoluteFilePath(QStringLiteral("tool"));
|
2023-12-20 20:19:48 -05:00
|
|
|
const QDir dxvkDir = compatibilityToolDir.absoluteFilePath(QStringLiteral("dxvk"));
|
|
|
|
const QDir dxvk64Dir = dxvkDir.absoluteFilePath(QStringLiteral("x64"));
|
|
|
|
|
|
|
|
const QDir winePrefix = profile.winePrefixPath();
|
|
|
|
const QDir driveC = winePrefix.absoluteFilePath(QStringLiteral("drive_c"));
|
|
|
|
const QDir windows = driveC.absoluteFilePath(QStringLiteral("windows"));
|
|
|
|
const QDir system32 = windows.absoluteFilePath(QStringLiteral("system32"));
|
|
|
|
|
2023-12-20 21:05:39 -05:00
|
|
|
for (const auto &entry : dxvk64Dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot)) {
|
2023-12-20 21:07:52 -05:00
|
|
|
if (QFile::exists(system32.absoluteFilePath(entry.fileName()))) {
|
|
|
|
QFile::remove(system32.absoluteFilePath(entry.fileName()));
|
|
|
|
}
|
2023-12-20 20:19:48 -05:00
|
|
|
QFile::copy(entry.absoluteFilePath(), system32.absoluteFilePath(entry.fileName()));
|
|
|
|
}
|
2023-10-11 14:30:21 -04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2023-12-20 18:02:36 -05:00
|
|
|
if (isGame && profile.gamescopeEnabled()) {
|
|
|
|
arguments.push_back(QStringLiteral("gamescope"));
|
2023-10-11 14:30:21 -04:00
|
|
|
|
2023-12-20 18:02:36 -05:00
|
|
|
if (profile.gamescopeFullscreen())
|
|
|
|
arguments.push_back(QStringLiteral("-f"));
|
2023-10-11 14:30:21 -04:00
|
|
|
|
2023-12-20 18:02:36 -05:00
|
|
|
if (profile.gamescopeBorderless())
|
|
|
|
arguments.push_back(QStringLiteral("-b"));
|
2023-10-11 14:30:21 -04:00
|
|
|
|
2023-12-31 17:19:29 -05:00
|
|
|
if (profile.gamescopeWidth() > 0) {
|
|
|
|
arguments.push_back(QStringLiteral("-w"));
|
|
|
|
arguments.push_back(QString::number(profile.gamescopeWidth()));
|
|
|
|
}
|
2023-10-11 14:30:21 -04:00
|
|
|
|
2023-12-31 17:19:29 -05:00
|
|
|
if (profile.gamescopeHeight() > 0) {
|
|
|
|
arguments.push_back(QStringLiteral("-h"));
|
|
|
|
arguments.push_back(QString::number(profile.gamescopeHeight()));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (profile.gamescopeRefreshRate() > 0) {
|
|
|
|
arguments.push_back(QStringLiteral("-r"));
|
|
|
|
arguments.push_back(QString::number(profile.gamescopeRefreshRate()));
|
|
|
|
}
|
2023-10-11 14:30:21 -04:00
|
|
|
|
2023-12-31 17:19:29 -05:00
|
|
|
arguments.push_back(QStringLiteral("--"));
|
2023-10-11 14:30:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef ENABLE_GAMEMODE
|
|
|
|
if (isGame && profile.gamemodeEnabled()) {
|
|
|
|
gamemode_request_start();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2024-04-19 20:37:51 -04:00
|
|
|
if (m_launcher.settings()->enableRenderDocCapture()) {
|
|
|
|
env.insert(QStringLiteral("VK_LAYER_RENDERDOC_Capture"), QStringLiteral("VK_LAYER_RENDERDOC_Capture"));
|
|
|
|
env.insert(QStringLiteral("ENABLE_VULKAN_RENDERDOC_CAPTURE"), QString::number(1));
|
|
|
|
}
|
|
|
|
|
2023-10-11 14:30:21 -04:00
|
|
|
#if defined(Q_OS_LINUX)
|
2023-12-20 18:00:40 -05:00
|
|
|
env.insert(QStringLiteral("WINEESYNC"), QString::number(1));
|
|
|
|
env.insert(QStringLiteral("WINEFSYNC"), QString::number(1));
|
|
|
|
env.insert(QStringLiteral("WINEFSYNC_FUTEX2"), QString::number(1));
|
|
|
|
|
2023-12-31 17:23:55 -05:00
|
|
|
const QDir dataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
|
|
|
const QString logDir = dataDir.absoluteFilePath(QStringLiteral("log"));
|
2023-10-11 14:30:21 -04:00
|
|
|
|
|
|
|
env.insert(QStringLiteral("DXVK_LOG_PATH"), logDir);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(Q_OS_MAC) || defined(Q_OS_LINUX)
|
2023-12-20 18:02:36 -05:00
|
|
|
env.insert(QStringLiteral("WINEPREFIX"), profile.winePrefixPath());
|
2023-10-11 14:30:21 -04:00
|
|
|
|
2023-12-20 20:19:48 -05:00
|
|
|
if (profile.wineType() == Profile::WineType::BuiltIn) {
|
2023-12-20 21:05:39 -05:00
|
|
|
env.insert(QStringLiteral("WINEDLLOVERRIDES"), QStringLiteral("msquic=,mscoree=n,b;d3d9,d3d11,d3d10core,dxgi=n,b"));
|
2023-12-20 20:19:48 -05:00
|
|
|
}
|
|
|
|
|
2023-12-20 18:02:36 -05:00
|
|
|
arguments.push_back(profile.winePath());
|
2023-10-11 14:30:21 -04:00
|
|
|
#endif
|
|
|
|
|
2024-04-19 20:29:28 -04:00
|
|
|
if (!profile.isBenchmark() && profile.account()->license() == Account::GameLicense::WindowsSteam) {
|
2023-12-23 10:32:54 -05:00
|
|
|
env.insert(QStringLiteral("IS_FFXIV_LAUNCH_FROM_STEAM"), QStringLiteral("1"));
|
|
|
|
}
|
|
|
|
|
2023-10-11 14:30:21 -04:00
|
|
|
arguments.append(args);
|
|
|
|
|
2023-12-23 11:13:52 -05:00
|
|
|
const QString executable = arguments.takeFirst();
|
2023-10-11 14:30:21 -04:00
|
|
|
|
2024-04-19 20:29:28 -04:00
|
|
|
if (isGame) {
|
|
|
|
if (profile.isBenchmark()) {
|
|
|
|
// Benchmarks usually have some data located in the root
|
|
|
|
process->setWorkingDirectory(profile.gamePath());
|
|
|
|
} else {
|
|
|
|
process->setWorkingDirectory(profile.gamePath() + QStringLiteral("/game/"));
|
|
|
|
}
|
|
|
|
}
|
2023-10-11 14:30:21 -04:00
|
|
|
|
|
|
|
process->setProcessEnvironment(env);
|
|
|
|
|
2023-12-31 17:19:29 -05:00
|
|
|
process->setProgram(executable);
|
|
|
|
process->setArguments(arguments);
|
2023-12-23 11:11:02 -05:00
|
|
|
|
2023-12-31 17:19:29 -05:00
|
|
|
process->start();
|
2023-10-11 14:30:21 -04:00
|
|
|
}
|
|
|
|
|
2023-12-23 11:11:02 -05:00
|
|
|
void GameRunner::addRegistryKey(const Profile &settings, const QString &key, const QString &value, const QString &data)
|
2023-10-11 14:30:21 -04:00
|
|
|
{
|
2024-07-04 20:53:06 -04:00
|
|
|
const auto process = new QProcess(this);
|
2023-10-11 14:30:21 -04:00
|
|
|
process->setProcessEnvironment(QProcessEnvironment::systemEnvironment());
|
|
|
|
launchExecutable(settings,
|
|
|
|
process,
|
2023-12-23 11:11:02 -05:00
|
|
|
{QStringLiteral("reg"), QStringLiteral("add"), key, QStringLiteral("/v"), value, QStringLiteral("/d"), data, QStringLiteral("/f")},
|
2023-10-11 14:30:21 -04:00
|
|
|
false,
|
|
|
|
false);
|
2023-12-31 17:19:29 -05:00
|
|
|
process->waitForFinished();
|
2023-12-23 11:11:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void GameRunner::setWindowsVersion(const Profile &settings, const QString &version)
|
|
|
|
{
|
2024-07-04 20:53:06 -04:00
|
|
|
const auto process = new QProcess(this);
|
2023-12-23 11:11:02 -05:00
|
|
|
process->setProcessEnvironment(QProcessEnvironment::systemEnvironment());
|
|
|
|
launchExecutable(settings, process, {QStringLiteral("winecfg"), QStringLiteral("/v"), version}, false, false);
|
2023-12-31 17:19:29 -05:00
|
|
|
process->waitForFinished();
|
2024-11-09 14:45:51 -05:00
|
|
|
}
|