使用ReF创建的机器与一些主流科技模组的机器存在一个明显差别:

前者执行配方时能量会在进度条跑满后一次性消耗,而后者在执行的同时渐渐消耗。

本教程受启发于幻想科技(但实际上它的脚本并不能达成预期效果,作者应该是修改了ReF本身),给出了一种消除此差异的方法,以增加整合包的整体性。



整体思路


额外增加一个与机器能量槽等大的隐形能量缓冲槽,满足配方条件时每tick消耗能量槽中的能量并填充入能量缓冲槽,在进度条跑完时检测能量缓冲槽中的能量是否等于需要消耗的能量并清空能量缓冲槽。



实现


能量缓冲槽:

在正常定义能量槽的同时设置交互面为ComponentFace.none(),并调用setHidden()、setAccess(false, false)函数使其在GUI中不可见并且无法与能量管道交互。

如:

<assembly:chamber>.setEnergySlot(8, 2, ComponentFace.none(), 16000).setHidden()
.setAccess(false, false).setGroup("fake_energy");


检测配方条件:

新增一个能耗专用配方,调用setSubProcess(String)使其与原配方在不同处理组;物品、流体等条件与原配方相同,但设置抽取的min、max为0,这样原料就不会消耗;设置从能量槽抽取每tick需要消耗的能量并输出在缓冲槽中。

由于未知原因,设置不同处理组只能使两个配方在同一tick检测条件而无法在同一tick执行,所以需要额外设置世界条件:仅当缓冲槽中的能量小于一次配方所需能量时执行这个能耗专用配方。这是为了给原配方执行的机会,否则满足配方条件时只会不断执行能耗专用配方直至缓冲槽满或者能量槽空。

示例:

//这里用一个函数将这些操作封装以便调用
function chamberEnergyTick(itemIn as IIngredient, fluidIn as ILiquidStack, time as int, energyTick as int){
    var energyUse = mods.requious.AssemblyRecipe.create(function(container) {
        container.addEnergyOutput("fake_energy", energyTick);
    });
    //设置处理组
    energyUse = energyUse.setSubProcess("energyProcessing");
    //检测原料
    energyUse = energyUse.requireFluid("input1",fluidIn, 0, 0);
    energyUse = energyUse.requireItem("input2",itemIn, 0, 0);
    //设置世界条件
    energyUse = energyUse.requireWorldCondition("checkFakeEnergy", function(machineContainer) {
        //第一个条件检测缓冲槽能量小于配方所需能量,第二个条件是原配方已有条件(原配方有条件的话须和这个额外条件与处理),
        //用于检测能量槽中能量是否满足总能量需求。
        if(machineContainer.getEnergy(8, 2) < time * energyTick && 
        machineContainer.getEnergy(7, 1) >= time * energyTick)
                return true;
        return false;
    //下面这个"1"表示每1tick检测一次这个世界条件
    },1);
    energyUse = energyUse.requireEnergy("energy", energyTick);
    //无需添加在JEI中(避免多余的误导性显示)
    <assembly:chamber>.addRecipe(energyUse);
}


原配方及能量缓冲槽的处理:

能量条件不从能量槽抽取,从缓冲槽抽取(将min设为需消耗能量,max设为能量槽最大值,以达到清空缓冲槽效果),且将这个条件的检测置于进度条检测之后(使能量的减少与进度条同步进行)。

在跑进度条前增加世界条件(避免进度条跑满后发现能量不够停在那里有点丑):检测能量槽能量是否足够,如果不够不执行配方。

*注意JEI配方单独添加。

示例:

//使用函数封装操作以便调用
function chamberRecipe(itemIn as IIngredient, fluidIn as ILiquidStack, itemOut as IItemStack,
fluidOut as ILiquidStack, gasOut as ILiquidStack, energyTick as int, time as int){
    var recipe = mods.requious.AssemblyRecipe.create(function(container) {
        if(!isNull(itemOut))
            container.addItemOutput("output3",itemOut);
        if(!isNull(fluidOut))
            container.addFluidOutput("output2",fluidOut);
        if(!isNull(gasOut))
            container.addFluidOutput("output1",gasOut);
    });
    //设置处理组
    recipe = recipe.setSubProcess("recipeProcessing");
    recipe = recipe.requireFluid("input1",fluidIn);
    recipe = recipe.requireItem("input2",itemIn);
    //能量检测条件
    recipe = recipe.requireWorldCondition("checkEnergy", function(machineContainer) {
        if(machineContainer.getEnergy(7, 1) >= time * energyTick) return true;
        return false;
    },1);
    recipe = recipe.requireDuration("duration",time);
    //在进度条后添加对缓冲槽的处理
    recipe = recipe.requireEnergy("fake_energy", time * energyTick, 16000);
    <assembly:chamber>.addRecipe(recipe);
    //单独添加JEI配方
    var recipeJEI = mods.requious.AssemblyRecipe.create(function(container) {
        if(!isNull(itemOut))
            container.addItemOutput("output3",itemOut);
        if(!isNull(fluidOut))
            container.addFluidOutput("output2",fluidOut);
        if(!isNull(gasOut))
            container.addFluidOutput("output1",gasOut);
    });
    recipeJEI = recipeJEI.requireFluid("input1",fluidIn);
    recipeJEI = recipeJEI.requireItem("input2",itemIn);
    recipeJEI = recipeJEI.requireEnergy("energy", time * energyTick);
    recipeJEI = recipeJEI.requireDuration("duration",time);
    <assembly:chamber>.addJEIRecipe(recipeJEI);
    //调用以生成能耗专用配方
    chamberEnergyTick(itemIn, fluidIn, time, energyTick);
}


至此全部实现。下面是一个简单的调用示例:

chamberRecipe(<ore:dustSalt>, <liquid:water> * 600, null, <liquid:brine> * 600, null, 20, 70);



现在你的自定义机器就能更加接近科技模组里的"原装机器"啦!