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 }