Cat_Anchor 发表于 2025-6-7 15:32:32

附加包教程:56.命令

本帖最后由 Cat_Anchor 于 2025-6-20 19:49 编辑




前言

在 1.21.80.22 中,官方加入了自定义命令功能,可以通过 SAPI 自定义命令。


https://klpbbs.com/static/image/hrline/line5.png


准备

首先需要在 manifest.json 中导入 @minecraft-server 模块。在 dependencies 字段下:
{
"module_name": "@minecraft/server",
"version": "2.1.0-beta"
}
注意其中的 version 字段。在 1.21.80 中,应该填写 2.0.0-beta,而在 1.21.90 中应该是 2.1.0-beta。

然后添加脚本模块,如果以前没有脚本模块的话。在 modules 字段下:
{
"type": "script",
"language": "javascript",
"uuid": "", // 需要填写 UUID。
"entry": "main.js", // 可以替换为其他名称,但必须以 .js 结尾。
"version": "0.1.0"
}
之后在行为包根目录下创建 scripts 文件夹(如果以前没有创建的话),打开它,创建 main.js(或自定义的名称),打开这个文件。

我们需要导入一些用于创建自定义命令的类和枚举。
import {
system,
CommandPermissionLevel,
CustomCommandParamType
} from "@minecraft/server";

其中,system 用于订阅世界启动的事件,我们需要在启动前注册自定义命令。CommandPermissionLevel 是自定义命令权限的枚举,CustomCommandParamType 是命令参数的枚举。


https://klpbbs.com/static/image/hrline/line7.png


编写命令

现在我们可以开始了。为了方便编写多个命令,我们可以仿照自定义组件的写法,先定义一个列表,其中的每个对象都代表一个自定义命令,然后用 for ... of 遍历注册每个自定义命令。

首先来定义一个命令,比如渲染文本的命令:const commandDefinitions = [{
commandDefinition: {
    name: "complementary:rendertext",
    description: "在指定位置渲染文本",
    permissionLevel: CommandPermissionLevel.GameDirectors,
    cheatsRequired: true,
    mandatoryParameters: [{
      type: CustomCommandParamType.Location,
      name: 'pos'
    }, {
      type: CustomCommandParamType.String,
      name: 'text'
    }],
    optionalParameters: [{
      type: CustomCommandParamType.Float,
      name: 'time'
    }, {
      type: CustomCommandParamType.Float,
      name: 'scale'
    }, {
      type: CustomCommandParamType.String,
      name: 'color'
    }, {
      type: CustomCommandParamType.String,
      name: 'rotation'
    }]
},
functionName: rendertextCommand
}];

我们首先定义了一个 commandDefinitions 列表,存放全部的自定义命令。然后,其中的每个对象表示一个命令。每个命令分为两个部分,语法和逻辑。语法在 commandDefinition 中定义,逻辑在 functionName 中定义。

commandDefinition 表示这个命令的基本信息,比如命令,描述,还有语法。

name 表示命令的名称,必须包含命名空间。必须填写。名称可以是中文,比如“test:一个命令”是可行的。

description 表示命令的描述,就是在聊天栏中跟在命令名称后方的描述命令作用的提示性文字。必须填写。可以填写任何文本,包括 \n 这样的特殊字符。可以使用§改变文本格式。目前不能本地化(也就是不能使用 .lang 文件翻译)。

permissionLevel 表示命令执行所需权限。必须填写。需要输入 CommandPermissionLevel 枚举中的值。可用值如下(括号中的值是枚举中定义的值,也可以用括号前面的键来代表那个值):

CommandPermissionLevel.Any(0)- 任何玩家或其他来源都能执行此命令。

CommandPermissionLevel.GameDirectors(1)- 操作员或命令方块可以执行此命令。

CommandPermissionLevel.Admin(2)- 操作员可以执行此命令,命令方块不行。

CommandPermissionLevel.Host(3)- 服务器主机可以执行此命令。

CommandPermissionLevel.Owner(4)- 基岩版专用服务器(BDS,Bedrock Dedicated Server)可以执行此命令。

cheatsRequired 表示命令是否需要启用作弊才能执行。可选,默认为 true。

mandatoryParameters 表示这个命令的必需参数。是一个列表,列表中的对象是命令参数项。可选,如果不填,表示这个命令不需要必需参数。

optionalParameters 表示这个命令的可选参数。是一个列表,列表中的对象是命令参数项。可选,如果不填,表示这个命令不需要可选参数。

如果 mandatoryParameters 和 optionalParameters 都为空,那么此命令不需要也不应该被提供任何参数即可运行。

注意,一个自定义命令最多只能有 8 个参数。

命令参数项是表示命令中一个参数的对象。其中 name 是此参数在聊天栏出现时的名称,type 是参数的类型。必须填写 name 和 type。比如一个可选的参数,在语法树中出现的形式是 。

