using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using HarmonyLib; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using MimesisSlotKeys; using Mimic.Actors; using Mimic.InputSystem; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(SlotKeysMod), "MimesisSlotKeys", "1.0.0", "vonhoon", null)] [assembly: MelonGame(null, "MIMESIS")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("MimesisSlotKeys")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("MimesisSlotKeys")] [assembly: AssemblyTitle("MimesisSlotKeys")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace MimesisSlotKeys { public enum EmoteMode { Numpad, ShiftNumber, CtrlNumber } public class SlotKeysMod : MelonMod { internal static Instance Log; private static MelonPreferences_Category _cat; private static MelonPreferences_Entry _emoteModeEntry; internal const int KeyCount = 4; internal const int EmoteCount = 10; private static InputManager _appliedInputman; private static EmoteMode _appliedMode; private static readonly string[] _modeLabels = new string[3] { "Numpad", "Shift + #", "Ctrl + #" }; internal static EmoteMode Mode { get { int num = ((_emoteModeEntry != null) ? _emoteModeEntry.Value : 0); if (num < 0 || num > 2) { num = 0; } return (EmoteMode)num; } set { if (_emoteModeEntry != null) { _emoteModeEntry.Value = (int)value; MelonPreferences_Category cat = _cat; if (cat != null) { cat.SaveToFile(false); } } _appliedInputman = null; } } public override void OnInitializeMelon() { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown Log = ((MelonBase)this).LoggerInstance; _cat = MelonPreferences.CreateCategory("MimesisSlotKeys"); _emoteModeEntry = _cat.CreateEntry("EmoteMode", 0, (string)null, "Emote binding: 0 = Numpad 1-4, 1 = Shift + top-row 1-4, 2 = Ctrl + top-row 1-4. Top-row 1-4 always selects inventory slots 1-4.", false, false, (ValueValidator)null, (string)null); Type typeFromHandle = typeof(ProtoActor); ((MelonBase)this).HarmonyInstance.Patch((MethodBase)AccessTools.Method(typeFromHandle, "ProcessUISelectKey", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(SlotKeysMod), "InventoryPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((MelonBase)this).HarmonyInstance.Patch((MethodBase)AccessTools.Method(typeFromHandle, "ProcessEmoteKey", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(SlotKeysMod), "EmotePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.Msg($"Initialized. EmoteMode={Mode}. Top-row 1-4 = inventory slots."); } private static InputManager GetInputman() { if (!((Object)(object)Hub.s == (Object)null)) { return Traverse.Create((object)Hub.s).Property("inputman", (object[])null).GetValue(); } return null; } private static MMEmoteTable GetEmoteTable() { if ((Object)(object)Hub.s == (Object)null) { return null; } object value = Traverse.Create((object)Hub.s).Property("tableman", (object[])null).GetValue(); if (value != null) { return Traverse.Create(value).Field("emote").GetValue(); } return null; } private static void ShowEmoteBlockedToast() { try { object value = Traverse.Create(Traverse.Create((object)Hub.s).Property("tableman", (object[])null).GetValue()).Field("uiprefabs").GetValue(); string value2 = Traverse.Create(typeof(Hub)).Method("GetL10NText", new object[1] { "STRING_DO_NOT_EMOTE" }).GetValue(); Traverse.Create(value).Method("ShowTimerDialog", new object[3] { "ToastSimple", 0f, value2 }).GetValue(); } catch { } } private static bool ShiftHeld(Keyboard kb) { if (!((ButtonControl)kb.leftShiftKey).isPressed) { return ((ButtonControl)kb.rightShiftKey).isPressed; } return true; } private static bool CtrlHeld(Keyboard kb) { if (!((ButtonControl)kb.leftCtrlKey).isPressed) { return ((ButtonControl)kb.rightCtrlKey).isPressed; } return true; } private static bool EmoteModifierHeld(Keyboard kb) { return Mode switch { EmoteMode.ShiftNumber => ShiftHeld(kb), EmoteMode.CtrlNumber => CtrlHeld(kb), _ => false, }; } private static KeyControl Digit(Keyboard kb, int i) { return (KeyControl)(i switch { 0 => kb.digit1Key, 1 => kb.digit2Key, 2 => kb.digit3Key, _ => kb.digit4Key, }); } private static void EnsureEmoteBindings(InputManager im) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)im == (Object)null || (Object)(object)im.data == (Object)null || im.data.data == null) { return; } EmoteMode mode = Mode; if (im == _appliedInputman && mode == _appliedMode) { return; } foreach (Mapping datum in im.data.data) { int num = EmoteActionIndex(datum.action); if (num < 1 || num > 10) { continue; } HashSet hashSet = SplitKeys(datum.keys); string item = "k_num" + ((num != 10) ? num : 0); if (num <= 4) { hashSet.Clear(); if (mode == EmoteMode.Numpad) { hashSet.Add(item); } } else { if (mode != EmoteMode.Numpad) { continue; } hashSet.Add(item); } datum.keys = string.Join(",", hashSet); } im.RefreshInputAssign(); _appliedInputman = im; _appliedMode = mode; Instance log = Log; if (log != null) { log.Msg($"Applied emote bindings for mode {mode}."); } } private static HashSet SplitKeys(string keys) { HashSet hashSet = new HashSet(); if (string.IsNullOrEmpty(keys)) { return hashSet; } string[] array = keys.Split(','); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0) { hashSet.Add(text); } } return hashSet; } private static int EmoteActionIndex(InputAction a) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Expected I4, but got Unknown int num = (int)a; if (num < 21 || num > 30) { return 0; } return num - 20; } private static void InventoryPostfix(ProtoActor __instance) { try { EnsureEmoteBindings(GetInputman()); Keyboard current = Keyboard.current; if (current == null) { return; } bool flag = Mode != EmoteMode.Numpad; bool flag2 = flag && EmoteModifierHeld(current); for (int i = 0; i < 4; i++) { if (((ButtonControl)Digit(current, i)).wasPressedThisFrame && !(flag && flag2)) { SelectInventorySlot(__instance, i); } } } catch (Exception ex) { Instance log = Log; if (log != null) { log.Error("InventoryPostfix: " + ex); } } } private static void EmotePostfix(ProtoActor __instance) { try { if (Mode == EmoteMode.Numpad) { return; } Keyboard current = Keyboard.current; if (current == null || !EmoteModifierHeld(current)) { return; } for (int i = 0; i < 4; i++) { if (((ButtonControl)Digit(current, i)).wasPressedThisFrame) { TriggerEmote(__instance, i + 1); break; } } } catch (Exception ex) { Instance log = Log; if (log != null) { log.Error("EmotePostfix: " + ex); } } } private static void SelectInventorySlot(ProtoActor actor, int index) { Traverse val = Traverse.Create((object)actor); object value = val.Field("inventory").GetValue(); if (value == null) { return; } Traverse val2 = Traverse.Create(value); int num = 0; Traverse val3 = val2.Field("slotSize"); if (val3.FieldExists()) { num = val3.GetValue(); } if (num <= 0 || index < num) { object value2 = val.Property("main", (object[])null).GetValue(); if (value2 != null) { Traverse.Create(value2).Method("TryPerformInteractionEnd", Array.Empty()).GetValue(); } val2.Method("SelectSlot", new object[1] { index }).GetValue(); } } private static void TriggerEmote(ProtoActor actor, int emoteNumber) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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) Traverse val = Traverse.Create((object)actor); Traverse val2 = val.Field("movementInput"); if (val2.FieldExists()) { Vector2 value = val2.GetValue(); if (((Vector2)(ref value)).sqrMagnitude > 0f) { return; } } EmotePlayer value2 = val.Field("emotePlayer").GetValue(); if (value2 == null) { return; } if (value2.IsEmoteDisabledByHandheldItem()) { ShowEmoteBlockedToast(); return; } MMEmoteTable emoteTable = GetEmoteTable(); InputAction val3 = (InputAction)(20 + emoteNumber); Emote val4 = default(Emote); if ((Object)(object)emoteTable != (Object)null && emoteTable.TryGetEmote(val3, ref val4) && val4 != null) { value2.SendStartEmote(val4.emoteMasterID); } } public override void OnGUI() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); if (!(((Scene)(ref activeScene)).name != "MainMenuScene")) { GUILayout.BeginArea(new Rect((float)Screen.width - 250f - 16f, (float)Screen.height - 84f - 56f, 250f, 84f), GUI.skin.box); GUILayout.Label("Emote keys (top-row 1-4 = inventory)", Array.Empty()); int mode = (int)Mode; int num = GUILayout.Toolbar(mode, _modeLabels, Array.Empty()); if (num != mode) { Mode = (EmoteMode)num; } GUILayout.EndArea(); } } } }