diff --git a/AdventureBackpacks/AdventureBackpacks.cs b/AdventureBackpacks/AdventureBackpacks.cs index 1293085..4cd439a 100644 --- a/AdventureBackpacks/AdventureBackpacks.cs +++ b/AdventureBackpacks/AdventureBackpacks.cs @@ -28,7 +28,7 @@ public class AdventureBackpacks : BaseUnityPlugin, IPluginInfo //Module Constants private const string _pluginId = "vapok.mods.adventurebackpacks"; private const string _displayName = "Adventure Backpacks"; - private const string _version = "1.6.14"; + private const string _version = "1.6.15"; //Interface Properties public string PluginId => _pluginId; diff --git a/AdventureBackpacks/Assets/Backpacks.cs b/AdventureBackpacks/Assets/Backpacks.cs index 077ff7f..1d5b27b 100644 --- a/AdventureBackpacks/Assets/Backpacks.cs +++ b/AdventureBackpacks/Assets/Backpacks.cs @@ -54,6 +54,9 @@ public static void UpdateItemDataConfigValues(object sender, EventArgs e) if (Player.m_localPlayer == null || Player.m_localPlayer.GetInventory() == null) return; + //Close Inventory before making changes. Leaving open can have undesirable effects. + InventoryGui.instance.Hide(); + void SearchInventory(List inventory) { if (inventory == null) diff --git a/AdventureBackpacks/Patches/InventoryGui.cs b/AdventureBackpacks/Patches/InventoryGui.cs index 075d806..7dc3ef7 100644 --- a/AdventureBackpacks/Patches/InventoryGui.cs +++ b/AdventureBackpacks/Patches/InventoryGui.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Reflection.Emit; using AdventureBackpacks.Assets; -using AdventureBackpacks.Assets.Factories; using AdventureBackpacks.Components; using AdventureBackpacks.Configuration; using AdventureBackpacks.Extensions; @@ -18,11 +17,12 @@ internal static class InventoryGuiPatches { public static bool BackpackIsOpen; public static bool BackpackEquipped = false; - private static bool _showBackpack = false; + private static bool _showBackpack ; [HarmonyPatch(typeof(InventoryGui), nameof(InventoryGui.DoCrafting))] static class InventoryGuiDoCraftingPrefix { + [UsedImplicitly] static void Postfix(InventoryGui __instance) { if (__instance.m_craftUpgradeItem != null && __instance.m_craftUpgradeItem.IsBackpack()) @@ -37,6 +37,7 @@ static void Postfix(InventoryGui __instance) [HarmonyPatch(typeof(InventoryGui), nameof(InventoryGui.OnSelectedItem))] static class InventoryGuiOnSelectedItem { + [UsedImplicitly] static Exception Finalizer(Exception __exception, InventoryGrid grid, ItemDrop.ItemData item, Vector2i pos, InventoryGrid.Modifier mod, InventoryGui __instance) { @@ -75,7 +76,7 @@ public static bool CheckForTextInput() if (textInputPanel != null) { - if (textInputPanel.activeSelf) + if (textInputPanel.activeInHierarchy) textInputVisible = true; } @@ -84,8 +85,19 @@ public static bool CheckForTextInput() public static void ShowBackpack(Player player, InventoryGui instance) { + if (ConfigRegistry.OpenWithInventory.Value && !BackpackIsOpen && player.CanOpenBackpack()) + { + _showBackpack = true; + } + if (_showBackpack) { + if (!BackpackIsOpen && instance.m_currentContainer != null) + { + instance.m_currentContainer.SetInUse(false); + instance.m_currentContainer = null; + } + _showBackpack = false; player.OpenBackpack(instance); } @@ -98,36 +110,53 @@ public static void HideBackpack(InventoryGui instance) instance.CloseContainer(); BackpackIsOpen = false; - if (ConfigRegistry.CloseInventory.Value) + if (ConfigRegistry.CloseInventory.Value && !ConfigRegistry.OpenWithHoverInteract.Value) instance.Hide(); } } - public static bool DetectInputToHide(KeyCode defaultKeyCode, Player player, InventoryGui instance) + public static bool DetectInputToHide(Player player, InventoryGui instance) { - var defaultInputDown = Input.GetKeyDown(defaultKeyCode); - var hotKeyDown = ConfigRegistry.HotKeyOpen.Value.IsDown(); - var hotKeyDownOnClose = ConfigRegistry.CloseInventory.Value && hotKeyDown; - var hotKeyDrop = ConfigRegistry.OutwardMode.Value && ConfigRegistry.HotKeyDrop.Value.IsDown(); + var hotKeyDown = ZInput.GetKeyDown(ConfigRegistry.HotKeyOpen.Value.MainKey); + var hotKeyDownOnClose = ConfigRegistry.CloseInventory.Value && hotKeyDown && !ConfigRegistry.OpenWithHoverInteract.Value; + var hotKeyDrop = ConfigRegistry.OutwardMode.Value && ZInput.GetKeyDown(ConfigRegistry.HotKeyDrop.Value.MainKey); var openBackpack = hotKeyDown && !BackpackIsOpen && player.CanOpenBackpack() && !ConfigRegistry.OpenWithHoverInteract.Value; + + var grids = new List(); + grids.AddRange(instance.m_player.GetComponentsInChildren()); - if (hotKeyDown && ConfigRegistry.OpenWithHoverInteract.Value) + if (hotKeyDown && !BackpackIsOpen && ConfigRegistry.OpenWithHoverInteract.Value && !CheckForTextInput()) { - var hoveredElement = instance.m_playerGrid.GetHoveredElement(); + ItemDrop.ItemData hoveredItem = null; + + foreach (var grid in grids) + { + if (grid.GetHoveredElement() == null) + continue; + + var hoveredElement = grid.GetHoveredElement(); + hoveredItem = grid.GetInventory().GetItemAt(hoveredElement.m_pos.x, hoveredElement.m_pos.y); + } - if (hoveredElement != null) + if (ZInput.IsGamepadActive() && hoveredItem == null) { - var hoveredItem = player.GetInventory().GetItemAt(hoveredElement.m_pos.x, hoveredElement.m_pos.y); - if (hoveredItem != null && hoveredItem.IsBackpack() && hoveredItem.m_equiped && !BackpackIsOpen && - player.CanOpenBackpack()) + foreach (var grid in grids) { - openBackpack = true; + if (grid.GetGamepadSelectedItem() == null) + continue; + hoveredItem = grid.GetGamepadSelectedItem(); } } + + if (hoveredItem != null && hoveredItem.IsBackpack() && hoveredItem.m_equiped && !BackpackIsOpen && + player.CanOpenBackpack()) + { + openBackpack = true; + } } - if (openBackpack) + if (openBackpack & !CheckForTextInput()) { if (instance.m_currentContainer != null) { @@ -138,55 +167,82 @@ public static bool DetectInputToHide(KeyCode defaultKeyCode, Player player, Inve return false; } - if (hotKeyDown && BackpackIsOpen && (!hotKeyDownOnClose || ConfigRegistry.OpenWithHoverInteract.Value)) + if (hotKeyDown && BackpackIsOpen && (!hotKeyDownOnClose || ConfigRegistry.OpenWithHoverInteract.Value) && !CheckForTextInput()) { - instance.CloseContainer(); - BackpackIsOpen = false; - return false; + bool closeBackpack = false; + + if (ConfigRegistry.OpenWithHoverInteract.Value) + { + ItemDrop.ItemData hoveredItem = null; + + foreach (var grid in grids) + { + if (grid.GetHoveredElement() == null) + continue; + + var hoveredElement = grid.GetHoveredElement(); + hoveredItem = grid.GetInventory().GetItemAt(hoveredElement.m_pos.x, hoveredElement.m_pos.y); + } + + if (ZInput.IsGamepadActive() && hoveredItem == null) + { + foreach (var grid in grids) + { + if (grid.GetGamepadSelectedItem() == null) + continue; + hoveredItem = grid.GetGamepadSelectedItem(); + } + } + + if (hoveredItem != null && hoveredItem.IsBackpack() && hoveredItem.m_equiped && BackpackIsOpen) + { + closeBackpack = true; + } + } + else + { + closeBackpack = true; + } + + if (closeBackpack) + { + instance.CloseContainer(); + BackpackIsOpen = false; + return false; + } } - if (hotKeyDrop) + if (hotKeyDrop && !CheckForTextInput()) { player.QuickDropBackpack(); } - return defaultInputDown || (hotKeyDownOnClose && !ConfigRegistry.OpenWithHoverInteract.Value) || hotKeyDrop; + return ((hotKeyDownOnClose) || hotKeyDrop) && !CheckForTextInput(); } - public static bool DetectInputToShow(string defaultKeyCode, Player player, InventoryGui instance) + public static bool DetectInputToShow(Player player, InventoryGui instance) { - var zInputDown = ZInput.GetButtonDown(defaultKeyCode); - var hotKeyDown = ConfigRegistry.HotKeyOpen.Value.IsDown(); - var hotKeyDrop = ConfigRegistry.OutwardMode.Value && ConfigRegistry.HotKeyDrop.Value.IsDown(); + var hotKeyDown = ZInput.GetKeyDown(ConfigRegistry.HotKeyOpen.Value.MainKey); + var hotKeyDrop = ConfigRegistry.OutwardMode.Value && ZInput.GetKeyDown(ConfigRegistry.HotKeyDrop.Value.MainKey); - if (hotKeyDrop) + if (hotKeyDrop && !CheckForTextInput()) { player.QuickDropBackpack(); } - if (hotKeyDown && !BackpackIsOpen && player.CanOpenBackpack() && !ConfigRegistry.OpenWithHoverInteract.Value) + if (hotKeyDown && !ConfigRegistry.OpenWithHoverInteract.Value && !BackpackIsOpen && player.CanOpenBackpack() && !CheckForTextInput()) { _showBackpack = true; } - if (zInputDown && ConfigRegistry.OpenWithInventory.Value && !ConfigRegistry.OpenWithHoverInteract.Value && !BackpackIsOpen && player.CanOpenBackpack()) - { - _showBackpack = true; - } - - if (_showBackpack && !BackpackIsOpen && instance.m_currentContainer != null) - { - instance.m_currentContainer.SetInUse(false); - instance.m_currentContainer = null; - } - - return (zInputDown || (hotKeyDown && !ConfigRegistry.OpenWithHoverInteract.Value) || _showBackpack) && !CheckForTextInput(); + return _showBackpack && !CheckForTextInput(); } [HarmonyPatch(typeof(InventoryGui), nameof(InventoryGui.Update))] static class InventoryGuiUpdateTranspiler { - public static IEnumerable Transpiler(IEnumerable instructions) + [UsedImplicitly] + public static IEnumerable Transpiler(IEnumerable instructions, ILGenerator ilGenerator) { var instrs = instructions.ToList(); @@ -197,6 +253,17 @@ CodeInstruction LogMessage(CodeInstruction instruction) AdventureBackpacks.Log.Debug($"IL_{counter}: Opcode: {instruction.opcode} Operand: {instruction.operand}"); return instruction; } + + CodeInstruction FindInstructionWithLabel(List codeInstructions, int index, Label label) + { + if (index >= codeInstructions.Count) + return null; + + if (codeInstructions[index].labels.Contains(label)) + return codeInstructions[index]; + + return FindInstructionWithLabel(codeInstructions, index + 1, label); + } var resetButtonStatus = AccessTools.DeclaredMethod(typeof(ZInput), nameof(ZInput.ResetButtonStatus)); var menuVisibleMethod = AccessTools.DeclaredMethod(typeof(Menu), nameof(Menu.IsVisible)); @@ -256,48 +323,98 @@ CodeInstruction LogMessage(CodeInstruction instruction) counter++; } else if (i > 6 && instrs[i].opcode == OpCodes.Call && instrs[i].operand.Equals(inputKeyDown) && instrs[i - 1].operand.Equals((sbyte)KeyCode.Escape) && instrs[i + 2].opcode == OpCodes.Ldstr && instrs[i + 2].operand.Equals("Use")) { - //Add Inventory Open Key from Config - //Get Player - var ldLocInstruction = new CodeInstruction(OpCodes.Ldloc_1); - //Move Any Labels from the instruction position being patched to new instruction. - if (instrs[i].labels.Count > 0) - instrs[i].MoveLabelsTo(ldLocInstruction); - //Patch Call Method for Detecting Key Press - yield return LogMessage(ldLocInstruction); + //1. Output current spot. + yield return LogMessage(instrs[i]); counter++; - //InventoryGui Argument. - yield return LogMessage(new CodeInstruction(OpCodes.Ldarg_0)); + //2. Output i + 1 (this is the brtrue). + yield return LogMessage(instrs[i + 1]); counter++; - //Patch Call Method for Detect Hide. + //3. Grab label from brtrue. + Label originalLabel = (Label)instrs[i + 1].operand; + + //4. Look ahead and find instruction with label. + var instWithLabel = FindInstructionWithLabel(instrs, i + 2, originalLabel); + + if (instWithLabel == null) + { + AdventureBackpacks.Log.Error($"Can't Find Instruction with Label {originalLabel}"); + continue; + } + + i++; + + //5. Generate new label. + var detectHideLabel = ilGenerator.DefineLabel(); + + //6. Save Label to instruction ahead. + instWithLabel.labels.Add(detectHideLabel); + + //7. Write Player Var + yield return LogMessage(new CodeInstruction(OpCodes.Ldloc_1)); + counter++; + + //8. Write LdArg Var + yield return LogMessage(new CodeInstruction(OpCodes.Ldarg_0)); + counter++; + + //9. Write Call instruction yield return LogMessage(new CodeInstruction(OpCodes.Call, AccessTools.DeclaredMethod(typeof(InventoryGuiPatches), nameof(DetectInputToHide)))); counter++; + //10. Write Brture instruction with new label + yield return LogMessage(new CodeInstruction(OpCodes.Brtrue, detectHideLabel)); + counter++; + } else if (i > 6 && instrs[i].opcode == OpCodes.Call && instrs[i].operand.Equals(zInputButtonDown) && instrs[i - 1].operand.Equals("Inventory") && instrs[i + 1].opcode == OpCodes.Brtrue && instrs[i + 2].opcode == OpCodes.Ldstr && instrs[i + 2].operand.Equals("JoyButtonY")) { + //1. Output current spot. + yield return LogMessage(instrs[i]); + counter++; - //Add Inventory Open Key from Config - //Get Player - var ldLocInstruction = new CodeInstruction(OpCodes.Ldloc_1); - //Move Any Labels from the instruction position being patched to new instruction. - if (instrs[i].labels.Count > 0) - instrs[i].MoveLabelsTo(ldLocInstruction); - - //Patch Call Method for Detecting Key Press - yield return LogMessage(ldLocInstruction); + //2. Output i + 1 (this is the brtrue). + yield return LogMessage(instrs[i + 1]); counter++; - //InventoryGui Argument. + //3. Grab label from brtrue. + Label originalLabel = (Label)instrs[i + 1].operand; + + //4. Look ahead and find instruction with label. + var instWithLabel = FindInstructionWithLabel(instrs, i + 2, originalLabel); + + if (instWithLabel == null) + { + AdventureBackpacks.Log.Error($"Can't Find Instruction with Label {originalLabel}"); + continue; + } + + i++; + + //5. Generate new label. + var detectShowLabel = ilGenerator.DefineLabel(); + + //6. Save Label to instruction ahead. + instWithLabel.labels.Add(detectShowLabel); + + //7. Write Player Var + yield return LogMessage(new CodeInstruction(OpCodes.Ldloc_1)); + counter++; + + //8. Write LdArg Var yield return LogMessage(new CodeInstruction(OpCodes.Ldarg_0)); counter++; - //Patch Call Method for Detect Show. + //9. Write Call instruction yield return LogMessage(new CodeInstruction(OpCodes.Call, AccessTools.DeclaredMethod(typeof(InventoryGuiPatches), nameof(DetectInputToShow)))); counter++; + + //10. Write Brture instruction with new label + yield return LogMessage(new CodeInstruction(OpCodes.Brtrue, detectShowLabel)); + counter++; } else { diff --git a/AdventureBackpacks/Patches/ItemDrop.cs b/AdventureBackpacks/Patches/ItemDrop.cs index 6016829..f2e463e 100644 --- a/AdventureBackpacks/Patches/ItemDrop.cs +++ b/AdventureBackpacks/Patches/ItemDrop.cs @@ -1,4 +1,6 @@ -using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Emit; using AdventureBackpacks.Assets; using AdventureBackpacks.Components; using HarmonyLib; @@ -9,35 +11,82 @@ namespace AdventureBackpacks.Patches; public class ItemDropPatches { [HarmonyPatch(typeof(ItemDrop.ItemData), nameof(ItemDrop.ItemData.GetWeight))] - [HarmonyBefore(new string[]{"randyknapp.mods.epicloot"})] - static class GetWeightPatch + static class ItemDataGetWeightTranspiler { - static void Postfix(ItemDrop.ItemData __instance, ref float __result) + public static float OverrideBackpackWeight(ItemDrop.ItemData item, float originalWeight) { - if (__instance == null || __instance.m_shared == null) - return; - - try + var returnedWeight = originalWeight; + + if (!string.IsNullOrEmpty(item.m_shared.m_name) && item.TryGetBackpackItem(out var backpack)) { - if (string.IsNullOrEmpty(__instance.m_shared.m_name)) - return; + + // If the item in GetWeight() is a backpack, call GetTotalWeight() on its Inventory. + // Note that GetTotalWeight() just returns a the value of m_totalWeight, and doesn't do any calculation on its own. + // If the Inventory has been changed at any point, it calls UpdateTotalWeight(), which should ensure that its m_totalWeight is accurate. + var inventoryWeight = item.Data().GetOrCreate().GetInventory()?.GetTotalWeight() ?? 0; + + // To the backpack's item weight, add the backpack's inventory weight multiplied by the weightMultiplier in the configs. + returnedWeight += inventoryWeight * backpack.WeightMultiplier.Value; + } + + return returnedWeight; + } + + public static IEnumerable Transpiler(IEnumerable instructions) + { + var instrs = instructions.ToList(); + + var counter = 0; + + CodeInstruction LogMessage(CodeInstruction instruction) + { + AdventureBackpacks.Log.Debug($"IL_{counter}: Opcode: {instruction.opcode} Operand: {instruction.operand}"); + return instruction; + } - if (__instance.TryGetBackpackItem(out var backpack)) + var scaleWeightByQualityField = AccessTools.DeclaredField(typeof(ItemDrop.ItemData.SharedData),"m_scaleWeightByQuality"); + + for (int i = 0; i < instrs.Count; ++i) + { + if (i > 6 && instrs[i].opcode == OpCodes.Ldloc_0 && instrs[i-1].opcode == OpCodes.Stloc_0 && instrs[i-2].opcode == OpCodes.Add && + instrs[i - 3].opcode == OpCodes.Mul && instrs[i - 4].opcode == OpCodes.Ldfld && + instrs[i - 4].operand.Equals(scaleWeightByQualityField)) { + //Call to Hide Backpack + var ldArgInstruction = new CodeInstruction(OpCodes.Ldarg_0); + //Move Any Labels from the instruction position being patched to new instruction. + if (instrs[i].labels.Count > 0) + instrs[i].MoveLabelsTo(ldArgInstruction); + + //Insert new instructions first. + + //Patch ldarg_0 this is instance of ItemData. + yield return LogMessage(ldArgInstruction); + counter++; - // If the item in GetWeight() is a backpack, call GetTotalWeight() on its Inventory. - // Note that GetTotalWeight() just returns a the value of m_totalWeight, and doesn't do any calculation on its own. - // If the Inventory has been changed at any point, it calls UpdateTotalWeight(), which should ensure that its m_totalWeight is accurate. - var inventoryWeight = __instance.Data().GetOrCreate().GetInventory()?.GetTotalWeight() ?? 0; + //Get Weight which is ldloc0 + yield return LogMessage(new CodeInstruction(OpCodes.Ldloc_0)); + counter++; - // To the backpack's item weight, add the backpack's inventory weight multiplied by the weightMultiplier in the configs. - __result += inventoryWeight * backpack.WeightMultiplier.Value; + //Patch Call Method for Overriding the Weight. + yield return LogMessage(new CodeInstruction(OpCodes.Call, AccessTools.DeclaredMethod(typeof(ItemDataGetWeightTranspiler), nameof(OverrideBackpackWeight)))); + counter++; + + //Set Weight which is stloc0 + yield return LogMessage(new CodeInstruction(OpCodes.Stloc_0)); + counter++; + + //Output current Operation + yield return LogMessage(instrs[i]); + counter++; + } + else + { + yield return LogMessage(instrs[i]); + counter++; } } - catch (Exception e) - { - AdventureBackpacks.Log.Debug($"[ItemDrop.ItemData.GetWeight] An Error occurred - {e.Message}"); - } } } + } \ No newline at end of file diff --git a/AdventureBackpacks/Properties/AssemblyInfo.cs b/AdventureBackpacks/Properties/AssemblyInfo.cs index 6961bb4..ed4ad02 100644 --- a/AdventureBackpacks/Properties/AssemblyInfo.cs +++ b/AdventureBackpacks/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.6.14.0")] -[assembly: AssemblyFileVersion("1.6.14.0")] \ No newline at end of file +[assembly: AssemblyVersion("1.6.15.0")] +[assembly: AssemblyFileVersion("1.6.15.0")] \ No newline at end of file diff --git a/PATCHNOTES.md b/PATCHNOTES.md index c9545c6..0b30fa5 100644 --- a/PATCHNOTES.md +++ b/PATCHNOTES.md @@ -1,5 +1,13 @@ # Adventure Backpacks Patchnotes +# 1.6.15.0 - Controller Support!!!, also some bug fixes. +* Fully Implemented Controller/Gamepad Support. + * Set bindings in configuration for opening up the backpack and other settings. +* Rebuilt the mechanism for calculating backpack weight. Now uses transpiler. +* Addition Sign and Tame Rename Interaction Fixes +* Open Backpack With Hover now fully works on extended inventory and quick slot grids. +* Open with Inventory now work with Open/Close Backpack with Hover. + # 1.6.14.0 - Fixing Equippable Items, Adding Hover Over Interaction option, Fixing Signs. * New Feature: Open Inventory with Hover Interaction * When enabled, this will override the Open with Inventory and Close Inventory Options. diff --git a/README.md b/README.md index 02d0a08..007746a 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ learn how to make your very own, Adventure Backpacks! Go forth and wander, ye w * The default hotkey is `I` to open the equipped backpack. * Each backpack is completely different in form, function, and size. Upgrading backpacks will unlock additional features depending on the progresion that backpack is intended to be used with. * Check the Configuration for ALL the different ways that you can modify these packs. +* Keybindings and Actions are Controller Supported ## How To Install Adventure Backpacks * Install Adventure Backpacks into it's own FOLDER inside of the `BepInEx/plugins` folder. @@ -55,8 +56,7 @@ learn how to make your very own, Adventure Backpacks! Go forth and wander, ye w * Can also set Mouse, Keyboard, and Gamepad bindings. * Configure Opening of Backpack with Hover + Interaction * When enabled, will open backpack when hovered over in Player Inventory and the Open Hot Key is pressed. - * This feature overrides Open with Inventory and Close with Inventory. - * This feature will only work when backpack is in player inventory, and NOT in Extended Inventory windows. + * This feature overrides Close with Inventory. * Backpack Inventory Protection Guard * Every backpack inventory is specially handled by Thor himself and is monitored for any interactions that might otherwise harm the existence of items in your backpacks. * Backpacks in Backpacks is not allowed and the only feature that is not configurable. This is how the Allfather dreamt of it. diff --git a/manifest.json b/manifest.json index 07179d6..b87b110 100644 --- a/manifest.json +++ b/manifest.json @@ -1,6 +1,6 @@ { "name": "AdventureBackpacks", - "version_number": "1.6.14", + "version_number": "1.6.15", "website_url": "https://github.com/Vapok/AdventureBackpacks", "description": "A Valheim Mod to add a catalogue of Adventuring Backpacks to the Game. These packs will grow and become more useful as the game progresses.", "dependencies": [