User Tools

Site Tools






Blocks and Block Entities



World Generation

Recipe Types




Dynamic Data Generation

Tutorials for Minecraft 1.15

Tutorials for Minecraft 1.14



Creating a Custom Recipe Type

In this page, we will create our own custom recipe type, including the shapeless version! We won't use any vanilla Minecraft classes, it will be a fully custom recipe type.

You can find and learn how to make other recipe types. Creating a custom cooking recipe type

Adding the Block

We will need to create a block to open the recipe gui. Some of the classes will be created later.
public class TestRecipeBlock extends Block {
	private static final Text TITLE = new TranslatableText("container.test_crafting");
	public SpiritpowerCrafterBlock(Settings settings) {
	public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
		if(world.isClient) {
			return ActionResult.SUCCESS;
		} else {
			player.openHandledScreen(state.createScreenHandlerFactory(world, pos));
			return ActionResult.CONSUME;
	public NamedScreenHandlerFactory createScreenHandlerFactory(BlockState state, World world, BlockPos pos) {
		return new SimpleNamedScreenHandlerFactory((i, playerInventory, playerEntity) -> {
			return new TestCraftingScreenHandler(i, playerInventory, ScreenHandlerContext.create(world, pos));
		}, TITLE);

Now we need to register the Block and BlockItem.
public class ExampleCustomRecipeMod implements ModInitializer {
	public static final TestRecipeBlock TEST_RECIPE_BLOCK = new TestRecipeBlock(FabricBlockSettings.of(Material.METAL));
	public void onInitialize() {  
    		// Resuming later...

Creating the Recipe Class

Now we will do the most fun part of this page, creating the recipe class.

Creating the Shaped Recipe Class

Shaped recipes are a recipe type that requires an item to be in that specific slot or pattern. It is mostly used on grid recipes such as Crafting Recipe.

The Recipe interface expects an Inventory class as a type parameter. Any inventory that contains the ingredients for the recipe would work. But we will be using CraftingInventory.
public class TestRecipe implements Recipe<CraftingInventory> {
	//You can add as much inputs as you want here.
	//It is important to always use Ingredient, so you can support tags.
	private final Ingredient inputA;
	private final Ingredient inputB;
	private final ItemStack result;
	private final Identifier id;
	public TestRecipe(Identifier id, ItemStack result, Ingredient inputA, Ingredient inputB) { = id;
		this.inputA = inputA;
		this.inputB = inputB;
		this.result = result;
	public Ingredient getInputA() {
		return this.inputA;
	public Ingredient getInputB() {
		return this.inputB;
	public ItemStack getOutput() {
		return this.result;
	public Identifier getId() {

We would need to care about craft, because it is needed to craft the result. In craft, it is a good idea to return this.getOutput().copy(). fits should return true.
public class TestRecipe implements Recipe<CraftingInventory> {
	public ItemStack craft(CraftingInventory inv) {
		return this.getOutput().copy();

In matches, we need to say if a given inventory satisfies a recipe's input. We will return true if the first and second slot matches first and second input.
public class TestRecipe implements Recipe<CraftingInventory> {
	public boolean matches(CraftingInventory inv, World world) {
		if(inv.getInvSize(0) < 2) return false;
		return inputA.test(inventory.getInvStack(0)) && inputB.test(inventory.getInvStack(1));

Now we need the Type of the recipe. All you have to do is to create an instance of a class that extends RecipeType<TestRecipe>.
public class TestRecipe implements Recipe<CraftingInventory> {
	public static Type implements RecipeType<TestRecipe> {
		private Type() {}
		public static final Type INSTANCE = new Type();
		public static final String ID = "test_recipe";
	pubilc RecipeType<?> getType() {
		return Type.INSTANCE;

SOURCE: Defining Custom Crafting Recipes

tutorial/recipe_type.txt · Last modified: 2021/08/29 18:18 by banana