配方系统
配方是 EmakiForge 的核心数据结构,定义了一次锻造需要什么图纸、什么材料、怎么算品质、产出什么东西。每个配方对应 recipes/ 目录下的一个 YAML 文件。
配方完整格式
下面是一个包含所有可用字段的完整示例。实际使用时,大部分字段是可选的,按需配置即可。
# 配方唯一标识符
id: example_sword
# 显示名称(支持 MiniMessage 格式)
display_name: "<gold>铁剑锻造"
# 锻造容量 — 限制可投入材料的总容量
forge_capacity: 100
# ===== 图纸需求 =====
# 锻造前必须在图纸槽位放入匹配的图纸
blueprint_requirements:
- iron_sword_blueprint
# ===== 材料列表 =====
materials:
# 必选材料
- item: "minecraft:iron_ingot"
amount: 5
optional: false
capacity_cost: 10
effects:
- type: stat_contribution
stat: physical_damage
amount: 12.0
- type: quality_modify
modifier_type: minimum # minimum | force
tier: "精良"
# 可选材料
- item: "neigeitems:magic_crystal"
amount: 1
optional: true
capacity_cost: 20
effects:
- type: attribute
attribute: "攻击力"
value: 5.0
- type: capacity_bonus
amount: 15
- type: name_modify
format: "<light_purple>魔力{name}"
- type: lore_action
action: append
section: enchant_info
lines:
- "<gray>附魔:<aqua>魔力注入"
- type: structured_presentation
name_contributions:
magic_prefix:
order: 1
format: "<light_purple>魔力 "
lore_sections:
magic_info:
order: 50
lines:
- "<gray>魔力注入:<aqua>+5"
# 可选材料数量上限
optional_material_limit: 3
# ===== 条件系统 =====
# 条件类型:all_match(全部满足)| any_match(任一满足)
condition_type: all_match
conditions:
- type: permission
value: "emakiforge.recipe.example_sword"
- type: level
operator: ">="
value: 10
- type: placeholder
placeholder: "%player_exp%"
operator: ">="
value: "500"
# ===== 品质配置 =====
quality:
# 自定义品质池(不设置则使用全局 config.yml 中的 tiers)
custom_pool:
- "普通-40-1.0"
- "精良-35-1.3"
- "史诗-20-1.6"
- "传说-5-2.0"
# 品质动作 — 根据品质等级触发不同动作
actions:
传说:
- "broadcast message=<gold>{player} <yellow>锻造出了传说品质的 {item}!"
- "playsound sound=ui.toast.challenge_complete volume=1.0 pitch=1.0"
史诗:
- "playsound sound=entity.player.levelup volume=1.0 pitch=1.2"
# ===== 结果定义 =====
result:
# 输出物品(物品来源 ID)
output_item: "minecraft:iron_sword"
# 元动作 — 对输出物品执行的修改操作
meta_actions:
- type: set_name
value: "{quality} 铁剑"
- type: set_lore
lines:
- "<gray>物理伤害:<white>{physical_damage}"
- "<gray>品质:<white>{quality}"
- "<gray>品质倍率:<white>{multiplier}"
- type: set_custom_model_data
value: 10001
# 动作阶段
action:
# 锻造前执行
pre:
- "playsound sound=block.anvil.use volume=1.0 pitch=0.8"
- "sendmessage message=<gray>开始锻造..."
# 锻造成功后执行
success:
- "playsound sound=block.anvil.land volume=1.0 pitch=1.2"
- "sendmessage message=<green>锻造成功!品质:{quality}"
- "giveexp amount=100"
# 锻造失败后执行(当前版本锻造默认成功,此阶段为预留)
failure:
- "playsound sound=block.anvil.destroy volume=1.0 pitch=0.5"
- "sendmessage message=<red>锻造失败了..."
# 权限节点(可选,覆盖全局权限检查)
permission: "emakiforge.recipe.example_sword"材料效果类型
每种材料可以挂载多个效果(effects 列表),在锻造时一起生效。支持的效果类型如下:
| 效果类型 | 做什么 | 关键字段 |
|---|---|---|
stat_contribution | 给产物贡献数值属性(如物理伤害),最终值会乘以品质倍率 | stat, amount |
structured_presentation | 控制产物的名称前缀/后缀和 Lore 区块的渲染 | name_contributions, lore_sections |
capacity_bonus | 增加本次锻造的容量上限,让你能塞进更多材料 | amount |
quality_modify | 干预品质结果:强制指定品质,或设定品质下限 | modifier_type, tier |
attribute | 向产物写入 EmakiAttribute 属性 | attribute, value |
name_modify | 直接修改产物的显示名称 | format |
lore_action | 追加或替换产物的 Lore 行 | action, section, lines |
skill | 向产物写入技能 ID,让装备解锁对应的 EmakiSkills 技能 | skills 或 skill |
stat_contribution 详解
这是最常用的材料效果。它的计算逻辑很直接:
最终属性值 = amount × quality_multiplier| 变量 | 说明 |
|---|---|
stat | 属性名称,比如 physical_damage、spell_power |
amount | 这个材料贡献的基础属性值 |
quality_multiplier | 品质倍率,由最终品质等级决定(比如传说 = 2.0) |
举个例子:材料贡献 physical_damage = 12.0,最终品质是"传说"(倍率 2.0),那物理伤害 = 12.0 × 2.0 = 24.0。
如果多个材料都贡献了同一个 stat,它们的 amount 会先累加,再乘以品质倍率。
quality_modify 详解
品质修正有两种模式,适用于不同场景:
| modifier_type | 效果 | 典型用途 |
|---|---|---|
force | 直接把品质锁定为指定等级,跳过随机 | 特殊材料(如"传说之心")保证出传说品质 |
minimum | 设定品质下限,随机结果低于这个等级时自动提升 | 高级材料保底不出太差的品质 |
effects:
- type: quality_modify
modifier_type: minimum
tier: "精良"structured_presentation 详解
这个效果让材料可以往产物的名称和 Lore 上"注入"内容。多个材料的注入内容会按 order 排序后合并。
effects:
- type: structured_presentation
name_contributions:
magic_prefix:
order: 1 # 排序权重,越小越靠前
format: "<light_purple>魔力 "
lore_sections:
magic_info:
order: 50 # Lore 区块排序权重
lines:
- "<gray>魔力注入:<aqua>+5"name_contributions 中的每个条目会按 order 排序后拼接成最终名称。lore_sections 同理,按 order 排序后依次追加到 Lore 中。这样设计是为了让不同材料的展示内容能有序地组合在一起,而不是互相覆盖。
skill 详解
skill 效果让材料可以给产物写入技能 ID。锻造完成后,产物的 PDC 中会包含技能 ID 列表(通过 ReflectiveSkillPdcGateway 写入),EmakiSkills 扫描装备时就能识别并解锁对应技能。
effects:
# 列表写法(推荐,一次声明多个技能)
- type: skill
skills:
- "fireball"
- "ice_bolt"
# 单个写法
- type: skill
skill: "mana_shield"多个材料都声明了 skill 效果时,所有技能 ID 会合并去重后写入产物。
结果 meta_actions
meta_actions 在锻造完成后对输出物品做最终修改:
| 动作类型 | 做什么 | 字段 |
|---|---|---|
set_name | 设置物品显示名称 | value |
set_lore | 设置物品 Lore | lines |
set_custom_model_data | 设置自定义模型数据(用于资源包切换模型) | value |
meta_actions 中的 value 和 lines 都支持变量注入,所以你可以写 "{quality} 铁剑" 这样的模板。
变量注入
配方的 meta_actions、action 阶段和品质动作中都可以用以下变量:
| 变量 | 说明 | 示例值 |
|---|---|---|
{physical_damage} | 物理伤害属性值(已经乘过品质倍率) | 24.0 |
{quality} | 品质等级名称 | 传说 |
{multiplier} | 品质倍率 | 2.0 |
{player} | 玩家名称 | Steve |
{item} | 输出物品名称 | 铁剑 |
提示
所有 stat_contribution 中声明的 stat 名称都会自动注册为变量。比如你声明了 stat: spell_power,就可以在模板中用 {spell_power} 引用它的最终值。
审计数据
每次锻造完成后,系统会把这次锻造的关键信息记录到玩家数据文件中,方便排查问题或做数据统计:
| 字段 | 说明 |
|---|---|
recipe_id | 使用的配方 ID |
quality | 最终品质等级 |
quality_multiplier | 品质倍率 |
materials_used | 消耗的材料列表 |
stat_values | 最终属性值映射 |
timestamp | 锻造时间戳 |
blueprint_id | 使用的图纸 ID |
ForgeLayerSnapshotBuilder 流程
ForgeLayerSnapshotBuilder 负责把锻造结果打包成 layer snapshot 并写入产物。整个过程是这样的:
收集所有材料的贡献
↓
计算品质等级(加权随机 / 保底 / 材料修正)
↓
把品质倍率乘到所有 stat_contribution 上
↓
合并 structured_presentation(名称贡献 + Lore 区块)
↓
合并 attribute 写入列表
↓
构建 ForgeLayerSnapshot
↓
通过 AssemblyService 写入物品 PDC
↓
触发 StructuredPresentationRenderer 重建物品展示这个流程是同步执行的。先算好所有数据,再一次性写入,保证物品状态的一致性。
注意
配方加载时会做严格校验:condition_type 如果不是 all_match 或 any_match,加载器会直接拒绝。配方中如果出现 target_item 节点也会被拒绝(这是旧版字段,已废弃)。