diff --git a/src/lwjgl/java/net/minestom/demo/largeframebuffers/Demo.java b/src/lwjgl/java/net/minestom/demo/largeframebuffers/Demo.java
index 2516082d7..2fb89afc3 100644
--- a/src/lwjgl/java/net/minestom/demo/largeframebuffers/Demo.java
+++ b/src/lwjgl/java/net/minestom/demo/largeframebuffers/Demo.java
@@ -6,8 +6,9 @@ import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.type.decoration.EntityItemFrame;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceManager;
+import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
-import net.minestom.server.item.metadata.MapMeta;
+import net.minestom.server.item.meta.MapMeta;
import net.minestom.server.map.Framebuffer;
import net.minestom.server.map.LargeFramebuffer;
import net.minestom.server.map.MapColors;
@@ -67,8 +68,9 @@ public class Demo {
private static void createFrame(Instance instance, int id, int x, int y, int z) {
EntityItemFrame itemFrame = new EntityItemFrame(new Position(x, y, z), EntityItemFrame.ItemFrameOrientation.NORTH);
itemFrame.getPosition().setYaw(180f);
- ItemStack map = new ItemStack(Material.FILLED_MAP, (byte) 1);
- map.setItemMeta(new MapMeta(id));
+ ItemStack map = ItemStack.builder(Material.FILLED_MAP)
+ .meta(new MapMeta.Builder().mapId(id).build())
+ .build();
itemFrame.setItemStack(map);
itemFrame.setInstance(instance);
itemFrame.setCustomNameVisible(true);
diff --git a/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayerController.java b/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayerController.java
index 08444fa19..6a9e8eeb2 100644
--- a/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayerController.java
+++ b/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayerController.java
@@ -4,7 +4,7 @@ import net.minestom.server.entity.Entity;
import net.minestom.server.entity.Player;
import net.minestom.server.instance.block.BlockFace;
import net.minestom.server.inventory.Inventory;
-import net.minestom.server.inventory.InventoryModifier;
+import net.minestom.server.inventory.AbstractInventory;
import net.minestom.server.inventory.PlayerInventory;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.client.ClientPlayPacket;
@@ -48,12 +48,12 @@ public class FakePlayerController {
*/
public void clickWindow(boolean playerInventory, short slot, byte button, short action, int mode) {
Inventory inventory = playerInventory ? null : fakePlayer.getOpenInventory();
- InventoryModifier inventoryModifier = inventory == null ? fakePlayer.getInventory() : inventory;
- playerInventory = inventoryModifier instanceof PlayerInventory;
+ AbstractInventory abstractInventory = inventory == null ? fakePlayer.getInventory() : inventory;
+ playerInventory = abstractInventory instanceof PlayerInventory;
slot = playerInventory ? (short) PlayerInventoryUtils.convertToPacketSlot(slot) : slot;
- ItemStack itemStack = inventoryModifier.getItemStack(slot);
+ ItemStack itemStack = abstractInventory.getItemStack(slot);
ClientClickWindowPacket clickWindowPacket = new ClientClickWindowPacket();
clickWindowPacket.windowId = playerInventory ? 0 : inventory.getWindowId();
diff --git a/src/main/java/net/minestom/server/inventory/AbstractInventory.java b/src/main/java/net/minestom/server/inventory/AbstractInventory.java
new file mode 100644
index 000000000..88abcb383
--- /dev/null
+++ b/src/main/java/net/minestom/server/inventory/AbstractInventory.java
@@ -0,0 +1,316 @@
+package net.minestom.server.inventory;
+
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+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 java.util.ArrayList;
+import java.util.List;
+import java.util.function.UnaryOperator;
+
+/**
+ * Represents an inventory where items can be modified/retrieved.
+ */
+public abstract class AbstractInventory {
+
+ /**
+ * Sets an {@link ItemStack} at the specified slot and send relevant update to the viewer(s).
+ *
+ * @param slot the slot to set the item
+ * @param itemStack the item to set
+ */
+ public abstract void setItemStack(int slot, @NotNull ItemStack itemStack);
+
+ protected abstract void safeItemInsert(int slot, @NotNull ItemStack itemStack);
+
+ /**
+ * Adds an {@link ItemStack} to the inventory and sends relevant update to the viewer(s).
+ *
+ * Even the item cannot be fully added, the amount of {@code itemStack} will be updated.
+ *
+ * @param itemStack the item to add
+ * @return true if the item has been successfully fully added, false otherwise
+ */
+ public boolean addItemStack(@NotNull ItemStack itemStack) {
+ Int2ObjectMap itemChangesMap = new Int2ObjectOpenHashMap<>();
+
+ final StackingRule stackingRule = itemStack.getStackingRule();
+ for (int i = 0; i < getInnerSize(); i++) {
+ ItemStack inventoryItem = getItemStack(i);
+ if (inventoryItem.isAir()) {
+ continue;
+ }
+ if (stackingRule.canBeStacked(itemStack, inventoryItem)) {
+ final int itemAmount = stackingRule.getAmount(inventoryItem);
+ if (itemAmount == stackingRule.getMaxSize())
+ continue;
+ final int itemStackAmount = stackingRule.getAmount(itemStack);
+ final int totalAmount = itemStackAmount + itemAmount;
+ if (!stackingRule.canApply(itemStack, totalAmount)) {
+ // Slot cannot accept the whole item, reduce amount to 'itemStack'
+ itemChangesMap.put(i, stackingRule.apply(inventoryItem, stackingRule.getMaxSize()));
+ itemStack = stackingRule.apply(itemStack, totalAmount - stackingRule.getMaxSize());
+ } else {
+ // Slot can accept the whole item
+ itemChangesMap.put(i, inventoryItem.withAmount(totalAmount));
+ itemStack = ItemStack.AIR;
+ break;
+ }
+ }
+ }
+ for (int i = 0; i < getInnerSize(); i++) {
+ ItemStack inventoryItem = getItemStack(i);
+ if (!inventoryItem.isAir()) {
+ continue;
+ }
+ // Fill the slot
+ itemChangesMap.put(i, itemStack);
+ itemStack = ItemStack.AIR;
+ break;
+ }
+
+ if (itemStack.isAir()) {
+ // Item can be fully placed inside the inventory, do so
+ itemChangesMap.forEach(this::safeItemInsert);
+ return true;
+ } else {
+ // Inventory cannot accept the item fully
+ return false;
+ }
+ }
+
+ /**
+ * Adds {@link ItemStack}s to the inventory and sends relevant updates to the viewer(s).
+ *
+ * Even items cannot be fully added, the amount of {@code itemStack}s will be updated.
+ *
+ * @param itemStacks items to add
+ * @return list of itemstacks that could not be successfully fully added, empty list otherwise
+ */
+ public List addItemStacks(@NotNull List itemStacks) {
+ List result = new ArrayList<>();
+ itemStacks.forEach(itemStack -> {
+ if (!addItemStack(itemStack)) {
+ result.add(itemStack);
+ }
+ });
+ return result;
+ }
+
+ /**
+ * Checks whether {@link ItemStack} can be fully added to the inventory.
+ *
+ * @param itemStack the item to be checked
+ * @return true if the item can be fully added to the inventory, false otherwise
+ */
+ public boolean canAddItemStack(@NotNull ItemStack itemStack) {
+ final StackingRule stackingRule = itemStack.getStackingRule();
+ int amountLeft = itemStack.getAmount();
+ for (int i = 0; i < getInnerSize(); i++) {
+ ItemStack inventoryItem = getItemStack(i);
+ if (stackingRule.canBeStacked(itemStack, inventoryItem)) {
+ final int itemAmount = stackingRule.getAmount(inventoryItem);
+ if (itemAmount == stackingRule.getMaxSize())
+ continue;
+ if (!stackingRule.canApply(itemStack, amountLeft + itemAmount)) {
+ // Slot cannot accept the whole item, reduce amount to 'itemStack'
+ amountLeft -= stackingRule.getMaxSize() - itemAmount;
+ } else {
+ return true;
+ }
+ } else if (inventoryItem.isAir()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks whether {@link ItemStack}s can be fully added to the inventory.
+ *
+ * @param itemStacks items to be checked
+ * @return true if all the items can be fully added to the inventory, false otherwise
+ */
+ public boolean canAddItemStacks(@NotNull List itemStacks) {
+ return itemStacks.stream().allMatch(this::canAddItemStack);
+ }
+
+ /**
+ * Takes an {@link ItemStack} from the inventory and sends relevant update to the viewer(s).
+ *
+ * Even the item cannot be fully taken, the amount of {@code itemStack} will be updated.
+ *
+ * @param itemStack the item to take
+ * @return true if the item has been successfully fully taken, false otherwise
+ */
+ public boolean takeItemStack(@NotNull ItemStack itemStack) {
+ Int2ObjectMap itemChangesMap = new Int2ObjectOpenHashMap<>();
+
+ final StackingRule stackingRule = itemStack.getStackingRule();
+ for (int i = 0; i < getInnerSize(); i++) {
+ ItemStack inventoryItem = getItemStack(i);
+ if (inventoryItem.isAir()) {
+ continue;
+ }
+ if (stackingRule.canBeStacked(itemStack, inventoryItem)) {
+ final int itemAmount = stackingRule.getAmount(inventoryItem);
+ final int itemStackAmount = stackingRule.getAmount(itemStack);
+ if (itemStackAmount < itemAmount) {
+ itemChangesMap.put(i, stackingRule.apply(inventoryItem, itemAmount - itemStackAmount));
+ itemStack = ItemStack.AIR;
+ break;
+ }
+ itemChangesMap.put(i, ItemStack.AIR);
+ itemStack = itemStack.withAmount(amount -> amount - itemAmount);
+ if (itemStack.getAmount() == 0) {
+ itemStack = ItemStack.AIR;
+ break;
+ }
+ }
+ }
+
+ if (itemStack.isAir()) {
+ // Item can be fully taken from the inventory, do so
+ itemChangesMap.forEach(this::safeItemInsert);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Takes {@link ItemStack}s from the inventory and sends relevant updates to the viewer(s).
+ *
+ * Even items cannot be fully taken, the amount of {@code itemStack}s will be updated.
+ *
+ * @param itemStacks items to take
+ * @return list of itemstacks that could not be successfully fully taken, empty list otherwise
+ */
+ public List takeItemStacks(@NotNull List itemStacks) {
+ List result = new ArrayList<>();
+ itemStacks.forEach(itemStack -> {
+ if (!takeItemStack(itemStack)) {
+ result.add(itemStack);
+ }
+ });
+ return result;
+ }
+
+ /**
+ * Checks whether {@link ItemStack} can be fully taken from the inventory.
+ *
+ * @param itemStack the item to be checked
+ * @return true if the item can be fully taken from the inventory, false otherwise
+ */
+ public boolean canTakeItemStack(@NotNull ItemStack itemStack) {
+ final StackingRule stackingRule = itemStack.getStackingRule();
+ for (int i = 0; i < getInnerSize(); i++) {
+ ItemStack inventoryItem = getItemStack(i);
+ if (inventoryItem.isAir()) {
+ continue;
+ }
+ if (stackingRule.canBeStacked(itemStack, inventoryItem)) {
+ final int itemAmount = stackingRule.getAmount(inventoryItem);
+ final int itemStackAmount = stackingRule.getAmount(itemStack);
+ if (itemStackAmount <= itemAmount) {
+ return true;
+ }
+ itemStack = itemStack.withAmount(amount -> amount - itemAmount);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks whether {@link ItemStack}s can be fully taken from the inventory.
+ *
+ * @param itemStacks items to be checked
+ * @return true if all the items can be fully taken from the inventory, false otherwise
+ */
+ public boolean canTakeItemStacks(@NotNull List itemStacks) {
+ return itemStacks.stream().allMatch(this::canTakeItemStack);
+ }
+
+ public void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) {
+ var currentItem = getItemStack(slot);
+ setItemStack(slot, operator.apply(currentItem));
+ }
+
+ /**
+ * Clears the inventory and send relevant update to the viewer(s).
+ */
+ public abstract void clear();
+
+ /**
+ * Gets the {@link ItemStack} at the specified slot.
+ *
+ * @param slot the slot to check
+ * @return the item in the slot {@code slot}
+ */
+ @NotNull
+ public abstract ItemStack getItemStack(int slot);
+
+ /**
+ * Gets all the {@link ItemStack} in the inventory.
+ *
+ * Be aware that the returned array does not need to be the original one,
+ * meaning that modifying it directly may not work.
+ *
+ * @return an array containing all the inventory's items
+ */
+ @NotNull
+ public abstract ItemStack[] getItemStacks();
+
+ /**
+ * Gets the size of the inventory.
+ *
+ * @return the inventory's size
+ */
+ public abstract int getSize();
+
+ /**
+ * Gets the size of the "inner inventory" (which includes only "usable" slots).
+ *
+ * @return inner inventory's size
+ */
+ public int getInnerSize() {
+ return getSize();
+ }
+
+ /**
+ * Gets all the {@link InventoryCondition} of this inventory.
+ *
+ * @return a modifiable {@link List} containing all the inventory conditions
+ */
+ @NotNull
+ public abstract List getInventoryConditions();
+
+ /**
+ * Adds a new {@link InventoryCondition} to this inventory.
+ *
+ * @param inventoryCondition the inventory condition to add
+ */
+ public abstract void addInventoryCondition(@NotNull InventoryCondition inventoryCondition);
+
+ /**
+ * Places all the items of {@code itemStacks} into the internal array.
+ *
+ * @param itemStacks the array to copy the content from
+ * @throws IllegalArgumentException if the size of the array is not equal to {@link #getSize()}
+ * @throws NullPointerException if {@code itemStacks} contains one null element or more
+ */
+ public void copyContents(@NotNull ItemStack[] itemStacks) {
+ Check.argCondition(itemStacks.length != getSize(),
+ "The size of the array has to be of the same size as the inventory: " + getSize());
+
+ for (int i = 0; i < itemStacks.length; i++) {
+ final ItemStack itemStack = itemStacks[i];
+ Check.notNull(itemStack, "The item array cannot contain any null element!");
+ setItemStack(i, itemStack);
+ }
+ }
+}
diff --git a/src/main/java/net/minestom/server/inventory/Inventory.java b/src/main/java/net/minestom/server/inventory/Inventory.java
index f3baf2fc3..0bb92d6e9 100644
--- a/src/main/java/net/minestom/server/inventory/Inventory.java
+++ b/src/main/java/net/minestom/server/inventory/Inventory.java
@@ -37,7 +37,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 implements InventoryModifier, InventoryClickHandler, Viewable, DataContainer {
+public class Inventory extends AbstractInventory implements InventoryClickHandler, Viewable, DataContainer {
// incremented each time an inventory is created (used in the window packets)
private static final AtomicInteger LAST_INVENTORY_ID = new AtomicInteger();
@@ -150,19 +150,13 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View
@Override
public synchronized boolean addItemStack(@NotNull ItemStack itemStack) {
// Make the method synchronized
- return InventoryModifier.super.addItemStack(itemStack);
- }
-
- @Override
- public synchronized boolean addItemStack(@NotNull ItemStack itemStack, int startSlot, int endSlot) {
- // Make the method synchronized
- return InventoryModifier.super.addItemStack(itemStack, startSlot, endSlot);
+ return super.addItemStack(itemStack);
}
@Override
public synchronized void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) {
// Make the method synchronized
- InventoryModifier.super.replaceItemStack(slot, operator);
+ super.replaceItemStack(slot, operator);
}
@Override
@@ -299,7 +293,8 @@ public class Inventory implements InventoryModifier, InventoryClickHandler, View
* @param slot the internal slot id
* @param itemStack the item to insert
*/
- private synchronized void safeItemInsert(int slot, @NotNull ItemStack itemStack) {
+ @Override
+ protected synchronized void safeItemInsert(int slot, @NotNull ItemStack itemStack) {
this.itemStacks[slot] = itemStack;
SetSlotPacket setSlotPacket = new SetSlotPacket();
setSlotPacket.windowId = getWindowId();
diff --git a/src/main/java/net/minestom/server/inventory/InventoryModifier.java b/src/main/java/net/minestom/server/inventory/InventoryModifier.java
deleted file mode 100644
index 0a52f59d4..000000000
--- a/src/main/java/net/minestom/server/inventory/InventoryModifier.java
+++ /dev/null
@@ -1,145 +0,0 @@
-package net.minestom.server.inventory;
-
-import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
-import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
-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 java.util.List;
-import java.util.function.UnaryOperator;
-
-/**
- * Represents an inventory where items can be modified/retrieved.
- */
-public interface InventoryModifier {
-
- /**
- * Sets an {@link ItemStack} at the specified slot and send relevant update to the viewer(s).
- *
- * @param slot the slot to set the item
- * @param itemStack the item to set
- */
- void setItemStack(int slot, @NotNull ItemStack itemStack);
-
- /**
- * Adds an {@link ItemStack} to the inventory and send relevant update to the viewer(s).
- *
- * Even the item cannot be fully added, the amount of {@code itemStack} will be updated.
- *
- * @param itemStack the item to add
- * @return true if the item has been successfully fully added, false otherwise
- */
- default boolean addItemStack(@NotNull ItemStack itemStack) {
- return addItemStack(itemStack, 0, getSize());
- }
-
- default boolean addItemStack(@NotNull ItemStack itemStack, int startSlot, int endSlot) {
- Int2ObjectMap itemChangesMap = new Int2ObjectOpenHashMap<>();
-
- final StackingRule stackingRule = itemStack.getStackingRule();
- for (int i = startSlot; i < endSlot; i++) {
- ItemStack inventoryItem = getItemStack(i);
- if (stackingRule.canBeStacked(itemStack, inventoryItem)) {
- final int itemAmount = stackingRule.getAmount(inventoryItem);
- if (itemAmount == stackingRule.getMaxSize())
- continue;
- final int itemStackAmount = stackingRule.getAmount(itemStack);
- final int totalAmount = itemStackAmount + itemAmount;
- if (!stackingRule.canApply(itemStack, totalAmount)) {
- // Slot cannot accept the whole item, reduce amount to 'itemStack'
- itemChangesMap.put(i, stackingRule.apply(inventoryItem, stackingRule.getMaxSize()));
- itemStack = stackingRule.apply(itemStack, totalAmount - stackingRule.getMaxSize());
- } else {
- // Slot can accept the whole item
- itemChangesMap.put(i, inventoryItem.withAmount(totalAmount));
- itemStack = ItemStack.AIR;
- break;
- }
- } else if (inventoryItem.isAir()) {
- // Fill the slot
- itemChangesMap.put(i, itemStack);
- itemStack = ItemStack.AIR;
- break;
- }
- }
-
- if (itemStack.isAir()) {
- // Item can be fully placed inside the inventory, do so
- itemChangesMap.forEach(this::setItemStack);
- return true;
- } else {
- // Inventory cannot accept the item fully
- return false;
- }
- }
-
- default void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) {
- var currentItem = getItemStack(slot);
- setItemStack(slot, operator.apply(currentItem));
- }
-
- /**
- * Clears the inventory and send relevant update to the viewer(s).
- */
- void clear();
-
- /**
- * Gets the {@link ItemStack} at the specified slot.
- *
- * @param slot the slot to check
- * @return the item in the slot {@code slot}
- */
- @NotNull ItemStack getItemStack(int slot);
-
- /**
- * Gets all the {@link ItemStack} in the inventory.
- *
- * Be aware that the returned array does not need to be the original one,
- * meaning that modifying it directly may not work.
- *
- * @return an array containing all the inventory's items
- */
- @NotNull ItemStack[] getItemStacks();
-
- /**
- * Gets the size of the inventory.
- *
- * @return the inventory's size
- */
- int getSize();
-
- /**
- * Gets all the {@link InventoryCondition} of this inventory.
- *
- * @return a modifiable {@link List} containing all the inventory conditions
- */
- @NotNull List getInventoryConditions();
-
- /**
- * Adds a new {@link InventoryCondition} to this inventory.
- *
- * @param inventoryCondition the inventory condition to add
- */
- void addInventoryCondition(@NotNull InventoryCondition inventoryCondition);
-
- /**
- * Places all the items of {@code itemStacks} into the internal array.
- *
- * @param itemStacks the array to copy the content from
- * @throws IllegalArgumentException if the size of the array is not equal to {@link #getSize()}
- * @throws NullPointerException if {@code itemStacks} contains one null element or more
- */
- default void copyContents(@NotNull ItemStack[] itemStacks) {
- Check.argCondition(itemStacks.length != getSize(),
- "The size of the array has to be of the same size as the inventory: " + getSize());
-
- for (int i = 0; i < itemStacks.length; i++) {
- final ItemStack itemStack = itemStacks[i];
- Check.notNull(itemStack, "The item array cannot contain any null element!");
- setItemStack(i, itemStack);
- }
- }
-}
diff --git a/src/main/java/net/minestom/server/inventory/PlayerInventory.java b/src/main/java/net/minestom/server/inventory/PlayerInventory.java
index d5a79ff4b..72ef75e96 100644
--- a/src/main/java/net/minestom/server/inventory/PlayerInventory.java
+++ b/src/main/java/net/minestom/server/inventory/PlayerInventory.java
@@ -30,9 +30,10 @@ import static net.minestom.server.utils.inventory.PlayerInventoryUtils.*;
/**
* Represents the inventory of a {@link Player}, retrieved with {@link Player#getInventory()}.
*/
-public class PlayerInventory implements InventoryModifier, InventoryClickHandler, EquipmentHandler, DataContainer {
+public class PlayerInventory extends AbstractInventory implements InventoryClickHandler, EquipmentHandler, DataContainer {
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];
@@ -93,24 +94,13 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler
return false;
itemStack = addItemStackEvent.getItemStack();
- return InventoryModifier.super.addItemStack(itemStack, 0, getSize() - 10);
- }
-
- @Override
- public synchronized boolean addItemStack(@NotNull ItemStack itemStack, int startSlot, int endSlot) {
- PlayerAddItemStackEvent addItemStackEvent = new PlayerAddItemStackEvent(player, itemStack);
- player.callEvent(PlayerAddItemStackEvent.class, addItemStackEvent);
- if (addItemStackEvent.isCancelled())
- return false;
-
- itemStack = addItemStackEvent.getItemStack();
- return InventoryModifier.super.addItemStack(itemStack, startSlot, endSlot);
+ return super.addItemStack(itemStack);
}
@Override
public synchronized void replaceItemStack(int slot, @NotNull UnaryOperator<@NotNull ItemStack> operator) {
// Make the method synchronized
- InventoryModifier.super.replaceItemStack(slot, operator);
+ super.replaceItemStack(slot, operator);
}
@Override
@@ -130,6 +120,11 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler
return INVENTORY_SIZE;
}
+ @Override
+ public int getInnerSize() {
+ return INNER_INVENTORY_SIZE;
+ }
+
@NotNull
@Override
public ItemStack getItemInMainHand() {
@@ -237,6 +232,7 @@ public class PlayerInventory implements InventoryModifier, InventoryClickHandler
* @throws IllegalArgumentException if the slot {@code slot} does not exist
* @throws NullPointerException if {@code itemStack} is null
*/
+ @Override
protected synchronized void safeItemInsert(int slot, @NotNull ItemStack itemStack) {
Check.argCondition(!MathUtils.isBetween(slot, 0, getSize()),
"The slot " + slot + " does not exist for player");
diff --git a/src/main/java/net/minestom/server/inventory/condition/InventoryCondition.java b/src/main/java/net/minestom/server/inventory/condition/InventoryCondition.java
index 5a5ace268..121adade1 100644
--- a/src/main/java/net/minestom/server/inventory/condition/InventoryCondition.java
+++ b/src/main/java/net/minestom/server/inventory/condition/InventoryCondition.java
@@ -1,11 +1,11 @@
package net.minestom.server.inventory.condition;
import net.minestom.server.entity.Player;
-import net.minestom.server.inventory.InventoryModifier;
+import net.minestom.server.inventory.AbstractInventory;
import net.minestom.server.inventory.click.ClickType;
/**
- * Can be added to any {@link InventoryModifier}
+ * Can be added to any {@link AbstractInventory}
* using {@link net.minestom.server.inventory.Inventory#addInventoryCondition(InventoryCondition)}
* or {@link net.minestom.server.inventory.PlayerInventory#addInventoryCondition(InventoryCondition)}
* in order to listen to any issued clicks.
diff --git a/src/main/java/net/minestom/server/item/meta/MapMeta.java b/src/main/java/net/minestom/server/item/meta/MapMeta.java
new file mode 100644
index 000000000..e67d05e8e
--- /dev/null
+++ b/src/main/java/net/minestom/server/item/meta/MapMeta.java
@@ -0,0 +1,278 @@
+package net.minestom.server.item.meta;
+
+import net.minestom.server.MinecraftServer;
+import net.minestom.server.chat.ChatColor;
+import net.minestom.server.color.Color;
+import net.minestom.server.item.ItemMeta;
+import net.minestom.server.item.ItemMetaBuilder;
+import net.minestom.server.utils.clone.PublicCloneable;
+import org.jetbrains.annotations.NotNull;
+import org.jglrxavpok.hephaistos.nbt.NBTCompound;
+import org.jglrxavpok.hephaistos.nbt.NBTList;
+import org.jglrxavpok.hephaistos.nbt.NBTTypes;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Supplier;
+
+public class MapMeta extends ItemMeta {
+
+ private final int mapId;
+ private final int mapScaleDirection;
+ private final List decorations;
+ private final Color mapColor;
+
+ protected MapMeta(ItemMetaBuilder metaBuilder,
+ int mapId,
+ int mapScaleDirection,
+ @NotNull List decorations,
+ @NotNull Color mapColor) {
+ super(metaBuilder);
+ this.mapId = mapId;
+ this.mapScaleDirection = mapScaleDirection;
+ this.decorations = decorations;
+ this.mapColor = mapColor;
+ }
+
+ /**
+ * Gets the map id.
+ *
+ * @return the map id
+ */
+ public int getMapId() {
+ return mapId;
+ }
+
+ /**
+ * Gets the map scale direction.
+ *
+ * @return the map scale direction
+ */
+ public int getMapScaleDirection() {
+ return mapScaleDirection;
+ }
+
+ /**
+ * Gets the map decorations.
+ *
+ * @return a modifiable list containing all the map decorations
+ */
+ public List getDecorations() {
+ return decorations;
+ }
+
+ /**
+ * Gets the map color.
+ *
+ * @return the map color
+ * @deprecated Use {@link #getMapColor()}
+ */
+ @Deprecated
+ public ChatColor getLegacyMapColor() {
+ return this.mapColor.asLegacyChatColor();
+ }
+
+ /**
+ * Gets the map color.
+ *
+ * @return the map color
+ */
+ public @NotNull Color getMapColor() {
+ return this.mapColor;
+ }
+
+ public static class Builder extends ItemMetaBuilder {
+
+ private int mapId;
+ private int mapScaleDirection = 1;
+ private List decorations = new CopyOnWriteArrayList<>();
+ private Color mapColor = new Color(0, 0, 0);
+
+ public Builder mapId(int value) {
+ this.mapId = value;
+ return this;
+ }
+
+ public Builder mapScaleDirection(int value) {
+ this.mapScaleDirection = value;
+ return this;
+ }
+
+ public Builder decorations(List value) {
+ this.decorations = value;
+ return this;
+ }
+
+ public Builder mapColor(Color value) {
+ this.mapColor = value;
+ return this;
+ }
+
+ @Override
+ public @NotNull ItemMeta build() {
+ return new MapMeta(this, mapId, mapScaleDirection, decorations, mapColor);
+ }
+
+ @Override
+ public void read(@NotNull NBTCompound compound) {
+ if (compound.containsKey("map")) {
+ this.mapId = compound.getAsInt("map");
+ }
+
+ if (compound.containsKey("map_scale_direction")) {
+ this.mapScaleDirection = compound.getAsInt("map_scale_direction");
+ }
+
+ if (compound.containsKey("Decorations")) {
+ final NBTList decorationsList = compound.getList("Decorations");
+ for (NBTCompound decorationCompound : decorationsList) {
+ final String id = decorationCompound.getString("id");
+ final byte type = decorationCompound.getAsByte("type");
+ byte x = 0;
+
+ if (decorationCompound.containsKey("x")) {
+ x = decorationCompound.getAsByte("x");
+ }
+
+ byte z = 0;
+ if (decorationCompound.containsKey("z")) {
+ z = decorationCompound.getAsByte("z");
+ }
+
+ double rotation = 0.0;
+ if (decorationCompound.containsKey("rot")) {
+ rotation = decorationCompound.getAsDouble("rot");
+ }
+
+ this.decorations.add(new MapDecoration(id, type, x, z, rotation));
+ }
+ }
+
+ if (compound.containsKey("display")) {
+ final NBTCompound displayCompound = compound.getCompound("display");
+ if (displayCompound.containsKey("MapColor")) {
+ this.mapColor = new Color(displayCompound.getAsInt("MapColor"));
+ }
+ }
+ }
+
+ @Override
+ public void write(@NotNull NBTCompound compound) {
+ compound.setInt("map", mapId);
+
+ compound.setInt("map_scale_direction", mapScaleDirection);
+
+ if (!decorations.isEmpty()) {
+ NBTList decorationsList = new NBTList<>(NBTTypes.TAG_Compound);
+ for (MapDecoration decoration : decorations) {
+ NBTCompound decorationCompound = new NBTCompound();
+ decorationCompound.setString("id", decoration.getId());
+ decorationCompound.setByte("type", decoration.getType());
+ decorationCompound.setByte("x", decoration.getX());
+ decorationCompound.setByte("z", decoration.getZ());
+ decorationCompound.setDouble("rot", decoration.getRotation());
+
+ decorationsList.add(decorationCompound);
+ }
+ compound.set("Decorations", decorationsList);
+ }
+
+ {
+ NBTCompound displayCompound;
+ if (compound.containsKey("display")) {
+ displayCompound = compound.getCompound("display");
+ } else {
+ displayCompound = new NBTCompound();
+ }
+ displayCompound.setInt("MapColor", mapColor.asRGB());
+ }
+ }
+
+ @Override
+ protected void deepClone(@NotNull ItemMetaBuilder metaBuilder) {
+ var mapBuilder = (MapMeta.Builder) metaBuilder;
+ mapBuilder.mapId = mapId;
+ mapBuilder.mapScaleDirection = mapScaleDirection;
+ mapBuilder.decorations = decorations;
+ mapBuilder.mapColor = mapColor;
+ }
+
+ @Override
+ protected @NotNull Supplier<@NotNull ItemMetaBuilder> getSupplier() {
+ return Builder::new;
+ }
+ }
+
+ public static class MapDecoration implements PublicCloneable {
+ private final String id;
+ private final byte type;
+ private final byte x, z;
+ private final double rotation;
+
+ public MapDecoration(@NotNull String id, byte type, byte x, byte z, double rotation) {
+ this.id = id;
+ this.type = type;
+ this.x = x;
+ this.z = z;
+ this.rotation = rotation;
+ }
+
+ /**
+ * Gets the arbitrary decoration id.
+ *
+ * @return the decoration id
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Gets the decoration type.
+ *
+ * @return the decoration type
+ * @see Map icons
+ */
+ public byte getType() {
+ return type;
+ }
+
+ /**
+ * Gets the X position of the decoration.
+ *
+ * @return the X position
+ */
+ public byte getX() {
+ return x;
+ }
+
+ /**
+ * Gets the Z position of the decoration.
+ *
+ * @return the Z position
+ */
+ public byte getZ() {
+ return z;
+ }
+
+ /**
+ * Gets the rotation of the symbol (0;360).
+ *
+ * @return the rotation of the symbol
+ */
+ public double getRotation() {
+ return rotation;
+ }
+
+ @NotNull
+ @Override
+ public MapDecoration clone() {
+ try {
+ return (MapDecoration) super.clone();
+ } catch (CloneNotSupportedException e) {
+ MinecraftServer.getExceptionManager().handleException(e);
+ throw new IllegalStateException("Something weird happened");
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/net/minestom/server/item/metadata/ItemMeta.java b/src/main/java/net/minestom/server/item/metadata/ItemMeta.java
index 72effbebe..4e200e331 100644
--- a/src/main/java/net/minestom/server/item/metadata/ItemMeta.java
+++ b/src/main/java/net/minestom/server/item/metadata/ItemMeta.java
@@ -1,6 +1,7 @@
package net.minestom.server.item.metadata;
import net.minestom.server.MinecraftServer;
+import net.minestom.server.item.ItemStack;
import net.minestom.server.utils.clone.PublicCloneable;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
diff --git a/src/main/java/net/minestom/server/item/metadata/MapMeta.java b/src/main/java/net/minestom/server/item/metadata/MapMeta.java
index f29e25e97..7fef87752 100644
--- a/src/main/java/net/minestom/server/item/metadata/MapMeta.java
+++ b/src/main/java/net/minestom/server/item/metadata/MapMeta.java
@@ -1,10 +1,8 @@
package net.minestom.server.item.metadata;
-import net.kyori.adventure.text.format.TextColor;
import net.minestom.server.MinecraftServer;
import net.minestom.server.chat.ChatColor;
import net.minestom.server.color.Color;
-import net.minestom.server.color.DyeColor;
import net.minestom.server.utils.clone.CloneUtils;
import net.minestom.server.utils.clone.PublicCloneable;
import org.jetbrains.annotations.NotNull;