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[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 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[oreIDs.keySet().size()]);
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 }