    001    package net.minecraft.tileentity;
    002
    003    import cpw.mods.fml.common.Side;
    004    import cpw.mods.fml.common.asm.SideOnly;
    005    import cpw.mods.fml.common.registry.GameRegistry;
    006    import net.minecraft.block.Block;
    007    import net.minecraft.block.BlockFurnace;
    008    import net.minecraft.block.material.Material;
    009    import net.minecraft.entity.player.EntityPlayer;
    010    import net.minecraft.inventory.IInventory;
    011    import net.minecraft.item.Item;
    012    import net.minecraft.item.ItemBlock;
    013    import net.minecraft.item.ItemHoe;
    014    import net.minecraft.item.ItemStack;
    015    import net.minecraft.item.ItemSword;
    016    import net.minecraft.item.ItemTool;
    017    import net.minecraft.item.crafting.FurnaceRecipes;
    018    import net.minecraft.nbt.NBTTagCompound;
    019    import net.minecraft.nbt.NBTTagList;
    020
    021    import net.minecraftforge.common.ForgeDirection;
    022    import net.minecraftforge.common.ISidedInventory;
    023
    024    public class TileEntityFurnace extends TileEntity implements IInventory, ISidedInventory
    025    {
    026        /**
    027         * The ItemStacks that hold the items currently being used in the furnace
    028         */
    029        private ItemStack[] furnaceItemStacks = new ItemStack[3];
    030
    031        /** The number of ticks that the furnace will keep burning */
    032        public int furnaceBurnTime = 0;
    033
    034        /**
    035         * The number of ticks that a fresh copy of the currently-burning item would keep the furnace burning for
    036         */
    037        public int currentItemBurnTime = 0;
    038
    039        /** The number of ticks that the current item has been cooking for */
    040        public int furnaceCookTime = 0;
    041
    042        /**
    043         * Returns the number of slots in the inventory.
    044         */
    045        public int getSizeInventory()
    046        {
    047            return this.furnaceItemStacks.length;
    048        }
    049
    050        /**
    051         * Returns the stack in slot i
    052         */
    053        public ItemStack getStackInSlot(int par1)
    054        {
    055            return this.furnaceItemStacks[par1];
    056        }
    057
    058        /**
    059         * Removes from an inventory slot (first arg) up to a specified number (second arg) of items and returns them in a
    060         * new stack.
    061         */
    062        public ItemStack decrStackSize(int par1, int par2)
    063        {
    064            if (this.furnaceItemStacks[par1] != null)
    065            {
    066                ItemStack var3;
    067
    068                if (this.furnaceItemStacks[par1].stackSize <= par2)
    069                {
    070                    var3 = this.furnaceItemStacks[par1];
    071                    this.furnaceItemStacks[par1] = null;
    072                    return var3;
    073                }
    074                else
    075                {
    076                    var3 = this.furnaceItemStacks[par1].splitStack(par2);
    077
    078                    if (this.furnaceItemStacks[par1].stackSize == 0)
    079                    {
    080                        this.furnaceItemStacks[par1] = null;
    081                    }
    082
    083                    return var3;
    084                }
    085            }
    086            else
    087            {
    088                return null;
    089            }
    090        }
    091
    092        /**
    093         * When some containers are closed they call this on each slot, then drop whatever it returns as an EntityItem -
    094         * like when you close a workbench GUI.
    095         */
    096        public ItemStack getStackInSlotOnClosing(int par1)
    097        {
    098            if (this.furnaceItemStacks[par1] != null)
    099            {
    100                ItemStack var2 = this.furnaceItemStacks[par1];
    101                this.furnaceItemStacks[par1] = null;
    102                return var2;
    103            }
    104            else
    105            {
    106                return null;
    107            }
    108        }
    109
    110        /**
    111         * Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections).
    112         */
    113        public void setInventorySlotContents(int par1, ItemStack par2ItemStack)
    114        {
    115            this.furnaceItemStacks[par1] = par2ItemStack;
    116
    117            if (par2ItemStack != null && par2ItemStack.stackSize > this.getInventoryStackLimit())
    118            {
    119                par2ItemStack.stackSize = this.getInventoryStackLimit();
    120            }
    121        }
    122
    123        /**
    124         * Returns the name of the inventory.
    125         */
    126        public String getInvName()
    127        {
    128            return "container.furnace";
    129        }
    130
    131        /**
    132         * Reads a tile entity from NBT.
    133         */
    134        public void readFromNBT(NBTTagCompound par1NBTTagCompound)
    135        {
    136            super.readFromNBT(par1NBTTagCompound);
    137            NBTTagList var2 = par1NBTTagCompound.getTagList("Items");
    138            this.furnaceItemStacks = new ItemStack[this.getSizeInventory()];
    139
    140            for (int var3 = 0; var3 < var2.tagCount(); ++var3)
    141            {
    142                NBTTagCompound var4 = (NBTTagCompound)var2.tagAt(var3);
    143                byte var5 = var4.getByte("Slot");
    144
    145                if (var5 >= 0 && var5 < this.furnaceItemStacks.length)
    146                {
    147                    this.furnaceItemStacks[var5] = ItemStack.loadItemStackFromNBT(var4);
    148                }
    149            }
    150
    151            this.furnaceBurnTime = par1NBTTagCompound.getShort("BurnTime");
    152            this.furnaceCookTime = par1NBTTagCompound.getShort("CookTime");
    153            this.currentItemBurnTime = getItemBurnTime(this.furnaceItemStacks[1]);
    154        }
    155
    156        /**
    157         * Writes a tile entity to NBT.
    158         */
    159        public void writeToNBT(NBTTagCompound par1NBTTagCompound)
    160        {
    161            super.writeToNBT(par1NBTTagCompound);
    162            par1NBTTagCompound.setShort("BurnTime", (short)this.furnaceBurnTime);
    163            par1NBTTagCompound.setShort("CookTime", (short)this.furnaceCookTime);
    164            NBTTagList var2 = new NBTTagList();
    165
    166            for (int var3 = 0; var3 < this.furnaceItemStacks.length; ++var3)
    167            {
    168                if (this.furnaceItemStacks[var3] != null)
    169                {
    170                    NBTTagCompound var4 = new NBTTagCompound();
    171                    var4.setByte("Slot", (byte)var3);
    172                    this.furnaceItemStacks[var3].writeToNBT(var4);
    173                    var2.appendTag(var4);
    174                }
    175            }
    176
    177            par1NBTTagCompound.setTag("Items", var2);
    178        }
    179
    180        /**
    181         * Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended. *Isn't
    182         * this more of a set than a get?*
    183         */
    184        public int getInventoryStackLimit()
    185        {
    186            return 64;
    187        }
    188
    189        @SideOnly(Side.CLIENT)
    190
    191        /**
    192         * Returns an integer between 0 and the passed value representing how close the current item is to being completely
    193         * cooked
    194         */
    195        public int getCookProgressScaled(int par1)
    196        {
    197            return this.furnaceCookTime * par1 / 200;
    198        }
    199
    200        @SideOnly(Side.CLIENT)
    201
    202        /**
    203         * Returns an integer between 0 and the passed value representing how much burn time is left on the current fuel
    204         * item, where 0 means that the item is exhausted and the passed value means that the item is fresh
    205         */
    206        public int getBurnTimeRemainingScaled(int par1)
    207        {
    208            if (this.currentItemBurnTime == 0)
    209            {
    210                this.currentItemBurnTime = 200;
    211            }
    212
    213            return this.furnaceBurnTime * par1 / this.currentItemBurnTime;
    214        }
    215
    216        /**
    217         * Returns true if the furnace is currently burning
    218         */
    219        public boolean isBurning()
    220        {
    221            return this.furnaceBurnTime > 0;
    222        }
    223
    224        /**
    225         * Allows the entity to update its state. Overridden in most subclasses, e.g. the mob spawner uses this to count
    226         * ticks and creates a new spawn inside its implementation.
    227         */
    228        public void updateEntity()
    229        {
    230            boolean var1 = this.furnaceBurnTime > 0;
    231            boolean var2 = false;
    232
    233            if (this.furnaceBurnTime > 0)
    234            {
    235                --this.furnaceBurnTime;
    236            }
    237
    238            if (!this.worldObj.isRemote)
    239            {
    240                if (this.furnaceBurnTime == 0 && this.canSmelt())
    241                {
    242                    this.currentItemBurnTime = this.furnaceBurnTime = getItemBurnTime(this.furnaceItemStacks[1]);
    243
    244                    if (this.furnaceBurnTime > 0)
    245                    {
    246                        var2 = true;
    247
    248                        if (this.furnaceItemStacks[1] != null)
    249                        {
    250                            --this.furnaceItemStacks[1].stackSize;
    251
    252                            if (this.furnaceItemStacks[1].stackSize == 0)
    253                            {
    254                                this.furnaceItemStacks[1] = this.furnaceItemStacks[1].getItem().getContainerItemStack(furnaceItemStacks[1]);
    255                            }
    256                        }
    257                    }
    258                }
    259
    260                if (this.isBurning() && this.canSmelt())
    261                {
    262                    ++this.furnaceCookTime;
    263
    264                    if (this.furnaceCookTime == 200)
    265                    {
    266                        this.furnaceCookTime = 0;
    267                        this.smeltItem();
    268                        var2 = true;
    269                    }
    270                }
    271                else
    272                {
    273                    this.furnaceCookTime = 0;
    274                }
    275
    276                if (var1 != this.furnaceBurnTime > 0)
    277                {
    278                    var2 = true;
    279                    BlockFurnace.updateFurnaceBlockState(this.furnaceBurnTime > 0, this.worldObj, this.xCoord, this.yCoord, this.zCoord);
    280                }
    281            }
    282
    283            if (var2)
    284            {
    285                this.onInventoryChanged();
    286            }
    287        }
    288
    289        /**
    290         * Returns true if the furnace can smelt an item, i.e. has a source item, destination stack isn't full, etc.
    291         */
    292        private boolean canSmelt()
    293        {
    294            if (this.furnaceItemStacks[0] == null)
    295            {
    296                return false;
    297            }
    298            else
    299            {
    300                ItemStack var1 = FurnaceRecipes.smelting().getSmeltingResult(this.furnaceItemStacks[0]);
    301                if (var1 == null) return false;
    302                if (this.furnaceItemStacks[2] == null) return true;
    303                if (!this.furnaceItemStacks[2].isItemEqual(var1)) return false;
    304                int result = furnaceItemStacks[2].stackSize + var1.stackSize;
    305                return (result <= getInventoryStackLimit() && result <= var1.getMaxStackSize());
    306            }
    307        }
    308
    309        /**
    310         * Turn one item from the furnace source stack into the appropriate smelted item in the furnace result stack
    311         */
    312        public void smeltItem()
    313        {
    314            if (this.canSmelt())
    315            {
    316                ItemStack var1 = FurnaceRecipes.smelting().getSmeltingResult(this.furnaceItemStacks[0]);
    317
    318                if (this.furnaceItemStacks[2] == null)
    319                {
    320                    this.furnaceItemStacks[2] = var1.copy();
    321                }
    322                else if (this.furnaceItemStacks[2].isItemEqual(var1))
    323                {
    324                    furnaceItemStacks[2].stackSize += var1.stackSize;
    325                }
    326
    327                --this.furnaceItemStacks[0].stackSize;
    328
    329                if (this.furnaceItemStacks[0].stackSize <= 0)
    330                {
    331                    this.furnaceItemStacks[0] = null;
    332                }
    333            }
    334        }
    335
    336        /**
    337         * Returns the number of ticks that the supplied fuel item will keep the furnace burning, or 0 if the item isn't
    338         * fuel
    339         */
    340        public static int getItemBurnTime(ItemStack par0ItemStack)
    341        {
    342            if (par0ItemStack == null)
    343            {
    344                return 0;
    345            }
    346            else
    347            {
    348                int var1 = par0ItemStack.getItem().shiftedIndex;
    349                Item var2 = par0ItemStack.getItem();
    350
    351                if (par0ItemStack.getItem() instanceof ItemBlock && Block.blocksList[var1] != null)
    352                {
    353                    Block var3 = Block.blocksList[var1];
    354
    355                    if (var3 == Block.woodSingleSlab)
    356                    {
    357                        return 150;
    358                    }
    359
    360                    if (var3.blockMaterial == Material.wood)
    361                    {
    362                        return 300;
    363                    }
    364                }
    365
    366                if (var2 instanceof ItemTool && ((ItemTool) var2).getToolMaterialName().equals("WOOD")) return 200;
    367                if (var2 instanceof ItemSword && ((ItemSword) var2).func_77825_f().equals("WOOD")) return 200;
    368                if (var2 instanceof ItemHoe && ((ItemHoe) var2).func_77842_f().equals("WOOD")) return 200;
    369                if (var1 == Item.stick.shiftedIndex) return 100;
    370                if (var1 == Item.coal.shiftedIndex) return 1600;
    371                if (var1 == Item.bucketLava.shiftedIndex) return 20000;
    372                if (var1 == Block.sapling.blockID) return 100;
    373                if (var1 == Item.blazeRod.shiftedIndex) return 2400;
    374                return GameRegistry.getFuelValue(par0ItemStack);
    375            }
    376        }
    377
    378        /**
    379         * Return true if item is a fuel source (getItemBurnTime() > 0).
    380         */
    381        public static boolean isItemFuel(ItemStack par0ItemStack)
    382        {
    383            return getItemBurnTime(par0ItemStack) > 0;
    384        }
    385
    386        /**
    387         * Do not make give this method the name canInteractWith because it clashes with Container
    388         */
    389        public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer)
    390        {
    391            return this.worldObj.getBlockTileEntity(this.xCoord, this.yCoord, this.zCoord) != this ? false : par1EntityPlayer.getDistanceSq((double)this.xCoord + 0.5D, (double)this.yCoord + 0.5D, (double)this.zCoord + 0.5D) <= 64.0D;
    392        }
    393
    394        public void openChest() {}
    395
    396        public void closeChest() {}
    397
    398        @Override
    399        public int getStartInventorySide(ForgeDirection side)
    400        {
    401            if (side == ForgeDirection.DOWN) return 1;
    402            if (side == ForgeDirection.UP) return 0;
    403            return 2;
    404        }
    405
    406        @Override
    407        public int getSizeInventorySide(ForgeDirection side)
    408        {
    409            return 1;
    410        }
    411    }