Bukkit  1.4.7-R1.0
 All Classes Namespaces Files Functions Variables Enumerator Pages
ItemStack.java
Go to the documentation of this file.
1 package org.bukkit.inventory;
2 
3 import com.google.common.collect.ImmutableMap;
4 import java.util.LinkedHashMap;
5 import java.util.Map;
6 
7 import org.apache.commons.lang.Validate;
8 import org.bukkit.Bukkit;
9 import org.bukkit.Material;
10 import org.bukkit.Utility;
11 import org.bukkit.configuration.serialization.ConfigurationSerializable;
12 import org.bukkit.enchantments.Enchantment;
13 import org.bukkit.inventory.meta.ItemMeta;
14 import org.bukkit.material.MaterialData;
15 
19 public class ItemStack implements Cloneable, ConfigurationSerializable {
20  private int type = 0;
21  private int amount = 0;
22  private MaterialData data = null;
23  private short durability = 0;
24  private ItemMeta meta;
25 
26  @Utility
27  protected ItemStack() {}
28 
34  public ItemStack(final int type) {
35  this(type, 1);
36  }
37 
43  public ItemStack(final Material type) {
44  this(type, 1);
45  }
46 
53  public ItemStack(final int type, final int amount) {
54  this(type, amount, (short) 0);
55  }
56 
63  public ItemStack(final Material type, final int amount) {
64  this(type.getId(), amount);
65  }
66 
74  public ItemStack(final int type, final int amount, final short damage) {
75  this.type = type;
76  this.amount = amount;
77  this.durability = damage;
78  }
79 
87  public ItemStack(final Material type, final int amount, final short damage) {
88  this(type.getId(), amount, damage);
89  }
90 
94  @Deprecated
95  public ItemStack(final int type, final int amount, final short damage, final Byte data) {
96  this.type = type;
97  this.amount = amount;
98  this.durability = damage;
99  if (data != null) {
100  createData(data);
101  this.durability = data;
102  }
103  }
104 
108  @Deprecated
109  public ItemStack(final Material type, final int amount, final short damage, final Byte data) {
110  this(type.getId(), amount, damage, data);
111  }
112 
119  public ItemStack(final ItemStack stack) throws IllegalArgumentException {
120  Validate.notNull(stack, "Cannot copy null stack");
121  this.type = stack.getTypeId();
122  this.amount = stack.getAmount();
123  this.durability = stack.getDurability();
124  this.data = stack.getData();
125  if (stack.hasItemMeta()) {
126  setItemMeta0(stack.getItemMeta(), getType0());
127  }
128  }
129 
135  @Utility
136  public Material getType() {
137  return getType0(getTypeId());
138  }
139 
140  private Material getType0() {
141  return getType0(this.type);
142  }
143 
144  private static Material getType0(int id) {
145  Material material = Material.getMaterial(id);
146  return material == null ? Material.AIR : material;
147  }
148 
156  @Utility
157  public void setType(Material type) {
158  Validate.notNull(type, "Material cannot be null");
159  setTypeId(type.getId());
160  }
161 
167  public int getTypeId() {
168  return type;
169  }
170 
178  public void setTypeId(int type) {
179  this.type = type;
180  if (this.meta != null) {
181  this.meta = Bukkit.getItemFactory().asMetaFor(meta, getType0());
182  }
183  createData((byte) 0);
184  }
185 
191  public int getAmount() {
192  return amount;
193  }
194 
200  public void setAmount(int amount) {
201  this.amount = amount;
202  }
203 
210  Material mat = getType();
211  if (data == null && mat != null && mat.getData() != null) {
212  data = mat.getNewData((byte) this.getDurability());
213  }
214 
215  return data;
216  }
217 
223  public void setData(MaterialData data) {
224  Material mat = getType();
225 
226  if (data == null || mat == null || mat.getData() == null) {
227  this.data = data;
228  } else {
229  if ((data.getClass() == mat.getData()) || (data.getClass() == MaterialData.class)) {
230  this.data = data;
231  } else {
232  throw new IllegalArgumentException("Provided data is not of type " + mat.getData().getName() + ", found " + data.getClass().getName());
233  }
234  }
235  }
236 
242  public void setDurability(final short durability) {
243  this.durability = durability;
244  }
245 
251  public short getDurability() {
252  return durability;
253  }
254 
261  @Utility
262  public int getMaxStackSize() {
263  Material material = getType();
264  if (material != null) {
265  return material.getMaxStackSize();
266  }
267  return -1;
268  }
269 
270  private void createData(final byte data) {
271  Material mat = Material.getMaterial(type);
272 
273  if (mat == null) {
274  this.data = new MaterialData(type, data);
275  } else {
276  this.data = mat.getNewData(data);
277  }
278  }
279 
280  @Override
281  @Utility
282  public String toString() {
283  StringBuilder toString = new StringBuilder("ItemStack{").append(getType().name()).append(" x ").append(getAmount());
284  if (hasItemMeta()) {
285  toString.append(", ").append(getItemMeta());
286  }
287  return toString.append('}').toString();
288  }
289 
290  @Override
291  @Utility
292  public boolean equals(Object obj) {
293  if (this == obj) {
294  return true;
295  }
296  if (!(obj instanceof ItemStack)) {
297  return false;
298  }
299 
300  ItemStack stack = (ItemStack) obj;
301  return getAmount() == stack.getAmount() && isSimilar(stack);
302  }
303 
310  @Utility
311  public boolean isSimilar(ItemStack stack) {
312  if (stack == null) {
313  return false;
314  }
315  if (stack == this) {
316  return true;
317  }
318  return getTypeId() == stack.getTypeId() && getDurability() == stack.getDurability() && hasItemMeta() == stack.hasItemMeta() && (hasItemMeta() ? Bukkit.getItemFactory().equals(getItemMeta(), stack.getItemMeta()) : true);
319  }
320 
321  @Override
322  public ItemStack clone() {
323  try {
324  ItemStack itemStack = (ItemStack) super.clone();
325 
326  if (this.meta != null) {
327  itemStack.meta = this.meta.clone();
328  }
329 
330  if (this.data != null) {
331  itemStack.data = this.data.clone();
332  }
333 
334  return itemStack;
335  } catch (CloneNotSupportedException e) {
336  throw new Error(e);
337  }
338  }
339 
340  @Override
341  @Utility
342  public final int hashCode() {
343  int hash = 1;
344 
345  hash = hash * 31 + getTypeId();
346  hash = hash * 31 + getAmount();
347  hash = hash * 31 + (getDurability() & 0xffff);
348  hash = hash * 31 + (hasItemMeta() ? (meta == null ? getItemMeta().hashCode() : meta.hashCode()) : 0);
349 
350  return hash;
351  }
352 
359  public boolean containsEnchantment(Enchantment ench) {
360  return meta == null ? false : meta.hasEnchant(ench);
361  }
362 
369  public int getEnchantmentLevel(Enchantment ench) {
370  return meta == null ? 0 : meta.getEnchantLevel(ench);
371  }
372 
378  public Map<Enchantment, Integer> getEnchantments() {
379  return meta == null ? ImmutableMap.<Enchantment, Integer>of() : meta.getEnchants();
380  }
381 
393  @Utility
394  public void addEnchantments(Map<Enchantment, Integer> enchantments) {
395  Validate.notNull(enchantments, "Enchantments cannot be null");
396  for (Map.Entry<Enchantment, Integer> entry : enchantments.entrySet()) {
397  addEnchantment(entry.getKey(), entry.getValue());
398  }
399  }
400 
410  @Utility
411  public void addEnchantment(Enchantment ench, int level) {
412  Validate.notNull(ench, "Enchantment cannot be null");
413  if ((level < ench.getStartLevel()) || (level > ench.getMaxLevel())) {
414  throw new IllegalArgumentException("Enchantment level is either too low or too high (given " + level + ", bounds are " + ench.getStartLevel() + " to " + ench.getMaxLevel());
415  } else if (!ench.canEnchantItem(this)) {
416  throw new IllegalArgumentException("Specified enchantment cannot be applied to this itemstack");
417  }
418 
419  addUnsafeEnchantment(ench, level);
420  }
421 
430  @Utility
431  public void addUnsafeEnchantments(Map<Enchantment, Integer> enchantments) {
432  for (Map.Entry<Enchantment, Integer> entry : enchantments.entrySet()) {
433  addUnsafeEnchantment(entry.getKey(), entry.getValue());
434  }
435  }
436 
448  public void addUnsafeEnchantment(Enchantment ench, int level) {
449  (meta == null ? meta = Bukkit.getItemFactory().getItemMeta(getType0()) : meta).addEnchant(ench, level, true);
450  }
451 
458  public int removeEnchantment(Enchantment ench) {
459  int level = getEnchantmentLevel(ench);
460  if (level == 0 || meta == null) {
461  return level;
462  }
463  meta.removeEnchant(ench);
464  return level;
465  }
466 
467  @Utility
468  public Map<String, Object> serialize() {
469  Map<String, Object> result = new LinkedHashMap<String, Object>();
470 
471  result.put("type", getType().name());
472 
473  if (getDurability() != 0) {
474  result.put("damage", getDurability());
475  }
476 
477  if (getAmount() != 1) {
478  result.put("amount", getAmount());
479  }
480 
481  ItemMeta meta = getItemMeta();
482  if (!Bukkit.getItemFactory().equals(meta, null)) {
483  result.put("meta", meta);
484  }
485 
486  return result;
487  }
488 
496  public static ItemStack deserialize(Map<String, Object> args) {
497  Material type = Material.getMaterial((String) args.get("type"));
498  short damage = 0;
499  int amount = 1;
500 
501  if (args.containsKey("damage")) {
502  damage = ((Number) args.get("damage")).shortValue();
503  }
504 
505  if (args.containsKey("amount")) {
506  amount = (Integer) args.get("amount");
507  }
508 
509  ItemStack result = new ItemStack(type, amount, damage);
510 
511  if (args.containsKey("enchantments")) { // Backward compatiblity, @deprecated
512  Object raw = args.get("enchantments");
513 
514  if (raw instanceof Map) {
515  Map<?, ?> map = (Map<?, ?>) raw;
516 
517  for (Map.Entry<?, ?> entry : map.entrySet()) {
518  Enchantment enchantment = Enchantment.getByName(entry.getKey().toString());
519 
520  if ((enchantment != null) && (entry.getValue() instanceof Integer)) {
521  result.addUnsafeEnchantment(enchantment, (Integer) entry.getValue());
522  }
523  }
524  }
525  } else if (args.containsKey("meta")) { // We cannot and will not have meta when enchantments (pre-ItemMeta) exist
526  Object raw = args.get("meta");
527  if (raw instanceof ItemMeta) {
528  result.setItemMeta((ItemMeta) raw);
529  }
530  }
531 
532  return result;
533  }
534 
541  return this.meta == null ? Bukkit.getItemFactory().getItemMeta(getType0()) : this.meta.clone();
542  }
543 
549  public boolean hasItemMeta() {
550  return !Bukkit.getItemFactory().equals(meta, null);
551  }
552 
560  public boolean setItemMeta(ItemMeta itemMeta) {
561  return setItemMeta0(itemMeta, getType0());
562  }
563 
564  /*
565  * Cannot be overridden, so it's safe for constructor call
566  */
567  private boolean setItemMeta0(ItemMeta itemMeta, Material material) {
568  if (itemMeta == null) {
569  this.meta = null;
570  return true;
571  }
572  if (!Bukkit.getItemFactory().isApplicable(itemMeta, material)) {
573  return false;
574  }
575  this.meta = Bukkit.getItemFactory().asMetaFor(itemMeta, material);
576  if (this.meta == itemMeta) {
577  this.meta = itemMeta.clone();
578  }
579 
580  return true;
581  }
582 }