Skip to content

图纸与材料 ​

图纸要求和材料列表分别怎么写, 以及它们如何决定一次锻造能不能开始, 成本多大, 出什么品质, 给成品附加哪些效果

图纸管的是"能不能做", 材料管的是"用什么做, 做得多好": 图纸决定哪些配方可以被执行, 材料决定锻造成本, 品质和附加效果

图纸要求 ​

yaml
blueprint_requirements:
  - item_sources:
      - "minecraft-enchanted_book"
    amount: 1
字段类型必填默认值取值范围说明
idstring否由 item_sources 简写派生; 无物品源时退化为 matcher 摘要非空字符串 (声明了就不能为空白, 否则报 IDENTITY_BLANK)图纸要求的身份键, 同一个图纸的多个条目按它归到一起计数. 见下方同一图纸的多种形态
blueprint_idstring否同 id同上id 的别名; 两个都写时以 id 为准
item_sourceslist<string>否空 (不限来源)物品源简写, 如 minecraft-enchanted_book允许作为图纸的物品来源清单. 它和 matcher 必须同时满足; 两个都省略时, 这个条目永远不会命中 (BLUEPRINT_MATCH_EMPTY)
matcherobject否空 (不加额外条件)组件 / PDC / Lore 等非物品源条件通用物品匹配器. 见 物品匹配器
amountinteger否1> 0 (<= 0 使该条目解析失败, 整条配方被拒绝加载)需要的数量
itemstring否空物品源简写兼容键: 只有没写 item_sources 时才作为展示用的简写读取, 不参与身份推导

图纸不会被消耗, 只检查玩家是否持有. 你用它就能做出"要先拿到图纸才能锻造"的玩法

发货默认值: 随模块发布的 recipes/example_recipe.yml 用两个同 id 条目演示同一图纸的两种可接受形态; 可直接复制的写法见下面的同一图纸的多种形态

同一图纸的多种形态 ​

同一种图纸有多种可以接受的形态时, 把它们写成多个 id 相同的条目, 计数按 id 加起来, 玩家持有其中任意一种就算满足:

yaml
blueprint_requirements:
  # 两种形态都算"烈焰之剑图纸", 各算一份
  - id: flame_sword_blueprint
    item_sources:
      - "minecraft-enchanted_book"
    amount: 1
  - id: flame_sword_blueprint
    item_sources:
      - "minecraft-paper"
    matcher:
      type: component
      component: custom_name
      operator: contains
      value: 烈焰之剑图纸
    amount: 1

过去把多种形态塞进同一个 matcher 的 any_of, 现在改用这种写法

材料列表 ​

yaml
materials:
  - item_sources:
      - "minecraft-iron_ingot"
    amount: 3
    capacity_cost: 5
    effects:
      - type: "variables"
        variables:
          physical_damage: 5
      - type: "ea_attribute"
        ea_attributes:
          physical_attack: 5.0
字段类型必填默认值取值范围说明
material_idstring否由 item_sources 简写派生; 无物品源时退化为 matcher 摘要非空字符串 (声明了就不能为空白, 否则报 IDENTITY_BLANK)材料的身份键, 决定材料怎么被选中和查找; 它和 count_key / audit_id 可以各自独立设置. 见下方材料身份键
count_keystring否解析出的 material_id非空字符串计数和消耗时使用的身份键
audit_idstring否解析出的 material_id非空字符串; 同一配方内不能被不同 material_id 共用 (报 AUDIT_ID_CONFLICT)写进成品 PDC 并用于刷新时查找的审计身份
item_sourceslist<string>否空 (不限来源)物品源简写, 如 minecraft-iron_ingot允许作为材料的物品来源清单; 没显式声明身份时, 它会参与推导材料身份. 它和 matcher 必须同时满足; 两个都省略时, 这个条目永远不会命中 (MATERIAL_MATCH_EMPTY)
matcherobject否空 (不加额外条件)组件 / PDC / Lore 等非物品源条件通用物品匹配器. 见 物品匹配器
amountinteger否1非 0 (0 使该条目解析失败, 整条配方被拒绝加载)需要的数量
capacity_costnumber | expression否0求值后四舍五入取整, >= 0这种材料占用的锻造容量. 可以写表达式或随机配置, 每次锻造时求值
optionalboolean否falsetrue / false这种材料是不是可选的
effectslist<object>否空列表—这种材料附带的效果清单, 见材料效果
itemstring否空物品源简写兼容键: 只有没写 item_sources 时才作为展示用的简写读取, 不参与身份推导

