Add exception handling for main thread

wdym you're not supposed to just throw everything into a try catch block i have no idea what youre talking about
This commit is contained in:
pizzaboxer 2023-03-12 14:14:10 +00:00
parent 558fc4e983
commit 961d21cff9
6 changed files with 191 additions and 177 deletions

View File

@ -167,139 +167,153 @@ namespace Bloxstrap
Settings.Load();
State.Load();
}
#if !DEBUG
if (!IsUninstall && !IsFirstRun)
Updater.CheckInstalledVersion();
try
{
if (!IsUninstall && !IsFirstRun)
Updater.CheckInstalledVersion();
#endif
string commandLine = "";
string commandLine = "";
if (IsMenuLaunch)
{
Mutex mutex;
try
if (IsMenuLaunch)
{
mutex = Mutex.OpenExisting("Bloxstrap_MenuMutex");
Logger.WriteLine("[App::OnStartup] Bloxstrap_MenuMutex mutex exists, aborting menu launch...");
Terminate();
Mutex mutex;
try
{
mutex = Mutex.OpenExisting("Bloxstrap_MenuMutex");
Logger.WriteLine("[App::OnStartup] Bloxstrap_MenuMutex mutex exists, aborting menu launch...");
Terminate();
}
catch
{
// no mutex exists, continue to opening preferences menu
mutex = new(true, "Bloxstrap_MenuMutex");
}
if (Utilities.GetProcessCount(ProjectName) > 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);
new MainWindow().ShowDialog();
FastFlags.Save();
}
catch
else if (LaunchArgs.Length > 0)
{
// no mutex exists, continue to opening preferences menu
mutex = new(true, "Bloxstrap_MenuMutex");
}
if (Utilities.GetProcessCount(ProjectName) > 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);
new MainWindow().ShowDialog();
App.FastFlags.Save();
}
else if (LaunchArgs.Length > 0)
{
if (LaunchArgs[0].StartsWith("roblox-player:"))
{
commandLine = Protocol.ParseUri(LaunchArgs[0]);
}
else if (LaunchArgs[0].StartsWith("roblox:"))
{
commandLine = $"--app --deeplink {LaunchArgs[0]}";
if (LaunchArgs[0].StartsWith("roblox-player:"))
{
commandLine = Protocol.ParseUri(LaunchArgs[0]);
}
else if (LaunchArgs[0].StartsWith("roblox:"))
{
commandLine = $"--app --deeplink {LaunchArgs[0]}";
}
else
{
commandLine = "--app";
}
}
else
{
commandLine = "--app";
}
}
else
{
commandLine = "--app";
}
if (!String.IsNullOrEmpty(commandLine))
{
if (!IsFirstRun)
ShouldSaveConfigs = true;
DeployManager.SetChannel(Settings.Prop.Channel);
// start bootstrapper and show the bootstrapper modal if we're not running silently
Logger.WriteLine($"[App::OnStartup] Initializing bootstrapper");
Bootstrapper bootstrapper = new(commandLine);
IBootstrapperDialog? dialog = null;
if (!IsQuiet)
if (!String.IsNullOrEmpty(commandLine))
{
Logger.WriteLine($"[App::OnStartup] Initializing bootstrapper dialog");
dialog = Settings.Prop.BootstrapperStyle.GetNew();
bootstrapper.Dialog = dialog;
dialog.Bootstrapper = bootstrapper;
}
if (!IsFirstRun)
ShouldSaveConfigs = true;
// handle roblox singleton mutex for multi-instance launching
// note we're handling it here in the main thread and NOT in the
// bootstrapper as handling mutexes in async contexts suuuuuucks
DeployManager.SetChannel(Settings.Prop.Channel);
Mutex? singletonMutex = null;
// start bootstrapper and show the bootstrapper modal if we're not running silently
Logger.WriteLine($"[App::OnStartup] Initializing bootstrapper");
Bootstrapper bootstrapper = new(commandLine);
IBootstrapperDialog? dialog = null;
if (Settings.Prop.MultiInstanceLaunching)
{
Logger.WriteLine("[App::OnStartup] Creating singleton mutex");
try
if (!IsQuiet)
{
Mutex.OpenExisting("ROBLOX_singletonMutex");
Logger.WriteLine("[App::OnStartup] Warning - singleton mutex already exists!");
Logger.WriteLine($"[App::OnStartup] Initializing bootstrapper dialog");
dialog = Settings.Prop.BootstrapperStyle.GetNew();
bootstrapper.Dialog = dialog;
dialog.Bootstrapper = bootstrapper;
}
catch
// handle roblox singleton mutex for multi-instance launching
// note we're handling it here in the main thread and NOT in the
// bootstrapper as handling mutexes in async contexts suuuuuucks
Mutex? singletonMutex = null;
if (Settings.Prop.MultiInstanceLaunching)
{
// create the singleton mutex before the game client does
singletonMutex = new Mutex(true, "ROBLOX_singletonMutex");
Logger.WriteLine("[App::OnStartup] Creating singleton mutex");
try
{
Mutex.OpenExisting("ROBLOX_singletonMutex");
Logger.WriteLine("[App::OnStartup] Warning - singleton mutex already exists!");
}
catch
{
// create the singleton mutex before the game client does
singletonMutex = new Mutex(true, "ROBLOX_singletonMutex");
}
}
}
// there's a bug here that i have yet to fix!
// sometimes the task just terminates when the bootstrapper hasn't
// actually finished, causing the bootstrapper to hang indefinitely
// i have no idea how the fuck this happens, but it happens like VERY
// rarely so i'm not too concerned by it
// maybe one day ill find out why it happens
Task bootstrapperTask = Task.Run(() => bootstrapper.Run()).ContinueWith(t =>
{
Logger.WriteLine("[App::OnStartup] Bootstrapper task has finished");
// there's a bug here that i have yet to fix!
// sometimes the task just terminates when the bootstrapper hasn't
// actually finished, causing the bootstrapper to hang indefinitely
// i have no idea how the fuck this happens, but it happens like VERY
// rarely so i'm not too concerned by it
// maybe one day ill find out why it happens
Task bootstrapperTask = Task.Run(() => bootstrapper.Run()).ContinueWith(t =>
{
Logger.WriteLine("[App::OnStartup] Bootstrapper task has finished");
if (t.Exception is null)
return;
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");
Logger.WriteLine($"[App::OnStartup] {t.Exception}");
if (t.Exception is null)
return;
Logger.WriteLine($"[App::OnStartup] {t.Exception}");
#if DEBUG
throw t.Exception;
throw t.Exception;
#else
var exception = t.Exception.InnerExceptions.Count >= 1 ? t.Exception.InnerExceptions[0] : t.Exception;
dialog?.ShowError($"{exception.GetType()}: {exception.Message}");
var exception = t.Exception.InnerExceptions.Count >= 1 ? t.Exception.InnerExceptions[0] : t.Exception;
dialog?.ShowError($"{exception.GetType()}: {exception.Message}");
#endif
});
}, TaskScheduler.FromCurrentSynchronizationContext());
dialog?.ShowBootstrapper();
bootstrapperTask.Wait();
dialog?.ShowBootstrapper();
bootstrapperTask.Wait();
if (singletonMutex is not null)
{
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!
// if we stop running, everything will screw up once any more roblox instances launched
while (Utilities.GetProcessCount("RobloxPlayerBeta", false) != 0)
if (singletonMutex is not null)
{
Thread.Sleep(5000);
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!
// if we stop running, everything will screw up once any more roblox instances launched
while (Utilities.GetProcessCount("RobloxPlayerBeta", false) != 0)
{
Thread.Sleep(5000);
}
}
}
#if !DEBUG
}
catch (Exception ex)
{
Logger.WriteLine("[App::OnStartup] An exception occurred when running the main thread");
Logger.WriteLine($"[App::OnStartup] {ex}");
Terminate();
if (!IsQuiet)
Settings.Prop.BootstrapperStyle.GetNew().ShowError($"{ex.GetType()}: {ex.Message}");
}
#endif
Terminate();
}
}
}

