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 | 264 +++++++++++++++++++++--------------------- 2 files changed, 136 insertions(+), 131 deletions(-) diff --git a/Bloxstrap/App.xaml b/Bloxstrap/App.xaml index 28b450ef..8f4642f9 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 fb76ee9a..e0286b0f 100644 --- a/Bloxstrap/App.xaml.cs +++ b/Bloxstrap/App.xaml.cs @@ -8,6 +8,8 @@ using System.Threading; using System.Threading.Tasks; using System.Windows; +using System.Windows.Threading; + using Microsoft.Win32; using Bloxstrap.Dialogs; @@ -77,34 +79,24 @@ private void InitLog() Logger.Initialize(Path.Combine(logdir, $"{ProjectName}_{timestamp}.log")); } - protected override void OnStartup(StartupEventArgs e) + void GlobalExceptionHandler(object sender, DispatcherUnhandledExceptionEventArgs e) { - base.OnStartup(e); + e.Handled = true; - Logger.WriteLine($"[App::OnStartup] Starting {ProjectName} v{Version}"); + Logger.WriteLine("[App::OnStartup] An exception occurred when running the main thread"); + Logger.WriteLine($"[App::OnStartup] {e.Exception}"); - // 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."; + if (!IsQuiet) + Settings.Prop.BootstrapperStyle.GetNew().ShowError($"{e.Exception.GetType()}: {e.Exception.Message}"); - // 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(); + Terminate(Bootstrapper.ERROR_INSTALL_FAILURE); + } - // 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."; + protected override void OnStartup(StartupEventArgs e) + { + base.OnStartup(e); - ShowMessageBox(message, MessageBoxImage.Warning); - } + Logger.WriteLine($"[App::OnStartup] Starting {ProjectName} v{Version}"); // To customize application configuration such as set high DPI settings or default font, // see https://aka.ms/applicationconfiguration. @@ -148,6 +140,29 @@ protected override void OnStartup(StartupEventArgs e) } } + // 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 @@ protected override void OnStartup(StartupEventArgs e) Settings.Load(); State.Load(); } + #if !DEBUG - try - { - if (!IsUninstall && !IsFirstRun) - Updater.CheckInstalledVersion(); + if (!IsUninstall && !IsFirstRun) + Updater.CheckInstalledVersion(); #endif - string commandLine = ""; + string commandLine = ""; - if (IsMenuLaunch) - { - Mutex mutex; + if (IsMenuLaunch) + { + 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"); - } + 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); + 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(); + new MainWindow().ShowDialog(); + FastFlags.Save(); + } + else if (LaunchArgs.Length > 0) + { + if (LaunchArgs[0].StartsWith("roblox-player:")) + { + commandLine = Protocol.ParseUri(LaunchArgs[0]); } - else if (LaunchArgs.Length > 0) + else if (LaunchArgs[0].StartsWith("roblox:")) { - 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"; - } + commandLine = $"--app --deeplink {LaunchArgs[0]}"; } else { commandLine = "--app"; } + } + else + { + commandLine = "--app"; + } - if (!String.IsNullOrEmpty(commandLine)) - { - if (!IsFirstRun) - ShouldSaveConfigs = true; + if (!String.IsNullOrEmpty(commandLine)) + { + if (!IsFirstRun) + ShouldSaveConfigs = true; - DeployManager.SetChannel(Settings.Prop.Channel); + 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; + // 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; - } + 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 - // 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; - Mutex? singletonMutex = null; + if (Settings.Prop.MultiInstanceLaunching) + { + Logger.WriteLine("[App::OnStartup] Creating singleton mutex"); - if (Settings.Prop.MultiInstanceLaunching) + try { - 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"); - } + Mutex.OpenExisting("ROBLOX_singletonMutex"); + Logger.WriteLine("[App::OnStartup] Warning - singleton mutex already exists!"); } - - // 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 => + catch { - Logger.WriteLine("[App::OnStartup] Bootstrapper task has finished"); + // 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.IsFaulted) + Logger.WriteLine("[App::OnStartup] An exception occurred when running the bootstrapper"); - if (t.Exception is null) - return; + if (t.Exception is null) + return; - Logger.WriteLine($"[App::OnStartup] {t.Exception}"); + Logger.WriteLine($"[App::OnStartup] {t.Exception}"); #if DEBUG - throw t.Exception; + throw t.Exception; #else - var exception = t.Exception.InnerExceptions.Count >= 1 ? t.Exception.InnerExceptions[0] : t.Exception; - dialog?.ShowError($"{exception.GetType()}: {exception.Message}"); + 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(); - 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"); - if (singletonMutex is not null) + // 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) { - 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); - } + Thread.Sleep(5000); } } -#if !DEBUG - } - catch (Exception ex) - { - Logger.WriteLine("[App::OnStartup] An exception occurred when running the main thread"); - Logger.WriteLine($"[App::OnStartup] {ex}"); - - if (!IsQuiet) - Settings.Prop.BootstrapperStyle.GetNew().ShowError($"{ex.GetType()}: {ex.Message}"); } -#endif 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 320a9c86..818085f3 100644 --- a/Bloxstrap/ViewModels/AppearanceViewModel.cs +++ b/Bloxstrap/ViewModels/AppearanceViewModel.cs @@ -118,7 +118,10 @@ public string CustomIconLocation 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 | 14 ++++++------ 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/Bloxstrap/Helpers/FastFlagManager.cs b/Bloxstrap/Helpers/FastFlagManager.cs index 3fb2da54..b23b8a6e 100644 --- a/Bloxstrap/Helpers/FastFlagManager.cs +++ b/Bloxstrap/Helpers/FastFlagManager.cs @@ -23,10 +23,23 @@ public class FastFlagManager : JsonManager> { "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 @@ public void SetRenderingMode(string value) 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 @@ public override void Save() 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 7467c803..c756ef84 100644 --- a/Bloxstrap/ViewModels/ModsViewModel.cs +++ b/Bloxstrap/ViewModels/ModsViewModel.cs @@ -39,22 +39,6 @@ public bool DisableAppPatchEnabled 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 @@ public string SelectedRenderingMode 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 cf1610b0..37619c6d 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"> @@ -104,20 +104,20 @@ - - + + - + - - + + - + 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 b23b8a6e..7558aa2e 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 @@ public void SetRenderingMode(string value) 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 fb59f7d2..dde78516 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 c756ef84..10f9b1a6 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 @@ public bool DisableAppPatchEnabled 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 @@ public bool ExclusiveFullscreenEnabled 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 37619c6d..29e0a25b 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 b5c7e43b..76fd5c36 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 @@ public ModsPage() 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 e0286b0f..bc11e55d 100644 --- a/Bloxstrap/App.xaml.cs +++ b/Bloxstrap/App.xaml.cs @@ -235,7 +235,6 @@ protected override void OnStartup(StartupEventArgs e) 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 261548ad..259c3f84 100644 --- a/Bloxstrap/ViewModels/MainWindowViewModel.cs +++ b/Bloxstrap/ViewModels/MainWindowViewModel.cs @@ -60,6 +60,7 @@ private void ConfirmSettings() 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 b9bc1073..8013ab9b 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -170,7 +170,7 @@ public async Task Run() CheckInstall(); - await RbxFpsUnlocker.CheckInstall(); + IntegrationMigrator.Execute(); // at this point we've finished updating our configs App.Settings.Save(); @@ -353,25 +353,6 @@ private async Task StartRoblox() 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 7558aa2e..13417314 100644 --- a/Bloxstrap/Helpers/FastFlagManager.cs +++ b/Bloxstrap/Helpers/FastFlagManager.cs @@ -71,7 +71,12 @@ public override void Load() // 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 00000000..4d3b4f7f --- /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 bb568862..00000000 --- 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 a8e96b64..95b1b8ef 100644 --- a/Bloxstrap/Models/Settings.cs +++ b/Bloxstrap/Models/Settings.cs @@ -25,8 +25,6 @@ public class Settings // 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 fcc2d7cd..be8c2214 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 e242d815..ca876b2d 100644 --- a/Bloxstrap/ViewModels/IntegrationsViewModel.cs +++ b/Bloxstrap/ViewModels/IntegrationsViewModel.cs @@ -97,23 +97,6 @@ public bool ReShadePresetsEnabled 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 2a31eeed..8130c336 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 8aebf4fe..a2049868 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 c4066ab1..5809833b 100644 --- a/Bloxstrap/Views/Pages/IntegrationsPage.xaml.cs +++ b/Bloxstrap/Views/Pages/IntegrationsPage.xaml.cs @@ -15,10 +15,6 @@ public IntegrationsPage() { 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 29e0a25b..1c19abcc 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 8013ab9b..41cd7c8d 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -68,6 +68,7 @@ public class Bootstrapper 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 @@ public async Task Run() 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 @@ public async Task Run() _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 @@ public async Task Run() CheckInstall(); - IntegrationMigrator.Execute(); - // at this point we've finished updating our configs App.Settings.Save(); App.State.Save(); @@ -336,7 +336,7 @@ private async Task StartRoblox() // 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 @@ private async Task InstallLatestVersion() 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 @@ private async Task ApplyModifications() 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 13417314..170e6b95 100644 --- a/Bloxstrap/Helpers/FastFlagManager.cs +++ b/Bloxstrap/Helpers/FastFlagManager.cs @@ -69,29 +69,24 @@ public override void Load() { 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 4d3b4f7f..e0737190 100644 --- a/Bloxstrap/Helpers/IntegrationMigrator.cs +++ b/Bloxstrap/Helpers/IntegrationMigrator.cs @@ -6,8 +6,6 @@ static class IntegrationMigrator { 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 bc11e55d..faf6167f 100644 --- a/Bloxstrap/App.xaml.cs +++ b/Bloxstrap/App.xaml.cs @@ -173,9 +173,6 @@ protected override void OnStartup(StartupEventArgs e) 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 170e6b95..a4ab45f8 100644 --- a/Bloxstrap/Helpers/FastFlagManager.cs +++ b/Bloxstrap/Helpers/FastFlagManager.cs @@ -72,6 +72,10 @@ public override void Load() // 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 c36636e9..c9c1ebea 100644 --- a/Bloxstrap/Helpers/Updater.cs +++ b/Bloxstrap/Helpers/Updater.cs @@ -78,14 +78,6 @@ public static void CheckInstalledVersion() 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 10f9b1a6..db8b2f7b 100644 --- a/Bloxstrap/ViewModels/ModsViewModel.cs +++ b/Bloxstrap/ViewModels/ModsViewModel.cs @@ -15,10 +15,7 @@ public class ModsViewModel : INotifyPropertyChanged 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 @@ public bool DisableAppPatchEnabled 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 @@ public bool ExclusiveFullscreenEnabled 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 76fd5c36..704448ea 100644 --- a/Bloxstrap/Views/Pages/ModsPage.xaml.cs +++ b/Bloxstrap/Views/Pages/ModsPage.xaml.cs @@ -13,8 +13,7 @@ public partial class ModsPage { 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 db8b2f7b..c5a88b13 100644 --- a/Bloxstrap/ViewModels/ModsViewModel.cs +++ b/Bloxstrap/ViewModels/ModsViewModel.cs @@ -75,6 +75,12 @@ public bool ExclusiveFullscreenEnabled } } + 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 1c19abcc..7e3b1724 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 96078704..86cee6d0 100644 --- a/Bloxstrap/ViewModels/InstallationViewModel.cs +++ b/Bloxstrap/ViewModels/InstallationViewModel.cs @@ -76,7 +76,13 @@ public string InstallLocation 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 @@ public bool ShowAllChannels 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 a4ab45f8..ce87d3e1 100644 --- a/Bloxstrap/Helpers/FastFlagManager.cs +++ b/Bloxstrap/Helpers/FastFlagManager.cs @@ -16,7 +16,7 @@ public class FastFlagManager : JsonManager> 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 @@ public class FastFlagManager : JsonManager> { "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 c5a88b13..52d21e58 100644 --- a/Bloxstrap/ViewModels/ModsViewModel.cs +++ b/Bloxstrap/ViewModels/ModsViewModel.cs @@ -35,14 +35,14 @@ public bool DisableAppPatchEnabled 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 @@ public bool ExclusiveFullscreenEnabled } } + 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 7e3b1724..107515a8 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 | 29 ++---- Bloxstrap/ViewModels/InstallationViewModel.cs | 88 +++++++++---------- Bloxstrap/Views/Pages/InstallationPage.xaml | 7 +- Bloxstrap/Views/Pages/ModsPage.xaml | 2 +- 4 files changed, 50 insertions(+), 76 deletions(-) diff --git a/Bloxstrap/Helpers/DeployManager.cs b/Bloxstrap/Helpers/DeployManager.cs index 40d01656..77f8b771 100644 --- a/Bloxstrap/Helpers/DeployManager.cs +++ b/Bloxstrap/Helpers/DeployManager.cs @@ -19,35 +19,16 @@ public class DeployManager 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", + "ZFlag", "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" + "ZAvatarTeam", + "ZSocialTeam" }; #endregion diff --git a/Bloxstrap/ViewModels/InstallationViewModel.cs b/Bloxstrap/ViewModels/InstallationViewModel.cs index 86cee6d0..81e40d5f 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 @@ public class InstallationViewModel : INotifyPropertyChanged 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 @@ public InstallationViewModel() 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 @@ public string InstallLocation 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 6142e79e..a67d2562 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 107515a8..c6360f4e 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 faf6167f..cf814920 100644 --- a/Bloxstrap/App.xaml.cs +++ b/Bloxstrap/App.xaml.cs @@ -258,7 +258,7 @@ protected override void OnStartup(StartupEventArgs e) 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 77f8b771..a745cd76 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 @@ public class DeployManager }; #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 81e40d5f..f72f01ec 100644 --- a/Bloxstrap/ViewModels/InstallationViewModel.cs +++ b/Bloxstrap/ViewModels/InstallationViewModel.cs @@ -39,7 +39,7 @@ private async Task LoadChannelDeployInfo(string channel) 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 184539f8..d3e7baa6 100644 --- a/Bloxstrap/Bloxstrap.csproj +++ b/Bloxstrap/Bloxstrap.csproj @@ -25,7 +25,6 @@ - diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index 7d834f94..bab2eade 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -181,11 +181,6 @@ public async Task Run() 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 @@ private async Task InstallLatestVersion() 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 @@ private async Task ApplyModifications() 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 ce87d3e1..76b676bc 100644 --- a/Bloxstrap/Helpers/FastFlagManager.cs +++ b/Bloxstrap/Helpers/FastFlagManager.cs @@ -113,8 +113,8 @@ public override void Load() 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 e0737190..a73ecf08 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 @@ public static void Execute() 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 5931f1ee..00000000 --- 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 5ecda898..00000000 --- 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 9110bf34..00000000 --- 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 95b1b8ef..dc274fcc 100644 --- a/Bloxstrap/Models/Settings.cs +++ b/Bloxstrap/Models/Settings.cs @@ -25,8 +25,6 @@ public class Settings // 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 be8c2214..f1eb02e5 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 ca876b2d..f5da0115 100644 --- a/Bloxstrap/ViewModels/IntegrationsViewModel.cs +++ b/Bloxstrap/ViewModels/IntegrationsViewModel.cs @@ -15,17 +15,9 @@ public class IntegrationsViewModel : INotifyPropertyChanged 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 @@ public bool DiscordActivityJoinEnabled 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 8130c336..e0235f66 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 a2049868..c4229b32 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 c6360f4e..e30be22e 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 cf814920..cfc62ffa 100644 --- a/Bloxstrap/App.xaml.cs +++ b/Bloxstrap/App.xaml.cs @@ -163,6 +163,9 @@ protected override void OnStartup(StartupEventArgs e) 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 bab2eade..948fb53f 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -117,6 +117,19 @@ private void SetStatus(string message) 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 @@ public async Task Run() 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 @@ public async Task Run() 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 @@ private async Task CheckLatestVersion() _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 @@ public void CancelInstall() App.Terminate(ERROR_INSTALL_USEREXIT); } -#endregion + #endregion #region App Install public static void Register() @@ -497,6 +393,69 @@ public static void Register() 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 @@ public static void CheckInstall() } } + 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 @@ private void Uninstall() 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 @@ private async Task InstallWebView2() 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 @@ private void ExtractFileFromPackage(string packageName, string fileName) entry.ExtractToFile(fileLocation); } -#endregion + #endregion } } diff --git a/Bloxstrap/Helpers/IntegrationMigrator.cs b/Bloxstrap/Helpers/IntegrationMigrator.cs deleted file mode 100644 index a73ecf08..00000000 --- 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 704448ea..e3c3b730 100644 --- a/Bloxstrap/Views/Pages/ModsPage.xaml.cs +++ b/Bloxstrap/Views/Pages/ModsPage.xaml.cs @@ -13,8 +13,6 @@ public partial class ModsPage { 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 cfc62ffa..fac80547 100644 --- a/Bloxstrap/App.xaml.cs +++ b/Bloxstrap/App.xaml.cs @@ -163,9 +163,6 @@ protected override void OnStartup(StartupEventArgs e) 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 @@ protected override void OnStartup(StartupEventArgs e) if (!IsQuiet) { IsSetupComplete = false; + FastFlags.Load(); new MainWindow().ShowDialog(); } } @@ -197,7 +195,7 @@ protected override void OnStartup(StartupEventArgs e) } 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 948fb53f..35e7281d 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -62,11 +62,11 @@ public class Bootstrapper }; 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 @@ public class Bootstrapper 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 @@ public class Bootstrapper #endregion #region Core - public Bootstrapper(string? launchCommandLine = null) + public Bootstrapper(string launchCommandLine) { _launchCommandLine = launchCommandLine; @@ -226,8 +226,6 @@ private async Task CheckLatestVersion() private async Task StartRoblox() { - string startEventName = App.ProjectName.Replace(" ", "") + "StartEvent"; - SetStatus("Starting Roblox..."); if (_launchCommandLine == "--app" && App.Settings.Prop.UseDisableAppPatch) @@ -237,14 +235,11 @@ private async Task StartRoblox() 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 @@ private async Task StartRoblox() 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 dde78516..ef39f9c5 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 8524566d..70c56b3e 100644 --- a/Bloxstrap/Helpers/Protocol.cs +++ b/Bloxstrap/Helpers/Protocol.cs @@ -18,7 +18,7 @@ public class Protocol { "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 @@ public static string ParseUri(string protocol) 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 35e7281d..ae01a8ac 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -243,13 +243,19 @@ private async Task StartRoblox() // 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 @@ private async Task StartRoblox() 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 fac80547..64461090 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 @@ protected override void OnStartup(StartupEventArgs e) // 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 d3e7baa6..bec8aa9c 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 ae01a8ac..52aa7077 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -247,7 +247,7 @@ private async Task StartRoblox() int gameClientPid; using (Process gameClient = Process.Start(_playerLocation, _launchCommandLine)) { - gameClientPid = gameClient.Id; + gameClientPid = gameClient.Id; } List autocloseProcesses = new(); @@ -819,6 +819,9 @@ public static void MigrateIntegrations() 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 a745cd76..2f88c9d6 100644 --- a/Bloxstrap/Helpers/DeployManager.cs +++ b/Bloxstrap/Helpers/DeployManager.cs @@ -80,6 +80,7 @@ public string BaseUrl public static readonly List SelectableChannels = new() { "LIVE", + "ZWinPlayer64", "ZFlag", "ZNext", "ZCanary", diff --git a/Bloxstrap/Models/State.cs b/Bloxstrap/Models/State.cs index f1eb02e5..3fb66487 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 a5500fe6..eb566502 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 18b037b8..fecc153e 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 bec8aa9c..c1d35ef1 100644 --- a/Bloxstrap/Bloxstrap.csproj +++ b/Bloxstrap/Bloxstrap.csproj @@ -25,6 +25,7 @@ + diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index 52aa7077..63bfa486 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -193,6 +193,11 @@ public async Task Run() 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 @@ private async Task InstallLatestVersion() 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 @@ public static void MigrateIntegrations() 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 @@ private async Task ApplyModifications() 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 76b676bc..ce87d3e1 100644 --- a/Bloxstrap/Helpers/FastFlagManager.cs +++ b/Bloxstrap/Helpers/FastFlagManager.cs @@ -113,8 +113,8 @@ public override void Load() 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 00000000..5931f1ee --- /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 00000000..5ecda898 --- /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 00000000..9110bf34 --- /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 dc274fcc..95b1b8ef 100644 --- a/Bloxstrap/Models/Settings.cs +++ b/Bloxstrap/Models/Settings.cs @@ -25,6 +25,8 @@ public class Settings // 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 3fb66487..be8c2214 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 f5da0115..d097c9d3 100644 --- a/Bloxstrap/ViewModels/IntegrationsViewModel.cs +++ b/Bloxstrap/ViewModels/IntegrationsViewModel.cs @@ -15,9 +15,17 @@ public class IntegrationsViewModel : INotifyPropertyChanged 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 @@ public bool DiscordActivityJoinEnabled 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 e0235f66..8130c336 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 c4229b32..a2049868 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 e30be22e..c6360f4e 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 fecc153e..18b037b8 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 64461090..29549584 100644 --- a/Bloxstrap/App.xaml.cs +++ b/Bloxstrap/App.xaml.cs @@ -16,6 +16,7 @@ using Bloxstrap.Dialogs; using Bloxstrap.Enums; using Bloxstrap.Helpers; +using Bloxstrap.Integrations; using Bloxstrap.Models; using Bloxstrap.Views; @@ -262,6 +263,9 @@ protected override void OnStartup(StartupEventArgs e) 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 2f88c9d6..c87534d0 100644 --- a/Bloxstrap/Helpers/DeployManager.cs +++ b/Bloxstrap/Helpers/DeployManager.cs @@ -94,7 +94,7 @@ public async Task GetLastDeploy(bool timestamp = false) { 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 5931f1ee..1a541aa2 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 @@ public static async Task CheckModifications() 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 8b677b7e..35ed8ff8 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 a2049868..4800714d 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 eb566502..3f4376ac 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

- +