API
事件
事件描述的是游戏中发生的事:玩家加入了、方块被破坏了、某个东西受到了伤害。它不描述运行了哪段游戏内部代码,所以监听 join 的模组即使在那段代码改变后也能继续运行。
监听事件
import { give_rubies } from "/lib/rewards"
import { SETTINGS } from "/settings"
on break(e) {
let p = e.player
if p == null { return }
if e.block.type == "minecraft:diamond_ore" and chance(SETTINGS["bonus_chance"]) {
give_rubies(p, 1)
p.play_sound("rubies:ruby_chime")
p.world.spawn_particle("rubies:ruby_spark", e.block.location, 12, 0.4, 0.02)
}
}package com.example.rubies.events
object MiningEvents {
fun register(config: RubiesConfig) {
Crafting.events.on<BlockBreakEvent> { e ->
val player = e.player ?: return@on
if (e.block.type.path == "diamond_ore" && Math.random() < config.dropChance) {
player.give(ItemStack.of(Items.RUBY))
player.playSound(Identifier.parse(Sounds.CHIME))
player.world.spawnParticle(Identifier.parse(Particles.SPARK), e.block.location, count = 12, spread = 0.4, speed = 0.02)
}
}
}
}在 CraftScript 中,事件的属性可以直接作为变量使用(player、block……),也可以通过你给事件起的名字访问(on break(e))。同一个事件可以在任意多个文件中监听:把每条规则放在所属主题的文件中。
全部事件
所有事件都会在真实游戏中触发,视情况在客户端或服务端。在 CraftScript 中,可以使用 snake_case 形式的短名称或长名称(join 或 player_join)。
| CraftScript | Kotlin | 属性 | 可取消 |
|---|---|---|---|
server_starting |
ServerStartingEvent |
server | |
start |
ServerStartedEvent |
server | |
stop |
ServerStoppingEvent |
server | |
tick |
ServerTickEvent |
server, tick, phase | |
client_tick |
ClientTickEvent |
tick, phase | |
world_load |
WorldLoadEvent |
world | |
world_unload |
WorldUnloadEvent |
world | |
join |
PlayerJoinEvent |
player, join_message | |
quit, leave |
PlayerQuitEvent |
player, quit_message | |
chat |
PlayerChatEvent |
player, message | 是 |
respawn |
PlayerRespawnEvent |
player, location | |
death |
PlayerDeathEvent |
player, death_message, keep_inventory | |
interact |
PlayerInteractBlockEvent |
player, block, hand, item | 是 |
interact_entity |
PlayerInteractEntityEvent |
player, entity, hand, item | 是 |
attack |
PlayerAttackEvent |
player, target | 是 |
key |
PlayerKeyEvent |
player, key | |
use_item |
PlayerUseItemEvent |
player, item, hand | 是 |
command |
PlayerCommandEvent |
player, command | 是 |
break |
BlockBreakEvent |
player(可能为 null), block, drop_items | 是 |
place |
BlockPlaceEvent |
player(可能为 null), block, placed | 是 |
spawn |
EntitySpawnEvent |
entity | 是 |
damage |
EntityDamageEvent |
entity, damage_type, amount(可修改), attacker | 是 |
entity_death |
EntityDeathEvent |
entity, drops | |
hit |
ProjectileHitEvent |
projectile, shooter, entity or block | 是 |
ready |
ModsLoadedEvent |
mod_ids | |
plugin_reload |
PluginReloadEvent |
plugin_id |
改变事件结果
有些属性可以修改,游戏会照此执行:
| 事件 | 属性 | 效果 |
|---|---|---|
chat |
message |
玩家说出的是新文本。 |
command |
command |
以该玩家身份执行新命令。 |
join、quit |
join_message、quit_message |
在游戏自带消息之外,再向所有人公告。 |
respawn |
location |
玩家在该位置重生。 |
break |
drop_items = false |
方块不掉落任何东西。 |
damage |
amount |
受到的伤害为新值。 |
entity_death |
drops.add(…) |
添加的物品会在其死亡位置掉落,额外加在常规战利品之上。 |
on entity_death(e) {
if e.entity.type == "minecraft:zombie" and chance(0.05) {
e.drops.add(item("rubies:ruby", 1))
}
}interact_entity 是右键点击实体:取消后什么都不会发生(不能挤奶、交易或骑乘)。attack 是玩家击打实体:取消后没有这次击打。damage 提供 attacker,即伤害背后的来源:攻击者,或发射弹射物的一方。key 在玩家按下模组的按键时运行(见界面)。
on interact_entity(e) {
if e.entity.type == "minecraft:cow" { e.player.send("This cow won't be milked"); e.cancel() }
}
on attack(e) {
if e.target.type == "minecraft:pig" { e.player.action_bar("This pig is protected"); e.cancel() }
}尚未生效。在 death 中,修改 death_message 或 keep_inventory 目前还没有效果。Crafting 会在日志中警告一次,而不是静默忽略。
优先级与取消
顺序:highest、high、normal、low、lowest 和 monitor。某个监听器取消事件后,后续监听器不再运行,monitor 监听器除外(在 Kotlin 中,传入 ignoreCancelled = true 的监听器也除外)。monitor 监听器只用于观察:不得修改事件。
on damage(e) priority high {
if e.damage_type == "minecraft:fall" {
e.amount = e.amount / 2 // 落地更轻柔
}
}object ChatEvents {
fun register() {
Crafting.events.on<PlayerChatEvent>(EventPriority.HIGHEST) { e ->
if (e.message.startsWith("!")) e.cancel()
}
Crafting.events.on<PlayerChatEvent>(EventPriority.MONITOR) { e ->
if (!e.isCancelled) Crafting.runtime.logger("chat").info("${e.player.name}: ${e.message}")
}
}
}出错时
- 抛出错误的监听器会连同所属模组名称记录到日志,其他监听器继续运行。
/crafting profile(执行两次:先开始,再查看)显示每个模组在其事件中花费了多少时间。- 没人监听的事件根本不会被构造,所以只监听少量事件几乎没有开销。