Bedrock Wiki
  • QQ
  • 原站
新手入门指南
  • Guide
    • 1. 简介
      指南
    • 2. 附加组件详解
    • 3. 软件与准备工作
    • 4. 项目设置
    • 5. 创建自定义物品
    • 6. 创建自定义实体
    • 7. Blockbench:建模、贴图与动画制作
    • 8. 添加战利品表、生成规则与合成配方
  • Extra
    • a. 理解JSON
    • b. 下载示例包
    • c. 故障排除
      帮助
    • d. 高级清单文件指南
    • e. 格式版本
    • f. Android 项目设置
JSON UI
  • General
    • JSON UI 入门指南
      指南
    • 最佳实践
      指南
  • Tutorials
    • Aseprite 动画
    • 保留标题文本
      中级
    • 修改服务器表单
      中级
    • 字符串与数字转换
      中级
    • 按钮与开关
      新手
    • 添加HUD界面元素
      新手
  • Documentation
    • JSON UI 文档
Meta
  • Style Guide
  • 使用JSON模式(Schemas)
  • 实用链接
  • 版本控制
  • 附加包性能优化
  • Q&A
    • GameTest 问答集 2021/08/06
    • 世界生成问答 2024/11/15
    • 延迟渲染技术预览问答 2024/02/23
    • 方块与物品问答 2024/08/30
    • 脚本与编辑器问答 2023/09/22
NBT
  • General
    • .mcstructure
  • Tutorials
    • 扩展结构限制
      简单
    • 教育版中的实验功能
      简单
  • NBT in Depth
    • NBT 库列表
      专家
    • NBT读取示例
      专家
    • 关于NBT(命名二进制标签)
      专家
世界生成
  • General
    • 世界生成入门
      指南
      实验性
    • 特性类型
      实验性
    • 生物群系
      指南
      实验性
  • Tutorials
    • 特征(Feature)的方块条件
      实验性
    • 生成地表区块
      实验性
    • 生成自定义矿石
      实验性
    • 生成自定义结构
      实验性
    • 高度图噪声地形
      实验性
  • Documentation
    • 生物群系标签
动画控制器
  • 动画控制器入门指南
    指南
  • 实体命令
    中级
  • AFK检测器
  • 将Molang变量转换为计分板数值
  • 死亡指令
  • 重生指令
命令
  • General
    • 命令方块入门指南
    • 函数
    • NBT 命令
    • 坐标系
    • 方块状态
    • 理解目标选择器
    • 记分板操作
  • Commands
    • Execute
      简单
    • Playanimation
    • 伤害
    • 播放音效
  • On Event Systems
    • 玩家首次加入时
    • On Player Join
    • 玩家离开时触发
    • 玩家死亡事件
    • 玩家重生事件系统
    • 首次加载世界时
  • Scoreboard Systems
    • 实体计数器
    • 计分板计时器
    • 比较与获取分数
  • Techniques
    • 执行逻辑门
    • MBE - Max的方块实体
    • FMBE - 创建显示实体的新方法
    • 视线检测
    • 移动状态检测
    • 轨道摄像机
  • Useful Creations
    • 多人位置重排系统
      函数
    • 自定义合成台
      简单
实体
  • General
    • Intro to Entities BP
      指南
      新手
    • 实体资源包入门
      指南
      新手
    • 实体问题排查指南
      帮助
    • NPC对话系统
      中级
    • 实体事件
      新手
    • 实体属性
    • 渲染控制器
      新手
    • 生成规则
  • Tutorials
    • 任意坐标系间的坐标转换(世界、实体、骨骼)
      中级
    • 创建船只
      中级
    • 实体手持物品
      中级
    • 实体攻击机制
      中级
    • 实体睡眠机制
      中级
    • 实体碰撞体
      中级
    • 实体移动
    • 实体计时器
      中级
    • 无敌实体
      新手
    • 村庄机制实现指南
    • 检测其他实体
      中级
    • 生成已驯服的实体
      脚本
      中级
    • 视线检测实体
      中级
    • 禁用队友伤害
      中级
    • 范围效果云入门指南
      中级
    • 虚拟实体
      新手
    • 飞行实体控制
      中级
  • Documentation
    • Vanilla Usage Spawn Rules
    • 原版使用组件
    • 抛射物
    • 虚拟组件
    • 运行时标识符
    • 非生物实体运行时标识符
