mirror of
https://github.com/redstrate/Astra.git
synced 2025-04-20 11:47:46 +00:00
There's a new "Game" menu where you can install the game if you missed the initial prompt on start-up. If you have XIV on Mac (a fellow XIV launcher) installed, you now have the option of using their wine binaries and libraries. There is more to come in future commits, especially pertaining DXVK and MoltenVK. Game installation has been fixed for macOS, enabling you to start updating right away without having to fiddle around with finding the right installer or app package.
676 lines
24 KiB
C++
Executable file
676 lines
24 KiB
C++
Executable file
#include <QPushButton>
|
|
#include <QProcess>
|
|
#include <QNetworkAccessManager>
|
|
#include <QNetworkReply>
|
|
#include <QUrlQuery>
|
|
#include <QDir>
|
|
#include <QFormLayout>
|
|
#include <QLineEdit>
|
|
#include <QRegularExpression>
|
|
#include <QComboBox>
|
|
#include <QJsonObject>
|
|
#include <QJsonDocument>
|
|
#include <QCheckBox>
|
|
#include <keychain.h>
|
|
#include <QMessageBox>
|
|
#include <QMenuBar>
|
|
#include <QCoreApplication>
|
|
#include <QStandardPaths>
|
|
#include <QRegularExpressionMatch>
|
|
#include <algorithm>
|
|
#include <QTcpServer>
|
|
|
|
#include "launchercore.h"
|
|
#include "sapphirelauncher.h"
|
|
#include "squarelauncher.h"
|
|
#include "squareboot.h"
|
|
#include "settingswindow.h"
|
|
#include "blowfish.h"
|
|
#include "assetupdater.h"
|
|
#include "encryptedarg.h"
|
|
|
|
#ifdef ENABLE_WATCHDOG
|
|
#include "watchdog.h"
|
|
#endif
|
|
|
|
void LauncherCore::setSSL(QNetworkRequest& request) {
|
|
QSslConfiguration config;
|
|
config.setProtocol(QSsl::AnyProtocol);
|
|
config.setPeerVerifyMode(QSslSocket::VerifyNone);
|
|
|
|
request.setSslConfiguration(config);
|
|
}
|
|
|
|
void LauncherCore::buildRequest(const ProfileSettings& settings, QNetworkRequest& request) {
|
|
setSSL(request);
|
|
|
|
if(settings.license == GameLicense::macOS) {
|
|
request.setHeader(QNetworkRequest::UserAgentHeader, "macSQEXAuthor/2.0.0(MacOSX; ja-jp)");
|
|
} else {
|
|
request.setHeader(QNetworkRequest::UserAgentHeader,
|
|
QString("SQEXAuthor/2.0.0(Windows 6.2; ja-jp; %1)").arg(QString(QSysInfo::bootUniqueId())));
|
|
}
|
|
|
|
request.setRawHeader("Accept",
|
|
"image/gif, image/jpeg, image/pjpeg, application/x-ms-application, application/xaml+xml, application/x-ms-xbap, */*");
|
|
request.setRawHeader("Accept-Encoding", "gzip, deflate");
|
|
request.setRawHeader("Accept-Language", "en-us");
|
|
}
|
|
|
|
void LauncherCore::launchGame(const ProfileSettings& profile, const LoginAuth auth) {
|
|
QList<QString> arguments;
|
|
|
|
QString dataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
|
|
|
if(profile.dalamud.enabled) {
|
|
arguments.push_back(dataDir + "/NativeLauncher.exe");
|
|
arguments.push_back("5248"); // TODO: make port configurable/random
|
|
}
|
|
|
|
// now for the actual game...
|
|
if(profile.useDX9) {
|
|
arguments.push_back(profile.gamePath + "\\game\\ffxiv.exe");
|
|
} else {
|
|
arguments.push_back(profile.gamePath + "\\game\\ffxiv_dx11.exe");
|
|
}
|
|
|
|
struct Argument {
|
|
QString key, value;
|
|
};
|
|
|
|
QList<Argument> gameArgs;
|
|
gameArgs.push_back({"DEV.DataPathType", QString::number(1)});
|
|
gameArgs.push_back({"DEV.UseSqPack", QString::number(1)});
|
|
|
|
gameArgs.push_back({"DEV.MaxEntitledExpansionID", QString::number(auth.maxExpansion)});
|
|
gameArgs.push_back({"DEV.TestSID", auth.SID});
|
|
gameArgs.push_back({"SYS.Region", QString::number(auth.region)});
|
|
gameArgs.push_back({"language", QString::number(profile.language)});
|
|
gameArgs.push_back({"ver", profile.gameVersion});
|
|
|
|
if(!auth.lobbyhost.isEmpty()) {
|
|
gameArgs.push_back({"DEV.GMServerHost", auth.frontierHost});
|
|
for(int i = 1; i < 9; i++) {
|
|
gameArgs.push_back({QString("DEV.LobbyHost0%1").arg(QString::number(i)), auth.lobbyhost});
|
|
gameArgs.push_back({QString("DEV.LobbyPort0%1").arg(QString::number(i)), QString::number(54994)});
|
|
}
|
|
}
|
|
|
|
auto gameProcess = new QProcess(this);
|
|
|
|
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
|
|
|
if(profile.license == GameLicense::WindowsSteam) {
|
|
gameArgs.push_back({"IsSteam", "1"});
|
|
env.insert("IS_FFXIV_LAUNCH_FROM_STEAM", QString::number(1));
|
|
}
|
|
|
|
if(profile.dalamud.enabled) {
|
|
// TODO: this depends on the default wine Z: path existing, which may not
|
|
// always the case.
|
|
env.insert("DALAMUD_RUNTIME",
|
|
"Z:" + dataDir.replace('/', '\\') + "\\DalamudRuntime");
|
|
}
|
|
|
|
gameProcess->setProcessEnvironment(env);
|
|
|
|
gameProcess->setProcessChannelMode(QProcess::ForwardedChannels);
|
|
|
|
const QString argFormat = profile.encryptArguments ? " /%1 =%2" : " %1=%2";
|
|
|
|
QString argJoined;
|
|
for(const auto& arg : gameArgs) {
|
|
argJoined += argFormat.arg(arg.key, arg.value);
|
|
}
|
|
|
|
if(profile.encryptArguments) {
|
|
arguments.append(encryptGameArg(argJoined));
|
|
} else {
|
|
arguments.append(argJoined);
|
|
}
|
|
|
|
if(profile.dalamud.enabled) {
|
|
auto socket = new QTcpServer();
|
|
|
|
connect(socket, &QTcpServer::newConnection, [this, profile, socket] {
|
|
auto connection = socket->nextPendingConnection();
|
|
|
|
connect(connection, &QTcpSocket::readyRead, [this, connection, profile, socket] {
|
|
QString output = connection->readAll();
|
|
bool success;
|
|
int exitCode = output.toInt(&success, 10);
|
|
|
|
if(exitCode != -1 && success) {
|
|
QString dataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
|
dataDir = "Z:" + dataDir.replace('/', '\\');
|
|
|
|
QJsonObject startInfo;
|
|
startInfo["WorkingDirectory"] = dataDir;
|
|
startInfo["ConfigurationPath"] = dataDir + "\\dalamudConfig.json";
|
|
startInfo["PluginDirectory"] = dataDir + "\\installedPlugins";
|
|
startInfo["AssetDirectory"] = dataDir + "\\DalamudAssets";
|
|
startInfo["DefaultPluginDirectory"] = dataDir + "\\devPlugins";
|
|
startInfo["DelayInitializeMs"] = 0;
|
|
startInfo["GameVersion"] = profile.gameVersion;
|
|
startInfo["Language"] = profile.language;
|
|
startInfo["OptOutMbCollection"] = profile.dalamud.optOutOfMbCollection;
|
|
|
|
QString argsEncoded = QJsonDocument(startInfo).toJson().toBase64();
|
|
|
|
auto dalamudProcess = new QProcess();
|
|
dalamudProcess->setProcessChannelMode(QProcess::ForwardedChannels);
|
|
|
|
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
|
env.insert("DALAMUD_RUNTIME", dataDir + "\\DalamudRuntime");
|
|
|
|
#if defined(Q_OS_LINUX) || defined(Q_OS_MAC)
|
|
env.insert("XL_WINEONLINUX", "true");
|
|
#endif
|
|
dalamudProcess->setProcessEnvironment(env);
|
|
|
|
auto list = dalamudProcess->processEnvironment().toStringList();
|
|
|
|
launchExecutable(profile, dalamudProcess, {dataDir + "/Dalamud/" + "Dalamud.Injector.exe", QString::number(exitCode), argsEncoded}, false);
|
|
|
|
connection->close();
|
|
socket->close();
|
|
}
|
|
});
|
|
});
|
|
|
|
socket->listen(QHostAddress::Any, 5248);
|
|
}
|
|
|
|
launchGameExecutable(profile, gameProcess, arguments);
|
|
|
|
successfulLaunch();
|
|
}
|
|
|
|
void LauncherCore::launchExecutable(const ProfileSettings& profile, const QStringList args) {
|
|
auto process = new QProcess(this);
|
|
process->setProcessEnvironment(QProcessEnvironment::systemEnvironment());
|
|
launchExecutable(profile, process, args, true);
|
|
}
|
|
|
|
void LauncherCore::launchExternalTool(const ProfileSettings& profile, const QStringList args) {
|
|
auto process = new QProcess(this);
|
|
process->setProcessEnvironment(QProcessEnvironment::systemEnvironment());
|
|
launchExecutable(profile, process, args, false);
|
|
}
|
|
|
|
void LauncherCore::launchGameExecutable(const ProfileSettings& profile, QProcess* process, const QStringList args) {
|
|
QList<QString> arguments;
|
|
|
|
arguments.append(args);
|
|
|
|
launchExecutable(profile, process, arguments, true);
|
|
}
|
|
|
|
void LauncherCore::launchExecutable(const ProfileSettings& profile, QProcess* process, const QStringList args, bool isGame) {
|
|
QList<QString> arguments;
|
|
auto env = process->processEnvironment();
|
|
|
|
#if defined(Q_OS_LINUX)
|
|
if (isGame) {
|
|
if (profile.useGamescope) {
|
|
arguments.push_back("gamescope");
|
|
|
|
if (profile.gamescope.fullscreen)
|
|
arguments.push_back("-f");
|
|
|
|
if (profile.gamescope.borderless)
|
|
arguments.push_back("-b");
|
|
|
|
if (profile.gamescope.width > 0)
|
|
arguments.push_back("-w " +
|
|
QString::number(profile.gamescope.width));
|
|
|
|
if (profile.gamescope.height > 0)
|
|
arguments.push_back("-h " +
|
|
QString::number(profile.gamescope.height));
|
|
|
|
if (profile.gamescope.refreshRate > 0)
|
|
arguments.push_back(
|
|
"-r " + QString::number(profile.gamescope.refreshRate));
|
|
}
|
|
|
|
if (profile.useGamemode)
|
|
arguments.push_back("gamemoderun");
|
|
}
|
|
#endif
|
|
|
|
#if defined(Q_OS_LINUX)
|
|
if(profile.useEsync) {
|
|
env.insert("WINEESYNC", QString::number(1));
|
|
env.insert("WINEFSYNC", QString::number(1));
|
|
env.insert("WINEFSYNC_FUTEX2", QString::number(1));
|
|
}
|
|
#endif
|
|
|
|
#if defined(Q_OS_MAC) || defined(Q_OS_LINUX)
|
|
env.insert("WINEPREFIX", profile.winePrefixPath);
|
|
|
|
// XIV on Mac bundle their own Wine install directory, complete with libs etc
|
|
if(profile.wineType == WineType::XIVOnMac) {
|
|
// TODO: don't hardcode this
|
|
QString xivLibPath = "/Applications/XIV on Mac.app/Contents/Resources/wine/lib";
|
|
|
|
env.insert("DYLD_FALLBACK_LIBRARY_PATH", xivLibPath);
|
|
}
|
|
|
|
arguments.push_back(profile.winePath);
|
|
#endif
|
|
|
|
arguments.append(args);
|
|
|
|
auto executable = arguments[0];
|
|
arguments.removeFirst();
|
|
|
|
if (isGame)
|
|
process->setWorkingDirectory(profile.gamePath + "/game/");
|
|
|
|
process->setProcessEnvironment(env);
|
|
|
|
qDebug() << "launching " << executable << " with args" << arguments;
|
|
|
|
process->start(executable, arguments);
|
|
}
|
|
|
|
QString LauncherCore::readVersion(QString path) {
|
|
QFile file(path);
|
|
file.open(QFile::OpenModeFlag::ReadOnly);
|
|
|
|
return file.readAll();
|
|
}
|
|
|
|
void LauncherCore::readInitialInformation() {
|
|
defaultProfileIndex = settings.value("defaultProfile", 0).toInt();
|
|
|
|
auto defaultAppSettings = AppSettings();
|
|
appSettings.closeWhenLaunched = settings.value("closeWhenLaunched", defaultAppSettings.closeWhenLaunched).toBool();
|
|
appSettings.showBanners = settings.value("showBanners", defaultAppSettings.showBanners).toBool();
|
|
appSettings.showNewsList = settings.value("showNewsList", defaultAppSettings.showNewsList).toBool();
|
|
|
|
gamescopeAvailable = checkIfInPath("gamescope");
|
|
gamemodeAvailable = checkIfInPath("gamemoderun");
|
|
|
|
const QString dataDir =
|
|
QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
|
|
|
const bool hasDalamud = QFile::exists(dataDir + "/Dalamud");
|
|
if (hasDalamud) {
|
|
if (QFile::exists(dataDir + "/Dalamud/Dalamud.deps.json")) {
|
|
QFile depsJson(dataDir + "/Dalamud/Dalamud.deps.json");
|
|
depsJson.open(QFile::ReadOnly);
|
|
QJsonDocument doc = QJsonDocument::fromJson(depsJson.readAll());
|
|
|
|
QString versionString;
|
|
if(doc["targets"].toObject().contains(".NETCoreApp,Version=v5.0")) {
|
|
versionString =
|
|
doc["targets"]
|
|
.toObject()[".NETCoreApp,Version=v5.0"]
|
|
.toObject()
|
|
.keys()
|
|
.filter("Dalamud")[0];
|
|
} else {
|
|
versionString =
|
|
doc["targets"]
|
|
.toObject()[".NETCoreApp,Version=v6.0"]
|
|
.toObject()
|
|
.keys()
|
|
.filter("Dalamud")[0];
|
|
}
|
|
|
|
dalamudVersion = versionString.remove("Dalamud/");
|
|
}
|
|
|
|
if(QFile::exists(dataDir + "/DalamudAssets/asset.ver")) {
|
|
QFile assetJson(dataDir + "/DalamudAssets/asset.ver");
|
|
assetJson.open(QFile::ReadOnly | QFile::Text);
|
|
|
|
dalamudAssetVersion = QString(assetJson.readAll()).toInt();
|
|
}
|
|
|
|
if(QFile::exists(dataDir + "/DalamudRuntime/runtime.ver")) {
|
|
QFile runtimeVer(dataDir + "/DalamudRuntime/runtime.ver");
|
|
runtimeVer.open(QFile::ReadOnly | QFile::Text);
|
|
|
|
runtimeVersion = QString(runtimeVer.readAll());
|
|
}
|
|
}
|
|
|
|
if(QFile::exists(dataDir + "/nativelauncher.ver")) {
|
|
QFile nativeVer(dataDir + "/nativelauncher.ver");
|
|
nativeVer.open(QFile::ReadOnly | QFile::Text);
|
|
|
|
nativeLauncherVersion = QString(nativeVer.readAll());
|
|
}
|
|
|
|
auto profiles = settings.childGroups();
|
|
|
|
// create the Default profile if it doesnt exist
|
|
if(profiles.empty())
|
|
profiles.append(QUuid::createUuid().toString(QUuid::StringFormat::WithoutBraces));
|
|
|
|
profileSettings.resize(profiles.size());
|
|
|
|
for(const auto& uuid : profiles) {
|
|
ProfileSettings profile;
|
|
profile.uuid = QUuid(uuid);
|
|
|
|
settings.beginGroup(uuid);
|
|
|
|
profile.name = settings.value("name", "Default").toString();
|
|
|
|
if(settings.contains("gamePath") && settings.value("gamePath").canConvert<QString>() && !settings.value("gamePath").toString().isEmpty()) {
|
|
profile.gamePath = settings.value("gamePath").toString();
|
|
} else {
|
|
profile.gamePath = getDefaultGamePath();
|
|
}
|
|
|
|
if(settings.contains("winePrefixPath") && settings.value("winePrefixPath").canConvert<QString>() && !settings.value("winePrefixPath").toString().isEmpty()) {
|
|
profile.winePrefixPath = settings.value("winePrefixPath").toString();
|
|
} else {
|
|
profile.winePrefixPath = getDefaultWinePrefixPath();
|
|
}
|
|
|
|
if(settings.contains("winePath") && settings.value("winePath").canConvert<QString>() && !settings.value("winePath").toString().isEmpty()) {
|
|
profile.winePath = settings.value("winePath").toString();
|
|
}
|
|
|
|
ProfileSettings defaultSettings;
|
|
|
|
// login
|
|
profile.encryptArguments = settings.value("encryptArguments", defaultSettings.encryptArguments).toBool();
|
|
profile.isSapphire = settings.value("isSapphire", defaultSettings.isSapphire).toBool();
|
|
profile.lobbyURL = settings.value("lobbyURL", defaultSettings.lobbyURL).toString();
|
|
profile.rememberUsername = settings.value("rememberUsername", defaultSettings.rememberUsername).toBool();
|
|
profile.rememberPassword = settings.value("rememberPassword", defaultSettings.rememberPassword).toBool();
|
|
profile.useOneTimePassword = settings.value("useOneTimePassword", defaultSettings.useOneTimePassword).toBool();
|
|
profile.license = (GameLicense)settings.value("license", (int)defaultSettings.license).toInt();
|
|
|
|
profile.useDX9 = settings.value("useDX9", defaultSettings.useDX9).toBool();
|
|
|
|
// wine
|
|
profile.wineType = (WineType)settings.value("wineType", (int)defaultSettings.wineType).toInt();
|
|
profile.useEsync = settings.value("useEsync", defaultSettings.useEsync).toBool();
|
|
|
|
readWineInfo(profile);
|
|
|
|
if(gamescopeAvailable)
|
|
profile.useGamescope = settings.value("useGamescope", defaultSettings.useGamescope).toBool();
|
|
|
|
if(gamemodeAvailable)
|
|
profile.useGamemode = settings.value("useGamemode", defaultSettings.useGamemode).toBool();
|
|
|
|
profile.enableDXVKhud = settings.value("enableDXVKhud", defaultSettings.enableDXVKhud).toBool();
|
|
|
|
profile.enableWatchdog = settings.value("enableWatchdog", defaultSettings.enableWatchdog).toBool();
|
|
|
|
// gamescope
|
|
profile.gamescope.fullscreen = settings.value("gamescopeFullscreen", defaultSettings.gamescope.fullscreen).toBool();
|
|
profile.gamescope.borderless = settings.value("gamescopeBorderless", defaultSettings.gamescope.borderless).toBool();
|
|
profile.gamescope.width = settings.value("gamescopeWidth", defaultSettings.gamescope.width).toInt();
|
|
profile.gamescope.height = settings.value("gamescopeHeight", defaultSettings.gamescope.height).toInt();
|
|
profile.gamescope.refreshRate = settings.value("gamescopeRefreshRate", defaultSettings.gamescope.refreshRate).toInt();
|
|
|
|
profile.dalamud.enabled = settings.value("enableDalamud", defaultSettings.dalamud.enabled).toBool();
|
|
profile.dalamud.optOutOfMbCollection = settings.value("dalamudOptOut", defaultSettings.dalamud.optOutOfMbCollection).toBool();
|
|
profile.dalamud.channel = (DalamudChannel)settings.value("dalamudChannel", (int)defaultSettings.dalamud.channel).toInt();
|
|
|
|
profileSettings[settings.value("index").toInt()] = profile;
|
|
|
|
settings.endGroup();
|
|
}
|
|
|
|
readGameVersion();
|
|
}
|
|
|
|
void LauncherCore::readWineInfo(ProfileSettings& profile) {
|
|
#if defined(Q_OS_MAC)
|
|
switch(profile.wineType) {
|
|
case WineType::System: // system wine
|
|
profile.winePath = "/usr/local/bin/wine64";
|
|
break;
|
|
case WineType::Custom: // custom path
|
|
profile.winePath = profile.winePath;
|
|
break;
|
|
case WineType::Builtin: // ffxiv built-in (for mac users)
|
|
profile.winePath = "/Applications/FINAL FANTASY XIV ONLINE.app/Contents/SharedSupport/finalfantasyxiv/FINAL FANTASY XIV ONLINE/wine";
|
|
break;
|
|
case WineType::XIVOnMac:
|
|
profile.winePath = "/Applications/XIV on Mac.app/Contents/Resources/wine/bin/wine64";
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
#if defined(Q_OS_LINUX)
|
|
switch(profile.wineType) {
|
|
case WineType::System: // system wine (should be in $PATH)
|
|
profile.winePath = "/usr/bin/wine";
|
|
break;
|
|
case WineType::Custom: // custom pth
|
|
profile.winePath = profile.winePath;
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
#if defined(Q_OS_LINUX) || defined(Q_OS_MAC)
|
|
auto wineProcess = new QProcess();
|
|
wineProcess->setProcessChannelMode(QProcess::MergedChannels);
|
|
|
|
connect(wineProcess, &QProcess::readyRead, this, [wineProcess, &profile] {
|
|
profile.wineVersion = wineProcess->readAllStandardOutput().trimmed();
|
|
});
|
|
|
|
wineProcess->start(profile.winePath, {"--version"});
|
|
wineProcess->waitForFinished();
|
|
#endif
|
|
}
|
|
|
|
void LauncherCore::readGameVersion() {
|
|
for(auto& profile : profileSettings) {
|
|
profile.bootVersion = readVersion(profile.gamePath + "/boot/ffxivboot.ver");
|
|
profile.gameVersion = readVersion(profile.gamePath + "/game/ffxivgame.ver");
|
|
profile.installedMaxExpansion = 0;
|
|
|
|
for(auto dir : QDir(profile.gamePath + "/game/sqpack/").entryList(QDir::Filter::Dirs)) {
|
|
if(dir.contains("ex") && dir.length() == 3 && dir[2].isDigit()) {
|
|
const int expacVersion = dir[2].digitValue();
|
|
|
|
profile.installedMaxExpansion = std::max(profile.installedMaxExpansion, expacVersion);
|
|
}
|
|
}
|
|
|
|
readExpansionVersions(profile, profile.installedMaxExpansion);
|
|
}
|
|
}
|
|
|
|
LauncherCore::LauncherCore() : settings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::applicationName()) {
|
|
mgr = new QNetworkAccessManager();
|
|
sapphireLauncher = new SapphireLauncher(*this);
|
|
squareLauncher = new SquareLauncher(*this);
|
|
squareBoot = new SquareBoot(*this, *squareLauncher);
|
|
assetUpdater = new AssetUpdater(*this);
|
|
|
|
#ifdef ENABLE_WATCHDOG
|
|
watchdog = new Watchdog(*this);
|
|
#endif
|
|
|
|
readInitialInformation();
|
|
|
|
// check gate status before login
|
|
squareLauncher->gateOpen();
|
|
|
|
// TODO: we really should call this "heavy" signal
|
|
connect(squareLauncher, &SquareLauncher::gateStatusRecieved, this, &LauncherCore::settingsChanged);
|
|
}
|
|
|
|
LauncherCore::~LauncherCore() noexcept {
|
|
#ifdef ENABLE_WATCHDOG
|
|
delete watchdog;
|
|
#endif
|
|
}
|
|
|
|
ProfileSettings LauncherCore::getProfile(int index) const {
|
|
return profileSettings[index];
|
|
}
|
|
|
|
ProfileSettings& LauncherCore::getProfile(int index) {
|
|
return profileSettings[index];
|
|
}
|
|
|
|
int LauncherCore::getProfileIndex(QString name) {
|
|
for(int i = 0; i < profileSettings.size(); i++) {
|
|
if(profileSettings[i].name == name)
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
QList<QString> LauncherCore::profileList() const {
|
|
QList<QString> list;
|
|
for(auto profile : profileSettings) {
|
|
list.append(profile.name);
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
int LauncherCore::addProfile() {
|
|
ProfileSettings newProfile;
|
|
newProfile.uuid = QUuid::createUuid();
|
|
newProfile.name = "New Profile";
|
|
|
|
readWineInfo(newProfile);
|
|
|
|
newProfile.gamePath = getDefaultGamePath();
|
|
newProfile.winePrefixPath = getDefaultWinePrefixPath();
|
|
|
|
profileSettings.append(newProfile);
|
|
|
|
settingsChanged();
|
|
|
|
return profileSettings.size() - 1;
|
|
}
|
|
|
|
int LauncherCore::deleteProfile(QString name) {
|
|
int index = 0;
|
|
for(int i = 0; i < profileSettings.size(); i++) {
|
|
if(profileSettings[i].name == name)
|
|
index = i;
|
|
}
|
|
|
|
// remove group so it doesnt stay
|
|
settings.beginGroup(profileSettings[index].uuid.toString(QUuid::StringFormat::WithoutBraces));
|
|
settings.remove("");
|
|
settings.endGroup();
|
|
|
|
profileSettings.removeAt(index);
|
|
|
|
return index - 1;
|
|
}
|
|
|
|
void LauncherCore::saveSettings() {
|
|
settings.setValue("defaultProfile", defaultProfileIndex);
|
|
settings.setValue("closeWhenLaunched", appSettings.closeWhenLaunched);
|
|
settings.setValue("showBanners", appSettings.showBanners);
|
|
settings.setValue("showNewsList", appSettings.showNewsList);
|
|
|
|
for(int i = 0; i < profileSettings.size(); i++) {
|
|
const auto& profile = profileSettings[i];
|
|
|
|
settings.beginGroup(profile.uuid.toString(QUuid::StringFormat::WithoutBraces));
|
|
|
|
settings.setValue("name", profile.name);
|
|
settings.setValue("index", i);
|
|
|
|
// game
|
|
settings.setValue("useDX9", profile.useDX9);
|
|
settings.setValue("gamePath", profile.gamePath);
|
|
|
|
// wine
|
|
settings.setValue("wineType", (int)profile.wineType);
|
|
settings.setValue("winePath", profile.winePath);
|
|
settings.setValue("winePrefixPath", profile.winePrefixPath);
|
|
|
|
settings.setValue("useEsync", profile.useEsync);
|
|
settings.setValue("useGamescope", profile.useGamescope);
|
|
settings.setValue("useGamemode", profile.useGamemode);
|
|
|
|
// gamescope
|
|
settings.setValue("gamescopeFullscreen", profile.gamescope.fullscreen);
|
|
settings.setValue("gamescopeBorderless", profile.gamescope.borderless);
|
|
settings.setValue("gamescopeWidth", profile.gamescope.width);
|
|
settings.setValue("gamescopeHeight", profile.gamescope.height);
|
|
settings.setValue("gamescopeRefreshRate", profile.gamescope.refreshRate);
|
|
|
|
// login
|
|
settings.setValue("encryptArguments", profile.encryptArguments);
|
|
settings.setValue("isSapphire", profile.isSapphire);
|
|
settings.setValue("lobbyURL", profile.lobbyURL);
|
|
settings.setValue("rememberUsername", profile.rememberUsername);
|
|
settings.setValue("rememberPassword", profile.rememberPassword);
|
|
settings.setValue("useOneTimePassword", profile.useOneTimePassword);
|
|
settings.setValue("license", (int)profile.license);
|
|
|
|
settings.setValue("enableDalamud", profile.dalamud.enabled);
|
|
settings.setValue("dalamudOptOut", profile.dalamud.optOutOfMbCollection);
|
|
settings.setValue("dalamudChannel", (int)profile.dalamud.channel);
|
|
settings.setValue("enableWatchdog", profile.enableWatchdog);
|
|
|
|
settings.endGroup();
|
|
}
|
|
}
|
|
|
|
void LauncherCore::addUpdateButtons(const ProfileSettings& settings, QMessageBox& messageBox) {
|
|
auto launcherButton = messageBox.addButton("Launch Official Launcher", QMessageBox::NoRole);
|
|
connect(launcherButton, &QPushButton::clicked, [=] {
|
|
launchExecutable(settings, {settings.gamePath + "/boot/ffxivboot.exe"});
|
|
});
|
|
|
|
messageBox.addButton(QMessageBox::StandardButton::Ok);
|
|
}
|
|
|
|
void LauncherCore::readExpansionVersions(ProfileSettings& info, int max) {
|
|
info.expansionVersions.clear();
|
|
|
|
for(int i = 0; i < max; i++)
|
|
info.expansionVersions.push_back(readVersion(QString("%1/game/sqpack/ex%2/ex%2.ver").arg(info.gamePath, QString::number(i + 1))));
|
|
}
|
|
|
|
bool LauncherCore::checkIfInPath(const QString program) {
|
|
// TODO: also check /usr/local/bin, /bin32 etc (basically read $PATH)
|
|
const QString directory = "/usr/bin";
|
|
|
|
QFileInfo fileInfo(directory + "/" + program);
|
|
|
|
return fileInfo.exists() && fileInfo.isFile();
|
|
}
|
|
|
|
QString LauncherCore::getDefaultWinePrefixPath() {
|
|
#if defined(Q_OS_MACOS)
|
|
return QDir::homePath() + "/Library/Application Support/FINAL FANTASY XIV ONLINE/Bottles/published_Final_Fantasy";
|
|
#endif
|
|
|
|
#if defined(Q_OS_LINUX)
|
|
return QDir::homePath() + "/.wine";
|
|
#endif
|
|
|
|
return "";
|
|
}
|
|
|
|
QString LauncherCore::getDefaultGamePath() {
|
|
#if defined(Q_OS_WIN)
|
|
return "C:\\Program Files (x86)\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn";
|
|
#endif
|
|
|
|
#if defined(Q_OS_MAC)
|
|
return QDir::homePath() + "/Library/Application Support/FINAL FANTASY XIV ONLINE/Bottles/published_Final_Fantasy/drive_c/Program Files (x86)/SquareEnix/FINAL FANTASY XIV - A Realm Reborn";
|
|
#endif
|
|
|
|
#if defined(Q_OS_LINUX)
|
|
return QDir::homePath() + "/.wine/drive_c/Program Files (x86)/SquareEnix/FINAL FANTASY XIV - A Realm Reborn";
|
|
#endif
|
|
}
|