diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 12e90d4..00cd191 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -5,6 +5,10 @@ body: - type: markdown attributes: value: | + > [!IMPORTANT] + > Do NOT open an issue if you're getting an error saying "`The given key 'redist.zip' was not present in the dictionary.`", or if you're getting stuck on "Configuring Roblox...". + > This problem has been fixed in the latest version of Bloxstrap. You either have auto-updates disabled or are using someone's custom build of an old version. + > Download the latest version [here](https://github.com/pizzaboxer/bloxstrap/releases/latest). ### **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. - If it isn't, please confirm which pages that you read that were relevant to your issue. @@ -26,6 +30,14 @@ body: - label: I am using the latest version of Bloxstrap. required: true - label: I did not answer truthfully to all the above checkboxes. + - type: input + id: version + attributes: + label: Bloxstrap Version + description: "What version of Bloxstrap are you using? Find it in the 'About' section of the Settings" + placeholder: "v1.0.0" + validations: + required: true - type: textarea id: what-happened attributes: @@ -39,4 +51,4 @@ body: label: Bloxstrap Log description: If you're getting a Bloxstrap Exception error, upload your log file here. Otherwise, just leave it empty. value: "N/A" - #render: text + render: text diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index 39087c1..caf8255 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -39,23 +39,17 @@ jobs: if: startsWith(github.ref, 'refs/tags/v') steps: - # - name: Sign and download artifact - # uses: signpath/github-action-submit-signing-request@v1 - # with: - # api-token: '${{ secrets.SIGNPATH_API_TOKEN }}' - # organization-id: '107b3de5-057b-42fc-a985-3546e4261775' - # project-slug: 'bloxstrap' - # signing-policy-slug: 'release-signing' - # artifact-configuration-slug: 'github-ci' - # github-artifact-id: '${{ needs.build.outputs.artifact-id }}' - # wait-for-completion: true - # output-artifact-directory: 'release' - - - name: Download x64 release artifact - uses: actions/download-artifact@v4 + - name: Sign and download artifact + uses: signpath/github-action-submit-signing-request@v1 with: - name: Bloxstrap (Release) (${{ github.sha }}) - path: release + api-token: '${{ secrets.SIGNPATH_API_TOKEN }}' + organization-id: '107b3de5-057b-42fc-a985-3546e4261775' + project-slug: 'bloxstrap' + signing-policy-slug: 'release-signing' + artifact-configuration-slug: 'github-ci' + github-artifact-id: '${{ needs.build.outputs.artifact-id }}' + wait-for-completion: true + output-artifact-directory: 'release' - name: Rename binaries run: mv release/Bloxstrap.exe Bloxstrap-${{ github.ref_name }}.exe @@ -79,7 +73,7 @@ jobs: api-token: '${{ secrets.SIGNPATH_API_TOKEN }}' organization-id: '107b3de5-057b-42fc-a985-3546e4261775' project-slug: 'bloxstrap' - signing-policy-slug: 'test-signing' + signing-policy-slug: 'release-signing' artifact-configuration-slug: 'github-ci' github-artifact-id: '${{ needs.build.outputs.artifact-id }}' wait-for-completion: true diff --git a/Bloxstrap/App.xaml.cs b/Bloxstrap/App.xaml.cs index cfc86ab..4fd8b79 100644 --- a/Bloxstrap/App.xaml.cs +++ b/Bloxstrap/App.xaml.cs @@ -1,6 +1,7 @@ using System.Reflection; using System.Security.Cryptography; using System.Windows; +using System.Windows.Shell; using System.Windows.Threading; using Microsoft.Win32; @@ -35,6 +36,8 @@ namespace Bloxstrap public static string Version = Assembly.GetExecutingAssembly().GetName().Version!.ToString()[..^2]; + public static Bootstrapper? Bootstrapper { get; set; } = null!; + public static bool IsActionBuild => !String.IsNullOrEmpty(BuildMetadata.CommitRef); public static bool IsProductionBuild => IsActionBuild && BuildMetadata.CommitRef.StartsWith("tag", StringComparison.Ordinal); @@ -106,6 +109,16 @@ namespace Bloxstrap _showingExceptionDialog = true; + SendLog(); + + if (Bootstrapper?.Dialog != null) + { + if (Bootstrapper.Dialog.TaskbarProgressValue == 0) + Bootstrapper.Dialog.TaskbarProgressValue = 1; // make sure it's visible + + Bootstrapper.Dialog.TaskbarProgressState = TaskbarItemProgressState.Error; + } + Frontend.ShowExceptionDialog(ex); Terminate(ErrorCode.ERROR_INSTALL_FAILURE); @@ -150,6 +163,24 @@ namespace Bloxstrap } } + public static async void SendLog() + { + if (!Settings.Prop.EnableAnalytics || !IsProductionBuild) + return; + + try + { + await HttpClient.PostAsync( + $"https://bloxstraplabs.com/metrics/post-exception", + new StringContent(Logger.AsDocument) + ); + } + catch (Exception ex) + { + Logger.WriteException("App::SendLog", ex); + } + } + protected override void OnStartup(StartupEventArgs e) { const string LOG_IDENT = "App::OnStartup"; @@ -209,7 +240,6 @@ namespace Bloxstrap else { // check if user profile folder has been renamed - // honestly, i'll be expecting bugs from this var match = Regex.Match(value, @"^[a-zA-Z]:\\Users\\([^\\]+)", RegexOptions.IgnoreCase); if (match.Success) diff --git a/Bloxstrap/AppData/CommonAppData.cs b/Bloxstrap/AppData/CommonAppData.cs index 4a74118..54aaaa0 100644 --- a/Bloxstrap/AppData/CommonAppData.cs +++ b/Bloxstrap/AppData/CommonAppData.cs @@ -32,6 +32,7 @@ namespace Bloxstrap.AppData { "content-textures3.zip", @"PlatformContent\pc\textures\" }, { "content-terrain.zip", @"PlatformContent\pc\terrain\" }, { "content-platform-fonts.zip", @"PlatformContent\pc\fonts\" }, + { "content-platform-dictionaries.zip", @"PlatformContent\pc\shared_compression_dictionaries\" }, { "extracontent-luapackages.zip", @"ExtraContent\LuaPackages\" }, { "extracontent-translations.zip", @"ExtraContent\translations\" }, diff --git a/Bloxstrap/AppData/IAppData.cs b/Bloxstrap/AppData/IAppData.cs index b8a45c9..63a6b48 100644 --- a/Bloxstrap/AppData/IAppData.cs +++ b/Bloxstrap/AppData/IAppData.cs @@ -10,10 +10,10 @@ string ExecutableName { get; } - string StartEvent { get; } - string Directory { get; } + string OldDirectory { get; } + string LockFilePath { get; } string ExecutablePath { get; } diff --git a/Bloxstrap/AppData/RobloxPlayerData.cs b/Bloxstrap/AppData/RobloxPlayerData.cs index 923c6a1..6ec09a1 100644 --- a/Bloxstrap/AppData/RobloxPlayerData.cs +++ b/Bloxstrap/AppData/RobloxPlayerData.cs @@ -16,10 +16,10 @@ namespace Bloxstrap.AppData public override string ExecutableName => "RobloxPlayerBeta.exe"; - public string StartEvent => "www.roblox.com/robloxStartedEvent"; - public override string Directory => Path.Combine(Paths.Roblox, "Player"); + public string OldDirectory => Path.Combine(Paths.Roblox, "Player.old"); + public AppState State => App.State.Prop.Player; public override IReadOnlyDictionary PackageDirectoryMap { get; set; } = new Dictionary() diff --git a/Bloxstrap/AppData/RobloxStudioData.cs b/Bloxstrap/AppData/RobloxStudioData.cs index 73c630b..886e630 100644 --- a/Bloxstrap/AppData/RobloxStudioData.cs +++ b/Bloxstrap/AppData/RobloxStudioData.cs @@ -10,10 +10,10 @@ public override string ExecutableName => "RobloxStudioBeta.exe"; - public string StartEvent => "www.roblox.com/robloxStudioStartedEvent"; - public override string Directory => Path.Combine(Paths.Roblox, "Studio"); - + + public string OldDirectory => Path.Combine(Paths.Roblox, "Studio.old"); + public AppState State => App.State.Prop.Studio; public override IReadOnlyDictionary PackageDirectoryMap { get; set; } = new Dictionary() diff --git a/Bloxstrap/Bloxstrap.csproj b/Bloxstrap/Bloxstrap.csproj index 16b56e6..9f1b69a 100644 --- a/Bloxstrap/Bloxstrap.csproj +++ b/Bloxstrap/Bloxstrap.csproj @@ -7,8 +7,8 @@ true True Bloxstrap.ico - 2.8.0 - 2.8.0 + 2.8.1 + 2.8.1 app.manifest true false diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index 7e0b5ab..207c4a4 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -11,6 +11,8 @@ #warning "Automatic updater debugging is enabled" #endif +using System.ComponentModel; +using System.Data; using System.Windows; using System.Windows.Forms; using System.Windows.Shell; @@ -116,17 +118,21 @@ namespace Bloxstrap private void HandleConnectionError(Exception exception) { + const string LOG_IDENT = "Bootstrapper::HandleConnectionError"; + _noConnection = true; - string message = Strings.Dialog_Connectivity_Preventing; + App.Logger.WriteLine(LOG_IDENT, "Connectivity check failed"); + App.Logger.WriteException(LOG_IDENT, exception); - if (exception.GetType() == typeof(AggregateException)) + string message = Strings.Dialog_Connectivity_BadConnection; + + if (exception is AggregateException) exception = exception.InnerException!; - if (exception.GetType() == typeof(HttpRequestException)) + // https://gist.github.com/pizzaboxer/4b58303589ee5b14cc64397460a8f386 + if (exception is HttpRequestException && exception.InnerException is null) message = String.Format(Strings.Dialog_Connectivity_RobloxDown, "[status.roblox.com](https://status.roblox.com)"); - else if (exception.GetType() == typeof(TaskCanceledException)) - message = Strings.Dialog_Connectivity_TimedOut; if (_mustUpgrade) message += $"\n\n{Strings.Dialog_Connectivity_RobloxUpgradeNeeded}\n\n{Strings.Dialog_Connectivity_TryAgainLater}"; @@ -245,6 +251,10 @@ namespace Bloxstrap Dialog?.CloseBootstrapper(); } + /// + /// Will throw whatever HttpClient can throw + /// + /// private async Task GetLatestVersionInfo() { const string LOG_IDENT = "Bootstrapper::GetLatestVersionInfo"; @@ -255,7 +265,11 @@ namespace Bloxstrap using var key = Registry.CurrentUser.CreateSubKey($"SOFTWARE\\ROBLOX Corporation\\Environments\\{AppData.RegistryName}\\Channel"); - var match = Regex.Match(App.LaunchSettings.RobloxLaunchArgs, "channel:([a-zA-Z0-9-_]+)", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); + var match = Regex.Match( + App.LaunchSettings.RobloxLaunchArgs, + "channel:([a-zA-Z0-9-_]+)", + RegexOptions.IgnoreCase | RegexOptions.CultureInvariant + ); if (match.Groups.Count == 2) { @@ -266,9 +280,12 @@ namespace Bloxstrap Deployment.Channel = value.ToLowerInvariant(); } - App.Logger.WriteLine(LOG_IDENT, "Got channel as " + (String.IsNullOrEmpty(Deployment.Channel) ? Deployment.DefaultChannel : Deployment.Channel)); + if (String.IsNullOrEmpty(Deployment.Channel)) + Deployment.Channel = Deployment.DefaultChannel; - if (Deployment.Channel != "production") + App.Logger.WriteLine(LOG_IDENT, $"Got channel as {Deployment.DefaultChannel}"); + + if (!Deployment.IsDefaultChannel) App.SendStat("robloxChannel", Deployment.Channel); ClientVersion clientVersion; @@ -277,14 +294,9 @@ namespace Bloxstrap { clientVersion = await Deployment.GetInfo(); } - catch (HttpRequestException ex) + catch (InvalidChannelException ex) { - if (ex.StatusCode is not HttpStatusCode.Unauthorized - and not HttpStatusCode.Forbidden - and not HttpStatusCode.NotFound) - throw; - - App.Logger.WriteLine(LOG_IDENT, $"Changing channel from {Deployment.Channel} to {Deployment.DefaultChannel} because HTTP {(int)ex.StatusCode}"); + App.Logger.WriteLine(LOG_IDENT, $"Resetting channel from {Deployment.Channel} because {ex.StatusCode}"); Deployment.Channel = Deployment.DefaultChannel; clientVersion = await Deployment.GetInfo(); @@ -292,7 +304,7 @@ namespace Bloxstrap if (clientVersion.IsBehindDefaultChannel) { - App.Logger.WriteLine(LOG_IDENT, $"Changing channel from {Deployment.Channel} to {Deployment.DefaultChannel} because channel is behind production"); + App.Logger.WriteLine(LOG_IDENT, $"Resetting channel from {Deployment.Channel} because it's behind production"); Deployment.Channel = Deployment.DefaultChannel; clientVersion = await Deployment.GetInfo(); @@ -314,20 +326,15 @@ namespace Bloxstrap SetStatus(Strings.Bootstrapper_Status_Starting); - if (_launchMode == LaunchMode.Player) + if (_launchMode == LaunchMode.Player && App.Settings.Prop.ForceRobloxLanguage) { - if (App.Settings.Prop.ForceRobloxLanguage) - { - var match = Regex.Match(_launchCommandLine, "gameLocale:([a-z_]+)", RegexOptions.CultureInvariant); + 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.InvariantCultureIgnoreCase); - } - - if (!String.IsNullOrEmpty(_launchCommandLine)) - _launchCommandLine += " "; - - _launchCommandLine += "-isInstallerLaunch"; + if (match.Groups.Count == 2) + _launchCommandLine = _launchCommandLine.Replace( + "robloxLocale:en_us", + $"robloxLocale:{match.Groups[1].Value}", + StringComparison.OrdinalIgnoreCase); } var startInfo = new ProcessStartInfo() @@ -337,7 +344,12 @@ namespace Bloxstrap WorkingDirectory = AppData.Directory }; - if (_launchMode == LaunchMode.StudioAuth) + if (_launchMode == LaunchMode.Player && ShouldRunAsAdmin()) + { + startInfo.Verb = "runas"; + startInfo.UseShellExecute = true; + } + else if (_launchMode == LaunchMode.StudioAuth) { Process.Start(startInfo); return; @@ -345,66 +357,61 @@ namespace Bloxstrap string? logFileName = null; - using (var startEvent = new EventWaitHandle(false, EventResetMode.ManualReset, AppData.StartEvent)) + string rbxLogDir = Path.Combine(Paths.LocalAppData, "Roblox\\logs"); + + if (!Directory.Exists(rbxLogDir)) + Directory.CreateDirectory(rbxLogDir); + + var logWatcher = new FileSystemWatcher() { - startEvent.Reset(); + Path = rbxLogDir, + Filter = "*.log", + EnableRaisingEvents = true + }; - string rbxLogDir = Path.Combine(Paths.LocalAppData, "Roblox\\logs"); + var logCreatedEvent = new AutoResetEvent(false); - if (!Directory.Exists(rbxLogDir)) - Directory.CreateDirectory(rbxLogDir); + logWatcher.Created += (_, e) => + { + logWatcher.EnableRaisingEvents = false; + logFileName = e.FullPath; + logCreatedEvent.Set(); + }; - var logWatcher = new FileSystemWatcher() - { - Path = rbxLogDir, - Filter = "*.log", - EnableRaisingEvents = true - }; - - var logCreatedEvent = new AutoResetEvent(false); - - logWatcher.Created += (_, e) => - { - logWatcher.EnableRaisingEvents = false; - logFileName = e.FullPath; - logCreatedEvent.Set(); - }; - - // v2.2.0 - byfron will trip if we keep a process handle open for over a minute, so we're doing this now - try - { - using var process = Process.Start(startInfo)!; - _appPid = process.Id; - } - catch (Exception) - { - // attempt a reinstall on next launch - File.Delete(AppData.ExecutablePath); - throw; - } - - App.Logger.WriteLine(LOG_IDENT, $"Started Roblox (PID {_appPid}), waiting for start event"); - - if (startEvent.WaitOne(TimeSpan.FromSeconds(5))) - App.Logger.WriteLine(LOG_IDENT, "Start event signalled"); - else - App.Logger.WriteLine(LOG_IDENT, "Start event not signalled, implying successful launch"); - - logCreatedEvent.WaitOne(TimeSpan.FromSeconds(5)); - - if (String.IsNullOrEmpty(logFileName)) - { - App.Logger.WriteLine(LOG_IDENT, "Unable to identify log file"); - Frontend.ShowPlayerErrorDialog(); - return; - } - else - { - App.Logger.WriteLine(LOG_IDENT, $"Got log file as {logFileName}"); - } - - _mutex?.ReleaseAsync(); + // v2.2.0 - byfron will trip if we keep a process handle open for over a minute, so we're doing this now + try + { + using var process = Process.Start(startInfo)!; + _appPid = process.Id; } + catch (Win32Exception ex) when (ex.NativeErrorCode == 1223) + { + // 1223 = ERROR_CANCELLED, gets thrown if a UAC prompt is cancelled + return; + } + catch (Exception) + { + // attempt a reinstall on next launch + File.Delete(AppData.ExecutablePath); + throw; + } + + App.Logger.WriteLine(LOG_IDENT, $"Started Roblox (PID {_appPid}), waiting for log file"); + + logCreatedEvent.WaitOne(TimeSpan.FromSeconds(15)); + + if (String.IsNullOrEmpty(logFileName)) + { + App.Logger.WriteLine(LOG_IDENT, "Unable to identify log file"); + Frontend.ShowPlayerErrorDialog(); + return; + } + else + { + App.Logger.WriteLine(LOG_IDENT, $"Got log file as {logFileName}"); + } + + _mutex?.ReleaseAsync(); if (IsStudioLaunch) return; @@ -461,6 +468,27 @@ namespace Bloxstrap if (ipl.IsAcquired) Process.Start(Paths.Process, args); } + + // allow for window to show, since the log is created pretty far beforehand + Thread.Sleep(1000); + } + + private bool ShouldRunAsAdmin() + { + foreach (var root in WindowsRegistry.Roots) + { + using var key = root.OpenSubKey("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"); + + if (key is null) + continue; + + string? flags = (string?)key.GetValue(AppData.ExecutablePath); + + if (flags is not null && flags.Contains("RUNASADMIN", StringComparison.OrdinalIgnoreCase)) + return true; + } + + return false; } public void Cancel() @@ -636,21 +664,41 @@ namespace Bloxstrap if (Directory.Exists(AppData.Directory)) { + if (Directory.Exists(AppData.OldDirectory)) + Directory.Delete(AppData.OldDirectory, true); + try { - // gross hack to see if roblox is still running - // i don't want to rely on mutexes because they can change, and will false flag for - // running installations that are not by bloxstrap - File.Delete(AppData.ExecutablePath); + // test to see if any files are in use + // if you have a better way to check for this, please let me know! + Directory.Move(AppData.Directory, AppData.OldDirectory); } catch (Exception ex) { - App.Logger.WriteLine(LOG_IDENT, "Could not delete executable/folder, Roblox may still be running. Aborting update."); + App.Logger.WriteLine(LOG_IDENT, "Could not clear old files, aborting update."); App.Logger.WriteException(LOG_IDENT, ex); + + // 0x80070020 is the HRESULT that indicates that a process is still running + // (either RobloxPlayerBeta or RobloxCrashHandler), so we'll silently ignore it + if ((uint)ex.HResult != 0x80070020) + { + // ensure no files are marked as read-only for good measure + foreach (var file in Directory.GetFiles(AppData.Directory, "*", SearchOption.AllDirectories)) + Filesystem.AssertReadOnly(file); + + Frontend.ShowMessageBox( + Strings.Bootstrapper_FilesInUse, + _mustUpgrade ? MessageBoxImage.Error : MessageBoxImage.Warning + ); + + if (_mustUpgrade) + App.Terminate(ErrorCode.ERROR_CANCELLED); + } + return; } - Directory.Delete(AppData.Directory, true); + Directory.Delete(AppData.OldDirectory, true); } _isInstalling = true; @@ -1010,6 +1058,8 @@ namespace Bloxstrap if (_cancelTokenSource.IsCancellationRequested) return; + Directory.CreateDirectory(Paths.Downloads); + string packageUrl = Deployment.GetLocation($"/{_latestVersionGuid}-{package.Name}"); string robloxPackageLocation = Path.Combine(Paths.LocalAppData, "Roblox", "Downloads", package.Signature); @@ -1053,9 +1103,6 @@ namespace Bloxstrap const int maxTries = 5; - bool statIsRetrying = false; - bool statIsHttp = false; - App.Logger.WriteLine(LOG_IDENT, "Downloading..."); var buffer = new byte[4096]; @@ -1108,8 +1155,6 @@ namespace Bloxstrap App.Logger.WriteLine(LOG_IDENT, $"An exception occurred after downloading {totalBytesRead} bytes. ({i}/{maxTries})"); App.Logger.WriteException(LOG_IDENT, ex); - statIsRetrying = true; - if (ex.GetType() == typeof(ChecksumFailedException)) { App.SendStat("packageDownloadState", "httpFail"); @@ -1139,20 +1184,24 @@ namespace Bloxstrap { App.Logger.WriteLine(LOG_IDENT, "Retrying download over HTTP..."); packageUrl = packageUrl.Replace("https://", "http://"); - statIsHttp = true; } } } - - if (statIsRetrying) - App.SendStat("packageDownloadState", statIsHttp ? "httpSuccess" : "retrySuccess"); } private void ExtractPackage(Package package, List? files = null) { const string LOG_IDENT = "Bootstrapper::ExtractPackage"; - string packageFolder = Path.Combine(AppData.Directory, AppData.PackageDirectoryMap[package.Name]); + string? packageDir = AppData.PackageDirectoryMap.GetValueOrDefault(package.Name); + + if (packageDir is null) + { + App.Logger.WriteLine(LOG_IDENT, $"WARNING: {package.Name} was not found in the package map!"); + return; + } + + string packageFolder = Path.Combine(AppData.Directory, packageDir); string? fileFilter = null; // for sharpziplib, each file in the filter needs to be a regex diff --git a/Bloxstrap/Enums/BootstrapperIcon.cs b/Bloxstrap/Enums/BootstrapperIcon.cs index 8706e82..4125cc6 100644 --- a/Bloxstrap/Enums/BootstrapperIcon.cs +++ b/Bloxstrap/Enums/BootstrapperIcon.cs @@ -17,6 +17,8 @@ [EnumName(StaticName = "2022")] Icon2022, [EnumName(FromTranslation = "Common.Custom")] - IconCustom + IconCustom, + [EnumName(FromTranslation = "Enums.BootstrapperStyle.ClassicFluentDialog")] + IconBloxstrapClassic } } diff --git a/Bloxstrap/Exceptions/InvalidChannelException.cs b/Bloxstrap/Exceptions/InvalidChannelException.cs new file mode 100644 index 0000000..eff6d79 --- /dev/null +++ b/Bloxstrap/Exceptions/InvalidChannelException.cs @@ -0,0 +1,10 @@ +namespace Bloxstrap.Exceptions +{ + public class InvalidChannelException : Exception + { + public HttpStatusCode? StatusCode; + + public InvalidChannelException(HttpStatusCode? statusCode) : base() + => StatusCode = statusCode; + } +} diff --git a/Bloxstrap/Extensions/BootstrapperIconEx.cs b/Bloxstrap/Extensions/BootstrapperIconEx.cs index b2df13c..943cad6 100644 --- a/Bloxstrap/Extensions/BootstrapperIconEx.cs +++ b/Bloxstrap/Extensions/BootstrapperIconEx.cs @@ -14,6 +14,7 @@ namespace Bloxstrap.Extensions BootstrapperIcon.IconEarly2015, BootstrapperIcon.Icon2011, BootstrapperIcon.Icon2008, + BootstrapperIcon.IconBloxstrapClassic, BootstrapperIcon.IconCustom }; @@ -61,6 +62,7 @@ namespace Bloxstrap.Extensions BootstrapperIcon.Icon2017 => Properties.Resources.Icon2017, BootstrapperIcon.Icon2019 => Properties.Resources.Icon2019, BootstrapperIcon.Icon2022 => Properties.Resources.Icon2022, + BootstrapperIcon.IconBloxstrapClassic => Properties.Resources.IconBloxstrapClassic, _ => Properties.Resources.IconBloxstrap }; } diff --git a/Bloxstrap/FastFlagManager.cs b/Bloxstrap/FastFlagManager.cs index 284df3d..689299e 100644 --- a/Bloxstrap/FastFlagManager.cs +++ b/Bloxstrap/FastFlagManager.cs @@ -39,17 +39,17 @@ namespace Bloxstrap { "UI.FullscreenTitlebarDelay", "FIntFullscreenTitleBarTriggerDelayMillis" }, - { "UI.Menu.Style.V2Rollout", "FIntNewInGameMenuPercentRollout3" }, - { "UI.Menu.Style.EnableV4.1", "FFlagEnableInGameMenuControls" }, - { "UI.Menu.Style.EnableV4.2", "FFlagEnableInGameMenuModernization" }, - { "UI.Menu.Style.EnableV4Chrome", "FFlagEnableInGameMenuChrome" }, - { "UI.Menu.Style.ReportButtonCutOff", "FFlagFixReportButtonCutOff" }, + //{ "UI.Menu.Style.V2Rollout", "FIntNewInGameMenuPercentRollout3" }, + //{ "UI.Menu.Style.EnableV4.1", "FFlagEnableInGameMenuControls" }, + //{ "UI.Menu.Style.EnableV4.2", "FFlagEnableInGameMenuModernization" }, + //{ "UI.Menu.Style.EnableV4Chrome", "FFlagEnableInGameMenuChrome" }, + //{ "UI.Menu.Style.ReportButtonCutOff", "FFlagFixReportButtonCutOff" }, - { "UI.Menu.Style.ABTest.1", "FFlagEnableMenuControlsABTest" }, - { "UI.Menu.Style.ABTest.2", "FFlagEnableV3MenuABTest3" }, - { "UI.Menu.Style.ABTest.3", "FFlagEnableInGameMenuChromeABTest3" }, - { "UI.Menu.Style.ABTest.4", "FFlagEnableInGameMenuChromeABTest4" } + //{ "UI.Menu.Style.ABTest.1", "FFlagEnableMenuControlsABTest" }, + //{ "UI.Menu.Style.ABTest.2", "FFlagEnableV3MenuABTest3" }, + //{ "UI.Menu.Style.ABTest.3", "FFlagEnableInGameMenuChromeABTest3" }, + //{ "UI.Menu.Style.ABTest.4", "FFlagEnableInGameMenuChromeABTest4" } }; public static IReadOnlyDictionary RenderingModes => new Dictionary @@ -86,68 +86,68 @@ namespace Bloxstrap // this is one hell of a dictionary definition lmao // since these all set the same flags, wouldn't making this use bitwise operators be better? - public static IReadOnlyDictionary> IGMenuVersions => new Dictionary> - { - { - InGameMenuVersion.Default, - new Dictionary - { - { "V2Rollout", null }, - { "EnableV4", null }, - { "EnableV4Chrome", null }, - { "ABTest", null }, - { "ReportButtonCutOff", null } - } - }, + //public static IReadOnlyDictionary> IGMenuVersions => new Dictionary> + //{ + // { + // InGameMenuVersion.Default, + // new Dictionary + // { + // { "V2Rollout", null }, + // { "EnableV4", null }, + // { "EnableV4Chrome", null }, + // { "ABTest", null }, + // { "ReportButtonCutOff", null } + // } + // }, - { - InGameMenuVersion.V1, - new Dictionary - { - { "V2Rollout", "0" }, - { "EnableV4", "False" }, - { "EnableV4Chrome", "False" }, - { "ABTest", "False" }, - { "ReportButtonCutOff", "False" } - } - }, + // { + // InGameMenuVersion.V1, + // new Dictionary + // { + // { "V2Rollout", "0" }, + // { "EnableV4", "False" }, + // { "EnableV4Chrome", "False" }, + // { "ABTest", "False" }, + // { "ReportButtonCutOff", "False" } + // } + // }, - { - InGameMenuVersion.V2, - new Dictionary - { - { "V2Rollout", "100" }, - { "EnableV4", "False" }, - { "EnableV4Chrome", "False" }, - { "ABTest", "False" }, - { "ReportButtonCutOff", null } - } - }, + // { + // InGameMenuVersion.V2, + // new Dictionary + // { + // { "V2Rollout", "100" }, + // { "EnableV4", "False" }, + // { "EnableV4Chrome", "False" }, + // { "ABTest", "False" }, + // { "ReportButtonCutOff", null } + // } + // }, - { - InGameMenuVersion.V4, - new Dictionary - { - { "V2Rollout", "0" }, - { "EnableV4", "True" }, - { "EnableV4Chrome", "False" }, - { "ABTest", "False" }, - { "ReportButtonCutOff", null } - } - }, + // { + // InGameMenuVersion.V4, + // new Dictionary + // { + // { "V2Rollout", "0" }, + // { "EnableV4", "True" }, + // { "EnableV4Chrome", "False" }, + // { "ABTest", "False" }, + // { "ReportButtonCutOff", null } + // } + // }, - { - InGameMenuVersion.V4Chrome, - new Dictionary - { - { "V2Rollout", "0" }, - { "EnableV4", "True" }, - { "EnableV4Chrome", "True" }, - { "ABTest", "False" }, - { "ReportButtonCutOff", null } - } - } - }; + // { + // InGameMenuVersion.V4Chrome, + // new Dictionary + // { + // { "V2Rollout", "0" }, + // { "EnableV4", "True" }, + // { "EnableV4Chrome", "True" }, + // { "ABTest", "False" }, + // { "ReportButtonCutOff", null } + // } + // } + //}; // all fflags are stored as strings // to delete a flag, set the value as null @@ -243,9 +243,11 @@ namespace Bloxstrap // clone the dictionary OriginalProp = new(Prop); - // TODO - remove when activity tracking has been revamped if (GetPreset("Network.Log") != "7") SetPreset("Network.Log", "7"); + + if (GetPreset("Rendering.ManualFullscreen") != "False") + SetPreset("Rendering.ManualFullscreen", "False"); } } } diff --git a/Bloxstrap/Installer.cs b/Bloxstrap/Installer.cs index 10bb781..b5fa842 100644 --- a/Bloxstrap/Installer.cs +++ b/Bloxstrap/Installer.cs @@ -359,8 +359,6 @@ namespace Bloxstrap || Paths.Process.StartsWith(Path.Combine(Paths.LocalAppData, "Temp")) || Paths.Process.StartsWith(Paths.TempUpdates); - isAutoUpgrade = true; - var existingVer = FileVersionInfo.GetVersionInfo(Paths.Application).ProductVersion; var currentVer = FileVersionInfo.GetVersionInfo(Paths.Process).ProductVersion; @@ -592,6 +590,21 @@ namespace Bloxstrap } } + if (Utilities.CompareVersions(existingVer, "2.8.1") == VersionComparison.LessThan) + { + // wipe all escape menu flag presets + App.FastFlags.SetValue("FIntNewInGameMenuPercentRollout3", null); + App.FastFlags.SetValue("FFlagEnableInGameMenuControls", null); + App.FastFlags.SetValue("FFlagEnableInGameMenuModernization", null); + App.FastFlags.SetValue("FFlagEnableInGameMenuChrome", null); + App.FastFlags.SetValue("FFlagFixReportButtonCutOff", null); + App.FastFlags.SetValue("FFlagEnableMenuControlsABTest", null); + App.FastFlags.SetValue("FFlagEnableV3MenuABTest3", null); + App.FastFlags.SetValue("FFlagEnableInGameMenuChromeABTest3", null); + App.FastFlags.SetValue("FFlagEnableInGameMenuChromeABTest4", null); + } + + App.Settings.Save(); App.FastFlags.Save(); } diff --git a/Bloxstrap/Integrations/ActivityWatcher.cs b/Bloxstrap/Integrations/ActivityWatcher.cs index 2e0483a..8132250 100644 --- a/Bloxstrap/Integrations/ActivityWatcher.cs +++ b/Bloxstrap/Integrations/ActivityWatcher.cs @@ -102,8 +102,6 @@ await Task.Delay(1000); } - OnLogOpen?.Invoke(this, EventArgs.Empty); - LogLocation = logFileInfo.FullName; } else @@ -111,6 +109,8 @@ logFileInfo = new FileInfo(LogLocation); } + OnLogOpen?.Invoke(this, EventArgs.Empty); + var logFileStream = logFileInfo.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite); App.Logger.WriteLine(LOG_IDENT, $"Opened {LogLocation}"); diff --git a/Bloxstrap/LaunchHandler.cs b/Bloxstrap/LaunchHandler.cs index a9a60ca..f76629b 100644 --- a/Bloxstrap/LaunchHandler.cs +++ b/Bloxstrap/LaunchHandler.cs @@ -161,6 +161,8 @@ namespace Bloxstrap if (process is not null) PInvoke.SetForegroundWindow((HWND)process.MainWindowHandle); + + App.Terminate(); } } @@ -206,18 +208,18 @@ 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(launchMode); + App.Bootstrapper = new Bootstrapper(launchMode); IBootstrapperDialog? dialog = null; if (!App.LaunchSettings.QuietFlag.Active) { App.Logger.WriteLine(LOG_IDENT, "Initializing bootstrapper dialog"); dialog = App.Settings.Prop.BootstrapperStyle.GetNew(); - bootstrapper.Dialog = dialog; - dialog.Bootstrapper = bootstrapper; + App.Bootstrapper.Dialog = dialog; + dialog.Bootstrapper = App.Bootstrapper; } - Task.Run(bootstrapper.Run).ContinueWith(t => + Task.Run(App.Bootstrapper.Run).ContinueWith(t => { App.Logger.WriteLine(LOG_IDENT, "Bootstrapper task has finished"); diff --git a/Bloxstrap/LaunchSettings.cs b/Bloxstrap/LaunchSettings.cs index 28a06ea..3790148 100644 --- a/Bloxstrap/LaunchSettings.cs +++ b/Bloxstrap/LaunchSettings.cs @@ -72,6 +72,19 @@ namespace Bloxstrap _flagMap.Add(identifier, flag); } + // infer roblox launch uris + if (Args.Length >= 1) + { + string arg = Args[0]; + + if (arg.StartsWith("roblox:", StringComparison.OrdinalIgnoreCase) + || arg.StartsWith("roblox-player:", StringComparison.OrdinalIgnoreCase)) + { + RobloxLaunchMode = LaunchMode.Player; + RobloxLaunchArgs = arg; + } + } + // parse for (int i = 0; i < Args.Length; i++) { diff --git a/Bloxstrap/Logger.cs b/Bloxstrap/Logger.cs index 4d4ee69..884e077 100644 --- a/Bloxstrap/Logger.cs +++ b/Bloxstrap/Logger.cs @@ -12,6 +12,8 @@ public bool NoWriteMode = false; public string? FileLocation; + public string AsDocument => String.Join('\n', History); + public void Initialize(bool useTempDir = false) { const string LOG_IDENT = "Logger::Initialize"; @@ -115,7 +117,9 @@ { Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; - WriteLine($"[{identifier}] {ex}"); + string hresult = "0x" + ex.HResult.ToString("X8"); + + WriteLine($"[{identifier}] ({hresult}) {ex}"); Thread.CurrentThread.CurrentUICulture = Locale.CurrentCulture; } diff --git a/Bloxstrap/Models/SettingTasks/EmojiModPresetTask.cs b/Bloxstrap/Models/SettingTasks/EmojiModPresetTask.cs index 89c8d92..0f2c1d3 100644 --- a/Bloxstrap/Models/SettingTasks/EmojiModPresetTask.cs +++ b/Bloxstrap/Models/SettingTasks/EmojiModPresetTask.cs @@ -43,7 +43,7 @@ namespace Bloxstrap.Models.SettingTasks Directory.CreateDirectory(Path.GetDirectoryName(_filePath)!); - await using var fileStream = new FileStream(_filePath, FileMode.CreateNew); + await using var fileStream = new FileStream(_filePath, FileMode.Create); await response.Content.CopyToAsync(fileStream); OriginalState = NewState; diff --git a/Bloxstrap/Properties/Resources.Designer.cs b/Bloxstrap/Properties/Resources.Designer.cs index a65c8d7..64c37de 100644 --- a/Bloxstrap/Properties/Resources.Designer.cs +++ b/Bloxstrap/Properties/Resources.Designer.cs @@ -195,5 +195,17 @@ namespace Bloxstrap.Properties { return ((System.Drawing.Icon)(obj)); } } + + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + internal static System.Drawing.Icon IconBloxstrapClassic + { + get + { + object obj = ResourceManager.GetObject("IconBloxstrapClassic", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } } } diff --git a/Bloxstrap/Properties/Resources.resx b/Bloxstrap/Properties/Resources.resx index 7c24a62..dc3013d 100644 --- a/Bloxstrap/Properties/Resources.resx +++ b/Bloxstrap/Properties/Resources.resx @@ -154,4 +154,7 @@ ..\Resources\IconLate2015.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\IconBloxstrapClassic.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/Bloxstrap/Resources/IconBloxstrapClassic.ico b/Bloxstrap/Resources/IconBloxstrapClassic.ico new file mode 100644 index 0000000..56ab2c5 Binary files /dev/null and b/Bloxstrap/Resources/IconBloxstrapClassic.ico differ diff --git a/Bloxstrap/Resources/Strings.Designer.cs b/Bloxstrap/Resources/Strings.Designer.cs index a09298c..afa8196 100644 --- a/Bloxstrap/Resources/Strings.Designer.cs +++ b/Bloxstrap/Resources/Strings.Designer.cs @@ -70,7 +70,8 @@ namespace Bloxstrap.Resources { } /// - /// Looks up a localized string similar to These are the people currently supporting Bloxstrap through [Ko-fi]({0}). A massive thank you to everyone here!. + /// Looks up a localized string similar to These are the people who've supported Bloxstrap through [Ko-fi]({0}). A massive thank you to everyone here! + ///Every person here is ranked by their overall pledge.. /// public static string About_Supporters_Description { get { @@ -168,6 +169,17 @@ namespace Bloxstrap.Resources { } } + /// + /// Looks up a localized string similar to Bloxstrap tried to upgrade Roblox but can't because Roblox's files are still in use. + /// + ///Please close any applications that may be using Roblox's files, and relaunch.. + /// + public static string Bootstrapper_FilesInUse { + get { + return ResourceManager.GetString("Bootstrapper.FilesInUse", resourceCulture); + } + } + /// /// Looks up a localized string similar to You must first install Bloxstrap before uninstalling.. /// @@ -420,6 +432,15 @@ namespace Bloxstrap.Resources { } } + /// + /// Looks up a localized string similar to Export. + /// + public static string Common_Export { + get { + return ResourceManager.GetString("Common.Export", resourceCulture); + } + } + /// /// Looks up a localized string similar to Help. /// @@ -817,6 +838,15 @@ namespace Bloxstrap.Resources { } } + /// + /// Looks up a localized string similar to A connection could not be made, which likely indicates a poor internet connection or a firewall block. If your connection is fine, please ensure that your antivirus isn't blocking Bloxstrap.. + /// + public static string Dialog_Connectivity_BadConnection { + get { + return ResourceManager.GetString("Dialog.Connectivity.BadConnection", resourceCulture); + } + } + /// /// Looks up a localized string similar to More information:. /// @@ -826,15 +856,6 @@ namespace Bloxstrap.Resources { } } - /// - /// Looks up a localized string similar to Something is likely preventing Bloxstrap from connecting to the internet.. - /// - public static string Dialog_Connectivity_Preventing { - get { - return ResourceManager.GetString("Dialog.Connectivity.Preventing", resourceCulture); - } - } - /// /// Looks up a localized string similar to Roblox may be down right now. See {0} for more information.. /// @@ -862,15 +883,6 @@ namespace Bloxstrap.Resources { } } - /// - /// Looks up a localized string similar to The connection timed out, which could indicate a poor internet connection or a firewall block.. - /// - public static string Dialog_Connectivity_TimedOut { - get { - return ResourceManager.GetString("Dialog.Connectivity.TimedOut", resourceCulture); - } - } - /// /// Looks up a localized string similar to Connectivity error. /// @@ -974,6 +986,15 @@ namespace Bloxstrap.Resources { } } + /// + /// Looks up a localized string similar to Version {0}. + /// + public static string Dialog_Exception_Version { + get { + return ResourceManager.GetString("Dialog.Exception.Version", resourceCulture); + } + } + /// /// Looks up a localized string similar to The chosen bootstrapper icon could not be loaded. /// @@ -1022,7 +1043,9 @@ namespace Bloxstrap.Resources { } /// - /// Looks up a localized string similar to Please read the following help information, which will open in your web browser when you close this dialog.. + /// Looks up a localized string similar to For information about why this could be happening and how this can be resolved, please read [this help article]({0}). + /// + ///Check if Roblox works with [the original launcher]({1}). If it doesn't, then this isn't a Bloxstrap issue. If it does, then refer to the help article.. /// public static string Dialog_PlayerError_HelpInformation { get { @@ -1363,6 +1386,15 @@ namespace Bloxstrap.Resources { } } + /// + /// Looks up a localized string similar to Zip archive. + /// + public static string FileTypes_ZipArchive { + get { + return ResourceManager.GetString("FileTypes.ZipArchive", resourceCulture); + } + } + /// /// Looks up a localized string similar to Bloxstrap has been upgraded to v{0}. /// @@ -2089,6 +2121,42 @@ namespace Bloxstrap.Resources { } } + /// + /// Looks up a localized string similar to Gather information that can be uploaded online to troubleshoot a problem you're having.. + /// + public static string Menu_Bloxstrap_ExportData_Description { + get { + return ResourceManager.GetString("Menu.Bloxstrap.ExportData.Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bloxstrap configuration. + /// + public static string Menu_Bloxstrap_ExportData_ExportConfig { + get { + return ResourceManager.GetString("Menu.Bloxstrap.ExportData.ExportConfig", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All Bloxstrap logs. + /// + public static string Menu_Bloxstrap_ExportData_ExportLogs { + get { + return ResourceManager.GetString("Menu.Bloxstrap.ExportData.ExportLogs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Export diagnostic data. + /// + public static string Menu_Bloxstrap_ExportData_Title { + get { + return ResourceManager.GetString("Menu.Bloxstrap.ExportData.Title", resourceCulture); + } + } + /// /// Looks up a localized string similar to Add new. /// @@ -2745,7 +2813,7 @@ namespace Bloxstrap.Resources { } /// - /// Looks up a localized string similar to Roblox will fully close when you leave a game instead of dropping you back into the app.. + /// Looks up a localized string similar to Roblox will fully close when you leave a game instead of going back to the app. [Will break some things!]({0}). /// public static string Menu_Integrations_DesktopApp_Description { get { @@ -2898,7 +2966,7 @@ namespace Bloxstrap.Resources { } /// - /// Looks up a localized string similar to Font size can be adjusted in the Fast Flags tab.. + /// Looks up a localized string similar to Font size can be adjusted in the Engine Settings tab.. /// public static string Menu_Mods_Misc_CustomFont_Description { get { diff --git a/Bloxstrap/Resources/Strings.resx b/Bloxstrap/Resources/Strings.resx index c0ccf27..faf2613 100644 --- a/Bloxstrap/Resources/Strings.resx +++ b/Bloxstrap/Resources/Strings.resx @@ -123,14 +123,11 @@ Roblox is currently running, and launching another instance will close it. Are you sure you want to continue launching? - - Something is likely preventing Bloxstrap from connecting to the internet. - Roblox may be down right now. See {0} for more information. - - The connection timed out, which could indicate a poor internet connection or a firewall block. + + A connection could not be made, which likely indicates a poor internet connection or a firewall block. If your connection is fine, please ensure that your antivirus isn't blocking Bloxstrap. You must first install Bloxstrap before uninstalling. @@ -717,7 +714,7 @@ Selecting 'No' will ignore this warning and continue installation. Configure additional functionality to go alongside Roblox. - Roblox will fully close when you leave a game instead of dropping you back into the app. + Roblox will fully close when you leave a game instead of going back to the app. [Will break some things!]({0}) Don't exit to desktop app @@ -757,7 +754,7 @@ Selecting 'No' will ignore this warning and continue installation. Choose font... - Font size can be adjusted in the Fast Flags tab. + Font size can be adjusted in the Engine Settings tab. The file you have chosen does not appear to be a valid font file. @@ -906,6 +903,7 @@ Selecting 'No' will ignore this warning and continue installation. JSON files + Shown in the open file dialog, where the file type selection dropdown is, e.g. "JSON files (*.json)" The entry for '{0}' is not valid as the value must be a boolean (either 'True' or 'False') @@ -1104,7 +1102,9 @@ Are you sure you want to continue? Roblox has crashed. - Please read the following help information, which will open in your web browser when you close this dialog. + For information about why this could be happening and how this can be resolved, please read [this help article]({0}). + +Check if Roblox works with [the original launcher]({1}). If it doesn't, then this isn't a Bloxstrap issue. If it does, then refer to the help article. Could not load data because of a network error. @@ -1116,7 +1116,8 @@ Are you sure you want to continue? Supporters - These are the people currently supporting Bloxstrap through [Ko-fi]({0}). A massive thank you to everyone here! + These are the people who've supported Bloxstrap through [Ko-fi]({0}). A massive thank you to everyone here! +Every person here is ranked by their overall pledge. Your Settings could not be loaded. They have been reset to the default configuration. @@ -1239,4 +1240,35 @@ Would you like to enable test mode? Launch Roblox Studio + + Version {0} + + + Bloxstrap tried to upgrade Roblox but can't because Roblox's files are still in use. + +Please close any applications that may be using Roblox's files, and relaunch. + This is *not* for when Roblox is still running when trying to upgrade. This applies to files being open (i.e. image assets) + + + Zip archive + Shown in the save file dialog, where the file type selection dropdown is, e.g. "Zip archive (*.zip)" + + + Export + Currently used under the "Bloxstrap" settings tab for the button to export diagnostic data + + + Export diagnostic data + + + Gather information that can be uploaded online to troubleshoot a problem you're having. + + + Bloxstrap configuration + Label that appears next to a checkbox + + + All Bloxstrap logs + Label that appears next to a checkbox + \ No newline at end of file diff --git a/Bloxstrap/RobloxInterfaces/Deployment.cs b/Bloxstrap/RobloxInterfaces/Deployment.cs index 383cab4..da88c14 100644 --- a/Bloxstrap/RobloxInterfaces/Deployment.cs +++ b/Bloxstrap/RobloxInterfaces/Deployment.cs @@ -10,10 +10,17 @@ public static string BinaryType = "WindowsPlayer"; - public static bool IsDefaultChannel => String.Compare(Channel, DefaultChannel, StringComparison.OrdinalIgnoreCase) == 0; + public static bool IsDefaultChannel => Channel.Equals(DefaultChannel, StringComparison.OrdinalIgnoreCase); public static string BaseUrl { get; private set; } = null!; - + + public static readonly List BadChannelCodes = new() + { + HttpStatusCode.Unauthorized, + HttpStatusCode.Forbidden, + HttpStatusCode.NotFound + }; + private static readonly Dictionary ClientVersionCache = new(); // a list of roblox deployment locations that we check for, in case one of them don't work @@ -86,7 +93,7 @@ if (finishedTask.IsFaulted) exceptions.Add(finishedTask.Exception!.InnerException!); - else + else if (!finishedTask.IsCanceled) BaseUrl = finishedTask.Result; } @@ -94,7 +101,13 @@ tokenSource.Cancel(); if (string.IsNullOrEmpty(BaseUrl)) - return exceptions[0]; + { + if (exceptions.Any()) + return exceptions[0]; + + // task cancellation exceptions don't get added to the list + return new TaskCanceledException("All connection attempts timed out."); + } App.Logger.WriteLine(LOG_IDENT, $"Got {BaseUrl} as the optimal base URL"); @@ -153,6 +166,11 @@ { clientVersion = await Http.GetJson("https://clientsettingscdn.roblox.com" + path); } + catch (HttpRequestException httpEx) + when (!isDefaultChannel && BadChannelCodes.Contains(httpEx.StatusCode)) + { + throw new InvalidChannelException(httpEx.StatusCode); + } catch (Exception ex) { App.Logger.WriteLine(LOG_IDENT, "Failed to contact clientsettingscdn! Falling back to clientsettings..."); diff --git a/Bloxstrap/UI/Elements/About/Pages/SupportersPage.xaml b/Bloxstrap/UI/Elements/About/Pages/SupportersPage.xaml index 925a520..9620493 100644 --- a/Bloxstrap/UI/Elements/About/Pages/SupportersPage.xaml +++ b/Bloxstrap/UI/Elements/About/Pages/SupportersPage.xaml @@ -10,6 +10,7 @@ xmlns:resources="clr-namespace:Bloxstrap.Resources" mc:Ignorable="d" d:DesignHeight="1500" d:DesignWidth="800" + SizeChanged="UiPage_SizeChanged" Title="AboutPage" Scrollable="True"> @@ -93,7 +94,7 @@ - + @@ -122,7 +123,7 @@ - + diff --git a/Bloxstrap/UI/Elements/About/Pages/SupportersPage.xaml.cs b/Bloxstrap/UI/Elements/About/Pages/SupportersPage.xaml.cs index c824558..546d2e4 100644 --- a/Bloxstrap/UI/Elements/About/Pages/SupportersPage.xaml.cs +++ b/Bloxstrap/UI/Elements/About/Pages/SupportersPage.xaml.cs @@ -1,4 +1,6 @@ -using Bloxstrap.UI.ViewModels.About; +using System.Windows; + +using Bloxstrap.UI.ViewModels.About; namespace Bloxstrap.UI.Elements.About.Pages { @@ -7,10 +9,15 @@ namespace Bloxstrap.UI.Elements.About.Pages /// public partial class SupportersPage { + private readonly SupportersViewModel _viewModel = new(); + public SupportersPage() { - DataContext = new SupportersViewModel(); + DataContext = _viewModel; InitializeComponent(); } + + private void UiPage_SizeChanged(object sender, SizeChangedEventArgs e) + => _viewModel.WindowResizeEvent?.Invoke(sender, e); } } diff --git a/Bloxstrap/UI/Elements/Dialogs/ExceptionDialog.xaml b/Bloxstrap/UI/Elements/Dialogs/ExceptionDialog.xaml index 1debcfd..b98372d 100644 --- a/Bloxstrap/UI/Elements/Dialogs/ExceptionDialog.xaml +++ b/Bloxstrap/UI/Elements/Dialogs/ExceptionDialog.xaml @@ -40,11 +40,15 @@ - -