Skip to content

Commit

Permalink
Merge pull request #1230 from bluepilledgreat/feature/app-cleanup
Browse files Browse the repository at this point in the history
App cleanup
  • Loading branch information
pizzaboxer authored Feb 7, 2024
2 parents 9622a5d + aa1f2cc commit 62ae4c3
Show file tree
Hide file tree
Showing 7 changed files with 318 additions and 176 deletions.
241 changes: 74 additions & 167 deletions Bloxstrap/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,7 @@ public partial class App : Application
public static bool IsSetupComplete { get; set; } = true;
public static bool IsFirstRun { get; set; } = true;

public static bool IsQuiet { get; private set; } = false;
public static bool IsUninstall { get; private set; } = false;
public static bool IsNoLaunch { get; private set; } = false;
public static bool IsUpgrade { get; private set; } = false;
public static bool IsMenuLaunch { get; private set; } = false;
public static string[] LaunchArgs { get; private set; } = null!;
public static LaunchSettings LaunchSettings { get; private set; } = null!;

public static BuildMetadataAttribute BuildMetadata = Assembly.GetExecutingAssembly().GetCustomAttribute<BuildMetadataAttribute>()!;
public static string Version = Assembly.GetExecutingAssembly().GetName().Version!.ToString()[..^2];
Expand Down Expand Up @@ -96,13 +91,22 @@ public static void FinalizeExceptionHandling(Exception exception, bool log = tru

_showingExceptionDialog = true;

if (!IsQuiet)
if (!LaunchSettings.IsQuiet)
Frontend.ShowExceptionDialog(exception);

Terminate(ErrorCode.ERROR_INSTALL_FAILURE);
#endif
}

private void StartupFinished()
{
const string LOG_IDENT = "App::StartupFinished";

Logger.WriteLine(LOG_IDENT, "Successfully reached end of main thread. Terminating...");

Terminate();
}

