Decompiled source of BetterControls ReflectionFix v0.1.7

BepInEx/plugins/BetterControls_ReflectionFix/BetterControls.dll

Decompiled 3 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;

[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("BetterControls")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("BetterControls")]
[assembly: AssemblyTitle("BetterControls")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 DysonSphereProgram.Modding.BetterControls
{
	[BepInPlugin("com.zach.BetterControls", "BetterControls", "0.1.7.0")]
	[BepInProcess("DSPGAME.exe")]
	public class Plugin : BaseUnityPlugin
	{
		public const string GUID = "com.zach.BetterControls";

		public const string NAME = "BetterControls";

		public const string VERSION = "0.1.7.0";

		private Harmony _harmony;

		internal static ManualLogSource Log;

		private void Awake()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				_harmony = new Harmony("com.zach.BetterControls");
				_harmony.PatchAll(typeof(BetterControls));
				((BaseUnityPlugin)this).Logger.LogInfo((object)"BetterControls reflection fix loaded.");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"BetterControls failed to patch. DSP may have changed too much.");
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			Log = null;
		}
	}
	public static class KeyIds
	{
		public const int Jump = 8;

		public const int Takeoff = 9;

		public const int ClosePanel0 = 32;

		public const int Inventory = 34;

		public const int ClosePanel1 = 33;

		public const int GameMenu = 47;
	}
	internal static class BetterControls
	{
		private static bool[] conflicts;

		private static readonly Dictionary<int, int> indexes = new Dictionary<int, int>();

		private static readonly Dictionary<int, int> groups = new Dictionary<int, int>();

		private static readonly Dictionary<int, int> linked = new Dictionary<int, int>();

		private static FieldInfo Field(Type type, string name)
		{
			return AccessTools.Field(type, name);
		}

		private static T GetField<T>(object obj, string name)
		{
			if (obj == null)
			{
				return default(T);
			}
			FieldInfo fieldInfo = Field(obj.GetType(), name);
			if (fieldInfo == null)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Missing field " + obj.GetType().Name + "." + name));
				}
				return default(T);
			}
			return (T)fieldInfo.GetValue(obj);
		}

		private static bool SetField(object obj, string name, object value)
		{
			if (obj == null)
			{
				return false;
			}
			FieldInfo fieldInfo = Field(obj.GetType(), name);
			if (fieldInfo == null)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Missing field " + obj.GetType().Name + "." + name));
				}
				return false;
			}
			fieldInfo.SetValue(obj, value);
			return true;
		}

		private static object Call(object obj, string methodName, params object[] args)
		{
			if (obj == null)
			{
				return null;
			}
			MethodInfo methodInfo = AccessTools.Method(obj.GetType(), methodName, (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Missing method " + obj.GetType().Name + "." + methodName));
				}
				return null;
			}
			return methodInfo.Invoke(obj, args);
		}

		private static CombineKey GetKey(CombineKey builtin, CombineKey overrider)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (!((CombineKey)(ref overrider)).IsNull())
			{
				return overrider;
			}
			return builtin;
		}

		public static bool InventoryKeyDown()
		{
			try
			{
				if (VFInput.override_keys != null && VFInput.override_keys.Length > 34 && !((CombineKey)(ref VFInput.override_keys[34])).IsNull())
				{
					return ((CombineKey)(ref VFInput.override_keys[34])).GetKeyDown();
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Inventory override check failed; falling back to E. " + ex.Message));
				}
			}
			if (VFInput.noModifier)
			{
				return Input.GetKeyDown((KeyCode)101);
			}
			return false;
		}

		public static bool MenuKeyDown()
		{
			try
			{
				if (VFInput.override_keys != null && VFInput.override_keys.Length > 47 && !((CombineKey)(ref VFInput.override_keys[47])).IsNull())
				{
					return ((CombineKey)(ref VFInput.override_keys[47])).GetKeyDown();
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Menu override check failed; falling back to Escape. " + ex.Message));
				}
			}
			if (VFInput.noModifier)
			{
				return Input.GetKeyDown((KeyCode)27);
			}
			return false;
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(UIGame), "_OnUpdate")]
		private static IEnumerable<CodeInstruction> PatchInventoryKey(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(Input), "GetKeyDown", new Type[1] { typeof(KeyCode) }, (Type[])null);
			MethodInfo operandAndAdvance = AccessTools.Method(typeof(BetterControls), "InventoryKeyDown", (Type[])null, (Type[])null);
			CodeMatcher val = new CodeMatcher(instructions, generator).MatchForward(false, (CodeMatch[])(object)new CodeMatch[2]
			{
				new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction ci) => CodeInstructionExtensions.LoadsConstant(ci, (Enum)(object)(KeyCode)101)), (string)null),
				new CodeMatch((OpCode?)OpCodes.Call, (object)methodInfo, (string)null)
			});
			if (!val.IsValid)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"Could not find the hardcoded E inventory check in UIGame._OnUpdate. Skipping inventory patch.");
				}
				return instructions;
			}
			ManualLogSource log2 = Plugin.Log;
			if (log2 != null)
			{
				log2.LogInfo((object)"Patched UIGame._OnUpdate inventory key check.");
			}
			return val.RemoveInstruction().SetOperandAndAdvance((object)operandAndAdvance).InstructionEnumeration();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(VFInput), "OnUpdate")]
		private static void OnVFInputUpdate()
		{
			try
			{
				VFInput.escape = MenuKeyDown() && !VFInput.inputing;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Menu key patch failed this frame. " + ex.Message));
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(UIOptionWindow), "_OnOpen")]
		private static void OptionWindowOnOpen(UIOptionWindow __instance)
		{
			//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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			//IL_032b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: 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_0344: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: 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_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_037b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0384: Unknown result type (might be due to invalid IL or missing references)
			//IL_0393: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a2: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				BuiltinKey[] builtinKeys = DSPGame.key.builtinKeys;
				GameOption field = GetField<GameOption>(__instance, "tempOption");
				UIKeyEntry[] field2 = GetField<UIKeyEntry[]>(__instance, "keyEntries");
				if (builtinKeys == null || field2 == null)
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogWarning((object)"BetterControls could not access option window key data. UI features skipped.");
					}
					return;
				}
				CombineKey[] overrideKeys = field.overrideKeys;
				int num = builtinKeys.Length;
				CombineKey[] array = (CombineKey[])(object)new CombineKey[num];
				indexes.Clear();
				groups.Clear();
				linked.Clear();
				for (int i = 0; i < num; i++)
				{
					BuiltinKey val = builtinKeys[i];
					array[i] = GetKey(val.key, overrideKeys[val.id]);
					indexes[val.id] = i;
				}
				for (int j = 0; j < num - 1; j++)
				{
					CombineKey key = builtinKeys[j].key;
					if (groups.ContainsKey(j))
					{
						continue;
					}
					groups[j] = -1;
					for (int k = j + 1; k < num; k++)
					{
						CombineKey key2 = builtinKeys[k].key;
						if (((CombineKey)(ref key)).IsEquals(key2.keyCode, key2.modifier, key2.noneKey))
						{
							groups[j] = j;
							groups[k] = j;
						}
					}
				}
				if (!groups.ContainsKey(num - 1))
				{
					groups[num - 1] = -1;
				}
				conflicts = new bool[num];
				for (int l = 0; l < num - 1; l++)
				{
					CombineKey val2 = array[l];
					if (conflicts[l])
					{
						continue;
					}
					for (int m = l + 1; m < num; m++)
					{
						CombineKey val3 = array[m];
						if ((((BuiltinKey)(ref builtinKeys[l])).conflictKeyGroup & ((BuiltinKey)(ref builtinKeys[m])).conflictKeyGroup) > 0 && (groups[l] != groups[m] || groups[l] < 0) && ((CombineKey)(ref val2)).IsEquals(val3.keyCode, val3.modifier, val3.noneKey))
						{
							conflicts[l] = true;
							conflicts[m] = true;
						}
					}
				}
				int[] array2 = new int[6] { 9, 8, 32, 34, 33, 47 };
				for (int n = 0; n < array2.Length; n += 2)
				{
					if (!indexes.ContainsKey(array2[n]) || !indexes.ContainsKey(array2[n + 1]))
					{
						ManualLogSource log2 = Plugin.Log;
						if (log2 != null)
						{
							log2.LogWarning((object)("BetterControls could not find linked key ids " + array2[n] + " and " + array2[n + 1]));
						}
						continue;
					}
					int num2 = indexes[array2[n]];
					int num3 = indexes[array2[n + 1]];
					linked[num2] = num3;
					linked[num3] = num2;
					CombineKey val4 = array[num3];
					if (!((CombineKey)(ref array[num2])).IsEquals(val4.keyCode, val4.modifier, val4.noneKey) && num2 >= 0 && num2 < field2.Length && (Object)(object)field2[num2] != (Object)null)
					{
						Call(field2[num2], "OverrideKey", field, val4.keyCode, val4.modifier, val4.noneKey);
					}
				}
				ManualLogSource log3 = Plugin.Log;
				if (log3 != null)
				{
					log3.LogInfo((object)"BetterControls option-window reflection patch ran.");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log4 = Plugin.Log;
				if (log4 != null)
				{
					log4.LogWarning((object)("BetterControls option-window patch failed: " + ex));
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(BuiltinKey), "IsKeyVaild")]
		private static bool IsKeyValid(ref bool __result)
		{
			__result = true;
			return false;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(UIKeyEntry), "SetEntry")]
		private static void SetEntry(UIKeyEntry __instance, int _index, BuiltinKey _builtinKey, UIOptionWindow _optionWin)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (_builtinKey.id < 71 || 78 < _builtinKey.id)
				{
					((Component)__instance.setTheKeyInput).gameObject.SetActive(true);
					((Component)__instance.setTheKeyToggle).gameObject.SetActive(true);
					((Component)__instance.setDefaultUIButton).gameObject.SetActive(true);
					((Component)__instance.setNoneKeyUIButton).gameObject.SetActive(true);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("SetEntry patch failed: " + ex.Message));
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(UIKeyEntry), "Update")]
		private static void Update(UIKeyEntry __instance)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (conflicts != null && !((Object)(object)__instance == (Object)null))
				{
					BuiltinKey field = GetField<BuiltinKey>(__instance, "builtinKey");
					if (indexes.TryGetValue(field.id, out var value) && value >= 0 && value < conflicts.Length && conflicts[value])
					{
						((Graphic)__instance.keyText).color = Color.red;
					}
				}
			}
			catch
			{
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(UIKeyEntry), "OnSetNoneKeyClick")]
		private static bool OnSetNoneKeyClick(UIKeyEntry __instance)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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)
			try
			{
				UIOptionWindow field = GetField<UIOptionWindow>(__instance, "optionWin");
				if ((Object)(object)field == (Object)null)
				{
					return true;
				}
				GameOption val = (GameOption)Call(field, "GetTempOption");
				Call(__instance, "OverrideKey", val, 0, (byte)0, true);
				return false;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("OnSetNoneKeyClick patch failed: " + ex.Message));
				}
				return true;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(UIKeyEntry), "OverrideKey")]
		private static bool OverrideKey(UIKeyEntry __instance, GameOption tempOption, int keyCode, byte modifier, bool noneKey)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: 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_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_040e: Unknown result type (might be due to invalid IL or missing references)
			//IL_042d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				UIOptionWindow field = GetField<UIOptionWindow>(__instance, "optionWin");
				BuiltinKey field2 = GetField<BuiltinKey>(__instance, "builtinKey");
				if ((Object)(object)field == (Object)null)
				{
					return true;
				}
				if (__instance.inputUIButton._isPointerEnter && Input.GetKeyDown((KeyCode)323))
				{
					SetField(__instance, "nextNotOn", true);
				}
				int id = field2.id;
				if (!indexes.TryGetValue(id, out var value))
				{
					return true;
				}
				CombineKey key = field2.key;
				BuiltinKey[] builtinKeys = DSPGame.key.builtinKeys;
				CombineKey[] overrideKeys = tempOption.overrideKeys;
				int num = builtinKeys.Length;
				CombineKey[] array = (CombineKey[])(object)new CombineKey[num];
				for (int i = 0; i < num; i++)
				{
					array[i] = GetKey(builtinKeys[i].key, overrideKeys[builtinKeys[i].id]);
				}
				int keyCode2 = array[value].keyCode;
				byte modifier2 = array[value].modifier;
				bool noneKey2 = array[value].noneKey;
				int num2 = keyCode;
				byte b = modifier;
				bool flag = noneKey;
				if (keyCode == 0 && modifier == 0 && !noneKey)
				{
					num2 = key.keyCode;
					b = key.modifier;
					flag = key.noneKey;
				}
				if (keyCode2 == num2 && modifier2 == b && noneKey2 == flag)
				{
					__instance.inputUIButton.highlighted = false;
					return false;
				}
				if (((CombineKey)(ref key)).IsEquals(num2, b, flag))
				{
					((CombineKey)(ref overrideKeys[id])).Reset();
				}
				else
				{
					overrideKeys[id].keyCode = num2;
					overrideKeys[id].modifier = b;
					overrideKeys[id].noneKey = flag;
				}
				field.SetTempOption(tempOption);
				__instance.inputUIButton.highlighted = false;
				int num3 = -1;
				for (int j = 0; j < num; j++)
				{
					if (j != value && conflicts != null && conflicts[j] && (((BuiltinKey)(ref builtinKeys[j])).conflictKeyGroup & ((BuiltinKey)(ref builtinKeys[value])).conflictKeyGroup) > 0 && (groups[j] != groups[value] || groups[j] < 0) && ((CombineKey)(ref array[j])).IsEquals(keyCode2, modifier2, noneKey2))
					{
						if (num3 > -1 && (!linked.ContainsKey(num3) || linked[num3] != j))
						{
							num3 = -1;
							break;
						}
						num3 = j;
					}
				}
				if (num3 > -1 && conflicts != null)
				{
					conflicts[num3] = false;
					if (linked.ContainsKey(num3))
					{
						conflicts[linked[num3]] = false;
					}
				}
				if (conflicts != null)
				{
					conflicts[value] = false;
				}
				for (int k = 0; k < num; k++)
				{
					if (k == value || (((BuiltinKey)(ref builtinKeys[k])).conflictKeyGroup & ((BuiltinKey)(ref builtinKeys[value])).conflictKeyGroup) <= 0 || (groups[k] == groups[value] && groups[k] >= 0) || !((CombineKey)(ref array[k])).IsEquals(num2, b, flag))
					{
						continue;
					}
					if (conflicts != null)
					{
						conflicts[k] = true;
						conflicts[value] = true;
						if (linked.ContainsKey(k))
						{
							conflicts[linked[k]] = true;
						}
					}
					Call(__instance, "StartConflictText", k);
					__instance.setTheKeyToggle.isOn = false;
					((Component)__instance.waitingText).gameObject.SetActive(false);
					break;
				}
				if (linked.ContainsKey(value))
				{
					UIKeyEntry[] field3 = GetField<UIKeyEntry[]>(field, "keyEntries");
					int num4 = linked[value];
					if (field3 != null && num4 >= 0 && num4 < field3.Length && (Object)(object)field3[num4] != (Object)null && GetField<BuiltinKey>(field3[num4], "builtinKey").id != id)
					{
						Call(field3[num4], "OverrideKey", tempOption, num2, b, flag);
					}
				}
				return false;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("OverrideKey reflection patch failed; letting original run. " + ex.Message));
				}
				return true;
			}
		}
	}
}