    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    }