Skip to content

动作系统 ​

动作管道这样写: 在 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=2
  • union [ ] 内只允许源段, 写动作段或开关段会报 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_timesinteger否100正整数 (<=0 回退默认)every <间隔> times <次数> 的次数上限, 超限拒绝该条配置
action.pipeline.max_sequence_depthinteger否8正整数 (<=0 回退默认)run 的最大嵌套深度
action.pipeline.max_branch_depthinteger否16正整数 (<=0 回退默认)if, weight 与 on_error 共用的最大嵌套深度
action.pipeline.max_retry_timesinteger否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.enabledboolean否truetrue / false是否允许启动循环任务
action.loop.min_sync_intervalduration否5t>=1t (预检)同步域循环的最小间隔
action.loop.min_async_intervalduration否100ms>=1t (预检)异步域循环的最小间隔
action.loop.max_timesinteger否7200>0 (预检)单个循环任务的最大执行次数
action.loop.max_active_loops_totalinteger否5000>0 (预检)全服同时活动的循环任务上限
action.loop.max_active_loops_per_playerinteger否16>0 (预检)单个玩家同时活动的循环任务上限
action.loop.max_active_loops_per_plugininteger否1000>0 (预检)单个插件同时活动的循环任务上限
action.loop.cancel_player_loops_on_quitboolean否truetrue / false玩家退出时取消其循环任务
action.loop.cancel_plugin_loops_on_disableboolean否truetrue / 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/falsekeep=false, icon=true
DURATION时间. 支持 t (游戏刻), s (秒), ms (毫秒), 纯数字按游戏刻算20t, 1s, 500ms
PERCENTAGE概率. 支持百分比, 小数与分数50%, 0.5, 1/3
ENTITY_TYPEBukkit EntityType 名type=zombie
MATERIALBukkit Material 名material=stone
SOUND声音键. Bukkit Sound 枚举名或 namespace:keysound=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 变化不止加下划线:

旧写法现在
raysource looking_at
loopsync / loopasyncstart_task (同步/异步不再是配置项, 见该段说明)
cancelloopstop_task
@template=名称 / usetemplaterun 名称
killentity radius=... type=...source nearby 负责搜索, kill_entity 只负责移除
createitem id=... senditem id=...create_item 写入唯一的管道物品, send_item 读它, 不再需要 id
castmythicskillcast_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=8

trigger ​

触发器点名的实体, 用在触发者与施法者不是同一个人的场合. 无参数

上下文里存的是名字或 UUID, 不是实体本身 -- 管道可能在运行前很久就编译好了, 把活着的实体放进上下文会妨碍回收

text
trigger | send_message text="<yellow>你触发了机关</yellow>"

origin ​

管道的空间参考点, 作为一个位置目标. 无参数

text
origin | spawn_particle particle=flame count=20

looking_at ​

施法者准星指向的实体

参数类型必填默认值说明
rangeDOUBLE否5射线能伸多长
widthDOUBLE否0.5射线的粗细
text
looking_at range=12 | damage amount=6
looking_at | keep | send_message text="<red>你被锁定了</red>"

nearby ​

管道参考点周围的实体

参数类型必填默认值说明
radiusDOUBLE否1以管道参考点为中心向四周搜索多远
limitINTEGER否1最多返回几个实体
typeENTITY_TYPE否""按实体类型筛选, 留空表示不限类型
include_playersBOOLEAN否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=5s

nearby_players ​

管道参考点周围的玩家

参数类型必填默认值说明
radiusDOUBLE否1以管道参考点为中心向四周搜索多远
limitINTEGER否0最多返回几个, 0 表示全部都算

和 nearby 共用同一套过滤逻辑, 只是候选只取玩家. limit 默认为 0 (全部) 而不是 1, 因为面向队伍或区域的效果要覆盖所有玩家, 而不是最近的那一个

text
nearby_players radius=10 | send_message text="<gold>队伍获得了增益</gold>"

offset ​

相对管道参考点偏移出的一个位置

