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

792 lines
23 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-01-15 22:04:57 +01:00
import it.unimi.dsi.fastutil.objects.Object2ShortMap;
import it.unimi.dsi.fastutil.objects.Object2ShortOpenHashMap;
import net.minestom.server.MinecraftServer;
import net.minestom.server.chat.JsonMessage;
2020-04-24 03:25:58 +02:00
import net.minestom.server.data.Data;
import net.minestom.server.data.DataContainer;
import net.minestom.server.entity.ItemEntity;
import net.minestom.server.entity.Player;
import net.minestom.server.inventory.Inventory;
import net.minestom.server.inventory.PlayerInventory;
2020-08-13 19:12:16 +02:00
import net.minestom.server.inventory.click.ClickType;
2020-05-28 23:43:12 +02:00
import net.minestom.server.item.attribute.ItemAttribute;
2020-08-01 00:43:52 +02:00
import net.minestom.server.item.metadata.*;
2020-04-24 03:25:58 +02:00
import net.minestom.server.item.rule.VanillaStackingRule;
import net.minestom.server.network.packet.server.play.SetSlotPacket;
import net.minestom.server.registry.Registries;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.Direction;
import net.minestom.server.utils.NBTUtils;
import net.minestom.server.utils.clone.PublicCloneable;
import net.minestom.server.utils.ownership.OwnershipHandler;
2020-10-24 11:19:54 +02:00
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
2019-08-29 02:15:52 +02:00
2020-05-22 21:46:50 +02:00
import java.util.*;
2020-02-13 15:14:41 +01:00
2020-07-31 23:02:01 +02:00
// TODO should we cache a ByteBuf of this item for faster packet write
/**
* Represents an item in an inventory ({@link PlayerInventory}, {@link Inventory}) or on the ground ({@link ItemEntity}).
* <p>
* An item stack cannot be null, you can however use {@link #getAirItem()} instead.
* <p>
* WARNING: all setters will not update the item automatically, it will need to be refreshed manually.
* Here a non-exhaustive list of what you can do to update the item:
* {@link PlayerInventory#refreshSlot(short)}, {@link Inventory#refreshSlot(short)} or a raw {@link SetSlotPacket}.
*/
public class ItemStack implements DataContainer, PublicCloneable<ItemStack> {
2019-08-12 08:30:59 +02:00
2021-01-15 22:04:57 +01:00
public static final OwnershipHandler<Data> DATA_OWNERSHIP = new OwnershipHandler<>();
public static final String OWNERSHIP_DATA_KEY = "ownership_identifier";
private static final StackingRule VANILLA_STACKING_RULE = new VanillaStackingRule(64);
2020-05-27 12:33:12 +02:00
2021-01-15 22:04:57 +01:00
private final UUID identifier;
private Material material;
2020-04-23 12:30:49 +02:00
2020-03-20 19:50:22 +01:00
private static StackingRule defaultStackingRule;
2020-07-23 05:36:15 +02:00
private ItemMeta itemMeta;
2019-08-12 08:30:59 +02:00
2019-08-13 17:52:09 +02:00
private byte amount;
2020-07-06 23:34:22 +02:00
private int damage;
2019-08-12 08:30:59 +02:00
private JsonMessage displayName;
2019-08-22 14:52:32 +02:00
private boolean unbreakable;
private List<JsonMessage> lore;
2019-08-22 14:52:32 +02:00
2021-01-15 22:04:57 +01:00
private Object2ShortMap<Enchantment> enchantmentMap;
2020-05-28 23:43:12 +02:00
private List<ItemAttribute> attributes;
2020-05-22 21:46:50 +02:00
private int hideFlag;
2020-07-06 12:39:48 +02:00
private int customModelData;
2020-04-29 20:17:04 +02:00
2020-02-17 17:33:53 +01:00
private StackingRule stackingRule;
2019-08-29 02:15:52 +02:00
private Data data;
2020-05-29 20:24:39 +02:00
{
if (defaultStackingRule == null)
defaultStackingRule = VANILLA_STACKING_RULE;
2020-09-24 01:50:25 +02:00
this.stackingRule = defaultStackingRule;
2020-05-29 20:24:39 +02:00
}
public ItemStack(@NotNull Material material, byte amount, int damage) {
this.identifier = DATA_OWNERSHIP.generateIdentifier();
this.material = material;
this.amount = amount;
this.damage = damage;
this.lore = new ArrayList<>();
2021-01-15 22:04:57 +01:00
this.enchantmentMap = new Object2ShortOpenHashMap<>();
this.attributes = new ArrayList<>();
this.itemMeta = findMeta();
}
2020-10-24 11:19:54 +02:00
public ItemStack(@NotNull Material material, byte amount) {
2020-07-23 05:36:15 +02:00
this(material, amount, (short) 0);
2020-03-29 20:58:30 +02:00
}
2020-08-12 13:10:57 +02:00
/**
2020-10-15 21:16:31 +02:00
* Gets a new {@link ItemStack} with the material sets to {@link Material#AIR}.
* <p>
* Used when you require a "null item".
2020-08-12 13:10:57 +02:00
*
* @return an air item
*/
2020-10-24 11:19:54 +02:00
@NotNull
2020-07-23 05:36:15 +02:00
public static ItemStack getAirItem() {
return new ItemStack(Material.AIR, (byte) 0);
2019-08-22 14:52:32 +02:00
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Gets the default {@link StackingRule} for newly created {@link ItemStack}.
2020-05-30 01:39:52 +02:00
*
* @return the default stacking rule
*/
2020-10-24 11:19:54 +02:00
@NotNull
2020-05-30 01:39:52 +02:00
public static StackingRule getDefaultStackingRule() {
return defaultStackingRule;
}
/**
2020-10-15 21:16:31 +02:00
* Changes the default stacking rule for created item stack.
2020-05-30 01:39:52 +02:00
*
* @param defaultStackingRule the default item stack
* @throws NullPointerException if {@code defaultStackingRule} is null
*/
2020-10-24 11:19:54 +02:00
public static void setDefaultStackingRule(@NotNull StackingRule defaultStackingRule) {
2020-05-30 01:39:52 +02:00
ItemStack.defaultStackingRule = defaultStackingRule;
}
/**
2020-10-15 21:16:31 +02:00
* Loads an {@link ItemStack} from nbt.
*
* @param nbt the nbt compound containing the item
* @return the parsed item stack
*/
2020-10-24 11:19:54 +02:00
@NotNull
public static ItemStack fromNBT(@NotNull NBTCompound nbt) {
2020-07-23 05:36:15 +02:00
if (!nbt.containsKey("id") || !nbt.containsKey("Count"))
throw new IllegalArgumentException("Invalid item NBT, must at least contain 'id' and 'Count' tags");
final Material material = Registries.getMaterial(nbt.getString("id"));
final byte count = nbt.getAsByte("Count");
2020-07-23 05:36:15 +02:00
ItemStack s = new ItemStack(material, count);
NBTCompound tag = nbt.getCompound("tag");
if (tag != null) {
NBTUtils.loadDataIntoItem(s, tag);
}
return s;
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Gets if the item material is {@link Material#AIR}.
2020-05-30 01:39:52 +02:00
*
* @return true if the material is air, false otherwise
*/
2019-08-13 17:52:09 +02:00
public boolean isAir() {
2020-07-23 05:36:15 +02:00
return material == Material.AIR;
2019-08-13 17:52:09 +02:00
}
2020-02-13 15:14:41 +01:00
/**
2020-10-15 21:16:31 +02:00
* Gets if two items are similar.
* It does not take {@link #getAmount()} and {@link #getStackingRule()} in consideration.
2020-02-13 15:14:41 +01:00
*
2020-03-29 20:58:30 +02:00
* @param itemStack The ItemStack to compare to
* @return true if both items are similar
2020-02-13 15:14:41 +01:00
*/
2020-10-24 11:19:54 +02:00
public boolean isSimilar(@NotNull ItemStack itemStack) {
2020-08-14 15:24:57 +02:00
synchronized (ItemStack.class) {
if (itemStack.getIdentifier().equals(identifier)) {
return true;
}
final JsonMessage itemDisplayName = itemStack.getDisplayName();
final boolean displayNameCheck = (displayName == null && itemDisplayName == null) ||
(displayName != null && displayName.equals(itemDisplayName));
final Data itemData = itemStack.getData();
final boolean dataCheck = (data == null && itemData == null) ||
(data != null && data.equals(itemData));
2020-07-23 05:36:15 +02:00
final boolean sameMeta = (itemStack.itemMeta == null && itemMeta == null) ||
(itemStack.itemMeta != null && itemMeta != null && (itemStack.itemMeta.isSimilar(itemMeta)));
return itemStack.getMaterial() == material &&
displayNameCheck &&
itemStack.isUnbreakable() == unbreakable &&
itemStack.getDamage() == damage &&
itemStack.enchantmentMap.equals(enchantmentMap) &&
itemStack.attributes.equals(attributes) &&
itemStack.hideFlag == hideFlag &&
2020-07-23 05:36:15 +02:00
sameMeta &&
dataCheck;
}
2019-08-13 17:52:09 +02:00
}
2020-08-12 13:10:57 +02:00
/**
2020-10-15 21:16:31 +02:00
* Gets the item damage (durability).
2020-08-12 13:10:57 +02:00
*
2020-10-15 21:16:31 +02:00
* @return the item damage
2020-08-12 13:10:57 +02:00
*/
2020-07-06 23:34:22 +02:00
public int getDamage() {
2019-09-06 16:05:36 +02:00
return damage;
}
2020-08-12 13:10:57 +02:00
/**
2020-10-15 21:16:31 +02:00
* Sets the item damage (durability).
2020-08-12 13:10:57 +02:00
*
* @param damage the item damage
*/
public void setDamage(int damage) {
this.damage = damage;
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Gets the item amount.
2020-05-30 01:39:52 +02:00
* <p>
* WARNING: for amount computation it would be better to use {@link StackingRule#getAmount(ItemStack)}
2020-10-15 21:16:31 +02:00
* to support all stacking implementation.
2020-05-30 01:39:52 +02:00
*
* @return the item amount
*/
public byte getAmount() {
return amount;
2020-04-22 02:42:58 +02:00
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Changes the item amount.
2020-05-30 01:39:52 +02:00
* <p>
* WARNING: for amount computation it would be better to use {@link StackingRule#getAmount(ItemStack)}
2020-10-15 21:16:31 +02:00
* to support all stacking implementation.
2020-05-30 01:39:52 +02:00
*
* @param amount the new item amount
*/
2019-08-13 17:52:09 +02:00
public void setAmount(byte amount) {
this.amount = amount;
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Gets the special meta object for this item.
2020-07-23 05:36:15 +02:00
* <p>
* Can be null if not any.
2020-05-30 01:39:52 +02:00
*
2020-07-23 05:36:15 +02:00
* @return the item meta
2020-05-30 01:39:52 +02:00
*/
2020-10-24 11:19:54 +02:00
@Nullable
2020-07-23 05:36:15 +02:00
public ItemMeta getItemMeta() {
return itemMeta;
2020-05-30 01:39:52 +02:00
}
2020-07-23 07:36:49 +02:00
/**
2020-10-15 21:16:31 +02:00
* Changes the item meta linked to this item.
2020-07-23 07:36:49 +02:00
* <p>
* WARNING: be sure to have nbt data useful for this item, items should automatically get the appropriate
2020-10-15 21:16:31 +02:00
* item meta.
2020-07-23 07:36:49 +02:00
*
* @param itemMeta the new item meta
*/
2020-10-24 11:19:54 +02:00
public void setItemMeta(@Nullable ItemMeta itemMeta) {
2020-07-23 07:36:49 +02:00
this.itemMeta = itemMeta;
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Gets the item display name.
2020-05-30 01:39:52 +02:00
*
* @return the item display name, can be null if not present
*/
2020-10-24 11:19:54 +02:00
@Nullable
public JsonMessage getDisplayName() {
2019-08-22 14:52:32 +02:00
return displayName;
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Sets the item display name.
2020-05-30 01:39:52 +02:00
*
* @param displayName the item display name
*/
public void setDisplayName(@Nullable JsonMessage displayName) {
2019-08-22 14:52:32 +02:00
this.displayName = displayName;
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Gets if the item has a display name.
2020-05-30 01:39:52 +02:00
*
* @return the item display name
*/
2020-02-13 15:14:41 +01:00
public boolean hasDisplayName() {
return displayName != null;
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Gets the item lore.
2020-05-30 01:39:52 +02:00
*
2021-01-13 03:42:31 +01:00
* @return a modifiable list containing the item lore, can be empty if not present
2020-05-30 01:39:52 +02:00
*/
2021-01-13 03:42:31 +01:00
@NotNull
public List<JsonMessage> getLore() {
2020-02-13 15:14:41 +01:00
return lore;
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Sets the item lore.
2020-05-30 01:39:52 +02:00
*
2021-01-13 03:42:31 +01:00
* @param lore the item lore, can be empty to remove
2020-05-30 01:39:52 +02:00
*/
2021-01-13 03:42:31 +01:00
public void setLore(@NotNull List<JsonMessage> lore) {
2020-02-13 15:14:41 +01:00
this.lore = lore;
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Gets if the item has a lore.
2020-05-30 01:39:52 +02:00
*
* @return true if the item has lore, false otherwise
*/
2020-02-13 15:14:41 +01:00
public boolean hasLore() {
return lore != null && !lore.isEmpty();
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Gets the item enchantment map.
2020-05-30 01:39:52 +02:00
*
* @return an unmodifiable map containing the item enchantments
*/
2020-10-24 11:19:54 +02:00
@NotNull
2020-05-22 21:46:50 +02:00
public Map<Enchantment, Short> getEnchantmentMap() {
2020-04-29 20:17:04 +02:00
return Collections.unmodifiableMap(enchantmentMap);
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Sets an enchantment level.
2020-05-30 01:39:52 +02:00
*
* @param enchantment the enchantment type
* @param level the enchantment level
*/
2020-10-24 11:19:54 +02:00
public void setEnchantment(@NotNull Enchantment enchantment, short level) {
2020-04-29 20:17:04 +02:00
if (level < 1) {
removeEnchantment(enchantment);
return;
}
this.enchantmentMap.put(enchantment, level);
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Removes an enchantment.
2020-05-30 01:39:52 +02:00
*
* @param enchantment the enchantment type
*/
2020-10-24 11:19:54 +02:00
public void removeEnchantment(@NotNull Enchantment enchantment) {
2021-01-15 22:04:57 +01:00
this.enchantmentMap.removeShort(enchantment);
2020-04-29 20:17:04 +02:00
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Gets an enchantment level.
2020-05-30 01:39:52 +02:00
*
* @param enchantment the enchantment type
* @return the stored enchantment level, 0 if not present
*/
2020-10-24 11:19:54 +02:00
public int getEnchantmentLevel(@NotNull Enchantment enchantment) {
2020-05-22 21:46:50 +02:00
return this.enchantmentMap.getOrDefault(enchantment, (short) 0);
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Gets the item attributes.
2020-05-30 01:39:52 +02:00
*
* @return an unmodifiable {@link List} containing the item attributes
*/
2020-10-24 11:19:54 +02:00
@NotNull
2020-05-28 23:43:12 +02:00
public List<ItemAttribute> getAttributes() {
return Collections.unmodifiableList(attributes);
}
2020-10-05 01:46:02 +02:00
/**
2020-10-15 21:16:31 +02:00
* Gets the {@link ItemAttribute} with the specified internal name.
2020-10-05 01:46:02 +02:00
*
* @param internalName the internal name of the attribute
* @return the {@link ItemAttribute} with the internal name, null if not found
*/
2020-10-24 11:19:54 +02:00
public ItemAttribute getAttribute(@NotNull String internalName) {
2020-10-05 01:46:02 +02:00
for (ItemAttribute itemAttribute : attributes) {
if (itemAttribute.getInternalName().equals(internalName))
return itemAttribute;
}
return null;
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Adds an attribute to the item.
2020-05-30 01:39:52 +02:00
*
* @param itemAttribute the attribute to add
*/
2020-10-24 11:19:54 +02:00
public void addAttribute(@NotNull ItemAttribute itemAttribute) {
2020-05-28 23:43:12 +02:00
this.attributes.add(itemAttribute);
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Removes an attribute to the item.
2020-05-30 01:39:52 +02:00
*
* @param itemAttribute the attribute to remove
*/
2020-10-24 11:19:54 +02:00
public void removeAttribute(@NotNull ItemAttribute itemAttribute) {
2020-05-30 01:39:52 +02:00
this.attributes.remove(itemAttribute);
}
/**
2020-10-15 21:16:31 +02:00
* Gets the item hide flag.
2020-05-30 01:39:52 +02:00
*
* @return the item hide flag
*/
2020-05-22 21:46:50 +02:00
public int getHideFlag() {
return hideFlag;
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Changes the item hide flag. This is the integer sent when updating the item hide flag.
2020-05-30 01:39:52 +02:00
*
* @param hideFlag the new item hide flag
*/
2020-05-29 00:30:19 +02:00
public void setHideFlag(int hideFlag) {
this.hideFlag = hideFlag;
}
2020-07-06 12:39:48 +02:00
/**
2020-10-15 21:16:31 +02:00
* Gets the item custom model data.
2020-07-06 12:39:48 +02:00
*
* @return the item custom model data
*/
public int getCustomModelData() {
return customModelData;
}
/**
2020-10-15 21:16:31 +02:00
* Changes the item custom model data.
2020-07-06 12:39:48 +02:00
*
* @param customModelData the new item custom data model
*/
public void setCustomModelData(int customModelData) {
this.customModelData = customModelData;
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Adds flags to the item.
2020-05-30 01:39:52 +02:00
*
* @param flags the flags to add
*/
2020-10-24 11:19:54 +02:00
public void addItemFlags(@NotNull ItemFlag... flags) {
2020-05-30 01:39:52 +02:00
for (ItemFlag f : flags) {
2020-05-22 21:46:50 +02:00
this.hideFlag |= getBitModifier(f);
}
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Removes flags from the item.
2020-05-30 01:39:52 +02:00
*
* @param flags the flags to remove
*/
2020-10-24 11:19:54 +02:00
public void removeItemFlags(@NotNull ItemFlag... flags) {
2020-05-30 01:39:52 +02:00
for (ItemFlag f : flags) {
2020-05-22 21:46:50 +02:00
this.hideFlag &= ~getBitModifier(f);
}
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Gets the item flags.
2020-05-30 01:39:52 +02:00
*
* @return an unmodifiable {@link Set} containing the item flags
*/
2020-10-24 11:19:54 +02:00
@NotNull
2020-05-22 21:46:50 +02:00
public Set<ItemFlag> getItemFlags() {
Set<ItemFlag> currentFlags = EnumSet.noneOf(ItemFlag.class);
for (ItemFlag f : ItemFlag.values()) {
if (hasItemFlag(f)) {
currentFlags.add(f);
}
}
2020-05-30 01:39:52 +02:00
return Collections.unmodifiableSet(currentFlags);
2020-05-22 21:46:50 +02:00
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Gets if the item has an item flag.
2020-05-30 01:39:52 +02:00
*
* @param flag the item flag
* @return true if the item has the flag {@code flag}, false otherwise
*/
2020-10-24 11:19:54 +02:00
public boolean hasItemFlag(@NotNull ItemFlag flag) {
2020-08-12 13:10:57 +02:00
final int bitModifier = getBitModifier(flag);
2020-05-22 21:46:50 +02:00
return (this.hideFlag & bitModifier) == bitModifier;
2020-04-29 20:17:04 +02:00
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Gets if the item is unbreakable.
2020-05-30 01:39:52 +02:00
*
* @return true if the item is unbreakable, false otherwise
*/
2019-08-22 14:52:32 +02:00
public boolean isUnbreakable() {
return unbreakable;
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Makes the item unbreakable.
2020-05-30 01:39:52 +02:00
*
* @param unbreakable true to make the item unbreakable, false otherwise
*/
2019-08-22 14:52:32 +02:00
public void setUnbreakable(boolean unbreakable) {
this.unbreakable = unbreakable;
}
/**
* Gets the unique identifier of this object.
* <p>
* This value is non persistent and will be randomized once this item is separated with a right-click,
* when copied and when the server restart. It is used internally by the data ownership system.
*
* @return this item unique identifier
*/
@NotNull
public UUID getIdentifier() {
return identifier;
}
2020-07-23 05:36:15 +02:00
/**
2020-10-15 21:16:31 +02:00
* Gets the item {@link Material}.
2020-07-23 05:36:15 +02:00
*
* @return the item material
*/
2020-10-24 11:19:54 +02:00
@NotNull
2020-07-23 05:36:15 +02:00
public Material getMaterial() {
return material;
}
/**
2020-10-15 21:16:31 +02:00
* Changes the item {@link Material}.
*
* @param material the new material
*/
2020-10-24 11:19:54 +02:00
public void setMaterial(@NotNull Material material) {
this.material = material;
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Gets if the item has any nbt tag.
2020-05-30 01:39:52 +02:00
*
* @return true if the item has nbt tag, false otherwise
*/
2020-02-13 15:14:41 +01:00
public boolean hasNbtTag() {
return hasDisplayName() ||
hasLore() ||
damage != 0 ||
isUnbreakable() ||
2020-08-01 00:21:03 +02:00
!enchantmentMap.isEmpty() ||
2020-07-23 05:36:15 +02:00
!attributes.isEmpty() ||
hideFlag != 0 ||
customModelData != 0 ||
(itemMeta != null && itemMeta.hasNbt()) ||
(data != null && !data.isEmpty());
2020-02-13 15:14:41 +01:00
}
2020-05-30 01:39:52 +02:00
/**
* @deprecated use {@link #clone()}
*/
@Deprecated
@NotNull
public synchronized ItemStack copy() {
return clone();
}
/**
* Clones this item stack.
* <p>
* Be aware that the identifier ({@link #getIdentifier()}) will change.
2020-05-30 01:39:52 +02:00
*
* @return a cloned item stack with a different identifier
2020-05-30 01:39:52 +02:00
*/
2020-12-09 21:34:53 +01:00
@NotNull
@Override
public ItemStack clone() {
try {
ItemStack itemStack = (ItemStack) super.clone();
itemStack.setDisplayName(displayName);
itemStack.setUnbreakable(unbreakable);
if (lore != null) {
itemStack.setLore(new ArrayList<>(lore));
}
if (stackingRule != null) {
itemStack.setStackingRule(stackingRule);
}
2020-04-29 20:17:04 +02:00
2021-01-15 22:04:57 +01:00
itemStack.enchantmentMap = new Object2ShortOpenHashMap<>(enchantmentMap);
itemStack.attributes = new ArrayList<>(attributes);
2020-07-06 13:24:01 +02:00
itemStack.hideFlag = hideFlag;
itemStack.customModelData = customModelData;
2020-04-29 20:17:04 +02:00
if (itemMeta != null)
itemStack.itemMeta = itemMeta.clone();
2020-07-23 05:36:15 +02:00
final Data data = getData();
if (data != null)
itemStack.setData(data.clone());
return itemStack;
} catch (CloneNotSupportedException e) {
MinecraftServer.getExceptionManager().handleException(e);
return null;
}
2019-08-12 08:30:59 +02:00
}
2019-08-29 02:15:52 +02:00
@Nullable
2019-08-29 02:15:52 +02:00
@Override
public Data getData() {
return data;
}
/**
* Sets the data of this item.
*
* @param data the new {@link Data} of this container, null to remove it
*/
2019-08-29 02:15:52 +02:00
@Override
public void setData(@Nullable Data data) {
DATA_OWNERSHIP.saveOwnObject(getIdentifier(), data);
2019-08-29 02:15:52 +02:00
this.data = data;
}
2020-02-17 17:33:53 +01:00
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Gets the item {@link StackingRule}.
2020-05-30 01:39:52 +02:00
*
* @return the item stacking rule
*/
2020-10-24 11:19:54 +02:00
@NotNull
2020-05-30 01:39:52 +02:00
public StackingRule getStackingRule() {
return stackingRule;
2020-02-17 17:33:53 +01:00
}
2020-05-30 01:39:52 +02:00
/**
2020-10-15 21:16:31 +02:00
* Changes the {@link StackingRule} of the item.
2020-05-30 01:39:52 +02:00
*
* @param stackingRule the new item stacking rule
* @throws NullPointerException if {@code stackingRule} is null
*/
2020-10-24 11:19:54 +02:00
public void setStackingRule(@NotNull StackingRule stackingRule) {
2020-05-23 04:20:01 +02:00
this.stackingRule = stackingRule;
2020-02-17 17:33:53 +01:00
}
2020-05-22 21:46:50 +02:00
2020-07-24 18:23:15 +02:00
/**
2020-10-15 21:16:31 +02:00
* Consumes this item by a specific amount.
2020-07-24 18:23:15 +02:00
* <p>
2020-10-15 21:16:31 +02:00
* Will return null if the amount's amount isn't enough.
2020-07-24 18:23:15 +02:00
*
* @param amount the quantity to consume
* @return the new item with the updated amount, null if the item cannot be consumed by this much
*/
2020-10-24 11:19:54 +02:00
@Nullable
2020-07-24 18:23:15 +02:00
public ItemStack consume(int amount) {
final int currentAmount = stackingRule.getAmount(this);
if (currentAmount < amount)
return null;
return stackingRule.apply(this, currentAmount - amount);
}
2020-10-24 11:19:54 +02:00
private byte getBitModifier(@NotNull ItemFlag hideFlag) {
2020-05-22 21:46:50 +02:00
return (byte) (1 << hideFlag.ordinal());
}
2020-07-23 05:36:15 +02:00
/**
2020-10-15 21:16:31 +02:00
* Finds the {@link ItemMeta} based on the material type.
2020-07-23 05:36:15 +02:00
*
2020-10-24 11:19:54 +02:00
* @return the item meta, null if none found
2020-07-23 05:36:15 +02:00
*/
2020-10-24 11:19:54 +02:00
@Nullable
2020-07-23 05:36:15 +02:00
private ItemMeta findMeta() {
if (material == Material.POTION ||
material == Material.LINGERING_POTION ||
material == Material.SPLASH_POTION ||
material == Material.TIPPED_ARROW)
2020-07-23 05:36:15 +02:00
return new PotionMeta();
if (material == Material.FILLED_MAP)
return new MapMeta();
2020-08-01 00:43:52 +02:00
if (material == Material.COMPASS)
return new CompassMeta();
2020-08-01 00:21:03 +02:00
if (material == Material.ENCHANTED_BOOK)
return new EnchantedBookMeta();
2020-07-23 05:36:15 +02:00
2020-08-01 00:43:52 +02:00
if (material == Material.CROSSBOW)
return new CrossbowMeta();
if (material == Material.WRITABLE_BOOK)
return new WritableBookMeta();
if (material == Material.WRITTEN_BOOK)
return new WrittenBookMeta();
2021-01-13 03:42:31 +01:00
if (material == Material.FIREWORK_STAR)
return new FireworkEffectMeta();
if (material == Material.FIREWORK_ROCKET)
return new FireworkMeta();
2020-08-01 20:50:39 +02:00
if (material == Material.PLAYER_HEAD)
return new PlayerHeadMeta();
2020-08-01 03:33:22 +02:00
if (material == Material.LEATHER_HELMET ||
material == Material.LEATHER_CHESTPLATE ||
material == Material.LEATHER_LEGGINGS ||
material == Material.LEATHER_BOOTS)
return new LeatherArmorMeta();
2020-07-23 05:36:15 +02:00
return null;
}
/**
* Creates a {@link NBTCompound} containing the data of this item.
* <p>
* WARNING: modifying the returned nbt will not affect the item.
*
* @return this item nbt
*/
2020-10-24 11:19:54 +02:00
@NotNull
public NBTCompound toNBT() {
NBTCompound compound = new NBTCompound()
.setByte("Count", amount)
2020-07-23 05:36:15 +02:00
.setString("id", material.getName());
if (hasNbtTag()) {
NBTCompound additionalTag = new NBTCompound();
NBTUtils.saveDataIntoNBT(this, additionalTag);
compound.set("tag", additionalTag);
}
return compound;
}
2020-08-18 02:16:30 +02:00
/**
2020-10-15 21:16:31 +02:00
* WARNING: not implemented yet.
2020-08-18 02:16:30 +02:00
* <p>
* This is be called each time an item is serialized to be send to a player,
2020-10-15 21:16:31 +02:00
* can be used to customize the display of the item based on player data.
2020-08-18 02:16:30 +02:00
*
* @param player the player
* @return the custom {@link ItemDisplay} for {@code player},
2020-09-20 15:04:07 +02:00
* null to use the normal item display name &amp; lore
2020-08-18 02:16:30 +02:00
*/
public ItemDisplay getCustomDisplay(Player player) {
throw new UnsupportedOperationException("Not implemented yet");
}
// Callback events
/**
2020-10-14 16:41:36 +02:00
* Called when the player right clicks with this item.
*
2020-08-13 20:24:40 +02:00
* @param player the player who used the item
* @param hand the hand used
*/
2020-10-24 11:19:54 +02:00
public void onRightClick(@NotNull Player player, @NotNull Player.Hand hand) {
}
/**
2020-10-14 16:41:36 +02:00
* Called when the player left clicks with this item.
*
2020-08-13 20:24:40 +02:00
* @param player the player who used the item
* @param hand the hand used
*/
2020-10-24 11:19:54 +02:00
public void onLeftClick(@NotNull Player player, @NotNull Player.Hand hand) {
}
/**
2020-10-14 16:41:36 +02:00
* Called when the player right clicks with this item on a block.
*
2020-08-13 20:24:40 +02:00
* @param player the player who used the item
* @param hand the hand used
* @param position the position of the interacted block
* @param blockFace the block face
* @return true if it prevents normal item use (placing blocks for instance)
*/
2020-10-24 11:19:54 +02:00
public boolean onUseOnBlock(@NotNull Player player, @NotNull Player.Hand hand, @NotNull BlockPosition position, @NotNull Direction blockFace) {
return false;
}
2020-08-13 19:12:16 +02:00
/**
2020-10-14 16:41:36 +02:00
* Called when the player click on this item on an inventory.
2020-08-13 19:12:16 +02:00
* <p>
2020-10-14 16:41:36 +02:00
* Executed before any events.
2020-08-13 19:12:16 +02:00
*
2020-08-13 20:24:40 +02:00
* @param player the player who clicked on the item
* @param clickType the click type
* @param slot the slot clicked
* @param playerInventory true if the click is in the player inventory
2020-08-13 19:12:16 +02:00
*/
2020-10-24 11:19:54 +02:00
public void onInventoryClick(@NotNull Player player, @NotNull ClickType clickType, int slot, boolean playerInventory) {
2020-08-13 19:12:16 +02:00
}
}