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

    MultiblockTweaker的高版本提供了对格雷科技社区版:非官方版自定义多方块机器的支持(而低版本则仅支持格雷科技社区版),本文将以格雷科技:新视野中的镧处理(独居石处理线)中使用的多方块机器溶解罐(对其进行了一些符合GTCEu审美的调整)来演示如何具体使用MultiblockTweaker构建它们。相较于低版本MultiblockTweaker,高版本除了对GTCEu的支持还有许多足够好的优化,例如不需要加载器(loader gregtech),也不需要自动添加id,这避免了许多问题。

    具体操作上,(我个人认为)讲多方块机器分为本体构造、控制器配方与机器配方三个部分有利于对脚本的调配,所以我们从第一者先开始说明,并在这些说明结束后对lang文件的相关内容进行补充说明。本体构造即利用MultiblockTweaker进行多方块机器的构造,以溶解罐为例:首先依旧是导包,

import mods.gregtech.multiblock.Builder;
import mods.gregtech.multiblock.FactoryBlockPattern;
import mods.gregtech.multiblock.RelativeDirection;
import mods.gregtech.multiblock.functions.IPatternBuilderFunction;
import mods.gregtech.IControllerTile;
import mods.gregtech.multiblock.CTPredicate;
import mods.gregtech.multiblock.IBlockPattern;
import mods.gregtech.recipe.FactoryRecipeMap;
import mods.gregtech.recipe.RecipeMap;
import mods.gregtech.recipe.functions.IRunOverclockingLogicFunction;
import mods.gregtech.recipe.IRecipeLogic;
import mods.gregtech.recipe.IRecipe;

然后使用FactoryRecipeMap的方式声明一个多方块机器的配方模式,即输出/输入情况:

global dissolution_tank as RecipeMap = FactoryRecipeMap.start("dissolution_tank_controller")
    .maxInputs(1)
    .maxFluidInputs(2)
    .maxFluidOutputs(1)
    .build();

接下来要进行的就是具体的多方块配置,构建的结构为构造器-解释器式的,即先声明多方块机器如何构造,使用何等方块,再解释其中的方块分别对应游戏中的何方块;对于机器控制器方块的渲染亦是从此处完成的,同时可以加载相应的配方:

Builder.start("dissolution_tank")
    .withPattern(function(controller as IControllerTile) as IBlockPattern {
        return FactoryBlockPattern.start()
            .aisle("M###M", "MMMMM", "MGGGM", "MGGGM", "#MMM#")
            .aisle("#####", "MNNNM", "G###G", "G###G", "MMMMM")
            .aisle("#####", "MNNNM", "G###G", "G###G", "MMMMM")
            .aisle("#####", "MNNNM", "G###G", "G###G", "MMMMM")
            .aisle("M###M", "MMCMM", "MGGGM", "MGGGM", "#MMM#")
            .where("C", controller.self())
            .where("G", <metastate:gregtech:transparent_casing>)
            .where("M", CTPredicate.states(<metastate:gregtech:metal_casing:5>)
                | CTPredicate.abilities(<mte_ability:MAINTENANCE_HATCH>).setMinGlobalLimited(1).setMaxGlobalLimited(1).setPreviewCount(1)
                | CTPredicate.abilities(<mte_ability:INPUT_ENERGY>).setMinGlobalLimited(1).setMaxGlobalLimited(2).setPreviewCount(1)
                | CTPredicate.abilities(<mte_ability:IMPORT_ITEMS>).setMinGlobalLimited(1).setMaxGlobalLimited(1).setPreviewCount(1)
                | CTPredicate.abilities(<mte_ability:IMPORT_FLUIDS>).setMinGlobalLimited(2).setMaxGlobalLimited(2).setPreviewCount(2)
                | CTPredicate.abilities(<mte_ability:EXPORT_FLUIDS>).setMinGlobalLimited(1).setMaxGlobalLimited(1).setPreviewCount(1)
            )
            .where("N", <metastate:gregtech:multiblock_casing:2>)
            .where("#", CTPredicate.getAir())
        .build();
    } as IPatternBuilderFunction)
    .withRecipeMap(dissolution_tank)
    .withBaseTexture(<metastate:gregtech:metal_casing:5>)
    .buildAndRegister();

