Minestom/src/main/java/net/minestom/server/item/ItemStack.java

248 lines
8.8 KiB
Java
Raw Normal View History

2020-04-24 03:25:58 +02:00
package net.minestom.server.item;
2019-08-12 08:30:59 +02:00
2021-03-03 20:27:33 +01:00
import net.kyori.adventure.text.Component;
2021-04-10 17:01:50 +02:00
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.event.HoverEventSource;
2020-04-24 03:25:58 +02:00
import net.minestom.server.item.rule.VanillaStackingRule;
2021-05-28 17:00:48 +02:00
import net.minestom.server.tag.Tag;
import net.minestom.server.tag.TagReadable;
2021-04-10 17:01:50 +02:00
import net.minestom.server.utils.NBTUtils;
import net.minestom.server.utils.validate.Check;
2022-03-10 16:07:56 +01:00
import org.jetbrains.annotations.*;
2021-12-13 16:41:30 +01:00
import org.jglrxavpok.hephaistos.nbt.NBT;
2022-04-10 10:01:39 +02:00
import org.jglrxavpok.hephaistos.nbt.NBTByte;
2021-04-13 03:27:51 +02:00
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
2022-04-10 10:01:39 +02:00
import org.jglrxavpok.hephaistos.nbt.NBTString;
2019-08-29 02:15:52 +02:00
2021-04-02 18:13:02 +02:00
import java.util.List;
2021-12-13 16:41:30 +01:00
import java.util.Map;
2021-04-13 05:50:11 +02:00
import java.util.Objects;
2021-04-02 18:13:02 +02:00
import java.util.function.Consumer;
import java.util.function.IntUnaryOperator;
import java.util.function.UnaryOperator;
2020-02-13 15:14:41 +01:00
2021-04-03 00:21:23 +02:00
/**
* Represents an immutable item to be placed inside {@link net.minestom.server.inventory.PlayerInventory},
* {@link net.minestom.server.inventory.Inventory} or even on the ground {@link net.minestom.server.entity.ItemEntity}.
* <p>
* An item stack cannot be null, {@link ItemStack#AIR} should be used instead.
*/
2021-05-28 17:00:48 +02:00
public final class ItemStack implements TagReadable, HoverEventSource<HoverEvent.ShowItem> {
2022-04-01 01:00:18 +02:00
static final @NotNull VanillaStackingRule DEFAULT_STACKING_RULE = new VanillaStackingRule();
2021-07-20 22:18:24 +02:00
2021-04-03 00:21:23 +02:00
/**
* Constant AIR item. Should be used instead of 'null'.
*/
public static final @NotNull ItemStack AIR = ItemStack.of(Material.AIR);
2019-08-12 08:30:59 +02:00
2021-04-02 18:13:02 +02:00
private final Material material;
private final int amount;
private final ItemMeta meta;
2021-07-19 04:27:44 +02:00
ItemStack(@NotNull Material material, int amount,
2022-04-01 01:00:18 +02:00
@NotNull ItemMeta meta) {
this.material = material;
this.amount = amount;
2021-04-02 18:13:02 +02:00
this.meta = meta;
2020-07-23 05:36:15 +02:00
}
2021-04-02 18:13:02 +02:00
@Contract(value = "_ -> new", pure = true)
2021-04-03 19:08:07 +02:00
public static @NotNull ItemStackBuilder builder(@NotNull Material material) {
return new ItemStackBuilder(material);
2019-08-13 17:52:09 +02:00
}
2021-04-02 18:25:20 +02:00
@Contract(value = "_ ,_ -> new", pure = true)
2021-04-02 18:13:02 +02:00
public static @NotNull ItemStack of(@NotNull Material material, int amount) {
return builder(material).amount(amount).build();
2021-02-07 19:38:14 +01:00
}
2021-04-02 18:13:02 +02:00
@Contract(value = "_ -> new", pure = true)
public static @NotNull ItemStack of(@NotNull Material material) {
return of(material, 1);
}
2021-04-13 03:27:51 +02:00
@Contract(value = "_, _, _ -> new", pure = true)
public static @NotNull ItemStack fromNBT(@NotNull Material material, @Nullable NBTCompound nbtCompound, int amount) {
2021-12-20 20:15:26 +01:00
ItemMetaBuilder builder = ItemStackBuilder.getMetaBuilder(material);
if (nbtCompound != null) ItemMetaBuilder.resetMeta(builder, nbtCompound);
2022-04-01 01:00:18 +02:00
return new ItemStack(material, amount, builder.build());
2021-04-13 03:27:51 +02:00
}
@Contract(value = "_, _ -> new", pure = true)
public static @NotNull ItemStack fromNBT(@NotNull Material material, @Nullable NBTCompound nbtCompound) {
2021-04-13 03:27:51 +02:00
return fromNBT(material, nbtCompound, 1);
}
/**
* Converts this item to an NBT tag containing the id (material), count (amount), and tag (meta).
*
* @param nbtCompound The nbt representation of the item
*/
@ApiStatus.Experimental
public static @NotNull ItemStack fromItemNBT(@NotNull NBTCompound nbtCompound) {
String id = nbtCompound.getString("id");
Check.notNull(id, "Item NBT must contain an id field.");
Material material = Material.fromNamespaceId(id);
Check.notNull(material, "Unknown material: {0}", id);
Byte amount = nbtCompound.getByte("Count");
2022-04-10 10:01:39 +02:00
if (amount == null) amount = 1;
final NBTCompound tag = nbtCompound.getCompound("tag");
return tag != null ? fromNBT(material, tag, amount) : of(material, amount);
}
2021-04-02 18:13:02 +02:00
@Contract(pure = true)
public @NotNull Material getMaterial() {
return material;
2019-09-06 16:05:36 +02:00
}
2021-04-02 18:13:02 +02:00
@Contract(value = "_, -> new", pure = true)
2021-04-03 19:08:07 +02:00
public @NotNull ItemStack with(@NotNull Consumer<@NotNull ItemStackBuilder> builderConsumer) {
2021-04-02 18:13:02 +02:00
var builder = builder();
builderConsumer.accept(builder);
return builder.build();
2020-08-12 13:10:57 +02:00
}
2021-04-02 18:13:02 +02:00
@Contract(pure = true)
public int getAmount() {
2020-05-30 01:39:52 +02:00
return amount;
2020-04-22 02:42:58 +02:00
}
2021-04-02 18:13:02 +02:00
@Contract(value = "_, -> new", pure = true)
public @NotNull ItemStack withAmount(int amount) {
if (amount < 1) return AIR;
2022-04-01 01:00:18 +02:00
return new ItemStack(material, amount, meta);
2020-07-23 07:36:49 +02:00
}
2021-04-02 18:13:02 +02:00
@Contract(value = "_, -> new", pure = true)
public @NotNull ItemStack withAmount(@NotNull IntUnaryOperator intUnaryOperator) {
return withAmount(intUnaryOperator.applyAsInt(amount));
2021-03-03 20:27:33 +01:00
}
2021-07-23 01:47:43 +02:00
@ApiStatus.Experimental
@Contract(value = "_, -> new", pure = true)
public @NotNull ItemStack consume(int amount) {
2022-04-01 01:00:18 +02:00
return DEFAULT_STACKING_RULE.apply(this, currentAmount -> currentAmount - amount);
2021-07-23 01:47:43 +02:00
}
2021-04-02 18:13:02 +02:00
@Contract(value = "_, _ -> new", pure = true)
public <T extends ItemMetaBuilder, U extends ItemMetaBuilder.Provider<T>> @NotNull ItemStack withMeta(Class<U> metaType, Consumer<T> metaConsumer) {
return builder().meta(metaType, metaConsumer).build();
2019-08-22 14:52:32 +02:00
}
2021-04-02 22:14:48 +02:00
@Contract(value = "_ -> new", pure = true)
public <T extends ItemMetaBuilder> @NotNull ItemStack withMeta(@NotNull UnaryOperator<@NotNull T> metaOperator) {
2021-04-02 22:14:48 +02:00
return builder().meta(metaOperator).build();
}
@ApiStatus.Experimental
@Contract(value = "_ -> new", pure = true)
public @NotNull ItemStack withMeta(@NotNull ItemMeta meta) {
2022-04-01 01:00:18 +02:00
return new ItemStack(material, amount, meta);
}
2021-04-02 18:13:02 +02:00
@Contract(pure = true)
public @Nullable Component getDisplayName() {
return meta.getDisplayName();
2021-03-03 20:27:33 +01:00
}
2021-04-02 18:13:02 +02:00
@Contract(value = "_, -> new", pure = true)
public @NotNull ItemStack withDisplayName(@Nullable Component displayName) {
return builder().displayName(displayName).build();
2019-08-22 14:52:32 +02:00
}
2021-04-02 18:13:02 +02:00
@Contract(value = "_, -> new", pure = true)
public @NotNull ItemStack withDisplayName(@NotNull UnaryOperator<@Nullable Component> componentUnaryOperator) {
return withDisplayName(componentUnaryOperator.apply(getDisplayName()));
2020-02-13 15:14:41 +01:00
}
2021-04-02 18:13:02 +02:00
@Contract(pure = true)
2021-04-03 00:21:23 +02:00
public @NotNull List<@NotNull Component> getLore() {
2021-04-02 18:13:02 +02:00
return meta.getLore();
2021-03-03 20:27:33 +01:00
}
2021-04-02 18:13:02 +02:00
@Contract(value = "_, -> new", pure = true)
public @NotNull ItemStack withLore(@NotNull List<? extends Component> lore) {
2021-04-02 18:13:02 +02:00
return builder().lore(lore).build();
2020-02-13 15:14:41 +01:00
}
2021-04-02 18:13:02 +02:00
@Contract(value = "_, -> new", pure = true)
2021-04-04 20:49:21 +02:00
public @NotNull ItemStack withLore(@NotNull UnaryOperator<@NotNull List<@NotNull Component>> loreUnaryOperator) {
2021-04-02 18:13:02 +02:00
return withLore(loreUnaryOperator.apply(getLore()));
2020-04-29 20:17:04 +02:00
}
@Contract(pure = true)
2021-04-02 18:13:02 +02:00
public @NotNull ItemMeta getMeta() {
return meta;
2020-05-22 21:46:50 +02:00
}
@Contract(pure = true)
public boolean isAir() {
return material == Material.AIR;
}
@Contract(pure = true)
2021-04-02 18:13:02 +02:00
public boolean isSimilar(@NotNull ItemStack itemStack) {
return material == itemStack.material &&
2021-04-02 18:13:02 +02:00
meta.equals(itemStack.meta);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
2022-04-01 01:00:18 +02:00
if (!(o instanceof ItemStack itemStack)) return false;
return amount == itemStack.amount && material.equals(itemStack.material) && meta.equals(itemStack.meta);
}
@Override
public int hashCode() {
2022-04-01 01:00:18 +02:00
return Objects.hash(material, amount, meta);
}
2020-08-13 19:12:16 +02:00
@Override
public String toString() {
return "ItemStack{" +
2022-04-01 01:00:18 +02:00
"material=" + material +
", amount=" + amount +
", meta=" + meta +
'}';
}
2021-05-28 17:05:14 +02:00
@Contract(value = "_, _ -> new", pure = true)
public <T> @NotNull ItemStack withTag(@NotNull Tag<T> tag, @Nullable T value) {
return builder().meta(metaBuilder -> metaBuilder.set(tag, value)).build();
}
2021-05-28 17:00:48 +02:00
@Override
2022-03-10 16:07:56 +01:00
public <T> @UnknownNullability T getTag(@NotNull Tag<T> tag) {
2021-05-28 17:00:48 +02:00
return meta.getTag(tag);
}
2021-04-10 17:01:50 +02:00
@Override
public @NotNull HoverEvent<HoverEvent.ShowItem> asHoverEvent(@NotNull UnaryOperator<HoverEvent.ShowItem> op) {
return HoverEvent.showItem(op.apply(HoverEvent.ShowItem.of(this.material,
this.amount,
2021-12-15 04:46:29 +01:00
NBTUtils.asBinaryTagHolder(this.meta.toNBT()))));
2021-04-10 17:01:50 +02:00
}
2021-07-19 04:27:44 +02:00
/**
* Converts this item to an NBT tag containing the id (material), count (amount), and tag (meta)
*
* @return The nbt representation of the item
*/
@ApiStatus.Experimental
public @NotNull NBTCompound toItemNBT() {
2022-04-10 10:01:39 +02:00
final NBTString material = NBT.String(getMaterial().name());
final NBTByte amount = NBT.Byte(getAmount());
final NBTCompound nbt = getMeta().toNBT();
if (nbt.isEmpty()) return NBT.Compound(Map.of("id", material, "Count", amount));
return NBT.Compound(Map.of("id", material, "Count", amount, "tag", nbt));
}
2021-07-19 04:27:44 +02:00
@Contract(value = "-> new", pure = true)
private @NotNull ItemStackBuilder builder() {
2022-04-01 01:00:18 +02:00
return new ItemStackBuilder(material, meta.builder()).amount(amount);
2021-07-19 04:27:44 +02:00
}
}