Ingredients and Recipes

Link to ingredients-and-recipes

This page aims to give the intermediate scripter a more detailed look into some of the common concepts passed around when dealing with recipes.

Let's talk semantics: The Good, the Bad and the Block

Link to lets-talk-semantics-the-good-the-bad-and-the-block

It is fairly possible that in your scripting adventures, you've seen the following types being mentioned: IItemStack, IIngredient, ItemDefinition, MCTags, and Blocks.

However, their meaning within the context of the game might be a bit vague, so let's break them down individually shall we?

  • An ItemDefinition is an abstract representation of an in game item. At runtime, there is only one definition for each registered item during the whole execution of the game.
  • An IItemStack is a bundle of data, containing an ItemDefinition, a stack size, and extra NBT Data. Anything in your inventory is an IItemStack. Tons and tons of them are instantiated during the normal execution of the game.
  • An IIngredient is a predicate that matches some IItemStacks. Like in a cooking recipe, it is essentially a guideline for what fits in a recipe. Said guideline can be really strict: "1x pumpkin_seed", or vague: "1x any seed".
  • A BlockState is a Block with properties, found within a Level. A Block, like an ItemDefinition only has one instance.
  • A MCTag (not to be confused with NBT Tags) is a collection of registry objects, such as ItemDefinitions, Blocks, Fluids, or Biomes, along many others. MCTags are the ones that have contents, and not the other way around: An item (definition) is in many MCTags, or a single MCTag contains many ItemDefinitions.

So what do we interpret from this?

  • Blocks are rarely used in the context of recipes
  • MCTags do not contain IItemStacks, only ItemDefinitions. This means that any extra data (such as the stacksize, or NBT IData) won't be checked at the moment of looking at whether a MCTag contains an item.
  • IIngredients are an abstract template that determine what can go in a recipe.

About Ingredients and Predicates

Link to about-ingredients-and-predicates

Predicates are type of function. They take in one argument and return whether said argument passes all conditions.

ZenScript
Copy
//Checks if the given item is a diamond pickaxe. 
function overengineeredIngredient(ing as IItemStack) as boolean {
    //Remember, matches is not symmetric!
    //This check ignores all nbt data.
    //matches also checks stacksize. This does not matter for damageable items, but it is nice to know!
    return <item:minecraft:diamond_pickaxe>.matches(ing);
    //Would be the same as doing:
    //return <item:minecraft:diamond_pickaxe>.definition == ing.definition;
}

//Checks if the given ingredient is an undamaged, unenchanted diamond pickaxe
function strictIngredient(ing as IItemStack) as boolean {
    return ing.matches(<item:minecraft:diamond_pickaxe>);
}

Obviously, you don't need to do this at all! It is all handled behind the scenes by all recipes that take IIngredients as parameters. However, it is good to have a mental idea of how matching works with these types.

MCTags can also be implicitly as well as explicitly be converted to IIngredients. Their check more or less looks like this:

ZenScript
Copy
function tagMatches(tag as MCTag<ItemDefinition>, ing as IItemStack) {
    //Only the definition is queried, not the item's stacksize or extra data!
    return tag.contains(ing.definition);
}

Fine tuning your ingredients

Link to fine-tuning-your-ingredients

Sometimes, you'll want more precision, or to group ingredients. For this, you can use some of the methods found in the IIngredient class:

  • anyDamage
  • onlyDamaged
  • onlyDamagedAtLeast and onlyDamagedAtMost
  • onlyIf, the more flexible of them all, allows you to define a custom predicate.
  • reuse
  • transformCustom
  • transformReplace
  • transformDamage

And the magic IIngredientTransformed, which modify the item after being used. However, these require special support, and in Vanilla they will only work in a Crafting Table.

Using fancy ingredients in json recipes

Link to using-fancy-ingredients-in-json-recipes

CraftTweaker registers custom ingredient types so that you can use them in json recipes. The following are available to use:

  • crafttweaker:any
  • crafttweaker:list
  • crafttweaker:conditioned (except for onlyIf)
  • crafttweaker:transformed -> (except for transformCustom)
  • crafttweaker:partial_tag

Those are the ingredient types. Just about half of what you want. The following script should provide you with a json object, which you can copy and paste as an ingredient in a Json Recipe.

ZenScript
Copy
import crafttweaker.api.data.IData;

val ing = /* your ingredient here, an example of it being an Or Ingredient */ <item:minecraft:pumpkin> | <item:minecraft:dirt>;

//This should print a json object you might be able to use in your Json Recipes. However, some mods might choose to ignore what you've given them, so test your changes!
println((ing as IData).getAsString());

So, what do we learn from this post?

  • IIngredients are abstract. They're conditions an IItemStack must match in order to be considered valid.
  • MCTags are sets of ItemDefinitions, not IItemStacks.
  • Most ingredients and conditions can be serialized into json and used by other mods. However, the most complex of transformations re quire explicit support.