|
24 | 24 |
|
25 | 25 | import java.util.Objects; |
26 | 26 | import java.util.Set; |
| 27 | +import java.util.WeakHashMap; |
27 | 28 | import java.util.function.Consumer; |
28 | 29 | import java.util.function.Function; |
29 | 30 | import me.wolfyscript.customcrafting.CustomCrafting; |
30 | 31 | import me.wolfyscript.utilities.util.inventory.ItemUtils; |
31 | 32 | import org.bukkit.Bukkit; |
| 33 | +import org.bukkit.event.inventory.InventoryAction; |
32 | 34 | import org.bukkit.event.inventory.InventoryClickEvent; |
33 | 35 | import org.bukkit.event.inventory.InventoryDragEvent; |
| 36 | +import org.bukkit.event.inventory.InventoryEvent; |
34 | 37 | import org.bukkit.event.inventory.InventoryInteractEvent; |
35 | 38 | import org.bukkit.inventory.ItemStack; |
36 | 39 |
|
37 | 40 | public class InteractionUtils { |
38 | 41 |
|
| 42 | + private static final WeakHashMap<InventoryEvent, Integer> CACHE_COLLECT_TO_CURSOR = new WeakHashMap<>(); |
| 43 | + |
39 | 44 | /** |
40 | 45 | * Used to apply ItemStack changes from the InventoryInteractEvent. |
41 | 46 | * |
@@ -64,6 +69,14 @@ public static boolean applyItemFromInteractionEvent(int clickedSlot, InventoryIn |
64 | 69 | // Cancel the event when trying to shift-click the items from the bottom to the top inventory. |
65 | 70 | return true; |
66 | 71 | } |
| 72 | + /* |
| 73 | + * # issue: WolfyUtils calls all the ItemInputButtons on Shift-interaction, |
| 74 | + * we need to only update the clicked slot when moving stack into bottom inventory, |
| 75 | + * but still update all when stacks are moved into the GUI (top inventory), due to non-deterministic stack placement! |
| 76 | + */ |
| 77 | + if (clickEvent.getAction().equals(InventoryAction.MOVE_TO_OTHER_INVENTORY) && Objects.equals(clickEvent.getClickedInventory(), event.getView().getTopInventory()) && clickedSlot != clickEvent.getSlot()) { |
| 78 | + return false; // The event should not be cancelled yet. |
| 79 | + } |
67 | 80 | applyItemStack.accept(current); |
68 | 81 | } |
69 | 82 | // Other than the PICKUP_ALL, DROP_ALL is not called when there is only 1 item. |
@@ -91,8 +104,28 @@ public static boolean applyItemFromInteractionEvent(int clickedSlot, InventoryIn |
91 | 104 | } |
92 | 105 | // All these actions will keep remaining items in the slot, so lets just use the current stack. |
93 | 106 | // The stack will be updated, as it is a reference to the stack in the inventory. |
94 | | - case PICKUP_ONE, PICKUP_SOME, COLLECT_TO_CURSOR, DROP_ALL_CURSOR -> |
| 107 | + case PICKUP_ONE, PICKUP_SOME, DROP_ALL_CURSOR -> applyItemStack.accept(clickEvent.getCurrentItem()); |
| 108 | + case COLLECT_TO_CURSOR -> { |
| 109 | + /* |
| 110 | + * # issue: We need to determine which slots are cleared completely and which slots |
| 111 | + * are updated, because there are remaining items. |
| 112 | + * So we need to keep track of the collected amount to figure that out, since Spigot has no API for that. |
| 113 | + * This requires WolfyUtils v4.16.12 to properly function. |
| 114 | + */ |
| 115 | + if (clickedSlot == clickEvent.getSlot()) { |
| 116 | + CACHE_COLLECT_TO_CURSOR.put(event, clickEvent.getCursor().getAmount()); |
95 | 117 | applyItemStack.accept(clickEvent.getCurrentItem()); |
| 118 | + break; |
| 119 | + } |
| 120 | + ItemStack item = clickEvent.getClickedInventory().getItem(clickedSlot); |
| 121 | + if (item == null) break; |
| 122 | + int total = CACHE_COLLECT_TO_CURSOR.compute(event, (inventoryEvent, count) -> count == null ? item.getAmount() : (count + item.getAmount())); |
| 123 | + if (total > clickEvent.getCursor().getMaxStackSize()) { |
| 124 | + applyItemStack.accept(clickEvent.getClickedInventory().getItem(clickedSlot)); |
| 125 | + break; |
| 126 | + } |
| 127 | + applyItemStack.accept(null); |
| 128 | + } |
96 | 129 | // Hotbar swaps work all the same, so lets take the hotbar stack. |
97 | 130 | case HOTBAR_SWAP, HOTBAR_MOVE_AND_READD -> |
98 | 131 | applyItemStack.accept(event.getWhoClicked().getInventory().getItem(clickEvent.getHotbarButton())); |
|
0 commit comments