Line ending normalization... again...

This commit is contained in:
pizzaboxer 2023-06-26 23:10:39 +01:00
parent 6af7188ffe
commit 17c36ccb91
No known key found for this signature in database
GPG Key ID: 59D4A1DBAD0F2BA8
2 changed files with 1582 additions and 1582 deletions

View File

@ -1,357 +1,357 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Net; using System.Net;
using System.Reflection; using System.Reflection;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Threading; using System.Windows.Threading;
using Microsoft.Win32; using Microsoft.Win32;
using Bloxstrap.Extensions; using Bloxstrap.Extensions;
using Bloxstrap.Models; using Bloxstrap.Models;
using Bloxstrap.UI.BootstrapperDialogs; using Bloxstrap.UI.BootstrapperDialogs;
using Bloxstrap.UI.Menu.Views; using Bloxstrap.UI.Menu.Views;
using Bloxstrap.Utility; using Bloxstrap.Utility;
namespace Bloxstrap namespace Bloxstrap
{ {
/// <summary> /// <summary>
/// Interaction logic for App.xaml /// Interaction logic for App.xaml
/// </summary> /// </summary>
public partial class App : Application public partial class App : Application
{ {
public static readonly CultureInfo CultureFormat = CultureInfo.InvariantCulture; public static readonly CultureInfo CultureFormat = CultureInfo.InvariantCulture;
public const string ProjectName = "Bloxstrap"; public const string ProjectName = "Bloxstrap";
public const string ProjectRepository = "pizzaboxer/bloxstrap"; public const string ProjectRepository = "pizzaboxer/bloxstrap";
public const string RobloxAppName = "RobloxPlayerBeta"; public const string RobloxAppName = "RobloxPlayerBeta";
// used only for communicating between app and menu - use Directories.Base for anything else // used only for communicating between app and menu - use Directories.Base for anything else
public static string BaseDirectory = null!; public static string BaseDirectory = null!;
public static bool ShouldSaveConfigs { get; set; } = false; public static bool ShouldSaveConfigs { get; set; } = false;
public static bool IsSetupComplete { get; set; } = true; public static bool IsSetupComplete { get; set; } = true;
public static bool IsFirstRun { get; private set; } = true; public static bool IsFirstRun { get; private set; } = true;
public static bool IsQuiet { get; private set; } = false; public static bool IsQuiet { get; private set; } = false;
public static bool IsUninstall { get; private set; } = false; public static bool IsUninstall { get; private set; } = false;
public static bool IsNoLaunch { get; private set; } = false; public static bool IsNoLaunch { get; private set; } = false;
public static bool IsUpgrade { get; private set; } = false; public static bool IsUpgrade { get; private set; } = false;
public static bool IsMenuLaunch { get; private set; } = false; public static bool IsMenuLaunch { get; private set; } = false;
public static string[] LaunchArgs { get; private set; } = null!; public static string[] LaunchArgs { get; private set; } = null!;
public static string Version = Assembly.GetExecutingAssembly().GetName().Version!.ToString()[..^2]; public static string Version = Assembly.GetExecutingAssembly().GetName().Version!.ToString()[..^2];
// singletons // singletons
public static readonly Logger Logger = new(); public static readonly Logger Logger = new();
public static readonly JsonManager<Settings> Settings = new(); public static readonly JsonManager<Settings> Settings = new();
public static readonly JsonManager<State> State = new(); public static readonly JsonManager<State> State = new();
public static readonly FastFlagManager FastFlags = new(); public static readonly FastFlagManager FastFlags = new();
public static readonly HttpClient HttpClient = new(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.All }); public static readonly HttpClient HttpClient = new(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.All });
public static System.Windows.Forms.NotifyIcon Notification { get; private set; } = null!; public static System.Windows.Forms.NotifyIcon Notification { get; private set; } = null!;
// shorthand // shorthand
public static MessageBoxResult ShowMessageBox(string message, MessageBoxImage icon = MessageBoxImage.None, MessageBoxButton buttons = MessageBoxButton.OK) public static MessageBoxResult ShowMessageBox(string message, MessageBoxImage icon = MessageBoxImage.None, MessageBoxButton buttons = MessageBoxButton.OK)
{ {
if (IsQuiet) if (IsQuiet)
return MessageBoxResult.None; return MessageBoxResult.None;
return MessageBox.Show(message, ProjectName, buttons, icon); return MessageBox.Show(message, ProjectName, buttons, icon);
} }
public static void Terminate(int code = Bootstrapper.ERROR_SUCCESS) public static void Terminate(int code = Bootstrapper.ERROR_SUCCESS)
{ {
Logger.WriteLine($"[App::Terminate] Terminating with exit code {code}"); Logger.WriteLine($"[App::Terminate] Terminating with exit code {code}");
Settings.Save(); Settings.Save();
State.Save(); State.Save();
Notification.Dispose(); Notification.Dispose();
Environment.Exit(code); Environment.Exit(code);
} }
private void InitLog() private void InitLog()
{ {
// if we're running for the first time or uninstalling, log to temp folder // if we're running for the first time or uninstalling, log to temp folder
// else, log to bloxstrap folder // else, log to bloxstrap folder
bool isUsingTempDir = IsFirstRun || IsUninstall; bool isUsingTempDir = IsFirstRun || IsUninstall;
string logdir = isUsingTempDir ? Path.Combine(Directories.LocalAppData, "Temp") : Path.Combine(Directories.Base, "Logs"); string logdir = isUsingTempDir ? Path.Combine(Directories.LocalAppData, "Temp") : Path.Combine(Directories.Base, "Logs");
string timestamp = DateTime.UtcNow.ToString("yyyyMMdd'T'HHmmss'Z'"); string timestamp = DateTime.UtcNow.ToString("yyyyMMdd'T'HHmmss'Z'");
int processId = Process.GetCurrentProcess().Id; int processId = Process.GetCurrentProcess().Id;
Logger.Initialize(Path.Combine(logdir, $"{ProjectName}_{timestamp}_{processId}.log")); Logger.Initialize(Path.Combine(logdir, $"{ProjectName}_{timestamp}_{processId}.log"));
// clean up any logs older than a week // clean up any logs older than a week
if (!isUsingTempDir) if (!isUsingTempDir)
{ {
foreach (FileInfo log in new DirectoryInfo(logdir).GetFiles()) foreach (FileInfo log in new DirectoryInfo(logdir).GetFiles())
{ {
if (log.LastWriteTimeUtc.AddDays(7) > DateTime.UtcNow) if (log.LastWriteTimeUtc.AddDays(7) > DateTime.UtcNow)
continue; continue;
Logger.WriteLine($"[App::InitLog] Cleaning up old log file '{log.Name}'"); Logger.WriteLine($"[App::InitLog] Cleaning up old log file '{log.Name}'");
log.Delete(); log.Delete();
} }
} }
} }
void GlobalExceptionHandler(object sender, DispatcherUnhandledExceptionEventArgs e) void GlobalExceptionHandler(object sender, DispatcherUnhandledExceptionEventArgs e)
{ {
e.Handled = true; e.Handled = true;
Logger.WriteLine("[App::OnStartup] An exception occurred when running the main thread"); Logger.WriteLine("[App::OnStartup] An exception occurred when running the main thread");
Logger.WriteLine($"[App::OnStartup] {e.Exception}"); Logger.WriteLine($"[App::OnStartup] {e.Exception}");
if (!IsQuiet) if (!IsQuiet)
Settings.Prop.BootstrapperStyle.GetNew().ShowError($"{e.Exception.GetType()}: {e.Exception.Message}"); Settings.Prop.BootstrapperStyle.GetNew().ShowError($"{e.Exception.GetType()}: {e.Exception.Message}");
Terminate(Bootstrapper.ERROR_INSTALL_FAILURE); Terminate(Bootstrapper.ERROR_INSTALL_FAILURE);
} }
protected override void OnStartup(StartupEventArgs e) protected override void OnStartup(StartupEventArgs e)
{ {
base.OnStartup(e); base.OnStartup(e);
Logger.WriteLine($"[App::OnStartup] Starting {ProjectName} v{Version}"); Logger.WriteLine($"[App::OnStartup] Starting {ProjectName} v{Version}");
// To customize application configuration such as set high DPI settings or default font, // To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration. // see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize(); ApplicationConfiguration.Initialize();
LaunchArgs = e.Args; LaunchArgs = e.Args;
HttpClient.Timeout = TimeSpan.FromMinutes(5); HttpClient.Timeout = TimeSpan.FromMinutes(5);
HttpClient.DefaultRequestHeaders.Add("User-Agent", ProjectRepository); HttpClient.DefaultRequestHeaders.Add("User-Agent", ProjectRepository);
if (LaunchArgs.Length > 0) if (LaunchArgs.Length > 0)
{ {
if (Array.IndexOf(LaunchArgs, "-preferences") != -1 || Array.IndexOf(LaunchArgs, "-menu") != -1) if (Array.IndexOf(LaunchArgs, "-preferences") != -1 || Array.IndexOf(LaunchArgs, "-menu") != -1)
{ {
Logger.WriteLine("[App::OnStartup] Started with IsMenuLaunch flag"); Logger.WriteLine("[App::OnStartup] Started with IsMenuLaunch flag");
IsMenuLaunch = true; IsMenuLaunch = true;
} }
if (Array.IndexOf(LaunchArgs, "-quiet") != -1) if (Array.IndexOf(LaunchArgs, "-quiet") != -1)
{ {
Logger.WriteLine("[App::OnStartup] Started with IsQuiet flag"); Logger.WriteLine("[App::OnStartup] Started with IsQuiet flag");
IsQuiet = true; IsQuiet = true;
} }
if (Array.IndexOf(LaunchArgs, "-uninstall") != -1) if (Array.IndexOf(LaunchArgs, "-uninstall") != -1)
{ {
Logger.WriteLine("[App::OnStartup] Started with IsUninstall flag"); Logger.WriteLine("[App::OnStartup] Started with IsUninstall flag");
IsUninstall = true; IsUninstall = true;
} }
if (Array.IndexOf(LaunchArgs, "-nolaunch") != -1) if (Array.IndexOf(LaunchArgs, "-nolaunch") != -1)
{ {
Logger.WriteLine("[App::OnStartup] Started with IsNoLaunch flag"); Logger.WriteLine("[App::OnStartup] Started with IsNoLaunch flag");
IsNoLaunch = true; IsNoLaunch = true;
} }
if (Array.IndexOf(LaunchArgs, "-upgrade") != -1) if (Array.IndexOf(LaunchArgs, "-upgrade") != -1)
{ {
Logger.WriteLine("[App::OnStartup] Bloxstrap started with IsUpgrade flag"); Logger.WriteLine("[App::OnStartup] Bloxstrap started with IsUpgrade flag");
IsUpgrade = true; IsUpgrade = true;
} }
} }
// so this needs to be here because winforms moment // so this needs to be here because winforms moment
// onclick events will not fire unless this is defined here in the main thread so uhhhhh // onclick events will not fire unless this is defined here in the main thread so uhhhhh
// we'll show the icon if we're launching roblox since we're likely gonna be showing a // we'll show the icon if we're launching roblox since we're likely gonna be showing a
// bunch of notifications, and always showing it just makes the most sense i guess since it // bunch of notifications, and always showing it just makes the most sense i guess since it
// indicates that bloxstrap is running, even in the background // indicates that bloxstrap is running, even in the background
Notification = new() Notification = new()
{ {
Icon = Bloxstrap.Properties.Resources.IconBloxstrap, Icon = Bloxstrap.Properties.Resources.IconBloxstrap,
Text = ProjectName, Text = ProjectName,
Visible = !IsMenuLaunch Visible = !IsMenuLaunch
}; };
// check if installed // check if installed
using (RegistryKey? registryKey = Registry.CurrentUser.OpenSubKey($@"Software\{ProjectName}")) using (RegistryKey? registryKey = Registry.CurrentUser.OpenSubKey($@"Software\{ProjectName}"))
{ {
string? installLocation = null; string? installLocation = null;
if (registryKey is not null) if (registryKey is not null)
installLocation = (string?)registryKey.GetValue("InstallLocation"); installLocation = (string?)registryKey.GetValue("InstallLocation");
if (registryKey is null || installLocation is null) if (registryKey is null || installLocation is null)
{ {
Logger.WriteLine("[App::OnStartup] Running first-time install"); Logger.WriteLine("[App::OnStartup] Running first-time install");
BaseDirectory = Path.Combine(Directories.LocalAppData, ProjectName); BaseDirectory = Path.Combine(Directories.LocalAppData, ProjectName);
InitLog(); InitLog();
if (!IsQuiet) if (!IsQuiet)
{ {
IsSetupComplete = false; IsSetupComplete = false;
FastFlags.Load(); FastFlags.Load();
new MainWindow().ShowDialog(); new MainWindow().ShowDialog();
} }
} }
else else
{ {
IsFirstRun = false; IsFirstRun = false;
BaseDirectory = installLocation; BaseDirectory = installLocation;
} }
} }
// exit if we don't click the install button on installation // exit if we don't click the install button on installation
if (!IsSetupComplete) if (!IsSetupComplete)
{ {
Logger.WriteLine("[App::OnStartup] Installation cancelled!"); Logger.WriteLine("[App::OnStartup] Installation cancelled!");
Environment.Exit(Bootstrapper.ERROR_INSTALL_USEREXIT); Environment.Exit(Bootstrapper.ERROR_INSTALL_USEREXIT);
} }
Directories.Initialize(BaseDirectory); Directories.Initialize(BaseDirectory);
// we shouldn't save settings on the first run until the first installation is finished, // we shouldn't save settings on the first run until the first installation is finished,
// just in case the user decides to cancel the install // just in case the user decides to cancel the install
if (!IsFirstRun) if (!IsFirstRun)
{ {
InitLog(); InitLog();
Settings.Load(); Settings.Load();
State.Load(); State.Load();
FastFlags.Load(); FastFlags.Load();
} }
#if !DEBUG #if !DEBUG
if (!IsUninstall && !IsFirstRun) if (!IsUninstall && !IsFirstRun)
Updater.CheckInstalledVersion(); Updater.CheckInstalledVersion();
#endif #endif
string commandLine = ""; string commandLine = "";
if (IsMenuLaunch) if (IsMenuLaunch)
{ {
Process? menuProcess = Process.GetProcesses().Where(x => x.MainWindowTitle == $"{ProjectName} Menu").FirstOrDefault(); Process? menuProcess = Process.GetProcesses().Where(x => x.MainWindowTitle == $"{ProjectName} Menu").FirstOrDefault();
if (menuProcess is not null) if (menuProcess is not null)
{ {
IntPtr handle = menuProcess.MainWindowHandle; IntPtr handle = menuProcess.MainWindowHandle;
Logger.WriteLine($"[App::OnStartup] Found an already existing menu window with handle {handle}"); Logger.WriteLine($"[App::OnStartup] Found an already existing menu window with handle {handle}");
NativeMethods.SetForegroundWindow(handle); NativeMethods.SetForegroundWindow(handle);
} }
else else
{ {
if (Process.GetProcessesByName(ProjectName).Length > 1) if (Process.GetProcessesByName(ProjectName).Length > 1)
ShowMessageBox($"{ProjectName} is currently running, likely as a background Roblox process. Please note that not all your changes will immediately apply until you close all currently open Roblox instances.", MessageBoxImage.Information); ShowMessageBox($"{ProjectName} is currently running, likely as a background Roblox process. Please note that not all your changes will immediately apply until you close all currently open Roblox instances.", MessageBoxImage.Information);
new MainWindow().ShowDialog(); new MainWindow().ShowDialog();
} }
} }
else if (LaunchArgs.Length > 0) else if (LaunchArgs.Length > 0)
{ {
if (LaunchArgs[0].StartsWith("roblox-player:")) if (LaunchArgs[0].StartsWith("roblox-player:"))
{ {
commandLine = ProtocolHandler.ParseUri(LaunchArgs[0]); commandLine = ProtocolHandler.ParseUri(LaunchArgs[0]);
} }
else if (LaunchArgs[0].StartsWith("roblox:")) else if (LaunchArgs[0].StartsWith("roblox:"))
{ {
if (Settings.Prop.UseDisableAppPatch) if (Settings.Prop.UseDisableAppPatch)
ShowMessageBox("Roblox was launched via a deeplink, however the desktop app is required for deeplink launching to work. Because you've opted to disable the desktop app, it will temporarily be re-enabled for this launch only.", MessageBoxImage.Information); ShowMessageBox("Roblox was launched via a deeplink, however the desktop app is required for deeplink launching to work. Because you've opted to disable the desktop app, it will temporarily be re-enabled for this launch only.", MessageBoxImage.Information);
commandLine = $"--app --deeplink {LaunchArgs[0]}"; commandLine = $"--app --deeplink {LaunchArgs[0]}";
} }
else else
{ {
commandLine = "--app"; commandLine = "--app";
} }
} }
else else
{ {
commandLine = "--app"; commandLine = "--app";
} }
if (!String.IsNullOrEmpty(commandLine)) if (!String.IsNullOrEmpty(commandLine))
{ {
if (!IsFirstRun) if (!IsFirstRun)
ShouldSaveConfigs = true; ShouldSaveConfigs = true;
// start bootstrapper and show the bootstrapper modal if we're not running silently // start bootstrapper and show the bootstrapper modal if we're not running silently
Logger.WriteLine($"[App::OnStartup] Initializing bootstrapper"); Logger.WriteLine($"[App::OnStartup] Initializing bootstrapper");
Bootstrapper bootstrapper = new(commandLine); Bootstrapper bootstrapper = new(commandLine);
IBootstrapperDialog? dialog = null; IBootstrapperDialog? dialog = null;
if (!IsQuiet) if (!IsQuiet)
{ {
Logger.WriteLine($"[App::OnStartup] Initializing bootstrapper dialog"); Logger.WriteLine($"[App::OnStartup] Initializing bootstrapper dialog");
dialog = Settings.Prop.BootstrapperStyle.GetNew(); dialog = Settings.Prop.BootstrapperStyle.GetNew();
bootstrapper.Dialog = dialog; bootstrapper.Dialog = dialog;
dialog.Bootstrapper = bootstrapper; dialog.Bootstrapper = bootstrapper;
} }
// handle roblox singleton mutex for multi-instance launching // handle roblox singleton mutex for multi-instance launching
// note we're handling it here in the main thread and NOT in the // note we're handling it here in the main thread and NOT in the
// bootstrapper as handling mutexes in async contexts suuuuuucks // bootstrapper as handling mutexes in async contexts suuuuuucks
Mutex? singletonMutex = null; Mutex? singletonMutex = null;
if (Settings.Prop.MultiInstanceLaunching) if (Settings.Prop.MultiInstanceLaunching)
{ {
Logger.WriteLine("[App::OnStartup] Creating singleton mutex"); Logger.WriteLine("[App::OnStartup] Creating singleton mutex");
try try
{ {
Mutex.OpenExisting("ROBLOX_singletonMutex"); Mutex.OpenExisting("ROBLOX_singletonMutex");
Logger.WriteLine("[App::OnStartup] Warning - singleton mutex already exists!"); Logger.WriteLine("[App::OnStartup] Warning - singleton mutex already exists!");
} }
catch catch
{ {
// create the singleton mutex before the game client does // create the singleton mutex before the game client does
singletonMutex = new Mutex(true, "ROBLOX_singletonMutex"); singletonMutex = new Mutex(true, "ROBLOX_singletonMutex");
} }
} }
// there's a bug here that i have yet to fix! // there's a bug here that i have yet to fix!
// sometimes the task just terminates when the bootstrapper hasn't // sometimes the task just terminates when the bootstrapper hasn't
// actually finished, causing the bootstrapper to hang indefinitely // actually finished, causing the bootstrapper to hang indefinitely
// i have no idea how the fuck this happens, but it happens like VERY // i have no idea how the fuck this happens, but it happens like VERY
// rarely so i'm not too concerned by it // rarely so i'm not too concerned by it
// maybe one day ill find out why it happens // maybe one day ill find out why it happens
Task bootstrapperTask = Task.Run(() => bootstrapper.Run()).ContinueWith(t => Task bootstrapperTask = Task.Run(() => bootstrapper.Run()).ContinueWith(t =>
{ {
Logger.WriteLine("[App::OnStartup] Bootstrapper task has finished"); Logger.WriteLine("[App::OnStartup] Bootstrapper task has finished");
if (t.IsFaulted) if (t.IsFaulted)
Logger.WriteLine("[App::OnStartup] An exception occurred when running the bootstrapper"); Logger.WriteLine("[App::OnStartup] An exception occurred when running the bootstrapper");
if (t.Exception is null) if (t.Exception is null)
return; return;
Logger.WriteLine($"[App::OnStartup] {t.Exception}"); Logger.WriteLine($"[App::OnStartup] {t.Exception}");
#if DEBUG #if DEBUG
throw t.Exception; throw t.Exception;
#else #else
var exception = t.Exception.InnerExceptions.Count >= 1 ? t.Exception.InnerExceptions[0] : t.Exception; var exception = t.Exception.InnerExceptions.Count >= 1 ? t.Exception.InnerExceptions[0] : t.Exception;
dialog?.ShowError($"{exception.GetType()}: {exception.Message}"); dialog?.ShowError($"{exception.GetType()}: {exception.Message}");
Terminate(Bootstrapper.ERROR_INSTALL_FAILURE); Terminate(Bootstrapper.ERROR_INSTALL_FAILURE);
#endif #endif
}); });
dialog?.ShowBootstrapper(); dialog?.ShowBootstrapper();
bootstrapperTask.Wait(); bootstrapperTask.Wait();
if (singletonMutex is not null) if (singletonMutex is not null)
{ {
Logger.WriteLine($"[App::OnStartup] We have singleton mutex ownership! Running in background until all Roblox processes are closed"); Logger.WriteLine($"[App::OnStartup] We have singleton mutex ownership! Running in background until all Roblox processes are closed");
// we've got ownership of the roblox singleton mutex! // we've got ownership of the roblox singleton mutex!
// if we stop running, everything will screw up once any more roblox instances launched // if we stop running, everything will screw up once any more roblox instances launched
while (Process.GetProcessesByName("RobloxPlayerBeta").Any()) while (Process.GetProcessesByName("RobloxPlayerBeta").Any())
Thread.Sleep(5000); Thread.Sleep(5000);
} }
} }
Logger.WriteLine($"[App::OnStartup] Successfully reached end of main thread. Terminating..."); Logger.WriteLine($"[App::OnStartup] Successfully reached end of main thread. Terminating...");
Terminate(); Terminate();
} }
} }
} }

File diff suppressed because it is too large Load Diff