脚本API

来自Minecraft基岩版开发Wiki
Mojang官方使用脚本API编写的测试脚本。

脚本API(Script API)是Minecraft国际版中的一个脚本系统,可在附加包中实现脚本运算。目前脚本API在主机版上不可用[1],其他平台上均可使用。

脚本API支持使用JavaScript语言(以下简称JS)编写,因此其灵活性要远大于数据驱动,可为附加包的创作提供更多可能,但脚本API无法取代数据驱动的底层注册与定义功能,例如添加方块、实体、物品等内容。在附加包的实际开发过程中,脚本API可以弥补数据驱动在逻辑运算方面灵活性的不足,从而实现更复杂的效果,而且可以在一定程度上减小附加包编写过程中的繁琐程度。同时,脚本API与Molang的对接也可以使数据驱动的灵活性更进一层。

在游戏测试方面,Mojang加入了GameTest框架[注 1],用于对原版游戏进行测试。在游戏中通过/gametest命令可以加载一个预制的结构并运行对应脚本来进行游戏测试,最终会将测试结果反馈给玩家。

启用[编辑]

脚本系统[编辑]

启用该脚本系统需要在附加包的清单文件中添加类型为脚本的清单模块。示例如下:

{
  "format_version": 2,
  "header": {
    "description": "Test",
    "name": "Example Pack",
    "uuid": "f6d6da21-232a-4f86-b74a-9303cd91f5be",
    "version": [ 0, 0, 1 ],
    "min_engine_version": [ 1, 19, 0 ]
  },
  "modules": [
    {
      "type": "data",
      "uuid": "472fcc44-df74-4189-9d38-4d6ce686dae8",
      "version": [ 0, 0, 1 ]
    },
    {
      "type": "script",
      "uuid": "d9519751-f5f8-48f8-a058-92348a13868f",
      "version": [ 0, 0, 1 ],
      "language": "javascript",
      "entry": "scripts/Main.js"
    }
  ]
}

清单模块的类型(即type字段)为script时表示该包需启用脚本系统。其中language字段的值需填写为javascriptentry字段填写加载附加包时加载的JS文件。JS文件都存储在行为包的scripts文件夹中:

  •  Addon.mcaddon
    •  Resource Pack
    •  Behavior Pack
      •  scripts
        •  Main.js
        •  ……
      •  ……
      •  manifest.json
      •  pack_icon.png

因此需要将entry的值填写为scripts/<file_name>.js

依此成功启用脚本API后,还需要在清单文件中添加脚本API的模块作为依赖项,才能将原生接口导入并使用。

测试功能[编辑]

要启用脚本API在新版本中的测试功能,需要开启“测试版API”实验性玩法选项。

安全性[编辑]

JS中的eval()Function()不能直接在脚本系统中使用,若要启用这两项功能,需通过在清单文件功能字段中添加"script_eval"字符串来启用:

"capabilities": [ "script_eval" ]

重载[编辑]

使用/reload命令可以对脚本系统进行热重载。

模块[编辑]

脚本API提供的原生模块包含了很多的接口。原生模块需要在清单文件中的dependencies字段作为包的依赖项加载,并在脚本中使用import语句导入到脚本的作用域中。例如在清单文件中通过模块名加载:

"dependencies": [
  {
    "module_name": "@minecraft/server",
    "version": "1.0.0"
  }
]

或通过UUID加载:

"dependencies": [
  {
    "uuid": "b26a4d4c-afdf-4690-88f8-931846312678",
    "version": "1.0.0"
  }
]

然后在JS文件中导入之前加载的模块:

import * as Minecraft from "@minecraft/server";

版本[编辑]

模块的版本用于指定游戏使用对应版本的接口来加载脚本文件,而不因为游戏更新受到影响。Mojang于1.19.40.23版本修改了模块名之后,创作者在清单文件中加载任意版本的模块都应使用新名称,而在JS文件中通过import语句导入模块时,要使用对应版本的模块名。

需要注意的一点是,模块的测试版本(即版本号带“beta”字样的版本)在脚本API更新下一个版本时不会被保留,因此使用了模块测试版本的附加包需在新版本中修改模块版本号,否则将会抛出内容日志错误并无法正常加载脚本。

列表[编辑]

