Minecraft Modding: The Ore Dictionary And Recipes

Introduction



One of the basic ideas of Minecraft game play is the idea that you mine "ore" and then use that to smelt and craft things.

Many mods want to add variety and so might create variations on things, but still want them to act similarly to vanilla "ore" when used in recipes. This isn't as simple as simply creating classes that extend those vanilla things (although you might want to do that) because a lot of functionality in Minecraft will compare for exact match with the specific instance including metadata.

Registering Items/Blocks To Alias To Minecraft


To get around this allow for a sort of "aliasing" of custom blocks to be treated like the vanilla ones, Forge provides an "ore dictionary".  The OreDictionary class implements a system/registry which associates items/blocks with a string name (which can be same as vanilla types).

By default, Forge has changed out many of these default vanilla recipes to accept ore dictionary items. To see the available ore dictionary names that you can associate your block or item to, see here.

For example, wood planks are one of the items with an ore dictionary alias. So to register a new block or item that Minecraft will accept as a wood plank, simply put OreDictionary.registerOre("plankWood", yourBlockInstance); in your mods' method for handling the init life cycle event in your common proxy.


Registering Items/Blocks To Alias To Other Mods



Key Point: In addition to aliasing to the vanilla items, the ore dictionary also allows you to alias between other people's mods. For example, if you know a mod that has a "copperIngot" registered in the ore dictionary, you could make your own version that would be treated the same in that mod's recipes provided you also register yours as "copperIngot".

Using Ore Dictionary As Recipe Ingredients


So what if you want to use something from the ore dictionary as input to a recipe? The recipe registration methods accept the ore dictionary name preceeded by a ":". For example:

mod.addRecipe("woodenBoots 1", 3, 2, ":woodPlank", "", ":woodPlank", ":woodPlank", "", ":woodPlank");


Using Ore Dictionary Elsewhere


Outside of recipes, wherever you have code that looks for a specific item/block you should consider comparing with the Ore Dictionary because that would maximize compatibility with other mods.

The OreDictionary class provides the getOres() method (which returns an ArrayList of ItemStacks). You then need to loop through that list and compare with whatever ItemStack you're interested in.

Note: You should use the version of the getOres() method that takes a String parameter.

To loop through the list and compare, OreDictionary has a method called containsMatch(). Unfortunately that method is private so you can't access it, but it is a simple method that you can just copy. Then you just pass in the ArrayList you got from the getOres() method, plus the ItemStack you're interested in.

Warning: The loop required for containsMatch() can be slow so try not to invoke it every tick if you can avoid it. For example, if you're interested in checking something the player is holding it is better to check it whenever something new is equipped rather than every tick.

Further Reading


These other tutorials can give you better idea of actual implementations with the ore dictionary:


Remove A Recipe From Furnace


The list has public scope so you can edit it directly with standard methods, in this case remove():

FurnaceRecipes.smelting().getSmeltingList().remove(Block.oreIron.blockID);

Remove A Recipe From Crafting


It is a bit trickier with Crafting if you want to make sure all recipes for an item are removed, you'll need to iterate through them all like this:


Iterator<IRecipe> iterator = CraftingManager.getInstance().getRecipeList().iterator();

while (iterator.hasNext())
{
    IRecipe recipe = iterator.next();
    if (recipe == null)
     continue;
    ItemStack output = recipe.getRecipeOutput();
    if (output != null && output.itemID == Block.furnaceIdle.blockID)
     iterator.remove();
}

Why Does Some Code Use Object[] In Recipe Registration


Thanks to diesieben07 for this explanation.

You may see that the Minecraft code uses an Object[] in the recipe registrations. Something that looks like this:
GameRegistry.addShapedRecipe(new ItemStack(EFItems.lightBulb), new Object[] {"GGG", "GOG", "III", 'G', Blocks.glass, 'O', Items.gold_ingot, 'I', Items.iron_ingot});

However, you will see that many modders will do the registration like this instead (without the Object[]):
GameRegistry.addShapedRecipe(new ItemStack(EFItems.lightBulb), "GGG", "GOG", "III", 'G', Blocks.glass, 'O', Items.gold_ingot, 'I', Items.iron_ingot);

In Java these are actually equivalent -- you can use either, although most people would choose the latter since it is less typing and easy to read. The method in this case accepts "varargs" meaning that it can take a variable number of parameters; this is literally equivalent to passing an Object[] as the parameter. The vararg approach is an example of "syntactic sugar" which means it is a way of allowing simpler (or easier to read) coding syntax for something.

The reason why the Minecraft vanilla code will use the Object[] syntax is because the decompiler used doesn't take the step of translating to the vararg since the Object[] is already a correct decompilation.

Make Player-Specific Recipes


Check out diesieben07's Player-Specific Recipes Tutorial.

No comments:

Post a Comment