item_sources 与 matcher 都不写时, 这个材料条目永远不会命中

WARNING

materials[] 的条目里不要写 id, display_name 或 description. 材料解析器看到带这三个键的节点, 会当成"不是材料定义"而返回空, 结果整条配方加载失败 (INVALID_CONFIG). 材料的身份键是 material_id

同一条配方里, 同一个 material_id 的所有条目必须用相同的 count_key, audit_id, amount 与 optional, 否则报 MATERIAL_IDENTITY_CONFLICT

发货默认值: recipes/example_recipe.yml 的 materials: 列表演示了必需材料, 可选材料, capacity_bonus, 纯 matcher 材料与"物品源 + 组件条件"材料五类写法

容量与可选材料 ​

forge_capacity 限制这个配方允许投入的材料总容量, 你投入的所有材料的 capacity_cost 加起来不能超过这个值

yaml
forge_capacity: 35

建议:

  • 你给基础配方的容量小一点, 免得玩家一次投入太多, 看不懂发生了什么
  • 高级配方多留一些可选材料的空间, 让玩家去追求更高品质
  • 可选材料要在界面里展示清楚, 否则玩家不明白品质为什么变了

材料匹配建议 ​

  • 你用固定的 item_sources 格式 ("提供者-物品ID")
  • 贵重材料建议开启精确匹配, 免得玩家用外观相似的假物品顶替
  • 材料来自其他模块时, 先确认那个模块的加载顺序排在 Forge 之前

材料身份键 ​

每种材料有三类可以分开设置的身份: material_id 决定材料怎么被选中和查找, count_key 决定计数和消耗, audit_id 写进成品 PDC 并用于锻造审计和刷新查找. 没填的按下面的顺序补上:

  1. material_id 先取显式写的 material_id, 没写就取 item_sources 简写, 最后才取 matcher 内容摘要. count_key / audit_id 不参与推导 material_id
  2. count_key 不写时, 用推导出来的 material_id
  3. audit_id 不写时, 用推导出来的 material_id

纯 matcher 材料请显式写 material_id

一种材料只写 matcher, 不写 item_sources 时, 材料身份会退到 matcher 摘要 -- 随 matcher 的内容变化. 之后只要改了 matcher, 已经锻造好的物品在刷新时就可能报材料缺失

给这类材料显式写 material_id; 需要把选择, 计数消费和审计刷新分开设置时, 再分别写 count_key 与 audit_id. Forge 读旧审计记录时, 按 audit_id → material_id → count_key → 旧 material_item / source 的顺序逐个尝试; 不是完整规范格式的记录, 在成功解析后会请求刷新写回, 解析不到材料就保留原物品并告警, 不会用不完整的数据覆盖

通用物品匹配器 (matcher) ​

blueprint_requirements[] 和 materials[] 的判定都由两个并列字段一起决定, 两个都要满足: item_sources 只写允许的物品来源, matcher 只写组件 / PDC / Lore 这类与物品来源无关的条件. 完整语法 (包括全部类型, operator, path 和嵌套写法) 见 物品匹配器

WARNING

matcher 内部不能写物品源条件. type: item_source / item_sources / source / sources 会被解析器拒绝并告警, 该 matcher 永远不匹配

