diff --git a/src/main/java/net/minestom/server/inventory/AbstractInventory.java b/src/main/java/net/minestom/server/inventory/AbstractInventory.java index 88abcb383..f0d1c1b34 100644 --- a/src/main/java/net/minestom/server/inventory/AbstractInventory.java +++ b/src/main/java/net/minestom/server/inventory/AbstractInventory.java @@ -2,20 +2,43 @@ package net.minestom.server.inventory; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import net.minestom.server.data.Data; +import net.minestom.server.data.DataContainer; +import net.minestom.server.inventory.click.InventoryClickProcessor; import net.minestom.server.inventory.condition.InventoryCondition; import net.minestom.server.item.ItemStack; import net.minestom.server.item.StackingRule; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.UnaryOperator; /** * Represents an inventory where items can be modified/retrieved. */ -public abstract class AbstractInventory { +public abstract class AbstractInventory implements DataContainer { + + private final int size; + protected final ItemStack[] itemStacks; + + // list of conditions/callbacks assigned to this inventory + protected final List inventoryConditions = new CopyOnWriteArrayList<>(); + // the click processor which process all the clicks in the inventory + protected final InventoryClickProcessor clickProcessor = new InventoryClickProcessor(); + + private Data data; + + protected AbstractInventory(int size) { + this.size = size; + this.itemStacks = new ItemStack[getSize()]; + + Arrays.fill(itemStacks, ItemStack.AIR); + } /** * Sets an {@link ItemStack} at the specified slot and send relevant update to the viewer(s). @@ -35,7 +58,7 @@ public abstract class AbstractInventory { * @param itemStack the item to add * @return true if the item has been successfully fully added, false otherwise */ - public boolean addItemStack(@NotNull ItemStack itemStack) { + public synchronized boolean addItemStack(@NotNull ItemStack itemStack) { Int2ObjectMap itemChangesMap = new Int2ObjectOpenHashMap<>(); final StackingRule stackingRule = itemStack.getStackingRule(); @@ -235,7 +258,7 @@ public abstract class AbstractInventory { return itemStacks.stream().allMatch(this::canTakeItemStack); } - public void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) { + public synchronized void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) { var currentItem = getItemStack(slot); setItemStack(slot, operator.apply(currentItem)); } @@ -243,7 +266,14 @@ public abstract class AbstractInventory { /** * Clears the inventory and send relevant update to the viewer(s). */ - public abstract void clear(); + public synchronized void clear() { + // Clear the item array + Arrays.fill(itemStacks, ItemStack.AIR); + // Send the cleared inventory to viewers + update(); + } + + public abstract void update(); /** * Gets the {@link ItemStack} at the specified slot. @@ -252,7 +282,9 @@ public abstract class AbstractInventory { * @return the item in the slot {@code slot} */ @NotNull - public abstract ItemStack getItemStack(int slot); + public ItemStack getItemStack(int slot) { + return itemStacks[slot]; + } /** * Gets all the {@link ItemStack} in the inventory. @@ -263,14 +295,18 @@ public abstract class AbstractInventory { * @return an array containing all the inventory's items */ @NotNull - public abstract ItemStack[] getItemStacks(); + public ItemStack[] getItemStacks() { + return itemStacks.clone(); + } /** * Gets the size of the inventory. * * @return the inventory's size */ - public abstract int getSize(); + public int getSize() { + return size; + } /** * Gets the size of the "inner inventory" (which includes only "usable" slots). @@ -287,14 +323,18 @@ public abstract class AbstractInventory { * @return a modifiable {@link List} containing all the inventory conditions */ @NotNull - public abstract List getInventoryConditions(); + public List getInventoryConditions() { + return inventoryConditions; + } /** * Adds a new {@link InventoryCondition} to this inventory. * * @param inventoryCondition the inventory condition to add */ - public abstract void addInventoryCondition(@NotNull InventoryCondition inventoryCondition); + public void addInventoryCondition(@NotNull InventoryCondition inventoryCondition) { + this.inventoryConditions.add(inventoryCondition); + } /** * Places all the items of {@code itemStacks} into the internal array. @@ -313,4 +353,15 @@ public abstract class AbstractInventory { setItemStack(i, itemStack); } } + + @Nullable + @Override + public Data getData() { + return data; + } + + @Override + public void setData(@Nullable Data data) { + this.data = data; + } } diff --git a/src/main/java/net/minestom/server/inventory/Inventory.java b/src/main/java/net/minestom/server/inventory/Inventory.java index 0bb92d6e9..c66dae445 100644 --- a/src/main/java/net/minestom/server/inventory/Inventory.java +++ b/src/main/java/net/minestom/server/inventory/Inventory.java @@ -1,14 +1,10 @@ package net.minestom.server.inventory; import net.minestom.server.Viewable; -import net.minestom.server.data.Data; -import net.minestom.server.data.DataContainer; 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.InventoryClickProcessor; import net.minestom.server.inventory.click.InventoryClickResult; -import net.minestom.server.inventory.condition.InventoryCondition; import net.minestom.server.item.ItemStack; import net.minestom.server.network.packet.server.play.OpenWindowPacket; import net.minestom.server.network.packet.server.play.SetSlotPacket; @@ -19,17 +15,12 @@ import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.inventory.PlayerInventoryUtils; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import java.util.Arrays; import java.util.Collections; -import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.UnaryOperator; /** * Represents an inventory which can be viewed by a collection of {@link Player}. @@ -37,7 +28,7 @@ import java.util.function.UnaryOperator; * You can create one with {@link Inventory#Inventory(InventoryType, String)} or by making your own subclass. * It can then be opened using {@link Player#openInventory(Inventory)}. */ -public class Inventory extends AbstractInventory implements InventoryClickHandler, Viewable, DataContainer { +public class Inventory extends AbstractInventory implements InventoryClickHandler, Viewable { // incremented each time an inventory is created (used in the window packets) private static final AtomicInteger LAST_INVENTORY_ID = new AtomicInteger(); @@ -49,37 +40,21 @@ public class Inventory extends AbstractInventory implements InventoryClickHandle // the title of this inventory) private String title; - // the size based on the inventory type - private final int size; - private final int offset; - // the items in this inventory - private final ItemStack[] itemStacks; // the players currently viewing this inventory private final Set viewers = new CopyOnWriteArraySet<>(); private final Set unmodifiableViewers = Collections.unmodifiableSet(viewers); // (player -> cursor item) map, used by the click listeners private final ConcurrentHashMap cursorPlayersItem = new ConcurrentHashMap<>(); - // list of conditions/callbacks assigned to this inventory - private final List inventoryConditions = new CopyOnWriteArrayList<>(); - // the click processor which process all the clicks in the inventory - private final InventoryClickProcessor clickProcessor = new InventoryClickProcessor(); - - private Data data; - public Inventory(@NotNull InventoryType inventoryType, @NotNull String title) { + super(inventoryType.getSize()); this.id = generateId(); this.inventoryType = inventoryType; this.title = title; - this.size = inventoryType.getSize(); - - this.offset = size; - - this.itemStacks = new ItemStack[size]; - Arrays.fill(itemStacks, ItemStack.AIR); + this.offset = getSize(); } private static byte generateId() { @@ -147,58 +122,10 @@ public class Inventory extends AbstractInventory implements InventoryClickHandle safeItemInsert(slot, itemStack); } - @Override - public synchronized boolean addItemStack(@NotNull ItemStack itemStack) { - // Make the method synchronized - return super.addItemStack(itemStack); - } - - @Override - public synchronized void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) { - // Make the method synchronized - super.replaceItemStack(slot, operator); - } - - @Override - public synchronized void clear() { - // Clear the item array - Arrays.fill(itemStacks, ItemStack.AIR); - // Send the cleared inventory to viewers - update(); - } - - - @NotNull - @Override - public ItemStack getItemStack(int slot) { - return itemStacks[slot]; - } - - @NotNull - @Override - public ItemStack[] getItemStacks() { - return itemStacks.clone(); - } - - @Override - public int getSize() { - return size; - } - - @NotNull - @Override - public List getInventoryConditions() { - return inventoryConditions; - } - - @Override - public void addInventoryCondition(@NotNull InventoryCondition inventoryCondition) { - this.inventoryConditions.add(inventoryCondition); - } - /** * Refreshes the inventory for all viewers. */ + @Override public void update() { sendPacketToViewers(createNewWindowItemsPacket()); } @@ -604,15 +531,4 @@ public class Inventory extends AbstractInventory implements InventoryClickHandle update(player); } } - - @Nullable - @Override - public Data getData() { - return data; - } - - @Override - public void setData(@Nullable Data data) { - this.data = data; - } } diff --git a/src/main/java/net/minestom/server/inventory/PlayerInventory.java b/src/main/java/net/minestom/server/inventory/PlayerInventory.java index 72ef75e96..7586d7a6e 100644 --- a/src/main/java/net/minestom/server/inventory/PlayerInventory.java +++ b/src/main/java/net/minestom/server/inventory/PlayerInventory.java @@ -1,14 +1,11 @@ package net.minestom.server.inventory; -import net.minestom.server.data.Data; -import net.minestom.server.data.DataContainer; import net.minestom.server.entity.Player; import net.minestom.server.event.item.ArmorEquipEvent; import net.minestom.server.event.player.PlayerAddItemStackEvent; import net.minestom.server.event.player.PlayerSetItemStackEvent; import net.minestom.server.inventory.click.ClickType; import net.minestom.server.inventory.click.InventoryClickLoopHandler; -import net.minestom.server.inventory.click.InventoryClickProcessor; import net.minestom.server.inventory.click.InventoryClickResult; import net.minestom.server.inventory.condition.InventoryCondition; import net.minestom.server.item.ItemStack; @@ -18,60 +15,34 @@ import net.minestom.server.network.packet.server.play.WindowItemsPacket; import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.validate.Check; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.function.UnaryOperator; import static net.minestom.server.utils.inventory.PlayerInventoryUtils.*; /** * Represents the inventory of a {@link Player}, retrieved with {@link Player#getInventory()}. */ -public class PlayerInventory extends AbstractInventory implements InventoryClickHandler, EquipmentHandler, DataContainer { +public class PlayerInventory extends AbstractInventory implements InventoryClickHandler, EquipmentHandler { public static final int INVENTORY_SIZE = 46; public static final int INNER_INVENTORY_SIZE = 36; protected final Player player; - protected final ItemStack[] itemStacks = new ItemStack[INVENTORY_SIZE]; private ItemStack cursorItem = ItemStack.AIR; - private final List inventoryConditions = new CopyOnWriteArrayList<>(); - private final InventoryClickProcessor clickProcessor = new InventoryClickProcessor(); - - private Data data; - public PlayerInventory(@NotNull Player player) { + super(INVENTORY_SIZE); this.player = player; - Arrays.fill(itemStacks, ItemStack.AIR); - } - - @Override - public @NotNull ItemStack getItemStack(int slot) { - return this.itemStacks[slot]; - } - - @Override - public @NotNull ItemStack[] getItemStacks() { - return itemStacks.clone(); - } - - @Override - public @NotNull List getInventoryConditions() { - return inventoryConditions; } @Override public void addInventoryCondition(@NotNull InventoryCondition inventoryCondition) { + // fix packet slot to inventory slot conversion InventoryCondition condition = (p, slot, clickType, inventoryConditionResult) -> { final int convertedSlot = convertPlayerInventorySlot(slot, OFFSET); inventoryCondition.accept(p, convertedSlot, clickType, inventoryConditionResult); }; - this.inventoryConditions.add(condition); + super.addInventoryCondition(condition); } @Override @@ -97,29 +68,13 @@ public class PlayerInventory extends AbstractInventory implements InventoryClick return super.addItemStack(itemStack); } - @Override - public synchronized void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) { - // Make the method synchronized - super.replaceItemStack(slot, operator); - } - @Override public synchronized void clear() { - // Clear the item array - Arrays.fill(itemStacks, ItemStack.AIR); - - // Send the cleared inventory to the inventory's owner - update(); - + super.clear(); // Update equipments this.player.sendPacketToViewersAndSelf(player.getEquipmentsPacket()); } - @Override - public int getSize() { - return INVENTORY_SIZE; - } - @Override public int getInnerSize() { return INNER_INVENTORY_SIZE; @@ -195,6 +150,7 @@ public class PlayerInventory extends AbstractInventory implements InventoryClick * Refreshes the player inventory by sending a {@link WindowItemsPacket} containing all. * the inventory items */ + @Override public void update() { player.getPlayerConnection().sendPacket(createWindowItemsPacket()); } @@ -499,15 +455,4 @@ public class PlayerInventory extends AbstractInventory implements InventoryClick return !clickResult.isCancel(); } - - @Nullable - @Override - public Data getData() { - return data; - } - - @Override - public void setData(@Nullable Data data) { - this.data = data; - } }