From 7f284b88271a60b8d7f54cd8de22a5aa57e4b909 Mon Sep 17 00:00:00 2001 From: stefvanschie Date: Sun, 28 Jun 2020 20:11:45 +0200 Subject: [PATCH] Handle items being picked up (#61) When an item is now being picked up by a human entity who has an open gui which spans across the bottom inventory, items will now be moved to the internal cache if possible instead of picking put into the bottom inventory. Items that can't be put into the cache are left on the ground. --- .../inventoryframework/GuiListener.java | 42 +++++++++++++++ .../inventoryframework/HumanEntityCache.java | 52 +++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/src/main/java/com/github/stefvanschie/inventoryframework/GuiListener.java b/src/main/java/com/github/stefvanschie/inventoryframework/GuiListener.java index acaa1ec6..2f921f4f 100644 --- a/src/main/java/com/github/stefvanschie/inventoryframework/GuiListener.java +++ b/src/main/java/com/github/stefvanschie/inventoryframework/GuiListener.java @@ -5,10 +5,13 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityPickupItemEvent; import org.bukkit.event.inventory.*; import org.bukkit.event.server.PluginDisableEvent; import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.InventoryView; +import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.NotNull; @@ -71,6 +74,45 @@ public void onInventoryClick(@NotNull InventoryClickEvent event) { } } + /** + * Handles users picking up items while their bottom inventory is in use. + * + * @param event the event fired when an entity picks up an item + * @since 0.6.1 + */ + @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) + public void onEntityPickupItem(@NotNull EntityPickupItemEvent event) { + if (!(event.getEntity() instanceof HumanEntity)) { + return; + } + + InventoryHolder holder = ((HumanEntity) event.getEntity()).getOpenInventory().getTopInventory().getHolder(); + + if (!(holder instanceof Gui)) { + return; + } + + Gui gui = (Gui) holder; + + if (gui.getState() != Gui.State.BOTTOM) { + return; + } + + int leftOver = gui.getHumanEntityCache().add((HumanEntity) event.getEntity(), event.getItem().getItemStack()); + + if (leftOver == 0) { + event.getItem().remove(); + } else { + ItemStack itemStack = event.getItem().getItemStack(); + + itemStack.setAmount(leftOver); + + event.getItem().setItemStack(itemStack); + } + + event.setCancelled(true); + } + /** * Handles small drag events which are likely clicks instead. These small drags will be interpreted as clicks and * will fire a click event. diff --git a/src/main/java/com/github/stefvanschie/inventoryframework/HumanEntityCache.java b/src/main/java/com/github/stefvanschie/inventoryframework/HumanEntityCache.java index 8a6a7c6c..d6737dc4 100644 --- a/src/main/java/com/github/stefvanschie/inventoryframework/HumanEntityCache.java +++ b/src/main/java/com/github/stefvanschie/inventoryframework/HumanEntityCache.java @@ -59,6 +59,58 @@ public void restoreAndForgetAll() { clearCache(); } + /** + * Adds the given item stack to the human entity's cached inventory. The returned amount is the amount of items of + * the provided item stack that could not be put into the cached inventory. This number will always be equal or + * less than the amount of items in the provided item stack, but no less than zero. The item stack provided will not + * be updated with this leftover amount. If the human entity provided is not in the human entity cache, this method + * will return an {@link IllegalStateException}. The items will be added to the inventory in the same way as the + * items are stored. The items may be added to an already existing item stack, but the item stack's amount will + * never go over the maximum stack size. + * + * @param humanEntity the human entity to add the item to + * @param item the item to add to the cached inventory + * @return the amount of leftover items that couldn't be fit in the cached inventory + * @throws IllegalStateException if the human entity's inventory is not cached + * @since 0.6.1 + */ + protected int add(@NotNull HumanEntity humanEntity, @NotNull ItemStack item) { + ItemStack[] items = inventories.get(humanEntity); + + if (items == null) { + throw new IllegalStateException("The human entity '" + humanEntity.getUniqueId().toString() + + "' does not have a cached inventory"); + } + + int amountPutIn = 0; + + for (int i = 0; i < items.length; i++) { + ItemStack itemStack = items[i]; + + if (itemStack == null) { + items[i] = item.clone(); + items[i].setAmount(item.getAmount() - amountPutIn); + amountPutIn = item.getAmount(); + break; + } + + if (!itemStack.isSimilar(item)) { + continue; + } + + int additionalAmount = Math.min(itemStack.getMaxStackSize() - itemStack.getAmount(), item.getAmount()); + + itemStack.setAmount(itemStack.getAmount() + additionalAmount); + amountPutIn += additionalAmount; + + if (amountPutIn == item.getAmount()) { + break; + } + } + + return item.getAmount() - amountPutIn; + } + /** * Stores this player's inventory in the cache. If the player was already stored, their cache will be overwritten. *