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

前言

    最近在鼓捣GTL整合包的事情,发现其缺少将各种破碎、有瑕、无瑕晶体打粉的配方。

    辛辛苦苦筛出来的宝石,居然不能打粉,我不能忍!😂

    花了点时间研究了下js语法和kubuJS脚本解决了这个问题,基于整合包版本1.4.1.3


    整理了下思路,可以将脚本分为三步

  • 按标签读取物品列表

  • 生成输入输出和recipeID列表

  • 执行recipe注册


读取物品列表

kubeJS在其turial里面有提及相关的接口,如下

eventServerEvents.tags('item', event => {
      // Add all items from the forge:stone tag to the c:stone tag, unless the id contains diorite
      const stones = event.get('forge:stone').getObjectIds() //笔者注: 这里读取了含有输入标签的全部物品列表,返回的是一个obj类型数组
      const blacklist = Ingredient.of(/.*diorite.*/)
      stones.forEach(stone => {
            if (!blacklist.test(stone)) event.add('c:stone', stone)
      })
  })

通过 event.get('forge:stone').getObjectIds() 可以顺利得到含有需要的物品信息的数组

于是可以搞出下面这几句

    let chippedGemsObjList    = event.get('forge:chipped_gems').getObjectIds()
    let flawedGemsObjList     = event.get('forge:flawed_gems').getObjectIds()
    let flawlessGemsObjList   = event.get('forge:flawless_gems').getObjectIds()
    let exquisiteGemsObjList  = event.get('forge:exquisite_gems').getObjectIds()

有一个需要注意的点,这个数组和c++里面的数组不太一样,不能通过xxx[y]的形式访问,用typeof关键字确定其为java.util.ArrayList类型的数组,由目前未知的obj类型组成。

但是问题不大,可以通过以下的代码获取该obj类型的属性和值

//做非空判断避免错误
if(chippedGemsObjList.isEmpty() == false)
{
    //通过get(int index)访问特定元素
    let obj = chippedGemsObjList.get(0).namespace
    //打印各个属性的参数
    Object.keys(obj).forEach(key => {  
        console.log(`${key}: ${obj[key]}`);  
    });  
}

reload一下,得到以下输出:

[17:41:19] [INFO] debug.js#52: withPath: Function
[17:41:19] [INFO] debug.js#52: getClass: Function
[17:41:19] [INFO] debug.js#52: wait: Function
[17:41:19] [INFO] debug.js#52: toShortLanguageKey: Function
[17:41:19] [INFO] debug.js#52: withPrefix: Function
[17:41:19] [INFO] debug.js#52: notifyAll: Function
[17:41:19] [INFO] debug.js#52: setPath: Function
[17:41:19] [INFO] debug.js#52: compareTo: Function
[17:41:19] [INFO] debug.js#52: notify: Function
[17:41:19] [INFO] debug.js#52: path: chipped_rock_salt_gem
[17:41:19] [INFO] debug.js#52: toLanguageKey: Function
[17:41:19] [INFO] debug.js#52: getNamespace: Function
[17:41:19] [INFO] debug.js#52: hashCode: Function
[17:41:19] [INFO] debug.js#52: equals: Function
[17:41:19] [INFO] debug.js#52: compareNamespaced: Function
[17:41:19] [INFO] debug.js#52: getPath: Function
[17:41:19] [INFO] debug.js#52: namespace: gtceu
[17:41:19] [INFO] debug.js#52: toString: Function
[17:41:19] [INFO] debug.js#52: setNamespace: Function
[17:41:19] [INFO] debug.js#52: class: class net.minecraft.resources.ResourceLocation
[17:41:19] [INFO] debug.js#52: specialEquals: Function
[17:41:19] [INFO] debug.js#52: withSuffix: Function
[17:41:19] [INFO] debug.js#52: toDebugFileName: Function

注意到参数中namespace代表了物品所属的模组,path代表了物品的ID


obj类型的数组不能通过string 的方法进行处理,需要将其转换为string类型数组


//用forEach方法直接遍历访问各个元素的namespace和path属性,将其存储到新的一个数组中
function getGemInput(gemsObjList){
    let returnStringList = []
    gemsObjList.forEach(aaa =>{
        returnStringList.push("1x "+ aaa.namespace + ":" + aaa.path)
    })
    return returnStringList
}

别忘了之前是读取了四个标签的物品列表,这里将四个列表进行合并

用到了concat方法套娃

let gemsObjlist = chippedGemsObjList.concat(flawedGemsObjList.concat(flawlessGemsObjList.concat(exquisiteGemsObjList)))

到这里就已经读取列表完成了

看着很简单精炼,实际上卡了好久,第一次搞js语言,走了好多弯路


生成recipeID和输出产物

之前读取了四种标签的输入,四个标签的需要区分不同的产物

故定义了四种常数字符串

在生成产物数组的函数中额外添加了两个输入参数,分别是前缀(控制产物是小撮粉、普通粉还是小堆粉以及数量)、类型(识别是哪种碎宝石),用于区分

    const prefix_chipped    = "1x gtceu:tiny_"
    const prefix_flawed     = "2x gtceu:small_"
    const prefix_flawless   = "2x gtceu:"
    const prefix_exquisite  = "4x gtceu:"

    const Type_Chipped   = "chipped"
    const Type_flawed    = "flawed"
    const Type_flawless  = "flawless"
    const Type_exquisite = "exquisite"