参数类型必填默认值说明
xDOUBLE否0沿 X 轴偏移多少格
yDOUBLE否0沿 Y 轴偏移多少格
zDOUBLE否0沿 Z 轴偏移多少格
relativeBOOLEAN否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=false

at ​

一个绝对坐标, 或相对参考点的坐标

参数类型必填默认值说明
worldSTRING否""世界名; 留空就用参考点所在的世界
xSTRING否~X 坐标, 支持 ~
ySTRING否~Y 坐标, 支持 ~
zSTRING否~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_planks

player_by_name ​

按名字或 UUID 指定的在线玩家

参数类型必填默认值说明
nameSTRING是—玩家名或 UUID

name 是位置参数, 可以省略 name=

text
player_by_name Notch | send_message text="<yellow>你被点名了</yellow>"
player_by_name %var.winner% | give_money amount=500

select ​

按配置定义挑选目标, 详见下一节目标选择器

参数类型必填默认值说明
nameSTRING是—在 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=1

all_players ​

全服在线玩家. 执行域 SERVER_GLOBAL

参数类型必填取值范围默认值作用说明
limitINTEGER否整数0最多返回几个玩家, 0 表示不限制
text
all_players | send_message text="示例"

dropped_items ​

管道原点周围的掉落物. 执行域 LOCATION_REGION

参数类型必填取值范围默认值作用说明
radiusDOUBLE否有限数值8以管道参考点为中心向四周搜索多远
limitINTEGER否整数0最多返回几个掉落物, 0 表示不限制
text
dropped_items | send_message text="示例"

faction_members ​

指定阵营成员中的在线玩家. 执行域 SERVER_GLOBAL

参数类型必填取值范围默认值作用说明
memberSTRING是字符串—队伍成员的玩家名列表, 用逗号分隔
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

参数类型必填取值范围默认值作用说明
permissionSTRING是字符串—队伍权限节点, 如 emaki.party.alpha
text
party permission=emaki.party.alpha | send_message text="示例"

players_by_gamemode ​

处于指定游戏模式的在线玩家. 执行域 SERVER_GLOBAL

参数类型必填取值范围默认值作用说明
gamemodeSTRING是survival / creative / adventure / spectator—游戏模式, 可填 survival / creative / adventure / spectator
limitINTEGER否整数0最多返回几个玩家, 0 表示不限制
text
players_by_gamemode gamemode=survival | send_message text="示例"

players_in_region ​

以管道原点为中心的立方区域内的玩家. 执行域 LOCATION_REGION

参数类型必填取值范围默认值作用说明
widthDOUBLE否有限数值16以管道原点为中心, 沿 X 轴左右各延伸多少格
heightDOUBLE否有限数值16以管道原点为中心, 沿 Y 轴上下各延伸多少格
depthDOUBLE否有限数值16以管道原点为中心, 沿 Z 轴前后各延伸多少格
limitINTEGER否整数0最多返回几个玩家, 0 表示不限制
text
players_in_region | send_message text="示例"

players_with_material ​

背包中持有指定材质物品的在线玩家. 执行域 SERVER_GLOBAL

参数类型必填取值范围默认值作用说明
materialMATERIAL是Bukkit Material 名—物品的材质名
limitINTEGER否整数0最多返回几个玩家, 0 表示不限制
text
players_with_material material=diamond | send_message text="示例"

random ​

从在线玩家中随机抽取若干目标. 执行域 SERVER_GLOBAL

参数类型必填取值范围默认值作用说明
countINTEGER否整数1随机抽取几个目标
text
random | send_message text="示例"

region ​

以管道原点为角点的立方区域实体. 执行域 LOCATION_REGION

参数类型必填取值范围默认值作用说明
widthDOUBLE否有限数值8以管道原点为中心, 沿 X 轴左右各延伸多少格
heightDOUBLE否有限数值8以管道原点为中心, 沿 Y 轴上下各延伸多少格
depthDOUBLE否有限数值8以管道原点为中心, 沿 Z 轴前后各延伸多少格
limitINTEGER否整数0最多返回几个实体, 0 表示不限制
typeENTITY_TYPE否Bukkit EntityType 名``按实体类型筛选
include_playersBOOLEAN否true / falsetrue是否把玩家也算进候选目标
text
region | send_message text="示例"