战利品、配方与交易
  • General
    • 交易行为
  • Documentation
    • 战利品表
    • 交易表
    • 合成配方
    • 物品函数
  • Tutorials
    • 随机化结构战利品
      简单
文档
  • Shared Constructs
  • Molang 查询详解
  • Vanilla Materials
    专家
  • 声音定义
  • 文件类型
  • 材质配置文件说明
    专家
  • 菜单分类
  • 资源包文件夹结构
  • 雾效ID
  • 高级Molang指南
方块
  • General
    • 方块入门指南
      指南
      新手
    • 方块组件
    • Block Tags
    • 方块状态
    • Block Traits
    • 方块排列组合
    • 方块事件
      脚本
    • 方块事件迁移指南
      帮助
    • 方块物品化
      中级
    • 方块问题排查指南
      帮助
  • Visuals
    • 方块剔除
      中级
    • 方块模型
      指南
      新手
      简单
    • 方块着色
      简单
    • 方块纹理动画
      中级
    • 方块纹理变体
      中级
  • Tutorials
    • Precise Interaction
      专家
      脚本
    • Precise Rotation
      专家
      脚本
    • 伪方块
      中级
    • 可旋转方块
    • 应用持续效果
      简单
      脚本
    • 矿石战利品表
      简单
      脚本
    • 规避状态值限制
      专家
  • Vanilla Re-Creations
    • 自定义作物
      中级
      脚本
    • 自定义活板门
      中级
      脚本
    • 自定义玻璃
      新手
      简单
      已弃用
    • 自定义釉面陶瓦
      简单
  • Documentation
    • 原版方块模型
      新手
    • 方块形状
    • 方块格式历史
    • 方块音效
服务器
  • Software
    • Bedrock Server Software
  • Protocols
    • Bedrock Protocol
    • NetherNet 协议
    • RakNet 协议
概念
  • contents.json
  • Molang
    中级
  • Rawtext
  • textures_list.json
  • 命名空间
  • 子包
  • 文本与本地化
  • 着色器
  • 纹理图集
    中级
  • 表情符号与特殊字符
  • 覆盖资源
    中级
  • 音效
    中级
物品
  • General
    • 物品入门指南
      指南
      新手
    • 物品组件
    • 物品标签
    • 物品事件
      脚本
    • Item Event Migration
      帮助
    • 物品问题排查指南
      帮助
  • Tutorials
    • Custom Pottery Sherds
    • 可投掷物品
      中级
    • 生成物品
      中级
    • 自定义武器
      简单
    • 自定义盔甲
    • 自定义食物
      简单
      脚本
    • 通过装备物品执行命令
      实验性
      中级
    • 高分辨率物品
  • Documentation
    • 附魔
    • Numerical Item IDs
    • Vanilla Usage Components
    • 原版物品标识符
      已弃用
    • 可附着物
      新手
    • 物品格式历史记录
视觉效果
  • General
    • 实体视觉效果简介
      指南
    • 基岩版建模指南
    • 动画中的特效
    • 基于数学的动画
      中级
    • 材质
      专家
    • 材质创作
      专家
    • 皮肤包制作指南
    • 自定义死亡动画
      中级
  • Tutorials
    • Glowing Entity Texture
    • 受伤动画
      中级
    • 实体纹理动画
      中级
    • 栓绳位置调整
      简单
    • 玩家几何模型
      新手
    • 移除实体阴影
      中级
    • 重绘生成蛋纹理
      新手
  • Ideas
    • 结构展示技巧
粒子效果
  • General
    • 粒子效果入门
      指南
  • Tutorials
    • 禁用粒子效果
      新手
  • Documentation
    • 原版粒子效果
