Skip to content

原生脚本系统 ​

原生脚本系统的用法: 全局有哪些设置, 技能里的 script 块怎么写, 分成哪几个阶段, 能写哪些动作, 目标和条件又怎么写

除了交给 MythicMobs 执行技能效果, EmakiSkills 自己还带了一套原生脚本系统. 好处是不需要任何外部插件, 你直接在技能配置里就能定义效果逻辑

全局脚本引擎配置 ​

全局设置写在 config.yml 的 script_engine 节点:

yaml
script_engine:
  enabled: true
  # 未指定时使用的模式
  default_mode: "native"
  # 动作失败后是否停止当前阶段
  stop_on_failure: true
  # 单阶段最大行数; 小于 1 按 1 处理
  max_lines_per_phase: 64
  # 单动作最大目标数; 小于 1 按 1 处理
  max_targets_per_action: 16
  debug: false
字段类型必填默认值取值范围说明
script_engine.enabledboolean否truetrue / false是否启用原生技能脚本. 关掉后所有技能的 script 块都会被忽略, 只保留 MythicMobs 释放流程
script_engine.default_modestring否"native"native / mythic / hybrid技能没声明 script.mode 时用的默认模式; 留空回退 native
script_engine.stop_on_failureboolean否truetrue / false某个动作失败后, 是否停下当前阶段剩下的动作; 技能里可以用 script.stop_on_failure 覆盖它
script_engine.max_lines_per_phaseinteger否64≥ 1, 小于 1 按 1单个阶段最多允许多少行动作
script_engine.max_targets_per_actioninteger否16≥ 1, 小于 1 按 1单个动作最多处理多少个目标
script_engine.debugboolean否falsetrue / false是否输出脚本调试信息

这些限制是防炸服的: 避免一个技能一次释放处理太多动作或目标. 你做大范围技能时, 最好控制住目标数量, 把视觉效果, 伤害和消息分开测试

技能内的 script 块 ​

yaml
script:
  enabled: true
  mode: native
  stop_on_failure: true
  actions:
    cast:
      - 'self | play_sound sound=ENTITY_BLAZE_SHOOT volume=1 pitch=1.5'
    hit:
      - 'trigger | ignite duration=3s'
  conditions:
    hit:
      - "%level% >= 3"
字段类型必填默认值取值范围说明
script.enabledboolean否actions 中存在任意阶段时为 true, 否则 falsetrue / false显式关掉后, 这个技能的脚本不再编译执行
script.modestring否script_engine.default_modenative, mythic (别名 mythicmobs), hybrid (别名 both)执行方式. 认不出的取值回退 native
script.stop_on_failureboolean否script_engine.stop_on_failuretrue / false某个动作失败后, 是否停下当前阶段剩下的动作
script.actions.<阶段>list<\string>否[]动作管道行这个阶段要执行的动作行
script.conditions.<阶段>list<\string>否[]条件表达式这个阶段的前置条件; 全部通过才执行该阶段的动作, 不通过时返回 skill.script_phase_condition_failed, 并按跳过处理

脚本模式 ​

模式别名说明
native—只用内置脚本动作
mythicmythicmobs只用 MythicMobs 技能 (通过 mythic_skill 字段)
hybridboth同时执行 native 脚本和 mythic 技能; native 阶段失败时, mythic 那部分就不再执行

如果你没配 script 块, 或脚本没启用, 技能就直接走 MythicMobs 那条路; 这种情况下如果没有 mythic_skill, 释放会以 skill.mythic_not_configured 失败

脚本阶段 ​

每个阶段都能单独配 conditions 和 actions 两个列表:

阶段触发时机
cast技能释放时
hit命中目标时
miss没命中时
fail释放失败时 (条件不满足, 资源不足等)

注意: 阶段键名只认上表这几种写法, 不支持 on_cast 这类带前缀的形式. 走 hit 还是 miss, 取决于前一阶段传下来的目标流是不是空的

配置结构 ​

yaml
id: flame_strike
trigger_type: active
display_name: '<red>烈焰斩'
script:
  mode: native
  stop_on_failure: true
  actions:
    cast:
      - 'self | play_sound sound=ENTITY_BLAZE_SHOOT volume=1 pitch=1.5'
      - 'trigger | spawn_particle particle=FLAME count=20'
      - 'trigger | damage amount=%var.fire_damage%'
    hit:
      - 'trigger | ignite duration=3s'
      - 'self | send_message text="<red>烈焰灼烧!"'
    fail:
      - 'self | send_message text="<gray>技能释放失败。"'

脚本上下文变量 ​

脚本执行时会自动注入下面这些变量, 你在动作行, 阶段条件和文本里都用 %var.<名称>% 引用:

变量说明
%var.level%当前技能等级
%var.skill_id%技能 ID
%var.trigger_id%触发器 ID
%var.has_target%有没有目标 (0 或 1)
%var.<技能变量名>%技能 variables 里定义的变量, 见 变量类型

另外还同时注入 5 个供 MythicMobs 读取的同义变量, 在脚本中同样表现为 %var.emaki_skill_id% 等形式: emaki_skill_id, emaki_skill_level, emaki_trigger_id, emaki_is_passive, emaki_has_target

variables 块里的表达式还能额外读到这些上下文量 (它们只参与变量计算, 不会当成脚本行占位符注入): %max_level%, %target_level%, %is_passive%, %player_level%, %player_health%, %player_max_health%, %sneaking%

脚本动作 ​

你写的每一行技能脚本都由 CoreLib 的动作引擎编译执行, 所以能用的动作段就是 CoreLib 注册表里的那些, 再加上 EmakiSkills 自己注册的技能段. EmakiSkills 没有另搞一套私有的动作 ID

  • CoreLib 自带通用段的完整清单与参数见 CoreLib 动作系统
  • EmakiSkills 追加的 cast_skill, cast_mythic_skill, 等级/槽位/冷却/解锁段见 CoreLib 动作

动作 ID 要用注册表里的写法

段 ID 必须与注册名逐字一致, 写错的行在编译期就被丢弃并计入诊断, 不会在运行期报错. 下面是几种常见误写:

误写正确写法
messagesend_message
soundplay_sound
particlespawn_particle
mythiccast_mythic_skill

另外记住: ray 与 aoe_damage 不是已注册的段, 没有对应写法

目标不写在动作参数里, 而是用管道的 来源 | 段 语法指定, 见 CoreLib 动作系统

下面只列技能脚本里最常用的几个段, 能填的参数以注册表为准

damage ​

对目标造成伤害

参数必填默认值说明
amount是—扣除的生命值

heal ​

治疗目标

参数必填默认值说明
amount是—恢复的生命值

ignite ​

点燃目标

参数必填默认值说明
duration否5s燃烧持续时间, 支持 ms, s, t 后缀

send_message ​

发送聊天消息 (支持 MiniMessage)

参数必填默认值说明
text是—消息文本

play_sound ​

播放音效

参数必填默认值说明
sound是—Bukkit Sound 名称
volume否—音量
pitch否—音调

spawn_particle ​

生成粒子

参数必填默认值说明
particle是—粒子类型
count否—粒子数量
offset_x / offset_y / offset_z否—各轴扩散偏移
extra否—粒子额外参数 (多数粒子为速度)

projectile ​

发射自定义投射物, 每 tick 模拟一次飞行. 命中时会设置上下文里的目标实体

参数必填默认值说明
speed否1.5每 tick 飞行格数
gravity否0.05每 tick 重力加速度
lifetime否60最大存活 tick 数
hit_radius否0.5命中检测半径
pierce否0穿透实体数量
homing否false是否追踪目标
homing_strength否0.1追踪转向强度
particle否FLAME尾迹粒子类型
damage否0命中伤害 (0 表示不造成伤害)
direction否look初始方向: look (视线方向), target (朝向目标)

目标解析规则 ​

目标写在竖线左边的来源段里, 不是写在动作参数里. 技能脚本里常用的来源有下面这些:

来源解析为
self施法者自己. 省略来源时的默认值
trigger触发上下文指定的实体 (主动技能是准星目标, 被动技能是事件对象)
inherited / keep跨阶段传递的目标流; keep 记录当前目标, inherited 读取上游记录的目标
looking_at施法者准星前方的实体, 可以加 range=, width=
nearby / nearby_players周围的实体或玩家, 可以加 radius=, limit=, type=
player_by_name按名字指定玩家

完整来源清单与参数见 CoreLib 动作系统

条件, 概率与延迟 ​

条件, 概率和延迟都是管道里的 gate 段 (负责筛选或控制的段). 它们串在竖线之间, 不是写在行首的 @ 前缀:

yaml
actions:
  cast:
    - 'trigger | where %var.has_target%==1 | damage amount=20'
    - 'trigger | chance 30% | ignite duration=5s'
    - 'self | after 20t | send_message text="<gray>1 秒后触发。"'
gate说明
where <条件>条件不成立时清空目标流, 后面的段就不执行了
if <条件> [ ... ]条件成立时执行方括号里的管道
chance <n>%按概率放行
after <时间>延迟指定时间后再执行后面的段. 支持 ms, s, t 后缀

@ 前缀写法已废弃

旧版的 @if=, @chance=, @delay= 行首前缀已经不再被解析, 换成下面的写法即可: 对应关系是 @chance=25% → chance 25%, @delay=20t → after 20t, @if=<条件> → if <条件> [ ... ] 分支或 where <条件>. @ignore_failure 没有对应写法. 完整语法见 CoreLib 动作系统 - 从旧语法迁移

内置 JavaScript 段 ​

原生脚本还提供三个 GraalVM JavaScript 段, 让你在管道里做轻量计算, 或者读取实体和位置状态. 注意它们的返回值只会进动作结果的 script_result, 不会写回变量, 不会生成占位符, 也不会筛选或替换目标; 如果你要让算出来的数值参与后续计算, 请改用 variables 里的 expression

段绑定说明
js_computecontext (当前目标是玩家时另绑 player)纯计算, 不需要目标. context 可以读 var.* 变量
js_entityplayer, context操作已有的玩家目标; 非玩家目标会被不报错地跳过
js_locationlocation, context (关联玩家时另绑只读 player)读取位置目标

每个段都必须提供 code; timeout 单位是毫秒, 默认 5000, 填 <= 0 也回退到 5000