Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Register protocol handlers & replay file extensions to the operating system #136

Draft
wants to merge 25 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
48a7f24
Windows seems done
VasilisThePikachu Jan 20, 2024
831222d
OOPs forgor
VasilisThePikachu Jan 20, 2024
68279e9
OOPS
VasilisThePikachu Jan 20, 2024
4c1429e
PJB bullied me to making this good
VasilisThePikachu Jan 20, 2024
14c3eb6
Commiting so i can work on my macbook
VasilisThePikachu Jan 23, 2024
e17c3f6
MacOS
VasilisThePikachu Feb 7, 2024
81adfa2
I prefer doing this
VasilisThePikachu Feb 7, 2024
1017326
I give up on macos, im just gonna send over whatever i had
VasilisThePikachu Feb 14, 2024
6fb5187
Merge branch 'master' of ssh://github.com/space-wizards/SS14.Launcher…
VasilisThePikachu Mar 13, 2024
dac3514
Start of Robust Toolbox file extensions
VasilisThePikachu Mar 13, 2024
83b38e4
file extensions
VasilisThePikachu Mar 17, 2024
0c74a42
Remove debug code and finish windows
VasilisThePikachu Mar 17, 2024
b74cfec
Shitty bug fix for when you drop a content bundle that has a space in…
VasilisThePikachu Mar 17, 2024
f9d3f4f
ok but like maybe
VasilisThePikachu Apr 5, 2024
d380786
Ok no maybe
VasilisThePikachu Apr 10, 2024
934044f
Send this to my macbook please work
VasilisThePikachu Apr 10, 2024
5102306
a
VasilisThePikachu May 6, 2024
e4059dd
A
VasilisThePikachu Jul 20, 2024
01b3bae
Merge remote-tracking branch 'upstream/master' into protocol
VasilisThePikachu Jul 20, 2024
fd427b2
Why apple
VasilisThePikachu Jul 20, 2024
10865dd
123 im gonna squash this anyway later
VasilisThePikachu Jul 22, 2024
e135cba
Fix conflict
VasilisThePikachu Jul 26, 2024
0682c24
Fix macos kinda
VasilisThePikachu Jul 26, 2024
e2d1eac
MACOS IS DONE BOZOS FUCK YOU APPLE
VasilisThePikachu Jul 27, 2024
1535cd1
MacOS improvements (unregistration is fully correct idk)
VasilisThePikachu Jul 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions PublishFiles/SS14.desktop
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ Version=1.0
Type=Application
Exec=env ./SS14.Launcher %u
Name=Space Station 14
MimeType=x-scheme-handler/ss14s;
MimeType=x-scheme-handler/ss14;
32 changes: 32 additions & 0 deletions PublishFiles/Space Station 14 Launcher.app/Contents/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,37 @@
-->
<key>CFBundleIconFile</key>
<string>ss14</string>
<key>CFBundleIdentifier</key>
<string>com.spacestation14.launcher</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>com.spacestation14.launcher</string>
<key>CFBundleURLSchemes</key>
<array>
<string>ss14</string>
<string>ss14s</string>
</array>
</dict>
</array>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>rtreplay</string>
<string>rtbundle</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>ss14</string>
<key>LSHandlerRank</key>
<string>Owner</string>
<key>CFBundleTypeName</key>
<string>Robust Toolbox Bundle File</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
</array>
</dict>
</plist>
59 changes: 58 additions & 1 deletion SS14.Launcher.Bootstrap/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Diagnostics;
using System.IO;
using Microsoft.Win32;
using System.Linq;

