diff --git a/src/main/java/net/minestom/server/entity/ItemEntity.java b/src/main/java/net/minestom/server/entity/ItemEntity.java index 9faf2d958..c8c7e6289 100644 --- a/src/main/java/net/minestom/server/entity/ItemEntity.java +++ b/src/main/java/net/minestom/server/entity/ItemEntity.java @@ -77,7 +77,7 @@ public class ItemEntity extends Entity { if (getDistance(itemEntity) > mergeRange) return; final ItemStack itemStackEntity = itemEntity.getItemStack(); - final StackingRule stackingRule = itemStack.getStackingRule(); + final StackingRule stackingRule = StackingRule.get(); final boolean canStack = stackingRule.canBeStacked(itemStack, itemStackEntity); if (!canStack) return; diff --git a/src/main/java/net/minestom/server/inventory/TransactionType.java b/src/main/java/net/minestom/server/inventory/TransactionType.java index 4d1175d2b..253b4a4e3 100644 --- a/src/main/java/net/minestom/server/inventory/TransactionType.java +++ b/src/main/java/net/minestom/server/inventory/TransactionType.java @@ -21,7 +21,7 @@ public interface TransactionType { */ TransactionType ADD = (inventory, itemStack, slotPredicate, start, end, step) -> { Int2ObjectMap itemChangesMap = new Int2ObjectOpenHashMap<>(); - final StackingRule stackingRule = itemStack.getStackingRule(); + final StackingRule stackingRule = StackingRule.get(); // Check filled slot (not air) for (int i = start; i < end; i += step) { ItemStack inventoryItem = inventory.getItemStack(i); @@ -73,7 +73,7 @@ public interface TransactionType { */ TransactionType TAKE = (inventory, itemStack, slotPredicate, start, end, step) -> { Int2ObjectMap itemChangesMap = new Int2ObjectOpenHashMap<>(); - final StackingRule stackingRule = itemStack.getStackingRule(); + final StackingRule stackingRule = StackingRule.get(); for (int i = start; i < end; i += step) { final ItemStack inventoryItem = inventory.getItemStack(i); if (inventoryItem.isAir()) continue; 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 473e8bc05..d796f4e00 100644 --- a/src/main/java/net/minestom/server/inventory/click/InventoryClickProcessor.java +++ b/src/main/java/net/minestom/server/inventory/click/InventoryClickProcessor.java @@ -38,20 +38,19 @@ public final class InventoryClickProcessor { if (result.isCancel()) return result; clicked = result.getClicked(); cursor = result.getCursor(); - final StackingRule cursorRule = cursor.getStackingRule(); - final StackingRule clickedRule = clicked.getStackingRule(); - if (cursorRule.canBeStacked(cursor, clicked)) { + final StackingRule rule = StackingRule.get(); + if (rule.canBeStacked(cursor, clicked)) { // Try to stack items - final int totalAmount = cursorRule.getAmount(cursor) + clickedRule.getAmount(clicked); - final int maxSize = cursorRule.getMaxSize(cursor); - if (!clickedRule.canApply(clicked, totalAmount)) { + final int totalAmount = rule.getAmount(cursor) + rule.getAmount(clicked); + final int maxSize = rule.getMaxSize(cursor); + if (!rule.canApply(clicked, totalAmount)) { // Size is too big, stack as much as possible into clicked - result.setCursor(cursorRule.apply(cursor, totalAmount - maxSize)); - result.setClicked(clickedRule.apply(clicked, maxSize)); + result.setCursor(rule.apply(cursor, totalAmount - maxSize)); + result.setClicked(rule.apply(clicked, maxSize)); } else { // Merge cursor item clicked - result.setCursor(cursorRule.apply(cursor, 0)); - result.setClicked(clickedRule.apply(clicked, totalAmount)); + result.setCursor(rule.apply(cursor, 0)); + result.setClicked(rule.apply(clicked, totalAmount)); } } else { // Items are not compatible, swap them @@ -68,31 +67,30 @@ public final class InventoryClickProcessor { if (result.isCancel()) return result; clicked = result.getClicked(); cursor = result.getCursor(); - final StackingRule cursorRule = cursor.getStackingRule(); - final StackingRule clickedRule = clicked.getStackingRule(); - if (clickedRule.canBeStacked(clicked, cursor)) { + final StackingRule rule = StackingRule.get(); + if (rule.canBeStacked(clicked, cursor)) { // Items can be stacked - final int amount = clickedRule.getAmount(clicked) + 1; - if (!clickedRule.canApply(clicked, amount)) { + final int amount = rule.getAmount(clicked) + 1; + if (!rule.canApply(clicked, amount)) { // Size too large, stop here return result; } else { // Add 1 to clicked - result.setCursor(cursorRule.apply(cursor, operand -> operand - 1)); - result.setClicked(clickedRule.apply(clicked, amount)); + result.setCursor(rule.apply(cursor, operand -> operand - 1)); + result.setClicked(rule.apply(clicked, amount)); } } else { // Items cannot be stacked if (cursor.isAir()) { // Take half of clicked - final int amount = (int) Math.ceil((double) clickedRule.getAmount(clicked) / 2d); - result.setCursor(cursorRule.apply(clicked, amount)); - result.setClicked(clickedRule.apply(clicked, operand -> operand / 2)); + final int amount = (int) Math.ceil((double) rule.getAmount(clicked) / 2d); + result.setCursor(rule.apply(clicked, amount)); + result.setClicked(rule.apply(clicked, operand -> operand / 2)); } else { if (clicked.isAir()) { // Put 1 to clicked - result.setCursor(cursorRule.apply(cursor, operand -> operand - 1)); - result.setClicked(clickedRule.apply(cursor, 1)); + result.setCursor(rule.apply(cursor, operand -> operand - 1)); + result.setClicked(rule.apply(cursor, 1)); } else { // Swap items result.setCursor(clicked); @@ -171,7 +169,7 @@ public final class InventoryClickProcessor { int slot, int button, @NotNull ItemStack clicked, @NotNull ItemStack cursor) { InventoryClickResult clickResult = null; - final StackingRule stackingRule = cursor.getStackingRule(); + final StackingRule stackingRule = StackingRule.get(); if (slot != -999) { // Add slot if (button == 1) { @@ -219,8 +217,7 @@ public final class InventoryClickProcessor { final var inv = dragData.inventory; final int s = dragData.slot; ItemStack slotItem = inv.getItemStack(s); - final StackingRule slotItemRule = slotItem.getStackingRule(); - final int amount = slotItemRule.getAmount(slotItem); + final int amount = stackingRule.getAmount(slotItem); if (stackingRule.canBeStacked(cursor, slotItem)) { if (stackingRule.canApply(slotItem, amount + slotSize)) { // Append divided amount to slot @@ -270,10 +267,9 @@ public final class InventoryClickProcessor { final var inv = dragData.inventory; final int s = dragData.slot; ItemStack slotItem = inv.getItemStack(s); - StackingRule slotItemRule = slotItem.getStackingRule(); if (stackingRule.canBeStacked(cursor, slotItem)) { // Compatible item in the slot, increment by 1 - final int amount = slotItemRule.getAmount(slotItem) + 1; + final int amount = stackingRule.getAmount(slotItem) + 1; if (stackingRule.canApply(slotItem, amount)) { slotItem = stackingRule.apply(slotItem, amount); finalCursorAmount -= 1; @@ -299,9 +295,9 @@ public final class InventoryClickProcessor { if (clickResult.isCancel()) return clickResult; if (cursor.isAir()) return clickResult.cancelled(); - final StackingRule cursorRule = cursor.getStackingRule(); - final int amount = cursorRule.getAmount(cursor); - final int maxSize = cursorRule.getMaxSize(cursor); + final StackingRule rule = StackingRule.get(); + final int amount = rule.getAmount(cursor); + final int maxSize = rule.getMaxSize(cursor); final int remainingAmount = maxSize - amount; if (remainingAmount == 0) { // Item is already full @@ -323,7 +319,7 @@ public final class InventoryClickProcessor { return itemResult; }; - ItemStack remain = cursorRule.apply(cursor, remainingAmount); + ItemStack remain = rule.apply(cursor, remainingAmount); final var playerInventory = player.getInventory(); // Retrieve remain if (Objects.equals(clickedInventory, inventory)) { @@ -346,10 +342,10 @@ public final class InventoryClickProcessor { // Update cursor based on the remaining if (remain.isAir()) { // Item has been filled - clickResult.setCursor(cursorRule.apply(cursor, maxSize)); + clickResult.setCursor(rule.apply(cursor, maxSize)); } else { - final int tookAmount = remainingAmount - cursorRule.getAmount(remain); - clickResult.setCursor(cursorRule.apply(cursor, amount + tookAmount)); + final int tookAmount = remainingAmount - rule.getAmount(remain); + clickResult.setCursor(rule.apply(cursor, amount + tookAmount)); } return clickResult; } @@ -360,8 +356,7 @@ public final class InventoryClickProcessor { final InventoryClickResult clickResult = startCondition(player, inventory, slot, ClickType.DROP, clicked, cursor); if (clickResult.isCancel()) return clickResult; - final StackingRule clickedRule = clicked.getStackingRule(); - final StackingRule cursorRule = cursor.getStackingRule(); + final StackingRule rule = StackingRule.get(); ItemStack resultClicked = clicked; ItemStack resultCursor = cursor; @@ -370,44 +365,44 @@ public final class InventoryClickProcessor { // Click outside if (button == 0) { // Left (drop all) - final int amount = cursorRule.getAmount(resultCursor); - final ItemStack dropItem = cursorRule.apply(resultCursor, amount); + final int amount = rule.getAmount(resultCursor); + final ItemStack dropItem = rule.apply(resultCursor, amount); final boolean dropResult = player.dropItem(dropItem); clickResult.setCancel(!dropResult); if (dropResult) { - resultCursor = cursorRule.apply(resultCursor, 0); + resultCursor = rule.apply(resultCursor, 0); } } else if (button == 1) { // Right (drop 1) - final ItemStack dropItem = cursorRule.apply(resultCursor, 1); + final ItemStack dropItem = rule.apply(resultCursor, 1); final boolean dropResult = player.dropItem(dropItem); clickResult.setCancel(!dropResult); if (dropResult) { - final int amount = cursorRule.getAmount(resultCursor); + final int amount = rule.getAmount(resultCursor); final int newAmount = amount - 1; - resultCursor = cursorRule.apply(resultCursor, newAmount); + resultCursor = rule.apply(resultCursor, newAmount); } } } else if (!all) { if (button == 0) { // Drop key Q (drop 1) - final ItemStack dropItem = cursorRule.apply(resultClicked, 1); + final ItemStack dropItem = rule.apply(resultClicked, 1); final boolean dropResult = player.dropItem(dropItem); clickResult.setCancel(!dropResult); if (dropResult) { - final int amount = clickedRule.getAmount(resultClicked); + final int amount = rule.getAmount(resultClicked); final int newAmount = amount - 1; - resultClicked = cursorRule.apply(resultClicked, newAmount); + resultClicked = rule.apply(resultClicked, newAmount); } } else if (button == 1) { // Ctrl + Drop key Q (drop all) - final int amount = cursorRule.getAmount(resultClicked); - final ItemStack dropItem = clickedRule.apply(resultClicked, amount); + final int amount = rule.getAmount(resultClicked); + final ItemStack dropItem = rule.apply(resultClicked, amount); final boolean dropResult = player.dropItem(dropItem); clickResult.setCancel(!dropResult); if (dropResult) { - resultClicked = cursorRule.apply(resultClicked, 0); + resultClicked = rule.apply(resultClicked, 0); } } } diff --git a/src/main/java/net/minestom/server/item/ItemStack.java b/src/main/java/net/minestom/server/item/ItemStack.java index e53d35454..a3eab7dfe 100644 --- a/src/main/java/net/minestom/server/item/ItemStack.java +++ b/src/main/java/net/minestom/server/item/ItemStack.java @@ -27,26 +27,22 @@ import java.util.function.UnaryOperator; */ public final class ItemStack implements TagReadable, HoverEventSource { - private static final @NotNull VanillaStackingRule DEFAULT_STACKING_RULE = new VanillaStackingRule(); + static final @NotNull VanillaStackingRule DEFAULT_STACKING_RULE = new VanillaStackingRule(); /** * Constant AIR item. Should be used instead of 'null'. */ public static final @NotNull ItemStack AIR = ItemStack.of(Material.AIR); - private final StackingRule stackingRule; - private final Material material; private final int amount; private final ItemMeta meta; ItemStack(@NotNull Material material, int amount, - @NotNull ItemMeta meta, - @Nullable StackingRule stackingRule) { + @NotNull ItemMeta meta) { this.material = material; this.amount = amount; this.meta = meta; - this.stackingRule = Objects.requireNonNullElse(stackingRule, DEFAULT_STACKING_RULE); } @Contract(value = "_ -> new", pure = true) @@ -68,7 +64,7 @@ public final class ItemStack implements TagReadable, HoverEventSource currentAmount - amount); + return DEFAULT_STACKING_RULE.apply(this, currentAmount -> currentAmount - amount); } @Contract(value = "_, _ -> new", pure = true) @@ -141,7 +137,7 @@ public final class ItemStack implements TagReadable, HoverEventSource new", pure = true) private @NotNull ItemStackBuilder builder() { - return new ItemStackBuilder(material, meta.builder()) - .amount(amount) - .stackingRule(stackingRule); + return new ItemStackBuilder(material, meta.builder()).amount(amount); } } diff --git a/src/main/java/net/minestom/server/item/ItemStackBuilder.java b/src/main/java/net/minestom/server/item/ItemStackBuilder.java index 094cba504..d8b4d796e 100644 --- a/src/main/java/net/minestom/server/item/ItemStackBuilder.java +++ b/src/main/java/net/minestom/server/item/ItemStackBuilder.java @@ -2,7 +2,6 @@ package net.minestom.server.item; import net.kyori.adventure.text.Component; import net.minestom.server.item.metadata.*; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -20,8 +19,6 @@ public final class ItemStackBuilder { private int amount; private ItemMetaBuilder metaBuilder; - private StackingRule stackingRule; - ItemStackBuilder(@NotNull Material material, @NotNull ItemMetaBuilder metaBuilder) { this.material = material; this.amount = 1; @@ -106,17 +103,10 @@ public final class ItemStackBuilder { return this; } - @ApiStatus.Experimental - @Contract(value = "_ -> this") - public @NotNull ItemStackBuilder stackingRule(@Nullable StackingRule stackingRule) { - this.stackingRule = stackingRule; - return this; - } - @Contract(value = "-> new", pure = true) public @NotNull ItemStack build() { if (amount < 1) return ItemStack.AIR; - return new ItemStack(material, amount, metaBuilder.build(), stackingRule); + return new ItemStack(material, amount, metaBuilder.build()); } private static final class DefaultMeta extends ItemMetaBuilder { diff --git a/src/main/java/net/minestom/server/item/StackingRule.java b/src/main/java/net/minestom/server/item/StackingRule.java index dbb6ea1a7..b21893def 100644 --- a/src/main/java/net/minestom/server/item/StackingRule.java +++ b/src/main/java/net/minestom/server/item/StackingRule.java @@ -12,6 +12,10 @@ import java.util.function.IntUnaryOperator; */ public interface StackingRule { + static @NotNull StackingRule get() { + return ItemStack.DEFAULT_STACKING_RULE; + } + /** * Used to know if two {@link ItemStack} can be stacked together. * diff --git a/src/main/java/net/minestom/server/listener/BlockPlacementListener.java b/src/main/java/net/minestom/server/listener/BlockPlacementListener.java index 092898530..7e9433b02 100644 --- a/src/main/java/net/minestom/server/listener/BlockPlacementListener.java +++ b/src/main/java/net/minestom/server/listener/BlockPlacementListener.java @@ -135,7 +135,7 @@ public class BlockPlacementListener { // Block consuming if (playerBlockPlaceEvent.doesConsumeBlock()) { // Consume the block in the player's hand - final ItemStack newUsedItem = usedItem.getStackingRule().apply(usedItem, usedItem.getAmount() - 1); + final ItemStack newUsedItem = usedItem.consume(1); playerInventory.setItemInHand(hand, newUsedItem); } } diff --git a/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java b/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java index 37bc268c4..5274670d8 100644 --- a/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java +++ b/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java @@ -97,7 +97,7 @@ public final class PlayerDiggingListener { private static void dropSingle(Player player) { final ItemStack handItem = player.getInventory().getItemInMainHand(); - final StackingRule stackingRule = handItem.getStackingRule(); + final StackingRule stackingRule = StackingRule.get(); final int handAmount = stackingRule.getAmount(handItem); if (handAmount <= 1) { // Drop the whole item without copy