yaml
materials:
  # 窄条件写在前面: 附了锋利的铁锭才吃这一条
  - material_id: enchanted_iron_ingot
    item_sources:
      - "minecraft-iron_ingot"
    matcher:
      type: component
      component: enchantments
      path: sharpness
      operator: '>='
      value: 3
    amount: 1
    capacity_cost: 10
    effects:
      - type: "variables"
        variables:
          physical_damage: 15
  # 宽条件写在后面: 普通铁锭
  - item_sources:
      - "minecraft-iron_ingot"
    amount: 3
    capacity_cost: 5

上例两条材料的物品源相同, 所以窄条件那条必须显式写 material_id -- 否则两条会推导出同一个身份键, 计数会混在一起

DANGER

材料按配方里声明的顺序从上往下找, 第一个匹配上的就算, 先声明的宽条件会挡住后声明的窄条件

Forge 对每个投入的物品从上往下找第一条匹配的材料, 找到就停. 如果上例把普通铁锭那条写在前面, 附魔铁锭也会先命中它, 后面的窄条件永远轮不到

规则很简单: 窄条件写在前面, 宽条件写在后面. 图纸要求 (blueprint_requirements) 用同样的逻辑, 顺序要求一致

材料效果 ​

材料可以附带效果 (effects), 用来在锻造成功后影响结果物品. 效果写在材料配置的 effects 列表里

效果类型 ​

每条效果至少要写 type; 除 type 外的其他键都会被保存下来, 但真正读取的只有下表列出的键

字段类型必填默认值取值范围说明
effects[].typestring是—variables / ea_attribute / es_skill / name_action / lore_action / quality_modify / capacity_bonus效果的类型. 留空时这条效果解析失败, 整条配方被拒绝加载
effects[].variablesobject否空map<变量名, number | expression>variables 效果的变量表. 它给锻造结果提供文本和模板用的变量值, 不写入 Attribute PDC
effects[].ea_attributesobject否空map<属性 id, number | expression>ea_attribute 效果的属性表. 它向结果物品写入 PDC 属性, 需要安装 EmakiAttribute
effects[].es_skillslist<string>否空列表技能 ID 列表es_skill 效果绑定的技能, 去掉重复后写入, 需要安装 EmakiSkills
effects[].name_actionslist<object>否空列表CoreLib 名称动作name_action 效果对结果物品名称执行的动作链
effects[].lore_actionslist<object>否空列表CoreLib Lore 动作lore_action 效果对结果物品 Lore 执行的动作链
effects[].modestring否—force / minimumquality_modify 的模式; 缺失或留空时整条效果被忽略
effects[].tierstring否—品质池中存在的品质名quality_modify 的目标品质; 缺失或留空时整条效果被忽略
effects[].valuenumber | expression否0任意数值capacity_bonus 带来的容量加成. 每次锻造时求值再四舍五入取整, 负值部分加总为 0

发货默认值: recipes/example_recipe.yml 覆盖了除 quality_modify 外的六种效果类型, 可直接对照抄写

NOTE

效果值的最终算法是 配置值 × 材料数量 × 品质倍率. 这条对 variables 和 ea_attribute 效果都适用, 但两者的含义不同: variables 只用于文本和模板, 真实属性必须写在 ea_attributes 里

variables 效果 ​

给锻造结果注入变量值. 这些值会受品质倍率影响, 可以在 lore_actions 和 name_actions 的模板里使用

yaml
effects:
  - type: "variables"
    variables:
      fire_damage: 10
      fire_resistance: 5

ea_attribute 效果 ​

通过 EmakiAttribute 的 API 向结果物品写入结构化 PDC 属性层, 需要安装 EmakiAttribute

yaml
effects:
  - type: "ea_attribute"
    ea_attributes:
      physical_attack: 15.0
      physical_defense: 5.0

现在的配置不再使用 ea_attribute_meta. 属性值的最终结果就是 配置值 × 材料数量 × 品质倍率. 没装 EmakiAttribute 时这条效果走 no-op 路径 (空操作), 锻造照常完成, 只是不写入属性