脚本编写
  • General
    • 脚本编程入门
    • 什么是Script API?
    • API 模块
  • Tutorials
    • GameTests
      实验性
    • 简易聊天命令
      实验性
    • 脚本核心功能
    • 脚本表单
      实验性
    • 脚本请求API
      实验性
    • 阻止方块放置
  • Documentation
    • JavaScript 问题排查指南
    • Script Resources
    • Script Watchdog
      实验性
    • TypeScript
    • 引擎环境
虚拟现实
  • General
    • 启用VR模式
      指南
    • 配置资源包
      专家
  • Tutorials
    • 编辑你的第一个模型
      专家

脚本核心功能

脚本核心功能
  • 初始设置
  • 事件系统
  • 任务调度
  • 数据存储与读取
  • 执行命令
  • BeforeEvents权限系统

WARNING

脚本API目前处于积极开发阶段,经常会有破坏性变更。本文档基于Minecraft 1.21.20版本格式编写

在脚本API中,大多数核心功能都通过@minecraft/server模块实现,该模块包含大量与Minecraft世界交互的方法,涵盖实体、方块、维度等内容。本文将对部分核心API机制进行基础介绍。更详细信息请参阅微软官方文档。

初始设置 ​

需要在manifest.json中添加脚本模块作为依赖项。

BP/manifest.json
json
{
    "dependencies": [
        {
            "module_name": "@minecraft/server",
            "version": "1.13.0"
        }
    ]
}
1
2
3
4
5
6
7
8

事件系统 ​

在脚本API中,@minecraft/server模块采用事件驱动架构,通过订阅事件监听器可以在特定事件发生时执行代码。

世界事件

世界事件API提供了多个事件监听器,当Minecraft世界中发生特定类型事件时会触发,例如chatSend(聊天发送)、entityHurt(实体受伤)、playerSpawn(玩家生成)、worldInitialize(世界初始化)等。

TIP

请查阅微软文档了解Minecraft中可用的世界事件类型:

  • 前置事件(Before Events)在事件发生前触发,具有只读属性但可被取消。前置事件文档
  • 后置事件(After Events)在事件发生后触发,不可取消。后置事件文档
  • 除非需要取消事件,否则应优先使用后置事件

订阅事件需要从world对象获取afterEvents属性。以下示例展示如何订阅方块破坏事件:

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

// 订阅方块破坏事件
// 当玩家破坏方块时触发
world.afterEvents.playerBreakBlock.subscribe((event) => {
    const player = event.player; // 触发事件的玩家
    const block = event.block; // 被破坏的方块(注意此时该方块的typeId始终为空气)
    const permutation = event.brokenBlockPermutation; // 返回方块被破坏前的状态信息
    player.sendMessage(
        `你破坏了位于 ${block.x}, ${block.y}, ${block.z} 的 ${permutation.type.id}`
    ); // 向玩家发送消息
});
1
2
3
4
5
6
7
8
9
10
11
12

系统事件

系统事件在Minecraft附加包系统范围内发生特定类型事件时触发。

TIP

请查阅微软文档了解可用的系统事件类型:

  • 前置事件在事件发生前触发,具有只读属性但可被取消。前置事件文档
  • 后置事件在事件发生后触发,不可取消。后置事件文档
  • 两种事件类型适用于不同场景

从system对象获取beforeEvents属性。以下示例展示如何订阅watchdogTerminate事件,允许API在游戏超过性能边界时取消性能监视器关闭世界的操作(具体行为取决于脚本环境配置):

js
import { system } from "@minecraft/server";

// 订阅watchdogTerminate事件
system.beforeEvents.watchdogTerminate.subscribe((event) => {
    event.cancel = true; // 取消世界关闭操作(这将终止脚本引擎)
    console.warn("已取消类型为 " + event.terminateReason + " 的严重异常"); // 如果事件触发则在控制台打印警告
});
1
2
3
4
5
6
7

脚本事件

