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}