package net.minecraft.item;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import java.text.DecimalFormat;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentDurability;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.item.EntityItemFrame;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.event.HoverEvent;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.stats.StatList;
import net.minecraft.util.BlockPos;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.IChatComponent;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
public final class ItemStack
{
public static final DecimalFormat DECIMALFORMAT = new DecimalFormat("#.###");
/** Size of the stack. */
public int stackSize;
/**
* Number of animation frames to go when receiving an item (by walking into it, for example).
*/
public int animationsToGo;
private Item item;
/**
* A NBTTagMap containing data about an ItemStack. Can only be used for non stackable items
*/
private NBTTagCompound stackTagCompound;
private int itemDamage;
/** Item frame this stack is on, or null if not on an item frame. */
private EntityItemFrame itemFrame;
private Block canDestroyCacheBlock;
private boolean canDestroyCacheResult;
private Block canPlaceOnCacheBlock;
private boolean canPlaceOnCacheResult;
private static final String __OBFID = "CL_00000043";
public ItemStack(Block blockIn)
{
this(blockIn, 1);
}
public ItemStack(Block blockIn, int amount)
{
this(blockIn, amount, 0);
}
public ItemStack(Block blockIn, int amount, int meta)
{
this(Item.getItemFromBlock(blockIn), amount, meta);
}
public ItemStack(Item itemIn)
{
this(itemIn, 1);
}
public ItemStack(Item itemIn, int amount)
{
this(itemIn, amount, 0);
}
public ItemStack(Item itemIn, int amount, int meta)
{
this.canDestroyCacheBlock = null;
this.canDestroyCacheResult = false;
this.canPlaceOnCacheBlock = null;
this.canPlaceOnCacheResult = false;
this.item = itemIn;
this.stackSize = amount;
this.itemDamage = meta;
if (this.itemDamage < 0)
{
this.itemDamage = 0;
}
}
public static ItemStack loadItemStackFromNBT(NBTTagCompound nbt)
{
ItemStack var1 = new ItemStack();
var1.readFromNBT(nbt);
return var1.getItem() != null ? var1 : null;
}
private ItemStack()
{
this.canDestroyCacheBlock = null;
this.canDestroyCacheResult = false;
this.canPlaceOnCacheBlock = null;
this.canPlaceOnCacheResult = false;
}
/**
* Splits off a stack of the given amount of this stack and reduces this stack by the amount.
*/
public ItemStack splitStack(int amount)
{
ItemStack var2 = new ItemStack(this.item, amount, this.itemDamage);
if (this.stackTagCompound != null)
{
var2.stackTagCompound = (NBTTagCompound)this.stackTagCompound.copy();
}
this.stackSize -= amount;
return var2;
}
/**
* Returns the object corresponding to the stack.
*/
public Item getItem()
{
return this.item;
}
/**
* Called when the player uses this ItemStack on a Block (right-click). Places blocks, etc. (Legacy name:
* tryPlaceItemIntoWorld)
*/
public boolean onItemUse(EntityPlayer playerIn, World worldIn, BlockPos pos, EnumFacing side, float hitX, float hitY, float hitZ)
{
boolean var8 = this.getItem().onItemUse(this, playerIn, worldIn, pos, side, hitX, hitY, hitZ);
if (var8)
{
playerIn.triggerAchievement(StatList.objectUseStats[Item.getIdFromItem(this.item)]);
}
return var8;
}
public float getStrVsBlock(Block p_150997_1_)
{
return this.getItem().getStrVsBlock(this, p_150997_1_);
}
/**
* Called whenever this item stack is equipped and right clicked. Returns the new item stack to put in the position
* where this item is. Args: world, player
*/
public ItemStack useItemRightClick(World worldIn, EntityPlayer playerIn)
{
return this.getItem().onItemRightClick(this, worldIn, playerIn);
}
/**
* Called when the item in use count reach 0, e.g. item food eaten. Return the new ItemStack. Args : world, entity
*/
public ItemStack onItemUseFinish(World worldIn, EntityPlayer playerIn)
{
return this.getItem().onItemUseFinish(this, worldIn, playerIn);
}
/**
* Write the stack fields to a NBT object. Return the new NBT object.
*/
public NBTTagCompound writeToNBT(NBTTagCompound nbt)
{
ResourceLocation var2 = (ResourceLocation)Item.itemRegistry.getNameForObject(this.item);
nbt.setString("id", var2 == null ? "minecraft:air" : var2.toString());
nbt.setByte("Count", (byte)this.stackSize);
nbt.setShort("Damage", (short)this.itemDamage);
if (this.stackTagCompound != null)
{
nbt.setTag("tag", this.stackTagCompound);
}
return nbt;
}
/**
* Read the stack fields from a NBT object.
*/
public void readFromNBT(NBTTagCompound nbt)
{
if (nbt.hasKey("id", 8))
{
this.item = Item.getByNameOrId(nbt.getString("id"));
}
else
{
this.item = Item.getItemById(nbt.getShort("id"));
}
this.stackSize = nbt.getByte("Count");
this.itemDamage = nbt.getShort("Damage");
if (this.itemDamage < 0)
{
this.itemDamage = 0;
}
if (nbt.hasKey("tag", 10))
{
this.stackTagCompound = nbt.getCompoundTag("tag");
if (this.item != null)
{
this.item.updateItemStackNBT(this.stackTagCompound);
}
}
}
/**
* Returns maximum size of the stack.
*/
public int getMaxStackSize()
{
return this.getItem().getItemStackLimit();
}
/**
* Returns true if the ItemStack can hold 2 or more units of the item.
*/
public boolean isStackable()
{
return this.getMaxStackSize() > 1 && (!this.isItemStackDamageable() || !this.isItemDamaged());
}
/**
* true if this itemStack is damageable
*/
public boolean isItemStackDamageable()
{
return this.item == null ? false : (this.item.getMaxDamage() <= 0 ? false : !this.hasTagCompound() || !this.getTagCompound().getBoolean("Unbreakable"));
}
public boolean getHasSubtypes()
{
return this.item.getHasSubtypes();
}
/**
* returns true when a damageable item is damaged
*/
public boolean isItemDamaged()
{
return this.isItemStackDamageable() && this.itemDamage > 0;
}
public int getItemDamage()
{
return this.itemDamage;
}
public int getMetadata()
{
return this.itemDamage;
}
public void setItemDamage(int meta)
{
this.itemDamage = meta;
if (this.itemDamage < 0)
{
this.itemDamage = 0;
}
}
/**
* Returns the max damage an item in the stack can take.
*/
public int getMaxDamage()
{
return this.item.getMaxDamage();
}
/**
* Attempts to damage the ItemStack with par1 amount of damage, If the ItemStack has the Unbreaking enchantment
* there is a chance for each point of damage to be negated. Returns true if it takes more damage than
* getMaxDamage(). Returns false otherwise or if the ItemStack can't be damaged or if all points of damage are
* negated.
*/
public boolean attemptDamageItem(int amount, Random rand)
{
if (!this.isItemStackDamageable())
{
return false;
}
else
{
if (amount > 0)
{
int var3 = EnchantmentHelper.getEnchantmentLevel(Enchantment.unbreaking.effectId, this);
int var4 = 0;
for (int var5 = 0; var3 > 0 && var5 < amount; ++var5)
{
if (EnchantmentDurability.negateDamage(this, var3, rand))
{
++var4;
}
}
amount -= var4;
if (amount <= 0)
{
return false;
}
}
this.itemDamage += amount;
return this.itemDamage > this.getMaxDamage();
}
}
/**
* Damages the item in the ItemStack
*/
public void damageItem(int amount, EntityLivingBase entityIn)
{
if (!(entityIn instanceof EntityPlayer) || !((EntityPlayer)entityIn).capabilities.isCreativeMode)
{
if (this.isItemStackDamageable())
{
if (this.attemptDamageItem(amount, entityIn.getRNG()))
{
entityIn.renderBrokenItemStack(this);
--this.stackSize;
if (entityIn instanceof EntityPlayer)
{
EntityPlayer var3 = (EntityPlayer)entityIn;
var3.triggerAchievement(StatList.objectBreakStats[Item.getIdFromItem(this.item)]);
if (this.stackSize == 0 && this.getItem() instanceof ItemBow)
{
var3.destroyCurrentEquippedItem();
}
}
if (this.stackSize < 0)
{
this.stackSize = 0;
}
this.itemDamage = 0;
}
}
}
}
/**
* Calls the corresponding fct in di
*/
public void hitEntity(EntityLivingBase entityIn, EntityPlayer playerIn)
{
boolean var3 = this.item.hitEntity(this, entityIn, playerIn);
if (var3)
{
playerIn.triggerAchievement(StatList.objectUseStats[Item.getIdFromItem(this.item)]);
}
}
/**
* Called when a Block is destroyed using this ItemStack
*
* @param blockIn The block being destroyed
*/
public void onBlockDestroyed(World worldIn, Block blockIn, BlockPos pos, EntityPlayer playerIn)
{
boolean var5 = this.item.onBlockDestroyed(this, worldIn, blockIn, pos, playerIn);
if (var5)
{
playerIn.triggerAchievement(StatList.objectUseStats[Item.getIdFromItem(this.item)]);
}
}
/**
* Check whether the given Block can be harvested using this ItemStack.
*/
public boolean canHarvestBlock(Block p_150998_1_)
{
return this.item.canHarvestBlock(p_150998_1_);
}
public boolean interactWithEntity(EntityPlayer playerIn, EntityLivingBase entityIn)
{
return this.item.itemInteractionForEntity(this, playerIn, entityIn);
}
/**
* Returns a new stack with the same properties.
*/
public ItemStack copy()
{
ItemStack var1 = new ItemStack(this.item, this.stackSize, this.itemDamage);
if (this.stackTagCompound != null)
{
var1.stackTagCompound = (NBTTagCompound)this.stackTagCompound.copy();
}
return var1;
}
public static boolean areItemStackTagsEqual(ItemStack stackA, ItemStack stackB)
{
return stackA == null && stackB == null ? true : (stackA != null && stackB != null ? (stackA.stackTagCompound == null && stackB.stackTagCompound != null ? false : stackA.stackTagCompound == null || stackA.stackTagCompound.equals(stackB.stackTagCompound)) : false);
}
/**
* compares ItemStack argument1 with ItemStack argument2; returns true if both ItemStacks are equal
*/
public static boolean areItemStacksEqual(ItemStack stackA, ItemStack stackB)
{
return stackA == null && stackB == null ? true : (stackA != null && stackB != null ? stackA.isItemStackEqual(stackB) : false);
}
/**
* compares ItemStack argument to the instance ItemStack; returns true if both ItemStacks are equal
*/
private boolean isItemStackEqual(ItemStack other)
{
return this.stackSize != other.stackSize ? false : (this.item != other.item ? false : (this.itemDamage != other.itemDamage ? false : (this.stackTagCompound == null && other.stackTagCompound != null ? false : this.stackTagCompound == null || this.stackTagCompound.equals(other.stackTagCompound))));
}
/**
* Compares Item and damage value of the two stacks
*/
public static boolean areItemsEqual(ItemStack stackA, ItemStack stackB)
{
return stackA == null && stackB == null ? true : (stackA != null && stackB != null ? stackA.isItemEqual(stackB) : false);
}
/**
* compares ItemStack argument to the instance ItemStack; returns true if the Items contained in both ItemStacks are
* equal
*/
public boolean isItemEqual(ItemStack other)
{
return other != null && this.item == other.item && this.itemDamage == other.itemDamage;
}
public String getUnlocalizedName()
{
return this.item.getUnlocalizedName(this);
}
/**
* Creates a copy of a ItemStack, a null parameters will return a null.
*/
public static ItemStack copyItemStack(ItemStack stack)
{
return stack == null ? null : stack.copy();
}
public String toString()
{
return this.stackSize + "x" + this.item.getUnlocalizedName() + "@" + this.itemDamage;
}
/**
* Called each tick as long the ItemStack in on player inventory. Used to progress the pickup animation and update
* maps.
*/
public void updateAnimation(World worldIn, Entity entityIn, int inventorySlot, boolean isCurrentItem)
{
if (this.animationsToGo > 0)
{
--this.animationsToGo;
}
this.item.onUpdate(this, worldIn, entityIn, inventorySlot, isCurrentItem);
}
public void onCrafting(World worldIn, EntityPlayer playerIn, int amount)
{
playerIn.addStat(StatList.objectCraftStats[Item.getIdFromItem(this.item)], amount);
this.item.onCreated(this, worldIn, playerIn);
}
public int getMaxItemUseDuration()
{
return this.getItem().getMaxItemUseDuration(this);
}
public EnumAction getItemUseAction()
{
return this.getItem().getItemUseAction(this);
}
/**
* Called when the player releases the use item button. Args: world, entityplayer, itemInUseCount
*
* @param timeLeft The amount of ticks left before the using would have been complete
*/
public void onPlayerStoppedUsing(World worldIn, EntityPlayer playerIn, int timeLeft)
{
this.getItem().onPlayerStoppedUsing(this, worldIn, playerIn, timeLeft);
}
/**
* Returns true if the ItemStack has an NBTTagCompound. Currently used to store enchantments.
*/
public boolean hasTagCompound()
{
return this.stackTagCompound != null;
}
/**
* Returns the NBTTagCompound of the ItemStack.
*/
public NBTTagCompound getTagCompound()
{
return this.stackTagCompound;
}
/**
* Get an NBTTagCompound from this stack's NBT data.
*
* @param key The NBTTagCompound to get
* @param create Whether a new, empty compound should be created if none is present yet
*/
public NBTTagCompound getSubCompound(String key, boolean create)
{
if (this.stackTagCompound != null && this.stackTagCompound.hasKey(key, 10))
{
return this.stackTagCompound.getCompoundTag(key);
}
else if (create)
{
NBTTagCompound var3 = new NBTTagCompound();
this.setTagInfo(key, var3);
return var3;
}
else
{
return null;
}
}
public NBTTagList getEnchantmentTagList()
{
return this.stackTagCompound == null ? null : this.stackTagCompound.getTagList("ench", 10);
}
/**
* Assigns a NBTTagCompound to the ItemStack, minecraft validates that only non-stackable items can have it.
*/
public void setTagCompound(NBTTagCompound nbt)
{
this.stackTagCompound = nbt;
}
/**
* returns the display name of the itemstack
*/
public String getDisplayName()
{
String var1 = this.getItem().getItemStackDisplayName(this);
if (this.stackTagCompound != null && this.stackTagCompound.hasKey("display", 10))
{
NBTTagCompound var2 = this.stackTagCompound.getCompoundTag("display");
if (var2.hasKey("Name", 8))
{
var1 = var2.getString("Name");
}
}
return var1;
}
public ItemStack setStackDisplayName(String p_151001_1_)
{
if (this.stackTagCompound == null)
{
this.stackTagCompound = new NBTTagCompound();
}
if (!this.stackTagCompound.hasKey("display", 10))
{
this.stackTagCompound.setTag("display", new NBTTagCompound());
}
this.stackTagCompound.getCompoundTag("display").setString("Name", p_151001_1_);
return this;
}
/**
* Clear any custom name set for this ItemStack
*/
public void clearCustomName()
{
if (this.stackTagCompound != null)
{
if (this.stackTagCompound.hasKey("display", 10))
{
NBTTagCompound var1 = this.stackTagCompound.getCompoundTag("display");
var1.removeTag("Name");
if (var1.hasNoTags())
{
this.stackTagCompound.removeTag("display");
if (this.stackTagCompound.hasNoTags())
{
this.setTagCompound((NBTTagCompound)null);
}
}
}
}
}
/**
* Returns true if the itemstack has a display name
*/
public boolean hasDisplayName()
{
return this.stackTagCompound == null ? false : (!this.stackTagCompound.hasKey("display", 10) ? false : this.stackTagCompound.getCompoundTag("display").hasKey("Name", 8));
}
public EnumRarity getRarity()
{
return this.getItem().getRarity(this);
}
/**
* True if it is a tool and has no enchantments to begin with
*/
public boolean isItemEnchantable()
{
return !this.getItem().isItemTool(this) ? false : !this.isItemEnchanted();
}
/**
* Adds an enchantment with a desired level on the ItemStack.
*/
public void addEnchantment(Enchantment ench, int level)
{
if (this.stackTagCompound == null)
{
this.setTagCompound(new NBTTagCompound());
}
if (!this.stackTagCompound.hasKey("ench", 9))
{
this.stackTagCompound.setTag("ench", new NBTTagList());
}
NBTTagList var3 = this.stackTagCompound.getTagList("ench", 10);
NBTTagCompound var4 = new NBTTagCompound();
var4.setShort("id", (short)ench.effectId);
var4.setShort("lvl", (short)((byte)level));
var3.appendTag(var4);
}
/**
* True if the item has enchantment data
*/
public boolean isItemEnchanted()
{
return this.stackTagCompound != null && this.stackTagCompound.hasKey("ench", 9);
}
public void setTagInfo(String key, NBTBase value)
{
if (this.stackTagCompound == null)
{
this.setTagCompound(new NBTTagCompound());
}
this.stackTagCompound.setTag(key, value);
}
public boolean canEditBlocks()
{
return this.getItem().canItemEditBlocks();
}
/**
* Return whether this stack is on an item frame.
*/
public boolean isOnItemFrame()
{
return this.itemFrame != null;
}
/**
* Set the item frame this stack is on.
*/
public void setItemFrame(EntityItemFrame frame)
{
this.itemFrame = frame;
}
/**
* Return the item frame this stack is on. Returns null if not on an item frame.
*/
public EntityItemFrame getItemFrame()
{
return this.itemFrame;
}
/**
* Get this stack's repair cost, or 0 if no repair cost is defined.
*/
public int getRepairCost()
{
return this.hasTagCompound() && this.stackTagCompound.hasKey("RepairCost", 3) ? this.stackTagCompound.getInteger("RepairCost") : 0;
}
/**
* Set this stack's repair cost.
*/
public void setRepairCost(int cost)
{
if (!this.hasTagCompound())
{
this.stackTagCompound = new NBTTagCompound();
}
this.stackTagCompound.setInteger("RepairCost", cost);
}
/**
* Gets the attribute modifiers for this ItemStack.
* Will check for an NBT tag list containing modifiers for the stack.
*/
public Multimap getAttributeModifiers()
{
Object var1;
if (this.hasTagCompound() && this.stackTagCompound.hasKey("AttributeModifiers", 9))
{
var1 = HashMultimap.create();
NBTTagList var2 = this.stackTagCompound.getTagList("AttributeModifiers", 10);
for (int var3 = 0; var3 < var2.tagCount(); ++var3)
{
NBTTagCompound var4 = var2.getCompoundTagAt(var3);
AttributeModifier var5 = SharedMonsterAttributes.readAttributeModifierFromNBT(var4);
if (var5 != null && var5.getID().getLeastSignificantBits() != 0L && var5.getID().getMostSignificantBits() != 0L)
{
((Multimap)var1).put(var4.getString("AttributeName"), var5);
}
}
}
else
{
var1 = this.getItem().getItemAttributeModifiers();
}
return (Multimap)var1;
}
public void setItem(Item p_150996_1_)
{
this.item = p_150996_1_;
}
/**
* Get a ChatComponent for this Item's display name that shows this Item on hover
*/
public IChatComponent getChatComponent()
{
ChatComponentText var1 = new ChatComponentText(this.getDisplayName());
if (this.hasDisplayName())
{
var1.getChatStyle().setItalic(Boolean.valueOf(true));
}
IChatComponent var2 = (new ChatComponentText("[")).appendSibling(var1).appendText("]");
if (this.item != null)
{
NBTTagCompound var3 = new NBTTagCompound();
this.writeToNBT(var3);
var2.getChatStyle().setChatHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_ITEM, new ChatComponentText(var3.toString())));
var2.getChatStyle().setColor(this.getRarity().rarityColor);
}
return var2;
}
public boolean canDestroy(Block blockIn)
{
if (blockIn == this.canDestroyCacheBlock)
{
return this.canDestroyCacheResult;
}
else
{
this.canDestroyCacheBlock = blockIn;
if (this.hasTagCompound() && this.stackTagCompound.hasKey("CanDestroy", 9))
{
NBTTagList var2 = this.stackTagCompound.getTagList("CanDestroy", 8);
for (int var3 = 0; var3 < var2.tagCount(); ++var3)
{
Block var4 = Block.getBlockFromName(var2.getStringTagAt(var3));
if (var4 == blockIn)
{
this.canDestroyCacheResult = true;
return true;
}
}
}
this.canDestroyCacheResult = false;
return false;
}
}
public boolean canPlaceOn(Block blockIn)
{
if (blockIn == this.canPlaceOnCacheBlock)
{
return this.canPlaceOnCacheResult;
}
else
{
this.canPlaceOnCacheBlock = blockIn;
if (this.hasTagCompound() && this.stackTagCompound.hasKey("CanPlaceOn", 9))
{
NBTTagList var2 = this.stackTagCompound.getTagList("CanPlaceOn", 8);
for (int var3 = 0; var3 < var2.tagCount(); ++var3)
{
Block var4 = Block.getBlockFromName(var2.getStringTagAt(var3));
if (var4 == blockIn)
{
this.canPlaceOnCacheResult = true;
return true;
}
}
}
this.canPlaceOnCacheResult = false;
return false;
}
}
}