Skip to content

Recipes ​

A recipe defines what an attempt needs, how it is matched, what is consumed, what is produced, and which actions run on success or failure. You place recipe files in recipes/*.yml; the id comes from id, not the file name, and a duplicate id in the same directory is rejected

Root fields ​

FieldTypeRequiredDefaultAllowed valuesDescription
idstringYes—Non-blank stringUnique recipe id. A blank value skips the file with BLANK_ID
display_namestringNoidMiniMessage textRecipe display name used by the recipe book and the forge GUI title
gui_templatestringNoblankA template id under gui/, e.g. forge_guiGUI template used by this recipe. Blank falls back to the bundled forge_gui
blueprint_requirementslist<object>Noempty list—Blueprint requirements; presence is checked, nothing is consumed. Per-entry fields are in Blueprints and Materials
materialslist<object>Noempty list—Material entries. Per-entry fields are in Blueprints and Materials
forge_capacityintegerNo0>= 0 (negatives clamp to 0)Capacity limit for the sum of material capacity_cost. A value of 0 makes the GUI show the "waiting for blueprint" state
optional_material_limitintegerNo0>= 0 (negatives clamp to 0)Maximum number of optional material types per attempt
conditionobjectNoall_of / 0 / empty—Condition group, see Condition node
qualityobjectNodisabled—Recipe-level quality override; the full key set is in Quality
resultobjectNoempty—Result definition, see Result definition
actionsobjectNoempty—Flow actions, see Action nodes
permissionstringNoblankA permission node stringPermission required to use the recipe. Blank means no permission check
success_ratenumberNo1000 ~ 100 (clamped)Forge success rate in percent. Below 100 the forge can fail and failure_outcomes applies
failure_outcomeslist<object>Noempty list—Failure plans, meaningful only when success_rate < 100

Shipped default: the bundled recipes/example_recipe.yml is a complete sample (blueprint requirement, 7 materials, quality, result, and actions). A minimal copyable recipe:

yaml
id: flame_sword
display_name: '<red>Flame Sword Forging'
blueprint_requirements:
  - item_sources:
      - "minecraft-paper"
    amount: 1
materials:
  - item_sources:
      - "minecraft-blaze_rod"
    amount: 3
    capacity_cost: 5
forge_capacity: 10
optional_material_limit: 2
result:
  success:
    outputs:
      - item_source: "minecraft-diamond_sword"

Condition node ​

condition is parsed by the CoreLib condition group and supports five combination modes:

FieldTypeRequiredDefaultAllowed valuesDescription
condition.typestringNoall_ofall_of / any_of / none_of / at_least / exactlyCombination mode. Any other value rejects the recipe with INVALID_CONDITION_MODE
condition.required_countintegerNo0>= 0 (negatives clamp to 0)Comparison basis for at_least (at least N hold) and exactly (exactly N hold); ignored by the other modes
condition.entrieslistNoempty list—Condition entries. Each is a CoreLib condition expression or a nested condition group
yaml
condition:
  type: at_least
  required_count: 2
  entries:
    - "level >= 30"
    - "permission: blacksmith"
    - "world: world_nether"

WARNING

The CoreLib condition block also accepts condition.invalid_as_failure, condition.on_pass.actions, condition.on_fail.actions, condition.on_fail.block_output, and condition.on_fail.message, but Forge's forge flow only reads type / required_count / entries. Whether an invalid condition counts as a failure is controlled globally by condition.invalid_as_failure in config.yml, and on_pass / on_fail do not participate in forge validation. Writing them in a recipe has no effect

You can combine permission and condition to restrict who uses a recipe, for example "blacksmith profession only", "level 30 or above", or "must carry a PDC marker"

Result definition ​

FieldTypeRequiredDefaultAllowed valuesDescription
result.success.outputslist<object>Noempty list—Success-branch outputs; Forge uses only the first entry as the primary result. When empty the recipe needs a target item slot in the GUI (requiresTargetInput()), otherwise no result can be produced
result.success.outputs[].item_sourcestringYes (when the entry exists)—A single item sourceSource of the produced item. It must be scalar: a list reports OUTPUT_SOURCE_NOT_SINGLE and omission reports OUTPUT_SOURCE_MISSING
result.success.outputs[].item_sourceslistNo—Exactly one valid sourceLegacy form, read for compatibility with a WARNING (OUTPUT_LEGACY_SOURCE). Declaring it together with item_source reports OUTPUT_SOURCE_FIELD_CONFLICT
result.success.outputs[].matcher—No—Not allowedAn output entry may not declare matcher; doing so reports OUTPUT_MATCHER_FORBIDDEN
result.success.outputs[].amountintegerNoignored—The current implementation does not read this key; the primary result is always produced with amount 1. A wrong value neither errors nor takes effect
result.success.actionslist<string>Noempty listCoreLib action linesActions executed after the result is generated
result.success.name_actionslist<object>Noempty listCoreLib name operationsName operation chain for the result item
result.success.lore_actionslist<object>Noempty listCoreLib lore operationsLore operation chain for the result item

When result.success.outputs declares an output source, a successful forge creates the first entry as the primary result item and attaches the forge layer snapshot. This suits crafting a new weapon from materials, producing fixed equipment from a blueprint, or emitting EmakiItem and third-party plugin items

yaml
result:
  success:
    outputs:
      - item_source: "minecraft-diamond_sword"
    name_actions:
      - action: "append_suffix"
        value: " <gray>[%quality_name%]</gray>"
    lore_actions:
      - action: "append"
        content:
          - ""
          - "<gray>Quality: <white>%quality_name%</white></gray>"
          - "<gray>Multiplier: <white>%quality_multiplier%</white></gray>"

IMPORTANT

The bundled forge_gui template only provides blueprint and material slots; it has no target equipment input slot. When using the bundled GUI you must configure result.success.outputs, otherwise no forge result can be produced

Recipe result actions, material effect actions, and quality item_meta actions are merged and then applied to the result item together

Success rate and failure outcomes ​

success_rate defaults to 100, meaning the forge always succeeds. Set it below 100 and forging can fail, in which case one plan is picked from failure_outcomes by weight

FieldTypeRequiredDefaultAllowed valuesDescription
failure_outcomes[].typestringNoreturn_materialsreturn_materials / partial_consume / consume_materials (other values do not error but behave as a full refund)Failure handling plan
failure_outcomes[].weightintegerNo1>= 1 (values below 1 are raised to 1)Selection weight of this plan
failure_outcomes[].paramsobjectNoempty object—Plan parameters, read per type; undeclared keys use the source defaults
failure_outcomes[].params.return_ratenumberNo1.0 for return_materials; 0.5 for partial_consume0 ~ 1Refund ratio. Read only by those two type values
yaml
success_rate: 70
failure_outcomes:
  - type: "return_materials"
    weight: 50
    params:
      return_rate: 1.0
  - type: "partial_consume"
    weight: 30
    params:
      return_rate: 0.5
  - type: "consume_materials"
    weight: 20

NOTE

Without failure_outcomes, the default is return_materials with a full refund. Other type values do not raise an error but are treated as a full material refund

Quality configuration ​

See Quality for the full quality documentation. A typical recipe block:

yaml
quality:
  enabled: true
  custom_pool:
    - "Common-70-1.0"
    - "Fine-25-1.05"
    - "Epic-5-1.15"
  guarantee:
    enabled: true
    attempts: 10
    minimum: "Fine"

NOTE

The recipe-level pool field is custom_pool and the pity threshold field is attempts; the matching global keys in config.yml are tiers and threshold. custom_pool uses the "name-weight-multiplier" string form, and an empty pool falls back to the global pool

Guidance:

  • Give common tiers a large weight and rare tiers a small one
  • Give high-value recipes a pity so players do not go long without positive feedback
  • Keep quality ids consistent across presentation, attributes, and action config

Action nodes ​

NodeTypeTrigger
actions.prelist<string>Before recipe execution. If a pre-stage action fails, forging aborts and failure runs
actions.successlist<string>After a successful forge
actions.failurelist<string>After a failed forge
result.success.actionslist<string>When the result is generated or applied (before actions.success)

When you load a recipe, all four chains — actions.pre, result.success.actions, actions.success, and actions.failure — are trial-compiled with the CoreLib action engine; if any line fails to compile the recipe is rejected with INVALID_ACTION_LINE

The successful result chain runs in this order: result.success.actions → actions.success → quality actions. Actions inside each list run serially, and each stage waits for the previous stage to finish. Forge reads the final stack from the mutable item_target holder and delivers it only after all three stages settle. This lets EmakiItem component actions safely mutate the forge result without an older stack being delivered early. Failed action batches are logged but do not discard an already generated forge result

yaml
actions:
  pre:
    - 'send_message text="<gray>Forging begins..."'
  success:
    - 'send_title title="<green>Forged" subtitle="<gray>Your equipment was recast"'
    - 'play_sound sound=BLOCK_ANVIL_USE volume=1 pitch=1'
  failure:
    - 'send_message text="<red>The forge failed and the materials were ruined."'
    - 'play_sound sound=ENTITY_VILLAGER_NO volume=1 pitch=1'

NOTE

When actions.pre fails, the error message can use %reason%, %action%, and %line%

Available template variables ​

Available in result.success.name_actions value and result.success.lore_actions content:

VariableDescription
%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
%<stat_id>%Any variable injected through material variables effects, already scaled by material amount and quality multiplier

The complete variable set (including material effect and GUI variables) is in Placeholders

Minimal example ​

yaml
id: "flame_sword"
display_name: "<red>Flame Sword</red>"
permission: emakiforge.recipe.flame_sword
forge_capacity: 10
blueprint_requirements:
  - item_sources:
      - "minecraft-paper"
    amount: 1
materials:
  - item_sources:
      - "minecraft-blaze_rod"
    amount: 3
    capacity_cost: 5
    effects:
      - type: "variables"
        variables:
          fire_damage: 10
      - type: "lore_action"
        lore_actions:
          - action: "append"
            content:
              - "<red>Fire Damage: +%fire_damage%</red>"
optional_material_limit: 2
condition:
  type: all_of
  entries: []
quality:
  enabled: true
  custom_pool:
    - "Common-80-1.0"
    - "Fine-20-1.05"
result:
  success:
    outputs:
      - item_source: "minecraft-diamond_sword"
    name_actions:
      - action: "append_suffix"
        value: " <gray>[%quality_name%]</gray>"
    lore_actions:
      - action: "append"
        content:
          - ""
          - "<gray>Quality: <white>%quality_name%</white></gray>"
actions:
  success:
    - 'send_message text="<green>Flame power infused into the weapon."'