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