事件载荷¶
不管模组用什么语言写,每个事件到达模组时都是一段 SNBT 文本。这一页是这段文本里有什么的参考。 怎么订阅看各语言的指南;字段在哪门语言里都一样。
两类事件¶
LeviLamina 事件是 LeviLamina 自己事件注册表里的事件,用完整 id 订阅,比如 ll::event::MobDieEvent。
载荷是 LeviLamina 对事件的序列化,Pier 在上面补充字段(见下文),因为那份序列化只写出了引擎对象的名字,没有描述它们。
合成事件是 Pier 从自己的 hook 里发出的事件,比如 PlayerAttackTargetEvent。
载荷由 Pier 写出,每个事件的字段在各绑定的事件名列表里逐一说明。
Pier 给 LeviLamina 事件补了什么¶
载荷里的引擎对象会在旁边被描述出来,键名是同一个键前面加下划线。
出现的字段都是宿主读到的。读不到的字段,要么不出现,要么被列进 _unresolved,Pier 不会替它填一个默认值。
| 载荷里有 | Pier 补充 | 形状 |
|---|---|---|
事件所关于的玩家(self) |
_player |
{name, xuid, uuid, pos:{x,y,z}} |
其他任何实体,或不是玩家的 self |
_<键名> |
{uid, type, name, isPlayer, dim},玩家还多 xuid 和 realName |
| 伤害来源 | _<键名> |
{cause, attackerUid?, attacker?, projectileUid?, projectile?} |
| 实体类型 | _identifier |
{full, namespace, name} |
| 方块或物品 | _<键名> |
{name} |
BlockSource,或 self 实体 |
dim |
维度 id,事件本身没带时补上 |
uid 是实体的唯一 id,和所有实体槽位接收的是同一个数,所以模组可以对载荷里点名的实体直接操作。
name 是名牌,可能被插件改过;realName 是玩家的账号名。
谁杀了谁¶
MobDieEvent、PlayerDieEvent 和 ActorHurtEvent 都带伤害来源。伤害来自实体时,来源里有:
attackerUid:负责的那个实体。投射物伤害时是发射它的实体,不是箭本身。attacker:那个实体的描述,它还存在时才有。projectileUid和projectile:箭、三叉戟或其他投射物,只在投射物伤害时有。
即使实体已经不在了,uid 也会写出来,所以射手下线后被箭射死,仍然知道是谁干的。
因此没有 attacker 表示"已经不在了";没有 attackerUid 才表示伤害根本不是实体造成的:火、摔落、虚空。
两种情况下 cause 都是引擎的伤害原因编号。
有东西解析不出来的时候¶
既不是在线玩家、也不在运行时实体表里的实体无法描述。它的键名会被列进 _unresolved,事件照常到达。
基于这种载荷做保护决定的模组应当拒绝,而不是猜;Rust SDK 的 check_complete() 和 dim() 已经替你这样做了。
合成事件的约定¶
合成事件的载荷遵守三条规则,让模组能分清"答案"和"失败":
partial:"partial":1表示至少有一个字段没读到、只是默认值。出现在ExplosionEvent、FarmlandDecayEvent、SpawnItemActorEvent、ChestPairEvent和PistonPushEvent里,全部读到时不出现。targetKnown:在PlayerAttackTargetEvent和PlayerInteractEntityEvent里,0 表示目标没读到。 这时targetIsPlayer为 1,所以 PvP 规则会拒绝。- 取消:回调会拿到一个写回接口,可取消的事件通过写回时带上取消标记来取消;各绑定都包装好了,Rust 里是
ev.cancel()。 标为只观察的事件不能取消,它的文档会指出该去拦哪个事件。