시작하기
지원 Minecraft Script API 버전
Kairo는 Minecraft의 안정(stable) Script API가 필요합니다:
@minecraft/server2.0.0 이상@minecraft/server-ui2.0.0 이상
2.0.0 이전 버전은 초기화 모델이 다르며(예: WorldLoad 대신 WorldInitialize 사용), 지원되지 않습니다.
kairo 설치
kairo 비헤이비어 팩을 월드에 추가하세요. 모든 애드온 간의 통신 허브 역할을 합니다.
kairo는 GitHub Releases에서 다운로드할 수 있습니다.
Kairo는 월드별 설정이 필요 없습니다. 같은 월드에 여러 Kairo 버전이 있어도 Kairo가 active host 하나를 자동으로 선택합니다. 애드온 코드는 계속 @kairo-js/router에만 의존하면 되며, 어떤 Kairo 팩 인스턴스가 호스트인지 알 필요가 없습니다.
kairo-router 사용하기
다른 애드온과 통신하려면 kairo-router를 애드온에 추가하세요.
설치
pnpm add @kairo-js/router @kairo-js/properties@kairo-js/router는 애드온 간 통신을 위한 runtime API입니다. @kairo-js/properties는 router.init()에 전달하는 AddonProperties 타입과 manifest 메타데이터에 맞는 구조를 제공합니다.
Kairo는 @kairo-js/utils도 제공합니다. router를 시작하는 데 필수는 아니지만 SemVer 유틸리티, seeded random, JSON parse helper, TypeBox compile helper 같은 공통 도구를 사용할 수 있습니다.
시작 이벤트에서 API 선언하기
모든 API 등록과 훅 선언은 반드시 router.beforeEvents.startup 내부에서 이루어져야 합니다.
import { router } from '@kairo-js/router'
import type { AddonProperties } from '@kairo-js/properties'
import { properties } from './properties'
router.beforeEvents.startup.subscribe((ev) => {
// Register an API your addon provides
ev.addonApi.register<{ playerId: string }, { balance: number }>(
'economy/getBalance',
async ({ playerId }) => ({ balance: 100 }),
)
})
router.init(properties)Minecraft custom component 등록
Minecraft custom component도 router.beforeEvents.startup 안에서 등록합니다. startup event에 노출된 native registry를 그대로 사용하세요.
router.beforeEvents.startup.subscribe((ev) => {
ev.itemComponentRegistry.registerCustomComponent('my:item_component', {
onUse(event) {
console.log(event.source?.name)
},
})
ev.blockComponentRegistry.registerCustomComponent('my:block_component', {
onPlayerInteract(event) {
console.log(event.player?.name)
},
})
})다른 애드온의 API 호출하기
// fire-and-forget
router.send('economy-addon', 'onTransaction', { amount: 50 })
// await result
const result = await router.request<{ balance: number }>(
'economy-addon',
'getBalance',
{ playerId: '...' },
)
if ('canceled' in result) {
console.log(result.reason)
} else {
console.log(result.balance)
}전체 API는 kairo-router API 레퍼런스를 참고하세요.
필수 dependencies
properties.ts에 "kairo"를 필수 dependency로 선언해야 합니다. 누락된 경우 router.init()이 즉시 오류를 발생시킵니다.
import type { AddonProperties } from '@kairo-js/properties'
export const properties: AddonProperties = {
id: 'my-addon',
dependencies: {
kairo: '^1.0.0',
// optional: 'kairo-database': '^2.0.0' — router.save/load/delete/has에 필요
},
}활성화에 필수적이지 않은 통합은 optionalDependencies에 작성하세요. 예를 들어 router.save(), router.load(), router.delete(), router.has()는 kairo-database가 dependencies 또는 optionalDependencies 중 하나에 포함되어 있어야 사용할 수 있습니다.
커스텀 커맨드
커스텀 커맨드는 Minecraft native registry에 직접 등록하지 말고, router.beforeEvents.startup 안에서 ev.customCommandRegistry를 통해 등록하세요.
Minecraft는 일반적으로 같은 id의 커스텀 커맨드를 여러 개 등록하는 것을 거부합니다. 이 때문에 같은 월드에 여러 애드온 버전이 있으면 한 버전만 커맨드를 등록할 수 있습니다. Kairo-router는 커맨드 등록을 래핑하여 중복 native 등록을 안전하게 건너뛰고, Kairo가 실행을 현재 active인 애드온 버전으로 라우팅하게 합니다. 따라서 월드에서 버전을 전환해도 같은 command id를 유지한 커맨드를 계속 사용할 수 있습니다.
Command id와 인수 타입 순서는 호환성 계약입니다. 한 번 릴리스한 커맨드는 같은 command id에서 정렬된 인수 타입을 바꾸지 마세요. 인수 이름은 문서 메타데이터이므로 변경할 수 있습니다. 예를 들어 target: string을 player: string으로 바꾸는 것은 호환됩니다. 타입 순서를 바꾸거나, 기존 인수 앞에 새 필수 인수를 추가하거나, 인수를 string에서 entity로 바꾸는 것은 호환되지 않습니다.
호환되지 않는 커맨드 시그니처가 필요하다면 major 버전을 올리고, 이전 시그니처를 사용하는 낮은 버전을 제거해야 한다는 점을 사용자에게 안내하세요. 또는 새 command id를 추가하고 기존 월드를 위해 오래된 커맨드를 유지할 수 있습니다.
스탠드얼론 모드
router.init()에 { standalone: true }를 전달하면 스탠드얼론 활성화가 켜집니다. kairo가 설치되지 않은 경우, 필수 dependencies가 kairo와 kairo-database만 포함되어 있으면 자동으로 활성화됩니다. kairo의 라이프사이클 관리를 선택적으로 활용하는 단독 애드온에 유용합니다.
자세한 내용은 RouterInitOptions를 참조하세요.
초기화 타이밍
월드 로드 후 kairo는 Discovery · Registration · Activation 초기화 플로우를 실행한 뒤 addonActivate를 발생시킵니다. 설치된 애드온 수에 따라 다르지만 약 30〜50틱의 지연이 발생합니다.
이 지연은 의도된 것입니다. Minecraft Script API 2.0.0+에서는 WorldLoad 완료 전에 world 관련 메서드를 호출하면 오류가 발생하는데, addonActivate는 그 대체 안전 신호 역할을 합니다.
router.afterEvents.addonActivate.subscribe(() => {
// 여기서부터 world 메서드 호출 및 다른 애드온 API 사용이 안전합니다
})TIP
바닐라 Script API 애드온에 익숙한 경우, addonActivate를 WorldLoad의 대체로 생각하세요. 추가 틱은 kairo의 핸드셰이크 비용이며, 낭비되는 시간이 아닙니다.