模块 UUID 可用性
描述
@minecraft/client c1b4d019-b5cf-4e20-956d-8014a3e8c824 仅客户端
@minecraft/common 77ec12b4-1b2b-4c98-8d34-d1cd63f849d5 可用
@minecraft/debug-utilities 1796ea86-0daf-4409-99ee-fd6467cf1203 可用 该模块包含一些系统调试工具。
@minecraft/math N/A NPM包
@minecraft/server b26a4d4c-afdf-4690-88f8-931846312678 可用 该模块包含了与原版世界游戏机制有关的接口。
@minecraft/server-admin 53d7f2bf-bf9c-49c4-ad1f-7c803d947920 可用 该模块包含与BDS有关的接口。这些接口允许在BDS的JSON文件中配置变量和秘密,且不能在客户端使用。
@minecraft/server-editor 1d565354-296d-11ed-a261-0242ac120002 可用 该模块包含与编辑器有关的接口。
@minecraft/server-editor-bindings 8518d9c7-a1f5-4bf3-acc7-78e87df595fc 可用
@minecraft/server-gametest 6f4b6893-1bb6-42fd-b458-7fa3d0c89616 可用 GameTest框架模块,该模块提供了与原版游戏机制有关的用于测试的接口。
@minecraft/server-identity d8e7cb98-b05f-11ec-b909-0242ac120002 仅开发者版
@minecraft/server-live-events-utilities 538443f1-63a6-4f02-b191-7bc828f225e0 仅开发者版
@minecraft/server-net 777b1798-13a6-401c-9cba-0cf17e31a81b 可用 该模块包含执行基于HTTP请求的接口,且只能在BDS服务端上使用。
@minecraft/server-ui 2bd50a27-ab5f-4f40-a596-3641627c635e 可用 该模块包含了基于对话框的UI接口。
@minecraft/vanilla-data N/A NPM包

脚本编写[编辑]

脚本API目前仅支持JS,但也可先使用TypeScript(以下简称TS)编写再转化为JS来运行。官方在脚本API文档中引入了部分TS概念并适当使用TS进行演示[2],这有利于开发者对脚本API的理解,提高编写代码过程的便捷性。本Wiki的脚本API相关页面也将使用部分TS概念进行演示。

枚举[编辑]

枚举(Enumeration)包含了一组命名常量,可以使脚本编写中的某些特定值更规范统一。枚举值的调用方式与对象属性的调用方式一致,例如调用Direction枚举的值进行比较判断:

import { world, Direction } from "@minecraft/server";

world.beforeEvents.itemUseOn.subscribe(data => {
    if(data.blockFace == Direction.Up) {
        world.sendMessage("你右键点击了方块顶面。");
    };
});

接口[编辑]

接口(Interface)是一种用于描述对象内容格式的TS类型。在脚本API的编写中,接口表示传入参数的格式或者返回值格式。

JS中以接口指定格式对象编写即可,下面是一个同时使用EntityQueryOptions接口和Vector3接口的示例:

import { world } from "@minecraft/server";

const queryOptions = {
    closest: 2,
    gameMode: "creative",
    location: {
        x: 1,
        y: 64,
        z: 1
    } // Vector3
}; // EntityQueryOptions
const target = world.getDimension("overworld").getPlayers(queryOptions);
world.sendMessage(`${target[1].name}是距离位置 1,64,1 第二近的创造模式玩家。`);

类型别名[编辑]

官方在文档中引入了类型别名(Type Alias),用于为脚本API的编写提供便利。类型别名是TS中的一种类型,其本质是一种名称映射。在获取NPM包后类型别名可用于TS的编写,其并不存在于游戏的脚本引擎中。

核心功能[编辑]

在脚本API中,大多数核心功能都在@minecraft/server模块中,可以使用其与Minecraft中的实体、方块、维度等进行交互。

只读模式[编辑]

只读模式(Read-only Mode)是Mojang定义的一种非只读属性或函数的锁定状态[3],在此状态下脚本系统将禁止写入某些属性或调用某些函数,并且会抛出内容日志错误[注 2]。此模式是Mojang对前事件作出的一种限制。

在传入前事件的回调函数中进行任何改变世界状态的操作都将受到此限制,相关的属性和方法会被设置为只读模式。例如以下操作:

import { world } from "@minecraft/server";

world.beforeEvents.itemUseOn.subscribe(data => {
    data.block.setType("minecraft:stone");
});

但可通过使用system.run()等方式来延迟执行操作,从而错开前事件的触发时间。

动态属性[编辑]

