Skip to main content
Version: 1.20.x

Ingredients

Ingredients are predicate handlers for item-based inputs which check whether a certain ItemStack meets the condition to be a valid input in a recipe. All vanilla recipes that take inputs use an Ingredient or a list of Ingredients, which is then merged into a single Ingredient.

Custom Ingredients

Custom ingredients can be specified by setting type to the name of the [ingredient's serializer][serializer], with the exception of compound ingredients. When no type is specified, the vanilla ingredient is used. Custom ingredients can also easily be used in data generation by calling ICustomIngredient#toVanilla.

NeoForge Types

NeoForge provides a few additional Ingredient types for programmers to implement.

CompoundIngredient

Though they are functionally identical, compound ingredients replaces the way one would implement a list of ingredients in a recipe. They work as a set OR where the passed in stack must be within at least one of the supplied ingredients. This change was made to allow custom ingredients to work correctly within lists. As such, no type needs to be specified.

// For some input
[
// At least one of these ingredients must match to succeed
{
// Ingredient
},
{
// Custom ingredient
"type": "examplemod:example_ingredient"
}
]

DataComponentIngredient

DataComponentIngredients compare the item, damagage, and data components on an ItemStack. When strict is true, the ItemStack is checked for an exact match. Otherwise, if only the components specified match, the ingredient will pass. This can be used by specifying the type as neoforge:components.

// For some input
{
"type": "neoforge:components",
// Can be either a single item or list of items
"items": "examplemod:example_item",
"components": {
// Add component information
},
// true requires an exact match
// false only requires a match of the specified components
"strict": true
}

IntersectionIngredient

IntersectionIngredients work as a set AND where the passed in stack must match all supplied ingredients. There must be at least two ingredients supplied to this. This can be used by specifying the type as neoforge:intersection.

// For some input
{
"type": "neoforge:intersection",

// All of these ingredients must return true to succeed
"children": [
{
// Ingredient 1
},
{
// Ingredient 2
}
// ...
]
}

DifferenceIngredient

DifferenceIngredients work as a set subtraction (SUB) where the passed in stack must match the first ingredient but must not match the second ingredient. This can be used by specifying the type as neoforge:difference.

// For some input
{
"type": "neoforge:difference",
"base": {
// Ingredient the stack is in
},
"subtracted": {
// Ingredient the stack is NOT in
}
}

Creating Custom Ingredients

Custom ingredients can be created by implementing ICustomIngredient and registering the associated IngredientType to NeoForgeRegistries.Keys.INGREDIENT_TYPES.

ICustomIngredient

There are four important methods to implement:

MethodDescription
testReturns true if the stack matches this ingredient.
getItemsReturns the list of stacks this ingredient accepts; however, this does not need to be exhaustive as it is only for display purposes
isSimpleReturns false if information on the stack needs to be tested, or true if only the item needs to be checked
getTypeReturns the type of this ingredient

IngredientType

IngredientType contains two values: a map codec used to encode and decode the ingredient, and a StreamCodec to sync the ingredient if ICustomIngredient#isSimple returns false. If #isSimple is true, then IngredientType has a constructor overload that only takes in the map codec.

The IngredientType needs to be registered.

// For some DeferredRegister<IngredientType<?>> REGISTRAR
public static final DeferredHolder<IngredientType<?>, IngredientType<ExampleIngredient>> EXAMPLE_INGREDIENT = REGISTRAR.register(
"example_ingredient", () -> new IngredientType(...)
);

// In ExampleIngredient
@Override
public IngredientType<?> getType() {
return EXAMPLE_INGREDIENT.get();
}