ring ​

位于内半径与外半径之间的环形区域实体. 执行域 LOCATION_REGION

参数类型必填取值范围默认值作用说明
min_radiusDOUBLE否有限数值1环形内圈的半径
max_radiusDOUBLE否有限数值8环形外圈的半径
limitINTEGER否整数0最多返回几个实体, 0 表示不限制
typeENTITY_TYPE否Bukkit EntityType 名``按实体类型筛选
include_playersBOOLEAN否true / falsetrue是否把玩家也算进候选目标
text
ring | send_message text="示例"

vertical_block ​

管道原点垂直偏移后的方块位置. 执行域 LOCATION_REGION

参数类型必填取值范围默认值作用说明
offsetINTEGER否整数1相对管道原点向上或向下偏移几格, 正数向上, 负数向下
text
vertical_block | send_message text="示例"

world_players ​

指定世界内的在线玩家. 执行域 SERVER_GLOBAL

参数类型必填取值范围默认值作用说明
worldSTRING否字符串``世界名, 留空就用管道原点所在的世界
limitINTEGER否整数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=5

filter 的位置参数必须用引号包裹; 谓词串内空格是 AND, || 是 OR, 前缀 ! 是 NOT, 圆括号可分组, 逗号是值列表. 完整规则与全部可用键见 filter

不想记谓词串语法时改用 where 写表达式, 它按 %target_*% 目标占位符逐目标求值:

text
nearby radius=16 limit=5 type=zombie | where %target_health_percent%<=50 | damage amount=5

where 只接受一个表达式, 条件变多时要层层叠加 &&, 可读性不如谓词串

命名选择器写法 (先配置后调用) ​

