From 1f453a7a271b95423a6476370d993af4591f90a1 Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Sun, 9 Apr 2023 18:16:26 +0100 Subject: [PATCH 01/24] Add proper global exception handling --- Bloxstrap/App.xaml | 3 +- Bloxstrap/App.xaml.cs | 306 +++++++++++++++++++++--------------------- 2 files changed, 157 insertions(+), 152 deletions(-) diff --git a/Bloxstrap/App.xaml b/Bloxstrap/App.xaml index 28b450e..8f4642f 100644 --- a/Bloxstrap/App.xaml +++ b/Bloxstrap/App.xaml @@ -3,7 +3,8 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Bloxstrap" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" - ShutdownMode="OnExplicitShutdown"> + ShutdownMode="OnExplicitShutdown" + DispatcherUnhandledException="GlobalExceptionHandler"> diff --git a/Bloxstrap/App.xaml.cs b/Bloxstrap/App.xaml.cs index fb76ee9..e0286b0 100644 --- a/Bloxstrap/App.xaml.cs +++ b/Bloxstrap/App.xaml.cs @@ -8,6 +8,8 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; using System.Windows; +using System.Windows.Threading; + using Microsoft.Win32; using Bloxstrap.Dialogs; @@ -77,35 +79,25 @@ namespace Bloxstrap Logger.Initialize(Path.Combine(logdir, $"{ProjectName}_{timestamp}.log")); } + void GlobalExceptionHandler(object sender, DispatcherUnhandledExceptionEventArgs e) + { + e.Handled = true; + + Logger.WriteLine("[App::OnStartup] An exception occurred when running the main thread"); + Logger.WriteLine($"[App::OnStartup] {e.Exception}"); + + if (!IsQuiet) + Settings.Prop.BootstrapperStyle.GetNew().ShowError($"{e.Exception.GetType()}: {e.Exception.Message}"); + + Terminate(Bootstrapper.ERROR_INSTALL_FAILURE); + } + protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); Logger.WriteLine($"[App::OnStartup] Starting {ProjectName} v{Version}"); - // todo: remove this once 32-bit support is fully gone - if (!App.IsQuiet && !Environment.Is64BitOperatingSystem) - { - string message = "In the near future, Roblox will no longer support 32-bit Windows devices. To keep playing Roblox, please use a device that is 64-bit compatible."; - - // check if the processor actually supports 64-bit with wmic - // chances are the user just has a 32-bit version of windows installed on 64-bit hardware - Process p = new(); - p.StartInfo.CreateNoWindow = true; - p.StartInfo.UseShellExecute = false; - p.StartInfo.RedirectStandardOutput = true; - p.StartInfo.FileName = "wmic.exe"; - p.StartInfo.Arguments = "cpu get Architecture"; - p.Start(); - - // https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-processor - // architecture type 9 is x64 - if (p.StandardOutput.ReadToEnd().Contains('9')) - message += "\n\nYour computer is running a 32-bit version of Windows but is actually 64-bit compatible. Search online for how to upgrade to a 64-bit version of Windows."; - - ShowMessageBox(message, MessageBoxImage.Warning); - } - // To customize application configuration such as set high DPI settings or default font, // see https://aka.ms/applicationconfiguration. ApplicationConfiguration.Initialize(); @@ -148,6 +140,29 @@ namespace Bloxstrap } } + // todo: remove this once 32-bit support is fully gone + if (!App.IsQuiet && !Environment.Is64BitOperatingSystem) + { + string message = "In the near future, Roblox will no longer support 32-bit Windows devices. To keep playing Roblox, please use a device that is 64-bit compatible."; + + // check if the processor actually supports 64-bit with wmic + // chances are the user just has a 32-bit version of windows installed on 64-bit hardware + Process p = new(); + p.StartInfo.CreateNoWindow = true; + p.StartInfo.UseShellExecute = false; + p.StartInfo.RedirectStandardOutput = true; + p.StartInfo.FileName = "wmic.exe"; + p.StartInfo.Arguments = "cpu get Architecture"; + p.Start(); + + // https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-processor + // architecture type 9 is x64 + if (p.StandardOutput.ReadToEnd().Contains('9')) + message += "\n\nYour computer is running a 32-bit version of Windows but is actually 64-bit compatible. Search online for how to upgrade to a 64-bit version of Windows."; + + ShowMessageBox(message, MessageBoxImage.Warning); + } + // check if installed using (RegistryKey? registryKey = Registry.CurrentUser.OpenSubKey($@"Software\{ProjectName}")) { @@ -192,151 +207,140 @@ namespace Bloxstrap Settings.Load(); State.Load(); } + #if !DEBUG - try - { - if (!IsUninstall && !IsFirstRun) - Updater.CheckInstalledVersion(); + if (!IsUninstall && !IsFirstRun) + Updater.CheckInstalledVersion(); #endif - string commandLine = ""; + string commandLine = ""; - if (IsMenuLaunch) + if (IsMenuLaunch) + { + Mutex mutex; + + try { - Mutex mutex; - - try - { - mutex = Mutex.OpenExisting("Bloxstrap_MenuMutex"); - Logger.WriteLine("[App::OnStartup] Bloxstrap_MenuMutex mutex exists, aborting menu launch..."); - Terminate(); - } - catch - { - // no mutex exists, continue to opening preferences menu - mutex = new(true, "Bloxstrap_MenuMutex"); - } - - if (Utilities.GetProcessCount(ProjectName) > 1) - ShowMessageBox($"{ProjectName} 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.", MessageBoxImage.Information); - - new MainWindow().ShowDialog(); - FastFlags.Save(); + mutex = Mutex.OpenExisting("Bloxstrap_MenuMutex"); + Logger.WriteLine("[App::OnStartup] Bloxstrap_MenuMutex mutex exists, aborting menu launch..."); + Terminate(); } - else if (LaunchArgs.Length > 0) + catch { - if (LaunchArgs[0].StartsWith("roblox-player:")) - { - commandLine = Protocol.ParseUri(LaunchArgs[0]); - } - else if (LaunchArgs[0].StartsWith("roblox:")) - { - commandLine = $"--app --deeplink {LaunchArgs[0]}"; - } - else - { - commandLine = "--app"; - } + // no mutex exists, continue to opening preferences menu + mutex = new(true, "Bloxstrap_MenuMutex"); + } + + if (Utilities.GetProcessCount(ProjectName) > 1) + ShowMessageBox($"{ProjectName} 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.", MessageBoxImage.Information); + + new MainWindow().ShowDialog(); + FastFlags.Save(); + } + else if (LaunchArgs.Length > 0) + { + if (LaunchArgs[0].StartsWith("roblox-player:")) + { + commandLine = Protocol.ParseUri(LaunchArgs[0]); + } + else if (LaunchArgs[0].StartsWith("roblox:")) + { + commandLine = $"--app --deeplink {LaunchArgs[0]}"; } else { commandLine = "--app"; } - - if (!String.IsNullOrEmpty(commandLine)) - { - if (!IsFirstRun) - ShouldSaveConfigs = true; - - DeployManager.SetChannel(Settings.Prop.Channel); - - // start bootstrapper and show the bootstrapper modal if we're not running silently - Logger.WriteLine($"[App::OnStartup] Initializing bootstrapper"); - Bootstrapper bootstrapper = new(commandLine); - IBootstrapperDialog? dialog = null; - - if (!IsQuiet) - { - Logger.WriteLine($"[App::OnStartup] Initializing bootstrapper dialog"); - dialog = Settings.Prop.BootstrapperStyle.GetNew(); - bootstrapper.Dialog = dialog; - dialog.Bootstrapper = bootstrapper; - } - - // 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) - { - Logger.WriteLine("[App::OnStartup] Creating singleton mutex"); - - try - { - Mutex.OpenExisting("ROBLOX_singletonMutex"); - Logger.WriteLine("[App::OnStartup] Warning - singleton mutex already exists!"); - } - catch - { - // create the singleton mutex before the game client does - singletonMutex = new Mutex(true, "ROBLOX_singletonMutex"); - } - } - - // there's a bug here that i have yet to fix! - // sometimes the task just terminates when the bootstrapper hasn't - // actually finished, causing the bootstrapper to hang indefinitely - // i have no idea how the fuck this happens, but it happens like VERY - // rarely so i'm not too concerned by it - // maybe one day ill find out why it happens - Task bootstrapperTask = Task.Run(() => bootstrapper.Run()).ContinueWith(t => - { - Logger.WriteLine("[App::OnStartup] Bootstrapper task has finished"); - - if (t.IsFaulted) - Logger.WriteLine("[App::OnStartup] An exception occurred when running the bootstrapper"); - - if (t.Exception is null) - return; - - Logger.WriteLine($"[App::OnStartup] {t.Exception}"); - -#if DEBUG - throw t.Exception; -#else - var exception = t.Exception.InnerExceptions.Count >= 1 ? t.Exception.InnerExceptions[0] : t.Exception; - dialog?.ShowError($"{exception.GetType()}: {exception.Message}"); -#endif - }); - - dialog?.ShowBootstrapper(); - bootstrapperTask.Wait(); - - if (singletonMutex is not null) - { - Logger.WriteLine($"[App::OnStartup] 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 (Utilities.GetProcessCount("RobloxPlayerBeta", false) != 0) - { - Thread.Sleep(5000); - } - } - } -#if !DEBUG } - catch (Exception ex) + else { - Logger.WriteLine("[App::OnStartup] An exception occurred when running the main thread"); - Logger.WriteLine($"[App::OnStartup] {ex}"); + commandLine = "--app"; + } + + if (!String.IsNullOrEmpty(commandLine)) + { + if (!IsFirstRun) + ShouldSaveConfigs = true; + + DeployManager.SetChannel(Settings.Prop.Channel); + + // start bootstrapper and show the bootstrapper modal if we're not running silently + Logger.WriteLine($"[App::OnStartup] Initializing bootstrapper"); + Bootstrapper bootstrapper = new(commandLine); + IBootstrapperDialog? dialog = null; if (!IsQuiet) - Settings.Prop.BootstrapperStyle.GetNew().ShowError($"{ex.GetType()}: {ex.Message}"); - } + { + Logger.WriteLine($"[App::OnStartup] Initializing bootstrapper dialog"); + dialog = Settings.Prop.BootstrapperStyle.GetNew(); + bootstrapper.Dialog = dialog; + dialog.Bootstrapper = bootstrapper; + } + + // 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) + { + Logger.WriteLine("[App::OnStartup] Creating singleton mutex"); + + try + { + Mutex.OpenExisting("ROBLOX_singletonMutex"); + Logger.WriteLine("[App::OnStartup] Warning - singleton mutex already exists!"); + } + catch + { + // create the singleton mutex before the game client does + singletonMutex = new Mutex(true, "ROBLOX_singletonMutex"); + } + } + + // there's a bug here that i have yet to fix! + // sometimes the task just terminates when the bootstrapper hasn't + // actually finished, causing the bootstrapper to hang indefinitely + // i have no idea how the fuck this happens, but it happens like VERY + // rarely so i'm not too concerned by it + // maybe one day ill find out why it happens + Task bootstrapperTask = Task.Run(() => bootstrapper.Run()).ContinueWith(t => + { + Logger.WriteLine("[App::OnStartup] Bootstrapper task has finished"); + + if (t.IsFaulted) + Logger.WriteLine("[App::OnStartup] An exception occurred when running the bootstrapper"); + + if (t.Exception is null) + return; + + Logger.WriteLine($"[App::OnStartup] {t.Exception}"); + +#if DEBUG + throw t.Exception; +#else + var exception = t.Exception.InnerExceptions.Count >= 1 ? t.Exception.InnerExceptions[0] : t.Exception; + dialog?.ShowError($"{exception.GetType()}: {exception.Message}"); + Terminate(Bootstrapper.ERROR_INSTALL_FAILURE); #endif + }); + + dialog?.ShowBootstrapper(); + bootstrapperTask.Wait(); + + if (singletonMutex is not null) + { + Logger.WriteLine($"[App::OnStartup] 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 (Utilities.GetProcessCount("RobloxPlayerBeta", false) != 0) + { + Thread.Sleep(5000); + } + } + } Logger.WriteLine($"[App::OnStartup] Successfully reached end of main thread. Terminating..."); From a95ce870db1ba614d761a45a6f1b6399aef1186f Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Tue, 11 Apr 2023 13:19:10 +0100 Subject: [PATCH 02/24] Auto change icon to custom when changing location MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit i dont know what the issue id for this is because im on a plane like 999999 feet in the air 😭 --- Bloxstrap/ViewModels/AppearanceViewModel.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Bloxstrap/ViewModels/AppearanceViewModel.cs b/Bloxstrap/ViewModels/AppearanceViewModel.cs index 320a9c8..818085f 100644 --- a/Bloxstrap/ViewModels/AppearanceViewModel.cs +++ b/Bloxstrap/ViewModels/AppearanceViewModel.cs @@ -118,7 +118,10 @@ namespace Bloxstrap.ViewModels get => App.Settings.Prop.BootstrapperIconCustomLocation; set { + App.Settings.Prop.BootstrapperIcon = BootstrapperIcon.IconCustom; App.Settings.Prop.BootstrapperIconCustomLocation = value; + + OnPropertyChanged(nameof(Icon)); OnPropertyChanged(nameof(IconPreviewSource)); } } From 7a305c6bd24a911d053d6581cf2e70c0e7a428fc Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Tue, 11 Apr 2023 23:54:03 +0200 Subject: [PATCH 03/24] Write all FastFlag values strictly as strings this is how roblox does it, and it just makes things easier --- Bloxstrap/Helpers/FastFlagManager.cs | 25 ++++++++++++++++----- Bloxstrap/ViewModels/ModsViewModel.cs | 32 +++++++++++++-------------- Bloxstrap/Views/Pages/ModsPage.xaml | 20 ++++++++--------- 3 files changed, 45 insertions(+), 32 deletions(-) diff --git a/Bloxstrap/Helpers/FastFlagManager.cs b/Bloxstrap/Helpers/FastFlagManager.cs index 3fb2da5..b23b8a6 100644 --- a/Bloxstrap/Helpers/FastFlagManager.cs +++ b/Bloxstrap/Helpers/FastFlagManager.cs @@ -23,10 +23,23 @@ namespace Bloxstrap.Helpers { "Vulkan", "FFlagDebugGraphicsPreferVulkan" } }; + // all fflags are stored as strings + // to delete a flag, set the value as null + public void SetValue(string key, object? value) + { + if (value == null) + { + Changes[key] = null; + App.Logger.WriteLine($"[FastFlagManager::SetValue] Deletion of '{key}' is pending"); + } + else + { + Changes[key] = value.ToString(); + App.Logger.WriteLine($"[FastFlagManager::SetValue] Value change for '{key}' to '{value}' is pending"); + } + } + // this returns null if the fflag doesn't exist - // this also returns as a string because deserializing an object doesn't - // deserialize back into the original object type, it instead deserializes - // as a "JsonElement" which is annoying public string? GetValue(string key) { // check if we have an updated change for it pushed first @@ -44,11 +57,11 @@ namespace Bloxstrap.Helpers foreach (var mode in RenderingModes) { if (mode.Key != "Automatic") - App.FastFlags.Changes[mode.Value] = null; + SetValue(mode.Value, null); } if (value != "Automatic") - App.FastFlags.Changes[RenderingModes[value]] = true; + SetValue(RenderingModes[value], "True"); } public override void Save() @@ -73,7 +86,7 @@ namespace Bloxstrap.Helpers continue; } - App.Logger.WriteLine($"[FastFlagManager::Save] Setting '{change.Key}' to {change.Value}"); + App.Logger.WriteLine($"[FastFlagManager::Save] Setting '{change.Key}' to '{change.Value}'"); Prop[change.Key] = change.Value; } diff --git a/Bloxstrap/ViewModels/ModsViewModel.cs b/Bloxstrap/ViewModels/ModsViewModel.cs index 7467c80..c756ef8 100644 --- a/Bloxstrap/ViewModels/ModsViewModel.cs +++ b/Bloxstrap/ViewModels/ModsViewModel.cs @@ -39,22 +39,6 @@ namespace Bloxstrap.ViewModels public IReadOnlyDictionary RenderingModes => FastFlagManager.RenderingModes; - // this flag has to be set to false to work, weirdly enough - public bool ExclusiveFullscreenEnabled - { - get => App.FastFlags.GetValue("FFlagHandleAltEnterFullscreenManually") == "False"; - set - { - App.FastFlags.Changes["FFlagHandleAltEnterFullscreenManually"] = value ? false : null; - - if (value) - { - App.FastFlags.SetRenderingMode("Direct3D 11"); - OnPropertyChanged(nameof(SelectedRenderingMode)); - } - } - } - public string SelectedRenderingMode { get @@ -71,6 +55,22 @@ namespace Bloxstrap.ViewModels set => App.FastFlags.SetRenderingMode(value); } + // this flag has to be set to false to work, weirdly enough + public bool ExclusiveFullscreenEnabled + { + get => App.FastFlags.GetValue("FFlagHandleAltEnterFullscreenManually") == "False"; + set + { + App.FastFlags.Changes["FFlagHandleAltEnterFullscreenManually"] = value ? false : null; + + if (value) + { + App.FastFlags.SetRenderingMode("Direct3D 11"); + OnPropertyChanged(nameof(SelectedRenderingMode)); + } + } + } + public bool DisableFullscreenOptimizationsEnabled { get => App.Settings.Prop.DisableFullscreenOptimizations; diff --git a/Bloxstrap/Views/Pages/ModsPage.xaml b/Bloxstrap/Views/Pages/ModsPage.xaml index cf1610b..37619c6 100644 --- a/Bloxstrap/Views/Pages/ModsPage.xaml +++ b/Bloxstrap/Views/Pages/ModsPage.xaml @@ -6,7 +6,7 @@ xmlns:models="clr-namespace:Bloxstrap.ViewModels" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" mc:Ignorable="d" - d:DesignHeight="450" d:DesignWidth="800" + d:DesignHeight="800" d:DesignWidth="800" Title="ModsPage" Scrollable="True"> @@ -102,15 +102,6 @@ - - - - - - - - - @@ -119,6 +110,15 @@ + + + + + + + + + From aeeb89445ef16b75ff2e990edd15d53f47bdb8ef Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Wed, 12 Apr 2023 00:28:54 +0200 Subject: [PATCH 04/24] Add FFlag preset for setting framerate cap this will replace rbxfpsunlocker, and yeah having a default value of 99999 might be a bit weird lol --- Bloxstrap/Helpers/FastFlagManager.cs | 10 ++++++++++ Bloxstrap/Helpers/JsonManager.cs | 20 ++++++++------------ Bloxstrap/ViewModels/ModsViewModel.cs | 11 +++++++++-- Bloxstrap/Views/Pages/ModsPage.xaml | 12 +++++++++++- Bloxstrap/Views/Pages/ModsPage.xaml.cs | 4 ++++ 5 files changed, 42 insertions(+), 15 deletions(-) diff --git a/Bloxstrap/Helpers/FastFlagManager.cs b/Bloxstrap/Helpers/FastFlagManager.cs index b23b8a6..7558aa2 100644 --- a/Bloxstrap/Helpers/FastFlagManager.cs +++ b/Bloxstrap/Helpers/FastFlagManager.cs @@ -1,4 +1,5 @@ using Newtonsoft.Json.Linq; +using System; using System.Collections.Generic; using System.IO; using System.Text.Json; @@ -64,6 +65,15 @@ namespace Bloxstrap.Helpers SetValue(RenderingModes[value], "True"); } + public override void Load() + { + base.Load(); + + // set to 99999 by default if it doesnt immediately exist + if (GetValue("DFIntTaskSchedulerTargetFps") is null) + SetValue("DFIntTaskSchedulerTargetFps", 99999); + } + public override void Save() { App.Logger.WriteLine($"[FastFlagManager::Save] Attempting to save JSON to {FileLocation}..."); diff --git a/Bloxstrap/Helpers/JsonManager.cs b/Bloxstrap/Helpers/JsonManager.cs index fb59f7d..dde7851 100644 --- a/Bloxstrap/Helpers/JsonManager.cs +++ b/Bloxstrap/Helpers/JsonManager.cs @@ -1,15 +1,6 @@ -using Bloxstrap.Models; -using Bloxstrap.Properties; -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Diagnostics; +using System; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Text.Json; -using System.Threading; namespace Bloxstrap.Helpers { @@ -19,14 +10,19 @@ namespace Bloxstrap.Helpers public virtual string FileLocation => AltFileLocation ?? Path.Combine(Directories.Base, $"{typeof(T).Name}.json"); public string? AltFileLocation { get; set; } - public void Load() + public virtual void Load() { App.Logger.WriteLine($"[JsonManager<{typeof(T).Name}>::Load] Loading JSON from {FileLocation}..."); try { T? settings = JsonSerializer.Deserialize(File.ReadAllText(FileLocation)); - Prop = settings ?? throw new ArgumentNullException("Deserialization returned null"); + + if (settings is null) + throw new ArgumentNullException("Deserialization returned null"); + + Prop = settings; + App.Logger.WriteLine($"[JsonManager<{typeof(T).Name}>::Load] JSON loaded successfully!"); } catch (Exception ex) diff --git a/Bloxstrap/ViewModels/ModsViewModel.cs b/Bloxstrap/ViewModels/ModsViewModel.cs index c756ef8..10f9b1a 100644 --- a/Bloxstrap/ViewModels/ModsViewModel.cs +++ b/Bloxstrap/ViewModels/ModsViewModel.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Windows.Input; @@ -39,6 +40,12 @@ namespace Bloxstrap.ViewModels public IReadOnlyDictionary RenderingModes => FastFlagManager.RenderingModes; + public int FramerateLimit + { + get => Int32.TryParse(App.FastFlags.GetValue("DFIntTaskSchedulerTargetFps"), out int x) ? x : 60; + set => App.FastFlags.Changes["DFIntTaskSchedulerTargetFps"] = value; + } + public string SelectedRenderingMode { get @@ -61,7 +68,7 @@ namespace Bloxstrap.ViewModels get => App.FastFlags.GetValue("FFlagHandleAltEnterFullscreenManually") == "False"; set { - App.FastFlags.Changes["FFlagHandleAltEnterFullscreenManually"] = value ? false : null; + App.FastFlags.SetValue("FFlagHandleAltEnterFullscreenManually", value ? false : null); if (value) { diff --git a/Bloxstrap/Views/Pages/ModsPage.xaml b/Bloxstrap/Views/Pages/ModsPage.xaml index 37619c6..29e0a25 100644 --- a/Bloxstrap/Views/Pages/ModsPage.xaml +++ b/Bloxstrap/Views/Pages/ModsPage.xaml @@ -99,9 +99,19 @@ + + + + + + + + + + @@ -110,7 +120,7 @@ - + diff --git a/Bloxstrap/Views/Pages/ModsPage.xaml.cs b/Bloxstrap/Views/Pages/ModsPage.xaml.cs index b5c7e43..76fd5c3 100644 --- a/Bloxstrap/Views/Pages/ModsPage.xaml.cs +++ b/Bloxstrap/Views/Pages/ModsPage.xaml.cs @@ -1,5 +1,7 @@ using System; using System.Windows; +using System.Windows.Input; + using Bloxstrap.ViewModels; namespace Bloxstrap.Views.Pages @@ -21,5 +23,7 @@ namespace Bloxstrap.Views.Pages if (Environment.OSVersion.Version.Build < 17093) this.MiscellaneousOptions.Visibility = Visibility.Collapsed; } + + private void ValidateInt32(object sender, TextCompositionEventArgs e) => e.Handled = !Int32.TryParse(e.Text, out int _); } } From 994d736eeb9854ddf07271be6bc037495be8885d Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Wed, 12 Apr 2023 00:33:05 +0200 Subject: [PATCH 05/24] Fix bug with FFlags being saved when cancelled --- Bloxstrap/App.xaml.cs | 1 - Bloxstrap/ViewModels/MainWindowViewModel.cs | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Bloxstrap/App.xaml.cs b/Bloxstrap/App.xaml.cs index e0286b0..bc11e55 100644 --- a/Bloxstrap/App.xaml.cs +++ b/Bloxstrap/App.xaml.cs @@ -235,7 +235,6 @@ namespace Bloxstrap ShowMessageBox($"{ProjectName} 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.", MessageBoxImage.Information); new MainWindow().ShowDialog(); - FastFlags.Save(); } else if (LaunchArgs.Length > 0) { diff --git a/Bloxstrap/ViewModels/MainWindowViewModel.cs b/Bloxstrap/ViewModels/MainWindowViewModel.cs index 261548a..259c3f8 100644 --- a/Bloxstrap/ViewModels/MainWindowViewModel.cs +++ b/Bloxstrap/ViewModels/MainWindowViewModel.cs @@ -60,6 +60,7 @@ namespace Bloxstrap.ViewModels if (!App.IsFirstRun) { App.ShouldSaveConfigs = true; + App.FastFlags.Save(); if (App.BaseDirectory != _originalBaseDirectory) { From 65c85b612a8c6e4bf6186d8d22abc055012aaadd Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Wed, 12 Apr 2023 00:55:59 +0200 Subject: [PATCH 06/24] Remove rbxfpsunlocker in favor of target FPS FFlag --- Bloxstrap/Bootstrapper.cs | 21 +-- Bloxstrap/Helpers/FastFlagManager.cs | 7 +- Bloxstrap/Helpers/IntegrationMigrator.cs | 18 +++ Bloxstrap/Integrations/RbxFpsUnlocker.cs | 122 ------------------ Bloxstrap/Models/Settings.cs | 2 - Bloxstrap/Models/State.cs | 1 - Bloxstrap/ViewModels/IntegrationsViewModel.cs | 17 --- Bloxstrap/Views/Pages/AboutPage.xaml | 6 - Bloxstrap/Views/Pages/IntegrationsPage.xaml | 24 +--- .../Views/Pages/IntegrationsPage.xaml.cs | 4 - Bloxstrap/Views/Pages/ModsPage.xaml | 2 +- 11 files changed, 27 insertions(+), 197 deletions(-) create mode 100644 Bloxstrap/Helpers/IntegrationMigrator.cs delete mode 100644 Bloxstrap/Integrations/RbxFpsUnlocker.cs diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index b9bc107..8013ab9 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -170,7 +170,7 @@ namespace Bloxstrap CheckInstall(); - await RbxFpsUnlocker.CheckInstall(); + IntegrationMigrator.Execute(); // at this point we've finished updating our configs App.Settings.Save(); @@ -353,25 +353,6 @@ namespace Bloxstrap if (!startEventFired) return; } - - if (App.Settings.Prop.RFUEnabled && Process.GetProcessesByName(RbxFpsUnlocker.ApplicationName).Length == 0) - { - App.Logger.WriteLine("[Bootstrapper::StartRoblox] Using rbxfpsunlocker"); - - ProcessStartInfo startInfo = new() - { - WorkingDirectory = Path.Combine(Directories.Integrations, "rbxfpsunlocker"), - FileName = Path.Combine(Directories.Integrations, @"rbxfpsunlocker\rbxfpsunlocker.exe") - }; - - Process process = Process.Start(startInfo)!; - - if (App.Settings.Prop.RFUAutoclose) - { - shouldWait = true; - autocloseProcesses.Add(process); - } - } if (App.Settings.Prop.UseDiscordRichPresence || App.Settings.Prop.ShowServerDetails) { diff --git a/Bloxstrap/Helpers/FastFlagManager.cs b/Bloxstrap/Helpers/FastFlagManager.cs index 7558aa2..1341731 100644 --- a/Bloxstrap/Helpers/FastFlagManager.cs +++ b/Bloxstrap/Helpers/FastFlagManager.cs @@ -71,7 +71,12 @@ namespace Bloxstrap.Helpers // set to 99999 by default if it doesnt immediately exist if (GetValue("DFIntTaskSchedulerTargetFps") is null) - SetValue("DFIntTaskSchedulerTargetFps", 99999); + { + SetValue("DFIntTaskSchedulerTargetFps", 9999); + + if (!App.IsFirstRun) + Save(); + } } public override void Save() diff --git a/Bloxstrap/Helpers/IntegrationMigrator.cs b/Bloxstrap/Helpers/IntegrationMigrator.cs new file mode 100644 index 0000000..4d3b4f7 --- /dev/null +++ b/Bloxstrap/Helpers/IntegrationMigrator.cs @@ -0,0 +1,18 @@ +using System.IO; + +namespace Bloxstrap.Helpers +{ + static class IntegrationMigrator + { + public static void Execute() + { + App.FastFlags.Load(); + + // v2.2.0 - remove rbxfpsunlocker + string rbxfpsunlocker = Path.Combine(Directories.Integrations, "rbxfpsunlocker"); + + if (Directory.Exists(rbxfpsunlocker)) + Directory.Delete(rbxfpsunlocker, true); + } + } +} diff --git a/Bloxstrap/Integrations/RbxFpsUnlocker.cs b/Bloxstrap/Integrations/RbxFpsUnlocker.cs deleted file mode 100644 index bb56886..0000000 --- a/Bloxstrap/Integrations/RbxFpsUnlocker.cs +++ /dev/null @@ -1,122 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.IO.Compression; -using System.Threading.Tasks; -using Bloxstrap.Helpers; - -using Bloxstrap.Models; - -namespace Bloxstrap.Integrations -{ - internal class RbxFpsUnlocker - { - public const string ApplicationName = "rbxfpsunlocker"; - public const string ProjectRepository = "axstin/rbxfpsunlocker"; - - // default settings but with QuickStart set to true and CheckForUpdates set to false - private static readonly string Settings = - "UnlockClient=true\n" + - "UnlockStudio=false\n" + - "FPSCapValues=[30.000000, 60.000000, 75.000000, 120.000000, 144.000000, 165.000000, 240.000000, 360.000000]\n" + - "FPSCapSelection=0\n" + - "FPSCap=0.000000\n" + - "CheckForUpdates=false\n" + - "NonBlockingErrors=true\n" + - "SilentErrors=false\n" + - "QuickStart=true\n"; - - public static void CheckIfRunning() - { - Process[] processes = Process.GetProcessesByName(ApplicationName); - - if (processes.Length == 0) - return; - - App.Logger.WriteLine("[RbxFpsUnlocker::CheckIfRunning] Closing currently running rbxfpsunlocker processes..."); - - try - { - foreach (Process process in processes) - { - if (process.MainModule?.FileName is null) - continue; - - if (!process.MainModule.FileName.Contains(Directories.Base)) - continue; - - process.Kill(); - process.Close(); - } - } - catch (Exception ex) - { - App.Logger.WriteLine($"[RbxFpsUnlocker::CheckIfRunning] Could not close rbxfpsunlocker process! {ex}"); - } - } - - public static async Task CheckInstall() - { - string folderLocation = Path.Combine(Directories.Base, "Integrations\\rbxfpsunlocker"); - string fileLocation = Path.Combine(folderLocation, "rbxfpsunlocker.exe"); - string settingsLocation = Path.Combine(folderLocation, "settings"); - - if (!App.Settings.Prop.RFUEnabled) - { - // don't delete rbxfpsunlocker if rbxfpsunlocker and roblox is currently running - if (Utilities.CheckIfProcessRunning(ApplicationName) && Utilities.CheckIfRobloxRunning()) - return; - - App.State.Prop.RbxFpsUnlockerVersion = ""; - App.State.Save(); - - if (Directory.Exists(folderLocation)) - { - CheckIfRunning(); - Directory.Delete(folderLocation, true); - } - - return; - } - - var releaseInfo = await Utilities.GetJson($"https://api.github.com/repos/{ProjectRepository}/releases/latest"); - - if (releaseInfo is null || releaseInfo.Assets is null) - return; - - string downloadUrl = releaseInfo.Assets[0].BrowserDownloadUrl; - - DirectoryInfo directory = new(folderLocation); - directory.Create(); - // i have no idea how the read only flag enables itself but apparently it just does - directory.Attributes &= ~FileAttributes.ReadOnly; - - if (File.Exists(fileLocation)) - { - // no new release published, return - if (App.State.Prop.RbxFpsUnlockerVersion == releaseInfo.TagName) - return; - - CheckIfRunning(); - File.Delete(fileLocation); - } - - App.Logger.WriteLine("[RbxFpsUnlocker::CheckInstall] Installing/Updating rbxfpsunlocker..."); - - { - byte[] bytes = await App.HttpClient.GetByteArrayAsync(downloadUrl); - - using MemoryStream zipStream = new(bytes); - using ZipArchive archive = new(zipStream); - - archive.ExtractToDirectory(folderLocation, true); - } - - if (!File.Exists(settingsLocation)) - await File.WriteAllTextAsync(settingsLocation, Settings); - - App.State.Prop.RbxFpsUnlockerVersion = releaseInfo.TagName; - App.State.Save(); - } - } -} diff --git a/Bloxstrap/Models/Settings.cs b/Bloxstrap/Models/Settings.cs index a8e96b6..95b1b8e 100644 --- a/Bloxstrap/Models/Settings.cs +++ b/Bloxstrap/Models/Settings.cs @@ -25,8 +25,6 @@ namespace Bloxstrap.Models // integration configuration public bool UseDiscordRichPresence { get; set; } = true; public bool HideRPCButtons { get; set; } = true; - public bool RFUEnabled { get; set; } = false; - public bool RFUAutoclose { get; set; } = false; public bool UseReShade { get; set; } = true; public bool UseReShadeExtraviPresets { get; set; } = true; public bool ShowServerDetails { get; set; } = false; diff --git a/Bloxstrap/Models/State.cs b/Bloxstrap/Models/State.cs index fcc2d7c..be8c221 100644 --- a/Bloxstrap/Models/State.cs +++ b/Bloxstrap/Models/State.cs @@ -9,7 +9,6 @@ namespace Bloxstrap.Models public class State { public string VersionGuid { get; set; } = ""; - public string RbxFpsUnlockerVersion { get; set; } = ""; public string ReShadeConfigVersion { get; set; } = ""; public string ExtraviReShadePresetsVersion { get; set; } = ""; public List ModManifest { get; set; } = new(); diff --git a/Bloxstrap/ViewModels/IntegrationsViewModel.cs b/Bloxstrap/ViewModels/IntegrationsViewModel.cs index e242d81..ca876b2 100644 --- a/Bloxstrap/ViewModels/IntegrationsViewModel.cs +++ b/Bloxstrap/ViewModels/IntegrationsViewModel.cs @@ -97,23 +97,6 @@ namespace Bloxstrap.ViewModels set => App.Settings.Prop.UseReShadeExtraviPresets = value; } - public bool RbxFpsUnlockerEnabled - { - get => App.Settings.Prop.RFUEnabled; - set - { - App.Settings.Prop.RFUEnabled = value; - RbxFpsUnlockerAutocloseEnabled = value; - OnPropertyChanged(nameof(RbxFpsUnlockerAutocloseEnabled)); - } - } - - public bool RbxFpsUnlockerAutocloseEnabled - { - get => App.Settings.Prop.RFUAutoclose; - set => App.Settings.Prop.RFUAutoclose = value; - } - public bool ShowServerDetailsEnabled { get => App.Settings.Prop.ShowServerDetails; diff --git a/Bloxstrap/Views/Pages/AboutPage.xaml b/Bloxstrap/Views/Pages/AboutPage.xaml index 2a31eee..8130c33 100644 --- a/Bloxstrap/Views/Pages/AboutPage.xaml +++ b/Bloxstrap/Views/Pages/AboutPage.xaml @@ -137,12 +137,6 @@ - - - - - - diff --git a/Bloxstrap/Views/Pages/IntegrationsPage.xaml b/Bloxstrap/Views/Pages/IntegrationsPage.xaml index 8aebf4f..a204986 100644 --- a/Bloxstrap/Views/Pages/IntegrationsPage.xaml +++ b/Bloxstrap/Views/Pages/IntegrationsPage.xaml @@ -93,28 +93,6 @@ - - - - - - - - - - - - - - - - - - - - - - @@ -127,7 +105,7 @@ - + diff --git a/Bloxstrap/Views/Pages/IntegrationsPage.xaml.cs b/Bloxstrap/Views/Pages/IntegrationsPage.xaml.cs index c4066ab..5809833 100644 --- a/Bloxstrap/Views/Pages/IntegrationsPage.xaml.cs +++ b/Bloxstrap/Views/Pages/IntegrationsPage.xaml.cs @@ -15,10 +15,6 @@ namespace Bloxstrap.Views.Pages { DataContext = new IntegrationsViewModel(); InitializeComponent(); - - // rbxfpsunlocker does not have 64 bit support - if (!Environment.Is64BitOperatingSystem) - this.RbxFpsUnlockerOptions.Visibility = Visibility.Collapsed; } public void CustomIntegrationSelection(object sender, SelectionChangedEventArgs e) diff --git a/Bloxstrap/Views/Pages/ModsPage.xaml b/Bloxstrap/Views/Pages/ModsPage.xaml index 29e0a25..1c19abc 100644 --- a/Bloxstrap/Views/Pages/ModsPage.xaml +++ b/Bloxstrap/Views/Pages/ModsPage.xaml @@ -106,7 +106,7 @@ - + From d7dc198a8ba2c1765b64a0b09e23e664e3b3e70b Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Wed, 12 Apr 2023 11:06:27 +0200 Subject: [PATCH 07/24] Check if player executable exists (#128) --- Bloxstrap/Bootstrapper.cs | 36 +++++++++++------------- Bloxstrap/Helpers/FastFlagManager.cs | 13 +++------ Bloxstrap/Helpers/IntegrationMigrator.cs | 2 -- 3 files changed, 20 insertions(+), 31 deletions(-) diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index 8013ab9..41cd7c8 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -68,6 +68,7 @@ namespace Bloxstrap private static bool FreshInstall => String.IsNullOrEmpty(App.State.Prop.VersionGuid); private static string DesktopShortcutLocation => Path.Combine(Directories.Desktop, "Play Roblox.lnk"); + private string _playerLocation => Path.Combine(_versionFolder, "RobloxPlayerBeta.exe"); private string? _launchCommandLine; @@ -144,8 +145,9 @@ namespace Bloxstrap CheckInstallMigration(); - // if roblox needs updating but is running and we have multiple instances open, ignore update for now - if (App.IsFirstRun || _versionGuid != App.State.Prop.VersionGuid && !Utilities.CheckIfRobloxRunning()) + // only update roblox if we're running for the first time, or if + // roblox isn't running and our version guid is out of date, or the player exe doesn't exist + if (App.IsFirstRun || !Utilities.CheckIfRobloxRunning() && (_versionGuid != App.State.Prop.VersionGuid || !File.Exists(_playerLocation))) await InstallLatestVersion(); // last time the version folder was set, it was set to the latest version guid @@ -153,10 +155,10 @@ namespace Bloxstrap _versionFolder = Path.Combine(Directories.Versions, App.State.Prop.VersionGuid); if (App.IsFirstRun) - { App.ShouldSaveConfigs = true; - App.FastFlags.Save(); - } + + IntegrationMigrator.Execute(); + App.FastFlags.Save(); if (App.Settings.Prop.UseReShade) SetStatus("Configuring/Downloading ReShade..."); @@ -170,8 +172,6 @@ namespace Bloxstrap CheckInstall(); - IntegrationMigrator.Execute(); - // at this point we've finished updating our configs App.Settings.Save(); App.State.Save(); @@ -336,7 +336,7 @@ namespace Bloxstrap // whether we should wait for roblox to exit to handle stuff in the background or clean up after roblox closes bool shouldWait = false; - Process gameClient = Process.Start(Path.Combine(_versionFolder, "RobloxPlayerBeta.exe"), _launchCommandLine); + Process gameClient = Process.Start(_playerLocation, _launchCommandLine); List autocloseProcesses = new(); GameActivityWatcher? activityWatcher = null; DiscordRichPresence? richPresence = null; @@ -708,23 +708,20 @@ namespace Bloxstrap string oldVersionFolder = Path.Combine(Directories.Versions, App.State.Prop.VersionGuid); + // and also to delete our old version folder if (_versionGuid != App.State.Prop.VersionGuid && Directory.Exists(oldVersionFolder)) - { - // and also to delete our old version folder Directory.Delete(oldVersionFolder, true); - } // move old compatibility flags for the old location using (RegistryKey appFlagsKey = Registry.CurrentUser.CreateSubKey($"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers")) { string oldGameClientLocation = Path.Combine(oldVersionFolder, "RobloxPlayerBeta.exe"); - string newGameClientLocation = Path.Combine(_versionFolder, "RobloxPlayerBeta.exe"); string? appFlags = (string?)appFlagsKey.GetValue(oldGameClientLocation); if (appFlags is not null) { - App.Logger.WriteLine($"[Bootstrapper::InstallLatestVersion] Migrating app compatibility flags from {oldGameClientLocation} to {newGameClientLocation}..."); - appFlagsKey.SetValue(newGameClientLocation, appFlags); + App.Logger.WriteLine($"[Bootstrapper::InstallLatestVersion] Migrating app compatibility flags from {oldGameClientLocation} to {_playerLocation}..."); + appFlagsKey.SetValue(_playerLocation, appFlags); appFlagsKey.DeleteValue(oldGameClientLocation); } } @@ -747,23 +744,22 @@ namespace Bloxstrap using (RegistryKey appFlagsKey = Registry.CurrentUser.CreateSubKey($"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers")) { const string flag = " DISABLEDXMAXIMIZEDWINDOWEDMODE"; - string gameClientLocation = Path.Combine(_versionFolder, "RobloxPlayerBeta.exe"); - string? appFlags = (string?)appFlagsKey.GetValue(gameClientLocation); + string? appFlags = (string?)appFlagsKey.GetValue(_playerLocation); if (App.Settings.Prop.DisableFullscreenOptimizations) { if (appFlags is null) - appFlagsKey.SetValue(gameClientLocation, $"~{flag}"); + appFlagsKey.SetValue(_playerLocation, $"~{flag}"); else if (!appFlags.Contains(flag)) - appFlagsKey.SetValue(gameClientLocation, appFlags + flag); + appFlagsKey.SetValue(_playerLocation, appFlags + flag); } else if (appFlags is not null && appFlags.Contains(flag)) { // if there's more than one space, there's more flags set we need to preserve if (appFlags.Split(' ').Length > 2) - appFlagsKey.SetValue(gameClientLocation, appFlags.Remove(appFlags.IndexOf(flag), flag.Length)); + appFlagsKey.SetValue(_playerLocation, appFlags.Remove(appFlags.IndexOf(flag), flag.Length)); else - appFlagsKey.DeleteValue(gameClientLocation); + appFlagsKey.DeleteValue(_playerLocation); } } diff --git a/Bloxstrap/Helpers/FastFlagManager.cs b/Bloxstrap/Helpers/FastFlagManager.cs index 1341731..170e6b9 100644 --- a/Bloxstrap/Helpers/FastFlagManager.cs +++ b/Bloxstrap/Helpers/FastFlagManager.cs @@ -69,29 +69,24 @@ namespace Bloxstrap.Helpers { base.Load(); - // set to 99999 by default if it doesnt immediately exist + // set to 9999 by default if it doesnt already exist if (GetValue("DFIntTaskSchedulerTargetFps") is null) - { SetValue("DFIntTaskSchedulerTargetFps", 9999); - - if (!App.IsFirstRun) - Save(); - } } public override void Save() { App.Logger.WriteLine($"[FastFlagManager::Save] Attempting to save JSON to {FileLocation}..."); + // reload for any changes made while the menu was open + Load(); + if (Changes.Count == 0) { App.Logger.WriteLine($"[FastFlagManager::Save] No changes to apply, aborting."); return; } - // reload for any changes made while the menu was open - Load(); - foreach (var change in Changes) { if (change.Value is null) diff --git a/Bloxstrap/Helpers/IntegrationMigrator.cs b/Bloxstrap/Helpers/IntegrationMigrator.cs index 4d3b4f7..e073719 100644 --- a/Bloxstrap/Helpers/IntegrationMigrator.cs +++ b/Bloxstrap/Helpers/IntegrationMigrator.cs @@ -6,8 +6,6 @@ namespace Bloxstrap.Helpers { public static void Execute() { - App.FastFlags.Load(); - // v2.2.0 - remove rbxfpsunlocker string rbxfpsunlocker = Path.Combine(Directories.Integrations, "rbxfpsunlocker"); From c5d46f5d46b0e438fe1316107f60ee3320f1faf3 Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Thu, 13 Apr 2023 21:04:54 +0200 Subject: [PATCH 08/24] Change how default flag values are handled they're now all handled before they're saved/loaded --- Bloxstrap/App.xaml.cs | 3 --- Bloxstrap/Helpers/FastFlagManager.cs | 4 ++++ Bloxstrap/Helpers/Updater.cs | 8 -------- Bloxstrap/ViewModels/ModsViewModel.cs | 9 +++------ Bloxstrap/Views/Pages/ModsPage.xaml.cs | 3 +-- 5 files changed, 8 insertions(+), 19 deletions(-) diff --git a/Bloxstrap/App.xaml.cs b/Bloxstrap/App.xaml.cs index bc11e55..faf6167 100644 --- a/Bloxstrap/App.xaml.cs +++ b/Bloxstrap/App.xaml.cs @@ -173,9 +173,6 @@ namespace Bloxstrap BaseDirectory = Path.Combine(Directories.LocalAppData, ProjectName); InitLog(); - // we have reshade enabled by default so we need this - FastFlags.SetRenderingMode("Direct3D 11"); - if (!IsQuiet) { IsSetupComplete = false; diff --git a/Bloxstrap/Helpers/FastFlagManager.cs b/Bloxstrap/Helpers/FastFlagManager.cs index 170e6b9..a4ab45f 100644 --- a/Bloxstrap/Helpers/FastFlagManager.cs +++ b/Bloxstrap/Helpers/FastFlagManager.cs @@ -72,6 +72,10 @@ namespace Bloxstrap.Helpers // set to 9999 by default if it doesnt already exist if (GetValue("DFIntTaskSchedulerTargetFps") is null) SetValue("DFIntTaskSchedulerTargetFps", 9999); + + // reshade / exclusive fullscreen requires direct3d 11 to work + if (GetValue(RenderingModes["Direct3D 11"]) != "True" && (App.Settings.Prop.UseReShade || App.FastFlags.GetValue("FFlagHandleAltEnterFullscreenManually") == "False")) + SetRenderingMode("Direct3D 11"); } public override void Save() diff --git a/Bloxstrap/Helpers/Updater.cs b/Bloxstrap/Helpers/Updater.cs index c36636e..c9c1ebe 100644 --- a/Bloxstrap/Helpers/Updater.cs +++ b/Bloxstrap/Helpers/Updater.cs @@ -78,14 +78,6 @@ namespace Bloxstrap.Helpers Bootstrapper.Register(); - // update check: if we're upgrading to v2.1.0 and have reshade enabled, - // we need to set our renderer to direct3d 11 - if (App.Settings.Prop.UseReShade && App.FastFlags.GetValue(FastFlagManager.RenderingModes["Direct3D 11"]) is null) - { - App.FastFlags.SetRenderingMode("Direct3D 11"); - App.FastFlags.Save(); - } - if (isAutoUpgrade) { NotifyIcon notification = new() diff --git a/Bloxstrap/ViewModels/ModsViewModel.cs b/Bloxstrap/ViewModels/ModsViewModel.cs index 10f9b1a..db8b2f7 100644 --- a/Bloxstrap/ViewModels/ModsViewModel.cs +++ b/Bloxstrap/ViewModels/ModsViewModel.cs @@ -15,10 +15,7 @@ namespace Bloxstrap.ViewModels public ICommand OpenModsFolderCommand => new RelayCommand(OpenModsFolder); - private void OpenModsFolder() - { - Process.Start("explorer.exe", Directories.Modifications); - } + private void OpenModsFolder() => Process.Start("explorer.exe", Directories.Modifications); public bool OldDeathSoundEnabled { @@ -43,7 +40,7 @@ namespace Bloxstrap.ViewModels public int FramerateLimit { get => Int32.TryParse(App.FastFlags.GetValue("DFIntTaskSchedulerTargetFps"), out int x) ? x : 60; - set => App.FastFlags.Changes["DFIntTaskSchedulerTargetFps"] = value; + set => App.FastFlags.SetValue("DFIntTaskSchedulerTargetFps", value); } public string SelectedRenderingMode @@ -68,7 +65,7 @@ namespace Bloxstrap.ViewModels get => App.FastFlags.GetValue("FFlagHandleAltEnterFullscreenManually") == "False"; set { - App.FastFlags.SetValue("FFlagHandleAltEnterFullscreenManually", value ? false : null); + App.FastFlags.SetValue("FFlagHandleAltEnterFullscreenManually", value ? "False" : null); if (value) { diff --git a/Bloxstrap/Views/Pages/ModsPage.xaml.cs b/Bloxstrap/Views/Pages/ModsPage.xaml.cs index 76fd5c3..704448e 100644 --- a/Bloxstrap/Views/Pages/ModsPage.xaml.cs +++ b/Bloxstrap/Views/Pages/ModsPage.xaml.cs @@ -13,8 +13,7 @@ namespace Bloxstrap.Views.Pages { public ModsPage() { - if (!App.IsFirstRun) - App.FastFlags.Load(); + App.FastFlags.Load(); DataContext = new ModsViewModel(); InitializeComponent(); From 45f760bc1447db6af7356ee388be64c62d53bf56 Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Fri, 14 Apr 2023 21:31:34 +0200 Subject: [PATCH 09/24] Add FFlag mod preset for 0-21 graphics slider --- Bloxstrap/ViewModels/ModsViewModel.cs | 6 ++++++ Bloxstrap/Views/Pages/ModsPage.xaml | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/Bloxstrap/ViewModels/ModsViewModel.cs b/Bloxstrap/ViewModels/ModsViewModel.cs index db8b2f7..c5a88b1 100644 --- a/Bloxstrap/ViewModels/ModsViewModel.cs +++ b/Bloxstrap/ViewModels/ModsViewModel.cs @@ -75,6 +75,12 @@ namespace Bloxstrap.ViewModels } } + public bool AlternateGraphicsSelectorEnabled + { + get => App.FastFlags.GetValue("FFlagFixGraphicsQuality") == "True"; + set => App.FastFlags.SetValue("FFlagFixGraphicsQuality", value ? "True" : null); + } + public bool DisableFullscreenOptimizationsEnabled { get => App.Settings.Prop.DisableFullscreenOptimizations; diff --git a/Bloxstrap/Views/Pages/ModsPage.xaml b/Bloxstrap/Views/Pages/ModsPage.xaml index 1c19abc..7e3b172 100644 --- a/Bloxstrap/Views/Pages/ModsPage.xaml +++ b/Bloxstrap/Views/Pages/ModsPage.xaml @@ -100,6 +100,7 @@ + @@ -129,6 +130,15 @@ + + + + + + + + + From 3927d5829044f5a07fd45d4d370338edba5968f1 Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Fri, 14 Apr 2023 22:02:48 +0200 Subject: [PATCH 10/24] Show channel name if not in predefined lists --- Bloxstrap/ViewModels/InstallationViewModel.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Bloxstrap/ViewModels/InstallationViewModel.cs b/Bloxstrap/ViewModels/InstallationViewModel.cs index 9607870..86cee6d 100644 --- a/Bloxstrap/ViewModels/InstallationViewModel.cs +++ b/Bloxstrap/ViewModels/InstallationViewModel.cs @@ -76,7 +76,13 @@ namespace Bloxstrap.ViewModels public IEnumerable Channels { - get => _channels; + get + { + if (_channels == DeployManager.ChannelsAll && !_channels.Contains(App.Settings.Prop.Channel)) + _channels = _channels.Append(App.Settings.Prop.Channel); + + return _channels; + } set => _channels = value; } @@ -103,8 +109,12 @@ namespace Bloxstrap.ViewModels else { Channels = DeployManager.ChannelsAbstracted; - Channel = DeployManager.DefaultChannel; - OnPropertyChanged(nameof(Channel)); + + if (!Channels.Contains(Channel)) + { + Channel = DeployManager.DefaultChannel; + OnPropertyChanged(nameof(Channel)); + } } OnPropertyChanged(nameof(Channels)); From eafce44bad3a59b20b1793ca72b579eca7b52edb Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Fri, 14 Apr 2023 23:18:24 +0100 Subject: [PATCH 11/24] Add FFlag mod preset for menu versions --- Bloxstrap/Helpers/FastFlagManager.cs | 44 +++++++++++++++++++++++++-- Bloxstrap/ViewModels/ModsViewModel.cs | 37 ++++++++++++++++++++-- Bloxstrap/Views/Pages/ModsPage.xaml | 10 ++++++ 3 files changed, 87 insertions(+), 4 deletions(-) diff --git a/Bloxstrap/Helpers/FastFlagManager.cs b/Bloxstrap/Helpers/FastFlagManager.cs index a4ab45f..ce87d3e 100644 --- a/Bloxstrap/Helpers/FastFlagManager.cs +++ b/Bloxstrap/Helpers/FastFlagManager.cs @@ -16,7 +16,7 @@ namespace Bloxstrap.Helpers public Dictionary Changes = new(); // only one missing here is Metal because lol - public static IReadOnlyDictionary RenderingModes { get; set; } = new Dictionary() + public static IReadOnlyDictionary RenderingModes => new Dictionary { { "Automatic", "" }, { "Direct3D 11", "FFlagDebugGraphicsPreferD3D11" }, @@ -24,11 +24,51 @@ namespace Bloxstrap.Helpers { "Vulkan", "FFlagDebugGraphicsPreferVulkan" } }; + // this is one hell of a variable definition lmao + public static IReadOnlyDictionary> IGMenuVersions => new Dictionary> + { + { + "Default", + new Dictionary + { + { "FFlagDisableNewIGMinDUA", null }, + { "FFlagEnableInGameMenuV3", null } + } + }, + + { + "Version 1 (2015)", + new Dictionary + { + { "FFlagDisableNewIGMinDUA", "True" }, + { "FFlagEnableInGameMenuV3", "False" } + } + }, + + { + "Version 2 (2020)", + new Dictionary + { + { "FFlagDisableNewIGMinDUA", "False" }, + { "FFlagEnableInGameMenuV3", "False" } + } + }, + + { + "Version 3 (2021)", + new Dictionary + { + { "FFlagDisableNewIGMinDUA", "False" }, + { "FFlagEnableInGameMenuV3", "True" } + } + } + }; + // all fflags are stored as strings // to delete a flag, set the value as null public void SetValue(string key, object? value) { - if (value == null) + if (value is null) { Changes[key] = null; App.Logger.WriteLine($"[FastFlagManager::SetValue] Deletion of '{key}' is pending"); diff --git a/Bloxstrap/ViewModels/ModsViewModel.cs b/Bloxstrap/ViewModels/ModsViewModel.cs index c5a88b1..52d21e5 100644 --- a/Bloxstrap/ViewModels/ModsViewModel.cs +++ b/Bloxstrap/ViewModels/ModsViewModel.cs @@ -35,14 +35,14 @@ namespace Bloxstrap.ViewModels set => App.Settings.Prop.UseDisableAppPatch = value; } - public IReadOnlyDictionary RenderingModes => FastFlagManager.RenderingModes; - public int FramerateLimit { get => Int32.TryParse(App.FastFlags.GetValue("DFIntTaskSchedulerTargetFps"), out int x) ? x : 60; set => App.FastFlags.SetValue("DFIntTaskSchedulerTargetFps", value); } + public IReadOnlyDictionary RenderingModes => FastFlagManager.RenderingModes; + public string SelectedRenderingMode { get @@ -75,6 +75,39 @@ namespace Bloxstrap.ViewModels } } + public IReadOnlyDictionary> IGMenuVersions => FastFlagManager.IGMenuVersions; + + public string SelectedIGMenuVersion + { + get + { + // yeah this kinda sucks + foreach (var version in IGMenuVersions) + { + bool flagsMatch = true; + + foreach (var flag in version.Value) + { + if (App.FastFlags.GetValue(flag.Key) != flag.Value) + flagsMatch = false; + } + + if (flagsMatch) + return version.Key; + } + + return "Default"; + } + + set + { + foreach (var flag in IGMenuVersions[value]) + { + App.FastFlags.SetValue(flag.Key, flag.Value); + } + } + } + public bool AlternateGraphicsSelectorEnabled { get => App.FastFlags.GetValue("FFlagFixGraphicsQuality") == "True"; diff --git a/Bloxstrap/Views/Pages/ModsPage.xaml b/Bloxstrap/Views/Pages/ModsPage.xaml index 7e3b172..107515a 100644 --- a/Bloxstrap/Views/Pages/ModsPage.xaml +++ b/Bloxstrap/Views/Pages/ModsPage.xaml @@ -101,6 +101,7 @@ + @@ -139,6 +140,15 @@ + + + + + + + + + From 1f40efd10d12392d8427856b6d01bde9f60122fc Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Sat, 15 Apr 2023 01:41:11 +0100 Subject: [PATCH 12/24] Add manual channel entry (#132) --- Bloxstrap/Helpers/DeployManager.cs | 31 ++----- Bloxstrap/ViewModels/InstallationViewModel.cs | 88 +++++++++---------- Bloxstrap/Views/Pages/InstallationPage.xaml | 7 +- Bloxstrap/Views/Pages/ModsPage.xaml | 2 +- 4 files changed, 51 insertions(+), 77 deletions(-) diff --git a/Bloxstrap/Helpers/DeployManager.cs b/Bloxstrap/Helpers/DeployManager.cs index 40d0165..77f8b77 100644 --- a/Bloxstrap/Helpers/DeployManager.cs +++ b/Bloxstrap/Helpers/DeployManager.cs @@ -19,35 +19,16 @@ namespace Bloxstrap.Helpers public string BaseUrl { get; private set; } = DefaultBaseUrl; public string Channel { get; private set; } = DefaultChannel; - // basically any channel that has had a deploy within the past month with a windowsplayer build - public static readonly List ChannelsAbstracted = new() + // most commonly used/interesting channels + public static readonly List SelectableChannels = new() { "LIVE", - "ZNext", - "ZCanary", - "ZIntegration" - }; - - // why not? - public static readonly List ChannelsAll = new() - { - "LIVE", - "ZAvatarTeam", - "ZAvatarRelease", - "ZCanary", - "ZCanary1", - "ZCanary2", - "ZCanary3", - "ZCanaryApps", "ZFlag", - "ZIntegration", - "ZIntegration1", - "ZLive", - "ZLive1", "ZNext", - "ZSocialTeam", - "ZStudioInt1", - "ZStudioInt2" + "ZCanary", + "ZIntegration", + "ZAvatarTeam", + "ZSocialTeam" }; #endregion diff --git a/Bloxstrap/ViewModels/InstallationViewModel.cs b/Bloxstrap/ViewModels/InstallationViewModel.cs index 86cee6d..81e40d5 100644 --- a/Bloxstrap/ViewModels/InstallationViewModel.cs +++ b/Bloxstrap/ViewModels/InstallationViewModel.cs @@ -1,17 +1,15 @@ -using Bloxstrap.Enums; -using System; +using System; using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; using System.Linq; -using System.Text; using System.Threading.Tasks; +using System.Windows; +using System.Windows.Forms; using System.Windows.Input; using CommunityToolkit.Mvvm.Input; -using System.Windows.Forms; -using Wpf.Ui.Mvvm.Interfaces; -using System.ComponentModel; using Bloxstrap.Helpers; using Bloxstrap.Models; -using System.Diagnostics; namespace Bloxstrap.ViewModels { @@ -20,14 +18,13 @@ namespace Bloxstrap.ViewModels public event PropertyChangedEventHandler? PropertyChanged; public void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - private IEnumerable _channels = DeployManager.ChannelsAbstracted.Contains(App.Settings.Prop.Channel) ? DeployManager.ChannelsAbstracted : DeployManager.ChannelsAll; - private bool _showAllChannels = !DeployManager.ChannelsAbstracted.Contains(App.Settings.Prop.Channel); + private bool _manualChannelEntry = !DeployManager.SelectableChannels.Contains(App.Settings.Prop.Channel); public ICommand BrowseInstallLocationCommand => new RelayCommand(BrowseInstallLocation); public ICommand OpenFolderCommand => new RelayCommand(OpenFolder); - - public DeployInfo? ChannelDeployInfo { get; private set; } = null; //new DeployInfo(){ Version = "hi", VersionGuid = "hi", Timestamp = "January 25 2023 at 6:03:48 PM" }; + public DeployInfo? ChannelDeployInfo { get; private set; } = null; + public string ChannelInfoLoadingText { get; private set; } = null!; public InstallationViewModel() { @@ -36,20 +33,32 @@ namespace Bloxstrap.ViewModels private async Task LoadChannelDeployInfo(string channel) { + ChannelInfoLoadingText = "Fetching latest deploy info, please wait..."; + OnPropertyChanged(nameof(ChannelInfoLoadingText)); + ChannelDeployInfo = null; OnPropertyChanged(nameof(ChannelDeployInfo)); App.DeployManager.SetChannel(channel); - ClientVersion info = await App.DeployManager.GetLastDeploy(true); - ChannelDeployInfo = new DeployInfo + try { - Version = info.Version, - VersionGuid = info.VersionGuid, - Timestamp = info.Timestamp?.ToString("dddd, d MMMM yyyy 'at' h:mm:ss tt", App.CultureFormat)! - }; + ClientVersion info = await App.DeployManager.GetLastDeploy(true); - OnPropertyChanged(nameof(ChannelDeployInfo)); + ChannelDeployInfo = new DeployInfo + { + Version = info.Version, + VersionGuid = info.VersionGuid, + Timestamp = info.Timestamp?.ToString("dddd, d MMMM yyyy 'at' h:mm:ss tt", App.CultureFormat)! + }; + + OnPropertyChanged(nameof(ChannelDeployInfo)); + } + catch (Exception) + { + ChannelInfoLoadingText = "Failed to get deploy info.\nIs the channel name valid?"; + OnPropertyChanged(nameof(ChannelInfoLoadingText)); + } } private void BrowseInstallLocation() @@ -74,53 +83,36 @@ namespace Bloxstrap.ViewModels set => App.BaseDirectory = value; } - public IEnumerable Channels - { - get - { - if (_channels == DeployManager.ChannelsAll && !_channels.Contains(App.Settings.Prop.Channel)) - _channels = _channels.Append(App.Settings.Prop.Channel); - - return _channels; - } - set => _channels = value; - } + public IEnumerable Channels => DeployManager.SelectableChannels; public string Channel { get => App.Settings.Prop.Channel; set { - //Task.Run(() => GetChannelInfo(value)); Task.Run(() => LoadChannelDeployInfo(value)); App.Settings.Prop.Channel = value; } } - public bool ShowAllChannels + public bool ManualChannelEntry { - get => _showAllChannels; + get => _manualChannelEntry; set { - if (value) - { - Channels = DeployManager.ChannelsAll; - } - else - { - Channels = DeployManager.ChannelsAbstracted; + _manualChannelEntry = value; - if (!Channels.Contains(Channel)) - { - Channel = DeployManager.DefaultChannel; - OnPropertyChanged(nameof(Channel)); - } - } + if (!value && !Channels.Contains(Channel)) + Channel = DeployManager.DefaultChannel; - OnPropertyChanged(nameof(Channels)); - - _showAllChannels = value; + OnPropertyChanged(nameof(Channel)); + OnPropertyChanged(nameof(ChannelComboBoxVisibility)); + OnPropertyChanged(nameof(ChannelTextBoxVisibility)); } } + + // cant use data bindings so i have to do whatever tf this is + public Visibility ChannelComboBoxVisibility => ManualChannelEntry ? Visibility.Collapsed : Visibility.Visible; + public Visibility ChannelTextBoxVisibility => ManualChannelEntry ? Visibility.Visible : Visibility.Collapsed; } } diff --git a/Bloxstrap/Views/Pages/InstallationPage.xaml b/Bloxstrap/Views/Pages/InstallationPage.xaml index 6142e79..a67d256 100644 --- a/Bloxstrap/Views/Pages/InstallationPage.xaml +++ b/Bloxstrap/Views/Pages/InstallationPage.xaml @@ -59,7 +59,8 @@ - + + @@ -114,10 +115,10 @@ - + - + diff --git a/Bloxstrap/Views/Pages/ModsPage.xaml b/Bloxstrap/Views/Pages/ModsPage.xaml index 107515a..c6360f4 100644 --- a/Bloxstrap/Views/Pages/ModsPage.xaml +++ b/Bloxstrap/Views/Pages/ModsPage.xaml @@ -135,7 +135,7 @@ - + From c87eff997a912593df92fe7153e149d6aefc59d6 Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Sun, 16 Apr 2023 01:58:11 +0100 Subject: [PATCH 13/24] Add check for working deployment domain (#134) this is gonna suck to merge into 2.2.0 lmao --- Bloxstrap/App.xaml.cs | 2 +- Bloxstrap/Helpers/DeployManager.cs | 76 +++++++++++++++---- Bloxstrap/ViewModels/InstallationViewModel.cs | 2 +- 3 files changed, 63 insertions(+), 17 deletions(-) diff --git a/Bloxstrap/App.xaml.cs b/Bloxstrap/App.xaml.cs index faf6167..cf81492 100644 --- a/Bloxstrap/App.xaml.cs +++ b/Bloxstrap/App.xaml.cs @@ -258,7 +258,7 @@ namespace Bloxstrap if (!IsFirstRun) ShouldSaveConfigs = true; - DeployManager.SetChannel(Settings.Prop.Channel); + DeployManager.Channel = Settings.Prop.Channel; // start bootstrapper and show the bootstrapper modal if we're not running silently Logger.WriteLine($"[App::OnStartup] Initializing bootstrapper"); diff --git a/Bloxstrap/Helpers/DeployManager.cs b/Bloxstrap/Helpers/DeployManager.cs index 77f8b77..a745cd7 100644 --- a/Bloxstrap/Helpers/DeployManager.cs +++ b/Bloxstrap/Helpers/DeployManager.cs @@ -13,11 +13,68 @@ namespace Bloxstrap.Helpers public class DeployManager { #region Properties - public const string DefaultBaseUrl = "https://setup.rbxcdn.com"; public const string DefaultChannel = "LIVE"; - - public string BaseUrl { get; private set; } = DefaultBaseUrl; - public string Channel { get; private set; } = DefaultChannel; + + private string _channel = DefaultChannel; + + public string Channel + { + get => _channel; + set + { + if (_channel != value) + App.Logger.WriteLine($"[DeployManager::SetChannel] Changed channel to {value}"); + + _channel = value; + } + } + + // a list of roblox delpoyment locations that we check for, in case one of them don't work + private List BaseUrls = new() + { + "https://setup.rbxcdn.com", + "https://setup-ak.rbxcdn.com", + "https://s3.amazonaws.com/setup.roblox.com" + }; + + private string? _baseUrl = null; + + public string BaseUrl + { + get + { + if (String.IsNullOrEmpty(_baseUrl)) + { + // check for a working accessible deployment domain + foreach (string attemptedUrl in BaseUrls) + { + App.Logger.WriteLine($"[DeployManager::DefaultBaseUrl.Set] Testing connection to '{attemptedUrl}'..."); + + try + { + App.HttpClient.GetAsync($"{attemptedUrl}/version").Wait(); + App.Logger.WriteLine($"[DeployManager::DefaultBaseUrl.Set] Connection successful!"); + _baseUrl = attemptedUrl; + break; + } + catch (Exception ex) + { + App.Logger.WriteLine($"[DeployManager::DefaultBaseUrl.Set] Connection failed!"); + App.Logger.WriteLine($"[DeployManager::DefaultBaseUrl.Set] {ex}"); + continue; + } + } + + if (String.IsNullOrEmpty(_baseUrl)) + throw new Exception("Unable to find an accessible Roblox deploy mirror!"); + } + + if (Channel == DefaultChannel) + return _baseUrl; + else + return $"{_baseUrl}/channel/{Channel.ToLower()}"; + } + } // most commonly used/interesting channels public static readonly List SelectableChannels = new() @@ -32,17 +89,6 @@ namespace Bloxstrap.Helpers }; #endregion - public void SetChannel(string channel) - { - if (Channel == channel) - return; - - App.Logger.WriteLine($"[DeployManager::SetChannel] Set channel to {Channel}"); - - Channel = channel; - BaseUrl = channel == DefaultChannel ? DefaultBaseUrl : $"{DefaultBaseUrl}/channel/{channel.ToLower()}"; - } - public async Task GetLastDeploy(bool timestamp = false) { App.Logger.WriteLine($"[DeployManager::GetLastDeploy] Getting deploy info for channel {Channel} (timestamp={timestamp})"); diff --git a/Bloxstrap/ViewModels/InstallationViewModel.cs b/Bloxstrap/ViewModels/InstallationViewModel.cs index 81e40d5..f72f01e 100644 --- a/Bloxstrap/ViewModels/InstallationViewModel.cs +++ b/Bloxstrap/ViewModels/InstallationViewModel.cs @@ -39,7 +39,7 @@ namespace Bloxstrap.ViewModels ChannelDeployInfo = null; OnPropertyChanged(nameof(ChannelDeployInfo)); - App.DeployManager.SetChannel(channel); + App.DeployManager.Channel = channel; try { From 6cc701f6a2d9233f199a4612572c37b785d39084 Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Thu, 20 Apr 2023 09:55:18 +0100 Subject: [PATCH 14/24] Remove ReShade also fixed a bug with deleted mods not being correctly applied after adding webview2 support --- Bloxstrap/Bloxstrap.csproj | 1 - Bloxstrap/Bootstrapper.cs | 9 +- Bloxstrap/Helpers/FastFlagManager.cs | 4 +- Bloxstrap/Helpers/IntegrationMigrator.cs | 18 + Bloxstrap/Integrations/ReShade.cs | 505 ------------------ Bloxstrap/Models/ReShadeShaderConfig.cs | 21 - Bloxstrap/Models/ReShadeVersionManifest.cs | 9 - Bloxstrap/Models/Settings.cs | 2 - Bloxstrap/Models/State.cs | 2 - Bloxstrap/ViewModels/IntegrationsViewModel.cs | 33 +- Bloxstrap/Views/Pages/AboutPage.xaml | 20 +- Bloxstrap/Views/Pages/IntegrationsPage.xaml | 60 --- Bloxstrap/Views/Pages/ModsPage.xaml | 2 +- 13 files changed, 26 insertions(+), 660 deletions(-) delete mode 100644 Bloxstrap/Integrations/ReShade.cs delete mode 100644 Bloxstrap/Models/ReShadeShaderConfig.cs delete mode 100644 Bloxstrap/Models/ReShadeVersionManifest.cs diff --git a/Bloxstrap/Bloxstrap.csproj b/Bloxstrap/Bloxstrap.csproj index 184539f..d3e7baa 100644 --- a/Bloxstrap/Bloxstrap.csproj +++ b/Bloxstrap/Bloxstrap.csproj @@ -25,7 +25,6 @@ - diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index 7d834f9..bab2ead 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -181,11 +181,6 @@ namespace Bloxstrap if (ShouldInstallWebView2) await InstallWebView2(); - if (App.Settings.Prop.UseReShade) - SetStatus("Configuring/Downloading ReShade..."); - - await ReShade.CheckModifications(); - await ApplyModifications(); if (App.IsFirstRun || FreshInstall) @@ -720,8 +715,6 @@ namespace Bloxstrap if (!FreshInstall) { - ReShade.SynchronizeConfigFile(); - // let's take this opportunity to delete any packages we don't need anymore foreach (string filename in Directory.GetFiles(Directories.Downloads)) { @@ -894,7 +887,7 @@ namespace Bloxstrap try { - packageDirectory = PackageDirectories.First(x => x.Key != "RobloxApp.zip" && fileLocation.StartsWith(x.Value)); + packageDirectory = PackageDirectories.First(x => x.Key != "RobloxApp.zip" && x.Key != "WebView2.zip" && fileLocation.StartsWith(x.Value)); } catch (InvalidOperationException) { diff --git a/Bloxstrap/Helpers/FastFlagManager.cs b/Bloxstrap/Helpers/FastFlagManager.cs index ce87d3e..76b676b 100644 --- a/Bloxstrap/Helpers/FastFlagManager.cs +++ b/Bloxstrap/Helpers/FastFlagManager.cs @@ -113,8 +113,8 @@ namespace Bloxstrap.Helpers if (GetValue("DFIntTaskSchedulerTargetFps") is null) SetValue("DFIntTaskSchedulerTargetFps", 9999); - // reshade / exclusive fullscreen requires direct3d 11 to work - if (GetValue(RenderingModes["Direct3D 11"]) != "True" && (App.Settings.Prop.UseReShade || App.FastFlags.GetValue("FFlagHandleAltEnterFullscreenManually") == "False")) + // exclusive fullscreen requires direct3d 11 to work + if (GetValue(RenderingModes["Direct3D 11"]) != "True" && App.FastFlags.GetValue("FFlagHandleAltEnterFullscreenManually") == "False") SetRenderingMode("Direct3D 11"); } diff --git a/Bloxstrap/Helpers/IntegrationMigrator.cs b/Bloxstrap/Helpers/IntegrationMigrator.cs index e073719..a73ecf0 100644 --- a/Bloxstrap/Helpers/IntegrationMigrator.cs +++ b/Bloxstrap/Helpers/IntegrationMigrator.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Windows; namespace Bloxstrap.Helpers { @@ -11,6 +12,23 @@ namespace Bloxstrap.Helpers if (Directory.Exists(rbxfpsunlocker)) Directory.Delete(rbxfpsunlocker, true); + + // v2.2.0 - remove reshade + string reshadeLocation = Path.Combine(Directories.Modifications, "dxgi.dll"); + + if (File.Exists(reshadeLocation)) + { + App.ShowMessageBox( + "As of April 18th, Roblox has started out rolling out the Byfron anticheat as well as 64-bit support. Because of this, ReShade will no longer work, and will be deactivated from now on.\n\n" + + $"Your ReShade configs and files will still be kept, which are all located in the {App.ProjectName} folder.", + MessageBoxImage.Warning + ); + + File.Delete(reshadeLocation); + + if (App.FastFlags.GetValue(FastFlagManager.RenderingModes["Direct3D 11"]) == "True" && App.FastFlags.GetValue("FFlagHandleAltEnterFullscreenManually") != "False") + App.FastFlags.SetRenderingMode("Automatic"); + } } } } diff --git a/Bloxstrap/Integrations/ReShade.cs b/Bloxstrap/Integrations/ReShade.cs deleted file mode 100644 index 5931f1e..0000000 --- a/Bloxstrap/Integrations/ReShade.cs +++ /dev/null @@ -1,505 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Threading.Tasks; -using Bloxstrap.Helpers; - -using Bloxstrap.Models; - -using IniParser; -using IniParser.Model; - -namespace Bloxstrap.Integrations -{ - internal class ReShade - { - // i havent even started this and i know for a fact this is gonna be a mess of an integration lol - // there's a lot of nuances involved in how reshade functionality is supposed to work (shader management, config management, etc) - // it's gonna be a bit of a pain in the ass, and i'm expecting a lot of bugs to arise from this... - // well, looks like v1.7.0 is gonna be held back for quite a while lol - - // also, this is going to be fairly restrictive without a lot of heavy work - // reshade's official installer gives you a list of shader packs and lets you choose which ones you want to install - // and here we're effectively choosing for the user... hm... - // i mean, it should be fine? importing shaders is still gonna be a thing, though maybe not as simple, but most people would be looking to use extravi's presets anyway - - private static string BaseDirectory => Path.Combine(Directories.Integrations, "ReShade"); - private static string FontsFolder => Path.Combine(BaseDirectory, "Fonts"); - private static string PresetsFolder => Path.Combine(BaseDirectory, "Presets"); - private static string ShadersFolder => Path.Combine(BaseDirectory, "Shaders"); - private static string TexturesFolder => Path.Combine(BaseDirectory, "Textures"); - private static string ConfigLocation => Path.Combine(Directories.Modifications, "ReShade.ini"); - - // the base url that we're fetching all our remote configs and resources and stuff from - private const string BaseUrl = "https://raw.githubusercontent.com/Extravi/extravi.github.io/main/update"; - - // this is a list of selectable shaders to download - private static readonly List Shaders = new() - { - // shaders required for extravi's presets: - new ReShadeShaderConfig { Name = "AstrayFX", DownloadLocation = "https://github.com/BlueSkyDefender/AstrayFX/archive/refs/heads/master.zip" }, - new ReShadeShaderConfig { Name = "Brussell", DownloadLocation = "https://github.com/brussell1/Shaders/archive/refs/heads/master.zip" }, - new ReShadeShaderConfig { Name = "Depth3D", DownloadLocation = "https://github.com/BlueSkyDefender/Depth3D/archive/refs/heads/master.zip" }, - new ReShadeShaderConfig { Name = "Glamarye", DownloadLocation = "https://github.com/rj200/Glamarye_Fast_Effects_for_ReShade/archive/refs/heads/main.zip" }, - new ReShadeShaderConfig { Name = "NiceGuy", DownloadLocation = "https://github.com/mj-ehsan/NiceGuy-Shaders/archive/refs/heads/main.zip" }, - new ReShadeShaderConfig { Name = "prod80", DownloadLocation = "https://github.com/prod80/prod80-ReShade-Repository/archive/refs/heads/master.zip" }, - new ReShadeShaderConfig { Name = "qUINT", DownloadLocation = "https://github.com/martymcmodding/qUINT/archive/refs/heads/master.zip" }, - new ReShadeShaderConfig { Name = "StockLegacy", DownloadLocation = "https://github.com/crosire/reshade-shaders/archive/refs/heads/legacy.zip" }, - new ReShadeShaderConfig { Name = "SweetFX", DownloadLocation = "https://github.com/CeeJayDK/SweetFX/archive/refs/heads/master.zip" }, - - // these ones needs some additional configuration - - new ReShadeShaderConfig - { - Name = "Stock", - DownloadLocation = "https://github.com/crosire/reshade-shaders/archive/refs/heads/master.zip", - ExcludedFiles = new List() - { - // overriden by stormshade - "Shaders/MXAO.fx" - } - }, - - new ReShadeShaderConfig - { - Name = "AlucardDH", - DownloadLocation = "https://github.com/AlucardDH/dh-reshade-shaders/archive/refs/heads/master.zip", - ExcludedFiles = new List() - { - // compiler errors - // dh_Lain only errors when performance mode is disabled, but it's not used by any presets anyway - "Shaders/dh_rtgi.fx", - "Shaders/dh_Lain.fx" - } - }, - - new ReShadeShaderConfig - { - Name = "Stormshade", - DownloadLocation = "https://github.com/cyrie/Stormshade/archive/refs/heads/master.zip", - BaseFolder = "reshade-shaders/", - ExcludedFiles = new List() - { - // these file names conflict with effects in the stock reshade config - "Shaders/AmbientLight.fx", - "Shaders/Clarity.fx", - "Shaders/DOF.fx", - "Shaders/DPX.fx", - "Shaders/FilmGrain.fx", - "Shaders/FineSharp.fx", - "Shaders/FXAA.fx", - "Shaders/FXAA.fxh", - "Shaders/LumaSharpen.fx", - //"Shaders/MXAO.fx", - "Shaders/ReShade.fxh", - "Shaders/Vibrance.fx", - "Shaders/Vignette.fx" - } - }, - }; - - private static readonly string[] ExtraviPresetsShaders = new string[] - { - "AlucardDH", - "Brussell", - "AstrayFX", - "Brussell", - "Depth3D", - "Glamarye", - "NiceGuy", - "prod80", - "qUINT", - "StockLegacy", - "Stormshade", - "SweetFX", - }; - - private static string GetSearchPath(string type, string name) - { - return $",..\\..\\Integrations\\ReShade\\{type}\\{name}"; - } - - public static async Task DownloadConfig() - { - App.Logger.WriteLine("[ReShade::DownloadConfig] Downloading/Upgrading config file..."); - - { - byte[] bytes = await App.HttpClient.GetByteArrayAsync($"{BaseUrl}/config.zip"); - - using MemoryStream zipStream = new(bytes); - using ZipArchive archive = new(zipStream); - - - archive.Entries.First(x => x.FullName == "ReShade.ini").ExtractToFile(ConfigLocation, true); - - // when we extract the file we have to make sure the last modified date is overwritten - // or else it will synchronize with the config in the version folder - // really the config adjustments below should do this for us, but this is just to be safe - File.SetLastWriteTime(ConfigLocation, DateTime.Now); - - // we also gotta download the editor fonts - foreach (ZipArchiveEntry entry in archive.Entries.Where(x => x.FullName.EndsWith(".ttf"))) - entry.ExtractToFile(Path.Combine(FontsFolder, entry.FullName), true); - } - - // now we have to adjust the config file to use the paths that we need - // some of these can be removed later when the config file is better adjusted for bloxstrap by default - - FileIniDataParser parser = new(); - IniData data = parser.ReadFile(ConfigLocation); - - data["GENERAL"]["EffectSearchPaths"] = "..\\..\\Integrations\\ReShade\\Shaders"; - data["GENERAL"]["TextureSearchPaths"] = "..\\..\\Integrations\\ReShade\\Textures"; - data["GENERAL"]["PresetPath"] = data["GENERAL"]["PresetPath"].Replace(".\\reshade-presets\\", "..\\..\\Integrations\\ReShade\\Presets\\"); - //data["SCREENSHOT"]["SavePath"] = "..\\..\\ReShade\\Screenshots"; - data["SCREENSHOT"]["SavePath"] = Path.Combine(Directories.MyPictures, "Roblox-ReShade"); - data["STYLE"]["EditorFont"] = data["STYLE"]["EditorFont"].Replace(".\\", "..\\..\\Integrations\\ReShade\\Fonts\\"); - data["STYLE"]["Font"] = data["STYLE"]["Font"].Replace(".\\", "..\\..\\Integrations\\ReShade\\Fonts\\"); - - // add search paths for shaders and textures - - foreach (string name in Directory.GetDirectories(ShadersFolder).Select(x => Path.GetRelativePath(ShadersFolder, x)).ToArray()) - data["GENERAL"]["EffectSearchPaths"] += GetSearchPath("Shaders", name); - - foreach (string name in Directory.GetDirectories(TexturesFolder).Select(x => Path.GetRelativePath(TexturesFolder, x)).ToArray()) - data["GENERAL"]["TextureSearchPaths"] += GetSearchPath("Textures", name); - - parser.WriteFile(ConfigLocation, data); - } - - public static void SynchronizeConfigFile() - { - App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] Synchronizing configuration file..."); - - // yeah, this is going to be a bit of a pain - // keep in mind the config file is going to be in two places: the mod folder and the version folder - // so we have to make sure the two below scenaros work flawlessly: - // - if the user manually updates their reshade config in the mod folder or it gets updated, it must be copied to the version folder - // - if the user updates their reshade settings ingame, the updated config must be copied to the mod folder - // the easiest way to manage this is to just compare the modification dates of the two - // anyway, this is where i'm expecting most of the bugs to arise from - // config synchronization will be done whenever roblox updates or whenever we launch roblox - - string modFolderConfigPath = ConfigLocation; - string versionFolderConfigPath = Path.Combine(Directories.Versions, App.State.Prop.VersionGuid, "ReShade.ini"); - - // we shouldn't be here if the mod config doesn't already exist - if (!File.Exists(modFolderConfigPath)) - { - App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] ReShade.ini in modifications folder does not exist, aborting sync"); - return; - } - - // copy to the version folder if it doesn't already exist there - if (!File.Exists(versionFolderConfigPath)) - { - App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] ReShade.ini in version folder does not exist, synchronized with modifications folder"); - File.Copy(modFolderConfigPath, versionFolderConfigPath); - } - - // if both the mod and version configs match, then we don't need to do anything - if (Utilities.MD5File(modFolderConfigPath) == Utilities.MD5File(versionFolderConfigPath)) - { - App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] ReShade.ini in version and modifications folder match"); - return; - } - - FileInfo modFolderConfigFile = new(modFolderConfigPath); - FileInfo versionFolderConfigFile = new(versionFolderConfigPath); - - if (modFolderConfigFile.LastWriteTime > versionFolderConfigFile.LastWriteTime) - { - // overwrite version config if mod config was modified most recently - App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] ReShade.ini in version folder is older, synchronized with modifications folder"); - File.Copy(modFolderConfigPath, versionFolderConfigPath, true); - } - else if (versionFolderConfigFile.LastWriteTime > modFolderConfigFile.LastWriteTime) - { - // overwrite mod config if version config was modified most recently - App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] ReShade.ini in modifications folder is older, synchronized with version folder"); - File.Copy(versionFolderConfigPath, modFolderConfigPath, true); - } - } - - public static async Task DownloadShaders(string name) - { - ReShadeShaderConfig config = Shaders.First(x => x.Name == name); - - // not all shader packs have a textures folder, so here we're determining if they exist purely based on if they have a Shaders folder - if (Directory.Exists(Path.Combine(ShadersFolder, name))) - return; - - App.Logger.WriteLine($"[ReShade::DownloadShaders] Downloading shaders for {name}"); - - { - byte[] bytes = await App.HttpClient.GetByteArrayAsync(config.DownloadLocation); - - using MemoryStream zipStream = new(bytes); - using ZipArchive archive = new(zipStream); - - foreach (ZipArchiveEntry entry in archive.Entries) - { - if (entry.FullName.EndsWith('/') || !entry.FullName.Contains(config.BaseFolder)) - continue; - - // github branch zips have a root folder of the name of the branch, so let's just remove that - string fullPath = entry.FullName.Substring(entry.FullName.IndexOf(config.BaseFolder) + config.BaseFolder.Length); - - // skip file if it's not in the Shaders or Textures folder - if (!fullPath.StartsWith("Shaders") && !fullPath.StartsWith("Textures")) - continue; - - if (config.ExcludedFiles.Contains(fullPath)) - continue; - - // and now we do it again because of how we're handling folder management - // e.g. reshade-shaders-master/Shaders/Vignette.fx should go to ReShade/Shaders/Stock/Vignette.fx - // so in this case, relativePath should just be "Vignette.fx" - string relativePath = fullPath.Substring(fullPath.IndexOf('/') + 1); - - // now we stitch it all together - string extractionPath = Path.Combine( - BaseDirectory, - fullPath.StartsWith("Shaders") ? "Shaders" : "Textures", - name, - relativePath - ); - - // make sure the folder that we're extracting it to exists - Directory.CreateDirectory(Path.GetDirectoryName(extractionPath)!); - - // and now extract - await Task.Run(() => entry.ExtractToFile(extractionPath)); - } - } - - // now we have to update ReShade.ini and add the installed shaders to the search paths - FileIniDataParser parser = new(); - IniData data = parser.ReadFile(ConfigLocation); - - if (!data["GENERAL"]["EffectSearchPaths"].Contains(name)) - data["GENERAL"]["EffectSearchPaths"] += GetSearchPath("Shaders", name); - - // not every shader pack has a textures folder - if (Directory.Exists(Path.Combine(TexturesFolder, name)) && !data["GENERAL"]["TextureSearchPaths"].Contains(name)) - data["GENERAL"]["TextureSearchPaths"] += GetSearchPath("Textures", name); - - parser.WriteFile(ConfigLocation, data); - } - - public static void DeleteShaders(string name) - { - App.Logger.WriteLine($"[ReShade::DeleteShaders] Deleting shaders for {name}"); - - string shadersPath = Path.Combine(ShadersFolder, name); - string texturesPath = Path.Combine(TexturesFolder, name); - - if (Directory.Exists(shadersPath)) - Directory.Delete(shadersPath, true); - - if (Directory.Exists(texturesPath)) - Directory.Delete(texturesPath, true); - - if (!File.Exists(ConfigLocation)) - return; - - // now we have to update ReShade.ini and remove the installed shaders from the search paths - FileIniDataParser parser = new(); - IniData data = parser.ReadFile(ConfigLocation); - - string shaderSearchPaths = data["GENERAL"]["EffectSearchPaths"]; - string textureSearchPaths = data["GENERAL"]["TextureSearchPaths"]; - - if (shaderSearchPaths.Contains(name)) - { - string searchPath = GetSearchPath("Shaders", name); - if (shaderSearchPaths.Contains(searchPath)) - data["GENERAL"]["EffectSearchPaths"] = shaderSearchPaths.Remove(shaderSearchPaths.IndexOf(searchPath), searchPath.Length); - } - - if (textureSearchPaths.Contains(name)) - { - string searchPath = GetSearchPath("Textures", name); - if (textureSearchPaths.Contains(searchPath)) - data["GENERAL"]["TextureSearchPaths"] = textureSearchPaths.Remove(textureSearchPaths.IndexOf(searchPath), searchPath.Length); - } - - parser.WriteFile(ConfigLocation, data); - } - - public static async Task InstallExtraviPresets() - { - App.Logger.WriteLine("[ReShade::InstallExtraviPresets] Installing Extravi's presets..."); - - foreach (string name in ExtraviPresetsShaders) - await DownloadShaders(name); - - byte[] bytes = await App.HttpClient.GetByteArrayAsync($"{BaseUrl}/reshade-presets.zip"); - - using MemoryStream zipStream = new(bytes); - using ZipArchive archive = new(zipStream); - - foreach (ZipArchiveEntry entry in archive.Entries) - { - if (entry.FullName.EndsWith('/')) - continue; - - // remove containing folder - string filename = entry.FullName.Substring(entry.FullName.IndexOf('/') + 1); - - await Task.Run(() => entry.ExtractToFile(Path.Combine(PresetsFolder, filename), true)); - } - } - - public static void UninstallExtraviPresets() - { - if (!Directory.Exists(PresetsFolder)) - return; - - App.Logger.WriteLine("[ReShade::UninstallExtraviPresets] Uninstalling Extravi's ReShade presets..."); - - FileInfo[] presets = new DirectoryInfo(PresetsFolder).GetFiles(); - - foreach (FileInfo preset in presets) - { - if (preset.Name.StartsWith("Extravi")) - preset.Delete(); - } - - foreach (string name in ExtraviPresetsShaders) - DeleteShaders(name); - } - - public static async Task CheckModifications() - { - App.Logger.WriteLine("[ReShade::CheckModifications] Checking ReShade modifications..."); - - string injectorLocation = Path.Combine(Directories.Modifications, "dxgi.dll"); - - if (!App.Settings.Prop.UseReShadeExtraviPresets && !string.IsNullOrEmpty(App.State.Prop.ExtraviReShadePresetsVersion)) - { - if (Utilities.CheckIfRobloxRunning()) - return; - - UninstallExtraviPresets(); - - App.State.Prop.ExtraviReShadePresetsVersion = ""; - App.State.Save(); - } - - if (!App.Settings.Prop.UseReShade) - { - if (Utilities.CheckIfRobloxRunning()) - return; - - App.Logger.WriteLine("[ReShade::CheckModifications] ReShade is not enabled"); - - // we should already be uninstalled - // we want to ensure this is done one-time only as this could possibly interfere with other rendering hooks using dxgi.dll - if (string.IsNullOrEmpty(App.State.Prop.ReShadeConfigVersion)) - return; - - App.Logger.WriteLine("[ReShade::CheckModifications] Uninstalling ReShade..."); - - // delete any stock config files - File.Delete(injectorLocation); - File.Delete(ConfigLocation); - - if (Directory.Exists(BaseDirectory)) - Directory.Delete(BaseDirectory, true); - - App.State.Prop.ReShadeConfigVersion = ""; - App.State.Save(); - - return; - } - - // the version manfiest contains the version of reshade available for download and the last date the presets were updated - var versionManifest = await Utilities.GetJson("https://raw.githubusercontent.com/Extravi/extravi.github.io/main/update/version.json"); - bool shouldFetchReShade = false; - bool shouldFetchConfig = false; - - if (!File.Exists(injectorLocation)) - { - shouldFetchReShade = true; - } - else if (versionManifest is not null) - { - // check if an update for reshade is available - FileVersionInfo injectorVersionInfo = FileVersionInfo.GetVersionInfo(injectorLocation); - - if (injectorVersionInfo.ProductVersion != versionManifest.ReShade) - shouldFetchReShade = true; - - // UPDATE CHECK - if we're upgrading to reshade 5.7.0, or we have extravi's presets - // enabled with a known shader downloaded (like AlucardDH) but without stormshade downloaded (5.7.0+ specific), - // we need to redownload all our shaders fresh - if ( - injectorVersionInfo.ProductVersion != versionManifest.ReShade && versionManifest.ReShade == "5.7.0" || - App.Settings.Prop.UseReShadeExtraviPresets && Directory.Exists(Path.Combine(ShadersFolder, "AlucardDH")) && !Directory.Exists(Path.Combine(ShadersFolder, "Stormshade")) - ) - { - Directory.Delete(ShadersFolder, true); - Directory.Delete(TexturesFolder, true); - App.State.Prop.ExtraviReShadePresetsVersion = ""; - App.Logger.WriteLine("[ReShade::CheckModifications] Upgrading to ReShade 5.7.0 - redownloading all shaders!"); - } - } - else - { - App.Logger.WriteLine("[ReShade::CheckModifications] versionManifest is null!"); - } - - // we're about to download - initialize directories - Directory.CreateDirectory(BaseDirectory); - Directory.CreateDirectory(FontsFolder); - Directory.CreateDirectory(ShadersFolder); - Directory.CreateDirectory(TexturesFolder); - Directory.CreateDirectory(PresetsFolder); - - // check if we should download a fresh copy of the config - // extravi may need to update the config ota, in which case we'll redownload it - if (!File.Exists(ConfigLocation) || versionManifest is not null && App.State.Prop.ReShadeConfigVersion != versionManifest.ConfigFile) - shouldFetchConfig = true; - - if (shouldFetchReShade) - { - App.Logger.WriteLine("[ReShade::CheckModifications] Installing/Upgrading ReShade..."); - - { - byte[] bytes = await App.HttpClient.GetByteArrayAsync($"{BaseUrl}/dxgi.zip"); - using MemoryStream zipStream = new(bytes); - using ZipArchive archive = new(zipStream); - archive.ExtractToDirectory(Directories.Modifications, true); - } - } - - if (shouldFetchConfig) - { - await DownloadConfig(); - - if (versionManifest is not null) - { - App.State.Prop.ReShadeConfigVersion = versionManifest.ConfigFile; - App.State.Save(); - } - } - - await DownloadShaders("Stock"); - - if (App.Settings.Prop.UseReShadeExtraviPresets && App.State.Prop.ExtraviReShadePresetsVersion != versionManifest!.Presets) - { - await InstallExtraviPresets(); - App.State.Prop.ExtraviReShadePresetsVersion = versionManifest.Presets; - App.State.Save(); - } - - SynchronizeConfigFile(); - } - } -} diff --git a/Bloxstrap/Models/ReShadeShaderConfig.cs b/Bloxstrap/Models/ReShadeShaderConfig.cs deleted file mode 100644 index 5ecda89..0000000 --- a/Bloxstrap/Models/ReShadeShaderConfig.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Bloxstrap.Models -{ - public class ReShadeShaderConfig - { - // it's assumed that the BaseFolder has a "Textures" folder and a "Shaders" folder - // the files listed in ExcludedFiles are relative to the BaseFolder - - public string Name { get; set; } = null!; - public string DownloadLocation { get; set; } = null!; - public string BaseFolder { get; set; } = "/"; - public List ExcludedFiles { get; set; } = new List(); - - public override string ToString() => Name; - } -} diff --git a/Bloxstrap/Models/ReShadeVersionManifest.cs b/Bloxstrap/Models/ReShadeVersionManifest.cs deleted file mode 100644 index 9110bf3..0000000 --- a/Bloxstrap/Models/ReShadeVersionManifest.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Bloxstrap.Models -{ - public class ReShadeVersionManifest - { - public string ReShade { get; set; } = null!; - public string Presets { get; set; } = null!; - public string ConfigFile { get; set; } = null!; - } -} diff --git a/Bloxstrap/Models/Settings.cs b/Bloxstrap/Models/Settings.cs index 95b1b8e..dc274fc 100644 --- a/Bloxstrap/Models/Settings.cs +++ b/Bloxstrap/Models/Settings.cs @@ -25,8 +25,6 @@ namespace Bloxstrap.Models // integration configuration public bool UseDiscordRichPresence { get; set; } = true; public bool HideRPCButtons { get; set; } = true; - public bool UseReShade { get; set; } = true; - public bool UseReShadeExtraviPresets { get; set; } = true; public bool ShowServerDetails { get; set; } = false; public ObservableCollection CustomIntegrations { get; set; } = new(); diff --git a/Bloxstrap/Models/State.cs b/Bloxstrap/Models/State.cs index be8c221..f1eb02e 100644 --- a/Bloxstrap/Models/State.cs +++ b/Bloxstrap/Models/State.cs @@ -9,8 +9,6 @@ namespace Bloxstrap.Models public class State { public string VersionGuid { get; set; } = ""; - public string ReShadeConfigVersion { get; set; } = ""; - public string ExtraviReShadePresetsVersion { get; set; } = ""; public List ModManifest { get; set; } = new(); } } diff --git a/Bloxstrap/ViewModels/IntegrationsViewModel.cs b/Bloxstrap/ViewModels/IntegrationsViewModel.cs index ca876b2..f5da011 100644 --- a/Bloxstrap/ViewModels/IntegrationsViewModel.cs +++ b/Bloxstrap/ViewModels/IntegrationsViewModel.cs @@ -15,17 +15,9 @@ namespace Bloxstrap.ViewModels public event PropertyChangedEventHandler? PropertyChanged; public void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - public ICommand OpenReShadeFolderCommand => new RelayCommand(OpenReShadeFolder); public ICommand AddIntegrationCommand => new RelayCommand(AddIntegration); public ICommand DeleteIntegrationCommand => new RelayCommand(DeleteIntegration); - public bool CanOpenReShadeFolder => App.Settings.Prop.UseReShade; - - private void OpenReShadeFolder() - { - Process.Start("explorer.exe", Path.Combine(Directories.Integrations, "ReShade")); - } - private void AddIntegration() { CustomIntegrations.Add(new CustomIntegration() @@ -76,34 +68,13 @@ namespace Bloxstrap.ViewModels set => App.Settings.Prop.HideRPCButtons = !value; } - public bool ReShadeEnabled - { - get => App.Settings.Prop.UseReShade; - set - { - App.Settings.Prop.UseReShade = value; - ReShadePresetsEnabled = value; - - if (value) - App.FastFlags.SetRenderingMode("Direct3D 11"); - - OnPropertyChanged(nameof(ReShadePresetsEnabled)); - } - } - - public bool ReShadePresetsEnabled - { - get => App.Settings.Prop.UseReShadeExtraviPresets; - set => App.Settings.Prop.UseReShadeExtraviPresets = value; - } - public bool ShowServerDetailsEnabled { get => App.Settings.Prop.ShowServerDetails; - set => App.Settings.Prop.ShowServerDetails = value; + set => App.Settings.Prop.ShowServerDetails = value; } - public ObservableCollection CustomIntegrations + public ObservableCollection CustomIntegrations { get => App.Settings.Prop.CustomIntegrations; set => App.Settings.Prop.CustomIntegrations = value; diff --git a/Bloxstrap/Views/Pages/AboutPage.xaml b/Bloxstrap/Views/Pages/AboutPage.xaml index 8130c33..e0235f6 100644 --- a/Bloxstrap/Views/Pages/AboutPage.xaml +++ b/Bloxstrap/Views/Pages/AboutPage.xaml @@ -83,8 +83,6 @@ - - @@ -111,32 +109,18 @@ - - - - - - - + - - - + - - - - - - diff --git a/Bloxstrap/Views/Pages/IntegrationsPage.xaml b/Bloxstrap/Views/Pages/IntegrationsPage.xaml index a204986..c4229b3 100644 --- a/Bloxstrap/Views/Pages/IntegrationsPage.xaml +++ b/Bloxstrap/Views/Pages/IntegrationsPage.xaml @@ -33,66 +33,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Bloxstrap/Views/Pages/ModsPage.xaml b/Bloxstrap/Views/Pages/ModsPage.xaml index c6360f4..e30be22 100644 --- a/Bloxstrap/Views/Pages/ModsPage.xaml +++ b/Bloxstrap/Views/Pages/ModsPage.xaml @@ -117,7 +117,7 @@ - + From 826b0a04cadc71060ba14a207bf584b24ced99a7 Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Thu, 20 Apr 2023 10:32:51 +0100 Subject: [PATCH 15/24] Reorganize stuff moved around stuff to better reflect the regions they're supposed to be in --- Bloxstrap/App.xaml.cs | 3 + Bloxstrap/Bootstrapper.cs | 296 ++++++++++++----------- Bloxstrap/Helpers/IntegrationMigrator.cs | 34 --- Bloxstrap/Views/Pages/ModsPage.xaml.cs | 2 - 4 files changed, 164 insertions(+), 171 deletions(-) delete mode 100644 Bloxstrap/Helpers/IntegrationMigrator.cs diff --git a/Bloxstrap/App.xaml.cs b/Bloxstrap/App.xaml.cs index cf81492..cfc62ff 100644 --- a/Bloxstrap/App.xaml.cs +++ b/Bloxstrap/App.xaml.cs @@ -163,6 +163,9 @@ namespace Bloxstrap ShowMessageBox(message, MessageBoxImage.Warning); } + // this needs to be loaded this early for the menu and also to check for default values + FastFlags.Load(); + // check if installed using (RegistryKey? registryKey = Registry.CurrentUser.OpenSubKey($@"Software\{ProjectName}")) { diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index bab2ead..948fb53 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -117,6 +117,19 @@ namespace Bloxstrap Dialog.Message = message; } + private void UpdateProgressbar() + { + int newProgress = (int)Math.Floor(_progressIncrement * _totalDownloadedBytes); + + // bugcheck: if we're restoring a file from a package, it'll incorrectly increment the progress beyond 100 + // too lazy to fix properly so lol + if (newProgress > 100) + return; + + if (Dialog is not null) + Dialog.ProgressValue = newProgress; + } + public async Task Run() { App.Logger.WriteLine("[Bootstrapper::Run] Running bootstrapper"); @@ -175,12 +188,12 @@ namespace Bloxstrap if (App.IsFirstRun) App.ShouldSaveConfigs = true; - IntegrationMigrator.Execute(); - App.FastFlags.Save(); + MigrateIntegrations(); if (ShouldInstallWebView2) await InstallWebView2(); + App.FastFlags.Save(); await ApplyModifications(); if (App.IsFirstRun || FreshInstall) @@ -201,60 +214,6 @@ namespace Bloxstrap await StartRoblox(); } - private async Task CheckForUpdates() - { - // don't update if there's another instance running (likely running in the background) - if (Utilities.GetProcessCount(App.ProjectName) > 1) - { - App.Logger.WriteLine($"[Bootstrapper::CheckForUpdates] More than one Bloxstrap instance running, aborting update check"); - return; - } - - string currentVersion = $"{App.ProjectName} v{App.Version}"; - - App.Logger.WriteLine($"[Bootstrapper::CheckForUpdates] Checking for {App.ProjectName} updates..."); - - var releaseInfo = await Utilities.GetJson($"https://api.github.com/repos/{App.ProjectRepository}/releases/latest"); - - if (releaseInfo?.Assets is null || currentVersion == releaseInfo.Name) - { - App.Logger.WriteLine($"[Bootstrapper::CheckForUpdates] No updates found"); - return; - } - - SetStatus($"Getting the latest {App.ProjectName}..."); - - // 64-bit is always the first option - GithubReleaseAsset asset = releaseInfo.Assets[Environment.Is64BitOperatingSystem ? 0 : 1]; - string downloadLocation = Path.Combine(Directories.LocalAppData, "Temp", asset.Name); - - App.Logger.WriteLine($"[Bootstrapper::CheckForUpdates] Downloading {releaseInfo.Name}..."); - - if (!File.Exists(downloadLocation)) - { - var response = await App.HttpClient.GetAsync(asset.BrowserDownloadUrl); - - await using var fileStream = new FileStream(downloadLocation, FileMode.CreateNew); - await response.Content.CopyToAsync(fileStream); - } - - App.Logger.WriteLine($"[Bootstrapper::CheckForUpdates] Starting {releaseInfo.Name}..."); - - ProcessStartInfo startInfo = new() - { - FileName = downloadLocation, - }; - - foreach (string arg in App.LaunchArgs) - startInfo.ArgumentList.Add(arg); - - App.Settings.Save(); - - Process.Start(startInfo); - - Environment.Exit(0); - } - private async Task CheckLatestVersion() { SetStatus("Connecting to Roblox..."); @@ -265,69 +224,6 @@ namespace Bloxstrap _versionPackageManifest = await PackageManifest.Get(_latestVersionGuid); } - private void 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 == Directories.Base) - return; - - SetStatus("Migrating install location..."); - - if (Directory.Exists(oldInstallLocation)) - { - App.Logger.WriteLine($"[Bootstrapper::CheckInstallMigration] Moving all files in {oldInstallLocation} to {Directories.Base}..."); - - foreach (string oldFileLocation in Directory.GetFiles(oldInstallLocation, "*.*", SearchOption.AllDirectories)) - { - string relativeFile = oldFileLocation.Substring(oldInstallLocation.Length + 1); - string newFileLocation = Path.Combine(Directories.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($"[Bootstrapper::CheckInstallMigration] Failed to move {oldFileLocation} to {newFileLocation}! {ex}"); - } - } - - try - { - Directory.Delete(oldInstallLocation, true); - App.Logger.WriteLine("[Bootstrapper::CheckInstallMigration] Deleted old install location"); - } - catch (Exception ex) - { - App.Logger.WriteLine($"[Bootstrapper::CheckInstallMigration] Failed to delete old install location! {ex}"); - } - } - - applicationKey.DeleteValue("OldInstallLocation"); - - // allow shortcuts to be re-registered - if (Directory.Exists(Directories.StartMenu)) - Directory.Delete(Directories.StartMenu, true); - - if (File.Exists(DesktopShortcutLocation)) - { - File.Delete(DesktopShortcutLocation); - App.Settings.Prop.CreateDesktopIcon = true; - } - - App.Logger.WriteLine("[Bootstrapper::CheckInstallMigration] Finished migrating install location!"); - } - private async Task StartRoblox() { string startEventName = App.ProjectName.Replace(" ", "") + "StartEvent"; @@ -464,7 +360,7 @@ namespace Bloxstrap App.Terminate(ERROR_INSTALL_USEREXIT); } -#endregion + #endregion #region App Install public static void Register() @@ -497,6 +393,69 @@ namespace Bloxstrap App.Logger.WriteLine("[Bootstrapper::StartRoblox] Registered application"); } + private void 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 == Directories.Base) + return; + + SetStatus("Migrating install location..."); + + if (Directory.Exists(oldInstallLocation)) + { + App.Logger.WriteLine($"[Bootstrapper::CheckInstallMigration] Moving all files in {oldInstallLocation} to {Directories.Base}..."); + + foreach (string oldFileLocation in Directory.GetFiles(oldInstallLocation, "*.*", SearchOption.AllDirectories)) + { + string relativeFile = oldFileLocation.Substring(oldInstallLocation.Length + 1); + string newFileLocation = Path.Combine(Directories.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($"[Bootstrapper::CheckInstallMigration] Failed to move {oldFileLocation} to {newFileLocation}! {ex}"); + } + } + + try + { + Directory.Delete(oldInstallLocation, true); + App.Logger.WriteLine("[Bootstrapper::CheckInstallMigration] Deleted old install location"); + } + catch (Exception ex) + { + App.Logger.WriteLine($"[Bootstrapper::CheckInstallMigration] Failed to delete old install location! {ex}"); + } + } + + applicationKey.DeleteValue("OldInstallLocation"); + + // allow shortcuts to be re-registered + if (Directory.Exists(Directories.StartMenu)) + Directory.Delete(Directories.StartMenu, true); + + if (File.Exists(DesktopShortcutLocation)) + { + File.Delete(DesktopShortcutLocation); + App.Settings.Prop.CreateDesktopIcon = true; + } + + App.Logger.WriteLine("[Bootstrapper::CheckInstallMigration] Finished migrating install location!"); + } + public static void CheckInstall() { App.Logger.WriteLine("[Bootstrapper::StartRoblox] Checking install"); @@ -556,6 +515,60 @@ namespace Bloxstrap } } + private async Task CheckForUpdates() + { + // don't update if there's another instance running (likely running in the background) + if (Utilities.GetProcessCount(App.ProjectName) > 1) + { + App.Logger.WriteLine($"[Bootstrapper::CheckForUpdates] More than one Bloxstrap instance running, aborting update check"); + return; + } + + string currentVersion = $"{App.ProjectName} v{App.Version}"; + + App.Logger.WriteLine($"[Bootstrapper::CheckForUpdates] Checking for {App.ProjectName} updates..."); + + var releaseInfo = await Utilities.GetJson($"https://api.github.com/repos/{App.ProjectRepository}/releases/latest"); + + if (releaseInfo?.Assets is null || currentVersion == releaseInfo.Name) + { + App.Logger.WriteLine($"[Bootstrapper::CheckForUpdates] No updates found"); + return; + } + + SetStatus($"Getting the latest {App.ProjectName}..."); + + // 64-bit is always the first option + GithubReleaseAsset asset = releaseInfo.Assets[Environment.Is64BitOperatingSystem ? 0 : 1]; + string downloadLocation = Path.Combine(Directories.LocalAppData, "Temp", asset.Name); + + App.Logger.WriteLine($"[Bootstrapper::CheckForUpdates] Downloading {releaseInfo.Name}..."); + + if (!File.Exists(downloadLocation)) + { + var response = await App.HttpClient.GetAsync(asset.BrowserDownloadUrl); + + await using var fileStream = new FileStream(downloadLocation, FileMode.CreateNew); + await response.Content.CopyToAsync(fileStream); + } + + App.Logger.WriteLine($"[Bootstrapper::CheckForUpdates] Starting {releaseInfo.Name}..."); + + ProcessStartInfo startInfo = new() + { + FileName = downloadLocation, + }; + + foreach (string arg in App.LaunchArgs) + startInfo.ArgumentList.Add(arg); + + App.Settings.Save(); + + Process.Start(startInfo); + + Environment.Exit(0); + } + private void Uninstall() { // prompt to shutdown roblox if its currently running @@ -628,22 +641,9 @@ namespace Bloxstrap Dialog?.ShowSuccess($"{App.ProjectName} has succesfully uninstalled"); } -#endregion + #endregion #region Roblox Install - private void UpdateProgressbar() - { - int newProgress = (int)Math.Floor(_progressIncrement * _totalDownloadedBytes); - - // bugcheck: if we're restoring a file from a package, it'll incorrectly increment the progress beyond 100 - // too lazy to fix properly so lol - if (newProgress > 100) - return; - - if (Dialog is not null) - Dialog.ProgressValue = newProgress; - } - private async Task InstallLatestVersion() { _isInstalling = true; @@ -792,6 +792,32 @@ namespace Bloxstrap App.Logger.WriteLine($"[Bootstrapper::InstallWebView2] Finished installing runtime"); } + public static void MigrateIntegrations() + { + // v2.2.0 - remove rbxfpsunlocker + string rbxfpsunlocker = Path.Combine(Directories.Integrations, "rbxfpsunlocker"); + + if (Directory.Exists(rbxfpsunlocker)) + Directory.Delete(rbxfpsunlocker, true); + + // v2.2.0 - remove reshade + string reshadeLocation = Path.Combine(Directories.Modifications, "dxgi.dll"); + + if (File.Exists(reshadeLocation)) + { + App.ShowMessageBox( + "As of April 18th, Roblox has started out rolling out the Byfron anticheat as well as 64-bit support. Because of this, ReShade will no longer work, and will be deactivated from now on.\n\n" + + $"Your ReShade configs and files will still be kept, which are all located in the {App.ProjectName} folder.", + MessageBoxImage.Warning + ); + + File.Delete(reshadeLocation); + + if (App.FastFlags.GetValue(FastFlagManager.RenderingModes["Direct3D 11"]) == "True" && App.FastFlags.GetValue("FFlagHandleAltEnterFullscreenManually") != "False") + App.FastFlags.SetRenderingMode("Automatic"); + } + } + private async Task ApplyModifications() { SetStatus("Applying Roblox modifications..."); @@ -1075,6 +1101,6 @@ namespace Bloxstrap entry.ExtractToFile(fileLocation); } -#endregion + #endregion } } diff --git a/Bloxstrap/Helpers/IntegrationMigrator.cs b/Bloxstrap/Helpers/IntegrationMigrator.cs deleted file mode 100644 index a73ecf0..0000000 --- a/Bloxstrap/Helpers/IntegrationMigrator.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.IO; -using System.Windows; - -namespace Bloxstrap.Helpers -{ - static class IntegrationMigrator - { - public static void Execute() - { - // v2.2.0 - remove rbxfpsunlocker - string rbxfpsunlocker = Path.Combine(Directories.Integrations, "rbxfpsunlocker"); - - if (Directory.Exists(rbxfpsunlocker)) - Directory.Delete(rbxfpsunlocker, true); - - // v2.2.0 - remove reshade - string reshadeLocation = Path.Combine(Directories.Modifications, "dxgi.dll"); - - if (File.Exists(reshadeLocation)) - { - App.ShowMessageBox( - "As of April 18th, Roblox has started out rolling out the Byfron anticheat as well as 64-bit support. Because of this, ReShade will no longer work, and will be deactivated from now on.\n\n" + - $"Your ReShade configs and files will still be kept, which are all located in the {App.ProjectName} folder.", - MessageBoxImage.Warning - ); - - File.Delete(reshadeLocation); - - if (App.FastFlags.GetValue(FastFlagManager.RenderingModes["Direct3D 11"]) == "True" && App.FastFlags.GetValue("FFlagHandleAltEnterFullscreenManually") != "False") - App.FastFlags.SetRenderingMode("Automatic"); - } - } - } -} diff --git a/Bloxstrap/Views/Pages/ModsPage.xaml.cs b/Bloxstrap/Views/Pages/ModsPage.xaml.cs index 704448e..e3c3b73 100644 --- a/Bloxstrap/Views/Pages/ModsPage.xaml.cs +++ b/Bloxstrap/Views/Pages/ModsPage.xaml.cs @@ -13,8 +13,6 @@ namespace Bloxstrap.Views.Pages { public ModsPage() { - App.FastFlags.Load(); - DataContext = new ModsViewModel(); InitializeComponent(); From b3dcb48038a408bf1f5af528fa0c44daa93efc65 Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Thu, 20 Apr 2023 11:51:37 +0100 Subject: [PATCH 16/24] Make launch behaviour closer to official launcher no custom start event, only specifying launchtime when launched from website oh yeah i fixed a bug with fflag management --- Bloxstrap/App.xaml.cs | 6 ++---- Bloxstrap/Bootstrapper.cs | 23 +++++++++-------------- Bloxstrap/Helpers/JsonManager.cs | 3 +-- Bloxstrap/Helpers/Protocol.cs | 6 +++++- 4 files changed, 17 insertions(+), 21 deletions(-) diff --git a/Bloxstrap/App.xaml.cs b/Bloxstrap/App.xaml.cs index cfc62ff..fac8054 100644 --- a/Bloxstrap/App.xaml.cs +++ b/Bloxstrap/App.xaml.cs @@ -163,9 +163,6 @@ namespace Bloxstrap ShowMessageBox(message, MessageBoxImage.Warning); } - // this needs to be loaded this early for the menu and also to check for default values - FastFlags.Load(); - // check if installed using (RegistryKey? registryKey = Registry.CurrentUser.OpenSubKey($@"Software\{ProjectName}")) { @@ -179,6 +176,7 @@ namespace Bloxstrap if (!IsQuiet) { IsSetupComplete = false; + FastFlags.Load(); new MainWindow().ShowDialog(); } } @@ -197,7 +195,7 @@ namespace Bloxstrap } Directories.Initialize(BaseDirectory); - FastFlags.AltFileLocation = Path.Combine(Directories.Modifications, "ClientSettings\\ClientAppSettings.json"); + FastFlags.Load(); // we shouldn't save settings on the first run until the first installation is finished, // just in case the user decides to cancel the install diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index 948fb53..35e7281 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -62,11 +62,11 @@ namespace Bloxstrap }; private const string AppSettings = - "\n" + - "\n" + - " content\n" + - " http://www.roblox.com\n" + - "\n"; + "\r\n" + + "\r\n" + + " content\r\n" + + " http://www.roblox.com\r\n" + + "\r\n"; private readonly CancellationTokenSource _cancelTokenSource = new(); @@ -76,7 +76,7 @@ namespace Bloxstrap private string _playerLocation => Path.Combine(_versionFolder, "RobloxPlayerBeta.exe"); - private string? _launchCommandLine; + private string _launchCommandLine; private string _latestVersionGuid = null!; private PackageManifest _versionPackageManifest = null!; @@ -92,7 +92,7 @@ namespace Bloxstrap #endregion #region Core - public Bootstrapper(string? launchCommandLine = null) + public Bootstrapper(string launchCommandLine) { _launchCommandLine = launchCommandLine; @@ -226,8 +226,6 @@ namespace Bloxstrap private async Task StartRoblox() { - string startEventName = App.ProjectName.Replace(" ", "") + "StartEvent"; - SetStatus("Starting Roblox..."); if (_launchCommandLine == "--app" && App.Settings.Prop.UseDisableAppPatch) @@ -237,14 +235,11 @@ namespace Bloxstrap return; } - // launch time isn't really required for all launches, but it's usually just safest to do this - _launchCommandLine += " --launchtime=" + DateTimeOffset.Now.ToUnixTimeMilliseconds(); + _launchCommandLine = _launchCommandLine.Replace("LAUNCHTIMEPLACEHOLDER", DateTimeOffset.Now.ToUnixTimeMilliseconds().ToString()); if (App.Settings.Prop.Channel.ToLower() != DeployManager.DefaultChannel.ToLower()) _launchCommandLine += " -channel " + App.Settings.Prop.Channel.ToLower(); - _launchCommandLine += " -startEvent " + startEventName; - // whether we should wait for roblox to exit to handle stuff in the background or clean up after roblox closes bool shouldWait = false; @@ -256,7 +251,7 @@ namespace Bloxstrap App.Logger.WriteLine($"[Bootstrapper::StartRoblox] Started Roblox (PID {gameClient.Id})"); - using (SystemEvent startEvent = new(startEventName)) + using (SystemEvent startEvent = new("www.roblox.com/robloxStartedEvent")) { bool startEventFired = await startEvent.WaitForEvent(); diff --git a/Bloxstrap/Helpers/JsonManager.cs b/Bloxstrap/Helpers/JsonManager.cs index dde7851..ef39f9c 100644 --- a/Bloxstrap/Helpers/JsonManager.cs +++ b/Bloxstrap/Helpers/JsonManager.cs @@ -7,8 +7,7 @@ namespace Bloxstrap.Helpers public class JsonManager where T : new() { public T Prop { get; set; } = new(); - public virtual string FileLocation => AltFileLocation ?? Path.Combine(Directories.Base, $"{typeof(T).Name}.json"); - public string? AltFileLocation { get; set; } + public virtual string FileLocation => Path.Combine(Directories.Base, $"{typeof(T).Name}.json"); public virtual void Load() { diff --git a/Bloxstrap/Helpers/Protocol.cs b/Bloxstrap/Helpers/Protocol.cs index 8524566..70c56b3 100644 --- a/Bloxstrap/Helpers/Protocol.cs +++ b/Bloxstrap/Helpers/Protocol.cs @@ -18,7 +18,7 @@ namespace Bloxstrap.Helpers { "launchmode", "--" }, { "gameinfo", "-t " }, { "placelauncherurl", "-j "}, - // { "launchtime", "--launchtime=" }, we'll set this when launching the game client + { "launchtime", "--launchtime=" }, { "browsertrackerid", "-b " }, { "robloxLocale", "--rloc " }, { "gameLocale", "--gloc " }, @@ -50,6 +50,10 @@ namespace Bloxstrap.Helpers if (key == "placelauncherurl") val = HttpUtility.UrlDecode(val); + // we'll set this before launching because for some reason roblox just refuses to launch if its like a few minutes old so ??? + if (key == "launchtime") + val = "LAUNCHTIMEPLACEHOLDER"; + if (key == "channel") { if (val.ToLower() != App.Settings.Prop.Channel.ToLower()) From 6ea198f1e1b088b61bd118270f52051712f6dd76 Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Thu, 20 Apr 2023 12:54:02 +0100 Subject: [PATCH 17/24] Fix Byfron crashes turns out byfron will trip if you keep a process handle for robloxplayerbeta open for any longer than a minute --- Bloxstrap/Bootstrapper.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index 35e7281..ae01a8a 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -243,13 +243,19 @@ namespace Bloxstrap // whether we should wait for roblox to exit to handle stuff in the background or clean up after roblox closes bool shouldWait = false; - Process gameClient = Process.Start(_playerLocation, _launchCommandLine); + // v2.2.0 - byfron will trip if we keep a process handle open for over a minute, so we're doing this now + int gameClientPid; + using (Process gameClient = Process.Start(_playerLocation, _launchCommandLine)) + { + gameClientPid = gameClient.Id; + } + List autocloseProcesses = new(); GameActivityWatcher? activityWatcher = null; DiscordRichPresence? richPresence = null; ServerNotifier? serverNotifier = null; - App.Logger.WriteLine($"[Bootstrapper::StartRoblox] Started Roblox (PID {gameClient.Id})"); + App.Logger.WriteLine($"[Bootstrapper::StartRoblox] Started Roblox (PID {gameClientPid})"); using (SystemEvent startEvent = new("www.roblox.com/robloxStartedEvent")) { @@ -311,8 +317,11 @@ namespace Bloxstrap activityWatcher?.StartWatcher(); App.Logger.WriteLine("[Bootstrapper::StartRoblox] Waiting for Roblox to close"); - await gameClient.WaitForExitAsync(); - App.Logger.WriteLine($"[Bootstrapper::StartRoblox] Roblox exited with code {gameClient.ExitCode}"); + + while (Process.GetProcesses().Any(x => x.Id == gameClientPid)) + await Task.Delay(1000); + + App.Logger.WriteLine($"[Bootstrapper::StartRoblox] Roblox has exited"); richPresence?.Dispose(); From 055e75cfbed4f87a257fe972196638b195c60493 Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Thu, 20 Apr 2023 13:30:29 +0100 Subject: [PATCH 18/24] Formatting fixes, bump version --- Bloxstrap/App.xaml.cs | 5 ++--- Bloxstrap/Bloxstrap.csproj | 4 ++-- Bloxstrap/Bootstrapper.cs | 5 ++++- Bloxstrap/Helpers/DeployManager.cs | 1 + Bloxstrap/Models/State.cs | 1 + 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Bloxstrap/App.xaml.cs b/Bloxstrap/App.xaml.cs index fac8054..6446109 100644 --- a/Bloxstrap/App.xaml.cs +++ b/Bloxstrap/App.xaml.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.Globalization; using System.IO; +using System.Linq; using System.Net.Http; using System.Net; using System.Reflection; @@ -332,10 +333,8 @@ namespace Bloxstrap // we've got ownership of the roblox singleton mutex! // if we stop running, everything will screw up once any more roblox instances launched - while (Utilities.GetProcessCount("RobloxPlayerBeta", false) != 0) - { + while (Process.GetProcessesByName("RobloxPlayerBeta").Any()) Thread.Sleep(5000); - } } } diff --git a/Bloxstrap/Bloxstrap.csproj b/Bloxstrap/Bloxstrap.csproj index d3e7baa..bec8aa9 100644 --- a/Bloxstrap/Bloxstrap.csproj +++ b/Bloxstrap/Bloxstrap.csproj @@ -7,8 +7,8 @@ true True Bloxstrap.ico - 2.1.0 - 2.1.0.0 + 2.2.0 + 2.2.0.0 app.manifest diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index ae01a8a..52aa707 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -247,7 +247,7 @@ namespace Bloxstrap int gameClientPid; using (Process gameClient = Process.Start(_playerLocation, _launchCommandLine)) { - gameClientPid = gameClient.Id; + gameClientPid = gameClient.Id; } List autocloseProcesses = new(); @@ -819,6 +819,9 @@ namespace Bloxstrap if (App.FastFlags.GetValue(FastFlagManager.RenderingModes["Direct3D 11"]) == "True" && App.FastFlags.GetValue("FFlagHandleAltEnterFullscreenManually") != "False") App.FastFlags.SetRenderingMode("Automatic"); + + // this is just in case something ever changes, i doubt it but lol + App.State.Prop.HadReShadeInstalled = true; } } diff --git a/Bloxstrap/Helpers/DeployManager.cs b/Bloxstrap/Helpers/DeployManager.cs index a745cd7..2f88c9d 100644 --- a/Bloxstrap/Helpers/DeployManager.cs +++ b/Bloxstrap/Helpers/DeployManager.cs @@ -80,6 +80,7 @@ namespace Bloxstrap.Helpers public static readonly List SelectableChannels = new() { "LIVE", + "ZWinPlayer64", "ZFlag", "ZNext", "ZCanary", diff --git a/Bloxstrap/Models/State.cs b/Bloxstrap/Models/State.cs index f1eb02e..3fb6648 100644 --- a/Bloxstrap/Models/State.cs +++ b/Bloxstrap/Models/State.cs @@ -9,6 +9,7 @@ namespace Bloxstrap.Models public class State { public string VersionGuid { get; set; } = ""; + public bool HadReShadeInstalled { get; set; } = false; public List ModManifest { get; set; } = new(); } } From 4758c4ead9d48d2ad0291214d69e2a19ad9fce1e Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Thu, 20 Apr 2023 14:01:25 +0100 Subject: [PATCH 19/24] Update README.md --- README.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index a5500fe..eb56650 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Alternatively, you can install Bloxstrap via [Winget](https://winstall.app/apps/ > winget install bloxstrap ``` -You will also need the [.NET 6 Desktop Runtime](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-6.0.14-windows-x64-installer). If you don't already have it installed, you'll be prompted to install it anyway. Be sure to install Bloxstrap after you've installed this. +You will also need the [.NET 6 Desktop Runtime](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-6.0.16-windows-x64-installer). If you don't already have it installed, you'll be prompted to install it anyway. Be sure to install Bloxstrap after you've installed this. It's not unlikely that Windows Smartscreen will show a popup when you run Bloxstrap for the first time. This happens because it's an unknown program, not because it's actually detected as being malicious. To dismiss it, just click on "More info" and then "Run anyway". @@ -34,22 +34,21 @@ If you want to build Bloxstrap's source code, see the [guide for building from s Here's some of the features that Bloxstrap provides over the stock Roblox bootstrapper: * Persistent file modifications - re-adds the old death sound! -* Support for shaders with [ReShade](https://reshade.me) and [Extravi's ReShade Presets](https://bloxshade.com/) * Painless support for Discord Rich Presence - no auth cookie needed! -* Automatic silent FPS unlocking with [rbxfpsunlocker](https://github.com/axstin/rbxfpsunlocker) -* Ability to disable the Roblox desktop app +* Built-in FPS unlocking * A customizable launcher look - includes dark theme! -* Ability to opt into non-production Roblox release channels -* Ability to see what region your current server is located in -* Support for having multiple Roblox game instances open simultaneously +* Lets you disable the Roblox desktop app +* Lets you opt into non-production Roblox release channels +* Lets you see what region your current server is located in +* Lets you have multiple Roblox game instances open simultaneously All the available features are browsable through the Bloxstrap menu. There's not too many, but it's recommended to look through all of them. -Bloxstrap also has inherent benefits over some other Roblox mods, as ReShade does not break whenever Roblox updates and thus require a reinstall, and is completely free, forever. It also only runs whenever necessary, so it doesn't stay running in the background when you're not playing. +Bloxstrap also has inherent benefits over some other Roblox mods, as it only runs whenever necessary, so it doesn't stay running in the background when you're not playing. ## Screenshots

