From 8e0ca7ea44a1dac519b458393a93d9664a06039e Mon Sep 17 00:00:00 2001 From: NichtStudioCode <51272202+NichtStudioCode@users.noreply.github.com> Date: Tue, 11 May 2021 15:29:53 +0200 Subject: [PATCH] Respect maxStackSize in VirtualInventory#addItem --- .../de/studiocode/invui/util/ArrayUtils.java | 13 ++++++ .../virtualinventory/VirtualInventory.java | 45 ++++++++++++------- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/src/main/java/de/studiocode/invui/util/ArrayUtils.java b/src/main/java/de/studiocode/invui/util/ArrayUtils.java index 942a6d7..e9a8aae 100644 --- a/src/main/java/de/studiocode/invui/util/ArrayUtils.java +++ b/src/main/java/de/studiocode/invui/util/ArrayUtils.java @@ -2,7 +2,9 @@ package de.studiocode.invui.util; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.function.Predicate; @@ -16,6 +18,17 @@ public class ArrayUtils { return -1; } + @NotNull + public static List findEmptyIndices(@NotNull Object[] array) { + List emptyIndices = new ArrayList<>(); + for (int index = 0; index < array.length; index++) { + if (array[index] == null) emptyIndices.add(index); + } + + return emptyIndices; + } + + @NotNull public static Map findAllOccurrences(@NotNull T[] array, Predicate predicate) { Map occurrences = new HashMap<>(); diff --git a/src/main/java/de/studiocode/invui/virtualinventory/VirtualInventory.java b/src/main/java/de/studiocode/invui/virtualinventory/VirtualInventory.java index ed59a2f..204f1c6 100644 --- a/src/main/java/de/studiocode/invui/virtualinventory/VirtualInventory.java +++ b/src/main/java/de/studiocode/invui/virtualinventory/VirtualInventory.java @@ -8,12 +8,14 @@ import de.studiocode.invui.window.Window; import org.bukkit.Bukkit; import org.bukkit.configuration.serialization.ConfigurationSerializable; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.function.Consumer; +// TODO: clean up public class VirtualInventory implements ConfigurationSerializable { private final Set windows = new HashSet<>(); @@ -340,10 +342,14 @@ public class VirtualInventory implements ConfigurationSerializable { /** * Adds an {@link ItemStack} to the {@link VirtualInventory}. + * This method does not work the same way as Bukkit's addItem method + * as it respects the max stack size of the item type. * * @param updateReason The reason for item update, can be null. * @param itemStack The {@link ItemStack} to add * @return The amount of items that couldn't be added + * @see #simulateAdd(ItemStack) + * @see #simulateMultiAdd(List) */ public int addItem(@Nullable UpdateReason updateReason, ItemStack itemStack) { final int originalAmount = itemStack.getAmount(); @@ -355,15 +361,11 @@ public class VirtualInventory implements ConfigurationSerializable { if (amountLeft == 0) break; } - if (amountLeft != 0) { - // there are still items left, put the rest on an empty slot - int emptyIndex = ArrayUtils.findFirstEmptyIndex(items); - if (emptyIndex != -1) { - ItemStack leftover = itemStack.clone(); - leftover.setAmount(amountLeft); - if (!place(updateReason, emptyIndex, leftover)) - amountLeft = 0; - } + // find all empty slots and put the item there + while (amountLeft > 0) { + int emptySlot = ArrayUtils.findFirstEmptyIndex(items); + if (emptySlot == -1) break; + amountLeft = addToEmpty(updateReason, emptySlot, itemStack, amountLeft); } // if items have been added, notify windows @@ -382,17 +384,20 @@ public class VirtualInventory implements ConfigurationSerializable { * @return How many items wouldn't fit in the inventory when added */ public int simulateAdd(ItemStack itemStack) { + int maxStackSize = itemStack.getMaxStackSize(); int amountLeft = itemStack.getAmount(); // find all slots where the item partially fits for (int partialSlot : findPartialSlots(itemStack)) { ItemStack partialItem = items[partialSlot]; - amountLeft = Math.max(0, amountLeft - (partialItem.getMaxStackSize() - partialItem.getAmount())); + amountLeft = Math.max(0, amountLeft - (maxStackSize - partialItem.getAmount())); if (amountLeft == 0) break; } - // remaining items would be added to an empty slot - if (amountLeft != 0 && ArrayUtils.findFirstEmptyIndex(items) != -1) amountLeft = 0; + // remaining items would be added to empty slots + for (int ignored : ArrayUtils.findEmptyIndices(items)) { + amountLeft -= Math.min(amountLeft, maxStackSize); + } return amountLeft; } @@ -496,6 +501,15 @@ public class VirtualInventory implements ConfigurationSerializable { } else return amount; } + private int addToEmpty(@Nullable UpdateReason updateReason, int index, @NotNull ItemStack type, int amount) { + int maxAddable = Math.min(type.getType().getMaxStackSize(), amount); + ItemStack newStack = type.clone(); + newStack.setAmount(maxAddable); + + if (setItemStack(updateReason, index, newStack)) return amount; + else return amount - maxAddable; + } + private int takeFrom(@Nullable UpdateReason updateReason, int index, int maxTake) { ItemStack itemStack = items[index]; int amount = itemStack.getAmount(); @@ -573,11 +587,8 @@ public class VirtualInventory implements ConfigurationSerializable { } /** - * Sets the item update handler which is an alternative for using - * Bukkit's event system for handling item updates in this virtual - * inventory. The item update handler is called before the Bukkit event - * is fired and all changes made are visible when catching Bukkit's - * event. + * Sets the item update handler which will get called every time + * an item gets updated in this {@link VirtualInventory}. * * @param itemUpdateHandler The item update handler */