配方生成
继承 RecipeProvider 并实现 #buildRecipes,即可为模组生成配方。当消费者接受一个 FinishedRecipe 视图时,该配方就提供给数据生成。FinishedRecipe 可手动创建并提供,也可以方便地通过 RecipeBuilder 创建。实现后,必须将提供者添加到 DataGenerator。
原创说明图,依据 Forge 1.21.x 官方文档 绘制。
// 在模组事件总线上
@SubscribeEvent
public void gatherData(GatherDataEvent event) {
event.getGenerator().addProvider(
event.includeServer(), // 仅生成服务端数据时运行
MyRecipeProvider::new
);
}
RecipeBuilder
RecipeBuilder 是方便创建待生成 FinishedRecipe 的实现。它通过 #unlockedBy、#group、#save 和 #getResult 分别提供解锁、分组、保存及获取配方结果的基本定义。
重要:原版配方构建器不支持配方中的
ItemStack输出。要用现有原版配方序列化器生成此类数据,必须以其他方式构建FinishedRecipe。
警告:生成的物品结果必须指定有效的
RecipeCategory,否则会抛出NullPointerException。
除 SpecialRecipeBuilder 外,所有配方构建器都要求指定进度条件。所有配方都会生成一个条件:玩家此前使用过该配方时解锁它。但还必须指定一个额外条件,让玩家无需事先知道配方即可获得它。指定条件中任意一个为真时,玩家便在配方书中获得该配方。
提示:配方条件通常使用
InventoryChangeTrigger,在玩家物品栏存在某些物品时解锁配方。
ShapedRecipeBuilder
ShapedRecipeBuilder 生成有序配方,通过 #shaped 初始化。保存前可指定配方组、输入符号图案、符号对应的原料以及解锁条件。
// 在 RecipeProvider#buildRecipes(writer) 中
ShapedRecipeBuilder builder = ShapedRecipeBuilder.shaped(RecipeCategory.MISC, result)
.pattern("a a") // 创建配方图案
.define('a', item) // 定义符号代表的物品
.unlockedBy("criteria", criteria) // 解锁方式
.save(writer); // 将数据添加到 builder
额外验证
有序配方构建前还会进行以下验证:
- 必须定义图案,且包含多个物品。
- 所有图案行宽度必须一致。
- 同一符号不能定义多次。
- 空格字符(
' ')保留用于表示空槽位,不能定义。 - 图案必须使用用户定义的所有符号。
ShapelessRecipeBuilder
ShapelessRecipeBuilder 生成无序配方,通过 #shapeless 初始化。保存前可指定组、输入原料和解锁条件。
// 在 RecipeProvider#buildRecipes(writer) 中
ShapelessRecipeBuilder builder = ShapelessRecipeBuilder.shapeless(RecipeCategory.MISC, result)
.requires(item) // 添加物品
.unlockedBy("criteria", criteria) // 配方解锁方式
.save(writer); // 将数据交给写入器
SimpleCookingRecipeBuilder
该构建器生成熔炼、高炉、烟熏和营火烹饪配方;使用 SimpleCookingSerializer 的自定义烹饪配方也可使用它生成。分别通过 #smelting、#blasting、#smoking、#campfireCooking 或 #cooking 初始化,保存前可指定组和解锁条件。
// 在 RecipeProvider#buildRecipes(writer) 中
SimpleCookingRecipeBuilder builder = SimpleCookingRecipeBuilder.smelting(input, RecipeCategory.MISC, result, experience, cookingTime)
.unlockedBy("criteria", criteria) // 配方解锁方式
.save(writer); // 将数据交给写入器
SingleItemRecipeBuilder
该构建器生成切石配方,也可生成使用类似 SingleItemRecipe$Serializer 序列化器的自定义单物品配方。分别通过 #stonecutting 或构造函数初始化,保存前可指定组和解锁条件。
// 在 RecipeProvider#buildRecipes(writer) 中
SingleItemRecipeBuilder builder = SingleItemRecipeBuilder.stonecutting(input, RecipeCategory.MISC, result)
.unlockedBy("criteria", criteria) // 配方解锁方式
.save(writer); // 将数据交给写入器
不实现 RecipeBuilder 的构建器
一些配方构建器因缺少上述配方共有的功能而不实现 RecipeBuilder。
SmithingTransformRecipeBuilder
用于生成转换物品的锻造配方,也可生成使用类似 SmithingTransformRecipe$Serializer 的自定义配方。分别通过 #smithing 或构造函数初始化;保存前可指定解锁条件。
// 在 RecipeProvider#buildRecipes(writer) 中
SmithingTransformRecipeBuilder builder = SmithingTransformRecipeBuilder.smithing(template, base, addition, RecipeCategory.MISC, result)
.unlocks("criteria", criteria) // 配方解锁方式
.save(writer, name); // 将数据交给写入器
SmithingTrimRecipeBuilder
用于生成盔甲纹饰的锻造配方,也可生成使用类似 SmithingTrimRecipe$Serializer 的自定义升级配方。分别通过 #smithingTrim 或构造函数初始化;保存前可指定解锁条件。
// 在 RecipeProvider#buildRecipes(writer) 中
SmithingTrimRecipeBuilder builder = SmithingTrimRecipeBuilder.smithingTrim(template, base, addition, RecipeCategory.MISC)
.unlocks("criteria", criteria) // 配方解锁方式
.save(writer, name); // 将数据交给写入器
原文示例将类写成
SmithingTrimRecipe,与本节所述构建器不一致;译文改为SmithingTrimRecipeBuilder。下列代码沿用原文的链式写法,具体#save签名应以目标 Forge 版本为准。
SpecialRecipeBuilder
用于为不易限制在配方 JSON 格式内的动态配方生成空 JSON,例如盔甲染色和烟花。通过 #special 初始化。
// 在 RecipeProvider#buildRecipes(writer) 中
SpecialRecipeBuilder.special(dynamicRecipeSerializer)
.save(writer, name); // 将数据添加到构建器
条件配方
也可通过 ConditionalRecipe$Builder 生成条件配方,使用 #builder 获取构建器。
先调用 #addCondition 指定每个配方的条件,在全部条件指定后调用 #addRecipe。这一过程可以重复任意次数。指定所有配方后,可在末尾使用 #generateAdvancement 为每个配方添加进度;也可使用 #setAdvancement 设置条件进度。
// 在 RecipeProvider#buildRecipes(writer) 中
ConditionalRecipe.builder()
.addCondition(...) // 添加配方条件
.addRecipe(...) // 条件为真时返回的配方
.addCondition(...) // 下一配方的条件
.addRecipe(...) // 条件为真时返回的下一配方
.generateAdvancement() // 使用上述配方的条件和解锁进度创建条件进度
.build(writer, name);
IConditionBuilder
为方便向条件配方添加条件,无需手动构造每个条件实例,继承的 RecipeProvider 可实现 IConditionBuilder。该接口添加了方便构造条件实例的方法。
// 在 ConditionalRecipe$Builder#addCondition 中:
// examplemod:example_item 或 examplemod:example_item2 存在,且 NOT FALSE
// 以下方法由 IConditionBuilder 定义
(
and(
or(itemExists("examplemod", "example_item"), itemExists("examplemod", "example_item2")),
not(FALSE())
)
)
自定义配方序列化器
通过创建能构造 FinishedRecipe 的构建器,可以生成自定义配方序列化器的数据。完成的配方将配方数据和存在时的解锁进度编码为 JSON,还指定配方名称及序列化器,以确定写入位置及加载时由什么解码对象。构造完成后,只需将 FinishedRecipe 传入 RecipeProvider#buildRecipes 提供的 Consumer。
提示:
FinishedRecipe足够灵活,可生成任何对象转换的数据,而不限于物品。