type 接受 CustomCommandParamType 枚举中的值:

CustomCommandParamType.BlockType("BlockType")- 方块类型。

CustomCommandParamType.Boolean("Boolean")- 布尔值。

CustomCommandParamType.EntitySelector("EntitySelector")- 实体选择器。

CustomCommandParamType.EntityType("EntityType")- 实体类型。

CustomCommandParamType.Enum("Enum")- 枚举。此时 name 需要是已经注册的枚举。会出现自动补全提示。仍可以输入不是枚举中的值并被解析。

CustomCommandParamType.Float("Float")- 浮点数。

CustomCommandParamType.Integer("Integer")- 整数。

CustomCommandParamType.ItemType("ItemType")- 物品类型。会出现自动补全提示。

CustomCommandParamType.Location("Location")- 位置,也就是以空格分割的三维坐标。

CustomCommandParamType.PlayerSelector("PlayerSelector")- 玩家选择器。仅能选择玩家的实体选择器。

CustomCommandParamType.String("String")- 字符串。

functionName 表示命令的逻辑处理部分,是一个回调函数,执行命令时将命令的执行环境和解析的命令参数传递给这个函数。传递的顺序是首先传递命令的执行环境,然后根据语法顺序依次传递解析后的参数。

在以上示例中,functionName 是 rendertextCommand 这个函数。所以接下来定义这个函数。

function rendertextCommand(e, pos, text, time = 5, scale = 1, color, rot) {
let shape = new DebugText(pos, text);
shape.text = text;
shape.color = parseCommandParamRGB(color);
shape.rotation = parseCommandParamRotation(rot);
shape.timeLeft = time > 0 ? time * 50000 : undefined;
shape.scale = scale;
debugDrawer.addShape(shape);
return {
    status: 0,
    message: `尝试渲染了以下文本:${text}。`
};
}

可以看到,这个函数接收的参数是 (e, pos, text, time = 5, scale = 1, color, rot)。第一个是 e,表示命令的执行环境;其他的是刚才定义的参数。

命令的执行环境中包含 sourceBlock sourceEntity 和 initiator 属性,根据命令执行的来源而选择性存在,含义如下:

sourceBlock 表示执行命令的方块,比如命令方块。

sourceEntity 表示执行命令的实体,比如在聊天栏执行命令时的玩家,或者被给予指示执行命令的 NPC。

initiator 表示与 NPC 互动并导致 NPC 执行命令的玩家。

命令的执行环境中还有命令执行的来源信息,会通过 sourceType 属性告诉我们命令执行来自哪里。

sourceType 属性的值如下:

Block - 方块执行了这个命令。此时 sourceBlock 属性存在。

Entity - 实体执行了这个命令。此时 sourceEntity 属性存在。

NPCDialogue - 玩家通过 NPC 执行了这个命令。此时 sourceEntity 和 initiator 属性存在。

Server - 服务器执行了这个命令。此时命令没有其他执行环境。

rendertextCommand 函数还返回了一个对象,表示命令的执行结果。这个对象有 message 和 status 两个字段。

message 表示命令返回的消息。可选,不能本地化。

status 表示命令的执行状态。必须填写 CustomCommandStatus 枚举中的值:

CustomCommandStatus.Success(0)- 命令执行成功。
CustomCommandStatus.Failure(1)- 命令执行失败。

使用 CustomCommandParamType.Enum 类型的参数时,我们需要自定义枚举。可以仿照定义命令的方式定义枚举:const enumDefinitions = [{
name: 'complementary:configOperations',
values: ['open', 'reset']
}];

name 是枚举的命令,需要与命令参数定义中的 name 一致。必须有命名空间。显示命令语法时,会隐藏命名空间。

values 是枚举的值。

现在来注册已经定义的命令和枚举:system.beforeEvents.startup.subscribe((i) => {
for (const e of enumDefinitions) {
    i.customCommandRegistry.registerEnum(e.name, e.values);
}
for (const e of commandDefinitions) {
    i.customCommandRegistry.registerCommand(e.commandDefinition, e.functionName);
}
});

我们首先订阅通过 system 访问的 System 类中 beforeEvents 中的 startup 事件,然后通过 for ... of 循环遍历 enumDefinitions 枚举定义和 commandDefinitions 枚举定义。对于其中每个元素,都执行 customCommandRegistry.registerEnum 和 customCommandRegistry.registerCommand,将之前定义的参数传递给这两个函数。

就这样,我们成功定义了命令。


https://klpbbs.com/static/image/hrline/line7.png


总结

这一期讲解了如何定义新的命令。




第五十五期 第五十六期 第五十七期
页: [1]
查看完整版本: 附加包教程:56.命令