Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of SaveKeyBinds v1.0.5
SaveKeyBinds.dll
Decompiled a week agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using HarmonyLib; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes; using Il2CppScheduleOne; using Il2CppSystem.Collections.Generic; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using ScheduleIMod; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(Keybinder), "SaveKeyBinds", "1.0.0", "arc", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")] [assembly: AssemblyCompany("SaveKeyBinds")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("SaveKeyBinds")] [assembly: AssemblyTitle("Schedule I Keybind Mod")] [assembly: AssemblyVersion("1.0.0.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace ScheduleIMod { public class Keybinder : MelonMod { private static class ConsoleMethodCache { private static bool _initialized; private static readonly object _lock = new object(); public static Action<Console, KeyCode, string>? Bind; public static Action<Console, KeyCode>? Unbind; public static Action<Console, KeyCode, string>? AddBinding; public static Action<Console, KeyCode>? RemoveBinding; public static void EnsureInitialized(Console c) { if (_initialized) { return; } lock (_lock) { if (_initialized) { return; } Type type = ((object)c).GetType(); BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; MethodInfo method = type.GetMethod("Bind", bindingAttr, null, new Type[2] { typeof(KeyCode), typeof(string) }, null); if (method != null) { try { Bind = (Action<Console, KeyCode, string>)Delegate.CreateDelegate(typeof(Action<Console, KeyCode, string>), null, method); } catch { } } MethodInfo method2 = type.GetMethod("Unbind", bindingAttr, null, new Type[1] { typeof(KeyCode) }, null); if (method2 != null) { try { Unbind = (Action<Console, KeyCode>)Delegate.CreateDelegate(typeof(Action<Console, KeyCode>), null, method2); } catch { } } MethodInfo method3 = type.GetMethod("AddBinding", bindingAttr, null, new Type[2] { typeof(KeyCode), typeof(string) }, null); if (method3 != null) { try { AddBinding = (Action<Console, KeyCode, string>)Delegate.CreateDelegate(typeof(Action<Console, KeyCode, string>), null, method3); } catch { } } MethodInfo method4 = type.GetMethod("RemoveBinding", bindingAttr, null, new Type[1] { typeof(KeyCode) }, null); if (method4 != null) { try { RemoveBinding = (Action<Console, KeyCode>)Delegate.CreateDelegate(typeof(Action<Console, KeyCode>), null, method4); } catch { } } _initialized = true; } } } private MelonPreferences_Category? _cat; private MelonPreferences_Entry<bool>? _actLoad; private MelonPreferences_Entry<bool>? _actReset; private MelonPreferences_Entry<bool>? _actClear; private int _actionFrameLatch = -1; private bool bindingsAdded; private string configPath = string.Empty; private static bool _typesRegistered = false; private List<(string command, KeyCode key)> keybinds = new List<(string, KeyCode)>(); private static Keybinder? instance; private Console? console; private bool consoleCommandsRegistered; private int _rebindJobToken; private bool _rebindInFlight; private HashSet<KeyCode> _lastAppliedKeys = new HashSet<KeyCode>(); private DateTime _configTimestampUtc = DateTime.MinValue; private Harmony? _harmony; private readonly object _bindingsSync = new object(); private static bool _hasModManager = false; private static bool _mmTriedCache = false; private static Action? _mmRequestRefresh; private static readonly string[] ConfigHeader = new string[4] { "# Schedule I SaveKeyBinds Config", "# Format = 'command: KeyCode'", "# Available KeyCodes: https://docs.unity3d.com/ScriptReference/KeyCode.html", "" }; public static Keybinder? Instance => instance; public int KeybindCount { get { lock (_bindingsSync) { return keybinds.Count; } } } public string ConfigPath => configPath; internal static void Info(string msg) { if (instance != null) { ((MelonBase)instance).LoggerInstance.Msg(msg); } else { MelonLogger.Msg(msg); } } internal static void Warn(string msg) { if (instance != null) { ((MelonBase)instance).LoggerInstance.Warning(msg); } else { MelonLogger.Warning(msg); } } internal static void Err(string msg) { if (instance != null) { ((MelonBase)instance).LoggerInstance.Error(msg); } else { MelonLogger.Error(msg); } } private static string Q(string? s) { if (s != null) { return "\"" + s + "\""; } return "null"; } internal static string ExMsg(Exception ex) { Exception innerException = ex.InnerException; if (innerException != null) { return $"{ex.GetType().Name}: {ex.Message} | Inner {innerException.GetType().Name}: {innerException.Message}"; } return ex.GetType().Name + ": " + ex.Message; } private void RefreshIfStale() { try { if (File.Exists(configPath) && File.GetLastWriteTimeUtc(configPath) > _configTimestampUtc) { LoadConfig(); } } catch (Exception ex) { Err("RefreshIfStale failed: " + ExMsg(ex)); } } [Obsolete] public override void OnApplicationStart() { instance = this; _hasModManager = DetectModManager(); Info("Loaded successfully!"); configPath = Path.Combine(MelonUtils.GameDirectory, "UserData", "keyBinds.ini"); string directoryName = Path.GetDirectoryName(configPath); if (!string.IsNullOrEmpty(directoryName)) { Directory.CreateDirectory(directoryName); } _cat = MelonPreferences.CreateCategory("SaveKeyBinds", "Manage Local Config"); _actLoad = _cat.CreateEntry<bool>("Load", false, "Reload keyBinds.ini", (string)null, false, false, (ValueValidator)null, (string)null); _actReset = _cat.CreateEntry<bool>("Reset", false, "Reset keyBinds.ini to default", (string)null, false, false, (ValueValidator)null, (string)null); _actClear = _cat.CreateEntry<bool>("Clear", false, "Clear keyBinds.ini", (string)null, false, false, (ValueValidator)null, (string)null); MelonPreferences.Save(); if (_hasModManager) { Info("ModManagerPhoneApp found!"); } if (_hasModManager) { EnsureModManagerRefreshCached(); } LoadConfig(); SetupHarmonyPatch(); } public override void OnUpdate() { if (_hasModManager) { TryRunActionToggles(); } } private void TryRunActionToggles() { if (Time.frameCount == _actionFrameLatch) { return; } bool flag = false; if (_actLoad != null && _actLoad.Value) { try { LoadConfig(); ApplyKeybindingsReplaceManagedPublic(); Info("Loaded " + Path.GetFileName(ConfigPath) + "!"); } catch (Exception ex) { Err("LoadNow failed: " + ExMsg(ex)); } finally { _actLoad.Value = false; flag = true; } } if (_actReset != null && _actReset.Value) { try { ResetToDefaultsAndApply(); Info("Keybinds reset to default!"); } catch (Exception ex2) { Err("ResetToDefaults failed: " + ExMsg(ex2)); } finally { _actReset.Value = false; flag = true; } } if (_actClear != null && _actClear.Value) { try { ClearAllKeybinds(); Info("All keybinds cleared!"); } catch (Exception ex3) { Err("ClearAll failed: " + ExMsg(ex3)); } finally { _actClear.Value = false; flag = true; } } if (flag) { MelonPreferences.Save(); _actionFrameLatch = Time.frameCount; TryRequestSettingsUIRefresh(); } } public override void OnSceneWasLoaded(int buildIndex, string sceneName) { bool hasModManager = _hasModManager; _hasModManager = _hasModManager || DetectModManager(); if (!hasModManager && _hasModManager) { Info("ModManagerPhoneApp found!"); } if (!hasModManager && _hasModManager) { _mmTriedCache = false; EnsureModManagerRefreshCached(); } Console val = Object.FindObjectOfType<Console>(); if ((Object)(object)console == (Object)null || (Object)(object)val == (Object)null || (Object)(object)console != (Object)(object)val) { console = val; bindingsAdded = false; consoleCommandsRegistered = false; } ScheduleRebindAndRegister(); } public override void OnApplicationQuit() { try { Harmony? harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch (Exception ex) { Err("Harmony UnpatchSelf failed: " + ExMsg(ex)); } instance = null; console = null; } private static void TryRequestSettingsUIRefresh() { if (_hasModManager) { EnsureModManagerRefreshCached(); if (_mmRequestRefresh != null) { MelonCoroutines.Start(RequestSettingsUIRefreshAfter(0.6f)); } } } private static IEnumerator RequestSettingsUIRefreshAfter(float seconds) { if (seconds > 0f) { yield return (object)new WaitForSecondsRealtime(seconds); } try { _mmRequestRefresh?.Invoke(); } catch (Exception ex) { Warn("RequestUIRefresh failed: " + ExMsg(ex)); } } private static bool DetectModManager() { try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if ((assembly.GetName().Name ?? string.Empty).Contains("ModManagerPhoneApp", StringComparison.OrdinalIgnoreCase)) { return true; } if (assembly.GetType("ModManagerPhoneApp.ModSettingsEvents", throwOnError: false) != null) { return true; } } } catch { } return false; } private static void EnsureModManagerRefreshCached() { if (_mmTriedCache) { return; } _mmTriedCache = true; try { MethodInfo i = AppDomain.CurrentDomain.GetAssemblies().SelectMany(delegate(Assembly a) { try { return a.GetTypes(); } catch { return Type.EmptyTypes; } }).FirstOrDefault((Type x) => x.FullName == "ModManagerPhoneApp.ModSettingsEvents")?.GetMethod("RequestUIRefresh", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (!(i != null)) { return; } try { _mmRequestRefresh = (Action)Delegate.CreateDelegate(typeof(Action), i); } catch { _mmRequestRefresh = delegate { i.Invoke(null, null); }; } } catch { } } private void ScheduleRebindAndRegister() { _rebindJobToken++; if (!_rebindInFlight) { _rebindInFlight = true; MelonCoroutines.Start(RebindAndRegisterWhenReady(_rebindJobToken)); } } private IEnumerator RebindAndRegisterWhenReady(int token) { yield return null; for (int i = 0; i < 120; i++) { if (token != _rebindJobToken) { _rebindInFlight = false; yield break; } Console val = console ?? Object.FindObjectOfType<Console>(); if ((Object)(object)val != (Object)null) { console = val; break; } yield return null; } if ((Object)(object)console == (Object)null) { _rebindInFlight = false; yield break; } try { if (!bindingsAdded) { Info("Loaded " + configPath); ApplyKeybindings(); if (bindingsAdded) { RegisterLoadKeysCommand(); } } } catch (Exception ex) { Err("RebindAndRegisterWhenReady failed: " + ExMsg(ex)); } finally { _rebindInFlight = false; } } private void RegisterLoadKeysCommand() { if (!_typesRegistered) { try { ClassInjector.RegisterTypeInIl2Cpp<LoadKeysCommand>(); ClassInjector.RegisterTypeInIl2Cpp<ClearKeysCommand>(); ClassInjector.RegisterTypeInIl2Cpp<ResetKeysCommand>(); _typesRegistered = true; } catch (Exception ex) { Err("Error registering Il2Cpp types (once): " + ExMsg(ex)); } } if (consoleCommandsRegistered) { return; } try { Console val = console ?? Object.FindObjectOfType<Console>(); if ((Object)(object)val != (Object)null) { RegisterConsoleCommand(val, (ConsoleCommand)(object)new LoadKeysCommand()); RegisterConsoleCommand(val, (ConsoleCommand)(object)new ClearKeysCommand()); RegisterConsoleCommand(val, (ConsoleCommand)(object)new ResetKeysCommand()); consoleCommandsRegistered = true; } } catch (Exception ex2) { Err("Error registering console commands: " + ExMsg(ex2)); } } private void RegisterConsoleCommand(Console console, ConsoleCommand cmd) { try { Dictionary<string, ConsoleCommand> commands = Console.commands; if (commands != null) { string text = cmd.CommandWord?.ToLowerInvariant() ?? string.Empty; if (!string.IsNullOrEmpty(text)) { commands[text] = cmd; } } } catch (Exception ex) { Err("RegisterConsoleCommand(dict) failed: " + ExMsg(ex)); } try { List<ConsoleCommand> commands2 = Console.Commands; if (commands2 != null && !commands2.Contains(cmd)) { commands2.Add(cmd); } } catch (Exception ex2) { Err("RegisterConsoleCommand(list) failed: " + ExMsg(ex2)); } } private void SetupHarmonyPatch() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown try { _harmony = new Harmony("ScheduleIMod.Keybinder"); BindingFlags bindingAttr = BindingFlags.Public | BindingFlags.NonPublic; BindingFlags bindingAttr2 = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; Type nestedType = typeof(Console).GetNestedType("Bind", bindingAttr); if (nestedType != null) { MethodInfo method = nestedType.GetMethod("Execute", bindingAttr2); if (method != null) { MethodInfo method2 = typeof(Keybinder).GetMethod("BindExecutePostfix", BindingFlags.Static | BindingFlags.NonPublic); _harmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } Type nestedType2 = typeof(Console).GetNestedType("Unbind", bindingAttr); if (nestedType2 != null) { MethodInfo method3 = nestedType2.GetMethod("Execute", bindingAttr2); if (method3 != null) { MethodInfo method4 = typeof(Keybinder).GetMethod("UnbindExecutePostfix", BindingFlags.Static | BindingFlags.NonPublic); _harmony.Patch((MethodBase)method3, (HarmonyMethod)null, new HarmonyMethod(method4), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } } catch (Exception ex) { Err("Harmony patch setup failed: " + ExMsg(ex)); } } private static void BindExecutePostfix(List<string> args) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) try { if (args.Count >= 2) { string value = args[0]; List<string> list = new List<string>(); for (int i = 1; i < args.Count; i++) { list.Add(args[i]); } string command = string.Join(" ", list); if (Enum.TryParse<KeyCode>(value, ignoreCase: true, out KeyCode result) && instance != null) { instance.RefreshIfStale(); instance.SaveBindingToConfig(result, command); } } } catch (Exception ex) { Err("BindExecutePostfix failed: " + ExMsg(ex)); } } private static void UnbindExecutePostfix(List<string> args) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) try { if (args.Count >= 1 && Enum.TryParse<KeyCode>(args[0], ignoreCase: true, out KeyCode result) && instance != null) { instance.RefreshIfStale(); instance.RemoveBindingFromConfig(result); } } catch (Exception ex) { Err("UnbindExecutePostfix failed: " + ExMsg(ex)); } } private static string[] ReadAllLinesShared(string path) { using FileStream stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); using StreamReader streamReader = new StreamReader(stream); List<string> list = new List<string>(); while (!streamReader.EndOfStream) { list.Add(streamReader.ReadLine() ?? string.Empty); } return list.ToArray(); } public void LoadConfig() { //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_0284: 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_028f: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_0380: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_0329: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) try { if (!File.Exists(configPath)) { CreateDefaultConfig(); } DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(configPath); string[] array = ReadAllLinesShared(configPath); List<(string, KeyCode, int)> list = new List<(string, KeyCode, int)>(); List<string> list2 = new List<string>(); for (int i = 0; i < array.Length; i++) { string text = array[i]?.Trim(); if (string.IsNullOrWhiteSpace(text) || text.StartsWith("#")) { continue; } string[] array2 = text.Split(new char[1] { ':' }, 2); if (array2.Length == 2) { string item = array2[0].Trim(); string value = array2[1].Trim(); if (Enum.TryParse<KeyCode>(value, ignoreCase: true, out KeyCode result)) { list.Add((item, result, i)); continue; } list2.Add($"Line {i + 1}: Invalid key '{value}'"); Warn($"Config parse: invalid KeyCode at {Path.GetFileName(configPath)}:{i + 1} -> '{value}'"); } else { list2.Add($"Line {i + 1}: '{text}'"); Warn($"Config parse: malformed line at {Path.GetFileName(configPath)}:{i + 1} -> '{text}'"); } } Dictionary<KeyCode, (string, int)> dictionary = new Dictionary<KeyCode, (string, int)>(); foreach (var (text2, val, num) in list) { if (!dictionary.ContainsKey(val)) { dictionary[val] = (text2, num); } else if (dictionary[val].Item2 > num) { list2.Add($"Duplicate key {val}: removed '{dictionary[val].Item1}' (kept '{text2}')"); dictionary[val] = (text2, num); } else { list2.Add($"Duplicate key {val}: removed '{text2}' (kept '{dictionary[val].Item1}')"); } } List<(string, KeyCode)> collection = (from x in dictionary orderby x.Value.lineNumber select x into kvp select (kvp.Value.command, kvp.Key)).ToList(); lock (_bindingsSync) { keybinds.Clear(); keybinds.AddRange(collection); } if (list2.Count > 0 || dictionary.Count != list.Count) { if (File.GetLastWriteTimeUtc(configPath) == lastWriteTimeUtc) { SafeWriteConfig(); foreach (string item2 in list2) { Info("Removed: " + item2); } } else { Info("Config changed on disk during load; skipping clean write-back to avoid clobbering external edits."); } } try { _configTimestampUtc = File.GetLastWriteTimeUtc(configPath); } catch { } } catch (Exception ex) { Err("LoadConfig failed: " + ExMsg(ex)); CreateDefaultConfig(); } } private void SafeWriteConfig() { //IL_0071: Unknown result type (might be due to invalid IL or missing references) try { List<(string, KeyCode)> list; lock (_bindingsSync) { list = keybinds.ToList(); } List<string> list2 = new List<string>(ConfigHeader); foreach (var item in list) { list2.Add($"{item.Item1}: {item.Item2}"); } string text = configPath + ".tmp"; File.WriteAllLines(text, list2); if (File.Exists(configPath)) { string text2 = configPath + ".bak"; try { File.Replace(text, configPath, text2, ignoreMetadataErrors: true); try { if (File.Exists(text2)) { File.Delete(text2); } } catch { } } catch { File.Delete(configPath); File.Move(text, configPath); } } else { File.Move(text, configPath); } try { _configTimestampUtc = File.GetLastWriteTimeUtc(configPath); } catch { } } catch (Exception ex) { Err("SafeWriteConfig failed at path=" + Q(configPath) + ": " + ExMsg(ex)); } } public void ApplyKeybindingsPublic() { ApplyKeybindings(); } public void ApplyKeybindingsReplaceManagedPublic() { ApplyKeybindingsReplaceManaged(); } private void ApplyKeybindings() { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) try { Console val = console ?? Object.FindObjectOfType<Console>(); if ((Object)(object)val == (Object)null) { return; } List<(string, KeyCode)> list; lock (_bindingsSync) { list = keybinds.ToList(); } foreach (var (command, key) in list) { GameUnbind(key, val); GameBind(key, command, val); } lock (_bindingsSync) { _lastAppliedKeys = list.Select<(string, KeyCode), KeyCode>(((string command, KeyCode key) k) => k.key).ToHashSet(); } bindingsAdded = true; Info($"Applied {list.Count} keybinds from {Path.GetFileName(configPath)}!"); } catch (Exception ex) { Err("ApplyKeybindings failed: " + ExMsg(ex)); } } private void ApplyKeybindingsReplaceManaged() { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: 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) try { Console val = console ?? Object.FindObjectOfType<Console>(); if ((Object)(object)val == (Object)null) { return; } HashSet<KeyCode> hashSet; List<(string, KeyCode)> list; lock (_bindingsSync) { hashSet = new HashSet<KeyCode>(_lastAppliedKeys); list = keybinds.ToList(); } foreach (KeyCode item in hashSet) { GameUnbind(item, val); } foreach (var (command, key) in list) { GameBind(key, command, val); } lock (_bindingsSync) { _lastAppliedKeys = list.Select<(string, KeyCode), KeyCode>(((string command, KeyCode key) k) => k.key).ToHashSet(); } bindingsAdded = true; Info($"Applied {list.Count} keybinds from {Path.GetFileName(configPath)}!"); } catch (Exception ex) { Err("ApplyKeybindingsReplaceManaged failed: " + ExMsg(ex)); } } private void GameUnbind(KeyCode key, Console c) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_0013: 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_0080: Unknown result type (might be due to invalid IL or missing references) ConsoleMethodCache.EnsureInitialized(c); try { if (ConsoleMethodCache.Unbind != null) { ConsoleMethodCache.Unbind(c, key); return; } } catch (Exception ex) { Err($"Unbind(key={key}) threw: {ExMsg(ex)}; will try RemoveBinding."); } try { if (ConsoleMethodCache.RemoveBinding != null) { ConsoleMethodCache.RemoveBinding(c, key); } else { c.RemoveBinding(key); } } catch (Exception ex2) { Err($"RemoveBinding(key={key}) failed: {ExMsg(ex2)}"); } } private void GameBind(KeyCode key, string command, Console c) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) ConsoleMethodCache.EnsureInitialized(c); try { if (ConsoleMethodCache.Bind != null) { ConsoleMethodCache.Bind(c, key, command); return; } } catch (Exception ex) { Err($"Bind(key={key}, cmd={Q(command)}) threw: {ExMsg(ex)}; will try AddBinding."); } try { if (ConsoleMethodCache.AddBinding != null) { ConsoleMethodCache.AddBinding(c, key, command); } else { c.AddBinding(key, command); } } catch (Exception ex2) { Err($"AddBinding(key={key}, cmd={Q(command)}) failed: {ExMsg(ex2)}"); } } public void ClearAllKeybinds() { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) try { RefreshIfStale(); List<KeyCode> list; lock (_bindingsSync) { list = keybinds.Select<(string, KeyCode), KeyCode>(((string command, KeyCode key) k) => k.key).Distinct().ToList(); } Console val = console ?? Object.FindObjectOfType<Console>(); if ((Object)(object)val != (Object)null) { foreach (KeyCode item in list) { GameUnbind(item, val); } } lock (_bindingsSync) { keybinds.Clear(); _lastAppliedKeys.Clear(); } SafeWriteConfig(); } catch (Exception ex) { Err("ClearAllKeybinds failed: " + ExMsg(ex)); } } private List<(string command, KeyCode key)> GetDefaultBinds() { return new List<(string, KeyCode)> { ("cleartrash", (KeyCode)282), ("save", (KeyCode)283), ("showfps", (KeyCode)284), ("hidefps", (KeyCode)285) }; } private void CreateDefaultConfig() { try { lock (_bindingsSync) { keybinds = GetDefaultBinds(); } SafeWriteConfig(); } catch (Exception ex) { Err("CreateDefaultConfig failed: " + ExMsg(ex)); } } public void ResetToDefaultsAndApply() { //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) try { RefreshIfStale(); Console val = console ?? Object.FindObjectOfType<Console>(); List<(string, KeyCode)> defaultBinds = GetDefaultBinds(); HashSet<KeyCode> defaultKeys = defaultBinds.Select<(string, KeyCode), KeyCode>(((string command, KeyCode key) d) => d.key).ToHashSet(); List<KeyCode> source; lock (_bindingsSync) { source = keybinds.Select<(string, KeyCode), KeyCode>(((string command, KeyCode key) k) => k.key).ToList(); } List<KeyCode> list = source.Where((KeyCode k) => !defaultKeys.Contains(k)).ToList(); if ((Object)(object)val != (Object)null) { foreach (KeyCode item in list) { GameUnbind(item, val); } } lock (_bindingsSync) { keybinds = defaultBinds; } SafeWriteConfig(); if (!((Object)(object)val != (Object)null)) { return; } foreach (var (command, key) in defaultBinds) { GameBind(key, command, val); } lock (_bindingsSync) { _lastAppliedKeys = defaultBinds.Select<(string, KeyCode), KeyCode>(((string command, KeyCode key) k) => k.key).ToHashSet(); } bindingsAdded = true; } catch (Exception ex) { Err("ResetToDefaultsAndApply failed: " + ExMsg(ex)); } } private void SaveBindingToConfig(KeyCode key, string command) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) try { RefreshIfStale(); lock (_bindingsSync) { keybinds.RemoveAll(((string command, KeyCode key) kb) => kb.key == key); keybinds.Add((command, key)); } SafeWriteConfig(); } catch (Exception ex) { Err($"SaveBindingToConfig failed for key={key}, cmd={Q(command)}: {ExMsg(ex)}"); } } private void RemoveBindingFromConfig(KeyCode keyCode) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) try { RefreshIfStale(); lock (_bindingsSync) { keybinds.RemoveAll(((string command, KeyCode key) kb) => kb.key == keyCode); } } catch (Exception ex) { Err($"RemoveBindingFromConfig failed for key={keyCode}: {ExMsg(ex)}"); } finally { SafeWriteConfig(); } } } public class LoadKeysCommand : ConsoleCommand { public override string CommandWord => "loadkeys"; public override string CommandDescription => "Reloads keybinds from keyBinds.ini and reapplies them in-game (replacing previous custom binds)"; public override string ExampleUsage => "loadkeys"; public LoadKeysCommand(IntPtr ptr) : base(ptr) { } public LoadKeysCommand() : base(ClassInjector.DerivedConstructorPointer<LoadKeysCommand>()) { ClassInjector.DerivedConstructorBody((Il2CppObjectBase)(object)this); } public override void Execute(List<string> args) { try { if (Keybinder.Instance != null) { Keybinder.Instance.LoadConfig(); Keybinder.Instance.ApplyKeybindingsReplaceManagedPublic(); Keybinder.Info("Reloaded " + Path.GetFileName(Keybinder.Instance.ConfigPath) + "!"); } else { Keybinder.Info("Not found!"); } } catch (Exception ex) { Keybinder.Err("loadkeys failed: " + Keybinder.ExMsg(ex)); Keybinder.Info("Error: " + ex.Message); } } } public class ClearKeysCommand : ConsoleCommand { public override string CommandWord => "clearkeys"; public override string CommandDescription => "Clears all keybinds from keyBinds.ini and unbinds those keys in-game"; public override string ExampleUsage => "clearkeys"; public ClearKeysCommand(IntPtr ptr) : base(ptr) { } public ClearKeysCommand() : base(ClassInjector.DerivedConstructorPointer<ClearKeysCommand>()) { ClassInjector.DerivedConstructorBody((Il2CppObjectBase)(object)this); } public override void Execute(List<string> args) { try { if (Keybinder.Instance != null) { Keybinder.Instance.ClearAllKeybinds(); Keybinder.Info("All keybinds cleared!"); } else { Keybinder.Info("Not found!"); } } catch (Exception ex) { Keybinder.Err("clearkeys failed: " + Keybinder.ExMsg(ex)); Keybinder.Info("Error: " + ex.Message); } } } public class ResetKeysCommand : ConsoleCommand { public override string CommandWord => "resetkeys"; public override string CommandDescription => "Unbinds non-default keys, resets keyBinds.ini to defaults, and binds defaults in-game"; public override string ExampleUsage => "resetkeys"; public ResetKeysCommand(IntPtr ptr) : base(ptr) { } public ResetKeysCommand() : base(ClassInjector.DerivedConstructorPointer<ResetKeysCommand>()) { ClassInjector.DerivedConstructorBody((Il2CppObjectBase)(object)this); } public override void Execute(List<string> args) { try { if (Keybinder.Instance != null) { Keybinder.Instance.ResetToDefaultsAndApply(); Keybinder.Info("Keybinds reset to defaults!"); } else { Keybinder.Info("Not found!"); } } catch (Exception ex) { Keybinder.Err("resetkeys failed: " + Keybinder.ExMsg(ex)); Keybinder.Info("Error: " + ex.Message); } } } }