001 package net.minecraft.src; 002 003 import java.util.Iterator; 004 import java.util.List; 005 006 public class TileEntityChest extends TileEntity implements IInventory 007 { 008 private ItemStack[] chestContents = new ItemStack[36]; 009 010 /** Determines if the check for adjacent chests has taken place. */ 011 public boolean adjacentChestChecked = false; 012 013 /** Contains the chest tile located adjacent to this one (if any) */ 014 public TileEntityChest adjacentChestZNeg; 015 016 /** Contains the chest tile located adjacent to this one (if any) */ 017 public TileEntityChest adjacentChestXPos; 018 019 /** Contains the chest tile located adjacent to this one (if any) */ 020 public TileEntityChest adjacentChestXNeg; 021 022 /** Contains the chest tile located adjacent to this one (if any) */ 023 public TileEntityChest adjacentChestZPosition; 024 025 /** The current angle of the lid (between 0 and 1) */ 026 public float lidAngle; 027 028 /** The angle of the lid last tick */ 029 public float prevLidAngle; 030 031 /** The number of players currently using this chest */ 032 public int numUsingPlayers; 033 034 /** Server sync counter (once per 20 ticks) */ 035 private int ticksSinceSync; 036 037 /** 038 * Returns the number of slots in the inventory. 039 */ 040 public int getSizeInventory() 041 { 042 return 27; 043 } 044 045 /** 046 * Returns the stack in slot i 047 */ 048 public ItemStack getStackInSlot(int par1) 049 { 050 return this.chestContents[par1]; 051 } 052 053 /** 054 * Removes from an inventory slot (first arg) up to a specified number (second arg) of items and returns them in a 055 * new stack. 056 */ 057 public ItemStack decrStackSize(int par1, int par2) 058 { 059 if (this.chestContents[par1] != null) 060 { 061 ItemStack var3; 062 063 if (this.chestContents[par1].stackSize <= par2) 064 { 065 var3 = this.chestContents[par1]; 066 this.chestContents[par1] = null; 067 this.onInventoryChanged(); 068 return var3; 069 } 070 else 071 { 072 var3 = this.chestContents[par1].splitStack(par2); 073 074 if (this.chestContents[par1].stackSize == 0) 075 { 076 this.chestContents[par1] = null; 077 } 078 079 this.onInventoryChanged(); 080 return var3; 081 } 082 } 083 else 084 { 085 return null; 086 } 087 } 088 089 /** 090 * When some containers are closed they call this on each slot, then drop whatever it returns as an EntityItem - 091 * like when you close a workbench GUI. 092 */ 093 public ItemStack getStackInSlotOnClosing(int par1) 094 { 095 if (this.chestContents[par1] != null) 096 { 097 ItemStack var2 = this.chestContents[par1]; 098 this.chestContents[par1] = null; 099 return var2; 100 } 101 else 102 { 103 return null; 104 } 105 } 106 107 /** 108 * Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections). 109 */ 110 public void setInventorySlotContents(int par1, ItemStack par2ItemStack) 111 { 112 this.chestContents[par1] = par2ItemStack; 113 114 if (par2ItemStack != null && par2ItemStack.stackSize > this.getInventoryStackLimit()) 115 { 116 par2ItemStack.stackSize = this.getInventoryStackLimit(); 117 } 118 119 this.onInventoryChanged(); 120 } 121 122 /** 123 * Returns the name of the inventory. 124 */ 125 public String getInvName() 126 { 127 return "container.chest"; 128 } 129 130 /** 131 * Reads a tile entity from NBT. 132 */ 133 public void readFromNBT(NBTTagCompound par1NBTTagCompound) 134 { 135 super.readFromNBT(par1NBTTagCompound); 136 NBTTagList var2 = par1NBTTagCompound.getTagList("Items"); 137 this.chestContents = new ItemStack[this.getSizeInventory()]; 138 139 for (int var3 = 0; var3 < var2.tagCount(); ++var3) 140 { 141 NBTTagCompound var4 = (NBTTagCompound)var2.tagAt(var3); 142 int var5 = var4.getByte("Slot") & 255; 143 144 if (var5 >= 0 && var5 < this.chestContents.length) 145 { 146 this.chestContents[var5] = ItemStack.loadItemStackFromNBT(var4); 147 } 148 } 149 } 150 151 /** 152 * Writes a tile entity to NBT. 153 */ 154 public void writeToNBT(NBTTagCompound par1NBTTagCompound) 155 { 156 super.writeToNBT(par1NBTTagCompound); 157 NBTTagList var2 = new NBTTagList(); 158 159 for (int var3 = 0; var3 < this.chestContents.length; ++var3) 160 { 161 if (this.chestContents[var3] != null) 162 { 163 NBTTagCompound var4 = new NBTTagCompound(); 164 var4.setByte("Slot", (byte)var3); 165 this.chestContents[var3].writeToNBT(var4); 166 var2.appendTag(var4); 167 } 168 } 169 170 par1NBTTagCompound.setTag("Items", var2); 171 } 172 173 /** 174 * Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended. *Isn't 175 * this more of a set than a get?* 176 */ 177 public int getInventoryStackLimit() 178 { 179 return 64; 180 } 181 182 /** 183 * Do not make give this method the name canInteractWith because it clashes with Container 184 */ 185 public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer) 186 { 187 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; 188 } 189 190 /** 191 * Causes the TileEntity to reset all it's cached values for it's container block, blockID, metaData and in the case 192 * of chests, the adjcacent chest check 193 */ 194 public void updateContainingBlockInfo() 195 { 196 super.updateContainingBlockInfo(); 197 this.adjacentChestChecked = false; 198 } 199 200 private void func_90009_a(TileEntityChest par1TileEntityChest, int par2) 201 { 202 if (par1TileEntityChest.isInvalid()) 203 { 204 this.adjacentChestChecked = false; 205 } 206 else if (this.adjacentChestChecked) 207 { 208 switch (par2) 209 { 210 case 0: 211 if (this.adjacentChestZPosition != par1TileEntityChest) 212 { 213 this.adjacentChestChecked = false; 214 } 215 216 break; 217 case 1: 218 if (this.adjacentChestXNeg != par1TileEntityChest) 219 { 220 this.adjacentChestChecked = false; 221 } 222 223 break; 224 case 2: 225 if (this.adjacentChestZNeg != par1TileEntityChest) 226 { 227 this.adjacentChestChecked = false; 228 } 229 230 break; 231 case 3: 232 if (this.adjacentChestXPos != par1TileEntityChest) 233 { 234 this.adjacentChestChecked = false; 235 } 236 } 237 } 238 } 239 240 /** 241 * Performs the check for adjacent chests to determine if this chest is double or not. 242 */ 243 public void checkForAdjacentChests() 244 { 245 if (!this.adjacentChestChecked) 246 { 247 this.adjacentChestChecked = true; 248 this.adjacentChestZNeg = null; 249 this.adjacentChestXPos = null; 250 this.adjacentChestXNeg = null; 251 this.adjacentChestZPosition = null; 252 253 if (this.worldObj.getBlockId(this.xCoord - 1, this.yCoord, this.zCoord) == Block.chest.blockID) 254 { 255 this.adjacentChestXNeg = (TileEntityChest)this.worldObj.getBlockTileEntity(this.xCoord - 1, this.yCoord, this.zCoord); 256 } 257 258 if (this.worldObj.getBlockId(this.xCoord + 1, this.yCoord, this.zCoord) == Block.chest.blockID) 259 { 260 this.adjacentChestXPos = (TileEntityChest)this.worldObj.getBlockTileEntity(this.xCoord + 1, this.yCoord, this.zCoord); 261 } 262 263 if (this.worldObj.getBlockId(this.xCoord, this.yCoord, this.zCoord - 1) == Block.chest.blockID) 264 { 265 this.adjacentChestZNeg = (TileEntityChest)this.worldObj.getBlockTileEntity(this.xCoord, this.yCoord, this.zCoord - 1); 266 } 267 268 if (this.worldObj.getBlockId(this.xCoord, this.yCoord, this.zCoord + 1) == Block.chest.blockID) 269 { 270 this.adjacentChestZPosition = (TileEntityChest)this.worldObj.getBlockTileEntity(this.xCoord, this.yCoord, this.zCoord + 1); 271 } 272 273 if (this.adjacentChestZNeg != null) 274 { 275 this.adjacentChestZNeg.func_90009_a(this, 0); 276 } 277 278 if (this.adjacentChestZPosition != null) 279 { 280 this.adjacentChestZPosition.func_90009_a(this, 2); 281 } 282 283 if (this.adjacentChestXPos != null) 284 { 285 this.adjacentChestXPos.func_90009_a(this, 1); 286 } 287 288 if (this.adjacentChestXNeg != null) 289 { 290 this.adjacentChestXNeg.func_90009_a(this, 3); 291 } 292 } 293 } 294 295 /** 296 * Allows the entity to update its state. Overridden in most subclasses, e.g. the mob spawner uses this to count 297 * ticks and creates a new spawn inside its implementation. 298 */ 299 public void updateEntity() 300 { 301 super.updateEntity(); 302 this.checkForAdjacentChests(); 303 ++this.ticksSinceSync; 304 float var1; 305 306 if (!this.worldObj.isRemote && this.numUsingPlayers != 0 && (this.ticksSinceSync + this.xCoord + this.yCoord + this.zCoord) % 200 == 0) 307 { 308 this.numUsingPlayers = 0; 309 var1 = 5.0F; 310 List var2 = this.worldObj.getEntitiesWithinAABB(EntityPlayer.class, AxisAlignedBB.getAABBPool().addOrModifyAABBInPool((double)((float)this.xCoord - var1), (double)((float)this.yCoord - var1), (double)((float)this.zCoord - var1), (double)((float)(this.xCoord + 1) + var1), (double)((float)(this.yCoord + 1) + var1), (double)((float)(this.zCoord + 1) + var1))); 311 Iterator var3 = var2.iterator(); 312 313 while (var3.hasNext()) 314 { 315 EntityPlayer var4 = (EntityPlayer)var3.next(); 316 317 if (var4.openContainer instanceof ContainerChest) 318 { 319 IInventory var5 = ((ContainerChest)var4.openContainer).func_85151_d(); 320 321 if (var5 == this || var5 instanceof InventoryLargeChest && ((InventoryLargeChest)var5).func_90010_a(this)) 322 { 323 ++this.numUsingPlayers; 324 } 325 } 326 } 327 } 328 329 this.prevLidAngle = this.lidAngle; 330 var1 = 0.1F; 331 double var11; 332 333 if (this.numUsingPlayers > 0 && this.lidAngle == 0.0F && this.adjacentChestZNeg == null && this.adjacentChestXNeg == null) 334 { 335 double var8 = (double)this.xCoord + 0.5D; 336 var11 = (double)this.zCoord + 0.5D; 337 338 if (this.adjacentChestZPosition != null) 339 { 340 var11 += 0.5D; 341 } 342 343 if (this.adjacentChestXPos != null) 344 { 345 var8 += 0.5D; 346 } 347 348 this.worldObj.playSoundEffect(var8, (double)this.yCoord + 0.5D, var11, "random.chestopen", 0.5F, this.worldObj.rand.nextFloat() * 0.1F + 0.9F); 349 } 350 351 if (this.numUsingPlayers == 0 && this.lidAngle > 0.0F || this.numUsingPlayers > 0 && this.lidAngle < 1.0F) 352 { 353 float var9 = this.lidAngle; 354 355 if (this.numUsingPlayers > 0) 356 { 357 this.lidAngle += var1; 358 } 359 else 360 { 361 this.lidAngle -= var1; 362 } 363 364 if (this.lidAngle > 1.0F) 365 { 366 this.lidAngle = 1.0F; 367 } 368 369 float var10 = 0.5F; 370 371 if (this.lidAngle < var10 && var9 >= var10 && this.adjacentChestZNeg == null && this.adjacentChestXNeg == null) 372 { 373 var11 = (double)this.xCoord + 0.5D; 374 double var6 = (double)this.zCoord + 0.5D; 375 376 if (this.adjacentChestZPosition != null) 377 { 378 var6 += 0.5D; 379 } 380 381 if (this.adjacentChestXPos != null) 382 { 383 var11 += 0.5D; 384 } 385 386 this.worldObj.playSoundEffect(var11, (double)this.yCoord + 0.5D, var6, "random.chestclosed", 0.5F, this.worldObj.rand.nextFloat() * 0.1F + 0.9F); 387 } 388 389 if (this.lidAngle < 0.0F) 390 { 391 this.lidAngle = 0.0F; 392 } 393 } 394 } 395 396 /** 397 * Called when a client event is received with the event number and argument, see World.sendClientEvent 398 */ 399 public void receiveClientEvent(int par1, int par2) 400 { 401 if (par1 == 1) 402 { 403 this.numUsingPlayers = par2; 404 } 405 } 406 407 public void openChest() 408 { 409 ++this.numUsingPlayers; 410 this.worldObj.addBlockEvent(this.xCoord, this.yCoord, this.zCoord, Block.chest.blockID, 1, this.numUsingPlayers); 411 } 412 413 public void closeChest() 414 { 415 --this.numUsingPlayers; 416 this.worldObj.addBlockEvent(this.xCoord, this.yCoord, this.zCoord, Block.chest.blockID, 1, this.numUsingPlayers); 417 } 418 419 /** 420 * invalidates a tile entity 421 */ 422 public void invalidate() 423 { 424 super.invalidate(); 425 this.updateContainingBlockInfo(); 426 this.checkForAdjacentChests(); 427 } 428 }