2020-04-24 03:25:58 +02:00
|
|
|
package net.minestom.server.item;
|
2019-08-12 08:30:59 +02:00
|
|
|
|
2020-04-24 03:25:58 +02:00
|
|
|
import net.minestom.server.data.Data;
|
|
|
|
import net.minestom.server.data.DataContainer;
|
2020-05-28 23:43:12 +02:00
|
|
|
import net.minestom.server.item.attribute.ItemAttribute;
|
2020-04-24 03:25:58 +02:00
|
|
|
import net.minestom.server.item.rule.VanillaStackingRule;
|
2020-05-27 12:33:12 +02:00
|
|
|
import net.minestom.server.potion.PotionType;
|
2020-05-23 04:20:01 +02:00
|
|
|
import net.minestom.server.utils.validate.Check;
|
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
|
|
|
|
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-04-23 12:30:49 +02:00
|
|
|
public static ItemStack getAirItem() {
|
|
|
|
return new ItemStack((short) 0, (byte) 0);
|
|
|
|
}
|
|
|
|
|
2020-03-20 19:50:22 +01:00
|
|
|
private static StackingRule defaultStackingRule;
|
|
|
|
|
2020-04-10 12:45:04 +02:00
|
|
|
private short materialId;
|
2019-08-12 08:30:59 +02:00
|
|
|
|
2019-08-13 17:52:09 +02:00
|
|
|
private byte amount;
|
2019-09-06 16:05:36 +02:00
|
|
|
private short damage;
|
2019-08-12 08:30:59 +02:00
|
|
|
|
2019-08-22 14:52:32 +02:00
|
|
|
private String displayName;
|
|
|
|
private boolean unbreakable;
|
2020-02-13 15:14:41 +01:00
|
|
|
private ArrayList<String> 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:54:26 +02:00
|
|
|
private Map<Enchantment, Short> storedEnchantmentMap;
|
2020-05-28 23:43:12 +02:00
|
|
|
private List<ItemAttribute> attributes;
|
|
|
|
private Set<PotionType> potionTypes;
|
2020-05-22 21:46:50 +02:00
|
|
|
|
2020-05-27 12:33:12 +02:00
|
|
|
{
|
|
|
|
if (defaultStackingRule == null)
|
|
|
|
defaultStackingRule = DEFAULT_STACKING_RULE;
|
|
|
|
}
|
|
|
|
|
2020-05-22 21:46:50 +02:00
|
|
|
private int hideFlag;
|
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-04-10 12:45:04 +02:00
|
|
|
public ItemStack(short materialId, byte amount, short damage) {
|
2020-03-29 20:58:30 +02:00
|
|
|
this.materialId = materialId;
|
2019-08-13 17:52:09 +02:00
|
|
|
this.amount = amount;
|
2019-09-06 16:05:36 +02:00
|
|
|
this.damage = damage;
|
2020-02-13 15:14:41 +01:00
|
|
|
this.lore = new ArrayList<>();
|
2020-02-17 17:33:53 +01:00
|
|
|
|
2020-04-29 20:17:04 +02:00
|
|
|
this.enchantmentMap = new HashMap<>();
|
2020-05-28 23:54:26 +02:00
|
|
|
this.storedEnchantmentMap = new HashMap<>();
|
2020-05-28 23:43:12 +02:00
|
|
|
this.attributes = new ArrayList<>();
|
2020-05-27 12:33:12 +02:00
|
|
|
this.potionTypes = new HashSet<>();
|
2020-04-29 20:17:04 +02:00
|
|
|
|
2020-02-17 17:33:53 +01:00
|
|
|
this.stackingRule = defaultStackingRule;
|
2019-08-13 17:52:09 +02:00
|
|
|
}
|
|
|
|
|
2020-04-10 12:45:04 +02:00
|
|
|
public ItemStack(short materialId, byte amount) {
|
|
|
|
this(materialId, amount, (short) 0);
|
2020-03-29 20:58:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public ItemStack(Material material, byte amount) {
|
|
|
|
this(material.getId(), amount);
|
2019-08-22 14:52:32 +02:00
|
|
|
}
|
|
|
|
|
2019-08-13 17:52:09 +02:00
|
|
|
public boolean isAir() {
|
2020-03-29 20:58:30 +02:00
|
|
|
return materialId == Material.AIR.getId();
|
2019-08-13 17:52:09 +02:00
|
|
|
}
|
|
|
|
|
2020-02-13 15:14:41 +01:00
|
|
|
/**
|
|
|
|
* Do not take amount in consideration
|
|
|
|
*
|
2020-03-29 20:58:30 +02:00
|
|
|
* @param itemStack The ItemStack to compare to
|
|
|
|
* @return true if both items are similar (without comparing amount)
|
2020-02-13 15:14:41 +01:00
|
|
|
*/
|
2019-08-13 17:52:09 +02:00
|
|
|
public boolean isSimilar(ItemStack itemStack) {
|
2020-03-29 20:58:30 +02:00
|
|
|
return itemStack.getMaterialId() == materialId &&
|
2019-09-06 16:05:36 +02:00
|
|
|
itemStack.getDisplayName() == displayName &&
|
|
|
|
itemStack.isUnbreakable() == unbreakable &&
|
2020-02-13 15:14:41 +01:00
|
|
|
itemStack.getDamage() == damage &&
|
2020-04-29 20:17:04 +02:00
|
|
|
itemStack.enchantmentMap.equals(enchantmentMap) &&
|
2020-05-22 21:46:50 +02:00
|
|
|
itemStack.hideFlag == hideFlag &&
|
2020-02-16 19:11:36 +01:00
|
|
|
itemStack.getStackingRule() == stackingRule &&
|
2020-02-13 15:14:41 +01:00
|
|
|
itemStack.getData() == data;
|
2019-08-13 17:52:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public byte getAmount() {
|
|
|
|
return amount;
|
2019-08-12 08:30:59 +02:00
|
|
|
}
|
|
|
|
|
2019-09-06 16:05:36 +02:00
|
|
|
public short getDamage() {
|
|
|
|
return damage;
|
|
|
|
}
|
|
|
|
|
2020-04-10 12:45:04 +02:00
|
|
|
public short getMaterialId() {
|
2020-03-29 20:58:30 +02:00
|
|
|
return materialId;
|
2019-08-12 08:30:59 +02:00
|
|
|
}
|
|
|
|
|
2020-04-22 02:42:58 +02:00
|
|
|
public Material getMaterial() {
|
|
|
|
return Material.fromId(getMaterialId());
|
|
|
|
}
|
|
|
|
|
2019-08-13 17:52:09 +02:00
|
|
|
public void setAmount(byte amount) {
|
|
|
|
this.amount = amount;
|
|
|
|
}
|
|
|
|
|
2019-09-06 16:05:36 +02:00
|
|
|
public void setDamage(short damage) {
|
|
|
|
this.damage = damage;
|
|
|
|
}
|
|
|
|
|
2019-08-22 14:52:32 +02:00
|
|
|
public String getDisplayName() {
|
|
|
|
return displayName;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setDisplayName(String displayName) {
|
|
|
|
this.displayName = displayName;
|
|
|
|
}
|
|
|
|
|
2020-02-13 15:14:41 +01:00
|
|
|
public boolean hasDisplayName() {
|
|
|
|
return displayName != null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public ArrayList<String> getLore() {
|
|
|
|
return lore;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setLore(ArrayList<String> lore) {
|
|
|
|
this.lore = lore;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean hasLore() {
|
|
|
|
return lore != null && !lore.isEmpty();
|
|
|
|
}
|
|
|
|
|
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-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);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void removeEnchantment(Enchantment enchantment) {
|
|
|
|
this.enchantmentMap.remove(enchantment);
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getEnchantmentLevel(Enchantment enchantment) {
|
2020-05-22 21:46:50 +02:00
|
|
|
return this.enchantmentMap.getOrDefault(enchantment, (short) 0);
|
|
|
|
}
|
|
|
|
|
2020-05-28 23:54:26 +02:00
|
|
|
/**
|
|
|
|
* Stored enchantments are used on enchanted book
|
|
|
|
*
|
|
|
|
* @return an unmodifiable map containing the stored enchantments
|
|
|
|
*/
|
|
|
|
public Map<Enchantment, Short> getStoredEnchantmentMap() {
|
|
|
|
return Collections.unmodifiableMap(storedEnchantmentMap);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setStoredEnchantment(Enchantment enchantment, short level) {
|
|
|
|
if (level < 1) {
|
|
|
|
removeStoredEnchantment(enchantment);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.storedEnchantmentMap.put(enchantment, level);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void removeStoredEnchantment(Enchantment enchantment) {
|
|
|
|
this.storedEnchantmentMap.remove(enchantment);
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getStoredEnchantmentLevel(Enchantment enchantment) {
|
|
|
|
return this.storedEnchantmentMap.getOrDefault(enchantment, (short) 0);
|
|
|
|
}
|
|
|
|
|
2020-05-28 23:43:12 +02:00
|
|
|
public List<ItemAttribute> getAttributes() {
|
|
|
|
return Collections.unmodifiableList(attributes);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void addAttribute(ItemAttribute itemAttribute) {
|
|
|
|
this.attributes.add(itemAttribute);
|
|
|
|
}
|
|
|
|
|
2020-05-27 12:33:12 +02:00
|
|
|
public Set<PotionType> getPotionTypes() {
|
|
|
|
return Collections.unmodifiableSet(potionTypes);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void addPotionType(PotionType potionType) {
|
|
|
|
this.potionTypes.add(potionType);
|
|
|
|
}
|
|
|
|
|
2020-05-22 21:46:50 +02:00
|
|
|
public int getHideFlag() {
|
|
|
|
return hideFlag;
|
|
|
|
}
|
|
|
|
|
2020-05-29 00:30:19 +02:00
|
|
|
public void setHideFlag(int hideFlag) {
|
|
|
|
this.hideFlag = hideFlag;
|
|
|
|
}
|
|
|
|
|
2020-05-22 21:46:50 +02:00
|
|
|
public void addItemFlags(ItemFlag... hideFlags) {
|
|
|
|
for (ItemFlag f : hideFlags) {
|
|
|
|
this.hideFlag |= getBitModifier(f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void removeItemFlags(ItemFlag... hideFlags) {
|
|
|
|
for (ItemFlag f : hideFlags) {
|
|
|
|
this.hideFlag &= ~getBitModifier(f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public Set<ItemFlag> getItemFlags() {
|
|
|
|
Set<ItemFlag> currentFlags = EnumSet.noneOf(ItemFlag.class);
|
|
|
|
|
|
|
|
for (ItemFlag f : ItemFlag.values()) {
|
|
|
|
if (hasItemFlag(f)) {
|
|
|
|
currentFlags.add(f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return currentFlags;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean hasItemFlag(ItemFlag flag) {
|
|
|
|
int bitModifier = getBitModifier(flag);
|
|
|
|
return (this.hideFlag & bitModifier) == bitModifier;
|
2020-04-29 20:17:04 +02:00
|
|
|
}
|
|
|
|
|
2019-08-22 14:52:32 +02:00
|
|
|
public boolean isUnbreakable() {
|
|
|
|
return unbreakable;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setUnbreakable(boolean unbreakable) {
|
|
|
|
this.unbreakable = unbreakable;
|
|
|
|
}
|
|
|
|
|
2020-02-13 15:14:41 +01:00
|
|
|
public boolean hasNbtTag() {
|
2020-05-28 23:43:12 +02:00
|
|
|
return hasDisplayName() || hasLore() || isUnbreakable() ||
|
2020-05-28 23:54:26 +02:00
|
|
|
!enchantmentMap.isEmpty() || !storedEnchantmentMap.isEmpty() ||
|
|
|
|
!attributes.isEmpty() || !potionTypes.isEmpty();
|
2020-02-13 15:14:41 +01:00
|
|
|
}
|
|
|
|
|
2019-08-13 17:52:09 +02:00
|
|
|
public ItemStack clone() {
|
2020-03-29 20:58:30 +02:00
|
|
|
ItemStack itemStack = new ItemStack(materialId, amount, damage);
|
2019-08-22 14:52:32 +02:00
|
|
|
itemStack.setDisplayName(displayName);
|
|
|
|
itemStack.setUnbreakable(unbreakable);
|
2020-02-16 19:11:36 +01:00
|
|
|
itemStack.setLore(getLore());
|
|
|
|
itemStack.setStackingRule(getStackingRule());
|
2020-04-29 20:17:04 +02:00
|
|
|
|
|
|
|
itemStack.enchantmentMap = new HashMap<>(enchantmentMap);
|
|
|
|
|
2020-02-09 15:34:09 +01:00
|
|
|
Data data = getData();
|
|
|
|
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
|
|
|
|
2020-02-16 19:11:36 +01:00
|
|
|
public StackingRule getStackingRule() {
|
|
|
|
return stackingRule;
|
|
|
|
}
|
|
|
|
|
2020-05-23 04:20:01 +02:00
|
|
|
public static void setDefaultStackingRule(StackingRule defaultStackingRule) {
|
|
|
|
Check.notNull(defaultStackingRule, "StackingRule cannot be null!");
|
|
|
|
ItemStack.defaultStackingRule = defaultStackingRule;
|
2020-02-16 19:11:36 +01: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
|
|
|
|
|
|
|
public static StackingRule getDefaultStackingRule() {
|
|
|
|
return defaultStackingRule;
|
|
|
|
}
|
|
|
|
|
2020-05-23 04:20:01 +02:00
|
|
|
public void setStackingRule(StackingRule stackingRule) {
|
|
|
|
Check.notNull(stackingRule, "StackingRule cannot be null!");
|
|
|
|
this.stackingRule = stackingRule;
|
2020-02-17 17:33:53 +01:00
|
|
|
}
|
2020-05-22 21:46:50 +02:00
|
|
|
|
|
|
|
private byte getBitModifier(ItemFlag hideFlag) {
|
|
|
|
return (byte) (1 << hideFlag.ordinal());
|
|
|
|
}
|
2019-08-12 08:30:59 +02:00
|
|
|
}
|