脚本事件(ScriptEvents,注意不要与世界事件或系统事件混淆)允许我们通过注册scriptEventReceive事件处理器来响应输入的/scriptevent命令。当玩家、NPC或方块调用/scriptevent命令时会触发该事件。更多信息请参阅脚本事件文档。

/scriptevent <消息ID: 字符串> <消息内容: 字符串>
1
  • 命令中的messageId可通过ScriptEventCommandMessageEvent.id获取
  • 命令中的message可通过ScriptEventCommandMessageEvent.message获取

示例:

输入命令:

/scriptevent wiki:test Hello World
1

事件监听器返回内容:

js
import { system } from "@minecraft/server";

system.afterEvents.scriptEventReceive.subscribe((event) => {
    const {
        id, // 返回字符串 (wiki:test)
        initiator, // 返回实体 (如果是NPC触发的命令则返回undefined)
        message, // 返回字符串 (Hello World)
        sourceBlock, // 返回方块 (如果是方块触发的命令则返回undefined)
        sourceEntity, // 返回实体 (如果是实体触发的命令则返回undefined)
        sourceType, // 返回MessageSourceType (可能值为'Block'、'Entity'、'NPCDialogue'或'Server')
    } = event;
});
1
2
3
4
5
6
7
8
9
10
11
12

任务调度 ​

我们可能需要在未来某个特定时间执行函数,这称为"调度调用"。

在脚本API中,原生JavaScript方法如setTimeout和setInterval不可用。Minecraft实现了基于游戏刻(tick)而非真实时间的调度方法。

这些方法可通过导入的system对象访问:

js
import { system } from "@minecraft/server";
1

提供以下两种主要方法:

调度定时器system.run(callback) - 在下一个可用时间点执行指定函数。常用于实现延迟行为和游戏循环。在事件处理器中调用时,通常会在事件发生的同一刻末尾执行代码;在其他代码中调用时,会在下一刻执行(但根据系统负载情况,不能保证严格在同一刻或下一刻执行)。

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

system.run(() => {
    world.sendMessage("这条消息会在上一刻之后的一刻显示");
});
1
2
3
4
5

system.runInterval(callback: () => void, tickInterval?: number): number - 周期性重复执行代码,从第一次间隔时间后开始,之后每隔指定间隔重复执行。

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

system.runInterval(() => {
    world.sendMessage("这条消息每20刻显示一次(每秒一次)");
}, 20);
1
2
3
4
5

system.runTimeout(callback: () => void, tickDelay?: number): number - 在指定时间间隔后执行一次函数。

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

system.runTimeout(() => {
    world.sendMessage("这条消息将在20刻后显示一次");
}, 20);
1
2
3
4
5

system.runJob(generator: Generator<void, void, void>): number - 将生成器函数加入队列运行直至完成。生成器每刻会获得一个时间片,运行直至yield或完成。生成器函数参考。

js
import { system, world, BlockPermutation } from "@minecraft/server";

function* blockPlacingGenerator(size, startX, startY, startZ) {
    const overworld = world.getDimension("overworld"); // 获取主世界维度
    for (let x = startX; x < startX + size; x++) {
        for (let y = startY; y < startY + size; y++) {
            for (let z = startZ; z < startZ + size; z++) {
                const block = overworld.getBlock({ x: x, y: y, z: z }); // 获取当前循环坐标处的方块
                if (block) block.setType("minecraft:cobblestone"); // 如果方块已加载,则设置为圆石
                // 每放置一个方块后让出控制权
                yield;
            }
        }
    }
}
// 在主世界坐标(-2, -60, 1)处开始建造10x10x10的圆石立方体
system.runJob(blockPlacingGenerator(10, -2, -60, 1));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

清除定时器

system.clearRun(runId): void - 取消通过run、runTimeout或runInterval调度的函数执行。

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

const callbackId = system.runInterval(() => {
    world.sendMessage("每刻运行一次");
});

system.runTimeout(() => {
    system.clearRun(callbackId); // 20刻后停止system.runInterval回调
    world.sendMessage("已停止");
}, 20);
1
2
3
4
5
6
7
8
9
10

