本篇教程由作者设定未经允许禁止转载。

模块化机械:社区版 从入门到入土 —— Part.2 配方创建

本篇教程皆在引导模块化机械与模块化机械:社区版的初学者入门,本教程包含最基本的添加配方功能。

如果你是从模块化机械转移到本模组,社区版完全兼容模块化机械 1.11.1 版本的原版所有内容,但是请注意:某些附属模组可能不兼容社区版,详细信息请查看社区版页面介绍。

本教程主要使用的模组为模块化机械:社区版 - 1.11.1-r33、咕咕工具

注意:本教程内容可能随时都有变化,请仔细对照本教程使用的模组版本,以免引起模组更新导致莫名其妙的报错问题。

教程目录:

  • Part.1 基本机械创建

  • Part.2 基本配方创建(当前)

  • Part.3.1 高级配方运用

  • 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.2 配方创建 —— 模块化机械 - 从入门到入土-第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。

Part.2 配方创建 —— 模块化机械 - 从入门到入土-第2张图片/ct hand 输出内容


如果需要验证你的脚本是否编写正确,你可以在游戏内执行指令 /ct syntax 来验证脚本的语法。

Part.2 配方创建 —— 模块化机械 - 从入门到入土-第3张图片如果脚本没有问题,将会输出类似上方的内容,如果出现其他内容(红字)则需要检查一下你的脚本了。


配方添加完成后,保存文件,重启游戏。

如果你不想或不希望重启游戏,请继续阅读下方内容。

热重载

从 MMCE R28 起,模组还支持直接在游戏内重载大部分内容(需要安装 ZenUtils)。

你可以输入指令 /ct reload 或 /mm-reload、/mm-reload_client 来重载内容。

  • ct reload 可以正常重载大部分内容,默认情况下请使用该指令。

  • mm-reload 可以在服务器中使用(但是有可能会出现预料之外的问题)。

  • mm-reload_client 指令可以在服务器内重载客户端内容。

Part.2 配方创建 —— 模块化机械 - 从入门到入土-第4张图片

执行指令后,会输出与上图相似的内容,如果没有出现红字(即报错),则代表脚本没有问题,重载成功~

验证

重启游戏后,如果脚本没有运行问题,则你可以从 JEI 看到创建的配方。

Part.2 配方创建 —— 模块化机械 - 从入门到入土-第5张图片使用 CrT 创建的一个配方


如果需要添加其他类型的输入输出,请查看下方内容。

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 后方内容)。

Part.2 配方创建 —— 模块化机械 - 从入门到入土-第6张图片气体

能量:

//添加每 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 是一个高级功能,允许作者指定物品(不仅限物品)的输入输出仓(需要在机械文件中定义)

以下图为例:

Part.2 配方创建 —— 模块化机械 - 从入门到入土-第7张图片

//一旦被设置了 Tag,那么在机械结构内有 1 个以上的物品输出仓,则红石始终会被输出到 "selector-tag" 为 "receiver_array_structure" 的输出仓,输入或其他流体也同理。
addItemOutput(<minecraft:redstone>).setTag("receiver_array_structure");

材料组

材料组是特定的一组物品,它只会消耗这组物品的其中一种物品。

材料组内容可以是矿辞或物品,且每个物品都支持设定自己的消耗概率和数量。

:目前仅支持物品输入,不支持物品输出

Part.2 配方创建 —— 模块化机械 - 从入门到入土-第8张图片材料组

ZS 用法:

//添加物品组输入,效果等同上方图片
addIngredientArrayInput(
    IngredientArrayBuilder.newBuilder()
        .addIngredients([
            <ore:ingotStellarAlloy>,
            <ore:ingotGelidEnderium>,
            <ore:ingotBoundMetal> * 2,
            <ore:ingotSentientMetal> * 2,
        ])
    .build() //build() 是可选的,只是强迫症原因(雾)
)