    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 field_94455_b;
    030    @SideOnly(Side.CLIENT)
    031    private Icon field_94456_c;
    032    @SideOnly(Side.CLIENT)
    033    private Icon field_94454_cO;
    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.faceToSide[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 = func_98213_d(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 = func_98213_d(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 = func_94451_c(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
    206        super.breakBlock(par1World, par2, par3, par4, par5, par6);
    207    }
    208
    209    /**
    210     * The type of render function that is called for this block
    211     */
    212    public int getRenderType()
    213    {
    214        return 38;
    215    }
    216
    217    /**
    218     * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
    219     */
    220    public boolean renderAsNormalBlock()
    221    {
    222        return false;
    223    }
    224
    225    /**
    226     * Is this block (a) opaque and (b) a full 1m cube?  This determines whether or not to render the shared face of two
    227     * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
    228     */
    229    public boolean isOpaqueCube()
    230    {
    231        return false;
    232    }
    233
    234    public static int func_94451_c(int par0)
    235    {
    236        return par0 & 7;
    237    }
    238
    239    @SideOnly(Side.CLIENT)
    240
    241    /**
    242     * Returns true if the given side of this block type should be rendered, if the adjacent block is at the given
    243     * coordinates.  Args: blockAccess, x, y, z, side
    244     */
    245    public boolean shouldSideBeRendered(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
    246    {
    247        return true;
    248    }
    249
    250    @SideOnly(Side.CLIENT)
    251
    252    /**
    253     * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata
    254     */
    255    public Icon getBlockTextureFromSideAndMetadata(int par1, int par2)
    256    {
    257        return par1 == 1 ? this.field_94456_c : this.field_94455_b;
    258    }
    259
    260    public static boolean func_94452_d(int par0)
    261    {
    262        return (par0 & 8) != 8;
    263    }
    264
    265    public boolean func_96468_q_()
    266    {
    267        return true;
    268    }
    269
    270    public int func_94328_b_(World par1World, int par2, int par3, int par4, int par5)
    271    {
    272        return Container.func_94526_b(func_98213_d(par1World, par2, par3, par4));
    273    }
    274
    275    @SideOnly(Side.CLIENT)
    276    public void func_94332_a(IconRegister par1IconRegister)
    277    {
    278        this.field_94455_b = par1IconRegister.func_94245_a("hopper");
    279        this.field_94456_c = par1IconRegister.func_94245_a("hopper_top");
    280        this.field_94454_cO = par1IconRegister.func_94245_a("hopper_inside");
    281    }
    282
    283    @SideOnly(Side.CLIENT)
    284    public static Icon func_94453_b(String par0Str)
    285    {
    286        return par0Str == "hopper" ? Block.field_94340_cs.field_94455_b : (par0Str == "hopper_inside" ? Block.field_94340_cs.field_94454_cO : null);
    287    }
    288
    289    @SideOnly(Side.CLIENT)
    290    public String func_94327_t_()
    291    {
    292        return "hopper";
    293    }
    294
    295    public static TileEntityHopper func_98213_d(IBlockAccess par0IBlockAccess, int par1, int par2, int par3)
    296    {
    297        return (TileEntityHopper)par0IBlockAccess.getBlockTileEntity(par1, par2, par3);
    298    }
    299}