Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ChangeDefaultDisplayMonitor v1.0.0
plugins/MonitorSwitcher/MonitorSwitcher.dll
Decompiled 8 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Logging; using Microsoft.CodeAnalysis; using On.RoR2; using On.RoR2.UI; using R2API; using RoR2; using RoR2.ConVar; using RoR2.UI; using TMPro; using UnityEngine; using UnityEngine.Events; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("MonitorSwitcher")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+73a3aebcfd7d8d588f675aa4448a9ae6d4d5b8c6")] [assembly: AssemblyProduct("MonitorSwitcher")] [assembly: AssemblyTitle("MonitorSwitcher")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace MonitorSwitcher { internal static class DisplayMonitorConVar { private sealed class MonitorConVarImpl : BaseConVar { public MonitorConVarImpl() : base("display_monitor", (ConVarFlags)4, (string)null, "Which display the game window is shown on. Valid values are DISPLAY1, DISPLAY2, ... as listed by the Display Monitor option in the settings menu.") { } public override string GetString() { return MonitorManager.GetCurrentDisplayDeviceName() ?? string.Empty; } public override void SetString(string newValue) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) Log.Info($"MonitorSwitcher: SetString('{newValue}') loadFinished={RoR2Application.loadFinished}"); string error2; if (string.IsNullOrEmpty(newValue)) { MonitorManager.TryMoveToMonitor(null, out var _); } else if (!RoR2Application.loadFinished) { MonitorSwitcherPlugin.PendingStartupMonitor = newValue; } else if (!MonitorManager.TryMoveToMonitor(newValue, out error2)) { throw new ConCommandException(error2 ?? ("Unknown display '" + newValue + "'.")); } } } public const string Name = "display_monitor"; public static readonly BaseConVar Instance = (BaseConVar)(object)new MonitorConVarImpl(); private static bool _registered; public static void Register(Console console) { if (_registered) { return; } if (console.FindConVar("display_monitor") != null) { _registered = true; return; } _registered = true; MethodInfo method = typeof(Console).GetMethod("RegisterConVarInternal", BindingFlags.Instance | BindingFlags.NonPublic); if (method == null) { Log.Error("MonitorSwitcher: could not find Console.RegisterConVarInternal"); return; } method.Invoke(console, new object[1] { Instance }); Log.Info("MonitorSwitcher: registered convar 'display_monitor'"); } } internal static class Localization { public const string SettingNameToken = "MONITOR_SWITCHER_SETTING_NAME"; public const string ChoiceTokenPrefix = "MONITOR_SWITCHER_DISPLAY_"; public static void Init() { LanguageAPI.Add("MONITOR_SWITCHER_SETTING_NAME", "Display Monitor"); } public static string ChoiceToken(int index) { return "MONITOR_SWITCHER_DISPLAY_" + index; } } internal static class Log { private static ManualLogSource _logSource; internal static void Init(ManualLogSource logSource) { _logSource = logSource; } internal static void Debug(object data) { _logSource.LogDebug(data); } internal static void Error(object data) { _logSource.LogError(data); } internal static void Fatal(object data) { _logSource.LogFatal(data); } internal static void Info(object data) { _logSource.LogInfo(data); } internal static void Message(object data) { _logSource.LogMessage(data); } internal static void Warning(object data) { _logSource.LogWarning(data); } } internal class MonitorDropdownControl : BaseSettingsControl { internal static string PendingSettingName; public MPDropdown dropdown; private DisplayInfo[] _displays = Array.Empty<DisplayInfo>(); private bool _syncing; protected void Awake() { if (string.IsNullOrEmpty(base.settingName)) { base.settingName = PendingSettingName; } ((BaseSettingsControl)this).Awake(); } protected override void OnUpdateControls() { RefreshOptions(); } internal void Init(MPDropdown targetDropdown) { dropdown = targetDropdown; if (Object.op_Implicit((Object)(object)dropdown)) { ((UnityEventBase)((TMP_Dropdown)dropdown).onValueChanged).RemoveAllListeners(); ((UnityEvent<int>)(object)((TMP_Dropdown)dropdown).onValueChanged).AddListener((UnityAction<int>)OnDropdownValueChanged); } RefreshOptions(); } private void RefreshOptions() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown if (!Object.op_Implicit((Object)(object)dropdown)) { return; } _displays = MonitorManager.Enumerate().ToArray(); string currentValue = ((BaseSettingsControl)this).GetCurrentValue(); int valueWithoutNotify = 0; List<OptionData> list = new List<OptionData>(_displays.Length); for (int i = 0; i < _displays.Length; i++) { list.Add(new OptionData(_displays[i].Label)); if (string.Equals(_displays[i].DeviceName, currentValue, StringComparison.OrdinalIgnoreCase)) { valueWithoutNotify = i; } } _syncing = true; ((TMP_Dropdown)dropdown).ClearOptions(); ((TMP_Dropdown)dropdown).AddOptions(list); ((TMP_Dropdown)dropdown).SetValueWithoutNotify(valueWithoutNotify); _syncing = false; } private void OnDropdownValueChanged(int value) { if (!_syncing && value >= 0 && value < _displays.Length) { ((BaseSettingsControl)this).SubmitSetting(_displays[value].DeviceName); } } } internal struct NativeRect { public int Left; public int Top; public int Right; public int Bottom; public int Width => Right - Left; public int Height => Bottom - Top; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] internal struct MonitorInfoEx { public int CbSize; public NativeRect RcMonitor; public NativeRect RcWork; public uint DwFlags; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string SzDevice; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] internal struct DisplayDevice { public int Cb; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string DeviceName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string DeviceString; public uint StateFlags; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string DeviceID; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string DeviceKey; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)] internal struct DevMode { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string DeviceName; public ushort SpecVersion; public ushort DriverVersion; public ushort Size; public ushort DriverExtra; public uint Fields; public int PositionX; public int PositionY; public uint DisplayOrientation; public uint DisplayFixedOutput; public short Color; public short Duplex; public short YResolution; public short TTOption; public short Collate; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string FormName; public ushort LogPixels; public uint BitsPerPel; public uint PelsWidth; public uint PelsHeight; public uint DisplayFlags; public uint DisplayFrequency; public uint ICMethod; public uint ICMIntent; public uint MediaType; public uint DitherType; public uint Reserved1; public uint Reserved2; public uint PanningWidth; public uint PanningHeight; } internal struct DisplayModeInfo { public int Width; public int Height; public int RefreshRate; } internal sealed class DisplayInfo { private const string DeviceNamePrefix = "DISPLAY"; public string DeviceName; public string FullName; public string FriendlyName; public NativeRect Bounds; public NativeRect WorkArea; public bool IsPrimary; public string Label => $"Display {DisplayNumber} ({Bounds.Width} x {Bounds.Height})"; private string DisplayNumber { get { if (DeviceName != null && DeviceName.StartsWith("DISPLAY", StringComparison.OrdinalIgnoreCase) && int.TryParse(DeviceName.Substring("DISPLAY".Length), out var result)) { return result.ToString(); } return "?"; } } } internal static class MonitorManager { private delegate bool MonitorEnumProc(IntPtr hMonitor, IntPtr hdcMonitor, ref NativeRect lprcMonitor, IntPtr dwData); private static class Native { [DllImport("user32.dll")] internal static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumProc lpfnEnum, IntPtr dwData); [DllImport("user32.dll", CharSet = CharSet.Unicode)] internal static extern bool GetMonitorInfo(IntPtr hMonitor, ref MonitorInfoEx lpmi); [DllImport("user32.dll", CharSet = CharSet.Unicode)] internal static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DisplayDevice lpDisplayDevice, uint dwFlags); [DllImport("user32.dll", CharSet = CharSet.Unicode)] internal static extern bool EnumDisplaySettings(string lpszDeviceName, uint iModeNum, ref DevMode lpDevMode); [DllImport("user32.dll")] internal static extern IntPtr GetActiveWindow(); [DllImport("user32.dll")] internal static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags); [DllImport("user32.dll")] internal static extern bool GetWindowRect(IntPtr hWnd, out NativeRect lpRect); [DllImport("user32.dll")] internal static extern bool MoveWindow(IntPtr hWnd, int x, int y, int nWidth, int nHeight, bool bRepaint); [DllImport("user32.dll")] internal static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags); } private const uint MONITORINFOF_PRIMARY = 1u; private const uint MONITOR_DEFAULTTONEAREST = 2u; private const uint SWP_NOACTIVATE = 16u; private const uint SWP_SHOWWINDOW = 64u; private static readonly Dictionary<string, string> FriendlyNameCache = new Dictionary<string, string>(); public static event Action DisplayChanged; public static List<DisplayInfo> Enumerate() { List<DisplayInfo> list = new List<DisplayInfo>(); MonitorEnumProc lpfnEnum = delegate(IntPtr hMonitor, IntPtr hdc, ref NativeRect rc, IntPtr data) { MonitorInfoEx lpmi = new MonitorInfoEx { CbSize = Marshal.SizeOf(typeof(MonitorInfoEx)) }; if (Native.GetMonitorInfo(hMonitor, ref lpmi)) { list.Add(new DisplayInfo { DeviceName = NormalizeDeviceName(lpmi.SzDevice), FullName = lpmi.SzDevice, Bounds = lpmi.RcMonitor, WorkArea = lpmi.RcWork, IsPrimary = ((lpmi.DwFlags & 1) != 0), FriendlyName = GetFriendlyName(lpmi.SzDevice) }); } return true; }; Native.EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, lpfnEnum, IntPtr.Zero); return list; } public static string GetCurrentDisplayDeviceName() { IntPtr gameWindowHandle = GetGameWindowHandle(); if (gameWindowHandle != IntPtr.Zero) { IntPtr intPtr = Native.MonitorFromWindow(gameWindowHandle, 2u); if (intPtr != IntPtr.Zero) { MonitorInfoEx lpmi = new MonitorInfoEx { CbSize = Marshal.SizeOf(typeof(MonitorInfoEx)) }; if (Native.GetMonitorInfo(intPtr, ref lpmi)) { return NormalizeDeviceName(lpmi.SzDevice); } } } return GetPrimary()?.DeviceName; } public static string GetCurrentDisplayFullName() { IntPtr gameWindowHandle = GetGameWindowHandle(); if (gameWindowHandle != IntPtr.Zero) { IntPtr intPtr = Native.MonitorFromWindow(gameWindowHandle, 2u); if (intPtr != IntPtr.Zero) { MonitorInfoEx lpmi = new MonitorInfoEx { CbSize = Marshal.SizeOf(typeof(MonitorInfoEx)) }; if (Native.GetMonitorInfo(intPtr, ref lpmi)) { return lpmi.SzDevice; } } } return GetPrimary()?.FullName ?? string.Empty; } public static List<DisplayModeInfo> GetModesForMonitor(string fullDeviceName) { List<DisplayModeInfo> list = new List<DisplayModeInfo>(); DevMode lpDevMode = NewDevMode(); for (uint num = 0u; Native.EnumDisplaySettings(fullDeviceName, num, ref lpDevMode); num++) { if (lpDevMode.PelsWidth != 0 && lpDevMode.PelsHeight != 0 && lpDevMode.DisplayFrequency != 0) { list.Add(new DisplayModeInfo { Width = (int)lpDevMode.PelsWidth, Height = (int)lpDevMode.PelsHeight, RefreshRate = (int)lpDevMode.DisplayFrequency }); } lpDevMode = NewDevMode(); } return list; } public static DisplayModeInfo? GetCurrentMode(string fullDeviceName) { DevMode lpDevMode = NewDevMode(); if (Native.EnumDisplaySettings(fullDeviceName, uint.MaxValue, ref lpDevMode) && lpDevMode.PelsWidth != 0 && lpDevMode.PelsHeight != 0) { return new DisplayModeInfo { Width = (int)lpDevMode.PelsWidth, Height = (int)lpDevMode.PelsHeight, RefreshRate = (int)lpDevMode.DisplayFrequency }; } return null; } private static DevMode NewDevMode() { return new DevMode { Size = (ushort)Marshal.SizeOf(typeof(DevMode)) }; } public static bool TryMoveToMonitor(string deviceName, out string error) { //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Invalid comparison between Unknown and I4 //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Invalid comparison between Unknown and I4 //IL_015c: Unknown result type (might be due to invalid IL or missing references) error = null; string normalized = NormalizeDeviceName(deviceName); List<DisplayInfo> list = Enumerate(); DisplayInfo displayInfo = ((!string.IsNullOrEmpty(normalized)) ? list.Find((DisplayInfo d) => string.Equals(d.DeviceName, normalized, StringComparison.OrdinalIgnoreCase)) : null); displayInfo = displayInfo ?? list.Find((DisplayInfo d) => d.IsPrimary); if (displayInfo == null) { error = "No displays are currently connected."; return false; } IntPtr gameWindowHandle = GetGameWindowHandle(); Log.Info($"MonitorSwitcher: move to '{normalized}' hwnd={gameWindowHandle} target={displayInfo.DeviceName} bounds={displayInfo.Bounds.Left},{displayInfo.Bounds.Top} {displayInfo.Bounds.Width}x{displayInfo.Bounds.Height} mode={Screen.fullScreenMode}"); if (gameWindowHandle == IntPtr.Zero) { error = "Could not find the game window."; return false; } FullScreenMode fullScreenMode = Screen.fullScreenMode; if ((int)fullScreenMode == 0) { Screen.fullScreenMode = (FullScreenMode)3; PlaceWindow(gameWindowHandle, displayInfo.Bounds); Screen.fullScreenMode = fullScreenMode; MonitorManager.DisplayChanged?.Invoke(); return true; } if ((int)fullScreenMode == 1) { PlaceWindow(gameWindowHandle, displayInfo.Bounds); Log.Info("MonitorSwitcher: post-move current display = '" + GetCurrentDisplayFullName() + "'"); MonitorManager.DisplayChanged?.Invoke(); return true; } if (Native.GetWindowRect(gameWindowHandle, out var lpRect)) { int num = Mathf.Clamp(lpRect.Width, 0, displayInfo.WorkArea.Width); int num2 = Mathf.Clamp(lpRect.Height, 0, displayInfo.WorkArea.Height); int x = displayInfo.WorkArea.Left + (displayInfo.WorkArea.Width - num) / 2; int y = displayInfo.WorkArea.Top + (displayInfo.WorkArea.Height - num2) / 2; Native.MoveWindow(gameWindowHandle, x, y, num, num2, bRepaint: true); } else { Native.MoveWindow(gameWindowHandle, displayInfo.WorkArea.Left, displayInfo.WorkArea.Top, displayInfo.WorkArea.Width, displayInfo.WorkArea.Height, bRepaint: true); } MonitorManager.DisplayChanged?.Invoke(); return true; } private static void PlaceWindow(IntPtr hwnd, NativeRect bounds) { int x = bounds.Left; int y = bounds.Top; int width = bounds.Width; int height = bounds.Height; bool flag = Native.SetWindowPos(hwnd, IntPtr.Zero, x, y, width, height, 80u); Log.Info($"MonitorSwitcher: SetWindowPos({x},{y},{width}x{height}) result={flag}"); RoR2Application.onNextUpdate += delegate { if (hwnd != IntPtr.Zero) { Native.SetWindowPos(hwnd, IntPtr.Zero, x, y, width, height, 80u); } }; } private static DisplayInfo GetPrimary() { return Enumerate().Find((DisplayInfo d) => d.IsPrimary); } private static string NormalizeDeviceName(string deviceName) { if (deviceName != null && deviceName.StartsWith("\\\\.\\", StringComparison.Ordinal)) { return deviceName.Substring(4); } return deviceName; } private static IntPtr GetGameWindowHandle() { try { IntPtr mainWindowHandle = Process.GetCurrentProcess().MainWindowHandle; if (mainWindowHandle != IntPtr.Zero) { return mainWindowHandle; } } catch { } return Native.GetActiveWindow(); } private static string GetFriendlyName(string deviceName) { if (FriendlyNameCache.TryGetValue(deviceName, out var value)) { return value; } DisplayDevice lpDisplayDevice = new DisplayDevice { Cb = Marshal.SizeOf(typeof(DisplayDevice)) }; if (Native.EnumDisplayDevices(deviceName, 1u, ref lpDisplayDevice, 0u) && !string.IsNullOrEmpty(lpDisplayDevice.DeviceString)) { FriendlyNameCache[deviceName] = lpDisplayDevice.DeviceString; return lpDisplayDevice.DeviceString; } uint num = 0u; while (true) { DisplayDevice lpDisplayDevice2 = new DisplayDevice { Cb = Marshal.SizeOf(typeof(DisplayDevice)) }; if (!Native.EnumDisplayDevices(null, num, ref lpDisplayDevice2, 0u)) { break; } if (string.Equals(lpDisplayDevice2.DeviceName, deviceName, StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(lpDisplayDevice2.DeviceString)) { FriendlyNameCache[deviceName] = lpDisplayDevice2.DeviceString; return lpDisplayDevice2.DeviceString; } num++; } FriendlyNameCache[deviceName] = deviceName; return deviceName; } } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("Ovalsquare.MonitorSwitcher", "MonitorSwitcher", "1.0.0")] public class MonitorSwitcherPlugin : BaseUnityPlugin { [CompilerGenerated] private static class <>O { public static hook_Start <0>__OnSettingsPanelStart; public static hook_OnEnable <1>__OnSettingsPanelEnable; public static Action <2>__OnDisplayChanged; } public const string PluginAuthor = "Ovalsquare"; public const string PluginName = "MonitorSwitcher"; public const string PluginGUID = "Ovalsquare.MonitorSwitcher"; public const string PluginVersion = "1.0.0"; internal static string PendingStartupMonitor; private void Awake() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown Log.Init(((BaseUnityPlugin)this).Logger); Localization.Init(); Console.CacheConVars += new hook_CacheConVars(OnCacheConVars); Console.LoadStartupConfigs += new hook_LoadStartupConfigs(OnLoadStartupConfigs); object obj = <>O.<0>__OnSettingsPanelStart; if (obj == null) { hook_Start val = SettingsRowInjector.OnSettingsPanelStart; <>O.<0>__OnSettingsPanelStart = val; obj = (object)val; } SettingsPanelController.Start += (hook_Start)obj; object obj2 = <>O.<1>__OnSettingsPanelEnable; if (obj2 == null) { hook_OnEnable val2 = SettingsRowInjector.OnSettingsPanelEnable; <>O.<1>__OnSettingsPanelEnable = val2; obj2 = (object)val2; } SettingsPanelController.OnEnable += (hook_OnEnable)obj2; RoR2Application.OnMainMenuControllerInitialized += new hook_OnMainMenuControllerInitialized(OnMainMenuControllerInitialized); MonitorManager.DisplayChanged += OnDisplayChanged; ResolutionListFix.Hook(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Ovalsquare.MonitorSwitcher AWAKE_COMPLETE"); } private static void OnDisplayChanged() { ResolutionListFix.RefreshActiveControls(); } private void OnCacheConVars(orig_CacheConVars orig, Console self) { orig.Invoke(self); DisplayMonitorConVar.Register(self); } private void OnLoadStartupConfigs(orig_LoadStartupConfigs orig, Console self) { DisplayMonitorConVar.Register(self); orig.Invoke(self); } private void OnMainMenuControllerInitialized(orig_OnMainMenuControllerInitialized orig, RoR2Application self) { orig.Invoke(self); ApplyPendingStartupMonitor(); } private static void ApplyPendingStartupMonitor() { string pendingStartupMonitor = PendingStartupMonitor; PendingStartupMonitor = null; if (!string.IsNullOrEmpty(pendingStartupMonitor)) { if (MonitorManager.TryMoveToMonitor(pendingStartupMonitor, out var error)) { Log.Info("MonitorSwitcher: applied saved monitor " + pendingStartupMonitor + "."); } else { Log.Warning("MonitorSwitcher: could not apply saved monitor " + pendingStartupMonitor + ": " + error); } } } private void OnDestroy() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown Console.CacheConVars -= new hook_CacheConVars(OnCacheConVars); Console.LoadStartupConfigs -= new hook_LoadStartupConfigs(OnLoadStartupConfigs); object obj = <>O.<0>__OnSettingsPanelStart; if (obj == null) { hook_Start val = SettingsRowInjector.OnSettingsPanelStart; <>O.<0>__OnSettingsPanelStart = val; obj = (object)val; } SettingsPanelController.Start -= (hook_Start)obj; object obj2 = <>O.<1>__OnSettingsPanelEnable; if (obj2 == null) { hook_OnEnable val2 = SettingsRowInjector.OnSettingsPanelEnable; <>O.<1>__OnSettingsPanelEnable = val2; obj2 = (object)val2; } SettingsPanelController.OnEnable -= (hook_OnEnable)obj2; RoR2Application.OnMainMenuControllerInitialized -= new hook_OnMainMenuControllerInitialized(OnMainMenuControllerInitialized); MonitorManager.DisplayChanged -= OnDisplayChanged; ResolutionListFix.Unhook(); Log.Info("Ovalsquare.MonitorSwitcher unloaded"); } } internal static class ResolutionListFix { [CompilerGenerated] private static class <>O { public static hook_GenerateResolutionOptions <0>__OnGenerateResolutionOptions; } private static readonly FieldInfo ResolutionOptionsField = typeof(ResolutionControl).GetField("resolutionOptions", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly Type ResolutionOptionType = typeof(ResolutionControl).GetNestedType("ResolutionOption", BindingFlags.NonPublic); private static readonly ConstructorInfo ResolutionOptionCtor = ResolutionOptionType?.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); private static readonly FieldInfo SizeField = ResolutionOptionType?.GetField("size", BindingFlags.Instance | BindingFlags.Public); private static readonly FieldInfo RefreshRatesField = ResolutionOptionType?.GetField("supportedRefreshRates", BindingFlags.Instance | BindingFlags.Public); public static void Hook() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown object obj = <>O.<0>__OnGenerateResolutionOptions; if (obj == null) { hook_GenerateResolutionOptions val = OnGenerateResolutionOptions; <>O.<0>__OnGenerateResolutionOptions = val; obj = (object)val; } ResolutionControl.GenerateResolutionOptions += (hook_GenerateResolutionOptions)obj; } public static void Unhook() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown object obj = <>O.<0>__OnGenerateResolutionOptions; if (obj == null) { hook_GenerateResolutionOptions val = OnGenerateResolutionOptions; <>O.<0>__OnGenerateResolutionOptions = val; obj = (object)val; } ResolutionControl.GenerateResolutionOptions -= (hook_GenerateResolutionOptions)obj; } public static void RefreshActiveControls() { ResolutionControl[] array = Object.FindObjectsOfType<ResolutionControl>(); foreach (ResolutionControl self in array) { try { RebuildFromCurrentMonitor(self); } catch (Exception data) { Log.Error(data); } } } private static void OnGenerateResolutionOptions(orig_GenerateResolutionOptions orig, ResolutionControl self) { orig.Invoke(self); try { RebuildFromCurrentMonitor(self); } catch (Exception data) { Log.Error(data); } } private static void RebuildFromCurrentMonitor(ResolutionControl self) { //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Expected O, but got Unknown //IL_02ad: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02ce: Unknown result type (might be due to invalid IL or missing references) if (ResolutionOptionsField == null || ResolutionOptionType == null || ResolutionOptionCtor == null || SizeField == null || RefreshRatesField == null || !Object.op_Implicit((Object)(object)self.resolutionDropdown)) { return; } string currentDisplayFullName = MonitorManager.GetCurrentDisplayFullName(); if (string.IsNullOrEmpty(currentDisplayFullName)) { return; } List<DisplayModeInfo> modesForMonitor = MonitorManager.GetModesForMonitor(currentDisplayFullName); if (modesForMonitor.Count == 0) { return; } List<DisplayModeInfo> list = (from m in modesForMonitor orderby (long)m.Width * (long)m.Height descending, m.RefreshRate descending select m).ToList(); List<Vector2Int> list2 = new List<Vector2Int>(); Dictionary<Vector2Int, List<int>> dictionary = new Dictionary<Vector2Int, List<int>>(); Vector2Int val = default(Vector2Int); foreach (DisplayModeInfo item in list) { ((Vector2Int)(ref val))..ctor(item.Width, item.Height); if (!dictionary.TryGetValue(val, out var value)) { value = (dictionary[val] = new List<int>()); list2.Add(val); } if (!value.Contains(item.RefreshRate)) { value.Add(item.RefreshRate); } } Array array = Array.CreateInstance(ResolutionOptionType, list2.Count); OptionData[] array2 = (OptionData[])(object)new OptionData[list2.Count]; for (int num = 0; num < list2.Count; num++) { object obj = ResolutionOptionCtor.Invoke(null); SizeField.SetValue(obj, list2[num]); List<int> list4 = (List<int>)RefreshRatesField.GetValue(obj); list4.AddRange(dictionary[list2[num]]); array.SetValue(obj, num); int num2 = num; Vector2Int val2 = list2[num]; object arg = ((Vector2Int)(ref val2)).x; val2 = list2[num]; array2[num2] = new OptionData($"{arg}x{((Vector2Int)(ref val2)).y}"); } ResolutionOptionsField.SetValue(self, array); ((TMP_Dropdown)self.resolutionDropdown).ClearOptions(); ((TMP_Dropdown)self.resolutionDropdown).AddOptions(array2.ToList()); Resolution currentResolution = Screen.currentResolution; int width = ((Resolution)(ref currentResolution)).width; currentResolution = Screen.currentResolution; Vector2Int current2 = new Vector2Int(width, ((Resolution)(ref currentResolution)).height); int num3 = list2.FindIndex((Vector2Int s) => s == current2); if (num3 < 0) { DisplayModeInfo? currentMode = MonitorManager.GetCurrentMode(currentDisplayFullName); if (currentMode.HasValue) { num3 = list2.FindIndex((Vector2Int s) => s == new Vector2Int(currentMode.Value.Width, currentMode.Value.Height)); } } if (num3 < 0) { num3 = 0; } ((TMP_Dropdown)self.resolutionDropdown).value = num3; DisplayModeInfo displayModeInfo = list[0]; Log.Info($"MonitorSwitcher: resolution list rebuilt for {currentDisplayFullName} ({modesForMonitor.Count} modes, largest {displayModeInfo.Width}x{displayModeInfo.Height}@{displayModeInfo.RefreshRate})"); } } internal static class SettingsRowInjector { private static readonly FieldInfo SettingsControllersField = typeof(SettingsPanelController).GetField("settingsControllers", BindingFlags.Instance | BindingFlags.NonPublic); public static void OnSettingsPanelStart(orig_Start orig, SettingsPanelController self) { InjectRow(self); orig.Invoke(self); RefreshSettingsControllersSnapshot(self); } public static void OnSettingsPanelEnable(orig_OnEnable orig, SettingsPanelController self) { orig.Invoke(self); Log.Info("MonitorSwitcher: settings panel enabled: " + ((Object)((Component)self).gameObject).name); } private static void InjectRow(SettingsPanelController panel) { //IL_016e: Unknown result type (might be due to invalid IL or missing references) try { ResolutionControl componentInChildren = ((Component)panel).GetComponentInChildren<ResolutionControl>(true); if (!Object.op_Implicit((Object)(object)componentInChildren)) { return; } Transform parent = ((Component)componentInChildren).transform.parent; Transform val = (((Object)(object)parent != (Object)null) ? parent.parent : null); if ((Object)(object)val == (Object)null) { Log.Warning("MonitorSwitcher: could not find the Video settings row list; skipping row injection."); return; } GameObject val2 = Object.Instantiate<GameObject>(((Component)parent).gameObject, val); ((Object)val2).name = "Option, Display Monitor"; val2.transform.SetAsLastSibling(); ResolutionControl componentInChildren2 = val2.GetComponentInChildren<ResolutionControl>(true); if (Object.op_Implicit((Object)(object)componentInChildren2)) { Object.Destroy((Object)(object)componentInChildren2); } LanguageTextMeshController componentInChildren3 = val2.GetComponentInChildren<LanguageTextMeshController>(true); if (Object.op_Implicit((Object)(object)componentInChildren3)) { componentInChildren3.token = "MONITOR_SWITCHER_SETTING_NAME"; } MPDropdown val3 = null; MPDropdown[] componentsInChildren = val2.GetComponentsInChildren<MPDropdown>(true); for (int i = 0; i < componentsInChildren.Length; i++) { if (i == 0) { val3 = componentsInChildren[i]; continue; } ((Component)componentsInChildren[i]).gameObject.SetActive(false); Object.Destroy((Object)(object)componentsInChildren[i]); } if ((Object)(object)val3 == (Object)null) { Log.Warning("MonitorSwitcher: no MPDropdown found in cloned row; skipping row injection."); Object.Destroy((Object)(object)val2); return; } MonitorDropdownControl.PendingSettingName = "display_monitor"; MonitorDropdownControl monitorDropdownControl = val2.AddComponent<MonitorDropdownControl>(); ((BaseSettingsControl)monitorDropdownControl).nameToken = "MONITOR_SWITCHER_SETTING_NAME"; ((BaseSettingsControl)monitorDropdownControl).nameLabel = componentInChildren3; ((BaseSettingsControl)monitorDropdownControl).settingSource = (SettingSource)0; ((BaseSettingsControl)monitorDropdownControl).useConfirmationDialog = true; monitorDropdownControl.Init(val3); Log.Info($"MonitorSwitcher: injected Display Monitor dropdown as last row of '{((Object)val).name}' with {MonitorManager.Enumerate().Count} display(s)."); } catch (Exception data) { Log.Error(data); } } private static void RefreshSettingsControllersSnapshot(SettingsPanelController panel) { try { if (SettingsControllersField != null) { BaseSettingsControl[] componentsInChildren = ((Component)panel).GetComponentsInChildren<BaseSettingsControl>(true); SettingsControllersField.SetValue(panel, componentsInChildren); } } catch (Exception data) { Log.Error(data); } } } }