配方原料

配料

Ingredient 是基于物品的输入谓词处理器,检查某个 ItemStack 是否满足作为配方有效输入的条件。所有接收输入的原版配方都使用一个 Ingredient 或一组最终合并为一个 Ingredient 的配料。

配料组合真值表:A 或 B 至少匹配一项,A 与 B 要同时匹配,差集 A 减 B 要匹配 A 且不匹配 B;图中给出四种 A、B 布尔组合的结果。

原创说明图,依据 Forge 1.21.x 官方文档 绘制。

自定义配料

将 type 设为配料序列化器名称即可指定自定义配料,复合配料除外。未指定类型时默认为原版 minecraft:item。自定义配料也可以方便地用于数据生成。

Forge 类型

Forge 提供若干额外的 Ingredient 类型。

CompoundIngredient

复合配料取代配方中的配料列表写法,功能相同:作为集合 OR,传入的堆至少要匹配其中一个配料。此更改让自定义配料在列表中正确工作,因此无需指定类型。

带注释和省略号的示例用于说明结构;实际 JSON 文件需移除注释并补全内容。

// 某个输入:至少一个配料必须匹配
[
  { /* 配料 */ },
  { "type": "examplemod:example_ingredient" } // 自定义配料
]
StrictNBTIngredient

严格比较 ItemStack 的物品、损伤及共享标签(由 IForgeItem#getShareTag 定义)是否完全相等。类型为 forge:nbt。

{
  "type": "forge:nbt",
  "item": "examplemod:example_item",
  "nbt": { /* 添加 NBT 数据,必须与堆完全一致 */ }
}
PartialNBTIngredient

这是 StrictNBTIngredient 的宽松版本:比较一个或一组物品,以及共享标签中指定的键。类型为 forge:partial_nbt。

{
  "type": "forge:partial_nbt",
  // 必须指定 item 或 items;如果两者都有,只读取 item
  "item": "examplemod:example_item",
  "items": ["examplemod:example_item", "examplemod:example_item2"],
  "nbt": {
    // 只比较 key1 和 key2,堆中的其他键不检查
    "key1": "data1",
    "key2": { /* 数据 2 */ }
  }
}
IntersectionIngredient

作为集合 AND,传入的堆必须匹配所有给定配料,且至少提供两个。类型为 forge:intersection。

{
  "type": "forge:intersection",
  // 所有配料都必须返回 true
  "children": [ { /* 配料 1 */ }, { /* 配料 2 */ } /* ... */ ]
}
DifferenceIngredient

作为集合减法,传入的堆必须匹配第一个配料,但不能匹配第二个。类型为 forge:difference。

{
  "type": "forge:difference",
  "base": { /* 堆所属的配料 */ },
  "subtracted": { /* 堆不属于的配料 */ }
}

创建自定义配料

为创建的 Ingredient 子类实现 IIngredientSerializer。建议继承 AbstractIngredient,因为它提供便于实现的抽象。

Ingredient 子类

需要实现三个重要方法:

方法 说明
getSerializer 返回用于读写配料的序列化器。
test 输入对此配料有效时返回 true。
isSimple 根据堆的标签匹配时返回 false。AbstractIngredient 子类需定义此行为,Ingredient 子类默认返回 true。

其他定义的方法留给读者根据子类需要自行使用。

IIngredientSerializer

子类必须实现三个方法:parse(JSON)将 JsonObject 转为 Ingredient;parse(网络)读取缓冲区并解码配料;write 将配料写入网络缓冲区。

此外,Ingredient 子类应实现 Ingredient#toJson 以用于数据生成。AbstractIngredient 将 #toJson 声明为抽象方法,要求实现。

声明静态实例保存初始化后的序列化器,然后在 RecipeSerializer 的 RegisterEvent 或 FMLCommonSetupEvent 期间使用 CraftingHelper#register 注册。配料子类的 Ingredient#getSerializer 返回该静态实例。

// 在某个序列化器类中
public static final ExampleIngredientSerializer INSTANCE = new ExampleIngredientSerializer();

// 在某个处理器类中
public void registerSerializers(RegisterEvent event) {
  event.register(ForgeRegistries.Keys.RECIPE_SERIALIZERS,
    helper -> CraftingHelper.register(registryName, INSTANCE)
  );
}

// 在某个配料子类中
@Override
public IIngredientSerializer<? extends Ingredient> getSerializer() {
  return INSTANCE;
}

提示:如果在 FMLCommonSetupEvent 注册配料序列化器,必须通过 FMLCommonSetupEvent#enqueueWork 加入同步工作队列,因为 CraftingHelper#register 不是线程安全的。

原文:Ingredients。