001package net.minecraftforge.liquids;
002
003import static cpw.mods.fml.relauncher.Side.CLIENT;
004
005import com.google.common.base.Objects;
006
007import cpw.mods.fml.relauncher.SideOnly;
008import net.minecraft.block.Block;
009import net.minecraft.block.BlockFluid;
010import net.minecraft.client.renderer.texture.TextureManager;
011import net.minecraft.item.Item;
012import net.minecraft.item.ItemStack;
013import net.minecraft.nbt.NBTTagCompound;
014import net.minecraft.util.Icon;
015
016/**
017 * ItemStack substitute for liquids
018 * Things of note: they are equal if their items are equal. Amount does NOT matter for java equals() testing
019 * <br/>
020 * The canonical liquidstack is probably the only one that has a lot of the rendering data on it. Use {@link #canonical()}
021 * to get it.
022 *
023 * @author SirSengir
024 */
025public class LiquidStack
026{
027    public final int itemID;
028    public int amount;
029    public final int itemMeta;
030    public NBTTagCompound extra;
031
032    public LiquidStack(int itemID,  int amount) { this(itemID,        amount, 0); }
033    public LiquidStack(Item item,   int amount) { this(item.itemID,   amount, 0); }
034    public LiquidStack(Block block, int amount) { this(block.blockID, amount, 0); }
035
036    public LiquidStack(int itemID, int amount, int itemDamage)
037    {
038        this.itemID = itemID;
039        this.amount = amount;
040        this.itemMeta = itemDamage;
041    }
042
043    public LiquidStack(int itemID, int amount, int itemDamage, NBTTagCompound nbt)
044    {
045        this(itemID, amount, itemDamage);
046        if (nbt != null)
047        {
048            extra = (NBTTagCompound)nbt.copy();
049        }
050    }
051
052    public NBTTagCompound writeToNBT(NBTTagCompound nbt)
053    {
054        nbt.setInteger("Amount", amount);
055        nbt.setShort("Id", (short)itemID);
056        nbt.setShort("Meta", (short)itemMeta);
057        nbt.setString("LiquidName", LiquidDictionary.findLiquidName(this));
058        if (extra != null)
059        {
060            nbt.setTag("extra", extra);
061        }
062        return nbt;
063    }
064
065
066    /**
067     * NO-OP now. Use {@link #loadLiquidStackFromNBT(NBTTagCompound)} to get a new instance
068     *
069     * @param nbt
070     */
071    @Deprecated
072    public void readFromNBT(NBTTagCompound nbt)
073    {
074    }
075
076    /**
077     * @return A copy of this LiquidStack
078     */
079    public LiquidStack copy()
080    {
081        return new LiquidStack(itemID, amount, itemMeta, extra);
082    }
083
084    /**
085     * @param other
086     * @return true if this LiquidStack contains the same liquid as the one passed in.
087     */
088    public boolean isLiquidEqual(LiquidStack other)
089    {
090        return other != null && itemID == other.itemID && itemMeta == other.itemMeta && (extra == null ? other.extra == null : extra.equals(other.extra));
091    }
092
093    /**
094     * @param other
095     * @return true if this LiquidStack contains the other liquid (liquids are equal and amount >= other.amount).
096     */
097    public boolean containsLiquid(LiquidStack other)
098    {
099        return isLiquidEqual(other) && amount >= other.amount;
100    }
101
102    /**
103     * @param other ItemStack containing liquids.
104     * @return true if this LiquidStack contains the same liquid as the one passed in.
105     */
106    public boolean isLiquidEqual(ItemStack other)
107    {
108        if (other == null)
109        {
110            return false;
111        }
112
113        if (itemID == other.itemID && itemMeta == other.getItemDamage())
114        {
115            return true;
116        }
117
118        return isLiquidEqual(LiquidContainerRegistry.getLiquidForFilledItem(other));
119    }
120
121    /**
122     * @return ItemStack representation of this LiquidStack
123     */
124    public ItemStack asItemStack()
125    {
126        ItemStack stack = new ItemStack(itemID, 1, itemMeta);
127        if (extra != null)
128        {
129            stack.stackTagCompound = (NBTTagCompound)extra.copy();
130        }
131        return stack;
132    }
133
134    /**
135     * Reads a liquid stack from the passed nbttagcompound and returns it.
136     *
137     * @param nbt
138     * @return the liquid stack
139     */
140    public static LiquidStack loadLiquidStackFromNBT(NBTTagCompound nbt)
141    {
142        if (nbt == null)
143        {
144            return null;
145        }
146        String liquidName = nbt.getString("LiquidName");
147        int itemID = nbt.getShort("Id");
148        int itemMeta = nbt.getShort("Meta");
149        LiquidStack liquid = LiquidDictionary.getCanonicalLiquid(liquidName);
150        if(liquid != null) {
151            itemID = liquid.itemID;
152            itemMeta = liquid.itemMeta;
153        }
154        // if the item is not existent, and no liquid dictionary is found, null returns
155        else if (Item.itemsList[itemID] == null)
156        {
157            return null;
158        }
159        int amount = nbt.getInteger("Amount");
160        LiquidStack liquidstack = new LiquidStack(itemID, amount, itemMeta);
161        if (nbt.hasKey("extra"))
162        {
163            liquidstack.extra = nbt.getCompoundTag("extra");
164        }
165        return liquidstack.itemID == 0 ? null : liquidstack;
166    }
167
168    private String textureSheet = "/terrain.png";
169
170    /**
171     * Return the textureSheet used for this liquid stack's texture Icon
172     * Defaults to '/terrain.png'
173     *
174     * See {@link #getRenderingIcon()} for the actual icon
175     *
176     * @return The texture sheet
177     */
178    public String getTextureSheet()
179    {
180        return textureSheet;
181    }
182
183    /**
184     * Set the texture sheet for this icon (usually /terrain.png or /gui/items.png)
185     *
186     * See also the {@link #setRenderingIcon(Icon)} for the icon itself
187     *
188     * @param textureSheet
189     * @return the liquid stack
190     */
191    public LiquidStack setTextureSheet(String textureSheet)
192    {
193        this.textureSheet = textureSheet;
194        return this;
195    }
196    @SideOnly(CLIENT)
197    private Icon renderingIcon;
198
199    /**
200     * Get the rendering icon for this liquid stack, for presentation in the world or in GUIs.
201     * Defaults to handling water and lava, and returns the set rendering icon otherwise.
202     *
203     * See {@link #getTextureSheet()} to get the texture sheet this icon is associated with
204     *
205     * @return The icon for rendering this liquid
206     */
207    @SideOnly(CLIENT)
208    public Icon getRenderingIcon()
209    {
210        if (itemID == Block.waterStill.blockID)
211        {
212            return BlockFluid.func_94424_b("water");
213        }
214        else if (itemID == Block.lavaStill.blockID)
215        {
216            return BlockFluid.func_94424_b("lava");
217        }
218        return renderingIcon;
219    }
220
221    /**
222     * Set the icon for rendering this liquid
223     * It should be refreshed whenever textures are refreshed.
224     *
225     * See also {@link #setTextureSheet(String)} for setting the sheet this icon is associated with
226     *
227     * @param icon The icon to render
228     * @return The liquid stack
229     */
230    @SideOnly(CLIENT)
231    public LiquidStack setRenderingIcon(Icon icon)
232    {
233        this.renderingIcon = icon;
234        return this;
235    }
236
237    @Override
238    public final int hashCode()
239    {
240        return 31 * itemMeta + itemID;
241    }
242
243    @Override
244    public final boolean equals(Object ob)
245    {
246        if (ob instanceof LiquidStack)
247        {
248            LiquidStack ls = (LiquidStack)ob;
249            return ls.itemID == itemID && ls.itemMeta == itemMeta && (extra == null ? ls.extra == null : extra.equals(ls.extra));
250        }
251        return false;
252    }
253
254
255    /**
256     * Get the canonical version of this liquid stack (will contain things like icons and texturesheets)
257     * @return The canonical liquidstack
258     */
259    public LiquidStack canonical()
260    {
261        return LiquidDictionary.getCanonicalLiquid(this);
262    }
263}