clearJob(jobId: number): void - 取消通过runJob调度的任务执行。

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

const callbackId = system.runInterval(() => {
    world.sendMessage("每刻运行一次");
});

system.runTimeout(() => {
    system.clearRun(callbackId); // 20刻后停止system.runInterval回调
    world.sendMessage("已停止");
}, 20);
1
2
3
4
5
6
7
8
9
10

更多系统方法信息请参阅游戏循环与定时回调文档。

数据存储与读取 ​

通过@minecraft/server模块,开发者可以定义自己的自定义属性(称为动态属性),这些属性可以在Minecraft中使用和存储。数据会使用行为包头部UUID专门存储在世界文件夹的db目录中。

dynamic_properties

存储数据前需要先初始化属性。有多种方式可以声明动态属性,可以在实体、世界或物品上定义。虽然可以定义任意数量的数值和布尔值,但Minecraft API对每个行为包的动态属性数据存储量有限制:

  • 字符串动态属性最大长度为32767个字符
  • 数值动态属性最大值为64位浮点数限制范围(-1.7976931348623158e+308到-2.2250738585072014e-308,或2.2250738585072014e-308到1.7976931348623158e+308)

获取和设置动态属性

可以使用getDynamicProperty和setDynamicProperty方法获取和设置动态属性。

TIP

注意获取动态属性时不能保证该属性已有存储值。首次获取属性时方法会返回undefined。

以下是Minecraft中获取和设置动态属性的示例:

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

system.runInterval(() => {
    world.getPlayers().forEach((player) => {
        // 为每个玩家执行代码
        // 这三个属性对每个玩家都是唯一的,类似于标签/记分板数据
        player.setDynamicProperty("number_value", 12); // 设置玩家的数值属性
        player.setDynamicProperty("string_value", "这是一个字符串 :)"); // 字符串属性
        player.setDynamicProperty("boolean_value", true); // 布尔属性
    });
}, 20); // 每20游戏刻运行一次

