mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-24 09:01:54 +01:00
Unique stacking rule (#844)
This commit is contained in:
parent
8df0d37107
commit
4e6c92e2c5
@ -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;
|
||||
|
@ -21,7 +21,7 @@ public interface TransactionType {
|
||||
*/
|
||||
TransactionType ADD = (inventory, itemStack, slotPredicate, start, end, step) -> {
|
||||
Int2ObjectMap<ItemStack> 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<ItemStack> 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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,26 +27,22 @@ import java.util.function.UnaryOperator;
|
||||
*/
|
||||
public final class ItemStack implements TagReadable, HoverEventSource<HoverEvent.ShowItem> {
|
||||
|
||||
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<HoverEvent
|
||||
public static @NotNull ItemStack fromNBT(@NotNull Material material, @Nullable NBTCompound nbtCompound, int amount) {
|
||||
ItemMetaBuilder builder = ItemStackBuilder.getMetaBuilder(material);
|
||||
if (nbtCompound != null) ItemMetaBuilder.resetMeta(builder, nbtCompound);
|
||||
return new ItemStack(material, amount, builder.build(), null);
|
||||
return new ItemStack(material, amount, builder.build());
|
||||
}
|
||||
|
||||
@Contract(value = "_, _ -> new", pure = true)
|
||||
@ -114,7 +110,7 @@ public final class ItemStack implements TagReadable, HoverEventSource<HoverEvent
|
||||
@Contract(value = "_, -> new", pure = true)
|
||||
public @NotNull ItemStack withAmount(int amount) {
|
||||
if (amount < 1) return AIR;
|
||||
return new ItemStack(material, amount, meta, stackingRule);
|
||||
return new ItemStack(material, amount, meta);
|
||||
}
|
||||
|
||||
@Contract(value = "_, -> new", pure = true)
|
||||
@ -125,7 +121,7 @@ public final class ItemStack implements TagReadable, HoverEventSource<HoverEvent
|
||||
@ApiStatus.Experimental
|
||||
@Contract(value = "_, -> new", pure = true)
|
||||
public @NotNull ItemStack consume(int amount) {
|
||||
return stackingRule.apply(this, currentAmount -> 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<HoverEvent
|
||||
@ApiStatus.Experimental
|
||||
@Contract(value = "_ -> new", pure = true)
|
||||
public @NotNull ItemStack withMeta(@NotNull ItemMeta meta) {
|
||||
return new ItemStack(material, amount, meta, stackingRule);
|
||||
return new ItemStack(material, amount, meta);
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
@ -174,11 +170,6 @@ public final class ItemStack implements TagReadable, HoverEventSource<HoverEvent
|
||||
return withLore(loreUnaryOperator.apply(getLore()));
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
public @NotNull StackingRule getStackingRule() {
|
||||
return stackingRule;
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
public @NotNull ItemMeta getMeta() {
|
||||
return meta;
|
||||
@ -198,30 +189,19 @@ public final class ItemStack implements TagReadable, HoverEventSource<HoverEvent
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
ItemStack itemStack = (ItemStack) o;
|
||||
|
||||
if (amount != itemStack.amount) return false;
|
||||
if (!stackingRule.equals(itemStack.stackingRule)) return false;
|
||||
if (material != itemStack.material) return false;
|
||||
return meta.equals(itemStack.meta);
|
||||
if (!(o instanceof ItemStack itemStack)) return false;
|
||||
return amount == itemStack.amount && material.equals(itemStack.material) && meta.equals(itemStack.meta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = stackingRule.hashCode();
|
||||
result = 31 * result + material.hashCode();
|
||||
result = 31 * result + amount;
|
||||
result = 31 * result + meta.hashCode();
|
||||
return result;
|
||||
return Objects.hash(material, amount, meta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ItemStack{" +
|
||||
"stackingRule=" + stackingRule +
|
||||
", material=" + material +
|
||||
"material=" + material +
|
||||
", amount=" + amount +
|
||||
", meta=" + meta +
|
||||
'}';
|
||||
@ -259,8 +239,6 @@ public final class ItemStack implements TagReadable, HoverEventSource<HoverEvent
|
||||
|
||||
@Contract(value = "-> 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);
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user