API

Events

Ein Event beschreibt etwas, das im Spiel passiert ist: Ein Spieler ist beigetreten, ein Block wurde abgebaut, etwas hat Schaden genommen. Es beschreibt nicht, welcher interne Code des Spiels gelaufen ist, deshalb funktioniert eine Mod, die auf join hört, weiter, auch wenn sich dieser Code ändert.

Auf ein Event hören

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

In CraftScript stehen die Eigenschaften des Events als Variablen zur Verfügung (player, block…) oder über den Namen, den du ihm gibst (on break(e)). Du kannst auf jedes Event aus beliebig vielen Dateien hören: Leg jede Regel in die Datei ihres Themas.

Alle Events

Alle werden im echten Spiel ausgelöst, je nachdem auf dem Client oder dem Server. In CraftScript kannst du den kurzen oder den langen Namen in snake_case benutzen (join oder player_join).

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

Ändern, was passiert

Manche Eigenschaften lassen sich ändern, und das Spiel folgt ihnen:

Event Eigenschaft Wirkung
chat message Der Spieler sagt den neuen Text.
command command Der neue Befehl läuft, als dieser Spieler.
join, quit join_message, quit_message Wird allen angekündigt, zusätzlich zur Meldung des Spiels.
respawn location Der Spieler erscheint dort wieder.
break drop_items = false Der Block lässt nichts fallen.
damage amount Der erlittene Schaden ist der neue Wert.
entity_death drops.add(…) Die hinzugefügten Gegenstände fallen dort, wo es gestorben ist, zusätzlich zur normalen Beute.
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 ist ein Rechtsklick auf eine Entität: Wird er abgebrochen, passiert nichts (kein Melken, Handeln oder Reiten). attack ist ein Spieler, der eine Entität schlägt: Wird es abgebrochen, gibt es keinen Treffer. damage liefert attacker, wer hinter dem Schaden steckt: der Angreifer oder der Schütze eines Projektils. key läuft, wenn ein Spieler eine Taste einer Mod drückt (siehe Oberfläche).

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

Noch nicht umgesetzt. In death hat das Ändern von death_message oder keep_inventory noch keine Wirkung. Crafting warnt einmal im Log davor, statt es stillschweigend zu ignorieren.

Priorität und Abbrechen

Reihenfolge: highest, high, normal, low, lowest und monitor. Bricht ein Listener das Event ab, laufen die folgenden nicht mehr, außer monitor-Listenern (und in Kotlin denen, die ignoreCancelled = true übergeben). Ein monitor-Listener beobachtet nur: Er darf das Event nicht ändern.

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

Wenn etwas schiefgeht

  • Ein Listener, der einen Fehler wirft, wird mit dem Namen seiner Mod geloggt, und die anderen Listener laufen weiter.
  • /crafting profile (zweimal: starten, dann ansehen) zeigt, wie viel Zeit jede Mod in ihren Events verbringt.
  • Ein Event, auf das niemand hört, wird gar nicht erst erzeugt, also kostet es nichts, auf wenige Events zu hören.