API

월드와 플레이어

블록을 읽고 바꾸고, 엔티티를 생성하고, 플레이어와 대화합니다. CraftScript에서는 이름에 snake_case(block_at, max_health)를, Kotlin과 Java에서는 camelCase(blockAt, maxHealth)를 씁니다. 같은 객체입니다.

예제

commands/beacon.craftCraftScript
command beacon requires "rubies.beacon" describe "서 있는 자리에 불빛 밝히기" {
    if player == null { return "플레이어만 사용할 수 있습니다" }
    let w = player.world
    let at = player.location
    w.set_block(at.block_x, at.block_y, at.block_z, "minecraft:lantern", { hanging: false })
    w.spawn_particle("minecraft:flame", at, 30, 0.5, 0.02)
    w.play_sound(at, "minecraft:block.lantern.place")
    player.title("&e밝혔습니다", "")
}
commands/BeaconCommand.ktKotlin
object BeaconCommand {
    fun register() {
        Crafting.commands.command("beacon") {
            permission = "rubies.beacon"
            executes { c ->
                val at = c.player.location
                val world = c.player.world
                world.setBlock(at.blockX, at.blockY, at.blockZ, Identifier.parse("minecraft:lantern"), mapOf("hanging" to false))
                world.spawnParticle(Identifier.parse("minecraft:flame"), at, count = 30, spread = 0.5, speed = 0.02)
                world.playSound(at, Identifier.parse("minecraft:block.lantern.place"))
                c.player.title("&e밝혔습니다")
            }
        }
    }
}

월드

CraftScript에서는 world()(기본 월드, 또는 world("minecraft:the_nether")), Kotlin에서는 Crafting.server?.world(id) 또는 player.world.

멤버 하는 일
id, players, time, is_raining, data 월드 id, 플레이어, 시각(읽기와 쓰기), 비가 오는지 여부, 저장 데이터.
block_at(x, y, z) 그 위치의 블록.
set_block(x, y, z, type) 블록을 놓습니다.
set_block(x, y, z, type, states) 상태를 지정해 블록을 놓습니다: { open: true }, { facing: "north" }.
spawn(type, location) 엔티티를 생성합니다.
drop_item(location, stack) 아이템을 바닥에 떨어뜨립니다.
explode(location, power, fire?) 폭발.
strike_lightning(location) 번개.
spawn_particle(id, location, count?, spread?, speed?) 입자.
spawn_particle(id, location, velocity) 그 속도(틱당 블록 수)로 나아가는 입자 하나. minecraft:enchant와 minecraft:portal처럼 생성된 장소를 향해 가는 것도 있으며, 그런 입자는 location + velocity에서 옵니다.
play_sound(location, id, volume?, pitch?) 특정 위치의 소리.
light_at(x, y, z) 빛의 양, 0에서 15까지.
container_at(x, y, z) 상자, 통 등의 인벤토리, 또는 null.
set_sign_text(x, y, z, lines) 표지판의 텍스트.
set_chunk_loaded(cx, cz, loaded) 근처에 아무도 없어도 청크를 불러온 상태로 유지합니다.
entities() 월드의 엔티티.
living_near(location, radius) 어떤 장소 근처의 살아 있는 엔티티. 가까운 순서.
shoot(projectile, from, velocity, shooter?, damage?) 투사체를 발사합니다. 게임의 것도 모드의 것도 가능합니다.

플레이어

멤버 하는 일
name, uuid, is_op, has_crafting_client 신원. 클라이언트에 Crafting이 설치되어 있는지 여부.
send(msg), action_bar(msg), title(title, subtitle?) 채팅, 액션 바, 화면에 표시되는 메시지. 색상은 &로.
inventory, held_item, give(stack) 인벤토리, 손에 든 아이템, 아이템 주기.
set_held_item(stack) 주로 쓰는 손에 있던 것을 대신해 아이템을 넣습니다. null이면 비웁니다.
health, max_health, food_level, game_mode 체력, 허기(읽기와 쓰기), 게임 모드.
is_sleeping 플레이어가 자고 있는지 여부.
data 플레이어와 함께 저장되는 데이터(아래 참고).
play_sound(id, volume?, pitch?) 그 플레이어에게만 들리는 소리.
has_permission(p), kick(reason) 권한. 추방.

Player는 생명체 엔티티이기도 합니다(아래 참고).

엔티티, 블록, 인벤토리

