22
33import org .bukkit .GameMode ;
44import org .bukkit .entity .Player ;
5- import org .bukkit .event .inventory .ClickType ;
65import org .bukkit .event .inventory .InventoryAction ;
76import org .bukkit .event .inventory .InventoryClickEvent ;
87import org .bukkit .inventory .ItemStack ;
2322import xyz .xenondevs .invui .inventory .event .UpdateReason ;
2423import xyz .xenondevs .invui .item .*;
2524import xyz .xenondevs .invui .util .ItemUtils ;
26- import xyz .xenondevs .invui .window .*;
25+ import xyz .xenondevs .invui .window .AbstractWindow ;
26+ import xyz .xenondevs .invui .window .Window ;
27+ import xyz .xenondevs .invui .window .WindowManager ;
2728
2829import java .util .*;
2930import java .util .function .Consumer ;
@@ -61,7 +62,7 @@ public sealed abstract class AbstractGui
6162 viewers = new Set [size ];
6263 }
6364
64- public void handleClick (int slotNumber , Player player , ClickType clickType , InventoryClickEvent event ) {
65+ public void handleClick (int slotNumber , Player player , InventoryClickEvent event ) {
6566 // cancel all clicks if the gui is frozen or an animation is running
6667 if (frozen || animation != null ) {
6768 event .setCancelled (true );
@@ -72,12 +73,12 @@ public void handleClick(int slotNumber, Player player, ClickType clickType, Inve
7273 switch (slotElement ) {
7374 case SlotElement .GuiLink linkedElement -> {
7475 AbstractGui gui = (AbstractGui ) linkedElement .gui ();
75- gui .handleClick (linkedElement .slot (), player , clickType , event );
76+ gui .handleClick (linkedElement .slot (), player , event );
7677 }
7778
7879 case SlotElement .Item itemElement -> {
7980 event .setCancelled (true ); // if it is an Item, don't let the player move it
80- itemElement .item ().handleClick (clickType , player , new Click (event ));
81+ itemElement .item ().handleClick (event . getClick () , player , new Click (event ));
8182 }
8283
8384 case SlotElement .InventoryLink inventorySlotElement ->
@@ -88,7 +89,7 @@ public void handleClick(int slotNumber, Player player, ClickType clickType, Inve
8889 }
8990
9091 //<editor-fold desc="inventories">
91- protected void handleInvSlotElementClick (SlotElement .InventoryLink element , InventoryClickEvent event ) {
92+ private void handleInvSlotElementClick (SlotElement .InventoryLink element , InventoryClickEvent event ) {
9293 Inventory inventory = element .inventory ();
9394 int slot = element .slot ();
9495
@@ -158,7 +159,7 @@ private boolean isBuilderSimilar(@Nullable ItemProvider builder, Locale lang, @N
158159 }
159160
160161 @ SuppressWarnings ("deprecation" )
161- protected void handleInvLeftClick (InventoryClickEvent event , Inventory inventory , int slot , Player player , @ Nullable ItemStack clicked , @ Nullable ItemStack cursor ) {
162+ private void handleInvLeftClick (InventoryClickEvent event , Inventory inventory , int slot , Player player , @ Nullable ItemStack clicked , @ Nullable ItemStack cursor ) {
162163 // nothing happens if both cursor and clicked stack are empty
163164 if (clicked == null && cursor == null )
164165 return ;
@@ -186,7 +187,7 @@ protected void handleInvLeftClick(InventoryClickEvent event, Inventory inventory
186187 }
187188
188189 @ SuppressWarnings ("deprecation" )
189- protected void handleInvRightClick (InventoryClickEvent event , Inventory inventory , int slot , Player player , @ Nullable ItemStack clicked , @ Nullable ItemStack cursor ) {
190+ private void handleInvRightClick (InventoryClickEvent event , Inventory inventory , int slot , Player player , @ Nullable ItemStack clicked , @ Nullable ItemStack cursor ) {
190191 // nothing happens if both cursor and clicked stack are empty
191192 if (clicked == null && cursor == null )
192193 return ;
@@ -219,47 +220,46 @@ protected void handleInvRightClick(InventoryClickEvent event, Inventory inventor
219220 }
220221 }
221222
222- protected void handleInvItemShift (InventoryClickEvent event , Inventory inventory , int slot , Player player , @ Nullable ItemStack clicked ) {
223+ private void handleInvItemShift (InventoryClickEvent event , Inventory inventory , int slot , Player player , @ Nullable ItemStack clicked ) {
223224 if (clicked == null )
224225 return ;
225226
226- ItemStack previousStack = clicked .clone ();
227-
228227 UpdateReason updateReason = new PlayerUpdateReason (player , event );
229- Window window = WindowManager .getInstance ().getOpenWindow (player );
230- ItemPreUpdateEvent updateEvent = inventory .callPreUpdateEvent (updateReason , slot , previousStack , null );
231-
232- if (!updateEvent .isCancelled ()) {
233- int leftOverAmount ;
234- if (window instanceof AbstractDoubleWindow ) {
235- Gui otherGui ;
236- if (window instanceof AbstractSplitWindow splitWindow ) {
237- Gui [] guis = splitWindow .getGuis ();
238- otherGui = guis [0 ] == this ? guis [1 ] : guis [0 ];
239- } else {
240- otherGui = this ;
241- }
242-
243- leftOverAmount = ((AbstractGui ) otherGui ).putIntoFirstInventory (updateReason , clicked , inventory );
244- } else {
245- Inventory playerInventory = ReferencingInventory .fromReversedPlayerStorageContents (player .getInventory ());
246- leftOverAmount = playerInventory .addItem (null , inventory .getItem (slot ));
247- }
248-
249- clicked .setAmount (leftOverAmount );
250- if (ItemUtils .isEmpty (clicked ))
251- clicked = null ;
252-
253- inventory .setItemSilently (slot , clicked );
228+ ItemPreUpdateEvent updateEvent = inventory .callPreUpdateEvent (updateReason , slot , clicked , null );
229+ if (updateEvent .isCancelled ())
230+ return ;
231+
232+ var window = WindowManager .getInstance ().getOpenWindow (player );
233+ assert window != null ;
234+
235+ int leftOverAmount ;
236+ if (window .isDouble ()) {
237+ // for double windows, move into the first inventory that accepts the item, sorted by priority
238+ var inventories = window .getGuis ().stream ()
239+ .flatMap (gui -> gui .getInventories (inventory ).stream ())
240+ .sorted (Comparator .comparingInt (Inventory ::getGuiPriority ).reversed ())
241+ .toList ();
254242
255- inventory .callPostUpdateEvent (updateReason , slot , previousStack , clicked );
243+ leftOverAmount = putIntoFirstInventory (updateReason , clicked , inventories );
244+ } else {
245+ // for single windows, the player inventory takes priority
246+ Inventory playerInventory = ReferencingInventory .fromReversedPlayerStorageContents (player .getInventory ());
247+ leftOverAmount = playerInventory .addItem (null , clicked );
256248 }
249+
250+ ItemStack newStack = clicked .clone ();
251+ newStack .setAmount (leftOverAmount );
252+
253+ inventory .setItemSilently (slot , newStack );
254+ inventory .callPostUpdateEvent (updateReason , slot , clicked , newStack );
257255 }
258256
259257 // TODO: add support for merged windows
260- protected void handleInvNumberKey (InventoryClickEvent event , Inventory inventory , int slot , Player player , @ Nullable ItemStack clicked ) {
258+ private void handleInvNumberKey (InventoryClickEvent event , Inventory inventory , int slot , Player player , @ Nullable ItemStack clicked ) {
261259 Window window = WindowManager .getInstance ().getOpenWindow (player );
262- if (window instanceof AbstractSingleWindow ) {
260+ assert window != null ;
261+
262+ if (!window .isDouble ()) {
263263 org .bukkit .inventory .Inventory playerInventory = player .getInventory ();
264264 int hotbarButton = event .getHotbarButton ();
265265 ItemStack hotbarItem = ItemUtils .takeUnlessEmpty (playerInventory .getItem (hotbarButton ));
@@ -272,9 +272,11 @@ protected void handleInvNumberKey(InventoryClickEvent event, Inventory inventory
272272 }
273273
274274 // TODO: add support for merged windows
275- protected void handleInvOffHandKey (InventoryClickEvent event , Inventory inventory , int slot , Player player , @ Nullable ItemStack clicked ) {
275+ private void handleInvOffHandKey (InventoryClickEvent event , Inventory inventory , int slot , Player player , @ Nullable ItemStack clicked ) {
276276 Window window = WindowManager .getInstance ().getOpenWindow (player );
277- if (window instanceof AbstractSingleWindow ) {
277+ assert window != null ;
278+
279+ if (!window .isDouble ()) {
278280 PlayerInventory playerInventory = player .getInventory ();
279281 ItemStack offhandItem = ItemUtils .takeUnlessEmpty (playerInventory .getItemInOffHand ());
280282
@@ -285,7 +287,7 @@ protected void handleInvOffHandKey(InventoryClickEvent event, Inventory inventor
285287 }
286288 }
287289
288- protected void handleInvDrop (boolean ctrl , InventoryClickEvent event , Inventory inventory , int slot , Player player , @ Nullable ItemStack clicked ) {
290+ private void handleInvDrop (boolean ctrl , InventoryClickEvent event , Inventory inventory , int slot , Player player , @ Nullable ItemStack clicked ) {
289291 if (clicked == null )
290292 return ;
291293
@@ -302,7 +304,7 @@ protected void handleInvDrop(boolean ctrl, InventoryClickEvent event, Inventory
302304
303305 }
304306
305- protected void handleInvDoubleClick (InventoryClickEvent event , Player player , @ Nullable ItemStack cursor ) {
307+ private void handleInvDoubleClick (InventoryClickEvent event , Player player , @ Nullable ItemStack cursor ) {
306308 if (cursor == null )
307309 return ;
308310
@@ -312,7 +314,7 @@ protected void handleInvDoubleClick(InventoryClickEvent event, Player player, @N
312314 }
313315
314316 @ SuppressWarnings ("deprecation" )
315- protected void handleInvMiddleClick (InventoryClickEvent event , Inventory inventory , int slot , Player player ) {
317+ private void handleInvMiddleClick (InventoryClickEvent event , Inventory inventory , int slot , Player player ) {
316318 if (player .getGameMode () != GameMode .CREATIVE )
317319 return ;
318320
@@ -361,22 +363,50 @@ public void handleItemShift(InventoryClickEvent event) {
361363 }
362364 }
363365
366+ /**
367+ * Puts the given {@link ItemStack} into the first inventory that accepts it, starting with the
368+ * {@link Inventory#getGuiPriority() highest priority} inventory. If one inventory accepts any amount
369+ * of items, further inventories will not be queried, meaning that an item stack will not be split
370+ * across multiple inventories.
371+ *
372+ * @param updateReason the update reason to use
373+ * @param itemStack the item stack to put
374+ * @param ignored the inventories to ignore
375+ * @return the amount of items that are left over
376+ */
364377 protected int putIntoFirstInventory (UpdateReason updateReason , ItemStack itemStack , Inventory ... ignored ) {
365- Collection <Inventory > inventories = getAllInventories (ignored );
378+ return putIntoFirstInventory (updateReason , itemStack , getInventories (ignored ));
379+ }
380+
381+ /**
382+ * Puts the given {@link ItemStack} into the first inventory that accepts it of the given collection of inventories.
383+ * If one inventory accepts any amount of items, further inventories will not be queried, meaning that an item stack
384+ * will not be split across multiple inventories.
385+ *
386+ * @param updateReason the update reason to use
387+ * @param itemStack the item stack to put
388+ * @param inventories the inventories to put the item stack into
389+ * @return the amount of items that are left over
390+ */
391+ protected int putIntoFirstInventory (UpdateReason updateReason , ItemStack itemStack , SequencedCollection <? extends Inventory > inventories ) {
366392 int originalAmount = itemStack .getAmount ();
367-
368- if (!inventories .isEmpty ()) {
369- for (Inventory inventory : inventories ) {
370- int amountLeft = inventory .addItem (updateReason , itemStack );
371- if (originalAmount != amountLeft )
372- return amountLeft ;
373- }
393+ for (Inventory inventory : inventories ) {
394+ int amountLeft = inventory .addItem (updateReason , itemStack );
395+ if (originalAmount != amountLeft )
396+ return amountLeft ;
374397 }
375398
376399 return originalAmount ;
377400 }
378401
379- public Map <Inventory , Set <Integer >> getAllInventorySlots (Inventory ... ignored ) {
402+ /**
403+ * Gets a map of all inventories and their visible slots in this gui, ignoring the specified inventories,
404+ * sorted by their {@link Inventory#getGuiPriority()}, with the highest priorities coming first.
405+ *
406+ * @param ignored the inventories to ignore
407+ * @return a map of all inventories and their visible slots
408+ */
409+ private SequencedMap <Inventory , Set <Integer >> getAllInventorySlots (Inventory ... ignored ) {
380410 HashMap <Inventory , Set <Integer >> slots = new HashMap <>();
381411 Set <Inventory > ignoredSet = Arrays .stream (ignored ).collect (Collectors .toSet ());
382412
@@ -399,9 +429,10 @@ public Map<Inventory, Set<Integer>> getAllInventorySlots(Inventory... ignored) {
399429 .collect (Collectors .toMap (Map .Entry ::getKey , Map .Entry ::getValue , (a , b ) -> a , LinkedHashMap ::new ));
400430 }
401431
402- public Collection <Inventory > getAllInventories (Inventory ... ignored ) {
432+ @ Override
433+ public SequencedCollection <? extends Inventory > getInventories (Inventory ... ignored ) {
403434 if (!ignoreObscuredInventorySlots )
404- return getAllInventorySlots (ignored ).keySet ( );
435+ return Collections . unmodifiableSequencedCollection ( getAllInventorySlots (ignored ).sequencedKeySet () );
405436
406437 ArrayList <Inventory > inventories = new ArrayList <>();
407438 for (Map .Entry <Inventory , Set <Integer >> entry : getAllInventorySlots (ignored ).entrySet ()) {
@@ -410,7 +441,7 @@ public Collection<Inventory> getAllInventories(Inventory... ignored) {
410441 inventories .add (new ObscuredInventory (inventory , slot -> !slots .contains (slot )));
411442 }
412443
413- return inventories ;
444+ return Collections . unmodifiableList ( inventories ) ;
414445 }
415446 //</editor-fold>
416447
0 commit comments