Skip to content

Script Engine

Noogear edited this page Mar 9, 2026 · 4 revisions

脚本引擎

GloomLib Script — 高性能声明式 YAML 脚本引擎,将事件处理逻辑编译为 JVM 字节码执行。

目录

数学表达式完整语法 → 数学表达式

集合操作详细参考 → 集合操作


顶层结构

id: "my-script"                              # 脚本标识符(可选,默认 AnonymousScript)
event: "com.example.MyEvent"                 # 必填,事件/载荷类的全限定名
priority: 0                                  # 可选,事件优先级(默认 0)
ignore-cancelled: true                       # 可选,已取消事件是否跳过(默认 true)

variables:
  # ...

flow:
  # ...
字段 类型 必填 默认值 说明
id String AnonymousScript 脚本唯一标识,用于日志和错误追踪
event String 载荷类全限定名
priority Integer 0 事件监听优先级
ignore-cancelled boolean true true 时已被取消的事件不触发脚本
variables Map {} 变量声明映射
flow List [] 流程节点列表

variables 变量声明

将载荷对象的属性映射为脚本变量。

variables:
  # 简单属性:调用 event.getDamage()
  damage: "damage"

  # 链式属性:event.getEntity().getName()
  entityName: "entity.name"

  # 集合索引:event.getPlayer().getInventory().get(0)
  firstItem: "player.inventory[0]"

  # Map 索引:event.getMetadata().get("key")
  metaValue: "metadata[key]"
  quotedKey: "metadata['damage_all']"

  # payload 别名:直接引用载荷对象本身
  event: "$self"

属性解析规则

语法 示例 解析方式
简单属性 damage 调用 getDamage()damage()
链式属性 entity.name 依次调用 getEntity()getName()
List 索引 inventory[0] 调用 getInventory()List.get(0)
Map 索引 metadata[key] 调用 getMetadata()Map.get("key")
payload 别名 $self 直接引用载荷对象

getter 查找优先级

  1. getXxx() — 标准 Java Bean getter
  2. isXxx() — boolean getter
  3. xxx() — Record 风格 accessor

flow 流程节点

flow 是一个有序列表,引擎按顺序执行每个节点。共支持 8 种节点类型

类型 YAML 触发键 说明
CHECK check 条件判断
ACTION action 或动态推断 调用已注册动作
RETURN return 返回值并终止
SWITCH switch 多分支选择
MATH math 数学表达式求值
ANY any OR 复合条件
ALL all AND 复合条件
COLLECT collect 集合遍历与筛选

节点类型通过触发键自动推断,无需显式声明 type 字段。


check 条件判断

# 基本格式
- check: <variable>
  op: "<operator>"
  value: <value>

# 带失败动作
- check: damage
  op: ">"
  value: 100
  on_fail:
    - action: "log"
      args: ["条件不满足"]
字段 类型 必填 说明
check String 检查的变量名
op String 操作符(支持 ! 前缀取反)
value any 视操作符 比较目标值
on_fail List 条件不满足时执行的节点列表

value 字段支持的类型

# 数值
value: 100
value: 3.14

# 字符串
value: "sword"

# 布尔
value: true

# 列表(用于 in / between)
value: ["sword", "bow", "axe"]           # in:候选值列表
value: [10.0, 50.0]                       # between:[下界, 上界] 闭区间

# 变量引用
value: "{maxHp}"

# 数学表达式(数值操作符时自动解析)
value: "{maxHp} * 0.5"

# 类名(用于 instanceof)
value: "com.example.PlayerEntity"

action 动作调用

# 标准格式
- action: "showIndicator"
  args: ["{target}", "{source}", "{value}", "CRITICAL"]

# 短语法(动态推断)
# 当节点中不含保留字段时,第一个字段被视为 action 名
- showIndicator: ["{target}", "{source}", "{value}", "CRITICAL"]

# 捕获返回值
- action: "someAction"
  args: ["arg1"]
  store: "result"
字段 类型 必填 说明
action String 已注册的动作名
args List 参数列表,支持 {变量} 模板插值
store String 将返回值存入此变量名