es_skill 效果 ​

给结果物品绑定技能 ID, 需要安装 EmakiSkills

yaml
effects:
  - type: "es_skill"
    es_skills:
      - "fire_slash"
      - "flame_shield"

现在推荐只用 es_skills 列表写法, 旧的单个 es_skill 字段不再推荐使用

name_action 效果 ​

对锻造结果物品的名称执行操作, 支持 CoreLib 名称操作系统的全部动作类型

yaml
effects:
  - type: "name_action"
    name_actions:
      - action: "prepend_prefix"
        value: "<red>烈焰 </red>"
      - action: "append_suffix"
        value: " <gray>[锻造]</gray>"

lore_action 效果 ​

对锻造结果物品的 Lore 执行操作, 支持 CoreLib Lore 操作系统的全部动作类型

yaml
effects:
  - type: "lore_action"
    lore_actions:
      - action: "insert_below"
        anchor: "锻造属性:"
        content:
          - "<gray>物理伤害: <red>+%physical_damage%</red></gray>"
          - "<gray>生命值: <green>+%max_health%</green></gray>"

模板变量 ​

在 name_actions 的 value 字段和 lore_actions 的 content 字段里, 可以用下面这些变量:

变量说明
%quality%品质名. 只有在品质档位解析成功时才会注入
%quality_name%品质显示名, 与 %quality% 取值相同
%quality_multiplier%品质倍率, 按 0.## 格式化
%multiplier%品质倍率的简写别名
%变量名%通过 variables 效果注入的变量值, 已经乘过材料数量和品质倍率

quality_modify 效果 ​

修改品质计算的结果. 支持两种模式:

模式说明
force把品质直接设成指定等级, 不管随机抽到什么
minimum设置品质下限, 抽到的结果低于这个等级时, 提升到这个等级
yaml
effects:
  - type: "quality_modify"
    mode: "force"
    tier: "史诗"

IMPORTANT

现在推荐用字段名 tier. 旧的 quality 不再推荐使用. force 模式会跳过保底计数器

capacity_bonus 效果 ​

带这种效果的材料, 本身的 capacity_cost 为 0, 同时给配方多加一些容量

yaml
effects:
  - type: "capacity_bonus"
    value: 20

IMPORTANT

现在推荐用字段名 value. 旧的 amount, bonus, capacity 不再推荐使用

完整示例 ​

yaml
id: "example_recipe"
display_name: "<gold>烈焰之剑锻造配方</gold>"
forge_capacity: 35

blueprint_requirements:
  - item_sources:
      - "minecraft-enchanted_book"
    amount: 1

materials:
  - item_sources:
      - "minecraft-iron_ingot"
    amount: 3
    capacity_cost: 5
    effects:
      - type: "variables"
        variables:
          physical_damage: 5
          max_health: 2
      - type: "ea_attribute"
        ea_attributes:
          physical_attack: 5.0
          max_health: 2.0
      - type: "lore_action"
        lore_actions:
          - action: "insert_below"
            anchor: "锻造属性:"
            content:
              - "<gray>物理伤害: <red>+%physical_damage%</red></gray>"
              - "<gray>生命值: <green>+%max_health%</green></gray>"

  - item_sources:
      - "minecraft-blaze_powder"
    amount: 1
    capacity_cost: 10
    effects:
      - type: "variables"
        variables:
          fire_damage: 10
          critical_chance: 5
      - type: "ea_attribute"
        ea_attributes:
          fire_damage: 10.0
          physical_crit_rate: 5.0
      - type: "es_skill"
        es_skills:
          - "flame_strike"
      - type: "name_action"
        name_actions:
          - action: "prepend_prefix"
            value: "<red>烈焰 </red>"
      - type: "lore_action"
        lore_actions:
          - action: "insert_below"
            anchor: "锻造属性:"
            content:
              - "<red>火焰伤害: +%fire_damage%</red>"