Skip to main content
Version: 1.21.4

内置配方类型(Built-In Recipe Types)

Minecraft 自带了多种配方类型(recipe types)和序列化器(serializers)供你直接使用。本文将介绍每种配方类型,并讲解如何生成这些配方。

合成(Crafting)

合成配方(crafting recipes)通常在合成台(crafting tables)、自动合成器(crafters)或模组添加的合成台或机器中制作。它们的配方类型为 minecraft:crafting

有序合成(Shaped Crafting)

一些最重要的配方——比如合成台、木棍以及大多数工具——都是通过有序配方(shaped recipes)制作的。这类配方通过一个合成图案(pattern)或形状(shape)来定义物品的放置方式(因此称为“有序”)。下面是一个示例:

{
"type": "minecraft:crafting_shaped",
"category": "equipment",
"key": {
"#": "minecraft:stick",
"X": "minecraft:iron_ingot"
},
"pattern": [
"XXX",
" # ",
" # "
],
"result": {
"count": 1,
"id": "minecraft:iron_pickaxe"
}
}

我们逐行解析一下这个示例:

  • type:这是有序配方序列化器(shaped recipe serializer)的 ID,即 minecraft:crafting_shaped
  • category:这是一个可选字段,用于定义合成书(crafting book)中的 CraftingBookCategory
  • keypattern:这两个字段共同定义了物品在合成格中的放置方式。
    • pattern 定义了最多三行、每行最多三个字符的字符串,描述合成图案。所有行的长度必须相同,也就是说图案必须是矩形。空格用于表示该格应为空。
    • key 用于将图案中使用的字符与配料关联。在上面的例子中,图案中的所有 X 都必须是铁锭,所有 # 都必须是木棍。
  • result:配方的输出结果。这是物品堆 JSON 表示
  • 示例中未展示的 group 键:这是一个可选字符串属性,用于在配方书中创建分组。属于同一分组的配方会在配方书中作为一个条目显示。
  • 示例中未展示的 show_notification:这是一个可选布尔值,如果为 false,则在首次使用或解锁该配方时,不会在右上角弹出提示。

接下来,我们来看一下如何在 RecipeProvider#buildRecipes 方法中生成这个配方:

// 我们使用的是构建器模式,因此不会创建变量。通过调用
// ShapedRecipeBuilder#shaped,并传入配方类别(可在 RecipeCategory 枚举中找到)
// 以及结果物品、结果物品和数量,或一个物品堆,来创建一个新的构建器。
ShapedRecipeBuilder.shaped(this.registries.lookupOrThrow(Registries.ITEM), RecipeCategory.TOOLS, Items.IRON_PICKAXE)
// 创建你的配方图案的每一行。每次调用 #pattern 都会添加一行。
// 图案会被校验,也就是说会检查它们的形状。
.pattern("XXX")
.pattern(" # ")
.pattern(" # ")
// 为图案定义键。所有在图案中使用的非空格字符都必须被定义。
// 这里可以接受 Ingredients、TagKey<Item> 或 ItemLikes,也就是物品或方块。
.define('X', Items.IRON_INGOT)
.define('#', Items.STICK)
// 创建配方的进度(advancement)。虽然后端系统不是强制要求,
// 但如果省略这一项,配方构建器会抛出异常。第一个参数是进度名称,
// 第二个参数是条件。通常你会使用 has() 这个便捷方法来设置条件。
// 可以多次调用 #unlockedBy 来添加多个进度条件。
.unlockedBy("has_iron_ingot", this.has(Items.IRON_INGOT))
// 将配方存储到传入的 RecipeOutput 中,以便写入磁盘。
// 如果你想为配方添加条件,可以在输出对象上设置。
.save(this.output);

此外,你还可以调用 #group#showNotification,分别用于设置配方书分组和是否弹出提示通知。

无序合成(Shapeless Crafting)

与有序合成配方(shaped crafting recipe)不同,无序合成配方不关心原材料的放置顺序。因此,这类配方没有图案和键,只有一个原材料的列表:

