简体中文
原生脚本系统
原生脚本系统的用法: 全局有哪些设置, 技能里的 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.enabled | boolean | 否 | true | true / false | 是否启用原生技能脚本. 关掉后所有技能的 script 块都会被忽略, 只保留 MythicMobs 释放流程 |
script_engine.default_mode | string | 否 | "native" | native / mythic / hybrid | 技能没声明 script.mode 时用的默认模式; 留空回退 native |
script_engine.stop_on_failure | boolean | 否 | true | true / false | 某个动作失败后, 是否停下当前阶段剩下的动作; 技能里可以用 script.stop_on_failure 覆盖它 |
script_engine.max_lines_per_phase | integer | 否 | 64 | ≥ 1, 小于 1 按 1 | 单个阶段最多允许多少行动作 |
script_engine.max_targets_per_action | integer | 否 | 16 | ≥ 1, 小于 1 按 1 | 单个动作最多处理多少个目标 |
script_engine.debug | boolean | 否 | false | true / 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.enabled | boolean | 否 | actions 中存在任意阶段时为 true, 否则 false | true / false | 显式关掉后, 这个技能的脚本不再编译执行 |
script.mode | string | 否 | script_engine.default_mode | native, mythic (别名 mythicmobs), hybrid (别名 both) | 执行方式. 认不出的取值回退 native |
script.stop_on_failure | boolean | 否 | script_engine.stop_on_failure | true / false | 某个动作失败后, 是否停下当前阶段剩下的动作 |
script.actions.<阶段> | list<\string> | 否 | [] | 动作管道行 | 这个阶段要执行的动作行 |
script.conditions.<阶段> | list<\string> | 否 | [] | 条件表达式 | 这个阶段的前置条件; 全部通过才执行该阶段的动作, 不通过时返回 skill.script_phase_condition_failed, 并按跳过处理 |
脚本模式
| 模式 | 别名 | 说明 |
|---|---|---|
native | — | 只用内置脚本动作 |
mythic | mythicmobs | 只用 MythicMobs 技能 (通过 mythic_skill 字段) |
hybrid | both | 同时执行 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 必须与注册名逐字一致, 写错的行在编译期就被丢弃并计入诊断, 不会在运行期报错. 下面是几种常见误写:
| 误写 | 正确写法 |
|---|---|
message | send_message |
sound | play_sound |
particle | spawn_particle |
mythic | cast_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_compute | context (当前目标是玩家时另绑 player) | 纯计算, 不需要目标. context 可以读 var.* 变量 |
js_entity | player, context | 操作已有的玩家目标; 非玩家目标会被不报错地跳过 |
js_location | location, context (关联玩家时另绑只读 player) | 读取位置目标 |
每个段都必须提供 code; timeout 单位是毫秒, 默认 5000, 填 <= 0 也回退到 5000