动态推断

当节点不包含任何保留键(checkswitchreturnanyallmathcollectactiontype)时,引擎将第一个字段视为动作名,其值视为参数列表。

# 以下两种写法等价
- action: "sendMessage"
  args: ["hello"]

- sendMessage: ["hello"]

return 返回值

# 1. 空返回(返回 null)
- return

# 2. 变量返回
- return: "{damage}"

# 3. 模板字符串返回
- return: "HP:{hp} 伤害:{damage}"

# 4. 字面量返回
- return: 42
- return: true
- return: "固定文本"

# 5. 集合字面量返回
- return: [1, "{hp}", "fixed", true]

switch 多分支

- switch: weaponType
  cases:
    SWORD:
      - action: "log"
        args: ["剑类武器"]
    BOW:
      - action: "log"
        args: ["弓类武器"]
    DAGGER:
      - action: "log"
        args: ["匕首类武器"]
字段 类型 必填 说明
switch String 用于分支匹配的变量名
cases Map 分支映射,key 为匹配值,value 为节点列表

若无匹配分支,switch 不执行任何操作,继续后续流程。


math 数学运算

- math: "{damage} * 1.5 + {bonus}"
  store: "finalDamage"
字段 类型 必填 说明
math String 数学表达式(支持 {变量} 引用)
store String 结果存入此变量名(double 类型)

完整的运算符、函数、优先级参考 → 数学表达式


any / all 复合条件

# ANY(OR 短路):任一子条件成立即通过
- any:
    - check: damage
      op: ">"
      value: 50
    - check: weaponName
      op: "=="
      value: "sword"
  on_fail:
    - action: "log"
      args: ["所有条件都不满足"]

# ALL(AND 短路):全部子条件成立才通过
- all:
    - check: damage
      op: ">"
      value: 10
    - check: weaponName
      op: "=="
      value: "sword"
  on_fail:
    - return
字段 类型 必填 说明
any / all List 子条件节点列表
on_fail List 条件不满足时执行的节点列表

嵌套

支持任意深度的嵌套组合:

- any:
    - all:
        - check: damage
          op: ">"
          value: 100
        - check: rank
          op: ">="
          value: 5
    - check: weaponName
      op: "=="
      value: "legendary_sword"

collect 集合操作

遍历集合变量,按条件筛选或聚合。

- collect: items
  op: exists
  match:
    - op: "contains"
      value: "sword"
  on_fail:
    - return
字段 类型 必填 说明
collect String 集合变量名
op String 操作类型
match List 匹配条件列表(多条件 AND 关系)
store String 视操作 结果存储变量名(count/index/find/filter 必填)
on_fail List 量词操作失败时执行的节点列表

操作类型

操作 取反 结果 说明
exists !exists 控制流 是否存在匹配元素(∃)
all !all 控制流 是否全部元素匹配(∀)
count int → store 统计匹配元素数量
index int → store 首个匹配元素索引(-1 表示未找到)
find Object → store 首个匹配元素(null 表示未找到)
filter List → store 所有匹配元素组成的列表

集合操作的详细语法与示例 → 集合操作


操作符完整参考

所有操作符前均可加 ! 前缀取反(如 !null!contains!==)。

操作符矩阵

操作符 分类 说明
null 空值检测 检查变量是否为 null
instanceof 类型检测 检查类型并自动窄化
== 相等 相等比较
!= 相等 不等比较
> 数值 大于
>= 数值 大于等于
< 数值 小于
<= 数值 小于等于
between 数值 闭区间范围检查,value 为 [low, high]
starts_with 字符串 前缀匹配
ends_with 字符串 后缀匹配
matches 字符串 Java 正则全匹配
contains 成员 字符串包含 / 集合成员检查
in 成员 检查变量值是否在给定列表中

拼写纠错

引擎内置常见拼写错误的自动提示:

错误拼写 建议修正
startsWithstartswithstart_with starts_with
endsWithendswithend_with ends_with
matchregex matches
includeincludeshas contains
eqisequalequals ==
neneqnot !=
gt / lt / gte / lte > / < / >= / <=

