SnowyGems

技能与 BUFF

技能行语法、内置函数、触发标记、条件与概率、形态切换、常驻 BUFF 的完整配置参考。

技能与 BUFF

技能定义放在 plugins/SnowyGems/skills/ 下,文件名任意。技能不是绑在宝石上的,而是绑在装备的 lore 文本上:装备 lore 里出现某段文字,就获得对应技能。

一个最小可用的技能:

向前闪现:                        # 技能 ID
  Lore: "右键即可闪现"            # 装备 lore 含这段文字就绑定此技能
  Cooldown: 10.0                 # 冷却 10 秒
  Skills:
    - action: Blink
      distance: 32
      trigger: onUse
      target: Forward

玩家主手持有 Lore 含「右键即可闪现」的装备时,右键尝试向前闪现,遇到阻挡会缩短距离。


技能定义的字段

字段说明
Lore绑定标记。装备 lore 含这段文字即生效(去色比较,可含颜色码)
Cooldown非负有限秒数,不写或 0 表示无冷却;成功施放后开始
Slot来源槽位列表:mainhand / offhand / head / chest / legs / feet;空列表不额外限制
CooldownTip冷却中的提示,本身也是一个函数表达式
Skills技能行列表
Lore 留空的技能定义不会被任何装备触发——它只能作为形态切换的目标(见下文 Switch),或者被 Reward{...} 嵌套调用。

冷却按玩家 + 技能 ID计算,同一定义的主动与定时技能共享。至少一条效果成功才进入冷却;所有条件不满足、全部无效时不扣冷却。成功安排 Delay/Repeat 任务也算施放成功,不等待延迟效果完成。

Slot 限制技能来源:主动交互目前以主手为入口;定时 BUFF 支持六个装备 / 手持槽位;耐久事件按损耗物品所在槽位检查。这里的 mainhand/offhand 与 Attribute 奖励的 hand/off_hand 是两套参数,不能混写。

定时引擎按主手、副手、头、胸、腿、脚顺序检查。同一技能 ID 每名玩家每轮至多成功施放一次,不会自动选择最高等级的装备。仅带 Lore 且具有 onTimer 行的定义参与定时扫描。

潜行左键同一服务器 tick 去重。发射物通用与专用触发合并为一次施放,一行同时匹配两种标记也只执行一次。发射物原物品快照缺失时不借用玩家当前主手;切换装备不能给旧发射物补上另一件装备的技能。

技能隐藏粉尘不会停用技能;匹配标记与 $LORE: 等级读取同时读取可见和隐藏内容。


技能动作结构

推荐把动作写成 YAML 对象:

Skills:
  - action: PotionBuff
    type: SLOW_FALLING
    trigger: onTimer

action 指函数;其他函数参数直接列在下方。trigger 必填,多个触发器用逗号隔开;target 可省略,默认 Self。完整迁移与编辑器说明见新语法、迁移与游戏内编辑器。旧的技能行继续兼容:

函数名{参数1=值;参数2=值} ~触发标记 @作用目标

旧文本行分三部分:

部分必填说明
函数名{参数}是做什么。参数用 ; 分隔
~触发标记是什么时候触发。不写则永远不会触发
@作用目标否作用于谁,默认 @Self

作用目标:

写法含义
@Self作用于自己(默认)
@Entity作用于本次攻击/命中事件中的生物;没有目标时跳过,不会回退到自己
@Location作用于命中坐标(闪现、粒子、闪电常用)

0.0.9 起,控制流子动作没有填写 target 时会继承外层目标。例如 Repeat 使用 target: Entity,其 then 下的 All、Damage、Particle 也作用于被攻击的生物;子动作明确写 target: Self 可改回玩家。onAttack 使用伤害事件实际命中的生物,不会另取准心附近的实体。


触发标记

标记触发时机
~onUse右键使用
~onShiftUse潜行 + 右键
~onSwing左键挥臂
~onShiftSwing潜行 + 左键(三叉戟/矛也可用)
~onAttack近战攻击命中实体
~onKill击杀实体
~onHit发射物命中(任意类型)
~onHit:类型发射物命中指定类型
~onLaunch发射物射出(任意类型)
~onLaunch:类型发射物射出指定类型
~onBreak挖掉方块
~onDamaged物品即将损失耐久
~onTimer每秒轮询(常驻 BUFF 用)

~onHit:类型 的类型直接取实体类型名,不是固定清单:ARROW、TRIDENT、EGG、SNOWBALL、FIREBALL… 服务端有什么发射物实体就能写什么。1.21.11 的矛是近战武器,不会触发 onLaunch 或 onHit:SPEAR;矛应使用 onUse、onShiftUse、onSwing 或 onAttack。

