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    }