protected override void OnStartup(StartupEventArgs e)
{
const string LOG_IDENT = "App::OnStartup";
Expand All @@ -122,47 +126,10 @@ protected override void OnStartup(StartupEventArgs e)
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();

LaunchArgs = e.Args;

#if DEBUG
Logger.WriteLine(LOG_IDENT, $"Arguments: {string.Join(' ', LaunchArgs)}");
#endif
LaunchSettings = new LaunchSettings(e.Args);

HttpClient.Timeout = TimeSpan.FromSeconds(30);
HttpClient.DefaultRequestHeaders.Add("User-Agent", ProjectRepository);

if (LaunchArgs.Length > 0)
{
if (Array.IndexOf(LaunchArgs, "-preferences") != -1 || Array.IndexOf(LaunchArgs, "-menu") != -1)
{
Logger.WriteLine(LOG_IDENT, "Started with IsMenuLaunch flag");
IsMenuLaunch = true;
}

if (Array.IndexOf(LaunchArgs, "-quiet") != -1)
{
Logger.WriteLine(LOG_IDENT, "Started with IsQuiet flag");
IsQuiet = true;
}

if (Array.IndexOf(LaunchArgs, "-uninstall") != -1)
{
Logger.WriteLine(LOG_IDENT, "Started with IsUninstall flag");
IsUninstall = true;
}

if (Array.IndexOf(LaunchArgs, "-nolaunch") != -1)
{
Logger.WriteLine(LOG_IDENT, "Started with IsNoLaunch flag");
IsNoLaunch = true;
}

if (Array.IndexOf(LaunchArgs, "-upgrade") != -1)
{
Logger.WriteLine(LOG_IDENT, "Bloxstrap started with IsUpgrade flag");
IsUpgrade = true;
}
}

using (var checker = new InstallChecker())
{
Expand All @@ -175,7 +142,7 @@ protected override void OnStartup(StartupEventArgs e)
// just in case the user decides to cancel the install
if (!IsFirstRun)
{
Logger.Initialize(IsUninstall);
Logger.Initialize(LaunchSettings.IsUninstall);

if (!Logger.Initialized)
{
Expand All @@ -188,18 +155,15 @@ protected override void OnStartup(StartupEventArgs e)
FastFlags.Load();
}

if (!IsUninstall && !IsMenuLaunch)
if (!LaunchSettings.IsUninstall && !LaunchSettings.IsMenuLaunch)
NotifyIcon = new();

#if !DEBUG
if (!IsUninstall && !IsFirstRun)
if (!LaunchSettings.IsUninstall && !IsFirstRun)
InstallChecker.CheckUpgrade();
#endif

string commandLine = "";
LaunchMode? launchMode = null;

if (IsMenuLaunch)
if (LaunchSettings.IsMenuLaunch)
{
Process? menuProcess = Process.GetProcesses().Where(x => x.MainWindowTitle == $"{ProjectName} Menu").FirstOrDefault();

Expand All @@ -211,160 +175,103 @@ protected override void OnStartup(StartupEventArgs e)
}
else
{
if (Process.GetProcessesByName(ProjectName).Length > 1 && !IsQuiet)
if (Process.GetProcessesByName(ProjectName).Length > 1 && !LaunchSettings.IsQuiet)
Frontend.ShowMessageBox(
Bloxstrap.Resources.Strings.Menu_AlreadyRunning,
MessageBoxImage.Information
);

Frontend.ShowMenu();
}
}
else if (LaunchArgs.Length > 0)
{
if (LaunchArgs[0].StartsWith("roblox-player:"))
{
commandLine = ProtocolHandler.ParseUri(LaunchArgs[0]);

launchMode = LaunchMode.Player;
}
else if (LaunchArgs[0].StartsWith("roblox:"))
{
if (Settings.Prop.UseDisableAppPatch)
Frontend.ShowMessageBox(
Bloxstrap.Resources.Strings.Bootstrapper_DeeplinkTempEnabled,
MessageBoxImage.Information
);

commandLine = $"--app --deeplink {LaunchArgs[0]}";
StartupFinished();
return;
}

launchMode = LaunchMode.Player;
}
else if (LaunchArgs[0].StartsWith("roblox-studio:"))
{
commandLine = ProtocolHandler.ParseUri(LaunchArgs[0]);
if (!IsFirstRun)
ShouldSaveConfigs = true;

if (!commandLine.Contains("-startEvent"))
commandLine += " -startEvent www.roblox.com/robloxQTStudioStartedEvent";
// start bootstrapper and show the bootstrapper modal if we're not running silently
Logger.WriteLine(LOG_IDENT, "Initializing bootstrapper");
Bootstrapper bootstrapper = new(LaunchSettings.RobloxLaunchArgs, LaunchSettings.RobloxLaunchMode);
IBootstrapperDialog? dialog = null;

launchMode = LaunchMode.Studio;
}
else if (LaunchArgs[0].StartsWith("roblox-studio-auth:"))
{
commandLine = HttpUtility.UrlDecode(LaunchArgs[0]);
if (!LaunchSettings.IsQuiet)
{
Logger.WriteLine(LOG_IDENT, "Initializing bootstrapper dialog");
dialog = Settings.Prop.BootstrapperStyle.GetNew();
bootstrapper.Dialog = dialog;
dialog.Bootstrapper = bootstrapper;
}

launchMode = LaunchMode.StudioAuth;
}
else if (LaunchArgs[0] == "-ide")
{
launchMode = LaunchMode.Studio;
// 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

if (LaunchArgs.Length >= 2)
commandLine = $"-task EditFile -localPlaceFile \"{LaunchArgs[1]}\"";
}
else
{
commandLine = "--app";
Mutex? singletonMutex = null;

launchMode = LaunchMode.Player;
}
}
else
if (Settings.Prop.MultiInstanceLaunching && LaunchSettings.RobloxLaunchMode == LaunchMode.Player)
{
commandLine = "--app";
Logger.WriteLine(LOG_IDENT, "Creating singleton mutex");

launchMode = LaunchMode.Player;
}

if (launchMode != null)
{
if (!IsFirstRun)
ShouldSaveConfigs = true;

// start bootstrapper and show the bootstrapper modal if we're not running silently
Logger.WriteLine(LOG_IDENT, "Initializing bootstrapper");
Bootstrapper bootstrapper = new(commandLine, (LaunchMode)launchMode);
IBootstrapperDialog? dialog = null;

if (!IsQuiet)
try
{
Logger.WriteLine(LOG_IDENT, "Initializing bootstrapper dialog");
dialog = Settings.Prop.BootstrapperStyle.GetNew();
bootstrapper.Dialog = dialog;
dialog.Bootstrapper = bootstrapper;
Mutex.OpenExisting("ROBLOX_singletonMutex");
Logger.WriteLine(LOG_IDENT, "Warning - singleton mutex already exists!");
}

// 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 && launchMode == LaunchMode.Player)
catch
{
Logger.WriteLine(LOG_IDENT, "Creating singleton mutex");

try
{
Mutex.OpenExisting("ROBLOX_singletonMutex");
Logger.WriteLine(LOG_IDENT, "Warning - singleton mutex already exists!");
}
catch
{
// create the singleton mutex before the game client does
singletonMutex = new Mutex(true, "ROBLOX_singletonMutex");
}
// create the singleton mutex before the game client does
singletonMutex = new Mutex(true, "ROBLOX_singletonMutex");
}
}

Task bootstrapperTask = Task.Run(async () => await bootstrapper.Run()).ContinueWith(t =>
{
Logger.WriteLine(LOG_IDENT, "Bootstrapper task has finished");
Task bootstrapperTask = Task.Run(async () => await bootstrapper.Run()).ContinueWith(t =>
{
Logger.WriteLine(LOG_IDENT, "Bootstrapper task has finished");

// notifyicon is blocking main thread, must be disposed here
NotifyIcon?.Dispose();
// notifyicon is blocking main thread, must be disposed here
NotifyIcon?.Dispose();

if (t.IsFaulted)
Logger.WriteLine(LOG_IDENT, "An exception occurred when running the bootstrapper");
if (t.IsFaulted)
Logger.WriteLine(LOG_IDENT, "An exception occurred when running the bootstrapper");

if (t.Exception is null)
return;
if (t.Exception is null)
return;

Logger.WriteException(LOG_IDENT, t.Exception);
Logger.WriteException(LOG_IDENT, t.Exception);

Exception exception = t.Exception;
Exception exception = t.Exception;

#if !DEBUG
if (t.Exception.GetType().ToString() == "System.AggregateException")
if (t.Exception.GetType().ToString() == "System.AggregateException")
exception = t.Exception.InnerException!;
#endif

FinalizeExceptionHandling(exception, false);
});
FinalizeExceptionHandling(exception, false);
});

// this ordering is very important as all wpf windows are shown as modal dialogs, mess it up and you'll end up blocking input to one of them
dialog?.ShowBootstrapper();
// this ordering is very important as all wpf windows are shown as modal dialogs, mess it up and you'll end up blocking input to one of them
dialog?.ShowBootstrapper();

if (!IsNoLaunch && Settings.Prop.EnableActivityTracking)
NotifyIcon?.InitializeContextMenu();
if (!LaunchSettings.IsNoLaunch && Settings.Prop.EnableActivityTracking)
NotifyIcon?.InitializeContextMenu();

Logger.WriteLine(LOG_IDENT, "Waiting for bootstrapper task to finish");
Logger.WriteLine(LOG_IDENT, "Waiting for bootstrapper task to finish");

bootstrapperTask.Wait();
bootstrapperTask.Wait();

if (singletonMutex is not null)
{
Logger.WriteLine(LOG_IDENT, "We have singleton mutex ownership! Running in background until all Roblox processes are closed");
if (singletonMutex is not null)
{
Logger.WriteLine(LOG_IDENT, "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 (Process.GetProcessesByName("RobloxPlayerBeta").Any())
Thread.Sleep(5000);
}
// we've got ownership of the roblox singleton mutex!
// if we stop running, everything will screw up once any more roblox instances launched
while (Process.GetProcessesByName("RobloxPlayerBeta").Any())
Thread.Sleep(5000);
}

Logger.WriteLine(LOG_IDENT, "Successfully reached end of main thread. Terminating...");

Terminate();
StartupFinished();
}
}
}
10 changes: 5 additions & 5 deletions Bloxstrap/Bootstrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public async Task Run()

