All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bukkit.inventory.ItemStack Maven / Gradle / Ivy

package org.bukkit.inventory;

import com.google.common.collect.ImmutableMap;
import net.minecraft.server.NBTTagCompound;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Utility;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.material.MaterialData;
import walkmc.Materials;
import walkmc.item.IItem;
import walkmc.item.ItemRegistry;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Represents a stack of items
 */
public class ItemStack implements Cloneable, ConfigurationSerializable {
  private int type = 0;
  private int amount = 0;
  private MaterialData data = null;
  private short durability = 0;
  private ItemMeta meta;
  
  //
  //    From WalkMC section:
  //
  
  private IItem customItem;
  private NBTTagCompound tag = new NBTTagCompound();
  
  public NBTTagCompound getTag() {
    return tag;
  }
  
  public void setTag(NBTTagCompound tag) {
    this.tag = tag;
  }
  
  public boolean hasTag() {
    return tag != null && !tag.isEmpty();
  }
  
  //
  //    End of all sections.
  //
  
  @Utility
  protected ItemStack() {
  }

  /**
   * Creates a item stack from a Materials new enum object.
   */
  public ItemStack(final Materials type) {
    this(type.toItem(1));
  }

  /**
   * Creates a item stack from a Materials new enum object.
   */
  public ItemStack(final Materials type, final int amount) {
    this(type.toItem(amount));
  }

  /**
   * Defaults stack size to 1, with no extra data
   *
   * @param type item material id
   * @deprecated Magic value
   */
  @Deprecated
  public ItemStack(final int type) {
    this(type, 1);
  }

  /**
   * Defaults stack size to 1, with no extra data
   *
   * @param type item material
   */
  public ItemStack(final Material type) {
    this(type, 1);
  }

  /**
   * An item stack with no extra data
   *
   * @param type   item material id
   * @param amount stack size
   * @deprecated Magic value
   */
  @Deprecated
  public ItemStack(final int type, final int amount) {
    this(type, amount, (short) 0);
  }

  /**
   * An item stack with no extra data
   *
   * @param type   item material
   * @param amount stack size
   */
  public ItemStack(final Material type, final int amount) {
    this(type.getId(), amount);
  }

  /**
   * An item stack with the specified damage / durability
   *
   * @param type   item material id
   * @param amount stack size
   * @param damage durability / damage
   * @deprecated Magic value
   */
  @Deprecated
  public ItemStack(final int type, final int amount, final short damage) {
    this.type = type;
    this.amount = amount;
    this.durability = damage;
    this.data = new MaterialData(type, (byte) durability);
  }

  /**
   * An item stack with the specified damage / durabiltiy
   *
   * @param type   item material
   * @param amount stack size
   * @param damage durability / damage
   */
  public ItemStack(final Material type, final int amount, final short damage) {
    this(type.getId(), amount, damage);
  }

  /**
   * @param type   the raw type id
   * @param amount the amount in the stack
   * @param damage the damage value of the item
   * @param data   the data value or null
   * @deprecated this method uses an ambiguous data byte object
   */
  @Deprecated
  public ItemStack(final int type, final int amount, final short damage, final Byte data) {
    this.type = type;
    this.amount = amount;
    this.durability = damage;
    if (data != null) {
      createData(data);
      this.durability = data;
    }
  }

  /**
   * @param type   the type
   * @param amount the amount in the stack
   * @param damage the damage value of the item
   * @param data   the data value or null
   * @deprecated this method uses an ambiguous data byte object
   */
  @Deprecated
  public ItemStack(final Material type, final int amount, final short damage, final Byte data) {
    this(type.getId(), amount, damage, data);
  }

  /**
   * Creates a new item stack derived from the specified stack
   *
   * @param stack the stack to copy
   * @throws IllegalArgumentException if the specified stack is null or
   *                                  returns an item meta not created by the item factory
   */
  public ItemStack(final ItemStack stack) throws IllegalArgumentException {
    Validate.notNull(stack, "Cannot copy null stack");
    this.type = stack.getTypeId();
    this.amount = stack.getAmount();
    this.durability = stack.getDurability();
    this.data = stack.getData();
    if (stack.hasCustomItem())
      setCustomItem(stack.getCustomItem());
    
    if (stack.hasTag())
      setTag(stack.getTag());
    
    if (stack.hasItemMeta()) {
      setItemMeta0(stack.getItemMeta(), getType0());
    }
  }

  private static Material getType0(int id) {
    Material material = Material.getMaterial(id);
    return material == null ? Material.AIR : material;
  }

