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 @@
-
+