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 System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using JetBrains.Annotations; using Jotunn.Utils; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using Zen; using Zen.Lib; using Zen.Lib.Config; using Zen.Lib.Controls; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ZenUseItem")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ZenUseItem")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [assembly: AssemblyFileVersion("0.0.1.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.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; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ZenUseItem { internal static class Configs { public static readonly ConfigEntry InventoryUseItem; public static readonly ConfigEntry HotbarModifierKey; public static readonly ConfigEntry HideHotbarNumbers; static Configs() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) InventoryUseItem = Config.Define(false, "General", "Inventory - Use Item", new KeyboardShortcut((KeyCode)324, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Press this key combo when pointing at an item in your inventory to use it on the crosshair target.\r\n[Must use Left (Mouse0) or Right (Mouse1) button plus a single modifier key]\r\n[logout required for changes to take effect]"); InventoryUseItem.SettingChanged += delegate { Inputs.SetupButtons(); }; HotbarModifierKey = Config.Define(false, "General", "Hotbar - Modifier Key", (KeyCode)308, "Using items directly from your hotbar on targets via 1-8 keys.\r\nKeyboard: Hold down this key and press the hotbar number.\r\nGamepad: Hold down the Interact-Alt button while pressing up on D-pad.\r\n[Note: If you set this to \"None\" it will revert to vanilla 1-8 hotbar behavior and you will not need to hold a modifier button.\r\nCaution: Without a modifier it's quite easy to attach your hammer to an item stand or launch your sword with a catapult!]"); HideHotbarNumbers = Config.Define(false, "General", "Hotbar - Hide Numbers", true, "Hide the hotbar numbers until the Modifier Key is held down while the player is standing still.\r\n[If the modifier key is \"None\" then this option will simply hide/show the numbers]"); } } [HarmonyPatch] internal static class HotbarUI { private static bool _isShowNumbers; public static void Init() { _isShowNumbers = true; } [HarmonyPostfix] [HarmonyPatch(typeof(InventoryGui), "Hide")] private static void InventoryGui_Hide() { Init(); } [HarmonyPostfix] [HarmonyPatch(typeof(HotkeyBar), "ToggleBindingHint")] private static void HotkeyBar_ToggleBindingHint(bool bShouldEnable) { _isShowNumbers = bShouldEnable; } [HarmonyPostfix] [HarmonyPatch(typeof(HotkeyBar), "Update")] private static void HotkeyBar_Update(HotkeyBar __instance) { UpdateHotbarNumbers(__instance); } private static void UpdateHotbarNumbers(HotkeyBar hotkeyBar) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) if (ZInput.IsGamepadActive()) { return; } if ((int)Configs.HotbarModifierKey.Value == 0) { if (_isShowNumbers != !Configs.HideHotbarNumbers.Value) { hotkeyBar.ToggleBindingHint(!Configs.HideHotbarNumbers.Value); } return; } if (!Configs.HideHotbarNumbers.Value) { if (!_isShowNumbers) { hotkeyBar.ToggleBindingHint(true); } return; } bool flag = Object.op_Implicit((Object)(object)Player.m_localPlayer) && ((Vector3)(ref ((Character)Player.m_localPlayer).m_currentVel)).sqrMagnitude < 1f; bool flag2 = TextInput.IsVisible() || Console.IsVisible() || Chat.instance.IsChatDialogWindowVisible(); bool flag3 = ZInput.GetKey(Configs.HotbarModifierKey.Value, true) && flag && !flag2 && !Minimap.IsOpen(); if (flag3 != _isShowNumbers) { Logging.Info((object)$"Show hotbar numbers: {flag3}", 0); hotkeyBar.ToggleBindingHint(flag3); } } } [HarmonyPatch] internal static class HudHoverText { private static readonly StringBuilder Sb = new StringBuilder(); private static string Pattern(string p) { return StringExt.RegexPattern(p, (Func)((string s) => StringExt.GlyphFix(s, true)), true); } [HarmonyPostfix] [HarmonyPatch(typeof(Hud), "UpdateCrosshair")] private static void Hud_UpdateCrosshair(Hud __instance) { TextMeshProUGUI hoverName = __instance.m_hoverName; if (Object.op_Implicit((Object)(object)hoverName) && !Utility.IsNullOrWhiteSpace(((TMP_Text)hoverName).text)) { Sb.Clear(); ((TMP_Text)hoverName).text = (InventoryGui.IsVisible() ? GetInventoryOpenText(((TMP_Text)hoverName).text) : GetInventoryClosedText(((TMP_Text)hoverName).text)); } } private static string GetInventoryClosedText(string text) { string pattern = "^" + Pattern(UI.PromptInteract) + " *(.+)$"; Match match = Regex.Match(text, pattern, RegexOptions.Multiline); string useItemText = (match.Success ? match.Groups[1].Value : string.Empty); string pattern2 = "^" + Pattern(UI.PromptUseItem) + " *(.+)\n?"; text = Regex.Replace(text, pattern2, delegate(Match m) { string value = m.Groups[1].Value; return (value == useItemText) ? string.Empty : StringExt.GlyphFix(StringExt.Localize(UI.Prompt("$KEY_Inventory") + " " + value + "\n"), true); }, RegexOptions.Multiline); return text; } private static string GetInventoryOpenText(string text) { string[] array = text.Split(new char[1] { '\n' }); string value = StringExt.GlyphFix(StringExt.Localize(UI.PromptInteract), true); string value2 = StringExt.GlyphFix(StringExt.Localize(UI.PromptInteractAlt), true); string oldValue = StringExt.GlyphFix(StringExt.Localize(UI.PromptUseItem), true); string[] array2 = array; foreach (string text2 in array2) { if (!text2.StartsWith(value) && !text2.StartsWith(value2)) { Sb.Append(text2.Replace(oldValue, string.Empty).Trim() + "\n"); } } if (InventoryGui.instance.IsContainerOpen()) { return Sb.ToString(); } if (!((Behaviour)InventoryGui.instance.m_playerGrid).isActiveAndEnabled) { return Sb.ToString(); } InventoryGrid playerGrid = InventoryGui.instance.m_playerGrid; Inventory inventory = playerGrid.GetInventory(); Element val = ((playerGrid.m_uiGroup.IsActive && ZInput.IsGamepadActive()) ? playerGrid.GetElement(playerGrid.m_selected.x, playerGrid.m_selected.y, inventory.GetWidth()) : playerGrid.GetHoveredElement()); if (val == null) { return Sb.ToString(); } ItemData itemAt = inventory.GetItemAt(val.m_pos.x, val.m_pos.y); if (itemAt == null) { return Sb.ToString(); } string prompt = Inputs.GetPrompt(); string text3 = "" + ItemDataExt.GetName(itemAt) + "\n" + prompt + " $settings_apply"; Sb.Append("\n"); Sb.Append(StringExt.Localize(text3)); return Sb.ToString(); } } internal static class Inputs { private static readonly ActionString Hold = ControlInputs.Create((string)null); private static readonly ActionString Main = ControlInputs.Create((string)null); public static bool IsUseItemPressed { get { if (ZInput.GetButton(ActionString.op_Implicit(Main))) { return ZInput.GetButton(ActionString.op_Implicit(Hold)); } return false; } } public static string GetPrompt() { string text = $"$KEY_{Hold} + $KEY_{Main}"; if (!ZInput.IsGamepadActive()) { return UI.Prompt(text); } return text; } public static void SetupButtons() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) Main.RemoveButtons(); Hold.RemoveButtons(); Main.AddButton((GamepadInput)7, false, false, false, 0f, 0f); Hold.AddButton((GamepadInput)17, false, false, false, 0f, 0f); KeyboardShortcut value = Configs.InventoryUseItem.Value; KeyCode mainKey = ((KeyboardShortcut)(ref value)).MainKey; KeyCode[] array = ((KeyboardShortcut)(ref value)).Modifiers.ToArray(); if (((object)(KeyboardShortcut)(ref value)).Equals((object?)KeyboardShortcut.Empty) || array.Length == 0) { KeyboardShortcut val = (KeyboardShortcut)((ConfigEntryBase)Configs.InventoryUseItem).DefaultValue; Logging.Warning((object)$"Not a valid shortcut {value}. Using default instead: {val}", 0); mainKey = ((KeyboardShortcut)(ref val)).MainKey; array = ((KeyboardShortcut)(ref val)).Modifiers.ToArray(); } Main.AddButton(mainKey, false, false, false, 0f, 0f); Hold.AddButton(array[0], false, false, false, 0f, 0f); } } [BepInPlugin("ZenDragon.ZenUseItem", "ZenUseItem", "1.1.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [SynchronizationMode(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class Plugin : ZenMod { public const string PluginName = "ZenUseItem"; public const string PluginVersion = "1.1.1"; public const string PluginGUID = "ZenDragon.ZenUseItem"; protected override void Setup() { base.RegisterInputs += Inputs.SetupButtons; } protected override void TitleScene(bool isFirstBoot) { } protected override void WorldStart() { HotbarUI.Init(); } protected override void Shutdown() { } protected override HelpInfo? GetHelpInfo() { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(HelpInfo.Format("How It Works", "- Put your cursor on the object that you want to apply an item to.\r\n- Open your inventory.\r\n- Point at the item in your inventory\r\n- Press the controls indicated in the center of the screen.", (string)null, false, false)); Inputs.GetPrompt(); stringBuilder.AppendLine(HelpInfo.Format(Configs.InventoryUseItem, true, true, true)); stringBuilder.AppendLine(HelpInfo.Format(Configs.HotbarModifierKey, true, true, false)); if (Configs.HideHotbarNumbers.Value) { stringBuilder.AppendLine(HelpInfo.Format(Configs.HideHotbarNumbers, false, true, true)); } return new HelpInfo("Use Item", stringBuilder.ToString()); } } [HarmonyPatch] internal static class UseItem { [HarmonyPatch(typeof(Player), "UseHotbarItem")] private static class PlayerUseHotbarItem { [UsedImplicitly] private static void Prefix() { _isUsedFromHotbar = true; } [UsedImplicitly] private static void Postfix() { _isUsedFromHotbar = false; } } private static bool _isUsedFromHotbar; private static bool _isItemUsedOnTarget; private static bool IsHoverTargetInteractable { get { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return Object.op_Implicit((Object)(object)HumanoidExt.GetHoverInteractable((Humanoid)(object)Player.m_localPlayer)); } return false; } } [HarmonyPrefix] [HarmonyPatch(typeof(Humanoid), "UseItem")] private static void Humanoid_UseItem_Prefix(Humanoid __instance, Inventory inventory, ItemData item, ref bool fromInventoryGui) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) if (_isUsedFromHotbar) { if ((int)Configs.HotbarModifierKey.Value == 0) { fromInventoryGui = false; } else if (ZInput.IsGamepadActive()) { fromInventoryGui = !ZInput.GetButton(ControlInputs.JoyAlt); } else { fromInventoryGui = !ZInput.GetKey(Configs.HotbarModifierKey.Value, true); } } } [HarmonyPrefix] [HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")] private static void InventoryGui_OnSelectedItem(InventoryGui __instance, InventoryGrid grid, ItemData item, ref bool __runOriginal) { if (TryUseItemOnTarget(__instance, grid, item)) { __runOriginal = false; } } [HarmonyPrefix] [HarmonyPatch(typeof(InventoryGui), "OnRightClickItem")] private static void InventoryGui_OnRightClickItem(InventoryGui __instance, InventoryGrid grid, ItemData item, ref bool __runOriginal) { if (TryUseItemOnTarget(__instance, grid, item)) { __runOriginal = false; } } private static bool TryUseItemOnTarget(InventoryGui gui, InventoryGrid grid, ItemData item) { if (!Inputs.IsUseItemPressed) { return false; } if (gui.IsContainerOpen()) { return false; } if (!IsHoverTargetInteractable) { return false; } _isItemUsedOnTarget = true; ((Humanoid)Player.m_localPlayer).UseItem(grid.GetInventory(), item, false); _isItemUsedOnTarget = false; return true; } [HarmonyTranspiler] [HarmonyPatch(typeof(Humanoid), "UseItem")] [HarmonyPriority(100)] private static IEnumerable Humanoid_UseItem_Transpile(IEnumerable codes) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Expected O, but got Unknown Func func = ConsumableTypeIntercept; CodeMatch[] array = (CodeMatch[])(object)new CodeMatch[5] { new CodeMatch((OpCode?)OpCodes.Ldarg_2, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)AccessTools.DeclaredField(typeof(ItemData), "m_shared"), (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)AccessTools.DeclaredField(typeof(SharedData), "m_itemType"), (string)null), new CodeMatch((OpCode?)OpCodes.Ldc_I4_2, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Bne_Un, (object)null, (string)null) }; MethodInfo methodInfo = AccessTools.Method(typeof(Humanoid), "ToggleEquipped", (Type[])null, (Type[])null); Func func2 = ToggleEquippedIntercept; return Transpilers.MethodReplacer(new CodeMatcher(codes, (ILGenerator)null).MatchEndForward(array).ThrowIfInvalid("Unable to match IL").Advance(-1) .SetInstruction(new CodeInstruction(OpCodes.Call, (object)func.Method)) .InstructionEnumeration(), (MethodBase)methodInfo, (MethodBase)func2.Method); static ItemType ConsumableTypeIntercept() { if (_isItemUsedOnTarget) { return (ItemType)(-1); } return (ItemType)2; } static bool ToggleEquippedIntercept(Humanoid self, ItemData item) { if (!_isItemUsedOnTarget) { return self.ToggleEquipped(item); } return false; } } [HarmonyTranspiler] [HarmonyPatch(typeof(HotkeyBar), "Update")] private static IEnumerable HotkeyBar_Update(IEnumerable codes) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown CodeMatch[] array = (CodeMatch[])(object)new CodeMatch[3] { new CodeMatch((OpCode?)OpCodes.Ldstr, (object)"JoyAltKeys", (string)null), new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.DeclaredMethod(typeof(ZInput), "GetButton", (Type[])null, (Type[])null), (string)null), new CodeMatch((OpCode?)OpCodes.Brtrue, (object)null, (string)null) }; Func func = AdjustBehavior; return new CodeMatcher(codes, (ILGenerator)null).End().MatchEndBackwards(array).ThrowIfInvalid("Unable to match IL") .Insert((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Call, (object)func.Method) }) .InstructionEnumeration(); static bool AdjustBehavior(bool orig) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if ((int)Configs.HotbarModifierKey.Value == 0) { return orig; } return false; } } } }