简体中文
动作系统
动作管道这样写: 在 YAML 里一行行描述"发生某件事后要执行哪些效果", 再查清一条管道能用到哪些段, 每个段有哪些参数
动作系统是 CoreLib 被其他模块用得最多的能力之一, 这些场景里都有它:
- 锻造成功后发送消息, 播放音效, 发放奖励
- 强化失败后显示 Title, 执行惩罚动作
- 技能释放时扣资源, 执行命令, 对准星上的目标造成伤害
- 烹饪完成后发放物品, 广播提示, 播放粒子
- GUI 按钮点击后打开界面, 执行命令或触发业务流程
一条管道就是一行文本
先记住: 不同模块里放动作的字段名可能不一样, 例如 actions.success, actions, deny_actions, result.success.actions; 但写法是同一套, 列表里的每一行都是一条独立的管道, 从上往下按顺序执行
一条管道由若干段 (stage) 用 | 串起来, 数据从左往右流动:
text
self | chance 25% | after 20t | send_message text="<green>触发成功</green>"这一行读作: 取自己作为目标, 25% 概率通过, 等 20 个游戏刻 (1 个游戏刻 = 1/20 秒), 然后发消息. 段与段之间传递的是目标流 (一份目标列表), 所以"选谁"和"对他做什么"被分成了不同的段. 这也是管道写法和早期单行动作最大的差别: 以前 killentity radius=5 limit=3 type=zombie 把"找哪些实体"和"杀掉"混在一个动作里, 现在前者是 nearby, 后者是 kill_entity
yaml
actions:
success:
- 'self | send_message text="<green>锻造成功!</green>"'
- 'self | play_sound sound=minecraft:entity.player.levelup volume=1 pitch=1'
- 'run_command_as_console command="say %player_name% 完成了一次锻造"'NOTE
段的参数在执行前会先解析占位符. CoreLib 自带 %player%, %player_name%, %player_uuid%, %player_world%, %player_x%, %player_y%, %player_z%, 并会解析调用模块写入上下文的其他占位符, 以及 PlaceholderAPI 提供的占位符. 管道自己写入的变量读作 %var.<名字>%. 各模块可用的业务变量请参阅对应模块文档
第三方执行与结构化结果
第三方插件可以调用 EmakiCoreLibApi.executeActionLineAsync(plugin, line, CoreActionExecutionContext) 编译并执行一整条管道. 这个方法在哪个线程都能调; 返回的 future 可能在调用线程上完成 (比如一上来校验就失败), 也可能在最后一个段所在的线程上完成, 所以在 continuation 里碰 Bukkit 之前, 必须先用 EmakiCoreLibApi.scheduling() 切到合适的线程. 编译失败和业务执行失败都会当成正常完成的结果返回, 不能只靠异常来判断
结果类型是 CoreActionExecutionResult, 里面有 status, reasonKey/reasonArguments, 编译期的 diagnostics, 按顺序排列的 stages 摘要和 keptTargets. status 的取值有 SUCCESS, SKIPPED, PARTIAL, COMPILE_FAILED, EXECUTION_FAILED, INVALID_REQUEST, UNAVAILABLE; 调用方可以据此分别处理"没有工作""部分完成""配置无法编译""运行失败"这几种情况
同一套接口还提供只读的注册表查询: actionStages() / actionStage(id) 和 actionTriggers() / actionTrigger(id). 注册自定义段时, CoreActionExecutionTarget.contextEntity() 表示实体上下文执行域; 规划上下文用 context.target() 或 context.caster(), 不要用不存在的 subject(). 返回的 CoreStageRegistration 用 registration.close() 注销
最小的第三方执行示例:
java
CoreActionExecutionContext context = CoreActionExecutionContext.builder()
.caster(player)
.build();
EmakiCoreLibApi.executeActionLineAsync(this,
"self | send_message text='<green>Hello</green>'", context)
.thenAccept(result -> getLogger().info(result.status().name()));语法
管道的完整语法如下:
text
line := node ('|' node)*
node := branch | weighted | stage
branch := 'if' condition '[' line ']' ('else' '[' line ']')?
weighted := 'weight' (weight '[' line ']') +
stage := name arg*
arg := key '=' value | bare_value要点:
- 一条管道永远是一行文本. 没有结构化 YAML 形式的管道, 也没有第二套解析器
- 段名与参数之间用空格分隔, 不是括号. 写
send_message text="...", 不要写send_message(text="...") - 参数有两种写法:
key=value, 或者裸值 (positional, 位置参数). 裸值按段声明的顺序对应到位置参数上, 所以chance 25%和chance chance=25%等价 - 段名会被转成小写,
Send_Message和send_message等价. 参数名同样转小写 - 空行与以
#开头的行会被忽略 - 单引号和双引号都能用来包裹参数值, 加了引号后支持
\n,\t,\\,\",\'转义. 引号内的|,[,]只是普通字符, 所以text="a | b"里的竖线不会被当成分段符 - 引号外的
|,[,]就算没有空格也会切分 token,a|b和a | b完全一样 ||是管道符的转义写法, 也是条件里的逻辑或; 它永远不会被当成分段符
三种角色
每个段都有固定的角色, 角色决定它能出现在管道的什么位置:
| 角色 | 作用 | 例子 |
|---|---|---|
| source | 负责产生目标流, 写在管道的第一段 | self, looking_at, nearby radius=5 |
| gate | 用来过滤和排序目标, 控制先后顺序, 或者往上下文里写入值 | chance 25%, where ..., after 20t |
| action | 真正产生效果, 作用在流里的每一个目标上 | send_message, damage, give_money |
角色是段自身的属性, 不是位置决定的, 所以 /emakicorelib action list 按角色分组列出, 而不是平铺成一张清单 -- 同一个 id 只在一种位置上合法
省略 source 时默认就是 self, 你可要留意这个默认值: 想作用在调用方传进来的目标上, 必须显式写 inherited, 否则会悄悄作用在施法者身上
分支
条件不是写在段前面的前缀, 而是管道里的一个节点:
text
if %player_world%=="world" [ self | send_message text="你在主世界" ] else [ self | send_message text="你不在主世界" ]else 分支可以省略. 分支体本身就是一条完整管道, 可以有自己的 source, 也可以有多个段. 条件支持 &&, ||, !, 括号, 以及 <, <=, ==, !=, >=, > 这些比较运算符. 字符串比较时建议给右侧加引号, 避免被当成数字表达式. 分支条件里的逻辑或必须写成 ||
分支体里也可以只放一个 gate 段 (负责筛选或控制的段), 例如用 stop 提前结束:
text
looking_at | if %var.dead% [ stop ] else [ damage amount=5 ]权重分支
if 按条件二选一, weight 按权重多选一: 每个权重后面紧跟自己的分支体, 运行时按权重占总和的比例抽中恰好一条执行
text
self | weight 70 [ send_message text="<gray>普通</gray>" ] 25 [ send_message text="<blue>稀有</blue>" ] 5 [ broadcast_message text="<gold>史诗!</gold>" ]这一行读作: 70/25/5 的相对概率抽一条, 抽中哪条就只执行那条的分支体. 权重不要求总和为 100, 写 7 2.5 0.5 概率完全一样 -- 权重看的是相对关系, 详见权重
权重紧贴各自的分支体, 不是单独一个列表. 这是刻意的: 如果权重集中写成 [70, 25, 5] 再按顺序对应后面的动作, 那么插入, 删除或调整分支顺序都会让权重错位, 而这种错位在加载期检查不出来, 只会表现为"概率好像不对"
要点:
- 分支体和
if的分支体一样, 本身就是一条完整管道, 可以有自己的 source 和多个段 weight恰好选中一条. 想表达"每条独立判定, 可能同时触发多条", 那是多行chance, 不是weight- 权重写
0表示禁用该分支, 它永远不会被抽中. 但所有分支都是0会在加载期报错, 因为那样这一段永远选不出任何分支 - 权重可以是算式或占位符, 例如
weight %var.luck% [ ... ] 30 [ ... ]. 占位符在执行前渲染, 因此概率可以随玩家状态变化 - 权重必须是非负数. 负权重在加载期就会被拒绝 (字面量) 或在运行期报错 (占位符渲染结果), 不会一声不响地忽略掉 -- 否则一个手滑的负号会让整条分支凭空消失
- 权重是无名值, 不写成
名称=值.weight chance=70 [ ... ]会报错 weight与if共用action.pipeline.max_branch_depth(默认 16) 这一个嵌套深度上限, 两者可以互相嵌套
weight 与 chance 解决的是不同的事: chance 25% 是一道开关, 没摇中就结束整条管道; weight 是多路选一, 总会选中一条 (除非全部权重为 0). 需要"25% 触发, 否则什么都不做"用 chance; 需要"必定发生, 但发生哪种按概率分配"用 weight
text
self | weight 1 [ nearby radius=5 | damage amount=8 ] 1 [ send_message text="<gray>这次没打中</gray>" ]
self | if %var.is_boss% [ weight 80 [ run drop_common ] 20 [ run drop_rare ] ] else [ run drop_trash ]命名序列与 run
一组经常重复使用的管道, 你可以定义成命名序列, 再用 run 调用:
yaml
action:
templates:
reward_common:
- 'self | send_message text="<green>领取奖励成功</green>"'
- 'self | play_sound sound=minecraft:entity.experience_orb.pickup volume=0.8 pitch=1.2'
level_up_effect:
- 'self | send_title title="<gold>等级提升!</gold>" subtitle="<gray>当前等级:%var.level%</gray>"'
- 'self | play_sound sound=minecraft:entity.player.levelup volume=1 pitch=1'
- 'self | spawn_particle particle=totem_of_undying count=30 offset_x=0.5 offset_y=1 offset_z=0.5'调用时把参数直接写在 run 后面, 序列体内读作 %var.<名字>%:
text
run reward_common
run level_up_effect level=10
run reward_with_amount amount=100 reason=每日签到序列定义可以放在 CoreLib 主配置的 action.templates, 也可以放在各业务模块自己的数据目录; run 只认名字, 不关心定义来自哪里. 序列名不区分大小写
序列在加载配置时就会被编译, 同时检查互相调用有没有成环. 所以互相调用成环, 调用了不存在的名字, 缺少必需参数, 都会在加载配置时报错, 不用等运行起来才发现
命名别名 (aliases)
经常重复使用的管道片段, 你可以起个别名, 在任何管道行里直接用别名代替:
yaml
action:
aliases:
buff_essentials: 'give_potion_effect effect=speed duration=30s amplifier=0 | give_potion_effect effect=jump_boost duration=30s amplifier=0'
punish_msg: 'send_message text="<red>操作被拒绝</red>"'text
self | buff_essentials | damage amount=1
damage amount=3 on_error [ punish_msg ]规则:
- 编译时先把别名展开成原来的内容再解析, 别名可以引用另一个别名 (最多 8 层, 成环报
alias_cycle诊断); if/else/run/weight/on_error/union/parse_if这些保留字永远不会被别名盖掉;- 别名与已注册段 id 同名时, 启动日志会警告并忽略该别名 (不会一声不响地把原来的段吞掉);
- 展开后报错时给出的列号会按别名的位置偏移, 但仍然指向你在管道行里实际写的位置
多源并集 (union)
一条管道默认只能写一个源段; union [ ... ] 把多个源段的结果去重合并成一条目标流:
text
union [ all_players | nearby type=zombie radius=16 ] | filter 'health_percent<=50' | damage amount=2union [ ]内只允许源段, 写动作段或开关段会报union_only_sources;- 某个源段没命中不会让整条管道失败, 全部落空时才以空流继续;
- 合并按
LinkedHashSet去重 (同一实体被两个源选中只出现一次); union能通过校验, 同时旧诊断multiple_sources仍会拦截"裸写两个源段"的写法 -- 看到它就改成union
编译期分支 (parse_if)
if 在运行期求值; parse_if 在编译期求值, 条件不成立时整段不进入编译产物 -- 在超长的嵌套里用来剪掉不可能走到的分支, 既省解析又省运行期的判断:
text
parse_if true [ send_message text="这段会被编译进去" ]
parse_if false [ send_message text="整段在加载期就被丢弃" ]- 条件必须是静态可求值的表达式; 含
%...%占位符报parse_if_placeholder(那是运行期的事, 改用if); - 编译期求不出布尔值报
parse_if_not_evaluable; - 条件为假时整段跳过解析, 后续节点列号不受影响
错误控制流 (on_error 与 retry)
on_error [ ... ] 让动作失败时转到处理器; retry= / retry_delay= 让段失败后隔一段时间重试:
text
damage amount=3 on_error [ send_message text="<red>伤害失败:%var.error%</red>" ]
take_item item=sword amount=1 retry=3 retry_delay=1s%var.error%展开为七类失败类型之一 (INVALID_CONFIG/MISSING_CONTEXT/WRONG_THREAD/TIMEOUT/OWNER_DISABLED/INTERNAL_ERROR/REJECTED),%var.error_reason%为细分原因键;- 处理器里不能再嵌套
on_error(编译期nested_on_error拦截, 需要更深的错误处理请拆成多条管道); retry次数受action.pipeline.max_retry_times限制,retry_delay支持1s/20t写法;on_error的()括号写法无效, 必须用[ ]
编译上限
下面这些上限在加载配置时检查. 超限会拒绝这一条配置并保留上一份有效配置, 而不是悄悄截断 -- 被截断的 times=100000 看起来像是生效了, 比直接报错更难排查. 出厂默认值:
yaml
action:
pipeline:
max_repeat_times: 100
max_sequence_depth: 8
max_branch_depth: 16
max_retry_times: 5| 字段 | 类型 | 必填 | 默认值 | 取值范围 | 说明 |
|---|---|---|---|---|---|
action.pipeline.max_repeat_times | integer | 否 | 100 | 正整数 (<=0 回退默认) | every <间隔> times <次数> 的次数上限, 超限拒绝该条配置 |
action.pipeline.max_sequence_depth | integer | 否 | 8 | 正整数 (<=0 回退默认) | run 的最大嵌套深度 |
action.pipeline.max_branch_depth | integer | 否 | 16 | 正整数 (<=0 回退默认) | if, weight 与 on_error 共用的最大嵌套深度 |
action.pipeline.max_retry_times | integer | 否 | 5 | 正整数 (<=0 回退默认) | 单段 retry= 的重试次数上限, 超限的编译诊断 retry_limit_exceeded |
配置示例: 把 every 的循环次数上限放宽到 500, 同时允许更深的 weight 嵌套
yaml
action:
pipeline:
max_repeat_times: 500
max_branch_depth: 24公共参数 (所有段通用)
下面三个参数不属于某个段的专属参数, 而是编译时在解析阶段统一从段参数里挑出来的通用控制项, 所以 source / gate / action 三类段一律能用, 你按需跟在段名后面写即可:
| 参数 | 类型 | 默认值 | 作用说明 |
|---|---|---|---|
on_error [ ... ] | 分支体 | 无 | 本段执行失败时转入该分支体 (一条完整管道); 分支体读 %var.error% (七类失败类型之一) 与 %var.error_reason% (细分原因键). 分支体内不得再嵌套 on_error (编译诊断 nested_on_error) |
retry= | INTEGER | 不重试 | 本段失败后的重试次数, 上限 action.pipeline.max_retry_times (默认 5), 超限诊断 retry_limit_exceeded; 只能写非负整数, 否则会按 -1 处理并触发诊断 |
retry_delay= | DURATION | 立即 | 每次重试前的等待时间, 支持 20t / 1s / 500ms 写法; 负值按 0 处理. 要和 retry= 一起用, 没写 retry= 时不起作用 |
使用规范:
- 通用控制项与专属参数写在一起, 都写在段名后面的参数区. 编译器会先把控制项挑出来, 再校验段自己的参数, 所以不会撞上
unknown_argument. 示例:damage amount=3 on_error [ send_message text="失败" ],take_item item=sword amount=1 retry=3 retry_delay=1s - 分隔写法: 控制项的分支体必须用
[ ]配对,on_error ( ... )的圆括号写法无效 - 参数名与段名都转小写:
Send_Message与send_message等价,AMOUNT=3与amount=3等价 - 两种写法:
key=value, 或裸值 (positional, 位置参数). 裸值按段声明的顺序对应到位置参数, 如chance 25%等价于chance chance=25% - 引号与转义: 值含空格, MiniMessage 标签,
|,[,]或:,#时必须用引号包裹; 单双引号均可, 引号内支持\n,\t,\\,\",\'转义, 且引号内的|不会切分管道 - 占位符延迟求值: 值里的
%var.*%/ PAPI 占位符在执行前渲染, 因此非占位符字面量在编译期按参数类型校验, 含占位符的值跳过类型校验, 留待运行期, 类型错配报invalid_argument_type - 未声明即拒绝: 段未在注册时声明的参数名一律报
unknown_argument(带候选建议); 必填参数缺失报missing_required_argument. 用<任意插件根命令> debug action check "<管道行>"可在加载前拿到全部诊断
各段自身的专属参数见动作系统下方各段详情页; 段 id 与跳转入口见段 ID 表. 参数类型的完整定义与示例见参数类型说明
循环任务限制
start_task 启动的长期循环由 action.loop.* 单独限制, 与上面的编译上限互不影响. 出厂默认值:
yaml
action:
loop:
enabled: true
min_sync_interval: 5t
min_async_interval: 100ms
max_times: 7200
max_active_loops_total: 5000
max_active_loops_per_player: 16
max_active_loops_per_plugin: 1000
cancel_player_loops_on_quit: true
cancel_plugin_loops_on_disable: true| 字段 | 类型 | 必填 | 默认值 | 取值范围 | 说明 |
|---|---|---|---|---|---|
action.loop.enabled | boolean | 否 | true | true / false | 是否允许启动循环任务 |
action.loop.min_sync_interval | duration | 否 | 5t | >=1t (预检) | 同步域循环的最小间隔 |
action.loop.min_async_interval | duration | 否 | 100ms | >=1t (预检) | 异步域循环的最小间隔 |
action.loop.max_times | integer | 否 | 7200 | >0 (预检) | 单个循环任务的最大执行次数 |
action.loop.max_active_loops_total | integer | 否 | 5000 | >0 (预检) | 全服同时活动的循环任务上限 |
action.loop.max_active_loops_per_player | integer | 否 | 16 | >0 (预检) | 单个玩家同时活动的循环任务上限 |
action.loop.max_active_loops_per_plugin | integer | 否 | 1000 | >0 (预检) | 单个插件同时活动的循环任务上限 |
action.loop.cancel_player_loops_on_quit | boolean | 否 | true | true / false | 玩家退出时取消其循环任务 |
action.loop.cancel_plugin_loops_on_disable | boolean | 否 | true | true / false | 插件禁用时取消其循环任务 |
min_sync_interval 与 min_async_interval 都是时间值 (t/s/ms), 预检要求它们至少为 1 个游戏刻, 非法值会让预检报错. 循环任务本身用 start_task/stop_task 段创建与取消, 见长时间任务
配置示例: 把单个插件的循环上限提到 2000, 并让玩家退出后循环继续运行
yaml
action:
loop:
max_active_loops_per_plugin: 2000
cancel_player_loops_on_quit: false参数类型说明
段参数有以下类型, 在后面的参数表里会标注. 这些类型在加载配置时就会校验, 你写错的值不会拖到运行时才暴露
| 类型 | 说明 | 示例 |
|---|---|---|
| STRING | 字符串. 含空格或特殊字符时需加引号 | text="<green>成功" |
| INTEGER | 整数 | amount=3, count=10 |
| DOUBLE | 浮点数 | volume=0.8, amount=25.5 |
| BOOLEAN | 布尔值. true/false | keep=false, icon=true |
| DURATION | 时间. 支持 t (游戏刻), s (秒), ms (毫秒), 纯数字按游戏刻算 | 20t, 1s, 500ms |
| PERCENTAGE | 概率. 支持百分比, 小数与分数 | 50%, 0.5, 1/3 |
| ENTITY_TYPE | Bukkit EntityType 名 | type=zombie |
| MATERIAL | Bukkit Material 名 | material=stone |
| SOUND | 声音键. Bukkit Sound 枚举名或 namespace:key | sound=minecraft:block.anvil.use |
| EXPRESSION | 由 CoreLib 表达式引擎求值的算式 | amount=%var.level%*4+18 |
从旧语法迁移
如果你手上还有旧配置, 对照下面三条规则改写就行:
- 段 id 加下划线分词.
sendmessage写作send_message,givemoney写作give_money,runcommandasconsole写作run_command_as_console, 以此类推 @控制前缀改为管道中的段.@chance=25%写作chance 25%,@delay=20t写作after 20t,@if=<条件>写作if <条件> [ ... ]分支.@ignore_failure没有对应写法: 管道的失败处理由段自己决定, 需要"失败不阻断"的地方改用分支, 或把该段拆到单独一行- 补上 source. 旧的动作行默认作用在事件里的玩家身上; 管道要显式写 source. 作用在施法者上写
self(省略时也是这个), 作用在调用方传入的目标上写inherited
几个 id 变化不止加下划线:
| 旧写法 | 现在 |
|---|---|
ray | source looking_at |
loopsync / loopasync | start_task (同步/异步不再是配置项, 见该段说明) |
cancelloop | stop_task |
@template=名称 / usetemplate | run 名称 |
killentity radius=... type=... | source nearby 负责搜索, kill_entity 只负责移除 |
createitem id=... senditem id=... | create_item 写入唯一的管道物品, send_item 读它, 不再需要 id |
castmythicskill | cast_mythic_skill, 由 EmakiSkills 提供 |
cast_skill 有一处会破坏旧配置的改动: 它的 skill 参数现在填的是 EmakiSkills 技能 id, 不再是 MythicMobs 技能 id. 旧配置里 cast_skill skill=<Mythic 技能> 必须改成 cast_mythic_skill skill=<Mythic 技能>, 否则会因找不到 EmakiSkills 技能而失败
内置 source
source 产生目标流, 写在管道最前面. 省略 source 等价于 self
self
施法者自己. 无参数
text
self | send_message text="<green>操作成功!</green>"inherited
调用方或上一个阶段交进来的目标流. 无参数
必须显式写出: 省略 source 会退化为 self, 所以一条本想作用在继承目标上的管道如果漏写 source, 就会悄悄作用在施法者身上
配合 keep 使用: 前一个阶段写 looking_at | keep 记下目标, 后一个阶段用 inherited 读回来
text
inherited | damage amount=8trigger
触发器点名的实体, 用在触发者与施法者不是同一个人的场合. 无参数
上下文里存的是名字或 UUID, 不是实体本身 -- 管道可能在运行前很久就编译好了, 把活着的实体放进上下文会妨碍回收
text
trigger | send_message text="<yellow>你触发了机关</yellow>"origin
管道的空间参考点, 作为一个位置目标. 无参数
text
origin | spawn_particle particle=flame count=20looking_at
施法者准星指向的实体
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
range | DOUBLE | 否 | 5 | 射线能伸多长 |
width | DOUBLE | 否 | 0.5 | 射线的粗细 |
text
looking_at range=12 | damage amount=6
looking_at | keep | send_message text="<red>你被锁定了</red>"nearby
管道参考点周围的实体
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
radius | DOUBLE | 否 | 1 | 以管道参考点为中心向四周搜索多远 |
limit | INTEGER | 否 | 1 | 最多返回几个实体 |
type | ENTITY_TYPE | 否 | "" | 按实体类型筛选, 留空表示不限类型 |
include_players | BOOLEAN | 否 | false | 是否把玩家也算进候选目标 |
结果按到参考点的距离排序后截断到 limit. 找不到任何实体是"空", 会跳过后续段; 写了一个不存在的实体类型是"无效", 会报错 -- 旧实现把打错的类型当成跳过, 服主根本看不到自己写错了
text
nearby radius=8 limit=5 type=zombie | damage amount=10
nearby radius=4 limit=20 include_players=true | give_potion_effect type=slowness level=1 duration=5snearby_players
管道参考点周围的玩家
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
radius | DOUBLE | 否 | 1 | 以管道参考点为中心向四周搜索多远 |
limit | INTEGER | 否 | 0 | 最多返回几个, 0 表示全部都算 |
和 nearby 共用同一套过滤逻辑, 只是候选只取玩家. limit 默认为 0 (全部) 而不是 1, 因为面向队伍或区域的效果要覆盖所有玩家, 而不是最近的那一个
text
nearby_players radius=10 | send_message text="<gold>队伍获得了增益</gold>"offset
相对管道参考点偏移出的一个位置
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
x | DOUBLE | 否 | 0 | 沿 X 轴偏移多少格 |
y | DOUBLE | 否 | 0 | 沿 Y 轴偏移多少格 |
z | DOUBLE | 否 | 0 | 沿 Z 轴偏移多少格 |
relative | BOOLEAN | 否 | false | 是否沿参考点自身朝向偏移 |
relative=false 时沿世界坐标轴偏移; relative=true 时沿参考点自身朝向, 此时 z 是前方, x 是右方
text
offset y=2 | spawn_particle particle=end_rod count=30
offset z=3 relative=true | explosion power=2 break_blocks=falseat
一个绝对坐标, 或相对参考点的坐标
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
world | STRING | 否 | "" | 世界名; 留空就用参考点所在的世界 |
x | STRING | 否 | ~ | X 坐标, 支持 ~ |
y | STRING | 否 | ~ | Y 坐标, 支持 ~ |
z | STRING | 否 | ~ | Z 坐标, 支持 ~ |
坐标是 STRING 而不是 DOUBLE, 这样 ~ 写法才能继续用: ~ 表示"参考点在这一轴上的值", ~5 表示"比它多 5", 与原版命令坐标语法一致
text
at world=world x=100 y=65 z=-30 | spawn_particle particle=end_rod count=50
at x=~ y=~-1 z=~ | set_block material=oak_planksplayer_by_name
按名字或 UUID 指定的在线玩家
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
name | STRING | 是 | — | 玩家名或 UUID |
name 是位置参数, 可以省略 name=
text
player_by_name Notch | send_message text="<yellow>你被点名了</yellow>"
player_by_name %var.winner% | give_money amount=500select
按配置定义挑选目标, 详见下一节目标选择器
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
name | STRING | 是 | — | 在 action.selectors 里定义的选择器 id |
name 是位置参数, 可以省略 name=
text
select nearby_elites | damage amount=5
select nearby_elites | play_sound sound=minecraft:entity.zombie.hurt volume=1 pitch=1all_players
全服在线玩家. 执行域 SERVER_GLOBAL
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
limit | INTEGER | 否 | 整数 | 0 | 最多返回几个玩家, 0 表示不限制 |
text
all_players | send_message text="示例"dropped_items
管道原点周围的掉落物. 执行域 LOCATION_REGION
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
radius | DOUBLE | 否 | 有限数值 | 8 | 以管道参考点为中心向四周搜索多远 |
limit | INTEGER | 否 | 整数 | 0 | 最多返回几个掉落物, 0 表示不限制 |
text
dropped_items | send_message text="示例"faction_members
指定阵营成员中的在线玩家. 执行域 SERVER_GLOBAL
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
member | STRING | 是 | 字符串 | — | 队伍成员的玩家名列表, 用逗号分隔 |
text
faction_members member=player1, player2 | send_message text="示例"highest_block
管道原点所在列的最高方块. 执行域 LOCATION_REGION
此段没有专属参数
text
highest_block | send_message text="示例"op_players
全服在线的 OP 玩家. 执行域 SERVER_GLOBAL
此段没有专属参数
text
op_players | send_message text="示例"party
拥有同一队伍权限节点的在线玩家. 执行域 SERVER_GLOBAL
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
permission | STRING | 是 | 字符串 | — | 队伍权限节点, 如 emaki.party.alpha |
text
party permission=emaki.party.alpha | send_message text="示例"players_by_gamemode
处于指定游戏模式的在线玩家. 执行域 SERVER_GLOBAL
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
gamemode | STRING | 是 | survival / creative / adventure / spectator | — | 游戏模式, 可填 survival / creative / adventure / spectator |
limit | INTEGER | 否 | 整数 | 0 | 最多返回几个玩家, 0 表示不限制 |
text
players_by_gamemode gamemode=survival | send_message text="示例"players_in_region
以管道原点为中心的立方区域内的玩家. 执行域 LOCATION_REGION
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
width | DOUBLE | 否 | 有限数值 | 16 | 以管道原点为中心, 沿 X 轴左右各延伸多少格 |
height | DOUBLE | 否 | 有限数值 | 16 | 以管道原点为中心, 沿 Y 轴上下各延伸多少格 |
depth | DOUBLE | 否 | 有限数值 | 16 | 以管道原点为中心, 沿 Z 轴前后各延伸多少格 |
limit | INTEGER | 否 | 整数 | 0 | 最多返回几个玩家, 0 表示不限制 |
text
players_in_region | send_message text="示例"players_with_material
背包中持有指定材质物品的在线玩家. 执行域 SERVER_GLOBAL
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
material | MATERIAL | 是 | Bukkit Material 名 | — | 物品的材质名 |
limit | INTEGER | 否 | 整数 | 0 | 最多返回几个玩家, 0 表示不限制 |
text
players_with_material material=diamond | send_message text="示例"random
从在线玩家中随机抽取若干目标. 执行域 SERVER_GLOBAL
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
count | INTEGER | 否 | 整数 | 1 | 随机抽取几个目标 |
text
random | send_message text="示例"region
以管道原点为角点的立方区域实体. 执行域 LOCATION_REGION
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
width | DOUBLE | 否 | 有限数值 | 8 | 以管道原点为中心, 沿 X 轴左右各延伸多少格 |
height | DOUBLE | 否 | 有限数值 | 8 | 以管道原点为中心, 沿 Y 轴上下各延伸多少格 |
depth | DOUBLE | 否 | 有限数值 | 8 | 以管道原点为中心, 沿 Z 轴前后各延伸多少格 |
limit | INTEGER | 否 | 整数 | 0 | 最多返回几个实体, 0 表示不限制 |
type | ENTITY_TYPE | 否 | Bukkit EntityType 名 | `` | 按实体类型筛选 |
include_players | BOOLEAN | 否 | true / false | true | 是否把玩家也算进候选目标 |
text
region | send_message text="示例"ring
位于内半径与外半径之间的环形区域实体. 执行域 LOCATION_REGION
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
min_radius | DOUBLE | 否 | 有限数值 | 1 | 环形内圈的半径 |
max_radius | DOUBLE | 否 | 有限数值 | 8 | 环形外圈的半径 |
limit | INTEGER | 否 | 整数 | 0 | 最多返回几个实体, 0 表示不限制 |
type | ENTITY_TYPE | 否 | Bukkit EntityType 名 | `` | 按实体类型筛选 |
include_players | BOOLEAN | 否 | true / false | true | 是否把玩家也算进候选目标 |
text
ring | send_message text="示例"vertical_block
管道原点垂直偏移后的方块位置. 执行域 LOCATION_REGION
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
offset | INTEGER | 否 | 整数 | 1 | 相对管道原点向上或向下偏移几格, 正数向上, 负数向下 |
text
vertical_block | send_message text="示例"world_players
指定世界内的在线玩家. 执行域 SERVER_GLOBAL
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
world | STRING | 否 | 字符串 | `` | 世界名, 留空就用管道原点所在的世界 |
limit | INTEGER | 否 | 整数 | 0 | 最多返回几个玩家, 0 表示不限制 |
text
world_players | send_message text="示例"目标选择器
选择器把"用哪个源段选, 按什么条件筛, 最多要几个"收进配置, 动作行里只写一个名字就行. 你不必先定义选择器: 单行动作本来就能靠 filter 直接写条件, 选择器只是把要重复使用的那部分收进主配置, 方便在多条 action 之间统一维护
两种使用方式
同一个筛选目标既可以直接写在一行动作里, 也可以先定义成选择器再调用. 行内写法不需要任何预配置
| 方式 | 写法 | 适用场景 |
|---|---|---|
| 行内筛选 | 源段 + filter 或 where 筛选段 | 一次性条件, 随手写, 随手改, 不必回主配置 |
| 命名选择器 | 主配置 action.selectors.<id> + select <id> | 同一套条件被多条 action 反复使用, 或需要改一处全局生效 |
| 混合 | select <id> 行内覆盖参数, 再叠加 filter | 重复使用一套基准条件, 再为当前这条 action 追加一次性条件 |
下面用同一个任务演示三种写法: 对 16 格内血量不高于 50% 的僵尸各造成 5 点伤害
行内写法 (无需预配置)
源段, 筛选段与动作段写在同一行. 实体类型交给源段自带的 type 参数, 血量比例交给 filter 的谓词串:
text
nearby radius=16 limit=5 type=zombie | filter 'health_percent<=50' | damage amount=5也可以把类型条件一并写进谓词串, 让 filter 承担全部筛选:
text
nearby radius=16 limit=5 | filter 'entity_type=ZOMBIE health_percent<=50' | damage amount=5filter 的位置参数必须用引号包裹; 谓词串内空格是 AND, || 是 OR, 前缀 ! 是 NOT, 圆括号可分组, 逗号是值列表. 完整规则与全部可用键见 filter
不想记谓词串语法时改用 where 写表达式, 它按 %target_*% 目标占位符逐目标求值:
text
nearby radius=16 limit=5 type=zombie | where %target_health_percent%<=50 | damage amount=5where 只接受一个表达式, 条件变多时要层层叠加 &&, 可读性不如谓词串
命名选择器写法 (先配置后调用)
把同一套条件收进主配置的 action.selectors.<id>:
yaml
action:
selectors:
low_health_zombies:
source: nearby
arguments:
radius: 16
limit: 5
type: zombie
condition:
predicates: 'health_percent<=50'动作行里只剩下一个名字:
text
select low_health_zombies | damage amount=5混合写法 (引用已有段 + 行内追加)
选择器提供基准条件, 行内覆盖被引用源段的参数, 或再用 filter / where 叠加当次条件:
text
select low_health_zombies radius=24
select low_health_zombies radius=24 | filter 'level>=30'行内参数必须是被引用源段声明的参数 (nearby 是 radius, limit, type, include_players), 写错名字会返回 unknown_argument, 而不是一声不响地被忽略掉; 选择器自身的 limit 只能在配置里设置
怎么选
两种写法共用同一套求值设施: filter 的谓词串与选择器 condition.predicates 完全同语法, 谓词键与 condition.entries 的类型节点同名
- 条件只用一次, 或要按当前这条 action 单独微调 → 行内
filter/where - 同一套条件出现在配方, GUI, 触发器等多处, 希望改一处全局生效 → 命名选择器
- 需要
at_least/exactly计数组合, 或需要invalid_as_failure: false(不可判定时放行) → 只能回主配置定义选择器;filter固定按不可判定即排除处理
定义选择器
选择器定义在 CoreLib 主配置的 action.selectors.<id>:
yaml
action:
selectors:
nearby_elites:
source: nearby
arguments:
radius: 16
limit: 5
include_players: false
limit: 2
condition:
type: all_of
invalid_as_failure: true
entries:
- type: entity_type
value: [ZOMBIE, SKELETON]
- type: health_percent
op: "<="
value: 50| 字段 | 类型 | 必填 | 默认值 | 取值范围 | 说明 |
|---|---|---|---|---|---|
source | string | 是 | — | 已注册的源段 id (不含 select 自身) | 引用的源段 id, 可用任意已注册源段 (含其他模块注册的) |
arguments | section | 否 | {} | 标量值 | 传给源段的参数, 写法与动作行参数一致, 值必须是标量 |
limit | integer | 否 | 0 | 非负整数; 0 表示不截断 | 条件过滤后再截断的数量 |
condition | section | 否 | {} | 条件组 (type / entries / required_count / predicates / invalid_as_failure) | 见下方条件组语法; 不写时源段选出的目标全部保留 |
source 不能写 select 自身, 否则会在加载期被拒绝. 选择器的线程域跟随被引用的源段: 引用 nearby 就仍按位置 region 调度, 不引入跨 region 读取
动作行里用 select <选择器 id> 调用, 选择器名不区分大小写.行内可以覆盖被引用源段的参数, 只写要改的那几个, 其余沿用主配置:
text
select low_health_elites
select low_health_elites radius=24 limit=8
select low_health_elites radius=24 | filter 'level>=30'行内参数必须是被引用源段声明的参数, 写错名字会返回 unknown_argument, 而不是一声不响地被忽略掉; 选择器自身的 limit 只能在配置里设置. 要叠加更多条件时直接用 filter 或 where, 不必回到主配置
条件组语法
condition 与条件系统 同构: entries 是条件节点列表, type 是组合方式, required_count 供计数模式使用
条件也可以写成一行的谓词串 (与 filter 完全同一套语法), 此时用 predicates 字段代替 entries:
yaml
condition:
predicates: 'entity_type=ZOMBIE health_percent<=50'
invalid_as_failure: falsepredicates 与 entries 只能选一个, 同时写会被加载期拒绝 (而不是悄悄忽略其中一个). 简单条件用 predicates 一行写完, 需要 at_least/exactly 或深层嵌套时用结构化的 entries
| 组合方式 | 含义 | 等价写法 |
|---|---|---|
all_of | 全部满足 | and |
any_of | 至少一个满足 | or |
none_of | 全部不满足 | not |
at_least | 至少 required_count 个满足 | — |
exactly | 恰好 required_count 个满足 | — |
在 entries 里写带 entries 的对象即可嵌套, 嵌套组自己再声明 type:
yaml
condition:
type: all_of
entries:
- type: any_of
entries:
- type: permission
value: emaki.admin
- type: level
op: ">="
value: 30
- type: none_of
entries:
- type: mythicmobs
id: SkeletonKing条件节点
节点分四类: 字符串或 type: expression 的表达式节点, 内置类型节点, 已注册生物系统节点, 第三方注册的类型节点. 求值顺序是内置类型 → 生物系统 → 第三方注册条件
内置类型节点:
type | 判定对象 | 字段 |
|---|---|---|
entity_type | 实体类型 | value: 类型名或列表, 按任一命中判定 |
player | 是否为玩家 | value: true / false |
dead | 是否已死亡 | value: true / false |
world | 所在世界 | value: 世界名或 namespace:key |
health | 当前生命值 | op + value |
health_percent | 生命值百分比 (0–100) | op + value |
distance | 与管道原点的距离 (格) | op + value |
level | 玩家经验等级 | op + value |
food | 玩家饥饿值 | op + value |
gamemode | 玩家游戏模式 | value: survival / creative / adventure / spectator |
permission | 玩家权限 | value: 权限节点或列表, 按任一命中判定 |
potion_effect | 状态效果 | effect: 效果名或列表; min_amplifier: 最低等级, 默认 0 |
scoreboard_tag | 计分板标签 | value: 标签或列表 |
state | 实体状态布尔值 | key: 状态名; value: 期望值, 默认 true |
op 是数值比较运算符, 取值 ==, !=, <, <=, >, >=, 必填. state 的 key 可用值: sneaking, sprinting, flying, gliding, swimming, in_water, on_ground; 其中 sprinting, flying 只对玩家可判定
生物系统节点: type 直接写系统 id, id 过滤生物 id (可写列表), op + level 过滤等级 (系统无等级概念时恒为 0)
yaml
condition:
entries:
- type: mythicmobs
id: [SkeletonKing, ZombieLord]
op: ">="
level: 5
- type: emakimobs
id: elite_zombiemythicmobs 由 EmakiCoreLib 内置识别; emakimobs 由 EmakiMobs 在启用时注册. 其他生物系统可以经 EmakiCoreLibApi.registerTargetIdentityProvider(plugin, provider) 注册自己的识别器. 系统未注册时该节点不可判定, 注册了但实体不属于该系统时判定为不满足
表达式节点与目标占位符
表达式节点照常写条件表达式, 并获得一组以 %target_ 开头的目标占位符:
| 占位符 | 含义 |
|---|---|
%target_type% | 实体类型名 |
%target_name% | 实体名 |
%target_world% | 所在世界名 |
%target_health% | 当前生命值 |
%target_max_health% | 最大生命值 |
%target_health_percent% | 生命值百分比 |
%target_distance% | 与管道原点的距离 |
%target_level% / %target_food% / %target_gamemode% | 玩家经验等级, 饥饿值, 游戏模式 |
%target_permission_<节点>% | 玩家是否拥有该权限, 结果 true / false |
%target_tag_<标签>% | 是否带有该计分板标签, 结果 true / false |
%target_state_<状态名>% | 该状态是否成立, 结果 true / false; 状态对目标不适用时保持原样 |
%target_effect_<效果名>% | 该状态效果的等级数字 (0 即 I 级), 没有该效果时为空串 |
%target_<系统>_id% | 生物系统 id, 例如 %target_mythicmobs_id% |
%target_<系统>_level% | 生物系统等级 |
无法判定的占位符保持原样, 表达式因此求值失败并按下方规则处理
yaml
condition:
entries:
- '%target_health_percent% <= 30 && %target_distance% <= 8'不可判定与 invalid_as_failure
条件节点有三种结果: 满足, 不满足, 不可判定. 不可判定的典型来源是非玩家目标上的玩家专属条件, 未安装的生物系统, 缺 op 或 value 的数值节点, 无法求值的表达式
invalid_as_failure 决定不可判定怎么参与组合, 含义与条件系统 一致:
true(默认): 任一节点不可判定即整组判为不满足, 目标被排除. 这偏向"宁可不选", 避免配置写错时把不该选的目标放进流程false: 不可判定节点被跳过, 不计入通过数; 若全部节点都被跳过, 则该组判为满足
示例
按"残血精英"筛选:
yaml
action:
selectors:
low_health_elites:
source: nearby
arguments:
radius: 20
limit: 10
condition:
type: all_of
entries:
- type: entity_type
value: [ZOMBIE, HUSK, DROWNED]
- type: health_percent
op: "<="
value: 40
- type: state
key: on_ground按玩家条件挑选 (周边, 有权限, 等级达标, 不在创造模式):
yaml
action:
selectors:
reward_candidates:
source: nearby_players
arguments:
radius: 32
limit: 5
condition:
type: all_of
entries:
- type: any_of
entries:
- type: permission
value: emaki.vip
- type: level
op: ">="
value: 30
- type: none_of
entries:
- type: gamemode
value: creative引用 MythicMobs 与 EmakiMobs 身份:
yaml
action:
selectors:
boss_like:
source: nearby
arguments:
radius: 24
condition:
type: any_of
entries:
- type: mythicmobs
op: ">="
level: 10
- type: emakimobs
id: bone_lord在动作行里使用:
text
select low_health_elites | kill_entity
select reward_candidates | give_money amount=100加载期检查
配置预检会检查选择器的结构性错误并给出路径 (如 action.selectors.low_health_elites.condition.entries[1]): 缺 source, source 写 select 自身, 引用的源段当前未注册, 数值节点缺 op 或 value, state 的状态名无效. 其中前两项是错误, 会让预检失败并保留上一份有效配置; 其余为警告
运行时若条件节点的 type 既不是内置类型, 也不是已注册系统或第三方条件, 控制台会打印一次告警并列出可用类型; 该节点按不可判定处理
第三方条件类型
业务模块与第三方插件可以注册自己的条件类型, 注册后即可在选择器的 condition.entries 里使用:
java
EmakiCoreLibApi.registerTargetCondition(this, new CoreTargetCondition() {
@Override
public String id() {
return "myplugin_custom";
}
@Override
public CoreTargetOutcome test(CoreActionSubject subject,
CoreStageContext context,
CoreTargetConditionArguments arguments) {
return subject.entityOrNull() == null
? CoreTargetOutcome.UNKNOWN
: CoreTargetOutcome.PASS;
}
});内置类型 id 不能被覆盖 -- 重名注册会被拒绝并返回稳定的 reasonKey. 注册句柄在插件停用时关闭; 该注册表不随 CoreLib 重载重建
内置 gate
gate 段负责过滤目标流, 控制先后顺序, 或往管道上下文写值; 它们自己不产生效果
where
按条件逐个目标筛选: 条件不成立的目标从流里移除
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
condition | STRING | 是 | — | 布尔条件 |
condition 是位置参数. 条件在调用前先完成管道占位符替换, 再逐个目标求值, 因此既能用 %var.<名字>%, CoreLib 自带的玩家占位符, 调用模块写入上下文的变量与 PlaceholderAPI 占位符, 也能用 %target_*% 目标占位符 (见目标选择器 的占位符表)
条件里不含 %target_*% 时, 每个目标得到同一个结果, 整条流要么全留要么全清 -- 既有配置行为不变. 含 %target_*% 时才真正逐目标筛选
text
self | set threshold=10 | looking_at | where %var.threshold%>5 | kill_entity
nearby radius=6 limit=10 | where %target_health_percent%<=30 | damage amount=4条件写得复杂时, 用 filter 的谓词串更省事, 需要跨多条 action 重复使用时放进 action.selectors
filter
按行内谓词逐个目标筛选, 不必先在主配置里定义选择器. 位置参数是一条引号包裹的谓词串:
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
condition | STRING | 是 | — | 谓词串 |
谓词串的规则:
| 规则 | 写法 | 含义 |
|---|---|---|
| 并列 | entity_type=ZOMBIE health_percent<=50 | 空格相邻即全部成立 (AND) |
| 或 | level>=30 || permission=emaki.vip | || 即 OR |
| 非 | !gamemode=creative | 前缀 ! 即 NOT |
| 分组 | (health<=30 || level>=50) entity_type=ZOMBIE | 圆括号可任意嵌套 |
| 值列表 | entity_type=ZOMBIE,SKELETON | 逗号分隔, 任一命中即成立; 配 != 表示都不属于 |
可用键与 action.selectors 的条件类型同名, 没有别名:
| 键 | 写法 | 说明 |
|---|---|---|
entity_type | entity_type=ZOMBIE,SKELETON | 实体类型 |
player / dead | player=true, dead=false | 是否为玩家 / 是否已死亡 |
world | world=world_nether | 世界名或 namespace:key |
health | health<=10 | 当前生命值 |
health_percent | health_percent<=50 | 生命值百分比 (0–100) |
distance | distance<=8 | 与管道原点的距离 |
level / food | level>=30 | 玩家经验等级 / 饥饿值 |
gamemode | gamemode!=creative | 玩家游戏模式 |
permission | permission=emaki.vip | 权限节点, 列表按任一命中 |
scoreboard_tag | scoreboard_tag=elite | 计分板标签 |
state.<状态名> | state.sneaking, state.on_ground=false | 实体状态布尔值, 默认期望 true |
potion_effect.<效果名> | potion_effect.speed>=2 | 状态效果等级 (0 即 I 级); >=0 只要求存在 |
<神话生物 id> | mythicmobs=SkeletonKing, emakimobs=elite_zombie | 生物系统身份, 可写 id 列表 |
<神话生物 id>_level | mythicmobs_level>=5 | 生物系统等级 |
数值键的运算符为 ==, !=, <, <=, >, >=, 必填 -- health 少写运算符会直接报错, 不会一声不响地放过. 谓词串必须用引号包裹: 不加引号时 entity_type=ZOMBIE 会被当成段参数并因"未知参数"报错, 这是刻意做的快速失败
text
nearby radius=12 | filter 'entity_type=ZOMBIE health_percent<=50' | damage amount=5
select low_health_elites | filter 'level>=30 || permission=emaki.vip' | give_money amount=100filter 与 where 可以叠加, 按管道顺序依次筛选. 求值与 action.selectors 的条件组共用同一套设施; filter 固定按 invalid_as_failure: true 处理不可判定 (非玩家目标上的玩家专属条件, 未注册的生物系统, 无法求值的表达式都算不可判定), 也就是一遇到不可判定就排除该目标. 需要"不可判定时放行"时, 用 action.selectors 定义带 invalid_as_failure: false 的选择器
chance
概率没通过就结束管道
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
chance | PERCENTAGE | 是 | — | 概率, 如 50%, 0.5, 1/3 |
chance 是位置参数. 没摇中是"停止"而不是"无效" -- 摇不中本来就是这个段的意义所在; 而 chance abc 是打错了, 服主需要看到报错
需要"必定发生, 但发生哪一种按概率分配"时用权重分支, 不要用多行 chance 拼概率 -- 那样每行独立判定, 可能一条都不中, 也可能同时中好几条
text
self | chance 10% | broadcast_message text="<gold>%player_name% 触发了稀有奖励!</gold>"
self | chance 1/3 | give_money amount=100 provider=vaultlimit
保留流里前 count 个目标, 保持原有顺序
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
count | INTEGER | 是 | — | 保留几个目标 |
count 是位置参数
text
nearby radius=15 limit=50 | sort_by distance | limit 3 | damage amount=12sort_by
按距离或生命值给目标流排序
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
key | STRING | 是 | — | distance 或 health |
order | STRING | 否 | asc | asc 或 desc |
key 是位置参数. 搭配 limit 就能表达"最近的 3 个"或"血最少的那个"
text
nearby radius=20 limit=30 | sort_by health order=asc | limit 1 | kill_entity
nearby_players radius=25 | sort_by distance order=desc | limit 5 | send_title title="<red>远离战场</red>"set
写入管道变量, 之后读作 %var.<名字>%
这个段不声明任何参数, 因为变量名由写管道的人自己定 -- set damage=%var.level%*4+18 命名的变量 CoreLib 事先不可能知道. 加载配置时会对这个段跳过"未知参数"检查
能作为算式求值的值会被存成数字, 所以 %var.damage% 读回来是 22 而不是 %var.level%*4+18; 其余的原样保存
text
self | set damage=%var.level%*4+18 | set label=暴击 | send_message text="<red>%var.label% %var.damage%</red>"keep
把当前目标流标记为要带到下一阶段的那一份. 无参数
管道内部目标流本来就在段之间传递, 所以这个 gate 原样放行. 它不只是一个什么都不做的段, 原因在于: 解释器会把它看到的流记录下来, 这是把一个阶段的目标交给下一个阶段的方式. 技能脚本在 cast 阶段写 looking_at | keep, 在 hit 阶段用 inherited 读回来
它记录的是运行到它时的流, 而不是管道最终的流, 所以这一行放在阶段里的什么位置不影响结果: 后面的 gate 收窄了流, 不会改变已记录的内容; 第二个 keep 会覆盖第一个
text
looking_at | keep | send_message text="<gray>已锁定目标</gray>"stop
在此结束管道. 无参数
上报的是"停止", 所以整条管道的结果是跳过而不是失败 -- 刻意停下来不是错误. 主要用在分支里
text
looking_at | if %var.dead% [ stop ] else [ damage amount=5 ]create_item
构建一个物品, 并作为管道的物品值发布出去
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
item_source | STRING | 否 | "" | 物品来源 (短横线简写) |
amount | INTEGER | 否 | 1 | 物品个数 |
它被登记成 gate 而不是 action, 因为往上下文里写入带类型的数据是 gate 的职责: 只有 gate 通过时才能把数据写回管道上下文. 这也是它原样放行目标流的原因 -- 这个段只是添了一个值, 并没有消耗目标
管道里只有一个物品键, 所以没有名字可起, 旧的 id 参数不存在了; 同一条管道里第二个 create_item 会替换掉前一个的值
item_source 使用 CoreLib 物品来源短横线简写, 详见 物品来源, 例如原版 minecraft-diamond, 自定义来源 emakiitem-flame_blade. 原版来源不接受 minecraft:diamond 这种冒号写法
text
self | create_item item_source=minecraft-golden_apple amount=2 | send_item
self | create_item item_source=emakiitem-flame_sword | send_itemafter
延迟它之后的每一个段
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
delay | DURATION | 是 | — | 延迟, 如 10t, 500ms, 2s |
delay 是位置参数. 这是个时序段而不是流变换: 解释器认出 after, 把管道余下的部分当成它的主体, 然后带延迟调度这个主体. 主体运行前会重新校验施法者, 目标和归属插件, 所以等待期间消失的目标会导致跳过而不是报错
text
self | after 1s | send_message text="<gray>1 秒后发送的提示"
self | send_message text="<gold>准备</gold>" | after 20t | send_message text="<red>开始!</red>"every
按间隔重复它之后的每一个段
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
interval | DURATION | 否 | 1t | 间隔, 如 20t, 1s |
times | INTEGER | 否 | 0 | 首次之后额外执行的次数 |
写作 every <间隔> times <次数>. times 计的是首次之外的额外次数, 所以 times 0 (默认值) 表示主体只跑一次. 次数受 action.pipeline.max_repeat_times (默认 100) 限制, 超限会拒绝该条配置
text
self | every 10t times 5 | spawn_particle particle=flame count=10
origin | every 1s times 3 | play_sound sound=minecraft:block.note_block.bell volume=1 pitch=1.5every 适合一条管道内的短促重复. 需要长时间运行, 能按 key 取消的循环, 用 start_task
distance_filter
只保留与管道原点距离在 [min, max] 内的目标. 线程需求 NEEDS_ENTITY_READ
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
min | DOUBLE | 否 | 有限数值 | 0 | 最小距离 |
max | DOUBLE | 否 | 有限数值 | 32 | 最大距离 |
text
self | distance_filter | send_message text="示例"sample
随机抽取 count 个目标. 线程需求 PURE
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
count (裸值) | INTEGER | 是 | 整数 | — | 随机抽取几个目标量 |
text
self | sample '3' | send_message text="示例"shuffle
随机打乱目标顺序. 线程需求 PURE
此段没有专属参数
text
self | shuffle | send_message text="示例"where_all
只保留同时满足全部谓词的目标; 谓词以 || 分隔. 线程需求 NEEDS_ENTITY_READ
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
conditions (裸值) | STRING | 是 | 字符串 | — | 多个谓词, |
text
self | where_all 'player || health_percent<=50' | send_message text="示例"where_any
只保留满足任一谓词的目标; 谓词以 || 分隔. 线程需求 NEEDS_ENTITY_READ
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
conditions (裸值) | STRING | 是 | 字符串 | — | 多个谓词, |
text
self | where_any 'health_percent<=50 || dead' | send_message text="示例"内置 action
action 是真正产生效果的段. 参数表里的"目标要求"说明这个段需要什么样的目标流; 不满足时该段会被跳过, 不会让整条管道失败
NONE: 完全不需要目标OPTIONAL: 有无目标都能跑, 零目标时仍执行一次REQUIRED_ENTITY: 至少要一个实体目标REQUIRED_LOCATION: 至少要一个位置目标REQUIRED_ANY: 至少要一个目标, 实体或位置都可以
数值类段的校验与审计
生命, 饱食度, 经验, 货币和物品数量类段会明确校验 amount, 不再一声不响地把它改成合法值:
- 非法数值直接以
INVALID_CONFIG失败, 并在文案里带上该数值; 这类问题对服主可见, 不会被当成"配置写错但勉强能跑" - 生命, 饱食度, 经验, 货币类段要求
amount是有限非负数 (NaN,Infinity均非法); 扣除类段 (take_exp,take_money,take_item,take_food) 与物品发放类段 (give_item,set_item,drop_item) 还要求大于 0 - 扣除不足 (经验, 货币, 物品, 饱食度) 返回
REJECTED, 并携带所需与当前数量, 不做部分扣除, 也不会把余额或数量扣成负数 - 每次成功或失败的数值变动都会经 CoreLib
DebugLogger的action.audit模块输出审计行, 字段包含stage,operation, 目标,before/after,amount, 来源插件与phase; 失败行另带reason与details. 开启方式见 命令与权限 的全局 Debug 开关
消息与反馈
send_message
发送 MiniMessage 格式聊天消息. 目标要求 REQUIRED_ENTITY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
text | STRING | 是 | — | MiniMessage 格式的消息文本 |
yaml
actions:
# 基础消息
- 'self | send_message text="<green>操作成功!</green>"'
# 带占位符的消息
- 'self | send_message text="<yellow>欢迎回来,%player_name%!</yellow>"'
# 复杂 MiniMessage 格式 (渐变色 + 悬浮提示)
- 'self | send_message text="<hover:show_text:''点击查看详情''><click:run_command:/menu><gradient:gold:yellow>打开菜单</gradient></click></hover>"'send_action_bar
发送 ActionBar 消息. 目标要求 REQUIRED_ENTITY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
text | STRING | 是 | — | MiniMessage 格式的 ActionBar 文本 |
yaml
actions:
- 'self | send_action_bar text="<green>+50 经验</green>"'
- 'self | send_action_bar text="<gray>烹饪进度:<green>████</green><dark_gray>██████</dark_gray> 40%</gray>"'send_title
显示 Title (大标题 + 副标题). 目标要求 REQUIRED_ENTITY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
title | STRING | 是 | — | 主标题 (MiniMessage 格式) |
subtitle | STRING | 否 | "" | 副标题 (MiniMessage 格式) |
fade_in | DURATION | 否 | 10t | 淡入时间 |
stay | DURATION | 否 | 40t | 停留时间 |
fade_out | DURATION | 否 | 10t | 淡出时间 |
yaml
actions:
# 基础 Title
- 'self | send_title title="<gold>任务完成</gold>" subtitle="<gray>获得经验奖励</gray>"'
# 自定义时间参数
- 'self | send_title title="<red>警告</red>" subtitle="<yellow>你即将进入危险区域</yellow>" fade_in=5t stay=60t fade_out=20t'
# 仅显示主标题 (快速闪烁效果)
- 'self | send_title title="<bold><gold>LEVEL UP!</gold></bold>" fade_in=0t stay=20t fade_out=5t'broadcast_message
向全服广播 MiniMessage 消息. 目标要求 NONE
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
text | STRING | 是 | — | MiniMessage 格式的广播文本 |
不需要目标, 所以可以不写 source:
yaml
actions:
# 全服公告
- 'broadcast_message text="<gold>[公告] <white>服务器将在 5 分钟后重启</white></gold>"'
# 玩家成就广播
- 'broadcast_message text="<light_purple>✦ %player_name% 完成了传说级锻造!✦</light_purple>"'play_sound
给目标播放声音. 目标要求 REQUIRED_ENTITY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
sound | SOUND | 是 | — | 声音键名. 可写 Bukkit Sound 枚举名或 minecraft: 风格键 |
volume | DOUBLE | 否 | 1 | 音量 (0 以上, 大于 1 时增加可听距离) |
pitch | DOUBLE | 否 | 1 | 音调 (0.5–2.0, 1 为正常音调) |
yaml
actions:
# 升级音效
- 'self | play_sound sound=minecraft:entity.player.levelup volume=1 pitch=1'
# 铁砧使用音效 (低音调, 大音量远距离可听)
- 'self | play_sound sound=minecraft:block.anvil.use volume=2 pitch=0.8'
# 给周围所有玩家播放
- 'nearby_players radius=12 | play_sound sound=minecraft:entity.villager.no volume=1 pitch=1'spawn_particle
在目标位置生成粒子. 目标要求 REQUIRED_ANY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
particle | STRING | 是 | — | 粒子键名 (Bukkit Particle 枚举名) |
count | INTEGER | 否 | 1 | 生成多少个粒子 |
offset_x | DOUBLE | 否 | 0 | 粒子在 X 轴上的散开范围 |
offset_y | DOUBLE | 否 | 0 | 粒子在 Y 轴上的散开范围 |
offset_z | DOUBLE | 否 | 0 | 粒子在 Z 轴上的散开范围 |
extra | DOUBLE | 否 | 0 | 额外参数 (速度或数据, 依粒子类型而定) |
坐标不再是这个段的参数: 位置由 source 决定, self 是玩家位置, at, offset, origin 给出指定位置
yaml
actions:
# 玩家位置生成绿色粒子 (成功反馈)
- 'self | spawn_particle particle=happy_villager count=15 offset_x=0.3 offset_y=0.5 offset_z=0.3'
# 玩家位置火焰粒子 (技能释放)
- 'self | spawn_particle particle=flame count=30 offset_x=0.5 offset_y=0.2 offset_z=0.5 extra=0.05'
# 指定世界坐标生成粒子
- 'at world=world x=100 y=65 z=-30 | spawn_particle particle=end_rod count=50 offset_x=1 offset_y=2 offset_z=1 extra=0.02'
# 玩家头顶两格
- 'offset y=2 | spawn_particle particle=explosion count=3 offset_x=0.1 offset_y=0.1 offset_z=0.1'boss_bar_show
给目标显示一个 Boss 血条. 目标要求 REQUIRED_ENTITY. 同一 id 再次调用会更新已有血条
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
id | STRING | 是 | — | Boss 血条 ID, 用于后续更新或隐藏 |
title | STRING | 是 | — | 血条标题 (MiniMessage 格式) |
progress | DOUBLE | 否 | 1 | 进度, 取值 0 到 1 |
color | STRING | 否 | purple | 血条颜色 |
style | STRING | 否 | solid | 血条样式 |
flags | STRING | 否 | "" | 逗号分隔的血条标志 |
yaml
actions:
- 'self | boss_bar_show id=forge_progress title="<gold>锻造中</gold>" progress=0.5 color=yellow'
- 'self | boss_bar_show id=forge_progress title="<green>即将完成</green>" progress=0.9'boss_bar_hide
隐藏之前显示的 Boss 血条. 目标要求 REQUIRED_ENTITY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
id | STRING | 是 | — | Boss 血条 ID, 或写 all 隐藏全部 |
yaml
actions:
- 'self | boss_bar_hide id=forge_progress'
- 'self | boss_bar_hide id=all'reset_title
清除玩家屏幕上的标题与副标题. 分类 message, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
此段没有专属参数
yaml
actions:
- 'self | reset_title'send_title_fade
发送带淡入淡出时长的标题. 分类 message, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
title | STRING | 是 | 字符串 | — | 主标题内容 |
subtitle | STRING | 否 | 字符串 | `` | 副标题文本 |
fade_in | INTEGER | 否 | 整数 | 10 | 淡入的游戏刻数 |
stay | INTEGER | 否 | 整数 | 40 | 停留的游戏刻数 |
fade_out | INTEGER | 否 | 整数 | 10 | 淡出的游戏刻数 |
yaml
actions:
- 'self | send_title_fade title=example'
- 'self | send_title_fade title=example subtitle='spawn_particle_at
在指定坐标生成粒子效果. 分类 visual, 目标要求 NONE, 执行域 LOCATION_REGION
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
particle | STRING | 是 | 字符串 | — | 粒子类型 |
x | DOUBLE | 否 | 有限数值 | 0 | 相对目标位置的 X 轴偏移 |
y | DOUBLE | 否 | 有限数值 | 0 | 相对目标位置的 Y 轴偏移 |
z | DOUBLE | 否 | 有限数值 | 0 | 相对目标位置的 Z 轴偏移 |
count | INTEGER | 否 | 整数 | 1 | 生成多少个粒子 |
yaml
actions:
- 'spawn_particle_at particle=flame'
- 'spawn_particle_at particle=flame x=0'生命与状态
heal
恢复目标生命. 目标要求 REQUIRED_ENTITY (需要是存活实体; 非存活实体跳过). 恢复后不超过最大生命值
amount 必须是非负有限数; 负数或非有限值会让该段以 INVALID_CONFIG 失败, 不会被当成 0 继续跑
IMPORTANT
此段直接设置生命值, 不触发 Bukkit EntityRegainHealthEvent. 不受任何治疗加成或减免影响
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
amount | DOUBLE | 是 | — | 治疗量 (半心为单位, 1 = 半颗心) |
yaml
actions:
# 治疗 4 点 (2 颗心)
- 'self | heal amount=4'
# 满血治疗 (超出部分会被限制到最大生命)
- 'self | heal amount=9999'
# 少量治疗 (配合概率使用)
- 'self | chance 30% | heal amount=2'damage
扣除目标生命. 目标要求 REQUIRED_ENTITY. 扣除后生命最低为 0
amount 必须是非负有限数; 负数或非有限值会让该段以 INVALID_CONFIG 失败, 不会被当成 0 继续跑
IMPORTANT
此段直接设置生命值, 不触发 Bukkit EntityDamageEvent. 不受护甲, 抗性, 附魔等任何减免影响, 也不会导致玩家死亡 (最低为 0)
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
amount | DOUBLE | 是 | — | 伤害量 |
yaml
actions:
# 扣除 2 点生命 (1 颗心)
- 'self | damage amount=2'
# 对准星上的目标造成伤害
- 'looking_at range=10 | damage amount=8'
# 配合条件使用
- 'if %player_world%=="world_nether" [ self | damage amount=1 ]'set_health
把目标生命设为指定值. 目标要求 REQUIRED_ENTITY. 自动限制在 0 到最大生命值之间
amount 必须是非负有限数; 负数或非有限值会让该段以 INVALID_CONFIG 失败
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
amount | DOUBLE | 是 | — | 目标生命值 |
想让一个玩家死亡就用这个段设为 0, kill_entity 拒绝玩家目标
yaml
actions:
- 'self | set_health amount=20'
- 'self | set_health amount=1'
- 'looking_at | set_health amount=0'feed
恢复目标饱食度. 目标要求 REQUIRED_ENTITY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
amount | INTEGER | 否 | 20 | 恢复的饱食度点数 |
saturation | DOUBLE | 否 | 0 | 恢复的饱和度 |
amount 为负会让该段以 INVALID_CONFIG 失败; saturation 为负按 0 处理. 恢复后饱食度与饱和度都不超过 20
yaml
actions:
- 'self | feed'
- 'self | feed amount=6 saturation=3'take_food
扣除目标饱食度, 可选同时扣除饱和度. 目标要求 REQUIRED_ENTITY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
amount | INTEGER | 是 | — | 扣除的饱食度点数 |
saturation | DOUBLE | 否 | 0 | 额外扣除的饱和度点数 |
amount 必须大于 0, 否则该段以 INVALID_CONFIG 失败. 饱食度不足时返回 REJECTED (携带所需与当前数量), 不做部分扣除; saturation 为负按 0 处理, 且扣到 0 为止
yaml
actions:
- 'self | take_food amount=6'
# 同时扣除 2 点饱和度
- 'self | take_food amount=4 saturation=2'
# 饱食度不足时不生效, 而不是扣成负数
- 'self | take_food amount=20'ignite
点燃目标. 目标要求 REQUIRED_ENTITY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
duration | DURATION | 否 | 5s | 燃烧持续时间 |
yaml
actions:
- 'looking_at | ignite duration=8s'
- 'nearby radius=5 limit=10 | ignite'extinguish
熄灭目标身上的火. 目标要求 REQUIRED_ENTITY. 无参数
yaml
actions:
- 'self | extinguish'kill_entity
移除目标实体. 目标要求 REQUIRED_ENTITY. 无参数
这是旧的 killentity 去掉搜索之后剩下的部分: radius / limit / type / include_players 全部搬到了 source nearby. 选择哪些实体从来不是这个段的事, 现在它只是把流交给它的东西移除掉
玩家目标会被拒绝. 对玩家调用 Entity#remove 不是受支持的操作; 要让玩家死亡请用 set_health amount=0
yaml
actions:
# 清掉周围 8 格内最多 5 只僵尸
- 'nearby radius=8 limit=5 type=zombie | kill_entity'
# 清掉准星上的实体
- 'looking_at range=20 | kill_entity'projectile
从施法者发射一枚自驱动的抛射物. 目标要求 OPTIONAL
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
speed | DOUBLE | 否 | 1.5 | 每 1/20 秒 (一个游戏刻) 飞行的格数 |
gravity | DOUBLE | 否 | 0.05 | 每个游戏刻的下坠量 |
lifetime | INTEGER | 否 | 60 | 最长存活多少个游戏刻 |
hit_radius | DOUBLE | 否 | 0.5 | 命中判定的半径 |
pierce | INTEGER | 否 | 0 | 额外穿透几个实体 |
homing | BOOLEAN | 否 | false | 是否追踪当前目标 |
homing_strength | DOUBLE | 否 | 0.1 | 追踪时转向的强度 |
particle | STRING | 否 | flame | 飞行尾迹用哪种粒子 |
damage | DOUBLE | 否 | 0 | 命中时造成的伤害, 0 表示不造成伤害 |
direction | STRING | 否 | look | 初始方向: look (视线) 或 target (目标) |
yaml
actions:
# 直线火球
- 'self | projectile speed=2 damage=8 particle=flame'
# 追踪弹, 需要先有目标
- 'looking_at range=25 | projectile homing=true homing_strength=0.2 damage=12 direction=target'
# 穿透弹
- 'self | projectile speed=2.5 pierce=3 damage=5 gravity=0'set_absorption
设置实体的伤害吸收生命值. 分类 entity, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
amount | DOUBLE | 是 | 有限数值 | — | 要设置多少吸收生命值 |
yaml
actions:
- 'self | set_absorption amount=1.0'set_arrows_in_body
设置插在实体身上的箭矢数量. 分类 entity, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
count | INTEGER | 是 | 整数 | — | 插在身上的箭矢数量 |
yaml
actions:
- 'self | set_arrows_in_body count=3'set_collidable
控制生物之间是否互相碰撞. 分类 entity, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
collidable | BOOLEAN | 是 | true / false | — | 是否与其他生物互相碰撞 |
yaml
actions:
- 'self | set_collidable collidable=true'set_max_no_damage_ticks
设置实体无敌时间的上限 (无敌帧就是受伤后那段打不动的短暂免伤时间). 分类 entity, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
ticks | INTEGER | 是 | 整数 | — | 无敌时间的上限 |
yaml
actions:
- 'self | set_max_no_damage_ticks ticks=3'set_no_damage_ticks
设置实体的无敌时间时长. 分类 entity, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
ticks | INTEGER | 是 | 整数 | — | 无敌时间的游戏刻数 |
yaml
actions:
- 'self | set_no_damage_ticks ticks=3'set_remaining_air
设置实体剩余呼吸值. 分类 entity, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
ticks | INTEGER | 是 | 整数 | — | 还能在水下呼吸多少个游戏刻 |
yaml
actions:
- 'self | set_remaining_air ticks=200'实体元数据
add_scoreboard_tag
为实体添加记分板标签. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
tag | STRING | 是 | 字符串 | — | 要添加或移除的标签内容 |
yaml
actions:
- 'self | add_scoreboard_tag tag=example'remove_scoreboard_tag
移除实体的记分板标签. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
tag | STRING | 是 | 字符串 | — | 要添加或移除的标签内容 |
yaml
actions:
- 'self | remove_scoreboard_tag tag=example'set_ai
控制生物的 AI 开关. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
enabled | BOOLEAN | 是 | true / false | — | 是否启用 AI |
yaml
actions:
- 'self | set_ai enabled=true'set_can_pickup_items
控制生物是否能拾取掉落物. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
can_pickup | BOOLEAN | 是 | true / false | — | 能不能拾取掉落物 |
yaml
actions:
- 'self | set_can_pickup_items can_pickup=true'set_fire_ticks
设置实体着火时长 (单位是游戏刻, 负数表示熄灭). 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
ticks | INTEGER | 是 | 整数 | — | 着火的游戏刻数 |
yaml
actions:
- 'self | set_fire_ticks ticks=100'set_glowing
控制实体是否发光描边. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
glowing | BOOLEAN | 是 | true / false | — | 是否发光 |
yaml
actions:
- 'self | set_glowing glowing=true'set_gravity
控制实体是否受重力影响. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
gravity | BOOLEAN | 是 | true / false | — | 是否受重力 |
yaml
actions:
- 'self | set_gravity gravity=true'set_invulnerable
控制实体是否无敌. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
invulnerable | BOOLEAN | 是 | true / false | — | 是否无敌 |
yaml
actions:
- 'self | set_invulnerable invulnerable=true'set_name
设置实体的自定义名称 (MiniMessage). 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
name | STRING | 是 | 字符串 | — | 要设置的名字 |
yaml
actions:
- 'self | set_name name=<gold>Boss</gold>'set_name_visible
控制实体自定义名称是否常显. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
visible | BOOLEAN | 是 | true / false | — | 是否常显 |
yaml
actions:
- 'self | set_name_visible visible=true'set_persistent
控制实体是否在区块卸载后保留. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
persistent | BOOLEAN | 是 | true / false | — | 是否保留 |
yaml
actions:
- 'self | set_persistent persistent=true'set_remove_when_far_away
控制生物距离过远时是否被移除. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
remove | BOOLEAN | 是 | true / false | — | 是否移除 |
yaml
actions:
- 'self | set_remove_when_far_away remove=true'set_silent
控制实体是否静音. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
silent | BOOLEAN | 是 | true / false | — | 是否静音 |
yaml
actions:
- 'self | set_silent silent=true'set_visible_by_default
控制实体默认是否对所有玩家可见. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
visible | BOOLEAN | 是 | true / false | — | 是否默认可见 |
yaml
actions:
- 'self | set_visible_by_default visible=true'移动与速度
add_velocity
给实体叠加速度向量 (击退/弹射). 分类 movement, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
x | DOUBLE | 是 | 有限数值 | — | 叠加到 X 轴方向的速度 |
y | DOUBLE | 是 | 有限数值 | — | 叠加到 Y 轴方向的速度 |
z | DOUBLE | 是 | 有限数值 | — | 叠加到 Z 轴方向的速度 |
yaml
actions:
- 'self | add_velocity x=1.0 y=1.0 z=1.0'knockback
把目标从施法者方向推开. 分类 movement, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
strength | DOUBLE | 否 | 有限数值 | 1 | 推开对方的力度 |
vertical | DOUBLE | 否 | 有限数值 | 0.4 | 向上抬起的力度 |
yaml
actions:
- 'self | knockback'
- 'self | knockback strength=1'set_rotation
设置实体朝向 (yaw/pitch). 分类 movement, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
yaw | DOUBLE | 是 | 有限数值 | — | 水平朝向的角度 |
pitch | DOUBLE | 是 | 有限数值 | — | 俯仰角度 |
yaml
actions:
- 'self | set_rotation yaw=1.0 pitch=1.0'set_velocity
设置实体速度向量. 分类 movement, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
x | DOUBLE | 是 | 有限数值 | — | X 轴方向的速度 |
y | DOUBLE | 是 | 有限数值 | — | Y 轴方向的速度 |
z | DOUBLE | 是 | 有限数值 | — | Z 轴方向的速度 |
yaml
actions:
- 'self | set_velocity x=1.0 y=1.0 z=1.0'药水效果
give_potion_effect
给目标添加药水效果. 目标要求 REQUIRED_ENTITY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
type | STRING | 是 | — | 药水效果类型. 可写 speed, minecraft:strength 等 |
level | INTEGER | 是 | — | 效果等级, 从 1 起算. 1 对应 Bukkit amplifier 0 (游戏内 I 级) |
duration | DURATION | 是 | — | 持续时间. 如 100t, 5s, 10000ms |
ambient | BOOLEAN | 否 | false | 是否为环境效果 (粒子更稀疏, 更透明) |
particles | BOOLEAN | 否 | true | 是否显示粒子 |
icon | BOOLEAN | 否 | true | 是否在 HUD 显示效果图标 |
yaml
actions:
# 速度 II 持续 30 秒
- 'self | give_potion_effect type=speed level=2 duration=30s particles=true icon=true'
# 力量 I 持续 1 分钟 (无粒子, 更隐蔽)
- 'self | give_potion_effect type=strength level=1 duration=60s particles=false icon=true'
# 夜视 (环境效果, 粒子稀疏)
- 'self | give_potion_effect type=night_vision level=1 duration=5s ambient=true'
# 使用 minecraft: 前缀写法
- 'self | give_potion_effect type=minecraft:regeneration level=3 duration=10s'
# 给周围敌人上减速
- 'nearby radius=6 limit=10 | give_potion_effect type=slowness level=2 duration=5s'remove_potion_effect
移除目标的指定药水效果. 目标要求 REQUIRED_ENTITY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
type | STRING | 是 | — | 药水效果类型 |
yaml
actions:
- 'self | remove_potion_effect type=slowness'
- 'self | remove_potion_effect type=minecraft:weakness'clear_potion_effects
清除目标当前所有药水效果. 目标要求 REQUIRED_ENTITY. 无参数
yaml
actions:
# 清除所有药水效果 (净化)
- 'self | clear_potion_effects'
# 延迟 2 秒后清除
- 'self | after 2s | clear_potion_effects'
# 仅在特定世界清除
- 'if %player_world%=="world_arena" [ self | clear_potion_effects ]'物品
多个物品段用同一个 item_source 参数, 取值是 CoreLib 物品来源短横线简写, 详见 物品来源
槽位参数 slot 支持:
mainhand,main_hand,handoffhand,off_handhelmet,chestplate/chest,leggings/legs,boots- 背包索引
0到35, 也可写slot_0,hotbar_0
物品数量类段 (give_item, set_item, take_item, drop_item) 的 amount 必须大于 0, 否则以 INVALID_CONFIG 失败; take_item 数量不足时返回 REJECTED (携带所需与当前数量), 不做部分扣除. repair_item 与 damage_item 的 amount 含义不同, 见各自小节
send_item
把管道物品交给目标. 目标要求 REQUIRED_ENTITY. 无参数
这个段声明了自己需要管道物品, 所以同一条管道里没有前置 create_item 就写 send_item, 是加载配置时的错误, 不会等到运行时才变成空值: 校验器会拿这个声明和触发阶段承诺提供的上下文比对
旧的 id 和 keep 参数都没了. 管道里只有一个物品键而不是一张按名字索引的表, 而读取上下文的值并不会消耗它, 所以"保留在临时仓库里"已经无从谈起
yaml
actions:
- 'self | create_item item_source=minecraft-golden_apple amount=2 | send_item'give_item
把物品来源对应的物品发放到目标背包. 目标要求 REQUIRED_ENTITY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
item_source | STRING | 否 | "" | 物品来源 (短横线简写) |
amount | INTEGER | 否 | 1 | 个数 |
和 create_item + send_item 的区别在于: 这个段直接按来源发放, 不经过管道物品, 所以不需要两段配合, 但也无法在发放前对物品做别的处理
yaml
actions:
- 'self | give_item item_source=minecraft-diamond amount=5'
- 'nearby_players radius=10 | give_item item_source=emakiitem-strengthen_stone amount=1'set_item
把目标指定槽位的物品设为给定来源的物品. 目标要求 REQUIRED_ENTITY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
slot | STRING | 否 | mainhand | 要操作的背包槽位 |
item_source | STRING | 否 | "" | 物品来源 (短横线简写) |
amount | INTEGER | 否 | 1 | 个数 |
yaml
actions:
- 'self | set_item slot=mainhand item_source=emakiitem-flame_sword'
- 'self | set_item slot=helmet item_source=minecraft-diamond_helmet'clear_item
清空目标指定槽位的物品. 目标要求 REQUIRED_ENTITY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
slot | STRING | 是 | — | 要操作的背包槽位 |
item_source | STRING | 否 | "" | 期望的物品来源. 指定后只有匹配时才清空, 不匹配则跳过 |
yaml
actions:
# 清空主手物品 (无条件)
- 'self | clear_item slot=mainhand'
# 仅当主手是木棍时才清空
- 'self | clear_item slot=mainhand item_source=minecraft-stick'
# 清空头盔槽位 (仅匹配自定义物品时)
- 'self | clear_item slot=helmet item_source=emakiitem-cursed_helmet'
# 清空指定背包格子
- 'self | clear_item slot=0'take_item
从目标背包扣除匹配的物品. 目标要求 REQUIRED_ENTITY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
item_source | STRING | 否 | "" | 期望扣除的物品来源 |
amount | INTEGER | 否 | 1 | 扣除多少个 |
yaml
actions:
- 'self | take_item item_source=minecraft-emerald amount=3'
- 'self | take_item item_source=emakiitem-forge_token amount=1'drop_item
在目标位置掉落物品. 目标要求 REQUIRED_ANY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
item_source | STRING | 否 | "" | 物品来源 (短横线简写) |
amount | INTEGER | 否 | 1 | 物品个数 |
坐标由 source 提供, 不再是这个段的参数
yaml
actions:
# 在玩家头顶掉落物品
- 'offset y=2 | drop_item item_source=minecraft-diamond amount=1'
# 在固定坐标掉落奖励
- 'at world=world x=100 y=65 z=-50 | drop_item item_source=minecraft-gold_ingot amount=5'
# 在玩家前方三格掉落
- 'offset z=3 relative=true | drop_item item_source=minecraft-emerald amount=2'repair_item
修复目标槽位中物品的耐久. 目标要求 REQUIRED_ENTITY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
slot | STRING | 否 | mainhand | 要操作的背包槽位 |
amount | INTEGER | 否 | 0 | 修复的耐久点数; 小于等于 0 表示完全修复 |
yaml
actions:
- 'self | repair_item'
- 'self | repair_item slot=chestplate amount=50'damage_item
增加目标槽位中物品的损耗. 目标要求 REQUIRED_ENTITY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
slot | STRING | 否 | mainhand | 要操作的背包槽位 |
amount | INTEGER | 否 | 1 | 增加的损耗点数 |
delete_item | BOOLEAN | 否 | false | 耐久耗尽时是否移除该物品 |
amount 为负返回 INVALID_CONFIG; 为 0 时该段跳过且不修改物品
yaml
actions:
- 'self | damage_item amount=10'
- 'self | damage_item slot=mainhand amount=100 delete_item=true'玩家状态
clear_inventory
清空玩家背包. 分类 player, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
此段没有专属参数
yaml
actions:
- 'self | clear_inventory'set_bed_spawn
把玩家重生点设置为管道原点. 分类 player, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
此段没有专属参数
yaml
actions:
- 'self | set_bed_spawn'set_compass_target
把玩家指南针指向管道原点. 分类 player, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
此段没有专属参数
yaml
actions:
- 'self | set_compass_target'set_exp_to_level
直接设置玩家经验条百分比. 分类 player, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
percent | INTEGER | 是 | 0 至 100 | — | 经验条百分比 0-100 |
yaml
actions:
- 'self | set_exp_to_level percent=3'set_fly_speed
设置玩家飞行速度. 分类 player, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
speed | DOUBLE | 是 | -1.0 至 1.0 | — | 飞行速度, 范围 -1.0 至 1.0 |
yaml
actions:
- 'self | set_fly_speed speed=1.0'set_gamemode
设置玩家游戏模式. 分类 player, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
gamemode | STRING | 是 | survival / creative / adventure / spectator | — | survival / creative / adventure / spectator |
yaml
actions:
- 'self | set_gamemode gamemode=creative'set_item_cooldown
为玩家的指定材质物品设置冷却. 分类 player, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
material | MATERIAL | 是 | Bukkit Material 名 | — | 物品的材质名 |
seconds | INTEGER | 是 | 整数 | — | 冷却多少秒 |
yaml
actions:
- 'self | set_item_cooldown material=golden_apple seconds=60'set_level
直接设置玩家经验等级. 分类 player, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
level | INTEGER | 是 | 整数 | — | 经验等级 |
yaml
actions:
- 'self | set_level level=3'set_saturation
设置玩家饱和度. 分类 player, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
value | DOUBLE | 是 | 有限数值 | — | 要设置的饱和度 |
yaml
actions:
- 'self | set_saturation value=1.0'set_walk_speed
设置玩家行走速度. 分类 player, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
speed | DOUBLE | 是 | -1.0 至 1.0 | — | 行走速度, 范围 -1.0 至 1.0 |
yaml
actions:
- 'self | set_walk_speed speed=1.0'方块与世界
place_block
在目标位置放置物品来源对应的方块. 目标要求 REQUIRED_ANY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
item_source | STRING | 否 | "" | 要放置的方块来自哪个物品来源 |
支持原版方块以及 CraftEngine, ItemsAdder, Nexo, Oraxen 自定义方块. 若来源不是可放置方块, 该段会跳过而不是中断整条管道. 有玩家上下文时会触发 Bukkit 放置事件, 保护插件取消时不会放置
yaml
actions:
# 放置原版方块 (注意用连字符分隔命名空间和 ID)
- 'at world=world x=100 y=64 z=-20 | place_block item_source=minecraft-stone'
# 在玩家脚下放置方块
- 'at x=~ y=~-1 z=~ | place_block item_source=minecraft-oak_planks'
# 放置 CraftEngine 自定义方块
- 'at x=~1 y=~ z=~ | place_block item_source=ce-cutting_board'
# 放置 ItemsAdder 自定义方块
- 'offset y=2 | place_block item_source=itemsadder-decorative_lamp'set_block
把目标位置设为某种方块. 目标要求 REQUIRED_ANY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
material | STRING | 否 | "" | 要设置的方块材质名 |
block_data | STRING | 否 | "" | Bukkit BlockData 字符串 |
apply_physics | BOOLEAN | 否 | true | 是否触发方块物理更新 |
和 place_block 的区别: 这个段直接写材质, 不走物品来源, 也不触发 Bukkit 放置事件, 所以能设置那些没有对应物品的方块状态
yaml
actions:
- 'at world=world x=50 y=70 z=100 | set_block material=chest'
- 'at x=~ y=~-1 z=~ | set_block material=oak_stairs block_data="[facing=north,half=top]"'
- 'origin | set_block material=air apply_physics=false'break_block
破坏或清除目标位置的方块. 目标要求 REQUIRED_ANY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
drop_items | BOOLEAN | 否 | false | 是否掉落方块物品 |
apply_physics | BOOLEAN | 否 | true | 清除方块时是否触发物理更新 |
yaml
actions:
- 'at x=~ y=~-1 z=~ | break_block drop_items=true'
- 'at world=world x=10 y=64 z=10 | break_block'explosion
在目标位置产生爆炸. 目标要求 REQUIRED_ANY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
power | DOUBLE | 否 | 0 | 爆炸威力 |
fire | BOOLEAN | 否 | false | 是否引燃 |
break_blocks | BOOLEAN | 否 | false | 是否破坏方块 |
默认威力为 0, 不引燃, 不破坏方块, 也就是只有视听效果, 需要真实破坏时要显式打开
yaml
actions:
# 纯特效爆炸
- 'self | explosion power=2'
# 会破坏方块的爆炸
- 'looking_at range=15 | explosion power=4 fire=true break_blocks=true'spawn_entity
在目标位置生成实体. 目标要求 REQUIRED_ANY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
type | ENTITY_TYPE | 是 | — | 实体类型 |
count | INTEGER | 否 | 1 | 生成几个 |
yaml
actions:
- 'at world=world x=100 y=65 z=-30 | spawn_entity type=zombie count=3'
- 'offset z=4 relative=true | spawn_entity type=armor_stand'set_difficulty
设置世界难度. 分类 world, 目标要求 NONE, 执行域 SERVER_GLOBAL
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
difficulty | STRING | 是 | peaceful / easy / normal / hard | — | 难度: peaceful / easy / normal / hard |
yaml
actions:
- 'set_difficulty difficulty=normal'set_game_rule
设置世界的原版游戏规则. 分类 world, 目标要求 NONE, 执行域 SERVER_GLOBAL
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
rule | STRING | 是 | 字符串 | — | 游戏规则名 |
value | STRING | 是 | 按规则类型为 true / false 或整数 | — | 规则要设成什么值 |
yaml
actions:
- 'set_game_rule rule=doDaylightCycle value=false'set_weather
设置世界天气. 分类 world, 目标要求 NONE, 执行域 SERVER_GLOBAL
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
weather | STRING | 是 | clear / rain / thunder | — | 天气: clear / rain / thunder |
duration | INTEGER | 否 | 整数 | 0 | 持续秒数, 0 表示无限 |
yaml
actions:
- 'set_weather weather=rain'
- 'set_weather weather=rain duration=0'set_world_spawn
把世界出生点设置为管道原点. 分类 world, 目标要求 NONE, 执行域 LOCATION_REGION
此段没有专属参数
yaml
actions:
- 'set_world_spawn'set_world_time
设置世界时间. 分类 world, 目标要求 NONE, 执行域 SERVER_GLOBAL
| 参数 | 类型 | 必填 | 取值范围 | 默认值 | 作用说明 |
|---|---|---|---|---|---|
time | STRING | 是 | tick 数或 day / night | — | 时间, 可填游戏刻数或 day/night |
yaml
actions:
- 'set_world_time time=day'传送
teleport
把目标传送到指定坐标. 目标要求 REQUIRED_ENTITY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
world | STRING | 否 | "" | 目标世界名. 空则使用目标当前世界 |
x | STRING | 否 | ~ | X 坐标. 支持 ~ 相对当前坐标 (如 ~5 表示 X+5) |
y | STRING | 否 | ~ | Y 坐标. 支持 ~ 相对坐标 |
z | STRING | 否 | ~ | Z 坐标. 支持 ~ 相对坐标 |
yaw | DOUBLE | 否 | 目标当前朝向 | 偏航角 (水平朝向, 0–360). 不填就保留当前朝向 |
pitch | DOUBLE | 否 | 目标当前朝向 | 俯仰角 (垂直朝向, -90–90). 不填就保留当前朝向 |
坐标是这个段自己的参数而不是靠 source 提供: source 决定的是"传送谁", 坐标决定的是"传到哪", 两者都是必要信息
yaml
actions:
# 传送到固定坐标
- 'self | teleport world=world x=0 y=100 z=0 yaw=180 pitch=0'
# 相对传送 (向上 10 格)
- 'self | teleport y=~10'
# 跨世界传送
- 'self | teleport world=world_nether x=50 y=64 z=-100 yaw=90 pitch=0'
# 把附近玩家都拉到出生点
- 'nearby_players radius=30 | teleport world=world x=0 y=65 z=0'经济
三个经济段共用同一组参数
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
amount | DOUBLE | 是 | — | 金额 |
provider | STRING | 否 | auto | 经济提供者. 可选: auto, vault, excellenteconomy |
currency | STRING | 否 | "" | 货币类型. ExcellentEconomy 多货币时必须指定 |
amount 必须是有限非负数; NaN, Infinity, 负数一律返回 INVALID_CONFIG. give_money 与 take_money 还要求金额大于 0; set_money 允许 0 (用于清空余额). 经济提供者不可用或货币不存在同样按 INVALID_CONFIG 处理
give_money
给目标增加余额. 目标要求 REQUIRED_ENTITY
yaml
actions:
# 基础给钱 (自动选择经济插件)
- 'self | give_money amount=100'
# 指定 Vault 经济
- 'self | give_money amount=500 provider=vault'
# ExcellentEconomy 多货币
- 'self | give_money amount=50 provider=excellenteconomy currency=gems'take_money
扣除目标余额. 目标要求 REQUIRED_ENTITY. 余额不足时返回 REJECTED (文案携带所需与当前余额), 不会扣成负数, 也不做部分扣除
yaml
actions:
- 'self | take_money amount=25.5 provider=vault'
- 'self | take_money amount=10 provider=excellenteconomy currency=coins'set_money
把目标余额设为指定值. 目标要求 REQUIRED_ENTITY
yaml
actions:
- 'self | set_money amount=0 provider=vault'
- 'self | set_money amount=1000 provider=auto'经验
三个经验段共用同一组参数. 目标要求都是 REQUIRED_ENTITY
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
amount | INTEGER | 是 | — | 经验点数或等级数 |
mode | STRING | 否 | points | 模式: points (经验点数) 或 levels (等级) |
give_exp 与 set_exp 要求 amount 非负, 负数返回 INVALID_CONFIG; take_exp 要求大于 0
give_exp
给目标增加经验
yaml
actions:
# 给予 100 经验点
- 'self | give_exp amount=100 mode=points'
# 给予 3 个等级
- 'self | give_exp amount=3 mode=levels'
# 默认模式为 points, 可省略
- 'self | give_exp amount=50'take_exp
扣除目标经验. 经验不足时返回 REJECTED (携带 mode 与所需/当前数量), 不做部分扣除, 也不会扣成负数; points 模式按总经验判定, levels 模式按等级判定
yaml
actions:
- 'self | take_exp amount=200 mode=points'
- 'self | take_exp amount=1 mode=levels'set_exp
把目标总经验或等级设为指定值
yaml
actions:
- 'self | set_exp amount=30 mode=levels'
- 'self | set_exp amount=0 mode=points'命令
三个命令段共用同一个参数. 命令值会自动去掉开头的 /, 但为了可读性建议配置里不要写
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
command | STRING | 是 | — | 要执行的命令 (不含开头 /) |
run_command_as_player
以目标玩家身份执行命令. 目标要求 REQUIRED_ENTITY. 受玩家权限限制
yaml
actions:
- 'self | run_command_as_player command="spawn"'
- 'self | run_command_as_player command="menu open main"'run_command_as_op
临时给目标玩家 OP 执行命令, 执行后恢复原 OP 状态. 目标要求 REQUIRED_ENTITY
CAUTION
这个段会临时赋予 OP 权限, 存在安全风险: 命令执行期间玩家拥有完整 OP 权限, 如果命令内容来自可被玩家影响的占位符, 等于把提权入口交了出去. 建议优先用 run_command_as_console, 或者用权限插件做临时授权
yaml
actions:
- 'self | run_command_as_op command="lp user %player_name% permission set example.vip true"'run_command_as_console
以控制台身份执行命令. 目标要求 NONE (占位符仍会解析)
不需要目标, 所以可以不写 source:
yaml
actions:
# 全服公告
- 'run_command_as_console command="say %player_name% 完成了一次锻造"'
# 给予权限
- 'run_command_as_console command="lp user %player_name% permission set forge.master true"'
# 执行其他插件命令
- 'run_command_as_console command="crate give %player_name% legendary 1"'长时间任务
every 适合一条管道内的短促重复. 要启动一个能长时间运行, 能按 key 取消, 玩家离线或死亡时自动停止的循环, 用下面两个段
start_task
启动一个按间隔重复执行的命名序列. 目标要求 OPTIONAL
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
sequence | STRING | 是 | — | 要重复执行的序列名 |
times | INTEGER | 否 | 1 | 一共执行几次 |
interval | DURATION | 否 | 20t | 每隔多久执行一次 |
initial_delay | DURATION | 否 | 0t | 首次执行前的延迟 |
key | STRING | 否 | "" | 任务 key, 用于后续取消 |
on_conflict | STRING | 否 | replace | key 冲突策略: replace, ignore, allow_duplicate |
stop_when_offline | BOOLEAN | 否 | true | 玩家离线时停止 |
stop_when_dead | BOOLEAN | 否 | false | 玩家死亡时停止 |
stop_when | STRING | 否 | "" | 条件成立时停止 |
stop_on_failure | BOOLEAN | 否 | false | 序列执行失败时停止 |
这一个段取代了旧的 loopsync 和 loopasync. 旧实现里 async 标记只是选了个不同的最小间隔并多跑一次前置检查, 调度方式两者完全一样; 真正的线程归属来自每个段自己声明的执行域, 所以配置层面的同步/异步开关已经无从表达
不在上表里的参数会被当成序列体的参数传下去, 在序列里读作 %var.<名字>%. 这取代了旧的 with. 前缀 -- 那个前缀存在的唯一原因是旧参数模型分不清"声明过的参数"和"额外的参数", 现在能分清了
yaml
action:
templates:
burn_tick:
- 'inherited | damage amount=1'
- 'inherited | spawn_particle particle=flame count=5'
buff_pulse:
- 'self | send_action_bar text="<gold>祝福剩余 %var.label%</gold>"'
actions:
# 每秒一次, 共 10 次
- 'looking_at | keep | start_task sequence=burn_tick times=10 interval=20t key=burn_%player_name%'
# 带序列参数, 玩家死亡时停止
- 'self | start_task sequence=buff_pulse times=30 interval=1s key=buff stop_when_dead=true label=神圣祝福'
# 条件不成立就停
- 'self | start_task sequence=buff_pulse times=100 interval=20t stop_when=%player_world%!="world_arena"'stop_task
按 key 取消正在运行的任务. 目标要求 NONE
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
key | STRING | 是 | — | 要取消的任务 key |
match | STRING | 否 | exact | 匹配方式: exact 或 prefix |
什么都没取消到会被当成跳过而不是失败: 配置里经常要取消一个可能并没在跑的任务, 比如在一个两种情况都会触发的事件上清理增益循环, 把这种情况当错误会让日志被正确的配置刷满
yaml
actions:
- 'stop_task key=burn_%player_name%'
- 'stop_task key=buff_ match=prefix'脚本
三个 js_* 段执行 GraalJS 脚本. 它们共用同一组参数, 区别只在目标要求与线程域: 选错会导致脚本在错误的线程上碰 Bukkit API
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
code | STRING | 是 | — | JavaScript 代码 |
timeout | INTEGER | 否 | 5000 | 超时时间, 单位毫秒 |
timeout 写 0 或负数时按默认值处理. 代码为空, 超时或被中断都算跳过而不是失败; 脚本抛错才算失败
脚本的求值结果只写入该段执行结果里的 script_result 一个键, 不会自动变成管道变量, 所以后续段读不到 %var.script_result%
js_compute
纯计算脚本, 不操作 Bukkit 状态. 目标要求 NONE, 执行域 ASYNC_COMPUTE. 绑定 context; 当前目标是玩家时额外绑定 player
因为跑在异步线程, 脚本里不得触碰 Bukkit 状态
脚本里可以用 context.getVariable(名字) 与 context.hasVariable(名字) 读取管道变量
yaml
actions:
- 'self | set level=%player_level% | js_compute code="context.getVariable(''level'') * 10"'js_entity
操作玩家/实体的脚本. 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY. 绑定 player 与 context; 目标不是玩家时跳过
js_location
操作方块/位置的脚本. 目标要求 REQUIRED_LOCATION, 执行域 LOCATION_REGION. 绑定 location 与 context; 当前目标是玩家时额外绑定只读的 player
MythicMobs 与技能
cast_mythic_skill 和 cast_skill 由 EmakiSkills 模块提供, 不是 CoreLib 内置段, 参数与行为见 Skills CoreLib 动作
在命令中查看与执行管道
管理员可在服务端内直接查看当前注册表, 并手动执行一条管道:
text
/corelib action list
/corelib action run <管道文本>同样可通过 /emakicorelib action, /emakicore action 或复数别名 actions 调用. 该命令使用 emakicorelib.admin 权限; 控制台执行时没有玩家上下文, 需要实体目标的段会按既有目标要求跳过. run 关键字可以省略, /corelib action self | heal amount=4 与带 run 等价
action list 按角色 (source / gate / action) 分组列出 id 与所属插件. 之所以分组而不给平铺清单: 一个 id 只在管道的某一种位置上合法, 平铺列表无法告诉运维这个 id 能用在哪
action run 会先编译再执行, 所以语法错误或未知段名会带着自己的诊断信息报出来, 而不是变成一个笼统的执行失败. 只显示第一条诊断 -- 编译器会报出一行上的所有问题, 其余多数是第一个问题的连带结果. 执行结束后会报告整条管道的状态; 失败时会指出是哪个段失败的, 因为手打的管道多半是在调试, 失败的段就是答案本身
子插件段在哪里看
CoreLib 提供段注册表和统一的管道引擎; 业务插件可以在启用时向同一个注册表追加自己的 source, gate 和 action. 为了避免 CoreLib 页面集中维护所有插件的专属段参数, 这里只列 CoreLib 内置段
子插件注册的段已拆分到对应插件自己的动作页:
| 来源模块 | 文档 |
|---|---|
| EmakiAttribute | Attribute CoreLib 动作 |
| EmakiForge | Forge CoreLib 动作 |
| EmakiStrengthen | Strengthen CoreLib 动作 |
| EmakiCooking | Cooking CoreLib 动作 |
| EmakiGem | Gem CoreLib 动作 |
| EmakiLevel | Level CoreLib 动作 |
| EmakiSkills | Skills CoreLib 动作 |
| EmakiItem | Item CoreLib 动作 |
| EmakiCodex | Codex CoreLib 动作 |
| EmakiStorage | Storage CoreLib 动作 |
EmakiMobs 注册的 4 个 source 与 4 个 action 暂时没有独立动作页, 只在段 ID 表 里列出 ID 与用途
如果一个段来自某个业务插件, 它的参数, 上下文变量和执行时机以该插件文档为准
第三方插件注册段
外部插件开发者可以只依赖 emaki-corelib-api, 按角色调用对应的注册方法把自定义段注册进 CoreLib 的共享注册表:
EmakiCoreLibApi.registerActionStage(plugin, stage)— 注册 actionEmakiCoreLibApi.registerActionSource(plugin, source)— 注册 sourceEmakiCoreLibApi.registerActionGate(plugin, gate)— 注册 gate
可用 actionStages() / actionStage(id) 与 actionTriggers() / actionTrigger(id) 查询当前只读注册表. CoreLib 重建注册表后, onStageRegistryRebuilt(plugin, callback) 兼容地按 owner 替换旧回调; 同一插件需要多个独立回调时用 addStageRegistryRebuildListener(plugin, callback), 它们会独立追加并返回可关闭句柄. 插件禁用时 CoreLib 会自动撤销该 owner 的段与回调; 调用方仍应在生命周期结束时显式关闭返回句柄
action 实现 CoreActionStage, 声明 id, category, description, parameters, targetRequirement, requiredContext 与 executionTarget. CoreLib 会用同一套词法, 语法, 参数校验, 占位符渲染, 调度与 debug 输出
executionTarget 没有默认实现, 这是有意的: 一个段必须自己说清楚它要在哪个线程上跑, 不能靠继承一个默认值含糊过去. requiredContext 则是让"缺少前置段"变成加载期错误的机制 -- send_item 声明自己需要管道物品, 校验器就能在加载配置时发现少了 create_item
最小示例:
java
CoreStageRegistration registration = EmakiCoreLibApi.registerActionStage(plugin, new CoreActionStage() {
@Override
public String id() {
return "my_custom_stage";
}
@Override
public String category() {
return "myplugin";
}
@Override
public String description() {
return "Runs my plugin's custom effect.";
}
@Override
public List<CoreStageParameter> parameters() {
return List.of(CoreStageParameter.required("value", CoreStageParameterType.STRING, "Custom value"));
}
@Override
public CoreTargetRequirement targetRequirement() {
return CoreTargetRequirement.REQUIRED_ENTITY;
}
@Override
public CoreActionExecutionTarget executionTarget(CoreStagePlanningContext context) {
// 需要 Bukkit 主线程 API 时选实体所属线程
return CoreActionExecutionTarget.contextEntity();
}
@Override
public CoreActionOutcome execute(CoreStageContext context, CoreResolvedArguments arguments) {
// 这里执行你的插件逻辑
return CoreActionOutcome.success();
}
});
// 插件禁用时:
registration.close();段 ID 速查表
想查全部 218 个段 (CoreLib 内置 131: source 25 / gate 16 / action 90; 附属插件注册 87) 的分类清单, 用途说明, 注册来源与跳转入口, 看段 ID 表; 各内置段的专属参数以每一节的参数表为准, 附属插件注册的段以子插件段在哪里看 列出的动作页为准, 三类段通用的控制项与书写规范见上方公共参数 (所有段通用)
故障排查
加载时报未知段名. 检查 id 是否用下划线分词: 是 send_message 而不是 sendmessage. 用 /corelib action list 确认这个 id 存在, 并确认它出现在管道的正确位置 -- source 不能写在 action 的位置上
段名对但报"未知参数". 参数名也变了几个: 物品来源统一叫 item_source (不再有 source / item 别名), set_block 没有 block 别名, start_task 的额外参数直接写而不带 with. 前缀
管道跳过了但没报错. 目标要求不满足会跳过而不是失败. 最常见的原因是漏写 source 导致退化成 self, 而 self 在没有玩家上下文时是空的; 或者 nearby 没搜到实体
分支条件里的 || 不生效. 逻辑或必须写成 ||, 单个 | 会被当成分段符
send_item 在加载时报错. 这个段需要管道物品, 同一条管道里必须先有 create_item
times 报超限. every ... times N 的上限是 action.pipeline.max_repeat_times (默认 100). 需要更多次数请用 start_task, 它的次数配额由任务服务单独控制
参数值里的空格被拆开了. 含空格, MiniMessage 标签或命令的值必须加引号. YAML 里整行管道本身也建议用单引号包起来, 避免 : 和 # 被 YAML 解析
完整管道示例
以下是一个锻造成功后的完整配置, 展示多种段的组合使用:
yaml
action:
success:
# 基础反馈
- 'self | send_title title="<gold>锻造成功</gold>" subtitle="<gray>品质:%forge_quality%</gray>" fade_in=5t stay=40t fade_out=10t'
- 'self | play_sound sound=minecraft:block.anvil.use volume=1 pitch=1.2'
- 'self | spawn_particle particle=happy_villager count=20 offset_x=0.5 offset_y=0.5 offset_z=0.5'
# 经济奖励 (10% 概率返还部分费用)
- 'self | chance 10% | give_money amount=50 provider=vault | send_message text="<yellow>幸运!返还了 50 金币。</yellow>"'
# 经验奖励
- 'self | give_exp amount=30 mode=points'
# 高品质额外奖励
- 'if %forge_quality%=="epic" [ self | send_message text="<light_purple>史诗品质!额外获得强化石。</light_purple>" | create_item item_source=emakiitem-strengthen_stone amount=1 | send_item ]'
# 全服广播 (仅传说品质)
- 'if %forge_quality%=="legendary" [ broadcast_message text="<gold>%player_name% 锻造出了传说品质装备!</gold>" ]'
# 延迟提示
- 'self | after 2s | send_message text="<gray>装备已更新,请查看背包。</gray>"'注意第二条: chance 通过后, 同一条管道里后面的 give_money 和 send_message 都会执行. 旧写法要在两行上各写一次概率, 两次独立摇点, 结果可能出现给了钱却没提示; 现在一条管道摇一次点, 后续段共享这次结果