🔍 条件判断¶
KaMenu 提供了强大的通用条件判断系统,可以在菜单的任意文本字段和动作列表中使用,根据玩家状态动态显示不同内容或执行不同操作。
支持的位置¶
条件判断可用于以下所有位置:
| 位置 | 说明 |
|---|---|
Title |
菜单标题 |
Body.*.text |
Body 组件文本 |
Body.*.name / Body.*.lore |
物品组件名称和 Lore |
Body.*.type |
组件类型(用于条件隐藏组件) |
Inputs.*.text |
输入组件标签文字 |
Bottom.*.text |
所有按钮文字 |
Bottom.*.actions |
按钮动作列表(执行条件分支) |
Events.* |
菜单事件动作列表(详见事件系统) |
文本字段条件判断¶
语法¶
条件表达式中的任意文本都可以继续使用内置占位符,例如 {data:...}、{gdata:...}、{meta:...}、$(input),以及 {js:...}:
变量解析顺序¶
条件判断会先解析表达式中的变量,再把解析后的结果交给条件表达式引擎和内置条件方法判断。
例如:
condition: "isNull.{data:nickname}"
condition: "isNull.%player_name%"
condition: "isNull.$(nickname)"
执行时会先解析 {data:nickname}、%player_name% 或 $(nickname),然后再将解析结果传给 isNull 判断。动作列表内的条件会额外携带当前按钮、输入组件和动作包参数上下文,因此 $(input)、{arg:0} 等也会先被替换后再判断。
运行时变量值会作为一个完整字符串参与判断,不会被重新解释为条件表达式语法。也就是说,玩家输入中即使包含 ||、&&、换行、引号或类似 YAML 的文本,也只会作为普通字符串值处理。
示例¶
菜单标题:
输入组件标签:
Inputs:
amount:
type: 'slider'
text:
- condition: "%player_level% >= 10"
allow: '&6VIP 购买数量(最多 64)'
deny: '&7购买数量(最多 16)'
min: 1
max:
- condition: "%player_level% >= 10"
allow: '64'
deny: '16'
按钮文字:
Bottom:
type: 'confirmation'
confirm:
text:
- condition: "%player_level% >= 10"
allow: '&6[ VIP 确认 ]'
deny: '&a[ 确认 ]'
动作列表条件判断¶
在 actions 列表中嵌套条件,可以实现分支执行:
语法¶
actions:
- condition: "条件表达式"
allow:
- '条件满足时执行的动作1'
- '条件满足时执行的动作2'
deny:
- '条件不满足时执行的动作1'
- '条件不满足时执行的动作2'
deny 字段为可选项;不提供时,条件不满足则不执行任何操作。
混合使用¶
可以在同一个 actions 列表中混合使用普通动作和条件动作:
actions:
- 'sound: ui.button.click' # 无论如何都执行
- condition: "%player_balance% >= 100"
allow:
- 'console: eco take %player_name% 100'
- 'tell: &a扣款成功!'
deny:
- 'tell: &c余额不足!'
- 'close' # 无论如何都执行
条件表达式语法¶
比较运算符¶
| 运算符 | 说明 | 示例 |
|---|---|---|
== |
等于 | %player_name% == Steve |
!= |
不等于 | %world_name% != world_nether |
> |
大于 | %player_level% > 10 |
>= |
大于等于 | %player_health% >= 10 |
< |
小于 | %player_food_level% < 18 |
<= |
小于等于 | %player_exp% <= 100 |
注意:
- 字符串比较(
==和!=)默认不区分大小写 - 无法转换为数值的字符串在数值比较中会被当作
0处理 - 条件中也支持
{js:...},用于动态计算返回值
逻辑运算符¶
| 运算符 | 说明 | 优先级 |
|---|---|---|
&& |
逻辑与(AND) | 高 |
\|\| |
逻辑或(OR) | 低 |
() |
括号(改变优先级) | 最高 |
支持短路求值:
||:第一个条件为true时,不再计算后续条件&&:第一个条件为false时,不再计算后续条件
表达式示例¶
# 单个条件
- condition: "%player_level% >= 10"
# AND 条件
- condition: "%player_level% >= 10 && %player_level% < 20"
# OR 条件
- condition: "%player_is_op% == true || %player_level% >= 20"
# 使用括号
- condition: "(%player_level% >= 5 && %player_level% <= 10) || %player_is_op% == true"
内置条件方法¶
KaMenu 提供了一些内置的条件判断方法,使用 . 符号调用。
语法¶
支持的方法¶
| 方法 | 说明 | 正向示例 | 反向示例 |
|---|---|---|---|
isNull |
判断值是否为空。空字符串、全空格字符串、null 都视为空 |
isNull.$(nickname) |
!isNull.{data:nickname} |
isPass |
判断值是否为绝对空字符串。只有长度为 0 时通过,空格字符串不通过 | isPass.$(nickname) |
!isPass.$(nickname) |
isTrue |
判断值是否为真。接受 true、yes、1,其中 true / yes 不区分大小写 |
isTrue.$(agree) |
!isTrue.{data:enabled} |
getLength |
输出字符串长度,通常搭配比较运算符使用 | getLength.%player_name% >= 3 |
getLength.$(nickname) == 0 |
isNum |
判断是否为数字(整数或小数) | isNum.$(amount) |
!isNum.$(amount) |
isPosNum |
判断是否为正数(大于0) | isPosNum.{data:price} |
!isPosNum.{data:price} |
isInt |
判断是否为整数 | isInt.$(count) |
!isInt.$(count) |
isPosInt |
判断是否为正整数(大于0) | isPosInt.$(amount) |
!isPosInt.$(amount) |
hasPerm |
判断玩家是否拥有权限 | hasPerm.kamenu.admin |
!hasPerm.kamenu.admin |
hasMoney |
判断玩家是否有足够的金币 | hasMoney.100 |
!hasMoney.100 |
hasItem |
判断玩家背包中是否有指定材质、数量的物品 | hasItem.[mats=DIAMOND;amount=10] |
!hasItem.hasItem.[mats=DIAMOND;amount=10] |
hasStockItem |
判断玩家背包中是否有存储库的物品 | hasStockItem.神秘果;16 |
!hasStockItem.神秘果;16 |
inList / inGlist |
判断某个值是否在玩家列表/全局列表内 | inGlist.%player_name%;{glist:vip_players} |
!inList.%player_name%;Steve,Alex |
关于物品判断详细使用方法,请参阅 hasItem 和 hasStockItem 条件方法 。
使用示例¶
判断输入值是否为整数:
actions:
- condition: "isInt.$(amount)"
allow:
- 'tell: &a输入的值是整数: $(amount)'
deny:
- 'tell: &c请输入一个有效的整数!'
判断输入或数据是否为空:
actions:
- condition: "isNull.$(nickname)"
allow:
- 'toast: type=error;msg=请输入昵称;icon=barrier'
- 'return'
- condition: "!isNull.{data:nickname}"
allow:
- 'tell: &a已保存的昵称: {data:nickname}'
isNull 可用于 PAPI、KaMenu 内置变量和输入组件值:
判断是否为绝对空字符串:
actions:
- condition: "isPass.$(nickname)"
allow:
- 'toast: type=error;msg=请输入昵称;icon=barrier'
- 'return'
isPass 只在值长度为 0 时通过。输入一个或多个空格不算通过;如果希望空格也算空,请使用 isNull。
判断值是否为 true:
actions:
- condition: "isTrue.$(agree)"
allow:
- 'toast: type=task;msg=已同意;icon=emerald'
deny:
- 'toast: type=error;msg=请先勾选;icon=barrier'
- 'return'
isTrue 接受 true、yes、数字 1;true 和 yes 不区分大小写。其他值、空值、空格字符串都视为 false。
判断字符串长度:
actions:
- condition: "getLength.%player_name% >= 3"
allow:
- 'tell: &a你的名字长度至少为 3'
- condition: "getLength.$(nickname) > 12"
allow:
- 'toast: type=error;msg=昵称过长;icon=barrier'
- 'return'
getLength.xxx 会先解析变量,再输出解析后字符串的长度。它是值函数,通常与 ==、!=、>、>=、<、<= 一起使用。
判断是否为正整数:
actions:
- condition: "isPosInt.$(amount)"
allow:
- 'tell: &a有效的正整数: $(amount)'
deny:
- 'tell: &c请输入大于0的整数!'
判断玩家是否有足够金币:
actions:
- condition: "hasMoney.100"
allow:
- 'console: eco take %player_name% 100'
- 'tell: &a购买成功!'
deny:
- 'tell: &c余额不足,需要 100 金币'
判断某个值是否在列表中:
actions:
- condition: "inGlist.%player_name%;{glist:vip_players}"
allow:
- 'toast: type=task;msg=已在名单;icon=emerald'
deny:
- 'toast: type=error;msg=不在名单;icon=barrier'
inList 和 inGlist 功能相同,分别用于表达玩家列表和全局列表场景。参数格式为 值;列表,列表支持:
{list:key}/{glist:key}返回的 JSON 字符串数组- JSON 字符串数组,例如
["Steve","Alex"] - 简易字符串列表,例如
Steve,Alex,Notch
成员匹配为精确匹配,默认不区分大小写。
权限检查(正向):
Bottom:
confirm:
text: '管理员操作'
actions:
- condition: "hasPerm.kamenu.admin"
allow:
- 'open: admin_panel'
deny:
- 'tell: &c你没有权限执行此操作!'
权限检查(反向 - 没有权限时执行):
Bottom:
confirm:
text: '管理员操作'
actions:
- condition: "!hasPerm.kamenu.admin"
allow:
- 'tell: &c你没有权限!'
actions:
- condition: "hasItem.[mats=DIAMOND;amount=10]"
allow:
- 'tell: &a你有足够的钻石!'
deny:
- 'tell: &c你需要 10 个钻石!'
判断玩家是否有 16 个神秘果:
actions:
- condition: "hasStockItem.神秘果;16"
allow:
- 'tell: &a你有足够的神秘果!'
deny:
- 'tell: &c你需要 16 个神秘果!'
变量支持¶
条件表达式中支持以下变量格式:
| 变量格式 | 说明 | 示例 |
|---|---|---|
%papi_var% |
PlaceholderAPI 变量 | %player_level% |
{data:key} |
玩家个人数据(持久化) | {data:vip_level} |
{gdata:key} |
全局共享数据(持久化) | {gdata:server_status} |
{meta:key} |
玩家元数据(内存缓存) | {meta:last_visit} |
$(key) |
对话框输入变量(仅在动作和 Inputs 区域支持,Body 区域不支持) | $(amount) |
Body 区域特殊说明:
- Body 区域的文本在对话框和按钮输入前渲染,因此不支持
$(key)输入变量 - Body 区域支持
{data:key}、{gdata:key}和{meta:key}内置变量 - Inputs 和 Actions 区域支持所有变量格式
元数据说明:
- 元数据仅存储在内存中,不持久化到数据库
- 玩家退出时自动清理该玩家的元数据
- 插件重载或关服时清理全部元数据
- 适用于需要短时间存储临时数据的场景
完整示例¶
示例 1:VIP 等级判断¶
Bottom:
type: 'notice'
confirm:
text: '&a领取每日奖励'
actions:
- condition: "%player_level% >= 10"
allow:
- 'console: give %player_name% diamond 5'
- 'tell: &a&lVIP 奖励: &f5 颗钻石'
- 'title: title=&6领取成功;subtitle=&fVIP 专属奖励;in=5;keep=40;out=10'
deny:
- 'console: give %player_name% dirt 1'
- 'tell: &7普通奖励: 1 块泥土'
- 'tell: &e达到 10 级可领取 VIP 奖励!'
示例 2:管理员操作¶
Bottom:
type: 'multi'
columns: 2
buttons:
admin_panel:
text:
- condition: "%player_is_op% == true"
allow: '&4[ 管理面板 ]'
deny: '&8[ 已锁定 ]'
actions:
- condition: "%player_is_op% == true"
allow:
- 'open: admin/tools'
deny:
- 'tell: &c你没有权限访问管理面板!'
示例 3:余额检查¶
actions:
- condition: "hasMoney.1000"
allow:
- 'console: eco take %player_name% 1000'
- 'tell: &a购买成功!已扣除 1000 金币'
- 'sound: entity.player.levelup'
deny:
- 'tell: &c余额不足!需要 1000 金币'
- 'tell: &7当前余额: &f%player_balance%'
- 'sound: block.note_block.bass'
示例 4:复杂多条件¶
actions:
- condition: "(%player_level% >= 5 && %player_level% <= 10) || %player_is_op% == true"
allow:
- 'tell: &a条件通过:你是 5-10 级玩家,或者你是管理员'
deny:
- 'tell: &c不符合条件'
示例 5:元数据状态检查¶
actions:
- condition: "{meta:temp_status} != null"
allow:
- 'tell: &a临时状态存在: {meta:temp_status}'
deny:
- 'tell: &7未设置临时状态'
- 'set-meta: last_action clicked'
示例 6:元数据与条件结合¶
actions:
# 设置临时状态
- 'set-meta: temp_user true'
- condition: "{meta:temp_user} == true"
allow:
- 'tell: &a已标记为临时用户'
- 'open: temp_menu'
deny:
- 'tell: &c未标记为临时用户'
示例 7:使用内置方法验证输入¶
Inputs:
amount:
type: 'input'
text: '请输入数量(正整数)'
actions:
- condition: "isPosInt.$(amount)"
allow:
- 'tell: &a有效输入: $(amount)'
- 'set-meta: purchase_amount $(amount)'
deny:
- 'tell: &c请输入大于0的整数!'
- 'close'
示例 8:反向权限检查(没有权限时提示)¶
Bottom:
confirm:
text: '购买 VIP'
actions:
# 没有权限时提示(反向判断)
- condition: "!hasPerm.vip.purchase"
allow:
- 'tell: &c你需要购买 vip.purchase 权限才能执行此操作!'
deny: []
# 有权限时执行购买逻辑
- condition: "hasPerm.vip.purchase"
allow:
- 'console: eco give %player_name% 1000'
- 'tell: &a已发放 1000 金币作为 VIP 奖励!'
注意事项¶
- PAPI 依赖:使用
%papi_var%格式的变量需要安装 PlaceholderAPI 插件 - 数值转换:无法转换为数值的字符串在数值比较(
>、<等)中被视为0 - 大小写不敏感:
==和!=运算符在字符串比较时不区分大小写 - deny 可省略:动作条件中
deny字段为可选;文本字段条件中deny建议填写以避免空白显示 - 嵌套括号:支持多层括号嵌套来构建复杂的逻辑表达式
- 数据持久化:
{data:key}和{gdata:key}存储在数据库中,持久化保存{meta:key}仅存储在内存中,玩家退出或插件重载后自动清空- 使用
{meta:key} != null判断元数据是否存在
- 内置方法格式:
- 使用
method.value格式,如isInt.$(amount) - 支持反向判断,使用
!前缀,如!hasPerm.kamenu.admin - 反向判断适用于需要在条件不满足时执行操作的场景
- 使用
相关文档¶
- 🍉 hasItem和hasStockItem条件方法 - 了解物品判断的详细使用
- ⚙️ 事件 (Events) - 了解事件系统的详细使用
- 🤖 动作 (Actions) - 了解所有可用的动作类型
- 💾 数据存储 - 了解数据存储和变量使用
演示菜单¶
插件内置了条件判断的演示菜单,可通过以下指令打开体验: