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