其中 .aisle 的具体定位是需要调配的,利用CTPredicate包可以调配机器的可替换方块:例如上述的溶解罐中的可替换方块为,

| CTPredicate.abilities(<mte_ability:MAINTENANCE_HATCH>).setMinGlobalLimited(1).setMaxGlobalLimited(1).setPreviewCount(1)
| CTPredicate.abilities(<mte_ability:INPUT_ENERGY>).setMinGlobalLimited(1).setMaxGlobalLimited(2).setPreviewCount(1)
| CTPredicate.abilities(<mte_ability:IMPORT_ITEMS>).setMinGlobalLimited(1).setMaxGlobalLimited(1).setPreviewCount(1)
| CTPredicate.abilities(<mte_ability:IMPORT_FLUIDS>).setMinGlobalLimited(2).setMaxGlobalLimited(2).setPreviewCount(2)
| CTPredicate.abilities(<mte_ability:EXPORT_FLUIDS>).setMinGlobalLimited(1).setMaxGlobalLimited(1).setPreviewCount(1)

分别是维护仓,能源仓,输入总线,输入仓,输出仓;其中的三个调整参数分别为(这个方块在多方块机器中)最小数量,最大数量与展示数量(即在JEI中显示的数量)。利用 .withBaseTexture 可以声明这个多方块机器的控制器为何材质,例如:

.withBaseTexture(<metastate:gregtech:metal_casing:5>)

需要注意的是,在这些内容中调用的并不严格是方块本身,而是方块映射到的“元”版本,所以在声明时不能直接使用 <gregtech:metal_casing:5> 这样的形式。除此以外,还有一种无甚必要的方式实现同样的效果,即利用CTPredicate包调用这些内容,比如上面的

.where("G", <metastate:gregtech:transparent_casing>)

还可以利用CTPredicate来调用:

.where("G", CTPredicate.states(<metastate:gregtech:transparent_casing>))

单纯从代码风格上而言,固然在声明可替换方块时必须使用,但对于每个情况都如此使用便有些累赘。事实上,如果非要使用这种手段,你可以通过赋值的方式来尽可能简化你的代码,例如:

val transparent_casing = CTPredicate.states(<metastate:gregtech:transparent_casing>)

然后直接使用:

.where("G", transparent_casing)

这样同样可以达到效果。对于FactoryRecipeMap部分的内容放在一开始而区分于Builder部分(在我个人看来)可以便于调试,但是你也可以将它们直接在Builder部分而非利用赋值改换位置,这些对于代码上的建议都是基于个人的:在之前的过程中,我们使用 .withRecipeMap() 配合赋值来完成这部分

.withRecipeMap(dissolution_tank)

而直接写进去的办法亦可以效仿此法:

.withRecipeMap(
    FactoryRecipeMap.start("dissolution_tank_controller")
        .maxInputs(1)
        .maxFluidInputs(2)
        .maxFluidOutputs(1)
        .build();
)

两种方法并无差别。

    当你通过这种方法创造出一个多方块机器时,接下来除了为其的部件(例如控制器)配置具体配方以外还有配置相应的语言文件。在resources中创建multiblocktweaker文件夹,再在其中创造lang文件夹,在其中放入相应的语言文件即可。MultiblockTweaker的具体语言配置分为三个部分:多方块机器(整体)的名字与多方块在合成表中显示的名字。直观理解上,前两者是属于多方块机器自己的,而后者一般是JEI中查看相应合成表时显示于其上的名字。例如上面的溶解罐:

multiblocktweaker.machine.dissolution_tank.name=溶解罐
multiblocktweaker.multiblock.dissolution_tank.name=溶解罐
recipemap.dissolution_tank_controller.name=溶解罐

就需要如此三条内容。综上,我们就完成了一个多方块机器的具体构造,完整代码如下:

import mods.gregtech.multiblock.Builder;
import mods.gregtech.multiblock.FactoryBlockPattern;
import mods.gregtech.multiblock.RelativeDirection;
import mods.gregtech.multiblock.functions.IPatternBuilderFunction;
import mods.gregtech.IControllerTile;
import mods.gregtech.multiblock.CTPredicate;
import mods.gregtech.multiblock.IBlockPattern;
import mods.gregtech.recipe.FactoryRecipeMap;
import mods.gregtech.recipe.RecipeMap;
import mods.gregtech.recipe.functions.IRunOverclockingLogicFunction;
import mods.gregtech.recipe.IRecipeLogic;
import mods.gregtech.recipe.IRecipe;

