2020-04-24 03:25:58 +02:00
|
|
|
package net.minestom.server.item;
|
2019-08-12 08:30:59 +02:00
|
|
|
|
2020-06-22 23:25:00 +02:00
|
|
|
import net.minestom.server.chat.ColoredText;
|
2020-04-24 03:25:58 +02:00
|
|
|
import net.minestom.server.data.Data;
|
|
|
|
import net.minestom.server.data.DataContainer;
|
2020-10-14 16:33:32 +02:00
|
|
|
import net.minestom.server.entity.ItemEntity;
|
2020-08-13 19:00:19 +02:00
|
|
|
import net.minestom.server.entity.Player;
|
2020-10-14 16:33:32 +02:00
|
|
|
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;
|
2020-10-14 16:33:32 +02:00
|
|
|
import net.minestom.server.network.packet.server.play.SetSlotPacket;
|
2020-07-13 14:36:39 +02:00
|
|
|
import net.minestom.server.registry.Registries;
|
2020-08-13 19:00:19 +02:00
|
|
|
import net.minestom.server.utils.BlockPosition;
|
|
|
|
import net.minestom.server.utils.Direction;
|
2020-07-13 14:36:39 +02:00
|
|
|
import net.minestom.server.utils.NBTUtils;
|
2020-05-23 04:20:01 +02:00
|
|
|
import net.minestom.server.utils.validate.Check;
|
2020-07-13 14:36:39 +02:00
|
|
|
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
|
2020-10-14 16:33:32 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Represents an item in an inventory ({@link PlayerInventory}, {@link Inventory}) or on the ground ({@link ItemEntity}).
|
|
|
|
* <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}.
|
|
|
|
*/
|
2019-08-29 02:15:52 +02:00
|
|
|
public class ItemStack implements DataContainer {
|
2019-08-12 08:30:59 +02:00
|
|
|
|
2020-05-27 12:33:12 +02:00
|
|
|
private static final StackingRule DEFAULT_STACKING_RULE = new VanillaStackingRule(127);
|
|
|
|
|
2020-10-14 16:33:32 +02:00
|
|
|
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
|
|
|
|
2020-07-23 05:36:15 +02:00
|
|
|
public ItemStack(Material material, byte amount, int damage) {
|
|
|
|
this.material = material;
|
|
|
|
this.amount = amount;
|
|
|
|
this.damage = damage;
|
|
|
|
this.lore = new ArrayList<>();
|
|
|
|
|
|
|
|
this.enchantmentMap = new HashMap<>();
|
|
|
|
this.attributes = new ArrayList<>();
|
|
|
|
|
|
|
|
this.itemMeta = findMeta();
|
|
|
|
}
|
|
|
|
|
2020-06-22 23:25:00 +02:00
|
|
|
private ColoredText displayName;
|
2019-08-22 14:52:32 +02:00
|
|
|
private boolean unbreakable;
|
2020-06-22 23:25:00 +02:00
|
|
|
private ArrayList<ColoredText> lore;
|
2019-08-22 14:52:32 +02:00
|
|
|
|
2020-05-22 21:46:50 +02:00
|
|
|
private Map<Enchantment, Short> 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-07-09 15:51:39 +02:00
|
|
|
private NBTConsumer nbtConsumer;
|
|
|
|
|
2020-05-29 20:24:39 +02:00
|
|
|
{
|
|
|
|
if (defaultStackingRule == null)
|
|
|
|
defaultStackingRule = DEFAULT_STACKING_RULE;
|
2020-09-24 01:50:25 +02:00
|
|
|
this.stackingRule = defaultStackingRule;
|
2020-05-29 20:24:39 +02:00
|
|
|
}
|
|
|
|
|
2020-07-23 05:36:15 +02:00
|
|
|
public ItemStack(Material material, byte amount) {
|
|
|
|
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}.
|
2020-08-12 13:10:57 +02:00
|
|
|
*
|
|
|
|
* @return an air item
|
|
|
|
*/
|
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
|
|
|
|
*/
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
public static void setDefaultStackingRule(StackingRule defaultStackingRule) {
|
|
|
|
Check.notNull(defaultStackingRule, "StackingRule cannot be null!");
|
|
|
|
ItemStack.defaultStackingRule = defaultStackingRule;
|
|
|
|
}
|
|
|
|
|
2020-10-14 16:33:32 +02:00
|
|
|
/**
|
2020-10-15 21:16:31 +02:00
|
|
|
* Loads an {@link ItemStack} from nbt.
|
2020-10-14 16:33:32 +02:00
|
|
|
*
|
|
|
|
* @param nbt the nbt compound containing the item
|
|
|
|
* @return the parsed item stack
|
|
|
|
*/
|
2020-07-23 05:36:15 +02:00
|
|
|
public static ItemStack fromNBT(NBTCompound nbt) {
|
|
|
|
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"));
|
2020-10-16 16:32:57 +02:00
|
|
|
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.
|
2020-10-14 16:33:32 +02:00
|
|
|
* 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
|
2020-05-29 21:30:42 +02:00
|
|
|
* @return true if both items are similar
|
2020-02-13 15:14:41 +01:00
|
|
|
*/
|
2020-08-14 15:24:57 +02:00
|
|
|
public boolean isSimilar(ItemStack itemStack) {
|
|
|
|
synchronized (ItemStack.class) {
|
2020-06-22 23:25:00 +02:00
|
|
|
final ColoredText itemDisplayName = itemStack.getDisplayName();
|
2020-05-29 21:30:42 +02:00
|
|
|
final boolean displayNameCheck = (displayName == null && itemDisplayName == null) ||
|
2020-10-19 11:56:26 +02:00
|
|
|
(displayName != null && displayName.equals(itemDisplayName));
|
2020-05-29 21:30:42 +02:00
|
|
|
|
|
|
|
final Data itemData = itemStack.getData();
|
|
|
|
final boolean dataCheck = (data == null && itemData == null) ||
|
2020-10-19 11:56:26 +02:00
|
|
|
(data != null && data.equals(itemData));
|
2020-05-29 21:30:42 +02:00
|
|
|
|
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 &&
|
2020-05-29 21:30:42 +02:00
|
|
|
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 &&
|
2020-05-29 21:30:42 +02:00
|
|
|
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>
|
2020-10-19 11:56:26 +02:00
|
|
|
* 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-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
|
|
|
|
*/
|
|
|
|
public void setItemMeta(ItemMeta itemMeta) {
|
|
|
|
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-06-22 23:25:00 +02:00
|
|
|
public ColoredText 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
|
|
|
|
*/
|
2020-06-22 23:25:00 +02:00
|
|
|
public void setDisplayName(ColoredText 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
|
|
|
*
|
|
|
|
* @return the item lore, can be null if not present
|
|
|
|
*/
|
2020-06-22 23:25:00 +02:00
|
|
|
public ArrayList<ColoredText> 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
|
|
|
*
|
|
|
|
* @param lore the item lore, can be null to remove
|
|
|
|
*/
|
2020-06-22 23:25:00 +02:00
|
|
|
public void setLore(ArrayList<ColoredText> 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-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-05-22 21:46:50 +02:00
|
|
|
public void setEnchantment(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-04-29 20:17:04 +02:00
|
|
|
public void removeEnchantment(Enchantment enchantment) {
|
|
|
|
this.enchantmentMap.remove(enchantment);
|
|
|
|
}
|
|
|
|
|
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-04-29 20:17:04 +02:00
|
|
|
public int getEnchantmentLevel(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-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
|
|
|
|
*/
|
|
|
|
public ItemAttribute getAttribute(String internalName) {
|
|
|
|
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-05-28 23:43:12 +02:00
|
|
|
public void addAttribute(ItemAttribute itemAttribute) {
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
public void removeAttribute(ItemAttribute itemAttribute) {
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
public void addItemFlags(ItemFlag... flags) {
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
public void removeItemFlags(ItemFlag... flags) {
|
|
|
|
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-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-05-22 21:46:50 +02:00
|
|
|
public boolean hasItemFlag(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;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
public Material getMaterial() {
|
|
|
|
return material;
|
|
|
|
}
|
|
|
|
|
2020-10-14 16:33:32 +02:00
|
|
|
/**
|
2020-10-15 21:16:31 +02:00
|
|
|
* Changes the item {@link Material}.
|
2020-10-14 16:33:32 +02:00
|
|
|
*
|
|
|
|
* @param material the new material
|
|
|
|
*/
|
|
|
|
public void setMaterial(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() {
|
2020-10-04 03:04:51 +02:00
|
|
|
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() ||
|
2020-10-04 03:04:51 +02:00
|
|
|
hideFlag != 0 ||
|
|
|
|
customModelData != 0 ||
|
|
|
|
(itemMeta != null && itemMeta.hasNbt());
|
2020-02-13 15:14:41 +01:00
|
|
|
}
|
|
|
|
|
2020-05-30 01:39:52 +02:00
|
|
|
/**
|
2020-10-15 21:16:31 +02:00
|
|
|
* Clones this item stack.
|
2020-05-30 01:39:52 +02:00
|
|
|
*
|
|
|
|
* @return a cloned item stack
|
|
|
|
*/
|
2020-05-29 20:24:39 +02:00
|
|
|
public synchronized ItemStack clone() {
|
2020-07-23 05:36:15 +02:00
|
|
|
ItemStack itemStack = new ItemStack(material, amount, damage);
|
2019-08-22 14:52:32 +02:00
|
|
|
itemStack.setDisplayName(displayName);
|
|
|
|
itemStack.setUnbreakable(unbreakable);
|
2020-07-06 13:24:01 +02:00
|
|
|
itemStack.setLore(new ArrayList<>(getLore()));
|
2020-02-16 19:11:36 +01:00
|
|
|
itemStack.setStackingRule(getStackingRule());
|
2020-04-29 20:17:04 +02:00
|
|
|
|
|
|
|
itemStack.enchantmentMap = new HashMap<>(enchantmentMap);
|
2020-05-29 18:56:42 +02:00
|
|
|
itemStack.attributes = new ArrayList<>(attributes);
|
2020-07-06 13:24:01 +02:00
|
|
|
|
2020-05-29 18:56:42 +02:00
|
|
|
itemStack.hideFlag = hideFlag;
|
2020-07-06 13:24:01 +02:00
|
|
|
itemStack.customModelData = customModelData;
|
2020-04-29 20:17:04 +02:00
|
|
|
|
2020-07-23 05:36:15 +02:00
|
|
|
if (itemMeta != null)
|
|
|
|
itemStack.itemMeta = itemMeta.clone();
|
|
|
|
|
|
|
|
final Data data = getData();
|
2020-02-09 15:34:09 +01:00
|
|
|
if (data != null)
|
|
|
|
itemStack.setData(data.clone());
|
2019-08-22 14:52:32 +02:00
|
|
|
return itemStack;
|
2019-08-12 08:30:59 +02:00
|
|
|
}
|
2019-08-29 02:15:52 +02:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public Data getData() {
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void setData(Data data) {
|
|
|
|
this.data = data;
|
|
|
|
}
|
2020-02-17 17:33:53 +01:00
|
|
|
|
2020-07-09 15:51:39 +02:00
|
|
|
/**
|
2020-10-19 11:56:26 +02:00
|
|
|
* Gets the {@link NBTConsumer} called when the item is serialized into a packet.
|
2020-07-09 15:51:39 +02:00
|
|
|
*
|
|
|
|
* @return the item nbt consumer, null if not any
|
|
|
|
*/
|
|
|
|
public NBTConsumer getNBTConsumer() {
|
|
|
|
return nbtConsumer;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-19 11:56:26 +02:00
|
|
|
* Changes the item {@link NBTConsumer}.
|
2020-07-09 15:51:39 +02:00
|
|
|
*
|
|
|
|
* @param nbtConsumer the new item nbt consumer
|
|
|
|
*/
|
|
|
|
public void setNBTConsumer(NBTConsumer nbtConsumer) {
|
|
|
|
this.nbtConsumer = nbtConsumer;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
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-05-23 04:20:01 +02:00
|
|
|
public void setStackingRule(StackingRule stackingRule) {
|
2020-08-12 13:10:57 +02:00
|
|
|
Check.notNull(stackingRule, "The stacking rule cannot be null!");
|
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
|
|
|
|
*/
|
|
|
|
public ItemStack consume(int amount) {
|
|
|
|
final int currentAmount = stackingRule.getAmount(this);
|
|
|
|
if (currentAmount < amount)
|
|
|
|
return null;
|
|
|
|
return stackingRule.apply(this, currentAmount - amount);
|
|
|
|
}
|
|
|
|
|
2020-05-22 21:46:50 +02:00
|
|
|
private byte getBitModifier(ItemFlag hideFlag) {
|
|
|
|
return (byte) (1 << hideFlag.ordinal());
|
|
|
|
}
|
2020-07-13 14:36:39 +02:00
|
|
|
|
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
|
|
|
*
|
|
|
|
* @return the item meta
|
|
|
|
*/
|
|
|
|
private ItemMeta findMeta() {
|
2020-08-09 20:30:46 +02:00
|
|
|
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();
|
|
|
|
|
2020-08-01 03:19:48 +02:00
|
|
|
if (material == Material.WRITABLE_BOOK)
|
|
|
|
return new WritableBookMeta();
|
|
|
|
|
|
|
|
if (material == Material.WRITTEN_BOOK)
|
|
|
|
return new WrittenBookMeta();
|
|
|
|
|
2020-08-01 03:57:55 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-07-13 14:36:39 +02:00
|
|
|
public NBTCompound toNBT() {
|
|
|
|
NBTCompound compound = new NBTCompound()
|
|
|
|
.setByte("Count", amount)
|
2020-07-23 05:36:15 +02:00
|
|
|
.setString("id", material.getName());
|
|
|
|
if (hasNbtTag()) {
|
2020-07-13 14:36:39 +02:00
|
|
|
NBTCompound additionalTag = new NBTCompound();
|
|
|
|
NBTUtils.saveDataIntoNBT(this, additionalTag);
|
|
|
|
compound.set("tag", additionalTag);
|
|
|
|
}
|
|
|
|
return compound;
|
|
|
|
}
|
2020-08-13 19:00:19 +02:00
|
|
|
|
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 & lore
|
2020-08-18 02:16:30 +02:00
|
|
|
*/
|
|
|
|
public ItemDisplay getCustomDisplay(Player player) {
|
|
|
|
throw new UnsupportedOperationException("Not implemented yet");
|
|
|
|
}
|
|
|
|
|
2020-08-13 19:00:19 +02:00
|
|
|
// Callback events
|
|
|
|
|
|
|
|
/**
|
2020-10-14 16:41:36 +02:00
|
|
|
* Called when the player right clicks with this item.
|
2020-08-13 19:00:19 +02:00
|
|
|
*
|
2020-08-13 20:24:40 +02:00
|
|
|
* @param player the player who used the item
|
|
|
|
* @param hand the hand used
|
2020-08-13 19:00:19 +02:00
|
|
|
*/
|
|
|
|
public void onRightClick(Player player, Player.Hand hand) {
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-10-14 16:41:36 +02:00
|
|
|
* Called when the player left clicks with this item.
|
2020-08-13 19:00:19 +02:00
|
|
|
*
|
2020-08-13 20:24:40 +02:00
|
|
|
* @param player the player who used the item
|
|
|
|
* @param hand the hand used
|
2020-08-13 19:00:19 +02:00
|
|
|
*/
|
|
|
|
public void onLeftClick(Player player, 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 19:00:19 +02:00
|
|
|
*
|
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
|
2020-08-13 19:00:19 +02:00
|
|
|
* @return true if it prevents normal item use (placing blocks for instance)
|
|
|
|
*/
|
|
|
|
public boolean onUseOnBlock(Player player, Player.Hand hand, BlockPosition position, 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
|
|
|
*/
|
|
|
|
public void onInventoryClick(Player player, ClickType clickType, int slot, boolean playerInventory) {
|
|
|
|
|
|
|
|
}
|
2019-08-12 08:30:59 +02:00
|
|
|
}
|