001package net.minecraftforge.oredict; 002 003import java.util.ArrayList; 004import java.util.HashMap; 005import java.util.Iterator; 006import java.util.List; 007import java.util.Map; 008import java.util.Map.Entry; 009 010import net.minecraft.block.Block; 011import net.minecraft.item.Item; 012import net.minecraft.item.ItemStack; 013import net.minecraft.item.crafting.CraftingManager; 014import net.minecraft.item.crafting.IRecipe; 015import net.minecraft.item.crafting.ShapedRecipes; 016import net.minecraft.item.crafting.ShapelessRecipes; 017import net.minecraftforge.common.MinecraftForge; 018import net.minecraftforge.event.Event; 019 020public 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[replacements.keySet().size()]); 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[recipe.recipeItems.size()]), 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 { 189 return -1; 190 } 191 192 for(Entry<Integer, ArrayList<ItemStack>> ore : oreStacks.entrySet()) 193 { 194 for(ItemStack target : ore.getValue()) 195 { 196 if(itemStack.itemID == target.itemID && (target.getItemDamage() == -1 || itemStack.getItemDamage() == target.getItemDamage())) 197 { 198 return ore.getKey(); 199 } 200 } 201 } 202 return -1; // didn't find it. 203 } 204 205 /** 206 * Retrieves the ArrayList of items that are registered to this ore type. 207 * Creates the list as empty if it did not exist. 208 * 209 * @param name The ore name, directly calls getOreID 210 * @return An arrayList containing ItemStacks registered for this ore 211 */ 212 public static ArrayList<ItemStack> getOres(String name) 213 { 214 return getOres(getOreID(name)); 215 } 216 217 /** 218 * Retrieves a list of all unique ore names that are already registered. 219 * 220 * @return All unique ore names that are currently registered. 221 */ 222 public static String[] getOreNames() 223 { 224 return oreIDs.keySet().toArray(new String[oreIDs.keySet().size()]); 225 } 226 227 /** 228 * Retrieves the ArrayList of items that are registered to this ore type. 229 * Creates the list as empty if it did not exist. 230 * 231 * @param id The ore ID, see getOreID 232 * @return An arrayList containing ItemStacks registered for this ore 233 */ 234 public static ArrayList<ItemStack> getOres(Integer id) 235 { 236 ArrayList<ItemStack> val = oreStacks.get(id); 237 if (val == null) 238 { 239 val = new ArrayList<ItemStack>(); 240 oreStacks.put(id, val); 241 } 242 return val; 243 } 244 245 private static boolean containsMatch(boolean strict, ItemStack[] inputs, ItemStack... targets) 246 { 247 for (ItemStack input : inputs) 248 { 249 for (ItemStack target : targets) 250 { 251 if (itemMatches(target, input, strict)) 252 { 253 return true; 254 } 255 } 256 } 257 return false; 258 } 259 260 public static boolean itemMatches(ItemStack target, ItemStack input, boolean strict) 261 { 262 if (input == null && target != null || input != null && target == null) 263 { 264 return false; 265 } 266 return (target.itemID == input.itemID && ((target.getItemDamage() == -1 && !strict) || target.getItemDamage() == input.getItemDamage())); 267 } 268 269 //Convenience functions that make for cleaner code mod side. They all drill down to registerOre(String, int, ItemStack) 270 public static void registerOre(String name, Item ore){ registerOre(name, new ItemStack(ore)); } 271 public static void registerOre(String name, Block ore){ registerOre(name, new ItemStack(ore)); } 272 public static void registerOre(String name, ItemStack ore){ registerOre(name, getOreID(name), ore); } 273 public static void registerOre(int id, Item ore){ registerOre(id, new ItemStack(ore)); } 274 public static void registerOre(int id, Block ore){ registerOre(id, new ItemStack(ore)); } 275 public static void registerOre(int id, ItemStack ore){ registerOre(getOreName(id), id, ore); } 276 277 /** 278 * Registers a ore item into the dictionary. 279 * Raises the registerOre function in all registered handlers. 280 * 281 * @param name The name of the ore 282 * @param id The ID of the ore 283 * @param ore The ore's ItemStack 284 */ 285 private static void registerOre(String name, int id, ItemStack ore) 286 { 287 ArrayList<ItemStack> ores = getOres(id); 288 ore = ore.copy(); 289 ores.add(ore); 290 MinecraftForge.EVENT_BUS.post(new OreRegisterEvent(name, ore)); 291 } 292 293 public static class OreRegisterEvent extends Event 294 { 295 public final String Name; 296 public final ItemStack Ore; 297 298 public OreRegisterEvent(String name, ItemStack ore) 299 { 300 this.Name = name; 301 this.Ore = ore; 302 } 303 } 304}