    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.craftingInventory instanceof ContainerChest)
    318                    {
    319                        IInventory var5 = ((ContainerChest)var4.craftingInventory).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    }