API

Eventos

Un evento describe algo que pasó en el juego: un jugador entró, se rompió un bloque, algo recibió daño. No describe qué código interno del juego se ejecutó, y por eso un mod que escucha join sigue funcionando aunque ese código cambie.

Escuchar un evento

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)
            }
        }
    }
}

En CraftScript, las propiedades del evento están disponibles como variables (player, block…) o a través del nombre que le des (on break(e)). Cada evento se puede escuchar desde tantos archivos como quieras: pon cada regla en el archivo de su tema.

Todos los eventos

Todos se disparan en el juego real, en el cliente o en el servidor según corresponda. En CraftScript vale el nombre corto o el largo en snake_case (join o player_join).

CraftScript Kotlin Propiedades Cancelable
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 Sí
respawn PlayerRespawnEvent player, location
death PlayerDeathEvent player, death_message, keep_inventory
interact PlayerInteractBlockEvent player, block, hand, item Sí
interact_entity PlayerInteractEntityEvent player, entity, hand, item Sí
attack PlayerAttackEvent player, target Sí
key PlayerKeyEvent player, key
use_item PlayerUseItemEvent player, item, hand Sí
command PlayerCommandEvent player, command Sí
break BlockBreakEvent player (puede ser null), block, drop_items Sí
place BlockPlaceEvent player (puede ser null), block, placed Sí
spawn EntitySpawnEvent entity Sí
damage EntityDamageEvent entity, damage_type, amount (modificable), attacker Sí
entity_death EntityDeathEvent entity, drops
hit ProjectileHitEvent projectile, shooter, entity or block Sí
ready ModsLoadedEvent mod_ids
plugin_reload PluginReloadEvent plugin_id

Cambiar lo que pasa

Algunas propiedades se pueden cambiar, y el juego hace caso:

Evento Propiedad Efecto
chat message El jugador dice el texto nuevo.
command command Se ejecuta el comando nuevo, como ese jugador.
join, quit join_message, quit_message Se anuncia a todos, además del mensaje del juego.
respawn location El jugador aparece ahí.
break drop_items = false El bloque no suelta nada.
damage amount El daño recibido es el nuevo.
entity_death drops.add(…) Los objetos añadidos caen donde murió, además de su botín normal.
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 es un clic derecho sobre una entidad: si lo cancelas no pasa nada (ni ordeñar, ni comerciar, ni montar). attack es un jugador golpeando a una entidad: si lo cancelas no hay golpe. damage da attacker, quien está detrás del daño: el atacante o quien disparó un proyectil. key se ejecuta cuando un jugador pulsa una tecla de un mod (ver Interfaz).

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() }
}

Todavía no se aplica. En death, cambiar death_message o keep_inventory aún no tiene efecto. Crafting lo avisa una vez en el log en lugar de ignorarlo en silencio.

Prioridad y cancelación

Orden: highest, high, normal, low, lowest y monitor. Cuando un listener cancela el evento, los siguientes no se ejecutan, salvo los de monitor (y en Kotlin los que pasen ignoreCancelled = true). Un listener monitor solo observa: no debe cambiar el evento.

events/falls.craftCraftScript
on damage(e) priority high {
    if e.damage_type == "minecraft:fall" {
        e.amount = e.amount / 2        // softer landings
    }
}
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}")
        }
    }
}

Si algo falla

  • Un listener que lanza un error se registra en el log con el nombre de su mod, y los demás listeners siguen.
  • /crafting profile (dos veces: empezar y ver) muestra cuánto tiempo pasa cada mod en sus eventos.
  • Un evento que nadie escucha ni siquiera se construye, así que escuchar pocos eventos no cuesta nada.