KaMenu API 文档
KaMenu 提供公开 API,允许其他插件打开文件菜单、渲染内存 YAML 菜单、注册自定义动作命名空间,并解析原版或第三方物品的原生 Sprite 文本组件。
API 类#
org.katacr.kamenu.api.KaMenuAPI#
openMenu(Player player, String menuId, List<String> arguments = emptyList())#
打开由 KaMenu MenuManager 加载的菜单。
参数:
player- 目标玩家menuId- 菜单 ID,例如"main_menu"或"shop/weapons"arguments- 按位置传入目标菜单的参数列表,可在菜单中使用{arg:0}、{arg:1}读取
返回值:
boolean- 是否成功提交打开请求
import org.katacr.kamenu.api.KaMenuAPI
val success = KaMenuAPI.openMenu(player, "main_menu")
KaMenuAPI.openMenu(player, "shop/weapons", listOf("weapons", "vip"))
import org.katacr.kamenu.api.KaMenuAPI;
import java.util.List;
boolean success = KaMenuAPI.openMenu(player, "main_menu");
KaMenuAPI.openMenu(player, "shop/weapons", List.of("weapons", "vip"));
openYaml(Player player, String yaml, String contextId = "external", List<String> arguments = emptyList())#
解析内存中的 YAML 字符串,并作为 KaMenu 菜单打开。该 YAML 不会写入 menus 目录,也不需要执行菜单重载。
参数:
player- 目标玩家yaml- 完整的 KaMenu 菜单 YAML 内容contextId- 外部上下文标识,用于日志定位来源arguments- 按位置传入目标菜单的参数列表
返回值:
boolean- 是否成功解析 YAML 并提交打开请求
val yaml = """
Title: "&a游戏中心"
Body:
welcome:
type: message
text: "&7欢迎你,%player_name%!"
Bottom:
type: notice
confirm:
text: "&a加入"
actions:
- "kgc:join lobby"
""".trimIndent()
KaMenuAPI.openYaml(player, yaml, "kagamecenter:main", listOf("lobby", "solo"))
如果 YAML 解析失败,KaMenu 会在警告日志中写入 contextId。
openConfig(Player player, YamlConfiguration config, String contextId = "external", List<String> arguments = emptyList())#
打开内存中的 YamlConfiguration。该配置不要求来自 MenuManager。
参数:
player- 目标玩家config- 完整的 KaMenu 菜单配置contextId- 外部上下文标识,用于日志定位来源arguments- 按位置传入目标菜单的参数列表
返回值:
boolean- 是否成功提交打开请求
import org.bukkit.configuration.file.YamlConfiguration
import org.katacr.kamenu.api.KaMenuAPI
val config = YamlConfiguration()
config.loadFromString(yaml)
KaMenuAPI.openConfig(player, config, "myplugin:dynamic-shop", listOf("diamond", "buy"))
三个平台都会在渲染前执行 Events.Open;若动作链执行 return,菜单不会继续打开。外部内存菜单使用 reset 时会重新打开当前内存 YamlConfiguration,不要求配置来自 MenuManager。
目标菜单可通过 Settings.pass_arguments 设置默认参数和最少参数数量。显式传入参数优先按索引使用;缺少的索引会使用目标菜单的 default 补位。菜单配置中可使用 {arg:0}、{arg:1}、{args} 和 {arg_count}。当补位后的参数数量小于 must 时,菜单不会打开。
registerActionHandler(String namespace, KaMenuActionHandler handler)#
注册自定义动作命名空间。形如 namespace:payload 的动作会先交给已注册的 handler 处理,再决定是否继续走 KaMenu 内置动作逻辑。
参数:
namespace- 不包含:的动作命名空间,例如"kgc"handler- 自定义动作处理器
返回值:
boolean- 是否注册成功
import org.katacr.kamenu.api.KaMenuAPI
KaMenuAPI.registerActionHandler("kgc") { player, action, variables, config ->
val payload = action.removePrefix("kgc:").trim()
when {
payload == "open-main" -> {
KaMenuAPI.openYaml(player, buildMainMenuYaml(player), "kagamecenter:main")
true
}
payload.startsWith("join ") -> {
val arenaId = payload.removePrefix("join ").trim()
joinArena(player, arenaId)
true
}
else -> false
}
}
菜单 YAML 中可以在任意支持动作列表的位置使用该命名空间:
Bottom:
type: notice
confirm:
text: "&a加入"
actions:
- "kgc:join lobby"
handler 会收到已解析变量后的动作字符串、输入变量(如 $(name))以及当前菜单配置。返回 true 表示动作已处理;返回 false 表示未处理,KaMenu 会继续尝试内置动作逻辑。handler 抛出异常时,KaMenu 会记录命名空间和动作内容。
unregisterActionHandler(String namespace)#
注销自定义动作命名空间。
KaMenuAPI.unregisterActionHandler("kgc")
resolveItemSprite(String itemId)#
将物品 ID 解析为可直接拼接到 Adventure 文本的原生 Component Sprite。支持原版材质(如 "diamond")以及 KaMenu 支持的外部物品前缀:ce: / craftengine:、ia: / itemsadder: 和 oraxen:。
参数:
itemId- 原版材质名或带提供方前缀的物品 ID,例如"ce:hfrpg:hefeng_shard"
返回值:
Component- 已固定白色的原生 Sprite Componentnull- KaMenu 未初始化、服务端低于 Minecraft1.21.9,或物品无法解析
返回的是原生 Component,不是 legacy 或 MiniMessage 字符串。调用方应直接 append 它,不能再经 LegacyComponentSerializer、ItemMeta#setLore(List<String>) 或其他字符串 API 回写,否则 Sprite 会降级为文本。
import net.kyori.adventure.text.Component
import org.katacr.kamenu.api.KaMenuAPI
val icon = KaMenuAPI.resolveItemSprite("ce:hfrpg:hefeng_shard")
val line = Component.text("强化道具:").append(icon ?: Component.empty()).append(Component.text(" 荷风碎片"))
meta.lore(listOf(line))
import net.kyori.adventure.text.Component;
import org.katacr.kamenu.api.KaMenuAPI;
import java.util.List;
Component icon = KaMenuAPI.resolveItemSprite("ce:hfrpg:hefeng_shard");
Component line = Component.text("强化道具:")
.append(icon == null ? Component.empty() : icon)
.append(Component.text(" 荷风碎片"));
meta.lore(List.of(line));
该方法会访问第三方物品 API 和 CraftEngine 最终资源包;请只在 Bukkit 主线程或 Folia 对应玩家/区域线程调用。
isAvailable()#
检查 KaMenu 是否已加载并可用。
if (KaMenuAPI.isAvailable()) {
KaMenuAPI.openMenu(player, "main_menu")
}
getPlugin()#
获取 KaMenu 插件实例。如果 KaMenu 未加载,返回 null。
动作处理器接口#
package org.katacr.kamenu.api
import org.bukkit.configuration.file.YamlConfiguration
import org.bukkit.entity.Player
fun interface KaMenuActionHandler {
fun execute(
player: Player,
action: String,
variables: Map<String, String>,
rawConfig: YamlConfiguration?
): Boolean
}
建议为你的插件选择唯一命名空间。除非你明确希望拦截内置动作,否则不要使用 tell、open、command、console、js 等内置动作名称作为命名空间。
在其他插件中使用#
方法 1:反射调用#
如果你的插件不需要直接编译依赖 KaMenu,可以使用反射调用 API:
fun openKaMenu(player: Player, menuId: String): Boolean {
return try {
val kaMenuPlugin = player.server.pluginManager.getPlugin("KaMenu") ?: return false
val apiClass = Class.forName("org.katacr.kamenu.api.KaMenuAPI")
val openMenuMethod = apiClass.getMethod("openMenu", Player::class.java, String::class.java)
openMenuMethod.invoke(null, player, menuId) == true
} catch (e: Exception) {
e.printStackTrace()
false
}
}
方法 2:添加插件依赖#
如果希望使用类型安全的 API,可以在 plugin.yml 中添加 KaMenu 作为依赖:
name: YourPlugin
version: 1.0.0
main: com.yourname.yourplugin.Main
api-version: "1.21"
depend:
- KaMenu
然后直接调用:
import org.katacr.kamenu.api.KaMenuAPI
fun openShop(player: Player) {
KaMenuAPI.openMenu(player, "shop/weapons")
}
注意事项#
- 插件依赖:调用 API 前请确保 KaMenu 已安装并启用。
- 菜单来源:文件菜单使用
openMenu,动态内存菜单使用openYaml或openConfig。 - 线程:
openConfig和openYaml可以从异步代码调用;KaMenu 会将实际 Dialog 渲染调度回服务器主线程。 - Open 事件:内存菜单同样会在渲染前执行
Events.Open。 - 错误处理:建议检查布尔返回值,并在 API 调用失败时给玩家或日志提供反馈。
完整示例#
package com.example.plugin
import org.bukkit.command.Command
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
import org.bukkit.plugin.java.JavaPlugin
import org.katacr.kamenu.api.KaMenuAPI
class ExamplePlugin : JavaPlugin() {
override fun onEnable() {
if (!KaMenuAPI.isAvailable()) {
logger.warning("KaMenu 插件未安装,部分功能将不可用")
}
KaMenuAPI.registerActionHandler("example") { player, action, variables, config ->
val payload = action.removePrefix("example:").trim()
if (payload == "reward") {
player.sendMessage("§a奖励动作已由 ExamplePlugin 处理")
true
} else {
false
}
}
}
override fun onDisable() {
KaMenuAPI.unregisterActionHandler("example")
}
override fun onCommand(
sender: CommandSender,
command: Command,
label: String,
args: Array<out String>
): Boolean {
if (!command.name.equals("openmenu", ignoreCase = true)) {
return false
}
if (sender !is Player) {
sender.sendMessage("§c该指令只能由玩家执行")
return true
}
val yaml = """
Title: "&a示例菜单"
Body:
text:
type: message
text: "&7该菜单来自内存 YAML。"
Bottom:
type: notice
confirm:
text: "&a领取奖励"
actions:
- "example:reward"
""".trimIndent()
val success = KaMenuAPI.openYaml(sender, yaml, "example:command")
if (!success) {
sender.sendMessage("§c打开菜单失败")
}
return true
}
}
监听事件#
KaMenu 提供两个公开 Bukkit 事件,供其他插件(如 EcoQuests)监听菜单打开与数据变化,以驱动任务、统计等逻辑。事件类位于 org.katacr.kamenu.api.event 包。
KaMenuOpenEvent#
玩家打开 KaMenu 菜单时触发。该事件在菜单真正打开(容器菜单或 Dialog 菜单均可)前同步抛出,携带菜单 ID、来源与参数。
| 字段 | 类型 | 说明 |
|---|---|---|
player |
Player |
打开菜单的玩家 |
menuId |
String |
菜单 ID,如 "主菜单/主菜单" |
source |
KaMenuOpenEvent.Source |
打开来源:COMMAND / BUTTON / API / OTHER |
arguments |
List<String> |
传入菜单的参数列表 |
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.katacr.kamenu.api.event.KaMenuOpenEvent
class MyListener : Listener {
@EventHandler
fun onMenuOpen(event: KaMenuOpenEvent) {
val player = event.player
if (event.menuId == "主菜单/主菜单") {
// 玩家打开了主菜单
}
}
}
KaMenuDataChangeEvent#
KaMenu 数据存储(data / gdata / list / glist / meta / 临时数据)发生写入、修改、增减或删除时触发。
| 字段 | 类型 | 说明 |
|---|---|---|
scope |
KaMenuDataChangeEvent.Scope |
作用域:PLAYER_DATA / GLOBAL_DATA / PLAYER_LIST / GLOBAL_LIST / META / PLAYER_TMP |
action |
KaMenuDataChangeEvent.Action |
操作:SET / MODIFY / ADD / REMOVE / CLEAR |
player |
Player? |
相关玩家;全局作用域或玩家不在线时为 null |
key |
String |
数据键 |
value |
String? |
写入/追加的新值;删除类操作可能为 null |
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.katacr.kamenu.api.event.KaMenuDataChangeEvent
class DataListener : Listener {
@EventHandler
fun onDataChange(event: KaMenuDataChangeEvent) {
if (event.scope == KaMenuDataChangeEvent.Scope.PLAYER_DATA && event.key == "quest_progress") {
val player = event.player ?: return
// 玩家 data 键 quest_progress 发生变化
}
}
}
注意事项#
- 事件是同步抛出的:
KaMenuOpenEvent在主线程抛出;KaMenuDataChangeEvent由异步数据库写操作触发,KaMenu 会先切回主线程再抛出。监听器内可安全调用 Bukkit API。 - 在线玩家:
KaMenuDataChangeEvent.player仅在玩家在线时非空;跨服/离线玩家数据变化时该字段为null。 - 列表写操作:
list/glist方法复用data/gdata写入路径,因此一次列表写会同时触发对应的标量事件与列表事件,可按scope区分。 - 示例联动:EcoQuests 等插件可通过监听
KaMenuOpenEvent在任务书里添加"打开菜单"类任务。