跳转至

🔍 条件判断

KaMenu 提供了强大的通用条件判断系统,可以在菜单的任意文本字段动作列表中使用,根据玩家状态动态显示不同内容或执行不同操作。


支持的位置

条件判断可用于以下所有位置:

位置 说明
Title 菜单标题
Body.*.text Body 组件文本
Body.*.name / Body.*.lore 物品组件名称和 Lore
Body.*.type 组件类型(用于条件隐藏组件)
Inputs.*.text 输入组件标签文字
Bottom.*.text 所有按钮文字
Bottom.*.actions 按钮动作列表(执行条件分支)
Events.* 菜单事件动作列表(详见事件系统

文本字段条件判断

语法

字段名:
  - condition: "条件表达式"
    allow: '条件满足时的值'
    deny: '条件不满足时的值'

条件表达式中的任意文本都可以继续使用内置占位符,例如 {data:...}{gdata:...}{meta:...}$(input),以及 {js:...}

condition: '{js:player.getLevel() >= 10} == true'
allow: '&a等级足够'
deny: '&c等级不足'

变量解析顺序

条件判断会先解析表达式中的变量,再把解析后的结果交给条件表达式引擎和内置条件方法判断。

例如:

condition: "isNull.{data:nickname}"
condition: "isNull.%player_name%"
condition: "isNull.$(nickname)"

执行时会先解析 {data:nickname}%player_name%$(nickname),然后再将解析结果传给 isNull 判断。动作列表内的条件会额外携带当前按钮、输入组件和动作包参数上下文,因此 $(input){arg:0} 等也会先被替换后再判断。

运行时变量值会作为一个完整字符串参与判断,不会被重新解释为条件表达式语法。也就是说,玩家输入中即使包含 ||&&、换行、引号或类似 YAML 的文本,也只会作为普通字符串值处理。

示例

菜单标题:

Title:
  - condition: "%player_is_op% == true"
    allow: '&8» &4&l管理员面板 &8«'
    deny: '&8» &6&l玩家面板 &8«'

输入组件标签:

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 提供了一些内置的条件判断方法,使用 . 符号调用。

语法

method.value    # 正向判断
!method.value   # 反向判断

支持的方法

方法 说明 正向示例 反向示例
isNull 判断值是否为空。空字符串、全空格字符串、null 都视为空 isNull.$(nickname) !isNull.{data:nickname}
isPass 判断值是否为绝对空字符串。只有长度为 0 时通过,空格字符串不通过 isPass.$(nickname) !isPass.$(nickname)
isTrue 判断值是否为真。接受 trueyes1,其中 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 内置变量和输入组件值:

condition: "isNull.%some_placeholder%"
condition: "isNull.{data:var}"
condition: "isNull.$(input)"

判断是否为绝对空字符串:

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 接受 trueyes、数字 1trueyes 不区分大小写。其他值、空值、空格字符串都视为 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'

inListinGlist 功能相同,分别用于表达玩家列表和全局列表场景。参数格式为 值;列表,列表支持:

  • {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你没有权限!'
判断玩家是否有 10 个钻石:

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 奖励!'

注意事项

  1. PAPI 依赖:使用 %papi_var% 格式的变量需要安装 PlaceholderAPI 插件
  2. 数值转换:无法转换为数值的字符串在数值比较(>< 等)中被视为 0
  3. 大小写不敏感==!= 运算符在字符串比较时不区分大小写
  4. deny 可省略:动作条件中 deny 字段为可选;文本字段条件中 deny 建议填写以避免空白显示
  5. 嵌套括号:支持多层括号嵌套来构建复杂的逻辑表达式
  6. 数据持久化
    • {data:key}{gdata:key} 存储在数据库中,持久化保存
    • {meta:key} 仅存储在内存中,玩家退出或插件重载后自动清空
    • 使用 {meta:key} != null 判断元数据是否存在
  7. 内置方法格式
    • 使用 method.value 格式,如 isInt.$(amount)
    • 支持反向判断,使用 ! 前缀,如 !hasPerm.kamenu.admin
    • 反向判断适用于需要在条件不满足时执行操作的场景

相关文档


演示菜单

插件内置了条件判断的演示菜单,可通过以下指令打开体验:

/km open example/actions_demo