App.Logger.WriteLine(LOG_IDENT, "Running bootstrapper");

if (App.IsUninstall)
if (App.LaunchSettings.IsUninstall)
{
Uninstall();
return;
Expand Down Expand Up @@ -226,9 +226,9 @@ public async Task Run()

await mutex.ReleaseAsync();

if (App.IsFirstRun && App.IsNoLaunch)
if (App.IsFirstRun && App.LaunchSettings.IsNoLaunch)
Dialog?.ShowSuccess(Resources.Strings.Bootstrapper_SuccessfullyInstalled);
else if (!App.IsNoLaunch && !_cancelFired)
else if (!App.LaunchSettings.IsNoLaunch && !_cancelFired)
await StartRoblox();
}

Expand Down Expand Up @@ -302,7 +302,7 @@ private async Task StartRoblox()
MessageBoxImage.Error
);

if (!App.IsQuiet)
if (!App.LaunchSettings.IsQuiet)
Utilities.ShellExecute("https://support.microsoft.com/en-us/topic/media-feature-pack-list-for-windows-n-editions-c1c6fffa-d052-8338-7a79-a4bb980a700a");

Dialog?.CloseBootstrapper();
Expand Down Expand Up @@ -655,7 +655,7 @@ private async Task CheckForUpdates()
FileName = downloadLocation,
};

foreach (string arg in App.LaunchArgs)
foreach (string arg in App.LaunchSettings.Args)
startInfo.ArgumentList.Add(arg);

App.Settings.Save();
Expand Down
Loading

0 comments on commit 62ae4c3

Please sign in to comment.