Concepts of SAPI: WorldEvents & SystemEvents
本帖最后由 牢冥王 于 2026-2-21 19:17 编辑前言
实际上,世界事件(WorldEvents)和系统事件(SystemEvents)的概念被拆分成了两个类型:事件前事件(BeforeEvents)和事件后事件(AfterEvents)。有些事件前事件和事件后事件是一对,而有些事件前事件是独立的。注意,这里介绍的并不是行为文件定义的事件(Events)。
讲述
由于系统事件比较少,应用的范围也没有那么广,而且它们的原理是一样的,所以我们不单独介绍。在官方文档中,世界类(World Class)存在两个属性——afterEvents和beforeEvents:
它们分别表示事件后事件和事件前事件。在文档中还提到了“预执行(Early Execution)”的概念,这个东西出现在SAPI 2.0版本之后,在正式版中最早出现在1.21.70:
这里只需要知道它影响了事件前事件内容的运用,为了解决这个问题可以套一个System.run()。回到世界事件上,事件前事件表示的是事件即将发生,但成功与否未可知;而事件后事件必须在事件发生之后才存在。就爆炸前事件(ExplosionBeforeEvent)和爆炸后事件(ExplosionAfterEvent)来说,如果你在爆炸前事件中移除了产生爆炸的实体(Actor),那么爆炸就不会发生;在爆炸后事件移除产生爆炸的实体,那么即便实体被移除,爆炸造成的伤害、坑洞也不会消失。
应用
我们先来看爆炸前事件都有哪些属性和方法:
然后我们可以用以下代码阻止任何可能发生的(实体)爆炸:import { system, world } from "@minecraft/server"
world.beforeEvents.explosion.subscribe(event => {
system.run(() => {
event.cancel = true
})
})
如果用爆炸后事件,我们可以通过以下代码获知爆炸的信息:import { world } from "@minecraft/server"
world.afterEvents.explosion.subscribe(event => {
const coordinate = String(event.source?.location ?? "坐标尚不明确")
world.getPlayers().forEach(player => {
player.sendMessage("一个爆炸发生在"+event.dimension.id+","+coordinate+";"+"共影响"+String(event.getImpactedBlocks().length)+"个方块")
})
})
我们可以发现,上面的例子在注册爆炸前事件后又套了一层System.run(),而下面的爆炸后事件则没有。
总结
爆炸前后事件还是有一定局限性,不过世界事件中还有很多事件供你调用。在这里留一个小作业:用玩家互动实体前事件(PlayerInteractWithEntityBeforeEvent)实现一个可以对任意生物右键移除的钓鱼竿(可能用到Entity.remove()、Entity.kill())。以上的演示代码基本符合@minecraft-server-2.0.0以后的格式,如果你知道如何使用SAPI脚本就可以直接复制到.js文件中进行试验。
页: [1]