world.afterEvents.playerBreakBlock.subscribe((data) => {
    // 订阅方块破坏事件
    const player = data.player; // 定义玩家变量供后续使用
    const numberProperty = player.getDynamicProperty("number_value"); // 获取已存储的动态属性
    player.sendMessage(`你的属性值是 ${numberProperty}!`); // 将玩家存储的值打印到聊天栏
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

以下是全局级别获取和设置动态属性的示例:

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

world.setDynamicProperty("player_score", 100); // 设置一个数值属性
const playerScore = world.getDynamicProperty("player_score"); // 获取之前设置的属性-将返回100
1
2
3
4

执行命令 ​

Entity.runCommandAsync()或Dimension.runCommandAsync()允许API从更广泛的维度上下文异步执行特定命令。注意每个刻最多只能运行128个异步命令。应尽可能避免使用runCommandAsync调用,优先使用内置API方法。

游戏会在世界的下一个刻执行队列中的命令。要使命令与脚本并行运行,需要将代码包裹在异步函数中。

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

(async () => {
    await world.getDimension("overworld").runCommandAsync("say 在维度上使用say命令");

    world.sendMessage("这条消息会在runCommandAsync执行后显示");
})();
1
2
3
4
5
6
7

返回Promise<CommandResult>。如果队列已满会同步抛出错误。

脚本中应避免使用命令

通常我们建议避免使用命令,因为通过脚本API运行命令速度较慢,随着时间推移执行更多命令会导致服务器性能下降。但以下命令功能尚未在脚本API中实现,我们别无选择只能使用runCommand或runCommandAsync。

末影箱

脚本API没有提供任何获取/设置玩家末影箱信息的方法。可以使用/replaceitem、/clear、@s[hasitem=]等命令作为替代方案。

常加载区域

脚本API无法访问、设置或移除常加载区域。

踢出玩家

脚本API无法踢出玩家。

设置方块

脚本API无法破坏方块/setblock ... destroy。虽然可以设置方块。

玩家能力

  • 脚本API无法为每个玩家设置能力
  • 无法读取玩家能力

execute命令

脚本API可以利用新的execute语法运行带有大量if/unless条件的命令以简化操作或提高性能。

/execute可用于触发/loot命令,因为runCommandAsync无法直接访问原版战利品表。

Minecraft函数

  • 脚本API无法在不使用/function的情况下运行Minecraft函数文件

定位

  • 脚本API无法获取结构位置
  • 无法获取生物群系位置

战利品

  • 虽然战利品系统从一开始就有问题,但对于向玩家/世界掉落或设置物品很有用

天气

  • 脚本API无法获取/设置世界天气

难度

  • 脚本API无法设置世界难度

生物事件

  • 脚本API无法启用/禁用生物事件

雾效

  • 脚本API无法管理玩家的活动雾效设置

停止声音

  • 脚本API无法停止播放声音。可以使用World::stopMusic()或Player::stopMusic()停止音乐

对话

  • 脚本API无法向玩家打开NPC对话
  • 无法更改NPC显示的对话内容

BeforeEvents权限系统 ​

TIP

开发者可能会在微软文档中发布关于此主题的文章,但目前这是社区收集的信息。

在1.20.0版本中,Minecraft脚本API为前置事件(如ChatSendBeforeEvent)中的回调引入了权限系统。

这限制了在前置事件回调中允许执行的本地函数。这些本地函数会在同一刻中修改世界状态(如使用World::setTimeOfDay()设置世界时间)。此实现的目的是避免在游戏刻中间产生级联更改。

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

world.beforeEvents.chatSend.subscribe((event) => {
    event.cancel = true;
    world.setTimeOfDay(0);
});
1
2
3
4
5
6

在上面的示例代码中,发送到聊天栏的消息被取消,同时设置了世界时间。world.setTimeOfDay()会抛出错误,因为本地函数没有在事件触发的同一刻更改世界状态所需的权限。

要使代码适应此新系统,必须使用以下方法在事件触发后的刻中运行这些需要权限的本地函数:

  1. 使用system.run:
js
import { world, system } from "@minecraft/server";

world.beforeEvents.chatSend.subscribe((event) => {
    event.cancel = true;
    system.run(() => {
        world.setTimeOfDay(0);
    });
});
1
2
3
4
5
6
7
8

为了适应新的权限系统,world.setTimeOfDay()函数被包裹在system.run()方法中,这会将其执行延迟一刻。确保函数不会在前置事件触发的同一刻执行。

  1. 使用system.runTimeout:
js
import { world, system } from "@minecraft/server";

world.beforeEvents.chatSend.subscribe(async (event) => {
    event.cancel = true;
    system.runTimeout(() => {
        world.setTimeOfDay(0);
    }, 5);
});
1
2
3
4
5
6
7
8

此代码功能与system.run()示例非常相似,但可以在超时中指定自定义长度,从而更精确地控制代码触发时间。

  1. 使用async函数在之后的刻中执行:
js
import { world } from "@minecraft/server";

world.beforeEvents.chatSend.subscribe(async (event) => {
    // 同步代码
    event.cancel = true;

    // 异步代码
    await sleep(10); // 假设有一个sleep函数返回10刻后解析的promise
    world.setTimeOfDay(0);
});
1
2
3
4
5
6
7
8
9
10

通过使用等待超过一刻的async函数可以绕过权限系统。由于await之前的代码是同步运行的,因此可以使用event.cancel = true取消事件,然后在之后的刻中继续执行操作。注意仅使用async/await调用是不够的,因为以这种方式运行的代码在遇到阻塞调用(如示例中的sleep()函数)之前仍然是同步执行的。

贡献者

编辑 脚本核心功能

Bedrock Wiki by Bedrock OSS ,Translate by 8aka-Team

"Minecraft"是Mojang AB的注册商标。

Bedrock OSS、Bedrock Wiki以及 bedrock.dev 与Microsoft及Mojang AB不存在任何隶属关系。

  • 隐私政策
  • 加入QQ社区
  • 参与贡献指南
  • 访问代码仓库