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}