From dc6b879d5855180d7cee24a1b295fec85d16b292 Mon Sep 17 00:00:00 2001 From: Tyfon <29051038+tyfon7@users.noreply.github.com> Date: Thu, 20 Jun 2024 02:05:40 -0700 Subject: [PATCH] unpack keybind; multi equip, unequip, unload ammo --- MultiSelect.cs | 78 ++++++++++++++++++ Patches/ContextMenuPatches.cs | 31 ++++++- Patches/ContextMenuShortcutPatches.cs | 6 ++ Patches/MultiSelectPatches.cs | 112 +++++++++++++------------- Settings.cs | 10 +++ 5 files changed, 178 insertions(+), 59 deletions(-) diff --git a/MultiSelect.cs b/MultiSelect.cs index 55148ef..f6e5bca 100644 --- a/MultiSelect.cs +++ b/MultiSelect.cs @@ -175,6 +175,22 @@ namespace UIFixes get { return SelectedItems.Count > 0; } } + // Sort the items to prioritize the items that share a grid with the dragged item, prepend the dragContext as the first one + // Can pass no itemContext, and it just sorts items by their grid order + public static IEnumerable SortedItemContexts(ItemContextClass first = null, bool prepend = true) + { + static int gridOrder(LocationInGrid loc, StashGridClass grid) => grid.GridWidth.Value * loc.y + loc.x; + + var result = ItemContexts + .Where(ic => first == null || ic.Item != first.Item) + .OrderByDescending(ic => ic.ItemAddress is GClass2769) + .ThenByDescending(ic => first != null && first.ItemAddress is GClass2769 originalDraggedAddress && ic.ItemAddress is GClass2769 selectedGridAddress && selectedGridAddress.Grid == originalDraggedAddress.Grid) + .ThenByDescending(ic => ic.ItemAddress is GClass2769 selectedGridAddress ? selectedGridAddress.Grid.Id : null) + .ThenBy(ic => ic.ItemAddress is GClass2769 selectedGridAddress ? gridOrder(selectedGridAddress.LocationInGrid, selectedGridAddress.Grid) : 0); + + return first != null && prepend ? result.Prepend(first) : result; + } + public static void ShowDragCount(DraggedItemView draggedItemView) { if (draggedItemView != null && Count > 1) @@ -196,6 +212,68 @@ namespace UIFixes } } + public static int InteractionCount(EItemInfoButton interaction, ItemUiContext itemUiContext) + { + int count = 0; + foreach (ItemContextClass selectedItemContext in SortedItemContexts()) + { + ItemContextAbstractClass innerContext = selectedItemContext.GClass2813_0; + if (innerContext == null) + { + continue; + } + + var contextInteractions = itemUiContext.GetItemContextInteractions(innerContext, null); + if (!contextInteractions.IsInteractionAvailable(interaction)) + { + continue; + } + + ++count; + } + + return count; + } + + public static void EquipAll(ItemUiContext itemUiContext, bool allOrNothing) + { + if (!allOrNothing || InteractionCount(EItemInfoButton.Equip, itemUiContext) == Count) + { + foreach (ItemContextClass selectedItemContext in SortedItemContexts()) + { + itemUiContext.QuickEquip(selectedItemContext.Item).HandleExceptions(); + } + + itemUiContext.Tooltip?.Close(); + } + } + + public static void UnequipAll(ItemUiContext itemUiContext, bool allOrNothing) + { + if (!allOrNothing || InteractionCount(EItemInfoButton.Unequip, itemUiContext) == Count) + { + foreach (ItemContextClass selectedItemContext in SortedItemContexts()) + { + itemUiContext.Uninstall(selectedItemContext.GClass2813_0).HandleExceptions(); + } + + itemUiContext.Tooltip?.Close(); + } + } + + public static void UnloadAmmoAll(ItemUiContext itemUiContext, bool allOrNothing) + { + if (!allOrNothing || InteractionCount(EItemInfoButton.UnloadAmmo, itemUiContext) == Count) + { + foreach (ItemContextClass selectedItemContext in SortedItemContexts()) + { + itemUiContext.UnloadAmmo(selectedItemContext.Item).HandleExceptions(); + } + + itemUiContext.Tooltip?.Close(); + } + } + private static void ShowSelection(GridItemView itemView) { GameObject selectedMark = itemView.transform.Find("SelectedMark")?.gameObject; diff --git a/Patches/ContextMenuPatches.cs b/Patches/ContextMenuPatches.cs index 98cda70..85b1c73 100644 --- a/Patches/ContextMenuPatches.cs +++ b/Patches/ContextMenuPatches.cs @@ -88,7 +88,12 @@ namespace UIFixes [PatchPostfix] public static void Postfix(string caption, TextMeshProUGUI ____text) { - if (caption == EItemInfoButton.Insure.ToString() && MultiSelect.Count > 1) + if (MultiSelect.Count < 1) + { + return; + } + + if (caption == EItemInfoButton.Insure.ToString()) { InsuranceCompanyClass insurance = ItemUiContext.Instance.Session.InsuranceCompany; int count = MultiSelect.ItemContexts.Select(ic => ItemClass.FindOrCreate(ic.Item)) @@ -99,6 +104,30 @@ namespace UIFixes { ____text.text += " (x" + count + ")"; } + } + else if (caption == EItemInfoButton.Equip.ToString()) + { + int count = MultiSelect.InteractionCount(EItemInfoButton.Equip, ItemUiContext.Instance); + if (count > 0) + { + ____text.text += " (x" + count + ")"; + } + } + else if (caption == EItemInfoButton.Unequip.ToString()) + { + int count = MultiSelect.InteractionCount(EItemInfoButton.Unequip, ItemUiContext.Instance); + if (count > 0) + { + ____text.text += " (x" + count + ")"; + } + } + else if (caption == EItemInfoButton.UnloadAmmo.ToString()) + { + int count = MultiSelect.InteractionCount(EItemInfoButton.UnloadAmmo, ItemUiContext.Instance); + if (count > 0) + { + ____text.text += " (x" + count + ")"; + } } } } diff --git a/Patches/ContextMenuShortcutPatches.cs b/Patches/ContextMenuShortcutPatches.cs index 6f8dfdf..2d66ddc 100644 --- a/Patches/ContextMenuShortcutPatches.cs +++ b/Patches/ContextMenuShortcutPatches.cs @@ -78,6 +78,12 @@ namespace UIFixes return; } + if (Settings.UnpackKeyBind.Value.IsDown()) + { + interactions.ExecuteInteraction(EItemInfoButton.Unpack); + return; + } + if (Settings.FilterByKeyBind.Value.IsDown()) { interactions.ExecuteInteraction(EItemInfoButton.FilterSearch); diff --git a/Patches/MultiSelectPatches.cs b/Patches/MultiSelectPatches.cs index 280d13d..f9ab733 100644 --- a/Patches/MultiSelectPatches.cs +++ b/Patches/MultiSelectPatches.cs @@ -1,4 +1,5 @@ using Aki.Reflection.Patching; +using Aki.Reflection.Utils; using Comfort.Common; using EFT.Communications; using EFT.InventoryLogic; @@ -38,31 +39,43 @@ namespace UIFixes public static void Enable() { + // Initialization new InitializeCommonUIPatch().Enable(); new InitializeMenuUIPatch().Enable(); + + // Selection new SelectOnMouseDownPatch().Enable(); - new ItemViewClickPatch().Enable(); new DeselectOnTradingItemViewClickPatch().Enable(); new HandleItemViewInitPatch().Enable(); new HandleItemViewKillPatch().Enable(); new BeginDragPatch().Enable(); new EndDragPatch().Enable(); + + // Workarounds new DisableSplitPatch().Enable(); new DisableSplitTargetPatch().Enable(); + // Actions + new ItemViewClickPatch().Enable(); + new ContextActionsPatch().Enable(); + + // GridView new GridViewCanAcceptPatch().Enable(); new GridViewAcceptItemPatch().Enable(); new GridViewPickTargetPatch().Enable(); new GridViewDisableHighlightPatch().Enable(); new GridViewClearTooltipPatch().Enable(); + // SlotView new SlotViewCanAcceptPatch().Enable(); new SlotViewAcceptItemPatch().Enable(); + // TradingTableGridView new TradingTableCanAcceptPatch().Enable(); new TradingTableAcceptItemPatch().Enable(); new TradingTableGetHighlightColorPatch().Enable(); + // Various location finding new FindSpotKeepRotationPatch().Enable(); new FindLocationForItemPatch().Enable(); new FindPlaceToPutPatch().Enable(); @@ -173,7 +186,7 @@ namespace UIFixes if (altDown && !shiftDown && !ctrlDown) { - QuickEquip(___ItemUiContext); + MultiSelect.EquipAll(___ItemUiContext, true); return false; } @@ -188,45 +201,13 @@ namespace UIFixes return true; } - private static void QuickEquip(ItemUiContext itemUiContext) - { - bool allowed = true; - var selectedItemContexts = SortSelectedContexts(MultiSelect.ItemContexts); - foreach (ItemContextClass selectedItemContext in selectedItemContexts) - { - ItemContextAbstractClass innerContext = selectedItemContext.GClass2813_0; - if (innerContext == null) - { - allowed = false; - break; - } - - var contextInteractions = itemUiContext.GetItemContextInteractions(innerContext, null); - if (!contextInteractions.IsInteractionAvailable(EItemInfoButton.Equip)) - { - allowed = false; - break; - } - } - - if (allowed) - { - foreach (ItemContextClass selectedItemContext in selectedItemContexts) - { - itemUiContext.QuickEquip(selectedItemContext.Item).HandleExceptions(); - } - - itemUiContext.Tooltip?.Close(); - } - } - private static void QuickMove(GridItemView gridItemView, ItemUiContext itemUiContext, TraderControllerClass itemController) { bool succeeded = true; DisableMerge = true; IgnoreItemParent = true; Stack operations = new(); - foreach (ItemContextClass selectedItemContext in SortSelectedContexts(MultiSelect.ItemContexts)) + foreach (ItemContextClass selectedItemContext in MultiSelect.SortedItemContexts()) { GStruct413 operation = itemUiContext.QuickFindAppropriatePlace(selectedItemContext, itemController, false /*forceStash*/, false /*showWarnings*/, false /*simulate*/); if (operation.Succeeded && itemController.CanExecute(operation.Value)) @@ -282,6 +263,38 @@ namespace UIFixes } } + public class ContextActionsPatch : ModulePatch + { + protected override MethodBase GetTargetMethod() + { + return AccessTools.Method(typeof(GClass3021), nameof(GClass3021.ExecuteInteractionInternal)); + } + + [PatchPrefix] + public static bool Prefix(GClass3021 __instance, EItemInfoButton interaction, ItemUiContext ___itemUiContext_1) + { + if (!MultiSelect.Active) + { + return true; + } + + switch (interaction) + { + case EItemInfoButton.Equip: + MultiSelect.EquipAll(___itemUiContext_1, false); + return false; + case EItemInfoButton.Unequip: + MultiSelect.UnequipAll(___itemUiContext_1, false); + return false; + case EItemInfoButton.UnloadAmmo: + MultiSelect.UnloadAmmoAll(___itemUiContext_1, false); + return false; + default: + return true; + } + } + } + // TradingItemView overrides GridItemView.OnClick and doesn't call base public class DeselectOnTradingItemViewClickPatch : ModulePatch { @@ -446,7 +459,7 @@ namespace UIFixes bool showHighlights = targetItem == null; Stack operations = new(); - foreach (ItemContextClass selectedItemContext in SortSelectedContexts(MultiSelect.ItemContexts, itemContext)) + foreach (ItemContextClass selectedItemContext in MultiSelect.SortedItemContexts(itemContext)) { FindOrigin = GetTargetGridAddress(itemContext, selectedItemContext, hoveredAddress); FindVerticalFirst = selectedItemContext.ItemRotation == ItemRotation.Vertical; @@ -566,7 +579,7 @@ namespace UIFixes } var serializer = __instance.GetOrAddComponent(); - __result = serializer.Initialize(SortSelectedContexts(MultiSelect.ItemContexts, itemContext), ic => + __result = serializer.Initialize(MultiSelect.SortedItemContexts(itemContext), ic => { FindOrigin = GetTargetGridAddress(itemContext, ic, hoveredAddress); FindVerticalFirst = ic.ItemRotation == ItemRotation.Vertical; @@ -677,23 +690,6 @@ namespace UIFixes } } - // Sort the items to prioritize the items that share a grid with the dragged item, prepend the dragContext as the first one - // Can pass no itemContext, and it just sorts items by their grid order - private static IEnumerable SortSelectedContexts( - IEnumerable selectedContexts, ItemContextClass itemContext = null, bool prepend = true) - { - static int gridOrder(LocationInGrid loc, StashGridClass grid) => grid.GridWidth.Value * loc.y + loc.x; - - var result = selectedContexts - .Where(ic => itemContext == null || ic.Item != itemContext.Item) - .OrderByDescending(ic => ic.ItemAddress is GClass2769) - .ThenByDescending(ic => itemContext != null && itemContext.ItemAddress is GClass2769 originalDraggedAddress && ic.ItemAddress is GClass2769 selectedGridAddress && selectedGridAddress.Grid == originalDraggedAddress.Grid) - .ThenByDescending(ic => ic.ItemAddress is GClass2769 selectedGridAddress ? selectedGridAddress.Grid.Id : null) - .ThenBy(ic => ic.ItemAddress is GClass2769 selectedGridAddress ? gridOrder(selectedGridAddress.LocationInGrid, selectedGridAddress.Grid) : 0); - - return itemContext != null && prepend ? result.Prepend(itemContext) : result; - } - public class GridViewDisableHighlightPatch : ModulePatch { protected override MethodBase GetTargetMethod() @@ -751,7 +747,7 @@ namespace UIFixes } Stack operations = new(); - foreach (ItemContextClass itemContext in SortSelectedContexts(MultiSelect.ItemContexts, null, false)) + foreach (ItemContextClass itemContext in MultiSelect.SortedItemContexts()) { __result = itemContext.CanAccept(__instance.Slot, __instance.ParentItemContext, ___InventoryController, out operation, false /* simulate */); if (operation.Succeeded) @@ -798,7 +794,7 @@ namespace UIFixes InPatch = true; var serializer = __instance.GetOrAddComponent(); - __result = serializer.Initialize(SortSelectedContexts(MultiSelect.ItemContexts, null, false), itemContext => __instance.AcceptItem(itemContext, targetItemContext)); + __result = serializer.Initialize(MultiSelect.SortedItemContexts(), itemContext => __instance.AcceptItem(itemContext, targetItemContext)); __result.ContinueWith(_ => { InPatch = false; }); @@ -834,7 +830,7 @@ namespace UIFixes GClass2769 hoveredAddress = new(__instance.Grid, hoveredLocation); Stack operations = new(); - foreach (ItemContextClass selectedItemContext in SortSelectedContexts(MultiSelect.ItemContexts, itemContext)) + foreach (ItemContextClass selectedItemContext in MultiSelect.SortedItemContexts(itemContext)) { if (traderAssortmentController.CanPrepareItemToSell(selectedItemContext.Item)) { @@ -912,7 +908,7 @@ namespace UIFixes itemContext.CloseDependentWindows(); // For the rest of the items, still need to use quickfind - foreach (ItemContextClass selectedItemContext in SortSelectedContexts(MultiSelect.ItemContexts, itemContext, false)) + foreach (ItemContextClass selectedItemContext in MultiSelect.SortedItemContexts(itemContext, false)) { FindOrigin = GetTargetGridAddress(itemContext, selectedItemContext, hoveredAddress); FindVerticalFirst = selectedItemContext.ItemRotation == ItemRotation.Vertical; diff --git a/Settings.cs b/Settings.cs index 275c820..bfda310 100644 --- a/Settings.cs +++ b/Settings.cs @@ -58,6 +58,7 @@ namespace UIFixes public static ConfigEntry UseKeyBind { get; set; } public static ConfigEntry UseAllKeyBind { get; set; } public static ConfigEntry UnloadKeyBind { get; set; } + public static ConfigEntry UnpackKeyBind { get; set; } public static ConfigEntry FilterByKeyBind { get; set; } public static ConfigEntry LinkedSearchKeyBind { get; set; } public static ConfigEntry UseRaidMouseScrollMulti { get; set; } // Advanced @@ -248,6 +249,15 @@ namespace UIFixes null, new ConfigurationManagerAttributes { }))); + configEntries.Add(UnpackKeyBind = config.Bind( + InputSection, + "Unpack Shortcut", + new KeyboardShortcut(KeyCode.None), + new ConfigDescription( + "Keybind to unpack a sealed weapons case, etc", + null, + new ConfigurationManagerAttributes { }))); + configEntries.Add(FilterByKeyBind = config.Bind( InputSection, "Filter by Item Shortcut",