Skip to content

Recipe Data Generation

Maksym Uimanov edited this page Jan 30, 2026 · 2 revisions

Recipe Data Generation

The @GenerateRecipe annotation enables automated recipe data generation during the gradle runData phase. This annotation eliminates the need for manual JSON recipe file creation by allowing developers to define recipe logic through Java classes that implement specific recipe description interfaces.

Responsibilities / Purpose

The @GenerateRecipe annotation serves to:

  • Automate recipe file generation - Create JSON recipe files from Java class definitions
  • Type-safe recipe creation - Provide compile-time validation for recipe properties
  • Support multiple recipe types - Handle shaped, shapeless, cooking, and smithing recipes
  • Reduce boilerplate code - Replace manual data provider implementations with declarative classes
  • Integrate with item registration - Work seamlessly with the framework's item system

How it works

The annotation system operates during data generation by scanning classes annotated with @GenerateRecipe. Each annotated class must implement one of the recipe description interfaces (e.g., ShapedRecipeDescription, ShapelessRecipeDescription, SmeltingRecipeDescription, ...). The framework then generates corresponding JSON files using appropriate recipe strategies.

Core Architecture

  • Type-level annotation - Applied to classes implementing recipe description interfaces
  • Strategy pattern implementation - Different strategies for each recipe type
  • Interface-based configuration - Recipe properties defined through method implementations
  • Automatic registration - Classes are automatically discovered and processed during data generation

How to use / Configure

Shapeless Recipe

@GenerateRecipe
public class ExampleShapelessRecipe implements ShapelessRecipeDescription {
    @Override
    public Map<ItemLike, Integer> getItemAndCountMap() {
        return Map.of(
            Items.DIAMOND, 1,
            Items.COPPER_BLOCK, 2
        );
    }

    @Override
    public RecipeCategory getRecipeCategory() {
        return RecipeCategory.MISC;
    }

    @Override
    public ItemLike getResult() {
        return ExampleItems.EXAMPLE_ITEM;
    }

    @Override
    public int getCount() {
        return 4;
    }
}

Shaped Recipe

@GenerateRecipe
public class ExampleShapedRecipe implements ShapedRecipeDescription {
    @Override
    public String[] getPattern() {
        return new String[]{
            "ABC",
            " B "
        };
    }

    @Override
    public Map<Character, ItemLike> getPatternTranslation() {
        return Map.of(
            'A', Items.DIAMOND,
            'B', Items.IRON_INGOT,
            'C', Items.GOLD_INGOT
        );
    }

    @Override
    public RecipeCategory getRecipeCategory() {
        return RecipeCategory.TOOLS;
    }

    @Override
    public ItemLike getResult() {
        return ExampleItems.EXAMPLE_TOOL;
    }
}

Smelting Recipe

@GenerateRecipe
public class ExampleSmeltingRecipe implements SmeltingRecipeDescription {
    @Override
    public ItemLike getIngredient() {
        return ExampleItems.EXAMPLE_ORE;
    }

    @Override
    public float getExperience() {
        return 0.7F;
    }

    @Override
    public int getCookingTime() {
        return 200;
    }

    @Override
    public String getGroup() {
        return "example_smelting";
    }

    @Override
    public RecipeCategory getRecipeCategory() {
        return RecipeCategory.MISC;
    }

    @Override
    public ItemLike getResult() {
        return ExampleItems.EXAMPLE_INGOT;
    }
}

Blasting Recipe

@GenerateRecipe
public class ExampleBlastingRecipe implements BlastingRecipeDescription {
    @Override
    public ItemLike getIngredient() {
        return ExampleItems.EXAMPLE_ORE;
    }

    @Override
    public float getExperience() {
        return 1.0F;
    }

    @Override
    public int getCookingTime() {
        return 100; // Faster than smelting
    }

    @Override
    public String getGroup() {
        return "example_blasting";
    }

