脚本表单
WARNING
脚本API目前处于积极开发阶段,重大变更频繁。本文基于Minecraft 1.20.60版本格式编写
在1.18.30版本中,Minecraft发布了一个出色的新脚本模块@minecraft/server-ui(原名mojang-minecraft-ui)。通过该模块,我们可以无需处理JSON UI即可创建表单界面。
准备工作
与其他模块类似,您需要在manifest.json中添加依赖项:
{
"dependencies": [
{
"module_name": "@minecraft/server-ui",
"version": "1.2.0-beta"
},
{
"module_name": "@minecraft/server",
"version": "1.9.0-beta"
}
]
}并在脚本文件中导入模块:
import {
ActionFormData,
MessageFormData,
ModalFormData
} from "@minecraft/server-ui";表单类型
@minecraft/server-ui模块提供三种表单类型:操作表单(Action Form)、消息表单(Message Form)和模态表单(Modal Form)。
操作表单(ActionFormData)
操作表单包含多个按钮,适合用于商店界面、小游戏选择等场景。如果您见过特色服务器中带有多按钮的UI,那就是这种表单。
首先需要创建表单实例:
let form = new ActionFormData();操作表单具有三个功能属性:标题(Title)、正文(Body)和按钮(Button)。
标题
标题显示在表单顶部:
form.title("操作表单");正文
正文用于描述表单功能:
form.body("这是操作表单的正文内容");按钮
按钮是表单的核心功能。每个按钮有两个参数:第一个是按钮标签文本,第二个是可选的图标路径(使用原版资源包路径如textures/items/compass,自定义纹理需要添加.png后缀并确保世界已加载相应资源包)。
// 无图标
form.button("按钮1");
// 使用原版纹理
form.button("按钮2", "textures/items/compass");
// 使用自定义纹理
form.button("按钮3", "textures/icon/btn_icon_3.png");WARNING
最多支持256个按钮,超出可能导致表单异常
示例
操作表单示例:
let form = new ActionFormData();
form.title("小游戏选择");
form.body("请选择游戏");
form.button("掘一死战", "textures/items/diamond_shovel");
form.button("杀手谜案", "textures/items/iron_sword");
form.button("起床战争", "textures/minigames/bedwars.png");
消息表单(MessageFormData)
消息表单包含两个按钮和大段正文描述,适合确认对话框等场景。
let form = new MessageFormData();消息表单与操作表单类似,主要区别在于按钮固定为两个(button1和button2)。
标题
form.title("消息表单");正文
消息表单支持多行文本,使用\n换行:
form.body("这是消息表单的正文内容");按钮
消息表单仅包含两个按钮:
form.button1("按钮1:否");
form.button2("按钮2:是");TIP
建议将"是/确定"选项设为button2,"否/取消"设为button1,具体原因见"显示与响应"章节
示例
消息表单示例:
let form = new MessageFormData();
form.title("高随机刻速度警告");
form.body("您确定要执行此命令吗:\n/gamerule randomtickspeed 1000\n这可能导致世界卡顿");
form.button1("否,保持默认!");
form.button2("是,确认执行!");
模态表单(ModalFormData)
模态表单支持最丰富的输入类型,包括文本框、下拉菜单、滑块和开关,适合复杂表单如效果生成器。
let form = new ModalFormData();模态表单包含五种组件:标题、文本框、下拉菜单、滑块和开关。
标题
form.title("模态表单");文本框
文本框包含三个参数:
- 标签文本
- 占位符文本
- 默认值(可选)
// 无默认值
form.textField("文本框", "在此输入内容");
// 含默认值
form.textField("文本框", "在此输入内容", "默认文本");下拉菜单
下拉菜单包含三个参数:
- 标签文本
- 选项列表
- 默认选项索引(可选,默认为0)
// 内联选项
form.dropdown("下拉菜单", ["选项1", "选项2", "选项3"], 1);
// 外部选项(推荐)
let options = ["选项1", "选项2", "选项3"];
form.dropdown("下拉菜单", options);滑块
滑块包含五个参数:
- 标签文本
- 最小值
- 最大值
- 步长
- 默认值(可选)
// 1到100范围
form.slider("滑块", 1, 100, 1);
// 0到10的偶数,默认值10
form.slider("滑块", 0, 10, 2, 10);开关
开关包含两个参数:
- 标签文本
- 默认状态(可选,默认为false)
// 无默认值
form.toggle("开关");
// 默认开启
form.toggle("开关", true);示例
模态表单完整示例:
let form = new ModalFormData()
let effectList = ["生命恢复", "保护", "中毒", "凋零"]
form.title("效果生成器");
form.textField("目标", "输入效果目标")
form.dropdown("效果类型", effectList)
form.slider("效果等级", 0, 255, 1)
form.toggle("隐藏效果粒子", true)
显示与响应
创建表单后需要向玩家显示并处理响应。通常使用itemUse事件(当玩家使用物品时触发)。
例如使用名为"表单开启器"的木棍打开表单:
world.beforeEvents.itemUse.subscribe(event => {
if (event.itemStack.typeId === "minecraft:stick" && event.itemStack.nameTag === "表单开启器") {
// 表单代码
};
});WARNING
表单仅在无其他UI打开时显示。若要通过命令/聊天消息打开,需先用/damage关闭聊天界面。建议使用其他事件触发。
使用.show()显示表单,并通过.then()处理响应:
form.show(event.source).then(r => {
// 玩家响应后的代码
}).catch((e) => {
console.error(e, e.stack);
});为防止玩家直接关闭表单时意外执行代码,需检查.canceled:
form.show(event.source).then(r => {
if (r.canceled) return;
// 玩家实际响应后的代码
}).catch(e => {
console.error(e, e.stack);
});操作表单响应
操作表单响应存储在.selection中,返回按钮索引(从0开始):
form.show(event.source).then(r => {
if (r.canceled) return;
let response = r.selection;
switch (response) {
case 0:
// 按钮1的代码
break;
case 1:
// 按钮2的代码
break;
default:
// 未定义按钮的处理
}
}).catch(e => {
console.error(e, e.stack);
});消息表单响应
消息表单同样使用.selection,button1返回0,button2返回1:
form.show(event.source).then(r => {
if(r.canceled || r.selection == 0){
// 取消或按钮1的代码
return
}
// 按钮2的代码
}).catch(e => {
console.error(e, e.stack);
});模态表单响应
模态表单响应存储在.formValues数组中,按组件从上到下排序:
let form = new ModalFormData();
form.textField(...);
form.dropdown(...);
form.slider(...);
form.toggle(...);
form.show(event.source).then(r => {
if (r.canceled) return;
// 解构赋值各输入值
let [ textField, dropdown, slider, toggle ] = r.formValues;
// 处理逻辑
}).catch(e => {
console.error(e, e.stack);
});










