Skip to content

Materials and Quality

This page provides detailed documentation on EmakiForge's material definition format, quality calculation pipeline, pity mechanism, blueprint format, and item refresh service.

Quality System

Quality Tier Format

Quality tiers are defined using a compact three-segment format:

"name-weight-multiplier"
SegmentTypeDescriptionExample
NameStringDisplay name of the quality传说
WeightIntegerWeight for weighted randomization2
MultiplierDoubleMultiplier for material contributions2.0

Example quality pool:

yaml
tiers:
  - "粗糙-40-0.6"     # 40% weight, 0.6 multiplier
  - "普通-30-1.0"     # 30% weight, 1.0 multiplier
  - "精良-20-1.3"     # 20% weight, 1.3 multiplier
  - "史诗-8-1.6"      #  8% weight, 1.6 multiplier
  - "传说-2-2.0"      #  2% weight, 2.0 multiplier

Quality Calculation Pipeline

The final quality is determined through the following pipeline:

1. Determine quality pool
   ├── Recipe declares custom_pool? → Use recipe's custom quality pool
   └── Not declared? → Use global tiers from config.yml

2. Apply material quality modifiers
   ├── Has force modifier? → Directly use force-specified quality, skip to step 4
   └── Has minimum modifier? → Record minimum quality tier

3. Check pity counter
   ├── Counter ≥ guarantee.count? → Force guarantee.tier, reset counter
   └── Not reached? → Continue

4. Execute weighted random
   └── Randomly select a quality tier from the pool by weight

5. Apply minimum modifier
   ├── Random result below minimum? → Raise to minimum tier
   └── Random result ≥ minimum? → Keep random result

6. Update pity counter
   ├── Final quality ≥ guarantee.tier? → Reset counter to 0
   └── Final quality < guarantee.tier? → Counter +1

Pity Counter Mechanism

The pity system prevents players from being unable to obtain high-quality products for extended periods:

yaml
guarantee:
  enabled: true
  count: 50        # 50 consecutive misses of target quality
  tier: "史诗"     # Force Epic quality on the 51st attempt

How it works:

  • After each forging, if the final quality is below guarantee.tier, the counter increments by 1
  • If the final quality meets or exceeds guarantee.tier, the counter resets to 0
  • When the counter reaches the count threshold, the next forging forces guarantee.tier quality
  • The pity counter is tracked per player and stored in player data

Material Quality Modifiers

Materials can influence quality results through the quality_modify effect:

modifier_typeBehaviorPriority
forceForces quality to the specified tier, skipping randomizationHighest — direct override
minimumSets a quality floor; raises the result if random outcome is below this tierApplied after randomization
yaml
# Force quality example
effects:
  - type: quality_modify
    modifier_type: force
    tier: "传说"

# Minimum quality example
effects:
  - type: quality_modify
    modifier_type: minimum
    tier: "精良"

Note

When multiple materials declare force modifiers simultaneously, the last one to take effect wins. It is recommended to have at most one force modifier material per forging.

Quality structured_presentation Example

Quality tiers can be displayed on item names via item_meta.structured_presentation:

yaml
quality:
  item_meta:
    structured_presentation:
      name_contributions:
        quality_prefix:
          order: 0
          format: "{quality} "
      lore_sections:
        quality_info:
          order: 0
          lines:
            - "<gray>品质:<white>{quality}"
            - "<gray>倍率:<white>×{multiplier}"

Quality Action Examples

Trigger different actions based on quality tier (e.g., server-wide broadcast):

yaml
quality:
  actions:
    传说:
      - "broadcast message=<gold>✦ {player} <yellow>锻造出了 <gold>传说 <yellow>品质的 {item}!"
      - "playsound sound=ui.toast.challenge_complete volume=1.0 pitch=1.0"
      - "firework location=player colors=GOLD,YELLOW"
    史诗:
      - "playsound sound=entity.player.levelup volume=1.0 pitch=1.2"
      - "sendmessage message=<light_purple>锻造出了史诗品质!"

Blueprint Format

Blueprints define the base template for forging and are stored in the blueprints/ directory:

yaml
# Blueprint unique identifier
id: iron_sword_blueprint

# Display name
displayName: "<white>铁剑图纸"

# Item source (used to match the blueprint item placed by the player)
source: "minecraft:paper"

# Tags (used for blueprint_requirements matching in recipes)
tags:
  - sword
  - iron
  - melee

# Forge capacity (base capacity provided by the blueprint, stacks with recipe's forge_capacity)
forgeCapacity: 50
FieldTypeRequiredDescription
idStringYesBlueprint unique identifier
displayNameStringYesDisplay name, supports MiniMessage
sourceStringYesItem source ID, used for matching
tagsListNoTag list, used for recipe matching
forgeCapacityIntegerNoBase forge capacity provided by the blueprint

Material Format

Materials define the input items required for forging and their effects. They are stored in the materials/ directory or inlined directly in recipes:

yaml
# Item source ID
item: "minecraft:iron_ingot"

# Required amount
amount: 5

# Whether this is an optional material
optional: false

# Capacity cost (forge capacity points consumed)
capacity_cost: 10

# Material effect list
effects:
  - type: stat_contribution
    stat: physical_damage
    amount: 12.0
  - type: attribute
    attributes:
      physical_attack: 10.0
      physical_crit_rate: 5.0
  - type: skill
    skills:
      - "fireball"
  - type: quality_modify
    modifier_type: minimum
    tier: "精良"
FieldTypeRequiredDefaultDescription
itemStringYesItem source ID
amountIntegerYesRequired amount
optionalBooleanNofalseWhether this is an optional material
capacity_costIntegerNo0Capacity cost
effectsListNo[]Material effect list

ForgeItemRefreshService

The item refresh service automatically refreshes an item's display state when the forge layer data signature changes.

Trigger Conditions

  • When a player opens their inventory
  • When a player switches held items
  • When an admin executes the refresh command
  • After recipe/material resource reload

Refresh Pipeline

Check if item contains forge layer data

Read forge layer snapshot from item PDC

Calculate current snapshot signature (based on recipe version, material definitions, etc.)

Compare with old signature stored on the item
    ├── Signatures match → Skip refresh
    └── Signatures differ → Execute refresh

    Rebuild structured_presentation based on latest recipe and material definitions

    Update item name, Lore, and PDC data

    Write new signature

Signature Comparison

The signature is calculated based on the following data:

  • Recipe ID and version
  • Hash of material definitions
  • Quality tier and multiplier
  • Hash of structured_presentation templates

When a server admin modifies recipe or material definitions and reloads, the signatures of already-forged items will no longer match the new definitions, triggering automatic refresh to ensure all existing items' displays stay consistent with the latest configuration.

Tip

The refresh service only updates the item's display layer (name, Lore) and does not change the item's actual attribute values. Attribute values are determined at forging time and written to PDC, unaffected by subsequent configuration changes.

Released under the GPL-3.0 License