配方材料替换

还记得 1.12 的 recipes.replaceAllOccurence 吗?这个方法允许你把所有配方的 A 物品替换为 B 物品。1.16 中,Replacer 提供了配方材料替换的功能,同时不像 1.12 只支持工作台,若模组提供了支持,Replacer 甚至可以修改别的模组的机器的配方!比起 1.12 一行解决问题,1.16 的 Replacer 比较复杂,但功能更强大!

导入

import crafttweaker.api.recipe.Replacer;

创建

首先你需要创建一个 Replacer。

  • Replacer.forEverything() 创建一个会影响所有配方的 Replacer,但并非所有配方都允许替换材料,并不推荐使用。

  • Replacer.forTypes(managers as IRecipeManager...) 创建一个会修改一个或多个 Recipe Types 下的 Replacer,如 Replacer.forTypes(craftingTable) 则是一个只会修改工作台配方的 Replacer。

  • Replacer.forMods(mods as string...) 创建只修改一个或多个模组的配方的 Replacer,如 Replacer.forMods("minecraft") 是一个只会修改原版配方的 Replacer

  • Replacer.forOutput(output as IIngredient, managers as IRecipeManager...) 创建只会修改输出指定物品的配方,managers 是 Recipe Types 白名单,如 Replacer.forOutput(<tag:items:forge:blocks/copper>, craftingTable) 只会修改各模组铜块(因为使用了 Tag)的工作台配方,managers 参数可省略,那就会尝试修改所有 Recipe Types 的指定物品的配方

  • Replacer.forRegexRecipes(regex as string) 创建一个只会修改 ID 符合指定正则的 Replacer,如 Replacer.forRegexRecipes("minecraft:wooden_.*")

  • Replacer.forRegexTypes(regex as string) 创建一个 ID 符合正则的 Recipe Type 以下的配方,如 Replacer.forRegexTypes("minecraft:[a-z]*ing"),虽然也只有工作台 ID 匹配这个正则

  • Replacer.forRecipes(recipes as WrapperRecipe[]) 创建只会修改特定配方的 Replacer,这里的参数是实打实的配方类,不是配方 ID,往往你需要 IRecipeManagergetRecipeByName 等方法获取。例子:Replacer.forRecipes(craftingTable.getRecipeByName("minecraft:emerald_block"));

  • Replacer.forCustomRecipeSet(myPredicate as BiPredicate<WrapperRecipe, IRecipeManager>); 最高级的用法,以 WrapperRecipe 和 IRecipeManager 为参数,需要返回 boolean 的 lambda 表达式为参数,使用这个你可以完全指定符合什么条件的 Recipe Type 和什么条件的配方(WrapperRecipe)才会被修改。

craftingTable 如果用 recipe type 尖括号表示,就是 <recipetype:minecraft:crafting>,但这有点长,CrT 内部已经把这个作为全局变量了。所以这里的 IRecipeManager,你能填 recipe type 尖括号,也能用前面原版配方修改使用的全局变量。craftingTable furnace 等等。

设置替换规则

创建完后,你需要设置替换规则,表示配方需要怎么改以及一些额外的排除信息。

排除

以下方法用于设置额外的排除规则,部分配方将会跳过处理。

  • excluding(managers as IRecipeManager...) 哪些 Recipe Types 的配方将会被跳过处理。

Replacer.forEverything().excluding(stoneCutter); 修改所有配方,但切石机处理的配方将会被跳过。

  • excluding(recipes as MCResourceLocation[]) ID 为哪些的配方将会跳过处理。

Replacer.forTypes(craftingTable).excluding(<resource:minecraft:comparator>, <resource:minecraft:boat>) 修改所有工作台配方,跳过红石比较器和船的配方。请注意这里的参数是 MCResourceLocation 而不是 string,所以你填的格式是不一样的。MCResourceLocation 需要尖括号引用,前缀为 resource

  • excludingMods(mods as string...) 哪些模组的配方将会被跳过。

Replacer.forTypes(craftingTable).excludingMods("mekanism", "botania") 修改所有工作台配方,除了 mek 和植魔的

替换

以下方法用于指定替换规则,哪些物品将会被替换成哪个。注意调用这些方法,只会使 Replacer 记录下这些规则,你最后还需要调用 execute 方法才会使 Replacer 开始工作!

这些方法返回 Replacer 本身,允许链性调用

replace(from as IIngredient, to as IIngredient) replaceFully(from as IIngredient, to as IIngredient)

replace 方法是递归匹配的。只要配方的材料有这个物品,就会被替换。比如如果你使用 replace(<item:minecraft:stone>, ...),这个配方如果使用 <tag:item:minecraft:stones> 这个石头物品标签,由于这个标签包含 <item:minecraft:stone>,也会被替换。如果你不想要这个行为,请使用 replaceFully

replaceFully 则是需要材料完全匹配,上面的例子如果你使用 replaceFully 则不会被替换。

执行

现在你设置好了替换目标、额外排除的内容和替换规则,你就可以最后调用 execute 无参方法使 Replacer 开始工作。一定要调用这个方法,否则不会干活的。

抑制警告

有很多配方不支持材料替换,别的模组的机器没做支持就先不提了。即使是普通工作台配方,也会有一些模组不讲武德注册了一些特殊的配方,CrT 无法处理它们,只能报一些警告告诉你部分配方无法被替换。你可以用 excluding 方法告诉 Replacer 要跳过这些配方,又或者直接调用 suppressWarnings 方法抑制这些警告。

尽可能少创建 Replacer

是的,你最好尽可能少的创建 Replacer。execute 方法将会遍历所有符合条件的配方。比如 Replacer.forTypes(craftingTable) 就会遍历所有工作台配方,而工作台配方有多少无需多言了。如果你创建了五个这样的 Replacer 就会遍历五次工作台配方,这会造成大量的性能浪费。你应该创建一个 Replacer,而设置多个替换规则。

例子

import crafttweaker.api.recipe.Replacer;

Replacer.forTypes(craftingTable) // 修改工作台配方
    .excludingMods("mekanism") // 排除 mek 配方
    .suppressWarnings() // 抑制警告
    .replace(<item:minecraft:gold_ingot>, <item:minecraft:stick>) // 替换规则 A:金锭替换成木棍
    .replace(<item:minecraft:diamond>, <item:minecraft:dirt>) // 替换规则 B:钻石替换成泥土
    .replace(<tag:items:forge:ingots/copper>, <item:minecraft:stone>) // 替换规则 C:铜锭替换成石头
    .execute(); // 最后记得调用这个方法开始执行替换

最后更新于