001 package net.minecraftforge.common; 002 003 import java.util.*; 004 import java.util.Map.Entry; 005 006 import com.google.common.collect.ArrayListMultimap; 007 import com.google.common.collect.ListMultimap; 008 009 import cpw.mods.fml.common.FMLLog; 010 import cpw.mods.fml.common.Loader; 011 012 import net.minecraft.block.Block; 013 import net.minecraft.entity.EntityLiving; 014 import net.minecraft.entity.item.EntityItem; 015 import net.minecraft.entity.player.EntityPlayer; 016 import net.minecraft.item.Item; 017 import net.minecraft.item.ItemArmor; 018 import net.minecraft.item.ItemAxe; 019 import net.minecraft.item.ItemPickaxe; 020 import net.minecraft.item.ItemSpade; 021 import net.minecraft.item.ItemStack; 022 import net.minecraft.util.DamageSource; 023 import net.minecraft.util.EnumMovingObjectType; 024 import net.minecraft.util.MovingObjectPosition; 025 import net.minecraft.util.WeightedRandom; 026 import net.minecraft.util.WeightedRandomItem; 027 import net.minecraft.world.World; 028 import net.minecraftforge.event.ForgeEventFactory; 029 import net.minecraftforge.event.entity.item.ItemTossEvent; 030 import net.minecraftforge.event.entity.living.*; 031 import net.minecraftforge.event.entity.living.LivingEvent.*; 032 033 public class ForgeHooks 034 { 035 static class GrassEntry extends WeightedRandomItem 036 { 037 public final Block block; 038 public final int metadata; 039 public GrassEntry(Block block, int meta, int weight) 040 { 041 super(weight); 042 this.block = block; 043 this.metadata = meta; 044 } 045 } 046 047 static class SeedEntry extends WeightedRandomItem 048 { 049 public final ItemStack seed; 050 public SeedEntry(ItemStack seed, int weight) 051 { 052 super(weight); 053 this.seed = seed; 054 } 055 } 056 static final List<GrassEntry> grassList = new ArrayList<GrassEntry>(); 057 static final List<SeedEntry> seedList = new ArrayList<SeedEntry>(); 058 059 public static void plantGrass(World world, int x, int y, int z) 060 { 061 GrassEntry grass = (GrassEntry)WeightedRandom.getRandomItem(world.rand, grassList); 062 if (grass == null || grass.block == null || !grass.block.canBlockStay(world, x, y, z)) 063 { 064 return; 065 } 066 world.setBlockAndMetadataWithNotify(x, y, z, grass.block.blockID, grass.metadata); 067 } 068 069 public static ItemStack getGrassSeed(World world) 070 { 071 SeedEntry entry = (SeedEntry)WeightedRandom.getRandomItem(world.rand, seedList); 072 if (entry == null || entry.seed == null) 073 { 074 return null; 075 } 076 return entry.seed.copy(); 077 } 078 079 private static boolean toolInit = false; 080 static HashMap<Item, List> toolClasses = new HashMap<Item, List>(); 081 static HashMap<List, Integer> toolHarvestLevels = new HashMap<List, Integer>(); 082 static HashSet<List> toolEffectiveness = new HashSet<List>(); 083 084 public static boolean canHarvestBlock(Block block, EntityPlayer player, int metadata) 085 { 086 if (block.blockMaterial.isToolNotRequired()) 087 { 088 return true; 089 } 090 091 ItemStack stack = player.inventory.getCurrentItem(); 092 if (stack == null) 093 { 094 return player.canHarvestBlock(block); 095 } 096 097 List info = (List)toolClasses.get(stack.getItem()); 098 if (info == null) 099 { 100 return player.canHarvestBlock(block); 101 } 102 103 Object[] tmp = info.toArray(); 104 String toolClass = (String)tmp[0]; 105 int harvestLevel = (Integer)tmp[1]; 106 107 Integer blockHarvestLevel = (Integer)toolHarvestLevels.get(Arrays.asList(block, metadata, toolClass)); 108 if (blockHarvestLevel == null) 109 { 110 return player.canHarvestBlock(block); 111 } 112 113 if (blockHarvestLevel > harvestLevel) 114 { 115 return false; 116 } 117 return true; 118 } 119 120 public static boolean canToolHarvestBlock(Block block, int metadata, ItemStack stack) 121 { 122 if (stack == null) return false; 123 List info = (List)toolClasses.get(stack.getItem()); 124 if (info == null) return false; 125 126 Object[] tmp = info.toArray(); 127 String toolClass = (String)tmp[0]; 128 int harvestLevel = (Integer)tmp[1]; 129 130 Integer blockHarvestLevel = (Integer)toolHarvestLevels.get(Arrays.asList(block, metadata, toolClass)); 131 return !(blockHarvestLevel == null || blockHarvestLevel > harvestLevel); 132 } 133 134 public static float blockStrength(Block block, EntityPlayer player, World world, int x, int y, int z) 135 { 136 int metadata = world.getBlockMetadata(x, y, z); 137 float hardness = block.getBlockHardness(world, x, y, z); 138 if (hardness < 0.0F) 139 { 140 return 0.0F; 141 } 142 143 if (!canHarvestBlock(block, player, metadata)) 144 { 145 float speed = ForgeEventFactory.getBreakSpeed(player, block, metadata, 1.0f); 146 return (speed < 0 ? 0 : speed) / hardness / 100F; 147 } 148 else 149 { 150 return player.getCurrentPlayerStrVsBlock(block, metadata) / hardness / 30F; 151 } 152 } 153 154 public static boolean isToolEffective(ItemStack stack, Block block, int metadata) 155 { 156 List toolClass = (List)toolClasses.get(stack.getItem()); 157 if (toolClass == null) 158 { 159 return false; 160 } 161 return toolEffectiveness.contains(Arrays.asList(block, metadata, (String)toolClass.get(0))); 162 } 163 164 static void initTools() 165 { 166 if (toolInit) 167 { 168 return; 169 } 170 toolInit = true; 171 172 MinecraftForge.setToolClass(Item.pickaxeWood, "pickaxe", 0); 173 MinecraftForge.setToolClass(Item.pickaxeStone, "pickaxe", 1); 174 MinecraftForge.setToolClass(Item.pickaxeSteel, "pickaxe", 2); 175 MinecraftForge.setToolClass(Item.pickaxeGold, "pickaxe", 0); 176 MinecraftForge.setToolClass(Item.pickaxeDiamond, "pickaxe", 3); 177 178 MinecraftForge.setToolClass(Item.axeWood, "axe", 0); 179 MinecraftForge.setToolClass(Item.axeStone, "axe", 1); 180 MinecraftForge.setToolClass(Item.axeSteel, "axe", 2); 181 MinecraftForge.setToolClass(Item.axeGold, "axe", 0); 182 MinecraftForge.setToolClass(Item.axeDiamond, "axe", 3); 183 184 MinecraftForge.setToolClass(Item.shovelWood, "shovel", 0); 185 MinecraftForge.setToolClass(Item.shovelStone, "shovel", 1); 186 MinecraftForge.setToolClass(Item.shovelSteel, "shovel", 2); 187 MinecraftForge.setToolClass(Item.shovelGold, "shovel", 0); 188 MinecraftForge.setToolClass(Item.shovelDiamond, "shovel", 3); 189 190 for (Block block : ItemPickaxe.blocksEffectiveAgainst) 191 { 192 MinecraftForge.setBlockHarvestLevel(block, "pickaxe", 0); 193 } 194 195 for (Block block : ItemSpade.blocksEffectiveAgainst) 196 { 197 MinecraftForge.setBlockHarvestLevel(block, "shovel", 0); 198 } 199 200 for (Block block : ItemAxe.blocksEffectiveAgainst) 201 { 202 MinecraftForge.setBlockHarvestLevel(block, "axe", 0); 203 } 204 205 MinecraftForge.setBlockHarvestLevel(Block.obsidian, "pickaxe", 3); 206 MinecraftForge.setBlockHarvestLevel(Block.oreEmerald, "pickaxe", 2); 207 MinecraftForge.setBlockHarvestLevel(Block.oreDiamond, "pickaxe", 2); 208 MinecraftForge.setBlockHarvestLevel(Block.blockDiamond, "pickaxe", 2); 209 MinecraftForge.setBlockHarvestLevel(Block.oreGold, "pickaxe", 2); 210 MinecraftForge.setBlockHarvestLevel(Block.blockGold, "pickaxe", 2); 211 MinecraftForge.setBlockHarvestLevel(Block.oreIron, "pickaxe", 1); 212 MinecraftForge.setBlockHarvestLevel(Block.blockSteel, "pickaxe", 1); 213 MinecraftForge.setBlockHarvestLevel(Block.oreLapis, "pickaxe", 1); 214 MinecraftForge.setBlockHarvestLevel(Block.blockLapis, "pickaxe", 1); 215 MinecraftForge.setBlockHarvestLevel(Block.oreRedstone, "pickaxe", 2); 216 MinecraftForge.setBlockHarvestLevel(Block.oreRedstoneGlowing, "pickaxe", 2); 217 MinecraftForge.removeBlockEffectiveness(Block.oreRedstone, "pickaxe"); 218 MinecraftForge.removeBlockEffectiveness(Block.obsidian, "pickaxe"); 219 MinecraftForge.removeBlockEffectiveness(Block.oreRedstoneGlowing, "pickaxe"); 220 } 221 222 public static String getTexture(String _default, Object obj) 223 { 224 if (obj instanceof Item) 225 { 226 return ((Item)obj).getTextureFile(); 227 } 228 else if (obj instanceof Block) 229 { 230 return ((Block)obj).getTextureFile(); 231 } 232 else 233 { 234 return _default; 235 } 236 } 237 238 public static int getTotalArmorValue(EntityPlayer player) 239 { 240 int ret = 0; 241 for (int x = 0; x < player.inventory.armorInventory.length; x++) 242 { 243 ItemStack stack = player.inventory.armorInventory[x]; 244 if (stack != null && stack.getItem() instanceof ISpecialArmor) 245 { 246 ret += ((ISpecialArmor)stack.getItem()).getArmorDisplay(player, stack, x); 247 } 248 else if (stack != null && stack.getItem() instanceof ItemArmor) 249 { 250 ret += ((ItemArmor)stack.getItem()).damageReduceAmount; 251 } 252 } 253 return ret; 254 } 255 256 static 257 { 258 grassList.add(new GrassEntry(Block.plantYellow, 0, 20)); 259 grassList.add(new GrassEntry(Block.plantRed, 0, 10)); 260 seedList.add(new SeedEntry(new ItemStack(Item.seeds), 10)); 261 initTools(); 262 } 263 264 /** 265 * Called when a player uses 'pick block', calls new Entity and Block hooks. 266 */ 267 public static boolean onPickBlock(MovingObjectPosition target, EntityPlayer player, World world) 268 { 269 ItemStack result = null; 270 boolean isCreative = player.capabilities.isCreativeMode; 271 272 if (target.typeOfHit == EnumMovingObjectType.TILE) 273 { 274 int x = target.blockX; 275 int y = target.blockY; 276 int z = target.blockZ; 277 Block var8 = Block.blocksList[world.getBlockId(x, y, z)]; 278 279 if (var8 == null) 280 { 281 return false; 282 } 283 284 result = var8.getPickBlock(target, world, x, y, z); 285 } 286 else 287 { 288 if (target.typeOfHit != EnumMovingObjectType.ENTITY || target.entityHit == null || !isCreative) 289 { 290 return false; 291 } 292 293 result = target.entityHit.getPickedResult(target); 294 } 295 296 if (result == null) 297 { 298 return false; 299 } 300 301 for (int x = 0; x < 9; x++) 302 { 303 ItemStack stack = player.inventory.getStackInSlot(x); 304 if (stack != null && stack.isItemEqual(result) && ItemStack.areItemStackTagsEqual(stack, result)) 305 { 306 player.inventory.currentItem = x; 307 return true; 308 } 309 } 310 311 if (!isCreative) 312 { 313 return false; 314 } 315 316 int slot = player.inventory.getFirstEmptyStack(); 317 if (slot < 0 || slot >= 9) 318 { 319 slot = player.inventory.currentItem; 320 } 321 322 player.inventory.setInventorySlotContents(slot, result); 323 player.inventory.currentItem = slot; 324 return true; 325 } 326 327 //Optifine Helper Functions u.u, these are here specifically for Optifine 328 //Note: When using Optfine, these methods are invoked using reflection, which 329 //incurs a major performance penalty. 330 public static void onLivingSetAttackTarget(EntityLiving entity, EntityLiving target) 331 { 332 MinecraftForge.EVENT_BUS.post(new LivingSetAttackTargetEvent(entity, target)); 333 } 334 335 public static boolean onLivingUpdate(EntityLiving entity) 336 { 337 return MinecraftForge.EVENT_BUS.post(new LivingUpdateEvent(entity)); 338 } 339 340 public static boolean onLivingAttack(EntityLiving entity, DamageSource src, int amount) 341 { 342 return MinecraftForge.EVENT_BUS.post(new LivingAttackEvent(entity, src, amount)); 343 } 344 345 public static int onLivingHurt(EntityLiving entity, DamageSource src, int amount) 346 { 347 LivingHurtEvent event = new LivingHurtEvent(entity, src, amount); 348 return (MinecraftForge.EVENT_BUS.post(event) ? 0 : event.ammount); 349 } 350 351 public static boolean onLivingDeath(EntityLiving entity, DamageSource src) 352 { 353 return MinecraftForge.EVENT_BUS.post(new LivingDeathEvent(entity, src)); 354 } 355 356 public static boolean onLivingDrops(EntityLiving entity, DamageSource source, ArrayList<EntityItem> drops, int lootingLevel, boolean recentlyHit, int specialDropValue) 357 { 358 return MinecraftForge.EVENT_BUS.post(new LivingDropsEvent(entity, source, drops, lootingLevel, recentlyHit, specialDropValue)); 359 } 360 361 public static float onLivingFall(EntityLiving entity, float distance) 362 { 363 LivingFallEvent event = new LivingFallEvent(entity, distance); 364 return (MinecraftForge.EVENT_BUS.post(event) ? 0.0f : event.distance); 365 } 366 367 public static boolean isLivingOnLadder(Block block, World world, int x, int y, int z) 368 { 369 return block != null && block.isLadder(world, x, y, z); 370 } 371 372 public static void onLivingJump(EntityLiving entity) 373 { 374 MinecraftForge.EVENT_BUS.post(new LivingJumpEvent(entity)); 375 } 376 377 public static EntityItem onPlayerTossEvent(EntityPlayer player, ItemStack item) 378 { 379 player.captureDrops = true; 380 EntityItem ret = player.dropPlayerItemWithRandomChoice(item, false); 381 player.capturedDrops.clear(); 382 player.captureDrops = false; 383 384 ItemTossEvent event = new ItemTossEvent(ret, player); 385 if (MinecraftForge.EVENT_BUS.post(event)) 386 { 387 return null; 388 } 389 390 player.joinEntityItemWithWorld(event.entityItem); 391 return event.entityItem; 392 } 393 }