📖 简介
Universe 模块内置了基于 Rhino 的 JavaScript 引擎,允许用户通过编写 JS 脚本来扩展功能。
你可以用JS脚本实现自定义功能、自动化操作、界面定制等。
💡 提示:脚本运行在独立的沙箱环境中,不会影响核心功能的稳定性。
🚀 快速开始
第一个脚本
function onEnable() {
Log.info("脚本已启用!");
KJ.print("Hello, KJ!");
}
function onDisable() {
Log.info("脚本已禁用");
}
function onTick() {
}
生命周期
| 函数名 | 调用时机 | 说明 |
onEnable() | 脚本启用时 | 初始化代码放这里 |
onDisable() | 脚本禁用时 | 清理代码放这里 |
onTick() | 每游戏帧 | 约60次/秒 |
onChat(msg) | 收到聊天消息时 | msg为消息内容 |
📝 语法说明
Universe 脚本使用标准 JavaScript ES6 语法,基于 Mozilla Rhino 引擎。
支持的特性
- 变量声明:var, let, const
- 函数:普通函数、箭头函数
- 对象、数组、字符串方法
- 条件语句、循环
- 正则表达式
- JSON 解析/序列化
- setTimeout / setInterval
⚠️ 注意:onTick 函数中请避免执行耗时操作,否则可能导致游戏卡顿。
🎮 KJ 核心对象
全局对象 KJ 提供了所有游戏相关的API。
工具方法
| 方法 | 参数 | 返回值 | 说明 |
KJ.print(obj) |
anyobj |
void |
输出到控制台 |
KJ.toast(msg) |
stringmsg |
void |
显示Toast提示 |
KJ.getCurrentTimeMs() |
无 |
int |
获取当前时间戳(毫秒) |
KJ.getVersion() |
无 |
string |
获取模块版本号 |
👤 玩家 API
| 方法 | 返回类型 | 说明 |
KJ.getPlayerX() | float | 玩家X坐标 |
KJ.getPlayerY() | float | 玩家Y坐标 |
KJ.getPlayerZ() | float | 玩家Z坐标 |
KJ.getPlayerName() | string | 玩家名称 |
KJ.getPlayerHealth() | float | 玩家生命值 |
KJ.getPlayerHunger() | float | 玩家饥饿值 |
KJ.getPlayerDimension() | int | 维度ID (0=主世界, 1=地狱, 2=末地) |
KJ.isPlayerSprinting() | boolean | 是否在疾跑 |
KJ.isPlayerOnGround() | boolean | 是否在地面 |
KJ.isPlayerInWater() | boolean | 是否在水中 |
KJ.setPlayerMotion(x, y, z) | void | 设置玩家速度 |
KJ.sendChat(message) | void | 发送聊天消息 |
KJ.swingItem() | void | 挥动手臂 |
示例
var lastHello = 0;
function onTick() {
var now = KJ.getCurrentTimeMs();
if (now - lastHello > 60000) {
var name = KJ.getPlayerName();
KJ.sendChat("大家好!我是" + name);
lastHello = now;
}
}
🌍 世界 API
| 方法 | 返回类型 | 说明 |
KJ.getBlockX() | float | 准星指向方块X |
KJ.getBlockY() | float | 准星指向方块Y |
KJ.getBlockZ() | float | 准星指向方块Z |
KJ.getBlockName(x, y, z) | string | 获取方块名称 |
KJ.getBlockId(x, y, z) | int | 获取方块ID |
KJ.isBlockSolid(x, y, z) | boolean | 方块是否为实心 |
👾 实体 API
| 方法 | 返回类型 | 说明 |
KJ.getEntityCount() | int | 附近实体数量 |
KJ.getEntityName(index) | string | 实体名称 |
KJ.getEntityX(index) | float | 实体X坐标 |
KJ.getEntityY(index) | float | 实体Y坐标 |
KJ.getEntityZ(index) | float | 实体Z坐标 |
KJ.getEntityHealth(index) | float | 实体生命值 |
KJ.isEntityPlayer(index) | boolean | 是否为玩家 |
KJ.getDistanceToEntity(index) | float | 距离实体的距离 |
示例:列出附近玩家
function listNearbyPlayers() {
var count = KJ.getEntityCount();
var players = [];
for (var i = 0; i < count; i++) {
if (KJ.isEntityPlayer(i)) {
var name = KJ.getEntityName(i);
var dist = KJ.getDistanceToEntity(i).toFixed(1);
players.push(name + " (" + dist + "m)");
}
}
Log.info("附近玩家: " + players.join(", "));
return players;
}
🎒 背包 API
| 方法 | 返回类型 | 说明 |
KJ.getInventorySlot() | int | 当前选中的快捷栏槽位(0-8) |
KJ.setInventorySlot(slot) | void | 切换快捷栏槽位 |
KJ.getSlotItem(slot) | string | 获取槽位物品名 |
KJ.getSlotItemCount(slot) | int | 获取物品数量 |
KJ.clickSlot(slot) | void | 点击背包槽位 |
🎨 渲染 API
| 方法 | 参数 | 说明 |
KJ.addFloatingText() |
text, x, y, z, color |
添加悬浮文字 |
KJ.addTracer() |
x, y, z, color, thickness |
添加追踪线 |
KJ.addBox() |
x, y, z, color, width, height |
添加方块ESP框 |
KJ.clearRenderObjects() |
无 |
清除所有渲染对象 |
颜色格式
颜色使用ARGB整数格式:0xAARRGGBB
var red = 0x80FF0000;
var green = 0xFF00FF00;
var blue = 0x800088FF;
⚙️ 模块 API
| 方法 | 返回类型 | 说明 |
KJ.toggleModule(name, enabled) | void | 开关模块 |
KJ.isModuleEnabled(name) | boolean | 模块是否开启 |
可用模块名
| 分类 | 模块名 |
| 战斗 | KillAura, Killis, InfiniteAura, Hitbox, Trap, SelfTrap |
| 移动 | Fly, AutoJump, JumpHack, Spacing, AutoFollow |
| 世界 | ClickTP, Teleport, AutoBreak, ClickBreak, Scaffold, ChestStealer, ChestAura, InventorySort |
| 渲染 | ESP, Fog, EntityTrace, HeadHalo, AuraRing, Trail, FloatingText, TagRender |
| 建筑 | BuildingImport, AutoBuild, BuildSpeed, TowerBuild, FloorFill, WallBuilder |
📋 Log 日志
全局对象 Log 用于输出日志到脚本控制台。
| 方法 | 说明 |
Log.info(msg) | 信息级别日志 |
Log.debug(msg) | 调试级别日志 |
Log.warn(msg) | 警告级别日志 |
Log.error(msg) | 错误级别日志 |
⏱️ 定时器
支持标准的JS定时器函数。
| 函数 | 说明 | 返回值 |
setTimeout(fn, ms) | 延迟执行 | 定时器ID |
setInterval(fn, ms) | 定时重复执行 | 定时器ID |
clearTimeout(id) | 取消setTimeout | void |
clearInterval(id) | 取消setInterval | void |
示例
setTimeout(function() {
Log.info("3秒过去了");
}, 3000);
var count = 0;
var timer = setInterval(function() {
count++;
Log.info("已经过 " + count + " 秒");
if (count >= 10) {
clearInterval(timer);
}
}, 1000);
📡 事件系统
通过定义特定函数名来监听游戏事件。
| 事件函数 | 参数 | 触发时机 |
onEnable() | 无 | 脚本启用时 |
onDisable() | 无 | 脚本禁用时 |
onTick() | 无 | 每游戏帧 |
onRender() | 无 | 每渲染帧 |
onChat(msg) | msg: string | 收到聊天消息 |
onAttack() | 无 | 攻击时 |
onDamage() | 无 | 受伤时 |
onDeath() | 无 | 死亡时 |
onJoinWorld() | 无 | 进入世界时 |
💡 脚本示例
示例1:自动跳
var lastJump = 0;
function onTick() {
if (!KJ.isPlayerOnGround()) return;
var now = KJ.getCurrentTimeMs();
if (now - lastJump < 500) return;
var px = KJ.getPlayerX();
var py = KJ.getPlayerY();
var pz = KJ.getPlayerZ();
if (!KJ.isBlockSolid(px, py - 1, pz)) {
KJ.setPlayerMotion(0, 0.42, 0);
lastJump = now;
}
}
示例2:自动打招呼
var greeted = {};
function onTick() {
var count = KJ.getEntityCount();
var now = KJ.getCurrentTimeMs();
for (var i = 0; i < count; i++) {
if (!KJ.isEntityPlayer(i)) continue;
var name = KJ.getEntityName(i);
var dist = KJ.getDistanceToEntity(i);
if (dist < 8 && !greeted[name]) {
KJ.sendChat("你好 " + name + " 👋");
greeted[name] = now;
}
if (greeted[name] && now - greeted[name] > 300000) {
delete greeted[name];
}
}
}
function onDisable() {
greeted = {};
}
示例3:坐标显示
function onRender() {
KJ.clearRenderObjects();
var x = KJ.getPlayerX().toFixed(1);
var y = KJ.getPlayerY().toFixed(1);
var z = KJ.getPlayerZ().toFixed(1);
var text = "XYZ: " + x + ", " + y + ", " + z;
KJ.addFloatingText(
text,
KJ.getPlayerX(),
KJ.getPlayerY() + 2.5,
KJ.getPlayerZ(),
0xFF00FF00
);
}
💡 提示:更多示例可以在脚本编辑器中查看内置模板。