Skip to content

快速开始

支持的 Minecraft Script API 版本

Kairo 需要 Minecraft 的稳定版 Script API:

  • @minecraft/server 2.0.0 及以上
  • @minecraft/server-ui 2.0.0 及以上

2.0.0 之前的版本使用不同的初始化模型(例如使用 WorldInitialize 而非 WorldLoad),不受支持。

安装 kairo

kairo 行为包添加到你的世界中。它充当所有插件之间的通信中枢。

GitHub Releases 下载 kairo。

Kairo 不需要针对每个世界进行配置。即使同一世界中存在多个 Kairo 版本,Kairo 也会自动选择一个 active host。附加包代码仍然只需要依赖 @kairo-js/router,不需要知道当前由哪个 Kairo 包实例托管。

使用 kairo-router

kairo-router 添加到你的插件中,即可开始与其他插件进行通信。

安装

bash
pnpm add @kairo-js/router @kairo-js/properties

@kairo-js/router 是附加包通信的 runtime API。@kairo-js/properties 提供 AddonProperties 类型,以及适合 router.init() 和 manifest 元数据的结构。

Kairo 还发布了 @kairo-js/utils。开始使用 router 时通常不需要它,但它提供 SemVer 工具、seeded random、JSON parse helper 和 TypeBox compile helper 等共享工具。

在启动事件中声明 API

所有 API 注册和钩子声明必须在 router.beforeEvents.startup 内完成。

typescript
import { router } from '@kairo-js/router'
import type { AddonProperties } from '@kairo-js/properties'
import { properties } from './properties'

router.beforeEvents.startup.subscribe((ev) => {
  // 注册本插件提供的 API
  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。

typescript
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

typescript
// 发送后不等待结果
router.send('economy-addon', 'onTransaction', { amount: 50 })

// 等待返回结果
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 参考

必须依赖项

properties.ts 中必须将 "kairo" 声明为必须依赖项。如果缺失,router.init() 将立即抛出错误。

typescript
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 出现在 dependenciesoptionalDependencies 中。

自定义命令

请在 router.beforeEvents.startup 内通过 ev.customCommandRegistry 注册自定义命令,而不是直接使用 Minecraft native registry。

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 时,若必须依赖项仅包含 kairokairo-database,插件将自动激活。适用于希望选择性集成 kairo 生命周期管理的独立附加包。

详情请参见 RouterInitOptions

初始化时机

世界加载后,kairo 会执行 Discovery · Registration · Activation 初始化流程,之后才触发 addonActivate。根据已安装的附加包数量,大约有 30〜50 tick 的延迟

这个延迟是有意为之的。Minecraft Script API 2.0.0+ 规定在 WorldLoad 完成前调用 world 相关方法会报错,addonActivate 承担了同样的安全信号作用。

typescript
router.afterEvents.addonActivate.subscribe(() => {
  // 从这里开始可以安全地调用 world 方法和其他附加包的 API
})

TIP

如果你熟悉原版 Script API 开发,可以将 addonActivate 理解为 WorldLoad 的替代。额外的 tick 是 kairo 握手的成本,并非无效等待。

Released under the MIT License.