Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of GraphicsOverdrive v1.1.3
patchers/GraphicsOverdrive.Patcher.dll
Decompiled 9 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using BepInEx; using BepInEx.Logging; using Microsoft.CodeAnalysis; using Mono.Cecil; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("GraphicsOverdrive.Patcher")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Client-side BepInEx preloader patcher of Graphics Overdrive: opens the native door for FSR 3 (Vulkan layers + router plugin) before Unity creates its GPU device.")] [assembly: AssemblyFileVersion("1.1.3.0")] [assembly: AssemblyInformationalVersion("1.1.3")] [assembly: AssemblyProduct("GraphicsOverdrive.Patcher")] [assembly: AssemblyTitle("GraphicsOverdrive.Patcher")] [assembly: AssemblyVersion("1.1.3.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace GraphicsOverdrive.Patcher { public static class NativeDoor { private const string LayerName = "VK_LAYER_WUBARRK_graphics_overdrive"; private const string LibBase = "VkLayer_wubarrk_graphicsoverdrive"; private const string PluginGuid = "com.wubarrk.graphicsoverdrive"; private const int StrikeLimit = 2; private const string StrikesSince = "1.1.1"; private const int StageFull = 0; private const int StageReduced = 1; private const string DefaultDeviceExtensions = "VK_NVX_binary_import,VK_NVX_image_view_handle,VK_KHR_push_descriptor,VK_KHR_buffer_device_address,VK_KHR_timeline_semaphore,VK_KHR_synchronization2"; private const string DefaultFeatures = "bufferDeviceAddress,timelineSemaphore,synchronization2,storageWriteNoFormat,storageReadNoFormat"; private const string RayTracingExtensions = "VK_KHR_deferred_host_operations,VK_EXT_descriptor_indexing,VK_KHR_buffer_device_address,VK_KHR_shader_float_controls,VK_KHR_spirv_1_4,VK_KHR_acceleration_structure,VK_KHR_ray_query,VK_KHR_ray_tracing_pipeline"; private const string RayTracingFeatures = "bufferDeviceAddress,accelerationStructure,rayQuery,rayTracingPipeline"; private static ManualLogSource log; private static readonly StringBuilder pendingFile = new StringBuilder(); private static string workDir; public static IEnumerable<string> TargetDLLs => new string[0]; public static void Patch(AssemblyDefinition assembly) { } public static void Initialize() { try { Run(); } catch (Exception ex) { Note("Native door failed and was ignored, the game starts normally: " + ex); } finally { FlushFile(); } } private static void Run() { log = Logger.CreateLogSource("GraphicsOverdrive.Native"); bool flag = Environment.OSVersion.Platform == PlatformID.Win32NT; bool flag2 = !flag && File.Exists("/System/Library/CoreServices/SystemVersion.plist"); string text = (flag ? "windows-x64" : (flag2 ? "macos" : "linux-x64")); string path = (flag ? "VkLayer_wubarrk_graphicsoverdrive.dll" : "VkLayer_wubarrk_graphicsoverdrive.so"); string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string text2 = Path.Combine(Path.Combine(Path.Combine(directoryName, "native"), text), path); if (!File.Exists(text2)) { log.LogInfo((object)("Native door not available: this package has no native files for " + text + " (" + text2 + "). FSR 3 stays off; the mod works as usual.")); return; } workDir = Path.Combine(Path.Combine(Paths.CachePath, "GraphicsOverdrive"), "vulkan"); Directory.CreateDirectory(workDir); string cfgFile = Path.Combine(Paths.ConfigPath, "com.wubarrk.graphicsoverdrive.cfg"); string text3 = NativeFrameGen.Choice((string sec, string key, string dflt) => ReadConfigString(cfgFile, sec, key, dflt)); bool flag3 = !(Paths.ProcessName ?? "").ToLowerInvariant().Contains("server"); if (text3 == "NvidiaSmoothMotion" && flag3) { NativeFrameGen.SmoothMotion(Note, SetEnv); } if (!ShouldActivate(out var reason, out var switchedOff)) { NotActive(reason, switchedOff ? "off" : "not active"); if (switchedOff) { NativeRoute.Remove(Note); } return; } string text4 = NativeFiles.ReadSha256File(text2 + ".sha256"); if (text4 != null) { string b = NativeFiles.Sha256Hex(text2); if (!string.Equals(text4, b, StringComparison.OrdinalIgnoreCase)) { NotActive("payload hash mismatch", "not active"); return; } } string state = Path.Combine(workDir, "state.txt"); string strikesFile = Path.Combine(workDir, "strikes.txt"); if (!ChooseStage(state, strikesFile, out var stage, out var note, out reason, out var firstStartOfVersion)) { NotActive(reason, "not active"); return; } if (stage == 0) { SetEnv("GO_NATIVE_STATUS", "active"); } else { SetEnv("GO_NATIVE_STATUS", "active (reduced start: " + note + ")"); SetEnv("GO_NATIVE_STAGE_NOTE", note); Note("Reduced start: " + note); } SetEnv("GO_NATIVE_STAGE", (stage == 0) ? "full" : "reduced"); SetEnv("GO_NATIVE_DIR", workDir); SafeDelete(Path.Combine(workDir, "hardware-scan.txt")); bool flag4 = ReadConfigBool(cfgFile, "Native", "RayTracing", fallback: true); if (!flag4 && firstStartOfVersion && File.Exists(cfgFile)) { flag4 = true; SetEnv("GO_NATIVE_RT_DEFAULT", "1"); Note("[Native] RayTracing = false in the config is the default of an earlier version: switched on (ray tracing is part of the full set now; turn it off again in the settings if you do not want it)"); } bool flag5 = ReadConfigBool(cfgFile, "Native", "FrameGenPreload", fallback: true); string text5 = Path.Combine(workDir, "VkLayer_wubarrk_graphicsoverdrive.json"); string text6 = Path.Combine(workDir, "layer.cfg"); File.WriteAllText(text5, BuildManifest(text2)); File.WriteAllText(text6, BuildLayerConfig(state, stage == 0 && flag4, stage)); char sep = (flag ? ';' : ':'); SetEnv("VK_ADD_LAYER_PATH", Prepend(Environment.GetEnvironmentVariable("VK_ADD_LAYER_PATH"), workDir, sep)); SetEnv("VK_LOADER_LAYERS_ENABLE", Append(Environment.GetEnvironmentVariable("VK_LOADER_LAYERS_ENABLE"), "VK_LAYER_WUBARRK_graphics_overdrive", ',')); SetEnv("VK_INSTANCE_LAYERS", Append(Environment.GetEnvironmentVariable("VK_INSTANCE_LAYERS"), "VK_LAYER_WUBARRK_graphics_overdrive", sep)); SetEnv("GO_LAYER_CONFIG", text6); SetEnv("GO_LAYER_LIB", text2); Note("Native Vulkan layer activated: VK_LAYER_WUBARRK_graphics_overdrive from " + text2 + " (manifest " + text5 + ")"); NativeRoute.Install(directoryName, text, workDir, Note, SetEnv); if (text3 == "FSR3" || text3 == "DLSS") { NativeFrameGen.ActivatePresenter(text3, directoryName, text, workDir, Note, SetEnv, (string a, string value) => Prepend(a, value, sep), Append); } else if (text3 == "Off" && flag5 && stage == 0) { NativeFrameGen.ActivatePresenter("Off", directoryName, text, workDir, Note, SetEnv, (string a, string value) => Prepend(a, value, sep), Append); } else if (text3 == "Off" && flag5) { Note("Frame generation presenter not preloaded: reduced start (frame generation is switched on with a restart this session)"); } } private static void NotActive(string reason, string kind) { Note("Native Vulkan layer not activated: " + reason); SetEnv("GO_NATIVE_STATUS", kind + ": " + reason); } private static bool ShouldActivate(out string reason, out bool switchedOff) { switchedOff = false; string environmentVariable = Environment.GetEnvironmentVariable("GO_NATIVE"); if (environmentVariable == "0") { reason = "GO_NATIVE=0"; return false; } string[] commandLineArgs = Environment.GetCommandLineArgs(); string[] array = commandLineArgs; for (int i = 0; i < array.Length; i++) { if (array[i].ToLowerInvariant() == "-nographics") { reason = "headless process (-nographics)"; return false; } } string text = Paths.ProcessName ?? ""; if (text.ToLowerInvariant().Contains("server")) { reason = "dedicated server process (" + text + ")"; return false; } if (IntPtr.Size != 8) { reason = "32-bit process"; return false; } if (environmentVariable != "1" && !ReadConfigBool(Path.Combine(Paths.ConfigPath, "com.wubarrk.graphicsoverdrive.cfg"), "Native", "Enabled", fallback: true)) { reason = "switched off in the config ([Native] Enabled = false)"; switchedOff = true; return false; } bool flag = false; array = commandLineArgs; foreach (string text2 in array) { string text3 = text2.ToLowerInvariant(); if (text3 == "-force-vulkan") { flag = true; } switch (text3) { case "-force-d3d11": case "-force-d3d12": case "-force-glcore": case "-force-opengl": case "-force-gles": case "-force-metal": reason = "the game was launched with " + text2 + " (native mode is Vulkan only)"; return false; } } if (Environment.OSVersion.Platform == PlatformID.Win32NT && !flag) { reason = "on Windows the game runs Direct3D 11 unless it is started with -force-vulkan: add -force-vulkan to Valheim's launch options"; return false; } reason = null; return true; } private static bool ChooseStage(string state, string strikesFile, out int stage, out string note, out string reason, out bool firstStartOfVersion) { reason = null; note = null; stage = 0; string text = Path.Combine(Path.GetDirectoryName(strikesFile), "stage.txt"); if (Environment.GetEnvironmentVariable("GO_NATIVE_RESET") == "1") { SafeDelete(state); SafeDelete(strikesFile); SafeDelete(text); } string path = Path.Combine(Path.GetDirectoryName(strikesFile), "strikes-since.txt"); string text2 = null; try { if (File.Exists(path)) { text2 = File.ReadAllText(path).Trim(); } } catch { } firstStartOfVersion = text2 != "1.1.1"; if (firstStartOfVersion) { int result = 0; try { if (File.Exists(strikesFile)) { int.TryParse(File.ReadAllText(strikesFile).Trim(), out result); } } catch { } if (result > 0 || ReadStateValue(state) == "safe_mode" || File.Exists(text)) { Note("Safe-mode count from an older version cleared (" + result + " strike(s)): version 1.1.1 starts from a clean slate (it loads more by default and falls back in stages)"); } SafeDelete(state); SafeDelete(strikesFile); SafeDelete(text); try { File.WriteAllText(path, "1.1.1\n"); } catch { } } int result2 = 0; try { if (File.Exists(strikesFile)) { int.TryParse(File.ReadAllText(strikesFile).Trim(), out result2); } } catch { } int result3 = 0; bool flag = false; try { if (File.Exists(text)) { string[] array = File.ReadAllLines(text); foreach (string text3 in array) { if (text3.StartsWith("stage=")) { int.TryParse(text3.Substring(6).Trim(), out result3); } else if (text3.StartsWith("sticky=")) { flag = text3.Substring(7).Trim() == "1"; } } } } catch { } string text4 = ReadStateValue(state); bool flag2 = text4 == "instance_created" || text4 == "device_created" || text4 == "swapchain_requested"; if (text4 == "ok" || text4 == "clean_exit") { result2 = 0; } else if (flag2) { result2++; } try { File.WriteAllText(strikesFile, result2.ToString()); } catch { } if (result2 >= 2) { try { File.WriteAllText(state, "state=safe_mode\n"); } catch { } reason = "safe mode: " + result2 + " native starts in a row never reached a first frame. Delete " + strikesFile + " or start once with GO_NATIVE_RESET=1 to try again"; return false; } string text5 = ((text4 == "instance_created") ? "while the graphics device was being created" : ((text4 == "swapchain_requested") ? "while the game's swapchain was being created" : "after the graphics device was created (or it was closed while the game loaded its plugins)")); if (flag2) { stage = 1; bool flag3 = text4 != "device_created"; if (result3 == 0 && flag3) { flag = true; } note = "the last start never reached its first frame (it stopped " + text5 + "), so this start leaves out the ray tracing set and the frame generation preload. " + (flag ? ("Delete " + text + " or start once with GO_NATIVE_RESET=1 to try the full set again") : "If this start runs, the next one tries the full set again"); } else if (flag) { stage = 1; note = "an earlier start stopped while the graphics device or the swapchain was being created, so ray tracing set and frame generation preload stay left out. Delete " + text + " or start once with GO_NATIVE_RESET=1 to try the full set again"; } try { File.WriteAllText(text, "stage=" + stage + "\nsticky=" + (flag ? "1" : "0") + "\n"); } catch { } SafeDelete(state); return true; } private static string BuildManifest(string payload) { string text = payload.Replace("\\", "\\\\").Replace("\"", "\\\""); return "{\n \"file_format_version\": \"1.2.0\",\n \"layer\": {\n \"name\": \"VK_LAYER_WUBARRK_graphics_overdrive\",\n \"type\": \"GLOBAL\",\n \"library_path\": \"" + text + "\",\n \"api_version\": \"1.3.0\",\n \"implementation_version\": \"1\",\n \"description\": \"Graphics Overdrive native layer (client-side)\",\n \"functions\": { \"vkNegotiateLoaderLayerInterfaceVersion\": \"vkNegotiateLoaderLayerInterfaceVersion\" }\n }\n}\n"; } private static string BuildLayerConfig(string state, bool withRt, int stage) { string file = Path.Combine(Paths.ConfigPath, "com.wubarrk.graphicsoverdrive.cfg"); string value = ReadConfigString(file, "Native", "DeviceExtensions", "VK_NVX_binary_import,VK_NVX_image_view_handle,VK_KHR_push_descriptor,VK_KHR_buffer_device_address,VK_KHR_timeline_semaphore,VK_KHR_synchronization2"); string value2 = ReadConfigString(file, "Native", "Features", "bufferDeviceAddress,timelineSemaphore,synchronization2,storageWriteNoFormat,storageReadNoFormat"); bool flag = ReadConfigBool(file, "Native", "Inject", fallback: true); string value3 = ReadConfigString(file, "Native", "LayerLogLevel", "1"); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("log=").Append(Path.Combine(workDir, "layer.log")).Append('\n'); stringBuilder.Append("state_file=").Append(state).Append('\n'); stringBuilder.Append("scan_file=").Append(Path.Combine(workDir, "hardware-scan.txt")).Append('\n'); stringBuilder.Append("stage=").Append((stage == 0) ? "full" : "reduced").Append('\n'); stringBuilder.Append("inject=").Append(flag ? "1" : "0").Append('\n'); stringBuilder.Append("log_level=").Append(value3).Append('\n'); stringBuilder.Append("device_extensions=").Append(value).Append('\n'); stringBuilder.Append("features=").Append(value2).Append('\n'); if (withRt) { stringBuilder.Append("rt_device_extensions=").Append("VK_KHR_deferred_host_operations,VK_EXT_descriptor_indexing,VK_KHR_buffer_device_address,VK_KHR_shader_float_controls,VK_KHR_spirv_1_4,VK_KHR_acceleration_structure,VK_KHR_ray_query,VK_KHR_ray_tracing_pipeline").Append('\n'); stringBuilder.Append("rt_features=").Append("bufferDeviceAddress,accelerationStructure,rayQuery,rayTracingPipeline").Append('\n'); Note("Ray tracing set requested ([Native] RayTracing): the layer adds the hardware ray tracing extensions the GPU offers, and drops them again if the driver refuses the device with them"); } return stringBuilder.ToString(); } private static string Prepend(string existing, string value, char sep) { if (!string.IsNullOrEmpty(existing)) { return value + sep + existing; } return value; } private static string Append(string existing, string value, char sep) { if (string.IsNullOrEmpty(existing)) { return value; } string[] array = existing.Split(new char[1] { sep }); for (int i = 0; i < array.Length; i++) { if (array[i] == value) { return existing; } } return existing + sep + value; } [DllImport("libc", EntryPoint = "setenv")] private static extern int c_setenv(string name, string value, int overwrite); private static void SetEnv(string name, string value) { Environment.SetEnvironmentVariable(name, value); if (Environment.OSVersion.Platform != PlatformID.Win32NT) { try { c_setenv(name, value, 1); } catch (Exception ex) { Note("setenv(" + name + ") through libc failed: " + ex.Message); } } } private static string ReadConfigString(string file, string section, string key, string fallback) { try { if (!File.Exists(file)) { return fallback; } bool flag = false; string[] array = File.ReadAllLines(file); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.StartsWith("[") && text.EndsWith("]")) { flag = string.Equals(text.Substring(1, text.Length - 2), section, StringComparison.OrdinalIgnoreCase); } else if (flag && !text.StartsWith("#") && text.Length != 0) { int num = text.IndexOf('='); if (num >= 0 && string.Equals(text.Substring(0, num).Trim(), key, StringComparison.OrdinalIgnoreCase)) { return text.Substring(num + 1).Trim(); } } } } catch { } return fallback; } private static bool ReadConfigBool(string file, string section, string key, bool fallback) { string text = ReadConfigString(file, section, key, null); if (text == null || !bool.TryParse(text, out var result)) { return fallback; } return result; } private static string ReadStateValue(string state) { try { if (!File.Exists(state)) { return null; } string[] array = File.ReadAllLines(state); foreach (string text in array) { if (text.StartsWith("state=")) { return text.Substring(6).Trim(); } } } catch { } return null; } private static void SafeDelete(string path) { try { if (File.Exists(path)) { File.Delete(path); } } catch { } } private static void Note(string message) { if (log != null) { log.LogInfo((object)message); } pendingFile.Append(DateTime.UtcNow.ToString("HH:mm:ss.fff")).Append(' ').Append(message) .Append('\n'); } private static void FlushFile() { try { if (workDir != null) { File.AppendAllText(Path.Combine(workDir, "patcher.log"), pendingFile.ToString()); } } catch { } } } internal static class NativeFiles { internal static string ReadSha256File(string path) { try { return File.Exists(path) ? File.ReadAllText(path).Trim().Split(new char[1] { ' ' })[0] : null; } catch { return null; } } internal static string Sha256Hex(string path) { using SHA256 sHA = SHA256.Create(); using FileStream inputStream = File.OpenRead(path); byte[] array = sHA.ComputeHash(inputStream); StringBuilder stringBuilder = new StringBuilder(); byte[] array2 = array; foreach (byte b in array2) { stringBuilder.Append(b.ToString("x2")); } return stringBuilder.ToString(); } } internal static class NativeFrameGen { internal const string LayerName = "VK_LAYER_WUBARRK_frame_generation"; private const string LibBase = "VkLayer_wubarrk_frame_generation"; internal static string Choice(Func<string, string, string, string> readConfig) { string a = (readConfig("Native", "FrameGeneration", "Off") ?? "Off").Trim(); if (string.Equals(a, "NvidiaSmoothMotion", StringComparison.OrdinalIgnoreCase)) { return "NvidiaSmoothMotion"; } if (string.Equals(a, "FSR3", StringComparison.OrdinalIgnoreCase)) { return "FSR3"; } if (string.Equals(a, "DLSS", StringComparison.OrdinalIgnoreCase)) { return "DLSS"; } return "Off"; } internal static void SmoothMotion(Action<string> note, Action<string, string> setEnv) { try { if (Environment.OSVersion.Platform == PlatformID.Win32NT) { note("NVIDIA Smooth Motion not requested: the environment variable is documented for the Linux driver only"); return; } string[] commandLineArgs = Environment.GetCommandLineArgs(); foreach (string text in commandLineArgs) { switch (text.ToLowerInvariant()) { case "-nographics": case "-force-glcore": case "-force-opengl": case "-force-gles": note("NVIDIA Smooth Motion not requested: " + text); return; } } setEnv("NVPRESENT_ENABLE_SMOOTH_MOTION", "1"); note("NVIDIA Smooth Motion requested (NVPRESENT_ENABLE_SMOOTH_MOTION=1): the NVIDIA driver generates frames itself on RTX 40 series and newer"); } catch (Exception ex) { note("NVIDIA Smooth Motion switch ignored: " + ex.Message); } } internal static void ActivatePresenter(string backend, string patcherDir, string platformDir, string workDir, Action<string> note, Action<string, string> setEnv, Func<string, string, string> prepend, Func<string, string, char, string> append) { try { bool flag = Environment.OSVersion.Platform == PlatformID.Win32NT; string text = Path.Combine(Path.Combine(Path.Combine(patcherDir, "native"), platformDir), "VkLayer_wubarrk_frame_generation" + (flag ? ".dll" : ".so")); if (!File.Exists(text)) { note("Frame generation not enabled: presenter payload missing (" + text + ")"); return; } string text2 = NativeFiles.ReadSha256File(text + ".sha256"); if (text2 != null && !string.Equals(text2, NativeFiles.Sha256Hex(text), StringComparison.OrdinalIgnoreCase)) { note("Frame generation not enabled: presenter payload hash mismatch"); return; } string text3 = text.Replace("\\", "\\\\").Replace("\"", "\\\""); File.WriteAllText(Path.Combine(workDir, "VkLayer_wubarrk_frame_generation.json"), "{\n \"file_format_version\": \"1.2.0\",\n \"layer\": {\n \"name\": \"VK_LAYER_WUBARRK_frame_generation\",\n \"type\": \"GLOBAL\",\n \"library_path\": \"" + text3 + "\",\n \"api_version\": \"1.3.0\",\n \"implementation_version\": \"1\",\n \"description\": \"Graphics Overdrive frame generation presenter (client-side)\",\n \"functions\": { \"vkNegotiateLoaderLayerInterfaceVersion\": \"vkNegotiateLoaderLayerInterfaceVersion\" }\n }\n}\n"); string text4 = Path.Combine(workDir, "fg.cfg"); File.WriteAllText(text4, "log=" + Path.Combine(workDir, "fg.log") + "\nlog_level=1\nbackend=" + ((backend == "DLSS") ? "dlssg" : ((backend == "FSR3") ? "fsr3" : "off")) + "\n"); char arg = (flag ? ';' : ':'); setEnv("VK_LOADER_LAYERS_ENABLE", append(Environment.GetEnvironmentVariable("VK_LOADER_LAYERS_ENABLE"), "VK_LAYER_WUBARRK_frame_generation", ',')); setEnv("VK_INSTANCE_LAYERS", append(Environment.GetEnvironmentVariable("VK_INSTANCE_LAYERS"), "VK_LAYER_WUBARRK_frame_generation", arg)); setEnv("GO_FG_CONFIG", text4); setEnv("GO_FG_LAYER_LIB", text); string environmentVariable = Environment.GetEnvironmentVariable("GO_ADDON_DIRS"); if (!string.IsNullOrEmpty(environmentVariable)) { setEnv("GO_FG_ADDON_DIRS", environmentVariable); } note("Frame generation presenter enabled: VK_LAYER_WUBARRK_frame_generation from " + text + ((backend == "Off") ? ", preloaded (frame generation is Off: it passes the game's frames through until it is switched on)" : (", initial backend " + backend))); } catch (Exception ex) { note("Frame generation not enabled (ignored, the game starts normally): " + ex.Message); } } } internal static class NativeRoute { private static string RouterFileName { get { if (!IsWindows) { return "libgo_router.so"; } return "go_router.dll"; } } private static string BackendPrefix { get { if (!IsWindows) { return "libgo_backend_"; } return "go_backend_"; } } private static string LibExtension { get { if (!IsWindows) { return ".so"; } return ".dll"; } } private static bool IsWindows => Environment.OSVersion.Platform == PlatformID.Win32NT; private static string UnityPluginDir => Path.Combine(Path.Combine(Path.GetDirectoryName(Paths.ManagedPath), "Plugins"), "x86_64"); internal static void Install(string patcherDir, string platformDir, string workDir, Action<string> note, Action<string, string> setEnv) { try { string text = Path.Combine(Path.Combine(Path.Combine(patcherDir, "native"), platformDir), RouterFileName); if (!File.Exists(text)) { note("Router not installed: payload missing (" + text + ")"); return; } string b = NativeFiles.Sha256Hex(text); string text2 = NativeFiles.ReadSha256File(text + ".sha256"); if (text2 != null && !string.Equals(text2, b, StringComparison.OrdinalIgnoreCase)) { note("Router not installed: payload hash mismatch"); return; } string unityPluginDir = UnityPluginDir; string text3 = Path.Combine(unityPluginDir, RouterFileName); if (File.Exists(text3) && string.Equals(NativeFiles.Sha256Hex(text3), b, StringComparison.OrdinalIgnoreCase)) { note("Router already in place: " + text3); } else { Directory.CreateDirectory(unityPluginDir); string text4 = text3 + ".go-tmp"; File.Copy(text, text4, overwrite: true); if (File.Exists(text3)) { File.Delete(text3); } File.Move(text4, text3); note("Router installed: " + text3); } string text5 = Path.Combine(workDir, "router-data"); Directory.CreateDirectory(text5); setEnv("GO_ROUTER_LIB", text3); setEnv("GO_ROUTER_LOG", Path.Combine(workDir, "router.log")); setEnv("GO_ROUTER_DATA", text5); string text6 = FindAddonDirs(platformDir, note); setEnv("GO_ADDON_DIRS", text6); note("Router add-on folders: " + ((text6.Length == 0) ? "none" : text6)); } catch (Exception ex) { note("Router not installed (ignored, the game starts normally): " + ex.Message); } } internal static void Remove(Action<string> note) { try { string text = Path.Combine(UnityPluginDir, RouterFileName); if (File.Exists(text)) { File.Delete(text); note("Router removed from " + text + " (native mode is off)"); } } catch (Exception ex) { note("Router could not be removed: " + ex.Message); } } private static string FindAddonDirs(string platformDir, Action<string> note) { List<string> list = new List<string>(); if (!Directory.Exists(Paths.PatcherPluginPath)) { return ""; } string[] directories = Directory.GetDirectories(Paths.PatcherPluginPath); for (int i = 0; i < directories.Length; i++) { string text = Path.Combine(Path.Combine(directories[i], "native"), platformDir); if (!Directory.Exists(text)) { continue; } bool flag = false; bool flag2 = true; string[] files = Directory.GetFiles(text, BackendPrefix + "*" + LibExtension); foreach (string text2 in files) { flag = true; string text3 = NativeFiles.ReadSha256File(text2 + ".sha256"); if (text3 != null && !string.Equals(text3, NativeFiles.Sha256Hex(text2), StringComparison.OrdinalIgnoreCase)) { flag2 = false; note("Add-on skipped, hash mismatch: " + text2); } } if (flag && flag2) { list.Add(text); } } return string.Join(IsWindows ? ";" : ":", list.ToArray()); } } }
plugins/GraphicsOverdrive.dll
Decompiled 9 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using AmplifyOcclusion; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using GraphicsOverdrive.Benchmark; using GraphicsOverdrive.Native; using GraphicsOverdrive.Patches; using GraphicsOverdrive.Presets; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Experimental.Rendering; using UnityEngine.PostProcessing; using UnityEngine.Profiling; using UnityEngine.Rendering; using UnityEngine.UI; using Valheim.SettingsGui; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: IgnoresAccessChecksTo("assembly_guiutils")] [assembly: IgnoresAccessChecksTo("assembly_postprocessing")] [assembly: IgnoresAccessChecksTo("assembly_utils")] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: AssemblyCompany("GraphicsOverdrive")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Unlocks all the graphic dials in the Unity engine and Valheim into an easy to use, understand and tweak format.")] [assembly: AssemblyFileVersion("1.1.3.0")] [assembly: AssemblyInformationalVersion("1.1.3")] [assembly: AssemblyProduct("GraphicsOverdrive")] [assembly: AssemblyTitle("GraphicsOverdrive")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.3.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace GraphicsOverdrive { public static class AssetLoader { private static Texture2D s_cornerRibbonTex; private static Sprite s_cornerRibbonSprite; public static Sprite GetCornerRibbonSprite() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)s_cornerRibbonSprite != (Object)null) { return s_cornerRibbonSprite; } Texture2D cornerRibbonTexture = GetCornerRibbonTexture(); if ((Object)(object)cornerRibbonTexture != (Object)null) { s_cornerRibbonSprite = Sprite.Create(cornerRibbonTexture, new Rect(0f, 0f, (float)((Texture)cornerRibbonTexture).width, (float)((Texture)cornerRibbonTexture).height), new Vector2(0f, 1f)); ((Object)s_cornerRibbonSprite).hideFlags = (HideFlags)61; } return s_cornerRibbonSprite; } public static Texture2D GetCornerRibbonTexture() { if ((Object)(object)s_cornerRibbonTex != (Object)null) { return s_cornerRibbonTex; } s_cornerRibbonTex = LoadEmbeddedTexture("GraphicsOverdrive.wubarrk_red_ribbon.png"); if ((Object)(object)s_cornerRibbonTex == (Object)null) { s_cornerRibbonTex = CreateFallbackRibbon(); } ((Object)s_cornerRibbonTex).hideFlags = (HideFlags)61; return s_cornerRibbonTex; } private static Texture2D LoadEmbeddedTexture(string resourceName) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown Texture2D val = null; try { using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName); if (stream == null) { return null; } byte[] array; using (MemoryStream memoryStream = new MemoryStream()) { stream.CopyTo(memoryStream); array = memoryStream.ToArray(); } MethodInfo methodInfo = (Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule") ?? Type.GetType("UnityEngine.ImageConversion, UnityEngine"))?.GetMethod("LoadImage", new Type[2] { typeof(Texture2D), typeof(byte[]) }); if (methodInfo == null) { return null; } val = new Texture2D(2, 2, (TextureFormat)4, false); if ((bool)methodInfo.Invoke(null, new object[2] { val, array })) { ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; return val; } } catch (Exception ex) { Plugin.LogWarning("[AssetLoader] Could not load embedded resource '" + resourceName + "': " + ex.Message); } if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } return null; } private static Texture2D CreateFallbackRibbon() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(180, 180, (TextureFormat)4, false); Color val2 = default(Color); ((Color)(ref val2))..ctor(0f, 0f, 0f, 0f); Color val3 = default(Color); ((Color)(ref val3))..ctor(0.55f, 0.05f, 0.08f, 0.95f); Color val4 = default(Color); ((Color)(ref val4))..ctor(0.85f, 0.68f, 0.25f, 1f); for (int i = 0; i < 180; i++) { for (int j = 0; j < 180; j++) { int num = j + i; if (num >= 80 && num <= 150) { val.SetPixel(j, i, (num <= 84 || num >= 146) ? val4 : val3); } else { val.SetPixel(j, i, val2); } } } val.Apply(); return val; } } public static class BasicMode { public enum RtLevel { Off, Low, Medium, High, Ultra, Custom } private struct Recipe { public GraphicsConfig.RtShadowMode shadows; public GraphicsConfig.RtGiMode gi; public bool reflections; public bool water; public bool lights; public GraphicsConfig.RtResolution resolution; } public static readonly RtLevel[] Levels = new RtLevel[5] { RtLevel.Off, RtLevel.Low, RtLevel.Medium, RtLevel.High, RtLevel.Ultra }; public static bool IsBasic { get { if (GraphicsConfig.MenuMode != null) { return GraphicsConfig.MenuMode.Value == GraphicsConfig.MenuModeChoice.Basic; } return true; } } public static bool RtOffered => GraphicsConfig.RtSunShadows != null; public static string Label(RtLevel level) { return level switch { RtLevel.Off => "Off", RtLevel.Low => "Low", RtLevel.Medium => "Medium", RtLevel.High => "High", RtLevel.Ultra => "Ultra", _ => "Custom", }; } public static string Describe(RtLevel level) { return level switch { RtLevel.Off => "no ray tracing", RtLevel.Low => "sun shadows", RtLevel.Medium => "shadows, shade, torches, water", RtLevel.High => "+ bounced light, reflections", RtLevel.Ultra => "everything, full resolution", _ => "set in Expert mode", }; } private static Recipe Of(RtLevel level) { return level switch { RtLevel.Low => new Recipe { shadows = GraphicsConfig.RtShadowMode.Hybrid, gi = GraphicsConfig.RtGiMode.Off, resolution = GraphicsConfig.RtResolution.Half }, RtLevel.Medium => new Recipe { shadows = GraphicsConfig.RtShadowMode.Hybrid, gi = GraphicsConfig.RtGiMode.AmbientOcclusion, water = true, lights = true, resolution = GraphicsConfig.RtResolution.Half }, RtLevel.High => new Recipe { shadows = GraphicsConfig.RtShadowMode.Hybrid, gi = GraphicsConfig.RtGiMode.Full, reflections = true, water = true, lights = true, resolution = GraphicsConfig.RtResolution.Half }, RtLevel.Ultra => new Recipe { shadows = GraphicsConfig.RtShadowMode.Hybrid, gi = GraphicsConfig.RtGiMode.Full, reflections = true, water = true, lights = true, resolution = GraphicsConfig.RtResolution.Full }, _ => new Recipe { shadows = GraphicsConfig.RtShadowMode.Off, gi = GraphicsConfig.RtGiMode.Off, resolution = GraphicsConfig.RtResolution.Half }, }; } public static RtLevel CurrentRtLevel() { if (!RtOffered) { return RtLevel.Off; } RtLevel[] levels = Levels; foreach (RtLevel rtLevel in levels) { Recipe recipe = Of(rtLevel); bool flag = recipe.gi != GraphicsConfig.RtGiMode.Off || recipe.reflections || recipe.water || recipe.lights; if (GraphicsConfig.RtSunShadows.Value == recipe.shadows && GraphicsConfig.RtGlobalIllumination.Value == recipe.gi && GraphicsConfig.RtReflections.Value == recipe.reflections && GraphicsConfig.RtWaterReflections.Value == recipe.water && GraphicsConfig.RtPointLights.Value == recipe.lights && (!flag || GraphicsConfig.RtLightingResolution.Value == recipe.resolution)) { return rtLevel; } } return RtLevel.Custom; } public static void ApplyRtLevel(RtLevel level) { if (RtOffered && level != RtLevel.Custom) { Recipe recipe = Of(level); GraphicsConfig.RtSunShadows.Value = recipe.shadows; GraphicsConfig.RtGlobalIllumination.Value = recipe.gi; GraphicsConfig.RtReflections.Value = recipe.reflections; GraphicsConfig.RtWaterReflections.Value = recipe.water; GraphicsConfig.RtPointLights.Value = recipe.lights; if (recipe.gi != GraphicsConfig.RtGiMode.Off || recipe.reflections || recipe.water || recipe.lights) { GraphicsConfig.RtLightingResolution.Value = recipe.resolution; } } } } public static class CameraDials { internal enum PresetField { FieldOfView, Zoom, Shake } private sealed class Slot { public float Game; public float Written = float.NaN; public float Dial = float.NaN; public bool Yielding; public float Theirs; public bool Logged; } private const int Fov = 0; private const int Zoom = 1; private const int Boat = 2; private const int Shake = 3; private const int Slots = 4; private static readonly string[] s_names = new string[4] { "Field of view", "Zoom limit on foot", "Zoom limit on a boat", "Screen shake" }; private static readonly float[] s_default = new float[4] { 65f, 8f, 16f, 1f }; private static readonly Slot[] s_slots = (from i in Enumerable.Range(0, 4) select new Slot { Game = s_default[i] }).ToArray(); private static GameCamera s_camera; private static bool s_summaryLogged; private static string s_otherMods; private static string s_status = ""; private static bool s_statusDirty = true; private static GraphicsConfig.CameraControlMode s_statusMode; private static Vector4 s_loggedVerbose = new Vector4(float.NaN, 0f, 0f, 0f); private static GraphicsConfig.CameraControlMode Mode { get { if (!GraphicsConfig.MasterEnable.Value) { return GraphicsConfig.CameraControlMode.Off; } if (GraphicsConfig.CameraControl == null) { return GraphicsConfig.CameraControlMode.Auto; } return GraphicsConfig.CameraControl.Value; } } public static string StatusLine { get { GraphicsConfig.CameraControlMode mode = Mode; if (s_statusDirty || mode != s_statusMode) { s_statusDirty = false; s_statusMode = mode; s_status = BuildStatus(mode); } return s_status; } } public static string OtherCameraMods => s_otherMods ?? (s_otherMods = FindOtherCameraMods()); private static bool Near(float a, float b) { return Mathf.Abs(a - b) <= 0.001f; } internal static void OnCameraAwake(GameCamera cam) { if (!((Object)(object)cam == (Object)null)) { Begin(cam); s_slots[0].Game = cam.m_fov; s_slots[1].Game = cam.m_maxDistance; s_slots[2].Game = cam.m_maxDistanceBoat; s_slots[3].Game = cam.m_shakeMovement; } } private static void Begin(GameCamera cam) { s_camera = cam; s_summaryLogged = false; s_statusDirty = true; for (int i = 0; i < 4; i++) { Slot obj = s_slots[i]; obj.Game = s_default[i]; obj.Written = float.NaN; obj.Dial = float.NaN; obj.Yielding = false; } } internal static void Apply(GameCamera cam) { //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)cam == (Object)null) { return; } if (cam != s_camera) { Begin(cam); } GraphicsConfig.CameraControlMode mode = Mode; if (!s_summaryLogged) { LogSummary(cam, mode); } if (mode == GraphicsConfig.CameraControlMode.Off) { Release(cam); return; } if ((!(cam.m_fovInertia > 0f) || Mathf.Approximately(cam.m_fovTarget, cam.m_fov)) && Keep(0, ref cam.m_fov, GraphicsConfig.CameraFieldOfView.Value, mode) && cam.m_fovBase != 0f) { cam.m_fovBase = cam.m_fov; cam.m_fovTarget = cam.m_fov; } float value = GraphicsConfig.CameraMaxDistance.Value; Keep(1, ref cam.m_maxDistance, value, mode); Keep(2, ref cam.m_maxDistanceBoat, value * 2f, mode); Keep(3, ref cam.m_shakeMovement, GraphicsConfig.CameraShakeScale.Value, mode); if (GraphicsConfig.VerboseLogging.Value) { Vector4 val = default(Vector4); ((Vector4)(ref val))..ctor(cam.m_fov, cam.m_maxDistance, cam.m_maxDistanceBoat, cam.m_shakeMovement); if (val != s_loggedVerbose) { s_loggedVerbose = val; Plugin.LogInfo($"[Camera] in force: field of view {val.x:0.#}, zoom {val.y:0.#} m (boat {val.z:0.#} m), shake {val.w:0.##}x; {StatusLine}"); } } } internal static void Release(GameCamera cam) { if (!((Object)(object)cam == (Object)null) && cam == s_camera) { if (ReleaseOne(0, ref cam.m_fov) && cam.m_fovBase != 0f) { cam.m_fovBase = cam.m_fov; cam.m_fovTarget = cam.m_fov; } ReleaseOne(1, ref cam.m_maxDistance); ReleaseOne(2, ref cam.m_maxDistanceBoat); ReleaseOne(3, ref cam.m_shakeMovement); } } private static bool ReleaseOne(int i, ref float field) { Slot slot = s_slots[i]; bool result = false; if (!float.IsNaN(slot.Written) && Near(field, slot.Written)) { field = slot.Game; result = true; } if (!float.IsNaN(slot.Written) || slot.Yielding) { s_statusDirty = true; } slot.Written = float.NaN; slot.Dial = float.NaN; slot.Yielding = false; return result; } private static bool Keep(int i, ref float field, float want, GraphicsConfig.CameraControlMode mode) { Slot slot = s_slots[i]; float num = field; bool flag = !float.IsNaN(slot.Dial) && !Near(slot.Dial, want); slot.Dial = want; bool flag2 = !float.IsNaN(slot.Written) && Near(num, slot.Written); if (mode == GraphicsConfig.CameraControlMode.Auto && !flag2 && !Near(num, slot.Game) && !Near(num, want)) { if (!slot.Yielding) { Yield(i, num, slot); } slot.Yielding = true; if (!flag) { return false; } } if (slot.Yielding) { slot.Yielding = false; s_statusDirty = true; } bool flag3 = mode != GraphicsConfig.CameraControlMode.On && Near(want, s_default[i]); if (flag3 && float.IsNaN(slot.Written)) { return false; } float num2 = (flag3 ? slot.Game : want); float num3 = (flag3 ? float.NaN : want); if (!Near(slot.Written, num3) && (!float.IsNaN(slot.Written) || !float.IsNaN(num3))) { s_statusDirty = true; } slot.Written = num3; if (Near(num, num2)) { return false; } field = num2; return true; } private static void Yield(int i, float theirs, Slot s) { s.Theirs = theirs; s_statusDirty = true; if (!s.Logged) { s.Logged = true; string text = (float.IsNaN(s.Written) ? "" : (", this mod's last value " + Fmt(i, s.Written))); Plugin.LogInfo("[Camera] " + s_names[i] + ": another mod set it to " + Fmt(i, theirs) + " (the game's own value is " + Fmt(i, s.Game) + text + "), so Graphics Overdrive leaves it to that mod. Moving the dial applies it once; [7 - Post-FX & Camera] CameraControl = On makes the dials always win, Off keeps this mod away from the camera. " + ((OtherCameraMods.Length > 0) ? ("Plugins that patch GameCamera: " + OtherCameraMods + ".") : "No other plugin's patch on GameCamera was found (it may write the field from its own Update).")); } } private static string Fmt(int i, float v) { return i switch { 3 => $"{v:0.##}x", 0 => $"{v:0.#} degrees", _ => $"{v:0.#} m", }; } internal static bool PresetMayWrite(PresetField field) { switch ((GraphicsConfig.CameraControl != null) ? GraphicsConfig.CameraControl.Value : GraphicsConfig.CameraControlMode.Auto) { case GraphicsConfig.CameraControlMode.Off: return false; case GraphicsConfig.CameraControlMode.On: return true; default: switch (field) { case PresetField.FieldOfView: return !s_slots[0].Yielding; case PresetField.Zoom: if (!s_slots[1].Yielding) { return !s_slots[2].Yielding; } return false; default: return !s_slots[3].Yielding; } } } private static string BuildStatus(GraphicsConfig.CameraControlMode mode) { string text = mode switch { GraphicsConfig.CameraControlMode.Off => "Off", GraphicsConfig.CameraControlMode.On => "On", _ => "Auto", }; if (mode == GraphicsConfig.CameraControlMode.Off) { return text + ": Graphics Overdrive leaves the camera to the game and other mods"; } if ((Object)(object)s_camera == (Object)null) { return text + ": waiting for the game camera"; } List<string> list = new List<string>(); List<string> list2 = new List<string>(); for (int i = 0; i < 4; i++) { if (s_slots[i].Yielding) { list2.Add(s_names[i].ToLowerInvariant()); } else if (!float.IsNaN(s_slots[i].Written)) { list.Add(s_names[i].ToLowerInvariant()); } } string text2 = text + ": "; text2 += ((list.Count > 0) ? ("Graphics Overdrive sets the " + string.Join(", ", list)) : "no camera value is set by Graphics Overdrive (the dials sit at the game's own values)"); if (list2.Count > 0) { text2 = text2 + "; another mod owns the " + string.Join(", ", list2); } return text2; } private static void LogSummary(GameCamera cam, GraphicsConfig.CameraControlMode mode) { s_summaryLogged = true; try { List<string> list = new List<string>(); Camera component = ((Component)cam).GetComponent<Camera>(); Camera[] array = (Camera[])(object)new Camera[Camera.allCamerasCount]; int allCameras = Camera.GetAllCameras(array); for (int i = 0; i < allCameras; i++) { Camera val = array[i]; if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)component) && !((Object)(object)val == (Object)(object)cam.m_skyCamera) && (!((Object)(object)component != (Object)null) || !((Component)val).transform.IsChildOf(((Component)component).transform))) { list.Add(string.Format("{0} (depth {1:0.#}, {2}{3})", ((Object)val).name, val.depth, ((Object)(object)val.targetTexture != (Object)null) ? ("texture " + ((Texture)val.targetTexture).width + "x" + ((Texture)val.targetTexture).height) : "screen", ((Component)val).CompareTag("MainCamera") ? ", tagged MainCamera" : "")); } } Plugin.LogInfo($"[Camera] Game camera ready: CameraControl = {mode}; dials: field of view {GraphicsConfig.CameraFieldOfView.Value:0.#}, zoom limit {GraphicsConfig.CameraMaxDistance.Value:0.#} m, " + $"shake {GraphicsConfig.CameraShakeScale.Value:0.##}x (the game's own: {s_slots[0].Game:0.#}, {s_slots[1].Game:0.#} m, {s_slots[3].Game:0.##}x; a dial at the game's value is never written). " + ((OtherCameraMods.Length > 0) ? ("Plugins that patch GameCamera: " + OtherCameraMods + ". ") : "No other plugin patches GameCamera. ") + ((list.Count > 0) ? ("Other enabled cameras: " + string.Join("; ", list) + ".") : "No other enabled camera.")); } catch (Exception ex) { Plugin.LogWarning("[Camera] Could not list the cameras around the game camera: " + ex.Message); } } private static string FindOtherCameraMods() { try { SortedSet<string> sortedSet = new SortedSet<string>(); foreach (MethodBase allPatchedMethod in Harmony.GetAllPatchedMethods()) { if (allPatchedMethod.DeclaringType != typeof(GameCamera)) { continue; } Patches patchInfo = Harmony.GetPatchInfo(allPatchedMethod); if (patchInfo == null) { continue; } foreach (string owner in patchInfo.Owners) { if (owner != "com.wubarrk.graphicsoverdrive") { sortedSet.Add(owner); } } } PluginInfo value; return string.Join(", ", sortedSet.Select((string owner) => (!Chainloader.PluginInfos.TryGetValue(owner, out value)) ? owner : (value.Metadata.Name + " (" + owner + ")"))); } catch (Exception ex) { Plugin.LogWarning("[Camera] Could not list the plugins that patch GameCamera: " + ex.Message); return string.Empty; } } } public static class DisplayBasics { public enum WindowChoice { Fullscreen, Windowed } public struct Choice { public int Width; public int Height; public WindowChoice Window; public override string ToString() { return string.Format("{0} x {1} {2}", Width, Height, (Window == WindowChoice.Fullscreen) ? "fullscreen" : "windowed"); } } public interface IDisplayHost { Resolution[] Modes { get; } Resolution Desktop { get; } int Width { get; } int Height { get; } FullScreenMode Mode { get; } bool FrameGenOn { get; } string BlockedReason { get; } float Now { get; } void SetResolution(int width, int height, FullScreenMode mode, RefreshRate refresh); int GetPref(string key, int fallback); void SetPref(string key, int value); void SavePrefs(); bool GetPresent(out int fpsLimit, out bool vsync); void SetPresent(int fpsLimit, bool vsync); } private sealed class UnityHost : IDisplayHost { public Resolution[] Modes => Screen.resolutions; public Resolution Desktop { get { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) Resolution currentResolution = Screen.currentResolution; if (((Resolution)(ref currentResolution)).width <= 0 || ((Resolution)(ref currentResolution)).height <= 0) { ((Resolution)(ref currentResolution)).width = Display.main.systemWidth; ((Resolution)(ref currentResolution)).height = Display.main.systemHeight; } return currentResolution; } } public int Width => Screen.width; public int Height => Screen.height; public FullScreenMode Mode => Screen.fullScreenMode; public bool FrameGenOn { get { if ((!NativeBridge.FgPresenterLoaded && string.IsNullOrEmpty(Environment.GetEnvironmentVariable("GO_FG_LAYER_LIB"))) || GraphicsConfig.NativeFrameGeneration == null) { return false; } GraphicsConfig.FrameGenChoice value = GraphicsConfig.NativeFrameGeneration.Value; if (value != GraphicsConfig.FrameGenChoice.FSR3) { return value == GraphicsConfig.FrameGenChoice.DLSS; } return true; } } public float Now => Time.realtimeSinceStartup; public string BlockedReason { get { if (!GraphicsSettingsManager.CanChangePresentSettings()) { return "This platform does not let the game change its display."; } if (!((Object)(object)Settings.instance != (Object)null)) { return ""; } return "Close the game's Settings window first: it keeps its own copy of these values."; } } public void SetResolution(int width, int height, FullScreenMode mode, RefreshRate refresh) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) Screen.SetResolution(width, height, mode, refresh); } public int GetPref(string key, int fallback) { return PlayerPrefs.GetInt(key, fallback); } public void SetPref(string key, int value) { PlayerPrefs.SetInt(key, value); } public void SavePrefs() { PlayerPrefs.Save(); } public bool GetPresent(out int fpsLimit, out bool vsync) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) fpsLimit = 361; vsync = false; GraphicsSettingsManager instance = GraphicsSettingsManager.Instance; if ((Object)(object)instance == (Object)null) { return false; } try { PresentSettingsState presentSettings = instance.GetCurrentSettingsWithCurrentPresetApplied(false, false).m_presentSettings; fpsLimit = presentSettings.m_fpsLimit; vsync = presentSettings.m_vsync; return true; } catch (Exception) { return false; } } public unsafe void SetPresent(int fpsLimit, bool vsync) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) GraphicsSettingsManager instance = GraphicsSettingsManager.Instance; GraphicsSettingsState currentPlayerSettingsRaw = Unsafe.Read<GraphicsSettingsState>((void*)instance.CurrentPlayerSettingsRaw); currentPlayerSettingsRaw.m_presentSettings.m_fpsLimit = fpsLimit; currentPlayerSettingsRaw.m_presentSettings.m_vsync = vsync; GraphicsModeConfiguration currentGraphicsModeConfiguration = instance.GetCurrentGraphicsModeConfiguration(false); GraphicsSettingsPreset val = currentGraphicsModeConfiguration.GetPresetByID(instance.CurrentPresetID); if ((Object)(object)val == (Object)null && !currentGraphicsModeConfiguration.HasCustomPreset) { val = currentGraphicsModeConfiguration.DefaultPreset; } if ((Object)(object)val != (Object)null) { instance.SaveAndApplyGraphicsSettingsWithPreset(ref currentPlayerSettingsRaw, val.m_type); } else { instance.SaveAndApplyGraphicsSettingsCustom(ref currentPlayerSettingsRaw); } PlatformPrefs.Save(); } } public const float ConfirmSeconds = 10f; public const int FpsMin = 30; public const int FpsUnlimited = 361; private const int MinWidth = 1280; private const int MinHeight = 720; private const string PrefWidth = "Screenmanager Resolution Width"; private const string PrefHeight = "Screenmanager Resolution Height"; private const string PrefUseNative = "Screenmanager Resolution Use Native"; private const string PrefFullscreenMode = "Screenmanager Fullscreen mode"; private const float ListSeconds = 2f; private static IDisplayHost s_host = new UnityHost(); private static Choice s_pending; private static bool s_hasPending; private static Choice s_applied; private static int s_oldW; private static int s_oldH; private static FullScreenMode s_oldMode; private static RefreshRate s_oldRefresh; private static float s_deadline; private static List<Resolution> s_list; private static float s_listAt = -100f; private static bool s_listPresenter; public static IDisplayHost Host { get { return s_host; } set { s_host = value ?? new UnityHost(); Confirming = false; s_hasPending = false; s_list = null; LastResult = ""; } } public static string LastResult { get; private set; } = ""; public static bool Confirming { get; private set; } public static float Remaining { get { if (!Confirming) { return 0f; } return Math.Max(0f, s_deadline - Host.Now); } } private static bool GuardEnabled { get { if (GraphicsConfig.FixUnsupportedResolution != null) { return GraphicsConfig.FixUnsupportedResolution.Value; } return true; } } public static Choice Current => new Choice { Width = Host.Width, Height = Host.Height, Window = (((int)Host.Mode == 3) ? WindowChoice.Windowed : WindowChoice.Fullscreen) }; public static Choice Pending { get { if (!s_hasPending) { return Current; } return s_pending; } } public static bool HasPendingChange { get { if (s_hasPending) { return !Same(s_pending, Current); } return false; } } public static int HiddenInFullscreen => AllModes().Count - Offered(WindowChoice.Fullscreen).Count; private static bool Same(Choice a, Choice b) { if (a.Width == b.Width && a.Height == b.Height) { return a.Window == b.Window; } return false; } public static List<Resolution> Offered(WindowChoice window) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) List<Resolution> list = AllModes(); if (window == WindowChoice.Windowed) { return list; } List<Resolution> list2 = new List<Resolution>(list.Count); foreach (Resolution item in list) { Resolution current = item; if (Allowed(((Resolution)(ref current)).width, ((Resolution)(ref current)).height, window, out var _)) { list2.Add(current); } } return list2; } private static List<Resolution> AllModes() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) float now = Host.Now; bool frameGenOn = Host.FrameGenOn; if (s_list != null && now - s_listAt < 2f && frameGenOn == s_listPresenter) { return s_list; } Dictionary<long, Resolution> dictionary = new Dictionary<long, Resolution>(); Resolution[] array = (Resolution[])(((object)Host.Modes) ?? ((object)new Resolution[0])); for (int i = 0; i < array.Length; i++) { Resolution value = array[i]; if (((Resolution)(ref value)).width < 1280 || ((Resolution)(ref value)).height < 720) { continue; } long key = ((long)((Resolution)(ref value)).width << 32) | (uint)((Resolution)(ref value)).height; if (dictionary.TryGetValue(key, out var value2)) { RefreshRate refreshRateRatio = ((Resolution)(ref value)).refreshRateRatio; double value3 = ((RefreshRate)(ref refreshRateRatio)).value; refreshRateRatio = ((Resolution)(ref value2)).refreshRateRatio; if (!(value3 > ((RefreshRate)(ref refreshRateRatio)).value)) { continue; } } dictionary[key] = value; } List<Resolution> list = new List<Resolution>(dictionary.Values); Choice current = Current; if (current.Width > 0 && !dictionary.ContainsKey(((long)current.Width << 32) | (uint)current.Height)) { Resolution item = default(Resolution); ((Resolution)(ref item)).width = current.Width; ((Resolution)(ref item)).height = current.Height; Resolution desktop = Host.Desktop; ((Resolution)(ref item)).refreshRateRatio = ((Resolution)(ref desktop)).refreshRateRatio; list.Add(item); } list.Sort((Resolution a, Resolution b) => (((Resolution)(ref a)).width == ((Resolution)(ref b)).width) ? ((Resolution)(ref b)).height.CompareTo(((Resolution)(ref a)).height) : ((Resolution)(ref b)).width.CompareTo(((Resolution)(ref a)).width)); s_list = list; s_listAt = now; s_listPresenter = frameGenOn; return list; } public static bool Allowed(int width, int height, WindowChoice window, out string why) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) why = ""; if (window == WindowChoice.Windowed || !GuardEnabled || !Host.FrameGenOn) { return true; } Resolution desktop = Host.Desktop; if (((Resolution)(ref desktop)).width <= 0 || ((Resolution)(ref desktop)).height <= 0 || !ShapeDiffers(width, height, ((Resolution)(ref desktop)).width, ((Resolution)(ref desktop)).height)) { return true; } why = $"{width} x {height} is another shape than the display ({((Resolution)(ref desktop)).width} x {((Resolution)(ref desktop)).height}): with frame generation on that crashed the game's graphics driver"; return false; } private static bool ShapeDiffers(int w, int h, int nw, int nh) { return Math.Abs((double)w / (double)h - (double)nw / (double)nh) > 0.01; } public static void SelectResolution(int width, int height) { if (!Confirming) { Choice pending = Pending; pending.Width = width; pending.Height = height; s_pending = pending; s_hasPending = true; } } public static void SelectWindow(WindowChoice window) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (!Confirming) { Choice pending = Pending; pending.Window = window; if (!Allowed(pending.Width, pending.Height, window, out var _)) { Resolution desktop = Host.Desktop; LastResult = $"Fullscreen cannot use {pending.Width} x {pending.Height} while frame generation is loaded (another shape than the display): " + $"{((Resolution)(ref desktop)).width} x {((Resolution)(ref desktop)).height} picked."; pending.Width = ((Resolution)(ref desktop)).width; pending.Height = ((Resolution)(ref desktop)).height; } s_pending = pending; s_hasPending = true; } } public static void ClearPending() { if (!Confirming) { s_hasPending = false; } } public static bool CanApply(out string why) { why = Host.BlockedReason; if (why.Length > 0) { return false; } if (Confirming) { why = "Answer the question first: keep or revert."; return false; } if (!HasPendingChange) { why = "Pick a resolution or a window mode first."; return false; } Choice choice = s_pending; return Allowed(choice.Width, choice.Height, choice.Window, out why); } public static bool Apply() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) if (!CanApply(out var why)) { LastResult = why; return false; } Choice choice = s_pending; s_oldW = Host.Width; s_oldH = Host.Height; s_oldMode = Host.Mode; Resolution desktop = Host.Desktop; s_oldRefresh = ((Resolution)(ref desktop)).refreshRateRatio; FullScreenMode mode = (FullScreenMode)((choice.Window != WindowChoice.Windowed) ? 1 : 3); try { Host.SetResolution(choice.Width, choice.Height, mode, RefreshFor(choice.Width, choice.Height)); } catch (Exception ex) { LastResult = "The game refused the change: " + ex.Message; Plugin.LogWarning("[Display] SetResolution failed: " + ex.Message); return false; } s_applied = choice; Confirming = true; s_deadline = Host.Now + 10f; s_list = null; LastResult = ""; Plugin.LogInfo($"[Display] Applied {choice} (was {s_oldW} x {s_oldH} {s_oldMode}): kept or reverted within {10f:0} s."); return true; } private static RefreshRate RefreshFor(int w, int h) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) Resolution desktop = Host.Desktop; RefreshRate refreshRateRatio; if (((Resolution)(ref desktop)).width == w && ((Resolution)(ref desktop)).height == h) { refreshRateRatio = ((Resolution)(ref desktop)).refreshRateRatio; if (((RefreshRate)(ref refreshRateRatio)).value > 1.0) { return ((Resolution)(ref desktop)).refreshRateRatio; } } RefreshRate refreshRateRatio2 = ((Resolution)(ref desktop)).refreshRateRatio; double num = -1.0; Resolution[] array = (Resolution[])(((object)Host.Modes) ?? ((object)new Resolution[0])); for (int i = 0; i < array.Length; i++) { Resolution val = array[i]; if (((Resolution)(ref val)).width == w && ((Resolution)(ref val)).height == h) { refreshRateRatio = ((Resolution)(ref val)).refreshRateRatio; if (((RefreshRate)(ref refreshRateRatio)).value > num) { refreshRateRatio2 = ((Resolution)(ref val)).refreshRateRatio; refreshRateRatio = ((Resolution)(ref val)).refreshRateRatio; num = ((RefreshRate)(ref refreshRateRatio)).value; } } } return refreshRateRatio2; } public static void Keep() { if (Confirming) { Confirming = false; Choice choice = s_applied; try { Host.SetPref("Screenmanager Resolution Width", choice.Width); Host.SetPref("Screenmanager Resolution Height", choice.Height); Host.SetPref("Screenmanager Fullscreen mode", (choice.Window != WindowChoice.Windowed) ? 1 : 3); Host.SetPref("Screenmanager Resolution Use Native", 0); Host.SavePrefs(); } catch (Exception ex) { Plugin.LogWarning("[Display] Could not save the screen state: " + ex.Message); } s_hasPending = false; s_list = null; LastResult = $"Kept {choice}."; Plugin.LogInfo($"[Display] Kept {choice}."); } } public static void Revert(string reason) { //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) if (Confirming) { Confirming = false; try { Host.SetResolution(s_oldW, s_oldH, s_oldMode, s_oldRefresh); } catch (Exception ex) { Plugin.LogWarning("[Display] Could not switch back: " + ex.Message); } s_hasPending = false; s_list = null; LastResult = $"Reverted to {s_oldW} x {s_oldH} ({reason})."; Plugin.LogInfo($"[Display] Reverted to {s_oldW} x {s_oldH} {s_oldMode} ({reason})."); } } public static void Tick() { if (Confirming && Host.Now >= s_deadline) { Revert($"no answer in {10f:0} s"); } } public static bool TryGetPresent(out int fpsLimit, out bool vsync) { if (!Host.GetPresent(out var fpsLimit2, out vsync)) { fpsLimit = 361; return false; } fpsLimit = ((fpsLimit2 < 30 || fpsLimit2 > 360) ? 361 : fpsLimit2); return true; } public static void SetFpsLimit(int limit) { if (TryGetPresent(out var _, out var vsync) && Host.BlockedReason.Length <= 0) { Present(Mathf.Clamp(limit, 30, 361), vsync); } } public static void SetVsync(bool on) { if (TryGetPresent(out var fpsLimit, out var _) && Host.BlockedReason.Length <= 0) { Present(fpsLimit, on); } } private static void Present(int fps, bool vsync) { try { Host.SetPresent(fps, vsync); LastResult = ""; Plugin.LogInfo("[Display] FPS limit " + ((fps >= 361) ? "unlimited" : fps.ToString()) + ", Vsync " + (vsync ? "on" : "off") + " saved through the game's graphics settings."); } catch (Exception ex) { LastResult = "The game's graphics settings refused the change: " + ex.Message; Plugin.LogWarning("[Display] Could not save the FPS limit / Vsync: " + ex.Message); } } } public static class DisplayPacing { private static FieldRef<PresentManager, bool> s_vsyncField; private static bool s_vsyncKnown; private static bool s_vsyncOn; private static string s_logged = ""; public static int DisplayHz { get { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) Resolution currentResolution = Screen.currentResolution; RefreshRate refreshRateRatio = ((Resolution)(ref currentResolution)).refreshRateRatio; double value = ((RefreshRate)(ref refreshRateRatio)).value; if (!(value > 1.0)) { return 60; } return Mathf.RoundToInt((float)value); } } public static int LimitSetting { get { if (GraphicsConfig.FrameGenLimit == null) { return 0; } return GraphicsConfig.FrameGenLimit.Value; } } public static int FrameGenTargetFps { get { if (LimitSetting <= 0 || VsyncOn) { return DisplayHz; } return LimitSetting; } } public static bool Half { get { if (GraphicsConfig.HalfRefreshRate != null) { return GraphicsConfig.HalfRefreshRate.Value; } return false; } } public static bool FillChosen { get { if (GraphicsConfig.FrameGenPacing != null) { return GraphicsConfig.FrameGenPacing.Value == GraphicsConfig.FrameGenPacingMode.Fill; } return false; } } public static bool FillActive { get { if (NativeUpscaler.FrameGenActive && FillChosen) { return NativeUpscaler.SelectedFrameGen == 1; } return false; } } public static bool VsyncOn { get { if (!s_vsyncKnown) { return QualitySettings.vSyncCount > 0; } return s_vsyncOn; } } public static int RenderCap(bool vsyncOn) { int num = Math.Max(15, DisplayHz / 2); if (NativeUpscaler.FrameGenActive) { if (vsyncOn) { return -1; } int num2 = (FillActive ? FrameGenTargetFps : (FrameGenTargetFps / 2)); if (Half) { num2 = Math.Min(num2, num); } return Math.Max(15, num2); } if (!Half) { return -1; } return num; } public static void Apply(PresentManager manager, ref int limit) { if (manager != null) { if (s_vsyncField == null) { s_vsyncField = AccessTools.FieldRefAccess<PresentManager, bool>("m_setVSyncEnabled"); } s_vsyncOn = s_vsyncField.Invoke(manager); s_vsyncKnown = true; } int num = RenderCap(VsyncOn); if (num > 0) { limit = ((limit < 0) ? num : Math.Min(limit, num)); } bool frameGenActive = NativeUpscaler.FrameGenActive; string text = $"{DisplayHz}|{frameGenActive}|{FillActive}|{FrameGenTargetFps}|{Half}|{VsyncOn}|{num}"; if (text != s_logged) { s_logged = text; string text2 = ((!frameGenActive) ? "off" : (FillActive ? $"on, fills up to {FrameGenTargetFps} fps shown (real frames first)" : $"on, one frame halfway, up to {FrameGenTargetFps} fps shown")); Plugin.LogInfo(string.Format("[Display] display {0} Hz, frame generation {1}, half refresh {2}, Vsync {3}: ", DisplayHz, text2, Half ? "on" : "off", VsyncOn ? "on" : "off") + ((num > 0) ? $"the game renders at most {num} fps" : "no cap from these settings") + " (the game's own limits still apply)"); } } public static string StatusText(bool rich) { int displayHz = DisplayHz; int num = RenderCap(VsyncOn); int frameGenTargetFps = FrameGenTargetFps; int limitSetting = LimitSetting; bool frameGenActive = NativeUpscaler.FrameGenActive; bool vsyncOn = VsyncOn; bool fillActive = FillActive; string text = string.Format("Display {0} Hz • Vsync {1}", displayHz, vsyncOn ? "on" : "off"); text = ((frameGenActive && fillActive) ? (text + $" • frame generation fills up to {frameGenTargetFps} fps shown, real frames first" + ((num > 0) ? $" (the game renders up to {num})" : "")) : ((frameGenActive && vsyncOn) ? (text + $" • frame generation in step with the display: up to {displayHz / 2} rendered + {displayHz / 2} generated") : (frameGenActive ? (text + $" • frame generation limited to {frameGenTargetFps} fps shown: the game renders up to {num}") : ((num <= 0) ? (text + " • no cap") : (text + $" • the game renders up to {num} fps (half refresh)"))))); string text2 = ""; if (frameGenActive && !vsyncOn && limitSetting > displayHz) { text2 = $"The limit is above the display's {displayHz} Hz: the extra frames tear."; } else if (frameGenActive && !vsyncOn && limitSetting == 0) { text2 = $"Limit 0 = the display's {displayHz} Hz. For a VRR display set it a few below (e.g. {Math.Max(30, displayHz - 3)}) so frames stay in its range."; } else if (frameGenActive && !vsyncOn && limitSetting > 0 && limitSetting < displayHz && displayHz % limitSetting != 0 && EvenLimits(displayHz).Length > 0) { text2 = $"Without VRR, {limitSetting} fps on {displayHz} Hz holds frames for uneven numbers of refreshes (judder): {EvenLimits(displayHz)} keep them even."; } else if (frameGenActive && vsyncOn && limitSetting > 0) { text2 = "With the game's Vsync on the limiter is not needed: the display's refresh rate sets the pace."; } else if (frameGenActive && !fillActive && FillChosen && NativeUpscaler.SelectedFrameGen == 2) { text2 = "DLSS Frame Generation paces one frame halfway (fill pacing is FSR 3 only)."; } else if (!frameGenActive && Half && !vsyncOn) { text2 = "With Vsync off this is a frame cap: smooth with VRR, otherwise switch the game's Vsync on for every second refresh."; } if (text2.Length == 0) { return text; } if (!rich) { return text + "\n" + text2; } return text + "\n<size=9><color=#9A8A6A>" + text2 + " In menus the game caps at 60 fps.</color></size>"; } private static string EvenLimits(int display) { List<int> list = new List<int>(); for (int i = 2; i <= 8; i++) { if (list.Count >= 2) { break; } if (display % i == 0 && display / i >= 30) { list.Add(display / i); } } return string.Join(" or ", list); } } public static class DisplayResolutionGuard { private const string PrefWidth = "Screenmanager Resolution Width"; private const string PrefHeight = "Screenmanager Resolution Height"; private const string PrefUseNative = "Screenmanager Resolution Use Native"; private const string PrefFullscreenMode = "Screenmanager Fullscreen mode"; private const float WatchSeconds = 20f; private const float CheckInterval = 0.25f; private const int MaxFixes = 3; private static int s_badW; private static int s_badH; private static Resolution s_best; private static FullScreenMode s_mode; private static string s_reason = ""; private static float s_watchUntil = -1f; private static float s_nextCheck; private static int s_fixes; public static string LastAction { get; private set; } = ""; private static bool Enabled { get { if (GraphicsConfig.FixUnsupportedResolution != null) { return GraphicsConfig.FixUnsupportedResolution.Value; } return true; } } private static bool PresenterLoaded => !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("GO_FG_LAYER_LIB")); private static bool FrameGenOnAtStart { get { if (PresenterLoaded && GraphicsConfig.NativeFrameGeneration != null) { if (GraphicsConfig.NativeFrameGeneration.Value != GraphicsConfig.FrameGenChoice.FSR3) { return GraphicsConfig.NativeFrameGeneration.Value == GraphicsConfig.FrameGenChoice.DLSS; } return true; } return false; } } public static void OnLoad() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Invalid comparison between Unknown and I4 //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) try { int num = PlayerPrefs.GetInt("Screenmanager Resolution Width", 0); int num2 = PlayerPrefs.GetInt("Screenmanager Resolution Height", 0); FullScreenMode val = SavedMode(); bool flag = PlayerPrefs.GetInt("Screenmanager Resolution Use Native", 0) != 0; Resolution[] resolutions = Screen.resolutions; Resolution currentResolution = Screen.currentResolution; string text = (FrameGenOnAtStart ? "on at start" : (PresenterLoaded ? "off (presenter preloaded)" : "off")); string text2 = string.Format("saved {0}x{1} {2}{3}, window now {4}x{5} {6}, ", num, num2, val, flag ? " (use native)" : "", Screen.width, Screen.height, Screen.fullScreenMode); object[] obj = new object[5] { ((Resolution)(ref currentResolution)).width, ((Resolution)(ref currentResolution)).height, null, null, null }; RefreshRate refreshRateRatio = ((Resolution)(ref currentResolution)).refreshRateRatio; obj[2] = ((RefreshRate)(ref refreshRateRatio)).value; obj[3] = text; obj[4] = ModeList(); string text3 = text2 + string.Format("desktop {0}x{1} @ {2:0.##} Hz, frame generation {3}, display modes [{4}]", obj); Resolution native; string text4 = ((!Enabled) ? "off ([Display] FixUnsupportedResolution = false)" : (((int)val == 3) ? "windowed: any size is fine" : (flag ? "Unity uses the display's own size" : ((num > 0 && num2 > 0) ? ((resolutions == null || resolutions.Length == 0) ? "the display lists no modes: not checked" : ((!IsMode(resolutions, num, num2)) ? Replace(num, num2, val, Largest(resolutions), "not a mode of this display") : ((!FrameGenOnAtStart || !Native(resolutions, out native) || !ShapeDiffers(num, num2, ((Resolution)(ref native)).width, ((Resolution)(ref native)).height)) ? "a mode of this display: kept" : Replace(num, num2, val, native, $"another shape than the display ({((Resolution)(ref native)).width}x{((Resolution)(ref native)).height}) while frame generation is on")))) : "nothing saved")))); Plugin.LogInfo("[Display] Startup resolution check: " + text3 + " -> " + text4); } catch (Exception ex) { Plugin.LogWarning("[Display] Could not check the saved screen resolution: " + ex.Message); } } private static FullScreenMode SavedMode() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) int num = PlayerPrefs.GetInt("Screenmanager Fullscreen mode", -1); if (num < 0 || num > 3) { return Screen.fullScreenMode; } return (FullScreenMode)num; } public static void Tick() { if (s_watchUntil < 0f) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; if (realtimeSinceStartup > s_watchUntil) { s_watchUntil = -1f; } else { if (realtimeSinceStartup < s_nextCheck) { return; } s_nextCheck = realtimeSinceStartup + 0.25f; try { if (Enabled && s_fixes < 3 && Screen.width == s_badW && Screen.height == s_badH) { Fix("again, Unity still applied the old value"); } } catch (Exception ex) { s_watchUntil = -1f; Plugin.LogWarning("[Display] Could not check the screen resolution: " + ex.Message); } } } private static string Replace(int w, int h, FullScreenMode mode, Resolution best, string reason) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) s_badW = w; s_badH = h; s_best = best; s_mode = mode; s_reason = reason; Fix("at start"); s_watchUntil = Time.realtimeSinceStartup + 20f; return $"{reason}: {((Resolution)(ref best)).width}x{((Resolution)(ref best)).height} set"; } private static void Fix(string when) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) s_fixes++; PlayerPrefs.SetInt("Screenmanager Resolution Width", ((Resolution)(ref s_best)).width); PlayerPrefs.SetInt("Screenmanager Resolution Height", ((Resolution)(ref s_best)).height); PlayerPrefs.Save(); Screen.SetResolution(((Resolution)(ref s_best)).width, ((Resolution)(ref s_best)).height, s_mode, ((Resolution)(ref s_best)).refreshRateRatio); object[] obj = new object[6] { s_badW, s_badH, s_reason, ((Resolution)(ref s_best)).width, ((Resolution)(ref s_best)).height, null }; RefreshRate refreshRateRatio = ((Resolution)(ref s_best)).refreshRateRatio; obj[5] = ((RefreshRate)(ref refreshRateRatio)).value; LastAction = string.Format("The saved resolution {0}x{1} was {2}: switched to {3}x{4} at {5:0} Hz.", obj); object[] obj2 = new object[6] { s_badW, s_badH, s_reason, ((Resolution)(ref s_best)).width, ((Resolution)(ref s_best)).height, null }; refreshRateRatio = ((Resolution)(ref s_best)).refreshRateRatio; obj2[5] = ((RefreshRate)(ref refreshRateRatio)).value; Plugin.LogWarning(string.Format("[Display] Saved screen resolution {0}x{1} is {2}: set {3}x{4} at {5:0.##} Hz ", obj2) + when + " ([Display] FixUnsupportedResolution = false leaves it)."); } public static string FrameGenShapeProblem() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 try { if (!Enabled || (int)Screen.fullScreenMode == 3) { return ""; } Resolution[] resolutions = Screen.resolutions; if (resolutions == null || resolutions.Length == 0 || !Native(resolutions, out var native) || !ShapeDiffers(Screen.width, Screen.height, ((Resolution)(ref native)).width, ((Resolution)(ref native)).height)) { return ""; } return $"not started: the fullscreen resolution {Screen.width}x{Screen.height} has another shape than the monitor ({((Resolution)(ref native)).width}x{((Resolution)(ref native)).height}), " + $"which crashed the graphics driver with frame generation (Linux, XWayland). Pick {((Resolution)(ref native)).width}x{((Resolution)(ref native)).height} (or windowed) in the graphics " + "settings, then switch frame generation on"; } catch (Exception) { return ""; } } private static bool Native(Resolution[] modes, out Resolution native) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) Resolution val = (native = Screen.currentResolution); RefreshRate refreshRateRatio; if (((Resolution)(ref val)).width > 0 && ((Resolution)(ref val)).height > 0) { refreshRateRatio = ((Resolution)(ref val)).refreshRateRatio; if (((RefreshRate)(ref refreshRateRatio)).value > 1.0) { return true; } } int num = ((((Resolution)(ref val)).width > 0) ? ((Resolution)(ref val)).width : Display.main.systemWidth); int num2 = ((((Resolution)(ref val)).height > 0) ? ((Resolution)(ref val)).height : Display.main.systemHeight); native = default(Resolution); bool flag = false; for (int i = 0; i < modes.Length; i++) { Resolution val2 = modes[i]; if (((Resolution)(ref val2)).width != num || ((Resolution)(ref val2)).height != num2) { continue; } if (flag) { refreshRateRatio = ((Resolution)(ref val2)).refreshRateRatio; double value = ((RefreshRate)(ref refreshRateRatio)).value; refreshRateRatio = ((Resolution)(ref native)).refreshRateRatio; if (!(value > ((RefreshRate)(ref refreshRateRatio)).value)) { continue; } } native = val2; flag = true; } return flag; } private static bool ShapeDiffers(int w, int h, int nw, int nh) { return Math.Abs((double)w / (double)h - (double)nw / (double)nh) > 0.01; } private static bool IsMode(Resolution[] modes, int w, int h) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < modes.Length; i++) { Resolution val = modes[i]; if (((Resolution)(ref val)).width == w && ((Resolution)(ref val)).height == h) { return true; } } return false; } private static Resolution Largest(Resolution[] modes) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) Resolution result = modes[0]; for (int i = 1; i < modes.Length; i++) { Resolution val = modes[i]; long num = (long)((Resolution)(ref result)).width * (long)((Resolution)(ref result)).height; long num2 = (long)((Resolution)(ref val)).width * (long)((Resolution)(ref val)).height; if (num2 <= num) { if (num2 != num) { continue; } RefreshRate refreshRateRatio = ((Resolution)(ref val)).refreshRateRatio; double value = ((RefreshRate)(ref refreshRateRatio)).value; refreshRateRatio = ((Resolution)(ref result)).refreshRateRatio; if (!(value > ((RefreshRate)(ref refreshRateRatio)).value)) { continue; } } result = val; } return result; } private static string ModeList() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) List<string> list = new List<string>(); Resolution[] resolutions = Screen.resolutions; for (int i = 0; i < resolutions.Length; i++) { Resolution val = resolutions[i]; string item = ((Resolution)(ref val)).width + "x" + ((Resolution)(ref val)).height; if (!list.Contains(item)) { list.Add(item); } } return string.Join(", ", list); } } public class FpsCounterHUD : MonoBehaviour { private const int SampleCapacity = 1000; private const int AverageWindow = 60; private readonly float[] m_frameDeltas = new float[1000]; private readonly float[] m_sortedDeltas = new float[1000]; private int m_sampleCount; private int m_sampleIndex; private float m_updateTimer; private const float UpdateInterval = 0.25f; private const float MaxSampleSeconds = 1f; private float m_displayFps; private float m_displayMs; private float m_display1PercentLow; private float m_display01PercentLow; private long m_displayTotalMemMb; private string m_fpsLine = ""; private string m_realLine = ""; private float m_colorFps; private string m_lowsLine = ""; private string m_memLine = ""; private string m_vramLine = ""; private bool m_rebuildRequested = true; private bool m_wasActive; private GUIStyle m_fpsStyle; private GUIStyle m_subStyle; private void Awake() { Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); GraphicsConfig.OnSettingsChanged += RequestRebuild; } private void OnDestroy() { GraphicsConfig.OnSettingsChanged -= RequestRebuild; } private void RequestRebuild() { m_rebuildRequested = true; } private void Update() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (Input.GetKeyDown(GraphicsConfig.FpsHudToggleKey.Value)) { GraphicsConfig.EnableFpsHud.Value = !GraphicsConfig.EnableFpsHud.Value; } if (!GraphicsConfig.EnableFpsHud.Value || !GraphicsConfig.MasterEnable.Value) { m_wasActive = false; return; } if (!m_wasActive) { m_wasActive = true; m_sampleCount = 0; m_sampleIndex = 0; m_updateTimer = 0f; m_rebuildRequested = true; } float unscaledDeltaTime = Time.unscaledDeltaTime; if (unscaledDeltaTime < 1f) { m_frameDeltas[m_sampleIndex] = unscaledDeltaTime; m_sampleIndex = (m_sampleIndex + 1) % 1000; if (m_sampleCount < 1000) { m_sampleCount++; } } m_updateTimer += unscaledDeltaTime; if (m_updateTimer >= 0.25f || m_rebuildRequested) { m_updateTimer = 0f; m_rebuildRequested = false; CalculateMetrics(); BuildLines(); } } private void CalculateMetrics() { if (m_sampleCount != 0) { for (int i = 0; i < m_sampleCount; i++) { m_sortedDeltas[i] = m_frameDeltas[i]; } int num = Mathf.Min(m_sampleCount, 60); float num2 = 0f; for (int j = 1; j <= num; j++) { num2 += m_frameDeltas[(m_sampleIndex - j + 1000) % 1000]; } float num3 = num2 / (float)num; m_displayFps = ((num3 > 0f) ? (1f / num3) : 0f); m_displayMs = num3 * 1000f; Array.Sort(m_sortedDeltas, 0, m_sampleCount); int num4 = Mathf.Clamp(Mathf.FloorToInt((float)m_sampleCount * 0.99f), 0, m_sampleCount - 1); float num5 = m_sortedDeltas[num4]; m_display1PercentLow = ((num5 > 0f) ? (1f / num5) : 0f); int num6 = Mathf.Clamp(Mathf.FloorToInt((float)m_sampleCount * 0.999f), 0, m_sampleCount - 1); float num7 = m_sortedDeltas[num6]; m_display01PercentLow = ((num7 > 0f) ? (1f / num7) : 0f); m_displayTotalMemMb = Profiler.GetTotalAllocatedMemoryLong() / 1048576; } } private void BuildLines() { int num = Mathf.RoundToInt(m_displayFps); float num2 = (NativeUpscaler.FrameGenActive ? NativeUpscaler.FrameGenGeneratedFps : 0f); if (num2 > 0.5f) { m_colorFps = m_displayFps + num2; m_fpsLine = $"{Mathf.RoundToInt(m_colorFps)} FPS <size=13><color=#C8A865>with frame gen</color></size>"; m_realLine = (GraphicsConfig.FpsHudShowFrameTime.Value ? $"Real: <color=#F0E6D2>{num} FPS</color> ({m_displayMs:F1} ms) | generated <color=#F0E6D2>{Mathf.RoundToInt(num2)}</color>" : $"Real: <color=#F0E6D2>{num} FPS</color> | generated <color=#F0E6D2>{Mathf.RoundToInt(num2)}</color>"); } else { m_colorFps = m_displayFps; m_fpsLine = (GraphicsConfig.FpsHudShowFrameTime.Value ? $"{num} FPS <size=13><color=#C8A865>({m_displayMs:F1} ms)</color></size>" : $"{num} FPS"); m_realLine = ""; } m_lowsLine = $"1% Low: <color=#F5D058>{Mathf.RoundToInt(m_display1PercentLow)}</color> | 0.1%: <color=#F87171>{Mathf.RoundToInt(m_display01PercentLow)}</color>"; string arg = (NativeUpscaler.IsActive ? string.Format("{0} {1} {2}x{3}", (NativeUpscaler.SelectedBackend == 2) ? "DLSS" : "FSR 3", NativeUpscaler.ModeLabel, NativeUpscaler.RenderWidth, NativeUpscaler.RenderHeight) : (Fsr1Scaler.IsActive ? $"FSR 1 {Fsr1Scaler.RenderWidth}x{Fsr1Scaler.RenderHeight}" : $"{GraphicsConfig.CustomRenderScalePercent.Value}%")); m_memLine = $"Mem: <color=#F0E6D2>{m_displayTotalMemMb}MB</color> | Scale: <color=#F0E6D2>{arg}</color>"; if (GraphicsConfig.FpsHudShowVram.Value) { VramTracker.VramProjection projection = VramTracker.GetProjection(); string statusColorHex = VramTracker.GetStatusColorHex(projection.HealthStatus); if (projection.DetectedGpuDriverMB > 0f) { m_vramLine = $"VRAM: <color={statusColorHex}>{projection.DetectedGpuDriverGB:F1}G</color> / {VramTracker.TotalVramGB:F1}G [est. <color={statusColorHex}>{projection.ProjectedTotalGB:F1}G</color>]"; } else { m_vramLine = $"VRAM est.: <color={statusColorHex}>{projection.ProjectedTotalGB:F1}G</color> / {VramTracker.TotalVramGB:F1}G (<color={statusColorHex}>{projection.ProjectedUsagePercent:F0}%</color>)"; } } } private void InitStyles() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_0074: Unknown result type (might be due to invalid IL or missing references) float value = GraphicsConfig.FpsHudTextScale.Value; if (m_fpsStyle == null) { m_fpsStyle = new GUIStyle(); m_fpsStyle.fontStyle = (FontStyle)1; m_fpsStyle.alignment = (TextAnchor)3; m_fpsStyle.richText = true; } if (m_subStyle == null) { m_subStyle = new GUIStyle(); m_subStyle.normal.textColor = new Color(0.78f, 0.66f, 0.4f, 0.95f); m_subStyle.alignment = (TextAnchor)3; m_subStyle.richText = true; } m_fpsStyle.fontSize = Mathf.RoundToInt(20f * value); m_subStyle.fontSize = Mathf.RoundToInt(12f * value); } private void OnGUI() { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Unknown result type (might be due to invalid IL or missing references) //IL_0342: Unknown result type (might be due to invalid IL or missing references) if (GraphicsConfig.EnableFpsHud.Value && GraphicsConfig.MasterEnable.Value) { InitStyles(); Color textColor = default(Color); if (m_colorFps >= 59.5f) { ((Color)(ref textColor))..ctor(0.32f, 0.88f, 0.55f); } else if (m_colorFps >= 29.5f) { ((Color)(ref textColor))..ctor(0.96f, 0.82f, 0.35f); } else { ((Color)(ref textColor))..ctor(0.95f, 0.4f, 0.4f); } m_fpsStyle.normal.textColor = textColor; float num = 250f * GraphicsConfig.FpsHudTextScale.Value; float num2 = 40f * GraphicsConfig.FpsHudTextScale.Value; if (m_realLine.Length > 0) { num2 += 20f * GraphicsConfig.FpsHudTextScale.Value; } if (GraphicsConfig.FpsHudShowLows.Value) { num2 += 20f * GraphicsConfig.FpsHudTextScale.Value; } if (GraphicsConfig.FpsHudShowMemory.Value) { num2 += 20f * GraphicsConfig.FpsHudTextScale.Value; } if (GraphicsConfig.FpsHudShowVram.Value) { num2 += 20f * GraphicsConfig.FpsHudTextScale.Value; } float num3 = 15f; float num4 = 15f; switch (GraphicsConfig.FpsHudPosition.Value) { case GraphicsConfig.HudCorner.TopRight: num3 = (float)Screen.width - num - 15f; num4 = 15f; break; case GraphicsConfig.HudCorner.TopLeft: num3 = 15f; num4 = 15f; break; case GraphicsConfig.HudCorner.BottomRight: num3 = (float)Screen.width - num - 15f; num4 = (float)Screen.height - num2 - 15f; break; case GraphicsConfig.HudCorner.BottomLeft: num3 = 15f; num4 = (float)Screen.height - num2 - 15f; break; } Rect val = default(Rect); ((Rect)(ref val))..ctor(num3, num4, num, num2); Color color = GUI.color; float num5 = Mathf.Clamp(GraphicsConfig.FpsHudBackgroundAlpha.Value, 0.05f, 1f); GUI.color = new Color(0.02f, 0.02f, 0.04f, num5); GUI.DrawTexture(val, (Texture)(object)Texture2D.whiteTexture); GUI.color = new Color(0.85f, 0.68f, 0.28f, 0.7f); GUI.DrawTexture(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y, ((Rect)(ref val)).width, 1f), (Texture)(object)Texture2D.whiteTexture); GUI.DrawTexture(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y + ((Rect)(ref val)).height - 1f, ((Rect)(ref val)).width, 1f), (Texture)(object)Texture2D.whiteTexture); GUI.DrawTexture(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y + 1f, 1f, ((Rect)(ref val)).height - 2f), (Texture)(object)Texture2D.whiteTexture); GUI.DrawTexture(new Rect(((Rect)(ref val)).x + ((Rect)(ref val)).width - 1f, ((Rect)(ref val)).y + 1f, 1f, ((Rect)(ref val)).height - 2f), (Texture)(object)Texture2D.whiteTexture); GUI.color = color; GUILayout.BeginArea(new Rect(((Rect)(ref val)).x + 8f, ((Rect)(ref val)).y + 5f, ((Rect)(ref val)).width - 16f, ((Rect)(ref val)).height - 8f)); GUILayout.Label(m_fpsLine, m_fpsStyle, Array.Empty<GUILayoutOption>()); if (m_realLine.Length > 0) { GUILayout.Label(m_realLine, m_subStyle, Array.Empty<GUILayoutOption>()); } if (GraphicsConfig.FpsHudShowLows.Value) { GUILayout.Label(m_lowsLine, m_subStyle, Array.Empty<GUILayoutOption>()); } if (GraphicsConfig.FpsHudShowMemory.Value) { GUILayout.Label(m_memLine, m_subStyle, Array.Empty<GUILayoutOption>()); } if (GraphicsConfig.FpsHudShowVram.Value) { GUILayout.Label(m_vramLine, m_subStyle, Array.Empty<GUILayoutOption>()); } GUILayout.EndArea(); } } } public static class Fsr1Scaler { public enum Pick { Vanilla, Fsr1, Fsr3, Dlss } [CompilerGenerated] private static class <>O { public static CameraCallback <0>__OnPreCull; } private static readonly int SrcSizeId = Shader.PropertyToID("_GoSrcSize"); private static readonly int ParamsId = Shader.PropertyToID("_GoParams"); private static UpscaledFrameBuffer s_ufb; private static Camera s_wantCam; private static Camera s_cam; private static CommandBuffer s_cb; private static bool s_attached; private static bool s_hooked; private static bool s_failed; private static RenderTexture s_mid; private static float s_nextCameraSearch; public static bool IsActive { get; private set; } public static string StatusLine { get; private set; } = ""; public static int RenderWidth { get; private set; } public static int RenderHeight { get; private set; } public static int OutputWidth { get; private set; } public static int OutputHeight { get; private set; } public static bool Sharpening { get; private set; } public static RenderTexture Upscaled => s_mid; public static bool Chosen { get { if (GraphicsConfig.UpscaleFilter != null && GraphicsConfig.UpscaleFilter.Value == GraphicsConfig.GameScalerFilter.FSR1) { return NativeUpscaler.SelectedBackend == 0; } return false; } } public static bool Available { get { if ((Object)(object)DepthCopy.Fsr1EasuMaterial != (Object)null) { return (Object)(object)DepthCopy.Fsr1RcasMaterial != (Object)null; } return false; } } public static string Why => DepthCopy.Fsr1Why; public static Pick Picked { get { switch (NativeUpscaler.SelectedBackend) { case 1: return Pick.Fsr3; case 2: return Pick.Dlss; default: if (!Chosen) { return Pick.Vanilla; } return Pick.Fsr1; } } } public static void Choose(Pick pick) { switch (pick) { case Pick.Fsr3: if (GraphicsConfig.Scaler != null) { GraphicsConfig.Scaler.Value = GraphicsConfig.ScalerChoice.FSR3; } return; case Pick.Dlss: if (GraphicsConfig.Scaler != null) { GraphicsConfig.Scaler.Value = GraphicsConfig.ScalerChoice.DLSS; } return; } if (GraphicsConfig.Scaler != null) { GraphicsConfig.Scaler.Value = GraphicsConfig.ScalerChoice.Vanilla; } GraphicsConfig.UpscaleFilter.Value = ((pick == Pick.Fsr1) ? GraphicsConfig.GameScalerFilter.FSR1 : GraphicsConfig.GameScalerFilter.Game); } public static void Tick() { if (s_failed || GraphicsConfig.UpscaleFilter == null) { return; } try { RenderTexture val = null; string why; bool flag = Wanted(out why); if (flag && !FindCamera()) { flag = false; why = "FSR 1 waits for the game camera"; } if (flag) { val = GameFrameBuffer.RenderTextureOf(s_ufb); if ((Object)(object)val == (Object)null || ((Texture)val).width >= Screen.width || ((Texture)val).height >= Screen.height) { flag = false; why = "FSR 1 waits for a 3D render scale below 100 (it only scales up)"; } } if (flag) { Apply(val); return; } Release(); StatusLine = why; } catch (Exception ex) { s_failed = true; try { Release(); } catch (Exception) { } StatusLine = "FSR 1 failed: " + ex.Message; Plugin.LogWarning("[FSR 1] " + ex?.ToString() + " - the game's own stretch takes over again."); } } public static void Shutdown() { try { Release(); } catch (Exception) { } } private static bool Wanted(out string why) { why = ""; if (!Chosen) { return false; } if (!GraphicsConfig.MasterEnable.Value) { why = "Graphics Overdrive is switched off"; return false; } if (!GameFrameBuffer.Available) { why = "the game's 3D-resolution code has changed"; return false; } if (NativeUpscaler.IsActive) { why = "FSR 1 waits for the other scaler to stop"; return false; } if (!Available) { why = Why; return false; } return true; } private static bool FindCamera() { if ((Object)(object)s_ufb == (Object)null && Time.unscaledTime >= s_nextCameraSearch) { s_nextCameraSearch = Time.unscaledTime + 1f; s_ufb = Object.FindAnyObjectByType<UpscaledFrameBuffer>(); } if ((Object)(object)s_ufb == (Object)null) { return false; } Camera val = GameFrameBuffer.CameraOf(s_ufb); s_wantCam = (((Object)(object)val != (Object)null) ? val : ((Component)s_ufb).GetComponent<Camera>()); return (Object)(object)s_wantCam != (Object)null; } private static void SetSource(Material easu, int width, int height, bool sharpen) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Invalid comparison between Unknown and I4 //IL_0061: Unknown result type (might be due to invalid IL or missing references) easu.SetVector(SrcSizeId, new Vector4((float)width, (float)height, 1f / (float)width, 1f / (float)height)); easu.SetVector(ParamsId, new Vector4(((int)QualitySettings.activeColorSpace == 1) ? 1f : 0f, sharpen ? 1f : 0f, sharpen ? 0f : 1f, 0f)); } private static void Apply(RenderTexture rt) { //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Expected O, but got Unknown //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Invalid comparison between Unknown and I4 //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Expected O, but got Unknown //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Expected O, but got Unknown //IL_02a5: Unknown result type (might be due to invalid IL or missing references) Material fsr1EasuMaterial = DepthCopy.Fsr1EasuMaterial; Material fsr1RcasMaterial = DepthCopy.Fsr1RcasMaterial; float num = Mathf.Clamp01(GraphicsConfig.Fsr1Sharpness.Value); bool flag = num > 0.0005f; int width = Screen.width; int height = Screen.height; SetSource(fsr1EasuMaterial, ((Texture)rt).width, ((Texture)rt).height, flag); if (flag) { if ((Object)(object)s_mid == (Object)null || ((Texture)s_mid).width != width || ((Texture)s_mid).height != height) { ReleaseMid(); RenderTextureFormat val = (RenderTextureFormat)(SystemInfo.SupportsRenderTextureFormat((RenderTextureFormat)8) ? 8 : 0); s_mid = new RenderTexture(width, height, 0, val, (RenderTextureReadWrite)1) { name = "GO FSR 1 upscaled", filterMode = (FilterMode)0, wrapMode = (TextureWrapMode)1, useMipMap = false, hideFlags = (HideFlags)61 }; s_mid.Create(); } fsr1RcasMaterial.SetVector(SrcSizeId, new Vector4((float)width, (float)height, 1f / (float)width, 1f / (float)height)); fsr1RcasMaterial.SetVector(ParamsId, new Vector4(((int)QualitySettings.activeColorSpace == 1) ? 1f : 0f, Mathf.Pow(2f, -2f * (1f - num)), 1f, 0f)); } else { ReleaseMid(); } if ((Object)(object)s_cam != (Object)(object)s_wantCam) { Detach(); s_cam = s_wantCam; } if (s_cb == null) { s_cb = new CommandBuffer { name = "GO FSR 1 upscale" }; } if (!s_attached) { s_cam.AddCommandBuffer((CameraEvent)20, s_cb); s_attached = true; } if (!s_hooked) { CameraCallback onPreCull = Camera.onPreCull; object obj = <>O.<0>__OnPreCull; if (obj == null) { CameraCallback val2 = OnPreCull; <>O.<0>__OnPreCull = val2; obj = (object)val2; } Camera.onPreCull = (CameraCallback)Delegate.Combine((Delegate?)(object)onPreCull, (Delegate?)obj); s_hooked = true; } bool isActive = IsActive; IsActive = true; Sharpening = flag; RenderWidth = ((Texture)rt).width; RenderHeight = ((Texture)rt).height; OutputWidth = width; OutputHeight = height; foreach (FrameBufferScaler item in GameFrameBuffer.Subscribers(s_ufb)) { Show(item, rt); } StatusLine = $"{((Texture)rt).width}x{((Texture)rt).height} to {width}x{height}" + (flag ? "" : ", sharpening off"); if (!isActive) { Plugin.LogInfo($"[FSR 1] on: {StatusLine} ({SystemInfo.graphicsDeviceType})"); } } private static void Show(FrameBufferScaler scaler, RenderTexture rt) { RawImage val = (((Object)(object)scaler != (Object)null) ? GameFrameBuffer.RawImageOf(scaler) : null); if (!((Object)(object)val == (Object)null)) { Texture val2 = (Texture)(object)(Sharpening ? s_mid : rt); Material val3 = (Sharpening ? DepthCopy.Fsr1RcasMaterial : DepthCopy.Fsr1EasuMaterial); if (val.texture != val2) { val.texture = val2; } if (((Graphic)val).material != val3) { ((Graphic)val).material = val3; } } } public static void OnScalerBufferCreated(FrameBufferScaler scaler) { if (!IsActive || (Object)(object)s_ufb == (Object)null || (Object)(object)scaler == (Object)null) { return; } RenderTexture val = GameFrameBuffer.RenderTextureOf(s_ufb); if ((Object)(object)val == (Object)null || ((Texture)val).width >= Screen.width || ((Texture)val).height >= Screen.height) { RawImage val2 = GameFrameBuffer.RawImageOf(scaler); if ((Object)(object)val2 != (Object)null && Ours(((Graphic)val2).material)) { ((Graphic)val2).material = null; } } else { SetSource(DepthCopy.Fsr1EasuMaterial, ((Texture)val).width, ((Texture)val).height, Sharpening); RenderWidth = ((Texture)val).width; RenderHeight = ((Texture)val).height; Show(scaler, val); } } private static void OnPreCull(Camera cam) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) if (s_cb == null || (Object)(object)cam == (Object)null || (Object)(object)cam != (Object)(object)s_cam) { return; } s_cb.Clear(); if (IsActive && Sharpening && !((Object)(object)s_mid == (Object)null)) { RenderTexture targetTexture = cam.targetTexture; Material fsr1EasuMaterial = DepthCopy.Fsr1EasuMaterial; if (!((Object)(object)targetTexture == (Object)null) && !((Object)(object)fsr1EasuMaterial == (Object)null)) { SetSource(fsr1EasuMaterial, ((Texture)targetTexture).width, ((Texture)targetTexture).height, sharpen: true); s_cb.Blit((Texture)(object)targetTexture, RenderTargetIdentifier.op_Implicit((Texture)(object)s_mid), fsr1EasuMaterial); } } } private static bool Ours(Material material) { if ((Object)(object)material != (Object)null) { if (material != DepthCopy.Fsr1EasuMaterial) { return material == DepthCopy.Fsr1RcasMaterial; } return true; } return false; } private static void Detach() { if (s_attached && (Object)(object)s_cam != (Object)null && s_cb != null) { s_cam.RemoveCommandBuffer((CameraEvent)20, s_cb); } s_attached = false; s_cam = null; } private static void ReleaseMid() { if (!((Object)(object)s_mid == (Object)null)) { s_mid.Release(); Object.Destroy((Object)(object)s_mid); s_mid = null; } } private static void Release() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown Detach(); if (s_hooked) { CameraCallback onPreCull = Camera.onPreCull; object obj = <>O.<0>__OnPreCull; if (obj == null) { CameraCallback val = OnPreCull; <>O.<0>__OnPreCull = val; obj = (object)val; } Camera.onPreCull = (CameraCallback)Delegate.Remove((Delegate?)(object)onPreCull, (Delegate?)obj); s_hooked = false; } if (s_cb != null) { s_cb.Clear(); } if (IsActive && (Object)(object)s_ufb != (Object)null) { RenderTexture texture = GameFrameBuffer.RenderTextureOf(s_ufb); foreach (FrameBufferScaler item in GameFrameBuffer.Subscribers(s_ufb)) { RawImage val2 = (((Object)(object)item != (Object)null) ? GameFrameBuffer.RawImageOf(item) : null); if (!((Object)(object)val2 == (Object)null)) { if (Ours(((Graphic)val2).material)) { ((Graphic)val2).material = null; } if ((Object)(object)s_mid != (Object)null && (object)val2.texture == s_mid) { val2.texture = (Texture)(object)texture; } } } } ReleaseMid(); if (IsActive) { Plugin.LogInfo("[FSR 1] off"); } IsActive = false; Sharpening = false; } } internal static class GameFrameBuffer { private static FieldRef<uint> s_targetVertical; private static FieldRef<bool> s_autoTarget; private static FieldRef<UpscalingAlgorithm> s_algorithm; private static FieldRef<UpscaledFrameBuffer, Camera> s_camera; private static FieldRef<UpscaledFrameBuffer, RenderTexture> s_renderTexture; private static FieldRef<UpscaledFrameBuffer, List<FrameBufferScaler>> s_subscribers; private static FieldRef<UpscaledFrameBuffer, bool> s_scaledRendering; private static FieldRef<FrameBufferScaler, RawImage> s_rawImage; private static Action<UpscaledFrameBuffer> s_createClearCamera; private static Action<UpscaledFrameBuffer> s_reassignTexture; private static Action<UpscaledFrameBuffer> s_releaseTexture; private static Action<UpscaledFrameBuffer> s_destroyClearCamera; private static bool s_resolved; private static string s_missing = ""; internal static bool Available { get { Resolve(); return s_missing.Length == 0; } } internal static uint TargetVertical { get { return s_targetVertical.Invoke(); } set { s_targetVertical.Invoke() = value; } } internal static bool AutoTarget { get { return s_autoTarget.Invoke(); } set { s_autoTarget.Invoke() = value; } } internal static UpscalingAlgorithm Algorithm { get { return s_algorithm.Invoke(); } set { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected I4, but got Unknown s_algorithm.Invoke() = (UpscalingAlgorithm)(int)value; } } internal static ref Camera CameraOf(UpscaledFrameBuffer ufb) { return ref s_camera.Invoke(ufb); } internal static Camera ControllerCamera() { GameCamera instance = GameCamera.instance; if (!((Object)(object)instance != (Object)null)) { return null; } return ((Component)instance).GetComponent<Camera>(); } internal static RenderTexture RenderTextureOf(UpscaledFrameBuffer ufb) { return s_renderTexture.Invoke(ufb); } internal static List<FrameBufferScaler> Subscribers(UpscaledFrameBuffer ufb) { return s_subscribers.Invoke(ufb); } internal static ref bool UsingScaledRendering(UpscaledFrameBuffer ufb) { return ref s_scaledRendering.Invoke(ufb); } internal static RawImage RawImageOf(FrameBufferScaler scaler) { return s_rawImage.Invoke(scaler); } internal static void CreateClearCamera(UpscaledFrameBuffer ufb) { s_createClearCamera(ufb); } internal static void ReassignTextureIfNeeded(UpscaledFrameBuffer ufb) { s_reassignTexture(ufb); } internal static void ReleaseTextureIfExists(UpscaledFrameBuffer ufb) { s_releaseTexture(ufb); } internal static void DestroyClearCameraIfExists(UpscaledFrameBuffer ufb) { s_destroyClearCamera(ufb); } private static void Resolve() { if (!s_resolved) { s_resolved = true; List<string> list = new List<string>(); s_targetVertical = Static<uint>("m_targetResolutionVertical", list); s_autoTarget = Static<bool>("m_autoTargetResolution", list); s_algorithm = Static<UpscalingAlgorithm>("m_upscalingAlgorithm", list); s_camera = Instance<UpscaledFrameBuffer, Camera>("m_camera", list); s_renderTexture = Instance<UpscaledFrameBuffer, RenderTexture>("m_renderTexture", list); s_subscribers = Instance<UpscaledFrameBuffer, List<FrameBufferScaler>>("m_subscribers", list); s_scaledRendering = Instance<UpscaledFrameBuffer, bool>("m_isUsingScaledRendering", list); s_rawImage = Instance<FrameBufferScaler, RawImage>("m_rawImage", list); s_createClearCamera = Method("CreateClearCamera", list); s_reassignTexture = Method("ReassignTextureIfNeeded", list); s_releaseTexture = Method("ReleaseTextureIfExists", list); s_destroyClearCamera = Method("DestroyClearCameraIfExists", list); s_missing = string.Join(", ", list.ToArray()); if (list.Count > 0) { Plugin.LogWarning("[RenderScale] The game's 3D-resolution code has changed (not found: " + s_missing + "). The render scale dial, FSR 3 / DLSS and frame generation stay off; the game's own 3D resolution setting still works."); } } } internal static void ApplyHooks(Harmony harmony) { Resolve(); Hook(harmony, typeof(UpscaledFrameBuffer), "UpdateCameraTarget", Type.EmptyTypes, AccessTools.Method(typeof(WorldObjectPatches.Patch_UpscaledFrameBuffer_UpdateCameraTarget), "Prefix", (Type[])null, (Type[])null), null); Hook(harmony, typeof(FrameBufferScaler), "OnBufferCreated", new Type[2] { typeof(UpscaledFrameBuffer), typeof(RenderTexture) }, null, AccessTools.Method(typeof(NativeScalerPatches.Patch_FrameBufferScaler_OnBufferCreated), "Postfix", (Type[])null, (Type[])null)); } private static void Hook(Harmony harmony, Type type, string name, Type[] parameters, MethodInfo prefix, MethodInfo postfix) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) string text = type.Name + "." + name + "()"; try { MethodInfo method = type.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, parameters, null); if (method != null) { harmony.Patch((MethodBase)method, (!(prefix != null)) ? ((HarmonyMethod)null) : new HarmonyMethod(prefix), (!(postfix != null)) ? ((HarmonyMethod)null) : new HarmonyMethod(postfix), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return; } } catch (Exception ex) { text = text + " (" + ex.GetType().Name + ": " + ex.Message + ")"; } s_missing = ((s_missing.Length == 0) ? text : (s_missing + ", " + text)); Plugin.LogWarning("[RenderScale] The game's 3D-resolution code has changed (hook not applied: " + text + "). The render scale dial, FSR 3 / DLSS and frame generation stay off; the game's own 3D resolution setting still works."); } private static FieldRef<T> Static<T>(string name, List<string> missing) { try { FieldInfo field = typeof(UpscaledFrameBuffer).GetField(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field.FieldType == typeof(T)) { return AccessTools.StaticFieldRefAccess<T>(field); } } catch (Exception) { } missing.Add("UpscaledFrameBuffer." + name); return null; } private static FieldRef<TOwner, T> Instance<TOwner, T>(string name, List<string> missing) { try { FieldInfo field = typeof(TOwner).GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field.FieldType == typeof(T)) { return AccessTools.FieldRefAccess<TOwner, T>(field); } } catch (Exception) { } missing.Add(typeof(TOwner).Name + "." + name); return null; } private static Action<UpscaledFrameBuffer> Method(string name, List<string> missing) { try { MethodInfo method = typeof(UpscaledFrameBuffer).GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (method != null && method.ReturnType == typeof(void)) { return (Action<UpscaledFrameBuffer>)Delegate.CreateDelegate(typeof(Action<UpscaledFrameBuffer>), method); } } catch (Exception) { } missing.Add("UpscaledFrameBuffer." + name + "()"); return null; } } public static class GpuCapabilities { private const float RefreshSeconds = 0.5f; private static List<string> s_staticLines; private static List<string> s_lines; private static float s_nextRefresh; public static IReadOnlyList<string> HardwareScanLines { get; internal set; } = new List<string>(); private static string Row(string label, string value) { return "<color=#C8A865>" + label + ":</color> " + value; } private static string YesNo(bool value) { if (!value) { return "<color=#EF4444>no</color>"; } return "<color=#52E08D>yes</color>"; } public static List<string> GetLines() { if (s_lines != null && Time.unscaledTime < s_nextRefresh) { return s_lines; } s_nextRefresh = Time.unscaledTime + 0.5f; s_lines = Build(); return s_lines; } private static List<string> Build() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (s_staticLines == null) { s_staticLines = new List<string> { Row("Graphics API", $"{SystemInfo.graphicsDeviceType} ({SystemInfo.graphicsDeviceVersion})"), Row("GPU", $"{SystemInfo.graphicsDeviceName} ({SystemInfo.graphicsDeviceVendor}), {SystemInfo.graphicsMemorySize} MB"), Row("Compute shaders", YesNo(SystemInfo.supportsComputeShaders)) + " " + Row("Async compute queue", YesNo(SystemInfo.supportsAsyncCompute)), Row("Unity's own ray tracing", YesNo(SystemInfo.supportsRayTracing)) + " " + Row("Motion vectors", YesNo(SystemInfo.supportsMotionVectors)), Row("GPU fences", YesNo(SystemInfo.supportsGraphicsFence)) + " " + Row("Async GPU readback", YesNo(SystemInfo.supportsAsyncGPUReadback)) }; } List<string> list = new List<string>(s_staticLines); list.Add(Row("Hardware ray tracing (game's Vulkan device)", RayTracingProbe.DeviceSummary)); if (GraphicsConfig.RtSunShadows != null) { list.Add(Row("Ray tracing", RtShadows.Summary)); } AddRow(list, DisplayRow); AddRow(list, FramePacingRow); AddRow(list, TessellationRow); AddRow(list, RenderTargetRow); list.Add(NativeBridge.Loaded ? ("<color=#8A7A5A>" + NativeOptions.UpscalerNames + " upscaling and frame generation run through the Native Door (Settings > Graphics). Unity's own ray tracing and Reflex are not exposed by this game build; " + (NativeOptions.OfferRtShadows ? "the Native Door has the GPU's ray tracing ready on the game's device ([Native] RayTracing, on by default) for the ray-traced shadows and lighting (switch them on in the settings, no restart needed).</color>" : "the Native Door has the GPU's ray tracing ready on the game's device ([Native] RayTracing, on by default); nothing is drawn with it yet.</color>")) : ("<color=#8A7A5A>Unity's own ray tracing and Reflex are not exposed by this game build. " + NativeOptions.UpscalerNames + " upscaling, frame generation and the ray tracing probe need the Native Door (Settings > Graphics, Vulkan only).</color>")); return list; } private static void AddRow(List<string> lines, Func<string> row) { try { lines.Add(row()); } catch (Exception) { lines.Add("<color=#8A7A5A>(a row could not be read on this game version)</color>"); } } private static string DisplayRow() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) Resolution currentResolution = Screen.currentResolution; object[] obj = new object[4] { Screen.width, Screen.height, null, null }; RefreshRate refreshRateRatio = ((Resolution)(ref currentResolution)).refreshRateRatio; obj[2] = ((RefreshRate)(ref refreshRateRatio)).value; obj[3] = Screen.fullScreenMode; return Row("Display", string.Format("{0}x{1} at {2:F0} Hz, {3}", obj)); } private static string FramePacingRow() { return Row("Frame pacing", string.Format("limit {0}, vsync {1}, queued frames {2}", (Application.targetFrameRate <= 0) ? "none" : Application.targetFrameRate.ToString(), QualitySettings.vSyncCount, QualitySettings.maxQueuedFrames)); } private static string TessellationRow() { return Row("Tessellation (game setting)", WorldSurfaceDials.VanillaTessellationActive ? "<color=#52E