타입 멤버
Entity uuid, type, world, location, custom_name, is_alive, data, direction, vehicle; teleport, remove, set_rotation, add_tag, has_tag.
LivingEntity Entity의 모든 것에 더해 health, max_health; damage, heal, set_ai, add_effect, remove_effect, has_effect, effects, add_modifier, remove_modifier, attribute, set_attribute, equipment, set_equipment(자체 행동을 끄거나 켭니다).
Block type, x, y, z, world, location, is_solid, data; set_type, relative(dx, dy, dz).
Inventory size; get(slot), set(slot, stack), add(stack), count(id), clear().
Location world, x, y, z, yaw, pitch, block_x, block_y, block_z; add(dx, dy, dz), distance_to(other).

ItemStack은 id, 개수, 이름, 설명(lore), 모드 자체 데이터를 담고 있으며, 인벤토리와 상자 사이를 옮겨 다녀도 이를 유지합니다. CraftScript에서는 item("rubies:ruby", 3)으로, Kotlin에서는 ItemStack.of("rubies:ruby", 3)이나 전체 생성자로 만듭니다.

stack.enchantments는 각 마법 부여의 id에서 레벨로 가는 맵입니다(minecraft:sharpness → 3). 마법이 부여된 책에서는 그 책이 주는 것들입니다. Kotlin에서 stack.withEnchantments(mapOf(Identifier.parse("minecraft:sharpness") to 3))는 그 마법 부여를 가진 같은 스택입니다. 게임에서 읽은 스택은, 모드가 옮기거나 with_count 또는 withEnchantments로 바꾸더라도, API가 이름을 붙이지 않은 것(지도의 내용, 물약의 효과)을 포함해 가진 모든 것을 유지합니다(Kotlin의 copy는 유지하지 않습니다).

효과, 속성, 장비

효과. 살아 있는 모든 엔티티는 게임의 효과를 가질 수 있습니다. e.add_effect("minecraft:speed", 8, 3)은 id, 초, 레벨(1이 I)을 받으며, 선택 사항인 마지막 인자 true 또는 false로 입자를 보일지 정합니다. remove_effect(id), has_effect(id), effects(id에서 { level, seconds }로 가는 맵)가 짝을 이룹니다. Kotlin에서는 addEffect(Identifier.parse("minecraft:speed"), 8.0, 3)과 ActiveEffect(level, seconds)입니다.

모드는 자체 효과를 선언할 수 있습니다(블록, 아이템, 조합법 참고). 부여하고 확인할 때는 이와 같은 멤버를 씁니다.

속성. attribute("minecraft:movement_speed")는 방어구와 효과를 포함한 현재 값을 돌려줍니다. set_attribute("minecraft:scale", 1.6)은 기본값을 바꿉니다(scale, attack_damage, max_health, jump_strength, armor 등). Kotlin에서는 attribute(id)와 setAttribute(id, value)입니다.

commands/grow.craftCraftScript
command grow() {
    let p = player
    if p.attribute("minecraft:scale") > 1.2 { p.set_attribute("minecraft:scale", 1) } else { p.set_attribute("minecraft:scale", 1.6) }
}

수정자. 수정자는 기본값을 대체하지 않고 속성을 바꾸므로, 여러 개를 겹칠 수 있고 각각 따로 제거할 수 있습니다. e.add_modifier("minecraft:movement_speed", "mymod:frozen_slow", -0.3, "percent_of_base")는 속성, 수정자의 id, 양, 연산을 받으며, e.remove_modifier("minecraft:movement_speed", "mymod:frozen_slow")로 제거합니다. 같은 id를 다시 추가하면 교체됩니다. 연산은 add(양을 더함), percent_of_base(기본값에 양을 곱한 만큼 더함), multiply_total(결과에 1에 양을 더한 값을 곱함)입니다. Kotlin에서: addModifier(attr, id, amount, ModifierOperation.PERCENT_OF_BASE).

commands/chill.craftCraftScript
command chill() {
    player.add_modifier("minecraft:movement_speed", "mymod:chill", -0.3, "percent_of_base")
    // later: player.remove_modifier("minecraft:movement_speed", "mymod:chill")
}

탑승과 범위 효과. entity.vehicle은 엔티티가 타고 있는 것이며, 없으면 null입니다. world.living_near(location, radius)는 어떤 장소 주변의 살아 있는 엔티티를 가까운 순서로 나열하며, 범위 효과에 필요한 기능입니다:

