From 9ef6579a4163e2fb5b3c10ad16f588fd2a3c8947 Mon Sep 17 00:00:00 2001 From: bluepilledgreat <97983689+bluepilledgreat@users.noreply.github.com> Date: Fri, 14 Mar 2025 14:23:53 +0000 Subject: [PATCH 01/22] update ElementAttributeMissingChild string --- Bloxstrap/Resources/Strings.Designer.cs | 2 +- Bloxstrap/Resources/Strings.resx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Bloxstrap/Resources/Strings.Designer.cs b/Bloxstrap/Resources/Strings.Designer.cs index 69565c6..5395778 100644 --- a/Bloxstrap/Resources/Strings.Designer.cs +++ b/Bloxstrap/Resources/Strings.Designer.cs @@ -1082,7 +1082,7 @@ namespace Bloxstrap.Resources { } /// - /// Looks up a localized string similar to {0}.{1} is missing it's child. + /// Looks up a localized string similar to {0}.{1} is missing its child. /// public static string CustomTheme_Errors_ElementAttributeMissingChild { get { diff --git a/Bloxstrap/Resources/Strings.resx b/Bloxstrap/Resources/Strings.resx index 20624a5..7c42f6a 100644 --- a/Bloxstrap/Resources/Strings.resx +++ b/Bloxstrap/Resources/Strings.resx @@ -1369,7 +1369,7 @@ Please close any applications that may be using Roblox's files, and relaunch.{0} is the element name (e.g. Button) - {0}.{1} is missing it's child + {0}.{1} is missing its child {0}.{1} is the element & attribute name (e.g. Button.Text) From 338ebba191a850935015cbb80ac42486c173fd59 Mon Sep 17 00:00:00 2001 From: Matt <97983689+bluepilledgreat@users.noreply.github.com> Date: Sat, 15 Mar 2025 00:17:23 +0000 Subject: [PATCH 02/22] Localise more custom dialog related strings (#4881) * translate template comments * localise default custom theme name --- Bloxstrap/Extensions/CustomThemeTemplateEx.cs | 28 ++++++++++++++- .../CustomBootstrapperTemplate_Blank.xml | 4 +-- .../CustomBootstrapperTemplate_Simple.xml | 2 +- Bloxstrap/Resources/Strings.Designer.cs | 36 +++++++++++++++++++ Bloxstrap/Resources/Strings.resx | 13 +++++++ .../Dialogs/AddCustomThemeDialog.xaml.cs | 7 ++-- 6 files changed, 83 insertions(+), 7 deletions(-) diff --git a/Bloxstrap/Extensions/CustomThemeTemplateEx.cs b/Bloxstrap/Extensions/CustomThemeTemplateEx.cs index 4088f02..ed9dcea 100644 --- a/Bloxstrap/Extensions/CustomThemeTemplateEx.cs +++ b/Bloxstrap/Extensions/CustomThemeTemplateEx.cs @@ -1,10 +1,36 @@ -namespace Bloxstrap.Extensions +using System.Text; + +namespace Bloxstrap.Extensions { static class CustomThemeTemplateEx { + const string EXAMPLES_URL = "https://github.com/bloxstraplabs/custom-bootstrapper-examples"; + public static string GetFileName(this CustomThemeTemplate template) { return $"CustomBootstrapperTemplate_{template}.xml"; } + + public static string GetFileContents(this CustomThemeTemplate template) + { + string contents = Encoding.UTF8.GetString(Resource.Get(template.GetFileName()).Result); + + switch (template) + { + case CustomThemeTemplate.Blank: + { + string moreText = string.Format(Strings.CustomTheme_Templates_Blank_MoreExamples, EXAMPLES_URL); + return string.Format(contents, Strings.CustomTheme_Templates_Blank_UIElements, moreText); + } + case CustomThemeTemplate.Simple: + { + string moreText = string.Format(Strings.CustomTheme_Templates_Simple_MoreExamples, EXAMPLES_URL); + return string.Format(contents, moreText); + } + default: + Debug.Assert(false); + return contents; + } + } } } diff --git a/Bloxstrap/Resources/CustomBootstrapperTemplate_Blank.xml b/Bloxstrap/Resources/CustomBootstrapperTemplate_Blank.xml index 99efce9..3945086 100644 --- a/Bloxstrap/Resources/CustomBootstrapperTemplate_Blank.xml +++ b/Bloxstrap/Resources/CustomBootstrapperTemplate_Blank.xml @@ -1,4 +1,4 @@  - - + + \ No newline at end of file diff --git a/Bloxstrap/Resources/CustomBootstrapperTemplate_Simple.xml b/Bloxstrap/Resources/CustomBootstrapperTemplate_Simple.xml index 7664806..abe586d 100644 --- a/Bloxstrap/Resources/CustomBootstrapperTemplate_Simple.xml +++ b/Bloxstrap/Resources/CustomBootstrapperTemplate_Simple.xml @@ -1,5 +1,5 @@  - + diff --git a/Bloxstrap/Resources/Strings.Designer.cs b/Bloxstrap/Resources/Strings.Designer.cs index 5395778..848b724 100644 --- a/Bloxstrap/Resources/Strings.Designer.cs +++ b/Bloxstrap/Resources/Strings.Designer.cs @@ -973,6 +973,15 @@ namespace Bloxstrap.Resources { } } + /// + /// Looks up a localized string similar to Custom Theme {0}. + /// + public static string CustomTheme_DefaultName { + get { + return ResourceManager.GetString("CustomTheme.DefaultName", resourceCulture); + } + } + /// /// Looks up a localized string similar to Save changes to {0}?. /// @@ -1271,6 +1280,33 @@ namespace Bloxstrap.Resources { } } + /// + /// Looks up a localized string similar to Examples of custom bootstrappers can be found at {0}. + /// + public static string CustomTheme_Templates_Blank_MoreExamples { + get { + return ResourceManager.GetString("CustomTheme.Templates.Blank.MoreExamples", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Put UI elements here. + /// + public static string CustomTheme_Templates_Blank_UIElements { + get { + return ResourceManager.GetString("CustomTheme.Templates.Blank.UIElements", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Find more custom bootstrapper examples at {0}. + /// + public static string CustomTheme_Templates_Simple_MoreExamples { + get { + return ResourceManager.GetString("CustomTheme.Templates.Simple.MoreExamples", resourceCulture); + } + } + /// /// Looks up a localized string similar to Add Fast Flag. /// diff --git a/Bloxstrap/Resources/Strings.resx b/Bloxstrap/Resources/Strings.resx index 7c42f6a..f0355ae 100644 --- a/Bloxstrap/Resources/Strings.resx +++ b/Bloxstrap/Resources/Strings.resx @@ -1474,4 +1474,17 @@ Defaulting to {1}. Update Roblox in the background instead of waiting. Not recommended for slow networks. At least 3GB of free storage space is required for this feature to work. + + Put UI elements here + + + Examples of custom bootstrappers can be found at {0} + + + Find more custom bootstrapper examples at {0} + + + Custom Theme {0} + {0} is a string (e.g. '1', '1-1234') + \ No newline at end of file diff --git a/Bloxstrap/UI/Elements/Dialogs/AddCustomThemeDialog.xaml.cs b/Bloxstrap/UI/Elements/Dialogs/AddCustomThemeDialog.xaml.cs index 94ce4a8..9d88c8c 100644 --- a/Bloxstrap/UI/Elements/Dialogs/AddCustomThemeDialog.xaml.cs +++ b/Bloxstrap/UI/Elements/Dialogs/AddCustomThemeDialog.xaml.cs @@ -39,11 +39,12 @@ namespace Bloxstrap.UI.Elements.Dialogs { int count = Directory.GetDirectories(Paths.CustomThemes).Count(); - string name = $"Custom Theme {count + 1}"; + int i = count + 1; + string name = string.Format(Strings.CustomTheme_DefaultName, i); // TODO: this sucks if (File.Exists(GetThemePath(name))) - name += " " + Random.Shared.Next(1, 100000).ToString(); // easy + name = string.Format(Strings.CustomTheme_DefaultName, $"{i}-{Random.Shared.Next(1, 100000)}"); // easy return name; } @@ -76,7 +77,7 @@ namespace Bloxstrap.UI.Elements.Dialogs string themeFilePath = Path.Combine(dir, "Theme.xml"); - string templateContent = Encoding.UTF8.GetString(Resource.Get(template.GetFileName()).Result); + string templateContent = template.GetFileContents(); File.WriteAllText(themeFilePath, templateContent); } From f0eb2eb745facb0d153ccf57f5fcb2e47f9baa36 Mon Sep 17 00:00:00 2001 From: Matt <97983689+bluepilledgreat@users.noreply.github.com> Date: Sat, 15 Mar 2025 10:52:10 +0000 Subject: [PATCH 03/22] use `PathValidator` for `RenameCustomTheme` (#4886) --- .../Settings/AppearanceViewModel.cs | 42 +++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/Bloxstrap/UI/ViewModels/Settings/AppearanceViewModel.cs b/Bloxstrap/UI/ViewModels/Settings/AppearanceViewModel.cs index d09f23c..0870bfb 100644 --- a/Bloxstrap/UI/ViewModels/Settings/AppearanceViewModel.cs +++ b/Bloxstrap/UI/ViewModels/Settings/AppearanceViewModel.cs @@ -194,11 +194,47 @@ namespace Bloxstrap.UI.ViewModels.Settings private void RenameCustomTheme() { - if (SelectedCustomTheme is null) + const string LOG_IDENT = "AppearanceViewModel::RenameCustomTheme"; + + if (SelectedCustomTheme is null || SelectedCustomTheme == SelectedCustomThemeName) return; - if (SelectedCustomTheme == SelectedCustomThemeName) + if (string.IsNullOrEmpty(SelectedCustomThemeName)) + { + Frontend.ShowMessageBox(Strings.CustomTheme_Add_Errors_NameEmpty, MessageBoxImage.Error); return; + } + + var validationResult = PathValidator.IsFileNameValid(SelectedCustomThemeName); + + if (validationResult != PathValidator.ValidationResult.Ok) + { + switch (validationResult) + { + case PathValidator.ValidationResult.IllegalCharacter: + Frontend.ShowMessageBox(Strings.CustomTheme_Add_Errors_NameIllegalCharacters, MessageBoxImage.Error); + break; + case PathValidator.ValidationResult.ReservedFileName: + Frontend.ShowMessageBox(Strings.CustomTheme_Add_Errors_NameReserved, MessageBoxImage.Error); + break; + default: + App.Logger.WriteLine(LOG_IDENT, $"Got unhandled PathValidator::ValidationResult {validationResult}"); + Debug.Assert(false); + + Frontend.ShowMessageBox(Strings.CustomTheme_Add_Errors_Unknown, MessageBoxImage.Error); + break; + } + + return; + } + + // better to check for the file instead of the directory so broken themes can be overwritten + string path = Path.Combine(Paths.CustomThemes, SelectedCustomThemeName, "Theme.xml"); + if (File.Exists(path)) + { + Frontend.ShowMessageBox(Strings.CustomTheme_Add_Errors_NameTaken, MessageBoxImage.Error); + return; + } try { @@ -206,7 +242,7 @@ namespace Bloxstrap.UI.ViewModels.Settings } catch (Exception ex) { - App.Logger.WriteException("AppearanceViewModel::RenameCustomTheme", ex); + App.Logger.WriteException(LOG_IDENT, ex); Frontend.ShowMessageBox(string.Format(Strings.Menu_Appearance_CustomThemes_RenameFailed, SelectedCustomTheme, ex.Message), MessageBoxImage.Error); return; } From d0f1b9de226a59b1b8791a41f786000ae8450b69 Mon Sep 17 00:00:00 2001 From: bluepilledgreat <97983689+bluepilledgreat@users.noreply.github.com> Date: Sat, 15 Mar 2025 13:04:10 +0000 Subject: [PATCH 04/22] toggle `OpenReleaseNotes` --- Bloxstrap/Installer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bloxstrap/Installer.cs b/Bloxstrap/Installer.cs index d57e985..8d1a6e6 100644 --- a/Bloxstrap/Installer.cs +++ b/Bloxstrap/Installer.cs @@ -9,7 +9,7 @@ namespace Bloxstrap /// Should this version automatically open the release notes page? /// Recommended for major updates only. /// - private const bool OpenReleaseNotes = false; + private const bool OpenReleaseNotes = true; private static string DesktopShortcut => Path.Combine(Paths.Desktop, $"{App.ProjectName}.lnk"); From 49fd8eb2d2f860f3a80838b7fd228bdb00ebd5b5 Mon Sep 17 00:00:00 2001 From: bluepilledgreat <97983689+bluepilledgreat@users.noreply.github.com> Date: Sat, 15 Mar 2025 14:35:09 +0000 Subject: [PATCH 05/22] improve `Watcher` ctor macro exclusions --- Bloxstrap/Watcher.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Bloxstrap/Watcher.cs b/Bloxstrap/Watcher.cs index eef397e..d56c95f 100644 --- a/Bloxstrap/Watcher.cs +++ b/Bloxstrap/Watcher.cs @@ -28,21 +28,21 @@ namespace Bloxstrap string? watcherDataArg = App.LaunchSettings.WatcherFlag.Data; -#if DEBUG if (String.IsNullOrEmpty(watcherDataArg)) { +#if DEBUG string path = new RobloxPlayerData().ExecutablePath; using var gameClientProcess = Process.Start(path); _watcherData = new() { ProcessId = gameClientProcess.Id }; - } #else - if (String.IsNullOrEmpty(watcherDataArg)) throw new Exception("Watcher data not specified"); #endif - - if (!String.IsNullOrEmpty(watcherDataArg)) + } + else + { _watcherData = JsonSerializer.Deserialize(Encoding.UTF8.GetString(Convert.FromBase64String(watcherDataArg))); + } if (_watcherData is null) throw new Exception("Watcher data is invalid"); From d244f42b49ed3f12764e32f720e6118f5c869dd6 Mon Sep 17 00:00:00 2001 From: Matt <97983689+bluepilledgreat@users.noreply.github.com> Date: Sat, 15 Mar 2025 17:42:21 +0000 Subject: [PATCH 06/22] Reintroduce multi-instance launching (#4888) --- Bloxstrap/Bootstrapper.cs | 41 +++++++++-- Bloxstrap/LaunchHandler.cs | 29 +++++++- Bloxstrap/LaunchSettings.cs | 30 ++++---- Bloxstrap/Models/Persistable/Settings.cs | 1 + Bloxstrap/MultiInstanceWatcher.cs | 68 +++++++++++++++++++ Bloxstrap/Resources/Strings.Designer.cs | 18 +++++ Bloxstrap/Resources/Strings.resx | 6 ++ .../Settings/Pages/IntegrationsPage.xaml | 8 +++ .../Settings/IntegrationsViewModel.cs | 6 ++ 9 files changed, 185 insertions(+), 22 deletions(-) create mode 100644 Bloxstrap/MultiInstanceWatcher.cs diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index f680e00..af3e614 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -471,21 +471,48 @@ namespace Bloxstrap } } + private static void LaunchMultiInstanceWatcher() + { + const string LOG_IDENT = "Bootstrapper::LaunchMultiInstanceWatcher"; + + if (Utilities.DoesMutexExist("ROBLOX_singletonMutex")) + { + App.Logger.WriteLine(LOG_IDENT, "Roblox singleton mutex already exists"); + return; + } + + using EventWaitHandle initEventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, "Bloxstrap-MultiInstanceWatcherInitialisationFinished"); + Process.Start(Paths.Process, "-multiinstancewatcher"); + + bool initSuccess = initEventHandle.WaitOne(TimeSpan.FromSeconds(2)); + if (initSuccess) + App.Logger.WriteLine(LOG_IDENT, "Initialisation finished signalled, continuing."); + else + App.Logger.WriteLine(LOG_IDENT, "Did not receive the initialisation finished signal, continuing."); + } + private void StartRoblox() { const string LOG_IDENT = "Bootstrapper::StartRoblox"; SetStatus(Strings.Bootstrapper_Status_Starting); - if (_launchMode == LaunchMode.Player && App.Settings.Prop.ForceRobloxLanguage) + if (_launchMode == LaunchMode.Player) { - var match = Regex.Match(_launchCommandLine, "gameLocale:([a-z_]+)", RegexOptions.CultureInvariant); + // this needs to be done before roblox launches + if (App.Settings.Prop.MultiInstanceLaunching) + LaunchMultiInstanceWatcher(); - if (match.Groups.Count == 2) - _launchCommandLine = _launchCommandLine.Replace( - "robloxLocale:en_us", - $"robloxLocale:{match.Groups[1].Value}", - StringComparison.OrdinalIgnoreCase); + if (App.Settings.Prop.ForceRobloxLanguage) + { + var match = Regex.Match(_launchCommandLine, "gameLocale:([a-z_]+)", RegexOptions.CultureInvariant); + + if (match.Groups.Count == 2) + _launchCommandLine = _launchCommandLine.Replace( + "robloxLocale:en_us", + $"robloxLocale:{match.Groups[1].Value}", + StringComparison.OrdinalIgnoreCase); + } } var startInfo = new ProcessStartInfo() diff --git a/Bloxstrap/LaunchHandler.cs b/Bloxstrap/LaunchHandler.cs index 1eee8b2..4171b83 100644 --- a/Bloxstrap/LaunchHandler.cs +++ b/Bloxstrap/LaunchHandler.cs @@ -59,6 +59,11 @@ namespace Bloxstrap App.Logger.WriteLine(LOG_IDENT, "Opening watcher"); LaunchWatcher(); } + else if (App.LaunchSettings.MultiInstanceWatcherFlag.Active) + { + App.Logger.WriteLine(LOG_IDENT, "Opening multi-instance watcher"); + LaunchMultiInstanceWatcher(); + } else if (App.LaunchSettings.BackgroundUpdaterFlag.Active) { App.Logger.WriteLine(LOG_IDENT, "Opening background updater"); @@ -223,7 +228,7 @@ namespace Bloxstrap App.Terminate(ErrorCode.ERROR_FILE_NOT_FOUND); } - if (App.Settings.Prop.ConfirmLaunches && Mutex.TryOpenExisting("ROBLOX_singletonMutex", out var _)) + if (App.Settings.Prop.ConfirmLaunches && Mutex.TryOpenExisting("ROBLOX_singletonMutex", out var _) && !App.Settings.Prop.MultiInstanceLaunching) { // this currently doesn't work very well since it relies on checking the existence of the singleton mutex // which often hangs around for a few seconds after the window closes @@ -302,6 +307,28 @@ namespace Bloxstrap }); } + public static void LaunchMultiInstanceWatcher() + { + const string LOG_IDENT = "LaunchHandler::LaunchMultiInstanceWatcher"; + + App.Logger.WriteLine(LOG_IDENT, "Starting multi-instance watcher"); + + Task.Run(MultiInstanceWatcher.Run).ContinueWith(t => + { + App.Logger.WriteLine(LOG_IDENT, "Multi instance watcher task has finished"); + + if (t.IsFaulted) + { + App.Logger.WriteLine(LOG_IDENT, "An exception occurred when running the multi-instance watcher"); + + if (t.Exception is not null) + App.FinalizeExceptionHandling(t.Exception); + } + + App.Terminate(); + }); + } + public static void LaunchBackgroundUpdater() { const string LOG_IDENT = "LaunchHandler::LaunchBackgroundUpdater"; diff --git a/Bloxstrap/LaunchSettings.cs b/Bloxstrap/LaunchSettings.cs index e0a5051..e7e8543 100644 --- a/Bloxstrap/LaunchSettings.cs +++ b/Bloxstrap/LaunchSettings.cs @@ -12,33 +12,35 @@ namespace Bloxstrap { public class LaunchSettings { - public LaunchFlag MenuFlag { get; } = new("preferences,menu,settings"); + public LaunchFlag MenuFlag { get; } = new("preferences,menu,settings"); - public LaunchFlag WatcherFlag { get; } = new("watcher"); + public LaunchFlag WatcherFlag { get; } = new("watcher"); - public LaunchFlag BackgroundUpdaterFlag { get; } = new("backgroundupdater"); + public LaunchFlag MultiInstanceWatcherFlag { get; } = new("multiinstancewatcher"); - public LaunchFlag QuietFlag { get; } = new("quiet"); + public LaunchFlag BackgroundUpdaterFlag { get; } = new("backgroundupdater"); - public LaunchFlag UninstallFlag { get; } = new("uninstall"); + public LaunchFlag QuietFlag { get; } = new("quiet"); - public LaunchFlag NoLaunchFlag { get; } = new("nolaunch"); + public LaunchFlag UninstallFlag { get; } = new("uninstall"); + + public LaunchFlag NoLaunchFlag { get; } = new("nolaunch"); - public LaunchFlag TestModeFlag { get; } = new("testmode"); + public LaunchFlag TestModeFlag { get; } = new("testmode"); - public LaunchFlag NoGPUFlag { get; } = new("nogpu"); + public LaunchFlag NoGPUFlag { get; } = new("nogpu"); - public LaunchFlag UpgradeFlag { get; } = new("upgrade"); + public LaunchFlag UpgradeFlag { get; } = new("upgrade"); - public LaunchFlag PlayerFlag { get; } = new("player"); + public LaunchFlag PlayerFlag { get; } = new("player"); - public LaunchFlag StudioFlag { get; } = new("studio"); + public LaunchFlag StudioFlag { get; } = new("studio"); - public LaunchFlag VersionFlag { get; } = new("version"); + public LaunchFlag VersionFlag { get; } = new("version"); - public LaunchFlag ChannelFlag { get; } = new("channel"); + public LaunchFlag ChannelFlag { get; } = new("channel"); - public LaunchFlag ForceFlag { get; } = new("force"); + public LaunchFlag ForceFlag { get; } = new("force"); #if DEBUG public bool BypassUpdateCheck => true; diff --git a/Bloxstrap/Models/Persistable/Settings.cs b/Bloxstrap/Models/Persistable/Settings.cs index 0f6bb86..eb9c273 100644 --- a/Bloxstrap/Models/Persistable/Settings.cs +++ b/Bloxstrap/Models/Persistable/Settings.cs @@ -11,6 +11,7 @@ namespace Bloxstrap.Models.Persistable public string BootstrapperIconCustomLocation { get; set; } = ""; public Theme Theme { get; set; } = Theme.Default; public bool CheckForUpdates { get; set; } = true; + public bool MultiInstanceLaunching { get; set; } = false; public bool ConfirmLaunches { get; set; } = false; public string Locale { get; set; } = "nil"; public bool ForceRobloxLanguage { get; set; } = false; diff --git a/Bloxstrap/MultiInstanceWatcher.cs b/Bloxstrap/MultiInstanceWatcher.cs new file mode 100644 index 0000000..8799490 --- /dev/null +++ b/Bloxstrap/MultiInstanceWatcher.cs @@ -0,0 +1,68 @@ +namespace Bloxstrap +{ + internal static class MultiInstanceWatcher + { + private static int GetOpenProcessesCount() + { + const string LOG_IDENT = "MultiInstanceWatcher::GetOpenProcessesCount"; + + try + { + // prevent any possible race conditions by checking for bloxstrap processes too + int count = Process.GetProcesses().Count(x => x.ProcessName is "RobloxPlayerBeta" or "Bloxstrap"); + count -= 1; // ignore the current process + return count; + } + catch (Exception ex) + { + // everything process related can error at any time + App.Logger.WriteException(LOG_IDENT, ex); + return -1; + } + } + + private static void FireInitialisedEvent() + { + using EventWaitHandle initEventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, "Bloxstrap-MultiInstanceWatcherInitialisationFinished"); + initEventHandle.Set(); + } + + public static void Run() + { + const string LOG_IDENT = "MultiInstanceWatcher::Run"; + + // try to get the mutex + bool acquiredMutex; + using Mutex mutex = new Mutex(false, "ROBLOX_singletonMutex"); + try + { + acquiredMutex = mutex.WaitOne(0); + } + catch (AbandonedMutexException) + { + acquiredMutex = true; + } + + if (!acquiredMutex) + { + App.Logger.WriteLine(LOG_IDENT, "Client singleton mutex is already acquired"); + FireInitialisedEvent(); + return; + } + + App.Logger.WriteLine(LOG_IDENT, "Acquired mutex!"); + FireInitialisedEvent(); + + // watch for alive processes + int count; + do + { + Thread.Sleep(5000); + count = GetOpenProcessesCount(); + } + while (count == -1 || count > 0); // redo if -1 (one of the Process apis failed) + + App.Logger.WriteLine(LOG_IDENT, "All Roblox related processes have closed, exiting!"); + } + } +} diff --git a/Bloxstrap/Resources/Strings.Designer.cs b/Bloxstrap/Resources/Strings.Designer.cs index 848b724..f61475b 100644 --- a/Bloxstrap/Resources/Strings.Designer.cs +++ b/Bloxstrap/Resources/Strings.Designer.cs @@ -3425,6 +3425,24 @@ namespace Bloxstrap.Resources { } } + /// + /// Looks up a localized string similar to Allows for having more than one Roblox game client instance open simultaneously.. + /// + public static string Menu_Integrations_MultiInstanceLaunching_Description { + get { + return ResourceManager.GetString("Menu.Integrations.MultiInstanceLaunching.Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Allow multi-instance launching. + /// + public static string Menu_Integrations_MultiInstanceLaunching_Title { + get { + return ResourceManager.GetString("Menu.Integrations.MultiInstanceLaunching.Title", resourceCulture); + } + } + /// /// Looks up a localized string similar to When in-game, you'll be able to see where your server is located via [ipinfo.io]({0}).. /// diff --git a/Bloxstrap/Resources/Strings.resx b/Bloxstrap/Resources/Strings.resx index f0355ae..2e9abaa 100644 --- a/Bloxstrap/Resources/Strings.resx +++ b/Bloxstrap/Resources/Strings.resx @@ -1487,4 +1487,10 @@ Defaulting to {1}. Custom Theme {0} {0} is a string (e.g. '1', '1-1234') + + Allow multi-instance launching + + + Allows for having more than one Roblox game client instance open simultaneously. + \ No newline at end of file diff --git a/Bloxstrap/UI/Elements/Settings/Pages/IntegrationsPage.xaml b/Bloxstrap/UI/Elements/Settings/Pages/IntegrationsPage.xaml index 0e391bb..0cb02e6 100644 --- a/Bloxstrap/UI/Elements/Settings/Pages/IntegrationsPage.xaml +++ b/Bloxstrap/UI/Elements/Settings/Pages/IntegrationsPage.xaml @@ -66,6 +66,14 @@ + + + + + + diff --git a/Bloxstrap/UI/ViewModels/Settings/IntegrationsViewModel.cs b/Bloxstrap/UI/ViewModels/Settings/IntegrationsViewModel.cs index d66789d..4aed82e 100644 --- a/Bloxstrap/UI/ViewModels/Settings/IntegrationsViewModel.cs +++ b/Bloxstrap/UI/ViewModels/Settings/IntegrationsViewModel.cs @@ -125,6 +125,12 @@ namespace Bloxstrap.UI.ViewModels.Settings set => App.Settings.Prop.UseDisableAppPatch = value; } + public bool MultiInstanceLaunchingEnabled + { + get => App.Settings.Prop.MultiInstanceLaunching; + set => App.Settings.Prop.MultiInstanceLaunching = value; + } + public ObservableCollection CustomIntegrations { get => App.Settings.Prop.CustomIntegrations; From afc3200b681d9c2ef817bdff051d7ee58af314ba Mon Sep 17 00:00:00 2001 From: Matt <97983689+bluepilledgreat@users.noreply.github.com> Date: Sat, 15 Mar 2025 17:53:00 +0000 Subject: [PATCH 07/22] Improve LaunchSettings constructor (#4889) * update log ident * move flagMap inside the ctor function --- Bloxstrap/LaunchSettings.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Bloxstrap/LaunchSettings.cs b/Bloxstrap/LaunchSettings.cs index e7e8543..337e482 100644 --- a/Bloxstrap/LaunchSettings.cs +++ b/Bloxstrap/LaunchSettings.cs @@ -57,11 +57,9 @@ namespace Bloxstrap /// public string[] Args { get; private set; } - private readonly Dictionary _flagMap = new(); - public LaunchSettings(string[] args) { - const string LOG_IDENT = "LaunchSettings"; + const string LOG_IDENT = "LaunchSettings::LaunchSettings"; #if DEBUG App.Logger.WriteLine(LOG_IDENT, $"Launched with arguments: {string.Join(' ', args)}"); @@ -69,6 +67,8 @@ namespace Bloxstrap Args = args; + Dictionary flagMap = new(); + // build flag map foreach (var prop in this.GetType().GetProperties()) { @@ -79,7 +79,7 @@ namespace Bloxstrap continue; foreach (string identifier in flag.Identifiers.Split(',')) - _flagMap.Add(identifier, flag); + flagMap.Add(identifier, flag); } int startIdx = 0; @@ -119,7 +119,7 @@ namespace Bloxstrap string identifier = arg[1..]; - if (!_flagMap.TryGetValue(identifier, out LaunchFlag? flag) || flag is null) + if (!flagMap.TryGetValue(identifier, out LaunchFlag? flag) || flag is null) { App.Logger.WriteLine(LOG_IDENT, $"Unknown argument: {identifier}"); continue; From 3f02c6ba93ec2f24f020417506ff2542f086187e Mon Sep 17 00:00:00 2001 From: Matt <97983689+bluepilledgreat@users.noreply.github.com> Date: Sat, 15 Mar 2025 17:55:13 +0000 Subject: [PATCH 08/22] Reset `ForceReinstall` after upgrade (#4890) --- Bloxstrap/Bootstrapper.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index af3e614..d1889d4 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -1136,6 +1136,8 @@ namespace Bloxstrap App.Logger.WriteLine(LOG_IDENT, $"Registered as {totalSize} KB"); + App.State.Prop.ForceReinstall = false; + App.State.Save(); App.RobloxState.Save(); From bae578f94df4fde637503e4047c62f71f2daa919 Mon Sep 17 00:00:00 2001 From: bluepilledgreat <97983689+bluepilledgreat@users.noreply.github.com> Date: Sat, 15 Mar 2025 17:55:42 +0000 Subject: [PATCH 09/22] Update wpfui --- wpfui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wpfui b/wpfui index dca423b..f710123 160000 --- a/wpfui +++ b/wpfui @@ -1 +1 @@ -Subproject commit dca423b724ec24bd3377da3a27f4055ae317b50a +Subproject commit f710123e72d9dcc8d09fccc4e2a783cc5cf5e652 From 950277d1e9a45c451a86baf566a12930d2fd75f2 Mon Sep 17 00:00:00 2001 From: bluepilledgreat <97983689+bluepilledgreat@users.noreply.github.com> Date: Sun, 16 Mar 2025 02:12:41 +0000 Subject: [PATCH 10/22] fix crash on theme create --- Bloxstrap/Extensions/CustomThemeTemplateEx.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Bloxstrap/Extensions/CustomThemeTemplateEx.cs b/Bloxstrap/Extensions/CustomThemeTemplateEx.cs index ed9dcea..4b72197 100644 --- a/Bloxstrap/Extensions/CustomThemeTemplateEx.cs +++ b/Bloxstrap/Extensions/CustomThemeTemplateEx.cs @@ -20,12 +20,12 @@ namespace Bloxstrap.Extensions case CustomThemeTemplate.Blank: { string moreText = string.Format(Strings.CustomTheme_Templates_Blank_MoreExamples, EXAMPLES_URL); - return string.Format(contents, Strings.CustomTheme_Templates_Blank_UIElements, moreText); + return contents.Replace("{0}", Strings.CustomTheme_Templates_Blank_UIElements).Replace("{1}", moreText); } case CustomThemeTemplate.Simple: { string moreText = string.Format(Strings.CustomTheme_Templates_Simple_MoreExamples, EXAMPLES_URL); - return string.Format(contents, moreText); + return contents.Replace("{0}", moreText); } default: Debug.Assert(false); From 4d50381115e889c9122502435e23f4ce087fe8de Mon Sep 17 00:00:00 2001 From: bluepilledgreat <97983689+bluepilledgreat@users.noreply.github.com> Date: Sun, 16 Mar 2025 02:15:57 +0000 Subject: [PATCH 11/22] fix string not being localised --- Bloxstrap/Resources/Strings.Designer.cs | 9 +++++++++ Bloxstrap/Resources/Strings.resx | 3 +++ .../Editor/BootstrapperEditorWindowViewModel.cs | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Bloxstrap/Resources/Strings.Designer.cs b/Bloxstrap/Resources/Strings.Designer.cs index f61475b..fb38f4f 100644 --- a/Bloxstrap/Resources/Strings.Designer.cs +++ b/Bloxstrap/Resources/Strings.Designer.cs @@ -1036,6 +1036,15 @@ namespace Bloxstrap.Resources { } } + /// + /// Looks up a localized string similar to Your theme has been saved!. + /// + public static string CustomTheme_Editor_Save_Success_Description { + get { + return ResourceManager.GetString("CustomTheme.Editor.Save.Success.Description", resourceCulture); + } + } + /// /// Looks up a localized string similar to Editing "{0}". /// diff --git a/Bloxstrap/Resources/Strings.resx b/Bloxstrap/Resources/Strings.resx index 2e9abaa..e4111a7 100644 --- a/Bloxstrap/Resources/Strings.resx +++ b/Bloxstrap/Resources/Strings.resx @@ -1493,4 +1493,7 @@ Defaulting to {1}. Allows for having more than one Roblox game client instance open simultaneously. + + Your theme has been saved! + \ No newline at end of file diff --git a/Bloxstrap/UI/ViewModels/Editor/BootstrapperEditorWindowViewModel.cs b/Bloxstrap/UI/ViewModels/Editor/BootstrapperEditorWindowViewModel.cs index 2e0bcb4..b8c1968 100644 --- a/Bloxstrap/UI/ViewModels/Editor/BootstrapperEditorWindowViewModel.cs +++ b/Bloxstrap/UI/ViewModels/Editor/BootstrapperEditorWindowViewModel.cs @@ -64,7 +64,7 @@ namespace Bloxstrap.UI.ViewModels.Editor { File.WriteAllText(path, Code); CodeChanged = false; - ThemeSavedCallback.Invoke(true, "Your theme has been saved!"); + ThemeSavedCallback.Invoke(true, Strings.CustomTheme_Editor_Save_Success_Description); } catch (Exception ex) { From a037c9f867839574f980b5a6c1b2a8e04144343e Mon Sep 17 00:00:00 2001 From: bluepilledgreat <97983689+bluepilledgreat@users.noreply.github.com> Date: Sun, 16 Mar 2025 11:18:23 +0000 Subject: [PATCH 12/22] update localisation --- Bloxstrap/Resources/Strings.Designer.cs | 15 ++++++++++++--- Bloxstrap/Resources/Strings.resx | 9 ++++++--- .../Bootstrapper/CustomDialog.Elements.cs | 2 +- .../Editor/BootstrapperEditorWindowViewModel.cs | 2 +- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/Bloxstrap/Resources/Strings.Designer.cs b/Bloxstrap/Resources/Strings.Designer.cs index fb38f4f..547f49a 100644 --- a/Bloxstrap/Resources/Strings.Designer.cs +++ b/Bloxstrap/Resources/Strings.Designer.cs @@ -188,7 +188,7 @@ namespace Bloxstrap.Resources { } /// - /// Looks up a localized string similar to Failed to extract all files. + /// Looks up a localized string similar to Failed to extract files. /// public static string Bootstrapper_ExtractionFailed_Title { get { @@ -235,7 +235,7 @@ namespace Bloxstrap.Resources { } /// - /// Looks up a localized string similar to Failed to apply all modifications. + /// Looks up a localized string similar to Failed to apply modifications. /// public static string Bootstrapper_ModificationsFailed_Title { get { @@ -991,6 +991,15 @@ namespace Bloxstrap.Resources { } } + /// + /// Looks up a localized string similar to Failed to preview theme: {0}. + /// + public static string CustomTheme_Editor_Errors_PreviewFailed { + get { + return ResourceManager.GetString("CustomTheme.Editor.Errors.PreviewFailed", resourceCulture); + } + } + /// /// Looks up a localized string similar to Open Theme Directory. /// @@ -1218,7 +1227,7 @@ namespace Bloxstrap.Resources { } /// - /// Looks up a localized string similar to Custom bootstrappers can only have a maximum of {0} elements, got {1}.. + /// Looks up a localized string similar to Custom bootstrappers can only have a maximum of {0} elements, got {1}. /// public static string CustomTheme_Errors_TooManyElements { get { diff --git a/Bloxstrap/Resources/Strings.resx b/Bloxstrap/Resources/Strings.resx index e4111a7..33a9d19 100644 --- a/Bloxstrap/Resources/Strings.resx +++ b/Bloxstrap/Resources/Strings.resx @@ -1274,13 +1274,13 @@ Please close any applications that may be using Roblox's files, and relaunch.Roblox no longer supports Windows 7 or 8.1. To continue playing Roblox, please upgrade to Windows 10 or newer. - Failed to extract all files + Failed to extract files Some content may be missing. Force a Roblox reinstallation in settings to fix this. - Failed to apply all modifications + Failed to apply modifications Not all modifications will be present in the current launch. @@ -1302,7 +1302,7 @@ Please close any applications that may be using Roblox's files, and relaunch.Custom dialog has already been initialised - Custom bootstrappers can only have a maximum of {0} elements, got {1}. + Custom bootstrappers can only have a maximum of {0} elements, got {1} {0} and {1} are numbers @@ -1496,4 +1496,7 @@ Defaulting to {1}. Your theme has been saved! + + Failed to preview theme: {0} + \ No newline at end of file diff --git a/Bloxstrap/UI/Elements/Bootstrapper/CustomDialog.Elements.cs b/Bloxstrap/UI/Elements/Bootstrapper/CustomDialog.Elements.cs index 68a61d0..33743c6 100644 --- a/Bloxstrap/UI/Elements/Bootstrapper/CustomDialog.Elements.cs +++ b/Bloxstrap/UI/Elements/Bootstrapper/CustomDialog.Elements.cs @@ -416,7 +416,7 @@ namespace Bloxstrap.UI.Elements.Bootstrapper private static UIElement HandleXmlElement_BloxstrapCustomBootstrapper_Fake(CustomDialog dialog, XElement xmlElement) { // this only exists to error out the theme if someone tries to use two BloxstrapCustomBootstrappers - throw new Exception($"{xmlElement.Parent!.Name} cannot have a child of {xmlElement.Name}"); + throw new CustomThemeException("CustomTheme.Errors.ElementInvalidChild", xmlElement.Parent!.Name, xmlElement.Name); } private static DummyFrameworkElement HandleXmlElement_TitleBar(CustomDialog dialog, XElement xmlElement) diff --git a/Bloxstrap/UI/ViewModels/Editor/BootstrapperEditorWindowViewModel.cs b/Bloxstrap/UI/ViewModels/Editor/BootstrapperEditorWindowViewModel.cs index b8c1968..72129b8 100644 --- a/Bloxstrap/UI/ViewModels/Editor/BootstrapperEditorWindowViewModel.cs +++ b/Bloxstrap/UI/ViewModels/Editor/BootstrapperEditorWindowViewModel.cs @@ -50,7 +50,7 @@ namespace Bloxstrap.UI.ViewModels.Editor App.Logger.WriteLine(LOG_IDENT, "Failed to preview custom theme"); App.Logger.WriteException(LOG_IDENT, ex); - Frontend.ShowMessageBox($"Failed to preview theme: {ex.Message}", MessageBoxImage.Error, MessageBoxButton.OK); + Frontend.ShowMessageBox(string.Format(Strings.CustomTheme_Editor_Errors_PreviewFailed, ex.Message), MessageBoxImage.Error, MessageBoxButton.OK); } } From 40ed053ebe7651c6d626ad51e5313e90340aa449 Mon Sep 17 00:00:00 2001 From: bluepilledgreat <97983689+bluepilledgreat@users.noreply.github.com> Date: Sun, 16 Mar 2025 11:19:25 +0000 Subject: [PATCH 13/22] dont show error balloon tips if quiet --- Bloxstrap/Bootstrapper.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index d1889d4..5578fe2 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -294,11 +294,14 @@ namespace Bloxstrap if (!App.LaunchSettings.NoLaunchFlag.Active && !_cancelTokenSource.IsCancellationRequested) { - // show some balloon tips - if (!_packageExtractionSuccess) - Frontend.ShowBalloonTip(Strings.Bootstrapper_ExtractionFailed_Title, Strings.Bootstrapper_ExtractionFailed_Message, ToolTipIcon.Warning); - else if (!allModificationsApplied) - Frontend.ShowBalloonTip(Strings.Bootstrapper_ModificationsFailed_Title, Strings.Bootstrapper_ModificationsFailed_Message, ToolTipIcon.Warning); + if (!App.LaunchSettings.QuietFlag.Active) + { + // show some balloon tips + if (!_packageExtractionSuccess) + Frontend.ShowBalloonTip(Strings.Bootstrapper_ExtractionFailed_Title, Strings.Bootstrapper_ExtractionFailed_Message, ToolTipIcon.Warning); + else if (!allModificationsApplied) + Frontend.ShowBalloonTip(Strings.Bootstrapper_ModificationsFailed_Title, Strings.Bootstrapper_ModificationsFailed_Message, ToolTipIcon.Warning); + } StartRoblox(); } From ba799962cc721b0641d98db70650e2f46c4ca607 Mon Sep 17 00:00:00 2001 From: bluepilledgreat <97983689+bluepilledgreat@users.noreply.github.com> Date: Mon, 17 Mar 2025 18:14:23 +0000 Subject: [PATCH 14/22] add code signing policy to readme --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 4f31fc6..8a8be4c 100644 --- a/README.md +++ b/README.md @@ -83,3 +83,7 @@ Bloxstrap uses the [WPF UI](https://github.com/lepoco/wpfui) library for the use [crowdin-project]: https://crowdin.com/project/bloxstrap [discord-invite]: https://discord.gg/nKjV3mGq6R [tenor-gif]: https://media.tenor.com/FIkSGbGycmAAAAAd/manly-roblox.gif + +## Code signing policy + +Thanks to [SignPath.io](https://signpath.io/) for providing a free code signing service, and the [SignPath Foundation](https://signpath.org/) for providing the free code signing certificate. From 8e81983feef9b2905f7bd51996b803f8dd6f80a9 Mon Sep 17 00:00:00 2001 From: bluepilledgreat <97983689+bluepilledgreat@users.noreply.github.com> Date: Tue, 18 Mar 2025 10:12:46 +0000 Subject: [PATCH 15/22] fix crash in CleanupVersionsFolder --- Bloxstrap/Bootstrapper.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index 5578fe2..bfde105 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -859,6 +859,12 @@ namespace Bloxstrap return; } + if (!Directory.Exists(Paths.Versions)) + { + App.Logger.WriteLine(LOG_IDENT, "Versions directory does not exist, skipping cleanup."); + return; + } + foreach (string dir in Directory.GetDirectories(Paths.Versions)) { string dirName = Path.GetFileName(dir); From 12bc3ef6e70a691c03a39dbe92facc7fb0900572 Mon Sep 17 00:00:00 2001 From: Matt <97983689+bluepilledgreat@users.noreply.github.com> Date: Thu, 20 Mar 2025 16:39:02 +0000 Subject: [PATCH 16/22] Web environments (#4911) * add web environments * add comment * update enum name * fixes and improvements * add new enum value * update enum names --- Bloxstrap/App.xaml.cs | 42 +++++++++++++++++-- Bloxstrap/Enums/WebEnvironment.cs | 26 ++++++++++++ Bloxstrap/Extensions/TEnumEx.cs | 22 ++++++++++ Bloxstrap/JsonManager.cs | 3 ++ Bloxstrap/Models/Persistable/Settings.cs | 3 ++ .../Settings/Pages/BloxstrapPage.xaml | 8 ++++ .../ViewModels/Settings/BloxstrapViewModel.cs | 13 +++++- 7 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 Bloxstrap/Enums/WebEnvironment.cs create mode 100644 Bloxstrap/Extensions/TEnumEx.cs diff --git a/Bloxstrap/App.xaml.cs b/Bloxstrap/App.xaml.cs index dfc11ca..81cecce 100644 --- a/Bloxstrap/App.xaml.cs +++ b/Bloxstrap/App.xaml.cs @@ -65,6 +65,20 @@ namespace Bloxstrap ); private static bool _showingExceptionDialog = false; + + private static string? _webUrl = null; + public static string WebUrl + { + get { + if (_webUrl != null) + return _webUrl; + + string url = ConstructBloxstrapWebUrl(); + if (Settings.Loaded) // only cache if settings are done loading + _webUrl = url; + return url; + } + } public static void Terminate(ErrorCode exitCode = ErrorCode.ERROR_SUCCESS) { @@ -126,6 +140,25 @@ namespace Bloxstrap Terminate(ErrorCode.ERROR_INSTALL_FAILURE); } + public static string ConstructBloxstrapWebUrl() + { + // dont let user switch web environment if debug mode is not on + if (Settings.Prop.WebEnvironment == WebEnvironment.Production || !Settings.Prop.DeveloperMode) + return "bloxstraplabs.com"; + + string? sub = Settings.Prop.WebEnvironment.GetDescription(); + return $"web-{sub}.bloxstraplabs.com"; + } + + public static bool CanSendLogs() + { + // non developer mode always uses production + if (!Settings.Prop.DeveloperMode || Settings.Prop.WebEnvironment == WebEnvironment.Production) + return IsProductionBuild; + + return true; + } + public static async Task GetLatestRelease() { const string LOG_IDENT = "App::GetLatestRelease"; @@ -157,7 +190,7 @@ namespace Bloxstrap try { - await HttpClient.GetAsync($"https://bloxstraplabs.com/metrics/post?key={key}&value={value}"); + await HttpClient.GetAsync($"https://{WebUrl}/metrics/post?key={key}&value={value}"); } catch (Exception ex) { @@ -167,13 +200,13 @@ namespace Bloxstrap public static async void SendLog() { - if (!Settings.Prop.EnableAnalytics || !IsProductionBuild) + if (!Settings.Prop.EnableAnalytics || !CanSendLogs()) return; try { await HttpClient.PostAsync( - $"https://bloxstraplabs.com/metrics/post-exception", + $"https://{WebUrl}/metrics/post-exception", new StringContent(Logger.AsDocument) ); } @@ -347,6 +380,9 @@ namespace Bloxstrap Settings.Save(); } + Logger.WriteLine(LOG_IDENT, $"Developer mode: {Settings.Prop.DeveloperMode}"); + Logger.WriteLine(LOG_IDENT, $"Web environment: {Settings.Prop.WebEnvironment}"); + Locale.Set(Settings.Prop.Locale); if (!LaunchSettings.BypassUpdateCheck) diff --git a/Bloxstrap/Enums/WebEnvironment.cs b/Bloxstrap/Enums/WebEnvironment.cs new file mode 100644 index 0000000..5bf857a --- /dev/null +++ b/Bloxstrap/Enums/WebEnvironment.cs @@ -0,0 +1,26 @@ +using System.ComponentModel; + +namespace Bloxstrap.Enums +{ + [JsonConverter(typeof(JsonStringEnumConverter))] + public enum WebEnvironment + { + [Description("prod")] + Production, + + [Description("stage")] + Staging, + + [Description("dev")] + Dev, + + [Description("pizza")] + DevPizza, + + [Description("matt")] + DevMatt, + + [Description("local")] + Local + } +} diff --git a/Bloxstrap/Extensions/TEnumEx.cs b/Bloxstrap/Extensions/TEnumEx.cs new file mode 100644 index 0000000..ddefb8f --- /dev/null +++ b/Bloxstrap/Extensions/TEnumEx.cs @@ -0,0 +1,22 @@ +using System.ComponentModel; +using System.Reflection; + +namespace Bloxstrap.Extensions +{ + internal static class TEnumEx + { + public static string? GetDescription(this TEnum e) + { + string? enumName = e.ToString(); + if (enumName == null) + return null; + + FieldInfo? field = e.GetType().GetField(enumName); + if (field == null) + return null; + + DescriptionAttribute? attribute = field.GetCustomAttribute(); + return attribute?.Description; + } + } +} diff --git a/Bloxstrap/JsonManager.cs b/Bloxstrap/JsonManager.cs index 6c04a2a..2bf55cf 100644 --- a/Bloxstrap/JsonManager.cs +++ b/Bloxstrap/JsonManager.cs @@ -13,6 +13,8 @@ namespace Bloxstrap /// public string? LastFileHash { get; private set; } + public bool Loaded { get; set; } = false; + public virtual string ClassName => typeof(T).Name; public virtual string FileLocation => Path.Combine(Paths.Base, $"{ClassName}.json"); @@ -35,6 +37,7 @@ namespace Bloxstrap throw new ArgumentNullException("Deserialization returned null"); Prop = settings; + Loaded = true; LastFileHash = MD5Hash.FromString(contents); App.Logger.WriteLine(LOG_IDENT, "Loaded successfully!"); diff --git a/Bloxstrap/Models/Persistable/Settings.cs b/Bloxstrap/Models/Persistable/Settings.cs index eb9c273..13f834c 100644 --- a/Bloxstrap/Models/Persistable/Settings.cs +++ b/Bloxstrap/Models/Persistable/Settings.cs @@ -10,6 +10,8 @@ namespace Bloxstrap.Models.Persistable public string BootstrapperTitle { get; set; } = App.ProjectName; public string BootstrapperIconCustomLocation { get; set; } = ""; public Theme Theme { get; set; } = Theme.Default; + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public bool DeveloperMode { get; set; } = false; public bool CheckForUpdates { get; set; } = true; public bool MultiInstanceLaunching { get; set; } = false; public bool ConfirmLaunches { get; set; } = false; @@ -21,6 +23,7 @@ namespace Bloxstrap.Models.Persistable public bool BackgroundUpdatesEnabled { get; set; } = true; public bool DebugDisableVersionPackageCleanup { get; set; } = false; public string? SelectedCustomTheme { get; set; } = null; + public WebEnvironment WebEnvironment { get; set; } = WebEnvironment.Production; // integration configuration public bool EnableActivityTracking { get; set; } = true; diff --git a/Bloxstrap/UI/Elements/Settings/Pages/BloxstrapPage.xaml b/Bloxstrap/UI/Elements/Settings/Pages/BloxstrapPage.xaml index d4f731a..326f859 100644 --- a/Bloxstrap/UI/Elements/Settings/Pages/BloxstrapPage.xaml +++ b/Bloxstrap/UI/Elements/Settings/Pages/BloxstrapPage.xaml @@ -29,6 +29,14 @@ + + + + + diff --git a/Bloxstrap/UI/ViewModels/Settings/BloxstrapViewModel.cs b/Bloxstrap/UI/ViewModels/Settings/BloxstrapViewModel.cs index 63ce62f..b1eb626 100644 --- a/Bloxstrap/UI/ViewModels/Settings/BloxstrapViewModel.cs +++ b/Bloxstrap/UI/ViewModels/Settings/BloxstrapViewModel.cs @@ -1,4 +1,5 @@ -using System.Windows.Input; +using System.Windows; +using System.Windows.Input; using CommunityToolkit.Mvvm.Input; using ICSharpCode.SharpZipLib.Zip; using Microsoft.Win32; @@ -7,6 +8,8 @@ namespace Bloxstrap.UI.ViewModels.Settings { public class BloxstrapViewModel : NotifyPropertyChangedViewModel { + public WebEnvironment[] WebEnvironments => Enum.GetValues(); + public bool UpdateCheckingEnabled { get => App.Settings.Prop.CheckForUpdates; @@ -19,6 +22,14 @@ namespace Bloxstrap.UI.ViewModels.Settings set => App.Settings.Prop.EnableAnalytics = value; } + public WebEnvironment WebEnvironment + { + get => App.Settings.Prop.WebEnvironment; + set => App.Settings.Prop.WebEnvironment = value; + } + + public Visibility WebEnvironmentVisibility => App.Settings.Prop.DeveloperMode ? Visibility.Visible : Visibility.Collapsed; + public bool ShouldExportConfig { get; set; } = true; public bool ShouldExportLogs { get; set; } = true; From f75d755e9e434f16dc13c4bb17f4e309ea1afc86 Mon Sep 17 00:00:00 2001 From: bluepilledgreat <97983689+bluepilledgreat@users.noreply.github.com> Date: Thu, 20 Mar 2025 16:40:09 +0000 Subject: [PATCH 17/22] fix build warnings --- Bloxstrap/Extensions/TEnumEx.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Bloxstrap/Extensions/TEnumEx.cs b/Bloxstrap/Extensions/TEnumEx.cs index ddefb8f..971334d 100644 --- a/Bloxstrap/Extensions/TEnumEx.cs +++ b/Bloxstrap/Extensions/TEnumEx.cs @@ -7,11 +7,11 @@ namespace Bloxstrap.Extensions { public static string? GetDescription(this TEnum e) { - string? enumName = e.ToString(); + string? enumName = e?.ToString(); if (enumName == null) return null; - FieldInfo? field = e.GetType().GetField(enumName); + FieldInfo? field = e?.GetType().GetField(enumName); if (field == null) return null; From 4dcb72b27f24cbba7a32695bfc8a9f6e1e351214 Mon Sep 17 00:00:00 2001 From: Matt <97983689+bluepilledgreat@users.noreply.github.com> Date: Tue, 25 Mar 2025 09:02:44 +0000 Subject: [PATCH 18/22] Add help link to web environments (#4934) --- Bloxstrap/UI/Elements/Settings/Pages/BloxstrapPage.xaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Bloxstrap/UI/Elements/Settings/Pages/BloxstrapPage.xaml b/Bloxstrap/UI/Elements/Settings/Pages/BloxstrapPage.xaml index 326f859..75d050e 100644 --- a/Bloxstrap/UI/Elements/Settings/Pages/BloxstrapPage.xaml +++ b/Bloxstrap/UI/Elements/Settings/Pages/BloxstrapPage.xaml @@ -33,7 +33,8 @@ + Description="Site to use for metrics" + HelpLink="https://admin.bloxstraplabs.com/Wiki/Developers/Web-Environments"> From 0f13750d7cb65c3c802b96a8adb84d25b70ebecc Mon Sep 17 00:00:00 2001 From: bluepilledgreat <97983689+bluepilledgreat@users.noreply.github.com> Date: Tue, 25 Mar 2025 09:05:17 +0000 Subject: [PATCH 19/22] make background updates opt-in --- Bloxstrap/Models/Persistable/Settings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bloxstrap/Models/Persistable/Settings.cs b/Bloxstrap/Models/Persistable/Settings.cs index 13f834c..eebf03d 100644 --- a/Bloxstrap/Models/Persistable/Settings.cs +++ b/Bloxstrap/Models/Persistable/Settings.cs @@ -20,7 +20,7 @@ namespace Bloxstrap.Models.Persistable public bool UseFastFlagManager { get; set; } = true; public bool WPFSoftwareRender { get; set; } = false; public bool EnableAnalytics { get; set; } = true; - public bool BackgroundUpdatesEnabled { get; set; } = true; + public bool BackgroundUpdatesEnabled { get; set; } = false; public bool DebugDisableVersionPackageCleanup { get; set; } = false; public string? SelectedCustomTheme { get; set; } = null; public WebEnvironment WebEnvironment { get; set; } = WebEnvironment.Production; From 18ca67df274b1f0328f3ae2d12decd50cca1f373 Mon Sep 17 00:00:00 2001 From: bluepilledgreat <97983689+bluepilledgreat@users.noreply.github.com> Date: Tue, 25 Mar 2025 09:06:36 +0000 Subject: [PATCH 20/22] update name (#4906) --- Bloxstrap/UI/Elements/About/Pages/AboutPage.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bloxstrap/UI/Elements/About/Pages/AboutPage.xaml b/Bloxstrap/UI/Elements/About/Pages/AboutPage.xaml index 486cd12..2b6d6ed 100644 --- a/Bloxstrap/UI/Elements/About/Pages/AboutPage.xaml +++ b/Bloxstrap/UI/Elements/About/Pages/AboutPage.xaml @@ -127,7 +127,7 @@ - + From 055695e014262afea29dd83ee45f39d4ff4c4183 Mon Sep 17 00:00:00 2001 From: bluepilledgreat <97983689+bluepilledgreat@users.noreply.github.com> Date: Tue, 25 Mar 2025 09:10:45 +0000 Subject: [PATCH 21/22] update cancel button text in the simple template --- Bloxstrap/Resources/CustomBootstrapperTemplate_Simple.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bloxstrap/Resources/CustomBootstrapperTemplate_Simple.xml b/Bloxstrap/Resources/CustomBootstrapperTemplate_Simple.xml index abe586d..bb3b1d1 100644 --- a/Bloxstrap/Resources/CustomBootstrapperTemplate_Simple.xml +++ b/Bloxstrap/Resources/CustomBootstrapperTemplate_Simple.xml @@ -5,5 +5,5 @@ -