diff --git a/Bloxstrap/Bloxstrap.csproj b/Bloxstrap/Bloxstrap.csproj index bec8aa9..c1d35ef 100644 --- a/Bloxstrap/Bloxstrap.csproj +++ b/Bloxstrap/Bloxstrap.csproj @@ -25,6 +25,7 @@ + diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index 52aa707..63bfa48 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -193,6 +193,11 @@ namespace Bloxstrap if (ShouldInstallWebView2) await InstallWebView2(); + if (App.Settings.Prop.UseReShade) + SetStatus("Configuring/Downloading ReShade..."); + + await ReShade.CheckModifications(); + App.FastFlags.Save(); await ApplyModifications(); @@ -719,6 +724,8 @@ namespace Bloxstrap if (!FreshInstall) { + ReShade.SynchronizeConfigFile(); + // let's take this opportunity to delete any packages we don't need anymore foreach (string filename in Directory.GetFiles(Directories.Downloads)) { @@ -803,26 +810,6 @@ namespace Bloxstrap if (Directory.Exists(rbxfpsunlocker)) Directory.Delete(rbxfpsunlocker, true); - - // v2.2.0 - remove reshade - string reshadeLocation = Path.Combine(Directories.Modifications, "dxgi.dll"); - - if (File.Exists(reshadeLocation)) - { - App.ShowMessageBox( - "As of April 18th, Roblox has started out rolling out the Byfron anticheat as well as 64-bit support. Because of this, ReShade will no longer work, and will be deactivated from now on.\n\n" + - $"Your ReShade configs and files will still be kept, which are all located in the {App.ProjectName} folder.", - MessageBoxImage.Warning - ); - - File.Delete(reshadeLocation); - - if (App.FastFlags.GetValue(FastFlagManager.RenderingModes["Direct3D 11"]) == "True" && App.FastFlags.GetValue("FFlagHandleAltEnterFullscreenManually") != "False") - App.FastFlags.SetRenderingMode("Automatic"); - - // this is just in case something ever changes, i doubt it but lol - App.State.Prop.HadReShadeInstalled = true; - } } private async Task ApplyModifications() @@ -920,7 +907,7 @@ namespace Bloxstrap try { - packageDirectory = PackageDirectories.First(x => x.Key != "RobloxApp.zip" && x.Key != "WebView2.zip" && fileLocation.StartsWith(x.Value)); + packageDirectory = PackageDirectories.First(x => x.Value != "" && fileLocation.StartsWith(x.Value)); } catch (InvalidOperationException) { diff --git a/Bloxstrap/Helpers/FastFlagManager.cs b/Bloxstrap/Helpers/FastFlagManager.cs index 76b676b..ce87d3e 100644 --- a/Bloxstrap/Helpers/FastFlagManager.cs +++ b/Bloxstrap/Helpers/FastFlagManager.cs @@ -113,8 +113,8 @@ namespace Bloxstrap.Helpers if (GetValue("DFIntTaskSchedulerTargetFps") is null) SetValue("DFIntTaskSchedulerTargetFps", 9999); - // exclusive fullscreen requires direct3d 11 to work - if (GetValue(RenderingModes["Direct3D 11"]) != "True" && App.FastFlags.GetValue("FFlagHandleAltEnterFullscreenManually") == "False") + // reshade / exclusive fullscreen requires direct3d 11 to work + if (GetValue(RenderingModes["Direct3D 11"]) != "True" && (App.Settings.Prop.UseReShade || App.FastFlags.GetValue("FFlagHandleAltEnterFullscreenManually") == "False")) SetRenderingMode("Direct3D 11"); } diff --git a/Bloxstrap/Integrations/ReShade.cs b/Bloxstrap/Integrations/ReShade.cs new file mode 100644 index 0000000..5931f1e --- /dev/null +++ b/Bloxstrap/Integrations/ReShade.cs @@ -0,0 +1,505 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Threading.Tasks; +using Bloxstrap.Helpers; + +using Bloxstrap.Models; + +using IniParser; +using IniParser.Model; + +namespace Bloxstrap.Integrations +{ + internal class ReShade + { + // i havent even started this and i know for a fact this is gonna be a mess of an integration lol + // there's a lot of nuances involved in how reshade functionality is supposed to work (shader management, config management, etc) + // it's gonna be a bit of a pain in the ass, and i'm expecting a lot of bugs to arise from this... + // well, looks like v1.7.0 is gonna be held back for quite a while lol + + // also, this is going to be fairly restrictive without a lot of heavy work + // reshade's official installer gives you a list of shader packs and lets you choose which ones you want to install + // and here we're effectively choosing for the user... hm... + // i mean, it should be fine? importing shaders is still gonna be a thing, though maybe not as simple, but most people would be looking to use extravi's presets anyway + + private static string BaseDirectory => Path.Combine(Directories.Integrations, "ReShade"); + private static string FontsFolder => Path.Combine(BaseDirectory, "Fonts"); + private static string PresetsFolder => Path.Combine(BaseDirectory, "Presets"); + private static string ShadersFolder => Path.Combine(BaseDirectory, "Shaders"); + private static string TexturesFolder => Path.Combine(BaseDirectory, "Textures"); + private static string ConfigLocation => Path.Combine(Directories.Modifications, "ReShade.ini"); + + // the base url that we're fetching all our remote configs and resources and stuff from + private const string BaseUrl = "https://raw.githubusercontent.com/Extravi/extravi.github.io/main/update"; + + // this is a list of selectable shaders to download + private static readonly List Shaders = new() + { + // shaders required for extravi's presets: + new ReShadeShaderConfig { Name = "AstrayFX", DownloadLocation = "https://github.com/BlueSkyDefender/AstrayFX/archive/refs/heads/master.zip" }, + new ReShadeShaderConfig { Name = "Brussell", DownloadLocation = "https://github.com/brussell1/Shaders/archive/refs/heads/master.zip" }, + new ReShadeShaderConfig { Name = "Depth3D", DownloadLocation = "https://github.com/BlueSkyDefender/Depth3D/archive/refs/heads/master.zip" }, + new ReShadeShaderConfig { Name = "Glamarye", DownloadLocation = "https://github.com/rj200/Glamarye_Fast_Effects_for_ReShade/archive/refs/heads/main.zip" }, + new ReShadeShaderConfig { Name = "NiceGuy", DownloadLocation = "https://github.com/mj-ehsan/NiceGuy-Shaders/archive/refs/heads/main.zip" }, + new ReShadeShaderConfig { Name = "prod80", DownloadLocation = "https://github.com/prod80/prod80-ReShade-Repository/archive/refs/heads/master.zip" }, + new ReShadeShaderConfig { Name = "qUINT", DownloadLocation = "https://github.com/martymcmodding/qUINT/archive/refs/heads/master.zip" }, + new ReShadeShaderConfig { Name = "StockLegacy", DownloadLocation = "https://github.com/crosire/reshade-shaders/archive/refs/heads/legacy.zip" }, + new ReShadeShaderConfig { Name = "SweetFX", DownloadLocation = "https://github.com/CeeJayDK/SweetFX/archive/refs/heads/master.zip" }, + + // these ones needs some additional configuration + + new ReShadeShaderConfig + { + Name = "Stock", + DownloadLocation = "https://github.com/crosire/reshade-shaders/archive/refs/heads/master.zip", + ExcludedFiles = new List() + { + // overriden by stormshade + "Shaders/MXAO.fx" + } + }, + + new ReShadeShaderConfig + { + Name = "AlucardDH", + DownloadLocation = "https://github.com/AlucardDH/dh-reshade-shaders/archive/refs/heads/master.zip", + ExcludedFiles = new List() + { + // compiler errors + // dh_Lain only errors when performance mode is disabled, but it's not used by any presets anyway + "Shaders/dh_rtgi.fx", + "Shaders/dh_Lain.fx" + } + }, + + new ReShadeShaderConfig + { + Name = "Stormshade", + DownloadLocation = "https://github.com/cyrie/Stormshade/archive/refs/heads/master.zip", + BaseFolder = "reshade-shaders/", + ExcludedFiles = new List() + { + // these file names conflict with effects in the stock reshade config + "Shaders/AmbientLight.fx", + "Shaders/Clarity.fx", + "Shaders/DOF.fx", + "Shaders/DPX.fx", + "Shaders/FilmGrain.fx", + "Shaders/FineSharp.fx", + "Shaders/FXAA.fx", + "Shaders/FXAA.fxh", + "Shaders/LumaSharpen.fx", + //"Shaders/MXAO.fx", + "Shaders/ReShade.fxh", + "Shaders/Vibrance.fx", + "Shaders/Vignette.fx" + } + }, + }; + + private static readonly string[] ExtraviPresetsShaders = new string[] + { + "AlucardDH", + "Brussell", + "AstrayFX", + "Brussell", + "Depth3D", + "Glamarye", + "NiceGuy", + "prod80", + "qUINT", + "StockLegacy", + "Stormshade", + "SweetFX", + }; + + private static string GetSearchPath(string type, string name) + { + return $",..\\..\\Integrations\\ReShade\\{type}\\{name}"; + } + + public static async Task DownloadConfig() + { + App.Logger.WriteLine("[ReShade::DownloadConfig] Downloading/Upgrading config file..."); + + { + byte[] bytes = await App.HttpClient.GetByteArrayAsync($"{BaseUrl}/config.zip"); + + using MemoryStream zipStream = new(bytes); + using ZipArchive archive = new(zipStream); + + + archive.Entries.First(x => x.FullName == "ReShade.ini").ExtractToFile(ConfigLocation, true); + + // when we extract the file we have to make sure the last modified date is overwritten + // or else it will synchronize with the config in the version folder + // really the config adjustments below should do this for us, but this is just to be safe + File.SetLastWriteTime(ConfigLocation, DateTime.Now); + + // we also gotta download the editor fonts + foreach (ZipArchiveEntry entry in archive.Entries.Where(x => x.FullName.EndsWith(".ttf"))) + entry.ExtractToFile(Path.Combine(FontsFolder, entry.FullName), true); + } + + // now we have to adjust the config file to use the paths that we need + // some of these can be removed later when the config file is better adjusted for bloxstrap by default + + FileIniDataParser parser = new(); + IniData data = parser.ReadFile(ConfigLocation); + + data["GENERAL"]["EffectSearchPaths"] = "..\\..\\Integrations\\ReShade\\Shaders"; + data["GENERAL"]["TextureSearchPaths"] = "..\\..\\Integrations\\ReShade\\Textures"; + data["GENERAL"]["PresetPath"] = data["GENERAL"]["PresetPath"].Replace(".\\reshade-presets\\", "..\\..\\Integrations\\ReShade\\Presets\\"); + //data["SCREENSHOT"]["SavePath"] = "..\\..\\ReShade\\Screenshots"; + data["SCREENSHOT"]["SavePath"] = Path.Combine(Directories.MyPictures, "Roblox-ReShade"); + data["STYLE"]["EditorFont"] = data["STYLE"]["EditorFont"].Replace(".\\", "..\\..\\Integrations\\ReShade\\Fonts\\"); + data["STYLE"]["Font"] = data["STYLE"]["Font"].Replace(".\\", "..\\..\\Integrations\\ReShade\\Fonts\\"); + + // add search paths for shaders and textures + + foreach (string name in Directory.GetDirectories(ShadersFolder).Select(x => Path.GetRelativePath(ShadersFolder, x)).ToArray()) + data["GENERAL"]["EffectSearchPaths"] += GetSearchPath("Shaders", name); + + foreach (string name in Directory.GetDirectories(TexturesFolder).Select(x => Path.GetRelativePath(TexturesFolder, x)).ToArray()) + data["GENERAL"]["TextureSearchPaths"] += GetSearchPath("Textures", name); + + parser.WriteFile(ConfigLocation, data); + } + + public static void SynchronizeConfigFile() + { + App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] Synchronizing configuration file..."); + + // yeah, this is going to be a bit of a pain + // keep in mind the config file is going to be in two places: the mod folder and the version folder + // so we have to make sure the two below scenaros work flawlessly: + // - if the user manually updates their reshade config in the mod folder or it gets updated, it must be copied to the version folder + // - if the user updates their reshade settings ingame, the updated config must be copied to the mod folder + // the easiest way to manage this is to just compare the modification dates of the two + // anyway, this is where i'm expecting most of the bugs to arise from + // config synchronization will be done whenever roblox updates or whenever we launch roblox + + string modFolderConfigPath = ConfigLocation; + string versionFolderConfigPath = Path.Combine(Directories.Versions, App.State.Prop.VersionGuid, "ReShade.ini"); + + // we shouldn't be here if the mod config doesn't already exist + if (!File.Exists(modFolderConfigPath)) + { + App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] ReShade.ini in modifications folder does not exist, aborting sync"); + return; + } + + // copy to the version folder if it doesn't already exist there + if (!File.Exists(versionFolderConfigPath)) + { + App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] ReShade.ini in version folder does not exist, synchronized with modifications folder"); + File.Copy(modFolderConfigPath, versionFolderConfigPath); + } + + // if both the mod and version configs match, then we don't need to do anything + if (Utilities.MD5File(modFolderConfigPath) == Utilities.MD5File(versionFolderConfigPath)) + { + App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] ReShade.ini in version and modifications folder match"); + return; + } + + FileInfo modFolderConfigFile = new(modFolderConfigPath); + FileInfo versionFolderConfigFile = new(versionFolderConfigPath); + + if (modFolderConfigFile.LastWriteTime > versionFolderConfigFile.LastWriteTime) + { + // overwrite version config if mod config was modified most recently + App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] ReShade.ini in version folder is older, synchronized with modifications folder"); + File.Copy(modFolderConfigPath, versionFolderConfigPath, true); + } + else if (versionFolderConfigFile.LastWriteTime > modFolderConfigFile.LastWriteTime) + { + // overwrite mod config if version config was modified most recently + App.Logger.WriteLine($"[ReShade::SynchronizeConfigFile] ReShade.ini in modifications folder is older, synchronized with version folder"); + File.Copy(versionFolderConfigPath, modFolderConfigPath, true); + } + } + + public static async Task DownloadShaders(string name) + { + ReShadeShaderConfig config = Shaders.First(x => x.Name == name); + + // not all shader packs have a textures folder, so here we're determining if they exist purely based on if they have a Shaders folder + if (Directory.Exists(Path.Combine(ShadersFolder, name))) + return; + + App.Logger.WriteLine($"[ReShade::DownloadShaders] Downloading shaders for {name}"); + + { + byte[] bytes = await App.HttpClient.GetByteArrayAsync(config.DownloadLocation); + + using MemoryStream zipStream = new(bytes); + using ZipArchive archive = new(zipStream); + + foreach (ZipArchiveEntry entry in archive.Entries) + { + if (entry.FullName.EndsWith('/') || !entry.FullName.Contains(config.BaseFolder)) + continue; + + // github branch zips have a root folder of the name of the branch, so let's just remove that + string fullPath = entry.FullName.Substring(entry.FullName.IndexOf(config.BaseFolder) + config.BaseFolder.Length); + + // skip file if it's not in the Shaders or Textures folder + if (!fullPath.StartsWith("Shaders") && !fullPath.StartsWith("Textures")) + continue; + + if (config.ExcludedFiles.Contains(fullPath)) + continue; + + // and now we do it again because of how we're handling folder management + // e.g. reshade-shaders-master/Shaders/Vignette.fx should go to ReShade/Shaders/Stock/Vignette.fx + // so in this case, relativePath should just be "Vignette.fx" + string relativePath = fullPath.Substring(fullPath.IndexOf('/') + 1); + + // now we stitch it all together + string extractionPath = Path.Combine( + BaseDirectory, + fullPath.StartsWith("Shaders") ? "Shaders" : "Textures", + name, + relativePath + ); + + // make sure the folder that we're extracting it to exists + Directory.CreateDirectory(Path.GetDirectoryName(extractionPath)!); + + // and now extract + await Task.Run(() => entry.ExtractToFile(extractionPath)); + } + } + + // now we have to update ReShade.ini and add the installed shaders to the search paths + FileIniDataParser parser = new(); + IniData data = parser.ReadFile(ConfigLocation); + + if (!data["GENERAL"]["EffectSearchPaths"].Contains(name)) + data["GENERAL"]["EffectSearchPaths"] += GetSearchPath("Shaders", name); + + // not every shader pack has a textures folder + if (Directory.Exists(Path.Combine(TexturesFolder, name)) && !data["GENERAL"]["TextureSearchPaths"].Contains(name)) + data["GENERAL"]["TextureSearchPaths"] += GetSearchPath("Textures", name); + + parser.WriteFile(ConfigLocation, data); + } + + public static void DeleteShaders(string name) + { + App.Logger.WriteLine($"[ReShade::DeleteShaders] Deleting shaders for {name}"); + + string shadersPath = Path.Combine(ShadersFolder, name); + string texturesPath = Path.Combine(TexturesFolder, name); + + if (Directory.Exists(shadersPath)) + Directory.Delete(shadersPath, true); + + if (Directory.Exists(texturesPath)) + Directory.Delete(texturesPath, true); + + if (!File.Exists(ConfigLocation)) + return; + + // now we have to update ReShade.ini and remove the installed shaders from the search paths + FileIniDataParser parser = new(); + IniData data = parser.ReadFile(ConfigLocation); + + string shaderSearchPaths = data["GENERAL"]["EffectSearchPaths"]; + string textureSearchPaths = data["GENERAL"]["TextureSearchPaths"]; + + if (shaderSearchPaths.Contains(name)) + { + string searchPath = GetSearchPath("Shaders", name); + if (shaderSearchPaths.Contains(searchPath)) + data["GENERAL"]["EffectSearchPaths"] = shaderSearchPaths.Remove(shaderSearchPaths.IndexOf(searchPath), searchPath.Length); + } + + if (textureSearchPaths.Contains(name)) + { + string searchPath = GetSearchPath("Textures", name); + if (textureSearchPaths.Contains(searchPath)) + data["GENERAL"]["TextureSearchPaths"] = textureSearchPaths.Remove(textureSearchPaths.IndexOf(searchPath), searchPath.Length); + } + + parser.WriteFile(ConfigLocation, data); + } + + public static async Task InstallExtraviPresets() + { + App.Logger.WriteLine("[ReShade::InstallExtraviPresets] Installing Extravi's presets..."); + + foreach (string name in ExtraviPresetsShaders) + await DownloadShaders(name); + + byte[] bytes = await App.HttpClient.GetByteArrayAsync($"{BaseUrl}/reshade-presets.zip"); + + using MemoryStream zipStream = new(bytes); + using ZipArchive archive = new(zipStream); + + foreach (ZipArchiveEntry entry in archive.Entries) + { + if (entry.FullName.EndsWith('/')) + continue; + + // remove containing folder + string filename = entry.FullName.Substring(entry.FullName.IndexOf('/') + 1); + + await Task.Run(() => entry.ExtractToFile(Path.Combine(PresetsFolder, filename), true)); + } + } + + public static void UninstallExtraviPresets() + { + if (!Directory.Exists(PresetsFolder)) + return; + + App.Logger.WriteLine("[ReShade::UninstallExtraviPresets] Uninstalling Extravi's ReShade presets..."); + + FileInfo[] presets = new DirectoryInfo(PresetsFolder).GetFiles(); + + foreach (FileInfo preset in presets) + { + if (preset.Name.StartsWith("Extravi")) + preset.Delete(); + } + + foreach (string name in ExtraviPresetsShaders) + DeleteShaders(name); + } + + public static async Task CheckModifications() + { + App.Logger.WriteLine("[ReShade::CheckModifications] Checking ReShade modifications..."); + + string injectorLocation = Path.Combine(Directories.Modifications, "dxgi.dll"); + + if (!App.Settings.Prop.UseReShadeExtraviPresets && !string.IsNullOrEmpty(App.State.Prop.ExtraviReShadePresetsVersion)) + { + if (Utilities.CheckIfRobloxRunning()) + return; + + UninstallExtraviPresets(); + + App.State.Prop.ExtraviReShadePresetsVersion = ""; + App.State.Save(); + } + + if (!App.Settings.Prop.UseReShade) + { + if (Utilities.CheckIfRobloxRunning()) + return; + + App.Logger.WriteLine("[ReShade::CheckModifications] ReShade is not enabled"); + + // we should already be uninstalled + // we want to ensure this is done one-time only as this could possibly interfere with other rendering hooks using dxgi.dll + if (string.IsNullOrEmpty(App.State.Prop.ReShadeConfigVersion)) + return; + + App.Logger.WriteLine("[ReShade::CheckModifications] Uninstalling ReShade..."); + + // delete any stock config files + File.Delete(injectorLocation); + File.Delete(ConfigLocation); + + if (Directory.Exists(BaseDirectory)) + Directory.Delete(BaseDirectory, true); + + App.State.Prop.ReShadeConfigVersion = ""; + App.State.Save(); + + return; + } + + // the version manfiest contains the version of reshade available for download and the last date the presets were updated + var versionManifest = await Utilities.GetJson("https://raw.githubusercontent.com/Extravi/extravi.github.io/main/update/version.json"); + bool shouldFetchReShade = false; + bool shouldFetchConfig = false; + + if (!File.Exists(injectorLocation)) + { + shouldFetchReShade = true; + } + else if (versionManifest is not null) + { + // check if an update for reshade is available + FileVersionInfo injectorVersionInfo = FileVersionInfo.GetVersionInfo(injectorLocation); + + if (injectorVersionInfo.ProductVersion != versionManifest.ReShade) + shouldFetchReShade = true; + + // UPDATE CHECK - if we're upgrading to reshade 5.7.0, or we have extravi's presets + // enabled with a known shader downloaded (like AlucardDH) but without stormshade downloaded (5.7.0+ specific), + // we need to redownload all our shaders fresh + if ( + injectorVersionInfo.ProductVersion != versionManifest.ReShade && versionManifest.ReShade == "5.7.0" || + App.Settings.Prop.UseReShadeExtraviPresets && Directory.Exists(Path.Combine(ShadersFolder, "AlucardDH")) && !Directory.Exists(Path.Combine(ShadersFolder, "Stormshade")) + ) + { + Directory.Delete(ShadersFolder, true); + Directory.Delete(TexturesFolder, true); + App.State.Prop.ExtraviReShadePresetsVersion = ""; + App.Logger.WriteLine("[ReShade::CheckModifications] Upgrading to ReShade 5.7.0 - redownloading all shaders!"); + } + } + else + { + App.Logger.WriteLine("[ReShade::CheckModifications] versionManifest is null!"); + } + + // we're about to download - initialize directories + Directory.CreateDirectory(BaseDirectory); + Directory.CreateDirectory(FontsFolder); + Directory.CreateDirectory(ShadersFolder); + Directory.CreateDirectory(TexturesFolder); + Directory.CreateDirectory(PresetsFolder); + + // check if we should download a fresh copy of the config + // extravi may need to update the config ota, in which case we'll redownload it + if (!File.Exists(ConfigLocation) || versionManifest is not null && App.State.Prop.ReShadeConfigVersion != versionManifest.ConfigFile) + shouldFetchConfig = true; + + if (shouldFetchReShade) + { + App.Logger.WriteLine("[ReShade::CheckModifications] Installing/Upgrading ReShade..."); + + { + byte[] bytes = await App.HttpClient.GetByteArrayAsync($"{BaseUrl}/dxgi.zip"); + using MemoryStream zipStream = new(bytes); + using ZipArchive archive = new(zipStream); + archive.ExtractToDirectory(Directories.Modifications, true); + } + } + + if (shouldFetchConfig) + { + await DownloadConfig(); + + if (versionManifest is not null) + { + App.State.Prop.ReShadeConfigVersion = versionManifest.ConfigFile; + App.State.Save(); + } + } + + await DownloadShaders("Stock"); + + if (App.Settings.Prop.UseReShadeExtraviPresets && App.State.Prop.ExtraviReShadePresetsVersion != versionManifest!.Presets) + { + await InstallExtraviPresets(); + App.State.Prop.ExtraviReShadePresetsVersion = versionManifest.Presets; + App.State.Save(); + } + + SynchronizeConfigFile(); + } + } +} diff --git a/Bloxstrap/Models/ReShadeShaderConfig.cs b/Bloxstrap/Models/ReShadeShaderConfig.cs new file mode 100644 index 0000000..5ecda89 --- /dev/null +++ b/Bloxstrap/Models/ReShadeShaderConfig.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Bloxstrap.Models +{ + public class ReShadeShaderConfig + { + // it's assumed that the BaseFolder has a "Textures" folder and a "Shaders" folder + // the files listed in ExcludedFiles are relative to the BaseFolder + + public string Name { get; set; } = null!; + public string DownloadLocation { get; set; } = null!; + public string BaseFolder { get; set; } = "/"; + public List ExcludedFiles { get; set; } = new List(); + + public override string ToString() => Name; + } +} diff --git a/Bloxstrap/Models/ReShadeVersionManifest.cs b/Bloxstrap/Models/ReShadeVersionManifest.cs new file mode 100644 index 0000000..9110bf3 --- /dev/null +++ b/Bloxstrap/Models/ReShadeVersionManifest.cs @@ -0,0 +1,9 @@ +namespace Bloxstrap.Models +{ + public class ReShadeVersionManifest + { + public string ReShade { get; set; } = null!; + public string Presets { get; set; } = null!; + public string ConfigFile { get; set; } = null!; + } +} diff --git a/Bloxstrap/Models/Settings.cs b/Bloxstrap/Models/Settings.cs index dc274fc..95b1b8e 100644 --- a/Bloxstrap/Models/Settings.cs +++ b/Bloxstrap/Models/Settings.cs @@ -25,6 +25,8 @@ namespace Bloxstrap.Models // integration configuration public bool UseDiscordRichPresence { get; set; } = true; public bool HideRPCButtons { get; set; } = true; + public bool UseReShade { get; set; } = true; + public bool UseReShadeExtraviPresets { get; set; } = true; public bool ShowServerDetails { get; set; } = false; public ObservableCollection CustomIntegrations { get; set; } = new(); diff --git a/Bloxstrap/Models/State.cs b/Bloxstrap/Models/State.cs index 3fb6648..be8c221 100644 --- a/Bloxstrap/Models/State.cs +++ b/Bloxstrap/Models/State.cs @@ -9,7 +9,8 @@ namespace Bloxstrap.Models public class State { public string VersionGuid { get; set; } = ""; - public bool HadReShadeInstalled { get; set; } = false; + public string ReShadeConfigVersion { get; set; } = ""; + public string ExtraviReShadePresetsVersion { get; set; } = ""; public List ModManifest { get; set; } = new(); } } diff --git a/Bloxstrap/ViewModels/IntegrationsViewModel.cs b/Bloxstrap/ViewModels/IntegrationsViewModel.cs index f5da011..d097c9d 100644 --- a/Bloxstrap/ViewModels/IntegrationsViewModel.cs +++ b/Bloxstrap/ViewModels/IntegrationsViewModel.cs @@ -15,9 +15,17 @@ namespace Bloxstrap.ViewModels public event PropertyChangedEventHandler? PropertyChanged; public void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + public ICommand OpenReShadeFolderCommand => new RelayCommand(OpenReShadeFolder); public ICommand AddIntegrationCommand => new RelayCommand(AddIntegration); public ICommand DeleteIntegrationCommand => new RelayCommand(DeleteIntegration); + public bool CanOpenReShadeFolder => App.Settings.Prop.UseReShade; + + private void OpenReShadeFolder() + { + Process.Start("explorer.exe", Path.Combine(Directories.Integrations, "ReShade")); + } + private void AddIntegration() { CustomIntegrations.Add(new CustomIntegration() @@ -68,6 +76,27 @@ namespace Bloxstrap.ViewModels set => App.Settings.Prop.HideRPCButtons = !value; } + public bool ReShadeEnabled + { + get => App.Settings.Prop.UseReShade; + set + { + App.Settings.Prop.UseReShade = value; + ReShadePresetsEnabled = value; + + if (value) + App.FastFlags.SetRenderingMode("Direct3D 11"); + + OnPropertyChanged(nameof(ReShadePresetsEnabled)); + } + } + + public bool ReShadePresetsEnabled + { + get => App.Settings.Prop.UseReShadeExtraviPresets; + set => App.Settings.Prop.UseReShadeExtraviPresets = value; + } + public bool ShowServerDetailsEnabled { get => App.Settings.Prop.ShowServerDetails; diff --git a/Bloxstrap/Views/Pages/AboutPage.xaml b/Bloxstrap/Views/Pages/AboutPage.xaml index e0235f6..8130c33 100644 --- a/Bloxstrap/Views/Pages/AboutPage.xaml +++ b/Bloxstrap/Views/Pages/AboutPage.xaml @@ -83,6 +83,8 @@ + + @@ -109,18 +111,32 @@ - + + + + + + + - + + + + + + + + + diff --git a/Bloxstrap/Views/Pages/IntegrationsPage.xaml b/Bloxstrap/Views/Pages/IntegrationsPage.xaml index c4229b3..a204986 100644 --- a/Bloxstrap/Views/Pages/IntegrationsPage.xaml +++ b/Bloxstrap/Views/Pages/IntegrationsPage.xaml @@ -33,6 +33,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Bloxstrap/Views/Pages/ModsPage.xaml b/Bloxstrap/Views/Pages/ModsPage.xaml index e30be22..c6360f4 100644 --- a/Bloxstrap/Views/Pages/ModsPage.xaml +++ b/Bloxstrap/Views/Pages/ModsPage.xaml @@ -117,7 +117,7 @@ - +