diff --git a/src/main/java/net/minestom/server/inventory/AbstractInventory.java b/src/main/java/net/minestom/server/inventory/AbstractInventory.java index a95114d5b..b4cc7a641 100644 --- a/src/main/java/net/minestom/server/inventory/AbstractInventory.java +++ b/src/main/java/net/minestom/server/inventory/AbstractInventory.java @@ -55,8 +55,7 @@ public abstract class AbstractInventory implements InventoryClickHandler, DataCo public synchronized @NotNull T processItemStack(@NotNull ItemStack itemStack, @NotNull TransactionType type, @NotNull TransactionOption option) { - var pair = type.process(this, itemStack); - return option.fill(this, pair.left(), pair.right()); + return option.fill(type, this, itemStack); } public synchronized @NotNull List<@NotNull T> processItemStacks(@NotNull List<@NotNull ItemStack> itemStacks, diff --git a/src/main/java/net/minestom/server/inventory/Inventory.java b/src/main/java/net/minestom/server/inventory/Inventory.java index aa9be6aaf..c61aeb7c9 100644 --- a/src/main/java/net/minestom/server/inventory/Inventory.java +++ b/src/main/java/net/minestom/server/inventory/Inventory.java @@ -4,7 +4,6 @@ import net.kyori.adventure.text.Component; import net.minestom.server.Viewable; import net.minestom.server.entity.Player; import net.minestom.server.inventory.click.ClickType; -import net.minestom.server.inventory.click.InventoryClickLoopHandler; import net.minestom.server.inventory.click.InventoryClickResult; import net.minestom.server.item.ItemStack; import net.minestom.server.network.packet.server.play.OpenWindowPacket; @@ -468,17 +467,8 @@ public class Inventory extends AbstractInventory implements Viewable { final ItemStack cursor = getCursorItem(player); final boolean isInWindow = isClickInWindow(slot); - final InventoryClickResult clickResult = clickProcessor.doubleClick(isInWindow ? this : null, player, slot, cursor, - // Start by looping through the opened inventory - new InventoryClickLoopHandler(0, getSize(), 1, - i -> i, - this::getItemStack, - this::setItemStack), - // Looping through player inventory - new InventoryClickLoopHandler(0, PlayerInventory.INVENTORY_SIZE, 1, - PlayerInventoryUtils::convertToPacketSlot, - index -> playerInventory.getItemStack(index, PlayerInventoryUtils.OFFSET), - (index, itemStack) -> playerInventory.setItemStack(index, PlayerInventoryUtils.OFFSET, itemStack))); + final InventoryClickResult clickResult = clickProcessor.doubleClick(isInWindow ? this : playerInventory, + this, player, slot, cursor); if (clickResult == null) return false; diff --git a/src/main/java/net/minestom/server/inventory/PlayerInventory.java b/src/main/java/net/minestom/server/inventory/PlayerInventory.java index 5cd377e92..1dfa63a6f 100644 --- a/src/main/java/net/minestom/server/inventory/PlayerInventory.java +++ b/src/main/java/net/minestom/server/inventory/PlayerInventory.java @@ -3,7 +3,6 @@ package net.minestom.server.inventory; import net.minestom.server.entity.Player; import net.minestom.server.event.item.ArmorEquipEvent; import net.minestom.server.inventory.click.ClickType; -import net.minestom.server.inventory.click.InventoryClickLoopHandler; import net.minestom.server.inventory.click.InventoryClickResult; import net.minestom.server.inventory.condition.InventoryCondition; import net.minestom.server.item.ItemStack; @@ -406,12 +405,7 @@ public class PlayerInventory extends AbstractInventory implements EquipmentHandl @Override public boolean doubleClick(@NotNull Player player, int slot) { final ItemStack cursor = getCursorItem(); - - final InventoryClickResult clickResult = clickProcessor.doubleClick(null, player, slot, cursor, - new InventoryClickLoopHandler(0, itemStacks.length, 1, - i -> i < 9 ? i + 9 : i - 9, - index -> itemStacks[index], - this::setItemStack)); + final InventoryClickResult clickResult = clickProcessor.doubleClick(this, null, player, slot, cursor); if (clickResult == null) return false; @@ -419,6 +413,7 @@ public class PlayerInventory extends AbstractInventory implements EquipmentHandl if (clickResult.doRefresh()) update(); + setItemStack(slot, OFFSET, clickResult.getClicked()); setCursorItem(clickResult.getCursor()); return !clickResult.isCancel(); diff --git a/src/main/java/net/minestom/server/inventory/TransactionOption.java b/src/main/java/net/minestom/server/inventory/TransactionOption.java index 0fa871d87..577784ebd 100644 --- a/src/main/java/net/minestom/server/inventory/TransactionOption.java +++ b/src/main/java/net/minestom/server/inventory/TransactionOption.java @@ -44,4 +44,11 @@ public interface TransactionOption { @NotNull T fill(@NotNull AbstractInventory inventory, @NotNull ItemStack result, @NotNull Map<@NotNull Integer, @NotNull ItemStack> itemChangesMap); + + default @NotNull T fill(@NotNull TransactionType type, + @NotNull AbstractInventory inventory, + @NotNull ItemStack itemStack) { + var pair = type.process(inventory, itemStack); + return fill(inventory, pair.left(), pair.right()); + } } diff --git a/src/main/java/net/minestom/server/inventory/click/InventoryClickProcessor.java b/src/main/java/net/minestom/server/inventory/click/InventoryClickProcessor.java index b4c4b735b..ffa056637 100644 --- a/src/main/java/net/minestom/server/inventory/click/InventoryClickProcessor.java +++ b/src/main/java/net/minestom/server/inventory/click/InventoryClickProcessor.java @@ -1,6 +1,5 @@ package net.minestom.server.inventory.click; -import it.unimi.dsi.fastutil.ints.Int2IntFunction; import it.unimi.dsi.fastutil.ints.Int2ObjectFunction; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; @@ -9,6 +8,7 @@ import net.minestom.server.event.inventory.InventoryClickEvent; import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.AbstractInventory; import net.minestom.server.inventory.Inventory; +import net.minestom.server.inventory.TransactionOption; import net.minestom.server.inventory.TransactionType; import net.minestom.server.inventory.condition.InventoryCondition; import net.minestom.server.inventory.condition.InventoryConditionResult; @@ -21,7 +21,9 @@ import org.jetbrains.annotations.Nullable; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.BiConsumer; +import java.util.function.BiFunction; public class InventoryClickProcessor { @@ -342,8 +344,8 @@ public class InventoryClickProcessor { } @Nullable - public InventoryClickResult doubleClick(@Nullable Inventory inventory, @NotNull Player player, int slot, - @NotNull ItemStack cursor, @NotNull InventoryClickLoopHandler... loopHandlers) { + public InventoryClickResult doubleClick(@NotNull AbstractInventory clickedInventory, @Nullable Inventory inventory, @NotNull Player player, int slot, + @NotNull final ItemStack cursor) { InventoryClickResult clickResult = startCondition(inventory, player, slot, ClickType.START_DOUBLE_CLICK, ItemStack.AIR, cursor); if (clickResult.isCancel()) { @@ -354,49 +356,46 @@ public class InventoryClickProcessor { return null; final StackingRule cursorRule = cursor.getStackingRule(); - int amount = cursorRule.getAmount(cursor); + final int amount = cursorRule.getAmount(cursor); + final int remainingAmount = cursorRule.getMaxSize() - amount; - if (!cursorRule.canApply(cursor, amount + 1)) - return null; + ItemStack remain = cursorRule.apply(cursor, remainingAmount); - for (InventoryClickLoopHandler loopHandler : loopHandlers) { - final Int2IntFunction indexModifier = loopHandler.getIndexModifier(); - final Int2ObjectFunction itemGetter = loopHandler.getItemGetter(); - final BiConsumer itemSetter = loopHandler.getItemSetter(); + BiFunction func = (inv, rest) -> { + var pair = TransactionType.TAKE.process(inv, rest, (index, itemStack) -> { + if (index == slot) // Prevent item lose/duplication + return false; + InventoryClickResult result = startCondition(inventory, player, index, ClickType.DOUBLE_CLICK, itemStack, cursor); + return !result.isCancel(); + }); + var itemResult = pair.left(); + var map = pair.right(); + return TransactionOption.ALL.fill(inv, itemResult, map); + }; - for (int i = loopHandler.getStart(); i < loopHandler.getEnd(); i += loopHandler.getStep()) { - final int index = indexModifier.apply(i); - if (index == slot) - continue; + var playerInventory = player.getInventory(); - ItemStack item = itemGetter.apply(index); - final StackingRule itemRule = item.getStackingRule(); - if (!cursorRule.canApply(cursor, amount + 1)) - break; - if (cursorRule.canBeStacked(cursor, item)) { - clickResult = startCondition(inventory, player, index, ClickType.DOUBLE_CLICK, item, cursor); - if (clickResult.isCancel()) - break; - - final int totalAmount = amount + cursorRule.getAmount(item); - if (!cursorRule.canApply(cursor, totalAmount)) { - cursor = cursorRule.apply(cursor, cursorRule.getMaxSize()); - - item = itemRule.apply(item, totalAmount - itemRule.getMaxSize()); - } else { - cursor = cursorRule.apply(cursor, totalAmount); - item = itemRule.apply(item, 0); - } - itemSetter.accept(index, item); - amount = cursorRule.getAmount(cursor); - - callClickEvent(player, inventory, index, ClickType.DOUBLE_CLICK, item, cursor); - } + if (Objects.equals(clickedInventory, inventory)) { + // Clicked inside inventory + remain = func.apply(inventory, remain); + if (!remain.isAir()) { + remain = func.apply(playerInventory, remain); } + } else if (inventory != null && clickedInventory == playerInventory) { + // Clicked inside player inventory, but with another inventory open + remain = func.apply(playerInventory, remain); + if (!remain.isAir()) { + remain = func.apply(inventory, remain); + } + } else { + // Clicked inside player inventory + remain = func.apply(playerInventory, remain); } - clickResult.setCursor(cursor); + final int tookAmount = remainingAmount - cursorRule.getAmount(remain); + ItemStack resultCursor = cursorRule.apply(cursor, amount + tookAmount); + clickResult.setCursor(resultCursor); return clickResult; }