动态属性(Dynamic Property)是脚本系统存储自定义数据的一种格式。目前动态属性可以存储在实体、物品和世界上。相较于数据驱动中属性(或状态)的“静态性”,动态属性可以实时增删,且动态属性的类型不固定,脚本系统以此可以实现数据的动态存储。

用法[编辑]

官方提供了以下5个方法来对动态属性进行操作:

  • clearDynamicProperties:清除该对象上的所有动态属性。
  • getDynamicProperty:获取该对象上指定动态属性的值。
  • getDynamicPropertyIds:获取该对象上所有动态属性的ID。
  • getDynamicPropertyTotalByteCount:获取该对象上存储的所有动态属性的总字节数。
  • setDynamicProperty:在该对象上设置一个动态属性。

这些方法可从World、​EntityItemStack三个类中调用。

动态属性可以存储布尔型、数值型、字符串型和三维向量型的数据,单个动态属性的数据大小限制在32KB以内。大量的动态属性数据可能会导致某些设备上加载缓慢。

存储[编辑]

动态属性以NBT的形式存储,其数据内容位于DynamicProperties复合标签下。每个行为包的动态属性存储在以该行为包UUID命名的复合标签内。

动态属性NBT结构:
  •  DynamicProperties:实体的动态属性集合。
    •  <UUID>:该动态属性所属行为包的UUID。
      •  <dynamic_property_id>[①]:布尔型、数值型或字符串型动态属性。
      •  <dynamic_property_id>[②]:三维向量型动态属性。
        • :X轴分量。
        • :Y轴分量。
        • :Z轴分量。
      •  ……

设置在实体或物品上的动态属性存储于其NBT内,若该实体或物品被清除,则其携带的动态属性数据也会随之一同消失。结构可以保存实体或物品的动态属性,且动态属性的包UUID信息不会丢失。

卸载行为包并重新加载世界不会使该行为包设置的动态属性消失,动态属性数据仍然会保留在存档中,重新装载该行为包后可以正常读写以前设置的动态属性。

包独立性[编辑]

每个附加包的脚本都是独立的,它们之间互不相通。不能通过一个已启用脚本API的附加包来使其他未启用脚本API的附加包接入脚本系统,附加包之间的JS文件也不能互相依赖或调用。

动态属性在存储时会记录创建它的行为包的UUID并以此作区分,因此不同行为包创建的动态属性也是相互独立的。一个行为包不能删除、创建或读写属于另一个行为包的动态属性。

通过/scriptevent命令可以一定程度上实现包与包之间的数据和逻辑互通。

看门狗[编辑]

看门狗(Watchdog)是一个性能监视器,用于监控脚本引擎中运行缓慢的脚本。

历史[编辑]

基岩版
1.16.2101.16.210.60加入了GameTest框架。要启用该框架,需要在实验性玩法选项中开启“GameTest框架”实验性玩法。
1.19.201.19.20.20加入了看门狗。
?GameTest框架更名为脚本API。
1.19.401.19.40.23重命名了所有模块:
  • mojang-gametest → @minecraft/server-gametest
  • mojang-minecraft → @minecraft/server
  • mojang-minecraft-ui → @minecraft/server-ui
  • mojang-minecraft-server-admin → @minecraft/server-admin
  • mojang-net → @minecraft/server-net
现在eval()Function()在使用前必须在清单文件的capabilities字段中添加"script_eval"
导入模块时不再使用"script/<prefix>"的形式,而是"./<name>.js"
1.19.801.19.80.20现在运行时错误会以JavaScript错误的形式抛出。
修复了部分基类的继承问题,并为部分类加入了新的基类。

你知道吗[编辑]

  • 脚本API在社区曾被称呼为“Plugin系统”。
  • 脚本API是基于QuickJS引擎实现的,因此它对原生JavaScript语法有着较好的支持。

画廊[编辑]

参考[编辑]

  1. Minecraft Beta - 1.16.210.60 (Xbox One/Windows 10/Android)  — Minecraft Feedback,2021年2月18日。
  2. 官方脚本API微软文档
  3. Minecraft Beta - 1.20.0.20  — Minecraft Feedback,2023年4月12日。

注释[编辑]

  1. 脚本API原名如此,更名后GameTest框架成为其中一个模块
  2. [Scripting][error]-ReferenceError: Native function [<scope>] does not have required privileges.

Template:Navbox Addon