View File

@ -14,73 +14,73 @@ namespace Bloxstrap.Helpers
// to delete a fastflag, set the value to null
public Dictionary<string, object?> Changes = new();
// only one missing here is Metal because lol
public static IReadOnlyDictionary<string, string> RenderingModes { get; set; } = new Dictionary<string, string>()
{
{ "Automatic", "" },
{ "Direct3D 11", "FFlagDebugGraphicsPreferD3D11" },
{ "OpenGL", "FFlagDebugGraphicsPreferOpenGL" },
{ "Vulkan", "FFlagDebugGraphicsPreferVulkan" }
};
// only one missing here is Metal because lol
public static IReadOnlyDictionary<string, string> RenderingModes { get; set; } = new Dictionary<string, string>()
{
{ "Automatic", "" },
{ "Direct3D 11", "FFlagDebugGraphicsPreferD3D11" },
{ "OpenGL", "FFlagDebugGraphicsPreferOpenGL" },
{ "Vulkan", "FFlagDebugGraphicsPreferVulkan" }
};
// this returns null if the fflag doesn't exist
// this also returns as a string because deserializing an object doesn't
// deserialize back into the original object type, it instead deserializes
// as a "JsonElement" which is annoying
public string? GetValue(string key)
{
// check if we have an updated change for it pushed first
if (Changes.TryGetValue(key, out object? changedValue))
return changedValue?.ToString();
// this returns null if the fflag doesn't exist
// this also returns as a string because deserializing an object doesn't
// deserialize back into the original object type, it instead deserializes
// as a "JsonElement" which is annoying
public string? GetValue(string key)
{
// check if we have an updated change for it pushed first
if (Changes.TryGetValue(key, out object? changedValue))
return changedValue?.ToString();
if (Prop.TryGetValue(key, out object? value) && value is not null)
return value.ToString();
if (Prop.TryGetValue(key, out object? value) && value is not null)
return value.ToString();
return null;
}
return null;
}
public void SetRenderingMode(string value)
{
foreach (var mode in RenderingModes)
{
if (value != "Automatic")
App.FastFlags.Changes[mode.Value] = null;
}
public void SetRenderingMode(string value)
{
foreach (var mode in RenderingModes)
{
if (value != "Automatic")
App.FastFlags.Changes[mode.Value] = null;
}
if (value != "Automatic")
App.FastFlags.Changes[RenderingModes[value]] = true;
}
if (value != "Automatic")
App.FastFlags.Changes[RenderingModes[value]] = true;
}
public override void Save()
{
App.Logger.WriteLine($"[FastFlagManager::Save] Attempting to save JSON to {FileLocation}...");
public override void Save()
{
App.Logger.WriteLine($"[FastFlagManager::Save] Attempting to save JSON to {FileLocation}...");
if (Changes.Count == 0)
{
App.Logger.WriteLine($"[FastFlagManager::Save] No changes to apply, aborting.");
return;
}
if (Changes.Count == 0)
{
App.Logger.WriteLine($"[FastFlagManager::Save] No changes to apply, aborting.");
return;
}
// reload for any changes made while the menu was open
Load();
// reload for any changes made while the menu was open
Load();
foreach (var change in Changes)
{
if (change.Value is null)
{
App.Logger.WriteLine($"[FastFlagManager::Save] Removing '{change.Key}'");
Prop.Remove(change.Key);
continue;
}
foreach (var change in Changes)
{
if (change.Value is null)
{
App.Logger.WriteLine($"[FastFlagManager::Save] Removing '{change.Key}'");
Prop.Remove(change.Key);
continue;
}
App.Logger.WriteLine($"[FastFlagManager::Save] Setting '{change.Key}' to {change.Value}");
Prop[change.Key] = change.Value;
}
App.Logger.WriteLine($"[FastFlagManager::Save] Setting '{change.Key}' to {change.Value}");
Prop[change.Key] = change.Value;
}
Directory.CreateDirectory(Path.GetDirectoryName(FileLocation)!);
File.WriteAllText(FileLocation, JsonSerializer.Serialize(Prop, new JsonSerializerOptions { WriteIndented = true }));
Directory.CreateDirectory(Path.GetDirectoryName(FileLocation)!);
File.WriteAllText(FileLocation, JsonSerializer.Serialize(Prop, new JsonSerializerOptions { WriteIndented = true }));
App.Logger.WriteLine($"[FastFlagManager::Save] JSON saved!");
}
}
App.Logger.WriteLine($"[FastFlagManager::Save] JSON saved!");
}
}
}

