package net.minecraftforge.oredict; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import net.minecraft.block.Block; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.CraftingManager; import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.ShapedRecipes; import net.minecraft.item.crafting.ShapelessRecipes; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.Event; public class OreDictionary { private static boolean hasInit = false; private static int maxID = 0; private static HashMap oreIDs = new HashMap(); private static HashMap> oreStacks = new HashMap>(); /** * Minecraft changed from -1 to Short.MAX_VALUE in 1.5 release for the "block wildcard". Use this in case it * changes again. */ public static final int WILDCARD_VALUE = Short.MAX_VALUE; static { initVanillaEntries(); } public static void initVanillaEntries() { if (!hasInit) { registerOre("logWood", new ItemStack(Block.wood, 1, WILDCARD_VALUE)); registerOre("plankWood", new ItemStack(Block.planks, 1, WILDCARD_VALUE)); registerOre("slabWood", new ItemStack(Block.woodSingleSlab, 1, WILDCARD_VALUE)); registerOre("stairWood", Block.stairsWoodOak); registerOre("stairWood", Block.stairsWoodBirch); registerOre("stairWood", Block.stairsWoodJungle); registerOre("stairWood", Block.stairsWoodSpruce); registerOre("stickWood", Item.stick); registerOre("treeSapling", new ItemStack(Block.sapling, 1, WILDCARD_VALUE)); registerOre("treeLeaves", new ItemStack(Block.leaves, 1, WILDCARD_VALUE)); } // Build our list of items to replace with ore tags Map replacements = new HashMap(); replacements.put(new ItemStack(Block.planks, 1, WILDCARD_VALUE), "plankWood"); replacements.put(new ItemStack(Item.stick), "stickWood"); // Register dyes String[] dyes = { "dyeBlack", "dyeRed", "dyeGreen", "dyeBrown", "dyeBlue", "dyePurple", "dyeCyan", "dyeLightGray", "dyeGray", "dyePink", "dyeLime", "dyeYellow", "dyeLightBlue", "dyeMagenta", "dyeOrange", "dyeWhite" }; for(int i = 0; i < 16; i++) { ItemStack dye = new ItemStack(Item.dyePowder, 1, i); if (!hasInit) { registerOre(dyes[i], dye); } replacements.put(dye, dyes[i]); } hasInit = true; ItemStack[] replaceStacks = replacements.keySet().toArray(new ItemStack[replacements.keySet().size()]); // Ignore recipes for the following items ItemStack[] exclusions = new ItemStack[] { new ItemStack(Block.blockLapis), new ItemStack(Item.cookie), }; List recipes = CraftingManager.getInstance().getRecipeList(); List recipesToRemove = new ArrayList(); List recipesToAdd = new ArrayList(); // Search vanilla recipes for recipes to replace for(Object obj : recipes) { if(obj instanceof ShapedRecipes) { ShapedRecipes recipe = (ShapedRecipes)obj; ItemStack output = recipe.getRecipeOutput(); if (output != null && containsMatch(false, exclusions, output)) { continue; } if(containsMatch(true, recipe.recipeItems, replaceStacks)) { recipesToRemove.add(recipe); recipesToAdd.add(new ShapedOreRecipe(recipe, replacements)); } } else if(obj instanceof ShapelessRecipes) { ShapelessRecipes recipe = (ShapelessRecipes)obj; ItemStack output = recipe.getRecipeOutput(); if (output != null && containsMatch(false, exclusions, output)) { continue; } if(containsMatch(true, (ItemStack[])recipe.recipeItems.toArray(new ItemStack[recipe.recipeItems.size()]), replaceStacks)) { recipesToRemove.add((IRecipe)obj); IRecipe newRecipe = new ShapelessOreRecipe(recipe, replacements); recipesToAdd.add(newRecipe); } } } recipes.removeAll(recipesToRemove); recipes.addAll(recipesToAdd); if (recipesToRemove.size() > 0) { System.out.println("Replaced " + recipesToRemove.size() + " ore recipies"); } } /** * Gets the integer ID for the specified ore name. * If the name does not have a ID it assigns it a new one. * * @param name The unique name for this ore 'oreIron', 'ingotIron', etc.. * @return A number representing the ID for this ore type */ public static int getOreID(String name) { Integer val = oreIDs.get(name); if (val == null) { val = maxID++; oreIDs.put(name, val); oreStacks.put(val, new ArrayList()); } return val; } /** * Reverse of getOreID, will not create new entries. * * @param id The ID to translate to a string * @return The String name, or "Unknown" if not found. */ public static String getOreName(int id) { for (Map.Entry entry : oreIDs.entrySet()) { if (id == entry.getValue()) { return entry.getKey(); } } return "Unknown"; } /** * Gets the integer ID for the specified item stack. * If the item stack is not linked to any ore, this will return -1 and no new entry will be created. * * @param itemStack The item stack of the ore. * @return A number representing the ID for this ore type, or -1 if couldn't find it. */ public static int getOreID(ItemStack itemStack) { if (itemStack == null) { return -1; } for(Entry> ore : oreStacks.entrySet()) { for(ItemStack target : ore.getValue()) { if(itemStack.itemID == target.itemID && (target.getItemDamage() == WILDCARD_VALUE || itemStack.getItemDamage() == target.getItemDamage())) { return ore.getKey(); } } } return -1; // didn't find it. } /** * Retrieves the ArrayList of items that are registered to this ore type. * Creates the list as empty if it did not exist. * * @param name The ore name, directly calls getOreID * @return An arrayList containing ItemStacks registered for this ore */ public static ArrayList getOres(String name) { return getOres(getOreID(name)); } /** * Retrieves a list of all unique ore names that are already registered. * * @return All unique ore names that are currently registered. */ public static String[] getOreNames() { return oreIDs.keySet().toArray(new String[oreIDs.keySet().size()]); } /** * Retrieves the ArrayList of items that are registered to this ore type. * Creates the list as empty if it did not exist. * * @param id The ore ID, see getOreID * @return An arrayList containing ItemStacks registered for this ore */ public static ArrayList getOres(Integer id) { ArrayList val = oreStacks.get(id); if (val == null) { val = new ArrayList(); oreStacks.put(id, val); } return val; } private static boolean containsMatch(boolean strict, ItemStack[] inputs, ItemStack... targets) { for (ItemStack input : inputs) { for (ItemStack target : targets) { if (itemMatches(target, input, strict)) { return true; } } } return false; } public static boolean itemMatches(ItemStack target, ItemStack input, boolean strict) { if (input == null && target != null || input != null && target == null) { return false; } return (target.itemID == input.itemID && ((target.getItemDamage() == WILDCARD_VALUE && !strict) || target.getItemDamage() == input.getItemDamage())); } //Convenience functions that make for cleaner code mod side. They all drill down to registerOre(String, int, ItemStack) public static void registerOre(String name, Item ore){ registerOre(name, new ItemStack(ore)); } public static void registerOre(String name, Block ore){ registerOre(name, new ItemStack(ore)); } public static void registerOre(String name, ItemStack ore){ registerOre(name, getOreID(name), ore); } public static void registerOre(int id, Item ore){ registerOre(id, new ItemStack(ore)); } public static void registerOre(int id, Block ore){ registerOre(id, new ItemStack(ore)); } public static void registerOre(int id, ItemStack ore){ registerOre(getOreName(id), id, ore); } /** * Registers a ore item into the dictionary. * Raises the registerOre function in all registered handlers. * * @param name The name of the ore * @param id The ID of the ore * @param ore The ore's ItemStack */ private static void registerOre(String name, int id, ItemStack ore) { ArrayList ores = getOres(id); ore = ore.copy(); ores.add(ore); MinecraftForge.EVENT_BUS.post(new OreRegisterEvent(name, ore)); } public static class OreRegisterEvent extends Event { public final String Name; public final ItemStack Ore; public OreRegisterEvent(String name, ItemStack ore) { this.Name = name; this.Ore = ore; } } }