diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index e33b473..12955a3 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -38,9 +38,9 @@ namespace Bloxstrap private readonly CancellationTokenSource _cancelTokenSource = new(); private readonly IAppData AppData; + private readonly LaunchMode _launchMode; private string _launchCommandLine = App.LaunchSettings.RobloxLaunchArgs; - private LaunchMode _launchMode = App.LaunchSettings.RobloxLaunchMode; private string _latestVersionGuid = null!; private PackageManifest _versionPackageManifest = null!; @@ -59,8 +59,10 @@ namespace Bloxstrap #endregion #region Core - public Bootstrapper() + public Bootstrapper(LaunchMode launchMode) { + _launchMode = launchMode; + // this is now always enabled as of v2.8.0 if (Dialog is not null) Dialog.CancelEnabled = true; @@ -382,18 +384,23 @@ namespace Bloxstrap autoclosePids.Add(pid); } - string args = _appPid.ToString(); + string argPids = _appPid.ToString(); if (autoclosePids.Any()) - args += $";{String.Join(',', autoclosePids)}"; + argPids += $";{String.Join(',', autoclosePids)}"; - if (App.Settings.Prop.EnableActivityTracking || autoclosePids.Any()) + if (App.Settings.Prop.EnableActivityTracking || App.LaunchSettings.TestModeFlag.Active || autoclosePids.Any()) { using var ipl = new InterProcessLock("Watcher", TimeSpan.FromSeconds(5)); + string args = $"-watcher \"{argPids}\""; + + if (App.LaunchSettings.TestModeFlag.Active) + args += " -testmode"; + // TODO: look into if this needs to be launched *before* roblox starts if (ipl.IsAcquired) - Process.Start(Paths.Process, $"-watcher \"{args}\""); + Process.Start(Paths.Process, args); } } diff --git a/Bloxstrap/LaunchHandler.cs b/Bloxstrap/LaunchHandler.cs index 891a7ed..090bd03 100644 --- a/Bloxstrap/LaunchHandler.cs +++ b/Bloxstrap/LaunchHandler.cs @@ -18,8 +18,7 @@ namespace Bloxstrap break; case NextAction.LaunchRoblox: - App.LaunchSettings.RobloxLaunchMode = LaunchMode.Player; - LaunchRoblox(); + LaunchRoblox(LaunchMode.Player); break; default: @@ -39,7 +38,7 @@ namespace Bloxstrap else if (App.LaunchSettings.WatcherFlag.Active) LaunchWatcher(); else if (App.LaunchSettings.RobloxLaunchMode != LaunchMode.None) - LaunchRoblox(); + LaunchRoblox(App.LaunchSettings.RobloxLaunchMode); else if (!App.LaunchSettings.QuietFlag.Active) LaunchMenu(); else @@ -163,10 +162,13 @@ namespace Bloxstrap ProcessNextAction(dialog.CloseAction); } - public static void LaunchRoblox() + public static void LaunchRoblox(LaunchMode launchMode) { const string LOG_IDENT = "LaunchHandler::LaunchRoblox"; + if (launchMode == LaunchMode.None) + throw new InvalidOperationException("No Roblox launch mode set"); + if (!File.Exists(Path.Combine(Paths.System, "mfplat.dll"))) { Frontend.ShowMessageBox(Strings.Bootstrapper_WMFNotFound, MessageBoxImage.Error); @@ -194,7 +196,7 @@ namespace Bloxstrap // start bootstrapper and show the bootstrapper modal if we're not running silently App.Logger.WriteLine(LOG_IDENT, "Initializing bootstrapper"); - var bootstrapper = new Bootstrapper(); + var bootstrapper = new Bootstrapper(launchMode); IBootstrapperDialog? dialog = null; if (!App.LaunchSettings.QuietFlag.Active) diff --git a/Bloxstrap/LaunchSettings.cs b/Bloxstrap/LaunchSettings.cs index 4bd10b1..4250dab 100644 --- a/Bloxstrap/LaunchSettings.cs +++ b/Bloxstrap/LaunchSettings.cs @@ -21,6 +21,8 @@ namespace Bloxstrap public LaunchFlag UninstallFlag { get; } = new("uninstall"); public LaunchFlag NoLaunchFlag { get; } = new("nolaunch"); + + public LaunchFlag TestModeFlag { get; } = new("testmode"); public LaunchFlag NoGPUFlag { get; } = new("nogpu"); diff --git a/Bloxstrap/Resources/Strings.Designer.cs b/Bloxstrap/Resources/Strings.Designer.cs index 1d32a87..1c5b5d4 100644 --- a/Bloxstrap/Resources/Strings.Designer.cs +++ b/Bloxstrap/Resources/Strings.Designer.cs @@ -3241,6 +3241,28 @@ namespace Bloxstrap.Resources { } } + /// + /// Looks up a localized string similar to Test mode. + /// + public static string Menu_TestMode { + get { + return ResourceManager.GetString("Menu.TestMode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Test mode makes it easier to iteratively test how your settings affect Roblox. + /// + ///While enabled, it will automatically launch Roblox after closing Settings, and reopen Settings after closing Roblox, in a cycle until you disable it. + /// + ///Would you like to enable test mode?. + /// + public static string Menu_TestMode_Prompt { + get { + return ResourceManager.GetString("Menu.TestMode.Prompt", resourceCulture); + } + } + /// /// Looks up a localized string similar to Bloxstrap Settings. /// diff --git a/Bloxstrap/Resources/Strings.resx b/Bloxstrap/Resources/Strings.resx index e7be39f..4043b82 100644 --- a/Bloxstrap/Resources/Strings.resx +++ b/Bloxstrap/Resources/Strings.resx @@ -1237,4 +1237,14 @@ Please manually delete Bloxstrap.exe from the install location or try restarting Report exception + + Test mode + + + Test mode makes it easier to iteratively test how your settings affect Roblox. + +While enabled, it will automatically launch Roblox after closing Settings, and reopen Settings after closing Roblox, in a cycle until you disable it. + +Would you like to enable test mode? + \ No newline at end of file diff --git a/Bloxstrap/UI/Elements/About/Pages/AboutPage.xaml b/Bloxstrap/UI/Elements/About/Pages/AboutPage.xaml index 1b57bab..23e8d5e 100644 --- a/Bloxstrap/UI/Elements/About/Pages/AboutPage.xaml +++ b/Bloxstrap/UI/Elements/About/Pages/AboutPage.xaml @@ -10,9 +10,9 @@ xmlns:resources="clr-namespace:Bloxstrap.Resources" mc:Ignorable="d" d:DesignHeight="1500" d:DesignWidth="800" + d:DataContext="{d:DesignInstance dmodels:AboutViewModel, IsDesignTimeCreatable=True}" Title="AboutPage" Scrollable="True"> - @@ -126,6 +126,7 @@ + diff --git a/Bloxstrap/UI/Elements/ContextMenu/MenuContainer.xaml.cs b/Bloxstrap/UI/Elements/ContextMenu/MenuContainer.xaml.cs index d55c3dd..bf94311 100644 --- a/Bloxstrap/UI/Elements/ContextMenu/MenuContainer.xaml.cs +++ b/Bloxstrap/UI/Elements/ContextMenu/MenuContainer.xaml.cs @@ -36,14 +36,14 @@ namespace Bloxstrap.UI.Elements.ContextMenu _activityWatcher.OnLogOpen += ActivityWatcher_OnLogOpen; _activityWatcher.OnGameJoin += ActivityWatcher_OnGameJoin; _activityWatcher.OnGameLeave += ActivityWatcher_OnGameLeave; + + if (!App.Settings.Prop.UseDisableAppPatch) + GameHistoryMenuItem.Visibility = Visibility.Visible; } if (_watcher.RichPresence is not null) RichPresenceMenuItem.Visibility = Visibility.Visible; - if (!App.Settings.Prop.UseDisableAppPatch) - GameHistoryMenuItem.Visibility = Visibility.Visible; - VersionTextBlock.Text = $"{App.ProjectName} v{App.Version}"; } diff --git a/Bloxstrap/UI/Elements/Settings/MainWindow.xaml b/Bloxstrap/UI/Elements/Settings/MainWindow.xaml index e0922d9..ffb58d5 100644 --- a/Bloxstrap/UI/Elements/Settings/MainWindow.xaml +++ b/Bloxstrap/UI/Elements/Settings/MainWindow.xaml @@ -7,7 +7,9 @@ xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" xmlns:base="clr-namespace:Bloxstrap.UI.Elements.Base" xmlns:resources="clr-namespace:Bloxstrap.Resources" + xmlns:dmodels="clr-namespace:Bloxstrap.UI.ViewModels.Settings" mc:Ignorable="d" + d:DataContext="{d:DesignInstance dmodels:MainWindowViewModel, IsDesignTimeCreatable=True}" Title="{x:Static resources:Strings.Menu_Title}" MinWidth="960" Width="980" @@ -16,7 +18,8 @@ ExtendsContentIntoTitleBar="True" WindowBackdropType="Mica" WindowStartupLocation="CenterScreen" - Closing="WpfUiWindow_Closing"> + Closing="WpfUiWindow_Closing" + Closed="WpfUiWindow_Closed"> @@ -84,6 +87,7 @@ + @@ -91,10 +95,16 @@ - + + + + + + + - + diff --git a/Bloxstrap/UI/Elements/Settings/MainWindow.xaml.cs b/Bloxstrap/UI/Elements/Settings/MainWindow.xaml.cs index 37e9237..3fcc316 100644 --- a/Bloxstrap/UI/Elements/Settings/MainWindow.xaml.cs +++ b/Bloxstrap/UI/Elements/Settings/MainWindow.xaml.cs @@ -100,8 +100,13 @@ namespace Bloxstrap.UI.Elements.Settings _state.Left = this.Left; App.State.Save(); + } - if (!e.Cancel) + private void WpfUiWindow_Closed(object sender, EventArgs e) + { + if (App.LaunchSettings.TestModeFlag.Active) + LaunchHandler.LaunchRoblox(LaunchMode.Player); + else App.SoftTerminate(); } } diff --git a/Bloxstrap/UI/ViewModels/Settings/MainWindowViewModel.cs b/Bloxstrap/UI/ViewModels/Settings/MainWindowViewModel.cs index 5c04e50..a3826d3 100644 --- a/Bloxstrap/UI/ViewModels/Settings/MainWindowViewModel.cs +++ b/Bloxstrap/UI/ViewModels/Settings/MainWindowViewModel.cs @@ -1,4 +1,5 @@ -using System.Windows.Input; +using System.Windows; +using System.Windows.Input; using Bloxstrap.UI.Elements.About; using CommunityToolkit.Mvvm.Input; @@ -16,6 +17,23 @@ namespace Bloxstrap.UI.ViewModels.Settings public EventHandler? RequestCloseWindowEvent; + public bool TestModeEnabled + { + get => App.LaunchSettings.TestModeFlag.Active; + set + { + if (value) + { + var result = Frontend.ShowMessageBox(Strings.Menu_TestMode_Prompt, MessageBoxImage.Information, MessageBoxButton.YesNo); + + if (result != MessageBoxResult.Yes) + return; + } + + App.LaunchSettings.TestModeFlag.Active = value; + } + } + private void OpenAbout() => new MainWindow().ShowDialog(); private void CloseWindow() => RequestCloseWindowEvent?.Invoke(this, EventArgs.Empty); diff --git a/Bloxstrap/Watcher.cs b/Bloxstrap/Watcher.cs index 86859a8..ae67f8b 100644 --- a/Bloxstrap/Watcher.cs +++ b/Bloxstrap/Watcher.cs @@ -69,7 +69,7 @@ namespace Bloxstrap if (App.Settings.Prop.UseDisableAppPatch) { - ActivityWatcher.OnAppClose += (_, _) => + ActivityWatcher.OnAppClose += delegate { App.Logger.WriteLine(LOG_IDENT, "Received desktop app exit, closing Roblox"); using var process = Process.GetProcessById(_gameClientPid); @@ -125,6 +125,9 @@ namespace Bloxstrap foreach (int pid in _autoclosePids) CloseProcess(pid); + + if (App.LaunchSettings.TestModeFlag.Active) + Process.Start(Paths.Process, "-settings -testmode"); } public void Dispose()