English
Quality System
The quality system picks the tier a forge result lands on and also scales material effect values and the item presentation
Global configuration
Quality is configured globally under the quality node of config.yml. Shipped defaults:
yaml
quality:
tiers:
- name: "平庸"
weight: 60
multiplier: 1.0
- name: "精良"
weight: 30
multiplier: 1.05
- name: "有缺"
weight: 10
multiplier: 0.95
- name: "优质"
weight: 5
multiplier: 1.1
- name: "无暇"
weight: 2
multiplier: 1.15
- name: "完美"
weight: 1
multiplier: 1.2
default_tier: "平庸"
guarantee:
enabled: true
threshold: 60
minimum: "无暇"
item_meta:
enabled: true
tiers:
无暇:
name_actions:
- action: "prepend_prefix"
value: "<color:#4B64C8>[无暇] </color>"
lore_actions:
action:
- 'broadcast_message text="<color:#4B64C8>%player_name% forged a 无暇 item: %var.forge_show_item%</color>"'
完美:
name_actions:
- action: "prepend_prefix"
value: "<color:#FFD700>[完美] </color>"
lore_actions:
action:
- 'broadcast_message text="<color:#FFD700>%player_name% forged a 完美 item: %var.forge_show_item%</color>"'
# 平庸 / 精良 / 有缺 / 优质 only define name_actions and no broadcast actionconfig.yml registers 6 item_meta.tiers entries; the sample above omits the other 4, which share the same shape as 无暇 but define only name_actions
quality fields
| Field | Type | Required | Default | Allowed values | Description |
|---|---|---|---|---|---|
quality.tiers | list<object> | No | A single 普通 tier (weight 100, multiplier 1.0) | Each entry is a record or a "name-weight-multiplier" string | Quality pool. When empty, or when every entry is invalid, Forge falls back to the built-in default pool and disables pity and item_meta as well |
quality.tiers[].name | string | Yes (when the record exists) | — | Non-blank string | Unique tier id and display name. Entries with a blank name are ignored |
quality.tiers[].weight | integer | Yes (when the record exists) | — | > 0 | Draw weight; higher means more common. Entries with <= 0 are ignored |
quality.tiers[].multiplier | number | No | 1.0 | Any number | Multiplier applied to material effects (configured value × material amount × quality multiplier) |
quality.default_tier | string | No | 普通 | A tier name present in the pool | Fallback tier when no valid tier name matched. If the name does not exist, the first pool entry is used |
quality.guarantee | object | No | see below | — | Pity configuration, see Pity |
quality.item_meta | object | No | see below | — | Quality item metadata, see Item meta by quality |
yaml
quality:
tiers:
- name: "普通"
weight: 70
multiplier: 1.0
- name: "精良"
weight: 25
multiplier: 1.05
- name: "史诗"
weight: 5
multiplier: 1.15
default_tier: "普通"tiers format
Each quality.tiers entry can be written either as the record above or as a "name-weight-multiplier" string split by -; an entry that fails both parses is ignored
NOTE
If every tiers entry fails to parse, Forge falls back to the built-in default pool (a single 普通 tier with weight 100 and multiplier 1.0), with pity and item_meta both disabled
Pity
The "Default" column below is what the code uses when the key is missing from your config. It differs from the shipped config.yml, which sets enabled: true, threshold: 60, and minimum: "无暇" — so the default configuration does have pity enabled
| Field | Type | Required | Default | Allowed values | Description |
|---|---|---|---|---|---|
quality.guarantee.enabled | boolean | No | false | true / false | Whether global pity is enabled. The shipped value is true |
quality.guarantee.threshold | integer | No | 10 | >= 1 (values below 1 are raised to 1) | Number of consecutive attempts below the minimum tier before pity triggers. The shipped value is 60 |
quality.guarantee.minimum | string | No | 普通 | A tier name present in the pool | Minimum tier granted when pity triggers. When the name does not exist it falls back to default_tier. The shipped value is 无暇 |
Pity rules:
- After each forge, the drawn tier's position in the quality pool is compared with the pity minimum tier's position
- If the drawn tier ranks lower, the pity counter increases by 1; otherwise it resets to 0
- Once the counter reaches
threshold - 1, the next forge directly grants the pity tier and resets the counter
yaml
quality:
guarantee:
enabled: true
threshold: 30
minimum: "精良"NOTE
Pity counters are tracked per player and recipe and stored in data/<player-uuid>.yml. The force mode of quality_modify skips all pity logic: it neither triggers pity nor updates the counter. Recipe-level pity (attempts) and global pity never both take effect; see Recipe override
Item meta by quality
When quality.item_meta.enabled is true, the result item receives quality-specific name operations, lore operations, and actions
| Field | Type | Required | Default | Allowed values | Description |
|---|---|---|---|---|---|
quality.item_meta.enabled | boolean | No | false | true / false | Whether the tier's name, lore, and actions are written to the forge result. The shipped value is true |
quality.item_meta.tiers.<tier> | object | No | empty | Key is a tier name, case-insensitive | Metadata registered per tier. An entry whose tier name is not in the registry has no effect |
quality.item_meta.tiers.<tier>.name_actions | object | list | No | not registered | CoreLib name operations | Name operations applied to the result item. A null value (key written without a value) does not register a name action for that tier |
quality.item_meta.tiers.<tier>.lore_actions | object | list | No | not registered | CoreLib lore operations | Lore operations applied to the result item. In the shipped config.yml this key is written without a value (null), which means "do not register a lore action for this tier"; that differs from an explicit empty list [], which registers an empty action chain |
quality.item_meta.tiers.<tier>.action | list<string> | No | empty list | CoreLib action lines | Action lines executed per tier, such as a server-wide broadcast |
A copyable example: prefix 精良 items and let 完美 trigger a broadcast
yaml
quality:
item_meta:
enabled: true
tiers:
精良:
name_actions:
- action: "prepend_prefix"
value: "<color:#1F871F>[精良] </color>"
完美:
name_actions:
- action: "prepend_prefix"
value: "<color:#FFD700>[完美] </color>"
action:
- 'broadcast_message text="<color:#FFD700>%player_name% forged a 完美 item: %var.forge_show_item%</color>"'Quality metadata actions, recipe result.success actions, and material effect actions are merged and then applied to the result item together
Deterministic calculation
Quality uses a deterministic algorithm: the tier is derived from a fingerprint of "player UUID + recipe id + current pity counter + target and per-slot item signatures" plus a preview seed, rather than rolling a fresh random number each time. Internally that roll key is hashed with SHA-256, and the first 12 hex characters are converted into a 0~1 ratio used for weighted selection over the quality pool
The prepared forge result cache holds at most 128 entries with a 30-second TTL, so:
- The quality shown in the GUI matches the actual forging result
- Resubmitting the same input within 30 seconds does not change the result
- Changing materials or waiting for the cache to expire changes the result
Recipe override
Recipes can override global quality configuration under their own quality node. Note the recipe-level field names differ from the global config:
yaml
quality:
enabled: true
custom_pool:
- "Common-50-1.0"
- "Fine-35-1.08"
- "Epic-15-1.25"
guarantee:
enabled: true
attempts: 5
minimum: "Fine"| Field | Type | Required | Default | Allowed values | Description |
|---|---|---|---|---|---|
enabled | boolean | No | false | true / false | Whether recipe-level quality configuration is enabled. When false, neither custom_pool nor recipe-level pity applies |
custom_pool | list<string> | No | empty | "name-weight-multiplier" strings | Recipe-specific quality pool. When empty, or when every entry is invalid, the global quality.tiers is used |
guarantee.enabled | boolean | No | false | true / false | Whether recipe-level pity is enabled |
guarantee.attempts | integer | No | 10 | >= 1 (values below 1 are raised to 1) | Recipe-level pity threshold. Corresponds to threshold in the global config |
guarantee.minimum | string | No | 普通 | A tier name present in the pool | Recipe-level pity minimum tier. When the name does not exist the first pool entry is used, and failing that the global pity minimum |
NOTE
When recipe-level pity is disabled but global pity is enabled, Forge falls back to the global threshold and minimum. attempts / minimum are only used when both recipe quality.enabled and quality.guarantee.enabled are true
Interaction with material effects
variableseffect value =configured value × material amount × quality multiplierea_attributeeffect value =configured value × material amount × quality multiplier- The
forcemode ofquality_modifyskips pity evaluation and counter updates - The
minimummode ofquality_modifyraises the result only when the drawn tier is below the specified tier
See Materials for the full material effect syntax