diff --git a/src/XIVLauncher.Common.Unix/UnixSteam.cs b/src/XIVLauncher.Common.Unix/UnixSteam.cs
index 9fa1c8af4..8ca1280bf 100644
--- a/src/XIVLauncher.Common.Unix/UnixSteam.cs
+++ b/src/XIVLauncher.Common.Unix/UnixSteam.cs
@@ -1,81 +1,185 @@
+#nullable enable
using System;
+using System.Diagnostics;
+using System.Linq;
using System.Threading.Tasks;
using Steamworks;
using XIVLauncher.Common.PlatformAbstractions;
-namespace XIVLauncher.Common.Unix
+namespace XIVLauncher.Common.Unix;
+
+///
+/// An implementation of ISteam for Unix endpoints. Borrows logic heavily from Facepunch's lib.
+///
+public class UnixSteam : ISteam
{
- public class UnixSteam : ISteam
+ private Callback? textDismissedCallback;
+
+ public void Initialize(uint appId)
{
- public UnixSteam()
- {
- SteamUtils.OnGamepadTextInputDismissed += b => OnGamepadTextInputDismissed?.Invoke(b);
- }
+ // workaround because SetEnvironmentVariable doesn't actually touch the process environment on unix
+ [System.Runtime.InteropServices.DllImport("c")]
+ static extern int setenv(string name, string value, int overwrite);
- public void Initialize(uint appId)
- {
- // workaround because SetEnvironmentVariable doesn't actually touch the process environment on unix
- [System.Runtime.InteropServices.DllImport("c")]
- static extern int setenv(string name, string value, int overwrite);
+ setenv("SteamAppId", appId.ToString(), 1);
+ setenv("SteamGameId", appId.ToString(), 1);
- setenv("SteamAppId", appId.ToString(), 1);
- setenv("SteamGameId", appId.ToString(), 1);
+ this.IsValid = SteamAPI.Init();
- SteamClient.Init(appId);
- }
+ this.textDismissedCallback = Callback.Create(this.GamepadTextInputCallback);
+ }
- public bool IsValid => SteamClient.IsValid;
+ public bool IsValid { get; private set; }
- public bool BLoggedOn => SteamClient.IsLoggedOn;
+ public bool BLoggedOn => SteamUser.BLoggedOn();
- public bool BOverlayNeedsPresent => SteamUtils.DoesOverlayNeedPresent;
+ public bool BOverlayNeedsPresent => SteamUtils.BOverlayNeedsPresent();
- public void Shutdown()
- {
- SteamClient.Shutdown();
- }
+ public void Shutdown()
+ {
+ this.textDismissedCallback?.Dispose();
+ SteamAPI.Shutdown();
+ this.IsValid = false;
+ }
- public async Task GetAuthSessionTicketAsync()
- {
- var ticket = await SteamUser.GetAuthSessionTicketAsync().ConfigureAwait(true);
- return ticket?.Data;
- }
+ public async Task GetAuthSessionTicketAsync()
+ {
+ var result = EResult.k_EResultPending;
+ AuthTicket? ticket = null;
+ var stopwatch = Stopwatch.StartNew();
- public bool IsAppInstalled(uint appId)
+ // We need to register our callback _before_ we can request our auth session ticket. Ignore the modified closure warning, this is what
+ // we expect after all.
+ using var cb = Callback.Create(t =>
{
- return SteamApps.IsAppInstalled(appId);
- }
+ // ReSharper disable AccessToModifiedClosure
+ if (ticket == null || t.m_hAuthTicket != ticket.Handle) return;
- public string GetAppInstallDir(uint appId)
- {
- return SteamApps.AppInstallDir(appId);
- }
+ result = t.m_eResult;
+ });
- public bool ShowGamepadTextInput(bool password, bool multiline, string description, int maxChars, string existingText = "")
- {
- return SteamUtils.ShowGamepadTextInput(password ? GamepadTextInputMode.Password : GamepadTextInputMode.Normal, multiline ? GamepadTextInputLineMode.MultipleLines : GamepadTextInputLineMode.SingleLine, description, maxChars, existingText);
- }
+ ticket = this.GetAuthSessionTicket();
+ if (ticket == null) return null;
- public string GetEnteredGamepadText()
+ while (result == EResult.k_EResultPending)
{
- return SteamUtils.GetEnteredGamepadText();
+ await Task.Delay(10);
+
+ if (stopwatch.Elapsed.TotalSeconds > 10)
+ {
+ ticket.Cancel();
+ return null;
+ }
}
- public bool ShowFloatingGamepadTextInput(ISteam.EFloatingGamepadTextInputMode mode, int x, int y, int width, int height)
+ if (result == EResult.k_EResultOK)
{
- // Facepunch.Steamworks doesn't have this...
- return false;
+ return ticket.Data;
}
- public bool IsRunningOnSteamDeck() => SteamUtils.IsRunningOnSteamDeck;
+ ticket.Cancel();
+ return null;
+ }
+
+ public bool IsAppInstalled(uint appId)
+ {
+ return SteamApps.BIsAppInstalled((AppId_t)appId);
+ }
+
+ public string GetAppInstallDir(uint appId)
+ {
+ SteamApps.GetAppInstallDir((AppId_t)appId, out var result, 1024);
+ return result;
+ }
+
+ public bool ShowGamepadTextInput(bool password, bool multiline, string description, int maxChars, string existingText = "")
+ {
+ return SteamUtils.ShowGamepadTextInput(
+ password ? EGamepadTextInputMode.k_EGamepadTextInputModePassword : EGamepadTextInputMode.k_EGamepadTextInputModeNormal,
+ multiline ? EGamepadTextInputLineMode.k_EGamepadTextInputLineModeMultipleLines : EGamepadTextInputLineMode.k_EGamepadTextInputLineModeSingleLine,
+ description,
+ (uint)maxChars,
+ existingText
+ );
+ }
+
+ public string GetEnteredGamepadText()
+ {
+ var length = SteamUtils.GetEnteredGamepadTextLength();
+ SteamUtils.GetEnteredGamepadTextInput(out var result, length);
+
+ return result;
+ }
+
+ public bool ShowFloatingGamepadTextInput(ISteam.EFloatingGamepadTextInputMode mode, int x, int y, int width, int height)
+ {
+ return SteamUtils.ShowFloatingGamepadTextInput((EFloatingGamepadTextInputMode)mode, x, y, width, height);
+ }
+
+ public bool DismissFloatingGamepadTextInput()
+ {
+ return SteamUtils.DismissFloatingGamepadTextInput();
+ }
+
+ public bool IsRunningOnSteamDeck()
+ {
+ return SteamUtils.IsSteamRunningOnSteamDeck();
+ }
+
+ public uint GetServerRealTime()
+ {
+ return SteamUtils.GetServerRealTime();
+ }
+
+ public void ActivateGameOverlayToWebPage(string url, bool modal = false)
+ {
+ var mode = modal
+ ? EActivateGameOverlayToWebPageMode.k_EActivateGameOverlayToWebPageMode_Modal
+ : EActivateGameOverlayToWebPageMode.k_EActivateGameOverlayToWebPageMode_Default;
+
+ SteamFriends.ActivateGameOverlayToWebPage(url, mode);
+ }
+
+ public event Action? OnGamepadTextInputDismissed;
+
+ private void GamepadTextInputCallback(GamepadTextInputDismissed_t cb)
+ {
+ this.OnGamepadTextInputDismissed?.Invoke(cb.m_bSubmitted);
+ }
+
+ private AuthTicket? GetAuthSessionTicket()
+ {
+ var buffer = new byte[1024];
+ var ticket = SteamUser.GetAuthSessionTicket(buffer, buffer.Length, out var ticketLength);
+
+ if (ticket == HAuthTicket.Invalid) return null;
+
+ return new AuthTicket
+ {
+ Data = buffer.Take((int)ticketLength).ToArray(),
+ Handle = ticket
+ };
+ }
- public uint GetServerRealTime() => (uint)((DateTimeOffset)SteamUtils.SteamServerTime).ToUnixTimeSeconds();
+ private class AuthTicket : IDisposable
+ {
+ public byte[]? Data { get; set; }
+ public HAuthTicket Handle { get; set; }
- public void ActivateGameOverlayToWebPage(string url, bool modal = false)
+ public void Cancel()
{
- SteamFriends.OpenWebOverlay(url, modal);
+ if (this.Handle != HAuthTicket.Invalid)
+ {
+ SteamUser.CancelAuthTicket(this.Handle);
+ }
+
+ this.Handle = HAuthTicket.Invalid;
+ this.Data = null;
}
- public event Action OnGamepadTextInputDismissed;
+ public void Dispose()
+ {
+ this.Cancel();
+ }
}
-}
\ No newline at end of file
+}
diff --git a/src/XIVLauncher.Common.Unix/XIVLauncher.Common.Unix.csproj b/src/XIVLauncher.Common.Unix/XIVLauncher.Common.Unix.csproj
index bcc892546..9fcd7d7dc 100644
--- a/src/XIVLauncher.Common.Unix/XIVLauncher.Common.Unix.csproj
+++ b/src/XIVLauncher.Common.Unix/XIVLauncher.Common.Unix.csproj
@@ -5,6 +5,7 @@
Shared XIVLauncher platform-specific implementations for Unix-like systems.
1.0.0
disable
+ true
@@ -43,7 +44,6 @@
-
-
+
-
\ No newline at end of file
+
diff --git a/src/XIVLauncher.Common.Windows/WindowsSteam.cs b/src/XIVLauncher.Common.Windows/WindowsSteam.cs
index a34259ab3..ce7b69db1 100644
--- a/src/XIVLauncher.Common.Windows/WindowsSteam.cs
+++ b/src/XIVLauncher.Common.Windows/WindowsSteam.cs
@@ -161,6 +161,12 @@ public bool ShowFloatingGamepadTextInput(ISteam.EFloatingGamepadTextInputMode mo
return false;
}
+ public bool DismissFloatingGamepadTextInput()
+ {
+ // Facepunch.Steamworks doesn't have this...
+ return false;
+ }
+
public bool IsRunningOnSteamDeck() => SteamUtils.IsRunningOnSteamDeck;
public uint GetServerRealTime() => (uint)((DateTimeOffset)SteamUtils.SteamServerTime).ToUnixTimeSeconds();
@@ -172,4 +178,4 @@ public void ActivateGameOverlayToWebPage(string url, bool modal = false)
public event Action OnGamepadTextInputDismissed;
}
-}
\ No newline at end of file
+}
diff --git a/src/XIVLauncher.Common/PlatformAbstractions/ISteam.cs b/src/XIVLauncher.Common/PlatformAbstractions/ISteam.cs
index 9c8a5cefe..223a752df 100644
--- a/src/XIVLauncher.Common/PlatformAbstractions/ISteam.cs
+++ b/src/XIVLauncher.Common/PlatformAbstractions/ISteam.cs
@@ -16,6 +16,7 @@ public interface ISteam
bool ShowGamepadTextInput(bool password, bool multiline, string description, int maxChars, string existingText = "");
string GetEnteredGamepadText();
bool ShowFloatingGamepadTextInput(EFloatingGamepadTextInputMode mode, int x, int y, int width, int height);
+ bool DismissFloatingGamepadTextInput();
bool IsRunningOnSteamDeck();
uint GetServerRealTime();
public void ActivateGameOverlayToWebPage(string url, bool modal = false);
@@ -29,4 +30,4 @@ enum EFloatingGamepadTextInputMode
}
event Action OnGamepadTextInputDismissed;
-}
\ No newline at end of file
+}