{
"type": "minecraft:crafting_shapeless",
"category": "misc",
"ingredients": [
"minecraft:brown_mushroom",
"minecraft:red_mushroom",
"minecraft:bowl"
],
"result": {
"count": 1,
"id": "minecraft:mushroom_stew"
}
}

像之前一样,我们来逐行解析一下:

  • type:这是无序合成配方序列化器的 id,minecraft:crafting_shapeless
  • category:这个可选字段用于指定配方在合成书中的类别。
  • ingredients:一个 原材料 列表。列表的顺序会在代码中保留,用于配方展示,但实际合成时原材料顺序无关紧要。
  • result:配方的产物。这是 物品堆的 JSON 表示
  • 示例中未展示的 group 键:这是一个可选的字符串属性,用于在配方书中创建分组。属于同一分组的配方会在配方书中合并显示为一项。

接下来,让我们看看如何在 RecipeProvider#buildRecipes 方法中生成这个配方:

// 我们这里使用的是构建者模式(builder pattern),因此不会创建变量。通过调用
// ShapelessRecipeBuilder#shapeless 并传入配方类别(可在 RecipeCategory 枚举中找到)
// 以及一个结果物品、结果物品和数量,或一个结果物品栈,来创建一个新的构建者。
ShapelessRecipeBuilder.shapeless(this.registries.lookupOrThrow(Registries.ITEM), RecipeCategory.MISC, Items.MUSHROOM_STEW)
// 添加配方所需的原料。这里可以接受 Ingredient、TagKey<Item> 或 ItemLike。
// 也有重载方法可以额外指定数量,从而多次添加同一种原料。
.requires(Blocks.BROWN_MUSHROOM)
.requires(Blocks.RED_MUSHROOM)
.requires(Items.BOWL)
// 创建配方的进度(advancement)。虽然被消费的底层系统没有强制要求,
// 但如果省略该步骤,配方构建器会报错。第一个参数是进度的名称,
// 第二个参数是条件。通常你可以使用 has() 这个快捷方式来指定条件。
// 可以多次调用 #unlockedBy 来添加多个进度解锁条件。
.unlockedBy("has_mushroom_stew", this.has(Items.MUSHROOM_STEW))
.unlockedBy("has_bowl", this.has(Items.BOWL))
.unlockedBy("has_brown_mushroom", this.has(Blocks.BROWN_MUSHROOM))
.unlockedBy("has_red_mushroom", this.has(Blocks.RED_MUSHROOM))
// 将配方存储到传入的 RecipeOutput 中,最终会写入磁盘。
// 如果你希望为配方添加条件,可以在 output 上进行设置。
.save(this.output);

此外,你还可以调用 #group 方法为配方设置配方书分组。

info

单一物品的配方(例如储存块拆解)应使用无序合成(shapeless)配方,以符合原版规范。

转变合成(Transmute Crafting)

转变配方(transmute recipes)是一种特殊的单物品合成配方,其特点是输入物品栈(stack)的数据组件会被完整复制到输出物品栈中。转变通常发生在两个不同物品之间,其中一个是另一个的染色版本。例如:

{
"type": "minecraft:crafting_transmute",
"category": "misc",
"group": "shulker_box_dye",
"input": "#minecraft:shulker_boxes",
"material": "minecraft:blue_dye",
"result": "minecraft:blue_shulker_box"
}

和之前一样,我们逐行解析如下:

  • type:这是无序配方序列化器(shapeless recipe serializer)的 ID,minecraft:crafting_transmute
  • category:这是一个可选字段,定义了配方在合成书中的类别。
  • group:这是一个可选字符串属性,用于在配方书中创建分组。属于同一分组的配方会在配方书中合并显示,这对于转变类配方通常很有意义。
  • input:需要转变的原料
  • material:将物品栈转变为结果的原料
  • result:配方的输出结果。这是一个物品,其物品栈会根据输入的组件进行构建。 然后,让我们看看如何在 RecipeProvider#buildRecipes 方法中生成这个配方(recipe):
