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

教程版本:v1.0.0 based on KubeJS-forge-1605.3.19-build.299 - mcmod

1.16.5 KubeJS综合魔改教程-第1张图片

前言

简要介绍

KubeJS是一个于1.16.5版本开始兴起的基于JavaScript的魔改核心模组,同时支持Fabric和Forge环境。在热重载的加持下,您可以很便捷地修改游戏中的绝大多数内容。从新增/修改物品,方块,配方到自定义游戏内逻辑、修改战利品表,自定义世界生成......没有什么是不能借助KubeJS轻松实现的。除此以外,KubeJS还可以用于管理服务器,修改客户端显示内容等。


本文相关信息

本教程最初发布于https://www.mcbbs.net/thread-1207772-1-1.html

本教程使用Markdown编写, 发布于mcmod需要重新排版,为了获得更完整流畅的观看体验现阶段还请前往mcbbs查看教程


本文将翻译,讲解部分该mod的常用功能及其附属mod,并提供多个实例以供参考

本文中未完成的部分会标记🚧

本文内没有特别注明的原创内容,均根据知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可

受本人水平,时间因素及KubeJS自身版本更新的影响,本文中难免还存在一些问题/过时内容,还请各位坛友斧正,谢谢!


实用链接

KubeJS 官方Wiki:https://mods.latvian.dev/books/kubejs

KubeJS 站内搬运贴:https://www.mcbbs.net/thread-1200250-1-1.html

KubeJS 源代码(1.16.5分支):https://github.com/KubeJS-Mods/KubeJS/tree/1.16/main/common/src/main/java/dev/latvian/kubejs

KubeJS 官方Discord交流频道:https://discord.gg/hCVTFHKE

本文部分内容参考/翻译自以上内容,在这里表示感谢


基础代码格式和常用指令

脚本语言


KubeJS使用 JavaScript 来对游戏进行修改(这也就是为什么 Rhino 会是它的前置)。


文件结构

在正确安装KubeJS并启动过一次游戏后,你可以在版本根目录下找到kubejs这个文件夹,

kubejs
├─assets
│  └─kubejs
│      └─textures
│          ├─block
│          └─item
├─client_scripts
├─config
├─data
├─exported
│  └─tags
├─server_scripts
└─startup_scripts

以下为各个目录的功能(详见目录下README.txt):

  • assets 文件夹和资源包的功能基本相同,你可以在这里的对应目录下放自定义方块、物品的纹理、模型等,也可以当做一个全局资源包加载器(类似于OpenLoader)

  • config 中包括对KubeJS的一些配置选项

  • data 文件夹和数据包功能基本相同,类似于全局数据包加载器(类似于OpenLoader)

  • client_scripts 中为客户端资源被加载时加载脚本

    • (如 client.tick 等被标记为Client和Client Startup的事件)(可使用 F3 + T 重载)

  • server_scripts 中为服务端资源被加载时加载的脚本

    • (如 recipes 等被标记为Server和Server Startup的事件)(可使用游戏内命令 /reload 重载)

  • startup_scripts 中为启动时就被加载的脚本

    • (如 item.modification 等被标记Startup的事件)(可使用游戏内命令 /kubejs reload_startup_scripts 重载)


代码基础格式

如JavaScript一样,所有的脚本后缀名都应为.js

代码基础格式如下

onEvent('事件名称', event => {

  //在此处编写代码 <- 这是一行注释,JavaScript的注释格式详见百度

})

比如,以下代码会在玩家加入世界时将指定内容打印到控制台

onEvent('player.logged_in', event => {
  let name = event.player.name
  console.log("玩家 " + name + " 加入了游戏")
})

其中 player.logged_in 就是被监听的事件,当该事件发生时,就执行函数内容(console.log语句)


JavaScript语法

在阅读本篇教程前,你最好先了解以下内容

JavaScript语法

if 和 if else

for循环

while循环

函数

箭头函数

当然,你也可以把 JavaScript教程 看一遍


KubeJS游戏内指令

使用/kubejs custom_command <command> 可以执行自定义指令

使用/kubejs errors 可以在聊天栏中获取当前脚本的报错

使用/kubejs export 可以将游戏内的配方、tags、所有方块、实体类型、流体类型导出到kubejs\exported\kubejs-server-export.json



使用/kubejs hand 或 /kjs_hand 可以快速获取手中物品信息,这对于配方自定义等非常有帮助(点击文本即可复制)

1.16.5 KubeJS综合魔改教程-第2张图片使用/kubejs hotbar 可以将快捷栏中所有物品信息打印到聊天栏(同/kubejs hand)

使用/kubejs inventory 可以将玩家物品栏的所有物品信息打印到聊天栏(同/kubejs hand)

使用/kubejs offhand 可以将玩家副手的物品信息打印到聊天栏(同/kubejs hand)

