From 60f57680110928c53c9b744550ec25ddeb0300be Mon Sep 17 00:00:00 2001 From: TheMode Date: Wed, 14 Aug 2019 06:50:03 +0200 Subject: [PATCH] Inventory click listener --- .../fr/themode/minestom/entity/Player.java | 1 + .../themode/minestom/inventory/Inventory.java | 66 +++++++++-- .../minestom/inventory/InventoryModifier.java | 12 ++ .../minestom/inventory/PlayerInventory.java | 111 +++++++++++++++--- .../fr/themode/minestom/item/ItemStack.java | 2 +- .../packet/client/login/LoginStartPacket.java | 5 +- .../client/play/ClientClickWindowPacket.java | 2 +- 7 files changed, 165 insertions(+), 34 deletions(-) create mode 100644 src/main/java/fr/themode/minestom/inventory/InventoryModifier.java diff --git a/src/main/java/fr/themode/minestom/entity/Player.java b/src/main/java/fr/themode/minestom/entity/Player.java index adccd783c..1741e9816 100644 --- a/src/main/java/fr/themode/minestom/entity/Player.java +++ b/src/main/java/fr/themode/minestom/entity/Player.java @@ -136,6 +136,7 @@ public class Player extends LivingEntity { refreshOpenInventory(null); } playerConnection.sendPacket(closeWindowPacket); + inventory.update(); } public void refreshGameMode(GameMode gameMode) { diff --git a/src/main/java/fr/themode/minestom/inventory/Inventory.java b/src/main/java/fr/themode/minestom/inventory/Inventory.java index ef44875fe..c3b02c16f 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.entity.Player; import fr.themode.minestom.item.ItemStack; +import fr.themode.minestom.net.packet.server.play.SetSlotPacket; import fr.themode.minestom.net.packet.server.play.WindowItemsPacket; import java.util.Arrays; @@ -11,7 +12,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.atomic.AtomicInteger; -public class Inventory implements InventoryClickHandler { +public class Inventory implements InventoryModifier, InventoryClickHandler { private static AtomicInteger lastInventoryId = new AtomicInteger(); @@ -52,6 +53,7 @@ public class Inventory implements InventoryClickHandler { return id; } + @Override public void setItemStack(int slot, ItemStack itemStack) { if (slot < 0 || slot > inventoryType.getAdditionalSlot()) throw new IllegalArgumentException(inventoryType.toString() + " does not have slot " + slot); @@ -59,6 +61,12 @@ public class Inventory implements InventoryClickHandler { safeItemInsert(slot, itemStack); } + @Override + public boolean addItemStack(ItemStack itemStack) { + return false; + } + + @Override public ItemStack getItemStack(int slot) { return itemStacks[slot]; } @@ -88,7 +96,13 @@ public class Inventory implements InventoryClickHandler { private void safeItemInsert(int slot, ItemStack itemStack) { synchronized (this) { - this.itemStacks[slot] = itemStack == null ? ItemStack.AIR_ITEM : itemStack; + itemStack = itemStack == null ? ItemStack.AIR_ITEM : itemStack; + this.itemStacks[slot] = itemStack; + SetSlotPacket setSlotPacket = new SetSlotPacket(); + setSlotPacket.windowId = 1; + setSlotPacket.slot = (short) slot; + setSlotPacket.itemStack = itemStack; + getViewers().forEach(player -> player.getPlayerConnection().sendPacket(setSlotPacket)); } } @@ -125,9 +139,9 @@ public class Inventory implements InventoryClickHandler { resultCursor = cursorItem.clone(); resultClicked = clicked.clone(); int amount = cursorItem.getAmount() + clicked.getAmount(); - if (amount > 100) { - resultCursor.setAmount((byte) (amount - 100)); - resultClicked.setAmount((byte) 100); + if (amount > 64) { + resultCursor.setAmount((byte) (amount - 64)); + resultClicked.setAmount((byte) 64); } else { resultCursor = ItemStack.AIR_ITEM; resultClicked.setAmount((byte) amount); @@ -140,11 +154,11 @@ public class Inventory implements InventoryClickHandler { if (isInWindow) { setItemStack(slot, resultClicked); setCursorPlayerItem(player, resultCursor); - updateItems(); + //updateItems(); } else { playerInventory.setItemStack(slot, offset, resultClicked); setCursorPlayerItem(player, resultCursor); - playerInventory.update(); + //playerInventory.update(); } } @@ -165,7 +179,7 @@ public class Inventory implements InventoryClickHandler { resultCursor = cursorItem.clone(); resultClicked = clicked.clone(); int amount = clicked.getAmount() + 1; - if (amount > 100) { + if (amount > 64) { return; } else { resultCursor = cursorItem.clone(); @@ -200,11 +214,9 @@ public class Inventory implements InventoryClickHandler { if (isInWindow) { setItemStack(slot, resultClicked); setCursorPlayerItem(player, resultCursor); - updateItems(); } else { playerInventory.setItemStack(slot, offset, resultClicked); setCursorPlayerItem(player, resultCursor); - playerInventory.update(); } } @@ -215,7 +227,41 @@ public class Inventory implements InventoryClickHandler { @Override public void changeHeld(Player player, int slot, int key) { + PlayerInventory playerInventory = player.getInventory(); + if (!getCursorItem(player).isAir()) + return; + + boolean isInWindow = isClickInWindow(slot); + ItemStack heldItem = playerInventory.getItemStack(key); + ItemStack clicked = isInWindow ? getItemStack(slot) : playerInventory.getItemStack(slot, offset); + + ItemStack resultClicked; + ItemStack resultHeld; + + if (clicked.isAir()) { + // Set held item [key] to slot + resultClicked = ItemStack.AIR_ITEM; + resultHeld = clicked.clone(); + } else { + if (heldItem.isAir()) { + // if held item [key] is air then set clicked to held + resultClicked = ItemStack.AIR_ITEM; + resultHeld = clicked.clone(); + } else { + System.out.println("CASE3"); + // Otherwise replace held item and held + resultClicked = heldItem.clone(); + resultHeld = clicked.clone(); + } + } + + if (isInWindow) { + setItemStack(slot, resultClicked); + } else { + playerInventory.setItemStack(slot, offset, resultClicked); + } + playerInventory.setItemStack(key, resultHeld); } @Override diff --git a/src/main/java/fr/themode/minestom/inventory/InventoryModifier.java b/src/main/java/fr/themode/minestom/inventory/InventoryModifier.java new file mode 100644 index 000000000..305fc78bb --- /dev/null +++ b/src/main/java/fr/themode/minestom/inventory/InventoryModifier.java @@ -0,0 +1,12 @@ +package fr.themode.minestom.inventory; + +import fr.themode.minestom.item.ItemStack; + +public interface InventoryModifier { + + void setItemStack(int slot, ItemStack itemStack); + + boolean addItemStack(ItemStack itemStack); + + ItemStack getItemStack(int slot); +} diff --git a/src/main/java/fr/themode/minestom/inventory/PlayerInventory.java b/src/main/java/fr/themode/minestom/inventory/PlayerInventory.java index 596fb90f0..9ca1f2463 100644 --- a/src/main/java/fr/themode/minestom/inventory/PlayerInventory.java +++ b/src/main/java/fr/themode/minestom/inventory/PlayerInventory.java @@ -2,15 +2,29 @@ package fr.themode.minestom.inventory; import fr.themode.minestom.entity.Player; import fr.themode.minestom.item.ItemStack; +import fr.themode.minestom.net.packet.server.play.SetSlotPacket; import fr.themode.minestom.net.packet.server.play.WindowItemsPacket; import fr.themode.minestom.net.player.PlayerConnection; import java.util.Arrays; -public class PlayerInventory { +public class PlayerInventory implements InventoryModifier { + + private static final int TOTAL_INVENTORY_SIZE = 46; + + private static final int CRAFT_SLOT_1 = 36; + private static final int CRAFT_SLOT_2 = 37; + private static final int CRAFT_SLOT_3 = 38; + private static final int CRAFT_SLOT_4 = 39; + private static final int CRAFT_RESULT = 40; + private static final int HELMET_SLOT = 41; + private static final int CHESTPLATE_SLOT = 42; + private static final int LEGGINGS_SLOT = 43; + private static final int BOOTS_SLOT = 44; + private static final int OFFHAND_SLOT = 45; private Player player; - private ItemStack[] items = new ItemStack[45]; + private ItemStack[] items = new ItemStack[TOTAL_INVENTORY_SIZE]; public PlayerInventory(Player player) { this.player = player; @@ -18,28 +32,67 @@ public class PlayerInventory { Arrays.fill(items, ItemStack.AIR_ITEM); } + @Override public ItemStack getItemStack(int slot) { return this.items[slot]; } + @Override public void setItemStack(int slot, ItemStack itemStack) { safeItemInsert(slot, itemStack); } + @Override + public boolean addItemStack(ItemStack itemStack) { + synchronized (this) { + for (int i = 0; i < items.length - 10; i++) { + ItemStack item = items[i]; + if (item.isAir()) { + setItemStack(i, itemStack); + return true; + } else if (itemStack.isSimilar(item)) { + // TODO check max stack size + int itemAmount = item.getAmount(); + if (itemAmount == 64) + continue; + int totalAmount = itemStack.getAmount() + itemAmount; + if (totalAmount > 64) { + item.setAmount((byte) 64); + sendSlotRefresh((short) convertToPacketSlot(i), item); + itemStack.setAmount((byte) (totalAmount - 64)); + } else { + item.setAmount((byte) totalAmount); + sendSlotRefresh((short) convertToPacketSlot(i), item); + return true; + } + } + } + } + return false; + } + public void setHelmet(ItemStack itemStack) { - safeItemInsert(5, itemStack); + safeItemInsert(HELMET_SLOT, itemStack); } public void setChestplate(ItemStack itemStack) { - safeItemInsert(6, itemStack); + safeItemInsert(CHESTPLATE_SLOT, itemStack); } public void setLeggings(ItemStack itemStack) { - safeItemInsert(7, itemStack); + safeItemInsert(LEGGINGS_SLOT, itemStack); } public void setBoots(ItemStack itemStack) { - safeItemInsert(8, itemStack); + safeItemInsert(BOOTS_SLOT, itemStack); + } + + public void setItemInMainHand(ItemStack itemStack) { + safeItemInsert(player.getHeldSlot(), itemStack); + } + + public void setItemInOffHand(ItemStack itemStack) { + safeItemInsert(OFFHAND_SLOT, itemStack); } public void update() { @@ -49,13 +102,15 @@ public class PlayerInventory { private void safeItemInsert(int slot, ItemStack itemStack) { synchronized (this) { - this.items[slot] = itemStack == null ? ItemStack.AIR_ITEM : itemStack; + itemStack = itemStack == null ? ItemStack.AIR_ITEM : itemStack; + this.items[slot] = itemStack; + System.out.println("INSERT: " + slot); + sendSlotRefresh((short) slot, itemStack); } } protected void setItemStack(int slot, int offset, ItemStack itemStack) { slot = convertSlot(slot, offset); - // System.out.println("NEWSLOT: "+slot +" : "+itemStack.getItemId()); safeItemInsert(slot, itemStack); } @@ -64,6 +119,7 @@ public class PlayerInventory { return this.items[slot]; } + protected int convertSlot(int slot, int offset) { final int rowSize = 9; slot -= offset; @@ -72,27 +128,44 @@ public class PlayerInventory { } else { slot = slot + rowSize; } - System.out.println("DEBUG: " + slot); return slot; } + private int convertToPacketSlot(int slot) { + if (slot > -1 && slot < 9) { // Held bar 0-9 + slot = slot + 36; + } else if (slot > 8 && slot < 36) { // Inventory 9-35 + slot = slot; + } else if (slot >= CRAFT_SLOT_1 && slot <= CRAFT_RESULT) { // Crafting 36-40 + slot = slot - 36; + } else if (slot >= HELMET_SLOT && slot <= BOOTS_SLOT) { // Armor 41-44 + slot = slot - 36; + } else if (slot == OFFHAND_SLOT) { // Off hand + slot = 45; + } + return slot; + } + + private void sendSlotRefresh(short slot, ItemStack itemStack) { + SetSlotPacket setSlotPacket = new SetSlotPacket(); + setSlotPacket.windowId = (byte) (slot > 35 && slot < TOTAL_INVENTORY_SIZE ? 0 : -2); + setSlotPacket.slot = slot; + setSlotPacket.itemStack = itemStack; + player.getPlayerConnection().sendPacket(setSlotPacket); + } + private WindowItemsPacket createWindowItemsPacket() { - ItemStack[] convertedSlots = new ItemStack[45]; + ItemStack[] convertedSlots = new ItemStack[TOTAL_INVENTORY_SIZE]; Arrays.fill(convertedSlots, ItemStack.AIR_ITEM); // TODO armor and craft - // Hotbar - for (int i = 0; i < 9; i++) { - convertedSlots[36 + i] = items[i]; - } - - // Inventory - for (int i = 10; i < 9 + 9 * 3; i++) { - convertedSlots[i] = items[i]; + for (int i = 0; i < items.length; i++) { + int slot = convertToPacketSlot(i); + convertedSlots[slot] = items[i]; } WindowItemsPacket windowItemsPacket = new WindowItemsPacket(); windowItemsPacket.windowId = 0; - windowItemsPacket.count = 45; + windowItemsPacket.count = TOTAL_INVENTORY_SIZE; windowItemsPacket.items = convertedSlots; return windowItemsPacket; } diff --git a/src/main/java/fr/themode/minestom/item/ItemStack.java b/src/main/java/fr/themode/minestom/item/ItemStack.java index 14bab5d76..9e452fda6 100644 --- a/src/main/java/fr/themode/minestom/item/ItemStack.java +++ b/src/main/java/fr/themode/minestom/item/ItemStack.java @@ -1,6 +1,6 @@ package fr.themode.minestom.item; -public class ItemStack implements Cloneable { +public class ItemStack { public static final ItemStack AIR_ITEM = new ItemStack(0, (byte) 1); diff --git a/src/main/java/fr/themode/minestom/net/packet/client/login/LoginStartPacket.java b/src/main/java/fr/themode/minestom/net/packet/client/login/LoginStartPacket.java index 0cee77cd1..57592cc1c 100644 --- a/src/main/java/fr/themode/minestom/net/packet/client/login/LoginStartPacket.java +++ b/src/main/java/fr/themode/minestom/net/packet/client/login/LoginStartPacket.java @@ -143,9 +143,8 @@ public class LoginStartPacket implements ClientPreplayPacket { //System.out.println("HAHAHAHHAHHAH " + player.getUuid()); PlayerInventory inventory = player.getInventory(); - inventory.setItemStack(1, new ItemStack(1, (byte) 32)); - inventory.setItemStack(2, new ItemStack(1, (byte) 32)); - inventory.update(); + inventory.addItemStack(new ItemStack(1, (byte) 60)); + inventory.addItemStack(new ItemStack(1, (byte) 50)); Inventory inv = new Inventory(InventoryType.WINDOW_3X3, "Salut je suis le titre"); inv.setItemStack(0, new ItemStack(1, (byte) 1)); diff --git a/src/main/java/fr/themode/minestom/net/packet/client/play/ClientClickWindowPacket.java b/src/main/java/fr/themode/minestom/net/packet/client/play/ClientClickWindowPacket.java index 148e9e762..0fea667d5 100644 --- a/src/main/java/fr/themode/minestom/net/packet/client/play/ClientClickWindowPacket.java +++ b/src/main/java/fr/themode/minestom/net/packet/client/play/ClientClickWindowPacket.java @@ -52,7 +52,7 @@ public class ClientClickWindowPacket implements ClientPlayPacket { } break; case 2: - // Number key 1-9 + inventory.changeHeld(player, slot, button); break; case 3: // Middle click (only creative players in non-player inventories)