游戏内用 /sgem triggers 查看清单(内容来自 lang/<语言代码>.yml,可自行增删措辞)。


函数清单

游戏内用 /sgem skills [关键字] 查看,会标出每个函数在当前版本是否可用。

位移

函数别名用法
BlinkTeleport 闪现{distance=10} 沿视线瞬移;配合 @Location 传送到命中处
VelocityPush 击退 冲刺{forward=1.5;up=0.5} 或 {x=0;y=1;z=0}

Blink 沿视线逐格检查非空气方块并缩短距离;不是完整的双格安全传送检测。使用命中坐标传送时也应在目标场景测试。

战斗

函数别名用法
Damage伤害{amount=5}
Heal治疗 恢复{amount=5}
Fire点燃 燃烧{ticks=100}(20 tick = 1 秒)
Lightning闪电 雷击{damage=true},false 则只有视觉效果

反馈

函数别名用法
ChatMessage Msg 消息{m=&a技能发动!}
ActionBar动作栏{m=&b蓄力完成}
Title标题{m=主标题;s=副标题;fadeIn=10;stay=40;fadeOut=10}
Sound音效{name=ENTITY_PLAYER_LEVELUP;volume=1;pitch=1}
Particle粒子{name=FLAME;count=20;ox=0.5;oy=0.5;oz=0.5;speed=0}

音效名和粒子名随版本增删,写错或版本不支持会跳过并在日志说明,不会报错崩溃。

药水效果

函数别名用法
PotionPotionBuff Buff 药水{type=SPEED;level=2;duration=10},duration 单位为秒
Debuff负面{type=move;duration=5} 或 {type=BLINDNESS;level=1;duration=5}
ClearPotionRemovePotion 清除效果{type=POISON},不带参数则清除全部

Debuff 有两个语义化的特殊值:type=move 是强力缓慢(定身),type=fly 是禁飞。其余一律按效果名解析,所以 Debuff{type=weaving} 这种新版本效果也能写。

level 是「第几级」(从 1 起),不是 amplifier。

物品操作

函数别名用法
Enchant附魔{name=sharpness;level=5} 或 {name=fortune;limit=3}
Switch形态切换 切换{s=精准;时运}
Repair修复 耐久{amount=100},amount=full 则完全修复

Enchant 的四种语义:

写法效果
level=5设为 5 级
level=0移除,并记住原等级(供 restore 用)
level=restore恢复之前记住的等级
不写 level当前等级 +1,受 limit 限制

控制流

这一层是「技能引擎足够聪明」的关键:有了条件和组合,你可以自己拼出复杂逻辑,不需要等插件加新函数。

函数别名用法
AllGroup 组合then 列表,依次执行多个子动作
ChanceRandom 概率p: 0.3 加 then,p 为 0~1
IfCondition 条件c: "health<0.3" 加 then
Delay延迟t: 20 加 then,延迟 20 tick
Repeat循环times: 3、interval: 6 加 then
RewardDo 执行then 子动作,兼容旧的奖励包装写法
CommandCmd 命令{c=give %player% diamond 1;as=console}

then 可写单个对象,也可写动作列表。动作列表会按 All 的顺序执行;需要显式组合时可在 then 中写 action: All。嵌套里还可以继续嵌套,最多 16 层。旧的 {...} 行仍可读取,/sgem migrate 会转换可验证等价的嵌套行。

Skills:
  - action: Chance
    p: 0.1
    then:
      action: Potion
      type: HASTE
      level: 2
      duration: 8
    trigger: onBreak

If 支持的条件变量:

变量含义
health自己的生命比例(0~1)
raw_health自己的生命绝对值
max_health自己的生命上限
food饱食度(0~20)
level经验等级
y所在高度
target_health目标的生命比例(0~1)
target_raw_health目标的生命绝对值

运算符:> >= < <= == !=

target_* 在这次触发没有目标实体时取不到值,条件直接判为不成立(不是报错)。

Command 的 as 参数:player(默认)、op(临时提权后还原)、console。命令里可用 %player% 和 %uuid% 占位符。

Command{as=op} 会临时给玩家 OP 权限执行命令。虽然执行完立即还原,但如果命令内容里含玩家可控的文本(比如从 lore 读来的值),存在被利用的风险。能用 as=console 就别用 as=op。

Repeat.times 限制在 1~100;Delay.t 和 Repeat.interval 各限制在 0~72000 tick。单次施放及其嵌套、延迟子任务共享执行预算:最多 256 次函数分派、16 层嵌套、128 个延迟任务。这些是代码中的固定上限,没有对应 config.yml 开关。在 Folia 上,延迟任务跟随玩家或目标实体所属区域;若执行时施法者和目标已分属不同区域,该次子动作会跳过,避免跨区域访问。