使用/kubejs list_tags <tag> [block|fluid|item|entity_type] 来将给定标签的内容打印到聊天栏

  • 如/kubejs list_tag minecraft:logs item 会将#minecraft:logs标签下的元素打印出来


使用/kubejs painter <玩家名称> <PainterJS对象> 来调用PainterJS(见第十六章)

使用/kubejs reload [server_scripts|lang|texture|startup_scripts] 来重载服务器类型脚本、语言文件、纹理资源和启动类型脚本

  • 其中/kubejs reload server_scripts和/reload的效果基本相同

  • /kubejs reload startup_scripts 并不能重载所有启动脚本事件,如方块注册等


使用/kubejs stage [add|list|remove|clear] <玩家名称> 来为指定玩家添加、列出、移除或清除游戏阶段

  • 关于Gamestage的详细介绍见11.4和11.5章节


使用/kubejs warnings 来查看当前脚本中的警告信息

使用/kubejs wiki 来打开官方KubeJS Wiki

KubeJS中的事件


事件ID是否可被取消类型
initNoStartup
postinitNoStartup
loadedNoStartup
command.registryNoServer
command.runYesServer
client.initNoClient
client.debug_info.leftNoClient
client.debug_info.rightNoClient
client.logged_inNoClient
client.logged_outNoClient
client.tickNoClient
server.loadNoServer
server.unloadNoServer
server.tickNoServer
server.datapack.firstNoServer
server.datapack.lastNoServer
recipesNoServer
world.loadNoServer
world.unloadNoServer
world.tickNoServer
world.explosion.preYesServer
world.explosion.postNoServer
player.logged_inNoServer
player.logged_outNoServer
player.tickNoServer
player.data_from_server.YesClient
player.data_from_client.YesServer
player.chatYesServer
player.advancementNoServer
player.inventory.openedNoServer
player.inventory.closedNoServer
player.inventory.changedNoServer
player.chest.openedNoServer
player.chest.closedNoServer
entity.deathYesServer
entity.attackYesServer
entity.dropsYesServer
entity.check_spawnYesServer
entity.spawnedYesServer
block.registryNoStartup
block.missing_mappingsNoServer
block.tagsNoServer
block.right_clickYesServer
block.left_clickYesServer
block.placeYesServer
block.breakYesServer
block.dropsNoServer
item.food_eatenYesServer
item.registryNoStartup
item.missing_mappingsNoServer
item.tagsNoServer
item.right_clickYesServer
item.right_click_emptyNoServer
item.left_clickNoServer
item.entity_interactYesServer
item.modificationNoStartup
item.pickupYesServer
item.tooltipNoClient
item.tossYesServer
item.craftedNoServer
item.smeltedNoServer
fluid.registryNoStartup
fluid.tagsNoServer
entity_type.tagsNoServer
worldgen.addNoStartup
worldgen.removeNoStartup

配方


本章代码文件应放于.minecraft\kubejs\server_scripts下
本章内容对应事件:recipes,即你的代码应该是这样的

onEvent('recipes', event => {
        //示例配方修改
        event.shaped('3x minecraft:stone', [
                'SSS',
                'S S',
                'SSS'
          ], {
                S: 'minecraft:sponge'
          })
})

本章为了表述简洁省略了onEvent部分

物品表示与新建配方

物品的表示方法——IngredientJS和ItemstackJS

KubeJS提供了IngredientJS和ItemstackJS用于表示物品。比如,标签Ingredient.of("#minecraft:logs")就是Ingredient,Item.of('minecraft:iron_ingot')就是一个Itemstack