// 我们使用构建者模式(builder pattern),因此不会创建变量。通过调用
// TransmuteRecipeBuilder#transmute 来创建一个新的构建者,参数包括配方类别(可在 RecipeCategory 枚举中找到)、
// 输入材料(ingredient input)、材料(ingredient material),以及生成的物品(resulting item)。
TransmuteRecipeBuilder.transmute(RecipeCategory.MISC, this.tag(ItemTags.SHULKER_BOXES),
Ingredient.of(DyeItem.byColor(DyeColor.BLUE)), ShulkerBoxBlock.getBlockByColor(DyeColor.BLUE).asItem())
// 设置配方在配方书中显示的分组(group)。
.group("shulker_box_dye")
// 创建配方的进度(advancement)。虽然后端系统并不强制要求这一点,
// 但如果省略,配方构建器会报错。第一个参数是进度名称,第二个参数是解锁条件。
// 通常,你可以使用 has() 快捷方式来设置条件。
// 可以多次调用 #unlockedBy 添加多个解锁条件。
.unlockedBy("has_shulker_box", this.has(ItemTags.SHULKER_BOXES))
// 将配方存储到传入的 RecipeOutput 中,最终写入磁盘。
// 如果你想为配方添加条件,可以在 output 上设置。
.save(this.output);

特殊合成(Special Crafting)

在某些情况下,输出结果必须根据输入动态生成。大多数时候,这样做是为了根据输入堆栈(input stacks)计算其值,并将数据组件(data components)设置到输出上。这类配方通常只指定类型(type),其他内容都硬编码。例如:

{
"type": "minecraft:crafting_special_armordye"
}

这个配方用于皮革盔甲染色(leather armor dyeing),只指定了类型,其他内容都硬编码——最突出的是颜色的计算,这在 JSON 中很难表达。Minecraft 会为大多数特殊合成配方加上 crafting_special_ 前缀,但其实并不强制要求遵循这种命名方式。

RecipeProvider#buildRecipes 方法中生成这个配方的方式如下:

// #special 方法的参数是一个 Function<CraftingBookCategory, Recipe<?>>。
// 所有原版特殊配方都使用只带一个 CraftingBookCategory 参数的构造函数。
SpecialRecipeBuilder.special(ArmorDyeRecipe::new)
// 这个 #save 重载允许我们指定配方名称。它也可以用于有形或无形配方构建器。
.save(this.output, "armor_dye");

原版提供了以下特殊合成(special crafting)序列化器(serializers)(模组也可以添加更多):

  • minecraft:crafting_special_armordye:用于给皮革护甲以及其他可染色物品染色。
  • minecraft:crafting_special_bannerduplicate:用于复制旗帜。
  • minecraft:crafting_special_bookcloning:用于复制已写书籍。复制后生成的新书的 generation 属性会加一。
  • minecraft:crafting_special_firework_rocket:用于合成烟花火箭。
  • minecraft:crafting_special_firework_star:用于合成烟花之星。
  • minecraft:crafting_special_firework_star_fade:用于为烟花之星添加渐变效果。
  • minecraft:crafting_special_mapcloning:用于复制已填充的地图。同样适用于藏宝图。
  • minecraft:crafting_special_mapextending:用于扩展已填充的地图。
  • minecraft:crafting_special_repairitem:用于将两个损坏的物品修复为一个完整的物品。
  • minecraft:crafting_special_shielddecoration:用于将旗帜图案应用到盾牌上。
  • minecraft:crafting_special_shulkerboxcoloring:用于在保留潜影盒内容的同时为其染色。
  • minecraft:crafting_special_tippedarrow:用于根据输入的药水合成对应的药箭。
  • minecraft:crafting_decorated_pot:用于通过陶片合成装饰陶罐。

类熔炉配方(Furnace-like Recipes)