View File

@ -106,9 +106,9 @@ namespace Bloxstrap.Helpers
MessageBoxButton.OK
);
new MainWindow().ShowDialog();
App.Terminate();
}
new MainWindow().ShowDialog();
App.Terminate();
}
}
}
}

View File

@ -6,16 +6,16 @@ using System.Threading.Tasks;
namespace Bloxstrap.Models
{
public class ReShadeShaderConfig
{
// it's assumed that the BaseFolder has a "Textures" folder and a "Shaders" folder
// the files listed in ExcludedFiles are relative to the BaseFolder
public class ReShadeShaderConfig
{
// it's assumed that the BaseFolder has a "Textures" folder and a "Shaders" folder
// the files listed in ExcludedFiles are relative to the BaseFolder
public string Name { get; set; } = null!;
public string DownloadLocation { get; set; } = null!;
public string BaseFolder { get; set; } = "/";
public List<string> ExcludedFiles { get; set; } = new List<string>();
public string Name { get; set; } = null!;
public string DownloadLocation { get; set; } = null!;
public string BaseFolder { get; set; } = "/";
public List<string> ExcludedFiles { get; set; } = new List<string>();
public override string ToString() => Name;
}
public override string ToString() => Name;
}
}

View File

@ -85,9 +85,9 @@ namespace Bloxstrap.ViewModels
ReShadePresetsEnabled = value;
if (value)
App.FastFlags.SetRenderingMode("Direct3D 11");
App.FastFlags.SetRenderingMode("Direct3D 11");
OnPropertyChanged(nameof(ReShadePresetsEnabled));
OnPropertyChanged(nameof(ReShadePresetsEnabled));
}
}

View File

@ -8,11 +8,11 @@ using CommunityToolkit.Mvvm.Input;
namespace Bloxstrap.ViewModels
{
public class ModsViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
public void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
{
public event PropertyChangedEventHandler? PropertyChanged;
public void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
public ICommand OpenModsFolderCommand => new RelayCommand(OpenModsFolder);
public ICommand OpenModsFolderCommand => new RelayCommand(OpenModsFolder);
private void OpenModsFolder()
{
@ -49,9 +49,9 @@ namespace Bloxstrap.ViewModels
if (value)
{
App.FastFlags.SetRenderingMode("Direct3D 11");
OnPropertyChanged(nameof(SelectedRenderingMode));
}
App.FastFlags.SetRenderingMode("Direct3D 11");
OnPropertyChanged(nameof(SelectedRenderingMode));
}
}
}