物品定义与套装
EmakiItem 的物品文件通常位于 items/*.yml,套装文件位于 sets/*.yml。物品定义决定一个稳定物品 ID 如何生成 ItemStack,套装定义决定多个装备同时穿戴时如何提供额外效果。
物品定义字段
完整字段参考
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
id | string | 是 | — | 物品唯一 ID。其他模块引用时使用。 |
item | object | 是 | — | 共享基础物品定义,包含 source、amount、components。 |
name_actions | list/object | 否 | — | 在基础组件生成后处理名称的动作链。 |
lore_actions | list/object | 否 | — | 在基础组件生成后处理 Lore 的动作链。 |
effects | list | 否 | — | 变量、EmakiAttribute 属性和 EmakiSkills 技能等业务效果。 |
equip_slot | string | 否 | all | 业务属性/技能生效的装备槽:all、hand、main_hand、off_hand、helmet、chestplate、leggings、boots。不支持的值会回退为 all 并输出警告。 |
set | object | 否 | — | 套装信息。 |
condition | object | 否 | — | 装备条件配置。 |
repair | object | 否 | — | 修复配置。 |
update | object | 否 | — | 自动更新配置。 |
actions | object | 否 | — | 触发动作配置。 |
旧顶层 material、display_name、item_name、lore、components 和 amount 仍可读取并转换到共享 definition,但新配置、默认资源和 JavaScript 示例不再写这些字段。新旧同时存在时以嵌套 item 为准。
旧版物品定义自动迁移
items/*.{yml,yaml} 会在 definition 正式解析前执行一次 configured-item 迁移。它只转换 YAML 节点,不创建 Bukkit ItemStack,因此迁移结果不依赖玩家、世界或第三方物品插件运行状态。
主要映射包括:
| 旧字段 | 新字段 / 行为 |
|---|---|
material | 规范化为小写、下划线形式并写入 item.source,例如 DIAMOND_SWORD → minecraft-diamond_sword。 |
source、item_source、item_sources、标量 item | 取可用来源写入 item.source;列表来源保留运行时转换器的首个来源优先语义。 |
amount | 写入 item.amount。 |
display_name、item_name、lore | 写入 item.components.custom_name / item.components.item_name / item.components.lore。 |
custom_model_data | 写入 item.components.custom_model_data;在 1.21.5+ 配置中支持 floats 等结构。 |
enchantments | 写入 item.components.enchantments 的附魔 ID → 等级直接映射;旧隐藏附魔标记同步到 tooltip_display.hidden_components。 |
item_flags、hidden_components | 映射到 1.21.5+ item.components.tooltip_display。 |
unbreakable 等旧组件字段 | 转换为对应 namespaced component 结构,并保留现代组件优先规则。 |
安全边界:
- 现代
item.source、item.amount与已有item.components永远优先,旧字段只填补缺失值。 - 出现
components.raw或item.components.raw时跳过整个候选节点,不做部分迁移。 effects、equip_slot、set、condition、repair、update、actions等业务字段保持不变。- 每批修改先备份原文到
plugins/EmakiItem/migration-backups/configured-item-format/<时间戳>/,保留相对于items/的目录层级。 - 新 YAML 先写入同目录临时文件并重新解析校验;只有校验成功才替换原文件。失败时保留或恢复原文件,并拒绝使用未经验证的迁移结果。
- 迁移是幂等的;成功迁移后的文件再次启动不会重复改写。
迁移不读取 EmakiItem、CoreLib、配置或语言文件中的版本值,也不依赖某个历史版本号判断是否执行;只要候选节点仍包含旧字段,就会按相同规则处理。转换规则由 EmakiItem 自身持有,只在 definition 加载入口调用 CoreLib 的通用迁移执行器,兼容期结束后可移除该入口,而不改变共享 ConfiguredItemDefinition 或 canonical parser。
效果系统(effects)
物品效果统一使用 effects 列表,通过 type 字段区分类型:
| type | 说明 |
|---|---|
variables | 表达式引擎变量,用于 display_name 和 lore 中的占位符渲染。 |
ea_attribute | EmakiAttribute PDC 属性,写入物品 PDC。 |
es_skill | EmakiSkills 技能附加,装备时获得技能;payload 使用 es_skills 列表。 |
effects:
- type: "variables"
variables:
physical_attack: 12
physical_crit_rate: 5
- type: "ea_attribute"
ea_attributes:
physical_attack: 12.0
physical_crit_rate: 5.0
- type: "es_skill"
es_skills:
- "fireball"
- "flame_dash"
es_skill_triggers:
fireball: "right_click"es_skill 效果支持可选的 es_skill_triggers(也接受 skill_triggers),格式为 技能 ID: 触发器 ID。它写入装备强制触发器,使该技能在装备时由指定触发器释放,不占用玩家技能槽。
当前配置线不再使用 ea_attribute_meta;如果需要真实属性输出,请把属性值写入显式 ea_attributes。variables 只作为显示文本和占位符上下文,不会自动变成 Attribute PDC 属性。
技能 ID 与技能触发器写入物品 PDC 的过程不检查 EmakiSkills 是否启用;相关键由独立协议模块统一持有。
item 与原版组件
item:
source: minecraft-netherite_sword
amount: 1
components:
custom_name: '<gradient:red:gold>%name%</gradient>'
lore:
- '<gray>攻击:%physical_attack%</gray>'
item_model: emaki:flame_blade
custom_model_data:
floats: [1001.0]
attribute_modifiers:
- type: minecraft:attack_damage
id: emakiitem:flame_blade/attack_damage
amount: 12.0
operation: add_value
slot: mainhand
rarity: rare
max_stack_size: 1
$unset:
- repairable
$reset:
- enchantmentscomponents 使用 Minecraft namespaced data component ID;未写命名空间时默认使用 minecraft:,例如 custom_name 等价于 minecraft:custom_name,显式的其他命名空间保持不变。该规则同样适用于 $unset / $reset 列表。map/list/scalar 直接按 JSON 等价结构写成 YAML;普通值表示 SET,$unset 删除组件,$reset 恢复材质原型默认值。文本组件允许 MiniMessage 字符串简写;极少数 JSON 无法无损表达的 NBT 可使用受控 {$snbt: '...'} 逃生口。
错误与版本策略:
- 未知组件 ID:配置错误,definition 不进入有效缓存。
- 当前版本支持但值非法:配置错误,definition 不进入有效缓存。
- 已知但高于服务器版本:跳过该组件并记录警告,其余组件继续处理。
- 第三方 ItemSource:保留来源身份、PDC 和未知组件,只应用当前 Paper 可安全传递的组件。
item.source 不限于 Bukkit Material,可使用 CoreLib 当前注册的所有 ItemSource。resolver 不存在、插件未安装或来源无法创建时,该 EmakiItem definition 会被拒绝缓存。最低支持 Paper 1.21.8+;组件目录与运行时 capability 共同决定当前服务器可用能力。
物品示例
基础武器
id: "beginner_blade"
item:
source: minecraft-iron_sword
components:
minecraft:custom_name: "<white>新手长剑</white>"
minecraft:lore:
- "<gray>一把稳定可靠的基础武器。</gray>"
- ""
- "<gray>攻击力:<white>+10</white></gray>"
minecraft:unbreakable: {}
minecraft:tooltip_display:
hidden_components:
- minecraft:unbreakable
effects:
- type: "ea_attribute"
ea_attributes:
physical_attack: 10.0
set:
id: "beginner_set"
piece: "weapon"带变量的高级装备
id: "flame_blade"
item:
source: minecraft-netherite_sword
components:
minecraft:custom_name: "<gradient:red:gold>%name%</gradient>"
minecraft:lore:
- "<dark_gray>━━━━━━━━━━━━━━━━━━</dark_gray>"
- "<red>⚔ 物理攻击:<white>+%physical_attack%</white></red>"
- "<yellow>✦ 暴击率:<white>+%physical_crit_rate%%</white></yellow>"
- "<dark_gray>━━━━━━━━━━━━━━━━━━</dark_gray>"
- "<gray>传说中由龙焰锻造的神兵。</gray>"
minecraft:item_model: "emaki:flame_blade"
minecraft:enchantment_glint_override: true
minecraft:rarity: "rare"
minecraft:max_stack_size: 1
effects:
- type: "variables"
variables:
name: "烈焰之刃"
physical_attack: 45
physical_crit_rate: 12
- type: "ea_attribute"
ea_attributes:
physical_attack: 45.0
physical_crit_rate: 0.12
- type: "es_skill"
es_skills:
- "flame_slash"
set:
id: "flame_set"
piece: "weapon"消耗品
id: "health_potion_large"
item:
source: minecraft-potion
amount: 1
components:
minecraft:custom_name: "<red>大型生命药水</red>"
minecraft:lore:
- "<gray>右键使用,恢复 50 点生命。</gray>"
- "<dark_gray>使用后消耗。</dark_gray>"
minecraft:max_stack_size: 16
minecraft:custom_model_data:
floats: [1001.0]
actions:
right_click:
- 'heal amount=50'
- 'playsound sound=minecraft:entity.generic.drink volume=1 pitch=1'
- 'clearitem slot=mainhand source=emakiitem-health_potion_large'
- 'sendmessage text="<green>恢复了 50 点生命。</green>"'actions 的 key 必须是触发器页列出的触发器名,例如 right_click、consume、attack、give。未列出的 key 不会被执行。
条件配置
物品可以配置装备条件,不满足时该物品对该玩家整体失效:
condition:
type: "all_of"
entries:
- "%player_level% >= 10"
- "%player_class% == 'warrior'"
required_count: 2
invalid_as_failure: true
on_pass:
actions:
- 'sendmessage text="<green>装备条件满足,属性已生效。</green>"'
on_fail:
message: "<red>你不满足装备条件!</red>"
actions:
- 'sendmessage text="<red>需要等级 10 以上的战士才能装备此武器。</red>"'| 字段 | 说明 |
|---|---|
entries | 条件表达式列表。也可写作 conditions。 |
type | 条件组合方式:all_of(全部满足)/ any_of(任一满足);默认 all_of。 |
required_count | 需要满足的最少条件数。 |
invalid_as_failure | 表达式解析失败时是否视为不满足。 |
on_pass.actions | 满足时执行的动作。 |
on_fail.message | 不满足时的提示消息。 |
on_fail.actions | 不满足时执行的动作。 |
门控范围
条件不满足时,以下内容全部不生效:
| 传递面 | 数据来源 |
|---|---|
| EA 属性 | Lore 词条与 PDC 属性两条来源同时失效 |
| 装备技能 | Lore 与 PDC 两条来源同时失效 |
| 套装属性 | emakiitem 与 emakiitem_set 两个 PDC 来源 |
| 触发器动作 | 该次触发被拦截 |
仍然生效、不受此条件门控的部分:EmakiGem 宝石、EmakiForge 锻造、 EmakiStrengthen 强化各自写入的 PDC 属性。它们由对应模块拥有, 不随宿主物品条件失效。
求值时机:触发器动作在每次触发执行前求值;属性与技能在每次装备收集时 按玩家实时求值,因此等级、职业等变化后立即生效,无需重新装备。 属性与技能的门控求值不发送 on_fail.message、不执行 on_pass/on_fail 动作,这些只在触发器路径产生。
属性与技能门控由 EmakiAttribute 承载,需要 EmakiAttribute 已启用; 仅安装 EmakiItem 时条件只门控触发器动作。
修复配置
物品耐久耗尽后可以通过材料或金币修复:
repair:
enabled: true
materials:
- item_sources:
- "minecraft-diamond"
amount: 1
restore: 250
economy:
enabled: true
restore: "100%"
currencies:
- provider: "vault"
currency_id: ""
base_cost: 100
cost_formula: "base_cost + missing_durability * 0.25"
display_name: "金币"
on_disabled:
- 'sendmessage text="<red>你的武器已损坏!</red>"'
on_repaired:
- 'sendmessage text="<green>武器已修复!</green>"'字段含义与完整流程见物品修复系统。
套装定义
套装字段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | string | 是 | 套装唯一 ID。缺失或非法时跳过该文件。 |
display_name | string | 否 | 套装显示名(MiniMessage 格式);缺省时回退为套装 ID。 |
pieces | map | 否 | 套装部件定义(key 为部件标识)。 |
lore | object | 否 | 套装 Lore 显示格式配置。 |
thresholds | map | 否 | 件数阈值效果配置;key 为所需件数,必须为正整数。 |
套装文件放在 sets/ 下,支持子目录递归加载。重复 id 只保留首个定义并输出警告。
状态计算与错误槽位
套装 membership 可见性与激活件数分别计算。只要物品 definition 声明了可用的 set.id,当前状态就保留该套装,即使所有候选件都因槽位不匹配而无效,Lore 也会显示 0/%total%,而不是构造成缺少套装定义的空状态。
只有同时满足以下条件的装备才进入 activeCount 和激活阈值:
- 能唯一解析到
sets/*.yml中的真实部件; - 当前装备槽匹配物品 definition 的
equip_slot; - 当前装备槽同时匹配套装部件的
slot。
缺失或无法加载的套装定义会被安全隔离,不进入可见状态,也不会触发奖励或破坏性 Lore 写回;运行时会为每个缺失套装 ID 输出一次警告,启用 set DEBUG 时还会输出 [DEBUG:SET_STATE] state=missing_definition action=preserve。Folia 与 Paper 都使用同一纯状态构造规则,Folia 只改变 owner-thread 调度边界。
部件定义(pieces)
pieces:
blade:
item: "example_item"
slot: "main_hand"
display: "示例之刃"
helmet:
item: "example_guardian_helmet"
slot: "helmet"
display: "守护者头盔"| 字段 | 说明 |
|---|---|
item | 对应的物品 ID(items/ 目录下的物品定义);缺省时使用部件 key。 |
slot | 装备槽位(main_hand/off_hand/helmet/chestplate/leggings/boots);缺省时使用部件 key。 |
display | 在套装 Lore 中显示的部件名称;缺省时使用部件 key。 |
部件也可简写为 部件key: 物品ID,此时槽位与显示名都回退为部件 key。
Lore 显示配置
lore:
header: "<dark_gray>—— <aqua>套装名</aqua> <gray>(%active%/%total%)</gray> ——</dark_gray>"
equipped_format: "<green>✔ %piece%</green>"
missing_format: "<gray>✘ %piece%</gray>"
active_threshold_format: "<green>%line%</green>"
inactive_threshold_format: "<dark_gray>%line%</dark_gray>"
separator: ""套装示例
id: "example_set"
display_name: "<aqua>示例守护者套装</aqua>"
pieces:
blade:
item: "example_item"
slot: "main_hand"
display: "示例之刃"
helmet:
item: "example_guardian_helmet"
slot: "helmet"
display: "守护者头盔"
chestplate:
item: "example_guardian_chestplate"
slot: "chestplate"
display: "守护者胸甲"
boots:
item: "example_guardian_boots"
slot: "boots"
display: "守护者战靴"
lore:
header: "<dark_gray>—— <aqua>示例守护者套装</aqua> <gray>(%active%/%total%)</gray> ——</dark_gray>"
equipped_format: "<green>✔ %piece%</green>"
missing_format: "<gray>✘ %piece%</gray>"
active_threshold_format: "<green>%line%</green>"
inactive_threshold_format: "<dark_gray>%line%</dark_gray>"
separator: ""
thresholds:
2:
lore:
- "[2件套] 物理攻击 +5,解锁冲刺技能"
effects:
- type: "ea_attribute"
ea_attributes:
physical_attack: 5.0
- type: "es_skill"
es_skills:
- "guardian_dash"
4:
lore:
- "[4件套] 物理攻击 +15,物理防御 +10,解锁守护者光环"
effects:
- type: "ea_attribute"
ea_attributes:
physical_attack: 15.0
physical_defense: 10.0
- type: "es_skill"
es_skills:
- "guardian_aura"自动更新
update 配置控制物品在哪些时机自动刷新:
update:
enabled: true
version: 1
triggers:
join: true
held_change: true
inventory_click: true
inventory_drag: true
pickup: true
interact: true
command: true| 触发项 | 说明 | 性能影响 |
|---|---|---|
join | 玩家登录时。 | 低 |
held_change | 切换手持物品时。 | 低 |
inventory_click | 点击背包时。 | 中 |
inventory_drag | 拖拽物品时。 | 中 |
pickup | 拾取物品时。 | 低 |
interact | 交互事件时。 | 中 |
command | 执行 /ei update 时。 | 低 |
每次修改物品配置后递增 version 字段即可触发更新。建议不要开启过多高频触发,先确保手动 /ei update 正常,再逐步开启自动更新。