API

События

Событие описывает то, что произошло в игре: игрок зашёл, блок сломался, что-то получило урон. Оно не описывает, какой внутренний код игры выполнился, поэтому мод, который слушает join, продолжает работать, даже когда этот код меняется.

Как слушать событие

events/mining.craftCraftScript
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)
    }
}
events/MiningEvents.ktKotlin
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(…) Добавленные предметы выпадают там, где оно погибло, вдобавок к обычной добыче.
events/hunting.craftCraftScript
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 срабатывает, когда игрок нажимает клавишу мода (см. Интерфейс).

events/entities.craftCraftScript
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 только наблюдает: он не должен менять событие.

events/falls.craftCraftScript
on damage(e) priority high {
    if e.damage_type == "minecraft:fall" {
        e.amount = e.amount / 2        // приземление мягче
    }
}
events/ChatEvents.ktKotlin
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 (дважды: запуск, потом просмотр) показывает, сколько времени каждый мод тратит на свои события.
  • Событие, которое никто не слушает, даже не создаётся, поэтому слушать мало событий ничего не стоит.