diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 247eb15..d0ce08d 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -7,9 +7,10 @@ body: value: | ### **Preliminary instructions** - Before opening an issue, please [check the Wiki first](https://github.com/pizzaboxer/bloxstrap/wiki/) to see if your problem has been addressed there. - - **[Read this if Roblox is crashing or not launching](https://github.com/pizzaboxer/bloxstrap/wiki/Roblox-crashes-or-does-not-launch).** Only open an issue for it if this does not address your problem. + - If it isn't, please confirm which pages that you read that were relevant to your issue. + - If your problem is with Roblox itself (i.e. it crashes or doesn't launch), [check to see if it happens without Bloxstrap](https://github.com/pizzaboxer/bloxstrap/wiki/Roblox-crashes-or-does-not-launch). + - Please only open an issue if your problem happens only with Bloxstrap, and state clearly that this is the case, as anything else is out of my control. - If you are getting a Bloxstrap Exception error, please attach a copy of the provided log file. There is a button on the dialog that locates it for you. - - If your problem is with Roblox itself, [check to see if it happens without Bloxstrap](https://github.com/pizzaboxer/bloxstrap/wiki/Roblox-crashes-or-does-not-launch). Please only open an issue if your problem only happens with Bloxstrap, as anything else is out of my control. - If more clarification on the issue is needed, and you don't respond after a month, then your issue will be closed as stale. - type: checkboxes id: terms diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a504126..9438a2a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: with: submodules: true - - uses: actions/setup-dotnet@v3 + - uses: actions/setup-dotnet@v4 with: dotnet-version: '6.0.x' @@ -28,7 +28,7 @@ jobs: run: dotnet publish -p:PublishSingleFile=true -p:CommitHash=${{ github.sha }} -p:CommitRef=${{ github.ref_type }}/${{ github.ref_name }} -r win-x64 -c ${{ matrix.configuration }} --self-contained false .\Bloxstrap\Bloxstrap.csproj - name: Upload Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: Bloxstrap (${{ matrix.configuration }}) path: | @@ -41,7 +41,7 @@ jobs: steps: - name: Download x64 release artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: Bloxstrap (Release) path: x64 @@ -51,7 +51,7 @@ jobs: mv x64/Bloxstrap.exe Bloxstrap-${{ github.ref_name }}.exe - name: Release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 with: draft: true files: | diff --git a/Bloxstrap/App.xaml.cs b/Bloxstrap/App.xaml.cs index 8421d8d..f6e7072 100644 --- a/Bloxstrap/App.xaml.cs +++ b/Bloxstrap/App.xaml.cs @@ -27,12 +27,7 @@ namespace Bloxstrap 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()!; public static string Version = Assembly.GetExecutingAssembly().GetName().Version!.ToString()[..^2]; @@ -96,13 +91,22 @@ namespace Bloxstrap _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"; @@ -122,47 +126,10 @@ namespace Bloxstrap // 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()) { @@ -175,7 +142,7 @@ namespace Bloxstrap // just in case the user decides to cancel the install if (!IsFirstRun) { - Logger.Initialize(IsUninstall); + Logger.Initialize(LaunchSettings.IsUninstall); if (!Logger.Initialized) { @@ -188,18 +155,15 @@ namespace Bloxstrap 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(); @@ -211,7 +175,7 @@ namespace Bloxstrap } 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 @@ -219,152 +183,95 @@ namespace Bloxstrap 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]}"; - - launchMode = LaunchMode.Player; - } - else if (LaunchArgs[0].StartsWith("roblox-studio:")) - { - commandLine = ProtocolHandler.ParseUri(LaunchArgs[0]); - - if (!commandLine.Contains("-startEvent")) - commandLine += " -startEvent www.roblox.com/robloxQTStudioStartedEvent"; - - launchMode = LaunchMode.Studio; - } - else if (LaunchArgs[0].StartsWith("roblox-studio-auth:")) - { - commandLine = HttpUtility.UrlDecode(LaunchArgs[0]); - - launchMode = LaunchMode.StudioAuth; - } - else if (LaunchArgs[0] == "-ide") - { - launchMode = LaunchMode.Studio; - - if (LaunchArgs.Length >= 2) - commandLine = $"-task EditFile -localPlaceFile \"{LaunchArgs[1]}\""; - } - else - { - commandLine = "--app"; - - launchMode = LaunchMode.Player; - } - } - else - { - commandLine = "--app"; - - launchMode = LaunchMode.Player; + StartupFinished(); + return; } - 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(LaunchSettings.RobloxLaunchArgs, LaunchSettings.RobloxLaunchMode); + IBootstrapperDialog? dialog = null; + + if (!LaunchSettings.IsQuiet) { - 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; + Logger.WriteLine(LOG_IDENT, "Initializing bootstrapper dialog"); + dialog = Settings.Prop.BootstrapperStyle.GetNew(); + bootstrapper.Dialog = dialog; + dialog.Bootstrapper = bootstrapper; + } - if (!IsQuiet) + // 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 && LaunchSettings.RobloxLaunchMode == LaunchMode.Player) + { + Logger.WriteLine(LOG_IDENT, "Creating singleton mutex"); + + 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(); } } } diff --git a/Bloxstrap/Bloxstrap.csproj b/Bloxstrap/Bloxstrap.csproj index e551a10..aa1b921 100644 --- a/Bloxstrap/Bloxstrap.csproj +++ b/Bloxstrap/Bloxstrap.csproj @@ -7,8 +7,8 @@ true True Bloxstrap.ico - 2.5.3 - 2.5.3.0 + 2.6.0 + 2.6.0.0 app.manifest @@ -40,7 +40,7 @@ - + all diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index bd93f9e..6214e2e 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -99,10 +99,6 @@ namespace Bloxstrap message = message.Replace("{product}", productName); - // yea idk - if (App.Settings.Prop.BootstrapperStyle == BootstrapperStyle.ByfronDialog) - message = message.Replace("...", ""); - if (Dialog is not null) Dialog.Message = message; } @@ -127,7 +123,7 @@ namespace Bloxstrap App.Logger.WriteLine(LOG_IDENT, "Running bootstrapper"); - if (App.IsUninstall) + if (App.LaunchSettings.IsUninstall) { Uninstall(); return; @@ -230,9 +226,9 @@ namespace Bloxstrap 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(); } @@ -306,7 +302,7 @@ namespace Bloxstrap 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(); @@ -659,7 +655,7 @@ namespace Bloxstrap FileName = downloadLocation, }; - foreach (string arg in App.LaunchArgs) + foreach (string arg in App.LaunchSettings.Args) startInfo.ArgumentList.Add(arg); App.Settings.Save(); @@ -703,13 +699,13 @@ namespace Bloxstrap { foreach (Process process in Process.GetProcessesByName(App.RobloxPlayerAppName)) { - process.CloseMainWindow(); + process.Kill(); process.Close(); } foreach (Process process in Process.GetProcessesByName(App.RobloxStudioAppName)) { - process.CloseMainWindow(); + process.Kill(); process.Close(); } } diff --git a/Bloxstrap/Enums/BootstrapperStyle.cs b/Bloxstrap/Enums/BootstrapperStyle.cs index 2d1b063..118f3d2 100644 --- a/Bloxstrap/Enums/BootstrapperStyle.cs +++ b/Bloxstrap/Enums/BootstrapperStyle.cs @@ -7,6 +7,8 @@ LegacyDialog2011, ProgressDialog, FluentDialog, - ByfronDialog + ByfronDialog, + ProgressFluentDialog, + ProgressFluentAeroDialog } } diff --git a/Bloxstrap/Extensions/BootstrapperStyleEx.cs b/Bloxstrap/Extensions/BootstrapperStyleEx.cs index b170629..0681e54 100644 --- a/Bloxstrap/Extensions/BootstrapperStyleEx.cs +++ b/Bloxstrap/Extensions/BootstrapperStyleEx.cs @@ -3,5 +3,16 @@ static class BootstrapperStyleEx { public static IBootstrapperDialog GetNew(this BootstrapperStyle bootstrapperStyle) => Frontend.GetBootstrapperDialog(bootstrapperStyle); + + public static IReadOnlyCollection Selections => new BootstrapperStyle[] + { + BootstrapperStyle.FluentDialog, + BootstrapperStyle.ProgressFluentDialog, + BootstrapperStyle.ProgressFluentAeroDialog, + BootstrapperStyle.ByfronDialog, + BootstrapperStyle.LegacyDialog2011, + BootstrapperStyle.LegacyDialog2008, + BootstrapperStyle.VistaDialog + }; } } diff --git a/Bloxstrap/InstallChecker.cs b/Bloxstrap/InstallChecker.cs index 2524928..d3237d2 100644 --- a/Bloxstrap/InstallChecker.cs +++ b/Bloxstrap/InstallChecker.cs @@ -124,7 +124,7 @@ namespace Bloxstrap App.BaseDirectory = Path.Combine(Paths.LocalAppData, App.ProjectName); App.Logger.Initialize(true); - if (App.IsQuiet) + if (App.LaunchSettings.IsQuiet) return; App.IsSetupComplete = false; @@ -159,7 +159,7 @@ namespace Bloxstrap MessageBoxResult result; // silently upgrade version if the command line flag is set or if we're launching from an auto update - if (App.IsUpgrade || isAutoUpgrade) + if (App.LaunchSettings.IsUpgrade || isAutoUpgrade) { result = MessageBoxResult.Yes; } @@ -238,7 +238,7 @@ namespace Bloxstrap (_, _) => Utilities.ShellExecute($"https://github.com/{App.ProjectRepository}/releases/tag/v{currentVersionInfo.ProductVersion}") ); } - else if (!App.IsQuiet) + else if (!App.LaunchSettings.IsQuiet) { Frontend.ShowMessageBox( string.Format(Resources.Strings.InstallChecker_Updated, currentVersionInfo.ProductVersion), diff --git a/Bloxstrap/Integrations/ActivityWatcher.cs b/Bloxstrap/Integrations/ActivityWatcher.cs index 857b410..142eba8 100644 --- a/Bloxstrap/Integrations/ActivityWatcher.cs +++ b/Bloxstrap/Integrations/ActivityWatcher.cs @@ -60,7 +60,7 @@ int delay = 1000; - if (App.Settings.Prop.OhHeyYouFoundMe) + if (App.Settings.Prop.PowerTools) delay = 250; string logDirectory = Path.Combine(Paths.LocalAppData, "Roblox\\logs"); diff --git a/Bloxstrap/InterProcessLock.cs b/Bloxstrap/InterProcessLock.cs new file mode 100644 index 0000000..e1938e8 --- /dev/null +++ b/Bloxstrap/InterProcessLock.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Bloxstrap +{ + public class InterProcessLock : IDisposable + { + public Mutex Mutex { get; private set; } + + public bool IsAcquired { get; private set; } + + public InterProcessLock(string name, TimeSpan timeout) + { + Mutex = new Mutex(false, "Bloxstrap-" + name); + IsAcquired = Mutex.WaitOne(timeout); + } + + public void Dispose() + { + if (IsAcquired) + { + Mutex.ReleaseMutex(); + IsAcquired = false; + } + } + } +} diff --git a/Bloxstrap/LaunchSettings.cs b/Bloxstrap/LaunchSettings.cs new file mode 100644 index 0000000..16765fa --- /dev/null +++ b/Bloxstrap/LaunchSettings.cs @@ -0,0 +1,181 @@ +using Bloxstrap.Enums; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Windows; + +namespace Bloxstrap +{ + public class LaunchSettings + { + [LaunchFlag(new[] { "-preferences", "-menu" })] + public bool IsMenuLaunch { get; private set; } = false; + + [LaunchFlag("-quiet")] + public bool IsQuiet { get; private set; } = false; + + [LaunchFlag("-uninstall")] + public bool IsUninstall { get; private set; } = false; + + [LaunchFlag("-nolaunch")] + public bool IsNoLaunch { get; private set; } = false; + + [LaunchFlag("-upgrade")] + public bool IsUpgrade { get; private set; } = false; + + public LaunchMode RobloxLaunchMode { get; private set; } = LaunchMode.Player; + + public string RobloxLaunchArgs { get; private set; } = "--app"; + + /// + /// Original launch arguments + /// + public string[] Args { get; private set; } + + private Dictionary? _flagMap; + + // pizzaboxer wanted this + private void ParseLaunchFlagProps() + { + _flagMap = new Dictionary(); + + foreach (var prop in typeof(LaunchSettings).GetProperties()) + { + var attr = prop.GetCustomAttribute(); + + if (attr == null) + continue; + + if (!string.IsNullOrEmpty(attr.Name)) + { + _flagMap[attr.Name] = prop; + } + else + { + foreach (var name in attr.Names!) + _flagMap[name] = prop; + } + } + } + + private void ParseFlag(string arg) + { + const string LOG_IDENT = "LaunchSettings::ParseFlag"; + + arg = arg.ToLowerInvariant(); + + if (_flagMap!.ContainsKey(arg)) + { + var prop = _flagMap[arg]; + prop.SetValue(this, true); + App.Logger.WriteLine(LOG_IDENT, $"Started with {prop.Name} flag"); + } + } + + private void ParseRoblox(string arg, ref int i) + { + if (arg.StartsWith("roblox-player:")) + { + RobloxLaunchArgs = ProtocolHandler.ParseUri(arg); + + RobloxLaunchMode = LaunchMode.Player; + } + else if (arg.StartsWith("roblox:")) + { + if (App.Settings.Prop.UseDisableAppPatch) + Frontend.ShowMessageBox( + Resources.Strings.Bootstrapper_DeeplinkTempEnabled, + MessageBoxImage.Information + ); + + RobloxLaunchArgs = $"--app --deeplink {arg}"; + + RobloxLaunchMode = LaunchMode.Player; + } + else if (arg.StartsWith("roblox-studio:")) + { + RobloxLaunchArgs = ProtocolHandler.ParseUri(arg); + + if (!RobloxLaunchArgs.Contains("-startEvent")) + RobloxLaunchArgs += " -startEvent www.roblox.com/robloxQTStudioStartedEvent"; + + RobloxLaunchMode = LaunchMode.Studio; + } + else if (arg.StartsWith("roblox-studio-auth:")) + { + RobloxLaunchArgs = HttpUtility.UrlDecode(arg); + + RobloxLaunchMode = LaunchMode.StudioAuth; + } + else if (arg == "-ide") + { + RobloxLaunchMode = LaunchMode.Studio; + + if (Args.Length >= 2) + { + string pathArg = Args[i + 1]; + + if (pathArg.StartsWith('-')) + return; // likely a launch flag, ignore it. + + i++; // path arg + RobloxLaunchArgs = $"-task EditFile -localPlaceFile \"{pathArg}\""; + } + } + } + + private void Parse() + { + const string LOG_IDENT = "LaunchSettings::Parse"; + + App.Logger.WriteLine(LOG_IDENT, "Parsing launch arguments"); + +#if DEBUG + App.Logger.WriteLine(LOG_IDENT, $"Launch arguments: {string.Join(' ', Args)}"); +#endif + + if (Args.Length == 0) + { + App.Logger.WriteLine(LOG_IDENT, "No launch arguments to parse"); + return; + } + + int idx = 0; + string firstArg = Args[0]; + + // check & handle roblox arg + if (!firstArg.StartsWith('-') || firstArg == "-ide") + { + ParseRoblox(firstArg, ref idx); + idx++; // roblox arg + } + + // check if there are any launch flags + if (idx > Args.Length - 1) + return; + + App.Logger.WriteLine(LOG_IDENT, "Parsing launch flags"); + + // map out launch flags + ParseLaunchFlagProps(); + + // parse any launch flags + for (int i = idx; i < Args.Length; i++) + ParseFlag(Args[i]); + + // cleanup flag map + _flagMap!.Clear(); + _flagMap = null; + } + + public LaunchSettings(string[] args) + { + Args = args; + Parse(); + } + } +} diff --git a/Bloxstrap/Models/Attributes/LaunchFlagAttribute.cs b/Bloxstrap/Models/Attributes/LaunchFlagAttribute.cs new file mode 100644 index 0000000..60c3886 --- /dev/null +++ b/Bloxstrap/Models/Attributes/LaunchFlagAttribute.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Bloxstrap.Models.Attributes +{ + public class LaunchFlagAttribute : Attribute + { + public string? Name { get; private set; } + public string[]? Names { get; private set; } + + public LaunchFlagAttribute(string name) + { + Name = name; + } + + public LaunchFlagAttribute(string[] names) + { + Names = names; + } + } +} diff --git a/Bloxstrap/Models/Settings.cs b/Bloxstrap/Models/Settings.cs index 638052b..416d17c 100644 --- a/Bloxstrap/Models/Settings.cs +++ b/Bloxstrap/Models/Settings.cs @@ -13,7 +13,10 @@ namespace Bloxstrap.Models public bool CheckForUpdates { get; set; } = true; public bool CreateDesktopIcon { get; set; } = true; public bool MultiInstanceLaunching { get; set; } = false; - public bool OhHeyYouFoundMe { get; set; } = false; + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + [JsonPropertyName("OhHeyYouFoundMeAgain")] + public bool PowerTools { get; set; } = false; // channel configuration public string Channel { get; set; } = RobloxDeployment.DefaultChannel; diff --git a/Bloxstrap/Properties/PublishProfiles/Publish-x86.pubxml b/Bloxstrap/Properties/PublishProfiles/Publish-x86.pubxml deleted file mode 100644 index e6a7125..0000000 --- a/Bloxstrap/Properties/PublishProfiles/Publish-x86.pubxml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Release - Any CPU - bin\Release\net6.0-windows\publish\win-x86\ - FileSystem - <_TargetId>Folder - net6.0-windows - win-x86 - false - true - false - - \ No newline at end of file diff --git a/Bloxstrap/Resources/Strings.Designer.cs b/Bloxstrap/Resources/Strings.Designer.cs index b5fe355..4f01855 100644 --- a/Bloxstrap/Resources/Strings.Designer.cs +++ b/Bloxstrap/Resources/Strings.Designer.cs @@ -243,6 +243,24 @@ namespace Bloxstrap.Resources { } } + /// + /// Looks up a localized string similar to Style preview - Click the X button at the top right to close. + /// + public static string Bootstrapper_StylePreview_ImageCancel { + get { + return ResourceManager.GetString("Bootstrapper.StylePreview.ImageCancel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Style preview - Click Cancel to close. + /// + public static string Bootstrapper_StylePreview_TextCancel { + get { + return ResourceManager.GetString("Bootstrapper.StylePreview.TextCancel", resourceCulture); + } + } + /// /// Looks up a localized string similar to Bloxstrap has successfully installed. /// @@ -828,6 +846,24 @@ namespace Bloxstrap.Resources { } } + /// + /// Looks up a localized string similar to Fluent Progress (Aero). + /// + public static string Enums_BootstrapperStyle_ProgressFluentAeroDialog { + get { + return ResourceManager.GetString("Enums.BootstrapperStyle.ProgressFluentAeroDialog", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Fluent Progress. + /// + public static string Enums_BootstrapperStyle_ProgressFluentDialog { + get { + return ResourceManager.GetString("Enums.BootstrapperStyle.ProgressFluentDialog", resourceCulture); + } + } + /// /// Looks up a localized string similar to Vista (2008 - 2011). /// @@ -1426,7 +1462,7 @@ namespace Bloxstrap.Resources { } /// - /// Looks up a localized string similar to Bloxstrap 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.". + /// Looks up a localized string similar to Bloxstrap 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.. /// public static string Menu_AlreadyRunning { get { diff --git a/Bloxstrap/Resources/Strings.resx b/Bloxstrap/Resources/Strings.resx index 18b03f3..afaea78 100644 --- a/Bloxstrap/Resources/Strings.resx +++ b/Bloxstrap/Resources/Strings.resx @@ -180,6 +180,14 @@ Your ReShade configuration files will still be saved, and you can locate them by Waiting for other instances... + + Style preview - Click the X button at the top right to close + Text for style previews that use an X button. Currently only applies to Byfron + + + Style preview - Click Cancel to close + Text for style previews that use text button that says "Cancel" + Bloxstrap has successfully installed @@ -375,6 +383,12 @@ Your ReShade configuration files will still be saved, and you can locate them by Progress (~2014) + + Fluent Progress (Aero) + + + Fluent Progress + Vista (2008 - 2011) @@ -577,7 +591,7 @@ Would you like to upgrade your currently installed version? All files - Bloxstrap 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." + Bloxstrap 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. You can make it look different, retro, or even just like Roblox. diff --git a/Bloxstrap/UI/Elements/Bootstrapper/ByfronDialog.xaml b/Bloxstrap/UI/Elements/Bootstrapper/ByfronDialog.xaml index 1a0b6c8..bd965f7 100644 --- a/Bloxstrap/UI/Elements/Bootstrapper/ByfronDialog.xaml +++ b/Bloxstrap/UI/Elements/Bootstrapper/ByfronDialog.xaml @@ -14,7 +14,7 @@ Closing="Window_Closing"> - +