本篇教程由作者设定使用 CC BY-NC 协议。

一般来说,大部分的mod都会自带crt支持,少部分的mod没有crt支持,那这时候想使用crt增减配方怎么办呢。很简单,使用zenUtils的native功能就行了(或者去给mod作者发pr,一般都会通过)。首先你需要大概知道native功能有什么用(NativeMethodAccess (本地方法访问) ·friendlyhj/ZenUtils 维基)通过友谊妈写的wiki可以知道,它可以将crt和mc类互相转换,可以访问Java 原生类和方法等。

比如crafttweaker.world.IWorld这是一个crt类,你在他后面加个.native或者as World(当然你得导包import native.net.minecraft.world.World;)就能将他转为mc类:net.minecraft.world.World。

如IWorld.getFromID(0)是一个crt类,你在后面加个native或者as World就转换为mc类了(IWorld.getFromID(0).native | IWorld.getFromID(0)as World)

如果是要将mc类转换为crt类,那你需要在mc类的后面加个as crt类,如IWorld.getFromID(0).native as IWorld。

那可以互相转换类型有什么用呢。首先,crt类只能用于你写zenScript,你把crt类塞人家mc类该呆的位置,人家又不认识你,直接就给你爆了。所以你想要使用模组的函数 那你必须要把crt类转换成mc类。


那么接下来要做的事情就是找到mod的增添配方的位置,如果那个mod是开源的,那么只需要打开他的github或者其他软件的链接,在里面搜索recipe然后在里面找呀找,直到找到里面有一堆看起来就像是加减配方函数的文件,如mekceu就为mekceu配方链接,当然也不是所有mod都这么放,有的是一个机器塞一个文件如EIOEIO合金炉配方链接。我们拿mekceu举例,mekceu的大部分单方块机器都有crt支持,但多方块基本没有,那我们就先去mekceu配方链接里面搜索对应多方块的名字,如digitalAssemblyTable,这时就会找到327行的这个函数:

addDigitalAssemblyTableRecipe(ItemStack input, ItemStack input2, ItemStack input3, ItemStack input4, ItemStack input5, ItemStack input6, ItemStack input7, ItemStack input8, ItemStack input9, FluidStack inputFluid, GasStack inputGas,ItemStack outputItem, FluidStack outputFluid, GasStack outputGas, double extraEnergy, int ticks)

他里面有一个3*3的工作台样式的物品输入,一个流体输入,一个气体输入,一个物品输出,一个流体输出,一个气体输出,一个double的能量输入,一个int的工作时间。那现在就很简单了,我们已经知道想要给这个机器添加配方需要哪些要素了。那就新建一个zs文件,新建一个addDigitalAssemblyTableRecipe函数,由于是为了用zs来加配方,所以我们需要把他里面的mc类换成crt类,也就是:

function addDigitalAssemblyTableRecipe(itemInputs as IItemStack[],fluidInput as ILiquidStack,gasInput as IGasStack,itemOutput as IItemStack,fluidOutput as ILiquidStack,gasOutput as IGasStack,energy as double,duration as int)as void{}//因为他这input123...太多了所以换成了一个数组

那我们该怎么调用mekceu的这个函数呢,首先肯定得先导包,我们可以看到mekceu配方链接最上方有个package mekanism.common.recipe;我们只需要导入native+package名字+类名字。也就是

import native.mekanism.common.recipe.RecipeHandler;

然后使用类名字加函数就能访问了。RecipeHandler.addDigitalAssemblyTableRecipe(...)

那接下来我们先把这个塞到我们自己写的函数里。此时我们只需要把crt类转换成mc类再放到mek的函数里就行了。由于我们之前是把物品改成了个数组来写的,所以我们要先拆开来。

function addDigitalAssemblyTableRecipe(itemInputs as IItemStack[],fluidInput as ILiquidStack,gasInput as IGasStack,itemOutput as IItemStack,fluidOutput as ILiquidStack,gasOutput as IGasStack,energy as double,duration as int)as void{
    if(itemInputs.length != 9)return;//防止你物品输入少写或者多写,要判断里面的要素有多少
    val i1=itemInputs[0].native;
    val i2=itemInputs[1].native;
    val i3=itemInputs[2].native;
    val i4=itemInputs[3].native;
    val i5=itemInputs[4].native;
    val i6=itemInputs[5].native;
    val i7=itemInputs[6].native;
    val i8=itemInputs[7].native;
    val i9=itemInputs[8].native;
    RecipeHandler.addDigitalAssemblyTableRecipe(i1,i2,i3,i4,i5,i6,i7,i8,i9,fluidInput.native,gasInput.native,itemOutput.native,fluidOutput.native,gasOutput.native,energy,duration);
}

