本篇教程由作者设定未经允许禁止转载。
模块化机械:社区版 从入门到入土 —— Part.2 配方创建
本篇教程皆在引导模块化机械与模块化机械:社区版的初学者入门,本教程包含最基本的添加配方功能。
如果你是从模块化机械转移到本模组,社区版完全兼容模块化机械 1.11.1 版本的原版所有内容,但是请注意:某些附属模组可能不兼容社区版,详细信息请查看社区版页面介绍。
本教程主要使用的模组为模块化机械:社区版 - 1.11.1-r33、咕咕工具。
注意:本教程内容可能随时都有变化,请仔细对照本教程使用的模组版本,以免引起模组更新导致莫名其妙的报错问题。
教程目录:
Part.2 基本配方创建(当前)
Part 3.2 配方适配器 RecipeAdapter(未完成)
Part.3.3 机械事件系统(未完成)
Part.4.1 并行配方处理(未完成)
Part.4.2 工厂系统(未完成)
Part.4.3 工厂事件系统(未完成)
Part.4.4 智能数据接口(未完成)
Part.4.5 单方块 / 多方块机械升级(未完成)
Part.4.6 自定义 GUI 信息(未完成)
Part.5 配置文件解析(未完成)
环境准备
本教程强烈推荐使用 Visual Studio Code(以下简称 VSCode),可以大大减少你的魔改工作量。
使用 VSCode,你可以利用它的强大的功能来更快的完成复杂的操作,同时拥有代码提示,大大减少代码阅读难度和出错率,同时可以安装插件来扩展功能,使其更加强大。
要创建配方,你需要对 ZenScript(ZS)有一定的了解,如果你不了解,推荐查看 友谊hj 所编写的 Zentutorial 中文教程文档。
安装模组
如果你已安装 CraftTweaker 和模块化机械本体且已启动游戏,你可以跳过此段描述。
要创建配方,你需要使用 CraftTweaker(任意版本)。
要查看创建的配方,你需要使用 JEI(任意版本)。
创建你的第一个配方
阅读本教程即表你已阅读 Part.1 机械创建 部分,因此本教程将继续沿用 Part.1 的加工机为主来创建配方。
修改结构
要创建配方,我们先要修改机械的部分内容,因此,本段教程将为加工机添加输入仓与输出仓。
模块化机械一共提供了三种类型的输入,分别是:物品输入仓、流体输出仓、能量输入仓,同理,也提供了三种相同类型的输出仓:物品输出仓、流体输出仓、能量输出仓。
其中,物品仓共有 7 种大小,而流体仓和能量仓共有 8 种大小。
值得注意的是,流体输入仓也支持通用机械的气体输入。
除物品仓之外,流体仓和能量仓的各种大小的容量都可以在配置文件中修改(进阶)。
接下来,我们将为加工机添加 1 个物品输入仓、1 个物品输出仓、1 个流体输入仓、1 个流体输出仓和 1 个能量输入仓。
现在,这是一个带有输入输出仓的机械。
红色框内的是能量输入仓,绿色框内的是物品输入仓与物品输出仓,框中心的是机械控制器,蓝色框内的是流体输入仓和流体输出仓,框中心的是机械电路板(装饰)。
现在使用建造选择工具选择并创建结构,由于我们已经在 Part.1 部分讲解了创建机械的教程,本处不再过多描述。
注:如果在使用建造选择工具的时候右击方块会打开 GUI,你可以在蹲下的时候再右击方块。
结构创建完成并修改文件后,重启游戏。
配方脚本创建
首先需要创建一个脚本:
打开游戏目录,并找到 scripts 文件夹。
(可选)在内部文件夹创建一个名为 modularmachinery 文件夹,或其他名称,然后打开文件夹。(方便分类)
在文件夹内创建一个名为 recipes.zs 的文件,或其他名称。
使用 VSCode 打开文件夹,并键入以下内容:
import mods.modularmachinery.RecipePrimer;
import mods.modularmachinery.RecipeBuilder;
import mods.modularmachinery.IngredientArrayBuilder; //此行仅限模块化机械:社区版
上方内容为导包,更方便的创建配方。
配方创建
接下来我们将为加工机添加一个电路板加工配方示例。
创建配方可以有多种写法,本段仅演示两个最常用的写法。通常情况下,推荐使用第一张写法。
第一种写法(链式调用):
RecipeBuilder.newBuilder("circuit_0", "machine_1", 80)
.addEnergyPerTickInput(800)
.addItemInputs([
<ore:ingotOsmium> * 8,
<mekanism:compressedredstone> * 1,
])
.addItemOutput(<mekanism:controlcircuit> * 8)
.build();
第二种写法(普通用法):
val builder as RecipePrimer = RecipeBuilder.newBuilder("circuit_0", "machine_1", 80);
builder.addEnergyPerTickInput(800);
builder.addItemInputs([
<ore:ingotOsmium> * 8,
<mekanism:compressedredstone> * 1,
]);
builder.addItemOutput(<mekanism:controlcircuit> * 8);
builder.build();
这段代码将会创建一个耗时 80 tick,每 tick 消耗 800 FE 能量,消耗 8 个矿辞为 ingotOsmium(锇锭)和一个压缩红石,制造 8 个基础控制电路的配方。
也许还不了解代码中的含义?接下来将解析每一行的作用:
//此段将会为注册名 machine_1 的机械创建一个配方名为 circuit_0 的配方,工作时间为 80 tick。
RecipeBuilder.newBuilder("circuit_0", "machine_1", 80)
//下方内容只能通过 RecipePrimer 或通过链式调用,不能单独调用。
//添加每 tick 消耗 800FE 的能量消耗。
addEnergyPerTickInput(800)
//此方法为 模块化机械:社区版独有,模块化机械原版不支持。
//addItemInput() 和 addItemInputs() 是两个方法,不要弄混了。
addItemInputs([
<ore:ingotOsmium> * 8,
<mekanism:compressedredstone> * 1,
]) //添加两个物品输入,可以是矿辞也可以是物品,此处输入了 8 个矿辞为 ingotOsmium 的物品输入和 1 个压缩红石物品输入。
//上面三行也可以写成一行,写成三行是为了提升可读性
addItemInputs([<ore:ingotOsmium> * 8, <mekanism:compressedredstone> * 1,]) //单行写法,最后一个逗号可以不要。
# 注:中括号(数组)不是必须的,但是要记得删最后一个逗号。
# 模块化机械原版等效方法
addItemInput(<ore:ingotOsmium>, 8) //注意,矿辞和数量是两个参数,不能用 “*”,只能用 “,”
addItemInput(<mekanism:compressedredstone> * 1)
//添加 8 个基础控制电路的物品输出
addItemOutput(<mekanism:controlcircuit> * 8)
//配方创建完毕后,在最后加上此方法,才能注册配方。注意:调用这个方法后,不能再添加其他输入了!
build();
注:链式调用每个方法前都需要加一个 “.”,而普通用法需要在每个方法后面加上 “;”,绝对不能缺少。
注:如果你想要获取一个物品在 ZS 里面的名称,你可以在游戏内手持相应物品,然后输入指令 /ct hand。
如果需要验证你的脚本是否编写正确,你可以在游戏内执行指令 /ct syntax 来验证脚本的语法。
配方添加完成后,保存文件,重启游戏。
如果你不想或不希望重启游戏,请继续阅读下方内容。
热重载
从 MMCE R28 起,模组还支持直接在游戏内重载大部分内容(需要安装 ZenUtils)。
你可以输入指令 /ct reload 或 /mm-reload、/mm-reload_client 来重载内容。
ct reload 可以正常重载大部分内容,默认情况下请使用该指令。
mm-reload 可以在服务器中使用(但是有可能会出现预料之外的问题)。
mm-reload_client 指令可以在服务器内重载客户端内容。
执行指令后,会输出与上图相似的内容,如果没有出现红字(即报错),则代表脚本没有问题,重载成功~
验证
重启游戏后,如果脚本没有运行问题,则你可以从 JEI 看到创建的配方。
如果需要添加其他类型的输入输出,请查看下方内容。
CrT 方法大全
下方列出了所有 ZS 可调用的模块化机械:社区版和部分模块化机械原版用法。
请务必先导包后,再使用下方方法。
基础
//创建一个配方构建器。
//recipeRegistryName = 配方名,每个机器对应的配方名,单个机器内绝对不能重复。
//associatedMachineRegistryName = 添加到哪个机械内(注册名)。
//processingTickTime = 工作时间(tick)。
//sortingPriority = 配方优先级,影响机器搜索配方的优先级。
//cancelIfPerTickFails = 如果配方运行时失败(例如跳电),是否强制取消配方(吞材料)。
RecipeBuilder.newBuilder(String recipeRegistryName, String associatedMachineRegistryName, int processingTickTime)
//例
RecipeBuilder.newBuilder("recipe_0", "machine_0", 80)
RecipeBuilder.newBuilder(String recipeRegistryName, String associatedMachineRegistryName, int processingTickTime, int sortingPriority)
//例
RecipeBuilder.newBuilder("recipe_0", "machine_0", 80, 99)
RecipeBuilder.newBuilder(String recipeRegistryName, String associatedMachineRegistryName, int processingTickTime, int sortingPriority, boolean cancelIfPerTickFails)
//例
RecipeBuilder.newBuilder("recipe_0", "machine_0", 80, 99, true)
通用输入输出和多种通用输入输出
单种输入输出:
//添加材料输入。可以是物品(支持 withTag()),流体或矿辞,不支持气体。
addInput(IIngredient input)
# 例
addInput(<ore:ingotOsmium> * 64)
addInput(<mekanism:controlcircuit> * 64)
addInput(<liquid:water> * 1000)
//添加材料输出。可以是物品(支持 withTag()),流体或矿辞,不支持气体。
addOutput(IIngredient input)
# 例
addOutput(<ore:ingotOsmium> * 64)
addOutput(<mekanism:controlcircuit> * 64)
addOutput(<liquid:water> * 1000)
多种输入输出:
//添加多种材料输入,支持 withTag()。大致用法与上方相同,但是可以一个括号内写多种物品。
addInputs(IIngredient... input)
# 例
addInputs(<ore:ingotOsmium> * 64, <mekanism:controlcircuit> * 64, <liquid:water> * 1000)
addInputs([<ore:ingotOsmium> * 64, <mekanism:controlcircuit> * 64, <liquid:water> * 1000,])
addInputs([
<ore:ingotOsmium> * 64,
<mekanism:controlcircuit> * 64,
<liquid:water> * 1000,
])
addInputs(
<ore:ingotOsmium> * 64,
<mekanism:controlcircuit> * 64,
<liquid:water> * 1000
)
//添加多种材料输出,支持 withTag()。大致用法与上方相同,但是可以一个括号内写多种物品。
addOutputs(IIngredient... input)
# 例
addOutputs(<ore:ingotOsmium> * 64, <mekanism:controlcircuit> * 64, <liquid:water> * 1000)
addOutputs([<ore:ingotOsmium> * 64, <mekanism:controlcircuit> * 64, <liquid:water> * 1000,])
addOutputs([
<ore:ingotOsmium> * 64,
<mekanism:controlcircuit> * 64,
<liquid:water> * 1000,
])
addOutputs(
<ore:ingotOsmium> * 64,
<mekanism:controlcircuit> * 64,
<liquid:water> * 1000
)
特定类型单种输入输出
物品:
//添加物品输入,支持 withTag(),可以是物品或矿辞(虽然说与 addInput() 的传入类型是一样的,但是它不能传入流体,会被丢弃)
addItemInput(IIngredient input)
# 例
addItemInput(<mekanism:controlcircuit> * 64)
# ***仅限模块化机械:社区版***
addItemInput(<ore:ingotOsmium> * 64)
# ***模块化机械原版等效写法,社区版已弃用***
addItemInput(<ore:ingotOsmium>, 64)
//添加物品输出,支持 withTag(),可以是物品或矿辞(虽然说与 addOutput() 的传入类型是一样的,但是它不能传入流体,会被丢弃)
addItemOutput(IIngredient input)
# 例
addItemOutput(<mekanism:controlcircuit> * 64)
# ***仅限模块化机械:社区版***
addItemOutput(<ore:ingotOsmium> * 64)
# ***模块化机械原版等效写法,社区版已弃用***
addItemOutput(<ore:ingotOsmium>, 64)
流体:
//添加流体输入
addFluidInput(ILiquidStack stack)
# 例
addFluidInput(<liquid:water> * 1000)
addFluidInput(<liquid:water>)
//添加流体输出
addFluidOutput(ILiquidStack stack)
# 例
addFluidOutput(<liquid:water> * 1000)
addFluidOutput(<liquid:water>)
气体:
//***安装通用机械时可用***
//添加气体输入
addGasInput(String gasName, int amount)
# 例
addGasInput("fusionfuel", 1000)
//添加气体输出
addGasOutput(String gasName, int amount)
# 例
addGasOutput("fusionfuel", 1000)
注:通用机械的气体名可以通过手持含有特定气体的气体储罐,然后执行指令 /ct hand 通过 tag 获取,如下图,红色框内去掉双引号即为气体名(关键词:gasName 后方内容)。
能量:
//添加每 tick 能量消耗
//注:最大值为 long 的上限,接近无限。
addEnergyPerTickInput(long perTick)
# 例
addEnergyPerTickInput(2147483648)
//添加每 tick 能量输出
//注:最大值为 long 的上限,接近无限。
addEnergyPerTickOutput(long perTick)
# 例
addEnergyPerTickOutput(2147483648)
特定类型多种输入输出
物品:
//添加多种物品输入,支持 withTag(),可以是物品或矿辞(虽然说与 addInputs() 的传入类型是一样的,但是它不能传入流体,会被丢弃)
addItemInputs(IIngredient... input)
# 例
addItemInputs([<minecraft:diamond> * 64, <ore:ingotOsmium> * 64, <mekanism:controlcircuit> * 64,])
addItemInputs(<minecraft:diamond> * 64,<ore:ingotOsmium> * 64,<mekanism:controlcircuit> * 64)
addItemInputs([
<minecraft:diamond> * 64,
<ore:ingotOsmium> * 64,
<mekanism:controlcircuit> * 64,
])
addItemInputs(
<minecraft:diamond> * 64,
<ore:ingotOsmium> * 64,
<mekanism:controlcircuit> * 64
)
//添加多种物品输出,支持 withTag(),可以是物品或矿辞(虽然说与 addOutputs() 的传入类型是一样的,但是它不能传入流体,会被丢弃)
addItemOutputs(IIngredient... input)
# 例
addItemOutputs([<minecraft:diamond> * 64, <ore:ingotOsmium> * 64, <mekanism:controlcircuit> * 64,])
addItemOutputs(<minecraft:diamond> * 64,<ore:ingotOsmium> * 64,<mekanism:controlcircuit> * 64)
addItemOutputs([
<minecraft:diamond> * 64,
<ore:ingotOsmium> * 64,
<mekanism:controlcircuit> * 64,
])
addItemOutputs(
<minecraft:diamond> * 64,
<ore:ingotOsmium> * 64,
<mekanism:controlcircuit> * 64
)
流体:
//添加多种流体输入
addFluidInputs(ILiquidStack... stacks)
# 例
addFluidInputs([<liquid:water> * 1000, <liquid:lava> * 1000,])
addFluidInputs(<liquid:water> * 1000, <liquid:lava> * 1000)
addFluidInputs([
<liquid:water> * 1000,
<liquid:lava> * 1000,
])
addFluidInputs(
<liquid:water> * 1000,
<liquid:lava> * 1000
)
//添加多种流体输出
addFluidOutputs(ILiquidStack... stacks)
# 例
addFluidOutputs([<liquid:water> * 1000, <liquid:lava> * 1000,])
addFluidOutputs(<liquid:water> * 1000, <liquid:lava> * 1000)
addFluidOutputs([
<liquid:water> * 1000,
<liquid:lava> * 1000,
])
addFluidOutputs(
<liquid:water> * 1000,
<liquid:lava> * 1000
)
特殊
概率:
//设置输出概率,支持设置的种类有物品(包括矿辞)和流体以及材料组(仅限社区版),其他不支持
//setChance 只能在添加物品之后再添加,否则为非法调用,详细用法请参考下方例子
//多种输入输出(如:addInputs()、addOutputs())不支持设置概率
//1.0 为 100%,0.0 为 0%
setChance(float chance)
# 例
addItemInput(<minecraft:diamond>).setChance(0) //永不消耗
addFluidInput(<liquid:water>).setChance(0.22) //22% 概率消耗
addItemOutput(<minecraft:diamond>).setChance(0.3) //30% 概率输出
addFluidOutput(<liquid:water>).setChance(1) //???
组件 Tag 匹配:
//设置组件 tag 匹配(高级)
//注意:这不是 NBT!请使用 CrT 自带的 withTag() 来设置 NBT!
setTag(String selectorTag)
组件 Tag 是一个高级功能,允许作者指定物品(不仅限物品)的输入输出仓(需要在机械文件中定义)
以下图为例:
//一旦被设置了 Tag,那么在机械结构内有 1 个以上的物品输出仓,则红石始终会被输出到 "selector-tag" 为 "receiver_array_structure" 的输出仓,输入或其他流体也同理。
addItemOutput(<minecraft:redstone>).setTag("receiver_array_structure");
材料组
材料组是特定的一组物品,它只会消耗这组物品的其中一种物品。
材料组内容可以是矿辞或物品,且每个物品都支持设定自己的消耗概率和数量。
注:目前仅支持物品输入,不支持物品输出
ZS 用法:
//添加物品组输入,效果等同上方图片
addIngredientArrayInput(
IngredientArrayBuilder.newBuilder()
.addIngredients([
<ore:ingotStellarAlloy>,
<ore:ingotGelidEnderium>,
<ore:ingotBoundMetal> * 2,
<ore:ingotSentientMetal> * 2,
])
.build() //build() 是可选的,只是强迫症原因(雾)
)