v6/site/tutorials/forge-modding-1112/ore-dictionary.md

5.9 KiB

title = "Ore Dictionary"
date = "2016-08-08 11:28:00 -0400"

Forge's Ore Dictionary system provides an API that modders can use to mark items/blocks as equivalent to one another. This was originally created because multiple mods were all adding their own versions of the same ores and ingots (copper, tin, etc.). The way this system works is each ItemStack as a list of String ore names associated with it.

Let's create an ItemOreDict interface in the item package of our mod. This interface will be used to mark our items/blocks to be registered with the Ore Dictionary. This interface will have a single abstract method called initOreDict that performs the registration.

package net.shadowfacts.tutorial.item;

public interface ItemOreDict {
	
	void initOreDict();

}

We'll also create a ItemOre class that extends ItemBase and implements ItemOreDict to give us a nice fully implemented class for ore-dictionaried items.

package net.shadowfacts.tutorial.item;

import net.minecraftforge.oredict.OreDictionary;

public class ItemOre extends ItemBase implements ItemOreDict {

	private String oreName;

	public ItemOre(String name, String oreName) {
		super(name);

		this.oreName = oreName;
	}

	@Override
	public void initOreDict() {
		OreDictionary.registerOre(oreName, this);
	}

}

This class simply takes a second String parameter in its constructor that is the ore-dictionary name and then uses that in the initOreDict method.

We'll do something similar for our BlockOre class, that is, have it implement ItemOreDict and initOreDict and have a second parameter for the ore dictionary name.

package net.shadowfacts.tutorial.block;

import net.minecraft.block.material.Material;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraftforge.oredict.OreDictionary;
import net.shadowfacts.tutorial.item.ItemOreDict;

public class BlockOre extends BlockBase implements ItemOreDict {

	private String oreName;

	public BlockOre(String name, String oreName) {
		super(Material.ROCK, name);

		this.oreName = oreName;

		setHardness(3f);
		setResistance(5f);
	}

	@Override
	public void initOreDict() {
		OreDictionary.registerOre(oreName, this);
	}

	@Override
	public BlockOre setCreativeTab(CreativeTabs tab) {
		super.setCreativeTab(tab);
		return this;
	}

}

We'll need to make some changes to our ModItems and ModBlocks classes so they call the initOreDict method after the item/block is registered with the GameRegistry.

We'll first check if the item implements our ItemOreDict interface (because not all our items will use the Ore Dictionary) and if so, call the initOreDict method on it.

// ...
public class ModItems {
	// ...

	private static <T extends Item> T register(T item) {
		GameRegistry.register(item);

		if (item instanceof ItemModelProvider) {
			((ItemModelProvider)item).registerItemModel(item);
		}
		if (item instanceof ItemOreDict) {
			((ItemOreDict)item).initOreDict();
		}

		return item;
	}
}

We'll do this similarly in the ModBlocks class excpet we'll check instanceof ItemOreDict and call initOreDict on both the block itself and the associated ItemBlock.

// ...
public class ModBlocks {
	// ...

	private static <T extends Block> T register(T block, ItemBlock itemBlock) {
		GameRegistry.register(block);
		if (itemBlock != null) {
			GameRegistry.register(itemBlock);

			if (block instanceof ItemModelProvider) {
				((ItemModelProvider)block).registerItemModel(itemBlock);
			}
			if (block instanceof ItemOreDict) {
				((ItemOreDict)block).initOreDict();
			}
			if (itemBlock instanceof ItemOreDict) {
				((ItemOreDict)itemBlock).initOreDict();
			}
		}
	}
}

Now that we've got all our base classes setup, we're going to modify some of our items and blocks to given the ore dictionary names!

The only block that will have an ore dictionary name is the Copper Ore block. Following with the conventions for ore dictionary names (if you look in the OreDictionary class, you can get a general idea for what these conventions are), our Copper Ore block will have an ore dictionary name of oreCopper.

We'll simply change our registration call for the Copper Ore block to have a second parameter that is also "oreCopper", telling the BlockOre class to use oreCopper as the ore dictionary name for that block.

// ...
public class ModBlocks {
	// ...
	public static void init() {
		oreCopper = register(new BlockOre("ore_copper", "oreCopper"));
		// ...
	}
}

We'll now change both our Copper Ingot and Corn items to have ore dictionary names ingotCopper and cropCorn respectively. All this requires is changing the ItemBase instantiations to ItemOre instantiations and passing in the desired ore dictionary name as the second constructor parameter.

// ...
public class ModItems {
	// ...
	public static void init() {
		ingotCopper = register(new ItemOre("ingot_copper", "ingotCopper"));
		corn = register(new ItemOre("corn", "cropCorn"));
		// ...
	}
}

Recipes

Now that we've got ore dictionary names for some of our items and blocks, let's add recipes that utilize them. Forge adds the ShapedOreRecipe and ShapelessOreRecipe classes that are identical to the vanilla shaped and shapless recipes, except instead of just accepting an item/block/stack for the input, they can also accept a string of an ore dictionary name that will match anything with that given name.

These recipes need to be instantiated manually and registered using GameRegistry.addRecipe unlike normal shaped/shapeless recipes which have convienience methods in GameRegistry.

// ...
public class ModRecipes {
	
	public static void init() {
		// ...
		GameRegistry.addRecipe(new ShapedOreRecipe(Items.BUCKET, "I I", " I ", 'I', "ingotCopper"));

		// ...
	}

}

This recipe is the same as the vanilla bucket recipe, except it matches any item with the ingotCopper ore dictionary name instead of just iron ingots.

Shaped Ore Recipe