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 }