这时候我们保存文件,如果不出意外的话现在已经可以使用了,但我们还是去游戏里/ct syntax一下检测一下是否有语法错误。这时,游戏提示我们IGasStack没有native这个方法。这是为什么呢,其实这是因为GasStack并非mc类,而是mek自己写的一个类,这时想要添加气体得用mek的办法添加(GasStack),不过还好,mek的气体有crt支持,我们只需要找到crt气体支持的那个文件,将crt类转换一下就好了。找这种文件有个很方便的方法,先去找个有气体输入输出的机器,如加压反应室:reaction,找到这个文件Reaction,我们去看addRecipe那个函数那确实有个IGasStack gasInput,那我们就去看他是怎么把IGasStack转成GasStack的。41行可以看到他是用的GasHelper的toGas函数,那我们同样也用一下就行了。先导包import native.mekanism.common.integration.crafttweaker.helpers.GasHelper;然后再转换就完事了。

function addDigitalAssemblyTableRecipe(itemInputs as IItemStack[],fluidInput as ILiquidStack,gasInput as IGasStack,itemOutput as IItemStack,fluidOutput as ILiquidStack,gasOutput as IGasStack,energy as double,duration as int)as void{
    if(itemInputs.length != 9)return;
    val i1=itemInputs[0].native;
    val i2=itemInputs[1].native;
    val i3=itemInputs[2].native;
    val i4=itemInputs[3].native;
    val i5=itemInputs[4].native;
    val i6=itemInputs[5].native;
    val i7=itemInputs[6].native;
    val i8=itemInputs[7].native;
    val i9=itemInputs[8].native;
    val gasI=GasHelper.toGas(gasInput);
    val gasO=GasHelper.toGas(gasOutput);
    RecipeHandler.addDigitalAssemblyTableRecipe(i1,i2,i3,i4,i5,i6,i7,i8,i9,fluidInput.native,gasI,itemOutput.native,fluidOutput.native,gasO,energy,duration);
}

这时我们再打开游戏,输入/ct syntax。发现没有报错了,那我们加个配方进去试试。

addDigitalAssemblyTableRecipe([<minecraft:stone>,<minecraft:stone>,<minecraft:stone>,<minecraft:stone>,<minecraft:stone>,<minecraft:stone>,<minecraft:stone>,<minecraft:stone>,<minecraft:stone>],<liquid:water>*114,<gas:oxygen>*100,<minecraft:grass>,<liquid:lava>*514,<gas:brine>*30,88.0d,10);

输入9个石头和114的水100的氧气,输出一个草方块和514岩浆和50气态盐水,随便一点能量和时间。我们在文件的开头加上#reloadable。然后在游戏内输入/ct reload和/ct jeiReload就能热重载了,我们对着数字组装机按u,就能查看到我们添加的配方了。

[1.12.2]使用zu来为未添加crt支持的mod增删配方-第1张图片添加配方我们成功了,那如何删除配方呢,我们先尝试在mekceu配方链接里搜索removeDigitalAssemblyTableRecipe会发现没有这个函数,那我们就试试搜索remove,果然就在37行搜索到了,removeRecipe(@Nonnull Recipe<INPUT, OUTPUT, RECIPE> recipeMap, @Nonnull RECIPE recipe) ,我们先看看他要些什么,首先要一个非null的Recipe类,然后要一个非null的RECIPE类,我们先点一下Recipe可以在屏幕右边看到一个static class Recipe......,点一下跳转到那里,可以发现这还是在RecipeHandler.java内,他是一个RecipeHandler的内部类,那我们想要导这个包就得在RecipeHandler的后面再加上类名Recipe就行了。也就是:import native.mekanism.common.recipe.RecipeHandler.Recipe;

我们再来看看这个类是干嘛的,他里面有一堆final的变量名称,而且都还是大写的,可以猜到这个大概是用来存配方类型的,那我们是要删数字组装机的配方,那我们就找到DIGITAL_ASSEMBLY_TABLE,直接Recipe.DIGITAL_ASSEMBLY_TABLE调用就行了。

接下来是RECIPE类,同样是先点击RECIPE,我们会发现找不到这个类,不过我们能在这个文件下找到一个getRecipe函数,他是返回RECIPE的,那就很简单了,我们大概可以猜到removeRecipe里面的两个参数分别是配方类型和配方。我们之前在RecipeHandler文件里搜索digitalAssemblyTable时还找到过一个getDigitalAssemblyTableRecipe函数,他里面便是封装了一个getRecipe函数。有封装好的为什么不用的(当然你用getRecipe也行)。

我们可以看到getDigitalAssemblyTableRecipe里面有个CompositeInput类,我们点一下他,在屏幕右边有个class CompositeInput ...,打开这个文件,可以看到他的constructor方法是(ItemStack item, ItemStack item2, ItemStack item3, ItemStack item4, ItemStack item5, ItemStack item6, ItemStack item7, ItemStack item8, ItemStack item9,FluidStack fluid, GasStack gas),很明显这些参数就和我们之前添加配方的参数差不多,在上面也有标注说是input。那就很简单了,像添加配方那样写个函数就好了。首先导导包

import native.mekanism.common.recipe.inputs.CompositeInput;

然后把该填的都填进去就完事了

