mirror of
https://github.com/redstrate/Astra.git
synced 2025-04-20 11:47:46 +00:00
Fix Astra considering the game exited when Dalamud exits
This is a design limitation of the Dalamud Injector (at least from how we use it) because we depend on the child process exiting to be when the game exists. For vanilla games, this is true but not for Dalamud. Now we track the PID given to us by Dalamud and use that as an indicator to when the game exits. This is needed to properly keep tracked of when the game exists for the future sync feature.
This commit is contained in:
parent
e32a61edad
commit
3b95982dcf
6 changed files with 83 additions and 8 deletions
|
@ -56,6 +56,7 @@ target_sources(astra PRIVATE
|
|||
include/logger.h
|
||||
include/patcher.h
|
||||
include/processlogger.h
|
||||
include/processwatcher.h
|
||||
include/profile.h
|
||||
include/profilemanager.h
|
||||
include/sapphirelogin.h
|
||||
|
@ -79,6 +80,7 @@ target_sources(astra PRIVATE
|
|||
src/main.cpp
|
||||
src/patcher.cpp
|
||||
src/processlogger.cpp
|
||||
src/processwatcher.cpp
|
||||
src/profile.cpp
|
||||
src/profilemanager.cpp
|
||||
src/sapphirelogin.cpp
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
class ProcessLogger : public QObject
|
||||
{
|
||||
public:
|
||||
explicit ProcessLogger(QProcess *process);
|
||||
explicit ProcessLogger(const QString &baseName, QProcess *process);
|
||||
|
||||
private:
|
||||
QFile m_file;
|
||||
|
|
21
launcher/include/processwatcher.h
Normal file
21
launcher/include/processwatcher.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
|
||||
/// Listens and waits for a process to finish.
|
||||
class ProcessWatcher : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ProcessWatcher(const int PID);
|
||||
|
||||
Q_SIGNALS:
|
||||
void finished();
|
||||
|
||||
private:
|
||||
QTimer *m_timer = nullptr;
|
||||
};
|
|
@ -7,9 +7,11 @@
|
|||
#include <gamemode_client.h>
|
||||
#endif
|
||||
|
||||
#include "astra_log.h"
|
||||
#include "encryptedarg.h"
|
||||
#include "launchercore.h"
|
||||
#include "processlogger.h"
|
||||
#include "processwatcher.h"
|
||||
#include "utility.h"
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
|
@ -52,7 +54,7 @@ void GameRunner::beginVanillaGame(const QString &gameExecutablePath, Profile &pr
|
|||
|
||||
auto args = getGameArgs(profile, auth);
|
||||
|
||||
new ProcessLogger(gameProcess);
|
||||
new ProcessLogger(QStringLiteral("ffxiv"), gameProcess);
|
||||
|
||||
launchExecutable(profile, gameProcess, {gameExecutablePath, args}, true, true);
|
||||
}
|
||||
|
@ -75,7 +77,7 @@ void GameRunner::beginDalamudGame(const QString &gameExecutablePath, Profile &pr
|
|||
// so we need to match typical XIVQuickLauncher behavior here. Why? I have no clue.
|
||||
const QDir dalamudPluginDir = dalamudUserPluginDir.absoluteFilePath(QStringLiteral("installedPlugins"));
|
||||
|
||||
const QString logDir = dataDir.absoluteFilePath(QStringLiteral("log"));
|
||||
const QDir logDir = dataDir.absoluteFilePath(QStringLiteral("log"));
|
||||
Utility::createPathIfNeeded(logDir);
|
||||
|
||||
const QDir dalamudRuntimeDir = dalamudDir.absoluteFilePath(QStringLiteral("runtime"));
|
||||
|
@ -86,9 +88,35 @@ void GameRunner::beginDalamudGame(const QString &gameExecutablePath, Profile &pr
|
|||
const QString dalamudInjector = dalamudInstallDir.absoluteFilePath(QStringLiteral("Dalamud.Injector.exe"));
|
||||
|
||||
const auto dalamudProcess = new QProcess(this);
|
||||
connect(dalamudProcess, &QProcess::finished, this, [this, &profile](const int exitCode) {
|
||||
profile.setLoggedIn(false);
|
||||
connect(dalamudProcess, &QProcess::finished, this, [this, &profile, logDir](const int exitCode) {
|
||||
Q_UNUSED(exitCode)
|
||||
|
||||
// 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)) {
|
||||
const int PID = match.captured(1).toInt();
|
||||
if (PID > 0) {
|
||||
qCInfo(ASTRA_LOG) << "Recieved PID from Dalamud:" << PID;
|
||||
auto watcher = new ProcessWatcher(PID);
|
||||
connect(watcher, &ProcessWatcher::finished, this, [this, &profile] {
|
||||
profile.setLoggedIn(false);
|
||||
Q_EMIT m_launcher.gameClosed();
|
||||
});
|
||||
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);
|
||||
Q_EMIT m_launcher.gameClosed();
|
||||
});
|
||||
|
||||
|
@ -100,7 +128,7 @@ void GameRunner::beginDalamudGame(const QString &gameExecutablePath, Profile &pr
|
|||
#endif
|
||||
dalamudProcess->setProcessEnvironment(env);
|
||||
|
||||
new ProcessLogger(dalamudProcess);
|
||||
new ProcessLogger(QStringLiteral("dalamud-initial-injection"), dalamudProcess);
|
||||
|
||||
const auto args = getGameArgs(profile, auth);
|
||||
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
|
||||
#include <QStandardPaths>
|
||||
|
||||
ProcessLogger::ProcessLogger(QProcess *process)
|
||||
ProcessLogger::ProcessLogger(const QString &baseName, QProcess *process)
|
||||
{
|
||||
const QDir dataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
||||
const QDir logDirectory = dataDir.absoluteFilePath(QStringLiteral("log"));
|
||||
|
||||
m_file.setFileName(logDirectory.absoluteFilePath(QStringLiteral("ffxiv.log")));
|
||||
m_file.setFileName(logDirectory.absoluteFilePath(QStringLiteral("%1.log").arg(baseName)));
|
||||
m_file.open(QIODevice::WriteOnly | QIODevice::Unbuffered);
|
||||
|
||||
connect(process, &QProcess::readyReadStandardOutput, this, [this, process] {
|
||||
|
|
24
launcher/src/processwatcher.cpp
Normal file
24
launcher/src/processwatcher.cpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "processwatcher.h"
|
||||
|
||||
#include <KProcessList>
|
||||
|
||||
#include "moc_processwatcher.cpp"
|
||||
|
||||
ProcessWatcher::ProcessWatcher(const int PID)
|
||||
{
|
||||
m_timer = new QTimer();
|
||||
connect(m_timer, &QTimer::timeout, this, [this, PID] {
|
||||
const auto info = KProcessList::processInfo(PID);
|
||||
// If we can't find the PID, bail!
|
||||
if (!info.isValid()) {
|
||||
m_timer->stop();
|
||||
deleteLater();
|
||||
Q_EMIT finished();
|
||||
}
|
||||
});
|
||||
m_timer->setInterval(std::chrono::seconds(30));
|
||||
m_timer->start();
|
||||
}
|
Loading…
Add table
Reference in a new issue