mirror of
https://github.com/bloxstraplabs/bloxstrap.git
synced 2025-04-21 10:01:27 -07:00
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:
parent
558fc4e983
commit
961d21cff9
@ -167,139 +167,153 @@ namespace Bloxstrap
|
|||||||
Settings.Load();
|
Settings.Load();
|
||||||
State.Load();
|
State.Load();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
if (!IsUninstall && !IsFirstRun)
|
try
|
||||||
Updater.CheckInstalledVersion();
|
{
|
||||||
|
if (!IsUninstall && !IsFirstRun)
|
||||||
|
Updater.CheckInstalledVersion();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
string commandLine = "";
|
string commandLine = "";
|
||||||
|
|
||||||
if (IsMenuLaunch)
|
if (IsMenuLaunch)
|
||||||
{
|
|
||||||
Mutex mutex;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
mutex = Mutex.OpenExisting("Bloxstrap_MenuMutex");
|
Mutex mutex;
|
||||||
Logger.WriteLine("[App::OnStartup] Bloxstrap_MenuMutex mutex exists, aborting menu launch...");
|
|
||||||
Terminate();
|
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
|
if (LaunchArgs[0].StartsWith("roblox-player:"))
|
||||||
mutex = new(true, "Bloxstrap_MenuMutex");
|
{
|
||||||
}
|
commandLine = Protocol.ParseUri(LaunchArgs[0]);
|
||||||
|
}
|
||||||
if (Utilities.GetProcessCount(ProjectName) > 1)
|
else if (LaunchArgs[0].StartsWith("roblox:"))
|
||||||
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);
|
{
|
||||||
|
commandLine = $"--app --deeplink {LaunchArgs[0]}";
|
||||||
new MainWindow().ShowDialog();
|
}
|
||||||
App.FastFlags.Save();
|
else
|
||||||
}
|
{
|
||||||
else if (LaunchArgs.Length > 0)
|
commandLine = "--app";
|
||||||
{
|
}
|
||||||
if (LaunchArgs[0].StartsWith("roblox-player:"))
|
|
||||||
{
|
|
||||||
commandLine = Protocol.ParseUri(LaunchArgs[0]);
|
|
||||||
}
|
|
||||||
else if (LaunchArgs[0].StartsWith("roblox:"))
|
|
||||||
{
|
|
||||||
commandLine = $"--app --deeplink {LaunchArgs[0]}";
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
commandLine = "--app";
|
commandLine = "--app";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
commandLine = "--app";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!String.IsNullOrEmpty(commandLine))
|
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)
|
|
||||||
{
|
{
|
||||||
Logger.WriteLine($"[App::OnStartup] Initializing bootstrapper dialog");
|
if (!IsFirstRun)
|
||||||
dialog = Settings.Prop.BootstrapperStyle.GetNew();
|
ShouldSaveConfigs = true;
|
||||||
bootstrapper.Dialog = dialog;
|
|
||||||
dialog.Bootstrapper = bootstrapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle roblox singleton mutex for multi-instance launching
|
DeployManager.SetChannel(Settings.Prop.Channel);
|
||||||
// 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;
|
// 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)
|
if (!IsQuiet)
|
||||||
{
|
|
||||||
Logger.WriteLine("[App::OnStartup] Creating singleton mutex");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
Mutex.OpenExisting("ROBLOX_singletonMutex");
|
Logger.WriteLine($"[App::OnStartup] Initializing bootstrapper dialog");
|
||||||
Logger.WriteLine("[App::OnStartup] Warning - singleton mutex already exists!");
|
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
|
Logger.WriteLine("[App::OnStartup] Creating singleton mutex");
|
||||||
singletonMutex = new Mutex(true, "ROBLOX_singletonMutex");
|
|
||||||
|
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!
|
// 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.Exception is null)
|
if (t.IsFaulted)
|
||||||
return;
|
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)
|
||||||
Logger.WriteLine($"[App::OnStartup] {t.Exception}");
|
return;
|
||||||
|
|
||||||
|
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}");
|
||||||
#endif
|
#endif
|
||||||
});
|
}, TaskScheduler.FromCurrentSynchronizationContext());
|
||||||
|
|
||||||
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");
|
|
||||||
|
|
||||||
// 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);
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,73 +14,73 @@ namespace Bloxstrap.Helpers
|
|||||||
// to delete a fastflag, set the value to null
|
// to delete a fastflag, set the value to null
|
||||||
public Dictionary<string, object?> Changes = new();
|
public Dictionary<string, object?> Changes = new();
|
||||||
|
|
||||||
// only one missing here is Metal because lol
|
// only one missing here is Metal because lol
|
||||||
public static IReadOnlyDictionary<string, string> RenderingModes { get; set; } = new Dictionary<string, string>()
|
public static IReadOnlyDictionary<string, string> RenderingModes { get; set; } = new Dictionary<string, string>()
|
||||||
{
|
{
|
||||||
{ "Automatic", "" },
|
{ "Automatic", "" },
|
||||||
{ "Direct3D 11", "FFlagDebugGraphicsPreferD3D11" },
|
{ "Direct3D 11", "FFlagDebugGraphicsPreferD3D11" },
|
||||||
{ "OpenGL", "FFlagDebugGraphicsPreferOpenGL" },
|
{ "OpenGL", "FFlagDebugGraphicsPreferOpenGL" },
|
||||||
{ "Vulkan", "FFlagDebugGraphicsPreferVulkan" }
|
{ "Vulkan", "FFlagDebugGraphicsPreferVulkan" }
|
||||||
};
|
};
|
||||||
|
|
||||||
// this returns null if the fflag doesn't exist
|
// this returns null if the fflag doesn't exist
|
||||||
// this also returns as a string because deserializing an object doesn't
|
// this also returns as a string because deserializing an object doesn't
|
||||||
// deserialize back into the original object type, it instead deserializes
|
// deserialize back into the original object type, it instead deserializes
|
||||||
// as a "JsonElement" which is annoying
|
// as a "JsonElement" which is annoying
|
||||||
public string? GetValue(string key)
|
public string? GetValue(string key)
|
||||||
{
|
{
|
||||||
// check if we have an updated change for it pushed first
|
// check if we have an updated change for it pushed first
|
||||||
if (Changes.TryGetValue(key, out object? changedValue))
|
if (Changes.TryGetValue(key, out object? changedValue))
|
||||||
return changedValue?.ToString();
|
return changedValue?.ToString();
|
||||||
|
|
||||||
if (Prop.TryGetValue(key, out object? value) && value is not null)
|
if (Prop.TryGetValue(key, out object? value) && value is not null)
|
||||||
return value.ToString();
|
return value.ToString();
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetRenderingMode(string value)
|
public void SetRenderingMode(string value)
|
||||||
{
|
{
|
||||||
foreach (var mode in RenderingModes)
|
foreach (var mode in RenderingModes)
|
||||||
{
|
{
|
||||||
if (value != "Automatic")
|
if (value != "Automatic")
|
||||||
App.FastFlags.Changes[mode.Value] = null;
|
App.FastFlags.Changes[mode.Value] = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value != "Automatic")
|
if (value != "Automatic")
|
||||||
App.FastFlags.Changes[RenderingModes[value]] = true;
|
App.FastFlags.Changes[RenderingModes[value]] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Save()
|
public override void Save()
|
||||||
{
|
{
|
||||||
App.Logger.WriteLine($"[FastFlagManager::Save] Attempting to save JSON to {FileLocation}...");
|
App.Logger.WriteLine($"[FastFlagManager::Save] Attempting to save JSON to {FileLocation}...");
|
||||||
|
|
||||||
if (Changes.Count == 0)
|
if (Changes.Count == 0)
|
||||||
{
|
{
|
||||||
App.Logger.WriteLine($"[FastFlagManager::Save] No changes to apply, aborting.");
|
App.Logger.WriteLine($"[FastFlagManager::Save] No changes to apply, aborting.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// reload for any changes made while the menu was open
|
// reload for any changes made while the menu was open
|
||||||
Load();
|
Load();
|
||||||
|
|
||||||
foreach (var change in Changes)
|
foreach (var change in Changes)
|
||||||
{
|
{
|
||||||
if (change.Value is null)
|
if (change.Value is null)
|
||||||
{
|
{
|
||||||
App.Logger.WriteLine($"[FastFlagManager::Save] Removing '{change.Key}'");
|
App.Logger.WriteLine($"[FastFlagManager::Save] Removing '{change.Key}'");
|
||||||
Prop.Remove(change.Key);
|
Prop.Remove(change.Key);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
App.Logger.WriteLine($"[FastFlagManager::Save] Setting '{change.Key}' to {change.Value}");
|
App.Logger.WriteLine($"[FastFlagManager::Save] Setting '{change.Key}' to {change.Value}");
|
||||||
Prop[change.Key] = change.Value;
|
Prop[change.Key] = change.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(FileLocation)!);
|
Directory.CreateDirectory(Path.GetDirectoryName(FileLocation)!);
|
||||||
File.WriteAllText(FileLocation, JsonSerializer.Serialize(Prop, new JsonSerializerOptions { WriteIndented = true }));
|
File.WriteAllText(FileLocation, JsonSerializer.Serialize(Prop, new JsonSerializerOptions { WriteIndented = true }));
|
||||||
|
|
||||||
App.Logger.WriteLine($"[FastFlagManager::Save] JSON saved!");
|
App.Logger.WriteLine($"[FastFlagManager::Save] JSON saved!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,9 +106,9 @@ namespace Bloxstrap.Helpers
|
|||||||
MessageBoxButton.OK
|
MessageBoxButton.OK
|
||||||
);
|
);
|
||||||
|
|
||||||
new MainWindow().ShowDialog();
|
new MainWindow().ShowDialog();
|
||||||
App.Terminate();
|
App.Terminate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,16 +6,16 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Bloxstrap.Models
|
namespace Bloxstrap.Models
|
||||||
{
|
{
|
||||||
public class ReShadeShaderConfig
|
public class ReShadeShaderConfig
|
||||||
{
|
{
|
||||||
// it's assumed that the BaseFolder has a "Textures" folder and a "Shaders" folder
|
// it's assumed that the BaseFolder has a "Textures" folder and a "Shaders" folder
|
||||||
// the files listed in ExcludedFiles are relative to the BaseFolder
|
// the files listed in ExcludedFiles are relative to the BaseFolder
|
||||||
|
|
||||||
public string Name { get; set; } = null!;
|
public string Name { get; set; } = null!;
|
||||||
public string DownloadLocation { get; set; } = null!;
|
public string DownloadLocation { get; set; } = null!;
|
||||||
public string BaseFolder { get; set; } = "/";
|
public string BaseFolder { get; set; } = "/";
|
||||||
public List<string> ExcludedFiles { get; set; } = new List<string>();
|
public List<string> ExcludedFiles { get; set; } = new List<string>();
|
||||||
|
|
||||||
public override string ToString() => Name;
|
public override string ToString() => Name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,9 +85,9 @@ namespace Bloxstrap.ViewModels
|
|||||||
ReShadePresetsEnabled = value;
|
ReShadePresetsEnabled = value;
|
||||||
|
|
||||||
if (value)
|
if (value)
|
||||||
App.FastFlags.SetRenderingMode("Direct3D 11");
|
App.FastFlags.SetRenderingMode("Direct3D 11");
|
||||||
|
|
||||||
OnPropertyChanged(nameof(ReShadePresetsEnabled));
|
OnPropertyChanged(nameof(ReShadePresetsEnabled));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,11 +8,11 @@ using CommunityToolkit.Mvvm.Input;
|
|||||||
namespace Bloxstrap.ViewModels
|
namespace Bloxstrap.ViewModels
|
||||||
{
|
{
|
||||||
public class ModsViewModel : INotifyPropertyChanged
|
public class ModsViewModel : INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
public event PropertyChangedEventHandler? PropertyChanged;
|
public event PropertyChangedEventHandler? PropertyChanged;
|
||||||
public void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
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()
|
private void OpenModsFolder()
|
||||||
{
|
{
|
||||||
@ -49,9 +49,9 @@ namespace Bloxstrap.ViewModels
|
|||||||
|
|
||||||
if (value)
|
if (value)
|
||||||
{
|
{
|
||||||
App.FastFlags.SetRenderingMode("Direct3D 11");
|
App.FastFlags.SetRenderingMode("Direct3D 11");
|
||||||
OnPropertyChanged(nameof(SelectedRenderingMode));
|
OnPropertyChanged(nameof(SelectedRenderingMode));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user