function getGemOutput(gems, prefix, gemType) {
    let returnList = []    
    gems.forEach(gem => {
        let segments = gem.path.split("_");  
        let filteredSegments = segments.filter(segment => segment !== gemType && segment !== "gem");  
        let newElement = prefix + filteredSegments.join("_") + "_dust";  
        returnList.push(newElement);  
    })
    return returnList
}

实际调用,分别调用输入产物数组,存到输出产物数组中,最后concat套娃到一个数组中去

    let chippedOutput   = getGemOutput(chippedGemsObjList,prefix_chipped,Type_Chipped)
    let flawedOutput    = getGemOutput(flawedGemsObjList,prefix_flawed,Type_flawed)
    let flawlessOutput  = getGemOutput(flawlessGemsObjList,prefix_flawless,Type_flawless)
    let exquisiteOutput = getGemOutput(exquisiteGemsObjList,prefix_exquisite,Type_exquisite)

    gemOutput = chippedOutput.concat(flawedOutput.concat(flawlessOutput.concat(exquisiteOutput)))

至此,输出产物数组就完成了


同理可以搞定recipeID数组,用于区分每一个recipe,定义一个处理函数

function getGemRecipeID(gemsObjList){
    let retrunStringListRecipeID = []
    gemsObjList.forEach(aaa=>{
        retrunStringListRecipeID.push(aaa.path + "2Dsut")
    })
    return retrunStringListRecipeID
}

直接对总的输入产物数组调用该函数,生成recipeID数组

gemRecipe = getGemRecipeID(gemsObjlist)


用于批量生成recipe的数组全部生成完毕,下一步就是批量生成了


批量生成

直接用数组遍历,因为之前定义时就不使用查询函数返回的那个类型,而是string数组类型,所以可以直接使用xxx[y]的形式索引

ServerEvents.recipes(event => {
    for(let i = 0; i < gemRecipe.length ; i++)
    {
        event.recipes.gtceu.macerator(gemRecipe[i])
            .itemInputs(gemInput[i])
            .itemOutputs(gemOutput[i])
            .EUt(GTValues.VA[GTValues.ULV])
            .duration(20)
    }
})

代码总览

上面的文本是将每个部分分开解释,这里给出完成后的整个文件,放在server_scripts文件夹下

//添加破碎、有瑕、无瑕、精致的宝石粉碎配方

let gemRecipe = []
let gemInput = []
let gemOutput = []

//生成recipeID列表
function getGemRecipeID(gemsObjList){
    let retrunStringListRecipeID = []
    gemsObjList.forEach(aaa=>{
        retrunStringListRecipeID.push(aaa.path + "2Dsut")
    })
    return retrunStringListRecipeID
}

//生成输入物品列表
function getGemInput(gemsObjList){
    let returnStringList = []
    gemsObjList.forEach(aaa =>{
        returnStringList.push("1x "+ aaa.namespace + ":" + aaa.path)
    })
    return returnStringList
}

//生成输出物品列表
function getGemOutput(gems, prefix, gemType) {
    let returnList = []    
    gems.forEach(gem => {
        let segments = gem.path.split("_");  
        let filteredSegments = segments.filter(segment => segment !== gemType && segment !== "gem");  
        let newElement = prefix + filteredSegments.join("_") + "_dust";  
        returnList.push(newElement);  
    })
    return returnList
}

//监控标签事件,按标签读取列表和生成输入输出和recipceID等
ServerEvents.tags('item', event => {

    const prefix_chipped    = "1x gtceu:tiny_"
    const prefix_flawed     = "2x gtceu:small_"
    const prefix_flawless   = "2x gtceu:"
    const prefix_exquisite  = "4x gtceu:"

    const Type_Chipped   = "chipped"
    const Type_flawed    = "flawed"
    const Type_flawless  = "flawless"
    const Type_exquisite = "exquisite"

    let chippedGemsObjList    = event.get('forge:chipped_gems').getObjectIds()
    let flawedGemsObjList     = event.get('forge:flawed_gems').getObjectIds()
    let flawlessGemsObjList   = event.get('forge:flawless_gems').getObjectIds()
    let exquisiteGemsObjList  = event.get('forge:exquisite_gems').getObjectIds()

    let gemsObjlist = chippedGemsObjList.concat(flawedGemsObjList.concat(flawlessGemsObjList.concat(exquisiteGemsObjList)))

    gemRecipe = getGemRecipeID(gemsObjlist)
    gemInput = getGemInput(gemsObjlist)

    let chippedOutput   = getGemOutput(chippedGemsObjList,prefix_chipped,Type_Chipped)
    let flawedOutput    = getGemOutput(flawedGemsObjList,prefix_flawed,Type_flawed)
    let flawlessOutput  = getGemOutput(flawlessGemsObjList,prefix_flawless,Type_flawless)
    let exquisiteOutput = getGemOutput(exquisiteGemsObjList,prefix_exquisite,Type_exquisite)

    gemOutput = chippedOutput.concat(flawedOutput.concat(flawlessOutput.concat(exquisiteOutput)))

})

//导入配方
ServerEvents.recipes(event => {
    for(let i = 0; i < gemRecipe.length ; i++)
    {
        event.recipes.gtceu.macerator(gemRecipe[i])
            .itemInputs(gemInput[i])
            .itemOutputs(gemOutput[i])
            .EUt(GTValues.VA[GTValues.ULV])
            .duration(20)
    }
})

最终效果

[KJS][GTL]基于物品标签批量添加宝石打粉配方-第1张图片

[KJS][GTL]基于物品标签批量添加宝石打粉配方-第2张图片[KJS][GTL]基于物品标签批量添加宝石打粉配方-第3张图片