diff --git a/src/main/java/fr/themode/minestom/inventory/Inventory.java b/src/main/java/fr/themode/minestom/inventory/Inventory.java index 0ee527237..245530290 100644 --- a/src/main/java/fr/themode/minestom/inventory/Inventory.java +++ b/src/main/java/fr/themode/minestom/inventory/Inventory.java @@ -2,6 +2,7 @@ package fr.themode.minestom.inventory; import fr.themode.minestom.Viewable; import fr.themode.minestom.entity.Player; +import fr.themode.minestom.inventory.click.InventoryClickLoopHandler; import fr.themode.minestom.inventory.click.InventoryClickProcessor; import fr.themode.minestom.inventory.click.InventoryClickResult; import fr.themode.minestom.inventory.condition.InventoryCondition; @@ -372,109 +373,36 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View @Override public void doubleClick(Player player, int slot) { PlayerInventory playerInventory = player.getInventory(); - boolean isInWindow = isClickInWindow(slot); - ItemStack clicked = isInWindow ? getItemStack(slot) : playerInventory.getItemStack(slot, offset); // Isn't used in the algorithm - ItemStack cursorItem = getCursorItem(player); + ItemStack cursor = getCursorItem(player); - // Start condition - InventoryCondition inventoryCondition = getInventoryCondition(); - if (inventoryCondition != null) { - InventoryConditionResult result = new InventoryConditionResult(clicked, cursorItem); - inventoryCondition.accept(player, slot, result); - cursorItem = result.getCursorItem(); - clicked = result.getClickedItem(); + InventoryClickResult clickResult = clickProcessor.doubleClick(getInventoryCondition(), player, slot, cursor, + // Start by looping through the opened inventory + new InventoryClickLoopHandler(0, itemStacks.length, 1, + i -> i, + index -> itemStacks[index], + (index, itemStack) -> setItemStack(index, itemStack)), + // Looping through player inventory + new InventoryClickLoopHandler(0, PlayerInventory.INVENTORY_SIZE - 9, 1, + i -> playerInventory.convertToPacketSlot(i), + index -> playerInventory.getItemStack(index, offset), + (index, itemStack) -> playerInventory.setItemStack(index, offset, itemStack)), + // Player hotbar + new InventoryClickLoopHandler(0, 9, 1, + i -> playerInventory.convertToPacketSlot(i), + index -> playerInventory.getItemStack(index, offset), + (index, itemStack) -> { + playerInventory.setItemStack(index, offset, itemStack); + System.out.println("try: " + index); + })); - if (result.isCancel()) { - //System.out.println(clicked.getMaterial() + " + " + cursorItem.getMaterial()); - if (isInWindow) { - setItemStack(slot, clicked); - setCursorPlayerItem(player, cursorItem); - } else { - playerInventory.setItemStack(slot, offset, clicked); - setCursorPlayerItem(player, cursorItem); - } - // Refresh client window - player.getPlayerConnection().sendPacket(getWindowItemsPacket()); - return; - } - } - // End condition - - if (cursorItem.isAir()) + if (clickResult == null) return; - int amount = cursorItem.getAmount(); + if (clickResult.doRefresh()) + update(); - StackingRule cursorRule = cursorItem.getStackingRule(); - int maxSize = cursorRule.getMaxSize(); - - if (amount == maxSize) - return; - - // Start by looping through the opened inventory - for (int i = 0; i < itemStacks.length; i++) { - if (i == slot) - continue; - if (amount == maxSize) - break; - ItemStack item = itemStacks[i]; - if (cursorRule.canBeStacked(cursorItem, item)) { - int totalAmount = amount + item.getAmount(); - if (!cursorRule.canApply(cursorItem, totalAmount)) { - cursorItem = cursorRule.apply(cursorItem, maxSize); - item = cursorRule.apply(item, totalAmount - maxSize); - setItemStack(i, item); - } else { - cursorItem = cursorRule.apply(cursorItem, totalAmount); - setItemStack(i, ItemStack.AIR_ITEM); - } - amount = cursorItem.getAmount(); - } - } - - // Looping through player inventory - for (int i = 9; i < PlayerInventory.INVENTORY_SIZE - 9; i++) { // Inventory - if (playerInventory.convertToPacketSlot(i) == slot) - continue; - if (amount == maxSize) - break; - ItemStack item = playerInventory.getItemStack(i); - if (cursorRule.canBeStacked(cursorItem, item)) { - int totalAmount = amount + item.getAmount(); - if (!cursorRule.canApply(cursorItem, totalAmount)) { - cursorItem = cursorRule.apply(cursorItem, maxSize); - item = cursorRule.apply(item, totalAmount - maxSize); - playerInventory.setItemStack(i, offset, item); - } else { - cursorItem = cursorRule.apply(cursorItem, totalAmount); - playerInventory.setItemStack(i, offset, ItemStack.AIR_ITEM); - } - amount = cursorItem.getAmount(); - } - } - - for (int i = 0; i < 9; i++) { // Hotbar - if (playerInventory.convertToPacketSlot(i) == slot) - continue; - if (amount == maxSize) - break; - ItemStack item = playerInventory.getItemStack(i); - if (cursorRule.canBeStacked(cursorItem, item)) { - int totalAmount = amount + item.getAmount(); - if (!cursorRule.canApply(cursorItem, totalAmount)) { - cursorItem = cursorRule.apply(cursorItem, maxSize); - item = cursorRule.apply(item, totalAmount - maxSize); - playerInventory.setItemStack(i, offset, item); - } else { - cursorItem = cursorRule.apply(cursorItem, totalAmount); - playerInventory.setItemStack(i, offset, ItemStack.AIR_ITEM); - } - amount = cursorItem.getAmount(); - } - } - - setCursorPlayerItem(player, cursorItem); + setCursorPlayerItem(player, clickResult.getCursor()); playerInventory.update(); } } diff --git a/src/main/java/fr/themode/minestom/inventory/PlayerInventory.java b/src/main/java/fr/themode/minestom/inventory/PlayerInventory.java index fe77a1eda..d97ae5c72 100644 --- a/src/main/java/fr/themode/minestom/inventory/PlayerInventory.java +++ b/src/main/java/fr/themode/minestom/inventory/PlayerInventory.java @@ -2,6 +2,7 @@ package fr.themode.minestom.inventory; import fr.themode.minestom.entity.Player; import fr.themode.minestom.event.ArmorEquipEvent; +import fr.themode.minestom.inventory.click.InventoryClickLoopHandler; import fr.themode.minestom.inventory.click.InventoryClickProcessor; import fr.themode.minestom.inventory.click.InventoryClickResult; import fr.themode.minestom.inventory.condition.InventoryCondition; @@ -422,66 +423,28 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler if (clickResult == null) return; + if (clickResult.doRefresh()) + update(); + setCursorItem(clickResult.getCursor()); } @Override public void doubleClick(Player player, int slot) { - ItemStack cursorItem = getCursorItem(); - ItemStack clicked = getItemStack(slot, OFFSET); + ItemStack cursor = getCursorItem(); - // Start condition - InventoryCondition inventoryCondition = getInventoryCondition(); - if (inventoryCondition != null) { - InventoryConditionResult result = new InventoryConditionResult(clicked, cursorItem); - inventoryCondition.accept(player, slot, result); + InventoryClickResult clickResult = clickProcessor.doubleClick(getInventoryCondition(), player, slot, cursor, + new InventoryClickLoopHandler(0, items.length, 1, + i -> i < 9 ? i + 9 : i - 9, + index -> items[index], + (index, itemStack) -> setItemStack(index, itemStack))); - cursorItem = result.getCursorItem(); - clicked = result.getClickedItem(); - - if (result.isCancel()) { - setItemStack(slot, OFFSET, clicked); - setCursorItem(cursorItem); - // Refresh client slot - sendSlotRefresh((short) slot, clicked); - return; - } - } - // End condition - - if (cursorItem.isAir()) + if (clickResult == null) return; - StackingRule cursorRule = cursorItem.getStackingRule(); - int amount = cursorItem.getAmount(); + if (clickResult.doRefresh()) + update(); - if (!cursorRule.canApply(cursorItem, amount + 1)) - return; - - for (int i = 0; i < items.length; i++) { - int index = i < 9 ? i + 9 : i - 9; - if (index == slot) - continue; - ItemStack item = items[index]; - StackingRule itemRule = item.getStackingRule(); - if (!cursorRule.canApply(cursorItem, amount + 1)) - break; - if (cursorRule.canBeStacked(cursorItem, item)) { - int totalAmount = amount + item.getAmount(); - if (!cursorRule.canApply(cursorItem, totalAmount)) { - cursorItem = cursorRule.apply(cursorItem, cursorRule.getMaxSize()); - - item = itemRule.apply(item, totalAmount - itemRule.getMaxSize()); - setItemStack(index, item); - } else { - cursorItem = cursorRule.apply(cursorItem, totalAmount); - item = itemRule.apply(item, 0); - setItemStack(index, item); - } - amount = cursorItem.getAmount(); - } - } - - setCursorItem(cursorItem); + setCursorItem(clickResult.getCursor()); } } diff --git a/src/main/java/fr/themode/minestom/inventory/click/InventoryClickLoopHandler.java b/src/main/java/fr/themode/minestom/inventory/click/InventoryClickLoopHandler.java new file mode 100644 index 000000000..12ab0ce68 --- /dev/null +++ b/src/main/java/fr/themode/minestom/inventory/click/InventoryClickLoopHandler.java @@ -0,0 +1,52 @@ +package fr.themode.minestom.inventory.click; + +import fr.themode.minestom.item.ItemStack; + +import java.util.function.BiConsumer; +import java.util.function.Function; + +public class InventoryClickLoopHandler { + + private int start; + private int end; + private int step; + private Function indexModifier; + private Function itemGetter; + private BiConsumer itemSetter; + + public InventoryClickLoopHandler(int start, int end, int step, + Function indexModifier, + Function itemGetter, + BiConsumer itemSetter) { + this.start = start; + this.end = end; + this.step = step; + this.indexModifier = indexModifier; + this.itemGetter = itemGetter; + this.itemSetter = itemSetter; + } + + public int getStart() { + return start; + } + + public int getEnd() { + return end; + } + + public int getStep() { + return step; + } + + public Function getIndexModifier() { + return indexModifier; + } + + public Function getItemGetter() { + return itemGetter; + } + + public BiConsumer getItemSetter() { + return itemSetter; + } +} diff --git a/src/main/java/fr/themode/minestom/inventory/click/InventoryClickProcessor.java b/src/main/java/fr/themode/minestom/inventory/click/InventoryClickProcessor.java index 0f11aec95..09b1938eb 100644 --- a/src/main/java/fr/themode/minestom/inventory/click/InventoryClickProcessor.java +++ b/src/main/java/fr/themode/minestom/inventory/click/InventoryClickProcessor.java @@ -227,21 +227,25 @@ public class InventoryClickProcessor { for (Integer s : slots) { ItemStack draggedItem = cursor.clone(); ItemStack slotItem = itemGetter.apply(s); + clickResult = startCondition(clickResult, inventoryCondition, player, s, slotItem, cursor); if (clickResult.isCancel()) continue; + if (stackingRule.canBeStacked(draggedItem, slotItem)) { int amount = slotItem.getAmount() + 1; if (stackingRule.canApply(slotItem, amount)) { slotItem = stackingRule.apply(slotItem, amount); itemSetter.accept(s, slotItem); + cursorAmount -= 1; } } else if (slotItem.isAir()) { draggedItem = stackingRule.apply(draggedItem, 1); itemSetter.accept(s, draggedItem); + cursorAmount -= 1; } } - cursor = stackingRule.apply(cursor, cursorAmount - size); + cursor = stackingRule.apply(cursor, cursorAmount); clickResult.setCursor(cursor); rightDraggingMap.remove(player); @@ -266,6 +270,62 @@ public class InventoryClickProcessor { return clickResult; } + public InventoryClickResult doubleClick(InventoryCondition inventoryCondition, Player player, int slot, + ItemStack cursor, InventoryClickLoopHandler... loopHandlers) { + InventoryClickResult clickResult = new InventoryClickResult(ItemStack.AIR_ITEM, cursor); + + if (clickResult.isCancel()) { + return clickResult; + } + + if (cursor.isAir()) + return null; + + StackingRule cursorRule = cursor.getStackingRule(); + int amount = cursorRule.getAmount(cursor); + + if (!cursorRule.canApply(cursor, amount + 1)) + return null; + + for (InventoryClickLoopHandler loopHandler : loopHandlers) { + Function indexModifier = loopHandler.getIndexModifier(); + Function itemGetter = loopHandler.getItemGetter(); + BiConsumer itemSetter = loopHandler.getItemSetter(); + + for (int i = loopHandler.getStart(); i < loopHandler.getEnd(); i += loopHandler.getStep()) { + int index = indexModifier.apply(i); + if (index == slot) + continue; + + ItemStack item = itemGetter.apply(index); + StackingRule itemRule = item.getStackingRule(); + if (!cursorRule.canApply(cursor, amount + 1)) + break; + if (cursorRule.canBeStacked(cursor, item)) { + clickResult = startCondition(clickResult, inventoryCondition, player, index, item, cursor); + if (clickResult.isCancel()) + continue; + + 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); + } + } + } + + clickResult.setCursor(cursor); + + return clickResult; + } + private InventoryClickResult startCondition(InventoryClickResult clickResult, InventoryCondition inventoryCondition, Player player, int slot, ItemStack clicked, ItemStack cursor) { if (inventoryCondition != null) { InventoryConditionResult result = new InventoryConditionResult(clicked, cursor);