diff --git a/Bloxstrap/App.xaml.cs b/Bloxstrap/App.xaml.cs index cfd4ed9b..d7603903 100644 --- a/Bloxstrap/App.xaml.cs +++ b/Bloxstrap/App.xaml.cs @@ -49,6 +49,8 @@ public partial class App : Application ) ); + private static bool _showingExceptionDialog = false; + public static void Terminate(ErrorCode exitCode = ErrorCode.ERROR_SUCCESS) { if (IsFirstRun) @@ -85,6 +87,11 @@ public static void FinalizeExceptionHandling(Exception exception, bool log = tru #if DEBUG throw exception; #else + if (_showingExceptionDialog) + return; + + _showingExceptionDialog = true; + if (!IsQuiet) Controls.ShowExceptionDialog(exception); @@ -148,33 +155,6 @@ protected override void OnStartup(StartupEventArgs e) IsUpgrade = true; } } - - if (!IsMenuLaunch) - { - Logger.WriteLine(LOG_IDENT, "Performing connectivity check..."); - - try - { - HttpClient.GetAsync("https://detectportal.firefox.com").Wait(); - Logger.WriteLine(LOG_IDENT, "Connectivity check finished"); - } - catch (Exception ex) - { - Logger.WriteLine(LOG_IDENT, "Connectivity check failed!"); - Logger.WriteException(LOG_IDENT, ex); - - if (ex.GetType() == typeof(AggregateException)) - ex = ex.InnerException!; - - Controls.ShowConnectivityDialog( - "the internet", - $"Something may be preventing {ProjectName} from connecting to the internet, or you are currently offline. Please check and try again.", - ex - ); - - Terminate(ErrorCode.ERROR_CANCELLED); - } - } using (var checker = new InstallChecker()) { diff --git a/Bloxstrap/Bloxstrap.csproj b/Bloxstrap/Bloxstrap.csproj index 2257c751..48fc5dc0 100644 --- a/Bloxstrap/Bloxstrap.csproj +++ b/Bloxstrap/Bloxstrap.csproj @@ -7,8 +7,8 @@ true True Bloxstrap.ico - 2.5.0 - 2.5.0.0 + 2.5.1 + 2.5.1.0 app.manifest diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index 024fa9b7..0302340a 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -60,6 +60,7 @@ public class Bootstrapper private string _latestVersionGuid = null!; private PackageManifest _versionPackageManifest = null!; + private FileManifest _versionFileManifest = null!; private string _versionFolder = null!; private bool _isInstalling = false; @@ -114,6 +115,39 @@ public async Task Run() return; } + // connectivity check + + App.Logger.WriteLine(LOG_IDENT, "Performing connectivity check..."); + + SetStatus("Connecting to Roblox..."); + + try + { + await RobloxDeployment.GetInfo(RobloxDeployment.DefaultChannel); + } + catch (Exception ex) + { + App.Logger.WriteLine(LOG_IDENT, "Connectivity check failed!"); + App.Logger.WriteException(LOG_IDENT, ex); + + string message = $"It's possible that something is preventing {App.ProjectName} from connecting to the internet. Please check and try again."; + + if (ex.GetType() == typeof(HttpResponseException)) + message = "Roblox may be down right now. See status.roblox.com for more information. Please try again later."; + else if (ex.GetType() == typeof(TaskCanceledException)) + message = "Bloxstrap timed out when trying to connect to three different Roblox deployment mirrors, indicating a poor internet connection. Please try again later."; + else if (ex.GetType() == typeof(AggregateException)) + ex = ex.InnerException!; + + Controls.ShowConnectivityDialog("Roblox", message, ex); + + App.Terminate(ErrorCode.ERROR_CANCELLED); + } + finally + { + App.Logger.WriteLine(LOG_IDENT, "Connectivity check finished"); + } + #if !DEBUG if (!App.IsFirstRun && App.Settings.Prop.CheckForUpdates) await CheckForUpdates(); @@ -126,8 +160,9 @@ public async Task Run() try { - Mutex.OpenExisting("Bloxstrap_BootstrapperMutex").Close(); - App.Logger.WriteLine(LOG_IDENT, "Bloxstrap_BootstrapperMutex mutex exists, waiting..."); + Mutex.OpenExisting("Bloxstrap_SingletonMutex").Close(); + App.Logger.WriteLine(LOG_IDENT, "Bloxstrap_SingletonMutex mutex exists, waiting..."); + SetStatus("Waiting for other instances..."); mutexExists = true; } catch (Exception) @@ -136,7 +171,7 @@ public async Task Run() } // wait for mutex to be released if it's not yet - await using AsyncMutex mutex = new("Bloxstrap_BootstrapperMutex"); + await using var mutex = new AsyncMutex(true, "Bloxstrap_SingletonMutex"); await mutex.AcquireAsync(_cancelTokenSource.Token); // reload our configs since they've likely changed by now @@ -148,8 +183,6 @@ public async Task Run() await CheckLatestVersion(); - CheckInstallMigration(); - // install/update roblox if we're running for the first time, needs updating, or the player location doesn't exist if (App.IsFirstRun || _latestVersionGuid != App.State.Prop.VersionGuid || !File.Exists(_playerLocation)) await InstallLatestVersion(); @@ -187,7 +220,7 @@ public async Task Run() private async Task CheckLatestVersion() { - SetStatus("Connecting to Roblox..."); + const string LOG_IDENT = "Bootstrapper::CheckLatestVersion"; ClientVersion clientVersion; @@ -195,17 +228,14 @@ private async Task CheckLatestVersion() { clientVersion = await RobloxDeployment.GetInfo(App.Settings.Prop.Channel); } - catch (Exception ex) + catch (HttpResponseException ex) { - string message = "It's possible that Roblox is being blocked by a firewall. Please check and try again."; - - if (ex.GetType() == typeof(HttpResponseException)) - message = "Roblox may be down right now. See status.roblox.com for more information. Please try again later."; + if (ex.ResponseMessage.StatusCode != HttpStatusCode.NotFound) + throw; - Controls.ShowConnectivityDialog("Roblox", message, ex); - - App.Terminate(ErrorCode.ERROR_CANCELLED); - return; + App.Logger.WriteLine(LOG_IDENT, $"Reverting enrolled channel to {RobloxDeployment.DefaultChannel} because a WindowsPlayer build does not exist for {App.Settings.Prop.Channel}"); + App.Settings.Prop.Channel = RobloxDeployment.DefaultChannel; + clientVersion = await RobloxDeployment.GetInfo(App.Settings.Prop.Channel); } if (clientVersion.IsBehindDefaultChannel) @@ -235,6 +265,7 @@ private async Task CheckLatestVersion() _latestVersionGuid = clientVersion.VersionGuid; _versionFolder = Path.Combine(Paths.Versions, _latestVersionGuid); _versionPackageManifest = await PackageManifest.Get(_latestVersionGuid); + _versionFileManifest = await FileManifest.Get(_latestVersionGuid); } private async Task StartRoblox() @@ -266,8 +297,12 @@ private async Task StartRoblox() _launchCommandLine = _launchCommandLine.Replace("LAUNCHTIMEPLACEHOLDER", DateTimeOffset.Now.ToUnixTimeMilliseconds().ToString()); - if (App.Settings.Prop.Channel.ToLowerInvariant() != RobloxDeployment.DefaultChannel.ToLowerInvariant()) - _launchCommandLine += " -channel " + App.Settings.Prop.Channel.ToLowerInvariant(); + _launchCommandLine += " -channel "; + + if (App.Settings.Prop.Channel.ToLowerInvariant() == RobloxDeployment.DefaultChannel.ToLowerInvariant()) + _launchCommandLine += "production"; + else + _launchCommandLine += App.Settings.Prop.Channel.ToLowerInvariant(); // whether we should wait for roblox to exit to handle stuff in the background or clean up after roblox closes bool shouldWait = false; @@ -391,6 +426,8 @@ public void CancelInstall() App.Logger.WriteException(LOG_IDENT, ex); } + Dialog?.CloseBootstrapper(); + App.Terminate(ErrorCode.ERROR_CANCELLED); } #endregion @@ -444,71 +481,6 @@ public void RegisterProgramSize() App.Logger.WriteLine(LOG_IDENT, $"Registered as {totalSize} KB"); } - private void CheckInstallMigration() - { - const string LOG_IDENT = "Bootstrapper::CheckInstallMigration"; - - // check if we've changed our install location since the last time we started - // in which case, we'll have to copy over all our folders so we don't lose any mods and stuff - - using RegistryKey? applicationKey = Registry.CurrentUser.OpenSubKey($@"Software\{App.ProjectName}", true); - - string? oldInstallLocation = (string?)applicationKey?.GetValue("OldInstallLocation"); - - if (applicationKey is null || oldInstallLocation is null || oldInstallLocation == Paths.Base) - return; - - SetStatus("Migrating install location..."); - - if (Directory.Exists(oldInstallLocation)) - { - App.Logger.WriteLine(LOG_IDENT, $"Moving all files in {oldInstallLocation} to {Paths.Base}..."); - - foreach (string oldFileLocation in Directory.GetFiles(oldInstallLocation, "*.*", SearchOption.AllDirectories)) - { - string relativeFile = oldFileLocation.Substring(oldInstallLocation.Length + 1); - string newFileLocation = Path.Combine(Paths.Base, relativeFile); - string? newDirectory = Path.GetDirectoryName(newFileLocation); - - try - { - if (!String.IsNullOrEmpty(newDirectory)) - Directory.CreateDirectory(newDirectory); - - File.Move(oldFileLocation, newFileLocation, true); - } - catch (Exception ex) - { - App.Logger.WriteLine(LOG_IDENT, $"Failed to move {oldFileLocation} to {newFileLocation}! {ex}"); - } - } - - try - { - Directory.Delete(oldInstallLocation, true); - App.Logger.WriteLine(LOG_IDENT, "Deleted old install location"); - } - catch (Exception ex) - { - App.Logger.WriteLine(LOG_IDENT, $"Failed to delete old install location! {ex}"); - } - } - - applicationKey.DeleteValue("OldInstallLocation"); - - // allow shortcuts to be re-registered - if (Directory.Exists(Paths.StartMenu)) - Directory.Delete(Paths.StartMenu, true); - - if (File.Exists(DesktopShortcutLocation)) - { - File.Delete(DesktopShortcutLocation); - App.Settings.Prop.CreateDesktopIcon = true; - } - - App.Logger.WriteLine(LOG_IDENT, "Finished migrating install location!"); - } - public static void CheckInstall() { const string LOG_IDENT = "Bootstrapper::CheckInstall"; @@ -713,7 +685,7 @@ private void Uninstall() // if the folder we're installed to does not end with "Bloxstrap", we're installed to a user-selected folder // in which case, chances are they chose to install to somewhere they didn't really mean to (prior to the added warning in 2.4.0) // if so, we're walking on eggshells and have to ensure we only clean up what we need to clean up - bool cautiousUninstall = !Paths.Base.EndsWith(App.ProjectName); + bool cautiousUninstall = !Paths.Base.ToLower().EndsWith(App.ProjectName.ToLower()); var cleanupSequence = new List { @@ -783,7 +755,7 @@ private void Uninstall() }; } - Dialog?.ShowSuccess($"{App.ProjectName} has succesfully uninstalled", callback); + Dialog?.ShowSuccess($"{App.ProjectName} has successfully uninstalled", callback); } #endregion @@ -906,7 +878,16 @@ private async Task InstallLatestVersion() continue; App.Logger.WriteLine(LOG_IDENT, $"Removing old version folder for {dir.Name}"); - dir.Delete(true); + + try + { + dir.Delete(true); + } + catch (Exception ex) + { + App.Logger.WriteLine(LOG_IDENT, "Failed to delete version folder!"); + App.Logger.WriteException(LOG_IDENT, ex); + } } } } @@ -999,6 +980,12 @@ private async Task ApplyModifications() { const string LOG_IDENT = "Bootstrapper::ApplyModifications"; + if (Process.GetProcessesByName("RobloxPlayerBeta").Where(x => x.MainModule!.FileName == _playerLocation).Any()) + { + App.Logger.WriteLine(LOG_IDENT, "Roblox is running, aborting mod check"); + return; + } + SetStatus("Applying Roblox modifications..."); // set executable flags for fullscreen optimizations @@ -1332,6 +1319,9 @@ private async Task DownloadPackage(Package package) for (int i = 1; i <= maxTries; i++) { + if (_cancelFired) + return; + int totalBytesRead = 0; try @@ -1370,7 +1360,8 @@ private async Task DownloadPackage(Package package) App.Logger.WriteLine(LOG_IDENT, $"An exception occurred after downloading {totalBytesRead} bytes. ({i}/{maxTries})"); App.Logger.WriteException(LOG_IDENT, ex); - File.Delete(packageLocation); + if (File.Exists(packageLocation)) + File.Delete(packageLocation); if (i >= maxTries) throw; @@ -1415,6 +1406,16 @@ private async Task ExtractPackage(Package package) if (directory is not null) Directory.CreateDirectory(directory); + if (File.Exists(extractPath)) + { + var fileManifest = _versionFileManifest.FirstOrDefault(x => x.Name == Path.Combine(PackageDirectories[package.Name], entry.FullName)); + + if (fileManifest is not null && MD5Hash.FromFile(extractPath) == fileManifest.Signature) + continue; + + File.Delete(extractPath); + } + entry.ExtractToFile(extractPath, true); } diff --git a/Bloxstrap/FastFlagManager.cs b/Bloxstrap/FastFlagManager.cs index 0a3e36a8..6f435b7b 100644 --- a/Bloxstrap/FastFlagManager.cs +++ b/Bloxstrap/FastFlagManager.cs @@ -14,6 +14,8 @@ public class FastFlagManager : JsonManager> public static IReadOnlyDictionary PresetFlags = new Dictionary { + { "Network.Log", "FLogNetwork" }, + { "HTTP.Log", "DFLogHttpTraceLight" }, { "HTTP.Proxy.Enable", "DFFlagDebugEnableHttpProxy" }, @@ -25,7 +27,6 @@ public class FastFlagManager : JsonManager> { "Rendering.ManualFullscreen", "FFlagHandleAltEnterFullscreenManually" }, { "Rendering.TexturePack", "FStringPartTexturePackTable2022" }, { "Rendering.DisableScaling", "DFFlagDisableDPIScale" }, - { "Rendering.MSAA", "FIntDebugForceMSAASamples" }, { "Rendering.Mode.D3D11", "FFlagDebugGraphicsPreferD3D11" }, { "Rendering.Mode.D3D10", "FFlagDebugGraphicsPreferD3D11FL10" }, @@ -43,7 +44,12 @@ public class FastFlagManager : JsonManager> { "UI.Menu.GraphicsSlider", "FFlagFixGraphicsQuality" }, { "UI.Menu.Style.DisableV2", "FFlagDisableNewIGMinDUA" }, - { "UI.Menu.Style.EnableV4", "FFlagEnableInGameMenuControls" } + { "UI.Menu.Style.EnableV4", "FFlagEnableInGameMenuControls" }, + + { "UI.Menu.Style.ABTest.1", "FFlagEnableMenuControlsABTest" }, + { "UI.Menu.Style.ABTest.2", "FFlagEnableMenuModernizationABTest" }, + { "UI.Menu.Style.ABTest.3", "FFlagEnableMenuModernizationABTest2" }, + { "UI.Menu.Style.ABTest.4", "FFlagEnableV3MenuABTest3" } }; // only one missing here is Metal because lol @@ -82,7 +88,8 @@ public class FastFlagManager : JsonManager> new Dictionary { { "DisableV2", null }, - { "EnableV4", null } + { "EnableV4", null }, + { "ABTest", null } } }, @@ -91,7 +98,8 @@ public class FastFlagManager : JsonManager> new Dictionary { { "DisableV2", "True" }, - { "EnableV4", "False" } + { "EnableV4", "False" }, + { "ABTest", "False" } } }, @@ -100,7 +108,8 @@ public class FastFlagManager : JsonManager> new Dictionary { { "DisableV2", "False" }, - { "EnableV4", "False" } + { "EnableV4", "False" }, + { "ABTest", "False" } } }, @@ -109,7 +118,8 @@ public class FastFlagManager : JsonManager> new Dictionary { { "DisableV2", "True" }, - { "EnableV4", "True" } + { "EnableV4", "True" }, + { "ABTest", "False" } } } }; @@ -205,6 +215,11 @@ public override void Load() CheckManualFullscreenPreset(); + // TODO - remove when activity tracking has been revamped + if (GetPreset("Network.Log") != "7") + SetPreset("Network.Log", "7"); + + if (GetPreset("Rendering.Framerate") is not null) return; diff --git a/Bloxstrap/GlobalUsings.cs b/Bloxstrap/GlobalUsings.cs index 105c8d91..15c873c5 100644 --- a/Bloxstrap/GlobalUsings.cs +++ b/Bloxstrap/GlobalUsings.cs @@ -18,8 +18,9 @@ global using Bloxstrap.Exceptions; global using Bloxstrap.Extensions; global using Bloxstrap.Models; -global using Bloxstrap.Models.BloxstrapRPC; global using Bloxstrap.Models.Attributes; +global using Bloxstrap.Models.BloxstrapRPC; global using Bloxstrap.Models.RobloxApi; +global using Bloxstrap.Models.Manifest; global using Bloxstrap.UI; global using Bloxstrap.Utility; \ No newline at end of file diff --git a/Bloxstrap/InstallChecker.cs b/Bloxstrap/InstallChecker.cs index 285d61dd..7e4bb096 100644 --- a/Bloxstrap/InstallChecker.cs +++ b/Bloxstrap/InstallChecker.cs @@ -1,5 +1,4 @@ using System.Windows; - using Microsoft.Win32; namespace Bloxstrap @@ -29,9 +28,23 @@ internal void Check() return; } + App.Logger.WriteLine(LOG_IDENT, "Installation registry key is likely malformed"); + _installLocation = Path.GetDirectoryName(Paths.Process)!; - App.Logger.WriteLine(LOG_IDENT, $"Registry key is likely malformed. Setting install location as '{_installLocation}'"); + var result = Controls.ShowMessageBox( + $"It appears as if {App.ProjectName} hasn't been properly installed. Is it supposed to be installed at {_installLocation}?", + MessageBoxImage.Warning, + MessageBoxButton.YesNo + ); + + if (result != MessageBoxResult.Yes) + { + FirstTimeRun(); + return; + } + + App.Logger.WriteLine(LOG_IDENT, $"Setting install location as '{_installLocation}'"); if (_registryKey is null) _registryKey = Registry.CurrentUser.CreateSubKey($"Software\\{App.ProjectName}"); @@ -199,11 +212,23 @@ internal static void CheckUpgrade() // update migrations - if (App.BuildMetadata.CommitRef.StartsWith("tag") && existingVersionInfo.ProductVersion == "2.4.0") + if (App.BuildMetadata.CommitRef.StartsWith("tag")) { - App.FastFlags.SetValue("DFFlagDisableDPIScale", null); - App.FastFlags.SetValue("DFFlagVariableDPIScale2", null); - App.FastFlags.Save(); + if (existingVersionInfo.ProductVersion == "2.4.0") + { + App.FastFlags.SetValue("DFFlagDisableDPIScale", null); + App.FastFlags.SetValue("DFFlagVariableDPIScale2", null); + App.FastFlags.Save(); + } + else if (existingVersionInfo.ProductVersion == "2.5.0") + { + App.FastFlags.SetValue("FIntDebugForceMSAASamples", null); + + if (App.FastFlags.GetPreset("UI.Menu.Style.DisableV2") is not null) + App.FastFlags.SetPreset("UI.Menu.Style.ABTest", false); + + App.FastFlags.Save(); + } } if (isAutoUpgrade) diff --git a/Bloxstrap/Integrations/DiscordRichPresence.cs b/Bloxstrap/Integrations/DiscordRichPresence.cs index 1444b369..ab920d12 100644 --- a/Bloxstrap/Integrations/DiscordRichPresence.cs +++ b/Bloxstrap/Integrations/DiscordRichPresence.cs @@ -9,6 +9,7 @@ public class DiscordRichPresence : IDisposable private DiscordRPC.RichPresence? _currentPresence; private DiscordRPC.RichPresence? _currentPresenceCopy; + private Message? _stashedRPCMessage; private bool _visible = true; private long _currentUniverseId; @@ -55,6 +56,13 @@ public void ProcessRPCMessage(Message message) if (_currentPresence is null || _currentPresenceCopy is null) { + if (_activityWatcher.ActivityInGame) + { + App.Logger.WriteLine(LOG_IDENT, "Presence is not yet set, but is currently in game, stashing presence set request"); + _stashedRPCMessage = message; + return; + } + App.Logger.WriteLine(LOG_IDENT, "Presence is not set, aborting"); return; } @@ -173,7 +181,10 @@ public async Task SetCurrentGame() if (!_activityWatcher.ActivityInGame) { App.Logger.WriteLine(LOG_IDENT, "Not in game, clearing presence"); - _currentPresence = _currentPresenceCopy = null; + + _currentPresence = _currentPresenceCopy = null; + _stashedRPCMessage = null; + UpdatePresence(); return true; } @@ -250,6 +261,9 @@ public async Task SetCurrentGame() _ => $"by {universeDetails.Creator.Name}" + (universeDetails.Creator.HasVerifiedBadge ? " ☑️" : ""), }; + if (universeDetails.Name.Length < 2) + universeDetails.Name = $"{universeDetails.Name}\x2800\x2800\x2800"; + _currentPresence = new DiscordRPC.RichPresence { Details = $"Playing {universeDetails.Name}", @@ -268,7 +282,16 @@ public async Task SetCurrentGame() // this is used for configuration from BloxstrapRPC _currentPresenceCopy = _currentPresence.Clone(); - UpdatePresence(); + if (_stashedRPCMessage is not null) + { + App.Logger.WriteLine(LOG_IDENT, "Found stashed RPC message, invoking presence set command now"); + ProcessRPCMessage(_stashedRPCMessage); + _stashedRPCMessage = null; + } + else + { + UpdatePresence(); + } return true; } diff --git a/Bloxstrap/Logger.cs b/Bloxstrap/Logger.cs index b2760a1e..e193c322 100644 --- a/Bloxstrap/Logger.cs +++ b/Bloxstrap/Logger.cs @@ -43,6 +43,7 @@ public void Initialize(bool useTempDir = false) catch (IOException) { WriteLine(LOG_IDENT, "Failed to initialize because log file already exists"); + return; } @@ -64,7 +65,16 @@ public void Initialize(bool useTempDir = false) continue; WriteLine(LOG_IDENT, $"Cleaning up old log file '{log.Name}'"); - log.Delete(); + + try + { + log.Delete(); + } + catch (Exception ex) + { + WriteLine(LOG_IDENT, "Failed to delete log!"); + WriteException(LOG_IDENT, ex); + } } } } diff --git a/Bloxstrap/Models/Manifest/FileManifest.cs b/Bloxstrap/Models/Manifest/FileManifest.cs new file mode 100644 index 00000000..904f1ec3 --- /dev/null +++ b/Bloxstrap/Models/Manifest/FileManifest.cs @@ -0,0 +1,33 @@ +namespace Bloxstrap.Models.Manifest +{ + public class FileManifest : List + { + private FileManifest(string data) + { + using StringReader reader = new StringReader(data); + + while (true) + { + string? fileName = reader.ReadLine(); + string? signature = reader.ReadLine(); + + if (string.IsNullOrEmpty(fileName) || string.IsNullOrEmpty(signature)) + break; + + Add(new ManifestFile + { + Name = fileName, + Signature = signature + }); + } + } + + public static async Task Get(string versionGuid) + { + string pkgManifestUrl = RobloxDeployment.GetLocation($"/{versionGuid}-rbxManifest.txt"); + var pkgManifestData = await App.HttpClient.GetStringAsync(pkgManifestUrl); + + return new FileManifest(pkgManifestData); + } + } +} diff --git a/Bloxstrap/Models/Manifest/ManifestFile.cs b/Bloxstrap/Models/Manifest/ManifestFile.cs new file mode 100644 index 00000000..71b19767 --- /dev/null +++ b/Bloxstrap/Models/Manifest/ManifestFile.cs @@ -0,0 +1,13 @@ +namespace Bloxstrap.Models.Manifest +{ + public class ManifestFile + { + public string Name { get; set; } = ""; + public string Signature { get; set; } = ""; + + public override string ToString() + { + return $"[{Signature}] {Name}"; + } + } +} diff --git a/Bloxstrap/Models/Package.cs b/Bloxstrap/Models/Manifest/Package.cs similarity index 92% rename from Bloxstrap/Models/Package.cs rename to Bloxstrap/Models/Manifest/Package.cs index 8b6be56e..6feb162e 100644 --- a/Bloxstrap/Models/Package.cs +++ b/Bloxstrap/Models/Manifest/Package.cs @@ -4,7 +4,7 @@ * Copyright (c) 2015-present MaximumADHD */ -namespace Bloxstrap.Models +namespace Bloxstrap.Models.Manifest { public class Package { diff --git a/Bloxstrap/Models/PackageManifest.cs b/Bloxstrap/Models/Manifest/PackageManifest.cs similarity index 98% rename from Bloxstrap/Models/PackageManifest.cs rename to Bloxstrap/Models/Manifest/PackageManifest.cs index 4d7c3a18..13c71728 100644 --- a/Bloxstrap/Models/PackageManifest.cs +++ b/Bloxstrap/Models/Manifest/PackageManifest.cs @@ -4,7 +4,7 @@ * Copyright (c) 2015-present MaximumADHD */ -namespace Bloxstrap.Models +namespace Bloxstrap.Models.Manifest { public class PackageManifest : List { diff --git a/Bloxstrap/RobloxDeployment.cs b/Bloxstrap/RobloxDeployment.cs index 30267d2a..cdeda888 100644 --- a/Bloxstrap/RobloxDeployment.cs +++ b/Bloxstrap/RobloxDeployment.cs @@ -7,7 +7,7 @@ public static class RobloxDeployment private static Dictionary ClientVersionCache = new(); - // a list of roblox delpoyment locations that we check for, in case one of them don't work + // a list of roblox deployment locations that we check for, in case one of them don't work private static List BaseUrls = new() { "https://setup.rbxcdn.com", @@ -52,18 +52,6 @@ public static string BaseUrl return _baseUrl; } } - - // most commonly used/interesting channels - public static readonly List SelectableChannels = new() - { - "LIVE", - "ZFlag", - "ZNext", - "ZCanary", - "ZIntegration", - "ZAvatarTeam", - "ZSocialTeam" - }; #endregion public static string GetLocation(string resource, string? channel = null) diff --git a/Bloxstrap/UI/Elements/ContextMenu/MenuContainer.xaml.cs b/Bloxstrap/UI/Elements/ContextMenu/MenuContainer.xaml.cs index d2f6a8aa..8354ced9 100644 --- a/Bloxstrap/UI/Elements/ContextMenu/MenuContainer.xaml.cs +++ b/Bloxstrap/UI/Elements/ContextMenu/MenuContainer.xaml.cs @@ -96,7 +96,7 @@ private void Window_Loaded(object? sender, RoutedEventArgs e) private void RichPresenceMenuItem_Click(object sender, RoutedEventArgs e) => _richPresenceHandler?.SetVisibility(((MenuItem)sender).IsChecked); - private void InviteDeeplinkMenuItem_Click(object sender, RoutedEventArgs e) => Clipboard.SetText($"roblox://experiences/start?placeId={_activityWatcher?.ActivityPlaceId}&gameInstanceId={_activityWatcher?.ActivityJobId}"); + private void InviteDeeplinkMenuItem_Click(object sender, RoutedEventArgs e) => Clipboard.SetDataObject($"roblox://experiences/start?placeId={_activityWatcher?.ActivityPlaceId}&gameInstanceId={_activityWatcher?.ActivityJobId}"); private void ServerDetailsMenuItem_Click(object sender, RoutedEventArgs e) => ShowServerInformationWindow(); diff --git a/Bloxstrap/UI/Elements/Dialogs/AddFastFlagDialog.xaml b/Bloxstrap/UI/Elements/Dialogs/AddFastFlagDialog.xaml index 06e7cc08..3a475280 100644 --- a/Bloxstrap/UI/Elements/Dialogs/AddFastFlagDialog.xaml +++ b/Bloxstrap/UI/Elements/Dialogs/AddFastFlagDialog.xaml @@ -33,10 +33,10 @@ - + - + diff --git a/Bloxstrap/UI/Elements/Dialogs/BulkAddFastFlagDialog.xaml b/Bloxstrap/UI/Elements/Dialogs/BulkAddFastFlagDialog.xaml new file mode 100644 index 00000000..4cef49fb --- /dev/null +++ b/Bloxstrap/UI/Elements/Dialogs/BulkAddFastFlagDialog.xaml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + Paste in your JSON here... + + + + + + +