  /**
   * Required method for configuration serialization
   *
   * @param args map to deserialize
   * @return deserialized item stack
   * @see ConfigurationSerializable
   */
  public static ItemStack deserialize(Map args) {
    Material type = Material.getMaterial((String) args.get("type"));
    short damage = 0;
    int amount = 1;

    if (args.containsKey("damage")) {
      damage = ((Number) args.get("damage")).shortValue();
    }

    if (args.containsKey("amount")) {
      amount = ((Number) args.get("amount")).intValue();
    }

    ItemStack result = new ItemStack(type, amount, damage);
    
    if (args.containsKey("CustomItem"))
      result.setCustomItem(ItemRegistry.find((String) args.get("CustomItem")));

    if (args.containsKey("enchantments")) { // Backward compatiblity, @deprecated
      Object raw = args.get("enchantments");

      if (raw instanceof Map) {
        Map map = (Map) raw;

        for (Map.Entry entry : map.entrySet()) {
          Enchantment enchantment = Enchantment.getByName(entry.getKey().toString());

          if ((enchantment != null) && (entry.getValue() instanceof Integer)) {
            result.addUnsafeEnchantment(enchantment, (Integer) entry.getValue());
          }
        }
      }
    } else if (args.containsKey("meta")) { // We cannot and will not have meta when enchantments (pre-ItemMeta) exist
      Object raw = args.get("meta");
      if (raw instanceof ItemMeta) {
        result.setItemMeta((ItemMeta) raw);
      }
    }

    return result;
  }
  
  /**
   * Returns the custom item instance of this item stack.
   */
  public IItem getCustomItem() {
    return customItem;
  }
  
  /**
   * Sets the new custom item instance of this item stack.
   */
  public void setCustomItem(IItem customItem) {
    this.customItem = customItem;
  }
  
  /**
   * Returns if this item stack has a valid instance of custom item.
   */
  public boolean hasCustomItem() {
    return customItem != null;
  }
  
  /**
   * Returns this item stack as a craft item stack.
   */
  public CraftItemStack getCraftItem() {
    return CraftItemStack.asCraftCopy(this);
  }
  
  /**
   * Return the NMS handler of this item stack.
   *
   * Can return null if this item stack is not implemented by CraftItemStack or is AIR.
   */
  public net.minecraft.server.ItemStack getHandler() {
    return null;
  }
  
  /**
   * Gets the display name of this item stack.
   */
  public String getName() {
    return meta == null ? null : meta.getDisplayName();
  }
  
  /**
   * Sets the display name of this item stack.
   */
  public void setName(String name) {
    getOrCreateMeta().setDisplayName(name);
  }
  
  /**
   * Returns if this item stack has a display name.
   */
  public boolean hasName() {
    return meta != null && meta.hasDisplayName();
  }
  
  /**
   * Gets the lore of this item stack.
   */
  public List getLore() {
    return meta == null ? null : meta.getLore();
  }
  
  /**
   * Sets the new lore of this item stack.
   */
  public void setLore(List lore) {
    getOrCreateMeta().setLore(lore);
  }
  
  /**
   * Returns if this item stack has lore.
   */
  public boolean hasLore() {
    return meta != null && meta.hasLore();
  }
  
  /**
   * Gets the material object of this item.
   */
  public Materials getMaterial() {
    return Materials.from(type, durability);
  }
  
  /**
   * Sets the material object of this item.
   */
  public void setMaterial(Materials material) {
    this.setTypeId(material.getId());
    this.durability = (short) material.getSubdata();
    //this.data = material.getData(); TODO: Must have to set data?
  }
  
  /**
   * Updates the meta of this item stack to the data of the specified item.
   */
  public void updateMeta(net.minecraft.server.ItemStack item) {
    setItemMeta(CraftItemStack.getItemMeta(item));
  }

  /**
   * Gets the type of this item
   *
   * @return Type of the items in this stack
   */
  @Utility
  public Material getType() {
    return getType0(getTypeId());
  }

