    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        /**
    201         * Performs the check for adjacent chests to determine if this chest is double or not.
    202         */
    203        public void checkForAdjacentChests()
    204        {
    205            if (!this.adjacentChestChecked)
    206            {
    207                this.adjacentChestChecked = true;
    208                this.adjacentChestZNeg = null;
    209                this.adjacentChestXPos = null;
    210                this.adjacentChestXNeg = null;
    211                this.adjacentChestZPosition = null;
    212
    213                if (this.worldObj.getBlockId(this.xCoord - 1, this.yCoord, this.zCoord) == Block.chest.blockID)
    214                {
    215                    this.adjacentChestXNeg = (TileEntityChest)this.worldObj.getBlockTileEntity(this.xCoord - 1, this.yCoord, this.zCoord);
    216                }
    217
    218                if (this.worldObj.getBlockId(this.xCoord + 1, this.yCoord, this.zCoord) == Block.chest.blockID)
    219                {
    220                    this.adjacentChestXPos = (TileEntityChest)this.worldObj.getBlockTileEntity(this.xCoord + 1, this.yCoord, this.zCoord);
    221                }
    222
    223                if (this.worldObj.getBlockId(this.xCoord, this.yCoord, this.zCoord - 1) == Block.chest.blockID)
    224                {
    225                    this.adjacentChestZNeg = (TileEntityChest)this.worldObj.getBlockTileEntity(this.xCoord, this.yCoord, this.zCoord - 1);
    226                }
    227
    228                if (this.worldObj.getBlockId(this.xCoord, this.yCoord, this.zCoord + 1) == Block.chest.blockID)
    229                {
    230                    this.adjacentChestZPosition = (TileEntityChest)this.worldObj.getBlockTileEntity(this.xCoord, this.yCoord, this.zCoord + 1);
    231                }
    232
    233                if (this.adjacentChestZNeg != null)
    234                {
    235                    this.adjacentChestZNeg.updateContainingBlockInfo();
    236                }
    237
    238                if (this.adjacentChestZPosition != null)
    239                {
    240                    this.adjacentChestZPosition.updateContainingBlockInfo();
    241                }
    242
    243                if (this.adjacentChestXPos != null)
    244                {
    245                    this.adjacentChestXPos.updateContainingBlockInfo();
    246                }
    247
    248                if (this.adjacentChestXNeg != null)
    249                {
    250                    this.adjacentChestXNeg.updateContainingBlockInfo();
    251                }
    252            }
    253        }
    254
    255        /**
    256         * Allows the entity to update its state. Overridden in most subclasses, e.g. the mob spawner uses this to count
    257         * ticks and creates a new spawn inside its implementation.
    258         */
    259        public void updateEntity()
    260        {
    261            super.updateEntity();
    262            this.checkForAdjacentChests();
    263            ++this.ticksSinceSync;
    264            float var1;
    265
    266            if (!this.worldObj.isRemote && this.numUsingPlayers != 0 && (this.ticksSinceSync + this.xCoord + this.yCoord + this.zCoord) % 200 == 0)
    267            {
    268                this.numUsingPlayers = 0;
    269                var1 = 5.0F;
    270                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)));
    271                Iterator var3 = var2.iterator();
    272
    273                while (var3.hasNext())
    274                {
    275                    EntityPlayer var4 = (EntityPlayer)var3.next();
    276
    277                    if (var4.craftingInventory instanceof ContainerChest && ((ContainerChest)var4.craftingInventory).func_85151_d() == this)
    278                    {
    279                        ++this.numUsingPlayers;
    280                    }
    281                }
    282            }
    283
    284            this.prevLidAngle = this.lidAngle;
    285            var1 = 0.1F;
    286            double var11;
    287
    288            if (this.numUsingPlayers > 0 && this.lidAngle == 0.0F && this.adjacentChestZNeg == null && this.adjacentChestXNeg == null)
    289            {
    290                double var8 = (double)this.xCoord + 0.5D;
    291                var11 = (double)this.zCoord + 0.5D;
    292
    293                if (this.adjacentChestZPosition != null)
    294                {
    295                    var11 += 0.5D;
    296                }
    297
    298                if (this.adjacentChestXPos != null)
    299                {
    300                    var8 += 0.5D;
    301                }
    302
    303                this.worldObj.playSoundEffect(var8, (double)this.yCoord + 0.5D, var11, "random.chestopen", 0.5F, this.worldObj.rand.nextFloat() * 0.1F + 0.9F);
    304            }
    305
    306            if (this.numUsingPlayers == 0 && this.lidAngle > 0.0F || this.numUsingPlayers > 0 && this.lidAngle < 1.0F)
    307            {
    308                float var9 = this.lidAngle;
    309
    310                if (this.numUsingPlayers > 0)
    311                {
    312                    this.lidAngle += var1;
    313                }
    314                else
    315                {
    316                    this.lidAngle -= var1;
    317                }
    318
    319                if (this.lidAngle > 1.0F)
    320                {
    321                    this.lidAngle = 1.0F;
    322                }
    323
    324                float var10 = 0.5F;
    325
    326                if (this.lidAngle < var10 && var9 >= var10 && this.adjacentChestZNeg == null && this.adjacentChestXNeg == null)
    327                {
    328                    var11 = (double)this.xCoord + 0.5D;
    329                    double var6 = (double)this.zCoord + 0.5D;
    330
    331                    if (this.adjacentChestZPosition != null)
    332                    {
    333                        var6 += 0.5D;
    334                    }
    335
    336                    if (this.adjacentChestXPos != null)
    337                    {
    338                        var11 += 0.5D;
    339                    }
    340
    341                    this.worldObj.playSoundEffect(var11, (double)this.yCoord + 0.5D, var6, "random.chestclosed", 0.5F, this.worldObj.rand.nextFloat() * 0.1F + 0.9F);
    342                }
    343
    344                if (this.lidAngle < 0.0F)
    345                {
    346                    this.lidAngle = 0.0F;
    347                }
    348            }
    349        }
    350
    351        /**
    352         * Called when a client event is received with the event number and argument, see World.sendClientEvent
    353         */
    354        public void receiveClientEvent(int par1, int par2)
    355        {
    356            if (par1 == 1)
    357            {
    358                this.numUsingPlayers = par2;
    359            }
    360        }
    361
    362        public void openChest()
    363        {
    364            ++this.numUsingPlayers;
    365            this.worldObj.addBlockEvent(this.xCoord, this.yCoord, this.zCoord, Block.chest.blockID, 1, this.numUsingPlayers);
    366        }
    367
    368        public void closeChest()
    369        {
    370            --this.numUsingPlayers;
    371            this.worldObj.addBlockEvent(this.xCoord, this.yCoord, this.zCoord, Block.chest.blockID, 1, this.numUsingPlayers);
    372        }
    373
    374        /**
    375         * invalidates a tile entity
    376         */
    377        public void invalidate()
    378        {
    379            this.updateContainingBlockInfo();
    380            this.checkForAdjacentChests();
    381            super.invalidate();
    382        }
    383    }