namespace SS14.Launcher.Bootstrap
{
Expand All @@ -11,6 +12,53 @@ public static void Main(string[] args)
{
UnfuckDotnetRoot();

if (args.Contains("--register-protocol"))
{
// ss14s://
var key = Registry.ClassesRoot.CreateSubKey("ss14s");
key!.SetValue("URL Protocol", "Space Station 14 Secure protocol");
key = key.CreateSubKey("Shell\\Open\\Command");
key!.SetValue("", $"\"{AppDomain.CurrentDomain.BaseDirectory}Space Station 14 Launcher.exe\" \"%1\"");
key.Close();

// ss14://
key = Registry.ClassesRoot.CreateSubKey("ss14");
key!.SetValue("URL Protocol", "Space Station 14 protocol");
key = key.CreateSubKey("Shell\\Open\\Command");
key!.SetValue("", $"\"{AppDomain.CurrentDomain.BaseDirectory}Space Station 14 Launcher.exe\" \"%1\"");
key.Close();

// RobustToolbox (required for the file extensions)
key = Registry.ClassesRoot.CreateSubKey("RobustToolbox");
key!.SetValue("", "Robust Toolbox Bundle File");
var icon = key.CreateSubKey("DefaultIcon");
icon!.SetValue("", $"{AppDomain.CurrentDomain.BaseDirectory}Space Station 14 Launcher.exe");
key = key.CreateSubKey("Shell\\Open\\Command");
key!.SetValue("", $"\"{AppDomain.CurrentDomain.BaseDirectory}Space Station 14 Launcher.exe\" \"%1\"");
key.Close();

// .rtbundle
key = Registry.ClassesRoot.CreateSubKey(".rtbundle");
key!.SetValue("", "RobustToolbox");
key.Close();

// .rtreplay
key = Registry.ClassesRoot.CreateSubKey(".rtreplay");
key!.SetValue("", "RobustToolbox");
key.Close();

Environment.Exit(0);
}
if (args.Contains("--unregister-protocol"))
{
Registry.ClassesRoot.DeleteSubKeyTree("ss14s");
Registry.ClassesRoot.DeleteSubKeyTree("ss14");
Registry.ClassesRoot.DeleteSubKeyTree("RobustToolbox");
Registry.ClassesRoot.DeleteSubKeyTree(".rtbundle");
Registry.ClassesRoot.DeleteSubKeyTree(".rtreplay");
Environment.Exit(0);
}

var path = typeof(Program).Assembly.Location;
var ourDir = Path.GetDirectoryName(path);
Debug.Assert(ourDir != null);
Expand All @@ -19,7 +67,16 @@ public static void Main(string[] args)
var exeDir = Path.Combine(ourDir, "bin", "SS14.Launcher.exe");

Environment.SetEnvironmentVariable("DOTNET_ROOT", dotnetDir);
Process.Start(new ProcessStartInfo(exeDir));
if (args.Length > 0)
{
// blursed
// thanks anonymous for how to make args pass in properly
Process.Start(new ProcessStartInfo(exeDir, string.Join("", args.Select((str) => $"\"{str}\" "))));
}
else
{
Process.Start(new ProcessStartInfo(exeDir));
}
}

private static void UnfuckDotnetRoot()
Expand Down
12 changes: 12 additions & 0 deletions SS14.Launcher/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
Expand Down Expand Up @@ -34,6 +35,17 @@ public App()
public App(OverrideAssetsManager overrideAssets)
{
_overrideAssets = overrideAssets;

UrlsOpened += OnOSXUrlsOpened;
}

public void OnOSXUrlsOpened(object? sender, UrlOpenedEventArgs e)
{
// I think this only works on macOS anyway? Well i will leave this here just so I don't surprise myself later.
if (!OperatingSystem.IsMacOS())
return;

Program.ParseCommandLineArgs(e.Urls, new LauncherMessaging());
}

public override void Initialize()
Expand Down
16 changes: 15 additions & 1 deletion SS14.Launcher/LauncherCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Text;
using System.Threading.Channels;
using System.Threading.Tasks;
using Avalonia.Platform.Storage;
using Avalonia.Threading;
using Serilog;
using Splat;
Expand All @@ -18,13 +19,15 @@ public class LauncherCommands
private MainWindowViewModel _windowVm;
private LoginManager _loginMgr;
private LauncherMessaging _msgr;
private readonly IStorageProvider _storageProvider;
public readonly Channel<string> CommandChannel;

public LauncherCommands(MainWindowViewModel windowVm)
public LauncherCommands(MainWindowViewModel windowVm, IStorageProvider provider)
{
_windowVm = windowVm;
_loginMgr = Locator.Current.GetRequiredService<LoginManager>();
_msgr = Locator.Current.GetRequiredService<LauncherMessaging>();
_storageProvider = provider;

CommandChannel = Channel.CreateUnbounded<string>();
}
Expand Down Expand Up @@ -157,6 +160,16 @@ private async Task RunSingleCommand(string cmd)
// Used by the "pass URI as argument" logic, doesn't need to bother with safety measures
await Connect(cmd.Substring(1));
}
else if (cmd.StartsWith("b"))
{
// Content bundle file
var uri = new Uri(cmd.Substring(1));
var thingy = await _storageProvider.TryGetFileFromPathAsync(uri);
if (thingy != null)
await Task.Run(() => ConnectingViewModel.StartContentBundle(_windowVm, thingy));
else
Log.Error("File does not exist. Aborting");
}
else
{
Log.Error($"Unhandled launcher command: {cmd}");
Expand All @@ -169,5 +182,6 @@ private async Task RunSingleCommand(string cmd)
public const string RedialWaitCommand = ":RedialWait";
public const string BlankReasonCommand = "r";
public static string ConstructConnectCommand(Uri uri) => "c" + uri.ToString();
public static string ConstructContentBundleCommand(string fileName) => "b" + fileName;
}

