001package net.minecraft.tileentity; 002 003import java.util.List; 004import net.minecraft.block.Block; 005import net.minecraft.block.BlockChest; 006import net.minecraft.block.BlockHopper; 007import net.minecraft.command.IEntitySelector; 008import net.minecraft.entity.Entity; 009import net.minecraft.entity.item.EntityItem; 010import net.minecraft.entity.player.EntityPlayer; 011import net.minecraft.inventory.IInventory; 012import net.minecraft.inventory.ISidedInventory; 013import net.minecraft.item.ItemStack; 014import net.minecraft.nbt.NBTTagCompound; 015import net.minecraft.nbt.NBTTagList; 016import net.minecraft.util.AxisAlignedBB; 017import net.minecraft.util.Facing; 018import net.minecraft.util.MathHelper; 019import net.minecraft.world.World; 020 021public class TileEntityHopper extends TileEntity implements Hopper 022{ 023 private ItemStack[] field_94124_b = new ItemStack[5]; 024 private String field_94123_d; 025 private int field_98048_c = -1; 026 027 /** 028 * Reads a tile entity from NBT. 029 */ 030 public void readFromNBT(NBTTagCompound par1NBTTagCompound) 031 { 032 super.readFromNBT(par1NBTTagCompound); 033 NBTTagList nbttaglist = par1NBTTagCompound.getTagList("Items"); 034 this.field_94124_b = new ItemStack[this.getSizeInventory()]; 035 036 if (par1NBTTagCompound.hasKey("CustomName")) 037 { 038 this.field_94123_d = par1NBTTagCompound.getString("CustomName"); 039 } 040 041 this.field_98048_c = par1NBTTagCompound.getInteger("TransferCooldown"); 042 043 for (int i = 0; i < nbttaglist.tagCount(); ++i) 044 { 045 NBTTagCompound nbttagcompound1 = (NBTTagCompound)nbttaglist.tagAt(i); 046 byte b0 = nbttagcompound1.getByte("Slot"); 047 048 if (b0 >= 0 && b0 < this.field_94124_b.length) 049 { 050 this.field_94124_b[b0] = ItemStack.loadItemStackFromNBT(nbttagcompound1); 051 } 052 } 053 } 054 055 /** 056 * Writes a tile entity to NBT. 057 */ 058 public void writeToNBT(NBTTagCompound par1NBTTagCompound) 059 { 060 super.writeToNBT(par1NBTTagCompound); 061 NBTTagList nbttaglist = new NBTTagList(); 062 063 for (int i = 0; i < this.field_94124_b.length; ++i) 064 { 065 if (this.field_94124_b[i] != null) 066 { 067 NBTTagCompound nbttagcompound1 = new NBTTagCompound(); 068 nbttagcompound1.setByte("Slot", (byte)i); 069 this.field_94124_b[i].writeToNBT(nbttagcompound1); 070 nbttaglist.appendTag(nbttagcompound1); 071 } 072 } 073 074 par1NBTTagCompound.setTag("Items", nbttaglist); 075 par1NBTTagCompound.setInteger("TransferCooldown", this.field_98048_c); 076 077 if (this.func_94042_c()) 078 { 079 par1NBTTagCompound.setString("CustomName", this.field_94123_d); 080 } 081 } 082 083 /** 084 * Called when an the contents of an Inventory change, usually 085 */ 086 public void onInventoryChanged() 087 { 088 super.onInventoryChanged(); 089 } 090 091 /** 092 * Returns the number of slots in the inventory. 093 */ 094 public int getSizeInventory() 095 { 096 return this.field_94124_b.length; 097 } 098 099 /** 100 * Returns the stack in slot i 101 */ 102 public ItemStack getStackInSlot(int par1) 103 { 104 return this.field_94124_b[par1]; 105 } 106 107 /** 108 * Removes from an inventory slot (first arg) up to a specified number (second arg) of items and returns them in a 109 * new stack. 110 */ 111 public ItemStack decrStackSize(int par1, int par2) 112 { 113 if (this.field_94124_b[par1] != null) 114 { 115 ItemStack itemstack; 116 117 if (this.field_94124_b[par1].stackSize <= par2) 118 { 119 itemstack = this.field_94124_b[par1]; 120 this.field_94124_b[par1] = null; 121 return itemstack; 122 } 123 else 124 { 125 itemstack = this.field_94124_b[par1].splitStack(par2); 126 127 if (this.field_94124_b[par1].stackSize == 0) 128 { 129 this.field_94124_b[par1] = null; 130 } 131 132 return itemstack; 133 } 134 } 135 else 136 { 137 return null; 138 } 139 } 140 141 /** 142 * When some containers are closed they call this on each slot, then drop whatever it returns as an EntityItem - 143 * like when you close a workbench GUI. 144 */ 145 public ItemStack getStackInSlotOnClosing(int par1) 146 { 147 if (this.field_94124_b[par1] != null) 148 { 149 ItemStack itemstack = this.field_94124_b[par1]; 150 this.field_94124_b[par1] = null; 151 return itemstack; 152 } 153 else 154 { 155 return null; 156 } 157 } 158 159 /** 160 * Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections). 161 */ 162 public void setInventorySlotContents(int par1, ItemStack par2ItemStack) 163 { 164 this.field_94124_b[par1] = par2ItemStack; 165 166 if (par2ItemStack != null && par2ItemStack.stackSize > this.getInventoryStackLimit()) 167 { 168 par2ItemStack.stackSize = this.getInventoryStackLimit(); 169 } 170 } 171 172 /** 173 * Returns the name of the inventory. 174 */ 175 public String getInvName() 176 { 177 return this.func_94042_c() ? this.field_94123_d : "container.hopper"; 178 } 179 180 public boolean func_94042_c() 181 { 182 return this.field_94123_d != null && this.field_94123_d.length() > 0; 183 } 184 185 public void func_96115_a(String par1Str) 186 { 187 this.field_94123_d = par1Str; 188 } 189 190 /** 191 * Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended. *Isn't 192 * this more of a set than a get?* 193 */ 194 public int getInventoryStackLimit() 195 { 196 return 64; 197 } 198 199 /** 200 * Do not make give this method the name canInteractWith because it clashes with Container 201 */ 202 public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer) 203 { 204 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; 205 } 206 207 public void openChest() {} 208 209 public void closeChest() {} 210 211 public boolean func_94041_b(int par1, ItemStack par2ItemStack) 212 { 213 return true; 214 } 215 216 /** 217 * Allows the entity to update its state. Overridden in most subclasses, e.g. the mob spawner uses this to count 218 * ticks and creates a new spawn inside its implementation. 219 */ 220 public void updateEntity() 221 { 222 if (this.worldObj != null && !this.worldObj.isRemote) 223 { 224 --this.field_98048_c; 225 226 if (!this.func_98047_l()) 227 { 228 this.func_98046_c(0); 229 this.func_98045_j(); 230 } 231 } 232 } 233 234 public boolean func_98045_j() 235 { 236 if (this.worldObj != null && !this.worldObj.isRemote) 237 { 238 if (!this.func_98047_l() && BlockHopper.func_94452_d(this.getBlockMetadata())) 239 { 240 boolean flag = this.func_94116_j() | func_96116_a(this); 241 242 if (flag) 243 { 244 this.func_98046_c(8); 245 this.onInventoryChanged(); 246 return true; 247 } 248 } 249 250 return false; 251 } 252 else 253 { 254 return false; 255 } 256 } 257 258 private boolean func_94116_j() 259 { 260 int i = func_94115_a(this, -1); 261 boolean flag = false; 262 263 if (i > -1) 264 { 265 IInventory iinventory = this.func_94119_v(); 266 267 if (iinventory != null) 268 { 269 ItemStack itemstack = this.getStackInSlot(i).copy(); 270 ItemStack itemstack1 = func_94117_a(iinventory, this.decrStackSize(i, 1), Facing.faceToSide[BlockHopper.func_94451_c(this.getBlockMetadata())]); 271 272 if (itemstack1 != null && itemstack1.stackSize != 0) 273 { 274 this.setInventorySlotContents(i, itemstack); 275 } 276 else 277 { 278 flag |= true; 279 iinventory.onInventoryChanged(); 280 } 281 } 282 } 283 284 return flag; 285 } 286 287 public static boolean func_96116_a(Hopper par0Hopper) 288 { 289 boolean flag = false; 290 IInventory iinventory = func_96118_b(par0Hopper); 291 292 if (iinventory != null) 293 { 294 byte b0 = 0; 295 int i = 0; 296 int j = iinventory.getSizeInventory(); 297 298 if (iinventory instanceof ISidedInventory && b0 > -1) 299 { 300 ISidedInventory isidedinventory = (ISidedInventory)iinventory; 301 i = isidedinventory.func_94127_c(b0); 302 j = Math.min(j, i + isidedinventory.func_94128_d(b0)); 303 } 304 305 for (int k = i; k < j && !flag; ++k) 306 { 307 ItemStack itemstack = iinventory.getStackInSlot(k); 308 309 if (itemstack != null) 310 { 311 ItemStack itemstack1 = itemstack.copy(); 312 ItemStack itemstack2 = func_94117_a(par0Hopper, iinventory.decrStackSize(k, 1), -1); 313 314 if (itemstack2 != null && itemstack2.stackSize != 0) 315 { 316 iinventory.setInventorySlotContents(k, itemstack1); 317 } 318 else 319 { 320 flag |= true; 321 iinventory.onInventoryChanged(); 322 } 323 } 324 } 325 } 326 else 327 { 328 EntityItem entityitem = func_96119_a(par0Hopper.getWorldObj(), par0Hopper.func_96107_aA(), par0Hopper.func_96109_aB() + 1.0D, par0Hopper.func_96108_aC()); 329 330 if (entityitem != null) 331 { 332 flag |= func_96114_a(par0Hopper, entityitem); 333 } 334 } 335 336 return flag; 337 } 338 339 public static boolean func_96114_a(IInventory par0IInventory, EntityItem par1EntityItem) 340 { 341 boolean flag = false; 342 343 if (par1EntityItem == null) 344 { 345 return false; 346 } 347 else 348 { 349 ItemStack itemstack = par1EntityItem.getEntityItem().copy(); 350 ItemStack itemstack1 = func_94117_a(par0IInventory, itemstack, -1); 351 352 if (itemstack1 != null && itemstack1.stackSize != 0) 353 { 354 par1EntityItem.setEntityItemStack(itemstack1); 355 } 356 else 357 { 358 flag = true; 359 par1EntityItem.setDead(); 360 } 361 362 return flag; 363 } 364 } 365 366 public static int func_94115_a(IInventory par1IInventory, int par2) 367 { 368 int j = 0; 369 int k = par1IInventory.getSizeInventory(); 370 371 if (par1IInventory instanceof ISidedInventory && par2 > -1) 372 { 373 ISidedInventory isidedinventory = (ISidedInventory)par1IInventory; 374 j = isidedinventory.func_94127_c(par2); 375 k = Math.min(k, j + isidedinventory.func_94128_d(par2)); 376 } 377 378 for (int l = j; l < k; ++l) 379 { 380 if (par1IInventory.getStackInSlot(l) != null) 381 { 382 return l; 383 } 384 } 385 386 return -1; 387 } 388 389 public static ItemStack func_94117_a(IInventory par1IInventory, ItemStack par2ItemStack, int par3) 390 { 391 int j = 0; 392 int k = par1IInventory.getSizeInventory(); 393 394 if (par1IInventory instanceof ISidedInventory && par3 > -1) 395 { 396 ISidedInventory isidedinventory = (ISidedInventory)par1IInventory; 397 j = isidedinventory.func_94127_c(par3); 398 k = Math.min(k, j + isidedinventory.func_94128_d(par3)); 399 } 400 401 for (int l = j; l < k && par2ItemStack != null && par2ItemStack.stackSize > 0; ++l) 402 { 403 ItemStack itemstack1 = par1IInventory.getStackInSlot(l); 404 405 if (par1IInventory.func_94041_b(l, par2ItemStack)) 406 { 407 boolean flag = false; 408 409 if (itemstack1 == null) 410 { 411 par1IInventory.setInventorySlotContents(l, par2ItemStack); 412 par2ItemStack = null; 413 flag = true; 414 } 415 else if (func_94114_a(itemstack1, par2ItemStack)) 416 { 417 int i1 = par2ItemStack.getMaxStackSize() - itemstack1.stackSize; 418 int j1 = Math.min(par2ItemStack.stackSize, i1); 419 par2ItemStack.stackSize -= j1; 420 itemstack1.stackSize += j1; 421 flag = j1 > 0; 422 } 423 424 if (flag) 425 { 426 if (par1IInventory instanceof TileEntityHopper) 427 { 428 ((TileEntityHopper)par1IInventory).func_98046_c(8); 429 } 430 431 par1IInventory.onInventoryChanged(); 432 } 433 } 434 } 435 436 if (par2ItemStack != null && par2ItemStack.stackSize == 0) 437 { 438 par2ItemStack = null; 439 } 440 441 return par2ItemStack; 442 } 443 444 private IInventory func_94119_v() 445 { 446 int i = BlockHopper.func_94451_c(this.getBlockMetadata()); 447 return func_96117_b(this.getWorldObj(), (double)(this.xCoord + Facing.offsetsXForSide[i]), (double)(this.yCoord + Facing.offsetsYForSide[i]), (double)(this.zCoord + Facing.offsetsZForSide[i])); 448 } 449 450 public static IInventory func_96118_b(Hopper par0Hopper) 451 { 452 return func_96117_b(par0Hopper.getWorldObj(), par0Hopper.func_96107_aA(), par0Hopper.func_96109_aB() + 1.0D, par0Hopper.func_96108_aC()); 453 } 454 455 public static EntityItem func_96119_a(World par0World, double par1, double par3, double par5) 456 { 457 List list = par0World.selectEntitiesWithinAABB(EntityItem.class, AxisAlignedBB.getAABBPool().getAABB(par1, par3, par5, par1 + 1.0D, par3 + 1.0D, par5 + 1.0D), IEntitySelector.field_94557_a); 458 return list.size() > 0 ? (EntityItem)list.get(0) : null; 459 } 460 461 public static IInventory func_96117_b(World par0World, double par1, double par3, double par5) 462 { 463 IInventory iinventory = null; 464 int i = MathHelper.floor_double(par1); 465 int j = MathHelper.floor_double(par3); 466 int k = MathHelper.floor_double(par5); 467 468 if (iinventory == null) 469 { 470 TileEntity tileentity = par0World.getBlockTileEntity(i, j, k); 471 472 if (tileentity != null && tileentity instanceof IInventory) 473 { 474 iinventory = (IInventory)tileentity; 475 476 if (iinventory instanceof TileEntityChest) 477 { 478 int l = par0World.getBlockId(i, j, k); 479 Block block = Block.blocksList[l]; 480 481 if (block instanceof BlockChest) 482 { 483 iinventory = ((BlockChest)block).func_94442_h_(par0World, i, j, k); 484 } 485 } 486 } 487 } 488 489 if (iinventory == null) 490 { 491 List list = par0World.func_94576_a((Entity)null, AxisAlignedBB.getAABBPool().getAABB(par1, par3, par5, par1 + 1.0D, par3 + 1.0D, par5 + 1.0D), IEntitySelector.field_96566_b); 492 493 if (list != null && list.size() > 0) 494 { 495 iinventory = (IInventory)list.get(par0World.rand.nextInt(list.size())); 496 } 497 } 498 499 return iinventory; 500 } 501 502 private static boolean func_94114_a(ItemStack par1ItemStack, ItemStack par2ItemStack) 503 { 504 return par1ItemStack.itemID != par2ItemStack.itemID ? false : (par1ItemStack.getItemDamage() != par2ItemStack.getItemDamage() ? false : (par1ItemStack.stackSize > par1ItemStack.getMaxStackSize() ? false : ItemStack.areItemStackTagsEqual(par1ItemStack, par2ItemStack))); 505 } 506 507 public double func_96107_aA() 508 { 509 return (double)this.xCoord; 510 } 511 512 public double func_96109_aB() 513 { 514 return (double)this.yCoord; 515 } 516 517 public double func_96108_aC() 518 { 519 return (double)this.zCoord; 520 } 521 522 public void func_98046_c(int par1) 523 { 524 this.field_98048_c = par1; 525 } 526 527 public boolean func_98047_l() 528 { 529 return this.field_98048_c > 0; 530 } 531}