가이드
CraftScript
Crafting의 언어입니다. 영어 키워드, 짧은 문법, 컴파일 없음. 파일을 저장하면 모드를 다시 불러옵니다. 열 줄짜리 모드에도, 클래스와 타입을 쓰는 마흔 개 파일짜리 모드에도 알맞습니다.
지금 할 수 있는 것
| 분야 | 방법 |
|---|---|
| 아이템 | item "ruby" { … }: 희귀도, 반짝임, 음식, 도구, 내구도, 텍스처, 크리에이티브 탭, 사용 동작. |
| 블록 | block "ruby_ore" { … }: 단단함, 저항, 빛, 소리, 도구와 최소 등급, 드롭, 마찰, 투명도, 사용 동작. 모양과 모델은 블록 모양 참고. 계단, 문, 울타리, 상자, 표지판, 작물, 광석 같은 게임의 다른 종류, 좌석, 높이 2칸 블록은 블록 종류 참고. 블록은 밟힘과 틱에 반응하고, 포털이 되고, 상태를 갖고, 레드스톤을 쓰고, 아이템을 담을 수도 있습니다. 블록, 아이템, 조합법를 참조하세요. |
| 월드 생성 | ore, tree, patch, structure, biome: 새 청크에 나타나는 것들. terrain, biome_map, carver, 그리고 plan/build를 가진 구조물: 코드로 만드는 땅, 바이옴, 동굴, 건축물. 월드 생성과 코드로 생성하기 참고. |
| 몹 | creature "ghost" { … }: 게임 속 몹의 몸에 당신의 텍스처 또는 나만의 3D 모델, 능력치, 행동, 공격 대상, 전리품을 더합니다, 그리고 자연 스폰, 길들이기, 번식, 타기, 원거리 공격, 키프레임 애니메이션. 몹 참고. |
| 소리와 입자 | sound "chime" { file: … }, particle "spark" { textures: … }. id로 사용합니다. 소리와 입자 참고. |
| 조합법 | recipe shaped, shapeless, smelting. 모델, 전리품, 태그, 번역은 자동으로 생성됩니다. |
| 이벤트 | on join, on break(e)… 우선순위와 취소를 갖춘 모든 이벤트. |
| 방어구, 무기, 쿨다운 | 착용은 armor: { slot, defense, texture }, 타격 시에는 on_hit, 사용 간격은 cooldown. 블록, 아이템, 레시피 참고. |
| 효과, 속성, 장비 | e.add_effect(…), e.attribute(…), e.set_attribute(…), e.set_equipment(…). 월드와 플레이어 참고. |
| 키 | key "dash" { label: "Dash", default: "R" }와 on key(e), 엔티티 이벤트 on interact_entity와 on attack. 인터페이스와 이벤트 참고. |
| 명령어 | command pay(to: player, amount: int) requires "eco.pay", 별칭, 설명, 권한 포함. |
| 시간 | every 5 minutes { }, after 10 seconds { }, on tick. |
| 월드와 플레이어 | 상태가 있는 블록, 엔티티, 폭발, 입자, 소리, 시각, 상자, 표지판. 인벤토리, 체력, 제목, 순간이동. 월드와 플레이어 참고. |
| 인터페이스 | form(…)과 player.show_form, server.boss_bar, player.set_sidebar. 인터페이스 참고. |
| 저장 데이터 | p.data.set("rubies.visits", n), p.data.get_int("rubies.visits"): 플레이어, 엔티티, 블록, 월드에. 재시작해도 남습니다. 월드와 플레이어 참고. |
| 설정과 네트워크 | config("settings", { … }), listen, send, send_to_server. 설정과 네트워크 참고. |
| 대형 모드 | 선택적 타입, 상속이 있는 클래스, 열거형, 모듈, 상수. |
Kotlin 전용: 백그라운드 작업, Java 라이브러리, 그리고 월드 생성에서는 코드로 만드는 피처와 태그.
파일
모드는 파일 하나(mods/gems.craft)이거나, 커지면 더 나은 방법으로 main.craft와 그것이 가져오는 파일들이 든 폴더입니다. main.craft는 id, 이름, 버전을 지정하는 mod 헤더로 시작합니다.
mod "rubies" { name: "Rubies", version: "1.0.0", author: "you" }
// What exists
import "content/items"
import "content/ores"
import "content/world"
import "content/dimensions"
import "content/creatures"
import "content/sounds"
import "content/particles"
import "content/recipes"
// What happens
import "events/mining"
import "events/hunting"
import "events/welcome"
import "commands/realm"
import "commands/rubies"
import "commands/shop"나머지를 폴더로 나누는 방법과 그 이유는 모드 정리하기에 있습니다.
값과 변수
let coins = 100
const MAX_HOMES = 3 // const: 다시 대입할 수 없습니다
let greeting = "코인이 {coins * 2}개 있습니다"
let names = ["Ana", "Ben"]
let prices = { gold: 5, ruby: 2 }
names.add("Cleo")
prices["diamond"] = 9
log(len(names), prices.gold, prices.keys())숫자(항상 소수), 문자열, true/false, null, 리스트, 맵. 큰따옴표 안에서는 {expression}이 보간되며, \{는 중괄호 문자 그대로를 씁니다. 작은따옴표는 보간하지 않습니다. 채팅 색상은 &로 씁니다: "&a초록".
제어 흐름
fun describe(coins: number, banned: bool): string {
if coins > 100 and not banned {
return "부자"
} else if coins == 0 {
return "빈털터리"
}
return "보통"
}
fun countdown() {
for i in 1..5 { broadcast("{6 - i}…") } // 끝을 포함하는 범위
for p in players() { p.send("시작!") }
}
fun who(target: Player?, fallback: Player): string {
let p = target ?? fallback // ?? : null이면 대체 값
return p?.name ?? "아무도 없음" // ?. : null에 안전
}함수
fun give_rubies(p: Player, amount: number = 1) {
p.give(item("rubies:ruby", amount))
}
fun healthy(): list<Player> {
return players().filter(fun(p) { return p.health > 10 })
}기본값이 있는 매개변수, return, 그리고 fun(x) { … }로 쓰는 익명 함수. 익명 함수는 map, filter, on_use에 함수를 넘기는 방법입니다.
이벤트
on 안에서는 이벤트의 속성이 변수(player, message, block…)이거나, 이벤트에 이름을 붙일 수 있습니다: on chat(e). 취소할 수 있는 이벤트라면 e.cancel()로 취소합니다.
const BLOCKED = ["spam", "scam"]
on chat(e) priority high {
if BLOCKED.any(fun(w) { return e.message.contains(w) }) {
e.cancel()
e.player.send("&c서로 친절하게 대해 주세요")
}
}명령어
command heal(target: player?, amount: number?) requires "rubies.heal" alias "h" describe "플레이어 치유" {
let p = target ?? player
if p == null { return "플레이어 이름을 입력하세요" }
p.health = min(p.max_health, p.health + (amount ?? 20))
return "{p.name}을(를) 치유했습니다"
}명령어 안에서는 sender, player(콘솔이 실행하면 null), args를 쓸 수 있습니다. return한 값이 응답이 됩니다. 인수가 빠졌거나 타입이 틀리면 플레이어에게 올바른 사용법이 표시됩니다.
시간
every 5 minutes { broadcast("&6투표하는 것을 잊지 마세요") }
after 10 seconds { log("서버가 켜진 지 10초가 지났습니다") }대형 모드
선택적 타입
타입을 적은 곳에서는 강제되고, 적지 않은 곳에서는 코드가 자유롭습니다. 하나도 적지 않아도 검사기는 API 전체의 타입을 알고 있습니다.
on join {
player.helth = 20 // 오타
player.name = "Admin" // 읽기 전용 속성
player.give() // 인수 누락
}welcome.craft:2: error: Player has no property 'helth'. Did you mean 'health'?
welcome.craft:3: error: Player.name is read-only
welcome.craft:4: error: give() expects 1 argument(s), got 0fun heal(p: Player, amount: number = 20): bool {
p.health = min(p.max_health, p.health + amount)
return true
}
// heal(player, "a lot") → error: Argument 'amount' of heal() must be number, got string타입: number, string, bool, id, list<T>, map<T>, T?(null일 수 있음), any, void, fun, API 타입(Player, World, Block, Entity, ItemStack, Location, Inventory…), 이벤트, 그리고 직접 만든 클래스와 열거형. null 검사 후에는 검사기가 값이 존재한다는 것을 압니다.
command home(target: player?) {
if target == null { return "플레이어 이름을 입력하세요" }
target.teleport(world().block_at(0, 80, 0).location) // 여기서 target은 더 이상 null이 아닙니다
}클래스
class Wallet {
coins: number = 100
fun pay(n: number): bool {
if n > this.coins { return false }
this.coins -= n
return true
}
}
class VipWallet extends Wallet {
fun pay(n: number): bool {
return super.pay(n / 2) // VIP는 절반만 냅니다
}
}클래스가 선언하지 않은 필드에 값을 대입하면 오류입니다(오타가 그냥 넘어가지 않도록). 클래스가 init(…)을 정의하면 그것이 생성자이고, 정의하지 않으면 인수가 필드를 순서대로 채웁니다. is(value, Class)는 타입을 검사합니다.
열거형
enum Rank { PEASANT, KNIGHT, LORD, KING }
fun rank_for(coins: number): Rank {
if coins >= 1000 { return Rank.LORD }
return Rank.PEASANT
}
// Rank.LORD.name → "LORD", Rank.values() → [PEASANT, …], Rank.from("king") → KING모듈
import { VipWallet } from "/lib/wallet"
import { rank_for } from "/lib/rank"
let wallets = {}
on join {
wallets[player.name] = VipWallet()
player.send("등급: {rank_for(wallets[player.name].coins).name}")
}파일이 어떤 블록 바깥에서 선언한 모든 것은 가져올 수 있습니다: 함수, 클래스, 열거형, 상수. 여러 파일이 가져와도 각 파일은 한 번만 실행됩니다.
검사, 다시 불러오기, 안전
- 모드를 불러올 때 모든 것을 검사합니다. 오류가 있으면 불러오지 않고 위치를 알려 주며, 경고는 로그에 남습니다.
crafting check main.craft는 터미널에서 import를 따라가며 같은 일을 합니다. - 개발 모드(
-Dcrafting.dev=true,crafting sandbox에서는 항상 켜짐)에서는 저장하면 모드를 다시 불러옵니다./crafting reload <id>도 마찬가지입니다. 새 아이템이나 블록은 게임을 재시작해야 하고, 나머지는 즉시 바뀝니다. - 스크립트는 Crafting API만 볼 수 있습니다. 파일을 읽거나, 연결을 열거나, Java 클래스를 쓸 수 없습니다.
- 각 이벤트, 명령어, 타이머에는 2,000,000단계 제한이 있습니다. 무한 루프는 서버를 멈추게 하는 대신 오류와 함께 중단됩니다.
- 실행 중 오류는 파일과 줄과 함께 기록되고, 서버는 계속 실행됩니다.
모든 함수, 연산자, 멤버: CraftScript 레퍼런스.