- + From d30aff867a30f86b43c725e7d8c014b0183e1037 Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Thu, 20 Apr 2023 14:23:12 +0100 Subject: [PATCH 20/24] Make Mods the default page --- Bloxstrap/Views/MainWindow.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bloxstrap/Views/MainWindow.xaml b/Bloxstrap/Views/MainWindow.xaml index 18b037b..fecc153 100644 --- a/Bloxstrap/Views/MainWindow.xaml +++ b/Bloxstrap/Views/MainWindow.xaml @@ -41,8 +41,8 @@ - + From becc73929e150647b82c18bd17bc9eb97e1054ce Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Fri, 21 Apr 2023 11:55:43 +0100 Subject: [PATCH 21/24] Revert "Remove ReShade" instead of removing reshade outright, it's probably better to just make people switch to LIVE for now. yeah, reshade is on its last knees, but if there's still time, i'm taking it --- Bloxstrap/Bloxstrap.csproj | 1 + Bloxstrap/Bootstrapper.cs | 29 +- Bloxstrap/Helpers/FastFlagManager.cs | 4 +- Bloxstrap/Integrations/ReShade.cs | 505 ++++++++++++++++++ Bloxstrap/Models/ReShadeShaderConfig.cs | 21 + Bloxstrap/Models/ReShadeVersionManifest.cs | 9 + Bloxstrap/Models/Settings.cs | 2 + Bloxstrap/Models/State.cs | 3 +- Bloxstrap/ViewModels/IntegrationsViewModel.cs | 29 + Bloxstrap/Views/Pages/AboutPage.xaml | 20 +- Bloxstrap/Views/Pages/IntegrationsPage.xaml | 60 +++ Bloxstrap/Views/Pages/ModsPage.xaml | 2 +- 12 files changed, 658 insertions(+), 27 deletions(-) create mode 100644 Bloxstrap/Integrations/ReShade.cs create mode 100644 Bloxstrap/Models/ReShadeShaderConfig.cs create mode 100644 Bloxstrap/Models/ReShadeVersionManifest.cs diff --git a/Bloxstrap/Bloxstrap.csproj b/Bloxstrap/Bloxstrap.csproj index bec8aa9..c1d35ef 100644 --- a/Bloxstrap/Bloxstrap.csproj +++ b/Bloxstrap/Bloxstrap.csproj @@ -25,6 +25,7 @@ + diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index 52aa707..63bfa48 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -193,6 +193,11 @@ namespace Bloxstrap if (ShouldInstallWebView2) await InstallWebView2(); + if (App.Settings.Prop.UseReShade) + SetStatus("Configuring/Downloading ReShade..."); + + await ReShade.CheckModifications(); + App.FastFlags.Save(); await ApplyModifications(); @@ -719,6 +724,8 @@ namespace Bloxstrap if (!FreshInstall) { + ReShade.SynchronizeConfigFile(); + // let's take this opportunity to delete any packages we don't need anymore foreach (string filename in Directory.GetFiles(Directories.Downloads)) { @@ -803,26 +810,6 @@ namespace Bloxstrap if (Directory.Exists(rbxfpsunlocker)) Directory.Delete(rbxfpsunlocker, true); - - // v2.2.0 - remove reshade - string reshadeLocation = Path.Combine(Directories.Modifications, "dxgi.dll"); - - if (File.Exists(reshadeLocation)) - { - App.ShowMessageBox( - "As of April 18th, Roblox has started out rolling out the Byfron anticheat as well as 64-bit support. Because of this, ReShade will no longer work, and will be deactivated from now on.\n\n" + - $"Your ReShade configs and files will still be kept, which are all located in the {App.ProjectName} folder.", - MessageBoxImage.Warning - ); - - File.Delete(reshadeLocation); - - if (App.FastFlags.GetValue(FastFlagManager.RenderingModes["Direct3D 11"]) == "True" && App.FastFlags.GetValue("FFlagHandleAltEnterFullscreenManually") != "False") - App.FastFlags.SetRenderingMode("Automatic"); - - // this is just in case something ever changes, i doubt it but lol - App.State.Prop.HadReShadeInstalled = true; - } } private async Task ApplyModifications() @@ -920,7 +907,7 @@ namespace Bloxstrap try { - packageDirectory = PackageDirectories.First(x => x.Key != "RobloxApp.zip" && x.Key != "WebView2.zip" && fileLocation.StartsWith(x.Value)); + packageDirectory = PackageDirectories.First(x => x.Value != "" && fileLocation.StartsWith(x.Value)); } catch (InvalidOperationException) { diff --git a/Bloxstrap/Helpers/FastFlagManager.cs b/Bloxstrap/Helpers/FastFlagManager.cs index 76b676b..ce87d3e 100644 --- a/Bloxstrap/Helpers/FastFlagManager.cs +++ b/Bloxstrap/Helpers/FastFlagManager.cs @@ -113,8 +113,8 @@ namespace Bloxstrap.Helpers if (GetValue("DFIntTaskSchedulerTargetFps") is null) SetValue("DFIntTaskSchedulerTargetFps", 9999); - // exclusive fullscreen requires direct3d 11 to work - if (GetValue(RenderingModes["Direct3D 11"]) != "True" && App.FastFlags.GetValue("FFlagHandleAltEnterFullscreenManually") == "False") + // reshade / exclusive fullscreen requires direct3d 11 to work + if (GetValue(RenderingModes["Direct3D 11"]) != "True" && (App.Settings.Prop.UseReShade || App.FastFlags.GetValue("FFlagHandleAltEnterFullscreenManually") == "False")) SetRenderingMode("Direct3D 11"); } diff --git a/Bloxstrap/Integrations/ReShade.cs b/Bloxstrap/Integrations/ReShade.cs new file mode 100644 index 0000000..5931f1e --- /dev/null +++ b/Bloxstrap/Integrations/ReShade.cs @@ -0,0 +1,505 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Threading.Tasks; +using Bloxstrap.Helpers; + +using Bloxstrap.Models; + +using IniParser; +using IniParser.Model; + +namespace Bloxstrap.Integrations +{ + internal class ReShade + { + // i havent even started this and i know for a fact this is gonna be a mess of an integration lol + // there's a lot of nuances involved in how reshade functionality is supposed to work (shader management, config management, etc) + // it's gonna be a bit of a pain in the ass, and i'm expecting a lot of bugs to arise from this... + // well, looks like v1.7.0 is gonna be held back for quite a while lol + + // also, this is going to be fairly restrictive without a lot of heavy work + // reshade's official installer gives you a list of shader packs and lets you choose which ones you want to install + // and here we're effectively choosing for the user... hm... + // i mean, it should be fine? importing shaders is still gonna be a thing, though maybe not as simple, but most people would be looking to use extravi's presets anyway + + private static string BaseDirectory => Path.Combine(Directories.Integrations, "ReShade"); + private static string FontsFolder => Path.Combine(BaseDirectory, "Fonts"); + private static string PresetsFolder => Path.Combine(BaseDirectory, "Presets"); + private static string ShadersFolder => Path.Combine(BaseDirectory, "Shaders"); + private static string TexturesFolder => Path.Combine(BaseDirectory, "Textures"); + private static string ConfigLocation => Path.Combine(Directories.Modifications, "ReShade.ini"); + + // the base url that we're fetching all our remote configs and resources and stuff from + private const string BaseUrl = "https://raw.githubusercontent.com/Extravi/extravi.github.io/main/update"; + + // this is a list of selectable shaders to download + private static readonly List Shaders = new() + { + // shaders required for extravi's presets: + new ReShadeShaderConfig { Name = "AstrayFX", DownloadLocation = "https://github.com/BlueSkyDefender/AstrayFX/archive/refs/heads/master.zip" }, + new ReShadeShaderConfig { Name = "Brussell", DownloadLocation = "https://github.com/brussell1/Shaders/archive/refs/heads/master.zip" }, + new ReShadeShaderConfig { Name = "Depth3D", DownloadLocation = "https://github.com/BlueSkyDefender/Depth3D/archive/refs/heads/master.zip" }, + new ReShadeShaderConfig { Name = "Glamarye", DownloadLocation = "https://github.com/rj200/Glamarye_Fast_Effects_for_ReShade/archive/refs/heads/main.zip" }, + new ReShadeShaderConfig { Name = "NiceGuy", DownloadLocation = "https://github.com/mj-ehsan/NiceGuy-Shaders/archive/refs/heads/main.zip" }, + new ReShadeShaderConfig { Name = "prod80", DownloadLocation = "https://github.com/prod80/prod80-ReShade-Repository/archive/refs/heads/master.zip" }, + new ReShadeShaderConfig { Name = "qUINT", DownloadLocation = "https://github.com/martymcmodding/qUINT/archive/refs/heads/master.zip" }, + new ReShadeShaderConfig { Name = "StockLegacy", DownloadLocation = "https://github.com/crosire/reshade-shaders/archive/refs/heads/legacy.zip" }, + new ReShadeShaderConfig { Name = "SweetFX", DownloadLocation = "https://github.com/CeeJayDK/SweetFX/archive/refs/heads/master.zip" }, + + // these ones needs some additional configuration + + new ReShadeShaderConfig + { + Name = "Stock", + DownloadLocation = "https://github.com/crosire/reshade-shaders/archive/refs/heads/master.zip", + ExcludedFiles = new List() + { + // overriden by stormshade + "Shaders/MXAO.fx" + } + }, + + new ReShadeShaderConfig + { + Name = "AlucardDH", + DownloadLocation = "https://github.com/AlucardDH/dh-reshade-shaders/archive/refs/heads/master.zip", + ExcludedFiles = new List() + { + // compiler errors + // dh_Lain only errors when performance mode is disabled, but it's not used by any presets anyway + "Shaders/dh_rtgi.fx", + "Shaders/dh_Lain.fx" + } + }, + + new ReShadeShaderConfig + { + Name = "Stormshade", + DownloadLocation = "https://github.com/cyrie/Stormshade/archive/refs/heads/master.zip", + BaseFolder = "reshade-shaders/", + ExcludedFiles = new List() + { + // these file names conflict with effects in the stock reshade config + "Shaders/AmbientLight.fx", + "Shaders/Clarity.fx", + "Shaders/DOF.fx", + "Shaders/DPX.fx", + "Shaders/FilmGrain.fx", + "Shaders/FineSharp.fx", + "Shaders/FXAA.fx", + "Shaders/FXAA.fxh", + "Shaders/LumaSharpen.fx", + //"Shaders/MXAO.fx", + "Shaders/ReShade.fxh", + "Shaders/Vibrance.fx", + "Shaders/Vignette.fx" + } + }, + }; + + private static readonly string[] ExtraviPresetsShaders = new string[] + { + "AlucardDH", + "Brussell", + "AstrayFX", + "Brussell", + "Depth3D", + "Glamarye", + "NiceGuy", + "prod80", + "qUINT", + "StockLegacy", + "Stormshade", + "SweetFX", + }; + + private static string GetSearchPath(string type, string name) + { + return $",..\\..\\Integrations\\ReShade\\{type}\\{name}"; + } + + public static async Task DownloadConfig() + { + App.Logger.WriteLine("[ReShade::DownloadConfig] Downloading/Upgrading config file..."); + + { + byte[] bytes = await App.HttpClient.GetByteArrayAsync($"{BaseUrl}/config.zip"); + + using MemoryStream zipStream = new(bytes); + using ZipArchive archive = new(zipStream); + + + archive.Entries.First(x => x.FullName == "ReShade.ini").ExtractToFile(ConfigLocation, true); + + // when we extract the file we have to make sure the last modified date is overwritten + // or else it will synchronize with the config in the version folder + // really the config adjustments below should do this for us, but this is just to be safe + File.SetLastWriteTime(ConfigLocation, DateTime.Now); + + // we also gotta download the editor fonts + foreach (ZipArchiveEntry entry in archive.Entries.Where(x => x.FullName.EndsWith(".ttf"))) + entry.ExtractToFile(Path.Combine(FontsFolder, entry.FullName), true); + } + + // now we have to adjust the config file to use the paths that we need + // some of these can be removed later when the config file is better adjusted for bloxstrap by default + + FileIniDataParser parser = new(); + IniData data = parser.ReadFile(ConfigLocation); + + data["GENERAL"]["EffectSearchPaths"] = "..\\..\\Integrations\\ReShade\\Shaders"; + data["GENERAL"]["TextureSearchPaths"] = "..\\..\\Integrations\\ReShade\\Textures"; + data["GENERAL"]["PresetPath"] = data["GENERAL"]["PresetPath"].Replace(".\\reshade-presets\\", "..\\..\\Integrations\\ReShade\\Presets\\"); + //data["SCREENSHOT"]["SavePath"] = "..\\..\\ReShade\\Screenshots"; + data["SCREENSHOT"]["SavePath"] = Path.Combine(Directories.MyPictures, "Roblox-ReShade"); + data["STYLE"]["EditorFont"] = data["STYLE"]["EditorFont"].Replace(".\\", "..\\..\\Integrations\\ReShade\\Fonts\\"); + data["STYLE"]["Font"] = data["STYLE"]["Font"].Replace(".\\", "..\\..\\Integrations\\ReShade\\Fonts\\"); + + // add search paths for shaders and textures + + foreach (string name in Directory.GetDirectories(ShadersFolder).Select(x => Path.GetRelativePath(ShadersFolder, x)).ToArray()) + data["GENERAL"]["EffectSearchPaths"] += GetSearchPath("Shaders", name); + + foreach (string name in Directory.GetDirectories(TexturesFolder).Select(x => Path.GetRelativePath(TexturesFolder, x)).ToArray()) + data["GENERAL"]["TextureSearchPaths"] += GetSearchPath("Textures", name); + + parser.WriteFile(ConfigLocation, data); + } + + public static void SynchronizeConfigFile() + { + App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] Synchronizing configuration file..."); + + // yeah, this is going to be a bit of a pain + // keep in mind the config file is going to be in two places: the mod folder and the version folder + // so we have to make sure the two below scenaros work flawlessly: + // - if the user manually updates their reshade config in the mod folder or it gets updated, it must be copied to the version folder + // - if the user updates their reshade settings ingame, the updated config must be copied to the mod folder + // the easiest way to manage this is to just compare the modification dates of the two + // anyway, this is where i'm expecting most of the bugs to arise from + // config synchronization will be done whenever roblox updates or whenever we launch roblox + + string modFolderConfigPath = ConfigLocation; + string versionFolderConfigPath = Path.Combine(Directories.Versions, App.State.Prop.VersionGuid, "ReShade.ini"); + + // we shouldn't be here if the mod config doesn't already exist + if (!File.Exists(modFolderConfigPath)) + { + App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] ReShade.ini in modifications folder does not exist, aborting sync"); + return; + } + + // copy to the version folder if it doesn't already exist there + if (!File.Exists(versionFolderConfigPath)) + { + App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] ReShade.ini in version folder does not exist, synchronized with modifications folder"); + File.Copy(modFolderConfigPath, versionFolderConfigPath); + } + + // if both the mod and version configs match, then we don't need to do anything + if (Utilities.MD5File(modFolderConfigPath) == Utilities.MD5File(versionFolderConfigPath)) + { + App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] ReShade.ini in version and modifications folder match"); + return; + } + + FileInfo modFolderConfigFile = new(modFolderConfigPath); + FileInfo versionFolderConfigFile = new(versionFolderConfigPath); + + if (modFolderConfigFile.LastWriteTime > versionFolderConfigFile.LastWriteTime) + { + // overwrite version config if mod config was modified most recently + App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] ReShade.ini in version folder is older, synchronized with modifications folder"); + File.Copy(modFolderConfigPath, versionFolderConfigPath, true); + } + else if (versionFolderConfigFile.LastWriteTime > modFolderConfigFile.LastWriteTime) + { + // overwrite mod config if version config was modified most recently + App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] ReShade.ini in modifications folder is older, synchronized with version folder"); + File.Copy(versionFolderConfigPath, modFolderConfigPath, true); + } + } + + public static async Task DownloadShaders(string name) + { + ReShadeShaderConfig config = Shaders.First(x => x.Name == name); + + // not all shader packs have a textures folder, so here we're determining if they exist purely based on if they have a Shaders folder + if (Directory.Exists(Path.Combine(ShadersFolder, name))) + return; + + App.Logger.WriteLine($"[ReShade::DownloadShaders] Downloading shaders for {name}"); + + { + byte[] bytes = await App.HttpClient.GetByteArrayAsync(config.DownloadLocation); + + using MemoryStream zipStream = new(bytes); + using ZipArchive archive = new(zipStream); + + foreach (ZipArchiveEntry entry in archive.Entries) + { + if (entry.FullName.EndsWith('/') || !entry.FullName.Contains(config.BaseFolder)) + continue; + + // github branch zips have a root folder of the name of the branch, so let's just remove that + string fullPath = entry.FullName.Substring(entry.FullName.IndexOf(config.BaseFolder) + config.BaseFolder.Length); + + // skip file if it's not in the Shaders or Textures folder + if (!fullPath.StartsWith("Shaders") && !fullPath.StartsWith("Textures")) + continue; + + if (config.ExcludedFiles.Contains(fullPath)) + continue; + + // and now we do it again because of how we're handling folder management + // e.g. reshade-shaders-master/Shaders/Vignette.fx should go to ReShade/Shaders/Stock/Vignette.fx + // so in this case, relativePath should just be "Vignette.fx" + string relativePath = fullPath.Substring(fullPath.IndexOf('/') + 1); + + // now we stitch it all together + string extractionPath = Path.Combine( + BaseDirectory, + fullPath.StartsWith("Shaders") ? "Shaders" : "Textures", + name, + relativePath + ); + + // make sure the folder that we're extracting it to exists + Directory.CreateDirectory(Path.GetDirectoryName(extractionPath)!); + + // and now extract + await Task.Run(() => entry.ExtractToFile(extractionPath)); + } + } + + // now we have to update ReShade.ini and add the installed shaders to the search paths + FileIniDataParser parser = new(); + IniData data = parser.ReadFile(ConfigLocation); + + if (!data["GENERAL"]["EffectSearchPaths"].Contains(name)) + data["GENERAL"]["EffectSearchPaths"] += GetSearchPath("Shaders", name); + + // not every shader pack has a textures folder + if (Directory.Exists(Path.Combine(TexturesFolder, name)) && !data["GENERAL"]["TextureSearchPaths"].Contains(name)) + data["GENERAL"]["TextureSearchPaths"] += GetSearchPath("Textures", name); + + parser.WriteFile(ConfigLocation, data); + } + + public static void DeleteShaders(string name) + { + App.Logger.WriteLine($"[ReShade::DeleteShaders] Deleting shaders for {name}"); + + string shadersPath = Path.Combine(ShadersFolder, name); + string texturesPath = Path.Combine(TexturesFolder, name); + + if (Directory.Exists(shadersPath)) + Directory.Delete(shadersPath, true); + + if (Directory.Exists(texturesPath)) + Directory.Delete(texturesPath, true); + + if (!File.Exists(ConfigLocation)) + return; + + // now we have to update ReShade.ini and remove the installed shaders from the search paths + FileIniDataParser parser = new(); + IniData data = parser.ReadFile(ConfigLocation); + + string shaderSearchPaths = data["GENERAL"]["EffectSearchPaths"]; + string textureSearchPaths = data["GENERAL"]["TextureSearchPaths"]; + + if (shaderSearchPaths.Contains(name)) + { + string searchPath = GetSearchPath("Shaders", name); + if (shaderSearchPaths.Contains(searchPath)) + data["GENERAL"]["EffectSearchPaths"] = shaderSearchPaths.Remove(shaderSearchPaths.IndexOf(searchPath), searchPath.Length); + } + + if (textureSearchPaths.Contains(name)) + { + string searchPath = GetSearchPath("Textures", name); + if (textureSearchPaths.Contains(searchPath)) + data["GENERAL"]["TextureSearchPaths"] = textureSearchPaths.Remove(textureSearchPaths.IndexOf(searchPath), searchPath.Length); + } + + parser.WriteFile(ConfigLocation, data); + } + + public static async Task InstallExtraviPresets() + { + App.Logger.WriteLine("[ReShade::InstallExtraviPresets] Installing Extravi's presets..."); + + foreach (string name in ExtraviPresetsShaders) + await DownloadShaders(name); + + byte[] bytes = await App.HttpClient.GetByteArrayAsync($"{BaseUrl}/reshade-presets.zip"); + + using MemoryStream zipStream = new(bytes); + using ZipArchive archive = new(zipStream); + + foreach (ZipArchiveEntry entry in archive.Entries) + { + if (entry.FullName.EndsWith('/')) + continue; + + // remove containing folder + string filename = entry.FullName.Substring(entry.FullName.IndexOf('/') + 1); + + await Task.Run(() => entry.ExtractToFile(Path.Combine(PresetsFolder, filename), true)); + } + } + + public static void UninstallExtraviPresets() + { + if (!Directory.Exists(PresetsFolder)) + return; + + App.Logger.WriteLine("[ReShade::UninstallExtraviPresets] Uninstalling Extravi's ReShade presets..."); + + FileInfo[] presets = new DirectoryInfo(PresetsFolder).GetFiles(); + + foreach (FileInfo preset in presets) + { + if (preset.Name.StartsWith("Extravi")) + preset.Delete(); + } + + foreach (string name in ExtraviPresetsShaders) + DeleteShaders(name); + } + + public static async Task CheckModifications() + { + App.Logger.WriteLine("[ReShade::CheckModifications] Checking ReShade modifications..."); + + string injectorLocation = Path.Combine(Directories.Modifications, "dxgi.dll"); + + if (!App.Settings.Prop.UseReShadeExtraviPresets && !string.IsNullOrEmpty(App.State.Prop.ExtraviReShadePresetsVersion)) + { + if (Utilities.CheckIfRobloxRunning()) + return; + + UninstallExtraviPresets(); + + App.State.Prop.ExtraviReShadePresetsVersion = ""; + App.State.Save(); + } + + if (!App.Settings.Prop.UseReShade) + { + if (Utilities.CheckIfRobloxRunning()) + return; + + App.Logger.WriteLine("[ReShade::CheckModifications] ReShade is not enabled"); + + // we should already be uninstalled + // we want to ensure this is done one-time only as this could possibly interfere with other rendering hooks using dxgi.dll + if (string.IsNullOrEmpty(App.State.Prop.ReShadeConfigVersion)) + return; + + App.Logger.WriteLine("[ReShade::CheckModifications] Uninstalling ReShade..."); + + // delete any stock config files + File.Delete(injectorLocation); + File.Delete(ConfigLocation); + + if (Directory.Exists(BaseDirectory)) + Directory.Delete(BaseDirectory, true); + + App.State.Prop.ReShadeConfigVersion = ""; + App.State.Save(); + + return; + } + + // the version manfiest contains the version of reshade available for download and the last date the presets were updated + var versionManifest = await Utilities.GetJson("https://raw.githubusercontent.com/Extravi/extravi.github.io/main/update/version.json"); + bool shouldFetchReShade = false; + bool shouldFetchConfig = false; + + if (!File.Exists(injectorLocation)) + { + shouldFetchReShade = true; + } + else if (versionManifest is not null) + { + // check if an update for reshade is available + FileVersionInfo injectorVersionInfo = FileVersionInfo.GetVersionInfo(injectorLocation); + + if (injectorVersionInfo.ProductVersion != versionManifest.ReShade) + shouldFetchReShade = true; + + // UPDATE CHECK - if we're upgrading to reshade 5.7.0, or we have extravi's presets + // enabled with a known shader downloaded (like AlucardDH) but without stormshade downloaded (5.7.0+ specific), + // we need to redownload all our shaders fresh + if ( + injectorVersionInfo.ProductVersion != versionManifest.ReShade && versionManifest.ReShade == "5.7.0" || + App.Settings.Prop.UseReShadeExtraviPresets && Directory.Exists(Path.Combine(ShadersFolder, "AlucardDH")) && !Directory.Exists(Path.Combine(ShadersFolder, "Stormshade")) + ) + { + Directory.Delete(ShadersFolder, true); + Directory.Delete(TexturesFolder, true); + App.State.Prop.ExtraviReShadePresetsVersion = ""; + App.Logger.WriteLine("[ReShade::CheckModifications] Upgrading to ReShade 5.7.0 - redownloading all shaders!"); + } + } + else + { + App.Logger.WriteLine("[ReShade::CheckModifications] versionManifest is null!"); + } + + // we're about to download - initialize directories + Directory.CreateDirectory(BaseDirectory); + Directory.CreateDirectory(FontsFolder); + Directory.CreateDirectory(ShadersFolder); + Directory.CreateDirectory(TexturesFolder); + Directory.CreateDirectory(PresetsFolder); + + // check if we should download a fresh copy of the config + // extravi may need to update the config ota, in which case we'll redownload it + if (!File.Exists(ConfigLocation) || versionManifest is not null && App.State.Prop.ReShadeConfigVersion != versionManifest.ConfigFile) + shouldFetchConfig = true; + + if (shouldFetchReShade) + { + App.Logger.WriteLine("[ReShade::CheckModifications] Installing/Upgrading ReShade..."); + + { + byte[] bytes = await App.HttpClient.GetByteArrayAsync($"{BaseUrl}/dxgi.zip"); + using MemoryStream zipStream = new(bytes); + using ZipArchive archive = new(zipStream); + archive.ExtractToDirectory(Directories.Modifications, true); + } + } + + if (shouldFetchConfig) + { + await DownloadConfig(); + + if (versionManifest is not null) + { + App.State.Prop.ReShadeConfigVersion = versionManifest.ConfigFile; + App.State.Save(); + } + } + + await DownloadShaders("Stock"); + + if (App.Settings.Prop.UseReShadeExtraviPresets && App.State.Prop.ExtraviReShadePresetsVersion != versionManifest!.Presets) + { + await InstallExtraviPresets(); + App.State.Prop.ExtraviReShadePresetsVersion = versionManifest.Presets; + App.State.Save(); + } + + SynchronizeConfigFile(); + } + } +} diff --git a/Bloxstrap/Models/ReShadeShaderConfig.cs b/Bloxstrap/Models/ReShadeShaderConfig.cs new file mode 100644 index 0000000..5ecda89 --- /dev/null +++ b/Bloxstrap/Models/ReShadeShaderConfig.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Bloxstrap.Models +{ + public class ReShadeShaderConfig + { + // it's assumed that the BaseFolder has a "Textures" folder and a "Shaders" folder + // the files listed in ExcludedFiles are relative to the BaseFolder + + public string Name { get; set; } = null!; + public string DownloadLocation { get; set; } = null!; + public string BaseFolder { get; set; } = "/"; + public List ExcludedFiles { get; set; } = new List(); + + public override string ToString() => Name; + } +} diff --git a/Bloxstrap/Models/ReShadeVersionManifest.cs b/Bloxstrap/Models/ReShadeVersionManifest.cs new file mode 100644 index 0000000..9110bf3 --- /dev/null +++ b/Bloxstrap/Models/ReShadeVersionManifest.cs @@ -0,0 +1,9 @@ +namespace Bloxstrap.Models +{ + public class ReShadeVersionManifest + { + public string ReShade { get; set; } = null!; + public string Presets { get; set; } = null!; + public string ConfigFile { get; set; } = null!; + } +} diff --git a/Bloxstrap/Models/Settings.cs b/Bloxstrap/Models/Settings.cs index dc274fc..95b1b8e 100644 --- a/Bloxstrap/Models/Settings.cs +++ b/Bloxstrap/Models/Settings.cs @@ -25,6 +25,8 @@ namespace Bloxstrap.Models // integration configuration public bool UseDiscordRichPresence { get; set; } = true; public bool HideRPCButtons { get; set; } = true; + public bool UseReShade { get; set; } = true; + public bool UseReShadeExtraviPresets { get; set; } = true; public bool ShowServerDetails { get; set; } = false; public ObservableCollection CustomIntegrations { get; set; } = new(); diff --git a/Bloxstrap/Models/State.cs b/Bloxstrap/Models/State.cs index 3fb6648..be8c221 100644 --- a/Bloxstrap/Models/State.cs +++ b/Bloxstrap/Models/State.cs @@ -9,7 +9,8 @@ namespace Bloxstrap.Models public class State { public string VersionGuid { get; set; } = ""; - public bool HadReShadeInstalled { get; set; } = false; + public string ReShadeConfigVersion { get; set; } = ""; + public string ExtraviReShadePresetsVersion { get; set; } = ""; public List ModManifest { get; set; } = new(); } } diff --git a/Bloxstrap/ViewModels/IntegrationsViewModel.cs b/Bloxstrap/ViewModels/IntegrationsViewModel.cs index f5da011..d097c9d 100644 --- a/Bloxstrap/ViewModels/IntegrationsViewModel.cs +++ b/Bloxstrap/ViewModels/IntegrationsViewModel.cs @@ -15,9 +15,17 @@ namespace Bloxstrap.ViewModels public event PropertyChangedEventHandler? PropertyChanged; public void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + public ICommand OpenReShadeFolderCommand => new RelayCommand(OpenReShadeFolder); public ICommand AddIntegrationCommand => new RelayCommand(AddIntegration); public ICommand DeleteIntegrationCommand => new RelayCommand(DeleteIntegration); + public bool CanOpenReShadeFolder => App.Settings.Prop.UseReShade; + + private void OpenReShadeFolder() + { + Process.Start("explorer.exe", Path.Combine(Directories.Integrations, "ReShade")); + } + private void AddIntegration() { CustomIntegrations.Add(new CustomIntegration() @@ -68,6 +76,27 @@ namespace Bloxstrap.ViewModels set => App.Settings.Prop.HideRPCButtons = !value; } + public bool ReShadeEnabled + { + get => App.Settings.Prop.UseReShade; + set + { + App.Settings.Prop.UseReShade = value; + ReShadePresetsEnabled = value; + + if (value) + App.FastFlags.SetRenderingMode("Direct3D 11"); + + OnPropertyChanged(nameof(ReShadePresetsEnabled)); + } + } + + public bool ReShadePresetsEnabled + { + get => App.Settings.Prop.UseReShadeExtraviPresets; + set => App.Settings.Prop.UseReShadeExtraviPresets = value; + } + public bool ShowServerDetailsEnabled { get => App.Settings.Prop.ShowServerDetails; diff --git a/Bloxstrap/Views/Pages/AboutPage.xaml b/Bloxstrap/Views/Pages/AboutPage.xaml index e0235f6..8130c33 100644 --- a/Bloxstrap/Views/Pages/AboutPage.xaml +++ b/Bloxstrap/Views/Pages/AboutPage.xaml @@ -83,6 +83,8 @@ + + @@ -109,18 +111,32 @@ - + + + + + + + - + + + + + + + + + diff --git a/Bloxstrap/Views/Pages/IntegrationsPage.xaml b/Bloxstrap/Views/Pages/IntegrationsPage.xaml index c4229b3..a204986 100644 --- a/Bloxstrap/Views/Pages/IntegrationsPage.xaml +++ b/Bloxstrap/Views/Pages/IntegrationsPage.xaml @@ -33,6 +33,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Bloxstrap/Views/Pages/ModsPage.xaml b/Bloxstrap/Views/Pages/ModsPage.xaml index e30be22..c6360f4 100644 --- a/Bloxstrap/Views/Pages/ModsPage.xaml +++ b/Bloxstrap/Views/Pages/ModsPage.xaml @@ -117,7 +117,7 @@ - + From 2b8d850c046fff653a2357870de3e1b696256c95 Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Fri, 21 Apr 2023 11:56:25 +0100 Subject: [PATCH 22/24] Revert "Make Mods the default page" This reverts commit d30aff867a30f86b43c725e7d8c014b0183e1037. --- Bloxstrap/Views/MainWindow.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bloxstrap/Views/MainWindow.xaml b/Bloxstrap/Views/MainWindow.xaml index fecc153..18b037b 100644 --- a/Bloxstrap/Views/MainWindow.xaml +++ b/Bloxstrap/Views/MainWindow.xaml @@ -41,8 +41,8 @@ - + From 3b7a363aa06cbc851e9c3500b279cae0393e6d36 Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Fri, 21 Apr 2023 13:25:28 +0100 Subject: [PATCH 23/24] Auto switch to LIVE if using ReShade --- Bloxstrap/App.xaml.cs | 4 +++ Bloxstrap/Helpers/DeployManager.cs | 2 +- Bloxstrap/Integrations/ReShade.cs | 37 ++++++++++++++++++--- Bloxstrap/Views/Pages/BehaviourPage.xaml | 4 +-- Bloxstrap/Views/Pages/IntegrationsPage.xaml | 11 +++++- 5 files changed, 50 insertions(+), 8 deletions(-) diff --git a/Bloxstrap/App.xaml.cs b/Bloxstrap/App.xaml.cs index 6446109..2954958 100644 --- a/Bloxstrap/App.xaml.cs +++ b/Bloxstrap/App.xaml.cs @@ -16,6 +16,7 @@ using Microsoft.Win32; using Bloxstrap.Dialogs; using Bloxstrap.Enums; using Bloxstrap.Helpers; +using Bloxstrap.Integrations; using Bloxstrap.Models; using Bloxstrap.Views; @@ -262,6 +263,9 @@ namespace Bloxstrap DeployManager.Channel = Settings.Prop.Channel; + if (Settings.Prop.UseReShade) + ReShade.CheckRobloxReleaseChannel().Wait(); + // start bootstrapper and show the bootstrapper modal if we're not running silently Logger.WriteLine($"[App::OnStartup] Initializing bootstrapper"); Bootstrapper bootstrapper = new(commandLine); diff --git a/Bloxstrap/Helpers/DeployManager.cs b/Bloxstrap/Helpers/DeployManager.cs index 2f88c9d..c87534d 100644 --- a/Bloxstrap/Helpers/DeployManager.cs +++ b/Bloxstrap/Helpers/DeployManager.cs @@ -94,7 +94,7 @@ namespace Bloxstrap.Helpers { App.Logger.WriteLine($"[DeployManager::GetLastDeploy] Getting deploy info for channel {Channel} (timestamp={timestamp})"); - HttpResponseMessage deployInfoResponse = await App.HttpClient.GetAsync($"https://clientsettings.roblox.com/v2/client-version/WindowsPlayer/channel/{Channel}"); + HttpResponseMessage deployInfoResponse = await App.HttpClient.GetAsync($"https://clientsettings.roblox.com/v2/client-version/WindowsPlayer/channel/{Channel}").ConfigureAwait(false); string rawResponse = await deployInfoResponse.Content.ReadAsStringAsync(); diff --git a/Bloxstrap/Integrations/ReShade.cs b/Bloxstrap/Integrations/ReShade.cs index 5931f1e..1a541aa 100644 --- a/Bloxstrap/Integrations/ReShade.cs +++ b/Bloxstrap/Integrations/ReShade.cs @@ -1,14 +1,13 @@ using System; -using System.Collections; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Linq; using System.Threading.Tasks; -using Bloxstrap.Helpers; +using System.Windows; +using Bloxstrap.Helpers; using Bloxstrap.Models; using IniParser; @@ -501,5 +500,35 @@ namespace Bloxstrap.Integrations SynchronizeConfigFile(); } - } + + public static async Task CheckRobloxReleaseChannel() + { + App.Logger.WriteLine($"[ReShade::CheckRobloxReleaseChannel] Checking current Roblox release channel ({App.Settings.Prop.Channel})..."); + + if (App.Settings.Prop.Channel.ToLower() == DeployManager.DefaultChannel.ToLower()) + { + App.Logger.WriteLine($"[App::OnStartup] Channel is already {DeployManager.DefaultChannel}"); + return; + } + + ClientVersion versionInfo = await App.DeployManager.GetLastDeploy().ConfigureAwait(false); + string manifest = await App.HttpClient.GetStringAsync($"{App.DeployManager.BaseUrl}/{versionInfo.VersionGuid}-rbxManifest.txt"); + + if (!manifest.Contains("RobloxPlayerBeta.dll")) + return; + + MessageBoxResult result = !App.Settings.Prop.PromptChannelChange ? MessageBoxResult.Yes : App.ShowMessageBox( + $"You currently have ReShade enabled, however your current preferred channel ({App.Settings.Prop.Channel}) does not support ReShade. Would you like to switch to {DeployManager.DefaultChannel}? ", + MessageBoxImage.Question, + MessageBoxButton.YesNo + ); + + if (result != MessageBoxResult.Yes) + return; + + App.Logger.WriteLine($"[App::OnStartup] Changed Roblox build channel from {App.Settings.Prop.Channel} to {DeployManager.DefaultChannel}"); + App.DeployManager.Channel = App.Settings.Prop.Channel = DeployManager.DefaultChannel; + } + + } } diff --git a/Bloxstrap/Views/Pages/BehaviourPage.xaml b/Bloxstrap/Views/Pages/BehaviourPage.xaml index 8b677b7..35ed8ff 100644 --- a/Bloxstrap/Views/Pages/BehaviourPage.xaml +++ b/Bloxstrap/Views/Pages/BehaviourPage.xaml @@ -43,8 +43,8 @@ - - + + diff --git a/Bloxstrap/Views/Pages/IntegrationsPage.xaml b/Bloxstrap/Views/Pages/IntegrationsPage.xaml index a204986..4800714 100644 --- a/Bloxstrap/Views/Pages/IntegrationsPage.xaml +++ b/Bloxstrap/Views/Pages/IntegrationsPage.xaml @@ -34,6 +34,15 @@ + + + + + + + + + @@ -106,7 +115,7 @@ - + From 89e76efe6cd649d92793052f27c64bfc1970df0f Mon Sep 17 00:00:00 2001 From: pizzaboxer Date: Fri, 21 Apr 2023 13:43:02 +0100 Subject: [PATCH 24/24] Revert "Update README.md" This reverts commit 4758c4ead9d48d2ad0291214d69e2a19ad9fce1e. --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index eb56650..3f4376a 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ If you want to build Bloxstrap's source code, see the [guide for building from s Here's some of the features that Bloxstrap provides over the stock Roblox bootstrapper: * Persistent file modifications - re-adds the old death sound! +* Support for shaders with [ReShade](https://reshade.me) and [Extravi's ReShade Presets](https://bloxshade.com/) * Painless support for Discord Rich Presence - no auth cookie needed! * Built-in FPS unlocking * A customizable launcher look - includes dark theme! @@ -44,11 +45,11 @@ Here's some of the features that Bloxstrap provides over the stock Roblox bootst All the available features are browsable through the Bloxstrap menu. There's not too many, but it's recommended to look through all of them. -Bloxstrap also has inherent benefits over some other Roblox mods, as it only runs whenever necessary, so it doesn't stay running in the background when you're not playing. +Bloxstrap also has inherent benefits over some other Roblox mods, as ReShade does not break whenever Roblox updates and thus require a reinstall, and is completely free, forever. It also only runs whenever necessary, so it doesn't stay running in the background when you're not playing. ## Screenshots

- +