Modding:Grid Recipes Guide
This is a guide of available grid recipe features. For a follow-along tutorial, please see the simple recipes tutorial and the complex recipes tutorial .
Advanced
Type based recipes
There are more complicated things you can do with recipes. This the recipe for wooden planks which are crafted out of logs:
{
"ingredientPattern": "L",
"ingredients": {
"L": { "type": "block", "code": "game:log-*-ud", "name": "wood" }
},
"width": 1,
"height": 1,
"output": { "type": "block", "code": "planks-{wood}-hor", "quantity": 4 }
}
Instead of having a recipe for every wood type, you can assign a name to an ingredient (in this case it is "name": "wood"
) and everything identified by *
will later on replaced be for the output. Meaning {wood}
will be replaced by the type of the giving log.
For example if we would have a birch log block, its code would be log-birch-ud
, so *
would stand for birch
, therefore the output will be converted from "code": "planks-{wood}-hor"
to "code": "planks-birch-hor"
.
Converting an ingredient to another item upon crafting
Sometimes you want to keep one or more of the ingredients, but convert them to a different item after crafting. For example, when crafting a honey-sulfur poultice, the player needs a bowl filled with honey, but the bowl is not consumed to craft it. Instead the bowl of honey is turned into an empty bowl. This is accomplished by adding the returnedStack
property to the ingredient. This property's value needs to contain a type
and code
just like the standard ingredient properties. This tells the recipe which item to give the player back.
Continuing with the honey-sulfur poultice example, a bowl of honey as an ingredient looks like "B": { "type": "block", "code": "bowl-honey" }
, but the player would lose the bowl if the recipe were written this way. We need to add returnedStack
to the ingredient's properties and indicate which item to replace it with. In this case, the player should receive an empty bowl in place of the bowl of honey "returnedStack": { "type": "block", "code": "bowl-burned" }
. This property is placed alongside the type
and code
properties of an ingredient. Putting it all together:
{
"ingredientPattern": "SBS,_L_",
"ingredients": {
"L": { "type": "block", "code": "linen-*" },
"S": { "type": "item", "code": "powderedsulfur" },
"B": {
"type": "block",
"code": "bowl-honey",
"returnedStack": { "type": "block", "code": "bowl-burned" }
}
},
"width": 3,
"height": 2,
"output": { "type": "item", "code": "poultice-linen-honey-sulfur", "quantity": 4 }
}
Consuming more than one durability per tool
To balance durability consuming, it can be done by adding toolDurabilityCost
and isTool
. This is recipe for pulverizer pounder:
{
"ingredientPattern": "HL_,CL_,_L_",
"ingredients": {
"H": { "type": "item", "code": "hammer-*", isTool: true, toolDurabilityCost: 10 },
"C": { "type": "item", "code": "chisel-*", isTool: true, toolDurabilityCost: 10 },
"L": { "type": "block", "code": "log-placed-*-ud", "name": "wood" }
},
"width": 3,
"height": 3,
"output": { "type": "item", "code": "pounder-oak", "quantity": 1 }
}
Separating recipes on the same handbook page
Sometimes amount of recipes for one item can become overwhelming, to separate important ones, it can be done by adding recipeGroup
. These are recipes for wooden ladder:
{
"ingredientPattern": "S_S,SSS,S_S",
"ingredients": {
"S": { "type": "item", "code": "stick" }
},
"width": 3,
"height": 3,
"recipeGroup": 1,
"output": { "type": "block", "code": "ladder-wood-north", "quantity": 3 }
},
{
"ingredientPattern": "P_P,PSP,P_P",
"ingredients": {
"P": { "type": "item", "code": "plank-*" },
"S": { "type": "item", "code": "stick" }
},
"width": 3,
"height": 3,
"output": { "type": "block", "code": "ladder-wood-north", "quantity": 3 }
}
Restricting to a specific class
The recipe can be limited to a specific class. This can be done by adding requiresTrait
. This is recipe for sewing kit:
{
"ingredientPattern": "FFS,FF_",
"requiresTrait": "clothier",
"ingredients": {
"F": { "type": "item", "code": "flaxtwine" },
"S": { "type": "item", "code": "stick" }
},
"width": 3,
"height": 2,
"output": { "type": "item", "code": "sewingkit" }
}
Copying attributes
Some recipes can require to copy attributes. This is can be done by adding copyAttributesFrom
. This is recipe for labeled crate:
{
"ingredientPattern": "S,C",
"ingredients": {
"S": { "type": "item", "code": "paper-parchment" },
"C": { "type": "block", "code": "crate" }
},
"shapeless": true,
"copyAttributesFrom": 'C',
"width": 1,
"height": 2,
"output": { "type": "block", "code": "crate", "attributes": { "label": "paper-empty" } }
}
Hiding recipes from 'Created by' section from handbook
Some recipes are better hidden, it can be done by adding showInCreatedBy
.
{
"ingredientPattern": "H",
"ingredients": {
"H": { "type": "block", "code": "hay-normal-ud" }
},
"showInCreatedBy": false,
"width": 1,
"height": 1,
"output": { "type": "item", "code": "drygrass", "quantity": 8 }
}
Using liquid container as ingredient
Some recipes use liquid containers, such as buckets, bowls or jugs. For single liquid container, it can be done by adding liquidContainerProps
to recipe attributes. This is recipe for honey-sulfur poultice:
{
"ingredientPattern": "SBS,_L_",
"ingredients": {
"L": { "type": "block", "code": "linen-*" },
"S": { "type": "item", "code": "powderedsulfur" },
"B": { "type": "block", "code": "bowl-fired" }
},
"attributes": {
"liquidContainerProps": {
"requiresContent": { "type": "item", "code": "honeyportion" },
"requiresLitres": 0.25
}
},
"width": 3,
"height": 2,
"output": { "type": "item", "code": "poultice-linen-honey-sulfur", "quantity": 4 }
}
The above liquidContainerProps are stored in the grid attributes, which are shared for all containers in the recipe. This means that it cannot be used for recipes that need multiple liquids. Note that there is some code in BlockLiquidContainerBase to read the liquidContainerProps from the per-ingredient recipe attributes instead of the grid attributes, but the code is incomplete. Specifically, as of version 1.19.8, BlockLiquidContainerBase.OnHandbookRecipeRender still directly reads from the grid attributes.
Also the ucontents cannot be used as an alternative, because the real blocks have a contents attribute instead of ucontents attribute. ucontents is not converted to contents before the recipe matching. So the recipe fails to match because the candidate liquid container has a contents attribute instead of a ucontents attribute. Also the contents cannot be directly entered in the json, because it has the ItemstackAttribute type, which is not parsed from json.