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(두 번: 시작, 그다음 확인)은 각 모드가 이벤트에서 얼마나 시간을 쓰는지 보여 줍니다.
  • 아무도 듣지 않는 이벤트는 만들어지지도 않으므로, 적은 수의 이벤트를 듣는 데는 비용이 들지 않습니다.