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 = 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 = 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 = 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 = 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 = toolClasses.get(stack.getItem());
157 return toolClass != null && toolEffectiveness.contains(Arrays.asList(block, metadata, toolClass.get(0)));
158 }
159
160 static void initTools()
161 {
162 if (toolInit)
163 {
164 return;
165 }
166 toolInit = true;
167
168 MinecraftForge.setToolClass(Item.pickaxeWood, "pickaxe", 0);
169 MinecraftForge.setToolClass(Item.pickaxeStone, "pickaxe", 1);
170 MinecraftForge.setToolClass(Item.pickaxeSteel, "pickaxe", 2);
171 MinecraftForge.setToolClass(Item.pickaxeGold, "pickaxe", 0);
172 MinecraftForge.setToolClass(Item.pickaxeDiamond, "pickaxe", 3);
173
174 MinecraftForge.setToolClass(Item.axeWood, "axe", 0);
175 MinecraftForge.setToolClass(Item.axeStone, "axe", 1);
176 MinecraftForge.setToolClass(Item.axeSteel, "axe", 2);
177 MinecraftForge.setToolClass(Item.axeGold, "axe", 0);
178 MinecraftForge.setToolClass(Item.axeDiamond, "axe", 3);
179
180 MinecraftForge.setToolClass(Item.shovelWood, "shovel", 0);
181 MinecraftForge.setToolClass(Item.shovelStone, "shovel", 1);
182 MinecraftForge.setToolClass(Item.shovelSteel, "shovel", 2);
183 MinecraftForge.setToolClass(Item.shovelGold, "shovel", 0);
184 MinecraftForge.setToolClass(Item.shovelDiamond, "shovel", 3);
185
186 for (Block block : ItemPickaxe.blocksEffectiveAgainst)
187 {
188 MinecraftForge.setBlockHarvestLevel(block, "pickaxe", 0);
189 }
190
191 for (Block block : ItemSpade.blocksEffectiveAgainst)
192 {
193 MinecraftForge.setBlockHarvestLevel(block, "shovel", 0);
194 }
195
196 for (Block block : ItemAxe.blocksEffectiveAgainst)
197 {
198 MinecraftForge.setBlockHarvestLevel(block, "axe", 0);
199 }
200
201 MinecraftForge.setBlockHarvestLevel(Block.obsidian, "pickaxe", 3);
202 MinecraftForge.setBlockHarvestLevel(Block.oreEmerald, "pickaxe", 2);
203 MinecraftForge.setBlockHarvestLevel(Block.oreDiamond, "pickaxe", 2);
204 MinecraftForge.setBlockHarvestLevel(Block.blockDiamond, "pickaxe", 2);
205 MinecraftForge.setBlockHarvestLevel(Block.oreGold, "pickaxe", 2);
206 MinecraftForge.setBlockHarvestLevel(Block.blockGold, "pickaxe", 2);
207 MinecraftForge.setBlockHarvestLevel(Block.oreIron, "pickaxe", 1);
208 MinecraftForge.setBlockHarvestLevel(Block.blockSteel, "pickaxe", 1);
209 MinecraftForge.setBlockHarvestLevel(Block.oreLapis, "pickaxe", 1);
210 MinecraftForge.setBlockHarvestLevel(Block.blockLapis, "pickaxe", 1);
211 MinecraftForge.setBlockHarvestLevel(Block.oreRedstone, "pickaxe", 2);
212 MinecraftForge.setBlockHarvestLevel(Block.oreRedstoneGlowing, "pickaxe", 2);
213 MinecraftForge.removeBlockEffectiveness(Block.oreRedstone, "pickaxe");
214 MinecraftForge.removeBlockEffectiveness(Block.obsidian, "pickaxe");
215 MinecraftForge.removeBlockEffectiveness(Block.oreRedstoneGlowing, "pickaxe");
216 }
217
218 public static String getTexture(String _default, Object obj)
219 {
220 if (obj instanceof Item)
221 {
222 return ((Item)obj).getTextureFile();
223 }
224 else if (obj instanceof Block)
225 {
226 return ((Block)obj).getTextureFile();
227 }
228 else
229 {
230 return _default;
231 }
232 }
233
234 public static int getTotalArmorValue(EntityPlayer player)
235 {
236 int ret = 0;
237 for (int x = 0; x < player.inventory.armorInventory.length; x++)
238 {
239 ItemStack stack = player.inventory.armorInventory[x];
240 if (stack != null && stack.getItem() instanceof ISpecialArmor)
241 {
242 ret += ((ISpecialArmor)stack.getItem()).getArmorDisplay(player, stack, x);
243 }
244 else if (stack != null && stack.getItem() instanceof ItemArmor)
245 {
246 ret += ((ItemArmor)stack.getItem()).damageReduceAmount;
247 }
248 }
249 return ret;
250 }
251
252 static
253 {
254 grassList.add(new GrassEntry(Block.plantYellow, 0, 20));
255 grassList.add(new GrassEntry(Block.plantRed, 0, 10));
256 seedList.add(new SeedEntry(new ItemStack(Item.seeds), 10));
257 initTools();
258 }
259
260 /**
261 * Called when a player uses 'pick block', calls new Entity and Block hooks.
262 */
263 public static boolean onPickBlock(MovingObjectPosition target, EntityPlayer player, World world)
264 {
265 ItemStack result = null;
266 boolean isCreative = player.capabilities.isCreativeMode;
267
268 if (target.typeOfHit == EnumMovingObjectType.TILE)
269 {
270 int x = target.blockX;
271 int y = target.blockY;
272 int z = target.blockZ;
273 Block var8 = Block.blocksList[world.getBlockId(x, y, z)];
274
275 if (var8 == null)
276 {
277 return false;
278 }
279
280 result = var8.getPickBlock(target, world, x, y, z);
281 }
282 else
283 {
284 if (target.typeOfHit != EnumMovingObjectType.ENTITY || target.entityHit == null || !isCreative)
285 {
286 return false;
287 }
288
289 result = target.entityHit.getPickedResult(target);
290 }
291
292 if (result == null)
293 {
294 return false;
295 }
296
297 for (int x = 0; x < 9; x++)
298 {
299 ItemStack stack = player.inventory.getStackInSlot(x);
300 if (stack != null && stack.isItemEqual(result) && ItemStack.areItemStackTagsEqual(stack, result))
301 {
302 player.inventory.currentItem = x;
303 return true;
304 }
305 }
306
307 if (!isCreative)
308 {
309 return false;
310 }
311
312 int slot = player.inventory.getFirstEmptyStack();
313 if (slot < 0 || slot >= 9)
314 {
315 slot = player.inventory.currentItem;
316 }
317
318 player.inventory.setInventorySlotContents(slot, result);
319 player.inventory.currentItem = slot;
320 return true;
321 }
322
323 //Optifine Helper Functions u.u, these are here specifically for Optifine
324 //Note: When using Optfine, these methods are invoked using reflection, which
325 //incurs a major performance penalty.
326 public static void onLivingSetAttackTarget(EntityLiving entity, EntityLiving target)
327 {
328 MinecraftForge.EVENT_BUS.post(new LivingSetAttackTargetEvent(entity, target));
329 }
330
331 public static boolean onLivingUpdate(EntityLiving entity)
332 {
333 return MinecraftForge.EVENT_BUS.post(new LivingUpdateEvent(entity));
334 }
335
336 public static boolean onLivingAttack(EntityLiving entity, DamageSource src, int amount)
337 {
338 return MinecraftForge.EVENT_BUS.post(new LivingAttackEvent(entity, src, amount));
339 }
340
341 public static int onLivingHurt(EntityLiving entity, DamageSource src, int amount)
342 {
343 LivingHurtEvent event = new LivingHurtEvent(entity, src, amount);
344 return (MinecraftForge.EVENT_BUS.post(event) ? 0 : event.ammount);
345 }
346
347 public static boolean onLivingDeath(EntityLiving entity, DamageSource src)
348 {
349 return MinecraftForge.EVENT_BUS.post(new LivingDeathEvent(entity, src));
350 }
351
352 public static boolean onLivingDrops(EntityLiving entity, DamageSource source, ArrayList<EntityItem> drops, int lootingLevel, boolean recentlyHit, int specialDropValue)
353 {
354 return MinecraftForge.EVENT_BUS.post(new LivingDropsEvent(entity, source, drops, lootingLevel, recentlyHit, specialDropValue));
355 }
356
357 public static float onLivingFall(EntityLiving entity, float distance)
358 {
359 LivingFallEvent event = new LivingFallEvent(entity, distance);
360 return (MinecraftForge.EVENT_BUS.post(event) ? 0.0f : event.distance);
361 }
362
363 public static boolean isLivingOnLadder(Block block, World world, int x, int y, int z)
364 {
365 return block != null && block.isLadder(world, x, y, z);
366 }
367
368 public static void onLivingJump(EntityLiving entity)
369 {
370 MinecraftForge.EVENT_BUS.post(new LivingJumpEvent(entity));
371 }
372
373 public static EntityItem onPlayerTossEvent(EntityPlayer player, ItemStack item)
374 {
375 player.captureDrops = true;
376 EntityItem ret = player.dropPlayerItemWithRandomChoice(item, false);
377 player.capturedDrops.clear();
378 player.captureDrops = false;
379
380 ItemTossEvent event = new ItemTossEvent(ret, player);
381 if (MinecraftForge.EVENT_BUS.post(event))
382 {
383 return null;
384 }
385
386 player.joinEntityItemWithWorld(event.entityItem);
387 return event.entityItem;
388 }
389 }