commands/frostwave.craftCraftScript
command frostwave() {
    let p = player
    for other in p.world.living_near(p.location, 8) {
        if other.type != "minecraft:player" { other.add_effect("mymod:frozen", 4, 1) }
    }
}

장비. e.equipment("head")는 그 칸에 착용한 아이템이거나 null이고, e.set_equipment("main_hand", item("minecraft:iron_sword"))로 바꿉니다. 칸은 main_hand, off_hand, head, chest, legs, feet입니다. Kotlin에서는 EquipmentSlot.HEAD, equipment(slot), setEquipment(slot, stack)입니다.

방향과 쿨다운. entity.direction은 바라보는 방향으로, 길이가 블록 하나인 벡터입니다. player.set_cooldown(item, seconds)와 player.has_cooldown(item)로 아이템에 쿨다운을 걸고 확인합니다.

저장 데이터

플레이어, 엔티티, 블록, 월드에는 data가 있습니다. 재시작해도 남는 키-값 저장소입니다. 문자열, 숫자, 불리언, 리스트, 맵을 저장합니다.

lib/storage.craftCraftScript
// Data that survives restarts. Keys start with the mod id: they're shared by every mod.
const VISITS = "rubies.visits"

fun visits(p: Player): number {
    return p.data.get_int(VISITS) ?? 0
}

fun add_visit(p: Player): number {
    let n = visits(p) + 1
    p.data.set(VISITS, n)
    return n
}
storage/Visits.ktKotlin
package com.example.rubies.storage

object Visits {
    private const val KEY = "rubies.visits"   // shared by every mod: prefix it with the mod id

    fun of(player: Player): Int = player.data.getInt(KEY) ?: 0

    fun add(player: Player): Int = (of(player) + 1).also { player.data[KEY] = it }
}
CraftScript Kotlin / Java 하는 일
data.set(k, v) 또는 data[k] = v data[k] = v 값을 저장합니다(null이면 삭제).
data[k] data[k] 저장된 그대로 값을 읽습니다. 없으면 null.
data.get_int(k), get_number, get_string, get_boolean getInt(k), getNumber, getString, getBoolean 그 타입의 값을 읽습니다. 없으면 null.
data.remove(k), data.clear(), data.keys remove(k), clear(), keys 키 하나 삭제, 전부 삭제, 키 목록.
  • 키는 모든 모드가 공유합니다. 다른 모드의 키를 덮어쓰지 않도록 각 키를 모드 id로 시작하세요(rubies.visits).
  • 유지 기간: 플레이어의 데이터는 플레이어와 함께 남습니다. 엔티티의 데이터는 엔티티가 죽으면 사라집니다. 블록의 데이터는 플레이어가 그 블록을 부수거나 API로 교체되면 사라집니다.
  • 숫자는 소수로 저장되며, get_int는 정수로 반환합니다.
  • 키와 관련 함수는 한 파일에 두세요(lib/storage.craft, Kotlin에서는 storage/). 모드의 나머지 부분은 키를 알 필요가 없습니다. 모드 정리하기를 참고하세요.

서버

멤버 하는 일
players, worlds, motd, tps, is_dedicated 서버 상태. tps는 초당 평균 틱 수입니다(20이 이상적).
player(name), world(id) 접속 중인 플레이어나 월드를 찾습니다.
broadcast(msg) 모두에게 보내는 메시지.
stop() 저장하고 서버를 멈춥니다.
run_command(cmd) 비상구: 게임 명령어를 실행합니다(아래 참고).

비상구

게임 자체의 형식을 받는 함수가 두 개 있습니다. 게임 명령어를 실행하는 run_command(CraftScript에서는 run(…)), 그리고 게임 내부 형식의 데이터로 엔티티를 만드는 summon(type, location, nbt). API가 아직 다루지 않는 것을 위해 존재하지만, 이 형식들은 Minecraft의 것이라 새 버전에서 바뀔 수 있으므로 이에 의존하는 모드는 깨질 수 있습니다. 가능한 한 적게 쓰고 항상 API를 우선하세요.

지어낸 값은 없습니다. 어떤 API 멤버도 임시 값을 반환하지 않습니다. 실행 중인 게임에서 무언가가 작동할 수 없으면, 무엇이 왜 안 되는지 알려 주는 오류를 냅니다.