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