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