From ed9858de0050f0c9a600034554d0cf77b9174578 Mon Sep 17 00:00:00 2001 From: Tyfon <29051038+tyfon7@users.noreply.github.com> Date: Sat, 13 Jul 2024 18:07:10 -0700 Subject: [PATCH] Shift-click sort to keep containers in place --- Patches/SortPatches.cs | 57 ++++++++++++++++++++++ Plugin.cs | 1 + Sorter.cs | 108 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+) create mode 100644 Patches/SortPatches.cs create mode 100644 Sorter.cs diff --git a/Patches/SortPatches.cs b/Patches/SortPatches.cs new file mode 100644 index 0000000..34b16f9 --- /dev/null +++ b/Patches/SortPatches.cs @@ -0,0 +1,57 @@ +using System.Reflection; +using EFT.UI; +using EFT.UI.DragAndDrop; +using HarmonyLib; +using SPT.Reflection.Patching; +using UnityEngine; + +namespace UIFixes; + +public static class SortPatches +{ + public static void Enable() + { + new SortPatch().Enable(); + new ShiftClickPatch().Enable(); + } + + public class SortPatch : ModulePatch + { + public static bool IncludeContainers = true; + + protected override MethodBase GetTargetMethod() + { + return AccessTools.Method(typeof(InteractionsHandlerClass), nameof(InteractionsHandlerClass.Sort)); + } + + [PatchPrefix] + public static bool Prefix(LootItemClass sortingItem, InventoryControllerClass controller, bool simulate, ref GStruct414 __result) + { + __result = Sorter.Sort(sortingItem, controller, IncludeContainers, simulate); + return false; + } + } + + public class ShiftClickPatch : ModulePatch + { + protected override MethodBase GetTargetMethod() + { + return AccessTools.Method(typeof(GridSortPanel), nameof(GridSortPanel.method_0)); + } + + [PatchPrefix] + public static bool Prefix(GridSortPanel __instance, bool ___bool_0) + { + bool shiftDown = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift); + SortPatch.IncludeContainers = !shiftDown; + + if (SortPatch.IncludeContainers || ___bool_0) + { + return true; + } + + ItemUiContext.Instance.ShowMessageWindow("UI/Inventory/SortAcceptConfirmation".Localized(null) + " Containers will not be moved.", __instance.method_1, () => { }); + return false; + } + } +} \ No newline at end of file diff --git a/Plugin.cs b/Plugin.cs index f310463..01d0270 100644 --- a/Plugin.cs +++ b/Plugin.cs @@ -64,6 +64,7 @@ public class Plugin : BaseUnityPlugin FleaSlotSearchPatches.Enable(); MoveSortingTablePatches.Enable(); FilterOutOfStockPatches.Enable(); + SortPatches.Enable(); } public static bool InRaid() diff --git a/Sorter.cs b/Sorter.cs new file mode 100644 index 0000000..6799122 --- /dev/null +++ b/Sorter.cs @@ -0,0 +1,108 @@ +using System.Collections.Generic; +using System.Linq; +using EFT.InventoryLogic; + +namespace UIFixes; + +public static class Sorter +{ + public static GStruct414 Sort(LootItemClass sortingItem, InventoryControllerClass controller, bool includingContainers, bool simulate) + { + GClass2824 operation = new(sortingItem, controller); + if (!operation.CanExecute(controller)) + { + return new GClass3325(sortingItem); + } + + List itemsToSort = []; + foreach (StashGridClass grid in sortingItem.Grids) + { + operation.SetOldPositions(grid, grid.ItemCollection.ToListOfLocations()); + itemsToSort.AddRange(includingContainers ? grid.Items : grid.Items.Where(i => i is not LootItemClass compoundItem || !compoundItem.Grids.Any())); + var containers = includingContainers ? [] : grid.ItemCollection.Where(kvp => kvp.Key is LootItemClass compoundItem && compoundItem.Grids.Any()).Select(kvp => new GClass2521(kvp.Key, kvp.Value)).ToArray(); + grid.RemoveAll(); + controller.RaiseEvent(new GEventArgs23(grid)); + + // Immediately put the containers back in their original spots + foreach (var itemWithLocation in containers) + { + grid.Add(itemWithLocation.Item, itemWithLocation.Location, false); + operation.AddItemToGrid(grid, itemWithLocation); + } + } + + List sortedItems = GClass2772.Sort(itemsToSort); + int fallbackTries = 5; + InventoryError inventoryError = null; + + for (int i = 0; i < sortedItems.Count; i++) + { + Item item = sortedItems[i]; + if (item.CurrentAddress == null) + { + bool sorted = false; + foreach (StashGridClass grid in sortingItem.Grids) + { + if (grid.Add(item).Succeeded) + { + sorted = true; + operation.AddItemToGrid(grid, new GClass2521(item, ((GridItemAddress)item.CurrentAddress).LocationInGrid)); + break; + } + } + + if (!sorted && --fallbackTries > 0) + { + XYCellSizeStruct xycellSizeStruct = item.CalculateCellSize(); + while (!sorted && --i > 0) + { + Item item2 = sortedItems[i]; + XYCellSizeStruct xycellSizeStruct2 = item2.CalculateCellSize(); + if (!xycellSizeStruct.Equals(xycellSizeStruct2)) + { + StashGridClass stashGridClass3 = operation.RemoveItemFromGrid(item2); + if (stashGridClass3 != null && !stashGridClass3.Add(item).Failed) + { + sorted = true; + operation.AddItemToGrid(stashGridClass3, new GClass2521(item, ((ItemAddressClass)item.CurrentAddress).LocationInGrid)); + } + } + } + + i--; + continue; + } + + if (fallbackTries > 0) + { + continue; + } + + inventoryError = new GClass3326(sortingItem); + break; + } + } + + if (inventoryError != null) + { + operation.RollBack(); + operation.RaiseEvents(controller, CommandStatus.Failed); + return inventoryError; + } + + if (simulate) + { + operation.RollBack(); + } + + foreach (StashGridClass grid in sortingItem.Grids) + { + if (grid.ItemCollection.Any>() && grid is GClass2516 searchable) + { + searchable.FindAll(controller.Profile.ProfileId); + } + } + + return operation; + } +} \ No newline at end of file