  /**
   * Sets the type of this item
   * 

* Note that in doing so you will reset the MaterialData for this stack * * @param type New type to set the items in this stack to */ @Utility public void setType(Material type) { Validate.notNull(type, "Material cannot be null"); setTypeId(type.getId()); } private Material getType0() { return getType0(this.type); } /** * Gets the type id of this item * * @return Type Id of the items in this stack * @deprecated Magic value */ @Deprecated public int getTypeId() { return type; } /** * Sets the type id of this item *

* Note that in doing so you will reset the MaterialData for this stack * * @param type New type id to set the items in this stack to * @deprecated Magic value */ @Deprecated public void setTypeId(int type) { this.type = type; if (this.meta != null) { this.meta = Bukkit.getItemFactory().asMetaFor(meta, getType0()); } createData((byte) 0); } /** * Gets the amount of items in this stack * * @return Amount of items in this stick */ public int getAmount() { return amount; } /** * Sets the amount of items in this stack * * @param amount New amount of items in this stack */ public void setAmount(int amount) { this.amount = amount; } /** * Gets the MaterialData for this stack of items * * @return MaterialData for this item */ public MaterialData getData() { Material mat = getType(); if (data == null && mat != null && mat.getData() != null) { data = mat.getNewData((byte) this.getDurability()); } return data; } /** * Sets the MaterialData for this stack of items * * @param data New MaterialData for this item */ public void setData(MaterialData data) { Material mat = getType(); if (data == null || mat == null || mat.getData() == null) { this.data = data; } else { if ((data.getClass() == mat.getData()) || (data.getClass() == MaterialData.class)) { this.data = data; } else { throw new IllegalArgumentException("Provided data is not of type " + mat.getData().getName() + ", found " + data.getClass().getName()); } } } /** * Gets the durability of this item * * @return Durability of this item */ public short getDurability() { return durability; } /** * Sets the durability of this item * * @param durability Durability of this item */ public void setDurability(final short durability) { this.durability = durability; } /** * Get the maximum stacksize for the material hold in this ItemStack. * (Returns -1 if it has no idea) * * @return The maximum you can stack this material to. */ @Utility public int getMaxStackSize() { Material material = getType(); if (material != null) { return material.getMaxStackSize(); } return -1; } private void createData(final byte data) { Material mat = Material.getMaterial(type); if (mat == null) { this.data = new MaterialData(type, data); } else { this.data = mat.getNewData(data); } } @Override @Utility public String toString() { StringBuilder toString = new StringBuilder("ItemStack{").append(getType().name()).append(" x ").append(getAmount()); if (hasCustomItem()) { toString.append(" with custom item ").append(getCustomItem().getId()).append(" "); } if (hasItemMeta()) { toString.append(", ").append(getItemMeta()); } return toString.append('}').toString(); } @Override @Utility public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof ItemStack)) { return false; } ItemStack stack = (ItemStack) obj; return getAmount() == stack.getAmount() && isSimilar(stack); } /** * This method is the same as equals, but does not consider stack size * (amount). * * @param stack the item stack to compare to * @return true if the two stacks are equal, ignoring the amount */ @Utility public boolean isSimilar(ItemStack stack) { if (stack == null) return false; if (stack == this) return true; if (getTypeId() != stack.getTypeId()) return false; if (getDurability() != stack.getDurability()) return false; return hasCustomItem() == stack.hasCustomItem() && (!hasCustomItem() || getCustomItem().getId().equals(stack.getCustomItem().getId())) && hasItemMeta() == stack.hasItemMeta() && (!hasItemMeta() || Bukkit.getItemFactory().equals(getItemMeta(), stack.getItemMeta())) ; } @Override public ItemStack clone() { try { ItemStack itemStack = (ItemStack) super.clone(); if (hasCustomItem()) itemStack.customItem = customItem; if (this.meta != null) { itemStack.meta = this.meta.clone(); } if (this.data != null) { itemStack.data = this.data.clone(); } return itemStack; } catch (CloneNotSupportedException e) { throw new Error(e); } } @Override @Utility public final int hashCode() { int hash = 1; hash = hash * 31 + getTypeId(); hash = hash * 31 + getAmount(); hash = hash * 31 + (getDurability() & 0xffff); hash = hash * 31 + (hasItemMeta() ? (meta == null ? getItemMeta().hashCode() : meta.hashCode()) : 0); hash = hash * 31 + (hasCustomItem() ? getCustomItem().getId().hashCode() : 0); return hash; } /** * Checks if this ItemStack contains the given {@link Enchantment} * * @param ench Enchantment to test * @return True if this has the given enchantment */ public boolean containsEnchantment(Enchantment ench) { return meta != null && meta.hasEnchant(ench); } /** * Gets the level of the specified enchantment on this item stack * * @param ench Enchantment to check * @return Level of the enchantment, or 0 */ public int getEnchantmentLevel(Enchantment ench) { return meta == null ? 0 : meta.getEnchantLevel(ench); } /** * Gets a map containing all enchantments and their levels on this item. * * @return Map of enchantments. */ public Map getEnchantments() { return meta == null ? ImmutableMap.of() : meta.getEnchants(); } /** * Adds the specified enchantments to this item stack. *

* This method is the same as calling {@link * #addEnchantment(Enchantment, int)} for each * element of the map. * * @param enchantments Enchantments to add * @throws IllegalArgumentException if the specified enchantments is null * @throws IllegalArgumentException if any specific enchantment or level * is null. Warning: Some enchantments may be added before this * exception is thrown. */ @Utility public void addEnchantments(Map enchantments) { Validate.notNull(enchantments, "Enchantments cannot be null"); for (Map.Entry entry : enchantments.entrySet()) { addEnchantment(entry.getKey(), entry.getValue()); } } /** * Adds the specified {@link Enchantment} to this item stack. *

* If this item stack already contained the given enchantment (at any * level), it will be replaced. * * @param ench Enchantment to add * @param level Level of the enchantment * @throws IllegalArgumentException if enchantment null, or enchantment is * not applicable */ @Utility public void addEnchantment(Enchantment ench, int level) { Validate.notNull(ench, "Enchantment cannot be null"); if ((level < ench.getStartLevel()) || (level > ench.getMaxLevel())) { throw new IllegalArgumentException("Enchantment level is either too low or too high (given " + level + ", bounds are " + ench.getStartLevel() + " to " + ench.getMaxLevel() + ")"); } else if (!ench.canEnchantItem(this)) { throw new IllegalArgumentException("Specified enchantment cannot be applied to this itemstack"); } addUnsafeEnchantment(ench, level); } /** * Adds the specified enchantments to this item stack in an unsafe manner. *

* This method is the same as calling {@link * #addUnsafeEnchantment(Enchantment, int)} for * each element of the map. * * @param enchantments Enchantments to add */ @Utility public void addUnsafeEnchantments(Map enchantments) { for (Map.Entry entry : enchantments.entrySet()) { addUnsafeEnchantment(entry.getKey(), entry.getValue()); } } /** * Adds the specified {@link Enchantment} to this item stack. *

* If this item stack already contained the given enchantment (at any * level), it will be replaced. *

* This method is unsafe and will ignore level restrictions or item type. * Use at your own discretion. * * @param ench Enchantment to add * @param level Level of the enchantment */ public void addUnsafeEnchantment(Enchantment ench, int level) { getOrCreateMeta().addEnchant(ench, level, true); } private ItemMeta getOrCreateMeta() { if (meta == null) meta = Bukkit.getItemFactory().getItemMeta(getType0()); return meta; } /** * Removes the specified {@link Enchantment} if it exists on this * ItemStack * * @param ench Enchantment to remove * @return Previous level, or 0 */ public int removeEnchantment(Enchantment ench) { int level = getEnchantmentLevel(ench); if (level == 0 || meta == null) { return level; } meta.removeEnchant(ench); return level; } @Utility public Map serialize() { Map result = new LinkedHashMap<>(); result.put("type", getType().name()); if (getDurability() != 0) { result.put("damage", getDurability()); } if (getAmount() != 1) { result.put("amount", getAmount()); } if (hasCustomItem()) { result.put("CustomItem", getCustomItem().getId()); } ItemMeta meta = getItemMeta(); if (!Bukkit.getItemFactory().equals(meta, null)) { result.put("meta", meta); } return result; } /** * Get a copy of this ItemStack's {@link ItemMeta}. * * @return a copy of the current ItemStack's ItemData */ public ItemMeta getItemMeta() { return this.meta == null ? Bukkit.getItemFactory().getItemMeta(getType0()) : this.meta.clone(); } /** * Checks to see if any meta data has been defined. * * @return Returns true if some meta data has been set for this item */ public boolean hasItemMeta() { return !Bukkit.getItemFactory().equals(meta, null); } /** * Set the ItemMeta of this ItemStack. * * @param itemMeta new ItemMeta, or null to indicate meta data be cleared. * @return True if successfully applied ItemMeta, see {@link * ItemFactory#isApplicable(ItemMeta, ItemStack)} * @throws IllegalArgumentException if the item meta was not created by * the {@link ItemFactory} */ public boolean setItemMeta(ItemMeta itemMeta) { return setItemMeta0(itemMeta, getType0()); } /* * Cannot be overridden, so it's safe for constructor call */ private boolean setItemMeta0(ItemMeta itemMeta, Material material) { if (itemMeta == null) { this.meta = null; return true; } if (!Bukkit.getItemFactory().isApplicable(itemMeta, material)) { return false; } this.meta = Bukkit.getItemFactory().asMetaFor(itemMeta, material); if (this.meta == itemMeta) { this.meta = itemMeta.clone(); } return true; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy