English
Blueprints and Materials
Forge uses blueprint requirements to gate recipe entry and material entries to decide cost, capacity, quality modifiers, and extra effects. A blueprint answers "may I do this", a material answers "what do I use, and how well does it turn out"
Blueprint requirements
yaml
blueprint_requirements:
- item_sources:
- "minecraft-enchanted_book"
amount: 1| Field | Type | Required | Default | Allowed values | Description |
|---|---|---|---|---|---|
id | string | No | Derived from the item_sources shorthand, or a matcher digest when there is no source | Non-blank string (a declared blank value reports IDENTITY_BLANK) | Stable identity of the requirement; counts aggregate by it. See Accepting several forms of one blueprint |
blueprint_id | string | No | Same as id | Same as id | Alias of id; when both are present id wins |
item_sources | list<string> | No | empty (unrestricted source) | Item source shorthand, e.g. minecraft-enchanted_book | Allowed blueprint sources. ANDed with matcher; when both are omitted the entry never matches (BLUEPRINT_MATCH_EMPTY) |
matcher | object | No | empty (no extra condition) | Component / PDC / Lore conditions | General item matcher. See Item Matcher |
amount | integer | No | 1 | > 0 (<= 0 makes the entry fail to parse and rejects the whole recipe) | Required amount |
item | string | No | blank | Item source shorthand | Compatibility key: read as a display shorthand only when item_sources is absent; it does not participate in identity derivation |
Blueprint requirements are checked before forging and nothing is consumed. They are suitable for recipe scrolls, unlock items, or profession certificates
Shipped default: the bundled recipes/example_recipe.yml uses two entries sharing one id to demonstrate two acceptable forms of one blueprint; the copyable form is in Accepting several forms of one blueprint
Accepting several forms of one blueprint
Write each acceptable form as its own entry sharing one id. Counts aggregate by id, so holding any one form satisfies the requirement instead of being read as two separate blueprints the player must hold at once
yaml
blueprint_requirements:
# Narrow form first: an official knowledge book carrying the marker
- id: blueprint_accepted
item_sources:
- "minecraft-knowledge_book"
amount: 1
matcher:
type: component
component: custom_model_data
path: "floats[0]"
operator: "=="
value: 1.0
# Broad form last: a plain enchanted book
- id: blueprint_accepted
item_sources:
- "minecraft-enchanted_book"
amount: 1This replaces the older approach of packing every form into one matcher's any_of
Material list
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| Field | Type | Required | Default | Allowed values | Description |
|---|---|---|---|---|---|
material_id | string | No | Derived from the item_sources shorthand, or a matcher digest when there is no source | Non-blank string (a declared blank value reports IDENTITY_BLANK) | Stable selection and lookup identity; may be declared independently from count_key and audit_id. See Material identity |
count_key | string | No | The resolved material_id | Non-blank string | Quantity aggregation and consumption identity |
audit_id | string | No | The resolved material_id | Non-blank string; within one recipe it may not be shared by different material_id values (reports AUDIT_ID_CONFLICT) | Identity written into the forged-item PDC and used for refresh lookup |
item_sources | list<string> | No | empty (unrestricted source) | Item source shorthand, e.g. minecraft-iron_ingot | Allowed material sources; when no identity is declared they help derive one. ANDed with matcher; when both are omitted the entry never matches (MATERIAL_MATCH_EMPTY) |
matcher | object | No | empty (no extra condition) | Component / PDC / Lore conditions | General item matcher. See Item Matcher |
amount | integer | No | 1 | Non-zero (0 makes the entry fail to parse and rejects the whole recipe) | Required amount |
capacity_cost | number | expression | No | 0 | Rounded to an integer after evaluation, >= 0 | Forge capacity occupied by this material. Expressions and random configs are evaluated per attempt |
optional | boolean | No | false | true / false | Whether this material is optional |
effects | list<object> | No | empty list | — | Effects contributed by this material, see Material effects |
item | string | No | blank | Item source shorthand | Compatibility key: read as a display shorthand only when item_sources is absent; it does not participate in identity derivation |
When both item_sources and matcher are omitted, the material entry never matches
WARNING
Do not write id, display_name, or description inside a materials[] entry. The material parser treats a node carrying any of those three keys as "not a material definition" and returns nothing, which makes the whole recipe fail to load (INVALID_CONFIG). The material identity key is material_id
Within one recipe, every entry sharing a material_id must use the same count_key, audit_id, amount, and optional, otherwise MATERIAL_IDENTITY_CONFLICT is reported
Shipped default: the materials: list in recipes/example_recipe.yml demonstrates required materials, optional materials, capacity_bonus, matcher-only materials, and a material combining item_sources with a component condition
Capacity and optional materials
forge_capacity limits the total material capacity cost. The sum of every material's capacity_cost may not exceed it
yaml
forge_capacity: 35Guidance:
- Keep base recipes small so players are not overwhelmed by choices
- Advanced recipes may allow more optional material space so players can chase higher quality
- Show optional material limits clearly in the GUI, otherwise players cannot tell why quality changed
Material matching notes
- Use stable
item_sourcesshorthand ("provider-item_id") - For valuable materials pin
material_idso players cannot substitute counterfeit items with a different identity - If a material comes from another module, confirm that module loads before Forge
Material identity
Each material has three independently configurable identities: material_id drives selection and lookup, count_key drives quantity aggregation and consumption, and audit_id is written into the forged-item PDC and used for audit/refresh lookup. Missing values are filled in this order:
material_idtakes the explicitmaterial_id, then theitem_sourcesshorthand, then a matcher digest.count_key/audit_iddo not participate in derivingmaterial_idcount_keydefaults to the resolvedmaterial_idaudit_iddefaults to the resolvedmaterial_id
Matcher-only materials should declare material_id explicitly
A material declaring only matcher (no item_sources) falls back to a matcher digest for its identity, which drifts with the matcher content. A later matcher edit can make an already-forged item report the material as missing during refresh
Give such materials an explicit material_id; add count_key and audit_id separately when selection, consumption aggregation, and audit refresh must diverge. When reading legacy audit records, Forge falls back through audit_id → material_id → count_key → legacy material_item / source; a non-canonical record that resolves successfully is marked for refresh rewrite, and a record that resolves to nothing keeps the original item with a warning instead of overwriting it with incomplete data
General item matcher
Both blueprint_requirements[] and materials[] combine two sibling fields with AND: item_sources carries only allowed item sources, matcher carries only component / PDC / Lore conditions. Full syntax (the complete type set, operators, path, and nesting) is in Item Matcher
WARNING
A matcher must not contain item source conditions. type: item_source / item_sources / source / sources are rejected with a warning, and that matcher never matches
yaml
materials:
# Narrow condition first: only iron ingots carrying Sharpness
- 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
# Broad condition last: plain iron ingots
- item_sources:
- "minecraft-iron_ingot"
amount: 3
capacity_cost: 5The two materials above share the same item source, so the narrower entry must declare material_id explicitly; otherwise both derive the same identity key and their counts merge
DANGER
Materials are first-match in declaration order, so a broad condition declared earlier shadows a narrower one declared later
Forge scans materials top to bottom for each submitted item and stops at the first match. If the plain iron ingot entry above came first, enchanted iron ingots would match it too and the narrower entry would never be reached
The rule is simple: narrow conditions first, broad conditions last. blueprint_requirements uses the same first-match logic and the same ordering requirement
Material effects
Materials can carry effects that shape the result item after a successful forge. Effects live in a material's effects list
Effect types
Every effect needs at least type. The effect data keeps every key except type, but only the keys below are read
| Field | Type | Required | Default | Allowed values | Description |
|---|---|---|---|---|---|
effects[].type | string | Yes | — | variables / ea_attribute / es_skill / name_action / lore_action / quality_modify / capacity_bonus | Effect type. When blank the effect fails to parse and the whole recipe is rejected |
effects[].variables | object | No | empty | map<variable name, number | expression> | Variable table of a variables effect; contributes text/template values and never writes Attribute PDC |
effects[].ea_attributes | object | No | empty | map<attribute id, number | expression> | Attribute table of an ea_attribute effect, written into the structured PDC layer (requires EmakiAttribute) |
effects[].es_skills | list<string> | No | empty list | Skill ids | Skills attached by an es_skill effect; duplicates are removed (requires EmakiSkills) |
effects[].name_actions | list<object> | No | empty list | CoreLib name operations | Name operation chain executed by a name_action effect |
effects[].lore_actions | list<object> | No | empty list | CoreLib lore operations | Lore operation chain executed by a lore_action effect |
effects[].mode | string | No | — | force / minimum | Mode of a quality_modify effect; when missing or blank the effect is ignored entirely |
effects[].tier | string | No | — | A tier name present in the quality pool | Target tier of a quality_modify effect; when missing or blank the effect is ignored entirely |
effects[].value | number | expression | No | 0 | Any number | Capacity bonus of a capacity_bonus effect. Evaluated per attempt, rounded to an integer; a negative total becomes 0 |
Shipped default: recipes/example_recipe.yml covers six of the seven effect types (all but quality_modify) and can be copied directly
NOTE
The final effect value is configured value × material amount × quality multiplier. This applies to both variables and ea_attribute, but their semantics differ: variables only feeds the text/template context, while real attribute output must be written in ea_attributes
variables effect
Injects variable values into the forge result. They are scaled by the quality multiplier and can be used in lore_actions and name_actions templates
yaml
effects:
- type: "variables"
variables:
fire_damage: 10
fire_resistance: 5ea_attribute effect
Writes a structured PDC attribute layer through the EmakiAttribute authoritative API (requires EmakiAttribute). The attribute value is configured value × material amount × quality multiplier. Without EmakiAttribute this effect takes a no-op path: forging still completes but no attribute is written. Current configs no longer use ea_attribute_meta
yaml
effects:
- type: "ea_attribute"
ea_attributes:
physical_attack: 15.0
physical_defense: 5.0es_skill effect
Attaches skill ids to the result item (requires EmakiSkills). Use the es_skills list form; the old single es_skill field is no longer the recommended shape
yaml
effects:
- type: "es_skill"
es_skills:
- "fire_slash"
- "flame_shield"name_action effect
Runs name operations on the result item, supporting every action type of the CoreLib name operation system
yaml
effects:
- type: "name_action"
name_actions:
- action: "prepend_prefix"
value: "<red>Flame </red>"
- action: "append_suffix"
value: " <gray>[Forged]</gray>"lore_action effect
Runs lore operations on the result item, supporting every action type of the CoreLib lore operation system
yaml
effects:
- type: "lore_action"
lore_actions:
- action: "insert_below"
anchor: "Forged attributes:"
content:
- "<gray>Physical damage: <red>+%physical_damage%</red></gray>"
- "<gray>Max health: <green>+%max_health%</green></gray>"quality_modify effect
Modifies the quality result. Two modes are supported:
| Mode | Description |
|---|---|
force | Forces the tier to the specified quality, ignoring the roll |
minimum | Sets a quality floor; a lower roll is raised to that tier |
yaml
effects:
- type: "quality_modify"
mode: "force"
tier: "Epic"IMPORTANT
The recommended field name is tier; the old quality key is no longer the documented form. force mode also skips the pity counter logic entirely
capacity_bonus effect
A material carrying this effect behaves as if its own capacity_cost were 0 and contributes extra capacity to the recipe
yaml
effects:
- type: "capacity_bonus"
value: 20IMPORTANT
The recommended field name is value; the old amount, bonus, and capacity keys are no longer the documented form
Template variables
Available in name_actions value fields and lore_actions content fields:
| Variable | Description |
|---|---|
%quality% | Quality tier name. Injected only when a quality tier resolved |
%quality_name% | Quality display name, same value as %quality% |
%quality_multiplier% | Quality multiplier, formatted as 0.## |
%multiplier% | Short alias of the quality multiplier |
%<name>% | Any value injected through variables effects, already scaled by material amount and quality multiplier |
Full example
yaml
id: "example_recipe"
display_name: "<gold>Flame Sword Forging Recipe</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: "Forged attributes:"
content:
- "<gray>Physical damage: <red>+%physical_damage%</red></gray>"
- "<gray>Max health: <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>Flame </red>"
- type: "lore_action"
lore_actions:
- action: "insert_below"
anchor: "Forged attributes:"
content:
- "<red>Fire damage: +%fire_damage%</red>"