    @Override
    public RecipeCategory getRecipeCategory() {
        return RecipeCategory.MISC;
    }

    @Override
    public ItemLike getResult() {
        return ExampleItems.EXAMPLE_INGOT;
    }
}

Smithing Transform Recipe

@GenerateRecipe
public class ExampleSmithingTransformRecipe implements SmithingTransformRecipeDescription {
    @Override
    public ItemLike getTemplate() {
        return Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE;
    }

    @Override
    public ItemLike getBase() {
        return Items.DIAMOND_SWORD;
    }

    @Override
    public ItemLike getAddition() {
        return Items.NETHERITE_INGOT;
    }

    @Override
    public RecipeCategory getRecipeCategory() {
        return RecipeCategory.MISC;
    }

    @Override
    public ItemLike getResult() {
        return Items.NETHERITE_SWORD;
    }
}

Smithing Trim Recipe

@GenerateRecipe
public class ExampleSmithingTrimRecipe implements TemplateSmithingTrimRecipeDescription {
    @Override
    public ItemLike[] getTemplates() {
        return new ItemLike[]{ExampleItems.EXAMPLE_ARMOR_TRIM_SMITHING_TEMPLATE};
    }

    @Override
    public ItemLike getBase() {
        return Items.IRON_CHESTPLATE;
    }

    @Override
    public ItemLike getAddition() {
        return ExampleItems.EXAMPLE_TRIM_MATERIAL;
    }

    @Override
    public RecipeCategory getRecipeCategory() {
        return RecipeCategory.MISC;
    }

    @Override
    public ItemLike getResult() {
        return Items.IRON_CHESTPLATE; // Trim recipes return the base item
    }
}

Stone Cutting Recipe

@GenerateRecipe
public class ExampleStoneCuttingRecipe implements StoneCuttingRecipeDescription {
    @Override
    public ItemLike getIngredient() {
        return ExampleItems.EXAMPLE_STONE;
    }

    @Override
    public int getCount() {
        return 2;
    }

    @Override
    public RecipeCategory getRecipeCategory() {
        return RecipeCategory.STONECUTTER;
    }

    @Override
    public ItemLike getResult() {
        return ExampleItems.EXAMPLE_STONE_SLAB;
    }
}

Extension and Customization

Custom Recipe Categories

Use appropriate recipe categories for proper organization:

@Override
public RecipeCategory getRecipeCategory() {
    return RecipeCategory.BUILDING_BLOCKS; // For blocks
    return RecipeCategory.FOOD; // For food items
    return RecipeCategory.TOOLS; // For tools and weapons
    return RecipeCategory.REDSTONE; // For redstone components
    return RecipeCategory.MISC; // For miscellaneous items
}

Recipe Groups

Organize similar recipes with groups:

@Override
public String getGroup() {
    return "example_tools"; // Group all tool recipes
}

Custom Recipe Names

Override default naming for specific recipe types:

@Override
public String getName() {
    return "custom_recipe_name"; // Overrides default naming
}

Multiple Recipes in One Class

Create multiple recipe classes for complex item relationships:

@GenerateRecipe
public class ExampleItemRecipe implements ShapelessRecipeDescription {
    // Recipe for creating the item
}

@GenerateRecipe
public class ExampleItemSmeltingRecipe implements SmeltingRecipeDescription {
    // Recipe for processing the item
}

When to use

  • Standard recipe patterns - Use for conventional crafting, smelting, and smithing recipes
  • Type-safe development - Prefer when compile-time validation is important
  • Multiple recipe types - Use when items have multiple creation methods
  • Consistent naming - Use when following standard recipe naming conventions
  • Rapid prototyping - Use for quick recipe creation during development

The @GenerateRecipe annotation is designed for most recipe generation scenarios, providing type safety and integration with the framework's ecosystem. For highly specialized requirements or complex recipe logic, custom data providers offer more direct control.

Clone this wiki locally