    001package net.minecraft.block;
    002
    003import cpw.mods.fml.relauncher.Side;
    004import cpw.mods.fml.relauncher.SideOnly;
    005import java.util.List;
    006import java.util.Random;
    007import net.minecraft.block.material.Material;
    008import net.minecraft.client.renderer.texture.IconRegister;
    009import net.minecraft.creativetab.CreativeTabs;
    010import net.minecraft.entity.Entity;
    011import net.minecraft.entity.EntityLiving;
    012import net.minecraft.entity.item.EntityItem;
    013import net.minecraft.entity.player.EntityPlayer;
    014import net.minecraft.inventory.Container;
    015import net.minecraft.item.ItemStack;
    016import net.minecraft.nbt.NBTTagCompound;
    017import net.minecraft.tileentity.TileEntity;
    018import net.minecraft.tileentity.TileEntityHopper;
    019import net.minecraft.util.AxisAlignedBB;
    020import net.minecraft.util.Facing;
    021import net.minecraft.util.Icon;
    022import net.minecraft.world.IBlockAccess;
    023import net.minecraft.world.World;
    024
    025public class BlockHopper extends BlockContainer
    026{
    027    private final Random field_94457_a = new Random();
    028    @SideOnly(Side.CLIENT)
    029    private Icon hopperIcon;
    030    @SideOnly(Side.CLIENT)
    031    private Icon hopperTopIcon;
    032    @SideOnly(Side.CLIENT)
    033    private Icon hopperInsideIcon;
    034
    035    public BlockHopper(int par1)
    036    {
    037        super(par1, Material.iron);
    038        this.setCreativeTab(CreativeTabs.tabRedstone);
    039        this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
    040    }
    041
    042    /**
    043     * Updates the blocks bounds based on its current state. Args: world, x, y, z
    044     */
    045    public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
    046    {
    047        this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
    048    }
    049
    050    /**
    051     * Adds all intersecting collision boxes to a list. (Be sure to only add boxes to the list if they intersect the
    052     * mask.) Parameters: World, X, Y, Z, mask, list, colliding entity
    053     */
    054    public void addCollisionBoxesToList(World par1World, int par2, int par3, int par4, AxisAlignedBB par5AxisAlignedBB, List par6List, Entity par7Entity)
    055    {
    056        this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.625F, 1.0F);
    057        super.addCollisionBoxesToList(par1World, par2, par3, par4, par5AxisAlignedBB, par6List, par7Entity);
    058        float f = 0.125F;
    059        this.setBlockBounds(0.0F, 0.0F, 0.0F, f, 1.0F, 1.0F);
    060        super.addCollisionBoxesToList(par1World, par2, par3, par4, par5AxisAlignedBB, par6List, par7Entity);
    061        this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, f);
    062        super.addCollisionBoxesToList(par1World, par2, par3, par4, par5AxisAlignedBB, par6List, par7Entity);
    063        this.setBlockBounds(1.0F - f, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
    064        super.addCollisionBoxesToList(par1World, par2, par3, par4, par5AxisAlignedBB, par6List, par7Entity);
    065        this.setBlockBounds(0.0F, 0.0F, 1.0F - f, 1.0F, 1.0F, 1.0F);
    066        super.addCollisionBoxesToList(par1World, par2, par3, par4, par5AxisAlignedBB, par6List, par7Entity);
    067        this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
    068    }
    069
    070    /**
    071     * Called when a block is placed using its ItemBlock. Args: World, X, Y, Z, side, hitX, hitY, hitZ, block metadata
    072     */
    073    public int onBlockPlaced(World par1World, int par2, int par3, int par4, int par5, float par6, float par7, float par8, int par9)
    074    {
    075        int j1 = Facing.oppositeSide[par5];
    076
    077        if (j1 == 1)
    078        {
    079            j1 = 0;
    080        }
    081
    082        return j1;
    083    }
    084
    085    /**
    086     * Returns a new instance of a block's tile entity class. Called on placing the block.
    087     */
    088    public TileEntity createNewTileEntity(World par1World)
    089    {
    090        return new TileEntityHopper();
    091    }
    092
    093    /**
    094     * Called when the block is placed in the world.
    095     */
    096    public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLiving par5EntityLiving, ItemStack par6ItemStack)
    097    {
    098        super.onBlockPlacedBy(par1World, par2, par3, par4, par5EntityLiving, par6ItemStack);
    099
    100        if (par6ItemStack.hasDisplayName())
    101        {
    102            TileEntityHopper tileentityhopper = getHopperTile(par1World, par2, par3, par4);
    103            tileentityhopper.func_96115_a(par6ItemStack.getDisplayName());
    104        }
    105    }
    106
    107    /**
    108     * Called whenever the block is added into the world. Args: world, x, y, z
    109     */
    110    public void onBlockAdded(World par1World, int par2, int par3, int par4)
    111    {
    112        super.onBlockAdded(par1World, par2, par3, par4);
    113        this.func_96471_k(par1World, par2, par3, par4);
    114    }
    115
    116    /**
    117     * Called upon block activation (right click on the block.)
    118     */
    119    public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
    120    {
    121        if (par1World.isRemote)
    122        {
    123            return true;
    124        }
    125        else
    126        {
    127            TileEntityHopper tileentityhopper = getHopperTile(par1World, par2, par3, par4);
    128
    129            if (tileentityhopper != null)
    130            {
    131                par5EntityPlayer.func_94064_a(tileentityhopper);
    132            }
    133
    134            return true;
    135        }
    136    }
    137
    138    /**
    139     * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
    140     * their own) Args: x, y, z, neighbor blockID
    141     */
    142    public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
    143    {
    144        this.func_96471_k(par1World, par2, par3, par4);
    145    }
    146
    147    private void func_96471_k(World par1World, int par2, int par3, int par4)
    148    {
    149        int l = par1World.getBlockMetadata(par2, par3, par4);
    150        int i1 = getDirectionFromMetadata(l);
    151        boolean flag = !par1World.isBlockIndirectlyGettingPowered(par2, par3, par4);
    152        boolean flag1 = func_94452_d(l);
    153
    154        if (flag != flag1)
    155        {
    156            par1World.setBlockMetadataWithNotify(par2, par3, par4, i1 | (flag ? 0 : 8), 4);
    157        }
    158    }
    159
    160    /**
    161     * ejects contained items into the world, and notifies neighbours of an update, as appropriate
    162     */
    163    public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6)
    164    {
    165        TileEntityHopper tileentityhopper = (TileEntityHopper)par1World.getBlockTileEntity(par2, par3, par4);
    166
    167        if (tileentityhopper != null)
    168        {
    169            for (int j1 = 0; j1 < tileentityhopper.getSizeInventory(); ++j1)
    170            {
    171                ItemStack itemstack = tileentityhopper.getStackInSlot(j1);
    172
    173                if (itemstack != null)
    174                {
    175                    float f = this.field_94457_a.nextFloat() * 0.8F + 0.1F;
    176                    float f1 = this.field_94457_a.nextFloat() * 0.8F + 0.1F;
    177                    float f2 = this.field_94457_a.nextFloat() * 0.8F + 0.1F;
    178
    179                    while (itemstack.stackSize > 0)
    180                    {
    181                        int k1 = this.field_94457_a.nextInt(21) + 10;
    182
    183                        if (k1 > itemstack.stackSize)
    184                        {
    185                            k1 = itemstack.stackSize;
    186                        }
    187
    188                        itemstack.stackSize -= k1;
    189                        EntityItem entityitem = new EntityItem(par1World, (double)((float)par2 + f), (double)((float)par3 + f1), (double)((float)par4 + f2), new ItemStack(itemstack.itemID, k1, itemstack.getItemDamage()));
    190
    191                        if (itemstack.hasTagCompound())
    192                        {
    193                            entityitem.getEntityItem().setTagCompound((NBTTagCompound)itemstack.getTagCompound().copy());
    194                        }
    195
    196                        float f3 = 0.05F;
    197                        entityitem.motionX = (double)((float)this.field_94457_a.nextGaussian() * f3);
    198                        entityitem.motionY = (double)((float)this.field_94457_a.nextGaussian() * f3 + 0.2F);
    199                        entityitem.motionZ = (double)((float)this.field_94457_a.nextGaussian() * f3);
    200                        par1World.spawnEntityInWorld(entityitem);
    201                    }
    202                }
    203            }
    204
    205            par1World.func_96440_m(par2, par3, par4, par5);
    206        }
    207
    208        super.breakBlock(par1World, par2, par3, par4, par5, par6);
    209    }
    210
    211    /**
    212     * The type of render function that is called for this block
    213     */
    214    public int getRenderType()
    215    {
    216        return 38;
    217    }
    218
    219    /**
    220     * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
    221     */
    222    public boolean renderAsNormalBlock()
    223    {
    224        return false;
    225    }
    226
    227    /**
    228     * Is this block (a) opaque and (b) a full 1m cube?  This determines whether or not to render the shared face of two
    229     * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
    230     */
    231    public boolean isOpaqueCube()
    232    {
    233        return false;
    234    }
    235
    236    public static int getDirectionFromMetadata(int par0)
    237    {
    238        return par0 & 7;
    239    }
    240
    241    @SideOnly(Side.CLIENT)
    242
    243    /**
    244     * Returns true if the given side of this block type should be rendered, if the adjacent block is at the given
    245     * coordinates.  Args: blockAccess, x, y, z, side
    246     */
    247    public boolean shouldSideBeRendered(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
    248    {
    249        return true;
    250    }
    251
    252    @SideOnly(Side.CLIENT)
    253
    254    /**
    255     * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata
    256     */
    257    public Icon getIcon(int par1, int par2)
    258    {
    259        return par1 == 1 ? this.hopperTopIcon : this.hopperIcon;
    260    }
    261
    262    public static boolean func_94452_d(int par0)
    263    {
    264        return (par0 & 8) != 8;
    265    }
    266
    267    /**
    268     * If this returns true, then comparators facing away from this block will use the value from
    269     * getComparatorInputOverride instead of the actual redstone signal strength.
    270     */
    271    public boolean hasComparatorInputOverride()
    272    {
    273        return true;
    274    }
    275
    276    /**
    277     * If hasComparatorInputOverride returns true, the return value from this is used instead of the redstone signal
    278     * strength when this block inputs to a comparator.
    279     */
    280    public int getComparatorInputOverride(World par1World, int par2, int par3, int par4, int par5)
    281    {
    282        return Container.func_94526_b(getHopperTile(par1World, par2, par3, par4));
    283    }
    284
    285    @SideOnly(Side.CLIENT)
    286
    287    /**
    288     * When this method is called, your block should register all the icons it needs with the given IconRegister. This
    289     * is the only chance you get to register icons.
    290     */
    291    public void registerIcons(IconRegister par1IconRegister)
    292    {
    293        this.hopperIcon = par1IconRegister.registerIcon("hopper");
    294        this.hopperTopIcon = par1IconRegister.registerIcon("hopper_top");
    295        this.hopperInsideIcon = par1IconRegister.registerIcon("hopper_inside");
    296    }
    297
    298    @SideOnly(Side.CLIENT)
    299    public static Icon getHopperIcon(String par0Str)
    300    {
    301        return par0Str == "hopper" ? Block.hopperBlock.hopperIcon : (par0Str == "hopper_inside" ? Block.hopperBlock.hopperInsideIcon : null);
    302    }
    303
    304    @SideOnly(Side.CLIENT)
    305
    306    /**
    307     * Gets the icon name of the ItemBlock corresponding to this block. Used by hoppers.
    308     */
    309    public String getItemIconName()
    310    {
    311        return "hopper";
    312    }
    313
    314    public static TileEntityHopper getHopperTile(IBlockAccess par0IBlockAccess, int par1, int par2, int par3)
    315    {
    316        return (TileEntityHopper)par0IBlockAccess.getBlockTileEntity(par1, par2, par3);
    317    }
    318}