function removeDigitalAssemblyTableRecipe(itemInputs as IItemStack[],fluidInput as ILiquidStack,gasInput as IGasStack)as void{
    if(itemInputs.length != 9)return;
    val i1=itemInputs[0].native;
    val i2=itemInputs[1].native;
    val i3=itemInputs[2].native;
    val i4=itemInputs[3].native;
    val i5=itemInputs[4].native;
    val i6=itemInputs[5].native;
    val i7=itemInputs[6].native;
    val i8=itemInputs[7].native;
    val i9=itemInputs[8].native;
    val gasI=GasHelper.toGas(gasInput);
    RecipeHandler.removeRecipe(Recipe.DIGITAL_ASSEMBLY_TABLE,RecipeHandler.getDigitalAssemblyTableRecipe(CompositeInput(i1,i2,i3,i4,i5,i6,i7,i8,i9,fluidInput.native,gasI)));
}

我们可以随便删一个配方试试,就比如线程升级这个物品,我们把他的物品输入,流体输入和气体输入都填上去

removeDigitalAssemblyTableRecipe([<mekanism:ingot:4>*64,<mekanism:controlcircuit:3>*64,<mekanism:ingot:4>*64,<mekanism:tierinstaller>,<mekanism:modulebase>,<mekanism:tierinstaller>,<mekanism:atomicalloy>*64,<mekanism:energytablet>*4,<mekanism:atomicalloy>*64],<liquid:water>*20000,<gas:oxygen>*10000);

然后输入/ct reload和/ct jeiReload,我们再对着线程升级按r,就会发现配方已经删除成功了。到此,就算完结了。我的语言组织能力不行,大概能看得懂意思就好,看不懂的再问。

最后再放一下所有的代码

#reloadable

import crafttweaker.item.IItemStack;
import crafttweaker.liquid.ILiquidStack;
import mod.mekanism.gas.IGasStack;

import native.mekanism.common.recipe.RecipeHandler;
import native.mekanism.common.recipe.RecipeHandler.Recipe;
import native.mekanism.common.integration.crafttweaker.helpers.GasHelper;
import native.mekanism.common.recipe.inputs.CompositeInput;


function addDigitalAssemblyTableRecipe(itemInputs as IItemStack[],fluidInput as ILiquidStack,gasInput as IGasStack,itemOutput as IItemStack,fluidOutput as ILiquidStack,gasOutput as IGasStack,energy as double,duration as int)as void{
    if(itemInputs.length != 9)return;
    val i1=itemInputs[0].native;
    val i2=itemInputs[1].native;
    val i3=itemInputs[2].native;
    val i4=itemInputs[3].native;
    val i5=itemInputs[4].native;
    val i6=itemInputs[5].native;
    val i7=itemInputs[6].native;
    val i8=itemInputs[7].native;
    val i9=itemInputs[8].native;
    val gasI=GasHelper.toGas(gasInput);
    val gasO=GasHelper.toGas(gasOutput);
    RecipeHandler.addDigitalAssemblyTableRecipe(i1,i2,i3,i4,i5,i6,i7,i8,i9,fluidInput.native,gasI,itemOutput.native,fluidOutput.native,gasO,energy,duration);
}
addDigitalAssemblyTableRecipe([<minecraft:stone>,<minecraft:stone>,<minecraft:stone>,<minecraft:stone>,<minecraft:stone>,<minecraft:stone>,<minecraft:stone>,<minecraft:stone>,<minecraft:stone>],<liquid:water>*114,<gas:oxygen>*100,<minecraft:grass>,<liquid:lava>*514,<gas:brine>*30,88.0d,10);

function removeDigitalAssemblyTableRecipe(itemInputs as IItemStack[],fluidInput as ILiquidStack,gasInput as IGasStack)as void{
    if(itemInputs.length != 9)return;
    val i1=itemInputs[0].native;
    val i2=itemInputs[1].native;
    val i3=itemInputs[2].native;
    val i4=itemInputs[3].native;
    val i5=itemInputs[4].native;
    val i6=itemInputs[5].native;
    val i7=itemInputs[6].native;
    val i8=itemInputs[7].native;
    val i9=itemInputs[8].native;
    val gasI=GasHelper.toGas(gasInput);
    RecipeHandler.removeRecipe(Recipe.DIGITAL_ASSEMBLY_TABLE,RecipeHandler.getDigitalAssemblyTableRecipe(CompositeInput(i1,i2,i3,i4,i5,i6,i7,i8,i9,fluidInput.native,gasI)));
}
removeDigitalAssemblyTableRecipe([<mekanism:ingot:4>*64,<mekanism:controlcircuit:3>*64,<mekanism:ingot:4>*64,<mekanism:tierinstaller>,<mekanism:modulebase>,<mekanism:tierinstaller>,<mekanism:atomicalloy>*64,<mekanism:energytablet>*4,<mekanism:atomicalloy>*64],<liquid:water>*20000,<gas:oxygen>*10000);