001 package net.minecraft.tileentity; 002 003 import cpw.mods.fml.common.registry.GameRegistry; 004 import cpw.mods.fml.relauncher.Side; 005 import cpw.mods.fml.relauncher.SideOnly; 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().itemID; 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.itemID) return 100; 370 if (var1 == Item.coal.itemID) return 1600; 371 if (var1 == Item.bucketLava.itemID) return 20000; 372 if (var1 == Block.sapling.blockID) return 100; 373 if (var1 == Item.blazeRod.itemID) 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 }