using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Logging; using HarmonyLib; using KeybindLib.Classes; using TMPro; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("KeybindLib")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("KeybindLib")] [assembly: AssemblyCopyright("Copyright © 2024")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("a435cffd-1c69-437a-9daa-52fd5a9b02e6")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace KeybindLib { [BepInPlugin("bulletbot.keybindlib", "KeybindLib", "1.0.6")] internal class Plugin : BaseUnityPlugin { private const string modGUID = "bulletbot.keybindlib"; private const string modName = "KeybindLib"; private const string modVer = "1.0.6"; internal static Plugin instance; internal ManualLogSource logger; private readonly Harmony harmony = new Harmony("bulletbot.keybindlib"); private bool hasPatched; internal List registeredKeybinds; private void Awake() { instance = this; logger = Logger.CreateLogSource("KeybindLib"); registeredKeybinds = new List(); logger.LogMessage((object)"KeybindLib has started."); SceneManager.activeSceneChanged += delegate { if (!hasPatched) { harmony.PatchAll(); logger.LogMessage((object)($"{registeredKeybinds.Count((Keybind x) => !x.registeredAsToggle)} keybind(s) and " + $"{registeredKeybinds.Count((Keybind x) => x.registeredAsToggle)} toggle(s) has been initialized.")); hasPatched = true; } }; } } } namespace KeybindLib.Patches { [HarmonyPatch(typeof(MenuManager))] internal class MenuManagerPatch { private static readonly float _headerOffset = 30f; private static readonly float _categoryOffset = 26.5f; private static readonly float _categoryHeaderOffset = 6.5f; private static readonly float _buttonOffset = 42f; private static readonly float _buttonHeaderOffset = 15f; private static readonly float _buttonCategoryOffset = 11.5f; private static readonly float _buttonBoolSettingOffset = 27.25f; private static readonly float _buttonBoolSettingHeaderOffset = 12.5f; private static readonly float _buttonBoolSettingCategoryOffset = 9f; private static readonly float _boolSettingOffset = 32.25f; private static readonly float _boolSettingHeaderOffset = 15.25f; private static readonly float _boolSettingCategoryOffset = 20.25f; [HarmonyPatch("Start")] [HarmonyPrefix] private static void Start(ref List ___menuPages) { //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_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Expected O, but got Unknown //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_0366: Unknown result type (might be due to invalid IL or missing references) //IL_036f: Unknown result type (might be due to invalid IL or missing references) //IL_0376: Unknown result type (might be due to invalid IL or missing references) //IL_067d: Unknown result type (might be due to invalid IL or missing references) //IL_0682: Unknown result type (might be due to invalid IL or missing references) //IL_06cc: Unknown result type (might be due to invalid IL or missing references) //IL_06d5: Unknown result type (might be due to invalid IL or missing references) //IL_06dc: Unknown result type (might be due to invalid IL or missing references) //IL_046f: Unknown result type (might be due to invalid IL or missing references) //IL_0474: Unknown result type (might be due to invalid IL or missing references) //IL_048f: Unknown result type (might be due to invalid IL or missing references) //IL_0498: Unknown result type (might be due to invalid IL or missing references) //IL_049f: 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_052b: Unknown result type (might be due to invalid IL or missing references) //IL_0575: 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_0585: Unknown result type (might be due to invalid IL or missing references) if (Plugin.instance.registeredKeybinds.Count <= 0) { return; } MenuPages val = ((IEnumerable)___menuPages).FirstOrDefault((Func)((MenuPages x) => (int)x.menuPageIndex == 6)); Transform child = val.menuPage.transform.GetChild(3); MenuScrollBox component = ((Component)child).GetComponent(); Transform child2 = child.GetChild(1).GetChild(0); GameObject gameObject = ((Component)child2.Find("Header Player Expressions")).gameObject; Vector3 localPosition = gameObject.transform.localPosition; GameObject gameObject2 = ((Component)child2.Find("Header Grabbing")).gameObject; Vector3 localPosition2 = gameObject2.transform.localPosition; GameObject gameObject3 = ((Component)child2.Find("Big Button Map")).gameObject; Vector3 localPosition3 = gameObject3.transform.localPosition; GameObject gameObject4 = ((Component)child2.Find("Bool Setting - ")).gameObject; Vector3 localPosition4 = gameObject4.transform.localPosition; GameObject val2 = null; foreach (Transform item in child2) { Transform val3 = item; if (((Object)val3).name == "Bool Setting - ") { val2 = ((Component)val3).gameObject; } } Vector3 localPosition5 = val2.transform.localPosition; List currentHeaders = new List(); List<(string, string)> currentCategories = new List<(string, string)>(); Plugin.instance.registeredKeybinds.Sort(delegate(Keybind a, Keybind b) { int num2 = a.modOrderIndex.CompareTo(b.modOrderIndex); if (num2 != 0) { return num2; } bool flag3 = !string.IsNullOrEmpty(a.category); bool flag4 = !string.IsNullOrEmpty(b.category); if (flag3 != flag4) { return flag3.CompareTo(flag4); } bool registeredAsToggle = a.registeredAsToggle; bool registeredAsToggle2 = b.registeredAsToggle; return (registeredAsToggle != registeredAsToggle2) ? registeredAsToggle2.CompareTo(registeredAsToggle) : a.registerIndex.CompareTo(b.registerIndex); }); float num = child2.GetChild(child2.childCount - 1).localPosition.y; List registeredKeybinds = Plugin.instance.registeredKeybinds; for (int i = 0; i < registeredKeybinds.Count; i++) { Keybind keybind2 = registeredKeybinds[i]; bool flag = RequiresHeader(keybind2); if (flag) { num -= _headerOffset; GameObject val4 = Object.Instantiate(gameObject); LocalizationChangedEvent[] componentsInChildren = val4.GetComponentsInChildren(); foreach (LocalizationChangedEvent val5 in componentsInChildren) { Object.Destroy((Object)(object)val5); } ((Object)val4).name = "Header " + keybind2.modGuid; ((TMP_Text)val4.GetComponentInChildren()).text = keybind2.modGuid; val4.transform.SetParent(child2); val4.transform.localPosition = new Vector3(localPosition.x, num, localPosition.z); currentHeaders.Add(keybind2.modGuid); } bool flag2 = RequiresCategory(keybind2); if (flag2) { num -= _categoryOffset; if (flag) { num -= _categoryHeaderOffset; } GameObject val6 = Object.Instantiate(gameObject2); LocalizationChangedEvent[] componentsInChildren2 = val6.GetComponentsInChildren(); foreach (LocalizationChangedEvent val7 in componentsInChildren2) { Object.Destroy((Object)(object)val7); } ((Object)val6).name = "Category " + keybind2.modGuid + " " + keybind2.category; ((TMP_Text)val6.GetComponentInChildren()).text = keybind2.category; val6.transform.SetParent(child2); val6.transform.localPosition = new Vector3(localPosition2.x, num, localPosition2.z); currentCategories.Add((keybind2.modGuid, keybind2.category)); flag2 = true; } if (keybind2.inputAction != null) { num -= _buttonOffset; if (flag) { num -= _buttonHeaderOffset; } if (flag2) { num -= _buttonCategoryOffset; } GameObject val8 = Object.Instantiate(gameObject3); LocalizationChangedEvent[] componentsInChildren3 = val8.GetComponentsInChildren(); foreach (LocalizationChangedEvent val9 in componentsInChildren3) { Object.Destroy((Object)(object)val9); } string name = keybind2.inputAction.name; ((Object)val8).name = "Big Button " + keybind2.modGuid + " " + name; val8.GetComponent().buttonTitle = name; ((TMP_Text)val8.GetComponentInChildren()).text = name; val8.GetComponent().inputKey = keybind2.inputKey; val8.transform.SetParent(child2); val8.transform.localPosition = new Vector3(localPosition3.x, num, localPosition3.z); if (keybind2.toggle != null) { num -= _buttonBoolSettingOffset; GameObject val10 = Object.Instantiate(gameObject4); LocalizationChangedEvent[] componentsInChildren4 = val10.GetComponentsInChildren(); foreach (LocalizationChangedEvent val11 in componentsInChildren4) { Object.Destroy((Object)(object)val11); } ((Object)val10).name = "Button Toggle " + keybind2.modGuid + " " + name; val10.GetComponent().inputKey = keybind2.inputKey; MenuTwoOptions component2 = val10.GetComponent(); component2.option2Text = keybind2.toggle.falseText; component2.option1Text = keybind2.toggle.trueText; val10.transform.SetParent(child2); val10.transform.localPosition = new Vector3(localPosition4.x, num, localPosition4.z); } if (i + 1 < registeredKeybinds.Count) { Keybind keybind3 = registeredKeybinds[i + 1]; if (RequiresHeader(keybind3)) { num -= _buttonBoolSettingHeaderOffset; } if (RequiresCategory(keybind3)) { num -= _buttonBoolSettingCategoryOffset; } } } else { num -= _boolSettingOffset; if (flag) { num -= _boolSettingHeaderOffset; } if (flag2) { num -= _boolSettingCategoryOffset; } GameObject val12 = Object.Instantiate(val2); LocalizationChangedEvent[] componentsInChildren5 = val12.GetComponentsInChildren(); foreach (LocalizationChangedEvent val13 in componentsInChildren5) { Object.Destroy((Object)(object)val13); } ((Object)val12).name = "Toggle " + keybind2.modGuid + " " + keybind2.category; val12.GetComponent().inputKey = keybind2.inputKey; MenuTwoOptions component3 = val12.GetComponent(); component3.option2Text = keybind2.toggle.falseText; component3.option1Text = keybind2.toggle.trueText; val12.transform.SetParent(child2); val12.transform.localPosition = new Vector3(localPosition5.x, num, localPosition5.z); } component.heightPadding += 4f; } bool RequiresCategory(Keybind keybind) { return !string.IsNullOrEmpty(keybind.category) && !currentCategories.Contains((keybind.modGuid, keybind.category)); } bool RequiresHeader(Keybind keybind) { return !currentHeaders.Contains(keybind.modGuid); } } } [HarmonyPatch(typeof(InputManager))] internal class InputManagerPatch { [HarmonyPatch("Start")] [HarmonyTranspiler] private static IEnumerable StartTranspiler(IEnumerable instructions) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Expected O, but got Unknown //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null); val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Ldstr, (object)"DefaultKeyBindings.es3", (string)null) }); val.Insert((CodeInstruction[])(object)new CodeInstruction[3] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldflda, (object)AccessTools.Field(typeof(InputManager), "tagDictionary")), new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(InputManagerPatch), "Start", (Type[])null, (Type[])null)) }); return val.InstructionEnumeration(); } private static void Start(ref Dictionary tagDictionary) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) foreach (Keybind registeredKeybind in Plugin.instance.registeredKeybinds) { if (!string.IsNullOrEmpty(registeredKeybind.tag)) { tagDictionary.Add(registeredKeybind.tag, registeredKeybind.inputKey); } } } [HarmonyPatch("InitializeInputs")] [HarmonyTranspiler] private static IEnumerable InitializeInputsTranspiler(IEnumerable instructions) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Expected O, but got Unknown //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Expected O, but got Unknown //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Expected O, but got Unknown //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null); int num = -1; while (true) { val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.Method(typeof(Dictionary), "set_Item", (Type[])null, (Type[])null), (string)null) }); if (!val.IsValid) { break; } num = val.Pos; val.Advance(1); } if (num != -1) { val.Start(); val.Advance(num + 1); val.Insert((CodeInstruction[])(object)new CodeInstruction[5] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldflda, (object)AccessTools.Field(typeof(InputManager), "inputActions")), new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldflda, (object)AccessTools.Field(typeof(InputManager), "inputToggle")), new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(InputManagerPatch), "InitializeInputs", (Type[])null, (Type[])null)) }); } return val.InstructionEnumeration(); } private static void InitializeInputs(ref Dictionary inputActions, ref Dictionary inputToggle) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) foreach (Keybind registeredKeybind in Plugin.instance.registeredKeybinds) { if (registeredKeybind.inputAction != null) { inputActions[registeredKeybind.inputKey] = registeredKeybind.inputAction; } if (registeredKeybind.toggle != null) { inputToggle.Add(registeredKeybind.inputKey, registeredKeybind.toggle.defaultValue); } } } } } namespace KeybindLib.Classes { public class Keybind { public class Toggle { public bool defaultValue; public string falseText = "hold"; public string trueText = "toggle"; } internal bool registeredAsToggle; internal int modOrderIndex; internal int registerIndex; public string modGuid { get; internal set; } public string category { get; internal set; } public string tag { get; internal set; } public Toggle toggle { get; internal set; } public InputKey inputKey { get; internal set; } public InputAction inputAction { get; internal set; } } public static class Keybinds { internal static readonly Dictionary _modOrder = new Dictionary(); internal static int _nextRegisterIndex = 0; internal static int _nextModOrderIndex = 0; private static BepInPlugin GetPluginByCallingAssembly(Assembly assembly) { return SafeTypes().Select((Func)delegate(Type t) { try { return ((MemberInfo)t).GetCustomAttribute(); } catch { return null; } }).FirstOrDefault((Func)((BepInPlugin attr) => attr != null)); IEnumerable SafeTypes() { try { return assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { return ex.Types.Where((Type t) => t != null); } catch { try { return assembly.GetExportedTypes(); } catch { return Enumerable.Empty(); } } } } public static Keybind Bind(string name, string binding) { return Register(GetPluginByCallingAssembly(Assembly.GetCallingAssembly()), null, name, binding); } public static Keybind Bind(string category, string name, string binding) { return Register(GetPluginByCallingAssembly(Assembly.GetCallingAssembly()), category, name, binding); } public static Keybind Toggle(Keybind.Toggle toggle) { return Register(GetPluginByCallingAssembly(Assembly.GetCallingAssembly()), null, null, null, toggle, isToggle: true); } public static Keybind Toggle(string category, Keybind.Toggle toggle) { return Register(GetPluginByCallingAssembly(Assembly.GetCallingAssembly()), category, null, null, toggle, isToggle: true); } public static Keybind Toggle(Keybind keybind, Keybind.Toggle toggle) { BepInPlugin val = (from x in Assembly.GetCallingAssembly().GetTypes() select ((MemberInfo)x).GetCustomAttribute()).FirstOrDefault(); if (val == null) { Plugin.instance.logger.LogMessage((object)"Failed to apply toggle because the calling mod could not be identified."); return null; } if (keybind == null) { Plugin.instance.logger.LogMessage((object)"Failed to apply toggle because the provided keybind was null."); return null; } bool registeredAsToggle = keybind.registeredAsToggle; string modGuid = keybind.modGuid; string category = keybind.category; string text = ((keybind.inputAction != null) ? keybind.inputAction.name : null); bool flag = keybind.toggle != null; if (modGuid == val.GUID && Plugin.instance.registeredKeybinds.Contains(keybind)) { Plugin.instance.logger.LogMessage((object)(((toggle == null) ? "Removed" : (flag ? "Replaced" : "Attached")) + " toggle" + ((!registeredAsToggle) ? (((toggle == null) ? " from" : " to") + " keybind" + ((!string.IsNullOrEmpty(text)) ? (" \"" + text + "\"") : "")) : "") + ((!string.IsNullOrEmpty(category)) ? (" in category \"" + category + "\"") : "") + " for mod \"" + modGuid + "\".")); keybind.toggle = toggle; return keybind; } Plugin.instance.logger.LogMessage((object)("Failed to " + ((toggle == null) ? "remove" : (flag ? "replace" : "attach")) + " toggle" + ((!registeredAsToggle) ? (((toggle == null) ? " from" : " to") + " keybind" + ((!string.IsNullOrEmpty(text)) ? (" \"" + text + "\"") : "")) : "") + ((!string.IsNullOrEmpty(keybind.category)) ? (" in category \"" + category + "\"") : "") + " for mod \"" + modGuid + "\".")); return null; } internal static Keybind Register(BepInPlugin plugin, string category = null, string name = null, string binding = null, Keybind.Toggle toggle = null, bool isToggle = false) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Expected I4, but got Unknown //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Expected O, but got Unknown if (plugin == null) { Plugin.instance.logger.LogMessage((object)("Failed to register a " + (isToggle ? "toggle" : "keybind") + " because the calling mod could not be identified.")); return null; } string modGuid = plugin.GUID; InputKey inputKey = ComputeInputKey(); bool flag = !isToggle && (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(binding) || Plugin.instance.registeredKeybinds.Any((Keybind x) => x.modGuid == modGuid && SameCategory(x) && !x.registeredAsToggle && x.inputKey == inputKey)); bool flag2 = isToggle && (toggle == null || Plugin.instance.registeredKeybinds.Any((Keybind x) => x.modGuid == modGuid && SameCategory(x) && x.registeredAsToggle && x.inputKey == inputKey)); if (flag || flag2) { Plugin.instance.logger.LogMessage((object)("Failed to register " + (isToggle ? "toggle" : ("keybind" + ((!string.IsNullOrEmpty(name)) ? (" \"" + name + "\"") : ""))) + ((!string.IsNullOrEmpty(category)) ? (" in category \"" + category + "\"") : "") + " for mod \"" + modGuid + "\".")); return null; } Keybind keybind = new Keybind { modGuid = modGuid, category = category, inputKey = inputKey }; if (isToggle) { keybind.toggle = toggle; } else { keybind.tag = $"[{(int)inputKey}]"; keybind.inputAction = new InputAction(name, (InputActionType)0, binding, (string)null, (string)null, (string)null); } keybind.registeredAsToggle = isToggle; if (!_modOrder.TryGetValue(modGuid, out var value)) { value = _nextModOrderIndex++; _modOrder[modGuid] = value; } keybind.modOrderIndex = value; keybind.registerIndex = _nextRegisterIndex++; Plugin.instance.registeredKeybinds.Add(keybind); Plugin.instance.logger.LogMessage((object)("Registered " + (isToggle ? "toggle" : ("keybind \"" + name + "\"")) + ((!string.IsNullOrEmpty(category)) ? (" in category \"" + category + "\"") : "") + " for mod \"" + modGuid + "\".")); return keybind; InputKey ComputeInputKey() { //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(category)) { category = string.Empty; } if (string.IsNullOrEmpty(name)) { name = string.Empty; } string text = modGuid + "|" + category + "|" + name; uint num = 2166136261u; for (int i = 0; i < text.Length; i++) { num ^= text[i]; num *= 16777619; } num &= 0x3FFFFFFFu; num |= 0x40000000u; return (InputKey)num; } bool SameCategory(Keybind x) { return (string.IsNullOrEmpty(x.category) && string.IsNullOrEmpty(category)) || (!string.IsNullOrEmpty(x.category) && !string.IsNullOrEmpty(category) && x.category.Equals(category, StringComparison.OrdinalIgnoreCase)); } } } }