其中Ingredient多用于匹配物品。你可以使用Ingredient.matchAny("条件")来获得一个包含当前筛选条件的物品组,其中条件可以为物品ID(minecraft:diamond),mod注册名(@tinkersconstruct),标签(#minecraft:logs)

Itemstack主要用于表示准确的物品组,ItemstackJS可使用的属性/函数如下:

属性功能返回值
id返回该物品组的id字符串
tags返回该物品组的tagsCollection<ResourceLocation> tags
count设置/返回该物品组中物品数量int
block返回当前物品是否为方块布尔值
nbt返回当前物品组的nbtCompoundTag
nbtString返回字符串形式的nbt字符串
name返回当前物品组的名称Text
enchantments返回当前物品组的附魔MapJS
harvestSpeed返回当前物品组的破坏速度浮点型
itemGroup返回当前物品组在创造物品栏的位置字符串
vanillaPredicate获取当前物品谓词(?)Predicate<ItemStack>
empty返回当前物品组是否为空布尔值
函数功能返回值
hasTag(tag)判断物品是否有指定tag布尔值
withCount(整形 数量)返回一个指定数量的物品组ItemStackJS
hasNBT()判断是否具有NBT布尔值
removeNBT()移除物品的NBTvoid
withNBT(CompoundTag nbt)返回具有指定NBT的物品组ItemStackJS
withName(Text 名称)返回一个具有指定名称的物品组ItemStackJS
strongEquals(any)将当前物品组与给定内容对比(同时比较数量等)布尔值
hasEnchantment(字符串 附魔ID, 整形 等级)判断当前物品组是否有给定的附魔布尔值
enchant(字符串 附魔ID, 整形 等级)返回一个添加了指定附魔的物品组ItemStackJS
enchant(MapJS 附魔内容)返回一个添加了指定附魔的物品组ItemStackJS
ignoreNBT()返回忽略的NBT的IngredientJSIngredientJS
weakNBT()返回部分忽略的NBT的IngredientJSIngredientJS
areItemsEqual(ItemStackJS 对比对象)将当前物品组与给定物品组对比布尔值
isNBTEqual(ItemStackJS 对比对象)将当前物品组与给定物品组的NBT对比布尔值
getHarvestLevel(ToolType 工具类型, nullable PlayerJS 玩家, nullable BlockContainerJS 方块)返回其挖掘等级整形
getHarvestSpeed(nullable BlockContainerJS 方块)返回其挖掘速度浮点型

配方修改需要用到的大都是上表加粗的内容,剩余的内容大都等到第15章判断物品状态时才会用到。

估计你看到上面这些东西得有点麻了,不要慌,让我们看几个例子

例子意义
Item.of("minecraft:iron_ingot").withCount(5)5个铁锭
Item.of("minecraft:iron_ingot").withCount(5).withName("KubeJS魔改教程")5个名字为"KubeJS魔改教程"的铁锭
Item.of("minecraft:diamond_sword").ignoreNBT()忽略了NBT的钻石剑(长用于忽略物品耐久、附魔等属性)
Item.of("minecraft:enchanted_book", {StoredEnchantments:[{lvl:1,id:"minecraft:sweeping"}]})横扫之刃I附魔书(直接添加NBT例子)
Item.of("minecraft:enchanted_book").enchant("minecraft:sweeping", 1)横扫之刃I附魔书(使用函数添加NBT例子)
Item.of(/create:.*/)所有机械动力物品(正则表达式)

显然,上面的方法表示物品非常麻烦。KubeJS提供了一些简写方法:

你可以使用命名空间ID直接表示一个物品,如"minecraft:iron_ingot"

你可以直接使用标签的字符串表示这一标签下的使用物品,如"#minecraft:logs"

你可以在命名空间前加上倍数来表示物品个数,如"5x minecraft:iron_ingot"表示五个铁锭

当然,你也可以直接使用正则表达式

你可以使用指令/kubejs hand来快速获取手持物品信息,详见1.1 基础代码格式和常用指令

有序配方添加

语句:event.shaped(输出物品 , 输入物品)

例子:用8个海绵合成3个石头

onEvent('recipes', event => { // 监听recipes事件
        // 主体修改内容
        event.shaped('3x minecraft:stone', [
                'SSS',
                'S S',
                'SSS'
          ], {
                S: 'minecraft:sponge'
          })
})

1.16.5 KubeJS综合魔改教程-第3张图片

可以看到,KubeJS采用了类似原版的格式来修改配方,如果你的配方不需要三行的话,直接留空即可

注:下文为了表述简洁将省略onEvent部分


无序配方添加

语句:event.shapeless(输出物品 , 输入物品)

例子:用1个石头和1个带萤石粉标签的物品合成4个圆石

event.shapeless('4x minecraft:cobblestone', ['minecraft:stone', '#forge:dusts/glowstone'])

1.16.5 KubeJS综合魔改教程-第4张图片熔炉高炉等配方的添加

  // 添加切石机配方:用1个minecraft:golden_apple合成4个minecraft:apple
  event.stonecutting('4x minecraft:apple', 'minecraft:golden_apple')

  // 添加切石机配方:用1个minecraft:golden_apple合成2个minecraft:carrot
  event.stonecutting('2x minecraft:carrot', 'minecraft:golden_apple')

  // 添加熔炉配方:用1个minecraft:golden_apple合成2个minecraft:carrot
  // (event.recipes.minecraft.smelting的缩写)
  event.smelting('2x minecraft:carrot', 'minecraft:golden_apple')

  // 添加高炉,营火和烟熏炉的配方(与上文类似)
  event.blasting('3x minecraft:apple', 'minecraft:golden_apple')

  // 添加锻造台配方,将后2个物品合并成第一个物品 (将minecraft:gold_ingot和minecraft:apple合成为minecraft:golden_apple)
  event.smithing('minecraft:golden_apple', 'minecraft:apple', 'minecraft:gold_ingot')

1.16.5 KubeJS综合魔改教程-第5张图片

NBT和配方ID

带NBT的配方修改:

  event.shaped('minecraft:book', [
    'CCC',
    'WGL',
    'CCC'
  ], {
    C: '#forge:cobblestone',
    L: Item.of('minecraft:enchanted_book', {StoredEnchantments:[{lvl:1,id:"minecraft:sweeping"}]}),
    // 尽管格式是相同的,但是对于附魔来说,你还可以将其简写成如下形式:
    W: Item.of('minecraft:enchanted_book').enchant('minecraft:respiration', 2),
    G: '#forge:glass'
  })

mc中所有的配方都有一个随机的ID,但以下配方被指定了一个唯一的静态ID。这个功能对于编写Patchouli手册等比较有用

event.smelting('minecraft:golden_apple', 'minecraft:carrot').id('wudjimodpack:wudji_first_recipe_id')

配方的修改与删除

配方的移除

例子用途解释
event.remove({})删除所有配方
event.remove({id: '配方ID'})移除合成该物品的所有配方
event.remove({input: '#forge:dusts/redstone'})移除所有以带有#forge:dusts/redstone标签为输入物品的配方
' '内也可以填物品ID
event.remove({output: '#minecraft:wool'})移除所有以带有#minecraft:wool标签为输出物品的配方
' '内也可以填物品ID
event.remove({mod: 'fabricexamplemod'})移除所有id为fabricexamplemod的mod添加的配方
event.remove({type: 'minecraft:campfire_cooking'})移除以营火为合成方式的配方
event.remove({output: 'minecraft:cooked_chicken', type: 'minecraft:campfire_cooking'})(叠加不同修改逻辑的示例)
移除用营火烤鸡肉的配方, 或者叫“移除以营火为合成方式,输出物品为熟鸡肉的配方”

配方的修改

  // 在所有无序配方中,将任何木板替换为minecraft:gold_nugget
  event.replaceInput({type: 'minecraft:crafting_shapeless'}, '#minecraft:planks', 'minecraft:gold_nugget')
  //{}内可以填写配方类别
  
  // 在所有配方中,将输出物品中的minecraft:stick替换为minecraft:oak_sapling
  event.replaceOutput({}, 'minecraft:stick', 'minecraft:oak_sapling')

非标准配方修改

本节将介绍非标准配方的修改,包括非工作台配方、修改输入物品状态等(如原版中蛋糕的合成方式)

例子1:修改机械动力中粉碎轮的合成配方

注意!KubeJS现已有机械动力的拓展mod,无需使用该方法修改!

机械动力的修改教程详见本教程12.3部分

event.custom({
    type: 'create:crushing',//指定合成方式为粉碎轮
    ingredients: [
      Ingredient.of('minecraft:oak_sapling').toJson()//输入内容
    ],
    results: [//这里的 results(包括所有类似的位置的双引号都是可加可不加的)
      Item.of('minecraft:apple').toResultJson(),//100%输出苹果
      Item.of('minecraft:carrot').withChance(0.5).toResultJson()//50%输出苹果
    ],
    processingTime: 100 //所用时间
  })
//若上述配方使用Json格式添加(即原版数据包格式)
{
  "type": "create:crushing",
  "ingredients": [
    {
      "tag": "minecraft:oak_sapling"
    }
  ],
  "results": [
    {
      "item": "minecraft:apple",
      "count": 1
    },
    {
      "item": "minecraft:carrot",
      "chance": 0.5
    }
  ],
  "processingTime": 100
}


如果你使用自定义的配方格式,你必须使用类似于原版Json数据包的格式,也就是必须带有"type": "mod:recipe_id"!(比如上文中提到的"type": "create:crushing"). 通过这种方式,你可以为使用原版配方系统的任何配方处理器添加配方,即使它不兼容KubeJS. KubeJS提供的简写格式为:

{item: '物品注册名', count: 数量} → Item.of('物品注册名', 数量).toResultJson()
{item: '物品注册名'} / {tag: '标签名'} →Ingredient.of('物品注册名').toJson() 和 Ingredient.of('#标签名').toJson()


下面我们再看一个例子

例子2:为Extended Crafting添加配方

event.custom({
    type: 'extendedcrafting:shaped_table',
    tier: 4,
    pattern: [
        "XXXXXXXXX",
        "X       X",
        "X       X",
        "X       X",
        "X       X",
        "X       X",
        "X       X",
        "X       X",
        "XXXXXXXXX"
  ],
  key: {
      X: [Ingredient.of('#forge:ingots/gold').toJson()],//标签的使用
  }
      result: [Ingredient.of('minecraft:apple').toJson()]
  })
//上述配方使用数据包修改:
{
  "type": "extendedcrafting:shaped_table",
  "pattern": [
    "XXXXXXXXX",
    "X       X",
    "X       X",
    "X       X",
    "X       X",
    "X       X",
    "X       X",
    "X       X",
    "XXXXXXXXX"
  ],
  "key": {
    "X": {
      "tag": "forge:ingots/gold"
    }
  },
  "result": {
    "item": "minecraft:apple"
  }
}

例子3:修改输入物品状态

以下是一些内置的函数

功能函数格式
为输入物品减去耐久.damageIngredient(要修改的物品(输入过滤器), 减去的耐久值(整形))
替换输入物品(比如桶).replaceIngredient(要替换的物品(输入过滤器), 替换的物品(物品组))
保持输入物品不变.keepIngredient(要保留的物品(输入过滤器))
自定义事件(Server StartUp脚本注册).customIngredientAction(要操作的物品(输入过滤器), 自定义事件ID(字符串))

其中,所谓的输入过滤器可接受如下类型的内容

内容示例
ItemStackJS'minecraft:dirt', Item.of('minecraft:diamond_sword').ignoreNBT() 等,具体见2.1
合成输入索引整形,如0,1,2......
对象{item: 'something', index: 0}

你可以在整个配方修改脚本的最后加上它们来实现你想要的效果,比如:

onEvent('recipes', event => {
      event.shapeless().damageItem(Item.of('minecraft:diamond_sword').ignoreNBT())
      ......})

下面是几个例子

onEvent('recipes', event => {
    //用钻石剑切西瓜
      event.shapeless('9x minecraft:melon_slice', [ //无序合成,合成输出: 9个西瓜片
        Item.of('minecraft:diamond_sword').ignoreNBT(), //输入一个忽略NBT的钻石剑
        'minecraft:minecraft:melon' // 其他输入内容
    ]).damageItem(Item.of('minecraft:diamond_sword').ignoreNBT()) // 降低钻石剑耐久1点(必须忽略NBT)

    // 使用两个钻石剑合成kubejs:example_block. 合成后索引为1的钻石剑掉一点耐久并保留第二个钻石剑.
    event.shaped('kubejs:example_block', [
        'SD ',
        'D S'
    ], {
        S: Item.of('minecraft:diamond_sword').ignoreNBT(),
        D: 'minecraft:dirt'
    }).damageIngredient(0).keepIngredient('minecraft:diamond_sword')//叠加使用多个函数

    // 使用两个钻石剑合成kubejs:example_block. 合成后钻石剑被替换为石剑
    event.shapeless('kubejs:example_block', [
        Item.of('minecraft:diamond_sword').ignoreNBT(),
        'minecraft:stone',
        Item.of('minecraft:diamond_sword').ignoreNBT(),
        'minecraft:stone'
    ]).replaceIngredient('minecraft:diamond_sword', 'minecraft:stone_sword')

    // 使用沙子,骨粉,土方块和水瓶合成陶土. 合成后,水瓶被玻璃瓶所替代
    event.shapeless('minecraft:clay', [
        'minecraft:sand',
        'minecraft:bone_meal',
        'minecraft:dirt',
        Item.of('minecraft:potion', {Potion: "minecraft:water"})
    ]).replaceIngredient({item: Item.of('minecraft:potion', {Potion: "minecraft:water"})}, 'minecraft:glass_bottle')
})

标签

你应将本文件的内容放于.minecraft\kubejs\server_scripts下

onEvent('item.tags', event => {
        // 获取 #forge:cobblestone,然后将minecraft:diamond_ore添加进去
        event.add('forge:cobblestone', 'minecraft:diamond_ore')
  
        // 获取#forge:cobblestone,然后移除minecraft:mossy_cobblestone
        event.remove('forge:cobblestone', 'minecraft:mossy_cobblestone')
  
        // 移除#forge:ingots/copper
        event.removeAll('forge:ingots/copper')
})

    实体标签等其他类型的标签同理

    自定义Loot Table

    (本章参考了Minecraft 原版模组入门教程 - 战利品表(作者ruhuasiyu)

    (Forge推荐安装KubeJS附属LootJS以便捷修改战利品表,教程&相关介绍见本文12-7 便捷战利品表修改(LootJS Forge))

    KubeJS目前能修改全局、方块、实体、猫或村民礼物(村庄英雄Buff)、钓鱼、宝箱战利品表

    基本的方法名称如下

    事件ID覆盖原有战利品表的方法名称修改战利品表的方法名称
    generic.loot_tablesaddGenericmodify
    block.loot_tablesaddBlockmodifyBlock
    entity.loot_tablesaddEntitymodifyEntity
    gift.loot_tablesaddGiftmodify
    fishing.loot_tablesaddFishingmodify
    chest.loot_tablesaddChestmodify

    下面就下面5种的战利品表进行讲解。

    基本格式

    onEvent('事件ID', event => {
      event.覆盖/修改原有战利品表方法名称('物品/实体注册名', table => {
          //修改内容
      }

      //table.clearPools()//清空所有随机池
      //table.clearConditions()//清空条件
      //table.clearFunctions()//清空函数
    })

    方块战利品表(block.loot_tables)

    针对方块战利品表,KubeJS提供了很简单的添加单方块掉落物的方法。

    onEvent('block.loot_tables', event => {
      event.addSimpleBlock('minecraft:dirt', 'minecraft:red_sand')//覆盖泥土的战利品表并使泥土掉落红沙
      event.addSimpleBlock('minecraft:oak_leaves')//覆盖橡树树叶的战利品表并使橡树树叶在破坏时掉落自身
    })

    如果你想要实现更复杂的修改,你需要使用随机池。KubeJS提供了一些简写方法,具体见下方例子。

    onEvent('block.loot_tables', event => {
      event.addBlock('minecraft:dirt', table => {
        table.addPool(pool => {//新建随机池(覆盖原有的)
          pool.rolls = 1 // 固定值
          // pool.rolls = [4, 6] // 也可写为 {min: 4, max: 6} // 抽奖次数∈[4,6]
          // pool.rolls = {n: 4, p: 0.3} // 二项分布
          //以上两种值的表达方式为值提供器
          pool.addItem('minecraft:dirt')
          //pool.addItem('minecraft:dirt', 40) // 此处40为权重
          //pool.addItem('minecraft:dirt', 40, [4, 8]) // 物品个数∈[4,8]
          // pool.addCondition({json}) //json格式,抽取该物品需要满足的条件,原版数据包格式(具体使用情景详见14.1)
          // pool.addEntry({json})//json格式,项目类别
        })
      })
    })

    实体战利品表(entity.loot_tables)

    onEvent('entity.loot_tables', event => {
      // 覆盖僵尸的战利品表,掉落5个物品(25%概率为胡萝卜,75%为苹果)
      event.addEntity('minecraft:zombie', table => {
        table.addPool(pool => {
          pool.rolls = 5//抽5次奖
          pool.addItem('minecraft:carrot', 1)
          pool.addItem('minecraft:apple', 3)
        })
      })

      event.modifyEntity('minecraft:pig', table => {
        table.addPool(pool => {
          // 修改猪的战利品表,使在被玩家杀死时多掉落一个泥土
          // 注:只是修改战利品表。并不会覆盖原有的掉落生/熟猪肉的战利品表
          pool.addItem('minecraft:dirt')
          pool.killedByPlayer()
        })
      })
    })

    注:对于gift.loot_tables、fishing.loot_tables、chest.loot_tables,只能使用addJson(物品注册名, json原版格式)来进行修改

    常用表达方式

          

    自定义流体

    KubeJS允许你在startup阶段自定义流体。对应事件:fluid.registry

    不过到目前为止,Fabric下的KubeJS还不支持自定义流体

    不得不说KubeJS还是非常良心的,注册流体还免费送你个桶(doge)


    函数功能返回值
    create(字符串 流体ID)新建流体FluidBuilder
    color(整形 颜色)设置流体颜色[1]FluidBuilder
    bucketColor(整形 颜色)设置流体桶内流体的颜色FluidBuilder
    textureStill(资源位置 ID)设置液体静止时的贴图FluidBuilder
    textureFlowing(资源位置 ID)设置液体流动时的贴图FluidBuilder
    textureThick(整形 颜色)设置液体静止时的颜色FluidBuilder
    textureThin(整形 颜色)设置液体流动时的颜色FluidBuilder
    luminosity(整形 发光度)设置流体亮度(默认值为0)[2]FluidBuilder
    density(整形 密度)设置流体密度(默认值为1000)FluidBuilder
    temperature(整形 稳定)设置流体温度(默认值为300)FluidBuilder
    viscosity(整形 粘稠度)设置流体粘稠度(默认值为1000)FluidBuilder
    gaseous()设置流体为气体(???¿¿¿)(默认值为false)FluidBuilder

    [1]:使用16进制,形如0x844031

    [2]:从本行往下,楼主测试时均无法实现预期效果,功能描述为楼主的"臆断"(游戏版本1.16.5 KubeJS版本1605.3.19-build.299),但是理论上这些是可以用的,可能和楼主电脑有关系吧

    例子:

    onEvent('fluid.registry', event => {
        event.create("test_mud").displayName("泥").bucketColor(0x844031).textureThick(0x844031).textureThin(0x844031);
    })

    1.16.5 KubeJS综合魔改教程-第6张图片

    自定义世界生成

    onEvent('worldgen.add', event => {
      event.addLake(lake => { // 自定义湖
        lake.block = 'minecraft:diamond_block' // 方块ID (使用 [] 来为其添加属性)
        lake.chance = 3 // 约3个区块生成一次
      })

      event.addOre(ore => { //自定义矿石
        ore.block = 'minecraft:glowstone' // 方块ID (使用 [] 来为其添加属性)
        ore.spawnsIn.blacklist = false // 是否在矿石生成黑名单位置处生成
        ore.spawnsIn.values = [ // 该矿石可以在以下位置生成(支持方块ID、标签)
          '#minecraft:base_stone_overworld' // 默认的生成方式: 用于决定作为地下矿石生成时,该矿石能取代哪些方块。你可以在https://wiki.biligame.com/mc/%E6%A0%87%E7%AD%BE查看更多信息。
        ]
        
        ore.biomes.blacklist = true // 是否在矿石生成黑名单群系中生成
        ore.biomes.values = [ // 矿石可以生成的群系
          'minecraft:plains', // 群系ID
          '#nether' // 或者你可以使用“# + 群系类别”来代表群系, 在文末查看可用的列表
        ]
        
        ore.clusterMinSize = 5 // 每矿簇最少的矿石数量 (现在 ore.clusterMinSize 选项是被忽略的, 该功能将在以后更新, 现在它恒为1)
        ore.clusterMaxSize = 9 // 每矿簇最多的矿石数量
        ore.clusterCount = 30 // 每个区块矿石数量
        ore.minHeight = 0 // 最小Y值
        ore.maxHeight = 64 // 最大Y值
        ore.squared = true // 对X和Z值添加0~16的随机值. 推荐设置为 true
        // ore.chance = 4 // 每大约4个区块生成一次. 对于稀有的矿石来说, 你可以将它和 clusterCount = 1 一同使用
      })
      
      event.addSpawn(spawn => { // 自定义实体生成
        spawn.category = 'monster' // 实体类别, 可以设为 'creature', 'monster', 'ambient', 'water_creature' 和 'water_ambient'
        spawn.entity = 'minecraft:magma_cube' // 实体ID
        spawn.weight = 10 // 生成权重
        spawn.minCount = 4 // 每组最小数量
        spawn.maxCount = 4 // 每组最大数量
      })
    })



    onEvent('worldgen.remove', event => {
      event.removeOres(ores => {//移除矿石
        ores.blocks = [ 'minecraft:coal_ore', 'minecraft:iron_ore' ] // 移除铁矿和煤矿
        ores.biomes.values = [ 'minecraft:plains' ] // 限制该选项仅在平原生效
      })
      
      event.removeSpawnsByID(spawns => {//通过实体ID来禁止指定实体生成
        spawns.entities.values = [
          'minecraft:cow',
          'minecraft:chicken',
          'minecraft:pig',
          'minecraft:zombie'
        ]
      })
      
      event.removeSpawnsByCategory(spawns => {//移除实体生成
        spawns.biomes.values = [
          'minecraft:plains'//指定为平原群系
        ]
        spawns.categories.values = [//类型为怪物
          'monster'
        ]
      })
    })

    修改展示

    1.16.5 KubeJS综合魔改教程-第7张图片

    1.16.5 KubeJS综合魔改教程-第8张图片

    1.16.5 KubeJS综合魔改教程-第9张图片

    自定义方块

    onEvent('block.registry', event => {
      event.create('test_block', block => {
            block.material('glass')//设置方块材质
          block.hardness(0.5)//设置方块硬度
          block.displayName('Test Block')
      })
    })

    // MC1.16版本的KubeJS 3还可以将以上内容简写为:
    onEvent('block.registry', event => {
      event.create('test_block')
             .material('glass')
           .hardness(0.5)
           .displayName('Test Block')
    })

    //你还可以把他们在一行中连着写
    onEvent('block.registry', event => {
        event.create('example_block').material('wood').hardness(1.0).displayName('Example Block')
    })

    该方块的纹理必须被放于kubejs/assets/kubejs/textures/block/[方块名],如kubejs/assets/kubejs/textures/block/test_block.png

    如果你想要使用自定义的模型,你可以使用Blockbench制作并把它放于 kubejs/assets/kubejs/models/block/[方块名].json , 如 kubejs/assets/kubejs/models/block/test_block.json.

    其他支持的方法(需要在它们之前加block.):

    • material('material')// 设置方块的“质地”,可用的参数见下

    • type('basic') // 设置方块类型,可用的参数见下

    • hardness(float) // 设置方块硬度,值需要大于 >= 0.0;若要使方块无法被破坏,详见下方。

    • resistance(float) // 爆炸抗性,值需要大于 >= 0.0

    • unbreakable() // 设置方块无法被破坏

    • lightLevel(等级) // 方块光照等级,值属于[0 , 1](需要为整形)

    • harvestTool('工具', 工具等级) // 可以破坏该方块的工具。工具参数可以为 pickaxe, axe, hoe, shovel,工具等级需 >= 0

    • opaque(布尔值) // 方块是否透明

    • fullBlock(布尔值) // 设置是否为完整方块,与notSolid()共同使用可以实现如下图所示效果(即镂空方块)

    • requiresTool(布尔值) // 是否需要对应工具才能掉落

    • renderType('类型') // 设置方块的渲染类型,可用的选项有solid(实心), cutout(镂刻), translucent(半透明), 其中 cutout 可用于类似于玻璃的方块,translucent 可用于类似于染色玻璃的方块

    • color(tintindex, color)// 修改方块颜色,具体可参考此处介绍

    • texture('纹理路径')// 设置方块纹理

    • texture('方向', '纹理路径')// 设置方块纹理(可以单独设置每个朝向的纹理)

    • model('模型路径')// 设置方块使用的模型

    • noItem()// 添加方块而不添加方块对应的物品

    • box(x0, y0, z0, x1, y1, z1, true) // 设置方块碰撞箱(0~16),默认值为(0,0,0,16,16,16, true)

    • box(x0, y0, z0, x1, y1, z1, false) // 设置方块碰撞箱(0~1),默认值为(0,0,0,1,1,1, false)

    • noCollision() // 设置方块是否有碰撞箱

    • notSolid() // 见上

    • waterlogged() // 是否可以被充水

    • noDrops() // 被破坏是否掉落自身

    • slipperiness(浮点型) // 设置打滑程度

    • speedFactor(浮点型) // 玩家在上方移动速度倍率

    • jumpFactor(浮点型)

    • randomTick(randomTickEvent => {}) // 当方块被随机刻选中时发生的事件
      支持以下函数:
      BlockContainerJS block
      Random random
      下面是一个简单的例子

    • //当test_block_randomTickEvent被随机刻选中时将其换为minecraft:dirt
      onEvent('block.registry', event => {
        event.create('test_block_randomTickEvent', block => {
            //block.material('glass')
            //block.hardness(1.0)
            block.displayName('Test Block randomTickEvent')
            block.randomTick(randomTickEvent => {
              randomTickEvent.block.set('minecraft:dirt')// BlockContainerJS
            })
        })
      })
    • 注:BlockContainerJS会在后面讲到(15章,尚未更新)

    • item(itemBuilder => {}) // 掉落物设置

    • setLootTableJson(json) // 设置战利品表(原版json格式)

    • setBlockstateJson(json) // 设置方块状态(原版json格式)

    • setModelJson(json) // 设置模型

    • noValidSpawns(布尔值) // 是否可以生成怪物

    • suffocating(布尔值) // 是否可以使玩家窒息

    • viewBlocking(布尔值)

    • redstoneConductor(布尔值) // 是否传导红石信号

    • transparent(布尔值) // 是否透明

    • defaultCutout() // 用来制作类似于玻璃的方块的方法的集合

    • defaultTranslucent() // 与defaultCutout()类似,但是使用透明层

    • tag('forge:exampletag') // 添加block tag

    • tagBlockAndItem('forge:exampletag') // 为方块和物品添加tag

      可用的方块类型(type() 方法)

      • basic

      • slab

      • stairs

      • fence

      • fence_gate

      • wall

      • wooden_pressure_plate

      • stone_pressure_plate

      • wooden_button

      • stone_button


      可用的材质的值( material('material') ) - 该参数会改变方块被破坏和玩家行走在上面的声音并且预设一些属性(如破坏用的工具等):

      材质
      air
      wood
      rock
      iron
      organic
      earth
      water
      lava
      leaves
      plants
      sponge
      wool
      sand
      glass
      tnt
      coral
      ice
      snow
      clay
      groud
      dragon_egg
      portal
      cake
      web
      slime
      honey
      berry_bush
      lantern

      聊天事件

      一个基础的例子:当有人在发送‘kubejs教程’时回复'请访问https://www.mcbbs.net/thread-1207772-1-1.html'

      onEvent('player.chat', function (event) {
           // 检测如果聊天内容为“kubejs教程” 执行命令, 忽略大小写
        if (event.message.trim().equalsIgnoreCase('kubejs教程')) {
           // 将事件推迟1刻,否则服务器信息将会显示在玩家信息之前
          event.server.scheduleInTicks(1, event.server, function (callback) {
            // 对每个人说以下内容,颜色为绿色。聊天信息为[Server]
            callback.data.tell(text.green('请访问h t  tp s://www.mcbbs.net/thread-1207772-1-1.html'[/url]))
            // 下面这个设置了聊天信息为红色的[Test]
            callback.data.tell([Text.red('[Test]'),text.green('请访问h t  tp s://www.mcbbs.net/thread-1207772-1-1.html')])
          })
        }
      })

      另一个例子:监测到聊天信息时执行对应指令

      onEvent('player.chat', function (event) {
        if (event.message.startsWith('test')) {
          event.server.runCommandSilent('kick '+event.player.name+' test ')
          event.server.runCommandSilent(`say 已踢出玩家${event.player.name}`)
          event.cancel()//取消该事件,也就是说玩家的聊天信息不会显示
        }
      })

      利用取消的这一特性,你甚至还可以做到"伪造"聊天
      下面这个例子在检测到发送消息的玩家带有 rankexample 进度时在其聊天信息前加上rank标识

      onEvent('player.chat',function (event){
          let input = event.message.trim();//获取聊天信息
          if(event.player.stages.has("rankexample")){
              event.server.tell([Text.blue('[MVP--]').bold(), `<${event.player.name}> ${input}`]);
              event.cancel();
          }
      })

      1.16.5 KubeJS综合魔改教程-第10张图片

      注:更多关于gamestage的操作详见11-4章节,关于玩家、世界的操作详见第15章

      后续教程待搬运,请先前往mcbbs阅读