From a502d57c8f83e36f8154e0bf7004ac7fa06deee0 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Fri, 18 Aug 2023 23:27:29 -0400 Subject: [PATCH] Add graphical Steam compatibility tool installer --- .reuse/dep5 | 2 +- compatibilitytool/compatibilitytool.vdf | 14 --- compatibilitytool/toolmanifest.vdf | 5 - launcher/CMakeLists.txt | 2 + launcher/include/compatibilitytoolinstaller.h | 26 ++++++ launcher/include/launchercore.h | 2 + launcher/resources.qrc | 1 + launcher/src/compatibilitytoolinstaller.cpp | 91 +++++++++++++++++++ launcher/src/launchercore.cpp | 6 ++ launcher/src/main.cpp | 6 ++ .../ui/Settings/CompatibilityToolSetup.qml | 84 +++++++++++++++++ launcher/ui/Settings/SettingsPage.qml | 8 ++ 12 files changed, 227 insertions(+), 20 deletions(-) delete mode 100644 compatibilitytool/compatibilitytool.vdf delete mode 100644 compatibilitytool/toolmanifest.vdf create mode 100644 launcher/include/compatibilitytoolinstaller.h create mode 100644 launcher/src/compatibilitytoolinstaller.cpp create mode 100644 launcher/ui/Settings/CompatibilityToolSetup.qml diff --git a/.reuse/dep5 b/.reuse/dep5 index c728a06..55ea41c 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -3,7 +3,7 @@ Upstream-Name: Astra Upstream-Contact: Joshua Goins Source: https://git.sr.ht/~redstrate/astra -Files: README.md .build.yml .editorconfig zone.xiv.astra.yml zone.xiv.astra.desktop build-flatpak.sh compatibilitytool/* misc/* +Files: README.md .build.yml .editorconfig zone.xiv.astra.yml zone.xiv.astra.desktop build-flatpak.sh misc/* Copyright: Joshua Goins License: CC0-1.0 diff --git a/compatibilitytool/compatibilitytool.vdf b/compatibilitytool/compatibilitytool.vdf deleted file mode 100644 index f19cb63..0000000 --- a/compatibilitytool/compatibilitytool.vdf +++ /dev/null @@ -1,14 +0,0 @@ -"compatibilitytools" -{ - "compat_tools" - { - "Proton-Astra" // Internal name of this tool - { - "install_path" "." - "display_name" "Astra" - - "from_oslist" "windows" - "to_oslist" "linux" - } - } -} diff --git a/compatibilitytool/toolmanifest.vdf b/compatibilitytool/toolmanifest.vdf deleted file mode 100644 index 9704382..0000000 --- a/compatibilitytool/toolmanifest.vdf +++ /dev/null @@ -1,5 +0,0 @@ -"manifest" -{ - "version" "2" - "commandline" "/astra --steam %verb%" -} diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index f92fd39..3b414e1 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -6,6 +6,7 @@ target_sources(astra PRIVATE include/account.h include/accountmanager.h include/assetupdater.h + include/compatibilitytoolinstaller.h include/encryptedarg.h include/gameinstaller.h include/headline.h @@ -22,6 +23,7 @@ target_sources(astra PRIVATE src/account.cpp src/accountmanager.cpp src/assetupdater.cpp + src/compatibilitytoolinstaller.cpp src/encryptedarg.cpp src/gameinstaller.cpp src/launchercore.cpp diff --git a/launcher/include/compatibilitytoolinstaller.h b/launcher/include/compatibilitytoolinstaller.h new file mode 100644 index 0000000..e44239a --- /dev/null +++ b/launcher/include/compatibilitytoolinstaller.h @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: 2023 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include + +class LauncherCore; + +class CompatibilityToolInstaller : public QObject +{ + Q_OBJECT +public: + CompatibilityToolInstaller(LauncherCore &launcher, QObject *parent = nullptr); + + Q_INVOKABLE void installCompatibilityTool(); + Q_INVOKABLE void removeCompatibilityTool(); + +Q_SIGNALS: + void installFinished(); + void error(QString message); + +private: + LauncherCore &m_launcher; +}; \ No newline at end of file diff --git a/launcher/include/launchercore.h b/launcher/include/launchercore.h index 94429ff..9a6116c 100755 --- a/launcher/include/launchercore.h +++ b/launcher/include/launchercore.h @@ -20,6 +20,7 @@ class SquareLauncher; class AssetUpdater; class Watchdog; class GameInstaller; +class CompatibilityToolInstaller; class LoginInformation : public QObject { @@ -141,6 +142,7 @@ public: bool m_isSteam = false; Q_INVOKABLE GameInstaller *createInstaller(Profile *profile); + Q_INVOKABLE CompatibilityToolInstaller *createCompatInstaller(); bool isLoadingFinished() const; bool hasAccount() const; diff --git a/launcher/resources.qrc b/launcher/resources.qrc index 14ad376..5d8f696 100644 --- a/launcher/resources.qrc +++ b/launcher/resources.qrc @@ -12,6 +12,7 @@ SPDX-License-Identifier: GPL-3.0-or-later ui/Pages/NewsPage.qml ui/Pages/StatusPage.qml ui/Settings/AccountSettings.qml + ui/Settings/CompatibilityToolSetup.qml ui/Settings/DeveloperSettings.qml ui/Settings/GeneralSettings.qml ui/Settings/ProfileSettings.qml diff --git a/launcher/src/compatibilitytoolinstaller.cpp b/launcher/src/compatibilitytoolinstaller.cpp new file mode 100644 index 0000000..be0da82 --- /dev/null +++ b/launcher/src/compatibilitytoolinstaller.cpp @@ -0,0 +1,91 @@ +// SPDX-FileCopyrightText: 2023 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "compatibilitytoolinstaller.h" + +#include "launchercore.h" + +CompatibilityToolInstaller::CompatibilityToolInstaller(LauncherCore &launcher, QObject *parent) + : QObject(parent) + , m_launcher(launcher) +{ +} + +void CompatibilityToolInstaller::installCompatibilityTool() +{ + const QDir appDataDir = QStandardPaths::standardLocations(QStandardPaths::StandardLocation::GenericDataLocation)[0]; + const QDir steamDir = appDataDir.absoluteFilePath("Steam"); + if (!steamDir.exists()) { + Q_EMIT error("Could not find a Steam installation."); + return; + } + + const QDir compatToolDir = steamDir.absoluteFilePath("compatibilitytools.d"); + const QDir astraToolDir = compatToolDir.absoluteFilePath("astra"); + if (astraToolDir.exists()) { + Q_EMIT error("The compatibility tool is already installed."); + return; + } else { + QDir().mkpath(astraToolDir.absolutePath()); + } + + const QString appPath = QCoreApplication::applicationFilePath(); + QFile appFile(appPath); + appFile.link(astraToolDir.absoluteFilePath("astra")); + + const QString toolManifestContents = QStringLiteral( + "\"manifest\"\n" + "{\n" + " \"version\" \"2\"\n" + " \"commandline\" \"/astra --steam %verb%\"\n" + "}"); + + QFile toolManifestFile(astraToolDir.absoluteFilePath("toolmanifest.vdf")); + toolManifestFile.open(QIODevice::WriteOnly); + toolManifestFile.write(toolManifestContents.toUtf8()); + toolManifestFile.close(); + + const QString compatibilityToolContents = QStringLiteral( + "\"compatibilitytools\"\n" + "{\n" + " \"compat_tools\"\n" + " {\n" + "\t\"Proton-Astra\" // Internal name of this tool\n" + "\t{\n" + "\t \"install_path\" \".\"\n" + "\t \"display_name\" \"Astra\"\n" + "\n" + "\t \"from_oslist\" \"windows\"\n" + "\t \"to_oslist\" \"linux\"\n" + "\t}\n" + " }\n" + "}"); + + QFile compatibilityToolFile(astraToolDir.absoluteFilePath("compatibilitytool.vdf")); + compatibilityToolFile.open(QIODevice::WriteOnly); + compatibilityToolFile.write(compatibilityToolContents.toUtf8()); + compatibilityToolFile.close(); + + Q_EMIT installFinished(); +} + +void CompatibilityToolInstaller::removeCompatibilityTool() +{ + const QDir appDataDir = QStandardPaths::standardLocations(QStandardPaths::StandardLocation::GenericDataLocation)[0]; + const QDir steamDir = appDataDir.absoluteFilePath("Steam"); + if (!steamDir.exists()) { + Q_EMIT error("Could not find a Steam installation."); + return; + } + + const QDir compatToolDir = steamDir.absoluteFilePath("compatibilitytools.d"); + QDir astraToolDir = compatToolDir.absoluteFilePath("astra"); + if (!astraToolDir.exists()) { + Q_EMIT error("The compatibility tool is not installed."); + return; + } else { + astraToolDir.removeRecursively(); + } + + Q_EMIT installFinished(); +} diff --git a/launcher/src/launchercore.cpp b/launcher/src/launchercore.cpp index 4829fe9..a8495d0 100755 --- a/launcher/src/launchercore.cpp +++ b/launcher/src/launchercore.cpp @@ -16,6 +16,7 @@ #include "account.h" #include "assetupdater.h" +#include "compatibilitytoolinstaller.h" #include "config.h" #include "encryptedarg.h" #include "launchercore.h" @@ -450,6 +451,11 @@ GameInstaller *LauncherCore::createInstaller(Profile *profile) return new GameInstaller(*this, *profile, this); } +CompatibilityToolInstaller *LauncherCore::createCompatInstaller() +{ + return new CompatibilityToolInstaller(*this, this); +} + bool LauncherCore::isLoadingFinished() const { return m_loadingFinished; diff --git a/launcher/src/main.cpp b/launcher/src/main.cpp index 7f61ec3..8d42261 100755 --- a/launcher/src/main.cpp +++ b/launcher/src/main.cpp @@ -10,6 +10,7 @@ #include #include "astra-version.h" +#include "compatibilitytoolinstaller.h" #include "gameinstaller.h" #include "launchercore.h" #include "sapphirelauncher.h" @@ -75,6 +76,11 @@ int main(int argc, char *argv[]) qmlRegisterSingletonInstance("zone.xiv.astra", 1, 0, "LauncherCore", &c); qmlRegisterUncreatableType("zone.xiv.astra", 1, 0, "GameInstaller", QStringLiteral("Use LauncherCore::createInstaller")); + qmlRegisterUncreatableType("zone.xiv.astra", + 1, + 0, + "CompatibilityToolInstaller", + QStringLiteral("Use LauncherCore::createCompatInstaller")); qmlRegisterUncreatableType("zone.xiv.astra", 1, 0, "AccountManager", QStringLiteral("Use LauncherCore::accountManager")); qmlRegisterUncreatableType("zone.xiv.astra", 1, 0, "ProfileManager", QStringLiteral("Use LauncherCore::profileManager")); qmlRegisterUncreatableType("zone.xiv.astra", 1, 0, "Profile", QStringLiteral("Use from ProfileManager")); diff --git a/launcher/ui/Settings/CompatibilityToolSetup.qml b/launcher/ui/Settings/CompatibilityToolSetup.qml new file mode 100644 index 0000000..520ca7d --- /dev/null +++ b/launcher/ui/Settings/CompatibilityToolSetup.qml @@ -0,0 +1,84 @@ +// SPDX-FileCopyrightText: 2023 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick 2.15 +import QtQuick.Window 2.15 +import org.kde.kirigami 2.20 as Kirigami +import QtQuick.Controls 2.15 as Controls +import QtQuick.Layouts 1.15 +import org.kde.kirigamiaddons.labs.mobileform 0.1 as MobileForm +import zone.xiv.astra 1.0 + +Kirigami.Page { + id: page + + property var installer: null + + title: i18n("Install Compatibility Tool") + + ColumnLayout { + width: parent.width + MobileForm.FormCard { + Layout.topMargin: Kirigami.Units.largeSpacing + Layout.fillWidth: true + contentItem: ColumnLayout { + spacing: 0 + + MobileForm.FormCardHeader { + title: i18n("Compatibility Tool") + } + + MobileForm.FormTextDelegate { + text: i18n("Press the button below to install the compatibility tool for Steam.") + } + + MobileForm.FormDelegateSeparator {} + + MobileForm.FormButtonDelegate { + text: i18n("Install Tool") + icon.name: "install" + onClicked: { + page.installer = LauncherCore.createCompatInstaller(); + page.installer.installCompatibilityTool(); + } + } + + MobileForm.FormDelegateSeparator {} + + MobileForm.FormButtonDelegate { + text: i18n("Remove Tool") + icon.name: "delete" + onClicked: { + page.installer = LauncherCore.createCompatInstaller(); + page.installer.removeCompatibilityTool(); + } + } + } + } + } + + Kirigami.PromptDialog { + id: errorDialog + title: i18n("Install error") + + showCloseButton: false + standardButtons: Kirigami.Dialog.Ok + + onAccepted: applicationWindow().pageStack.layers.pop() + onRejected: applicationWindow().pageStack.layers.pop() + } + + Connections { + enabled: page.installer !== null + target: page.installer + + function onInstallFinished() { + applicationWindow().pageStack.layers.pop() + } + + function onError(message) { + errorDialog.subtitle = message + errorDialog.open() + } + } +} \ No newline at end of file diff --git a/launcher/ui/Settings/SettingsPage.qml b/launcher/ui/Settings/SettingsPage.qml index 32f1478..3d887ce 100644 --- a/launcher/ui/Settings/SettingsPage.qml +++ b/launcher/ui/Settings/SettingsPage.qml @@ -116,6 +116,14 @@ Kirigami.ScrollablePage { } } + MobileForm.FormButtonDelegate { + text: i18n("Setup Compatibility Tool") + icon.name: "install" + onClicked: applicationWindow().pageStack.layers.push('qrc:/ui/Settings/CompatibilityToolSetup.qml') + } + + MobileForm.FormDelegateSeparator {} + MobileForm.FormButtonDelegate { text: i18n("Developer Settings") icon.name: "configure"