    001package net.minecraftforge.common;
    002
    003import java.util.*;
    004import java.util.Map.Entry;
    005
    006import com.google.common.collect.ArrayListMultimap;
    007import com.google.common.collect.ListMultimap;
    008
    009import cpw.mods.fml.common.FMLLog;
    010import cpw.mods.fml.common.Loader;
    011
    012import net.minecraft.block.Block;
    013import net.minecraft.entity.EntityLiving;
    014import net.minecraft.entity.item.EntityItem;
    015import net.minecraft.entity.player.EntityPlayer;
    016import net.minecraft.item.Item;
    017import net.minecraft.item.ItemArmor;
    018import net.minecraft.item.ItemAxe;
    019import net.minecraft.item.ItemPickaxe;
    020import net.minecraft.item.ItemSpade;
    021import net.minecraft.item.ItemStack;
    022import net.minecraft.util.DamageSource;
    023import net.minecraft.util.EnumMovingObjectType;
    024import net.minecraft.util.MovingObjectPosition;
    025import net.minecraft.util.WeightedRandom;
    026import net.minecraft.util.WeightedRandomItem;
    027import net.minecraft.world.World;
    028import net.minecraftforge.event.ForgeEventFactory;
    029import net.minecraftforge.event.entity.item.ItemTossEvent;
    030import net.minecraftforge.event.entity.living.*;
    031import net.minecraftforge.event.entity.living.LivingEvent.*;
    032
    033public 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}