    001    package net.minecraftforge.oredict;
    002
    003    import java.util.ArrayList;
    004    import java.util.HashMap;
    005    import java.util.Iterator;
    006    import java.util.List;
    007    import java.util.Map;
    008    import java.util.Map.Entry;
    009
    010    import net.minecraft.block.Block;
    011    import net.minecraft.item.Item;
    012    import net.minecraft.item.ItemStack;
    013    import net.minecraft.item.crafting.CraftingManager;
    014    import net.minecraft.item.crafting.IRecipe;
    015    import net.minecraft.item.crafting.ShapedRecipes;
    016    import net.minecraft.item.crafting.ShapelessRecipes;
    017    import net.minecraftforge.common.MinecraftForge;
    018    import net.minecraftforge.event.Event;
    019
    020    public class OreDictionary
    021    {
    022        private static boolean hasInit = false;
    023        private static int maxID = 0;
    024        private static HashMap<String, Integer> oreIDs = new HashMap<String, Integer>();
    025        private static HashMap<Integer, ArrayList<ItemStack>> oreStacks = new HashMap<Integer, ArrayList<ItemStack>>();
    026
    027        static {
    028            initVanillaEntries();
    029        }
    030
    031        public static void initVanillaEntries()
    032        {
    033            if (!hasInit)
    034            {
    035                registerOre("logWood",     new ItemStack(Block.wood, 1, -1));
    036                registerOre("plankWood",   new ItemStack(Block.planks, 1, -1));
    037                registerOre("slabWood",    new ItemStack(Block.woodSingleSlab, 1, -1));
    038                registerOre("stairWood",   Block.stairCompactPlanks);
    039                registerOre("stairWood",   Block.stairsWoodBirch);
    040                registerOre("stairWood",   Block.stairsWoodJungle);
    041                registerOre("stairWood",   Block.stairsWoodSpruce);
    042                registerOre("stickWood",   Item.stick);
    043                registerOre("treeSapling", new ItemStack(Block.sapling, 1, -1));
    044                registerOre("treeLeaves",  new ItemStack(Block.leaves, 1, -1));
    045            }
    046
    047            // Build our list of items to replace with ore tags
    048            Map<ItemStack, String> replacements = new HashMap<ItemStack, String>();
    049            replacements.put(new ItemStack(Block.planks, 1, -1), "plankWood");
    050            replacements.put(new ItemStack(Item.stick), "stickWood");
    051
    052            // Register dyes
    053            String[] dyes =
    054            {
    055                "dyeBlack",
    056                "dyeRed",
    057                "dyeGreen",
    058                "dyeBrown",
    059                "dyeBlue",
    060                "dyePurple",
    061                "dyeCyan",
    062                "dyeLightGray",
    063                "dyeGray",
    064                "dyePink",
    065                "dyeLime",
    066                "dyeYellow",
    067                "dyeLightBlue",
    068                "dyeMagenta",
    069                "dyeOrange",
    070                "dyeWhite"
    071            };
    072
    073            for(int i = 0; i < 16; i++)
    074            {
    075                ItemStack dye = new ItemStack(Item.dyePowder, 1, i);
    076                if (!hasInit)
    077                {
    078                    registerOre(dyes[i], dye);
    079                }
    080                replacements.put(dye, dyes[i]);
    081            }
    082            hasInit = true;
    083
    084            ItemStack[] replaceStacks = replacements.keySet().toArray(new ItemStack[0]);
    085
    086            // Ignore recipes for the following items
    087            ItemStack[] exclusions = new ItemStack[]
    088            {
    089                new ItemStack(Block.blockLapis),
    090                new ItemStack(Item.cookie),
    091            };
    092
    093            List recipes = CraftingManager.getInstance().getRecipeList();
    094            List<IRecipe> recipesToRemove = new ArrayList<IRecipe>();
    095            List<IRecipe> recipesToAdd = new ArrayList<IRecipe>();
    096
    097            // Search vanilla recipes for recipes to replace
    098            for(Object obj : recipes)
    099            {
    100                if(obj instanceof ShapedRecipes)
    101                {
    102                    ShapedRecipes recipe = (ShapedRecipes)obj;
    103                    ItemStack output = recipe.getRecipeOutput();
    104                    if (output != null && containsMatch(false, exclusions, output))
    105                    {
    106                        continue;
    107                    }
    108
    109                    if(containsMatch(true, recipe.recipeItems, replaceStacks))
    110                    {
    111                        recipesToRemove.add(recipe);
    112                        recipesToAdd.add(new ShapedOreRecipe(recipe, replacements));
    113                    }
    114                }
    115                else if(obj instanceof ShapelessRecipes)
    116                {
    117                    ShapelessRecipes recipe = (ShapelessRecipes)obj;
    118                    ItemStack output = recipe.getRecipeOutput();
    119                    if (output != null && containsMatch(false, exclusions, output))
    120                    {
    121                        continue;
    122                    }
    123
    124                    if(containsMatch(true, (ItemStack[])recipe.recipeItems.toArray(new ItemStack[0]), replaceStacks))
    125                    {
    126                        recipesToRemove.add((IRecipe)obj);
    127                        IRecipe newRecipe = new ShapelessOreRecipe(recipe, replacements);
    128                        recipesToAdd.add(newRecipe);
    129                    }
    130                }
    131            }
    132
    133            recipes.removeAll(recipesToRemove);
    134            recipes.addAll(recipesToAdd);
    135            if (recipesToRemove.size() > 0)
    136            {
    137                System.out.println("Replaced " + recipesToRemove.size() + " ore recipies");
    138            }
    139        }
    140
    141        /**
    142         * Gets the integer ID for the specified ore name.
    143         * If the name does not have a ID it assigns it a new one.
    144         *
    145         * @param name The unique name for this ore 'oreIron', 'ingotIron', etc..
    146         * @return A number representing the ID for this ore type
    147         */
    148        public static int getOreID(String name)
    149        {
    150            Integer val = oreIDs.get(name);
    151            if (val == null)
    152            {
    153                val = maxID++;
    154                oreIDs.put(name, val);
    155                oreStacks.put(val, new ArrayList<ItemStack>());
    156            }
    157            return val;
    158        }
    159
    160        /**
    161         * Reverse of getOreID, will not create new entries.
    162         *
    163         * @param id The ID to translate to a string
    164         * @return The String name, or "Unknown" if not found.
    165         */
    166        public static String getOreName(int id)
    167        {
    168            for (Map.Entry<String, Integer> entry : oreIDs.entrySet())
    169            {
    170                if (id == entry.getValue())
    171                {
    172                    return entry.getKey();
    173                }
    174            }
    175            return "Unknown";
    176        }
    177
    178        /**
    179         * Gets the integer ID for the specified item stack.
    180         * If the item stack is not linked to any ore, this will return -1 and no new entry will be created.
    181         *
    182         * @param itemStack The item stack of the ore.
    183         * @return A number representing the ID for this ore type, or -1 if couldn't find it.
    184         */
    185        public static int getOreID(ItemStack itemStack)
    186        {
    187            if( itemStack == null )
    188                return -1;
    189
    190            for(int oreID : oreStacks.keySet())
    191            {
    192                for(ItemStack target : oreStacks.get(oreID))
    193                {
    194                    if(itemStack.itemID == target.itemID && (target.getItemDamage() == -1 || itemStack.getItemDamage() == target.getItemDamage()))
    195                        return oreID;
    196                }
    197            }
    198            return -1; // didn't find it.
    199        }
    200
    201        /**
    202         * Retrieves the ArrayList of items that are registered to this ore type.
    203         * Creates the list as empty if it did not exist.
    204         *
    205         * @param name The ore name, directly calls getOreID
    206         * @return An arrayList containing ItemStacks registered for this ore
    207         */
    208        public static ArrayList<ItemStack> getOres(String name)
    209        {
    210            return getOres(getOreID(name));
    211        }
    212
    213        /**
    214         * Retrieves a list of all unique ore names that are already registered.
    215         *
    216         * @return All unique ore names that are currently registered.
    217         */
    218        public static String[] getOreNames()
    219        {
    220            return oreIDs.keySet().toArray(new String[0]);
    221        }
    222
    223        /**
    224         * Retrieves the ArrayList of items that are registered to this ore type.
    225         * Creates the list as empty if it did not exist.
    226         *
    227         * @param id The ore ID, see getOreID
    228         * @return An arrayList containing ItemStacks registered for this ore
    229         */
    230        public static ArrayList<ItemStack> getOres(Integer id)
    231        {
    232            ArrayList<ItemStack> val = oreStacks.get(id);
    233            if (val == null)
    234            {
    235                val = new ArrayList<ItemStack>();
    236                oreStacks.put(id, val);
    237            }
    238            return val;
    239        }
    240
    241        private static boolean containsMatch(boolean strict, ItemStack[] inputs, ItemStack... targets)
    242        {
    243            for (ItemStack input : inputs)
    244            {
    245                for (ItemStack target : targets)
    246                {
    247                    if (itemMatches(target, input, strict))
    248                    {
    249                        return true;
    250                    }
    251                }
    252            }
    253            return false;
    254        }
    255
    256        public static boolean itemMatches(ItemStack target, ItemStack input, boolean strict)
    257        {
    258            if (input == null && target != null || input != null && target == null)
    259            {
    260                return false;
    261            }
    262            return (target.itemID == input.itemID && ((target.getItemDamage() == -1 && !strict) || target.getItemDamage() == input.getItemDamage()));
    263        }
    264
    265        //Convenience functions that make for cleaner code mod side. They all drill down to registerOre(String, int, ItemStack)
    266        public static void registerOre(String name, Item      ore){ registerOre(name, new ItemStack(ore));  }
    267        public static void registerOre(String name, Block     ore){ registerOre(name, new ItemStack(ore));  }
    268        public static void registerOre(String name, ItemStack ore){ registerOre(name, getOreID(name), ore); }
    269        public static void registerOre(int    id,   Item      ore){ registerOre(id,   new ItemStack(ore));  }
    270        public static void registerOre(int    id,   Block     ore){ registerOre(id,   new ItemStack(ore));  }
    271        public static void registerOre(int    id,   ItemStack ore){ registerOre(getOreName(id), id, ore);   }
    272
    273        /**
    274         * Registers a ore item into the dictionary.
    275         * Raises the registerOre function in all registered handlers.
    276         *
    277         * @param name The name of the ore
    278         * @param id The ID of the ore
    279         * @param ore The ore's ItemStack
    280         */
    281        private static void registerOre(String name, int id, ItemStack ore)
    282        {
    283            ArrayList<ItemStack> ores = getOres(id);
    284            ore = ore.copy();
    285            ores.add(ore);
    286            MinecraftForge.EVENT_BUS.post(new OreRegisterEvent(name, ore));
    287        }
    288
    289        public static class OreRegisterEvent extends Event
    290        {
    291            public final String Name;
    292            public final ItemStack Ore;
    293
    294            public OreRegisterEvent(String name, ItemStack ore)
    295            {
    296                this.Name = name;
    297                this.Ore = ore;
    298            }
    299        }
    300    }