    001package net.minecraft.tileentity;
    002
    003import java.util.List;
    004import net.minecraft.block.Block;
    005import net.minecraft.block.BlockChest;
    006import net.minecraft.block.BlockHopper;
    007import net.minecraft.command.IEntitySelector;
    008import net.minecraft.entity.Entity;
    009import net.minecraft.entity.item.EntityItem;
    010import net.minecraft.entity.player.EntityPlayer;
    011import net.minecraft.inventory.IInventory;
    012import net.minecraft.inventory.ISidedInventory;
    013import net.minecraft.item.ItemStack;
    014import net.minecraft.nbt.NBTTagCompound;
    015import net.minecraft.nbt.NBTTagList;
    016import net.minecraft.util.AxisAlignedBB;
    017import net.minecraft.util.Facing;
    018import net.minecraft.util.MathHelper;
    019import net.minecraft.world.World;
    020
    021public class TileEntityHopper extends TileEntity implements Hopper
    022{
    023    private ItemStack[] field_94124_b = new ItemStack[5];
    024    private String field_94123_d;
    025    private int field_98048_c = -1;
    026
    027    /**
    028     * Reads a tile entity from NBT.
    029     */
    030    public void readFromNBT(NBTTagCompound par1NBTTagCompound)
    031    {
    032        super.readFromNBT(par1NBTTagCompound);
    033        NBTTagList nbttaglist = par1NBTTagCompound.getTagList("Items");
    034        this.field_94124_b = new ItemStack[this.getSizeInventory()];
    035
    036        if (par1NBTTagCompound.hasKey("CustomName"))
    037        {
    038            this.field_94123_d = par1NBTTagCompound.getString("CustomName");
    039        }
    040
    041        this.field_98048_c = par1NBTTagCompound.getInteger("TransferCooldown");
    042
    043        for (int i = 0; i < nbttaglist.tagCount(); ++i)
    044        {
    045            NBTTagCompound nbttagcompound1 = (NBTTagCompound)nbttaglist.tagAt(i);
    046            byte b0 = nbttagcompound1.getByte("Slot");
    047
    048            if (b0 >= 0 && b0 < this.field_94124_b.length)
    049            {
    050                this.field_94124_b[b0] = ItemStack.loadItemStackFromNBT(nbttagcompound1);
    051            }
    052        }
    053    }
    054
    055    /**
    056     * Writes a tile entity to NBT.
    057     */
    058    public void writeToNBT(NBTTagCompound par1NBTTagCompound)
    059    {
    060        super.writeToNBT(par1NBTTagCompound);
    061        NBTTagList nbttaglist = new NBTTagList();
    062
    063        for (int i = 0; i < this.field_94124_b.length; ++i)
    064        {
    065            if (this.field_94124_b[i] != null)
    066            {
    067                NBTTagCompound nbttagcompound1 = new NBTTagCompound();
    068                nbttagcompound1.setByte("Slot", (byte)i);
    069                this.field_94124_b[i].writeToNBT(nbttagcompound1);
    070                nbttaglist.appendTag(nbttagcompound1);
    071            }
    072        }
    073
    074        par1NBTTagCompound.setTag("Items", nbttaglist);
    075        par1NBTTagCompound.setInteger("TransferCooldown", this.field_98048_c);
    076
    077        if (this.func_94042_c())
    078        {
    079            par1NBTTagCompound.setString("CustomName", this.field_94123_d);
    080        }
    081    }
    082
    083    /**
    084     * Called when an the contents of an Inventory change, usually
    085     */
    086    public void onInventoryChanged()
    087    {
    088        super.onInventoryChanged();
    089    }
    090
    091    /**
    092     * Returns the number of slots in the inventory.
    093     */
    094    public int getSizeInventory()
    095    {
    096        return this.field_94124_b.length;
    097    }
    098
    099    /**
    100     * Returns the stack in slot i
    101     */
    102    public ItemStack getStackInSlot(int par1)
    103    {
    104        return this.field_94124_b[par1];
    105    }
    106
    107    /**
    108     * Removes from an inventory slot (first arg) up to a specified number (second arg) of items and returns them in a
    109     * new stack.
    110     */
    111    public ItemStack decrStackSize(int par1, int par2)
    112    {
    113        if (this.field_94124_b[par1] != null)
    114        {
    115            ItemStack itemstack;
    116
    117            if (this.field_94124_b[par1].stackSize <= par2)
    118            {
    119                itemstack = this.field_94124_b[par1];
    120                this.field_94124_b[par1] = null;
    121                return itemstack;
    122            }
    123            else
    124            {
    125                itemstack = this.field_94124_b[par1].splitStack(par2);
    126
    127                if (this.field_94124_b[par1].stackSize == 0)
    128                {
    129                    this.field_94124_b[par1] = null;
    130                }
    131
    132                return itemstack;
    133            }
    134        }
    135        else
    136        {
    137            return null;
    138        }
    139    }
    140
    141    /**
    142     * When some containers are closed they call this on each slot, then drop whatever it returns as an EntityItem -
    143     * like when you close a workbench GUI.
    144     */
    145    public ItemStack getStackInSlotOnClosing(int par1)
    146    {
    147        if (this.field_94124_b[par1] != null)
    148        {
    149            ItemStack itemstack = this.field_94124_b[par1];
    150            this.field_94124_b[par1] = null;
    151            return itemstack;
    152        }
    153        else
    154        {
    155            return null;
    156        }
    157    }
    158
    159    /**
    160     * Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections).
    161     */
    162    public void setInventorySlotContents(int par1, ItemStack par2ItemStack)
    163    {
    164        this.field_94124_b[par1] = par2ItemStack;
    165
    166        if (par2ItemStack != null && par2ItemStack.stackSize > this.getInventoryStackLimit())
    167        {
    168            par2ItemStack.stackSize = this.getInventoryStackLimit();
    169        }
    170    }
    171
    172    /**
    173     * Returns the name of the inventory.
    174     */
    175    public String getInvName()
    176    {
    177        return this.func_94042_c() ? this.field_94123_d : "container.hopper";
    178    }
    179
    180    public boolean func_94042_c()
    181    {
    182        return this.field_94123_d != null && this.field_94123_d.length() > 0;
    183    }
    184
    185    public void func_96115_a(String par1Str)
    186    {
    187        this.field_94123_d = par1Str;
    188    }
    189
    190    /**
    191     * Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended. *Isn't
    192     * this more of a set than a get?*
    193     */
    194    public int getInventoryStackLimit()
    195    {
    196        return 64;
    197    }
    198
    199    /**
    200     * Do not make give this method the name canInteractWith because it clashes with Container
    201     */
    202    public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer)
    203    {
    204        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;
    205    }
    206
    207    public void openChest() {}
    208
    209    public void closeChest() {}
    210
    211    public boolean func_94041_b(int par1, ItemStack par2ItemStack)
    212    {
    213        return true;
    214    }
    215
    216    /**
    217     * Allows the entity to update its state. Overridden in most subclasses, e.g. the mob spawner uses this to count
    218     * ticks and creates a new spawn inside its implementation.
    219     */
    220    public void updateEntity()
    221    {
    222        if (this.worldObj != null && !this.worldObj.isRemote)
    223        {
    224            --this.field_98048_c;
    225
    226            if (!this.func_98047_l())
    227            {
    228                this.func_98046_c(0);
    229                this.func_98045_j();
    230            }
    231        }
    232    }
    233
    234    public boolean func_98045_j()
    235    {
    236        if (this.worldObj != null && !this.worldObj.isRemote)
    237        {
    238            if (!this.func_98047_l() && BlockHopper.func_94452_d(this.getBlockMetadata()))
    239            {
    240                boolean flag = this.func_94116_j() | func_96116_a(this);
    241
    242                if (flag)
    243                {
    244                    this.func_98046_c(8);
    245                    this.onInventoryChanged();
    246                    return true;
    247                }
    248            }
    249
    250            return false;
    251        }
    252        else
    253        {
    254            return false;
    255        }
    256    }
    257
    258    private boolean func_94116_j()
    259    {
    260        int i = func_94115_a(this, -1);
    261        boolean flag = false;
    262
    263        if (i > -1)
    264        {
    265            IInventory iinventory = this.func_94119_v();
    266
    267            if (iinventory != null)
    268            {
    269                ItemStack itemstack = this.getStackInSlot(i).copy();
    270                ItemStack itemstack1 = func_94117_a(iinventory, this.decrStackSize(i, 1), Facing.faceToSide[BlockHopper.func_94451_c(this.getBlockMetadata())]);
    271
    272                if (itemstack1 != null && itemstack1.stackSize != 0)
    273                {
    274                    this.setInventorySlotContents(i, itemstack);
    275                }
    276                else
    277                {
    278                    flag |= true;
    279                    iinventory.onInventoryChanged();
    280                }
    281            }
    282        }
    283
    284        return flag;
    285    }
    286
    287    public static boolean func_96116_a(Hopper par0Hopper)
    288    {
    289        boolean flag = false;
    290        IInventory iinventory = func_96118_b(par0Hopper);
    291
    292        if (iinventory != null)
    293        {
    294            byte b0 = 0;
    295            int i = 0;
    296            int j = iinventory.getSizeInventory();
    297
    298            if (iinventory instanceof ISidedInventory && b0 > -1)
    299            {
    300                ISidedInventory isidedinventory = (ISidedInventory)iinventory;
    301                i = isidedinventory.func_94127_c(b0);
    302                j = Math.min(j, i + isidedinventory.func_94128_d(b0));
    303            }
    304
    305            for (int k = i; k < j && !flag; ++k)
    306            {
    307                ItemStack itemstack = iinventory.getStackInSlot(k);
    308
    309                if (itemstack != null)
    310                {
    311                    ItemStack itemstack1 = itemstack.copy();
    312                    ItemStack itemstack2 = func_94117_a(par0Hopper, iinventory.decrStackSize(k, 1), -1);
    313
    314                    if (itemstack2 != null && itemstack2.stackSize != 0)
    315                    {
    316                        iinventory.setInventorySlotContents(k, itemstack1);
    317                    }
    318                    else
    319                    {
    320                        flag |= true;
    321                        iinventory.onInventoryChanged();
    322                    }
    323                }
    324            }
    325        }
    326        else
    327        {
    328            EntityItem entityitem = func_96119_a(par0Hopper.getWorldObj(), par0Hopper.func_96107_aA(), par0Hopper.func_96109_aB() + 1.0D, par0Hopper.func_96108_aC());
    329
    330            if (entityitem != null)
    331            {
    332                flag |= func_96114_a(par0Hopper, entityitem);
    333            }
    334        }
    335
    336        return flag;
    337    }
    338
    339    public static boolean func_96114_a(IInventory par0IInventory, EntityItem par1EntityItem)
    340    {
    341        boolean flag = false;
    342
    343        if (par1EntityItem == null)
    344        {
    345            return false;
    346        }
    347        else
    348        {
    349            ItemStack itemstack = par1EntityItem.getEntityItem().copy();
    350            ItemStack itemstack1 = func_94117_a(par0IInventory, itemstack, -1);
    351
    352            if (itemstack1 != null && itemstack1.stackSize != 0)
    353            {
    354                par1EntityItem.setEntityItemStack(itemstack1);
    355            }
    356            else
    357            {
    358                flag = true;
    359                par1EntityItem.setDead();
    360            }
    361
    362            return flag;
    363        }
    364    }
    365
    366    public static int func_94115_a(IInventory par1IInventory, int par2)
    367    {
    368        int j = 0;
    369        int k = par1IInventory.getSizeInventory();
    370
    371        if (par1IInventory instanceof ISidedInventory && par2 > -1)
    372        {
    373            ISidedInventory isidedinventory = (ISidedInventory)par1IInventory;
    374            j = isidedinventory.func_94127_c(par2);
    375            k = Math.min(k, j + isidedinventory.func_94128_d(par2));
    376        }
    377
    378        for (int l = j; l < k; ++l)
    379        {
    380            if (par1IInventory.getStackInSlot(l) != null)
    381            {
    382                return l;
    383            }
    384        }
    385
    386        return -1;
    387    }
    388
    389    public static ItemStack func_94117_a(IInventory par1IInventory, ItemStack par2ItemStack, int par3)
    390    {
    391        int j = 0;
    392        int k = par1IInventory.getSizeInventory();
    393
    394        if (par1IInventory instanceof ISidedInventory && par3 > -1)
    395        {
    396            ISidedInventory isidedinventory = (ISidedInventory)par1IInventory;
    397            j = isidedinventory.func_94127_c(par3);
    398            k = Math.min(k, j + isidedinventory.func_94128_d(par3));
    399        }
    400
    401        for (int l = j; l < k && par2ItemStack != null && par2ItemStack.stackSize > 0; ++l)
    402        {
    403            ItemStack itemstack1 = par1IInventory.getStackInSlot(l);
    404
    405            if (par1IInventory.func_94041_b(l, par2ItemStack))
    406            {
    407                boolean flag = false;
    408
    409                if (itemstack1 == null)
    410                {
    411                    par1IInventory.setInventorySlotContents(l, par2ItemStack);
    412                    par2ItemStack = null;
    413                    flag = true;
    414                }
    415                else if (func_94114_a(itemstack1, par2ItemStack))
    416                {
    417                    int i1 = par2ItemStack.getMaxStackSize() - itemstack1.stackSize;
    418                    int j1 = Math.min(par2ItemStack.stackSize, i1);
    419                    par2ItemStack.stackSize -= j1;
    420                    itemstack1.stackSize += j1;
    421                    flag = j1 > 0;
    422                }
    423
    424                if (flag)
    425                {
    426                    if (par1IInventory instanceof TileEntityHopper)
    427                    {
    428                        ((TileEntityHopper)par1IInventory).func_98046_c(8);
    429                    }
    430
    431                    par1IInventory.onInventoryChanged();
    432                }
    433            }
    434        }
    435
    436        if (par2ItemStack != null && par2ItemStack.stackSize == 0)
    437        {
    438            par2ItemStack = null;
    439        }
    440
    441        return par2ItemStack;
    442    }
    443
    444    private IInventory func_94119_v()
    445    {
    446        int i = BlockHopper.func_94451_c(this.getBlockMetadata());
    447        return func_96117_b(this.getWorldObj(), (double)(this.xCoord + Facing.offsetsXForSide[i]), (double)(this.yCoord + Facing.offsetsYForSide[i]), (double)(this.zCoord + Facing.offsetsZForSide[i]));
    448    }
    449
    450    public static IInventory func_96118_b(Hopper par0Hopper)
    451    {
    452        return func_96117_b(par0Hopper.getWorldObj(), par0Hopper.func_96107_aA(), par0Hopper.func_96109_aB() + 1.0D, par0Hopper.func_96108_aC());
    453    }
    454
    455    public static EntityItem func_96119_a(World par0World, double par1, double par3, double par5)
    456    {
    457        List list = par0World.selectEntitiesWithinAABB(EntityItem.class, AxisAlignedBB.getAABBPool().getAABB(par1, par3, par5, par1 + 1.0D, par3 + 1.0D, par5 + 1.0D), IEntitySelector.field_94557_a);
    458        return list.size() > 0 ? (EntityItem)list.get(0) : null;
    459    }
    460
    461    public static IInventory func_96117_b(World par0World, double par1, double par3, double par5)
    462    {
    463        IInventory iinventory = null;
    464        int i = MathHelper.floor_double(par1);
    465        int j = MathHelper.floor_double(par3);
    466        int k = MathHelper.floor_double(par5);
    467
    468        if (iinventory == null)
    469        {
    470            TileEntity tileentity = par0World.getBlockTileEntity(i, j, k);
    471
    472            if (tileentity != null && tileentity instanceof IInventory)
    473            {
    474                iinventory = (IInventory)tileentity;
    475
    476                if (iinventory instanceof TileEntityChest)
    477                {
    478                    int l = par0World.getBlockId(i, j, k);
    479                    Block block = Block.blocksList[l];
    480
    481                    if (block instanceof BlockChest)
    482                    {
    483                        iinventory = ((BlockChest)block).func_94442_h_(par0World, i, j, k);
    484                    }
    485                }
    486            }
    487        }
    488
    489        if (iinventory == null)
    490        {
    491            List list = par0World.func_94576_a((Entity)null, AxisAlignedBB.getAABBPool().getAABB(par1, par3, par5, par1 + 1.0D, par3 + 1.0D, par5 + 1.0D), IEntitySelector.field_96566_b);
    492
    493            if (list != null && list.size() > 0)
    494            {
    495                iinventory = (IInventory)list.get(par0World.rand.nextInt(list.size()));
    496            }
    497        }
    498
    499        return iinventory;
    500    }
    501
    502    private static boolean func_94114_a(ItemStack par1ItemStack, ItemStack par2ItemStack)
    503    {
    504        return par1ItemStack.itemID != par2ItemStack.itemID ? false : (par1ItemStack.getItemDamage() != par2ItemStack.getItemDamage() ? false : (par1ItemStack.stackSize > par1ItemStack.getMaxStackSize() ? false : ItemStack.areItemStackTagsEqual(par1ItemStack, par2ItemStack)));
    505    }
    506
    507    public double func_96107_aA()
    508    {
    509        return (double)this.xCoord;
    510    }
    511
    512    public double func_96109_aB()
    513    {
    514        return (double)this.yCoord;
    515    }
    516
    517    public double func_96108_aC()
    518    {
    519        return (double)this.zCoord;
    520    }
    521
    522    public void func_98046_c(int par1)
    523    {
    524        this.field_98048_c = par1;
    525    }
    526
    527    public boolean func_98047_l()
    528    {
    529        return this.field_98048_c > 0;
    530    }
    531}