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 ControllerChords v0.3.0
ControllerChords.dll
Decompiled 2 months agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("0.0.0.0")] namespace ControllerChords; [BepInPlugin("marc.valheim.controllerchords", "Controller Chords", "0.4.0")] [BepInProcess("valheim.exe")] public sealed class ControllerChordsPlugin : BaseUnityPlugin { private sealed class ChordSlot { public int Index; public ConfigEntry<bool> Enabled; public ConfigEntry<ControllerButton> Modifier; public ConfigEntry<ControllerButton> Button; public ConfigEntry<KeyCode> TargetKey; public ConfigEntry<bool> BlockModifierDefaultAction; public ConfigEntry<int> VirtualPressFrames; public ConfigEntry<bool> HoldMode; } private sealed class SingleButtonSlot { public int Index; public ConfigEntry<bool> Enabled; public ConfigEntry<ControllerButton> Button; public ConfigEntry<KeyCode> TargetKey; public ConfigEntry<bool> HoldMode; public ConfigEntry<bool> BlockButtonDefaultAction; public ConfigEntry<int> VirtualPressFrames; } private sealed class ScrollSlot { public int Index; public ConfigEntry<bool> Enabled; public ConfigEntry<ControllerButton> Modifier; public ConfigEntry<ControllerButton> Button; public ConfigEntry<ScrollDirection> Direction; public ConfigEntry<float> ScrollAmount; public ConfigEntry<int> PulseFrames; public ConfigEntry<ScrollFireMode> FireMode; public ConfigEntry<bool> BlockTriggerDefaultAction; public ConfigEntry<bool> BlockModifierDefaultAction; } private struct ChordDefaults { public readonly bool Enabled; public readonly ControllerButton Modifier; public readonly ControllerButton Button; public readonly KeyCode TargetKey; public readonly bool BlockModifierDefaultAction; public readonly int VirtualPressFrames; public ChordDefaults(bool enabled, ControllerButton modifier, ControllerButton button, KeyCode targetKey, bool blockModifierDefaultAction, int virtualPressFrames) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) Enabled = enabled; Modifier = modifier; Button = button; TargetKey = targetKey; BlockModifierDefaultAction = blockModifierDefaultAction; VirtualPressFrames = virtualPressFrames; } } private struct SingleButtonDefaults { public readonly bool Enabled; public readonly ControllerButton Button; public readonly KeyCode TargetKey; public readonly bool HoldMode; public readonly bool BlockButtonDefaultAction; public readonly int VirtualPressFrames; public SingleButtonDefaults(bool enabled, ControllerButton button, KeyCode targetKey, bool holdMode, bool blockButtonDefaultAction, int virtualPressFrames) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) Enabled = enabled; Button = button; TargetKey = targetKey; HoldMode = holdMode; BlockButtonDefaultAction = blockButtonDefaultAction; VirtualPressFrames = virtualPressFrames; } } private struct ScrollDefaults { public readonly bool Enabled; public readonly ControllerButton Modifier; public readonly ControllerButton Button; public readonly ScrollDirection Direction; public readonly float ScrollAmount; public readonly int PulseFrames; public readonly ScrollFireMode FireMode; public readonly bool BlockTriggerDefaultAction; public readonly bool BlockModifierDefaultAction; public ScrollDefaults(bool enabled, ControllerButton modifier, ControllerButton button, ScrollDirection direction, float scrollAmount, int pulseFrames, ScrollFireMode fireMode, bool blockTriggerDefaultAction, bool blockModifierDefaultAction) { Enabled = enabled; Modifier = modifier; Button = button; Direction = direction; ScrollAmount = scrollAmount; PulseFrames = pulseFrames; FireMode = fireMode; BlockTriggerDefaultAction = blockTriggerDefaultAction; BlockModifierDefaultAction = blockModifierDefaultAction; } } public const string PluginGuid = "marc.valheim.controllerchords"; public const string PluginName = "Controller Chords"; public const string PluginVersion = "0.4.0"; private const int SlotCount = 12; private const int SingleButtonSlotCount = 8; private const int ScrollSlotCount = 4; private const int MinimumVirtualPressFrames = 1; private const int MaximumVirtualPressFrames = 8; internal static ControllerChordsPlugin Instance; private ConfigEntry<bool> enabledConfig; private ConfigEntry<bool> allowInMenus; private ConfigEntry<bool> logChordEvents; private readonly List<ChordSlot> slots = new List<ChordSlot>(12); private readonly List<SingleButtonSlot> singleSlots = new List<SingleButtonSlot>(8); private readonly List<ScrollSlot> scrollSlots = new List<ScrollSlot>(4); private readonly Dictionary<KeyCode, int> virtualKeyFrames = new Dictionary<KeyCode, int>(); private readonly Dictionary<string, int> virtualButtonFrames = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); private readonly Dictionary<string, int> blockedButtonFrames = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); private readonly List<KeyCode> keyScratch = new List<KeyCode>(); private readonly List<string> stringScratch = new List<string>(); private readonly HashSet<int> heldChordActive = new HashSet<int>(); private readonly HashSet<int> heldSingleActive = new HashSet<int>(); private float virtualScrollValue; private int virtualScrollFrames; private Harmony harmony; private Type zInputType; private Func<string, bool> zGetButton; private Func<string, bool> zGetButtonDown; private PropertyInfo zVirtualKeyboardOpenProperty; private MethodInfo menuIsVisibleMethod; private MethodInfo inventoryGuiIsVisibleMethod; private MethodInfo storeGuiIsVisibleMethod; private MethodInfo textInputIsVisibleMethod; private MethodInfo consoleIsVisibleMethod; private bool zInputReady; private bool patchesInstalled; private int chordsFired; private void Awake() { Instance = this; BindConfig(); if (!enabledConfig.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Controller Chords is disabled by config. No Harmony patches were installed."); return; } ResolveZInput(); ResolveMenuGuards(); InstallPatches(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Controller Chords 0.4.0 loaded. Supports single-button, double-button (chord), and scroll-wheel controller mappings."); } private void OnDestroy() { if (harmony != null) { harmony.UnpatchSelf(); harmony = null; } virtualKeyFrames.Clear(); virtualButtonFrames.Clear(); blockedButtonFrames.Clear(); virtualScrollValue = 0f; virtualScrollFrames = 0; if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void Update() { if (enabledConfig.Value && zInputReady && (allowInMenus.Value || !IsMenuInputContext())) { ProcessSingleButtonSlots(); ProcessScrollSlots(); ProcessChordSlots(); } } private unsafe void ProcessSingleButtonSlots() { //IL_0042: 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) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < singleSlots.Count; i++) { SingleButtonSlot singleButtonSlot = singleSlots[i]; if (singleButtonSlot == null || !singleButtonSlot.Enabled.Value) { continue; } ControllerButton value = singleButtonSlot.Button.Value; if (value == ControllerButton.None || (int)singleButtonSlot.TargetKey.Value == 0) { continue; } string text = ToZInputButtonName(value); if (string.IsNullOrEmpty(text)) { continue; } KeyCode value2 = singleButtonSlot.TargetKey.Value; if (singleButtonSlot.HoldMode.Value) { if (SafeGetZButton(text)) { SetMaxFrameCount(virtualKeyFrames, value2, 2); if (singleButtonSlot.BlockButtonDefaultAction.Value) { SetMaxFrameCount(blockedButtonFrames, text, 2); } if (!heldSingleActive.Contains(singleButtonSlot.Index)) { heldSingleActive.Add(singleButtonSlot.Index); if (logChordEvents.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Controller Chords: single-button " + singleButtonSlot.Index + " (" + text + " HOLD -> " + ((object)(*(KeyCode*)(&value2))/*cast due to .constrained prefix*/).ToString() + ") ENGAGED.")); } } } else if (heldSingleActive.Contains(singleButtonSlot.Index)) { heldSingleActive.Remove(singleButtonSlot.Index); if (logChordEvents.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Controller Chords: single-button " + singleButtonSlot.Index + " HOLD released.")); } } } else if (SafeGetZButtonDown(text)) { int num = singleButtonSlot.VirtualPressFrames.Value; if (num < 1 || num > 8) { num = 2; } SetMaxFrameCount(virtualKeyFrames, value2, num); if (singleButtonSlot.BlockButtonDefaultAction.Value) { SetMaxFrameCount(blockedButtonFrames, text, num); } if (logChordEvents.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Controller Chords: single-button " + singleButtonSlot.Index + " (" + text + " -> " + ((object)(*(KeyCode*)(&value2))/*cast due to .constrained prefix*/).ToString() + ") FIRED.")); } chordsFired++; } } } private void ProcessScrollSlots() { for (int i = 0; i < scrollSlots.Count; i++) { ScrollSlot scrollSlot = scrollSlots[i]; if (scrollSlot == null || !scrollSlot.Enabled.Value) { continue; } ControllerButton value = scrollSlot.Button.Value; if (value == ControllerButton.None) { continue; } string text = ToZInputButtonName(value); if (string.IsNullOrEmpty(text)) { continue; } ControllerButton value2 = scrollSlot.Modifier.Value; string text2 = string.Empty; if (value2 != ControllerButton.None) { text2 = ToZInputButtonName(value2); if (string.IsNullOrEmpty(text2) || !SafeGetZButton(text2)) { continue; } } if ((scrollSlot.FireMode.Value != ScrollFireMode.WhileHeld) ? SafeGetZButtonDown(text) : SafeGetZButton(text)) { EmitScroll(scrollSlot.ScrollAmount.Value, scrollSlot.Direction.Value, scrollSlot.PulseFrames.Value); if (scrollSlot.BlockTriggerDefaultAction.Value) { SetMaxFrameCount(blockedButtonFrames, text, Math.Max(2, scrollSlot.PulseFrames.Value)); } if (value2 != ControllerButton.None && scrollSlot.BlockModifierDefaultAction.Value) { SetMaxFrameCount(blockedButtonFrames, text2, Math.Max(2, scrollSlot.PulseFrames.Value)); } if (logChordEvents.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Controller Chords: scroll " + scrollSlot.Index + " (" + text + " -> scroll " + scrollSlot.Direction.Value.ToString() + " " + virtualScrollValue.ToString("0.###") + ") FIRED.")); } chordsFired++; } } } private void ProcessChordSlots() { //IL_0060: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < slots.Count; i++) { ChordSlot chordSlot = slots[i]; if (chordSlot == null || !chordSlot.Enabled.Value) { continue; } ControllerButton value = chordSlot.Modifier.Value; if (!IsSupportedModifier(value)) { continue; } ControllerButton value2 = chordSlot.Button.Value; if (value2 == ControllerButton.None || value2 == value || (int)chordSlot.TargetKey.Value == 0) { continue; } string text = ToZInputButtonName(value); string text2 = ToZInputButtonName(value2); if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(text2)) { continue; } bool flag = SafeGetZButton(text); if (chordSlot.HoldMode.Value) { bool flag2 = SafeGetZButton(text2); if (flag && flag2) { HoldChord(chordSlot, text); } else if (heldChordActive.Contains(chordSlot.Index)) { heldChordActive.Remove(chordSlot.Index); if (logChordEvents.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Controller Chords: chord " + chordSlot.Index + " HOLD released.")); } } } else { bool flag3 = SafeGetZButtonDown(text2); if (flag && flag3) { FireChord(chordSlot, text); } } } } private void LateUpdate() { AgeKeyFrames(); AgeStringFrames(virtualButtonFrames); AgeStringFrames(blockedButtonFrames); AgeScroll(); } private void BindConfig() { //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_03c1: Unknown result type (might be due to invalid IL or missing references) enabledConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. If false at startup, Controller Chords installs no active input patches."); allowInMenus = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AllowInMenus", false, "Allow controller mappings while Valheim menus/text input are open."); logChordEvents = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "LogChordEvents", false, "Log each fired mapping to BepInEx/LogOutput.log."); for (int i = 1; i <= 8; i++) { SingleButtonDefaults singleButtonDefaults = GetSingleButtonDefaults(i); string text = "SingleButton " + i.ToString("00"); SingleButtonSlot item = new SingleButtonSlot { Index = i, Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>(text, "Enabled", singleButtonDefaults.Enabled, "Enable this single-button mapping."), Button = ((BaseUnityPlugin)this).Config.Bind<ControllerButton>(text, "Button", singleButtonDefaults.Button, "Controller button that triggers this action."), TargetKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>(text, "TargetKey", singleButtonDefaults.TargetKey, "Keyboard KeyCode exposed virtually to other mods."), HoldMode = ((BaseUnityPlugin)this).Config.Bind<bool>(text, "HoldMode", singleButtonDefaults.HoldMode, "When true, the target key is held DOWN for as long as you hold the controller button, and released when you let go. Use this for hold-to-act mods (e.g. FrostJack Zoom's hold-to-zoom key). When false, sends a brief tap."), BlockButtonDefaultAction = ((BaseUnityPlugin)this).Config.Bind<bool>(text, "BlockButtonDefaultAction", singleButtonDefaults.BlockButtonDefaultAction, "Temporarily suppress this controller button's normal Valheim action while the mapping is active. Defaults false."), VirtualPressFrames = ((BaseUnityPlugin)this).Config.Bind<int>(text, "VirtualPressFrames", singleButtonDefaults.VirtualPressFrames, "Number of frames the virtual key remains visible to input queries (tap mode only).") }; singleSlots.Add(item); } for (int j = 1; j <= 4; j++) { ScrollDefaults scrollDefaults = GetScrollDefaults(j); string text2 = "Scroll " + j.ToString("00"); ScrollSlot item2 = new ScrollSlot { Index = j, Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>(text2, "Enabled", scrollDefaults.Enabled, "Enable this scroll-wheel mapping."), Modifier = ((BaseUnityPlugin)this).Config.Bind<ControllerButton>(text2, "Modifier", scrollDefaults.Modifier, "Optional held gate button. When set, the scroll only fires while this button is held. Set to None for no gate."), Button = ((BaseUnityPlugin)this).Config.Bind<ControllerButton>(text2, "Button", scrollDefaults.Button, "Controller button that emits a scroll notch."), Direction = ((BaseUnityPlugin)this).Config.Bind<ScrollDirection>(text2, "Direction", scrollDefaults.Direction, "In = scroll up (usually zoom in). Out = scroll down (usually zoom out). Swap these if your zoom feels reversed."), ScrollAmount = ((BaseUnityPlugin)this).Config.Bind<float>(text2, "ScrollAmount", scrollDefaults.ScrollAmount, "Magnitude of the emitted scroll value. Most zoom mods only care about the sign, so 1.0 is fine. Lower it if a single press zooms too far."), PulseFrames = ((BaseUnityPlugin)this).Config.Bind<int>(text2, "PulseFrames", scrollDefaults.PulseFrames, "How many frames the scroll value is emitted per press. 1 = one notch per press (recommended). Raise to 2 only if presses are being missed; note that may step two levels at once."), FireMode = ((BaseUnityPlugin)this).Config.Bind<ScrollFireMode>(text2, "FireMode", scrollDefaults.FireMode, "OnPress = one scroll notch each time you press the button (recommended for stepped zoom). WhileHeld = emit continuously while the button is held."), BlockTriggerDefaultAction = ((BaseUnityPlugin)this).Config.Bind<bool>(text2, "BlockTriggerDefaultAction", scrollDefaults.BlockTriggerDefaultAction, "Suppress the trigger button's normal Valheim action while scrolling (e.g. stop the D-pad from also moving the hotbar). Defaults true."), BlockModifierDefaultAction = ((BaseUnityPlugin)this).Config.Bind<bool>(text2, "BlockModifierDefaultAction", scrollDefaults.BlockModifierDefaultAction, "Suppress the gate button's normal Valheim action while scrolling. Defaults false.") }; scrollSlots.Add(item2); } for (int k = 1; k <= 12; k++) { ChordDefaults defaults = GetDefaults(k); string text3 = "Chord " + k.ToString("00"); ChordSlot item3 = new ChordSlot { Index = k, Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>(text3, "Enabled", defaults.Enabled, "Enable this controller chord slot."), Modifier = ((BaseUnityPlugin)this).Config.Bind<ControllerButton>(text3, "Modifier", defaults.Modifier, "Held modifier button. Supported modifiers are RB, LB, RT, and LT."), Button = ((BaseUnityPlugin)this).Config.Bind<ControllerButton>(text3, "Button", defaults.Button, "Trigger button that fires on button-down while the modifier is held."), TargetKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>(text3, "TargetKey", defaults.TargetKey, "Keyboard KeyCode exposed virtually to other mods."), BlockModifierDefaultAction = ((BaseUnityPlugin)this).Config.Bind<bool>(text3, "BlockModifierDefaultAction", defaults.BlockModifierDefaultAction, "Temporarily suppress this modifier's ZInput action when the chord fires. Defaults false."), VirtualPressFrames = ((BaseUnityPlugin)this).Config.Bind<int>(text3, "VirtualPressFrames", defaults.VirtualPressFrames, "Number of frames the virtual key remains visible to input queries (tap mode only)."), HoldMode = ((BaseUnityPlugin)this).Config.Bind<bool>(text3, "HoldMode", false, "When true, the target key is held DOWN for as long as you hold the chord (modifier + trigger), and released when you let go. Use this for press-and-hold mods like climbing. When false (default), the chord sends a brief tap suitable for toggle hotkeys.") }; slots.Add(item3); } } private static SingleButtonDefaults GetSingleButtonDefaults(int index) { return index switch { 1 => new SingleButtonDefaults(enabled: true, ControllerButton.LB, (KeyCode)99, holdMode: true, blockButtonDefaultAction: false, 2), 2 => new SingleButtonDefaults(enabled: false, ControllerButton.None, (KeyCode)101, holdMode: false, blockButtonDefaultAction: false, 2), 3 => new SingleButtonDefaults(enabled: false, ControllerButton.None, (KeyCode)103, holdMode: false, blockButtonDefaultAction: false, 2), 4 => new SingleButtonDefaults(enabled: false, ControllerButton.None, (KeyCode)0, holdMode: false, blockButtonDefaultAction: false, 2), 5 => new SingleButtonDefaults(enabled: false, ControllerButton.None, (KeyCode)0, holdMode: false, blockButtonDefaultAction: false, 2), 6 => new SingleButtonDefaults(enabled: false, ControllerButton.None, (KeyCode)0, holdMode: false, blockButtonDefaultAction: false, 2), 7 => new SingleButtonDefaults(enabled: false, ControllerButton.None, (KeyCode)0, holdMode: false, blockButtonDefaultAction: false, 2), 8 => new SingleButtonDefaults(enabled: false, ControllerButton.None, (KeyCode)0, holdMode: false, blockButtonDefaultAction: false, 2), _ => new SingleButtonDefaults(enabled: false, ControllerButton.None, (KeyCode)0, holdMode: false, blockButtonDefaultAction: false, 2), }; } private static ScrollDefaults GetScrollDefaults(int index) { return index switch { 1 => new ScrollDefaults(enabled: true, ControllerButton.LB, ControllerButton.DPadUp, ScrollDirection.In, 1f, 1, ScrollFireMode.OnPress, blockTriggerDefaultAction: true, blockModifierDefaultAction: false), 2 => new ScrollDefaults(enabled: true, ControllerButton.LB, ControllerButton.DPadDown, ScrollDirection.Out, 1f, 1, ScrollFireMode.OnPress, blockTriggerDefaultAction: true, blockModifierDefaultAction: false), 3 => new ScrollDefaults(enabled: false, ControllerButton.None, ControllerButton.None, ScrollDirection.In, 1f, 1, ScrollFireMode.OnPress, blockTriggerDefaultAction: true, blockModifierDefaultAction: false), 4 => new ScrollDefaults(enabled: false, ControllerButton.None, ControllerButton.None, ScrollDirection.In, 1f, 1, ScrollFireMode.OnPress, blockTriggerDefaultAction: true, blockModifierDefaultAction: false), _ => new ScrollDefaults(enabled: false, ControllerButton.None, ControllerButton.None, ScrollDirection.In, 1f, 1, ScrollFireMode.OnPress, blockTriggerDefaultAction: true, blockModifierDefaultAction: false), }; } private static ChordDefaults GetDefaults(int index) { return index switch { 1 => new ChordDefaults(enabled: true, ControllerButton.RB, ControllerButton.A, (KeyCode)306, blockModifierDefaultAction: false, 2), 2 => new ChordDefaults(enabled: false, ControllerButton.RB, ControllerButton.B, (KeyCode)308, blockModifierDefaultAction: false, 2), 3 => new ChordDefaults(enabled: false, ControllerButton.RB, ControllerButton.X, (KeyCode)103, blockModifierDefaultAction: false, 2), 4 => new ChordDefaults(enabled: false, ControllerButton.RB, ControllerButton.Y, (KeyCode)104, blockModifierDefaultAction: false, 2), 5 => new ChordDefaults(enabled: false, ControllerButton.LB, ControllerButton.A, (KeyCode)106, blockModifierDefaultAction: false, 2), 6 => new ChordDefaults(enabled: false, ControllerButton.LB, ControllerButton.B, (KeyCode)107, blockModifierDefaultAction: false, 2), 7 => new ChordDefaults(enabled: false, ControllerButton.LB, ControllerButton.X, (KeyCode)108, blockModifierDefaultAction: false, 2), 8 => new ChordDefaults(enabled: false, ControllerButton.LB, ControllerButton.Y, (KeyCode)59, blockModifierDefaultAction: false, 2), 9 => new ChordDefaults(enabled: false, ControllerButton.RT, ControllerButton.A, (KeyCode)117, blockModifierDefaultAction: false, 2), 10 => new ChordDefaults(enabled: false, ControllerButton.RT, ControllerButton.B, (KeyCode)105, blockModifierDefaultAction: false, 2), 11 => new ChordDefaults(enabled: false, ControllerButton.RT, ControllerButton.X, (KeyCode)111, blockModifierDefaultAction: false, 2), 12 => new ChordDefaults(enabled: false, ControllerButton.RT, ControllerButton.Y, (KeyCode)112, blockModifierDefaultAction: false, 2), _ => new ChordDefaults(enabled: false, ControllerButton.None, ControllerButton.None, (KeyCode)0, blockModifierDefaultAction: false, 2), }; } private void EmitScroll(float amount, ScrollDirection direction, int frames) { float num = Mathf.Abs(amount); if (num <= 0f) { num = 1f; } virtualScrollValue = ((direction == ScrollDirection.Out) ? (0f - num) : num); if (frames < 1) { frames = 1; } else if (frames > 8) { frames = 8; } if (virtualScrollFrames < frames) { virtualScrollFrames = frames; } } private unsafe void FireChord(ChordSlot slot, string modifierName) { //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_0028: Unknown result type (might be due to invalid IL or missing references) int num = slot.VirtualPressFrames.Value; if (num < 1 || num > 8) { num = 2; } KeyCode value = slot.TargetKey.Value; SetMaxFrameCount(virtualKeyFrames, value, num); if (slot.BlockModifierDefaultAction.Value) { string key = ToZInputButtonName(slot.Modifier.Value); SetMaxFrameCount(blockedButtonFrames, key, num); } if (logChordEvents.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Controller Chords: chord " + slot.Index + " (" + modifierName + " + trigger -> " + ((object)(*(KeyCode*)(&value))/*cast due to .constrained prefix*/).ToString() + ") FIRED.")); } chordsFired++; } private void HoldChord(ChordSlot slot, string modifierName) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) if (heldChordActive.Contains(slot.Index)) { SetMaxFrameCount(virtualKeyFrames, slot.TargetKey.Value, 2); return; } heldChordActive.Add(slot.Index); SetMaxFrameCount(virtualKeyFrames, slot.TargetKey.Value, 2); if (slot.BlockModifierDefaultAction.Value) { string key = ToZInputButtonName(slot.Modifier.Value); SetMaxFrameCount(blockedButtonFrames, key, 2); } if (logChordEvents.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Controller Chords: chord " + slot.Index + " (" + modifierName + " + trigger HOLD) ENGAGED.")); } chordsFired++; } private bool IsVirtualKeyActive(KeyCode key) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return virtualKeyFrames.ContainsKey(key); } private bool IsVirtualButtonActive(string buttonName) { return virtualButtonFrames.ContainsKey(buttonName); } private bool IsButtonBlocked(string buttonName) { return blockedButtonFrames.ContainsKey(buttonName); } private bool SafeGetZButton(string buttonName) { if (!zInputReady || string.IsNullOrEmpty(buttonName) || zGetButton == null) { return false; } try { return zGetButton(buttonName); } catch { return false; } } private bool SafeGetZButtonDown(string buttonName) { if (!zInputReady || string.IsNullOrEmpty(buttonName) || zGetButtonDown == null) { return false; } try { return zGetButtonDown(buttonName); } catch { return false; } } private void ResolveZInput() { zInputReady = false; try { zInputType = Type.GetType("ZInput, Assembly-CSharp", throwOnError: false); if (zInputType == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Controller Chords: could not find ZInput type."); return; } MethodInfo method = zInputType.GetMethod("GetButton", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null); MethodInfo method2 = zInputType.GetMethod("GetButtonDown", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null); if (method != null) { zGetButton = (Func<string, bool>)Delegate.CreateDelegate(typeof(Func<string, bool>), method); } if (method2 != null) { zGetButtonDown = (Func<string, bool>)Delegate.CreateDelegate(typeof(Func<string, bool>), method2); } zVirtualKeyboardOpenProperty = zInputType.GetProperty("IsKeyboardOpen", BindingFlags.Static | BindingFlags.Public); if (zGetButton != null && zGetButtonDown != null) { zInputReady = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Controller Chords: ZInput initialized successfully."); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Controller Chords: could not initialize ZInput methods."); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Controller Chords: exception during ZInput resolution: " + ex.Message)); } } private void ResolveMenuGuards() { try { Type type = Type.GetType("GUI, Assembly-CSharp", throwOnError: false); if (type != null) { menuIsVisibleMethod = type.GetMethod("IsVisible", BindingFlags.Static | BindingFlags.Public); } Type type2 = Type.GetType("InventoryGui, Assembly-CSharp", throwOnError: false); if (type2 != null) { inventoryGuiIsVisibleMethod = type2.GetMethod("IsVisible", BindingFlags.Static | BindingFlags.Public); } Type type3 = Type.GetType("StoreGui, Assembly-CSharp", throwOnError: false); if (type3 != null) { storeGuiIsVisibleMethod = type3.GetMethod("IsVisible", BindingFlags.Static | BindingFlags.Public); } Type type4 = Type.GetType("TextInput, Assembly-CSharp", throwOnError: false); if (type4 != null) { textInputIsVisibleMethod = type4.GetMethod("IsVisible", BindingFlags.Static | BindingFlags.Public); } Type type5 = Type.GetType("Console, Assembly-CSharp", throwOnError: false); if (type5 != null) { consoleIsVisibleMethod = type5.GetMethod("IsVisible", BindingFlags.Static | BindingFlags.Public); } } catch { } } private bool IsMenuInputContext() { if (menuIsVisibleMethod != null) { try { if ((bool)menuIsVisibleMethod.Invoke(null, null)) { return true; } } catch { } } if (inventoryGuiIsVisibleMethod != null) { try { if ((bool)inventoryGuiIsVisibleMethod.Invoke(null, null)) { return true; } } catch { } } if (storeGuiIsVisibleMethod != null) { try { if ((bool)storeGuiIsVisibleMethod.Invoke(null, null)) { return true; } } catch { } } if (textInputIsVisibleMethod != null) { try { if ((bool)textInputIsVisibleMethod.Invoke(null, null)) { return true; } } catch { } } if (consoleIsVisibleMethod != null) { try { if ((bool)consoleIsVisibleMethod.Invoke(null, null)) { return true; } } catch { } } if (zVirtualKeyboardOpenProperty != null) { try { if ((bool)zVirtualKeyboardOpenProperty.GetValue(null)) { return true; } } catch { } } return false; } private void InstallPatches() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Expected O, but got Unknown //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Expected O, but got Unknown //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Expected O, but got Unknown //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Expected O, but got Unknown //IL_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Expected O, but got Unknown //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Expected O, but got Unknown if (patchesInstalled) { return; } harmony = new Harmony("marc.valheim.controllerchords"); try { Type type = Type.GetType("UnityEngine.Input, UnityEngine.InputLegacyModule", throwOnError: false); if (type != null) { MethodInfo method = type.GetMethod("GetKey", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(KeyCode) }, null); if (method != null) { harmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(typeof(ControllerChordsPlugin).GetMethod("InputKeyPostfix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } MethodInfo method2 = type.GetMethod("GetAxis", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null); if (method2 != null) { harmony.Patch((MethodBase)method2, (HarmonyMethod)null, new HarmonyMethod(typeof(ControllerChordsPlugin).GetMethod("InputGetAxisPostfix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } MethodInfo method3 = type.GetMethod("GetAxisRaw", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null); if (method3 != null) { harmony.Patch((MethodBase)method3, (HarmonyMethod)null, new HarmonyMethod(typeof(ControllerChordsPlugin).GetMethod("InputGetAxisRawPostfix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } PropertyInfo property = type.GetProperty("mouseScrollDelta", BindingFlags.Static | BindingFlags.Public); if (property != null) { MethodInfo getMethod = property.GetGetMethod(); if (getMethod != null) { harmony.Patch((MethodBase)getMethod, (HarmonyMethod)null, new HarmonyMethod(typeof(ControllerChordsPlugin).GetMethod("InputMouseScrollDeltaPostfix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } } } catch { } try { Type type2 = Type.GetType("ZInput, Assembly-CSharp", throwOnError: false); if (type2 != null) { MethodInfo method4 = type2.GetMethod("GetKey", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(KeyCode) }, null); if (method4 != null) { harmony.Patch((MethodBase)method4, (HarmonyMethod)null, new HarmonyMethod(typeof(ControllerChordsPlugin).GetMethod("ZInputKeyPostfix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } MethodInfo method5 = type2.GetMethod("GetButton", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null); if (method5 != null) { harmony.Patch((MethodBase)method5, (HarmonyMethod)null, new HarmonyMethod(typeof(ControllerChordsPlugin).GetMethod("ZInputButtonPostfix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } MethodInfo method6 = type2.GetMethod("GetMouseScrollWheel", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (method6 != null && method6.ReturnType == typeof(float)) { harmony.Patch((MethodBase)method6, (HarmonyMethod)null, new HarmonyMethod(typeof(ControllerChordsPlugin).GetMethod("ZInputMouseScrollWheelPostfix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } } catch { } patchesInstalled = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Controller Chords: Harmony patches installed."); } private void AgeKeyFrames() { //IL_0037: 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_006a: 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) //IL_0095: 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) if (virtualKeyFrames.Count == 0) { return; } keyScratch.Clear(); foreach (KeyValuePair<KeyCode, int> virtualKeyFrame in virtualKeyFrames) { keyScratch.Add(virtualKeyFrame.Key); } for (int i = 0; i < keyScratch.Count; i++) { KeyCode key = keyScratch[i]; int num = virtualKeyFrames[key] - 1; if (num <= 0) { virtualKeyFrames.Remove(key); } else { virtualKeyFrames[key] = num; } } } private void AgeStringFrames(Dictionary<string, int> framesByName) { if (framesByName.Count == 0) { return; } stringScratch.Clear(); foreach (KeyValuePair<string, int> item in framesByName) { stringScratch.Add(item.Key); } for (int i = 0; i < stringScratch.Count; i++) { string key = stringScratch[i]; int num = framesByName[key] - 1; if (num <= 0) { framesByName.Remove(key); } else { framesByName[key] = num; } } } private void AgeScroll() { if (virtualScrollFrames > 0) { virtualScrollFrames--; if (virtualScrollFrames <= 0) { virtualScrollFrames = 0; virtualScrollValue = 0f; } } } private static void SetMaxFrameCount(Dictionary<KeyCode, int> dictionary, KeyCode key, int frames) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (!dictionary.TryGetValue(key, out var value) || value < frames) { dictionary[key] = frames; } } private static void SetMaxFrameCount(Dictionary<string, int> dictionary, string key, int frames) { if (!string.IsNullOrEmpty(key) && (!dictionary.TryGetValue(key, out var value) || value < frames)) { dictionary[key] = frames; } } private static bool IsSupportedModifier(ControllerButton button) { if (button != ControllerButton.RB && button != ControllerButton.LB && button != ControllerButton.RT) { return button == ControllerButton.LT; } return true; } private static string ToZInputButtonName(ControllerButton button) { return button switch { ControllerButton.A => "JoyButtonA", ControllerButton.B => "JoyButtonB", ControllerButton.X => "JoyButtonX", ControllerButton.Y => "JoyButtonY", ControllerButton.DPadLeft => "JoyDPadLeft", ControllerButton.DPadRight => "JoyDPadRight", ControllerButton.DPadUp => "JoyDPadUp", ControllerButton.DPadDown => "JoyDPadDown", ControllerButton.LB => "JoyLBumper", ControllerButton.RB => "JoyRBumper", ControllerButton.LT => "JoyLTrigger", ControllerButton.RT => "JoyRTrigger", ControllerButton.LeftStick => "JoyLStick", ControllerButton.RightStick => "JoyRStick", ControllerButton.Back => "JoyBack", ControllerButton.Start => "JoyStart", _ => string.Empty, }; } private static void InputKeyPostfix(KeyCode __0, ref bool __result) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) ControllerChordsPlugin instance = Instance; if (!__result && !((Object)(object)instance == (Object)null) && instance.patchesInstalled && instance.IsVirtualKeyActive(__0)) { __result = true; } } private static void ZInputKeyPostfix(KeyCode __0, ref bool __result) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) ControllerChordsPlugin instance = Instance; if (!__result && !((Object)(object)instance == (Object)null) && instance.patchesInstalled && instance.IsVirtualKeyActive(__0)) { __result = true; } } private static void ZInputButtonPostfix(string __0, ref bool __result) { ControllerChordsPlugin instance = Instance; if (!((Object)(object)instance == (Object)null) && instance.patchesInstalled) { if (instance.IsButtonBlocked(__0)) { __result = false; } else if (!__result && instance.IsVirtualButtonActive(__0)) { __result = true; } } } private static void InputGetAxisPostfix(string __0, ref float __result) { ControllerChordsPlugin instance = Instance; if (!((Object)(object)instance == (Object)null) && instance.patchesInstalled && instance.virtualScrollFrames > 0 && string.Equals(__0, "Mouse ScrollWheel", StringComparison.OrdinalIgnoreCase)) { __result += instance.virtualScrollValue; } } private static void InputGetAxisRawPostfix(string __0, ref float __result) { ControllerChordsPlugin instance = Instance; if (!((Object)(object)instance == (Object)null) && instance.patchesInstalled && instance.virtualScrollFrames > 0 && string.Equals(__0, "Mouse ScrollWheel", StringComparison.OrdinalIgnoreCase)) { __result += instance.virtualScrollValue; } } private static void InputMouseScrollDeltaPostfix(ref Vector2 __result) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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) ControllerChordsPlugin instance = Instance; if (!((Object)(object)instance == (Object)null) && instance.patchesInstalled && instance.virtualScrollFrames > 0) { Vector2 val = __result; val.y += ((instance.virtualScrollValue > 0f) ? 1f : (-1f)); __result = val; } } private static void ZInputMouseScrollWheelPostfix(ref float __result) { ControllerChordsPlugin instance = Instance; if (!((Object)(object)instance == (Object)null) && instance.patchesInstalled && instance.virtualScrollFrames > 0) { __result += instance.virtualScrollValue; } } } public enum ControllerButton { None, A, B, X, Y, DPadLeft, DPadRight, DPadUp, DPadDown, LB, RB, LT, RT, LeftStick, RightStick, Back, Start } public enum ScrollDirection { In, Out } public enum ScrollFireMode { OnPress, WhileHeld }