2023-08-05 22:14:05 -04:00
|
|
|
// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
|
2023-07-30 08:49:34 -04:00
|
|
|
#include "gameinstaller.h"
|
|
|
|
|
2023-09-17 08:31:24 -04:00
|
|
|
#include <KLocalizedString>
|
2023-07-30 08:49:34 -04:00
|
|
|
#include <QDir>
|
|
|
|
#include <QNetworkAccessManager>
|
|
|
|
#include <QProcess>
|
|
|
|
#include <QStandardPaths>
|
|
|
|
#include <algorithm>
|
2023-09-16 18:37:42 -04:00
|
|
|
#include <qcoronetworkreply.h>
|
2023-07-30 08:49:34 -04:00
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
#ifdef ENABLE_GAMEMODE
|
|
|
|
#include <gamemode_client.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "account.h"
|
|
|
|
#include "assetupdater.h"
|
2023-08-18 23:27:29 -04:00
|
|
|
#include "compatibilitytoolinstaller.h"
|
2023-07-30 08:49:34 -04:00
|
|
|
#include "config.h"
|
|
|
|
#include "encryptedarg.h"
|
|
|
|
#include "launchercore.h"
|
|
|
|
#include "sapphirelauncher.h"
|
|
|
|
#include "squarelauncher.h"
|
2023-08-18 14:52:06 -04:00
|
|
|
#include "utility.h"
|
2023-07-30 08:49:34 -04:00
|
|
|
|
|
|
|
void LauncherCore::setSSL(QNetworkRequest &request)
|
|
|
|
{
|
|
|
|
QSslConfiguration config;
|
|
|
|
config.setProtocol(QSsl::AnyProtocol);
|
|
|
|
config.setPeerVerifyMode(QSslSocket::VerifyNone);
|
|
|
|
|
|
|
|
request.setSslConfiguration(config);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LauncherCore::buildRequest(const Profile &settings, QNetworkRequest &request)
|
|
|
|
{
|
|
|
|
setSSL(request);
|
|
|
|
|
|
|
|
if (settings.account()->license() == Account::GameLicense::macOS) {
|
2023-09-17 08:31:24 -04:00
|
|
|
request.setHeader(QNetworkRequest::UserAgentHeader, QByteArrayLiteral("macSQEXAuthor/2.0.0(MacOSX; ja-jp)"));
|
2023-07-30 08:49:34 -04:00
|
|
|
} else {
|
2023-09-17 08:31:24 -04:00
|
|
|
request.setHeader(QNetworkRequest::UserAgentHeader, QStringLiteral("SQEXAuthor/2.0.0(Windows 6.2; ja-jp; %1)").arg(QString(QSysInfo::bootUniqueId())));
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
|
|
|
|
2023-09-17 08:31:24 -04:00
|
|
|
request.setRawHeader(QByteArrayLiteral("Accept"),
|
|
|
|
QByteArrayLiteral("image/gif, image/jpeg, image/pjpeg, application/x-ms-application, application/xaml+xml, "
|
|
|
|
"application/x-ms-xbap, */*"));
|
|
|
|
request.setRawHeader(QByteArrayLiteral("Accept-Encoding"), QByteArrayLiteral("gzip, deflate"));
|
|
|
|
request.setRawHeader(QByteArrayLiteral("Accept-Language"), QByteArrayLiteral("en-us"));
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
|
|
|
|
2023-09-17 19:30:22 -04:00
|
|
|
void LauncherCore::launchGame(Profile &profile, const LoginAuth &auth)
|
2023-07-30 08:49:34 -04:00
|
|
|
{
|
2023-09-17 08:31:24 -04:00
|
|
|
m_steamApi->setLauncherMode(false);
|
2023-07-30 08:49:34 -04:00
|
|
|
|
|
|
|
beginGameExecutable(profile, auth);
|
|
|
|
}
|
|
|
|
|
2023-09-17 18:43:58 -04:00
|
|
|
QCoro::Task<> LauncherCore::beginLogin(LoginInformation &info)
|
|
|
|
{
|
|
|
|
qDebug() << "Logging in, performing asset update check.";
|
|
|
|
|
|
|
|
auto assetUpdater = new AssetUpdater(*info.profile, *this, this);
|
|
|
|
co_await assetUpdater->update();
|
|
|
|
|
|
|
|
if (info.profile->account()->isSapphire()) {
|
|
|
|
m_sapphireLauncher->login(info.profile->account()->lobbyUrl(), info);
|
|
|
|
} else {
|
|
|
|
m_squareBoot->checkGateStatus(info);
|
|
|
|
}
|
|
|
|
|
|
|
|
assetUpdater->deleteLater();
|
|
|
|
}
|
|
|
|
|
2023-09-17 19:30:22 -04:00
|
|
|
void LauncherCore::beginGameExecutable(Profile &profile, const LoginAuth &auth)
|
2023-07-30 08:49:34 -04:00
|
|
|
{
|
2023-09-17 08:31:24 -04:00
|
|
|
Q_EMIT stageChanged(i18n("Launching game..."));
|
2023-07-31 19:23:28 -04:00
|
|
|
|
2023-07-30 08:49:34 -04:00
|
|
|
QString gameExectuable;
|
|
|
|
if (profile.directx9Enabled()) {
|
2023-09-17 08:31:24 -04:00
|
|
|
gameExectuable = profile.gamePath() + QStringLiteral("/game/ffxiv.exe");
|
2023-07-30 08:49:34 -04:00
|
|
|
} else {
|
2023-09-17 08:31:24 -04:00
|
|
|
gameExectuable = profile.gamePath() + QStringLiteral("/game/ffxiv_dx11.exe");
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (profile.dalamudEnabled()) {
|
|
|
|
beginDalamudGame(gameExectuable, profile, auth);
|
|
|
|
} else {
|
|
|
|
beginVanillaGame(gameExectuable, profile, auth);
|
|
|
|
}
|
|
|
|
|
2023-09-17 19:30:22 -04:00
|
|
|
Q_EMIT successfulLaunch();
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
|
|
|
|
2023-09-17 19:30:22 -04:00
|
|
|
void LauncherCore::beginVanillaGame(const QString &gameExecutablePath, Profile &profile, const LoginAuth &auth)
|
2023-07-30 08:49:34 -04:00
|
|
|
{
|
2023-09-17 19:30:22 -04:00
|
|
|
profile.setLoggedIn(true);
|
|
|
|
|
2023-07-30 10:11:14 -04:00
|
|
|
auto gameProcess = new QProcess(this);
|
2023-07-30 08:49:34 -04:00
|
|
|
gameProcess->setProcessEnvironment(QProcessEnvironment::systemEnvironment());
|
2023-09-17 19:30:22 -04:00
|
|
|
connect(gameProcess, &QProcess::finished, this, [this, &profile](int exitCode) {
|
|
|
|
profile.setLoggedIn(false);
|
2023-07-30 16:20:51 -04:00
|
|
|
Q_UNUSED(exitCode)
|
|
|
|
Q_EMIT gameClosed();
|
|
|
|
});
|
2023-07-30 08:49:34 -04:00
|
|
|
|
|
|
|
auto args = getGameArgs(profile, auth);
|
|
|
|
|
|
|
|
launchExecutable(profile, gameProcess, {gameExecutablePath, args}, true, true);
|
|
|
|
}
|
|
|
|
|
2023-09-17 19:30:22 -04:00
|
|
|
void LauncherCore::beginDalamudGame(const QString &gameExecutablePath, Profile &profile, const LoginAuth &auth)
|
2023-07-30 08:49:34 -04:00
|
|
|
{
|
2023-09-17 19:30:22 -04:00
|
|
|
profile.setLoggedIn(true);
|
|
|
|
|
2023-08-18 14:52:06 -04:00
|
|
|
const QDir dataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
|
|
|
const QDir configDir = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
|
|
|
|
const QDir stateDir = Utility::stateDirectory();
|
2023-09-17 08:31:24 -04:00
|
|
|
const QDir dalamudDir = dataDir.absoluteFilePath(QStringLiteral("dalamud"));
|
2023-08-18 21:36:29 -04:00
|
|
|
|
2023-09-17 08:31:24 -04:00
|
|
|
const QDir dalamudConfigDir = configDir.absoluteFilePath(QStringLiteral("dalamud"));
|
2023-08-18 21:36:29 -04:00
|
|
|
const QDir userDalamudConfigDir = dalamudConfigDir.absoluteFilePath(profile.account()->uuid());
|
|
|
|
|
2023-09-17 08:31:24 -04:00
|
|
|
const QDir dalamudBasePluginDir = dalamudDir.absoluteFilePath(QStringLiteral("plugins"));
|
2023-08-18 21:36:29 -04:00
|
|
|
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.
|
2023-09-17 08:31:24 -04:00
|
|
|
const QDir dalamudPluginDir = dalamudUserPluginDir.absoluteFilePath(QStringLiteral("installedPlugins"));
|
2023-07-30 08:49:34 -04:00
|
|
|
|
2023-09-17 08:31:24 -04:00
|
|
|
const QString logDir = stateDir.absoluteFilePath(QStringLiteral("logs"));
|
2023-08-18 14:52:06 -04:00
|
|
|
|
|
|
|
if (!QDir().exists(logDir))
|
|
|
|
QDir().mkpath(logDir);
|
|
|
|
|
2023-09-17 08:31:24 -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"));
|
2023-08-18 14:52:06 -04:00
|
|
|
|
|
|
|
const QDir dalamudInstallDir = dalamudDir.absoluteFilePath(profile.dalamudChannelName());
|
2023-09-17 08:31:24 -04:00
|
|
|
const QString dalamudInjector = dalamudInstallDir.absoluteFilePath(QStringLiteral("Dalamud.Injector.exe"));
|
2023-07-30 08:49:34 -04:00
|
|
|
|
2023-07-30 10:11:14 -04:00
|
|
|
auto dalamudProcess = new QProcess(this);
|
2023-09-17 19:30:22 -04:00
|
|
|
connect(dalamudProcess, &QProcess::finished, this, [this, &profile](int exitCode) {
|
|
|
|
profile.setLoggedIn(false);
|
2023-07-30 16:20:51 -04:00
|
|
|
Q_UNUSED(exitCode)
|
|
|
|
Q_EMIT gameClosed();
|
|
|
|
});
|
2023-07-30 08:49:34 -04:00
|
|
|
|
|
|
|
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
2023-09-17 08:31:24 -04:00
|
|
|
env.insert(QStringLiteral("DALAMUD_RUNTIME"), Utility::toWindowsPath(dalamudRuntimeDir));
|
2023-07-30 08:49:34 -04:00
|
|
|
|
|
|
|
#if defined(Q_OS_LINUX) || defined(Q_OS_MAC)
|
2023-09-17 08:31:24 -04:00
|
|
|
env.insert(QStringLiteral("XL_WINEONLINUX"), QStringLiteral("true"));
|
2023-07-30 08:49:34 -04:00
|
|
|
#endif
|
|
|
|
dalamudProcess->setProcessEnvironment(env);
|
|
|
|
|
2023-09-17 18:43:58 -04:00
|
|
|
const auto args = getGameArgs(profile, auth);
|
2023-07-30 08:49:34 -04:00
|
|
|
|
|
|
|
launchExecutable(profile,
|
|
|
|
dalamudProcess,
|
2023-08-18 14:52:06 -04:00
|
|
|
{Utility::toWindowsPath(dalamudInjector),
|
2023-09-17 08:31:24 -04:00
|
|
|
QStringLiteral("launch"),
|
|
|
|
QStringLiteral("-m"),
|
2023-09-20 16:28:59 -04:00
|
|
|
profile.dalamudInjectMethod() == Profile::DalamudInjectMethod::Entrypoint ? QStringLiteral("entrypoint") : QStringLiteral("inject"),
|
2023-09-17 08:31:24 -04:00
|
|
|
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()),
|
2023-09-20 16:28:59 -04:00
|
|
|
QStringLiteral("--dalamud-delay-initialize=") + QString::number(profile.dalamudInjectDelay()),
|
2023-09-17 08:31:24 -04:00
|
|
|
QStringLiteral("--logpath=") + Utility::toWindowsPath(logDir),
|
|
|
|
QStringLiteral("--"),
|
2023-07-30 08:49:34 -04:00
|
|
|
args},
|
|
|
|
true,
|
|
|
|
true);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString LauncherCore::getGameArgs(const Profile &profile, const LoginAuth &auth)
|
|
|
|
{
|
|
|
|
struct Argument {
|
|
|
|
QString key, value;
|
|
|
|
};
|
|
|
|
|
|
|
|
QList<Argument> gameArgs;
|
2023-09-17 08:31:24 -04:00
|
|
|
gameArgs.push_back({QStringLiteral("DEV.DataPathType"), QString::number(1)});
|
|
|
|
gameArgs.push_back({QStringLiteral("DEV.UseSqPack"), QString::number(1)});
|
2023-07-30 08:49:34 -04:00
|
|
|
|
2023-09-17 08:31:24 -04:00
|
|
|
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)});
|
|
|
|
gameArgs.push_back({QStringLiteral("language"), QString::number(profile.account()->language())});
|
2023-09-17 08:51:26 -04:00
|
|
|
gameArgs.push_back({QStringLiteral("ver"), profile.baseGameVersion()});
|
2023-09-17 08:31:24 -04:00
|
|
|
gameArgs.push_back({QStringLiteral("UserPath"), Utility::toWindowsPath(profile.account()->getConfigDir().absolutePath())});
|
2023-08-18 14:52:06 -04:00
|
|
|
|
|
|
|
// FIXME: this should belong somewhere else...
|
|
|
|
if (!QDir().exists(profile.account()->getConfigDir().absolutePath())) {
|
|
|
|
QDir().mkpath(profile.account()->getConfigDir().absolutePath());
|
|
|
|
}
|
2023-07-30 08:49:34 -04:00
|
|
|
|
|
|
|
if (!auth.lobbyhost.isEmpty()) {
|
2023-09-17 08:31:24 -04:00
|
|
|
gameArgs.push_back({QStringLiteral("DEV.GMServerHost"), auth.frontierHost});
|
2023-07-30 08:49:34 -04:00
|
|
|
for (int i = 1; i < 9; i++) {
|
2023-09-17 08:31:24 -04: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(54994)});
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (profile.account()->license() == Account::GameLicense::WindowsSteam) {
|
2023-09-17 08:31:24 -04:00
|
|
|
gameArgs.push_back({QStringLiteral("IsSteam"), QStringLiteral("1")});
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
|
|
|
|
2023-09-17 08:31:24 -04:00
|
|
|
const QString argFormat = profile.argumentsEncrypted() ? QStringLiteral(" /%1 =%2") : QStringLiteral(" %1=%2");
|
2023-07-30 08:49:34 -04:00
|
|
|
|
|
|
|
QString argJoined;
|
|
|
|
for (const auto &arg : gameArgs) {
|
|
|
|
argJoined += argFormat.arg(arg.key, arg.value);
|
|
|
|
}
|
|
|
|
|
|
|
|
return profile.argumentsEncrypted() ? encryptGameArg(argJoined) : argJoined;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LauncherCore::launchExecutable(const Profile &profile, QProcess *process, const QStringList &args, bool isGame, bool needsRegistrySetup)
|
|
|
|
{
|
|
|
|
QList<QString> arguments;
|
2023-07-30 16:21:00 -04:00
|
|
|
auto env = process->processEnvironment();
|
2023-07-30 08:49:34 -04:00
|
|
|
|
|
|
|
if (needsRegistrySetup) {
|
|
|
|
#if defined(Q_OS_LINUX) || defined(Q_OS_MAC)
|
|
|
|
if (profile.account()->license() == Account::GameLicense::macOS) {
|
2023-09-17 08:31:24 -04:00
|
|
|
addRegistryKey(profile, QStringLiteral("HKEY_CURRENT_USER\\Software\\Wine"), QStringLiteral("HideWineExports"), QStringLiteral("0"));
|
2023-07-30 08:49:34 -04:00
|
|
|
} else {
|
2023-09-17 08:31:24 -04:00
|
|
|
addRegistryKey(profile, QStringLiteral("HKEY_CURRENT_USER\\Software\\Wine"), QStringLiteral("HideWineExports"), QStringLiteral("1"));
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(Q_OS_LINUX)
|
|
|
|
if (isGame) {
|
|
|
|
if (profile.gamescopeEnabled()) {
|
2023-09-17 08:31:24 -04:00
|
|
|
arguments.push_back(QStringLiteral("gamescope"));
|
2023-07-30 08:49:34 -04:00
|
|
|
|
|
|
|
if (profile.gamescopeFullscreen())
|
2023-09-17 08:31:24 -04:00
|
|
|
arguments.push_back(QStringLiteral("-f"));
|
2023-07-30 08:49:34 -04:00
|
|
|
|
|
|
|
if (profile.gamescopeBorderless())
|
2023-09-17 08:31:24 -04:00
|
|
|
arguments.push_back(QStringLiteral("-b"));
|
2023-07-30 08:49:34 -04:00
|
|
|
|
|
|
|
if (profile.gamescopeWidth() > 0)
|
2023-09-17 08:31:24 -04:00
|
|
|
arguments.push_back(QStringLiteral("-w ") + QString::number(profile.gamescopeWidth()));
|
2023-07-30 08:49:34 -04:00
|
|
|
|
|
|
|
if (profile.gamescopeHeight() > 0)
|
2023-09-17 08:31:24 -04:00
|
|
|
arguments.push_back(QStringLiteral("-h ") + QString::number(profile.gamescopeHeight()));
|
2023-07-30 08:49:34 -04:00
|
|
|
|
|
|
|
if (profile.gamescopeRefreshRate() > 0)
|
2023-09-17 08:31:24 -04:00
|
|
|
arguments.push_back(QStringLiteral("-r ") + QString::number(profile.gamescopeRefreshRate()));
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef ENABLE_GAMEMODE
|
2023-07-30 09:02:24 -04:00
|
|
|
if (isGame && profile.gamemodeEnabled()) {
|
2023-07-30 08:49:34 -04:00
|
|
|
gamemode_request_start();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(Q_OS_LINUX)
|
|
|
|
if (profile.esyncEnabled()) {
|
2023-09-17 08:31:24 -04:00
|
|
|
env.insert(QStringLiteral("WINEESYNC"), QString::number(1));
|
|
|
|
env.insert(QStringLiteral("WINEFSYNC"), QString::number(1));
|
|
|
|
env.insert(QStringLiteral("WINEFSYNC_FUTEX2"), QString::number(1));
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(Q_OS_MAC) || defined(Q_OS_LINUX)
|
|
|
|
if (m_isSteam) {
|
2023-09-17 08:31:24 -04:00
|
|
|
const QDir steamDirectory = QProcessEnvironment::systemEnvironment().value(QStringLiteral("STEAM_COMPAT_CLIENT_INSTALL_PATH"));
|
2023-08-18 23:03:13 -04:00
|
|
|
const QDir compatData =
|
2023-09-17 08:31:24 -04:00
|
|
|
QProcessEnvironment::systemEnvironment().value(QStringLiteral("STEAM_COMPAT_DATA_PATH")); // TODO: do these have to exist on the root steam folder?
|
2023-07-30 08:49:34 -04:00
|
|
|
|
2023-09-17 08:31:24 -04:00
|
|
|
const QString steamAppsPath = steamDirectory.absoluteFilePath(QStringLiteral("steamapps/common"));
|
2023-08-18 23:03:13 -04:00
|
|
|
|
|
|
|
// Find the highest Proton version
|
|
|
|
QDirIterator it(steamAppsPath);
|
|
|
|
QDir highestVersion;
|
|
|
|
int highestVersionNum = 1;
|
|
|
|
while (it.hasNext()) {
|
|
|
|
QString dir = it.next();
|
|
|
|
|
|
|
|
QFileInfo fileInfo(dir);
|
|
|
|
if (!fileInfo.isDir()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString dirName = fileInfo.fileName();
|
2023-09-17 08:31:24 -04:00
|
|
|
if (dirName.contains(QLatin1String("Proton"))) {
|
|
|
|
if (dirName == QLatin1String("Proton - Experimental")) {
|
2023-08-18 23:03:13 -04:00
|
|
|
highestVersion.setPath(dir);
|
|
|
|
break;
|
|
|
|
} else {
|
2023-09-17 08:31:24 -04:00
|
|
|
QString version = dirName.remove(QLatin1String("Proton "));
|
2023-08-18 23:03:13 -04:00
|
|
|
// Exclude "BattlEye Runtime" and other unrelated things
|
|
|
|
if (version.contains('.')) {
|
|
|
|
// TODO: better error handling (they might never be invalid, but better safe than sorry)
|
|
|
|
QStringList parts = version.split('.');
|
|
|
|
int versionNum = parts[0].toInt();
|
|
|
|
|
|
|
|
// TODO: doesn't handle minor versions, not like they really exist anymore anyway
|
|
|
|
if (versionNum > highestVersionNum) {
|
|
|
|
highestVersionNum = versionNum;
|
|
|
|
highestVersion.setPath(dir);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-17 08:31:24 -04:00
|
|
|
env.insert(QStringLiteral("STEAM_COMPAT_CLIENT_INSTALL_PATH"), steamDirectory.absolutePath());
|
|
|
|
env.insert(QStringLiteral("STEAM_COMPAT_DATA_PATH"), compatData.absolutePath());
|
2023-07-30 08:49:34 -04:00
|
|
|
|
2023-09-17 08:31:24 -04:00
|
|
|
arguments.push_back(highestVersion.absoluteFilePath(QStringLiteral("proton")));
|
|
|
|
arguments.push_back(QStringLiteral("run"));
|
2023-07-30 08:49:34 -04:00
|
|
|
} else {
|
2023-09-17 08:31:24 -04:00
|
|
|
env.insert(QStringLiteral("WINEPREFIX"), profile.winePrefixPath());
|
2023-07-30 08:49:34 -04:00
|
|
|
|
|
|
|
// XIV on Mac bundle their own Wine install directory, complete with libs etc
|
|
|
|
if (profile.wineType() == Profile::WineType::XIVOnMac) {
|
|
|
|
// TODO: don't hardcode this
|
2023-09-17 08:31:24 -04:00
|
|
|
QString xivLibPath = QStringLiteral(
|
2023-07-30 08:49:34 -04:00
|
|
|
"/Applications/XIV on Mac.app/Contents/Resources/wine/lib:/Applications/XIV on "
|
2023-09-17 08:31:24 -04:00
|
|
|
"Mac.app/Contents/Resources/MoltenVK/modern");
|
|
|
|
|
|
|
|
env.insert(QStringLiteral("DYLD_FALLBACK_LIBRARY_PATH"), xivLibPath);
|
|
|
|
env.insert(QStringLiteral("DYLD_VERSIONED_LIBRARY_PATH"), xivLibPath);
|
|
|
|
env.insert(QStringLiteral("MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE"), QStringLiteral("1"));
|
|
|
|
env.insert(QStringLiteral("MVK_CONFIG_RESUME_LOST_DEVICE"), QStringLiteral("1"));
|
|
|
|
env.insert(QStringLiteral("MVK_ALLOW_METAL_FENCES"), QStringLiteral("1"));
|
|
|
|
env.insert(QStringLiteral("MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS"), QStringLiteral("1"));
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(FLATPAK)
|
2023-09-17 08:31:24 -04:00
|
|
|
arguments.push_back(QStringLiteral("flatpak-spawn"));
|
|
|
|
arguments.push_back(QStringLiteral("--host"));
|
2023-07-30 08:49:34 -04:00
|
|
|
#endif
|
|
|
|
arguments.push_back(profile.winePath());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
arguments.append(args);
|
|
|
|
|
|
|
|
auto executable = arguments[0];
|
|
|
|
arguments.removeFirst();
|
|
|
|
|
|
|
|
if (isGame)
|
2023-09-17 08:31:24 -04:00
|
|
|
process->setWorkingDirectory(profile.gamePath() + QStringLiteral("/game/"));
|
2023-07-30 08:49:34 -04:00
|
|
|
|
|
|
|
process->setProcessEnvironment(env);
|
2023-08-18 23:03:13 -04:00
|
|
|
process->setProcessChannelMode(QProcess::ProcessChannelMode::ForwardedChannels);
|
2023-07-30 08:49:34 -04:00
|
|
|
|
|
|
|
process->start(executable, arguments);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LauncherCore::readInitialInformation()
|
|
|
|
{
|
|
|
|
m_profileManager->load();
|
|
|
|
m_accountManager->load();
|
|
|
|
|
|
|
|
// restore profile -> account connections
|
|
|
|
for (auto profile : m_profileManager->profiles()) {
|
|
|
|
if (auto account = m_accountManager->getByUuid(profile->accountUuid())) {
|
|
|
|
profile->setAccount(account);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_loadingFinished = true;
|
|
|
|
Q_EMIT loadingFinished();
|
|
|
|
}
|
|
|
|
|
2023-09-16 18:01:02 -04:00
|
|
|
LauncherCore::LauncherCore()
|
2023-07-30 08:49:34 -04:00
|
|
|
{
|
2023-07-30 10:11:14 -04:00
|
|
|
mgr = new QNetworkAccessManager(this);
|
2023-09-17 08:31:24 -04:00
|
|
|
m_sapphireLauncher = new SapphireLauncher(*this, this);
|
|
|
|
m_squareLauncher = new SquareLauncher(*this, this);
|
|
|
|
m_squareBoot = new SquareBoot(*this, *m_squareLauncher, this);
|
|
|
|
m_steamApi = new SteamAPI(*this, this);
|
2023-07-30 10:11:14 -04:00
|
|
|
m_profileManager = new ProfileManager(*this, this);
|
|
|
|
m_accountManager = new AccountManager(*this, this);
|
2023-07-30 08:49:34 -04:00
|
|
|
|
|
|
|
readInitialInformation();
|
|
|
|
|
2023-09-17 08:31:24 -04:00
|
|
|
m_steamApi->setLauncherMode(true);
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool LauncherCore::checkIfInPath(const QString &program)
|
|
|
|
{
|
2023-07-30 10:11:14 -04:00
|
|
|
const auto pathList = qgetenv("PATH").split(':');
|
2023-07-30 08:49:34 -04:00
|
|
|
|
2023-07-30 10:11:14 -04:00
|
|
|
return std::any_of(pathList.cbegin(), pathList.cend(), [program](const QByteArray &path) {
|
2023-09-17 08:31:24 -04:00
|
|
|
QFileInfo fileInfo(path + QStringLiteral("/") + program);
|
2023-07-30 10:11:14 -04:00
|
|
|
return fileInfo.exists() && fileInfo.isFile();
|
|
|
|
});
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void LauncherCore::addRegistryKey(const Profile &settings, QString key, QString value, QString data)
|
|
|
|
{
|
|
|
|
auto process = new QProcess(this);
|
|
|
|
process->setProcessEnvironment(QProcessEnvironment::systemEnvironment());
|
2023-09-17 08:31:24 -04:00
|
|
|
launchExecutable(settings,
|
|
|
|
process,
|
|
|
|
{QStringLiteral("reg"),
|
|
|
|
QStringLiteral("add"),
|
|
|
|
std::move(key),
|
|
|
|
QStringLiteral("/v"),
|
|
|
|
std::move(value),
|
|
|
|
QStringLiteral("/d"),
|
|
|
|
std::move(data),
|
|
|
|
QStringLiteral("/f")},
|
|
|
|
false,
|
|
|
|
false);
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void LauncherCore::login(Profile *profile, const QString &username, const QString &password, const QString &oneTimePassword)
|
|
|
|
{
|
2023-09-17 18:43:58 -04:00
|
|
|
Q_ASSERT(profile != nullptr);
|
2023-07-30 16:19:51 -04:00
|
|
|
|
2023-09-17 18:43:58 -04:00
|
|
|
auto loginInformation = new LoginInformation(this);
|
|
|
|
loginInformation->profile = profile;
|
|
|
|
loginInformation->username = username;
|
|
|
|
loginInformation->password = password;
|
|
|
|
loginInformation->oneTimePassword = oneTimePassword;
|
2023-07-30 08:49:34 -04:00
|
|
|
|
2023-09-17 18:43:58 -04:00
|
|
|
if (profile->account()->rememberPassword()) {
|
|
|
|
profile->account()->setPassword(password);
|
|
|
|
}
|
2023-07-30 16:19:51 -04:00
|
|
|
|
2023-09-17 18:43:58 -04:00
|
|
|
beginLogin(*loginInformation);
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
|
|
|
|
2023-09-17 19:20:41 -04:00
|
|
|
void LauncherCore::autoLogin(Profile *profile)
|
2023-07-30 08:49:34 -04:00
|
|
|
{
|
2023-09-17 19:20:41 -04:00
|
|
|
login(profile, profile->account()->name(), profile->account()->getPassword(), profile->account()->useOTP() ? profile->account()->getOTP() : QString());
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
|
|
|
|
2023-08-18 12:59:07 -04:00
|
|
|
GameInstaller *LauncherCore::createInstaller(Profile *profile)
|
2023-07-30 08:49:34 -04:00
|
|
|
{
|
2023-08-18 12:59:07 -04:00
|
|
|
Q_ASSERT(profile != nullptr);
|
|
|
|
return new GameInstaller(*this, *profile, this);
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
|
|
|
|
2023-08-18 23:27:29 -04:00
|
|
|
CompatibilityToolInstaller *LauncherCore::createCompatInstaller()
|
|
|
|
{
|
|
|
|
return new CompatibilityToolInstaller(*this, this);
|
|
|
|
}
|
|
|
|
|
2023-07-30 08:49:34 -04:00
|
|
|
bool LauncherCore::isLoadingFinished() const
|
|
|
|
{
|
|
|
|
return m_loadingFinished;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool LauncherCore::hasAccount() const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ProfileManager *LauncherCore::profileManager()
|
|
|
|
{
|
|
|
|
return m_profileManager;
|
|
|
|
}
|
|
|
|
|
|
|
|
AccountManager *LauncherCore::accountManager()
|
|
|
|
{
|
|
|
|
return m_accountManager;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool LauncherCore::closeWhenLaunched() const
|
|
|
|
{
|
|
|
|
return Config::closeWhenLaunched();
|
|
|
|
}
|
|
|
|
|
|
|
|
void LauncherCore::setCloseWhenLaunched(const bool value)
|
|
|
|
{
|
|
|
|
if (value != Config::closeWhenLaunched()) {
|
|
|
|
Config::setCloseWhenLaunched(value);
|
|
|
|
Config::self()->save();
|
|
|
|
Q_EMIT closeWhenLaunchedChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-31 18:59:42 -04:00
|
|
|
bool LauncherCore::showNews() const
|
2023-07-30 08:49:34 -04:00
|
|
|
{
|
2023-07-31 18:59:42 -04:00
|
|
|
return Config::showNews();
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
|
|
|
|
2023-07-31 18:59:42 -04:00
|
|
|
void LauncherCore::setShowNews(const bool value)
|
2023-07-30 08:49:34 -04:00
|
|
|
{
|
2023-07-31 18:59:42 -04:00
|
|
|
if (value != Config::showNews()) {
|
|
|
|
Config::setShowNews(value);
|
2023-07-30 08:49:34 -04:00
|
|
|
Config::self()->save();
|
2023-07-31 18:59:42 -04:00
|
|
|
Q_EMIT showNewsChanged();
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-19 11:20:47 -04:00
|
|
|
bool LauncherCore::showDevTools() const
|
|
|
|
{
|
|
|
|
return Config::showDevTools();
|
|
|
|
}
|
|
|
|
|
|
|
|
void LauncherCore::setShowDevTools(const bool value)
|
|
|
|
{
|
|
|
|
if (value != Config::showDevTools()) {
|
|
|
|
Config::setShowDevTools(value);
|
|
|
|
Config::self()->save();
|
|
|
|
Q_EMIT showDevToolsChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-18 14:52:06 -04:00
|
|
|
bool LauncherCore::keepPatches() const
|
|
|
|
{
|
|
|
|
return Config::keepPatches();
|
|
|
|
}
|
|
|
|
|
|
|
|
void LauncherCore::setKeepPatches(const bool value)
|
|
|
|
{
|
|
|
|
if (value != Config::keepPatches()) {
|
|
|
|
Config::setKeepPatches(value);
|
|
|
|
Config::self()->save();
|
|
|
|
Q_EMIT keepPatchesChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-18 21:36:29 -04:00
|
|
|
QString LauncherCore::dalamudDistribServer() const
|
|
|
|
{
|
|
|
|
return Config::dalamudDistribServer();
|
|
|
|
}
|
|
|
|
|
|
|
|
void LauncherCore::setDalamudDistribServer(const QString &value)
|
|
|
|
{
|
|
|
|
if (value != Config::dalamudDistribServer()) {
|
|
|
|
Config::setDalamudDistribServer(value);
|
|
|
|
Config::self()->save();
|
|
|
|
Q_EMIT dalamudDistribServerChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QString LauncherCore::squareEnixServer() const
|
|
|
|
{
|
|
|
|
return Config::squareEnixServer();
|
|
|
|
}
|
|
|
|
|
|
|
|
void LauncherCore::setSquareEnixServer(const QString &value)
|
|
|
|
{
|
|
|
|
if (value != Config::squareEnixServer()) {
|
|
|
|
Config::setSquareEnixServer(value);
|
|
|
|
Config::self()->save();
|
|
|
|
Q_EMIT squareEnixServerChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QString LauncherCore::squareEnixLoginServer() const
|
|
|
|
{
|
|
|
|
return Config::squareEnixLoginServer();
|
|
|
|
}
|
|
|
|
|
|
|
|
void LauncherCore::setSquareEnixLoginServer(const QString &value)
|
|
|
|
{
|
|
|
|
if (value != Config::squareEnixLoginServer()) {
|
|
|
|
Config::setSquareEnixLoginServer(value);
|
|
|
|
Config::self()->save();
|
|
|
|
Q_EMIT squareEnixLoginServerChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-17 19:20:41 -04:00
|
|
|
[[nodiscard]] QString LauncherCore::autoLoginProfileName() const
|
|
|
|
{
|
|
|
|
return Config::autoLoginProfile();
|
|
|
|
}
|
|
|
|
|
|
|
|
[[nodiscard]] Profile *LauncherCore::autoLoginProfile() const
|
|
|
|
{
|
|
|
|
if (Config::autoLoginProfile().isEmpty()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return m_profileManager->getProfileByUUID(Config::autoLoginProfile());
|
|
|
|
}
|
|
|
|
|
|
|
|
void LauncherCore::setAutoLoginProfile(Profile *profile)
|
|
|
|
{
|
|
|
|
if (profile == nullptr) {
|
|
|
|
Config::setAutoLoginProfile({});
|
|
|
|
Config::self()->save();
|
|
|
|
Q_EMIT autoLoginProfileChanged();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto uuid = profile->uuid();
|
|
|
|
if (uuid != Config::autoLoginProfile()) {
|
|
|
|
Config::setAutoLoginProfile(uuid);
|
|
|
|
Config::self()->save();
|
|
|
|
Q_EMIT autoLoginProfileChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-30 08:49:34 -04:00
|
|
|
void LauncherCore::refreshNews()
|
2023-09-16 18:37:42 -04:00
|
|
|
{
|
|
|
|
fetchNews();
|
|
|
|
}
|
|
|
|
|
|
|
|
QCoro::Task<> LauncherCore::fetchNews()
|
2023-07-30 08:49:34 -04:00
|
|
|
{
|
|
|
|
QUrlQuery query;
|
2023-09-17 08:31:24 -04:00
|
|
|
query.addQueryItem(QStringLiteral("lang"), QStringLiteral("en-us"));
|
|
|
|
query.addQueryItem(QStringLiteral("media"), QStringLiteral("pcapp"));
|
2023-07-30 08:49:34 -04:00
|
|
|
|
|
|
|
QUrl url;
|
2023-09-17 08:31:24 -04:00
|
|
|
url.setScheme(QStringLiteral("https"));
|
2023-08-18 21:36:29 -04:00
|
|
|
url.setHost(QStringLiteral("frontier.%1").arg(squareEnixServer()));
|
2023-09-17 08:31:24 -04:00
|
|
|
url.setPath(QStringLiteral("/news/headline.json"));
|
2023-07-30 08:49:34 -04:00
|
|
|
url.setQuery(query);
|
|
|
|
|
2023-09-17 08:31:24 -04:00
|
|
|
QNetworkRequest request(QStringLiteral("%1&%2").arg(url.toString(), QString::number(QDateTime::currentMSecsSinceEpoch())));
|
|
|
|
request.setRawHeader(QByteArrayLiteral("Accept"), QByteArrayLiteral("application/json, text/plain, */*"));
|
|
|
|
request.setRawHeader(QByteArrayLiteral("Origin"), QByteArrayLiteral("https://launcher.finalfantasyxiv.com"));
|
|
|
|
request.setRawHeader(QByteArrayLiteral("Referer"),
|
|
|
|
QStringLiteral("https://launcher.finalfantasyxiv.com/v600/index.html?rc_lang=%1&time=%2")
|
2023-07-30 08:49:34 -04:00
|
|
|
.arg("en-us", QDateTime::currentDateTimeUtc().toString("yyyy-MM-dd-HH"))
|
|
|
|
.toUtf8());
|
|
|
|
|
|
|
|
auto reply = mgr->get(request);
|
2023-09-16 18:37:42 -04:00
|
|
|
co_await reply;
|
2023-07-30 08:49:34 -04:00
|
|
|
|
2023-09-16 18:37:42 -04:00
|
|
|
auto document = QJsonDocument::fromJson(reply->readAll());
|
2023-07-30 08:49:34 -04:00
|
|
|
|
2023-09-16 18:37:42 -04:00
|
|
|
auto headline = new Headline(this);
|
|
|
|
if (document.isEmpty()) {
|
|
|
|
headline->failedToLoad = true;
|
|
|
|
}
|
2023-07-30 08:49:34 -04:00
|
|
|
|
2023-09-16 18:37:42 -04:00
|
|
|
const auto parseNews = [](QJsonObject object) -> News {
|
|
|
|
News news;
|
2023-09-17 08:31:24 -04:00
|
|
|
news.date = QDateTime::fromString(object[QLatin1String("date")].toString(), Qt::DateFormat::ISODate);
|
|
|
|
news.id = object[QLatin1String("id")].toString();
|
|
|
|
news.tag = object[QLatin1String("tag")].toString();
|
|
|
|
news.title = object[QLatin1String("title")].toString();
|
2023-07-30 08:49:34 -04:00
|
|
|
|
2023-09-17 08:31:24 -04:00
|
|
|
if (object[QLatin1String("url")].toString().isEmpty()) {
|
|
|
|
news.url = QUrl(QStringLiteral("https://na.finalfantasyxiv.com/lodestone/news/detail/%1").arg(news.id));
|
2023-09-16 18:37:42 -04:00
|
|
|
} else {
|
2023-09-17 08:31:24 -04:00
|
|
|
news.url = QUrl(object[QLatin1String("url")].toString());
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
|
|
|
|
2023-09-16 18:37:42 -04:00
|
|
|
return news;
|
|
|
|
};
|
2023-07-30 08:49:34 -04:00
|
|
|
|
2023-09-17 08:31:24 -04:00
|
|
|
for (auto bannerObject : document.object()[QLatin1String("banner")].toArray()) {
|
2023-09-16 18:37:42 -04:00
|
|
|
auto banner = Banner();
|
2023-09-17 08:31:24 -04:00
|
|
|
banner.link = QUrl(bannerObject.toObject()[QLatin1String("link")].toString());
|
|
|
|
banner.bannerImage = QUrl(bannerObject.toObject()[QLatin1String("lsb_banner")].toString());
|
2023-07-30 08:49:34 -04:00
|
|
|
|
2023-09-16 18:37:42 -04:00
|
|
|
headline->banners.push_back(banner);
|
|
|
|
}
|
2023-07-30 08:49:34 -04:00
|
|
|
|
2023-09-17 08:31:24 -04:00
|
|
|
for (auto newsObject : document.object()[QLatin1String("news")].toArray()) {
|
2023-09-16 18:37:42 -04:00
|
|
|
auto news = parseNews(newsObject.toObject());
|
|
|
|
headline->news.push_back(news);
|
|
|
|
}
|
|
|
|
|
2023-09-17 08:31:24 -04:00
|
|
|
for (auto pinnedObject : document.object()[QLatin1String("pinned")].toArray()) {
|
2023-09-16 18:37:42 -04:00
|
|
|
auto pinned = parseNews(pinnedObject.toObject());
|
|
|
|
headline->pinned.push_back(pinned);
|
|
|
|
}
|
|
|
|
|
2023-09-17 08:31:24 -04:00
|
|
|
for (auto pinnedObject : document.object()[QLatin1String("topics")].toArray()) {
|
2023-09-16 18:37:42 -04:00
|
|
|
auto pinned = parseNews(pinnedObject.toObject());
|
|
|
|
headline->topics.push_back(pinned);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_headline = headline;
|
|
|
|
Q_EMIT newsChanged();
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
|
|
|
|
2023-09-17 08:31:24 -04:00
|
|
|
Headline *LauncherCore::headline() const
|
2023-07-30 08:49:34 -04:00
|
|
|
{
|
|
|
|
return m_headline;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool LauncherCore::isSteam() const
|
|
|
|
{
|
|
|
|
return m_isSteam;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LauncherCore::openOfficialLauncher(Profile *profile)
|
|
|
|
{
|
|
|
|
struct Argument {
|
|
|
|
QString key, value;
|
|
|
|
};
|
|
|
|
|
2023-09-17 08:31:24 -04:00
|
|
|
QString executeArg = QStringLiteral("%1%2%3%4");
|
2023-07-30 08:49:34 -04:00
|
|
|
QDateTime dateTime = QDateTime::currentDateTime();
|
|
|
|
executeArg = executeArg.arg(dateTime.date().month() + 1, 2, 10, QLatin1Char('0'));
|
|
|
|
executeArg = executeArg.arg(dateTime.date().day(), 2, 10, QLatin1Char('0'));
|
|
|
|
executeArg = executeArg.arg(dateTime.time().hour(), 2, 10, QLatin1Char('0'));
|
|
|
|
executeArg = executeArg.arg(dateTime.time().minute(), 2, 10, QLatin1Char('0'));
|
|
|
|
|
2023-09-17 08:31:24 -04:00
|
|
|
QList<Argument> arguments{{QStringLiteral("ExecuteArg"), executeArg},
|
|
|
|
{QStringLiteral("UserPath"), Utility::toWindowsPath(profile->account()->getConfigDir().absolutePath())}};
|
2023-07-30 08:49:34 -04:00
|
|
|
|
2023-09-17 08:31:24 -04:00
|
|
|
const QString argFormat = QStringLiteral(" /%1 =%2");
|
2023-07-30 08:49:34 -04:00
|
|
|
|
|
|
|
QString argJoined;
|
|
|
|
for (auto &arg : arguments) {
|
2023-09-17 08:31:24 -04:00
|
|
|
argJoined += argFormat.arg(arg.key, arg.value.replace(QLatin1Char(' '), QLatin1String(" ")));
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
QString finalArg = encryptGameArg(argJoined);
|
|
|
|
|
2023-07-30 10:11:14 -04:00
|
|
|
auto launcherProcess = new QProcess(this);
|
2023-07-31 19:36:03 -04:00
|
|
|
launcherProcess->setProcessEnvironment(QProcessEnvironment::systemEnvironment());
|
2023-09-17 08:31:24 -04:00
|
|
|
launchExecutable(*profile, launcherProcess, {profile->gamePath() + QStringLiteral("/boot/ffxivlauncher64.exe"), finalArg}, false, true);
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void LauncherCore::openSystemInfo(Profile *profile)
|
|
|
|
{
|
2023-07-30 10:11:14 -04:00
|
|
|
auto sysinfoProcess = new QProcess(this);
|
2023-07-31 19:36:03 -04:00
|
|
|
sysinfoProcess->setProcessEnvironment(QProcessEnvironment::systemEnvironment());
|
2023-09-17 08:31:24 -04:00
|
|
|
launchExecutable(*profile, sysinfoProcess, {profile->gamePath() + QStringLiteral("/boot/ffxivsysinfo64.exe")}, false, false);
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void LauncherCore::openConfigBackup(Profile *profile)
|
|
|
|
{
|
2023-07-30 10:11:14 -04:00
|
|
|
auto configProcess = new QProcess(this);
|
2023-07-31 19:36:03 -04:00
|
|
|
configProcess->setProcessEnvironment(QProcessEnvironment::systemEnvironment());
|
2023-09-17 08:31:24 -04:00
|
|
|
launchExecutable(*profile, configProcess, {profile->gamePath() + QStringLiteral("/boot/ffxivconfig64.exe")}, false, false);
|
2023-07-30 08:49:34 -04:00
|
|
|
}
|
2023-07-31 18:58:02 -04:00
|
|
|
|
|
|
|
bool LauncherCore::isSteamDeck() const
|
|
|
|
{
|
2023-09-17 08:31:24 -04:00
|
|
|
return m_steamApi->isDeck();
|
2023-07-31 18:58:02 -04:00
|
|
|
}
|
2023-09-16 18:01:02 -04:00
|
|
|
|
|
|
|
void LauncherCore::setIsSteam(bool isSteam)
|
|
|
|
{
|
|
|
|
m_isSteam = isSteam;
|
|
|
|
}
|
2023-09-16 20:12:01 -04:00
|
|
|
|
|
|
|
Profile *LauncherCore::currentProfile() const
|
|
|
|
{
|
|
|
|
return m_profileManager->getProfile(m_currentProfileIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LauncherCore::setCurrentProfile(Profile *profile)
|
|
|
|
{
|
|
|
|
const int newIndex = m_profileManager->getProfileIndex(profile->name());
|
|
|
|
if (newIndex != m_currentProfileIndex) {
|
|
|
|
m_currentProfileIndex = newIndex;
|
|
|
|
Q_EMIT currentProfileChanged();
|
|
|
|
}
|
2023-09-17 18:43:58 -04:00
|
|
|
}
|