第二类最重要的配方,就是通过熔炼或类似过程制作的配方。所有在熔炉(类型为 minecraft:smelting)、烟熏炉(minecraft:smoking)、高炉(minecraft:blasting)以及营火(minecraft:campfire_cooking)中完成的配方,都采用相同的格式:

{
"type": "minecraft:smelting",
"category": "food",
"cookingtime": 200,
"experience": 0.1,
"ingredient": {
"item": "minecraft:kelp"
},
"result": {
"id": "minecraft:dried_kelp"
}
}

我们来逐行解释一下:

  • type:这是配方序列化器(serializer)的 ID,这里为 minecraft:smelting。如果你制作的是其他类型的类熔炉配方,这个值可能会不同。
  • category:这是一个可选字段,定义了该配方在合成手册中的分类。
  • cookingtime:该字段决定了配方处理所需的时间,单位为 tick。所有原版熔炉配方使用 200,烟熏炉和高炉使用 100,营火使用 600。当然,你可以设置为任何你想要的数值。
  • experience:决定制作该配方时获得的经验值。这个字段可选,如果省略则不会获得经验。
  • ingredient:配方的输入 原料
  • result:配方的输出结果。这里是 物品堆的 JSON 表示

这些配方的数据生成(datagen)在 RecipeProvider#buildRecipes 方法中如下所示:

// 对于烟熏食谱请使用 #smoking,对于高炉食谱请使用 #blasting,对于营火食谱请使用 #campfireCooking。
// 除此之外,这些构建器的用法都相同。
SimpleCookingRecipeBuilder.smelting(
// 我们的输入原料。
Ingredient.of(Items.KELP),
// 我们的食谱分类。
RecipeCategory.FOOD,
// 我们的输出物品。也可以是一个 ItemStack。
Items.DRIED_KELP,
// 给予的经验值奖励
0.1f,
// 烹饪所需时间。
200
)
// 食谱的进度解锁条件,与上面的合成食谱类似。
.unlockedBy("has_kelp", this.has(Blocks.KELP))
// 这个 #save 的重载方法允许我们指定名称。
.save(this.output, "dried_kelp_smelting");
info

这些食谱的类型与其食谱序列化器相同,例如熔炉使用 minecraft:smelting,烟熏炉使用 minecraft:smoking,以此类推。

石切(Stonecutting)

石切机食谱使用 minecraft:stonecutting 食谱类型。它们非常简单,只需要指定类型、输入和输出:

{
"type": "minecraft:stonecutting",
"ingredient": "minecraft:andesite",
"result": {
"count": 2,
"id": "minecraft:andesite_slab"
}
}

type 字段定义了食谱序列化器(minecraft:stonecutting)。ingredient 是一个 原料,而 result 是一个基础的 物品堆 JSON。与合成食谱类似,也可以选择性地通过 group 字段在食谱书中进行分组。

RecipeProvider#buildRecipes 中的数据生成也很简单:

SingleItemRecipeBuilder.stonecutting(Ingredient.of(Items.ANDESITE), RecipeCategory.BUILDING_BLOCKS, Items.ANDESITE_SLAB, 2)
.unlockedBy("has_andesite", this.has(Items.ANDESITE))
.save(this.output, "andesite_slab_from_andesite_stonecutting");

请注意,SingleItemRecipeBuilder(单物品食谱构建器)并不支持真正的 ItemStack 结果,因此无法带有数据组件的结果。然而,食谱的编解码器(codec)确实支持这一点,所以如果需要该功能,需要自行实现一个自定义构建器。

锻造(Smithing)

锻造台支持两种不同的食谱序列化器(recipe serializer)。一种用于将输入转化为输出,并复制输入物品的组件(如附魔),另一种则用于为输入物品应用组件。两者都使用 minecraft:smithing 食谱类型,并且都要求三个输入,分别称为 base(基底)、template(模板)和 addition(附加物品)。

转化型锻造(Transform Smithing)