把同一套条件收进主配置的 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
字段类型必填默认值取值范围说明
sourcestring是—已注册的源段 id (不含 select 自身)引用的源段 id, 可用任意已注册源段 (含其他模块注册的)
argumentssection否{}标量值传给源段的参数, 写法与动作行参数一致, 值必须是标量
limitinteger否0非负整数; 0 表示不截断条件过滤后再截断的数量
conditionsection否{}条件组 (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: false

predicates 与 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_zombie

mythicmobs 由 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 ​

按条件逐个目标筛选: 条件不成立的目标从流里移除

参数类型必填默认值说明
conditionSTRING是—布尔条件

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 ​

按行内谓词逐个目标筛选, 不必先在主配置里定义选择器. 位置参数是一条引号包裹的谓词串:

参数类型必填默认值说明
conditionSTRING是—谓词串

谓词串的规则:

规则写法含义
并列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_typeentity_type=ZOMBIE,SKELETON实体类型
player / deadplayer=true, dead=false是否为玩家 / 是否已死亡
worldworld=world_nether世界名或 namespace:key
healthhealth<=10当前生命值
health_percenthealth_percent<=50生命值百分比 (0–100)
distancedistance<=8与管道原点的距离
level / foodlevel>=30玩家经验等级 / 饥饿值
gamemodegamemode!=creative玩家游戏模式
permissionpermission=emaki.vip权限节点, 列表按任一命中
scoreboard_tagscoreboard_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>_levelmythicmobs_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=100

filter 与 where 可以叠加, 按管道顺序依次筛选. 求值与 action.selectors 的条件组共用同一套设施; filter 固定按 invalid_as_failure: true 处理不可判定 (非玩家目标上的玩家专属条件, 未注册的生物系统, 无法求值的表达式都算不可判定), 也就是一遇到不可判定就排除该目标. 需要"不可判定时放行"时, 用 action.selectors 定义带 invalid_as_failure: false 的选择器

chance ​

概率没通过就结束管道

参数类型必填默认值说明
chancePERCENTAGE是—概率, 如 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=vault

limit ​

保留流里前 count 个目标, 保持原有顺序

参数类型必填默认值说明
countINTEGER是—保留几个目标

count 是位置参数

text
nearby radius=15 limit=50 | sort_by distance | limit 3 | damage amount=12

sort_by ​

按距离或生命值给目标流排序

参数类型必填默认值说明
keySTRING是—distance 或 health
orderSTRING否ascasc 或 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_sourceSTRING否""物品来源 (短横线简写)
amountINTEGER否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_item

after ​

延迟它之后的每一个段

参数类型必填默认值说明
delayDURATION是—延迟, 如 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 ​

按间隔重复它之后的每一个段

参数类型必填默认值说明
intervalDURATION否1t间隔, 如 20t, 1s
timesINTEGER否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.5

every 适合一条管道内的短促重复. 需要长时间运行, 能按 key 取消的循环, 用 start_task

distance_filter ​

只保留与管道原点距离在 [min, max] 内的目标. 线程需求 NEEDS_ENTITY_READ

参数类型必填取值范围默认值作用说明
minDOUBLE否有限数值0最小距离
maxDOUBLE否有限数值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

参数类型必填默认值说明
textSTRING是—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

参数类型必填默认值说明
textSTRING是—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

参数类型必填默认值说明
titleSTRING是—主标题 (MiniMessage 格式)
subtitleSTRING否""副标题 (MiniMessage 格式)
fade_inDURATION否10t淡入时间
stayDURATION否40t停留时间
fade_outDURATION否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

参数类型必填默认值说明
textSTRING是—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

参数类型必填默认值说明
soundSOUND是—声音键名. 可写 Bukkit Sound 枚举名或 minecraft: 风格键
volumeDOUBLE否1音量 (0 以上, 大于 1 时增加可听距离)
pitchDOUBLE否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

参数类型必填默认值说明
particleSTRING是—粒子键名 (Bukkit Particle 枚举名)
countINTEGER否1生成多少个粒子
offset_xDOUBLE否0粒子在 X 轴上的散开范围
offset_yDOUBLE否0粒子在 Y 轴上的散开范围
offset_zDOUBLE否0粒子在 Z 轴上的散开范围
extraDOUBLE否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 再次调用会更新已有血条

参数类型必填默认值说明
idSTRING是—Boss 血条 ID, 用于后续更新或隐藏
titleSTRING是—血条标题 (MiniMessage 格式)
progressDOUBLE否1进度, 取值 0 到 1
colorSTRING否purple血条颜色
styleSTRING否solid血条样式
flagsSTRING否""逗号分隔的血条标志
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

参数类型必填默认值说明
idSTRING是—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

参数类型必填取值范围默认值作用说明
titleSTRING是字符串—主标题内容
subtitleSTRING否字符串``副标题文本
fade_inINTEGER否整数10淡入的游戏刻数
stayINTEGER否整数40停留的游戏刻数
fade_outINTEGER否整数10淡出的游戏刻数
yaml
actions:
  - 'self | send_title_fade title=example'
  - 'self | send_title_fade title=example subtitle='

spawn_particle_at ​

在指定坐标生成粒子效果. 分类 visual, 目标要求 NONE, 执行域 LOCATION_REGION

参数类型必填取值范围默认值作用说明
particleSTRING是字符串—粒子类型
xDOUBLE否有限数值0相对目标位置的 X 轴偏移
yDOUBLE否有限数值0相对目标位置的 Y 轴偏移
zDOUBLE否有限数值0相对目标位置的 Z 轴偏移
countINTEGER否整数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. 不受任何治疗加成或减免影响

参数类型必填默认值说明
amountDOUBLE是—治疗量 (半心为单位, 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)

参数类型必填默认值说明
amountDOUBLE是—伤害量
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 失败

参数类型必填默认值说明
amountDOUBLE是—目标生命值

想让一个玩家死亡就用这个段设为 0, kill_entity 拒绝玩家目标

yaml
actions:
  - 'self | set_health amount=20'
  - 'self | set_health amount=1'
  - 'looking_at | set_health amount=0'

feed ​

恢复目标饱食度. 目标要求 REQUIRED_ENTITY

参数类型必填默认值说明
amountINTEGER否20恢复的饱食度点数
saturationDOUBLE否0恢复的饱和度

amount 为负会让该段以 INVALID_CONFIG 失败; saturation 为负按 0 处理. 恢复后饱食度与饱和度都不超过 20

yaml
actions:
  - 'self | feed'
  - 'self | feed amount=6 saturation=3'

take_food ​

扣除目标饱食度, 可选同时扣除饱和度. 目标要求 REQUIRED_ENTITY

参数类型必填默认值说明
amountINTEGER是—扣除的饱食度点数
saturationDOUBLE否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

参数类型必填默认值说明
durationDURATION否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

参数类型必填默认值说明
speedDOUBLE否1.5每 1/20 秒 (一个游戏刻) 飞行的格数
gravityDOUBLE否0.05每个游戏刻的下坠量
lifetimeINTEGER否60最长存活多少个游戏刻
hit_radiusDOUBLE否0.5命中判定的半径
pierceINTEGER否0额外穿透几个实体
homingBOOLEAN否false是否追踪当前目标
homing_strengthDOUBLE否0.1追踪时转向的强度
particleSTRING否flame飞行尾迹用哪种粒子
damageDOUBLE否0命中时造成的伤害, 0 表示不造成伤害
directionSTRING否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

参数类型必填取值范围默认值作用说明
amountDOUBLE是有限数值—要设置多少吸收生命值
yaml
actions:
  - 'self | set_absorption amount=1.0'

set_arrows_in_body ​

设置插在实体身上的箭矢数量. 分类 entity, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
countINTEGER是整数—插在身上的箭矢数量
yaml
actions:
  - 'self | set_arrows_in_body count=3'

set_collidable ​

控制生物之间是否互相碰撞. 分类 entity, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
collidableBOOLEAN是true / false—是否与其他生物互相碰撞
yaml
actions:
  - 'self | set_collidable collidable=true'

set_max_no_damage_ticks ​

设置实体无敌时间的上限 (无敌帧就是受伤后那段打不动的短暂免伤时间). 分类 entity, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
ticksINTEGER是整数—无敌时间的上限
yaml
actions:
  - 'self | set_max_no_damage_ticks ticks=3'

set_no_damage_ticks ​

设置实体的无敌时间时长. 分类 entity, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
ticksINTEGER是整数—无敌时间的游戏刻数
yaml
actions:
  - 'self | set_no_damage_ticks ticks=3'

set_remaining_air ​

设置实体剩余呼吸值. 分类 entity, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
ticksINTEGER是整数—还能在水下呼吸多少个游戏刻
yaml
actions:
  - 'self | set_remaining_air ticks=200'

实体元数据 ​

add_scoreboard_tag ​

为实体添加记分板标签. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
tagSTRING是字符串—要添加或移除的标签内容
yaml
actions:
  - 'self | add_scoreboard_tag tag=example'

remove_scoreboard_tag ​

移除实体的记分板标签. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
tagSTRING是字符串—要添加或移除的标签内容
yaml
actions:
  - 'self | remove_scoreboard_tag tag=example'

set_ai ​

控制生物的 AI 开关. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
enabledBOOLEAN是true / false—是否启用 AI
yaml
actions:
  - 'self | set_ai enabled=true'

set_can_pickup_items ​

控制生物是否能拾取掉落物. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
can_pickupBOOLEAN是true / false—能不能拾取掉落物
yaml
actions:
  - 'self | set_can_pickup_items can_pickup=true'

set_fire_ticks ​

设置实体着火时长 (单位是游戏刻, 负数表示熄灭). 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
ticksINTEGER是整数—着火的游戏刻数
yaml
actions:
  - 'self | set_fire_ticks ticks=100'

set_glowing ​

控制实体是否发光描边. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
glowingBOOLEAN是true / false—是否发光
yaml
actions:
  - 'self | set_glowing glowing=true'

set_gravity ​

控制实体是否受重力影响. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
gravityBOOLEAN是true / false—是否受重力
yaml
actions:
  - 'self | set_gravity gravity=true'

set_invulnerable ​

控制实体是否无敌. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
invulnerableBOOLEAN是true / false—是否无敌
yaml
actions:
  - 'self | set_invulnerable invulnerable=true'

set_name ​

设置实体的自定义名称 (MiniMessage). 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
nameSTRING是字符串—要设置的名字
yaml
actions:
  - 'self | set_name name=<gold>Boss</gold>'

set_name_visible ​

控制实体自定义名称是否常显. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
visibleBOOLEAN是true / false—是否常显
yaml
actions:
  - 'self | set_name_visible visible=true'

set_persistent ​

控制实体是否在区块卸载后保留. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
persistentBOOLEAN是true / false—是否保留
yaml
actions:
  - 'self | set_persistent persistent=true'

set_remove_when_far_away ​

控制生物距离过远时是否被移除. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
removeBOOLEAN是true / false—是否移除
yaml
actions:
  - 'self | set_remove_when_far_away remove=true'

set_silent ​

控制实体是否静音. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
silentBOOLEAN是true / false—是否静音
yaml
actions:
  - 'self | set_silent silent=true'

set_visible_by_default ​

控制实体默认是否对所有玩家可见. 分类 meta, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
visibleBOOLEAN是true / false—是否默认可见
yaml
actions:
  - 'self | set_visible_by_default visible=true'

移动与速度 ​

add_velocity ​

给实体叠加速度向量 (击退/弹射). 分类 movement, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
xDOUBLE是有限数值—叠加到 X 轴方向的速度
yDOUBLE是有限数值—叠加到 Y 轴方向的速度
zDOUBLE是有限数值—叠加到 Z 轴方向的速度
yaml
actions:
  - 'self | add_velocity x=1.0 y=1.0 z=1.0'

knockback ​

把目标从施法者方向推开. 分类 movement, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
strengthDOUBLE否有限数值1推开对方的力度
verticalDOUBLE否有限数值0.4向上抬起的力度
yaml
actions:
  - 'self | knockback'
  - 'self | knockback strength=1'

set_rotation ​

设置实体朝向 (yaw/pitch). 分类 movement, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
yawDOUBLE是有限数值—水平朝向的角度
pitchDOUBLE是有限数值—俯仰角度
yaml
actions:
  - 'self | set_rotation yaw=1.0 pitch=1.0'

set_velocity ​

设置实体速度向量. 分类 movement, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
xDOUBLE是有限数值—X 轴方向的速度
yDOUBLE是有限数值—Y 轴方向的速度
zDOUBLE是有限数值—Z 轴方向的速度
yaml
actions:
  - 'self | set_velocity x=1.0 y=1.0 z=1.0'

药水效果 ​

give_potion_effect ​

给目标添加药水效果. 目标要求 REQUIRED_ENTITY

参数类型必填默认值说明
typeSTRING是—药水效果类型. 可写 speed, minecraft:strength 等
levelINTEGER是—效果等级, 从 1 起算. 1 对应 Bukkit amplifier 0 (游戏内 I 级)
durationDURATION是—持续时间. 如 100t, 5s, 10000ms
ambientBOOLEAN否false是否为环境效果 (粒子更稀疏, 更透明)
particlesBOOLEAN否true是否显示粒子
iconBOOLEAN否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

参数类型必填默认值说明
typeSTRING是—药水效果类型
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, hand
  • offhand, off_hand
  • helmet, 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_sourceSTRING否""物品来源 (短横线简写)
amountINTEGER否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

参数类型必填默认值说明
slotSTRING否mainhand要操作的背包槽位
item_sourceSTRING否""物品来源 (短横线简写)
amountINTEGER否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

参数类型必填默认值说明
slotSTRING是—要操作的背包槽位
item_sourceSTRING否""期望的物品来源. 指定后只有匹配时才清空, 不匹配则跳过
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_sourceSTRING否""期望扣除的物品来源
amountINTEGER否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_sourceSTRING否""物品来源 (短横线简写)
amountINTEGER否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

参数类型必填默认值说明
slotSTRING否mainhand要操作的背包槽位
amountINTEGER否0修复的耐久点数; 小于等于 0 表示完全修复
yaml
actions:
  - 'self | repair_item'
  - 'self | repair_item slot=chestplate amount=50'

damage_item ​

增加目标槽位中物品的损耗. 目标要求 REQUIRED_ENTITY

参数类型必填默认值说明
slotSTRING否mainhand要操作的背包槽位
amountINTEGER否1增加的损耗点数
delete_itemBOOLEAN否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

参数类型必填取值范围默认值作用说明
percentINTEGER是0 至 100—经验条百分比 0-100
yaml
actions:
  - 'self | set_exp_to_level percent=3'

set_fly_speed ​

设置玩家飞行速度. 分类 player, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
speedDOUBLE是-1.0 至 1.0—飞行速度, 范围 -1.0 至 1.0
yaml
actions:
  - 'self | set_fly_speed speed=1.0'

set_gamemode ​

设置玩家游戏模式. 分类 player, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
gamemodeSTRING是survival / creative / adventure / spectator—survival / creative / adventure / spectator
yaml
actions:
  - 'self | set_gamemode gamemode=creative'

set_item_cooldown ​

为玩家的指定材质物品设置冷却. 分类 player, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
materialMATERIAL是Bukkit Material 名—物品的材质名
secondsINTEGER是整数—冷却多少秒
yaml
actions:
  - 'self | set_item_cooldown material=golden_apple seconds=60'

set_level ​

直接设置玩家经验等级. 分类 player, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
levelINTEGER是整数—经验等级
yaml
actions:
  - 'self | set_level level=3'

set_saturation ​

设置玩家饱和度. 分类 player, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
valueDOUBLE是有限数值—要设置的饱和度
yaml
actions:
  - 'self | set_saturation value=1.0'

set_walk_speed ​

设置玩家行走速度. 分类 player, 目标要求 REQUIRED_ENTITY, 执行域 CONTEXT_ENTITY

参数类型必填取值范围默认值作用说明
speedDOUBLE是-1.0 至 1.0—行走速度, 范围 -1.0 至 1.0
yaml
actions:
  - 'self | set_walk_speed speed=1.0'

方块与世界 ​

place_block ​

在目标位置放置物品来源对应的方块. 目标要求 REQUIRED_ANY

参数类型必填默认值说明
item_sourceSTRING否""要放置的方块来自哪个物品来源

支持原版方块以及 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

参数类型必填默认值说明
materialSTRING否""要设置的方块材质名
block_dataSTRING否""Bukkit BlockData 字符串
apply_physicsBOOLEAN否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_itemsBOOLEAN否false是否掉落方块物品
apply_physicsBOOLEAN否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

参数类型必填默认值说明
powerDOUBLE否0爆炸威力
fireBOOLEAN否false是否引燃
break_blocksBOOLEAN否false是否破坏方块

默认威力为 0, 不引燃, 不破坏方块, 也就是只有视听效果, 需要真实破坏时要显式打开

yaml
actions:
  # 纯特效爆炸
  - 'self | explosion power=2'
  # 会破坏方块的爆炸
  - 'looking_at range=15 | explosion power=4 fire=true break_blocks=true'

spawn_entity ​

在目标位置生成实体. 目标要求 REQUIRED_ANY

参数类型必填默认值说明
typeENTITY_TYPE是—实体类型
countINTEGER否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

参数类型必填取值范围默认值作用说明
difficultySTRING是peaceful / easy / normal / hard—难度: peaceful / easy / normal / hard
yaml
actions:
  - 'set_difficulty difficulty=normal'

set_game_rule ​

设置世界的原版游戏规则. 分类 world, 目标要求 NONE, 执行域 SERVER_GLOBAL

参数类型必填取值范围默认值作用说明
ruleSTRING是字符串—游戏规则名
valueSTRING是按规则类型为 true / false 或整数—规则要设成什么值
yaml
actions:
  - 'set_game_rule rule=doDaylightCycle value=false'

set_weather ​

设置世界天气. 分类 world, 目标要求 NONE, 执行域 SERVER_GLOBAL

参数类型必填取值范围默认值作用说明
weatherSTRING是clear / rain / thunder—天气: clear / rain / thunder
durationINTEGER否整数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

参数类型必填取值范围默认值作用说明
timeSTRING是tick 数或 day / night—时间, 可填游戏刻数或 day/night
yaml
actions:
  - 'set_world_time time=day'

传送 ​

teleport ​

把目标传送到指定坐标. 目标要求 REQUIRED_ENTITY

参数类型必填默认值说明
worldSTRING否""目标世界名. 空则使用目标当前世界
xSTRING否~X 坐标. 支持 ~ 相对当前坐标 (如 ~5 表示 X+5)
ySTRING否~Y 坐标. 支持 ~ 相对坐标
zSTRING否~Z 坐标. 支持 ~ 相对坐标
yawDOUBLE否目标当前朝向偏航角 (水平朝向, 0–360). 不填就保留当前朝向
pitchDOUBLE否目标当前朝向俯仰角 (垂直朝向, -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'

经济 ​

三个经济段共用同一组参数

参数类型必填默认值说明
amountDOUBLE是—金额
providerSTRING否auto经济提供者. 可选: auto, vault, excellenteconomy
currencySTRING否""货币类型. 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

参数类型必填默认值说明
amountINTEGER是—经验点数或等级数
modeSTRING否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'

命令 ​

三个命令段共用同一个参数. 命令值会自动去掉开头的 /, 但为了可读性建议配置里不要写

参数类型必填默认值说明
commandSTRING是—要执行的命令 (不含开头 /)

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

参数类型必填默认值说明
sequenceSTRING是—要重复执行的序列名
timesINTEGER否1一共执行几次
intervalDURATION否20t每隔多久执行一次
initial_delayDURATION否0t首次执行前的延迟
keySTRING否""任务 key, 用于后续取消
on_conflictSTRING否replacekey 冲突策略: replace, ignore, allow_duplicate
stop_when_offlineBOOLEAN否true玩家离线时停止
stop_when_deadBOOLEAN否false玩家死亡时停止
stop_whenSTRING否""条件成立时停止
stop_on_failureBOOLEAN否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

参数类型必填默认值说明
keySTRING是—要取消的任务 key
matchSTRING否exact匹配方式: exact 或 prefix

什么都没取消到会被当成跳过而不是失败: 配置里经常要取消一个可能并没在跑的任务, 比如在一个两种情况都会触发的事件上清理增益循环, 把这种情况当错误会让日志被正确的配置刷满

yaml
actions:
  - 'stop_task key=burn_%player_name%'
  - 'stop_task key=buff_ match=prefix'

脚本 ​

三个 js_* 段执行 GraalJS 脚本. 它们共用同一组参数, 区别只在目标要求与线程域: 选错会导致脚本在错误的线程上碰 Bukkit API

参数类型必填默认值说明
codeSTRING是—JavaScript 代码
timeoutINTEGER否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 内置段

子插件注册的段已拆分到对应插件自己的动作页:

来源模块文档
EmakiAttributeAttribute CoreLib 动作
EmakiForgeForge CoreLib 动作
EmakiStrengthenStrengthen CoreLib 动作
EmakiCookingCooking CoreLib 动作
EmakiGemGem CoreLib 动作
EmakiLevelLevel CoreLib 动作
EmakiSkillsSkills CoreLib 动作
EmakiItemItem CoreLib 动作
EmakiCodexCodex CoreLib 动作
EmakiStorageStorage CoreLib 动作

EmakiMobs 注册的 4 个 source 与 4 个 action 暂时没有独立动作页, 只在段 ID 表 里列出 ID 与用途

如果一个段来自某个业务插件, 它的参数, 上下文变量和执行时机以该插件文档为准

第三方插件注册段 ​

外部插件开发者可以只依赖 emaki-corelib-api, 按角色调用对应的注册方法把自定义段注册进 CoreLib 的共享注册表:

  • EmakiCoreLibApi.registerActionStage(plugin, stage) — 注册 action
  • EmakiCoreLibApi.registerActionSource(plugin, source) — 注册 source
  • EmakiCoreLibApi.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 都会执行. 旧写法要在两行上各写一次概率, 两次独立摇点, 结果可能出现给了钱却没提示; 现在一条管道摇一次点, 后续段共享这次结果