重载或停用后旧延迟任务失效;执行时玩家已离线 / 死亡或目标已无效,也会跳过。配置复杂连招时应在测试服验证,不要用高频 onTimer 无限安排延迟任务。


CooldownTip:冷却提示

CooldownTip 本身也是一个函数表达式,支持三种:

CooldownTip: ActionBar{p=&c冷却时间;s=&a%.2fs;empty=&f|;full=&a|;length=75}

ActionBar 模式的参数:

参数说明
p前缀文字
s后缀模板,%.2f 会被替换成剩余秒数
empty进度条未填充部分的字符
full已填充部分的字符
length进度条长度

完整示例

条件技能:濒死保命

濒死守护:
  Lore: "&c濒死守护"
  Cooldown: 30.0
  CooldownTip: ActionBar{p=&c守护冷却;s=&c%.2fs;empty=&8|;full=&c|;length=40}
  Skills:
    # 物品即将损失耐久时,若当前血量低于 30%,尝试回血 + 抗性 + 音效
    - action: "If"
      c: "health<0.3"
      then:
        action: "All"
        then:
          - action: "Heal"
            amount: "20"
          - action: "Potion"
            type: "RESISTANCE"
            level: "3"
            duration: "6"
          - action: "Sound"
            name: "ITEM_TOTEM_USE"
      trigger: "onDamaged"
    - action: "If"
      c: "health<0.3"
      then:
        action: "Title"
        m: "&c&l守护发动"
        s: "&7生命已恢复"
      trigger: "onDamaged"

概率技能:攻击时随机触发

雷霆之刃:
  Lore: "&b雷霆之刃"
  Skills:
    - action: "Chance"
      p: "0.2"
      then:
        action: "Lightning"
        damage: "true"
      trigger: "onAttack"
      target: "Entity"
    - action: "Chance"
      p: "0.3"
      then:
        action: "Fire"
        ticks: "80"
      trigger: "onAttack"
      target: "Entity"
    - action: "Chance"
      p: "0.2"
      then:
        action: "ActionBar"
        m: "&e&l雷霆!"
      trigger: "onAttack"

连招:延迟与重复

三段斩:
  Lore: "&6三段斩"
  Cooldown: 8.0
  Skills:
    - action: "Repeat"
      times: "3"
      interval: "6"
      then:
        action: "All"
        then:
          - action: "Damage"
            amount: "4"
          - action: "Particle"
            name: "SWEEP_ATTACK"
            count: "8"
      trigger: "onAttack"
      target: "Entity"
    - action: "Sound"
      name: "ENTITY_PLAYER_ATTACK_SWEEP"
      trigger: "onAttack"

发射物技能:飞雷神

飞雷神三叉戟:
  Lore: "飞雷神三叉戟"
  Cooldown: 15.0
  Skills:
    - action: "Blink"
      distance: "120"
      trigger: "onHit:TRIDENT"
      target: "Location"
    - action: "Reward"
      then:
        action: "Title"
        m: "&e飞雷神之术"
      trigger: "onHit:TRIDENT"

矛技能(1.21.11+)

穿云长矛:
  Lore: "&f穿云长矛"
  Cooldown: 6.0
  Skills:
    - action: "ActionBar"
      m: "&f长矛已准备"
      trigger: "onUse"
    - action: "ActionBar"
      m: "&e长矛蓄力中"
      trigger: "onShiftUse"
    - action: "Particle"
      name: "CRIT"
      count: "8"
      trigger: "onAttack"
      target: "Entity"
矛的七种材质(木/石/铜/铁/金/钻石/下界合金)都会匹配 Require: [SPEAR],不需要按材质分别写。矛的攻击技能使用 onAttack 等通用近战标记;onLaunch 与 onHit 仅用于真正的发射物。这些分类和 lunge 附魔由 Compat.Modules.Spear 管辖,在没有矛的版本上自动失效。

从 lore 读数值:$LORE:$

技能参数可以从装备 lore 里动态读数值:

$LORE:标签?默认值$
向前闪现:
  Lore: "右键即可闪现"
  Skills:
    - action: "Blink"
      distance: "$LORE:闪现距离?32$"
      trigger: "onUse"
      target: "Forward"

装备 lore 里写「闪现距离 64」就用 64,没写就用 32。标签要写去掉颜色码的形式——插件会先把 lore 去色再比较,所以颜色码穿插在中间也能匹配。

这套机制让「同一个技能定义,不同装备不同数值」成为可能,配合宝石的 LoreVar 就能做出可升级的技能。


形态切换:Switch

「精准 ↔ 时运」这类切换:两个形态各自是一个技能定义,用 RewardSwitch 声明进入该形态要做什么。