instanceof 窄化

instanceof 检查成功后,变量类型自动窄化为目标类,后续节点可直接访问子类属性:

variables:
  entity: "entity"

flow:
  - check: entity
    op: "instanceof"
    value: "org.bukkit.entity.Player"

  # 窄化后可直接访问 Player 独有属性
  - action: "log"
    args: ["玩家名: {entity.playerName}"]

模板字符串

使用 {变量名} 语法在字符串中插入变量值。

# 单变量引用
args: ["{damage}"]

# 多变量模板
args: ["玩家 {playerName} 受到 {damage} 点伤害"]

# 链式属性引用
args: ["{entity.name}"]

# return 中使用模板
- return: "HP:{hp} DMG:{damage}"

属性链解析

属性路径支持多级嵌套:

player.inventory[0].amount
  │       │      │     └── getAmount() → int
  │       │      └──────── List.get(0) → ItemStack
  │       └─────────────── getInventory() → List<ItemStack>
  └─────────────────────── getPlayer() → Player
类型 语法 说明
属性访问 property 标准 getter 调用
List 索引 list[index] List.get(int)
Map 索引 map[key] Map.get(String),支持引号包裹 key

完整示例

示例 1:伤害指示器

id: "damage-indicator"
event: "org.bukkit.event.entity.EntityDamageByEntityEvent"
priority: 3

variables:
  target: "entity"
  source: "damager"
  value: "finalDamage"
  cause: "cause"
  critical: "critical"

flow:
  - check: target
    op: "instanceof"
    value: "org.bukkit.entity.LivingEntity"

  - check: value
    op: ">"
    value: 0

  - check: critical
    op: "!="
    value: true
    on_fail:
      - showIndicator: ["{target}", "{source}", "{value}", "CRITICAL"]
      - return

  - showIndicator: ["{target}", "{source}", "{value}", "{cause.name}"]

示例 2:复合条件与失败回退

id: "pvp-guard"
event: "org.bukkit.event.entity.EntityDamageByEntityEvent"

variables:
  damage: "damage"
  entity: "entity"
  weapon: "damager.itemInMainHand.type.name"

flow:
  - all:
      - check: damage
        op: ">"
        value: 5
      - check: weapon
        op: "in"
        value: ["DIAMOND_SWORD", "IRON_SWORD", "NETHERITE_SWORD"]
      - check: entity
        op: "!null"
    on_fail:
      - return

  - any:
      - check: damage
        op: "between"
        value: [100, 999]
      - check: weapon
        op: "starts_with"
        value: "NETHERITE"

  - showIndicator: ["{entity}", "{entity}", "{damage}", "SPECIAL"]

示例 3:数学计算与分支

id: "rpg-damage"
event: "com.example.CombatEvent"

variables:
  attack: "attacker.attack"
  defense: "target.defense"
  level: "attacker.level"
  weaponType: "weapon.type"

flow:
  - math: "clamp({attack} * (1 + {level} * 0.05) - {defense} * 0.3, 1, 99999)"
    store: "finalDmg"

  - switch: weaponType
    cases:
      SWORD:
        - math: "{finalDmg} * 1.2"
          store: "finalDmg"
      BOW:
        - math: "{finalDmg} * 0.9"
          store: "finalDmg"

  - action: "applyDamage"
    args: ["{finalDmg}"]

示例 4:集合筛选

id: "inventory-check"
event: "com.example.TradeEvent"

variables:
  items: "player.inventory"

flow:
  # 必须存在稀有物品
  - collect: items
    op: exists
    match:
      - op: "contains"
        value: "rare"
    on_fail:
      - action: "sendMessage"
        args: ["背包中没有稀有物品"]
      - return

  # 统计匹配数量
  - collect: items
    op: count
    store: "rareCount"
    match:
      - op: "contains"
        value: "rare"

  - action: "log"
    args: ["找到 {rareCount} 个稀有物品"]

Clone this wiki locally