global dissolution_tank as RecipeMap = FactoryRecipeMap.start("dissolution_tank_controller")
    .maxInputs(1)
    .maxFluidInputs(2)
    .maxFluidOutputs(1)
    .build();

Builder.start("dissolution_tank", 32002)
    .withPattern(function(controller as IControllerTile) as IBlockPattern {
        return FactoryBlockPattern.start()
            .aisle("M###M", "MMMMM", "MGGGM", "MGGGM", "#MMM#")
            .aisle("#####", "MNNNM", "G###G", "G###G", "MMMMM")
            .aisle("#####", "MNNNM", "G###G", "G###G", "MMMMM")
            .aisle("#####", "MNNNM", "G###G", "G###G", "MMMMM")
            .aisle("M###M", "MMCMM", "MGGGM", "MGGGM", "#MMM#")
            .where("C", controller.self())
            .where("G", <metastate:gregtech:transparent_casing>)
            .where("M", CTPredicate.states(<metastate:gregtech:metal_casing:5>)
                | CTPredicate.abilities(<mte_ability:MAINTENANCE_HATCH>).setMinGlobalLimited(1).setMaxGlobalLimited(1).setPreviewCount(1)
                | CTPredicate.abilities(<mte_ability:MUFFLER_HATCH>).setMinGlobalLimited(1).setMaxGlobalLimited(1).setPreviewCount(1)
                | CTPredicate.abilities(<mte_ability:INPUT_ENERGY>).setMinGlobalLimited(1).setMaxGlobalLimited(2).setPreviewCount(1)
                | CTPredicate.abilities(<mte_ability:IMPORT_ITEMS>).setMinGlobalLimited(1).setMaxGlobalLimited(1).setPreviewCount(1)
                | CTPredicate.abilities(<mte_ability:IMPORT_FLUIDS>).setMinGlobalLimited(2).setMaxGlobalLimited(2).setPreviewCount(2)
                | CTPredicate.abilities(<mte_ability:EXPORT_FLUIDS>).setMinGlobalLimited(1).setMaxGlobalLimited(1).setPreviewCount(1)
            )
            .where("N", <metastate:gregtech:multiblock_casing:2>)
            .where("#", CTPredicate.getAir())
        .build();
    } as IPatternBuilderFunction)
    .withRecipeMap(dissolution_tank)
    .withBaseTexture(<metastate:gregtech:metal_casing:5>)
    .buildAndRegister();

这些内容以.zs文件的方式放在scripts中,而如果你使用了自己绘制的材质,则需要先通过例如ContentTweaker等方式引入游戏中,再利用相应的构建方式构造方块(然后使用<metastate:contenttweaker:[方块名]>的方式引入),这部分内容需要放在resources文件夹中的对应位置,语言文件亦然。在构造控制器的合成表时,唯一需要注意的是其相应的编号,MultiblockTweaker在新版中可以避免手工标号的问题,但是相应造成的问题就是顺序上的(但是你仍旧可以手动声明机器的编号,这样在制作合成表时有些许的优势)。例如我们上述创造的溶解罐的id是32001,则它的控制器就是<gregtech:machine:32001>,这样我们就可以使用GTCEu标准的魔改手段构建合成了,例如:

import mods.gregtech.recipe.FactoryRecipeMap;
import mods.gregtech.recipe.RecipeMap;

assembler.recipeBuilder()
    .inputs([<gregtech:machine:989>, <gregtech:machine:1578> * 2, <gregtech:meta_item_1:130> * 4, <gregtech:meta_item_1:145> * 2, <ore:rotorTitanium> * 4, <ore:circuitEv> * 4])
    .circuit(6)
    .fluidInputs([<liquid:polytetrafluoroethylene> * 720])
    .outputs(<gregtech:machine:32002>)
    .duration(400)
    .EUt(960)
    .buildAndRegister();

这样就基本完成了多方块机器本体的构造,接下来只需要为其具体配置合成配方之类的即可。例如,我们要去除GTCEu中的稀土线,除了利用CraftTweaker把相应的配方去除以外,还可能需要创造相应的流体等内容,接下来只需要仿照一般的gt机器的recipemap就可以创造相应的配方。