精准时运切换:
  Lore: "§2Shift+右键切换模式(精准/时运)"
  Cooldown: 4.0
  CooldownTip: ActionBar{p=&c切换冷却;s=&a%.2fs;empty=&f|;full=&c|;length=75}
  Skills:
    - Switch{s=精准;时运} ~onShiftUse

# 精准模式:收起时运,恢复精准
精准:
  Skills:
    - RewardSwitch{Enchant{name=fortune;level=0}}
    - RewardSwitch{Enchant{name=silk_touch;level=restore}}
    - RewardSwitch{ActionBar{m=&b&l切换为精准模式}}

# 时运模式:收起精准,恢复时运
时运:
  Skills:
    - RewardSwitch{Enchant{name=silk_touch;level=0}}
    - RewardSwitch{Enchant{name=fortune;level=restore}}
    - RewardSwitch{ActionBar{m=&a&l切换为时运模式}}

工作原理:level=0 移除附魔并记住原等级,level=restore 恢复记住的等级。切换状态存在物品的 PDC 里。

你新写任意一组切换都不需要改插件。 引擎会读取两个形态各自声明的「特征附魔」(level=restore 或 level>0 的那些),看物品上实际带着谁的附魔,据此反推当前形态。所以「忠诚 ↔ 激流」「经验修补 ↔ 无限」「火焰附加 ↔ 击退」都能照抄上面的结构直接用。

两个形态定义不需要写 Lore——它们不由装备直接触发,而是被 Switch 调用。

如果目标形态自己配了 Chat/ActionBar/Title,就以配置为准;没配的话插件会发一条来自 lang/<语言代码>.yml 的兜底提示,避免按下去毫无反应像是插件坏了。


常驻 BUFF

BUFF 引擎每秒扫描每个在线玩家的主手、副手、四件盔甲,命中 lore 标记就执行该定义里带 ~onTimer 的技能行。

发光:
  Lore: "&6&l[&c&lBUFF&6&l] &b&l发光"
  Skills:
    - action: "Potion"
      type: "GLOWING"
      trigger: "onTimer"

定时技能每秒扫描一次,药水效果时长至少为 40 tick。想让效果持续,应让持续时间覆盖成功施放之间的间隔;如果配置了较长的共享冷却,只有 2 秒的效果仍会中断。

可叠加等级的 BUFF

配合宝石的 LoreVar 写数字,这里用 $LORE:$ 读回来:

抗性提升:
  Lore: "&6&l[&c&lBUFF&6&l] &b&l抗性提升 "
  Skills:
    - action: "Potion"
      type: "DAMAGE_RESISTANCE"
      level: "$LORE:[BUFF] 抗性提升?1$"
      trigger: "onTimer"
$LORE: 引用的标记必须和自己的 Lore 一致(去色后比较),否则等级永远读默认值 1——不报错,只是等级不涨。

智能 BUFF

~onTimer 上同样能用控制流,于是可以写「满足条件才生效」的 BUFF:

濒死爆发:
  Lore: "&6&l[&c&lBUFF&6&l] &c&l濒死爆发"
  Skills:
    - action: "If"
      c: "health<0.3"
      then:
        action: "All"
        then:
          - action: "Potion"
            type: "resistance"
            level: "2"
          - action: "Potion"
            type: "regeneration"
            level: "2"
      trigger: "onTimer"
引擎没有 in_water 这类环境变量。想判断「在水下」只能用 y<你服的海平面高度 近似。

BUFF 与宝石配对

BUFF 定义只是「准备好一个标记」。要让玩家能获得它,二选一:

  1. 在 gems/ 里写一颗宝石,Rewards 用 LoreAdd{lore=这里的 Lore 文本}
  2. 直接把这行 lore 加到装备上(用其他插件或命令)

skills/ModernBuffs.yml 里有 7 个已标注为「模板」的定义就属于第一种情况——标记准备好了但没配套宝石,需要你自己加。


性能提醒

BUFF 引擎每秒对每个在线玩家扫 6 个物品槽 × 所有带 Lore 的技能定义。定义数量大(几百个)且在线人数多(上百)时会有可观开销。建议:

  • 不需要的 BUFF 定义直接删掉,别留着
  • 常驻 BUFF 用 ~onTimer,一次性效果用 ~onUse 等事件触发标记
  • Repeat + 短 interval 会在短时间内塞入大量调度任务,谨慎用于高频触发的技能

验证

改完技能配置后 /sgem reload,然后:

  • /sgem skills 确认函数名没写错
  • /sgem triggers 确认触发标记没写错
  • /sgem compat all 查看配置自检结果

配置自检会明确报出「不是已注册的技能函数」(含拼写建议)和「这一行没有写触发标记,永远不会被触发」这两类最常见的笔误。

Copyright © 2026