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