87 changes: 50 additions & 37 deletions SS14.Launcher/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http.Headers;
using System.Text;
Expand Down Expand Up @@ -51,40 +52,7 @@ public static void Main(string[] args)
var msgr = new LauncherMessaging();
Locator.CurrentMutable.RegisterConstant(msgr);

// Parse arguments as early as possible for launcher messaging reasons.
string[] commands = { LauncherCommands.PingCommand };
var commandSendAnyway = false;
if (args.Length == 1)
{
// Check if this is a valid Uri, since that indicates re-invocation.
if (Uri.TryCreate(args[0], UriKind.Absolute, out var result))
{
commands = new string[]
{ LauncherCommands.BlankReasonCommand, LauncherCommands.ConstructConnectCommand(result) };
// This ensures we queue up the connection even if we're starting the launcher now.
commandSendAnyway = true;
}
}
else if (args.Length >= 2)
{
if (args[0] == "--commands")
{
// Trying to send an arbitrary series of commands.
// This is how the Loader is expected to communicate (and start the launcher if necessary).
// Note that there are special "untrusted text" versions of the commands that should be used.
commands = new string[args.Length - 1];
for (var i = 0; i < commands.Length; i++)
commands[i] = args[i + 1];
commandSendAnyway = true;
}
}

// Note: This MUST occur before we do certain actions like:
// + Open the launcher log file (and therefore wipe a user's existing launcher log)
// + Initialize Avalonia (and therefore waste whatever time it takes to do that)
// Therefore any messages you receive at this point will be Console.WriteLine-only!
if (msgr.SendCommandsOrClaim(commands, commandSendAnyway))
return;
ParseCommandLineArgs(args, msgr);

var logCfg = new LoggerConfiguration()
.MinimumLevel.Debug()
Expand Down Expand Up @@ -141,7 +109,52 @@ public static void Main(string[] args)
_serverTask?.Wait();
}

private static unsafe void CheckWindowsVersion()
public static void ParseCommandLineArgs(string[] args, LauncherMessaging msgr)
{
// Parse arguments as early as possible for launcher messaging reasons.
string[] commands = { LauncherCommands.PingCommand };
var commandSendAnyway = false;
if (args.Length == 1)
{
// Handle files being opened with the launcher.
if (args.Any(arg => arg.StartsWith("file://") || arg.EndsWith(".rtbundle") || arg.EndsWith(".rtreplay")))
{
commands = [LauncherCommands.BlankReasonCommand, LauncherCommands.ConstructContentBundleCommand(args[0])
];
commandSendAnyway = true;
}

// Check if this is a valid Uri, since that indicates re-invocation.
else if (Uri.TryCreate(args[0], UriKind.Absolute, out var result))
{
commands = [LauncherCommands.BlankReasonCommand, LauncherCommands.ConstructConnectCommand(result)];
// This ensures we queue up the connection even if we're starting the launcher now.
commandSendAnyway = true;
}
}
else if (args.Length >= 2)
{
if (args[0] == "--commands")
{
// Trying to send an arbitrary series of commands.
// This is how the Loader is expected to communicate (and start the launcher if necessary).
// Note that there are special "untrusted text" versions of the commands that should be used.
commands = new string[args.Length - 1];
for (var i = 0; i < commands.Length; i++)
commands[i] = args[i + 1];
commandSendAnyway = true;
}
}

// Note: This MUST occur before we do certain actions like:
// + Open the launcher log file (and therefore wipe a user's existing launcher log)
// + Initialize Avalonia (and therefore waste whatever time it takes to do that)
// Therefore any messages you receive at this point will be Console.WriteLine-only!
if (msgr.SendCommandsOrClaim(commands, commandSendAnyway))
return;
}

private static void CheckWindowsVersion()
{
// 14393 is Windows 10 version 1607, minimum we currently support.
if (!OperatingSystem.IsWindows() || Environment.OSVersion.Version.Build >= 14393)
Expand All @@ -166,7 +179,7 @@ private static unsafe void CheckWindowsVersion()
Helpers.MessageBoxHelper(text, caption, type);
}

private static unsafe void CheckBadAntivirus()
private static void CheckBadAntivirus()
{
// Avast Free Antivirus breaks the game due to their AMSI integration crashing the process. Awesome!
// Oh hey back here again, turns out AVG is just the same product as Avast with different paint.
Expand Down Expand Up @@ -290,7 +303,7 @@ private static void AppMain(Application app, string[] args)
GC.Collect();
};

var lc = new LauncherCommands(viewModel);
var lc = new LauncherCommands(viewModel, window.StorageProvider);
lc.RunCommandTask();
Locator.CurrentMutable.RegisterConstant(lc);
_serverTask = msgr.ServerTask(lc);
Expand Down
Loading
Loading