这种食谱序列化器用于将两个输入物品转化为一个输出物品,并保留第一个输入物品的数据组件。原版主要用于下界合金装备,但实际上可以用于任意物品:

{
"type": "minecraft:smithing_transform",
"addition": "#minecraft:netherite_tool_materials",
"base": "minecraft:diamond_axe",
"result": {
"count": 1,
"id": "minecraft:netherite_axe"
},
"template": "minecraft:netherite_upgrade_smithing_template"
}

让我们逐行拆解说明:

  • type:这是配方序列化器(recipe serializer)的 ID,这里为 minecraft:smithing_transform
  • base:配方的基础原料。通常是某种装备。
  • template:配方的模板原料。通常是锻造模板。
  • addition:配方的附加原料。通常是某种材料,例如下界合金锭。
  • result:配方的输出结果。这是物品堆栈的 JSON 表示

在数据生成(datagen)阶段,调用 SmithingTransformRecipeBuilder#smithing 方法,在 RecipeProvider#buildRecipes 中添加你的配方:

SmithingTransformRecipeBuilder.smithing(
// 模板原料
Ingredient.of(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE),
// 基础原料
Ingredient.of(Items.DIAMOND_AXE),
// 附加原料
this.tag(ItemTags.NETHERITE_TOOL_MATERIALS),
// 配方书分类
RecipeCategory.TOOLS,
// 输出物品。注意,虽然配方编解码器(codec)在这里接受物品堆栈(item stack),但构建器并不支持。
// 如果你需要输出物品堆栈,需要自定义构建器。
Items.NETHERITE_AXE
)
// 配方成就解锁条件,与上面其他配方类似。
.unlocks("has_netherite_ingot", this.has(ItemTags.NETHERITE_TOOL_MATERIALS))
// 此重载的 #save 方法允许我们指定配方名称。
.save(this.output, "netherite_axe_smithing");

装饰锻造(Trim Smithing)

装饰锻造是将护甲装饰(armor trims)应用到护甲上的过程:

{
"type": "minecraft:smithing_trim",
"addition": "#minecraft:trim_materials",
"base": "#minecraft:trimmable_armor",
"template": "minecraft:bolt_armor_trim_smithing_template"
}

同样,让我们逐项解析:

  • type:这是配方序列化器(recipe serializer)的 ID,这里为 minecraft:smithing_trim
  • base:配方的基础原料。所有原版用例都在这里使用 minecraft:trimmable_armor 标签。
  • template:配方的模板原料。所有原版用例都使用锻造装饰模板。
  • addition:配方的附加原料。所有原版用例都在这里使用 minecraft:trim_materials 标签。

你会注意到,这个配方序列化器没有 result 字段。这是因为它直接使用基础输入(base),并“应用”模板和附加物品,也就是说,它会根据其他输入设置基础物品的组件,并将该操作的结果作为配方的输出。

在数据生成阶段,调用 SmithingTrimRecipeBuilder#smithingTrim 方法,在 RecipeProvider#buildRecipes 中添加你的配方:

SmithingTrimRecipeBuilder.smithingTrim(
// 模板材料(template ingredient)。
Ingredient.of(Items.BOLT_ARMOR_TRIM_SMITHING_TEMPLATE),
// 基础材料(base ingredient)。
this.tag(ItemTags.TRIMMABLE_ARMOR),
// 附加材料(addition ingredient)。
this.tag(ItemTags.TRIM_MATERIALS),
// 配方书分类(recipe book category)。
RecipeCategory.MISC
)
// 配方进度(advancement),与上面的其它配方类似。
.unlocks("has_smithing_trim_template", this.has(Items.BOLT_ARMOR_TRIM_SMITHING_TEMPLATE))
// 这个 #save 的重载允许我们指定一个名称。没错,这个名字是直接复制自原版(vanilla)。
.save(this.output, "bolt_armor_trim_smithing_template_smithing_trim");

材料 物品 JSON