Decompiled source of DSPAASR v1.2.0
DSPAAMod.dll
Decompiled a month ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using System.Xml; using BepInEx; using BepInEx.Configuration; using DSPAAMod.Core; using DSPAAMod.Game; using DSPAAMod.Interop; using DSPAAMod.UI; using HarmonyLib; using Microsoft.CodeAnalysis; using Unity.Collections; using UnityEngine; using UnityEngine.Events; using UnityEngine.Experimental.Rendering; using UnityEngine.LowLevel; using UnityEngine.PlayerLoop; using UnityEngine.PostProcessing; using UnityEngine.Rendering; using UnityEngine.UI; using UnityStandardAssets.ImageEffects; [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("NordLandeW")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Adds anti-aliasing, DLSS/AMD FSR super resolution and frame generation to Dyson Sphere Program.")] [assembly: AssemblyFileVersion("1.2.0.0")] [assembly: AssemblyInformationalVersion("1.2.0+d9acbc2eda5311a22be61cd68392d9aaa4407c0e")] [assembly: AssemblyProduct("DSPAASR")] [assembly: AssemblyTitle("DSPAAMod")] [assembly: AssemblyVersion("1.2.0.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 DSPAAMod { [BepInPlugin("dspaa.mod", "DSPAASR", "1.2.0")] [BepInProcess("DSPGAME.exe")] public sealed class Plugin : BaseUnityPlugin { public const string Id = "dspaa.mod"; private ConfigEntry<AaTechnique> technique; private ConfigEntry<ModelSelection> model; private ConfigEntry<ResolutionMode> resolution; private ConfigEntry<float> fsrSharpness; private ConfigEntry<FrameGenerationBackend> frameGeneration; private ConfigEntry<FrameGenerationMode> frameGenerationMode; private ConfigEntry<uint> generatedFrames; private ConfigEntry<uint> frameLimitMicroseconds; private ConfigEntry<ReflexMode> reflex; private ConfigEntry<float> dynamicTargetFrameRate; private ConfigEntry<KeyboardShortcut> captureShortcut; private NativeBridge native; private Harmony harmony; private bool stopped; internal static Plugin Instance { get; private set; } internal RenderController Renderer { get; private set; } internal SettingsSession Settings { get; private set; } internal GraphicsOptions Options { get; private set; } internal FrameGenerationController Presentation { get; private set; } internal FrameGenerationSettingsSession FrameGeneration { get; private set; } internal PresentationStartupState StartupState => PresentationStartup.Read(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location)).State; internal bool CanRequestFrameGeneration(FrameGenerationBackend backend) { if (Presentation == null) { return backend == FrameGenerationBackend.Off; } NativePresentationStatus caps = Presentation?.Status ?? default(NativePresentationStatus); if (caps.Available || backend == FrameGenerationBackend.Off) { return PresentationAvailability.CanRequest(caps, StartupState, backend, runtimeFilesPresent: false); } string directory = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); bool runtimeFilesPresent = ((backend != FrameGenerationBackend.Fsr) ? (Has("sl.interposer.dll") && Has("sl.common.dll") && Has("sl.dlss_g.dll") && Has("sl.reflex.dll") && Has("sl.pcl.dll") && Has("nvngx_dlssg.dll")) : (Has("amd_fidelityfx_loader_dx12.dll") && Has("amd_fidelityfx_framegeneration_dx12.dll"))); return PresentationAvailability.CanRequest(caps, StartupState, backend, runtimeFilesPresent); bool Has(string name) { return File.Exists(Path.Combine(directory, name)); } } private void Awake() { //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Expected O, but got Unknown Instance = this; try { technique = ((BaseUnityPlugin)this).Config.Bind<AaTechnique>("Antialiasing", "Technique", AaTechnique.Original, "Original preserves game AA; Fxaa/Taa use the game's filters; Dlss/Fsr use the selected resolution mode. Legacy Dlaa migrates to Dlss with native-resolution DLAA. Changing this file requires restart."); model = ((BaseUnityPlugin)this).Config.Bind<ModelSelection>("Antialiasing", "Model", ModelSelection.Recommended, "Recommended: K for DLAA/Quality/Balanced, M for Performance, L for UltraPerformance. Explicit CNN/K/L/M overrides persist independently of resolution mode."); resolution = ((BaseUnityPlugin)this).Config.Bind<ResolutionMode>("Antialiasing", "Resolution", ResolutionMode.Dlaa, "DLSS/FSR resolution mode: Dlaa means native-resolution AA (DLAA or FSR Native AA); SR modes query the selected SDK for actual lower world-render dimensions. Model selection remains independent. Changing this file requires restart."); fsrSharpness = ((BaseUnityPlugin)this).Config.Bind<float>("FSR", "Sharpness", 0f, "FSR RCAS sharpening, 0 (disabled) to 1 (maximum). Independent of DLSS model. Changing this file requires restart."); captureShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Diagnostics", "CaptureShortcut", new KeyboardShortcut((KeyCode)291, (KeyCode[])(object)new KeyCode[2] { (KeyCode)306, (KeyCode)304 }), "Explicitly trace two Unity frames in LogOutput.log and capture consecutive DLSS submissions (raw color/depth/motion/output) into BepInEx/cache/DSPAAMod/captures. An incomplete pair fails at the end of the trace window. Nothing runs until this shortcut is pressed; captures can be large. Changing this file requires restart."); AaSettings initial; try { initial = new AaSettings(technique.Value, model.Value, resolution.Value, fsrSharpness.Value); } catch (ArgumentOutOfRangeException) { initial = AaSettings.Default; ((BaseUnityPlugin)this).Logger.LogWarning((object)"Invalid settings; using safe defaults without overwriting the config."); } Settings = new SettingsSession(initial); frameGeneration = ((BaseUnityPlugin)this).Config.Bind<FrameGenerationBackend>("FrameGeneration", "Backend", FrameGenerationBackend.Off, "Off/Fsr/Dlss, independently of AA/SR. The preloader creates the presentation bridge only when FG is selected at startup. Enabling FG without an active bridge requires restart; an existing bridge supports live switching and remains until game exit even after FG is turned Off."); frameGenerationMode = ((BaseUnityPlugin)this).Config.Bind<FrameGenerationMode>("FrameGeneration", "Mode", FrameGenerationMode.Fixed, "Fixed or DLSS Dynamic; availability is queried from the current SDK/device. Dynamic is not eAuto."); generatedFrames = ((BaseUnityPlugin)this).Config.Bind<uint>("FrameGeneration", "AdditionalFrames", 1u, "Number of additional frames, not display multiplier. FSR=1; DLSS upper limit comes from the runtime (MFG hardware required above 1)."); reflex = ((BaseUnityPlugin)this).Config.Bind<ReflexMode>("FrameGeneration", "Reflex", ReflexMode.On, "DLSS Reflex Off/On/OnWithBoost. Off retains before-input Sleep/PCL but pauses FG; this never changes driver settings."); dynamicTargetFrameRate = ((BaseUnityPlugin)this).Config.Bind<float>("FrameGeneration", "DynamicTargetFrameRate", 0f, "DLSS Dynamic target; 0 uses the monitor. VSync/driver restrictions still apply. No vendor-independent performance gate."); frameLimitMicroseconds = ((BaseUnityPlugin)this).Config.Bind<uint>("FrameGeneration", "FrameLimitMicroseconds", 0u, "Reflex frame limiter interval in microseconds; 0 disables that limiter. Does not rewrite the game's own frame-limit or VSync options."); FrameGenerationSettings frameGenerationSettings; try { frameGenerationSettings = new FrameGenerationSettings(frameGeneration.Value, frameGenerationMode.Value, generatedFrames.Value, reflex.Value, dynamicTargetFrameRate.Value, frameLimitMicroseconds.Value); } catch (ArgumentException) { frameGenerationSettings = FrameGenerationSettings.Default; ((BaseUnityPlugin)this).Logger.LogWarning((object)"Invalid FG settings; using Off without overwriting the config."); } FrameGeneration = new FrameGenerationSettingsSession(frameGenerationSettings); try { Presentation = new FrameGenerationController(this, AcquireNative(), frameGenerationSettings, delegate(string text) { ((BaseUnityPlugin)this).Logger.LogInfo((object)text); }, delegate(string text) { ((BaseUnityPlugin)this).Logger.LogWarning((object)text); }); } catch (Exception ex3) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Frame generation unavailable; AA/SR remain independent: " + ex3.Message)); } Renderer = new RenderController(initial, AcquireNative, delegate(string text) { ((BaseUnityPlugin)this).Logger.LogWarning((object)text); }, delegate(string text) { ((BaseUnityPlugin)this).Logger.LogInfo((object)text); }); Renderer.Presentation = Presentation; Renderer.Capture = new FrameCapture(Path.Combine(Paths.CachePath, "DSPAAMod", "captures"), delegate(string text) { ((BaseUnityPlugin)this).Logger.LogInfo((object)text); }); Options = new GraphicsOptions(this); harmony = new Harmony("dspaa.mod"); harmony.PatchAll(typeof(Plugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"DSPAASR loaded. DLSS and FSR use the selected AA/SR resolution mode; animated objects may exhibit visual artifacts. No driver settings are modified."); } catch (Exception ex4) { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } Guard(delegate { Presentation?.Dispose(); }); Guard(delegate { Renderer?.Shutdown(); }); Instance = null; ((BaseUnityPlugin)this).Logger.LogError((object)ex4); } } private NativeBridge AcquireNative() { if (native == null) { string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); string dataDirectory = Path.Combine(Paths.CachePath, "DSPAAMod"); try { native = new NativeBridge(directoryName, dataDirectory); } catch (NativeModuleLoadException ex) { ((BaseUnityPlugin)this).Logger.LogError((object)ex); throw; } } return native; } internal void ApplySettings() { Settings.Apply(); technique.Value = Settings.Applied.Technique; model.Value = Settings.Applied.Model; resolution.Value = Settings.Applied.Resolution; fsrSharpness.Value = Settings.Applied.FsrSharpness; ((BaseUnityPlugin)this).Config.Save(); Renderer.Configure(Settings.Applied); ((BaseUnityPlugin)this).Logger.LogInfo((object)("AA settings applied: " + Settings.Applied.Technique.ToString() + ", resolution " + Settings.Applied.Resolution.ToString() + ", model " + Settings.Applied.Model)); } private void StoreFrameGeneration(FrameGenerationSettings value) { frameGeneration.Value = value.Backend; frameGenerationMode.Value = value.Mode; generatedFrames.Value = value.GeneratedFrames; reflex.Value = value.Reflex; dynamicTargetFrameRate.Value = value.DynamicTargetFrameRate; frameLimitMicroseconds.Value = value.FrameLimitMicroseconds; } internal void ApplyFrameGeneration() { FrameGeneration.Apply(delegate(FrameGenerationSettings value) { bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; try { StoreFrameGeneration(value); ((BaseUnityPlugin)this).Config.Save(); } catch { StoreFrameGeneration(FrameGeneration.Applied); throw; } finally { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } }); FrameGenerationSettings applied = FrameGeneration.Applied; NativePresentationStatus nativePresentationStatus = Presentation?.Status ?? default(NativePresentationStatus); if (Presentation != null && !nativePresentationStatus.Available && !nativePresentationStatus.Quarantined && StartupState == PresentationStartupState.Inactive) { ((BaseUnityPlugin)this).Logger.LogInfo((object)((applied.Backend == FrameGenerationBackend.Off) ? "Frame generation remains Off; native presentation retained." : "Frame generation request saved; restart the game to check support and enable the presentation bridge.")); } else if (Presentation == null || !Presentation.Apply(applied)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Frame generation request could not be activated; check presentation status."); } } internal void Guard(Action action) { try { action(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)ex); } } private void Update() { if ((Object)(object)Instance != (Object)(object)this || stopped) { return; } Guard(delegate { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) Renderer.Update(); Presentation?.Update(); Options.Update(); KeyboardShortcut value = captureShortcut.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { if (Settings.Applied.Technique == AaTechnique.Dlss) { Renderer.RequestCapture(); } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Select DLSS before requesting a frame capture."); } } }); } private void OnDestroy() { if (!((Object)(object)Instance != (Object)(object)this) && !stopped) { stopped = true; Guard(delegate { Presentation?.Dispose(); }); Guard(delegate { Renderer.Shutdown(); }); Guard(delegate { Options.Dispose(); }); Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } Instance = null; } } } } namespace DSPAAMod.UI { internal sealed class FrameGenerationOptions : IDisposable { private readonly Plugin plugin; private readonly UIComboBox backend; private readonly UIComboBox multiplier; private readonly UIComboBox reflex; private FrameGenerationBackend[] backendChoices = Array.Empty<FrameGenerationBackend>(); private FrameMultiplierChoice[] multiplierChoices = Array.Empty<FrameMultiplierChoice>(); private readonly ReflexMode[] reflexChoices = GraphicsMenuChoices.ReflexModes(); private readonly Text backendLabel; private readonly Text multiplierLabel; private readonly Text reflexLabel; private readonly Text status; private readonly RectTransform root; private readonly float step; private bool synchronizing; private bool showDetails; private int statusRows; private uint shownFlags; private uint shownMaximum; private uint shownActive; private uint shownRequested; private uint shownSdkStatus; private FrameGenerationSettings shownDraft; private FrameGenerationSettings shownApplied; private PresentationStartupState shownStartup; private readonly Color warningColor; private static bool Chinese => (Localization.CurrentLanguageLCID & 0x3FF) == 4; private NativePresentationStatus Capabilities => plugin.Presentation?.Status ?? default(NativePresentationStatus); public int Rows => 1 + (showDetails ? 2 : 0) + statusRows; public bool Changed { get { NativePresentationStatus capabilities = Capabilities; if ((capabilities.Flags & 0xFFFFFF9Fu) == shownFlags && capabilities.MaximumGeneratedFrames == shownMaximum && capabilities.ActiveBackend == shownActive && capabilities.RequestedBackend == shownRequested && capabilities.SdkStatus == shownSdkStatus && plugin.StartupState == shownStartup && plugin.FrameGeneration.Draft.Equals(shownDraft)) { return !plugin.FrameGeneration.Applied.Equals(shownApplied); } return true; } } public FrameGenerationOptions(Plugin owner, UIComboBox template, Text label, Text statusTemplate, RectTransform content, float spacing) { //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Expected O, but got Unknown //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Expected O, but got Unknown //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Expected O, but got Unknown plugin = owner; root = content; step = spacing; try { backend = GraphicsOptions.Clone(template, "DSPAASR Frame Generation"); multiplier = GraphicsOptions.Clone(template, "DSPAASR FG Multiplier"); reflex = GraphicsOptions.Clone(template, "DSPAASR Reflex"); backendLabel = CloneLabel(label, "DSPAASR FG Label"); multiplierLabel = CloneLabel(label, "DSPAASR FG Multiplier Label"); reflexLabel = CloneLabel(label, "DSPAASR Reflex Label"); status = Object.Instantiate<Text>(statusTemplate, ((Component)label).transform.parent); ((Object)status).name = "DSPAASR FG Status"; warningColor = ((Graphic)statusTemplate).color; ((Graphic)status).color = ((Graphic)label).color; ((UnityEvent)backend.onItemIndexChange).AddListener(new UnityAction(BackendChanged)); ((UnityEvent)multiplier.onItemIndexChange).AddListener(new UnityAction(MultiplierChanged)); ((UnityEvent)reflex.onItemIndexChange).AddListener(new UnityAction(ReflexChanged)); } catch { Dispose(); throw; } } private static Text CloneLabel(Text source, string name) { Text val = Object.Instantiate<Text>(source, ((Component)source).transform.parent); ((Object)val).name = name; Localizer[] components = ((Component)val).GetComponents<Localizer>(); for (int i = 0; i < components.Length; i++) { ((Behaviour)components[i]).enabled = false; } return val; } public void Refresh() { //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Unknown result type (might be due to invalid IL or missing references) NativePresentationStatus capabilities = Capabilities; FrameGenerationSettings draft = plugin.FrameGeneration.Draft; shownFlags = capabilities.Flags & 0xFFFFFF9Fu; shownMaximum = capabilities.MaximumGeneratedFrames; shownActive = capabilities.ActiveBackend; shownRequested = capabilities.RequestedBackend; shownSdkStatus = capabilities.SdkStatus; shownDraft = draft; shownApplied = plugin.FrameGeneration.Applied; shownStartup = plugin.StartupState; bool flag = plugin.CanRequestFrameGeneration(FrameGenerationBackend.Dlss); bool flag2 = DlssDetailsKnown(capabilities); synchronizing = true; try { backendLabel.text = (Chinese ? "帧生成" : "Frame generation"); multiplierLabel.text = (Chinese ? "帧生成倍率" : "Frame multiplier"); reflexLabel.text = "NVIDIA Reflex"; backendChoices = GraphicsMenuChoices.Backends(plugin.CanRequestFrameGeneration(FrameGenerationBackend.Fsr), flag); GraphicsOptions.SetItems(backend, Array.ConvertAll(backendChoices, BackendLabel), Array.IndexOf(backendChoices, draft.Backend), BackendLabel(draft.Backend)); multiplierChoices = GraphicsMenuChoices.Multipliers(flag, flag2, capabilities.MaximumGeneratedFrames, capabilities.DynamicSupported); GraphicsOptions.SetItems(multiplier, Array.ConvertAll(multiplierChoices, (FrameMultiplierChoice choice) => MultiplierLabel(choice.Mode, choice.GeneratedFrames)), GraphicsMenuChoices.FindMultiplier(multiplierChoices, draft), MultiplierLabel(draft.Mode, draft.GeneratedFrames)); GraphicsOptions.SetItems(reflex, Array.ConvertAll(reflexChoices, ReflexLabel), Array.IndexOf(reflexChoices, draft.Reflex), ReflexLabel(draft.Reflex)); showDetails = draft.Backend == FrameGenerationBackend.Dlss; ((Component)multiplier).gameObject.SetActive(showDetails); ((Component)multiplierLabel).gameObject.SetActive(showDetails); ((Component)reflex).gameObject.SetActive(showDetails); ((Component)reflexLabel).gameObject.SetActive(showDetails); status.text = StatusText(capabilities, draft, out var warning); if (draft.Backend == FrameGenerationBackend.Dlss && flag && GraphicsMenuChoices.FindMultiplier(multiplierChoices, draft) < 0) { string text = ((!flag2) ? (Chinese ? "所请求的帧生成倍率尚未检测。" : "The requested frame multiplier has not been checked.") : (Chinese ? "所请求的帧生成倍率不可用。" : "The requested frame multiplier is unavailable.")); Text obj = status; obj.text = obj.text + ((status.text.Length == 0) ? "" : "\n") + text; warning = warning || flag2; } ((Graphic)status).color = (warning ? warningColor : ((Graphic)backendLabel).color); ((Component)status).gameObject.SetActive(status.text.Length != 0); statusRows = GraphicsOptions.MeasureNoteRows(status, step); } finally { synchronizing = false; } } private static bool DlssDetailsKnown(NativePresentationStatus caps) { if (caps.Available && !caps.Quarantined) { return caps.ActiveBackend == 2; } return false; } private static string BackendLabel(FrameGenerationBackend value) { switch (value) { default: return "DLSS"; case FrameGenerationBackend.Fsr: return "FSR 2×"; case FrameGenerationBackend.Off: if (!Chinese) { return "Off"; } return "关闭"; } } private static string MultiplierLabel(FrameGenerationMode mode, uint generatedFrames) { if (mode != FrameGenerationMode.Dynamic) { return (ulong)generatedFrames + 1uL + "×"; } if (!Chinese) { return "Dynamic"; } return "自适应"; } private static string ReflexLabel(ReflexMode value) { switch (value) { default: if (!Chinese) { return "On + Boost"; } return "开启并增强"; case ReflexMode.On: if (!Chinese) { return "On"; } return "开启"; case ReflexMode.Off: if (!Chinese) { return "Off"; } return "关闭"; } } private string StatusText(NativePresentationStatus caps, FrameGenerationSettings value, out bool warning) { warning = false; if (caps.Quarantined) { warning = true; if (!Chinese) { return "Frame generation was disabled after an error. Restart the game."; } return "帧生成因错误已停用,请重启游戏。"; } if (!caps.Available) { if (plugin.Presentation != null && plugin.StartupState == PresentationStartupState.Inactive && value.Backend == FrameGenerationBackend.Off) { return string.Empty; } if (PresentationAvailability.NeedsRestart(caps, plugin.StartupState, value) && plugin.CanRequestFrameGeneration(value.Backend)) { string text = ((!value.Equals(plugin.FrameGeneration.Applied)) ? (Chinese ? "应用设置并重启游戏,以检测支持并启用帧生成。" : "Apply settings and restart the game to check support and enable frame generation.") : (Chinese ? "设置已保存。重启游戏以检测支持并启用帧生成。" : "Settings saved. Restart the game to check support and enable frame generation.")); if (value.Backend == FrameGenerationBackend.Dlss && value.Reflex == ReflexMode.Off) { return (Chinese ? "DLSS 帧生成需要开启 NVIDIA Reflex。" : "DLSS frame generation requires NVIDIA Reflex.") + "\n" + text; } return text; } warning = true; if (!Chinese) { return "Frame generation is unavailable. Check the mod installation and restart the game."; } return "帧生成不可用,请检查模组安装并重启游戏。"; } if (value.Backend == FrameGenerationBackend.Off) { if (!caps.FsrRuntimePresent && !caps.DlssSupported) { warning = true; if (!Chinese) { return "Frame generation is unavailable. Check the GPU, driver and mod installation."; } return "帧生成不可用,请检查显卡、驱动与模组安装。"; } return string.Empty; } if (value.Backend == FrameGenerationBackend.Fsr && !caps.FsrRuntimePresent) { warning = true; if (!Chinese) { return "FSR frame generation files are missing. Reinstall the mod."; } return "缺少 FSR 帧生成组件,请重新安装模组。"; } if (value.Backend == FrameGenerationBackend.Dlss && !caps.DlssSupported) { warning = true; if (!Chinese) { return "DLSS frame generation is unavailable. Check the GPU, driver and mod installation."; } return "DLSS 帧生成不可用,请检查显卡、驱动与模组安装。"; } if (!value.Equals(plugin.FrameGeneration.Applied)) { if (value.Backend == FrameGenerationBackend.Dlss && value.Reflex == ReflexMode.Off) { if (!Chinese) { return "DLSS frame generation requires NVIDIA Reflex."; } return "DLSS 帧生成需要开启 NVIDIA Reflex。"; } if (!Chinese) { return "Apply settings to use these changes."; } return "应用设置后生效。"; } if (value.Backend == FrameGenerationBackend.Dlss && value.Reflex == ReflexMode.Off) { if (!Chinese) { return "Enable NVIDIA Reflex to use DLSS frame generation."; } return "开启 NVIDIA Reflex 以启用 DLSS 帧生成。"; } if (caps.ActiveBackend == 2 && value.Backend == FrameGenerationBackend.Dlss && caps.SdkStatus != 0) { warning = true; if (!Chinese) { return "DLSS frame generation is currently unavailable. Check the log for details."; } return "DLSS 帧生成暂不可用,请检查日志。"; } if (caps.RequestedBackend != (uint)value.Backend || caps.ActiveBackend != (uint)value.Backend) { if (!Chinese) { return "Settings applied. Frame generation is not active yet."; } return "设置已应用,帧生成尚未启用。"; } return string.Empty; } public void Layout(float firstCenter, float left) { //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) Position(((Component)backend).transform, firstCenter); Position(((Component)backendLabel).transform, firstCenter); Position(((Component)multiplier).transform, firstCenter - step); Position(((Component)multiplierLabel).transform, firstCenter - step); Position(((Component)reflex).transform, firstCenter - 2f * step); Position(((Component)reflexLabel).transform, firstCenter - 2f * step); Position(((Component)status).transform, firstCenter - step * ((float)((!showDetails) ? 1 : 3) + (float)(statusRows - 1) * 0.5f)); Vector3 val = ((Transform)root).InverseTransformPoint(((Transform)((Graphic)status).rectTransform).position); val.x = left; ((Transform)((Graphic)status).rectTransform).position = ((Transform)root).TransformPoint(val); } private void Position(Transform transform, float y) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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) //IL_001c: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) RectTransform val = (RectTransform)transform; RectTransform obj = root; Rect rect = val.rect; float y2 = ((Transform)obj).InverseTransformPoint(((Transform)val).TransformPoint(Vector2.op_Implicit(((Rect)(ref rect)).center))).y; Vector3 val2 = ((Transform)root).InverseTransformPoint(((Transform)val).position); val2.y += y - y2; ((Transform)val).position = ((Transform)root).TransformPoint(val2); } private void BackendChanged() { if (!synchronizing && backend.itemIndex >= 0 && backend.itemIndex < backendChoices.Length) { FrameGenerationBackend frameGenerationBackend = backendChoices[backend.itemIndex]; if (!plugin.CanRequestFrameGeneration(frameGenerationBackend)) { Refresh(); return; } FrameGenerationSettings draft = plugin.FrameGeneration.Draft; plugin.FrameGeneration.Draft = new FrameGenerationSettings(frameGenerationBackend, (frameGenerationBackend != FrameGenerationBackend.Fsr) ? draft.Mode : FrameGenerationMode.Fixed, (frameGenerationBackend == FrameGenerationBackend.Fsr) ? 1u : draft.GeneratedFrames, draft.Reflex, draft.DynamicTargetFrameRate, draft.FrameLimitMicroseconds); plugin.Options.Refresh(); } } private void MultiplierChanged() { if (!synchronizing && showDetails && multiplier.itemIndex >= 0 && multiplier.itemIndex < multiplierChoices.Length) { NativePresentationStatus capabilities = Capabilities; FrameGenerationSettings draft = plugin.FrameGeneration.Draft; FrameMultiplierChoice frameMultiplierChoice = multiplierChoices[multiplier.itemIndex]; FrameGenerationSettings frameGenerationSettings = new FrameGenerationSettings(draft.Backend, frameMultiplierChoice.Mode, frameMultiplierChoice.GeneratedFrames, draft.Reflex, draft.DynamicTargetFrameRate, draft.FrameLimitMicroseconds); if (GraphicsMenuChoices.FindMultiplier(GraphicsMenuChoices.Multipliers(plugin.CanRequestFrameGeneration(FrameGenerationBackend.Dlss), DlssDetailsKnown(capabilities), capabilities.MaximumGeneratedFrames, capabilities.DynamicSupported), frameGenerationSettings) < 0) { Refresh(); } else { plugin.FrameGeneration.Draft = frameGenerationSettings; } } } private void ReflexChanged() { if (!synchronizing && showDetails && reflex.itemIndex >= 0 && reflex.itemIndex < reflexChoices.Length) { FrameGenerationSettings draft = plugin.FrameGeneration.Draft; plugin.FrameGeneration.Draft = new FrameGenerationSettings(draft.Backend, draft.Mode, draft.GeneratedFrames, reflexChoices[reflex.itemIndex], draft.DynamicTargetFrameRate, draft.FrameLimitMicroseconds); } } private static void Remove(Component value) { if (Object.op_Implicit((Object)(object)value)) { value.gameObject.SetActive(false); Object.Destroy((Object)(object)value.gameObject); } } public void Dispose() { Remove((Component)(object)backend); Remove((Component)(object)multiplier); Remove((Component)(object)reflex); Remove((Component)(object)backendLabel); Remove((Component)(object)multiplierLabel); Remove((Component)(object)reflexLabel); Remove((Component)(object)status); } } internal sealed class GraphicsOptions : IDisposable { private readonly Plugin plugin; private UIOptionWindow window; private UIComboBox technique; private UIComboBox resolution; private UIComboBox configuration; private AaChoice[] techniqueChoices = Array.Empty<AaChoice>(); private FrameGenerationOptions frameGeneration; private RectTransform layoutRoot; private Vector2 originalContentSize; private Vector2 configurationPosition; private Vector2 configurationLabelPosition; private Vector2 availabilityPosition; private Text availabilityLabel; private UpscalerAvailability shownAvailability; private UpscalerAvailability shownFsrAvailability; private float rowStep; private bool originalConfigurationLabelActive; private readonly Dictionary<RectTransform, Vector2> movedRows = new Dictionary<RectTransform, Vector2>(); private AaMenuDraft draft; private Text aaLabel; private Text resolutionLabel; private Text configurationLabel; private Localizer aaLocalizer; private Localizer configurationLocalizer; private string originalAaLabel; private string originalConfigurationLabel; private bool originalAaActive; private bool originalFxaaActive; private bool originalAaLocalized; private bool originalConfigurationLocalized; private bool synchronizing; private int nativeRefreshMsaa; private bool nativeRefreshFxaa; private UIComboBox openedDropdown; private Vector3 dropdownPosition; private readonly Vector3[] dropdownCorners = (Vector3[])(object)new Vector3[4]; private static bool Chinese => (Localization.CurrentLanguageLCID & 0x3FF) == 4; public GraphicsOptions(Plugin owner) { plugin = owner; } private static int MsaaFromIndex(int index) { return index switch { 3 => 8, 2 => 4, 1 => 2, _ => 0, }; } public void Open(UIOptionWindow value) { plugin.Settings.Open(); plugin.FrameGeneration.Open(); plugin.Renderer.RequestUpscalerSupport(); if ((Object)(object)window != (Object)(object)value) { Dispose(); try { Install(value); } catch { Dispose(); throw; } } draft = new AaMenuDraft(plugin.Settings.Draft, MsaaFromIndex(window.msaaComp.itemIndex), window.fxaaComp.isOn); Refresh(); } private void Install(UIOptionWindow value) { //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Expected O, but got Unknown //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Expected O, but got Unknown //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_0306: Unknown result type (might be due to invalid IL or missing references) //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_0321: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_035d: Unknown result type (might be due to invalid IL or missing references) //IL_036e: Unknown result type (might be due to invalid IL or missing references) //IL_0373: Unknown result type (might be due to invalid IL or missing references) //IL_0378: Unknown result type (might be due to invalid IL or missing references) //IL_03ab: Unknown result type (might be due to invalid IL or missing references) //IL_03bc: Unknown result type (might be due to invalid IL or missing references) //IL_03c1: Unknown result type (might be due to invalid IL or missing references) //IL_04bb: Unknown result type (might be due to invalid IL or missing references) //IL_04f3: Unknown result type (might be due to invalid IL or missing references) //IL_04f9: Expected O, but got Unknown //IL_0574: Unknown result type (might be due to invalid IL or missing references) //IL_0579: Unknown result type (might be due to invalid IL or missing references) //IL_057e: Unknown result type (might be due to invalid IL or missing references) //IL_057f: Unknown result type (might be due to invalid IL or missing references) //IL_0586: Unknown result type (might be due to invalid IL or missing references) //IL_0598: Unknown result type (might be due to invalid IL or missing references) //IL_05a3: Unknown result type (might be due to invalid IL or missing references) //IL_05c1: Unknown result type (might be due to invalid IL or missing references) //IL_05d0: Unknown result type (might be due to invalid IL or missing references) //IL_05d5: Unknown result type (might be due to invalid IL or missing references) //IL_05e9: Unknown result type (might be due to invalid IL or missing references) //IL_05ee: Unknown result type (might be due to invalid IL or missing references) //IL_062c: Unknown result type (might be due to invalid IL or missing references) //IL_0636: Expected O, but got Unknown //IL_0648: Unknown result type (might be due to invalid IL or missing references) //IL_0652: Expected O, but got Unknown //IL_0664: Unknown result type (might be due to invalid IL or missing references) //IL_066e: Expected O, but got Unknown //IL_069f: Unknown result type (might be due to invalid IL or missing references) //IL_06a9: Expected O, but got Unknown //IL_0519: Unknown result type (might be due to invalid IL or missing references) //IL_051e: Unknown result type (might be due to invalid IL or missing references) //IL_0526: Unknown result type (might be due to invalid IL or missing references) //IL_0528: Unknown result type (might be due to invalid IL or missing references) window = value; UIComboBox msaaComp = window.msaaComp; originalAaActive = ((Component)msaaComp).gameObject.activeSelf; originalFxaaActive = ((Component)window.fxaaComp).gameObject.activeSelf; if (msaaComp.Items.Count != 4) { throw new InvalidOperationException("Another mod changed the MSAA list; refusing to overwrite its controls."); } aaLabel = FindLabel(window, "MSAA"); configurationLabel = FindLabel(window, "FXAA"); if (!Object.op_Implicit((Object)(object)aaLabel) || !Object.op_Implicit((Object)(object)configurationLabel)) { throw new InvalidOperationException("Cannot identify the native AA labels by their localization keys."); } originalAaLabel = aaLabel.text; originalConfigurationLabel = configurationLabel.text; originalConfigurationLabelActive = ((Component)configurationLabel).gameObject.activeSelf; aaLocalizer = ((Component)aaLabel).GetComponent<Localizer>(); configurationLocalizer = ((Component)configurationLabel).GetComponent<Localizer>(); if (Object.op_Implicit((Object)(object)aaLocalizer)) { originalAaLocalized = ((Behaviour)aaLocalizer).enabled; ((Behaviour)aaLocalizer).enabled = false; } if (Object.op_Implicit((Object)(object)configurationLocalizer)) { originalConfigurationLocalized = ((Behaviour)configurationLocalizer).enabled; ((Behaviour)configurationLocalizer).enabled = false; } Transform parent = ((Component)msaaComp).transform.parent; Transform parent2 = ((Component)aaLabel).transform.parent; if (!((Object)(object)((Component)configurationLabel).transform.parent != (Object)(object)parent2) && !((Object)(object)((Component)window.fxaaComp).transform.parent != (Object)(object)parent) && !((Object)(object)parent.parent != (Object)(object)parent2.parent)) { Transform parent3 = parent.parent; RectTransform val = (RectTransform)(object)((parent3 is RectTransform) ? parent3 : null); if (val != null) { layoutRoot = val; originalContentSize = val.sizeDelta; RectTransform val2 = (RectTransform)((Component)aaLabel).transform; RectTransform val3 = (RectTransform)((Component)configurationLabel).transform; Rect rect = val2.rect; float y = ((Transform)val).InverseTransformPoint(((Transform)val2).TransformPoint(Vector2.op_Implicit(((Rect)(ref rect)).center))).y; rect = val3.rect; float y2 = ((Transform)val).InverseTransformPoint(((Transform)val3).TransformPoint(Vector2.op_Implicit(((Rect)(ref rect)).center))).y; float num = y - y2; if (num <= 0f) { throw new InvalidOperationException("Invalid graphics-row spacing."); } rowStep = num; ShiftRows(parent2, y2, num); ShiftRows(parent, y2, num); val.sizeDelta = originalContentSize + new Vector2(0f, num); technique = Clone(msaaComp, "DSPAAMod Antialiasing"); resolution = Clone(msaaComp, "DSPAAMod Resolution"); configuration = Clone(msaaComp, "DSPAAMod Configuration"); Transform transform = ((Component)resolution).transform; transform.localPosition += new Vector3(0f, 0f - num, 0f); Transform transform2 = ((Component)configuration).transform; transform2.localPosition += new Vector3(0f, -2f * num, 0f); configurationPosition = ((RectTransform)((Component)configuration).transform).anchoredPosition; configurationLabelPosition = ((RectTransform)((Component)configurationLabel).transform).anchoredPosition; resolutionLabel = Object.Instantiate<Text>(configurationLabel, parent2); ((Object)resolutionLabel).name = "DSPAAMod Resolution Label"; Transform transform3 = ((Component)resolutionLabel).transform; transform3.localPosition += new Vector3(0f, num, 0f); Localizer[] components = ((Component)resolutionLabel).GetComponents<Localizer>(); for (int i = 0; i < components.Length; i++) { ((Behaviour)components[i]).enabled = false; } availabilityLabel = Object.Instantiate<Text>(aaLabel, parent2); ((Object)availabilityLabel).name = "DSPAASR Availability"; components = ((Component)availabilityLabel).GetComponents<Localizer>(); for (int i = 0; i < components.Length; i++) { ((Behaviour)components[i]).enabled = false; } availabilityLabel.alignment = (TextAnchor)3; availabilityLabel.supportRichText = false; ((Graphic)availabilityLabel).raycastTarget = false; availabilityLabel.horizontalOverflow = (HorizontalWrapMode)0; availabilityLabel.verticalOverflow = (VerticalWrapMode)0; availabilityLabel.resizeTextForBestFit = false; availabilityLabel.fontSize = aaLabel.fontSize; ((Graphic)availabilityLabel).color = new Color(1f, 0.82f, 0.55f, 1f); Vector3[] array = (Vector3[])(object)new Vector3[4]; float num2 = float.PositiveInfinity; float num3 = float.NegativeInfinity; RectTransform[] array2 = (RectTransform[])(object)new RectTransform[2] { val2, (RectTransform)((Component)technique).transform }; for (int i = 0; i < array2.Length; i++) { array2[i].GetWorldCorners(array); Vector3[] array3 = array; foreach (Vector3 val4 in array3) { float x = ((Transform)layoutRoot).InverseTransformPoint(val4).x; num2 = Mathf.Min(num2, x); num3 = Mathf.Max(num3, x); } } RectTransform rectTransform = ((Graphic)availabilityLabel).rectTransform; Vector2 anchorMin = (rectTransform.anchorMax = ((RectTransform)parent2).pivot); rectTransform.anchorMin = anchorMin; rectTransform.pivot = new Vector2(0f, 0.5f); ((Transform)rectTransform).localScale = Vector3.one; rectTransform.sizeDelta = new Vector2(num3 - num2, 2f * num - 4f); availabilityPosition = new Vector2(num2, y); ((Transform)rectTransform).position = ((Transform)layoutRoot).TransformPoint(new Vector3(num2, y, 0f)); ((Component)msaaComp).gameObject.SetActive(false); ((Component)window.fxaaComp).gameObject.SetActive(false); ((UnityEvent)technique.onItemIndexChange).AddListener(new UnityAction(TechniqueChanged)); ((UnityEvent)resolution.onItemIndexChange).AddListener(new UnityAction(ResolutionChanged)); ((UnityEvent)configuration.onItemIndexChange).AddListener(new UnityAction(ConfigurationChanged)); frameGeneration = new FrameGenerationOptions(plugin, msaaComp, aaLabel, availabilityLabel, layoutRoot, rowStep); Canvas.preWillRenderCanvases += new WillRenderCanvases(ConstrainDropdown); return; } } throw new InvalidOperationException("Unexpected graphics-row hierarchy; refusing to shift unrelated controls."); } private void ShiftRows(Transform column, float fromCenter, float distance) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown //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) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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) //IL_0057: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) foreach (Transform item in column) { object obj = (object)item; RectTransform val = (RectTransform)((obj is RectTransform) ? obj : null); if (val != null) { RectTransform obj2 = layoutRoot; Rect rect = val.rect; if (!(((Transform)obj2).InverseTransformPoint(((Transform)val).TransformPoint(Vector2.op_Implicit(((Rect)(ref rect)).center))).y > fromCenter + 0.5f)) { movedRows.Add(val, val.anchoredPosition); val.anchoredPosition += new Vector2(0f, 0f - distance); } } } } internal static UIComboBox Clone(UIComboBox source, string name) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Expected O, but got Unknown UIComboBox val = Object.Instantiate<UIComboBox>(source, ((Component)source).transform.parent); try { ((Object)val).name = name; val.InitItemIndexSelf = false; val.CanInput = false; val.translated = true; val.autoWidth = false; val.DoubleClickChange = false; val.isDroppedDown = false; val.onItemIndexChange = new ChangeEvent(); val.onSubmit = new SubmitEvent(); val.Items = new List<string>(); val.ItemsData = new List<int>(); Localizer[] componentsInChildren = ((Component)val).GetComponentsInChildren<Localizer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { ((Behaviour)componentsInChildren[i]).enabled = false; } foreach (Transform item in (Transform)val.m_DropDownContent) { Transform val2 = item; if (!((Object)(object)val2 == (Object)(object)((Component)val.m_ListItemRes).transform) && !((Object)(object)val2 == (Object)(object)((Component)val.m_EmptyItemRes).transform) && !((Object)(object)val2 == (Object)(object)((Component)val.m_SelectionBG).transform)) { ((Component)val2).gameObject.SetActive(false); Object.Destroy((Object)(object)((Component)val2).gameObject); } } ((Component)val).gameObject.SetActive(true); return val; } catch { Object.Destroy((Object)(object)((Component)val).gameObject); throw; } } private static Text FindLabel(UIOptionWindow owner, string key) { Localizer[] componentsInChildren = ((Component)owner).GetComponentsInChildren<Localizer>(true); foreach (Localizer val in componentsInChildren) { if (AaLabels.Matches(val.stringKey, key) || AaLabels.Matches(((Object)val).name, key)) { Text component = ((Component)val).GetComponent<Text>(); if (Object.op_Implicit((Object)(object)component)) { return component; } } } string text = Localization.Translate(key); Text[] componentsInChildren2 = ((Component)owner).GetComponentsInChildren<Text>(true); foreach (Text val2 in componentsInChildren2) { if (val2.text.Trim() == text || AaLabels.Matches(val2.text, key)) { return val2; } } return null; } internal static void SetItems(UIComboBox control, string[] items, int index, string missingCaption = "") { control.isDroppedDown = false; control.Items = new List<string>(items); control.ItemsData = new List<int>(); for (int i = 0; i < items.Length; i++) { control.ItemsData.Add(i); } control.UpdateItems(); control.itemIndex = index; if (index < 0) { control.m_Input.text = missingCaption; control.m_Text.text = missingCaption; } } private void TechniqueChanged() { if (!synchronizing && draft != null && Object.op_Implicit((Object)(object)technique) && technique.itemIndex >= 0 && technique.itemIndex < techniqueChoices.Length) { AaChoice choice = techniqueChoices[technique.itemIndex]; if (!draft.TrySelectTechnique(choice, plugin.Renderer.GetAvailability(choice))) { Refresh(); return; } plugin.Settings.Draft = draft.Settings; Refresh(); } } private void ResolutionChanged() { if (!synchronizing && draft != null && Object.op_Implicit((Object)(object)resolution) && draft.ResolutionEnabled && plugin.Renderer.GetAvailability(draft.Choice).Available && resolution.itemIndex >= 0 && resolution.itemIndex <= 4) { draft.SelectResolution((ResolutionMode)resolution.itemIndex); plugin.Settings.Draft = draft.Settings; } } private void ConfigurationChanged() { if (!synchronizing && draft != null && Object.op_Implicit((Object)(object)configuration) && draft.ConfigurationEnabled && configuration.itemIndex >= 0 && (draft.Choice != AaChoice.Dlss || plugin.Renderer.Availability.Available)) { draft.SelectConfiguration(configuration.itemIndex); plugin.Settings.Draft = draft.Settings; } } public void DropdownOpened(UIComboBox control) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)window) || !Object.op_Implicit((Object)(object)layoutRoot) || !Object.op_Implicit((Object)(object)control) || !((Component)control).transform.IsChildOf((Transform)(object)layoutRoot)) { return; } RestoreDropdown(); if (control.isDroppedDown) { Transform val = ((Component)control).transform; while (Object.op_Implicit((Object)(object)val) && (Object)(object)val != (Object)(object)layoutRoot) { val.SetAsLastSibling(); val = val.parent; } openedDropdown = control; dropdownPosition = ((Transform)control.m_DropDownList).localPosition; } } private void ConstrainDropdown() { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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_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_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Expected O, but got Unknown //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)openedDropdown)) { return; } if (!((Behaviour)openedDropdown).isActiveAndEnabled || !openedDropdown.isDroppedDown) { RestoreDropdown(); return; } ScrollRect componentInParent = ((Component)openedDropdown).GetComponentInParent<ScrollRect>(); if (Object.op_Implicit((Object)(object)componentInParent)) { RectTransform val = (RectTransform)(Object.op_Implicit((Object)(object)componentInParent.viewport) ? ((object)componentInParent.viewport) : ((object)(RectTransform)((Component)componentInParent).transform)); RectTransform dropDownList = openedDropdown.m_DropDownList; ((Transform)dropDownList).localPosition = dropdownPosition; BoundsIn(val, dropDownList, out var bottom, out var top); Rect rect = val.rect; float num = ((Rect)(ref rect)).yMin + 2f; rect = val.rect; float num2 = ((Rect)(ref rect)).yMax - 2f; float num3 = 0f; if (bottom < num) { BoundsIn(val, (RectTransform)((Component)openedDropdown).transform, out var _, out var top2); float num4 = top2 - bottom; num3 = ((top + num4 <= num2) ? num4 : (num - bottom)); } if (top + num3 > num2) { num3 = num2 - top; } ((Transform)dropDownList).position = ((Transform)dropDownList).position + ((Transform)val).TransformVector(new Vector3(0f, num3, 0f)); } } private void BoundsIn(RectTransform relativeTo, RectTransform rect, out float bottom, out float top) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) rect.GetWorldCorners(dropdownCorners); bottom = float.PositiveInfinity; top = float.NegativeInfinity; Vector3[] array = dropdownCorners; foreach (Vector3 val in array) { float y = ((Transform)relativeTo).InverseTransformPoint(val).y; bottom = Mathf.Min(bottom, y); top = Mathf.Max(top, y); } } private void RestoreDropdown() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)openedDropdown) && Object.op_Implicit((Object)(object)openedDropdown.m_DropDownList)) { ((Transform)openedDropdown.m_DropDownList).localPosition = dropdownPosition; } openedDropdown = null; } public void BeginNativeRefresh() { synchronizing = true; } public void EndNativeRefresh() { if (Object.op_Implicit((Object)(object)window)) { nativeRefreshMsaa = MsaaFromIndex(window.msaaComp.itemIndex); nativeRefreshFxaa = window.fxaaComp.isOn; } synchronizing = false; Refresh(); } public void Update() { if (!Object.op_Implicit((Object)(object)window) || draft == null) { return; } if (shownAvailability == plugin.Renderer.Availability && shownFsrAvailability == plugin.Renderer.FsrAvailability) { FrameGenerationOptions frameGenerationOptions = frameGeneration; if (frameGenerationOptions == null || !frameGenerationOptions.Changed) { return; } } Refresh(); } public void Refresh() { //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)window) || !Object.op_Implicit((Object)(object)technique) || !Object.op_Implicit((Object)(object)resolution) || !Object.op_Implicit((Object)(object)configuration) || draft == null) { return; } synchronizing = true; try { aaLabel.text = (Chinese ? "抗锯齿 / 超分辨率" : "AA / Super Resolution"); resolutionLabel.text = (Chinese ? "超分辨率档位" : "Resolution mode"); configurationLabel.text = (Chinese ? "配置" : "Configuration"); shownAvailability = plugin.Renderer.Availability; shownFsrAvailability = plugin.Renderer.FsrAvailability; techniqueChoices = GraphicsMenuChoices.Antialiasing(shownAvailability.Available, shownFsrAvailability.Available); SetItems(technique, Array.ConvertAll(techniqueChoices, TechniqueLabel), Array.IndexOf(techniqueChoices, draft.Choice), TechniqueLabel(draft.Choice)); string text = AvailabilityReason(shownAvailability); string text2 = AvailabilityReason(shownFsrAvailability); availabilityLabel.text = text + ((text.Length > 0 && text2.Length > 0) ? "\n" : "") + text2; bool flag = (!shownAvailability.Available && !shownAvailability.Pending) || (!shownFsrAvailability.Available && !shownFsrAvailability.Pending); ((Graphic)availabilityLabel).color = (Color)(flag ? new Color(1f, 0.82f, 0.55f, 1f) : ((Graphic)aaLabel).color); SetItems(resolution, new string[5] { (draft.Choice == AaChoice.Fsr) ? "Native AA" : "DLAA", Chinese ? "质量" : "Quality", Chinese ? "平衡" : "Balanced", Chinese ? "性能" : "Performance", Chinese ? "超级性能" : "Ultra Performance" }, (int)draft.Settings.Resolution); string[] items = ((draft.Choice != AaChoice.Dlss) ? ((draft.Choice != AaChoice.Msaa) ? new string[1] { Chinese ? "无" : "None" } : new string[3] { "2×", "4×", "8×" }) : new string[5] { Chinese ? "推荐" : "Recommended", "CNN", "Transformer K", "Transformer L", "Transformer M" }); SetItems(configuration, items, draft.ConfigurationIndex); frameGeneration?.Refresh(); RefreshLayout(); } finally { synchronizing = false; } } private string TechniqueLabel(AaChoice choice) { if (choice != AaChoice.None) { if (choice != AaChoice.Msaa) { if (choice != AaChoice.Fxaa) { if (choice != AaChoice.Taa) { return CapabilityLabel((choice == AaChoice.Fsr) ? shownFsrAvailability : shownAvailability); } return "TAA"; } return "FXAA"; } return "MSAA"; } if (!Chinese) { return "Off"; } return "关闭"; } private static string CapabilityLabel(UpscalerAvailability state) { return state.Name + (state.Available ? "" : ((!state.Pending) ? (Chinese ? "(不可用)" : " (unavailable)") : (Chinese ? "(检测中)" : " (checking)"))); } private static string AvailabilityReason(UpscalerAvailability state) { if (state.Reason != UpscalerSupportReason.Runtime) { return state.Describe(Chinese); } return state.Name + (Chinese ? " 不可用,请检查显卡、驱动与模组安装。" : " is unavailable. Check the GPU, driver and mod installation."); } internal static int MeasureNoteRows(Text note, float spacing) { if (string.IsNullOrEmpty(note.text)) { return 0; } int num = Mathf.Max(1, Mathf.CeilToInt((note.preferredHeight + 8f) / spacing)); ((Graphic)note).rectTransform.SetSizeWithCurrentAnchors((Axis)1, (float)num * spacing - 8f); return num; } private void RefreshLayout() { //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0125: 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) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) bool active = !string.IsNullOrEmpty(availabilityLabel.text); ((Component)availabilityLabel).gameObject.SetActive(active); int num = MeasureNoteRows(availabilityLabel, rowStep); bool available = plugin.Renderer.GetAvailability(draft.Choice).Available; bool flag = draft.ResolutionEnabled && available; bool flag2 = draft.ConfigurationEnabled && (draft.Choice != AaChoice.Dlss || available); ((Component)resolution).gameObject.SetActive(flag); ((Component)resolutionLabel).gameObject.SetActive(flag); ((Component)configuration).gameObject.SetActive(flag2); ((Component)configurationLabel).gameObject.SetActive(flag2); int num2 = (flag ? 1 : 0) + (flag2 ? 1 : 0); int num3 = num2 + num + (frameGeneration?.Rows ?? 0); RectTransform rectTransform = ((Graphic)aaLabel).rectTransform; RectTransform obj = layoutRoot; Rect rect = rectTransform.rect; float x = ((Transform)obj).InverseTransformPoint(((Transform)rectTransform).TransformPoint(new Vector3(((Rect)(ref rect)).xMin, 0f, 0f))).x; frameGeneration?.Layout(availabilityPosition.y - rowStep * (float)(num2 + num + 1), x); ((Transform)((Graphic)availabilityLabel).rectTransform).position = ((Transform)layoutRoot).TransformPoint(new Vector3(x, availabilityPosition.y - rowStep * ((float)num2 + 0.5f + (float)num * 0.5f), 0f)); Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(0f, rowStep * (float)(1 - num3)); foreach (KeyValuePair<RectTransform, Vector2> movedRow in movedRows) { if (Object.op_Implicit((Object)(object)movedRow.Key)) { movedRow.Key.anchoredPosition = movedRow.Value + val; } } ((RectTransform)((Component)configuration).transform).anchoredPosition = configurationPosition + new Vector2(0f, flag ? 0f : rowStep); ((RectTransform)((Component)configurationLabel).transform).anchoredPosition = configurationLabelPosition + new Vector2(0f, flag ? 0f : rowStep); layoutRoot.sizeDelta = originalContentSize - val; } public void Read(ref GameOption option) { if (draft != null && Object.op_Implicit((Object)(object)window)) { option.msaa = draft.NativeMsaa; option.fxaa = draft.NativeFxaa; plugin.Settings.Draft = draft.Settings; } } public void Close() { RestoreDropdown(); plugin.Settings.Cancel(); plugin.FrameGeneration.Cancel(); draft = null; } public void Defaults(int tab) { if (tab == 0) { plugin.Settings.Defaults(); plugin.FrameGeneration.Defaults(); draft = new AaMenuDraft(plugin.Settings.Draft, nativeRefreshMsaa, nativeRefreshFxaa); Refresh(); } } public void Dispose() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) Canvas.preWillRenderCanvases -= new WillRenderCanvases(ConstrainDropdown); RestoreDropdown(); frameGeneration?.Dispose(); frameGeneration = null; if (Object.op_Implicit((Object)(object)technique)) { ((Component)technique).gameObject.SetActive(false); Object.Destroy((Object)(object)((Component)technique).gameObject); } if (Object.op_Implicit((Object)(object)resolution)) { ((Component)resolution).gameObject.SetActive(false); Object.Destroy((Object)(object)((Component)resolution).gameObject); } if (Object.op_Implicit((Object)(object)resolutionLabel)) { ((Component)resolutionLabel).gameObject.SetActive(false); Object.Destroy((Object)(object)((Component)resolutionLabel).gameObject); } if (Object.op_Implicit((Object)(object)availabilityLabel)) { ((Component)availabilityLabel).gameObject.SetActive(false); Object.Destroy((Object)(object)((Component)availabilityLabel).gameObject); } availabilityLabel = null; shownAvailability = (shownFsrAvailability = null); foreach (KeyValuePair<RectTransform, Vector2> movedRow in movedRows) { if (Object.op_Implicit((Object)(object)movedRow.Key)) { movedRow.Key.anchoredPosition = movedRow.Value; } } movedRows.Clear(); if (Object.op_Implicit((Object)(object)layoutRoot)) { layoutRoot.sizeDelta = originalContentSize; } layoutRoot = null; if (Object.op_Implicit((Object)(object)configuration)) { ((Component)configuration).gameObject.SetActive(false); Object.Destroy((Object)(object)((Component)configuration).gameObject); } if (Object.op_Implicit((Object)(object)window)) { ((Component)window.msaaComp).gameObject.SetActive(originalAaActive); ((Component)window.fxaaComp).gameObject.SetActive(originalFxaaActive); } if (Object.op_Implicit((Object)(object)aaLabel) && originalAaLabel != null) { aaLabel.text = originalAaLabel; } if (Object.op_Implicit((Object)(object)configurationLabel) && originalConfigurationLabel != null) { configurationLabel.text = originalConfigurationLabel; ((Component)configurationLabel).gameObject.SetActive(originalConfigurationLabelActive); } if (Object.op_Implicit((Object)(object)aaLocalizer)) { ((Behaviour)aaLocalizer).enabled = originalAaLocalized; } if (Object.op_Implicit((Object)(object)configurationLocalizer)) { ((Behaviour)configurationLocalizer).enabled = originalConfigurationLocalized; } window = null; technique = (resolution = (configuration = null)); aaLabel = (resolutionLabel = (configurationLabel = null)); aaLocalizer = (configurationLocalizer = null); draft = null; } } [HarmonyPatch(typeof(UIOptionWindow), "_OnOpen")] internal static class OptionsOpenPatch { private static void Postfix(UIOptionWindow __instance) { Plugin.Instance?.Guard(delegate { Plugin.Instance.Options.Open(__instance); }); } } [HarmonyPatch(typeof(UIOptionWindow), "_OnClose")] internal static class OptionsClosePatch { private static void Postfix() { Plugin.Instance?.Options.Close(); } } [HarmonyPatch(typeof(UIOptionWindow), "TempOptionToUI")] internal static class OptionsRefreshPatch { private static void Prefix() { Plugin.Instance?.Options.BeginNativeRefresh(); } private static void Postfix() { Plugin.Instance?.Guard(delegate { Plugin.Instance.Options.EndNativeRefresh(); }); } } [HarmonyPatch(typeof(UIOptionWindow), "UIToTempOption")] internal static class OptionsReadPatch { private static void Postfix(ref GameOption ___tempOption) { //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) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) GameOption value = ___tempOption; Plugin.Instance?.Guard(delegate { Plugin.Instance.Options.Read(ref value); }); ___tempOption = value; } } [HarmonyPatch(typeof(UIOptionWindow), "ApplyOptions")] internal static class OptionsApplyPatch { private static void Prefix(ref GameOption ___tempOption) { //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) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) GameOption value = ___tempOption; Plugin.Instance?.Guard(delegate { Plugin.Instance.Options.Read(ref value); }); ___tempOption = value; } private static void Postfix() { Plugin.Instance?.Guard(delegate { Plugin.Instance.ApplySettings(); }); Plugin.Instance?.Guard(delegate { Plugin.Instance.ApplyFrameGeneration(); }); } } [HarmonyPatch(typeof(UIOptionWindow), "OnLanguageChange")] internal static class OptionsLanguagePatch { private static void Postfix() { Plugin.Instance?.Guard(delegate { Plugin.Instance.Options.Refresh(); }); } } [HarmonyPatch(typeof(UIComboBox), "OnPopButtonClick")] internal static class AaDropdownPatch { private static void Postfix(UIComboBox __instance) { Plugin.Instance?.Guard(delegate { Plugin.Instance.Options.DropdownOpened(__instance); }); } } [HarmonyPatch(typeof(UIOptionWindow), "OnRevertButtonClick")] internal static class OptionsDefaultsPatch { private static void Postfix(int idx) { Plugin.Instance?.Guard(delegate { Plugin.Instance.Options.Defaults(idx); }); } } } namespace DSPAAMod.Interop { public struct NativeFrame { public uint Size; public uint Version; public ulong Camera; public ulong Frame; public IntPtr Color; public IntPtr Output; public IntPtr Depth; public IntPtr Motion; public uint Width; public uint Height; public uint Preset; public uint Flags; public float JitterX; public float JitterY; public float MotionScaleX; public float MotionScaleY; public float FrameTimeMilliseconds; public uint Reserved; public uint OutputWidth; public uint OutputHeight; public uint Quality; public uint Reserved2; } public struct NativeFsrParameters { public uint Size; public float CameraNear; public float CameraFar; public float VerticalFov; public float PreExposure; public float ViewSpaceToMeters; public float Sharpness; public uint Reserved; public IntPtr OpaqueColor; } public struct NativeFsrOptimalSettings { public NativeOptimalSettings Settings; public uint JitterPhases; } public struct NativeStatus { public uint Size; public int Result; public ulong Frame; public uint RequestedPreset; public uint ObservedPreset; public uint Verification; public uint Reserved; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] public byte[] MessageBytes; public string Message { get { if (MessageBytes == null) { return string.Empty; } int num = Array.IndexOf(MessageBytes, (byte)0); return Encoding.UTF8.GetString(MessageBytes, 0, (num < 0) ? MessageBytes.Length : num); } } } public struct NativeOptimalSettings { public uint Size; public int Result; public uint OutputWidth; public uint OutputHeight; public uint Quality; public uint OptimalWidth; public uint OptimalHeight; public uint MinWidth; public uint MinHeight; public uint MaxWidth; public uint MaxHeight; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] public byte[] MessageBytes; public string Message { get { if (MessageBytes == null) { return string.Empty; } int num = Array.IndexOf(MessageBytes, (byte)0); return Encoding.UTF8.GetString(MessageBytes, 0, (num < 0) ? MessageBytes.Length : num); } } } public struct NativeSupport { public uint Size; public int Result; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] public byte[] MessageBytes; public string Message { get { if (MessageBytes == null) { return string.Empty; } int num = Array.IndexOf(MessageBytes, (byte)0); return Encoding.UTF8.GetString(MessageBytes, 0, (num < 0) ? MessageBytes.Length : num); } } } public sealed class NativeBridge { [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate uint Abi(); [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] private delegate int Initialize(string runtime, string data); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate IntPtr GetEvent(); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate IntPtr QueueFrame(ref NativeFrame frame); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate IntPtr QueueRelease(ulong camera); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate IntPtr QueueShutdown(); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate void CancelCommand(IntPtr token); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate int ReadStatus(ulong camera, ref NativeStatus status); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate IntPtr QueueOptimal(ulong camera, IntPtr deviceResource, uint width, uint height, uint quality); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate int ReadOptimal(ulong camera, ref NativeOptimalSettings settings); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate IntPtr QueueSupport(IntPtr deviceResource); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate int ReadSupport(IntPtr token, ref NativeSupport support); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate IntPtr QueueFsrFrame(ref NativeFrame frame, ref NativeFsrParameters parameters); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate IntPtr QueueBackendSupport(IntPtr resource, uint backend); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate IntPtr QueueBackendOptimal(ulong camera, IntPtr resource, uint width, uint height, uint quality, uint backend); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate int ReadFsrOptimal(ulong camera, ref NativeFsrOptimalSettings result); private readonly IntPtr module; private readonly QueueFrame queueFrame; private readonly QueueRelease queueRelease; private readonly QueueShutdown queueShutdown; private readonly CancelCommand cancel; private readonly ReadStatus readStatus; private readonly QueueOptimal queueOptimal; private readonly ReadOptimal readOptimal; private readonly QueueSupport queueSupport; private readonly ReadSupport readSupport; private readonly QueueFsrFrame queueFsrFrame; private readonly QueueBackendSupport queueBackendSupport; private readonly QueueBackendOptimal queueBackendOptimal; private readonly ReadFsrOptimal readFsrOptimal; public IntPtr RenderEvent { get; } public static uint FrameSize => (uint)Marshal.SizeOf(typeof(NativeFrame)); public static uint StatusSize => (uint)Marshal.SizeOf(typeof(NativeStatus)); public static uint OptimalSize => (uint)Marshal.SizeOf(typeof(NativeOptimalSettings)); public static uint SupportSize => (uint)Marshal.SizeOf(typeof(NativeSupport)); public static uint FsrParametersSize => (uint)Marshal.SizeOf(typeof(NativeFsrParameters)); public static uint FsrOptimalSize => (uint)Marshal.SizeOf(typeof(NativeFsrOptimalSettings)); [DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] private static extern IntPtr GetProcAddress(IntPtr module, string name); public NativeBridge(string directory, string dataDirectory) { if (!Environment.Is64BitProcess) { throw new PlatformNotSupportedException("DSPAAMod requires x64."); } module = NativeModule.Load(Path.Combine(directory, "DSPAANative.dll")); if (Get<Abi>("DspAaGetAbiVersion")() != 2 || FrameSize != 112 || StatusSize != 288 || OptimalSize != 300 || SupportSize != 264 || FsrParametersSize != 40 || FsrOptimalSize != 304) { throw new InvalidOperationException("Native/managed DSPAAMod ABI mismatch."); } queueFrame = Get<QueueFrame>("DspAaQueueFrame"); queueRelease = Get<QueueRelease>("DspAaQueueRelease"); queueShutdown = Get<QueueShutdown>("DspAaQueueShutdown"); cancel = Get<CancelCommand>("DspAaCancel"); readStatus = Get<ReadStatus>("DspAaGetStatus"); queueOptimal = Get<QueueOptimal>("DspAaQueueOptimalSettings"); readOptimal = Get<ReadOptimal>("DspAaGetOptimalSettings"); queueSupport = Get<QueueSupport>("DspAaQueueSupport"); readSupport = Get<ReadSupport>("DspAaGetSupport"); queueFsrFrame = Get<QueueFsrFrame>("DspAaQueueFsrFrame"); queueBackendSupport = Get<QueueBackendSupport>("DspAaQueueSupportForBackend"); queueBackendOptimal = Get<QueueBackendOptimal>("DspAaQueueOptimalSettingsForBackend"); readFsrOptimal = Get<ReadFsrOptimal>("DspAaGetFsrOptimalSettings"); RenderEvent = Get<GetEvent>("DspAaGetRenderEvent")(); if (RenderEvent == IntPtr.Zero || Get<Initialize>("DspAaInitialize")(directory, dataDirectory) != 1) { throw new InvalidOperationException("Native bridge initialization failed; check runtime path and log permissions."); } } internal T Get<T>(string name) where T : Delegate { IntPtr procAddress = GetProcAddress(module, name); if (procAddress == IntPtr.Zero) { throw new EntryPointNotFoundException(name); } return (T)Marshal.GetDelegateForFunctionPointer(procAddress, typeof(T)); } public IntPtr Submit(ref NativeFrame frame) { frame.Size = FrameSize; frame.Version = 2u; return queueFrame(ref frame); } public IntPtr SubmitFsr(ref NativeFrame frame, ref NativeFsrParameters parameters) { frame.Size = FrameSize; frame.Version = 2u; parameters.Size = FsrParametersSize; return queueFsrFrame(ref frame, ref parameters); } public IntPtr RequestOptimal(ulong camera, IntPtr resource, uint width, uint height, uint quality, uint backend) { return queueBackendOptimal(camera, resource, width, height, quality, backend); } public bool TryGetFsrOptimal(ulong camera, out NativeFsrOptimalSettings result) { result = new NativeFsrOptimalSettings { Settings = new NativeOptimalSettings { Size = FsrOptimalSize, MessageBytes = new byte[256] } }; return readFsrOptimal(camera, ref result) == 1; } public IntPtr RequestSupport(IntPtr resource, uint backend) { return queueBackendSupport(resource, backend); } public IntPtr RequestOptimal(ulong camera, IntPtr deviceResource, uint width, uint height, uint quality) { return queueOptimal(camera, deviceResource, width, height, quality); } public bool TryGetOptimal(ulong camera, out NativeOptimalSettings result) { result = new NativeOptimalSettings { Size = OptimalSize, MessageBytes = new byte[256] }; return readOptimal(camera, ref result) == 1; } public IntPtr RequestSupport(IntPtr deviceResource) { return queueSupport(deviceResource); } public bool TryGetSupport(IntPtr token, out NativeSupport result) { result = new NativeSupport { Size = SupportSize, MessageBytes = new byte[256] }; return readSupport(token, ref result) == 1; } public IntPtr Release(ulong camera) { return queueRelease(camera); } public IntPtr Shutdown() { return queueShutdown(); } public void Cancel(IntPtr token) { if (token != IntPtr.Zero) { cancel(token); } } public bool TryGetStatus(ulong camera, out NativeStatus status) { status = new NativeStatus { Size = StatusSize, MessageBytes = new byte[256] }; return readStatus(camera, ref status) == 1; } } internal static class NativeModule { [DllImport("kernel32.dll", CharSet = CharSet.Unicode, EntryPoint = "LoadLibraryExW", ExactSpelling = true, SetLastError = true)] private static extern IntPtr LoadLibraryEx(string path, IntPtr file, uint flags); internal static IntPtr Load(string path) { path = Path.GetFullPath(path); IntPtr intPtr = LoadLibraryEx(path, IntPtr.Zero, 4352u); if (intPtr == IntPtr.Zero) { throw new NativeModuleLoadException(Marshal.GetLastWin32Error(), path, File.Exists(path)); } return intPtr; } } internal sealed class NativeModuleLoadException : Win32Exception { internal string ModulePath { get; } internal bool ModuleFound { get; } internal NativeModuleLoadException(int error, string path, bool found) : base(error, Describe(error, found)) { ModulePath = path; ModuleFound = found; } private static string Describe(int error, bool found) { string text; if ((error == 2 || error == 3 || error == 126) && !found) { text = "Keep the complete package beside DSPAAMod.dll in the plugin folder."; } else { switch (error) { case 126: text = "The file exists; a required dependency may be missing."; break; case 193: case 216: text = "Check for a damaged or non-x64 DLL and reinstall the complete package."; break; default: text = "Check the installation and Windows file access."; break; } } return "Cannot load DSPAANative.dll (Windows error " + error + ": " + new Win32Exception(error).Message + "). " + text + " See BepInEx/LogOutput.log."; } public override string ToString() { return ((ExternalException)this).ToString() + Environment.NewLine + "Expected native module: " + ModulePath + Environment.NewLine + "File present at diagnostic check: " + ModuleFound; } } internal static class PresentationAvailability { internal static bool CanRequest(NativePresentationStatus caps, PresentationStartupState startup, FrameGenerationBackend backend, bool runtimeFilesPresent) { if (backend == FrameGenerationBackend.Off) { return true; } if (caps.Quarantined) { return false; } if (caps.Available) { return backend switch { FrameGenerationBackend.Dlss => caps.DlssSupported, FrameGenerationBackend.Fsr => caps.FsrRuntimePresent, _ => false, }; } if (startup == PresentationStartupState.Inactive && runtimeFilesPresent) { if (backend != FrameGenerationBackend.Fsr) { return backend == FrameGenerationBackend.Dlss; } return true; } return false; } internal static bool NeedsRestart(NativePresentationStatus caps, PresentationStartupState startup, FrameGenerationSettings request) { if (!caps.Available && !caps.Quarantined && startup == PresentationStartupState.Inactive) { return request.Backend != FrameGenerationBackend.Off; } return false; } } public struct NativePresentationConfiguration { public uint Size; public uint Version; public uint Backend; public uint Mode; public uint GeneratedFrames; public uint Reflex; public float DynamicTargetFrameRate; public uint FrameLimitMicroseconds; } public struct NativePresentationBegin { public uint Size; public uint Version; public ulong ApplicationFrameId; public ulong Generation; } public struct NativePresentationInputs { public uint Size; public uint Version; public ulong ApplicationFrameId; public ulong Generation; public IntPtr Hudless; public IntPtr Depth; public IntPtr Motion; public IntPtr FsrDistortion; public IntPtr SlDistortion; public uint RenderWidth; public uint RenderHeight; public uint Flags; public uint Reserved; public float JitterX; public float JitterY; public float MotionScaleX; public float MotionScaleY; public float Milliseconds; public float CameraNear; public float CameraFar; public float VerticalFov; public float PreExposure; public float ViewSpaceToMeters; public float MinLuminance; public float MaxLuminance; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public float[] CameraPosition; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public float[] CameraUp; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public float[] CameraRight; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public float[] CameraForward; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public float[] CameraViewToClip; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public float[] ClipToCameraView; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public float[] ClipToPrevClip; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public float[] PrevClipToClip; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public int[] GenerationRect; public uint LogicalOutputWidth; public uint LogicalOutputHeight; public static NativePresentationInputs Create() { return new NativePresentationInputs { CameraPosition = new float[3], CameraUp = new float[3], CameraRight = new float[3], CameraForward = new float[3], CameraViewToClip = new float[16], ClipToCameraView = new float[16], ClipToPrevClip = new float[16], PrevClipToClip = new float[16], GenerationRect = new int[4], PreExposure = 1f, ViewSpaceToMeters = 1f, MaxLuminance = 100f }; } } public struct NativePresentationStatus { public uint Size; public uint Version; public uint Flags; public uint RequestedBackend; public uint ActiveBackend; public uint ActiveMode; public uint MaximumGeneratedFrames; public uint Width; public uint Height; public uint SdkStatus; public ulong Generation; public ulong LastApplicationFrameId; public ulong LastPresentedFrameId; public ulong ApplicationPresents; public ulong GeneratedSubmissions; public ulong SdkReportedPresents; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 384)] public byte[] MessageBytes; public bool Available => (Flags & 1) != 0; public bool FsrRuntimePresent => (Flags & 2) != 0; public bool DlssSupported => (Flags & 4) != 0; public bool ReflexSupported => (Flags & 8) != 0; public bool DynamicSupported => (Flags & 0x10) != 0; public bool Generating => (Flags & 0x40) != 0; public bool Quarantined => (Flags & 0x80) != 0; public string Message { get { if (MessageBytes == null) { return string.Empty; } int num = Array.IndexOf(MessageBytes, (byte)0); return Encoding.UTF8.GetString(MessageBytes, 0, (num < 0) ? MessageBytes.Length : num); } } } public sealed class PresentationBridge { [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate uint Abi(); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate int ConfigureNative(ref NativePresentationConfiguration value); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate int BeginNative(ref NativePresentationBegin value); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate int EndSimulationNative(ulong id); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate IntPtr QueueNative(ref NativePresentationInputs value); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate void CancelNative(IntPtr token); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate int StatusNative(ref NativePresentationStatus value); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate IntPtr EventNative(); public const uint AbiVersion = 3u; private readonly ConfigureNative configure; private readonly BeginNative begin; private readonly EndSimulationNative simulationEnd; private readonly QueueNative queue; private readonly CancelNative cancel; private readonly StatusNative status; public IntPtr RenderEvent { get; } public static uint ConfigurationSize => (uint)Marshal.SizeOf(typeof(NativePresentationConfiguration)); public static uint BeginSize => (uint)Marshal.SizeOf(typeof(NativePresentationBegin)); public static uint InputsSize => (uint)Marshal.SizeOf(typeof(NativePresentationInputs)); public static uint StatusSize => (uint)Marshal.SizeOf(typeof(NativePresentationStatus)); public PresentationBridge(NativeBridge library) { if (library.Get<Abi>("DspAaGetPresentationAbiVersion")() != 3 || ConfigurationSize != 32 || BeginSize != 24 || InputsSize != 456 || StatusSize != 472) { throw new InvalidOperationException("Native/managed presentation ABI mismatch."); } configure = library.Get<ConfigureNative>("DspAaConfigurePresentation"); begin = library.Get<BeginNative>("DspAaBeginPresentationFrame"); simulationEnd = library.Get<EndSimulationNative>("DspAaPresentationSimulationEnd"); queue = library.Get<QueueNative>("DspAaQueuePresentationInputs"); cancel = library.Get<CancelNative>("DspAaCancelPresentationInputs"); status = library.Get<StatusNative>("DspAaGetPresentationStatus"); RenderEvent = library.Get<EventNative>("DspAaGetPresentationRenderEvent")(); if (RenderEvent == IntPtr.Zero) { throw new InvalidOperationException("Missing presentation render event."); } } public bool Configure(NativePresentationConfiguration value) { value.Size = ConfigurationSize; value.Version = 3u; return configure(ref value) == 1; } public bool Begin(out NativePresentationBegin value) { value = new NativePresentationBegin { Size = BeginSize, Version = 3u }; return begin(ref value) == 1; } public bool SimulationEnd(ulong id) { return simulationEnd(id) == 1; } public IntPtr Queue(ref NativePresentationInputs value) { value.Size = InputsSize; value.Version = 3u; return queue(ref value); } public void Cancel(IntPtr token) { if (token != IntPtr.Zero) { cancel(token); } } public bool TryGetStatus(out NativePresentationStatus value) { value = new NativePresentationStatus { Size = StatusSize, MessageBytes = new byte[384] }; return status(ref value) == 1; } } } namespace DSPAAMod.Game { internal sealed class FrameCapture { private sealed class Resource { public string Name; public string File; public string Error; public string Hash; public int Width; public int Height; public readonly Dictionary<string, string> Metadata = new Dictionary<string, string>(); public byte[] Bytes; public bool Claimed; } private sealed class Frame { public NativeFrame Native; public int UnityFrame; public readonly Dictionary<string, string> Metadata = new Dictionary<string, string>(); public readonly List<Resource> Resources = new List<Resource>(); } private sealed class Group { public string Id; public string Directory; public RenderTargets Targets; public readonly List<Frame> Frames = new List<Frame>(); public readonly List<string> Errors = new List<string>(); public int Pending; public bool Sealed; public bool Writing; } private readonly string directory; private readonly Action<string> log; private readonly object gate = new object(); private readonly Dictionary<RenderTargets, int> pending = new Dictionary<RenderTargets, int>(); private Group active; public FrameCapture(string directory, Action<string> log) { this.directory = directory; this.log = log; } public bool Request() { lock (gate) { if (active != null) { Log("Frame capture request ignored: a capture is already armed or in progress."); return false; } try { string id = DateTime.UtcNow.ToString("yyyyMMdd-HHmmss-fff", CultureInfo.InvariantCulture) + "-" + Guid.NewGuid().ToString("N"); Group obj = new Group { Id = id, Directory = Path.Combine(directory, id) }; if (Directory.Exists(obj.Directory)) { throw new IOException("Capture directory already exists."); } Directory.CreateDirectory(obj.Directory); WriteDocument(Path.Combine(obj.Directory, "request.xml"), "captureRequest", delegate(XmlWriter writer) { Value(writer, "id", id); Value(writer, "requestedUtc", DateTime.UtcNow.ToString("O", CultureInfo.InvariantCulture)); Value(writer, "frameCount", 2); Value(writer, "state", "armed; result.xml is the terminal record"); }); active = obj; if (!SystemInfo.supportsAsyncGPUReadback) { Fail(obj, "AsyncGPUReadback is unsupported on this device."); FinishIfReady(obj); } else { Log("Frame capture armed for two consecutive submissions from the first captured camera: " + obj.Directory); } return true; } catch (Exception ex) { Log("Cannot arm frame capture: " + ex.Message); if (active != null) { Fail(active, "Cannot finish arming capture: " + ex.Message); FinishIfReady(active); } return false; } } } public bool IsBusy(RenderTargets targets) { lock (gate) { int value; return targets != null && pending.TryGetValue(targets, out value) && value != 0; } } public void Cancel(string reason) { lock (gate) { if (active != null && !active.Sealed) { Fail(active, "Capture cancelled: " + reason); FinishIfReady(active); } } } public void Cancel(RenderTargets targets, string reason) { lock (gate) { if (active != null && active.Targets == targets) { Cancel(reason); } } } public void EnqueueIfRequested(NativeFrame native, RenderTargets targets, Camera camera, Matrix4x4 renderedProjection, int deferredWorldTextCount) { //IL_0582: Unknown result type (might be due to invalid IL or missing references) //IL_0588: Unknown result type (might be due to invalid IL or missing references) //IL_0520: Unknown result type (might be due to invalid IL or missing references) //IL_0525: Unknown result type (might be due to invalid IL or missing references) //IL_0550: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_0369: Unknown result type (might be due to invalid IL or missing references) //IL_0386: Unknown result type (might be due to invalid IL or missing references) //IL_03a3: Unknown result type (might be due to invalid IL or missing references) //IL_03c0: Unknown result type (might be due to invalid IL or missing references) //IL_03ca: Expected I4, but got Unknown //IL_0422: Unknown result type (might be due to invalid IL or missing references) //IL_0428: Invalid comparison between Unknown and I4 //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) lock (gate) { Group group = active; if (group == null || group.Sealed) { return; } if (group.Frames.Count != 0) { Frame frame = group.Frames[0]; int frameCount = Time.frameCount; if (native.Camera != frame.Native.Camera && frameCount <= frame.UnityFrame + 1) { return; } if (native.Camera != frame.Native.Camera || targets != group.Targets || native.Frame != frame.Native.Frame + 1 || frameCount != frame.UnityFrame + 1) { Fail(group, "Expected the same camera/targets on consecutive native and Unity frames; got native " + frame.Native.Frame + " -> " + native.Frame + ", Unity " + frame.UnityFrame + " -> " + frameCount + "."); FinishIfReady(group); return; } } try { if (targets == null || (Object)(object)camera == (Object)null) { throw new InvalidOperationException("Capture has no live targets/camera."); } Frame frame2 = new Frame { Native = native }; SnapshotFrame(frame2, camera, renderedProjection, deferredWorldTextCount); RenderTexture[] array = (RenderTexture[])(object)new RenderTexture[4] { targets.Color, targets.Depth, targets.Motion, targets.Output }; string[] array2 = new string[4] { "color", "depth", "motion", "output" }; for (int i = 0; i < array.Length; i++) { RenderTexture val = array[i]; if (!Object.op_Implicit((Object)(object)val) || !val.IsCreated()) { throw new InvalidOperationException(array2[i] + " texture is not created."); } if (!SystemInfo.IsFormatSupported(val.graphicsFormat, (FormatUsage)9)) { throw new NotSupportedException(array2[i] + " format does not support unconverted readback: " + ((object)val.graphicsFormat/*cast due to .constrained prefix*/).ToString()); } Resource resource = new Resource(); resource.Name = array2[i]; resource.File = "frame-" + group.Frames.Count + "-" + array2[i] + ".raw"; resource.Width = ((Texture)val).width; resource.Height = ((Texture)val).height; Resource resource2 = resource; Add(resource2.Metadata, "width", ((Texture)val).width); Add(resource2.Metadata, "height", ((Texture)val).height); Add(resource2.Metadata, "volumeDepth", val.volumeDepth); Add(resource2.Metadata, "dimension", ((Texture)val).dimension); Add(resource2.Metadata, "renderTextureFormat", val.format); Add(resource2.Metadata, "graphicsFormat", val.graphicsFormat); Add(resource2.Metadata, "graphicsFormatValue", (int)val.graphicsFormat); Add(resource2.Metadata, "antiAliasing", val.antiAliasing); Add(resource2.Metadata, "sRGB", val.sRGB); Add(resource2.Metadata, "mip", 0); if ((int)((Texture)val).dimension != 2 || val.volumeDepth != 1) { throw new NotSupportedException("Capture expects single-layer 2D render textures."); } frame2.Resources.Add(resource2); } group.Targets = targets; group.Frames.Add(frame2); group.Sealed = group.Frames.Count == 2; group.Pending += array.Length; pending.TryGetValue(targets, out var value); pending[targets] = value + array.Length; for (int j = 0; j < array.Length; j++) { Resource resource3 = frame2.Resources[j]; try { AsyncGPUReadbackRequest request = AsyncGPUReadback.Request((Texture)(object)array[j], 0, (Action<AsyncGPUReadbackRequest>)delegate(AsyncGPUReadbackRequest completed) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) Complete(group, targets, resource3, completed, null); }); if (((AsyncGPUReadbackRequest)(ref request)).hasError) { Complete(group, targets, resource3, request, "GPU readback request failed."); } } catch (Exception ex) { Complete(group, targets, resource3, default(AsyncGPUReadbackRequest), "Cannot submit readback: " + ex.Message); } } } catch (Exception ex2) { Fail(group, "Cannot capture submitted frame: " + ex2.Message); FinishIfReady(group); } } } private void Complete(Group group, RenderTargets targets, Resource resource, AsyncGPUReadbackRequest request, string failure) { //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) lock (gate) { if (resource.Claimed) { return; } resource.Claimed = true; } try { if (failure != null) { throw new InvalidOperationEx
patchers/DSPAASR.Preloader.dll
Decompiled a month agousing System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using DSPAAMod.Core; using DSPAAMod.Interop; 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("NordLandeW")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Early presentation entry for DSPAASR.")] [assembly: AssemblyFileVersion("1.2.0.0")] [assembly: AssemblyInformationalVersion("1.2.0+d9acbc2eda5311a22be61cd68392d9aaa4407c0e")] [assembly: AssemblyProduct("DSPAASR")] [assembly: AssemblyTitle("DSPAASR.Preloader")] [assembly: AssemblyVersion("1.2.0.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 DSPAAMod.Interop { internal static class NativeModule { [DllImport("kernel32.dll", CharSet = CharSet.Unicode, EntryPoint = "LoadLibraryExW", ExactSpelling = true, SetLastError = true)] private static extern IntPtr LoadLibraryEx(string path, IntPtr file, uint flags); internal static IntPtr Load(string path) { path = Path.GetFullPath(path); IntPtr intPtr = LoadLibraryEx(path, IntPtr.Zero, 4352u); if (intPtr == IntPtr.Zero) { throw new NativeModuleLoadException(Marshal.GetLastWin32Error(), path, File.Exists(path)); } return intPtr; } } internal sealed class NativeModuleLoadException : Win32Exception { internal string ModulePath { get; } internal bool ModuleFound { get; } internal NativeModuleLoadException(int error, string path, bool found) : base(error, Describe(error, found)) { ModulePath = path; ModuleFound = found; } private static string Describe(int error, bool found) { string text; if ((error == 2 || error == 3 || error == 126) && !found) { text = "Keep the complete package beside DSPAAMod.dll in the plugin folder."; } else { switch (error) { case 126: text = "The file exists; a required dependency may be missing."; break; case 193: case 216: text = "Check for a damaged or non-x64 DLL and reinstall the complete package."; break; default: text = "Check the installation and Windows file access."; break; } } return "Cannot load DSPAANative.dll (Windows error " + error + ": " + new Win32Exception(error).Message + "). " + text + " See BepInEx/LogOutput.log."; } public override string ToString() { return ((ExternalException)this).ToString() + Environment.NewLine + "Expected native module: " + ModulePath + Environment.NewLine + "File present at diagnostic check: " + ModuleFound; } } } namespace DSPAAMod.Core { public enum PresentationStartupState { Missing, Inactive, Started, Failed } public sealed class PresentationStartup { private const string ReceiptKey = "DSPAASR.PresentationStartup"; private const int ReceiptVersion = 1; public PresentationStartupState State { get; } public string RuntimeDirectory { get; } public int RequestedBackend { get; } public string Error { get; } private PresentationStartup(PresentationStartupState state, string directory, int backend, string error) { State = state; RuntimeDirectory = directory; RequestedBackend = backend; Error = error ?? string.Empty; } public static PresentationStartup Read(string runtimeDirectory) { string text; try { text = NormalizeDirectory(runtimeDirectory); } catch (Exception ex) { return Failure(string.Empty, "Invalid plugin directory: " + ex.Message); } object data; lock (AppDomain.CurrentDomain) { data = AppDomain.CurrentDomain.GetData("DSPAASR.PresentationStartup"); } if (data == null) { return new PresentationStartup(PresentationStartupState.Missing, text, -1, "The presentation preloader did not report a result in this process."); } if (!(data is object[] array) || array.Length != 5 || !(array[0] is int num) || num != 1 || !(array[1] is int num2) || num2 < 1 || num2 > 3 || !(array[2] is string text2) || !(array[3] is int num3) || num3 < -1 || num3 > 2 || !(array[4] is string error)) { return Failure(text, "Invalid presentation preloader receipt."); } PresentationStartupState presentationStartupState = (PresentationStartupState)num2; if ((presentationStartupState == PresentationStartupState.Inactive && num3 != 0) || (presentationStartupState == PresentationStartupState.Started && num3 != 1 && num3 != 2)) { return Failure(text, "Inconsistent presentation preloader intent."); } if (!string.Equals(text2, text, StringComparison.OrdinalIgnoreCase)) { if (presentationStartupState == PresentationStartupState.Failed && text2.Length == 0) { return new PresentationStartup(presentationStartupState, text, num3, error); } return Failure(text, "The presentation preloader selected a different plugin directory."); } return new PresentationStartup(presentationStartupState, text2, num3, error); } private static PresentationStartup Failure(string directory, string error) { return new PresentationStartup(PresentationStartupState.Failed, directory, -1, error); } internal static string NormalizeDirectory(string directory) { if (string.IsNullOrWhiteSpace(directory)) { throw new ArgumentException("A plugin directory is required."); } string fullPath = Path.GetFullPath(directory); string pathRoot = Path.GetPathRoot(fullPath); if (fullPath.Length <= pathRoot.Length) { return fullPath; } return fullPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); } internal static bool TryClaim() { lock (AppDomain.CurrentDomain) { if (AppDomain.CurrentDomain.GetData("DSPAASR.PresentationStartup") != null) { return false; } AppDomain.CurrentDomain.SetData("DSPAASR.PresentationStartup", new object[5] { 1, 3, string.Empty, -1, "Presentation preloader initialization did not complete." }); return true; } } internal static void Publish(PresentationStartupState state, string directory, int backend, string error = "") { if (state == PresentationStartupState.Missing) { throw new ArgumentOutOfRangeException("state"); } string text = (string.IsNullOrEmpty(directory) ? string.Empty : NormalizeDirectory(directory)); object[] data = new object[5] { 1, (int)state, text, backend, error ?? string.Empty }; lock (AppDomain.CurrentDomain) { AppDomain.CurrentDomain.SetData("DSPAASR.PresentationStartup", data); } } } public enum FrameGenerationBackend { Off, Fsr, Dlss } public enum FrameGenerationMode { Fixed, Dynamic } public enum ReflexMode { Off, On, OnWithBoost } public readonly struct FrameGenerationSettings : IEquatable<FrameGenerationSettings> { public readonly FrameGenerationBackend Backend; public readonly FrameGenerationMode Mode; public readonly uint GeneratedFrames; public readonly ReflexMode Reflex; public readonly float DynamicTargetFrameRate; public readonly uint FrameLimitMicroseconds; public static FrameGenerationSettings Default => new FrameGenerationSettings(FrameGenerationBackend.Off); public FrameGenerationSettings(FrameGenerationBackend backend, FrameGenerationMode mode = FrameGenerationMode.Fixed, uint generatedFrames = 1u, ReflexMode reflex = ReflexMode.On, float dynamicTargetFrameRate = 0f, uint frameLimitMicroseconds = 0u) { if (!Enum.IsDefined(typeof(FrameGenerationBackend), backend)) { throw new ArgumentOutOfRangeException("backend"); } if (!Enum.IsDefined(typeof(FrameGenerationMode), mode)) { throw new ArgumentOutOfRangeException("mode"); } if (!Enum.IsDefined(typeof(ReflexMode), reflex)) { throw new ArgumentOutOfRangeException("reflex"); } if (generatedFrames == 0 || generatedFrames == uint.MaxValue) { throw new ArgumentOutOfRangeException("generatedFrames"); } if (float.IsNaN(dynamicTargetFrameRate) || float.IsInfinity(dynamicTargetFrameRate) || dynamicTargetFrameRate < 0f) { throw new ArgumentOutOfRangeException("dynamicTargetFrameRate"); } if (backend == FrameGenerationBackend.Fsr && (mode != FrameGenerationMode.Fixed || generatedFrames != 1)) { throw new ArgumentException("Analytical FSR supports one additional frame, not DLSS Multi/Dynamic generation."); } Backend = backend; Mode = mode; GeneratedFrames = generatedFrames; Reflex = reflex; DynamicTargetFrameRate = dynamicTargetFrameRate; FrameLimitMicroseconds = frameLimitMicroseconds; } public bool Equals(FrameGenerationSettings other) { if (Backend == other.Backend && Mode == other.Mode && GeneratedFrames == other.GeneratedFrames && Reflex == other.Reflex && DynamicTargetFrameRate == other.DynamicTargetFrameRate) { return FrameLimitMicroseconds == other.FrameLimitMicroseconds; } return false; } public override bool Equals(object value) { if (value is FrameGenerationSettings other) { return Equals(other); } return false; } public override int GetHashCode() { uint num = ((((((uint)((int)Backend * 397) ^ (uint)Mode) * 397) ^ GeneratedFrames) * 397) ^ (uint)Reflex) * 397; float dynamicTargetFrameRate = DynamicTargetFrameRate; return (int)(((num ^ (uint)dynamicTargetFrameRate.GetHashCode()) * 397) ^ FrameLimitMicroseconds); } } public sealed class FrameGenerationSettingsSession { public FrameGenerationSettings Applied { get; private set; } public FrameGenerationSettings Draft { get; set; } public FrameGenerationSettingsSession(FrameGenerationSettings value) { Applied = (Draft = value); } public void Open() { Draft = Applied; } public void Cancel() { Draft = Applied; } public void Defaults() { Draft = FrameGenerationSettings.Default; } public void Apply() { Apply(null); } public void Apply(Action<FrameGenerationSettings> persist) { FrameGenerationSettings draft = Draft; persist?.Invoke(draft); Applied = draft; } } } namespace DSPAASR.Preloader { public static class Patcher { [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] private delegate int Bootstrap(uint abi, [MarshalAs(UnmanagedType.LPWStr)] string runtime, [MarshalAs(UnmanagedType.LPWStr)] string data, uint mode); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate uint GetAbi(); public static IEnumerable<string> TargetDLLs => Array.Empty<string>(); public static void Patch(AssemblyDefinition assembly) { } public static void Initialize() { if (!PresentationStartup.TryClaim()) { return; } string text = string.Empty; int num = -1; ManualLogSource val = Logger.CreateLogSource("DSPAASR.Preloader"); try { if (Environment.OSVersion.Platform != PlatformID.Win32NT || !Environment.Is64BitProcess || !string.Equals(Path.GetFileName(Paths.ExecutablePath), "DSPGAME.exe", StringComparison.OrdinalIgnoreCase)) { throw new PlatformNotSupportedException("DSPAASR presentation requires the Windows x64 DSPGAME process."); } text = FindRuntimeDirectory(Paths.PluginPath); num = ReadBackend(Path.Combine(Paths.ConfigPath, "dspaa.mod.cfg")); if (num == 0) { PresentationStartup.Publish(PresentationStartupState.Inactive, text, num); val.LogInfo((object)"Frame generation is off at startup; this preloader did not initialize the presentation bridge."); } else { StartPresentation(text, Path.Combine(Paths.CachePath, "DSPAAMod")); PresentationStartup.Publish(PresentationStartupState.Started, text, num); val.LogInfo((object)"Early presentation entry installed; awaiting the game's presentation channel."); } } catch (Exception ex) { PresentationStartup.Publish(PresentationStartupState.Failed, text, num, ex.Message); val.LogError((object)("Presentation startup failed; no retry or native unload will be attempted: " + ex)); } } private static string FindRuntimeDirectory(string pluginPath) { string path = PresentationStartup.NormalizeDirectory(pluginPath); if (!Directory.Exists(path)) { throw new DirectoryNotFoundException("The active profile has no plugin directory."); } string text = null; string[] files = Directory.GetFiles(path, "DSPAAMod.dll", SearchOption.AllDirectories); foreach (string text2 in files) { if (string.Equals(Path.GetFileName(text2), "DSPAAMod.dll", StringComparison.OrdinalIgnoreCase)) { if (text != null) { throw new InvalidOperationException("Multiple enabled DSPAASR plugin installations were found in this profile."); } text = text2; } } if (text == null) { throw new FileNotFoundException("The DSPAASR plugin is disabled or absent from this profile."); } AssemblyName assemblyName = AssemblyName.GetAssemblyName(text); Version version = typeof(Patcher).Assembly.GetName().Version; if (assemblyName.Name != "DSPAAMod" || assemblyName.Version != version) { throw new InvalidOperationException("The DSPAASR plugin and preloader versions do not match."); } string text3 = PresentationStartup.NormalizeDirectory(Path.GetDirectoryName(text)); if (!File.Exists(Path.Combine(text3, "DSPAANative.dll"))) { throw new FileNotFoundException("DSPAANative.dll is disabled or missing beside the active DSPAASR plugin.", Path.Combine(text3, "DSPAANative.dll")); } return text3; } private static int ReadBackend(string path) { //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) string value = new ConfigFile(path, false) { SaveOnConfigSet = false }.Bind<string>("FrameGeneration", "Backend", "Off", (ConfigDescription)null).Value; if (value != value.Trim() || !Enum.TryParse<FrameGenerationBackend>(value, ignoreCase: true, out var result) || !Enum.IsDefined(typeof(FrameGenerationBackend), result)) { throw new InvalidDataException("Unknown saved FrameGeneration.Backend: " + value); } return (int)result; } [DllImport("kernel32.dll", CharSet = CharSet.Unicode, EntryPoint = "GetModuleHandleExW", ExactSpelling = true, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetModuleHandleEx(uint flags, string path, out IntPtr module); [DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] private static extern IntPtr GetProcAddress(IntPtr module, string name); private static T Export<T>(IntPtr module, string name) where T : Delegate { IntPtr procAddress = GetProcAddress(module, name); if (procAddress == IntPtr.Zero) { throw new EntryPointNotFoundException("Missing DSPAANative export: " + name); } return (T)Marshal.GetDelegateForFunctionPointer(procAddress, typeof(T)); } private static void StartPresentation(string runtime, string data) { string path = Path.Combine(runtime, "DSPAANative.dll"); IntPtr module = NativeModule.Load(path); if (!GetModuleHandleEx(1u, path, out var _)) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Cannot pin DSPAANative.dll."); } if (Export<GetAbi>(module, "DspAaGetAbiVersion")() != 2 || Export<GetAbi>(module, "DspAaGetPresentationAbiVersion")() != 3) { throw new InvalidOperationException("The installed native DSPAASR ABI does not match this preloader."); } if (Export<Bootstrap>(module, "DspAaBootstrapPresentation")(1u, runtime, data, 1u) != 1) { throw new InvalidOperationException("Native early presentation initialization was rejected."); } } } }