技能与 BUFF
技能与 BUFF
技能定义放在 plugins/SnowyGems/skills/ 下,文件名任意。技能不是绑在宝石上的,而是绑在装备的 lore 文本上:装备 lore 里出现某段文字,就获得对应技能。
一个最小可用的技能:
向前闪现: # 技能 ID
Lore: "右键即可闪现" # 装备 lore 含这段文字就绑定此技能
Cooldown: 10.0 # 冷却 10 秒
Skills:
- Blink{distance=32} ~onUse @Forward
玩家拿着一件 lore 里有「右键即可闪现」的装备,右键就会向前闪现 32 格。
技能定义的字段
| 字段 | 说明 |
|---|---|
Lore | 绑定标记。装备 lore 含这段文字即生效(去色比较,可含颜色码) |
Cooldown | 冷却秒数,不写或 0 表示无冷却 |
CooldownTip | 冷却中的提示,本身也是一个函数表达式 |
Skills | 技能行列表 |
Lore 留空的技能定义不会被任何装备触发——它只能作为形态切换的目标(见下文 Switch),或者被 Reward{...} 嵌套调用。冷却是按技能定义计算的,不是按技能行。同一个定义里多行技能共享一个冷却。
技能行结构
函数名{参数1=值;参数2=值} ~触发标记 @作用目标
三部分:
| 部分 | 必填 | 说明 |
|---|---|---|
函数名{参数} | 是 | 做什么。参数用 ; 分隔 |
~触发标记 | 是 | 什么时候触发。不写则永远不会触发 |
@作用目标 | 否 | 作用于谁,默认 @Self |
作用目标:
| 写法 | 含义 |
|---|---|
@Self | 作用于自己(默认) |
@Entity | 作用于被攻击/被命中的实体 |
@Location | 作用于命中坐标(闪现、粒子、闪电常用) |
触发标记
| 标记 | 触发时机 |
|---|---|
~onUse | 右键使用 |
~onShiftUse | 潜行 + 右键 |
~onSwing | 左键挥臂 |
~onShiftSwing | 潜行 + 左键(三叉戟/矛也可用) |
~onAttack | 近战攻击命中实体 |
~onKill | 击杀实体 |
~onHit | 发射物命中(任意类型) |
~onHit:类型 | 发射物命中指定类型 |
~onLaunch | 发射物射出(任意类型) |
~onLaunch:类型 | 发射物射出指定类型 |
~onBreak | 挖掉方块 |
~onDamaged | 物品即将损失耐久 |
~onTimer | 每秒轮询(常驻 BUFF 用) |
~onHit:类型 的类型直接取实体类型名,不是固定清单:ARROW、TRIDENT、SPEAR、EGG、SNOWBALL、FIREBALL… 服务端有什么实体就能写什么。所以 1.21.11 的矛投出去后写 ~onHit:SPEAR 直接可用。
游戏内用 /sgem triggers 查看清单(内容来自 lang.yml,可自行增删措辞)。
函数清单
游戏内用 /sgem skills [关键字] 查看,会标出每个函数在当前版本是否可用。
位移
| 函数 | 别名 | 用法 |
|---|---|---|
Blink | Teleport 闪现 | {distance=10} 沿视线瞬移;配合 @Location 传送到命中处 |
Velocity | Push 击退 冲刺 | {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 则只有视觉效果 |
反馈
| 函数 | 别名 | 用法 |
|---|---|---|
Chat | Message 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} |
音效名和粒子名随版本增删,写错或版本不支持会跳过并在日志说明,不会报错崩溃。
药水效果
| 函数 | 别名 | 用法 |
|---|---|---|
Potion | PotionBuff Buff 药水 | {type=SPEED;level=2;duration=10},duration 单位为秒 |
Debuff | 负面 | {type=move;duration=5} 或 {type=BLINDNESS;level=1;duration=5} |
ClearPotion | RemovePotion 清除效果 | {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 限制 |
控制流
这一层是「技能引擎足够聪明」的关键:有了条件和组合,你可以自己拼出复杂逻辑,不需要等插件加新函数。
| 函数 | 别名 | 用法 |
|---|---|---|
All | Group 组合 | {Damage{amount=5};Fire{ticks=60}} 依次执行多个 |
Chance | Random 概率 | {p=0.3;Damage{amount=10}},p 为 0~1 |
If | Condition 条件 | {c=health<0.3;Heal{amount=10}} |
Delay | 延迟 | {t=20;Damage{amount=5}} 延迟 20 tick |
Repeat | 循环 | {times=3;interval=6;Damage{amount=2}} |
Reward | Do 执行 | {Chat{m=&a触发!}} 包一层(兼容老配置) |
Command | Cmd 命令 | {c=give %player% diamond 1;as=console} |
嵌套里可以再套控制流,例如 If{c=health<0.3;All{Heal{amount=20};Potion{type=RESISTANCE;level=3}}}。
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 上限是 100,防止手滑写 times=99999 卡死主线程。
CooldownTip:冷却提示
CooldownTip 本身也是一个函数表达式,支持三种:
CooldownTip: ActionBar{p=&c冷却时间;s=&a%.2fs;empty=&f|;full=&a|;length=75}
CooldownTip: Chat{m=&c技能还在冷却中}
CooldownTip: Title{m=&c冷却中}
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% 以下时,回血 + 抗性 + 音效
- If{c=health<0.3;All{Heal{amount=20};Potion{type=RESISTANCE;level=3;duration=6};Sound{name=ITEM_TOTEM_USE}}} ~onDamaged
- If{c=health<0.3;Title{m=&c&l守护发动;s=&7生命已恢复}} ~onDamaged
概率技能:攻击时随机触发
雷霆之刃:
Lore: "&b雷霆之刃"
Skills:
- Chance{p=0.2;Lightning{damage=true}} ~onAttack @Entity
- Chance{p=0.3;Fire{ticks=80}} ~onAttack @Entity
- Chance{p=0.2;ActionBar{m=&e&l雷霆!}} ~onAttack
连招:延迟与重复
三段斩:
Lore: "&6三段斩"
Cooldown: 8.0
Skills:
- Repeat{times=3;interval=6;All{Damage{amount=4};Particle{name=SWEEP_ATTACK;count=8}}} ~onAttack @Entity
- Sound{name=ENTITY_PLAYER_ATTACK_SWEEP} ~onAttack
发射物技能:飞雷神
飞雷神三叉戟:
Lore: "飞雷神三叉戟"
Cooldown: 15.0
Skills:
- Blink{distance=120} ~onHit:TRIDENT @Location
- Reward{Title{m=&e飞雷神之术}} ~onHit:TRIDENT
矛技能(1.21.11+)
穿云长矛:
Lore: "&f穿云长矛"
Cooldown: 6.0
Skills:
# 投出瞬间
- Sound{name=ITEM_TRIDENT_THROW} ~onLaunch:SPEAR
- ActionBar{m=&f长矛已投出} ~onLaunch:SPEAR
# 命中处
- Particle{name=EXPLOSION;count=1} ~onHit:SPEAR @Location
- Damage{amount=6} ~onHit:SPEAR @Entity
- Blink{distance=120} ~onHit:SPEAR @Location
从 lore 读数值:$LORE:$
技能参数可以从装备 lore 里动态读数值:
$LORE:标签?默认值$
向前闪现:
Lore: "右键即可闪现"
Skills:
- Blink{distance=$LORE:闪现距离?32$} ~onUse @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:
- Potion{type=GLOWING} ~onTimer
因为是每秒重新施加,效果时长只要 ≥2 秒就不会闪断(插件内部会把时长夹到至少 40 tick)。
可叠加等级的 BUFF
配合宝石的 LoreVar 写数字,这里用 $LORE:$ 读回来:
抗性提升:
Lore: "&6&l[&c&lBUFF&6&l] &b&l抗性提升 "
Skills:
- Potion{type=DAMAGE_RESISTANCE;level=$LORE:[BUFF] 抗性提升?1$} ~onTimer
$LORE: 引用的标记必须和自己的 Lore 一致(去色后比较),否则等级永远读默认值 1——不报错,只是等级不涨。智能 BUFF
~onTimer 上同样能用控制流,于是可以写「满足条件才生效」的 BUFF:
濒死爆发:
Lore: "&6&l[&c&lBUFF&6&l] &c&l濒死爆发"
Skills:
- If{c=health<0.3;All{Potion{type=resistance;level=2};Potion{type=regeneration;level=2}}} ~onTimer
矿工直觉:
Lore: "&6&l[&c&lBUFF&6&l] &e&l矿工直觉"
Skills:
# y<0 = 深板岩层/深暗之域
- If{c=y<0;All{Potion{type=night_vision;duration=15};Potion{type=haste;level=2}}} ~onTimer
不稳定祝福:
Lore: "&6&l[&c&lBUFF&6&l] &d&l不稳定祝福"
Skills:
- Chance{p=0.1;Potion{type=speed;level=2;duration=5}} ~onTimer
- Chance{p=0.1;Potion{type=strength;duration=5}} ~onTimer
- Chance{p=0.02;Potion{type=wind_charged;duration=5}} ~onTimer
in_water 这类环境变量。想判断「在水下」只能用 y<你服的海平面高度 近似。BUFF 与宝石配对
BUFF 定义只是「准备好一个标记」。要让玩家能获得它,二选一:
- 在
gems/里写一颗宝石,Rewards用LoreAdd{lore=这里的 Lore 文本} - 直接把这行 lore 加到装备上(用其他插件或命令)
skills/ModernBuffs.yml 里有 7 个已标注为「模板」的定义就属于第一种情况——标记准备好了但没配套宝石,需要你自己加。
性能提醒
BUFF 引擎每秒对每个在线玩家扫 6 个物品槽 × 所有带 Lore 的技能定义。定义数量大(几百个)且在线人数多(上百)时会有可观开销。建议:
- 不需要的 BUFF 定义直接删掉,别留着
- 常驻 BUFF 用
~onTimer,一次性效果用~onUse等事件触发标记 Repeat+ 短interval会在短时间内塞入大量调度任务,谨慎用于高频触发的技能
验证
改完技能配置后 /sgem reload,然后:
/sgem skills确认函数名没写错/sgem triggers确认触发标记没写错/sgem compat all查看配置自检结果
配置自检会明确报出「不是已注册的技能函数」(含拼写建议)和「这一行没有写触发标记,永远不会被触发」这两类最常见的笔误。