分解规则
分解规则用于判断输入物品是否可以分解,并定义匹配后生成的产物与执行的命令。
规则文件位于插件数据目录的 rule 文件夹。可以在该目录及其子目录中创建 .yml 文件,插件重载时会递归读取全部规则文件,并按文件完整路径排序后加载。
每个规则文件的最外层直接填写规则 ID。规则 ID 在全部规则文件中必须唯一。出现重复 ID 或其它阻止加载的问题时,本次重载不会替换当前正在运行的规则。
完整规则示例
yaml
'分解规则示例':
condition:
- "name('&a额外规则示例') || name('额外规则', contains)"
- "lore('武器', contains) || lore('防具', contains)"
- "!lore('已绑定', contains)"
- "material('276:0')"
commands:
- '[console]say %player_name% 触发了分解规则示例'
- '[op]say %player_name% 触发了分解规则示例'
- 'say %player_name% 触发了分解规则示例'
give-item: true
result:
- 'MythicMobs@分解产物1 1-2 0.5 {[console]say %player_name% 获得了分解产物1}'
- 'MythicMobs@分解产物2 2 1'规则字段
每条规则只允许使用以下字段。填写其它字段会导致本次重载失败。
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
condition | 字符串列表 | 无 | 物品与玩家需要满足的条件,必须至少填写一行 |
commands | 字符串列表 | 空列表 | 当前规则成功执行后依次执行的规则命令 |
give-item | 布尔值 | true | 是否生成并发放 result 中的产物 |
result | 字符串列表 | 空列表 | 当前规则的产物、数量、概率与产物命令 |
当 give-item 为 false 时,插件不会解析、生成或发放该规则的 result 产物,但仍会执行 commands。
如果 give-item 为 true,但没有配置任何 result,插件会输出警告,不会阻止规则加载。这类规则仍可执行 commands。
规则匹配机制
全局条件
主配置中的 global-condition 会在所有规则之前判断。物品只有先满足全部全局条件,才会继续匹配 rule 文件中的规则。
全局条件与规则的 condition 使用相同语法。全局条件不满足时,该物品不会匹配任何分解规则。
多规则叠加
一个物品可以同时匹配多条规则。插件会按规则加载顺序收集全部匹配规则,不会在匹配到第一条规则后停止。
执行单个物品的分解时:
- 所有匹配规则中
give-item: true的产物都会分别参与概率判断。 - 所有匹配规则的
commands都会加入规则命令列表。 - 界面预览会汇总所有匹配规则中能够创建的产物。
give-item: false的规则不会提供产物预览,但其规则命令仍会执行。- 任意实际抽中的产物无法创建时,本次单个物品的分解会失败,输入物品不会被扣除。
界面只预览输入区域内第一个可分解物品的产物,最多显示预览区域能够容纳的前 18 项产物。
条件组合
| 写法 | 逻辑 |
|---|---|
| 同一行顶层使用 ` | |
多行 condition | AND,每一行都必须成立 |
表达式前添加 ! | 对当前表达式结果取反 |
连续添加多个 ! | 每个 ! 依次取反,偶数个等于不取反 |
yaml
condition:
# 名称包含“武器”或“防具”时,本行成立
- "name('武器', contains) || name('防具', contains)"
# Lore不存在“已绑定”时,本行成立
- "!lore('已绑定', contains)"
# 玩家拥有指定权限时,本行成立
- "permission('lydecomposition.use')"条件表达式建议使用双引号包裹,函数中的文本参数使用单引号包裹。需要在字符串参数中表示单引号时,可以连续填写两个单引号。
yaml
condition:
- "name('冒险者''的长剑')"函数名与选项匹配时不区分英文大小写,建议统一使用文档中的写法。
条件函数
插件支持以下条件函数:
| 函数 | 用途 |
|---|---|
hasname() | 判断物品是否存在自定义名称 |
name() | 匹配物品自定义名称 |
haslore() | 判断物品是否存在 Lore |
lore() | 匹配物品任意一行 Lore |
material() | 匹配物品材质、数字 ID 或 Data |
permission() | 判断玩家是否拥有指定权限 |
papi() | 替换 PlaceholderAPI 变量并判断表达式 |
hasnbt() | 判断物品是否存在指定 NBT 节点 |
nbt() | 匹配指定 NBT 节点的值 |
名称条件
判断名称是否存在
yaml
condition:
- "hasname()"取反后表示物品不能存在自定义名称:
yaml
condition:
- "!hasname()"hasname() 不接受参数。
匹配名称内容
name() 的第一个参数是目标名称,后续可以填写一种匹配方式和 ignoreColor。
| 写法 | 说明 |
|---|---|
name('&a普通装备') | 完整匹配名称,颜色参与比较 |
name('&a普通装备', equals) | 显式使用完整匹配 |
name('普通装备', contains) | 名称包含指定内容 |
name('&a', startsWith) | 名称以指定内容开头 |
name('装备', endsWith) | 名称以指定内容结尾 |
name('普通装备', ignoreColor) | 忽略颜色后完整匹配 |
name('普通', contains, ignoreColor) | 忽略颜色后进行包含匹配 |
equals 是默认匹配方式。未填写 ignoreColor 时,颜色代码会参与比较,条件中的 & 颜色代码会先转换为服务端颜色符号。
yaml
condition:
- "name('&a普通装备')"
- "!name('绑定', contains)"物品没有自定义名称时,name() 返回不匹配。
Lore 条件
判断 Lore 是否存在
yaml
condition:
- "haslore()"取反后表示物品不能存在 Lore:
yaml
condition:
- "!haslore()"haslore() 不接受参数。
匹配 Lore 内容
lore() 会逐行检查物品 Lore,只要任意一行符合要求,当前函数就会成立。
| 写法 | 说明 |
|---|---|
lore('&7品质: &a一般') | 完整匹配任意一行 Lore,颜色参与比较 |
lore('&7品质: &a一般', equals) | 显式完整匹配任意一行 Lore |
lore('品质:', contains) | 任意一行 Lore 包含指定内容 |
lore('&7', startsWith) | 任意一行 Lore 以指定内容开头 |
lore('装备', endsWith) | 任意一行 Lore 以指定内容结尾 |
lore('品质: 一般', ignoreColor) | 忽略颜色后完整匹配任意一行 |
lore('品质', contains, ignoreColor) | 忽略颜色后进行包含匹配 |
yaml
condition:
- "lore('&7品质: &a一般')"
- "!lore('已绑定', contains)"!lore('已绑定', contains) 表示没有任何一行 Lore 可以包含“已绑定”。物品没有 Lore 时,原始 lore() 结果为不匹配,取反后结果为匹配。
材质条件
material() 只接受一个单引号字符串参数,可以使用数字 ID、数字 ID 与 Data,或材质枚举名称。
| 写法 | 说明 |
|---|---|
material('276') | 匹配数字 ID 为 276 的物品,不检查 Data |
material('276:0') | 同时匹配数字 ID 与 Data |
material('DIAMOND_SWORD') | 匹配材质枚举名称 |
material('minecraft:diamond_sword') | 去除 minecraft: 命名空间后匹配材质名称 |
yaml
condition:
- "material('DIAMOND_SWORD')"材质名称匹配不区分英文大小写。数字 ID 与 Data 主要用于仍使用旧版物品体系的服务端配置。
权限条件
permission() 用于判断执行分解的玩家是否拥有指定权限节点。它只读取服务端当前的权限结果,不代表插件内置了同名权限。
yaml
condition:
- "permission('lydecomposition.use')"取反后可以要求玩家没有某个权限:
yaml
condition:
- "!permission('lydecomposition.bypass')"permission() 只接受一个单引号字符串参数。
PlaceholderAPI 条件
papi() 会先替换括号内的 PlaceholderAPI 变量,再判断替换后的完整表达式。
使用 papi() 条件时必须安装并启用 PlaceholderAPI,否则包含该条件的全局条件、规则或额外按钮会导致本次重载失败。
比较与逻辑运算符
| 运算符 | 说明 |
|---|---|
== | 相等 |
!= | 不相等 |
> | 大于,仅支持数字 |
>= | 大于等于,仅支持数字 |
< | 小于,仅支持数字 |
<= | 小于等于,仅支持数字 |
&& | AND,同组表达式全部成立 |
| ` |
papi() 内部先按 || 划分 OR 组,再按 && 判断每个 OR 组中的表达式,因此 && 优先于 ||。
当 == 或 != 两侧都能解析为数字时,插件按数字比较;否则按区分大小写的文本进行完整比较。文本可以使用单引号包裹。
如果表达式中没有比较运算符,只有文本 true 会被判断为成立,英文大小写不受限制。
yaml
condition:
- "papi(%player_level% >= 5)"
- "papi(%player_level% >= 5 && %player_level% <= 10)"
- "papi(%player_class% == '战士')"
- "papi(%player_class% != '法师')"
- "papi(%player_class% == '战士' || %player_class% == '骑士')"
- "papi(%some_boolean_placeholder%)"PlaceholderAPI 替换后的内容直接参与表达式判断。对应变量必须返回能够与目标值正确比较的文本。
NBT 条件
NBT 键使用点号表示节点路径。例如 lyfj.a.b.c 表示根 NBT 中 lyfj 节点下的 a.b.c 节点。
使用 hasnbt() 或 nbt() 时,当前服务端版本必须存在可用的 NBT 适配器,否则包含 NBT 条件的配置会导致本次重载失败。
项目中提供 NBT 适配的服务端版本包括:
- 1.7.10
- 1.8.8
- 1.11.2
- 1.12.2
- 1.13.2
- 1.14.4
- 1.15.2
- 1.16.5
- 1.17.1
- 1.18.2
- 1.19.2
- 1.19.4
- 1.20.1
- 1.20.2
- 1.20.3
判断 NBT 节点是否存在
yaml
condition:
- "hasnbt('lyfj.a.b.c')"取反后表示该节点不能存在:
yaml
condition:
- "!hasnbt('lyfj.a.b.c')"hasnbt() 只接受一个单引号字符串参数。
匹配 NBT 值
nbt() 的 NBT 节点必须存在,否则条件不会成立。读取到的最终节点值会以字符串形式参与比较。
| 写法 | 说明 |
|---|---|
nbt('lyfj.a.b.c', 'sword') | 完整匹配字符串,默认使用 equals |
nbt('lyfj.attribute.level', 5) | 将节点值作为字符串与数字文本 5 完整匹配 |
nbt('lyfj.a.b.c', 'sword', equals) | 显式完整匹配 |
nbt('lyfj.a.b.c', 'bound', !=) | 节点值不等于指定内容 |
nbt('lyfj.a.b.c', 'swo', contains) | 节点值包含指定内容 |
nbt('lyfj.a.b.c', 'sword', startsWith) | 节点值以指定内容开头 |
nbt('lyfj.a.b.c', 'sword', endsWith) | 节点值以指定内容结尾 |
nbt('lyfj.a.b.c', 'SWORD', equals, ignoreCase) | 忽略英文大小写完整匹配 |
nbt('lyfj.attribute.level', 5, >) | 节点数值大于 5 |
nbt('lyfj.attribute.level', 5, >=) | 节点数值大于等于 5 |
nbt('lyfj.attribute.level', 10, <) | 节点数值小于 10 |
nbt('lyfj.attribute.level', 10, <=) | 节点数值小于等于 10 |
>、>=、<、<= 只有在实际值和目标值都能转换为数字时才会成立。
字符串目标值必须使用单引号包裹。不加引号的目标值必须是有效数字。
yaml
condition:
- "hasnbt('lyfj.attribute.level')"
- "nbt('lyfj.attribute.level', 5, >=)"
- "nbt('lyfj.attribute.type', 'SWORD', equals, ignoreCase)"分解产物
基础格式
每条产物至少包含物品标识、数量和概率:
text
物品库@物品ID 数量 概率| 部分 | 说明 |
|---|---|
物品库@物品ID | 指定产物来源物品库及其内部物品 ID |
数量 | 正整数固定数量,或 最小值-最大值 |
概率 | 0 到 1 之间的出现概率 |
yaml
result:
- 'MythicMobs@分解产物1 1-2 0.5'
- 'MythicMobs@分解产物2 2 1'上例中:
分解产物1有0.5的概率生成,数量在1到2之间随机。分解产物2必定生成,固定数量为2。- 每条产物独立进行概率判断。
- 概率为
0时不会生成,概率为1时必定生成。
数量范围的最小值必须大于 0,最大值必须大于等于最小值。
产物命令
可以从第四段开始为产物追加命令。每条命令必须分别放在一组 {} 中:
text
物品库@物品ID 数量 概率 {命令1} {命令2}yaml
result:
- 'MythicMobs@分解产物1 1-2 0.5 {[console]say %player_name% 获得了分解产物1} {say 产物已经发放}'产物命令具有以下规则:
- 只有当前产物通过概率判断并完成发放后才会执行。
- 同一产物的多条命令按填写顺序执行。
- 支持
[console]、[op]和无前缀玩家身份。 - 支持 PlaceholderAPI 变量替换。
- 单条产物未抽中时,其产物命令不会执行。
- 产物命令执行异常会记录为警告,不会撤回已经发放的产物。
产物命令与规则级 commands 的触发范围不同。产物命令只属于当前抽中的产物,规则命令属于整条匹配规则。
可用物品库前缀
规则产物支持以下物品库名称:
| 前缀 | 对应物品库 |
|---|---|
MythicMobs | MythicMobs 4 或 MythicMobs 5 |
LyItemSave | LyItemSave 提供的 MythicMobs 4 兼容接口 |
AzureFlow | AzureFlow |
NeonFlash | NeonFlash |
SX-Item | SX-Item |
NeigeItems | NeigeItems |
OriginAttribute | OriginAttribute |
MythicMobs 与 LyItemSave 两个名称互通。当 MythicMobs 或 LyItemSave 任意一个可用时,这两个前缀都会指向当前实际连接的兼容物品库。
如果 MythicMobs 已启用,插件会根据其版本选择 MythicMobs 4 或 MythicMobs 5 适配器。如果 MythicMobs 不可用但 LyItemSave 已启用,则使用 LyItemSave 提供的 MythicMobs 4 兼容接口。
物品库名称查找不区分英文大小写。
如果产物 ID 没有填写 物品库@ 前缀,插件会使用主配置中的 item-provider。当 item-provider 为空或缺失时,默认使用 MythicMobs。
yaml
result:
# 使用主配置指定的默认物品库
- '分解材料 1 1'
# 明确指定物品库
- 'NeigeItems@分解材料 1-3 0.25'规则重载时会检查产物对应的物品库适配器是否可用。物品库未安装、未启用或初始化失败时,本次重载不会替换当前运行数据。
物品库可用不代表内部物品 ID 一定存在。产物 ID 无法创建时,预览会跳过或报告该产物,实际抽中该产物时分解执行会失败。
产物发放顺序
产物生成后,会按照主配置 delivery-order 中的顺序依次尝试发放:
| 配置值 | 发放目标 |
|---|---|
inventory | 玩家背包 |
LyLootsWarehouse | LyLootsWareHouse 战利品仓库 |
LyWarehouse | LyWarehouse |
SpaceRingPlus | YeeCore 提供的灵魂空间 |
StarStorage | StarStorage |
当前目标不能完全接收时,剩余数量会继续尝试下一个目标。未安装或未启用的外部仓库无法接收物品。全部目标处理后仍有剩余时,剩余产物会掉落在玩家位置。
delivery-order 留空时仅尝试玩家背包,背包无法容纳的剩余产物会掉落在玩家位置。
产物的具体入库顺序由主配置管理,不需要写入规则文件。
规则命令
commands 中的规则命令会在全部产物生成和发放流程后,按照规则加载顺序与列表配置顺序执行。
| 格式 | 执行身份 |
|---|---|
[console]命令 | 控制台 |
[op]命令 | 玩家临时获得 OP 后执行,完成后恢复原状态 |
命令 | 玩家 |
yaml
commands:
- '[console]say %player_name% 完成了一次分解'
- '[op]say %player_name% 触发了临时OP命令'
- 'say 我完成了一次分解'命令支持 PlaceholderAPI 变量替换。未安装或未启用 PlaceholderAPI 时,非 papi() 条件中的命令仍可执行,但其中的变量会保留原文。
[console] 和 [op] 前缀匹配时不区分英文大小写。命令中不要填写开头的 /。
[op] 会临时修改玩家的 OP 状态,并在执行完成后恢复玩家原来的状态。能够使用控制台或普通玩家身份完成时,不建议使用该方式。
单条规则命令执行异常会作为警告记录,不会撤回已经发放的产物,也不会将成功结果改为失败。
执行顺序
单个输入物品匹配成功后的主要执行顺序如下:
- 收集全部匹配规则。
- 触发分解前置事件,外部插件可以取消本次分解。
- 对所有启用产物的匹配规则逐条进行概率判断并生成产物。
- 按
delivery-order发放每项实际生成的产物。 - 每项产物发放后执行该产物配置的
{命令}。 - 全部产物处理后执行所有匹配规则的
commands。 - 触发分解完成事件。
- 调用方确认执行成功后扣除一个输入物品。
如果产物配置或物品创建在生成阶段失败,本次执行不会成功,界面不会扣除当前输入物品。产物发放开始后的命令异常只会记录警告,不会回滚已经完成的发放。
纯命令规则
如果规则只需要执行命令,不需要发放物品,可以关闭 give-item 并省略 result:
yaml
'纯命令规则':
condition:
- "name('&e特殊物品')"
give-item: false
commands:
- '[console]say %player_name% 分解了特殊物品'condition 仍然必须至少填写一行。物品匹配成功后,这类规则可以与其它产物规则叠加执行。
旧版规则转换说明
插件包含从旧版 LyDecompositionReload 配置转换为当前规则格式的功能。转换来源包括:
plugins/LyDecompositionReload/config.yml中的decomposition-set。plugins/LyDecompositionReload/extra目录及子目录中的.yml文件。
转换结果会写入当前插件的:
text
rule/旧版转换/旧版配置转换.yml转换时会进行以下处理:
- 转换后的规则 ID 添加
旧版_前缀。 - 规则 ID 中的英文点
.会替换为全角点.,避免被 YAML 配置路径拆分。 - 旧版无物品库前缀的产物会补充
MythicMobs@。 - 旧版百分比概率会转换为
0到1的概率。 - 旧版
%p玩家变量会转换为%player_name%。 - 旧版
[player]规则命令会转换为无前缀玩家命令。 - 旧版无执行身份前缀的产物命令会按旧行为转换为
[console]命令。 - 覆盖已有转换文件前会创建固定
.bak备份。 - 转换文件明确使用 UTF-8 无 BOM 写入。
旧版转换生成的规则仍需要通过当前规则的完整校验后才能生效。
严格校验
插件重载时会校验主配置、全局条件、规则、产物、额外按钮和外部适配器。存在阻止加载的错误时,本次重载不会替换当前正在运行的数据。
以下问题会导致规则重载失败:
- YAML 格式错误或文件无法读取。
- 不同文件中存在重复的规则 ID。
- 规则包含
condition、give-item、commands、result之外的字段。 - 规则没有至少一行
condition。 - 条件函数名称、括号、单引号或基础格式错误。
- 使用
papi(),但 PlaceholderAPI 未安装或未启用。 - 使用 NBT 条件,但当前服务端没有可用的 NBT 适配器。
result的物品标识、数量、概率或产物命令格式无效。- 产物使用的物品库未安装、未启用或适配器初始化失败。
以下情况只会产生警告或运行时结果:
give-item: true但没有配置result,重载时只输出警告。- 物品库已连接但具体产物 ID 不存在,通常在预览或实际生成产物时发现。
- 产物最终无法进入任何配置目标,剩余物品会掉落在玩家位置并记录警告。
- 产物命令或规则命令执行异常,会记录警告,不会回滚已经完成的产物发放。
重载失败后,需要根据控制台输出修正规则,再执行插件重载指令。旧的运行数据会继续保留,不会被本次失败的配置覆盖。