本篇教程由作者设定未经允许禁止转载。
前言
KubeJS能干什么?如果能,该怎么实现?怎么使用更好的代码来实现?本文试图解答这些问题,并将会提供许多常用技巧及案例供大家参考。
Minecraft | Forge | KubeJS | Architectury | Rhino | ProbeJS |
1.19.2 | 43.3.5 | 1902.6.2-build.42 | 6.3.49 | 1902.2.2-build.280 | 5.3.2 |
使用Visual Studio Code 和ProbeJS
按照Visual Studio Code 和ProbeJS 安装之后,右键你的版本文件夹,通过code打开,可以看见类似如下的界面:
打开logs文件夹,把里面的文件长按拖动到右下角
3个文件都这样,以后再查看日志就更加方便了
编写代码时,可以看到ProbeJS提供的提示,按下Ctrl+空格可以再次唤起提示
使用KubeJS时的思路
当你想用KubeJS做某些事情时,你先要知道它该从哪里开始,一般是使用某个事件
事件的组成
事件被分为几个对象,每个对象中都有许多方法
PlayerEvents的方法:
decorateChat,chestOpened,advancement,chat,chestClosed,loggedIn,loggedOut,inventoryClosed,inventoryChanged,inventoryOpened,tick,respawned
在Wudji的教程或官方wiki中可以看到事件列表。当发生这些事件时可以开始执行代码。
使用ProbeJS可以直接看到事件的详细信息。
extra说明这个事件可以添加一个额外的参数,在这个实体受伤事件中表示受伤的实体的类型,如果不填也可以。@at表示事件是发生在服务端还是客户端或者都有。@cancellable说明这个事件可以被取消,如果没有就说明不能取消。
案例:
EntityEvents.hurt((event) => {
event.cancel();//当实体受伤时,取消事件
});
此时任何实体受伤都不会受到伤害,因为事件被取消了。若改为:
EntityEvents.hurt('minecraft:pig',(event) => {
event.cancel();//当minecraft:pig受伤时,取消事件
});
则只有minecraft:pig受伤时才会取消事件。它相当于简化了以下代码:
EntityEvents.hurt((event) => {
if (event.entity.type == "minecraft:pig") {
//当minecraft:pig受伤时
event.cancel(); //取消事件
}
});
某些事件是无法取消的,例如:
ServerEvents.loaded
loaded(handler: (event: Internal.ServerEventJS) => void): void
@at — server
event.cancel()同时还具有return的作用,它会直接退出函数。如果只使用return,那么只会退出函数而不会取消事件,例如:
EntityEvents.hurt((event) => {
if (event.entity.type != "minecraft:pig") {
//当不是minecraft:pig受伤时
return;//退出函数,后续代码不会执行
}
event.cancel(); //取消事件
});
回调函数
某些回调函数可以开始执行代码,例如注册一个物品时,当它被吃掉会运行一些代码:
StartupEvents.registry('item',event=>{
event.create('kubejs:test_food').maxStackSize(16).food(food=>{
food.hunger(5);
food.eaten(eaten=>{
eaten.player.tell('吃吃吃');
})
})
})
food.eaten()需要以一个回调函数,你可以在这个参数中写需要的代码。
如果想要热更新其中的部分代码,可以按照如下方式改写:
StartupEvents.registry("item", (event) => {
event
.create("kubejs:test_food")
.maxStackSize(16)
.food((food) => {
food.hunger(5);
food.saturation(1.5);
food.eaten((eaten) => {
global["test_food_eaten"](eaten);
});
});
});
global["test_food_eaten"] = (eaten) => {
eaten.player.tell("吃1吃");
};
为了在global函数中获得自动补全,你可以使用TypeScript也可以使用JSdoc。不管使用哪种,都需要获得这个回调函数的参数的类型。将鼠标放在eaten上,然后复制如下内容:
如果使用JSdoc,那么先在函数声明的上方(允许缩进,空格和空行)输入/* ,接下来按下Tab自动补全:
粘贴刚才复制的内容,之后下方的eaten参数就会被认为是Internal.FoodEatenEventJS而获得自动补全。
/**
*
* @param {Internal.FoodEatenEventJS} eaten
*/
global["test_food_eaten"] = (eaten) => {
eaten.player.tell("吃1吃");
};
当你第一次使用global后还需要重启游戏一次让global被加载到,在之后就只需要使用如下指令即可
/kubejs reload startup_scripts
获取和修改属性
我们总是需要获取和修改一些属性。获取属性可以使用get 或is 开头的方法:
let p = event.getPlayer();//获取事件的玩家
let f = p.isOnFire();//获取玩家是否着火
不过,如果这些方法没有参数,那么可以去掉get 或is 同时把首字母大写改成小写,直接获取属性:
let p = event.player;
let f = p.onFire;//只能更改首字母
let s = p.getHeldItem('main_hand');//需要参数不能简写
同理,修改属性(如果方法只有1个参数):
p.setHealth(10);//使用set 开头的方法修改属性
let h = p.health;//去掉set 并更改首字母,获取health 属性
h = 10;//直接赋值
以上代码可以使用解构赋值来优化:
let p = event.player;
let l = event.level;
const{player,level}=event;//除了变量名不同,没有区别
const{health}=player;//再解构一次
const{player:{health}}=event;//直接得到health
health = 10;//直接赋值
在之后的代码中都会使用解构赋值,以上使用单个字母作为变量名仅供演示。
一些JavaScript特性
使用JavaScript的特性可以优化代码,本节所有内容都会附带菜鸟教程和廖雪峰的官方网站的链接,希望你先学了JavaScript再来学KubeJS。
Array(数组)
在游戏中,可以输入以下命令获得一个物品的数组:
/kubejs hotbar
/kubejs inventory
#分别是快捷栏和物品栏
点击聊天栏复制,可能类似如下:
['minecraft:white_wool', 'minecraft:oak_wood', 'minecraft:oak_stairs', 'minecraft:jungle_planks']
接下来就可以到代码中去使用它:
ServerEvents.recipes((event) => {
let arr = [
"minecraft:white_wool",
"minecraft:oak_wood",
"minecraft:oak_stairs",
"minecraft:jungle_planks",
];
arr.forEach((f) => {
event.remove({ output: `${f}` });//批量移除物品配方
});
});
除了自己获得数组,你还可以使用Item.list获得,它是所有出现在创造模式物品栏中的物品的数组。
//在日志中打印出所有可附魔的物品
Item.list
.filter((f) => {
return f.enchantable;
})
.forEach((f) => {
console.log(f.toItemString());
});
//可能的输出的一部分:
//[15:17:48] [INFO] example.js#26: Item.of('minecraft:netherite_pickaxe', '{Damage:0}')
String(字符串)
字符串一般用于表示物品方块实体等,也可用于聊天事件中。
"命名空间 ID"可以表示1个物品,"10x 命名空间 ID"可以表示10个物品。
如果你想要更加方便的测试,可以试试:
PlayerEvents.chat((event) => {
const { player, message, level, server } = event;
if (message != "ts") {//如果不是ts就退出函数
return;
}
//当你在聊天栏输入ts时,将会执行代码
Item.list
.filter((f) => {
return f.enchantable;
})
.forEach((f) => {
console.log(f.toItemString());
});
});
一些小技巧和实例
以下是一些KubeJS的实例。
快速刷新
一次性刷新所有KubeJS可以刷新的脚本,并且比原版的/reload更快
PlayerEvents.chat((event) => {
const { player, message, level } = event;
const command = [
"client_scripts",
"config",
"lang",
"server_scripts",
"startup_scripts",
"textures",
];
if (message == "re") {
command.forEach((c) => level.runCommandSilent(`kubejs reload ${c}`));
player.tell(Text.of("Reloaded All Scripts!").green());
}
});