diff --git a/AvaloniaCommon/Assets/error.ico b/AvaloniaCommon/Assets/error.ico
deleted file mode 100644
index 529371fe..00000000
Binary files a/AvaloniaCommon/Assets/error.ico and /dev/null differ
diff --git a/AvaloniaCommon/Assets/information.ico b/AvaloniaCommon/Assets/information.ico
deleted file mode 100644
index 3a7f9bdd..00000000
Binary files a/AvaloniaCommon/Assets/information.ico and /dev/null differ
diff --git a/AvaloniaCommon/Assets/question.ico b/AvaloniaCommon/Assets/question.ico
deleted file mode 100644
index db04d421..00000000
Binary files a/AvaloniaCommon/Assets/question.ico and /dev/null differ
diff --git a/AvaloniaCommon/Assets/warning.ico b/AvaloniaCommon/Assets/warning.ico
deleted file mode 100644
index d4bd0f53..00000000
Binary files a/AvaloniaCommon/Assets/warning.ico and /dev/null differ
diff --git a/AvaloniaCommon/AvaloniaCommon.csproj b/AvaloniaCommon/AvaloniaCommon.csproj
deleted file mode 100644
index d66957be..00000000
--- a/AvaloniaCommon/AvaloniaCommon.csproj
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
- $(CommonNetVersion)
- enable
- enable
- true
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/AvaloniaCommon/Enums/MessageBoxButton.cs b/AvaloniaCommon/Enums/MessageBoxButton.cs
deleted file mode 100644
index 9dbd3571..00000000
--- a/AvaloniaCommon/Enums/MessageBoxButton.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System;
-
-namespace AvaloniaCommon.Enums;
-
-[Flags]
-public enum MessageBoxButton
-{
- No = 1,
- Yes = 2,
- Ok = 4,
- Cancel = 8
-}
\ No newline at end of file
diff --git a/AvaloniaCommon/Enums/MessageBoxIcon.cs b/AvaloniaCommon/Enums/MessageBoxIcon.cs
deleted file mode 100644
index 7d35f0fc..00000000
--- a/AvaloniaCommon/Enums/MessageBoxIcon.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System;
-
-namespace AvaloniaCommon.Enums;
-
-[Flags]
-public enum MessageBoxIcon
-{
- QUESTION = 1,
- INFORMATION = 2,
- WARNING = 4,
- ERROR = 8
-}
\ No newline at end of file
diff --git a/AvaloniaCommon/MessageBox.cs b/AvaloniaCommon/MessageBox.cs
deleted file mode 100644
index f88d7b51..00000000
--- a/AvaloniaCommon/MessageBox.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-namespace AvaloniaCommon;
-
-using Avalonia.Controls;
-using Avalonia.Threading;
-using AvaloniaCommon.Enums;
-using AvaloniaCommon.ViewModels;
-
-public static class MessageBox
-{
- public static MessageBoxButton? Show(string title, string message)
- {
- return Show(title, "", message);
- }
-
- public static MessageBoxButton? Error(string title, string message)
- {
- return Error(title, "", message);
- }
-
- public static MessageBoxButton? Error(Exception e)
- {
- return Error(string.IsNullOrEmpty(e.Message) ? "Unknown error" : e.Message, e.Message, e.ToString());
- }
- public static MessageBoxButton? QuestionYesNo(string title, string header, string message)
- {
- return Show(title, header, message, MessageBoxIcon.QUESTION, MessageBoxButton.No | MessageBoxButton.Yes);
- }
- public static MessageBoxButton? QuestionYesNoCancel(string title, string header, string message)
- {
- return Show(title, header, message, MessageBoxIcon.QUESTION, MessageBoxButton.No | MessageBoxButton.Yes | MessageBoxButton.Cancel);
- }
- public static MessageBoxButton? Info(string title, string header, string message)
- {
- return Show(title, header, message, MessageBoxIcon.INFORMATION);
- }
- public static MessageBoxButton? Warning(string title, string header, string message)
- {
- return Show(title, header, message, MessageBoxIcon.WARNING);
- }
- public static MessageBoxButton? Error(string title, string header, string message)
- {
- return Show(title, header, message, MessageBoxIcon.ERROR);
- }
-
- public static MessageBoxButton? Show(string title, string header, string message)
- {
- return Show(title, header, message, MessageBoxIcon.INFORMATION);
- }
-
- public static MessageBoxButton? Show(string title, string header, string message, MessageBoxIcon icon = MessageBoxIcon.INFORMATION, MessageBoxButton buttons = MessageBoxButton.Ok)
- {
- if (!Dispatcher.UIThread.CheckAccess())
- {
- return Dispatcher.UIThread.Invoke(() => ShowInternal(title, header, message, icon, buttons));
- }
- else
- {
- return ShowInternal(title, header, message, icon, buttons);
- }
- }
-
- internal static MessageBoxButton? ShowInternal(string title, string header, string message, MessageBoxIcon icon, MessageBoxButton buttons)
- {
- var messageBoxViewModel = new MessageBoxViewModel(icon, buttons)
- {
- Title = title,
- Header = header,
- Content = message
- };
-
- var messageBox = new Views.MessageBox();
- messageBoxViewModel.SetMessageBox(messageBox);
- messageBox.DataContext = messageBoxViewModel;
-
- using (var source = new CancellationTokenSource())
- {
- var tcs = new TaskCompletionSource();
- messageBox.Closing += (object? sender, WindowClosingEventArgs args) =>
- {
- tcs.TrySetResult(messageBoxViewModel.ButtonClicked);
- args.Cancel = false;
- };
-
- messageBox.Show();
-
- tcs.Task.ContinueWith(t => source.Cancel(), TaskScheduler.FromCurrentSynchronizationContext());
- Dispatcher.UIThread.MainLoop(source.Token);
- return tcs.Task.Result;
- }
- }
-}
diff --git a/AvaloniaCommon/Theme.cs b/AvaloniaCommon/Theme.cs
deleted file mode 100644
index 8583c3f4..00000000
--- a/AvaloniaCommon/Theme.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-using System;
-using System.Diagnostics.CodeAnalysis;
-using Avalonia;
-using Avalonia.Media;
-using Avalonia.Styling;
-
-namespace AvaloniaCommon;
-
-public class Theme
-{
- public IBrush AccentButtonBackground
- {
- get
- {
- return (IBrush)GetResource("AccentButtonBackground");
- }
- }
-
- public IBrush AccentButtonForeground
- {
- get
- {
- return (IBrush)GetResource("AccentButtonForeground");
- }
- }
-
- public IBrush ButtonBackground
- {
- get
- {
- return (IBrush)GetResource("ButtonBackground");
- }
- }
-
- public IBrush ButtonForeground
- {
- get
- {
- return (IBrush)GetResource("ButtonForeground");
- }
- }
-
- private object GetResource(string key)
- {
- app.TryGetResource(key, ThemeVariant.Default, out object? val);
- ThrowIfNull(val);
- return val;
- }
-
- private void ThrowIfNull([NotNull] object? val)
- {
- if (val == null)
- {
- throw new Exception("No styles where there should be");
- }
- }
-
- private Application app;
- public Theme(Application app)
- {
- this.app = app;
- }
-}
\ No newline at end of file
diff --git a/AvaloniaCommon/ViewModelBase.cs b/AvaloniaCommon/ViewModelBase.cs
deleted file mode 100644
index 31430754..00000000
--- a/AvaloniaCommon/ViewModelBase.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System;
-using System.Diagnostics;
-using CommunityToolkit.Mvvm.ComponentModel;
-
-namespace AvaloniaCommon;
-
-public partial class ViewModelBase : ObservableObject
-{
-
-}
diff --git a/AvaloniaCommon/ViewModels/MessageBoxViewModel.cs b/AvaloniaCommon/ViewModels/MessageBoxViewModel.cs
deleted file mode 100644
index 356eb700..00000000
--- a/AvaloniaCommon/ViewModels/MessageBoxViewModel.cs
+++ /dev/null
@@ -1,112 +0,0 @@
-using System;
-using Avalonia.Controls;
-using Avalonia.Media.Imaging;
-using Avalonia.Platform;
-using Avalonia.Threading;
-using AvaloniaCommon.Enums;
-using CommunityToolkit.Mvvm.ComponentModel;
-
-namespace AvaloniaCommon.ViewModels;
-
-public partial class MessageBoxViewModel : ViewModelBase
-{
- [ObservableProperty]
- private string title = "";
-
- [ObservableProperty]
- [NotifyPropertyChangedFor("HasHeader")]
- private string header = "";
- public bool HasHeader => !string.IsNullOrEmpty(this.Header);
-
- [ObservableProperty]
- private string content = "";
-
- [ObservableProperty]
- private string iconPath;
-
- [ObservableProperty]
- private Bitmap icon;
-
- [ObservableProperty]
- private WindowIcon windowIcon;
-
- [NotifyPropertyChangedFor("IsOkShowed")]
- [NotifyPropertyChangedFor("IsYesShowed")]
- [NotifyPropertyChangedFor("IsNoShowed")]
- [NotifyPropertyChangedFor("IsCancelShowed")]
-
- [ObservableProperty]
- private MessageBoxButton enabledButtons;
- public MessageBoxButton? ButtonClicked { get; private set; }
- public bool IsOkShowed => EnabledButtons.HasFlag(MessageBoxButton.Ok);
- public bool IsYesShowed => EnabledButtons.HasFlag(MessageBoxButton.Yes);
- public bool IsNoShowed => EnabledButtons.HasFlag(MessageBoxButton.No);
- public bool IsCancelShowed => EnabledButtons.HasFlag(MessageBoxButton.Cancel);
- public Action? Copy { get; set; }
- public Action? EnterPressed { get; set; }
- public Action? EscPressed { get; set; }
- private AvaloniaCommon.Views.MessageBox? messageBox;
- public MessageBoxViewModel(MessageBoxIcon icon, MessageBoxButton enabledButtons)
- {
-
- this.enabledButtons = enabledButtons;
- this.EnterPressed = PressDefaultIfPossible;
- this.IconPath = $"avares://AvaloniaCommon/Assets/{icon.ToString().ToLowerInvariant()}.ico";
- this.Icon = new Bitmap(AssetLoader.Open(new Uri(this.iconPath)));
- this.WindowIcon = new WindowIcon(this.Icon);
- }
-
- // Clipboard isn't accessible from App, instead it's available from every Control, so do this hack which is totally against mvvm principles
- public void SetMessageBox(AvaloniaCommon.Views.MessageBox messageBox)
- {
- this.messageBox = messageBox;
- this.Copy = messageBox.Copy;
- this.EscPressed = messageBox.Close;
- }
-
- public void PressDefaultIfPossible()
- {
- // If there's only one button enabled, then click it
- switch (EnabledButtons)
- {
- case MessageBoxButton.No:
- NoClicked();
- break;
- case MessageBoxButton.Yes:
- YesClicked();
- break;
- case MessageBoxButton.Cancel:
- CancelClicked();
- break;
- case MessageBoxButton.Ok:
- OkClicked();
- break;
- }
- // If there's multiple, try to cancel, never take a yes action automatically
- if (EnabledButtons.HasFlag(MessageBoxButton.Cancel))
- {
- CancelClicked();
- }
- }
- public void OkClicked()
- {
- ButtonClicked = MessageBoxButton.Ok;
- messageBox?.QueueClose();
- }
- public void YesClicked()
- {
- ButtonClicked = MessageBoxButton.Yes;
- messageBox?.QueueClose();
- }
- public void NoClicked()
- {
- ButtonClicked = MessageBoxButton.No;
- messageBox?.QueueClose();
- }
- public void CancelClicked()
- {
- ButtonClicked = MessageBoxButton.Cancel;
- messageBox?.QueueClose();
- }
-
-}
\ No newline at end of file
diff --git a/AvaloniaCommon/Views/MessageBox.axaml b/AvaloniaCommon/Views/MessageBox.axaml
deleted file mode 100644
index 6e2eefb1..00000000
--- a/AvaloniaCommon/Views/MessageBox.axaml
+++ /dev/null
@@ -1,110 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/AvaloniaCommon/Views/MessageBox.axaml.cs b/AvaloniaCommon/Views/MessageBox.axaml.cs
deleted file mode 100644
index e47129bd..00000000
--- a/AvaloniaCommon/Views/MessageBox.axaml.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using Avalonia;
-using Avalonia.Controls;
-using Avalonia.Threading;
-using AvaloniaCommon.Enums;
-using AvaloniaCommon.ViewModels;
-
-namespace AvaloniaCommon.Views;
-
-public partial class MessageBox : Window
-{
- public MessageBox()
- {
- InitializeComponent();
- }
-
- public void Copy()
- {
- MessageBoxViewModel? viewModel = (this.DataContext as MessageBoxViewModel);
- if (viewModel == null)
- {
- Console.WriteLine("DataContext failed to cast to MessageBoxViewModel! Copy failed!");
- return;
- }
-
- string fullTextToCopy = "";
- fullTextToCopy += viewModel.Title + "\n";
- fullTextToCopy += viewModel.Header + "\n";
- fullTextToCopy += viewModel.Content + "\n";
- fullTextToCopy += viewModel.EnabledButtons.ToString();
-
- if (this.Clipboard == null)
- {
- Console.WriteLine("this.Clipboard is null! Copy failed!");
- return;
- }
-
- this.Clipboard.SetTextAsync(fullTextToCopy);
- }
-
- public void QueueClose()
- {
- Dispatcher.UIThread.InvokeAsync(base.Close);
- }
-}
\ No newline at end of file
diff --git a/AvaloniaCommon/nuget.config b/AvaloniaCommon/nuget.config
deleted file mode 100644
index 42c6aa46..00000000
--- a/AvaloniaCommon/nuget.config
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/ChromeTestClient/ChromeIPCClient.cs b/ChromeTestClient/ChromeIPCClient.cs
deleted file mode 100644
index 2b2966cb..00000000
--- a/ChromeTestClient/ChromeIPCClient.cs
+++ /dev/null
@@ -1,140 +0,0 @@
-using System.Diagnostics.CodeAnalysis;
-using System.Runtime.InteropServices;
-using System.Text;
-using Google.Protobuf;
-using ipctest.Platform;
-using OpenSteamworks.Protobuf;
-using OpenSteamworks.Utils;
-
-namespace ipctest;
-
-public unsafe class ChromeIPCClient {
- private struct ChromeConnectionHelloResponse {
- public int m_eCmd;
- public int m_iServerPID;
- public fixed byte ResponseStreamName[64];
- }
-
- private struct ChromeConnectionHello {
- public int unk;
- public int unk1;
- public int m_iClientPID;
- public fixed byte ResponseStreamName[64];
- }
-
-
-
- private readonly IEvent managerEvent;
- public ChromeIPCClient() {
- using var masterStream = new SharedMemStream($"SteamChrome_MasterStream_uid{Platform.Linux.LinuxConsts.getuid()}_spid{GetSteamPID()}", out bool bCreated);
- if (bCreated) {
- throw new Exception("Failed to connect to master html process, created shared memory");
- }
-
- Console.WriteLine("created: " + bCreated);
- Console.WriteLine("capacity: " + masterStream.Capacity);
- Console.WriteLine("AvailableToRead: " + masterStream.AvailableToRead);
-
- var randomNumber = Random.Shared.NextInt64(0, 65535);
- string newClientName = $"SteamChrome_MasterStream_{GetSteamPID()}_{randomNumber}";
- using var childStream = new SharedMemStream(newClientName, out bool bChildCreated);
- if (bChildCreated == false) {
- throw new Exception("Collided with existing master response stream");
- }
-
- byte[] buf = new byte[sizeof(ChromeConnectionHello)];
- var hello = new ChromeConnectionHello();
- hello.unk = 1;
- hello.unk1 = 1;
- hello.m_iClientPID = Environment.ProcessId;
- Encoding.UTF8.GetBytes(newClientName).CopyTo(new Span(hello.ResponseStreamName, 64));
-
- new ReadOnlySpan(&hello, sizeof(ChromeConnectionHello)).CopyTo(buf);
-
- masterStream.Write(buf, 0, sizeof(ChromeConnectionHello));
-
- managerEvent = Globals.IPCImpl.CreateEvent($"SteamChrome_MasterStream_Event_uid{Platform.Linux.LinuxConsts.getuid()}_spid{GetSteamPID()}", out bool bEventCreated);
- Console.WriteLine("Signaling event");
- managerEvent.Signal();
-
- Console.WriteLine("Waiting for response");
- var gotData = childStream.BWaitForDataToGet();
-
- Console.WriteLine("HDR: " + childStream.HeaderPtr->ToString());
- Console.WriteLine("gotData: " + gotData);
-
- ChromeConnectionHelloResponse resp;
- if (gotData) {
- buf = new byte[sizeof(ChromeConnectionHelloResponse)];
- var actual = buf[0..childStream.Read(buf, 0, buf.Length)];
- if (actual.Length < sizeof(ChromeConnectionHelloResponse)) {
- throw new Exception($"not enough data, got {actual.Length}, but expected {sizeof(ChromeConnectionHelloResponse)}, exiting");
- }
-
- Console.WriteLine("actual: " + string.Join(" ", actual) + ", read: " + actual.Length);
- fixed (byte* bptr = actual) {
- resp = *(ChromeConnectionHelloResponse*)bptr;
- }
- } else {
- throw new Exception("got no data, exiting");
- }
-
- string? responseStreamName = Marshal.PtrToStringUTF8((nint)resp.ResponseStreamName);
- if (string.IsNullOrEmpty(responseStreamName)) {
- throw new Exception("got no response stream, exiting");
- }
-
- Console.WriteLine("CMD: " + resp.m_eCmd);
- Console.WriteLine("Server PID: " + resp.m_iServerPID);
- Console.WriteLine("ResponseStreamName: " + responseStreamName);
- CreateStreams(responseStreamName);
-
- CMsgBrowserCreate proto = new();
- proto.RequestId = 50;
- proto.BrowserType = 1;
- proto.InitialUrl = "https://google.com";
- proto.Useragent = "Valve Steam Client";
- PushCommand(10, 0, proto.ToByteArray());
- }
-
- private SharedMemStream sendStream;
- private SharedMemStream recvStream;
-
- [MemberNotNull(nameof(sendStream))]
- [MemberNotNull(nameof(recvStream))]
- private void CreateStreams(string responseStreamName, bool bIsServer = false) {
- string sendStreamName = responseStreamName + (bIsServer ? "_server" : "_client");
- string recvStreamName = responseStreamName + (bIsServer ? "_client" : "_server");
-
- sendStream = new SharedMemStream(sendStreamName, out _);
- sendStream.WriteTimeout = sendStream.ReadTimeout = 1000;
-
- recvStream = new SharedMemStream(recvStreamName, out _);
- recvStream.WriteTimeout = recvStream.ReadTimeout = 1000;
- }
-
- private int GetSteamPID() {
- var homevar = Environment.GetEnvironmentVariable("HOME");
- if (string.IsNullOrEmpty(homevar)) {
- throw new NullReferenceException("HOME not set, please set it");
- }
-
- return int.Parse(File.ReadAllText(Path.Combine(homevar, ".steam/steam.pid")));
- }
-
- public void PushCommand(int eMsg, int iBrowser, byte[] msg) {
- // Wire format is not known
- using var stream = new MemoryStream();
- using var writer = new EndianAwareBinaryWriter(stream, OpenSteamworks.Utils.Enum.Endianness.Little);
- // writer.WriteInt32(eMsg);
- // writer.WriteInt32(iBrowser);
- writer.WriteInt32(msg.Length);
- writer.Write(msg);
-
- var msgSerialized = stream.ToArray();
- sendStream.Write(msgSerialized, 0, msgSerialized.Length);
-
- Thread.Sleep(50);
- managerEvent.Signal();
- }
-}
\ No newline at end of file
diff --git a/ChromeTestClient/ChromeTestClient.csproj b/ChromeTestClient/ChromeTestClient.csproj
deleted file mode 100644
index 3e6f91c1..00000000
--- a/ChromeTestClient/ChromeTestClient.csproj
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
- Exe
- net8.0
- enable
- enable
- true
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/ChromeTestClient/EHTMLCommands.cs b/ChromeTestClient/EHTMLCommands.cs
deleted file mode 100644
index 9e8efad6..00000000
--- a/ChromeTestClient/EHTMLCommands.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace ipctest;
-
-public enum EHTMLCommands
-{
- Hello = 2,
- None = 165,
-}
\ No newline at end of file
diff --git a/ChromeTestClient/HTMLProtoMsg.cs b/ChromeTestClient/HTMLProtoMsg.cs
deleted file mode 100644
index 9813d4f7..00000000
--- a/ChromeTestClient/HTMLProtoMsg.cs
+++ /dev/null
@@ -1,2 +0,0 @@
-namespace ipctest;
-
diff --git a/ChromeTestClient/LiteHTMLHost.cs b/ChromeTestClient/LiteHTMLHost.cs
deleted file mode 100644
index 078fc795..00000000
--- a/ChromeTestClient/LiteHTMLHost.cs
+++ /dev/null
@@ -1,161 +0,0 @@
-using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
-using System.Runtime.Versioning;
-
-namespace ipctest;
-
-public static class LiteHTMLHost {
- private static readonly object CurrentHTMLHostLock = new();
- private static Process? CurrentHTMLHost;
- private static string InstallDir => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "OpenSteam");
- private static Thread? WatcherThread;
-
- [SupportedOSPlatform("windows")]
- private static string GetWindowsCEFPath() {
- string baseDir = Path.Combine(InstallDir, "bin", "cef");
-
- bool TryVersion(string ver, [NotNullWhen(true)] out string? path) {
- path = Path.Combine(baseDir, ver);
- bool isValid = Directory.Exists(path) && File.Exists(Path.Combine(path, "steamwebhelper.exe"));
- if (!isValid) {
- Console.WriteLine($"Wanted CEF version {ver}, but it doesn't exist.");
- }
-
- return isValid;
- }
-
-
- if (OperatingSystem.IsWindowsVersionAtLeast(10) && TryVersion("cef.win10x64", out string? path)) {
- return path;
- } else {
- if (TryVersion("cef.win7x64", out path)) {
- return path;
- } else if (TryVersion("cef.win7", out path)) {
- return path;
- } else {
- throw new Exception("No CEF available");
- }
- }
- }
-
- private static bool expectedToStop = false;
-
- [SupportedOSPlatform("linux")]
- [SupportedOSPlatform("windows")]
- public static void StartHTMLHost()
- {
- lock (CurrentHTMLHostLock)
- {
- Console.WriteLine("Creating steamwebhelper process");
-
- CurrentHTMLHost = new Process();
- if (OperatingSystem.IsLinux()) {
- CurrentHTMLHost.StartInfo.WorkingDirectory = Path.Combine(InstallDir, "ubuntu12_64");
-
- // Strace
- // CurrentHTMLHost.StartInfo.FileName = "/usr/bin/strace";
- // CurrentHTMLHost.StartInfo.ArgumentList.Add("-efutex");
- // CurrentHTMLHost.StartInfo.ArgumentList.Add("--detach-on=execve");
- // CurrentHTMLHost.StartInfo.ArgumentList.Add("--interruptible=never");
- // CurrentHTMLHost.StartInfo.ArgumentList.Add(Path.Combine(InstallDir, "ubuntu12_64", "steamwebhelper"));
-
- CurrentHTMLHost.StartInfo.FileName = Path.Combine(InstallDir, "ubuntu12_64", "steamwebhelper");
- CurrentHTMLHost.StartInfo.EnvironmentVariables["LD_LIBRARY_PATH"] = $".:{Environment.GetEnvironmentVariable("LD_LIBRARY_PATH")}";
- CurrentHTMLHost.StartInfo.ArgumentList.Add("--disable-seccomp-filter-sandbox");
- } else if (OperatingSystem.IsWindows()) {
- string basePath = GetWindowsCEFPath();
- CurrentHTMLHost.StartInfo.WorkingDirectory = basePath;
- CurrentHTMLHost.StartInfo.FileName = Path.Combine(basePath, "steamwebhelper.exe");
- }
-
- CurrentHTMLHost.StartInfo.ArgumentList.Add($"-lang=en-US");
-
- CurrentHTMLHost.StartInfo.ArgumentList.Add($"-cachedir={Path.Combine(InstallDir, "appcache", "htmlcache")}");
-
- // This could technically be improved by reading from the steam.pid file, but no need since this code always assumes we're the master
- CurrentHTMLHost.StartInfo.ArgumentList.Add($"-steampid={Environment.ProcessId}");
-
- CurrentHTMLHost.StartInfo.ArgumentList.Add($"-buildid={1716242052}");
-
- // Don't know our SteamID at this point.
- CurrentHTMLHost.StartInfo.ArgumentList.Add("-steamid=0");
- var logsDir = Path.Combine(InstallDir, "logs");
- CurrentHTMLHost.StartInfo.ArgumentList.Add($"-logdir={logsDir}");
- CurrentHTMLHost.StartInfo.ArgumentList.Add($"-uimode=7");
-
- // We don't track this.
- CurrentHTMLHost.StartInfo.ArgumentList.Add($"-startcount=0");
-
- CurrentHTMLHost.StartInfo.ArgumentList.Add($"-steamuniverse=1");
- CurrentHTMLHost.StartInfo.ArgumentList.Add($"-realm=1");
-
- // Doesn't exist, but we pass it anyway.
- CurrentHTMLHost.StartInfo.ArgumentList.Add($"-clientui={Path.Combine(InstallDir, "clientui")}");
-
- string steampath;
- if (OperatingSystem.IsLinux())
- {
- steampath = Directory.ResolveLinkTarget("/proc/self/exe", false)!.FullName;
- }
- else
- {
- steampath = Environment.ProcessPath!;
- }
-
- CurrentHTMLHost.StartInfo.ArgumentList.Add($"-steampath={steampath}");
-
- // No idea what this means or does.
- CurrentHTMLHost.StartInfo.ArgumentList.Add($"-launcher=0");
-
- // This should only be passed if we're in debug mode, but that info isn't really passed through to us in any way.
- CurrentHTMLHost.StartInfo.ArgumentList.Add($"-dev");
-
- CurrentHTMLHost.StartInfo.ArgumentList.Add($"-no-restart-on-ui-mode-change");
- CurrentHTMLHost.StartInfo.ArgumentList.Add($"--enable-media-stream");
-
- CurrentHTMLHost.StartInfo.ArgumentList.Add($"--enable-smooth-scrolling");
-
- CurrentHTMLHost.StartInfo.ArgumentList.Add($"--password-store=basic");
- CurrentHTMLHost.StartInfo.ArgumentList.Add($"--log-file={Path.Combine(logsDir, "cef_log.txt")}");
- CurrentHTMLHost.StartInfo.ArgumentList.Add($"--disable-quick-menu");
- CurrentHTMLHost.StartInfo.ArgumentList.Add($"--disable-features=SameSiteByDefaultCookies");
- CurrentHTMLHost.StartInfo.ArgumentList.Add($"--enable-blink-features=ResizeObserver,Worklet,AudioWorklet");
- CurrentHTMLHost.StartInfo.ArgumentList.Add($"--disable-blink-features=Badging");
-
- Console.WriteLine("Starting steamwebhelper process");
- CurrentHTMLHost.Start();
-
- if (WatcherThread == null)
- {
- Console.WriteLine("Creating watcher thread");
- WatcherThread = new Thread(() =>
- {
- do
- {
- if (CurrentHTMLHost.HasExited && !expectedToStop)
- {
- Console.WriteLine($"steamwebhelper crashed (exit code {CurrentHTMLHost.ExitCode})! Restarting in 1s.");
- Thread.Sleep(1000);
- StartHTMLHost();
- }
- Thread.Sleep(50);
- } while (true);
- });
-
- Console.WriteLine("Starting watcher thread");
- WatcherThread.Start();
- }
- }
- }
-
- public static void KillHTMLHost()
- {
- expectedToStop = true;
-
- var procs = Process.GetProcessesByName("steamwebhelper");
- for (int i = 0; i < procs.Length; i++)
- {
- procs[i].Kill();
- }
- }
-}
\ No newline at end of file
diff --git a/ChromeTestClient/Platform/Globals.cs b/ChromeTestClient/Platform/Globals.cs
deleted file mode 100644
index 2f12a444..00000000
--- a/ChromeTestClient/Platform/Globals.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-namespace ipctest.Platform;
-
-public static class Globals {
- public static IIPCImpl IPCImpl { get; }
- static Globals() {
- if (OperatingSystem.IsLinux()) {
- IPCImpl = new Linux.IPCImpl();
- return;
- }
-
- if (OperatingSystem.IsWindows()) {
- //IPCImpl = new Windows.IPCImpl();
- //return;
- }
-
- throw new NotImplementedException("unsupported os");
- }
-}
\ No newline at end of file
diff --git a/ChromeTestClient/Platform/IIPCImpl.cs b/ChromeTestClient/Platform/IIPCImpl.cs
deleted file mode 100644
index d80b4fa8..00000000
--- a/ChromeTestClient/Platform/IIPCImpl.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-namespace ipctest.Platform;
-
-public unsafe interface IIPCImpl {
- public ISharedMemory CreateSharedMemory(string name, uint size, out bool bCreated);
- public IEvent CreateEvent(string name, out bool bCreated, bool isManualReset = false, bool initiallySignaled = false);
- public IMutex CreateMutex(string name, out bool bCreated);
-}
-
-public unsafe interface ISharedMemory : IDisposable {
- public void* Data { get; }
- public uint Length { get; }
-}
-
-public unsafe interface IEvent : IDisposable {
- public void Signal();
- public void Reset();
-
- ///
- ///
- ///
- ///
- /// True if the state has changed, false if an error occurred.
- public bool WaitForStateChange(uint timeoutMS);
-}
-
-public unsafe interface IMutex : IDisposable {
- public IDisposable Lock(uint timeoutMS = 5000);
-}
\ No newline at end of file
diff --git a/ChromeTestClient/Platform/Linux/ErrnoException.cs b/ChromeTestClient/Platform/Linux/ErrnoException.cs
deleted file mode 100644
index 1abc5b99..00000000
--- a/ChromeTestClient/Platform/Linux/ErrnoException.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace ipctest.Platform.Linux;
-
-[System.Serializable]
-public class ErrnoException : System.Exception
-{
- public ErrnoException() { }
- public ErrnoException(int errno) : base($"Linux system call failed with {errno}") { }
- public ErrnoException(int errno, System.Exception inner) : base($"Linux system call failed with {errno}", inner) { }
-
- public static void ThrowIfNonZero(int value) {
- if (value != 0) {
- throw new ErrnoException(value);
- }
- }
-
- public static void ThrowCurrentMarshaledIfNegative(int value) {
- if (value < 0) {
- throw new ErrnoException(Marshal.GetLastWin32Error());
- }
- }
-}
\ No newline at end of file
diff --git a/ChromeTestClient/Platform/Linux/IPCImpl.cs b/ChromeTestClient/Platform/Linux/IPCImpl.cs
deleted file mode 100644
index 3c6e2125..00000000
--- a/ChromeTestClient/Platform/Linux/IPCImpl.cs
+++ /dev/null
@@ -1,364 +0,0 @@
-namespace ipctest.Platform.Linux;
-
-using System.IO.Hashing;
-using System.IO.MemoryMappedFiles;
-using System.Runtime.InteropServices;
-using System.Runtime.Intrinsics.X86;
-using System.Text;
-
-public unsafe class IPCImpl : IIPCImpl
-{
- public enum EntryType : int
- {
- None,
- Mutex,
- Event,
- SharedMemory,
- };
-
- [StructLayout(LayoutKind.Sequential)]
- public struct Entry_Mutex {
- public Entry Header;
- public SteamLinuxMutex Mutex;
-
- public override string ToString()
- {
- return $"{Header}: {Mutex}";
- }
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct Entry_Event {
- public Entry Header;
- public uint unk;
- public uint isSignaled;
- public uint sequence;
- public uint isManualReset;
-
- public override string ToString()
- {
- return $"{Header}: {unk} {isSignaled} {sequence} {isManualReset}";
- }
-
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct Entry {
- public EntryType Type;
- public uint NameCRC;
- public int RefCount;
-
- public const int PID_ARR_SIZE = 16;
- public fixed int ReferencingPIDS[PID_ARR_SIZE];
-
- public static void Init(Entry* pThis, EntryType type, uint nameCRC, bool AddReference = true) {
- pThis->NameCRC = nameCRC;
- if (AddReference) {
- Entry.AddReference(pThis);
- }
-
- pThis->Type = type;
- }
-
- public static void AddReference(Entry* pThis) {
- AddReferenceCore(pThis);
- }
-
- private static void AddReferenceCore(Entry* pThis, bool didCleanup = false) {
- var pid = Environment.ProcessId;
- for (int i = 0; i < PID_ARR_SIZE; i++)
- {
- if (pThis->ReferencingPIDS[i] == 0) {
- pThis->ReferencingPIDS[i] = pid;
- pThis->RefCount++;
- return;
- }
- }
-
- // No problem, try clearing out unused references and try again
- if (!didCleanup) {
- CleanupDeadReferences(pThis);
- AddReferenceCore(pThis, true);
- return;
- }
-
- throw new Exception("PID array ran out");
- }
-
- public static bool RemoveReference(Entry* pThis, int pid) {
- for (int i = 0; i < PID_ARR_SIZE; i++)
- {
- var elem = pThis->ReferencingPIDS[i];
- if (elem == pid) {
- elem = pid;
- pThis->RefCount--;
- return true;
- }
- }
-
- return false;
- }
-
- public static bool AreAnyReferencesAlive(Entry* pThis) {
- for (int i = 0; i < PID_ARR_SIZE; i++)
- {
- var elem = pThis->ReferencingPIDS[i];
- if (elem != 0) {
- if (LinuxConsts.kill(elem, 0) == 0) {
- return true;
- } else {
- // Clear it from the list if not alive
- pThis->ReferencingPIDS[i] = 0;
- pThis->RefCount--;
- }
- }
- }
-
- return false;
- }
-
- public static void CleanupDeadReferences(Entry* pThis) {
- for (int i = 0; i < PID_ARR_SIZE; i++)
- {
- var elem = pThis->ReferencingPIDS[i];
- if (elem != 0) {
- if (LinuxConsts.kill(elem, 0) != 0) {
- // Clear it from the list if not alive
- pThis->ReferencingPIDS[i] = 0;
- pThis->RefCount--;
- }
- }
- }
- }
-
- public static void Destruct(Entry* pThis)
- {
- //TODO: Get this info from the SharedObjectManagerHeader
- NativeMemory.Clear(pThis, MGR_ELEM_SIZE);
- }
-
- public static bool HasAnyReferences(Entry* pThis)
- {
- return pThis->RefCount != 0;
- }
-
- public override string ToString()
- {
- return $"T: {Type}, CRC: {NameCRC}, C: {RefCount}";
- }
- }
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct SharedObjectManagerHeader
- {
- public int version;
- public int elemSize;
- public int length;
- public int mgrMutexOwner;
- public int unused;
- public int unused2;
- public SteamLinuxMutex sysMgrMutex;
-
-
- public override string ToString()
- {
- return $"v: {version} elemSize: {elemSize} totalSize: {length} currentOwner: {mgrMutexOwner} {unused} {unused2} currentLockingThreadID: {sysMgrMutex.threadID}";
- }
- }
-
- public const int MGR_SHM_SIZE = 0x200000;
- public const int MGR_ELEM_SIZE = 256;
- public const int MGR_VERSION = 4;
-
- private void* mmapTarget;
- private SharedObjectManagerHeader* header => (SharedObjectManagerHeader*)mmapTarget;
-
- public IPCImpl()
- {
- int shm_fd = -1;
- bool isHoldingSysMgrMutex = false;
-
- try {
- var ipcName = GetIPCObjName();
- var shmFilepath = $"/dev/shm{ipcName}";
- Console.WriteLine("IPC obj at " + shmFilepath);
-
- shm_fd = LinuxConsts.shm_open(ipcName, 66, 511);
- Console.WriteLine("open result: " + shm_fd);
-
- if (shm_fd < 0) {
- throw new Exception($"Process {Environment.ProcessId} failed to shm_open {ipcName}");
- }
-
- if (LinuxConsts.flock(shm_fd, 2) != 0) {
- throw new Exception($"Error {Marshal.GetLastWin32Error()} locking shared memory file");
- }
-
- var allocated = new FileInfo(shmFilepath).Length;
- Console.WriteLine("Bytes Allocated: " + allocated);
- if (allocated < MGR_SHM_SIZE)
- {
- Console.WriteLine("ftruncate: " + LinuxConsts.ftruncate(shm_fd, MGR_SHM_SIZE));
- var newsize = new FileInfo(shmFilepath).Length;
- Console.WriteLine("New Size: " + newsize);
- }
-
- mmapTarget = LinuxConsts.mmap((void*)0x0, MGR_SHM_SIZE, 3, 1, shm_fd, 0);
- Console.WriteLine("mmap result: " + (nint)mmapTarget);
- Console.WriteLine(header->ToString());
-
- if (header->version == 0) {
- // Need to initialize
- header->length = MGR_SHM_SIZE;
- header->elemSize = MGR_ELEM_SIZE;
- header->version = MGR_VERSION;
- }
-
- if (header->version != MGR_VERSION && header->version != 0) {
- throw new NotImplementedException("version upgrade detected, new version is " + header->version);
- }
-
- if (header->elemSize != MGR_ELEM_SIZE) {
- throw new NotImplementedException($"element size change detected, expected {MGR_ELEM_SIZE}, got {header->elemSize}");
- }
- }
- finally
- {
- if (isHoldingSysMgrMutex && header != null)
- {
- SteamLinuxMutex.IPCMutexUnlock(&header->sysMgrMutex);
- }
-
- if (shm_fd != -1) {
- LinuxConsts.flock(shm_fd, 8);
- }
-
- }
- }
-
- public ISharedMemory CreateSharedMemory(string name, uint size, out bool bCreated) {
- Console.WriteLine("CreateSharedMemory: " + name);
-
- using var l = Lock();
- return new LinuxSharedMemory(name, size, out bCreated);
- }
-
- public IEvent CreateEvent(string name, out bool bCreated, bool isManualReset, bool initiallySignaled) {
- Console.WriteLine("CreateEvent: " + name);
-
- using var l = Lock();
- return new LinuxEvent(name, isManualReset, initiallySignaled, out bCreated);
- }
-
- public IMutex CreateMutex(string name, out bool bCreated) {
- Console.WriteLine("CreateMutex: " + name);
-
- SteamLinuxMutex.IPCMutexUnlock(&header->sysMgrMutex);
- using var l = Lock();
- return new LinuxMutex(name, out bCreated);
- }
-
- private MutexDisposable Lock() {
- return new MutexDisposable(&header->sysMgrMutex, 5000, () => { header->mgrMutexOwner = Environment.ProcessId; }, () => {header->mgrMutexOwner = 0; });
- }
-
- public static string HashName(string name) {
- return Convert.ToHexString(BitConverter.GetBytes(HashNameUInt32(name)).Reverse().ToArray());
- }
-
- public static uint HashNameUInt32(string name) {
- return Crc32.HashToUInt32(Encoding.UTF8.GetBytes(name));
- }
-
- public void* DynamicStart => (void*)((nint)mmapTarget + sizeof(SharedObjectManagerHeader) + 32);
- public Entry* FindEntry(EntryType type, string name) {
- uint nameCRC = HashNameUInt32(name);
- int sizeOfEntry = header->elemSize;
- void* current = DynamicStart;
- void* last = (void*)((nint)header + header->length);
- int entryCount = 0;
- while (current < last)
- {
- Entry* pEntry = (Entry*)current;
-
- if (pEntry->Type == 0) {
- goto loopEnd;
- }
-
- if (pEntry->Type == type && pEntry->NameCRC == nameCRC) {
- Console.WriteLine($"Match, found '{name}'");
- return pEntry;
- } else {
- Console.WriteLine("Not a match: a: " + pEntry->Type + ", w: " + type);
- Console.WriteLine("Not a match: a: " + pEntry->NameCRC + ", w: " + nameCRC);
- }
-
- loopEnd:
- entryCount++;
- current = (void*)((nint)current + sizeOfEntry);
- }
-
- //throw new Exception("Did not find entry, searched " + entryCount);
-
- return null;
- }
-
- public Entry* CreateEntry(EntryType type, string name) {
- uint nameCRC = HashNameUInt32(name);
- int sizeOfEntry = header->elemSize;
- void* current = DynamicStart;
- void* last = header + header->length;
- int entryCount = 0;
- while (current < last)
- {
- Entry* pEntry = (Entry*)current;
- if (pEntry->Type == 0) {
- // Non initialized entry, mark this as ours and return it
- Console.WriteLine("Init entry at pos " + entryCount);
- Entry.Init(pEntry, type, nameCRC);
- return pEntry;
- }
-
- current = (void*)((nint)current + sizeOfEntry);
- entryCount++;
- }
-
- throw new Exception("Ran out of IPC SharedObjectManager entries!");
- }
-
- private static string GetIPCObjName()
- {
- return $"/u{LinuxConsts.getuid()}-ValveIPCSharedObj-Steam";
- }
-
- ///
- /// LOCK BEFORE USING!
- ///
- public Entry* FindOrCreateEntry(EntryType type, string name, out bool bCreated)
- {
- Entry* entry = FindEntry(type, name);
- if (entry != null) {
- bCreated = false;
- IPCImpl.Entry.AddReference(entry);
- } else {
- bCreated = true;
- entry = CreateEntry(type, name);
- }
-
- return entry;
- }
-
- public void Deref(void* entry)
- {
- using var l = Lock();
-
- ArgumentNullException.ThrowIfNull(entry);
- if (!IPCImpl.Entry.RemoveReference((Entry*)entry, Environment.ProcessId)) {
- throw new Exception("Dereferencing failed");
- }
-
- if (!IPCImpl.Entry.HasAnyReferences((Entry*)entry)) {
- Entry.Destruct((Entry*)entry);
- }
- }
-}
\ No newline at end of file
diff --git a/ChromeTestClient/Platform/Linux/LinuxData.cs b/ChromeTestClient/Platform/Linux/LinuxData.cs
deleted file mode 100644
index c0870716..00000000
--- a/ChromeTestClient/Platform/Linux/LinuxData.cs
+++ /dev/null
@@ -1,89 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace ipctest.Platform.Linux;
-
-public unsafe static class LinuxConsts {
- public const int SYS_gettid = 186;
- public const int SYS_futex = 202;
- public const int SYS_set_robust_list = 273;
- public const int SYS_get_robust_list = 274;
- public const int FUTEX_WAIT = 0;
- public const int FUTEX_WAKE = 1;
- public const int FUTEX_CMP_REQUEUE = 4;
- public const int O_RDWR = 2;
- public const int O_CREAT = 100;
- public const int PROT_READ = 1;
- public const int PROT_WRITE = 2;
- public const int PROT_EXEC = 4;
- public const int MAP_SHARED = 1;
- public const int MAP_PRIVATE = 2;
- public const int MAP_SHARED_VALIDATE = 3;
- public const int MAP_TYPE = 0x0f;
-
- // This can't be const due to a dumb C# moment
- public static void* MAP_FAILED => (void*)-1;
-
-
-
- [DllImport("c", EntryPoint = "syscall", SetLastError = true)]
- public static extern long syscall_futex(long num, uint* uaddr, int futex_op, uint val, timespec* timeout, uint* uaddr2, uint val3);
-
- [DllImport("c", EntryPoint = "syscall", SetLastError = true)]
- public static extern long syscall_get_robust_list(long num, int pid, robust_list_head** head_ptr, UIntPtr* len_ptr);
-
- [DllImport("c", EntryPoint = "syscall", SetLastError = true)]
- public static extern long syscall_set_robust_list(long num, robust_list_head* head, UIntPtr len);
-
- [DllImport("c", EntryPoint = "syscall", SetLastError = true)]
- public static extern long syscall_gettid(long num);
-
- [DllImport("c", EntryPoint = "kill", SetLastError = true)]
- public static extern int kill(int pid, int op);
-
- [DllImport("c")]
- public static extern int getuid();
-
- [DllImport("c", SetLastError = true)]
- public static extern void* mmap(void* addr, uint length, int prot, int flags, int fd, uint offset);
-
- [DllImport("c", SetLastError = true)]
- public static extern int munmap(void* addr, uint length);
-
- [DllImport("c", SetLastError = true)]
- public static extern int ftruncate(int fd, uint length);
-
- [DllImport("c", SetLastError = true)]
- public static extern int shm_open([MarshalAs(UnmanagedType.LPUTF8Str)] string name, int oflag, int mode);
-
- [DllImport("c", SetLastError = true)]
- public static extern int shm_unlink([MarshalAs(UnmanagedType.LPUTF8Str)] string name);
-
- [DllImport("c", SetLastError = true)]
- public static extern int flock(int fd, int op);
-}
-
-public unsafe static class Errno {
- public const int EWOULDBLOCK = 11;
- public const int EINTR = 4;
- public const int ENOLCK = 37;
- public const int EPERM = 1;
- public const int EOWNERDEAD = 130;
- public const int EEXIST = 17;
- public const int EAGAIN = 11;
- public const int ETIMEDOUT = 110;
-}
-
-public struct timespec {
- public long tv_sec; /* seconds */
- public long tv_nsec; /* nanoseconds */
-}
-
-public unsafe struct robust_list {
- public robust_list* next;
-}
-
-public unsafe struct robust_list_head {
- public robust_list list;
- public long futex_offset;
- public robust_list* list_op_pending;
-}
\ No newline at end of file
diff --git a/ChromeTestClient/Platform/Linux/LinuxEvent.cs b/ChromeTestClient/Platform/Linux/LinuxEvent.cs
deleted file mode 100644
index 45912563..00000000
--- a/ChromeTestClient/Platform/Linux/LinuxEvent.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-using System.Runtime.InteropServices;
-using ipctest.Platform;
-
-namespace ipctest.Platform.Linux;
-
-public unsafe sealed class LinuxEvent : IEvent
-{
- private readonly IPCImpl.Entry_Event* entry;
-
- private IPCImpl ipcImpl => (Globals.IPCImpl as IPCImpl)!;
- public LinuxEvent(string name, bool isManualReset, bool initiallySignaled, out bool bCreated) {
- entry = (IPCImpl.Entry_Event*)ipcImpl.FindOrCreateEntry(IPCImpl.EntryType.Event, name, out bCreated);
- if (bCreated) {
- entry->isManualReset = isManualReset ? 1u : 0u;
- entry->isSignaled = initiallySignaled ? 1u : 0u;
- }
- }
-
- public void Dispose() {
- ipcImpl.Deref(entry);
- }
-
- public bool WaitForStateChange(uint timeoutMS)
- {
- bool isSet = Interlocked.CompareExchange(ref entry->isSignaled, entry->isManualReset, 1) == 1;
- if (!isSet) {
- timespec* timeoutPtr = null;
- timespec timeout;
- if (timeoutMS > 0) {
- timeout = new timespec() { tv_sec = timeoutMS / 1000 };
- timeoutPtr = &timeout;
- }
-
- while (!isSet)
- {
- var ret = LinuxConsts.syscall_futex(LinuxConsts.SYS_futex, &entry->isSignaled, LinuxConsts.FUTEX_WAIT, 0, timeoutPtr, null, 0);
- Console.WriteLine("ret: " + ret + ", val: " + entry->ToString());
-
- if (ret == -1) {
- var err = Marshal.GetLastWin32Error();
- if (err == Errno.ETIMEDOUT) {
- return isSet;
- }
-
- if ((err != Errno.EAGAIN) && (err != Errno.EINTR)) {
- return isSet;
- }
- }
-
- isSet = Interlocked.CompareExchange(ref entry->isSignaled, entry->isManualReset, 1) == 1;
- }
- }
-
- return true;
- }
-
- public void Signal() {
- Interlocked.Increment(ref entry->sequence);
- var isSignaled = Interlocked.CompareExchange(ref entry->isSignaled, 1, 0) == 0;
- if (isSignaled) {
- // It's not safe to release all waiters if it's a manual reset signal
- uint numToWake = entry->isManualReset == 0 ? int.MaxValue : 1u;
-
- LinuxConsts.syscall_futex(LinuxConsts.SYS_futex, &entry->isSignaled, LinuxConsts.FUTEX_WAKE, numToWake, null, null, 0);
- }
- }
-
- public void Reset()
- {
- Interlocked.Exchange(ref entry->isSignaled, 0);
- }
-}
\ No newline at end of file
diff --git a/ChromeTestClient/Platform/Linux/LinuxMutex.cs b/ChromeTestClient/Platform/Linux/LinuxMutex.cs
deleted file mode 100644
index 25011a74..00000000
--- a/ChromeTestClient/Platform/Linux/LinuxMutex.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-
-namespace ipctest.Platform.Linux;
-
-public sealed unsafe class LinuxMutex : IMutex {
- private readonly IPCImpl.Entry_Mutex* entry;
-
- private IPCImpl ipcImpl => (Globals.IPCImpl as IPCImpl)!;
- public LinuxMutex(string name, out bool bCreated) {
- entry = (IPCImpl.Entry_Mutex*)ipcImpl.FindOrCreateEntry(IPCImpl.EntryType.Mutex, name, out bCreated);
- }
-
- public void Dispose() {
- ipcImpl.Deref(entry);
- }
-
- public IDisposable Lock(uint timeoutMS)
- {
- return new MutexDisposable(&entry->Mutex, timeoutMS);
- }
-}
\ No newline at end of file
diff --git a/ChromeTestClient/Platform/Linux/LinuxSharedMemory.cs b/ChromeTestClient/Platform/Linux/LinuxSharedMemory.cs
deleted file mode 100644
index 044be28e..00000000
--- a/ChromeTestClient/Platform/Linux/LinuxSharedMemory.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using System.IO.Hashing;
-using System.Runtime.InteropServices;
-using System.Text;
-
-namespace ipctest.Platform.Linux;
-
-public unsafe sealed class LinuxSharedMemory : ISharedMemory
-{
- public void* Data { get; private set; }
- public uint Length { get; private set; }
-
- public void Dispose()
- {
- (Globals.IPCImpl as IPCImpl)!.Deref(entry);
- LinuxConsts.munmap(Data, Length);
- }
-
- private readonly IPCImpl.Entry* entry;
-
- public LinuxSharedMemory(string name, uint size, out bool bCreated) {
- bCreated = false;
- Length = size;
-
- var hash = IPCImpl.HashName(name);
- string memname = $"/u{LinuxConsts.getuid()}-Shm_{hash.ToLowerInvariant()}";
- string filename = $"/dev/shm{memname}";
-
- entry = (Globals.IPCImpl as IPCImpl)!.FindEntry(IPCImpl.EntryType.SharedMemory, name);
-
- int fd;
- if (entry != null) {
- bCreated = false;
- IPCImpl.Entry.AddReference(entry);
- Console.WriteLine("LinuxSharedMemory, opening: " + filename);
- fd = LinuxConsts.shm_open(memname, LinuxConsts.O_RDWR, 511);
- } else {
- Console.WriteLine("LinuxSharedMemory, creating: " + filename);
- bCreated = true;
- fd = LinuxConsts.shm_open(memname, LinuxConsts.O_RDWR | LinuxConsts.O_CREAT, 511);
- entry = (Globals.IPCImpl as IPCImpl)!.CreateEntry(IPCImpl.EntryType.SharedMemory, name);
- }
-
- try
- {
- if (fd < 0) {
- throw new Exception("Opening shared memory failed with " + Marshal.GetLastWin32Error());
- }
-
- var allocated = new FileInfo(filename).Length;
- Console.WriteLine("Bytes Allocated: " + allocated);
- if (allocated < size)
- {
- Console.WriteLine("ftruncate: " + LinuxConsts.ftruncate(fd, size));
- var newsize = new FileInfo(filename).Length;
- Console.WriteLine("New Size: " + newsize);
- }
-
- var ret = LinuxConsts.mmap(null, size, LinuxConsts.PROT_READ | LinuxConsts.PROT_WRITE, LinuxConsts.MAP_SHARED, fd, 0);
- if (ret == LinuxConsts.MAP_FAILED) {
- throw new Exception("mmap failed with " + Marshal.GetLastWin32Error());
- }
-
- Data = ret;
- }
- catch (System.Exception)
- {
- if (entry != null) {
- IPCImpl.Entry.RemoveReference(entry, Environment.ProcessId);
- }
-
- throw;
- }
- }
-}
\ No newline at end of file
diff --git a/ChromeTestClient/Platform/Linux/MutexDisposable.cs b/ChromeTestClient/Platform/Linux/MutexDisposable.cs
deleted file mode 100644
index c277d90a..00000000
--- a/ChromeTestClient/Platform/Linux/MutexDisposable.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-namespace ipctest.Platform.Linux;
-
-public unsafe sealed class MutexDisposable : IDisposable
-{
- private SteamLinuxMutex* mutex;
- private Action? destructExtraFunc;
- public MutexDisposable(SteamLinuxMutex* mutex, uint timeoutMS = 5000, Action? acquireExtraFunc = null, Action? destructExtraFunc = null) {
- this.destructExtraFunc = destructExtraFunc;
- this.mutex = mutex;
- if (timeoutMS != 0) {
- // Wait a specified timeout
- timespec timeout = new()
- {
- tv_sec = timeoutMS / 1000
- };
-
- ErrnoException.ThrowIfNonZero(SteamLinuxMutex.IPCMutexLock(mutex, &timeout));
- acquireExtraFunc?.Invoke();
- } else {
- // Wait forever
- ErrnoException.ThrowIfNonZero(SteamLinuxMutex.IPCMutexLock(mutex, null));
- acquireExtraFunc?.Invoke();
- }
- }
-
- public void Dispose()
- {
- destructExtraFunc?.Invoke();
- SteamLinuxMutex.IPCMutexUnlock(mutex);
- }
-}
\ No newline at end of file
diff --git a/ChromeTestClient/Platform/Linux/SteamLinuxMutex.cs b/ChromeTestClient/Platform/Linux/SteamLinuxMutex.cs
deleted file mode 100644
index 5cf8ac76..00000000
--- a/ChromeTestClient/Platform/Linux/SteamLinuxMutex.cs
+++ /dev/null
@@ -1,206 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace ipctest.Platform.Linux;
-
-//TODO: We could use managed thread ID's instead of native thread id's, however I'm pretty sure the code-executing thread may switch around every now and then when running managed code, so it may cause problems
-[StructLayout(LayoutKind.Sequential)]
-public unsafe struct SteamLinuxMutex
-{
- public int threadID;
- public uint unk1;
- public uint unk2;
- public uint unk3;
- public uint unk4;
- //public uint unk5;
- //public uint** anotherField;
- public robust_list robust_list;
-
- // This function is almost directly copied from Ghidra. It needs cleanup.
- public static int IPCMutexLock(SteamLinuxMutex* mutex, timespec* timeout)
- {
- int iVar1 = 0;
- uint actualThreadHolder = 0;
- long lVar2 = 0;
- uint ourThreadID = 0;
- uint expectedThreadID = 0;
- uint ownerThread = 0;
- uint fastAcquireRun = 0;
- uint uVar4 = 0;
- bool bVar5 = false;
- uint someLocal = 0;
- robust_list_head* robust_list = null;
- nuint len = 0;
- robust_list* ppuVar1 = null;
-
- var ret = LinuxConsts.syscall_get_robust_list(LinuxConsts.SYS_get_robust_list, 0, &robust_list, &len);
- if (robust_list == null || len != 24)
- {
- throw new Exception("Fatal error: futex robust_list not initialized by pthreads");
- }
-
- if (robust_list->futex_offset != -32)
- {
- throw new Exception("Fatal error: futex robust_list not pthreads-compatible");
- }
-
- robust_list->list_op_pending = (robust_list*)&mutex->robust_list;
-
- if (ourThreadID == 0)
- {
- ourThreadID = (uint)LinuxConsts.syscall_gettid(LinuxConsts.SYS_gettid);
- }
-
- ourThreadID = ourThreadID & 0x1fffffff;
- ownerThread = (uint)Interlocked.CompareExchange(ref mutex->threadID, (int)ourThreadID, 0);
- if (ownerThread != 0)
- {
- bool anyConditionMatches = false;
- if ((ourThreadID != (ownerThread & 0x1fffffff)))
- {
- anyConditionMatches = true;
- }
- else if ((ownerThread & 0x40000000) != 0)
- {
- anyConditionMatches = true;
- iVar1 = 0x23;
- }
-
- if (anyConditionMatches)
- {
- if ((timeout == (timespec*)0x0) || ((timeout->tv_sec != 0 || (timeout->tv_nsec != 0))))
- {
- fastAcquireRun = 0;
- someLocal = ownerThread & 0x40000000;
- expectedThreadID = ownerThread;
- uVar4 = ourThreadID;
- if (someLocal == 0) {
- do
- {
- bool doubleJump = false;
-
- uVar4 = ourThreadID;
- if (ownerThread == 0)
- {
- expectedThreadID = 0;
- someLocal = 0;
- }
- else if (fastAcquireRun < 100)
- {
- ownerThread = 0;
- fastAcquireRun = fastAcquireRun + 1;
- expectedThreadID = 0;
- }
- else
- {
- ourThreadID = ourThreadID | 0x80000000;
- expectedThreadID = ownerThread;
- uVar4 = ourThreadID;
- if (-1 < (int)ownerThread)
- {
- expectedThreadID = ownerThread | 0x80000000;
- actualThreadHolder = (uint)Interlocked.CompareExchange(ref mutex->threadID, (int)expectedThreadID, (int)ownerThread);
- if (((ownerThread ^ actualThreadHolder) & 0x7fffffff) != 0)
- {
- fastAcquireRun = fastAcquireRun + 1;
- doubleJump = true;
- goto breakOutOfIf;
- //goto LAB_010438bb;
- }
- }
- lVar2 = LinuxConsts.syscall_futex(LinuxConsts.SYS_futex, (uint*)&mutex->threadID, 0, expectedThreadID, timeout, null, 0);
- if (lVar2 < 0)
- {
- iVar1 = Marshal.GetLastWin32Error();
- if ((iVar1 != 0xb) && (iVar1 != 4))
- {
- if (iVar1 == 0) goto uncontestedLock;
- goto endOfFunction;
- }
- }
- fastAcquireRun = fastAcquireRun + 1;
- expectedThreadID = 0;
- ownerThread = 0;
- }
-
- breakOutOfIf:
-
- while (true)
- {
- if (doubleJump) {
- doubleJump = false;
- goto LAB_010438bb;
- }
-
- actualThreadHolder = (uint)Interlocked.CompareExchange(ref mutex->threadID, (int)ourThreadID, (int)expectedThreadID);
- if (actualThreadHolder == ownerThread)
- {
- if (someLocal == 0) goto uncontestedLock;
- iVar1 = 130;
- goto endOfFunction;
- }
- LAB_010438bb:
- someLocal = actualThreadHolder & 0x40000000;
- ownerThread = actualThreadHolder;
- expectedThreadID = actualThreadHolder;
- ourThreadID = uVar4;
- if (someLocal == 0) break;
- goto LAB_010438cd;
- }
- } while (true);
- }
-
- // someLocal != 0
- LAB_010438cd:
- ourThreadID = expectedThreadID & 0x80000000 | uVar4;
- ownerThread = expectedThreadID;
-
- }
-
- if ((ownerThread & 0x40000000) != 0)
- {
- bVar5 = Interlocked.CompareExchange(ref mutex->threadID, (int)(ourThreadID | ownerThread & 0x80000000), (int)ownerThread) == ownerThread;
- if (bVar5)
- {
- iVar1 = 130;
- goto endOfFunction;
- }
- }
-
- iVar1 = 110;
- }
-
- goto endOfFunction;
- }
-
- uncontestedLock:
- // ownerThread == 0
- ppuVar1 = &robust_list->list;
- (mutex->robust_list).next = ppuVar1->next;
- ppuVar1->next = &mutex->robust_list;
-
- endOfFunction:
- robust_list->list_op_pending = (robust_list*)0x0;
- return iVar1;
- }
-
- ///
- /// Unlocks the mutex. Make sure you actually own it before freeing, as there are no checks done.
- ///
- ///
- ///
- public static int IPCMutexUnlock(SteamLinuxMutex* mutex)
- {
- //Console.WriteLine("Unlocking mutex: " + (nint)mutex);
- var xchgResult = Interlocked.Exchange(ref mutex->threadID, 0);
- if (xchgResult < 0) {
- LinuxConsts.syscall_futex(LinuxConsts.SYS_futex, (uint*)&mutex->threadID, LinuxConsts.FUTEX_WAKE, 1, null, null, 0);
- }
-
- return xchgResult;
- }
-
- public override string ToString()
- {
- return $"{threadID} {unk1} {unk2} {unk3} {unk4}";
- }
-}
\ No newline at end of file
diff --git a/ChromeTestClient/Program.cs b/ChromeTestClient/Program.cs
deleted file mode 100644
index ad319034..00000000
--- a/ChromeTestClient/Program.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-using System;
-using System.Diagnostics;
-using System.IO.MemoryMappedFiles;
-using System.Runtime.InteropServices;
-using System.Text;
-
-namespace ipctest;
-
-public unsafe class Program
-{
- private static void Main(string[] args)
- {
- // PrintInfo();
-
- // var thread = new Thread(() =>
- // {
- // PrintInfo();
- // });
-
- // thread.Start();
- // Thread.Sleep(50);
-
- // thread = new Thread(() =>
- // {
- // PrintInfo();
- // });
-
- // thread.Start();
- // Thread.Sleep(50);
-
- // thread = new Thread(() =>
- // {
- // PrintInfo();
- // });
-
- // thread.Start();
- // Thread.Sleep(50);
- bool hasSteam = Process.GetProcessesByName("steam").FirstOrDefault() != null;
- if (OperatingSystem.IsLinux() && !hasSteam) {
- var homevar = Environment.GetEnvironmentVariable("HOME");
- if (string.IsNullOrEmpty(homevar)) {
- throw new NullReferenceException("HOME not set, please set it");
- }
-
- File.WriteAllText(Path.Combine(homevar, ".steam/steam.pid"), Environment.ProcessId.ToString());
- Console.WriteLine("Set steam PID to " + Environment.ProcessId.ToString());
- }
-
- if (!hasSteam) {
- Console.CancelKeyPress += (object? sender, ConsoleCancelEventArgs e) =>
- {
- LiteHTMLHost.KillHTMLHost();
- };
-
- LiteHTMLHost.StartHTMLHost();
- Thread.Sleep(1000);
- }
-
- var chromeIPCClient = new ChromeIPCClient();
-
- while (true)
- {
- Thread.Sleep(10);
- }
-
- // sharedMemoryIPC.CreateSharedMemory($"SteamChrome_MasterStream_uid{SharedMemoryIPC.getuid()}_spid{GetSteamPID()}_mem");
- // sharedMemoryIPC.CreateSharedMemory($"SteamChrome_MasterStream_3137_28054_mem");
- }
-}
\ No newline at end of file
diff --git a/ChromeTestClient/README.md b/ChromeTestClient/README.md
deleted file mode 100644
index a2e0ce80..00000000
--- a/ChromeTestClient/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# ipctest
-this is a terrible effort to reverse Steam's shared memory IPC on linux
-tread carefully. Pain is imminent.
\ No newline at end of file
diff --git a/ChromeTestClient/SharedMemStream.cs b/ChromeTestClient/SharedMemStream.cs
deleted file mode 100644
index 48084a96..00000000
--- a/ChromeTestClient/SharedMemStream.cs
+++ /dev/null
@@ -1,180 +0,0 @@
-using System.IO;
-using System.Runtime.InteropServices;
-using ipctest.Platform;
-
-namespace ipctest;
-
-public unsafe sealed class SharedMemStream : IDisposable
-{
- public struct SharedMemHeader {
- public uint totalRead;
- public uint totalWritten;
- public uint connSize;
- public uint availableBytes;
-
- public override string ToString()
- {
- return $"{totalRead} {totalWritten} {connSize} {availableBytes}";
- }
- }
-
- private readonly ISharedMemory sharedMemory;
- private readonly IEvent writtenEvent;
- private readonly IEvent availEvent;
- private readonly IMutex mutex;
- private bool isDisposed = false;
- public SharedMemHeader* HeaderPtr => (SharedMemHeader*)sharedMemory.Data;
- private byte* DataPtr => (byte*)((nint)sharedMemory.Data + sizeof(SharedMemHeader));
- private byte* EndPtr => (byte*)((nint)sharedMemory.Data + HeaderPtr->connSize);
-
- // Stream compat
- public int WriteTimeout { get; set; }
- public int ReadTimeout { get; set; }
-
-
- public SharedMemStream(string name, out bool bCreated, uint wantedSize = 0x1900000, int timeoutMS = 1000) {
- this.WriteTimeout = timeoutMS;
- this.ReadTimeout = timeoutMS;
-
- mutex = Globals.IPCImpl.CreateMutex($"{name}_mutex", out bool bCreatedMutex);
- IDisposable? constructLock = null;
- if (bCreatedMutex) {
- constructLock = mutex.Lock();
- }
-
- try
- {
- writtenEvent = Globals.IPCImpl.CreateEvent($"{name}_written", out _);
- availEvent = Globals.IPCImpl.CreateEvent($"{name}_avail", out _);
- var allocatedSize = (uint)(wantedSize + sizeof(SharedMemHeader));
- sharedMemory = Globals.IPCImpl.CreateSharedMemory($"{name}_mem", allocatedSize, out bCreated);
- Console.WriteLine($"Got ptr {(nint)sharedMemory.Data}");
- if (!bCreated) {
- // Check validity of existing stream
- if (HeaderPtr->connSize != wantedSize) {
- throw new Exception($"Size on connection to existing SharedMemStream doesn't match actual: {name}, {allocatedSize}, {HeaderPtr->connSize}");
- }
- } else {
- NativeMemory.Clear(sharedMemory.Data, allocatedSize);
- HeaderPtr->connSize = wantedSize;
- }
-
- ReadPosition = HeaderPtr->totalRead;
-
- }
- finally
- {
- constructLock?.Dispose();
- }
- }
-
- public void Dispose() {
- if (isDisposed) {
- return;
- }
-
- isDisposed = true;
- mutex.Dispose();
- sharedMemory.Dispose();
- writtenEvent.Dispose();
- availEvent.Dispose();
- }
-
- public bool BWaitForDataToGet(uint timeoutMS = 0) {
- ObjectDisposedException.ThrowIf(this.isDisposed, this);
- if (WritePosition > ReadPosition) {
- return true;
- }
-
- writtenEvent.WaitForStateChange(timeoutMS);
- Console.WriteLine("HDR: " + HeaderPtr->ToString());
- Console.WriteLine("AvailableToRead: " + AvailableToRead);
- return AvailableToRead > 0;
- }
-
- public long Capacity => HeaderPtr->connSize;
- public long ReadPosition { get; set; }
-
- public long WritePosition {
- get => HeaderPtr->totalWritten;
- set => HeaderPtr->totalWritten = (uint)value;
- }
-
- public long AvailableToRead
- => HeaderPtr->totalWritten - ReadPosition;
-
- public long RemainingCapacity
- => this.EndPtr - (this.DataPtr + HeaderPtr->availableBytes);
-
- public long GetOffsetReadPosition(int offset) {
- return ReadPosition + offset;
- }
-
- public long GetOffsetWritePosition(int offset) {
- return WritePosition + offset;
- }
-
- public int Read(byte[] buffer, int offset, int count)
- {
- ObjectDisposedException.ThrowIf(this.isDisposed, this);
- ThrowIfArrayDoesntMatchSize(buffer, count, nameof(count));
-
- Console.WriteLine("LockR");
- using var l = mutex.Lock((uint)this.ReadTimeout);
- Console.WriteLine("LockedR");
-
- long toRead = long.Clamp(count, 0, Capacity);
- toRead = long.Clamp(toRead, 0, buffer.Length);
- toRead = long.Clamp(toRead, 0, HeaderPtr->totalWritten - GetOffsetReadPosition(offset));
-
- Console.WriteLine("HDR: " + HeaderPtr->ToString());
- fixed (byte* ptr = buffer) {
- NativeMemory.Copy(DataPtr + GetOffsetReadPosition(offset), ptr, (nuint)toRead);
- }
-
- if (HeaderPtr->totalRead > ReadPosition) {
- // Only update the read count and available bytes if we're reading at the head
- HeaderPtr->totalRead += (uint)toRead;
-
- if (toRead >= HeaderPtr->availableBytes) {
- // Only update available bytes if we're reading at the top
- HeaderPtr->availableBytes -= (uint)toRead;
- availEvent.Signal();
- }
- }
-
- ReadPosition += (uint)toRead;
-
- // This API is terrible. Why do we need so many conversions?
- return (int)toRead;
- }
-
- public void Write(byte[] buffer, int offset, int count)
- {
- ObjectDisposedException.ThrowIf(this.isDisposed, this);
- ThrowIfArrayDoesntMatchSize(buffer, count, nameof(count));
-
- Console.WriteLine("LockW");
- using var l = mutex.Lock((uint)this.WriteTimeout);
- Console.WriteLine("LockedW");
-
- long maxWritable = long.Clamp(count, 0, Capacity - HeaderPtr->totalWritten - offset);
- if (maxWritable < count) {
- throw new ArgumentOutOfRangeException(nameof(count));
- }
-
- fixed (byte* ptr = buffer) {
- NativeMemory.Copy(ptr, DataPtr + GetOffsetWritePosition(offset), (nuint)maxWritable);
- HeaderPtr->availableBytes += (uint)maxWritable;
- HeaderPtr->totalWritten += (uint)maxWritable;
- }
-
- this.writtenEvent.Signal();
- }
-
- private static void ThrowIfArrayDoesntMatchSize(byte[] arr, long size, string argumentName) {
- if (size > arr.LongLength) {
- throw new ArgumentOutOfRangeException(argumentName);
- }
- }
-}
\ No newline at end of file
diff --git a/ChromeTestClient/nuget.config b/ChromeTestClient/nuget.config
deleted file mode 100644
index 42c6aa46..00000000
--- a/ChromeTestClient/nuget.config
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/GameOverlayDebugTarget/App.axaml b/GameOverlayDebugTarget/App.axaml
deleted file mode 100644
index 9a2f2deb..00000000
--- a/GameOverlayDebugTarget/App.axaml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/GameOverlayDebugTarget/App.axaml.cs b/GameOverlayDebugTarget/App.axaml.cs
deleted file mode 100644
index ed1bc57f..00000000
--- a/GameOverlayDebugTarget/App.axaml.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using Avalonia;
-using Avalonia.Controls.ApplicationLifetimes;
-using Avalonia.Markup.Xaml;
-
-namespace GameOverlayDebugTarget;
-
-public partial class App : Application
-{
- public override void Initialize()
- {
- AvaloniaXamlLoader.Load(this);
- }
-
- public override void OnFrameworkInitializationCompleted()
- {
- if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
- {
- desktop.MainWindow = new MainWindow();
- }
-
- base.OnFrameworkInitializationCompleted();
- }
-}
\ No newline at end of file
diff --git a/GameOverlayDebugTarget/GameOverlayDebugTarget.csproj b/GameOverlayDebugTarget/GameOverlayDebugTarget.csproj
deleted file mode 100644
index 1dd981ae..00000000
--- a/GameOverlayDebugTarget/GameOverlayDebugTarget.csproj
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
- WinExe
- net8.0
- enable
- true
- app.manifest
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/GameOverlayDebugTarget/MainWindow.axaml b/GameOverlayDebugTarget/MainWindow.axaml
deleted file mode 100644
index 27d4b87f..00000000
--- a/GameOverlayDebugTarget/MainWindow.axaml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
diff --git a/GameOverlayDebugTarget/MainWindow.axaml.cs b/GameOverlayDebugTarget/MainWindow.axaml.cs
deleted file mode 100644
index 0ba4b576..00000000
--- a/GameOverlayDebugTarget/MainWindow.axaml.cs
+++ /dev/null
@@ -1,295 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Threading;
-using Avalonia;
-using Avalonia.Controls;
-using Avalonia.Input;
-using Avalonia.Media.Imaging;
-using Avalonia.Platform;
-using Avalonia.Threading;
-using GameOverlayUI.IPC;
-
-namespace GameOverlayDebugTarget;
-
-public partial class MainWindow : Window
-{
- private Thread? thread;
- private readonly object inputsLock = new();
- private readonly List inputs = new();
-
- public MainWindow()
- {
- InitializeComponent();
- this.thread = new Thread(MainThread);
- this.thread.Start();
- this.SystemDecorations = SystemDecorations.None;
- this.WindowState = WindowState.FullScreen;
- }
-
- private static RawInputModifiers KeyModifiersToRawInputModifiers(KeyModifiers keyModifiers) {
- var raw = RawInputModifiers.None;
- if (keyModifiers.HasFlag(KeyModifiers.Alt)) {
- raw |= RawInputModifiers.Alt;
- }
-
- if (keyModifiers.HasFlag(KeyModifiers.Control)) {
- raw |= RawInputModifiers.Control;
- }
-
- if (keyModifiers.HasFlag(KeyModifiers.Meta)) {
- raw |= RawInputModifiers.Meta;
- }
-
- if (keyModifiers.HasFlag(KeyModifiers.Shift)) {
- raw |= RawInputModifiers.Shift;
- }
-
- return raw;
- }
-
- private static MouseButton PointerUpdateKindToMouseButton(PointerUpdateKind pointerUpdateKind) {
- return pointerUpdateKind switch
- {
- PointerUpdateKind.LeftButtonPressed => MouseButton.Left,
- PointerUpdateKind.LeftButtonReleased => MouseButton.Left,
- PointerUpdateKind.MiddleButtonPressed => MouseButton.Middle,
- PointerUpdateKind.MiddleButtonReleased => MouseButton.Middle,
- PointerUpdateKind.RightButtonPressed => MouseButton.Right,
- PointerUpdateKind.RightButtonReleased => MouseButton.Right,
- PointerUpdateKind.XButton1Pressed => MouseButton.XButton1,
- PointerUpdateKind.XButton1Released => MouseButton.XButton1,
- PointerUpdateKind.XButton2Pressed => MouseButton.XButton2,
- PointerUpdateKind.XButton2Released => MouseButton.XButton2,
- _ => MouseButton.None
- };
- }
-
- private void OnPointerReleased(object? sender, Avalonia.Input.PointerReleasedEventArgs e) {
- var pos = PixelPoint.FromPoint(e.GetPosition(RenderedImage), this.RenderScaling);
- Console.WriteLine("RELEASED at " + pos);
-
- lock (inputsLock)
- {
- inputs.Add(new InputData(KeyModifiersToRawInputModifiers(e.KeyModifiers), (uint)pos.X, (uint)pos.Y, PointerUpdateKindToMouseButton(e.GetCurrentPoint(null).Properties.PointerUpdateKind), false));
- }
- }
-
- private void OnPointerPressed(object? sender, Avalonia.Input.PointerPressedEventArgs e) {
- var pos = PixelPoint.FromPoint(e.GetPosition(RenderedImage), this.RenderScaling);
- Console.WriteLine("PRESSED at " + pos);
-
- lock (inputsLock)
- {
- inputs.Add(new InputData(KeyModifiersToRawInputModifiers(e.KeyModifiers), (uint)pos.X, (uint)pos.Y, PointerUpdateKindToMouseButton(e.GetCurrentPoint(null).Properties.PointerUpdateKind), true));
- }
- }
-
- private void OnPointerMoved(object? sender, Avalonia.Input.PointerEventArgs e) {
- var pos = e.GetPosition(RenderedImage);
- Console.WriteLine("MOVED at " + pos);
-
- lock (inputsLock)
- {
- inputs.Add(new InputData(KeyModifiersToRawInputModifiers(e.KeyModifiers), (uint)pos.X, (uint)pos.Y));
- }
- }
-
- private void OnKeyDown(object? sender, Avalonia.Input.KeyEventArgs e) {
- Console.WriteLine("key down");
- lock (inputsLock)
- {
- inputs.Add(new InputData(KeyModifiersToRawInputModifiers(e.KeyModifiers), e.Key, e.PhysicalKey, true));
- }
- }
-
- private void OnKeyUp(object? sender, Avalonia.Input.KeyEventArgs e) {
- Console.WriteLine("key up");
- lock (inputsLock)
- {
- inputs.Add(new InputData(KeyModifiersToRawInputModifiers(e.KeyModifiers), e.Key, e.PhysicalKey, false));
- }
- }
-
- private EOverlayState State {
- get {
- unsafe {
- return Program.Container.Get().ControlData.Data->State;
- }
- }
-
- set {
- unsafe {
- Program.Container.Get().ControlData.Data->State = value;
- }
- }
- }
-
- private unsafe void MainThread() {
- var sharedMemoryManager = Program.Container.Get();
- int fpsLimit = 0;
- double averageElapsed = 0;
- double averageFPS = 0;
- Stopwatch stopwatch = new();
- Stopwatch clientStopwatch = new();
- Stopwatch serverStopwatch = new();
- stopwatch.Start();
- while (true)
- {
- stopwatch.Reset();
- stopwatch.Start();
- serverStopwatch.Reset();
- clientStopwatch.Reset();
- clientStopwatch.Start();
-
- bool isChecked = false;
-
- Dispatcher.UIThread.Invoke(() =>
- {
- isChecked = ShouldRender.IsChecked != null && ShouldRender.IsChecked.Value;
- if (FPSLimitCheck.IsChecked != null && FPSLimitCheck.IsChecked.Value) {
- if (int.TryParse(FPSLimitBox.Text, out int fpsLimit2)) {
- fpsLimit = fpsLimit2;
- }
- } else {
- fpsLimit = 0;
- }
- });
-
- if (!isChecked) {
- Console.WriteLine("Render blocked");
- Thread.Sleep(1000);
- continue;
- }
-
-
- State = EOverlayState.ClientRequestLoopStart;
-
- clientStopwatch.Stop();
- serverStopwatch.Start();
- while (State != EOverlayState.ResponseAvailable)
- {
- if (State == EOverlayState.ServerRequestInputData) {
- goto inputDataAnswer;
- }
- }
-
- while (State != EOverlayState.ServerRequestInputData)
- {
-
- }
-
-inputDataAnswer:
- serverStopwatch.Stop();
- clientStopwatch.Start();
-
- List inputsCopy;
- lock (inputsLock)
- {
- inputsCopy = inputs.ToList();
- inputs.Clear();
- }
-
- uint newLength = (uint)(DynInputData.CalculateDataLength((uint)inputsCopy.Count) + sizeof(DynInputData));
- if (sharedMemoryManager.InputData.Length < newLength) {
- sharedMemoryManager.InputData.Resize(newLength);
- sharedMemoryManager.ControlData.Data->MemoryResized = newLength;
- } else {
- sharedMemoryManager.ControlData.Data->MemoryResized = 0;
- }
-
-
- DynInputData.EnqueueAll(sharedMemoryManager.InputData.Data, inputsCopy);
-
- serverStopwatch.Start();
- clientStopwatch.Stop();
- State = EOverlayState.ResponseAvailable;
- while (State != EOverlayState.ServerRequestDisplayAllocation)
- {
-
- }
-
- serverStopwatch.Stop();
- clientStopwatch.Start();
-
- newLength = (uint)(DynDisplayData.CalculateDataLength(sharedMemoryManager.DisplayData.Data) + sizeof(DynDisplayData));
- sharedMemoryManager.DisplayData.Resize(newLength);
- sharedMemoryManager.ControlData.Data->MemoryResized = newLength;
-
- serverStopwatch.Start();
- clientStopwatch.Stop();
- State = EOverlayState.ResponseAvailable;
-
- while (State != EOverlayState.RenderDataAvailable)
- {
-
- }
-
- serverStopwatch.Stop();
- clientStopwatch.Start();
-
- Dispatcher.UIThread.Invoke(() =>
- {
- WriteableBitmap bitmap;
-
- if (RenderedImage.Source is WriteableBitmap mp)
- {
- bitmap = mp;
- }
- else
- {
- Vector dpi = new Vector(96, 96);
-
- bitmap = new WriteableBitmap(
- new PixelSize((int)sharedMemoryManager.DisplayData.Data->Width, (int)sharedMemoryManager.DisplayData.Data->Height),
- dpi,
- PixelFormat.Bgra8888,
- AlphaFormat.Premul);
-
- RenderedImage.Source = bitmap;
- }
-
- using (var frameBuffer = bitmap.Lock())
- {
- NativeMemory.Copy(&sharedMemoryManager.DisplayData.Data->DynamicData, (void*)frameBuffer.Address, (nuint)DynDisplayData.CalculateDataLength(sharedMemoryManager.DisplayData.Data));
- }
-
- RenderedImage.InvalidateVisual();
- }, DispatcherPriority.Render);
-
- clientStopwatch.Stop();
-
- if (fpsLimit > 0) {
- double calculated = 1 / (double)fpsLimit * 1000;
- int sleepMS = (int)(calculated - stopwatch.Elapsed.TotalMilliseconds);
- if (sleepMS > 0) {
- Thread.Sleep(sleepMS);
- }
- }
-
- var totalElapsed = stopwatch.Elapsed.TotalMilliseconds;
- averageElapsed = (averageElapsed + totalElapsed) / 2;
- averageFPS = (averageFPS + (1 / totalElapsed * 1000)) / 2;
- string debugStrFPS = $"FPS: {TruncateDouble(averageFPS)}";
- string debugStrFTAvg = $"Avg ft: {TruncateDouble(averageElapsed)}ms";
- string debugStrFTLast = $"Last ft: {TruncateDouble(totalElapsed)}ms";
- string debugStrProcessServer = $"Server process {TruncateDouble(serverStopwatch.Elapsed.TotalMilliseconds)}ms";
- string debugStrProcessClient = $"Client process: {TruncateDouble(clientStopwatch.Elapsed.TotalMilliseconds)}ms";
-
- Dispatcher.UIThread.Post(() =>
- {
- FramerateDebugText.Text = debugStrFPS;
- FrametimeAvgDebugText.Text = debugStrFTAvg;
- FrametimeLastDebugText.Text = debugStrFTLast;
- ProcessServerDebugText.Text = debugStrProcessServer;
- ProcessClientDebugText.Text = debugStrProcessClient;
- });
- }
- }
-
- private static string TruncateDouble(double val) {
- return (Math.Truncate(val * 100) / 100).ToString();
- }
-}
\ No newline at end of file
diff --git a/GameOverlayDebugTarget/Program.cs b/GameOverlayDebugTarget/Program.cs
deleted file mode 100644
index d3d5f02c..00000000
--- a/GameOverlayDebugTarget/Program.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-using Avalonia;
-using GameOverlayUI.IPC;
-using OpenSteamClient.DI;
-using OpenSteamworks.Data.Structs;
-using System;
-
-namespace GameOverlayDebugTarget;
-
-public static class Program
-{
- public static Container Container { get; private set; } = new();
-
- // Initialization code. Don't use any Avalonia, third-party APIs or any
- // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
- // yet and stuff might break.
- [STAThread]
- public static void Main(string[] args)
- {
- Console.CancelKeyPress += HandleCtrlC;
- AppDomain.CurrentDomain.UnhandledException += HandleUnhandledException;
-
- if (args.Length < 1 || !uint.TryParse(args[0], out uint gamepid))
- {
- Console.WriteLine("Not enough args, required [GamePID]");
- return;
- }
-
- Console.WriteLine("Game PID: " + gamepid);
-
- var gameidstr = Environment.GetEnvironmentVariable("SteamOverlayGameId");
- CGameID gameid;
- if (string.IsNullOrEmpty(gameidstr) || !ulong.TryParse(gameidstr, out ulong ugameid) || !(gameid = new CGameID(ugameid)).IsValid()) {
- Console.WriteLine("Invalid SteamOverlayGameId");
- return;
- }
-
- Console.WriteLine("GameID: " + gameid);
- Container.RegisterInstance(new SharedMemoryManager(gamepid, true));
-
- try
- {
- BuildAvaloniaApp().StartWithClassicDesktopLifetime(args, Avalonia.Controls.ShutdownMode.OnExplicitShutdown);
- }
- finally
- {
- DisposeAll();
- }
- }
-
- private static void HandleUnhandledException(object sender, UnhandledExceptionEventArgs e)
- {
- DisposeAll();
- }
-
- private static void HandleCtrlC(object? sender, ConsoleCancelEventArgs e) {
- DisposeAll();
- }
-
- private static bool canDispose = true;
- private static void DisposeAll() {
- if (!canDispose) {
- return;
- }
-
- canDispose = false;
- Container?.Get().Dispose();
- }
-
- // Avalonia configuration, don't remove; also used by visual designer.
- public static AppBuilder BuildAvaloniaApp()
- {
- var builder = AppBuilder.Configure();
- return builder
- .UseSkia()
- .UsePlatformDetect()
- .WithInterFont()
- .LogToTrace();
-
- }
-}
diff --git a/GameOverlayDebugTarget/app.manifest b/GameOverlayDebugTarget/app.manifest
deleted file mode 100644
index 7121aab9..00000000
--- a/GameOverlayDebugTarget/app.manifest
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/GameOverlayDebugTarget/nuget.config b/GameOverlayDebugTarget/nuget.config
deleted file mode 100644
index 42c6aa46..00000000
--- a/GameOverlayDebugTarget/nuget.config
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/GameOverlayUI/AvaloniaApp.axaml b/GameOverlayUI/AvaloniaApp.axaml
deleted file mode 100644
index 184e3052..00000000
--- a/GameOverlayUI/AvaloniaApp.axaml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/GameOverlayUI/AvaloniaApp.axaml.cs b/GameOverlayUI/AvaloniaApp.axaml.cs
deleted file mode 100644
index 2f734d10..00000000
--- a/GameOverlayUI/AvaloniaApp.axaml.cs
+++ /dev/null
@@ -1,311 +0,0 @@
-using Avalonia;
-using Avalonia.Controls.ApplicationLifetimes;
-using Avalonia.Markup.Xaml;
-using OpenSteamworks.Client.Managers;
-using Avalonia.Controls;
-using OpenSteamClient.DI;
-using Avalonia.Threading;
-using AvaloniaCommon;
-using System.Diagnostics;
-using GameOverlayUI.ViewModels;
-using GameOverlayUI.IPC;
-using GameOverlayUI.Views;
-using Avalonia.Headless;
-using Avalonia.Media.Imaging;
-using Avalonia.Platform;
-using System.Runtime.InteropServices;
-using Avalonia.Input;
-using GameOverlayUI.Impl;
-using Avalonia.Platform.Storage;
-
-namespace GameOverlayUI;
-
-public class AvaloniaApp : Application
-{
- public new static AvaloniaApp? Current;
- public static Theme? Theme;
- public new IClassicDesktopStyleApplicationLifetime ApplicationLifetime => (base.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)!;
-
- public override void Initialize()
- {
- AvaloniaXamlLoader.Load(this);
- }
-
- private static void InvokeOnUIThread(Action callback)
- {
- if (!Program.Container.IsShuttingDown)
- {
- Avalonia.Threading.Dispatcher.UIThread.Invoke(callback);
- }
- }
-
- public override void OnFrameworkInitializationCompleted()
- {
- Theme = new Theme(this);
-
- var mainViewViewModel = new MainViewViewModel();
- Program.Container.RegisterInstance(mainViewViewModel);
-
- var mainView = new MainView
- {
- DataContext = mainViewViewModel,
- TransparencyLevelHint = new List() { WindowTransparencyLevel.Transparent }
- };
-
- Program.Container.RegisterInstance(mainView);
-
- ForceWindow(mainView);
-
- base.OnFrameworkInitializationCompleted();
-
- serverThread = new(ServerThreadMain);
- serverThread.Start();
- }
-
- // #define LOGSPAM
- private Thread? serverThread;
- private readonly ManualResetEventSlim threadMainMre = new();
- private unsafe void ServerThreadMain() {
- var sharedMemoryManager = Program.Container.Get();
- var mainView = Program.Container.Get();
- RenderTargetBitmap? renderTarget = null;
-
- while (!threadMainMre.IsSet) {
- OverlayControlData.WaitForLoopStart(sharedMemoryManager.ControlData.Data);
- #if LOGSPAM
- Console.WriteLine("Client started loop");
- #endif
-
- sharedMemoryManager.ControlData.Data->State = EOverlayState.ResponseAvailable;
-
- // First resize the display and then run the inputs
- #if LOGSPAM
- Console.WriteLine("Input data requested");
- #endif
-
- OverlayControlData.RequestInputData(sharedMemoryManager.ControlData.Data, out uint newAllocation);
- if (newAllocation != 0) {
- sharedMemoryManager.InputData.Resize(newAllocation + sizeof(DynInputData));
- }
-
- #if LOGSPAM
- Console.WriteLine("Input data received");
- #endif
-
-
- var inputDataIn = sharedMemoryManager.GetInputData();
- List inputData = new();
- int numMouseMoves = inputDataIn.Count(e => e.Type == EInputType.MouseMove);
- foreach (var item in inputDataIn)
- {
- if (item.Type == EInputType.MouseMove) {
- numMouseMoves--;
-
- // Allow 5 or so mouse moves per frame, anything extra will slow down everything to a halt
- if (numMouseMoves > 5) {
- continue;
- }
- }
-
- inputData.Add(item);
- }
-
- Dispatcher.UIThread.Invoke(() => {
- for (int i = 0; i < inputData.Count; i++)
- {
- var input = inputData[i];
- // Avalonia headless input system is seriously slow (it wasn't intended to be used like this)
- Console.WriteLine("Processing input type " + input.Type);
- Console.WriteLine("Mod: " + input.Modifiers);
- var pos = new Point(input.X, input.Y);
- input.Modifiers = RawInputModifiers.None;
-
- switch (input.Type)
- {
- case EInputType.MouseMove:
- mainView.MouseMove(pos, input.Modifiers);
- break;
-
- case EInputType.MouseDown:
- mainView.MouseDown(pos, input.MouseButton, input.Modifiers);
- //mainView.MouseUp(clickPos, input.MouseButton, input.Modifiers);
- break;
-
- case EInputType.MouseUp:
- mainView.MouseUp(pos, input.MouseButton, input.Modifiers);
- break;
-
- case EInputType.KeyDown:
- mainView.KeyPress(input.Key, input.Modifiers, input.PhysicalKey, null);
- break;
-
- case EInputType.KeyUp:
- mainView.KeyRelease(input.Key, input.Modifiers, input.PhysicalKey, null);
- break;
-
- case EInputType.MouseScrollDown:
- mainView.MouseWheel(pos, new Vector(0, -1.0), input.Modifiers);
- break;
-
- case EInputType.MouseScrollUp:
- mainView.MouseWheel(pos, new Vector(0, 1.0), input.Modifiers);
- break;
- }
- }
-
- }, DispatcherPriority.MaxValue);
-
- #if LOGSPAM
- Console.WriteLine("Display allocation requested");
- #endif
-
- OverlayControlData.RequestDisplayAllocation(sharedMemoryManager.ControlData.Data, out newAllocation);
- if (newAllocation != 0) {
- sharedMemoryManager.DisplayData.Resize(newAllocation + sizeof(DynDisplayData));
- }
-
- #if LOGSPAM
- Console.WriteLine("Display allocated");
- #endif
-
- if (renderTarget == null || sharedMemoryManager.DisplayData.Data->Width != renderTarget.PixelSize.Width || sharedMemoryManager.DisplayData.Data->Height != renderTarget.PixelSize.Height) {
- Dispatcher.UIThread.Invoke(() =>
- {
- // Update the resolution of the window itself
- Trace.Assert(mainView.PlatformImpl != null);
-
- #if LOGSPAM
- Console.WriteLine("Target W: " + sharedMemoryManager.DisplayData.Data->Width + ", H: " + sharedMemoryManager.DisplayData.Data->Height);
- #endif
-
- mainView.PlatformImpl.Resize(new Size(sharedMemoryManager.DisplayData.Data->Width, sharedMemoryManager.DisplayData.Data->Height), WindowResizeReason.User);
- }, DispatcherPriority.Render);
-
- renderTarget?.Dispose();
-
- renderTarget = new RenderTargetBitmap(PixelSize.FromSize(new Size(sharedMemoryManager.DisplayData.Data->Width, sharedMemoryManager.DisplayData.Data->Height), 1));
- }
-
- Dispatcher.UIThread.Invoke(() =>
- {
- renderTarget.Render(mainView);
- }, DispatcherPriority.MaxValue);
-
-
- // Console.WriteLine("ClientSize is now " + mainView.ClientSize);
- // Console.WriteLine("PixelSize is now " + );
-
- // AvaloniaHeadlessPlatform.ForceRenderTimerTick(1);
- // var frame = mainView.GetLastRenderedFrame();
-
- // if (frame != null) {
- sharedMemoryManager.SetPixels(renderTarget);
- // }
-
- #if LOGSPAM
- Console.WriteLine("rendered");
- #endif
- sharedMemoryManager.ControlData.Data->State = EOverlayState.RenderDataAvailable;
- }
-
- renderTarget?.Dispose();
-
- serverThread = null;
- }
-
- public void ActivateMainWindow() {
- ApplicationLifetime.MainWindow?.Show();
- ApplicationLifetime.MainWindow?.Activate();
- }
-
- ///
- /// Tries to show the window as a dialog
- ///
- ///
- public void TryShowDialog(Window dialog) {
- dialog.Show();
- }
-
- ///
- /// Tries to show the window as a dialog. If the window is already open, it focus on it.
- ///
- ///
- public void TryShowDialogSingle(Func dialogFactory) where T: Window {
- RunOnUIThread(DispatcherPriority.Send, () =>
- {
- var existingDialog = TryGetDialogSingle();
- if (existingDialog != null) {
- existingDialog.Show();
- existingDialog.Activate();
- return;
- }
-
- dialogFactory().Show();
- });
- }
-
- ///
- /// Runs the given action on the UI thread.
- /// If we're already on the UI thread, executes the function inline.
- /// Blocks until the function has been executed.
- ///
- ///
- public void RunOnUIThread(DispatcherPriority priority, Action func) {
- if (Dispatcher.UIThread.CheckAccess()) {
- func();
- return;
- }
-
- Dispatcher.UIThread.Invoke(func, priority);
- }
-
- public T? TryGetDialogSingle() where T: Window {
- var existingDialogs = ApplicationLifetime.Windows.Where(w => w.GetType() == typeof(T));
- if (existingDialogs.Any()) {
- return (T)existingDialogs.First();
- }
-
- return null;
- }
-
- ///
- /// Closes the current MainWindow (if exists) and replaces it with a user specified window
- ///
- public T ForceWindow(T window) where T : Window
- {
- if (!Program.Container.IsShuttingDown)
- {
- ApplicationLifetime.MainWindow?.Close();
- ApplicationLifetime.MainWindow = window;
- ApplicationLifetime.MainWindow.Show();
- }
-
- return window;
- }
-
- public AvaloniaApp()
- {
- Current = this;
- Name = "OpenSteamClient";
- DataContext = new AvaloniaAppViewModel();
- }
-
- ///
- /// Async exit function. Will hang in certain cases for some unknown reason.
- ///
- public async Task Exit(int exitCode = 0)
- {
- Progress operation = new();
- Progress subOperation = new();
- await Program.Container.RunClientShutdown(operation, subOperation);
- Console.WriteLine("Shutting down Avalonia");
- }
-
- ///
- /// A synchronous exit function. Simply calls Task.Run.
- ///
- public void ExitEventually(int exitCode = 0)
- {
- Dispatcher.UIThread.InvokeAsync(async () => await this.Exit(exitCode));
- }
-}
diff --git a/GameOverlayUI/GameOverlayUI.csproj b/GameOverlayUI/GameOverlayUI.csproj
deleted file mode 100644
index 801c559c..00000000
--- a/GameOverlayUI/GameOverlayUI.csproj
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
- Exe
- net8.0
- enable
- enable
- true
- true
-
-
-
-
-
-
-
-
-
-
diff --git a/GameOverlayUI/IPC/DynDisplayData.cs b/GameOverlayUI/IPC/DynDisplayData.cs
deleted file mode 100644
index 2c0cfded..00000000
--- a/GameOverlayUI/IPC/DynDisplayData.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System.Diagnostics;
-using Avalonia.Media.Imaging;
-
-namespace GameOverlayUI.IPC;
-
-public unsafe struct DynDisplayData {
- public uint Width;
- public uint Height;
-
- ///
- /// Start of dynamic data
- ///
- public byte DynamicData;
-
- public static long CalculateDataLength(DynDisplayData* ptr) {
- return ptr->Width * ptr->Height * 4;
- }
-
- public static void SetPixels(DynDisplayData* ptr, Bitmap frame)
- {
- //TODO: This code needs additional sanity checks (such as resolution check)
- //TODO: Resize support (currently game window resizing won't work, need to re-mmap)
-
- #if LOGSPAM
- Console.WriteLine("c: " + CalculateDataLength(ptr) + ", a: " + data.Length);
- Console.WriteLine("W: " + ptr->Width + ", H: " + ptr->Height);
- #endif
-
- const int BPP = 4;
- frame.CopyPixels(new Avalonia.PixelRect(0, 0, frame.PixelSize.Width, frame.PixelSize.Height), (nint)(&ptr->DynamicData), (int)CalculateDataLength(ptr), frame.PixelSize.Width * BPP);
- }
-
- public DynDisplayData()
- {
- }
-}
\ No newline at end of file
diff --git a/GameOverlayUI/IPC/DynInputData.cs b/GameOverlayUI/IPC/DynInputData.cs
deleted file mode 100644
index 80251da7..00000000
--- a/GameOverlayUI/IPC/DynInputData.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace GameOverlayUI.IPC;
-
-public unsafe struct DynInputData {
- public uint NumQueued;
- public byte DynamicStart;
-
- public static bool TryDequeueAll(DynInputData* ptr, out List inputData)
- {
- inputData = new();
- if (ptr->NumQueued < 1) {
- return false;
- }
-
- Span span = new(&ptr->DynamicStart, (int)CalculateDataLength(ptr));
- for (int i = 0; i < ptr->NumQueued; i++)
- {
- var data = Marshal.PtrToStructure((nint)(&ptr->DynamicStart + (i * Marshal.SizeOf())));
- inputData.Add(data);
- }
-
- ptr->NumQueued = 0;
- return true;
- }
-
- public static void EnqueueAll(DynInputData* ptr, List inputData)
- {
- for (int i = 0; i < inputData.Count; i++)
- {
- nint bufPtr = (nint)(&ptr->DynamicStart) + (i * Marshal.SizeOf());
- Marshal.StructureToPtr(inputData[i], bufPtr, false);
- }
-
- ptr->NumQueued = (uint)inputData.Count;
- }
-
- public static long CalculateDataLength(DynInputData* ptr) {
- return CalculateDataLength(ptr->NumQueued);
- }
-
- public static long CalculateDataLength(uint numInputs) {
- return numInputs * Marshal.SizeOf();
- }
-}
\ No newline at end of file
diff --git a/GameOverlayUI/IPC/EInputType.cs b/GameOverlayUI/IPC/EInputType.cs
deleted file mode 100644
index 9ae77ef3..00000000
--- a/GameOverlayUI/IPC/EInputType.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-namespace GameOverlayUI.IPC;
-
-public enum EInputType : uint {
- KeyDown,
- KeyUp,
- MouseDown,
- MouseUp,
- MouseMove,
-
- //TODO: Cannot support smooth scrolling
- MouseScrollDown,
- MouseScrollUp,
-}
\ No newline at end of file
diff --git a/GameOverlayUI/IPC/EOverlayState.cs b/GameOverlayUI/IPC/EOverlayState.cs
deleted file mode 100644
index 67bee34d..00000000
--- a/GameOverlayUI/IPC/EOverlayState.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-namespace GameOverlayUI.IPC;
-
-public enum EOverlayState : int {
- NotRunning = 0,
-
- ///
- /// Phase 1 of the overlay loop.
- ///
- ClientRequestLoopStart,
-
- ///
- /// Phase 2 of the overlay loop. The client will re-allocate the display's shared memory segment if the resolution has changed
- ///
- ServerRequestDisplayAllocation,
-
- ///
- /// Phase 3 of the overlay loop. The client will tell the server how big the input buffer is in MemoryResized or 0 if it is unchanged.
- ///
- ServerRequestInputData,
-
- ///
- /// Phase 4 of the overlay loop. Set by the server once rendering is done and the results are ready in memory to be displayed by the client.
- /// After the client finishes rendering, the client will reset the state to NotRunning or ClientRequestLoopStart
- ///
- RenderDataAvailable,
-
-
- ResponseAvailable,
-}
diff --git a/GameOverlayUI/IPC/InputData.cs b/GameOverlayUI/IPC/InputData.cs
deleted file mode 100644
index ece59fb3..00000000
--- a/GameOverlayUI/IPC/InputData.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-using System.Runtime.InteropServices;
-using Avalonia.Input;
-
-namespace GameOverlayUI.IPC;
-
-[StructLayout(LayoutKind.Explicit)]
-public unsafe struct InputData {
- [FieldOffset(0)]
- public EInputType Type;
-
- [FieldOffset(4)]
- public RawInputModifiers Modifiers;
-
- // Mouse specific
-
- [FieldOffset(8)]
- public MouseButton MouseButton;
-
- [FieldOffset(12)]
- public uint X;
-
- [FieldOffset(16)]
- public uint Y;
-
- // Keyboard specific
-
- [FieldOffset(8)]
- public Key Key;
-
- [FieldOffset(12)]
- public PhysicalKey PhysicalKey;
-
- public InputData(EInputType type, RawInputModifiers modifiers) {
- this.Type = type;
- this.Modifiers = modifiers;
- }
-
- public InputData(RawInputModifiers modifiers, uint x, uint y) : this(EInputType.MouseMove, modifiers) {
- this.X = x;
- this.Y = y;
- }
-
- public InputData(RawInputModifiers modifiers, uint x, uint y, MouseButton button, bool down = true) : this(modifiers, x, y) {
- this.Type = down ? EInputType.MouseDown : EInputType.MouseUp;
- this.MouseButton = button;
- }
-
- public InputData(RawInputModifiers modifiers, Key key, PhysicalKey physicalKey, bool down = true) : this(EInputType.KeyDown, modifiers) {
- this.Type = down ? EInputType.KeyDown : EInputType.KeyUp;
- this.Key = key;
- this.PhysicalKey = physicalKey;
- }
-}
\ No newline at end of file
diff --git a/GameOverlayUI/IPC/OverlayControlData.cs b/GameOverlayUI/IPC/OverlayControlData.cs
deleted file mode 100644
index f2d7a179..00000000
--- a/GameOverlayUI/IPC/OverlayControlData.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-namespace GameOverlayUI.IPC;
-
-public struct OverlayControlData {
- public EOverlayState State = EOverlayState.NotRunning;
- public uint MemoryResized = 0;
-
-
- public static unsafe void WaitForLoopStart(OverlayControlData* data) {
- while (data->State != EOverlayState.ClientRequestLoopStart)
- {
- // This is terible, but it will have to do unless we start using linux mutexes and that's complex (and even more not-cross platform).
- Thread.Sleep(1);
- }
- }
-
- public static unsafe void RequestInputData(OverlayControlData* data, out uint newAllocation) {
- data->State = EOverlayState.ServerRequestInputData;
- while (data->State != EOverlayState.ResponseAvailable)
- {
- //Thread.Sleep(1);
- }
-
- newAllocation = data->MemoryResized;
- data->MemoryResized = 0;
- }
-
- public static unsafe void RequestDisplayAllocation(OverlayControlData* data, out uint newAllocation) {
- data->State = EOverlayState.ServerRequestDisplayAllocation;
- while (data->State != EOverlayState.ResponseAvailable)
- {
- //Thread.Sleep(1);
- }
-
- newAllocation = data->MemoryResized;
- data->MemoryResized = 0;
- }
-
- public OverlayControlData() { }
-}
\ No newline at end of file
diff --git a/GameOverlayUI/IPC/SharedMemoryManager.cs b/GameOverlayUI/IPC/SharedMemoryManager.cs
deleted file mode 100644
index 922fb67f..00000000
--- a/GameOverlayUI/IPC/SharedMemoryManager.cs
+++ /dev/null
@@ -1,154 +0,0 @@
-using System.IO.MemoryMappedFiles;
-using System.Runtime.InteropServices;
-using Avalonia.Headless;
-using Avalonia.Media.Imaging;
-using Avalonia.Platform;
-using Avalonia.Threading;
-using SkiaSharp;
-
-namespace GameOverlayUI.IPC;
-
-public unsafe class SharedMemoryManager : IDisposable {
- public class SharedMemorySegment : IDisposable where TData : unmanaged
- {
- public string IPCFilePath => $"/dev/shm{IPCName}";
- public string IPCName { get; }
- public long Length { get; private set; }
- public TData* Data { get; private set; }
- public int FD { get; private set; }
-
- public SharedMemorySegment(string ipcName, long initialSize) {
- IPCName = ipcName;
- Resize(initialSize, true);
- }
-
- public void Resize(long newLength)
- => Resize(newLength, false);
-
- private void Resize(long newLength, bool isInit) {
- if (newLength == Length && !isInit) {
- #if LOGSPAM
- Console.WriteLine("No need to resize");
- #endif
-
- return;
- }
-
- if (Data != null) {
- munmap(Data, (uint)Length);
- }
-
- FD = shm_open(IPCName, 66, 511);
- Console.WriteLine("open result: " + FD);
-
- Console.WriteLine("ftruncate: " + ftruncate(FD, (uint)newLength));
- Length = new FileInfo(IPCFilePath).Length;
- Console.WriteLine("New Size: " + Length);
-
- Data = (TData*)mmap((void*)0x0, (uint)newLength, 3, 1, FD, 0);
- Console.WriteLine("mmap result: " + (nint)Data);
-
- var closeResult = close(FD);
- Console.WriteLine("close result: " + closeResult);
-
- Length = newLength;
- }
-
- public void Dispose()
- {
- if (Data == null) {
- throw new ObjectDisposedException(nameof(Data));
- }
-
- ReleaseSharedMemory();
- Data = null;
- Length = 0;
- }
-
- private void ReleaseSharedMemory() {
- var result = munmap(Data, (uint)Length);
- Console.WriteLine("munmap result: " + result);
-
- if (!isClient) {
- result = shm_unlink(IPCName);
- Console.WriteLine("unlink result: " + result);
- }
- }
- }
-
- [DllImport("c")]
- private static extern int getuid();
-
- [DllImport("c")]
- private static extern void* mmap(void* addr, uint length, int prot, int flags, int fd, uint offset);
-
- [DllImport("c")]
- private static extern int munmap(void* addr, uint length);
-
- [DllImport("c", SetLastError = true)]
- private static extern int ftruncate(int fd, uint length);
-
- [DllImport("c")]
- private static extern int shm_open([MarshalAs(UnmanagedType.LPUTF8Str)] string name, int oflag, int mode);
-
- [DllImport("c")]
- private static extern int shm_unlink([MarshalAs(UnmanagedType.LPUTF8Str)] string name);
-
- [DllImport("c")]
- private static extern int close(int fd);
-
- public SharedMemorySegment InputData { get; private set; }
- public SharedMemorySegment DisplayData { get; private set; }
- public SharedMemorySegment ControlData { get; private set; }
-
-
- public uint GamePID { get; init; }
- public string IPCNameInput => $"/u{getuid()}_OpenSteamClientIPC-GameOverlay_{GamePID}_Input";
- public string IPCNameDisplay => $"/u{getuid()}_OpenSteamClientIPC-GameOverlay_{GamePID}_Display";
- public string IPCNameControl => $"/u{getuid()}_OpenSteamClientIPC-GameOverlay_{GamePID}_Control";
-
- private static bool isClient = false;
- public SharedMemoryManager(uint gamePID, bool client = false) {
- isClient = client;
-
- if (!OperatingSystem.IsLinux()) {
- throw new NotSupportedException();
- }
-
- this.GamePID = gamePID;
-
- InputData = new(IPCNameInput, 1024);
- DisplayData = new(IPCNameDisplay, 1920 * 1080 * 4);
- ControlData = new(IPCNameControl, sizeof(OverlayControlData));
-
- if (!client) {
- // The server setups the initial screen allocation
- DisplayData.Data->Width = 1920;
- DisplayData.Data->Height = 1080;
- DisplayData.Resize(DynDisplayData.CalculateDataLength(DisplayData.Data) + sizeof(DynDisplayData));
- }
- }
-
- public List GetInputData() {
- if (DynInputData.TryDequeueAll(InputData.Data, out List inputData)) {
- Console.WriteLine("Got input data, count: " + inputData.Count);
- }
-
- return inputData;
- }
-
- public void SetPixels(Bitmap frame) {
- if (frame.Format != PixelFormat.Bgra8888) {
- throw new Exception("Invalid format for image");
- }
-
- DynDisplayData.SetPixels(DisplayData.Data, frame);
- }
-
- public void Dispose()
- {
- InputData.Dispose();
- DisplayData.Dispose();
- ControlData.Dispose();
- }
-}
\ No newline at end of file
diff --git a/GameOverlayUI/Impl/OverlayLauncher.cs b/GameOverlayUI/Impl/OverlayLauncher.cs
deleted file mode 100644
index 467b52db..00000000
--- a/GameOverlayUI/Impl/OverlayLauncher.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-using System.Diagnostics;
-using System.Text.RegularExpressions;
-using Avalonia.Input.Platform;
-using Avalonia.Platform.Storage;
-
-namespace GameOverlayUI.Impl;
-
-///
-/// Mostly copied from Avalonia BclLauncher
-///
-public class OverlayLauncher : ILauncher
-{
- public virtual Task LaunchUriAsync(Uri uri)
- {
- _ = uri ?? throw new ArgumentNullException(nameof(uri));
- if (uri.IsAbsoluteUri)
- {
- return Task.FromResult(Exec(uri.AbsoluteUri));
- }
-
- return Task.FromResult(false);
- }
-
- ///
- /// This Process based implementation doesn't handle the case, when there is no app to handle link.
- /// It will still return true in this case.
- ///
- public virtual Task LaunchFileAsync(IStorageItem storageItem)
- {
- _ = storageItem ?? throw new ArgumentNullException(nameof(storageItem));
- if (storageItem.TryGetLocalPath() is { } localPath
- && CanOpenFileOrDirectory(localPath))
- {
- return Task.FromResult(Exec(localPath));
- }
-
- return Task.FromResult(false);
- }
-
- protected virtual bool CanOpenFileOrDirectory(string localPath) => true;
-
- private static bool Exec(string urlOrFile)
- {
- if (OperatingSystem.IsLinux())
- {
- // If no associated application/json MimeType is found xdg-open opens return error
- // but it tries to open it anyway using the console editor (nano, vim, other..)
- ShellExec($"xdg-open {urlOrFile}", waitForExit: false);
- return true;
- }
- else if (OperatingSystem.IsWindows() || OperatingSystem.IsMacOS())
- {
- using var process = Process.Start(new ProcessStartInfo
- {
- FileName = OperatingSystem.IsWindows() ? urlOrFile : "open",
- Arguments = OperatingSystem.IsMacOS() ? $"{urlOrFile}" : "",
- CreateNoWindow = true,
- UseShellExecute = OperatingSystem.IsWindows()
- });
- return true;
- }
- else
- {
- return false;
- }
- }
-
- private static void ShellExec(string cmd, bool waitForExit = true)
- {
- var escapedArgs = Regex.Replace(cmd, "(?=[`~!#&*()|;'<>])", "\\")
- .Replace("\"", "\\\\\\\"");
-
- using (var process = Process.Start(
- new ProcessStartInfo
- {
- FileName = "/bin/sh",
- Arguments = $"-c \"{escapedArgs}\"",
- RedirectStandardOutput = true,
- UseShellExecute = false,
- CreateNoWindow = true,
- WindowStyle = ProcessWindowStyle.Hidden
- }
- ))
- {
- if (waitForExit)
- {
- process?.WaitForExit();
- }
- }
- }
-}
\ No newline at end of file
diff --git a/GameOverlayUI/Impl/OverlayLauncherFactory.cs b/GameOverlayUI/Impl/OverlayLauncherFactory.cs
deleted file mode 100644
index 7764e1ee..00000000
--- a/GameOverlayUI/Impl/OverlayLauncherFactory.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-#if AVALONIA_ILAUNCHER_API
-
-using Avalonia.Controls;
-using Avalonia.Controls.Platform;
-using Avalonia.Platform.Storage;
-
-namespace GameOverlayUI.Impl;
-
-public class OverlayLauncherFactory : ILauncherFactory
-{
- public ILauncher CreateLauncher(TopLevel topLevel)
- {
- return new OverlayLauncher();
- }
-}
-
-#endif
\ No newline at end of file
diff --git a/GameOverlayUI/Program.cs b/GameOverlayUI/Program.cs
deleted file mode 100644
index 9fdfb00e..00000000
--- a/GameOverlayUI/Program.cs
+++ /dev/null
@@ -1,108 +0,0 @@
-using Avalonia;
-using OpenSteamworks.Data.Structs;
-using Avalonia.Headless;
-using OpenSteamClient.DI;
-using GameOverlayUI.IPC;
-using Avalonia.Platform;
-using Avalonia.Platform.Storage;
-using Avalonia.Controls.Platform;
-using GameOverlayUI.Impl;
-
-namespace GameOverlayUI;
-
-public static class Program
-{
- public static Container Container { get; private set; } = new();
- public static bool IsUITestMode { get; private set; } = false;
-
- // Initialization code. Don't use any Avalonia, third-party APIs or any
- // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
- // yet and stuff might break.
- [STAThread]
- public static void Main(string[] args)
- {
- Console.CancelKeyPress += HandleCtrlC;
- AppDomain.CurrentDomain.UnhandledException += HandleUnhandledException;
-
- if (args.Length < 1 || !uint.TryParse(args[0], out uint gamepid))
- {
- Console.WriteLine("Not enough args, required [GamePID]");
- return;
- }
-
- Console.WriteLine("Game PID: " + gamepid);
-
- var gameidstr = Environment.GetEnvironmentVariable("SteamOverlayGameId");
- CGameID gameid;
- if (string.IsNullOrEmpty(gameidstr) || !ulong.TryParse(gameidstr, out ulong ugameid) || !(gameid = new CGameID(ugameid)).IsValid()) {
- Console.WriteLine("Invalid SteamOverlayGameId");
- return;
- }
-
- Console.WriteLine("GameID: " + gameid);
- Container.RegisterInstance(new SharedMemoryManager(gamepid));
-
- if (args.Length > 1) {
- Console.WriteLine("UI test mode enabled");
- IsUITestMode = args[1] == "testmode";
- }
-
- try
- {
- BuildAvaloniaApp().StartWithClassicDesktopLifetime(args, Avalonia.Controls.ShutdownMode.OnExplicitShutdown);
- }
- finally
- {
- DisposeAll();
- }
- }
-
- private static void HandleUnhandledException(object sender, UnhandledExceptionEventArgs e)
- {
- DisposeAll();
- }
-
- private static void HandleCtrlC(object? sender, ConsoleCancelEventArgs e) {
- DisposeAll();
- }
-
- private static bool canDispose = true;
- private static void DisposeAll() {
- if (!canDispose) {
- return;
- }
-
- canDispose = false;
- Container?.Get().Dispose();
- }
-
- // Avalonia configuration, don't remove; also used by visual designer.
- public static AppBuilder BuildAvaloniaApp()
- {
- var builder = AppBuilder.Configure();
- if (IsUITestMode) {
- return builder
- .UseSkia()
-#if AVALONIA_ILAUNCHER_API
- .With(new OverlayLauncherFactory())
-#endif
- .UsePlatformDetect()
- .WithInterFont()
- .LogToTrace();
-
- } else {
- return builder
- .UseSkia()
-#if AVALONIA_ILAUNCHER_API
- .With(new OverlayLauncherFactory())
-#endif
- .UseHeadless(new AvaloniaHeadlessPlatformOptions
- {
- UseHeadlessDrawing = false,
- FrameBufferFormat = PixelFormat.Bgra8888
- })
- .WithInterFont()
- .LogToTrace();
- }
- }
-}
diff --git a/GameOverlayUI/ViewModels/AvaloniaAppViewModel.cs b/GameOverlayUI/ViewModels/AvaloniaAppViewModel.cs
deleted file mode 100644
index 3469b786..00000000
--- a/GameOverlayUI/ViewModels/AvaloniaAppViewModel.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-using AvaloniaCommon;
-
-namespace GameOverlayUI.ViewModels;
-
-public class AvaloniaAppViewModel : ViewModelBase {
-
-}
\ No newline at end of file
diff --git a/GameOverlayUI/ViewModels/CustomWindowViewModel.cs b/GameOverlayUI/ViewModels/CustomWindowViewModel.cs
deleted file mode 100644
index 9358e597..00000000
--- a/GameOverlayUI/ViewModels/CustomWindowViewModel.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-using Avalonia;
-using Avalonia.Controls;
-using Avalonia.Dialogs;
-using Avalonia.Input;
-using Avalonia.Media.Imaging;
-using Avalonia.Reactive;
-using AvaloniaCommon;
-using CommunityToolkit.Mvvm.ComponentModel;
-
-namespace GameOverlayUI.ViewModels;
-
-public partial class CustomWindowViewModel : ViewModelBase {
- [ObservableProperty]
- private object? content;
-
- [ObservableProperty]
- private double x;
-
- [ObservableProperty]
- private double y;
-
- [ObservableProperty]
- private int z = 0;
-
- [ObservableProperty]
- private string title = string.Empty;
-
- [ObservableProperty]
- [NotifyPropertyChangedFor(nameof(IconVisible))]
- private Bitmap? icon = null;
- public bool IconVisible => Icon != null;
-
- private readonly Window underlyingWindow;
-
- public void Close() {
- var mainViewViewModel = Program.Container.Get();
- Console.WriteLine("Close");
- mainViewViewModel.RemoveWindow(this);
- underlyingWindow.Close();
- }
-
- public void LostFocus() {
- Z = 0;
- }
-
- public void GotFocus() {
- Z = 1;
- }
-
- public CustomWindowViewModel(Window underlyingWindow) {
- this.underlyingWindow = underlyingWindow;
-
- underlyingWindow.GetObservable(Window.TitleProperty).Subscribe(new AnonymousObserver(TitleChange));
- underlyingWindow.GetObservable(Window.IconProperty).Subscribe(new AnonymousObserver(IconChange));
- underlyingWindow.GetObservable(ContentControl.ContentProperty).Subscribe(new AnonymousObserver