English
Gem Definitions
Gem definition files are stored in gems/*.yml. A gem definition describes how the gem item is recognized, which socket types it supports, what effects it provides, and how inlay, extraction, and upgrade costs are handled. The gem id comes from the id field inside the file and is unrelated to the file name. Shipped default file: gems/example_gem.yml
Top-level fields
| Field | Type | Required | Default | Range | Description |
|---|---|---|---|---|---|
id | string | Yes | — | — | Unique gem id. Lowercased on load; the file is skipped when blank |
display_name | string | No | id | MiniMessage text | Display name |
lore | list | No | empty list | MiniMessage text | Lore of the gem item itself |
gem_type | string | No | "universal" | any type name (commonly attack, defense, utility, universal) | Gem type used for socket compatibility matching |
level | integer | No | 1 | ≥ 1 | Base gem level; increases on upgrade |
base_item_source | string | Yes | — | item source shorthand "provider-itemId" | Construction base material: which item is built when the gem is granted. A single item source shorthand, not a list, and not a matching position. The gem is skipped when it cannot be parsed. The legacy top-level item_sources key is still read as a fallback for this value (only when it has exactly one entry) |
item_sources | list | No | empty (unrestricted) | item source shorthand | Recognition: allowed item sources for the gem item. ANDed with the sibling matcher |
matcher | object | No | empty | see Item Matcher | Recognition: non-item-source conditions only (component, PDC, lore) |
custom_model_data | integer | No | unset | any integer | Optional custom model data |
effects | list | No | empty list | see Effect types | Effects applied when the gem is inlaid |
socket_compatibility | list | No | empty (any socket type) | socket types; containing universal also means any | Socket types that can accept this gem |
required_gems | list | No | empty | gem ids | Gem ids this gem depends on; lowercased and deduplicated on load |
conflicting_gems | list | No | empty | gem ids | Gem ids that conflict with this gem; checked in both directions |
inlay_cost | object | No | no cost | see Cost configuration | Cost paid when inlaying |
extract_cost | object | No | no cost | see Cost configuration | Cost paid when extracting |
extract_return | object | No | original / 1 / 0.0 | see Return modes | How the gem is returned after extraction |
stages | object | No | disabled | see Upgrade stages | Upgrade stage settings. The parser reads stages first |
upgrade | object | No | — | same as stages | Fallback alias for stages. Read only when the file has no stages key |
reroll | object | No | disabled | see Reroll | Reroll settings |
actions.inlay_success | list | No | empty | CoreLib action lines | Action lines run after a successful inlay |
actions.extract_success | list | No | empty | CoreLib action lines | Action lines run after a successful extraction |
NOTE
Listing universal in socket_compatibility lets the gem go into any socket type
Minimal example
yaml
id: "ruby_basic"
display_name: "<red>Ruby</red>"
gem_type: "attack"
level: 1
base_item_source: "minecraft-redstone"
item_sources:
- "minecraft-redstone"
socket_compatibility:
- "attack"
- "universal"
effects:
- type: "variables"
variables:
physical_attack: 5
- type: "ea_attribute"
ea_attributes:
physical_attack: 5.0Effect types
| Type | Payload key | Description |
|---|---|---|
variables | variables | Runtime variables used by lore templates and formulas |
ea_attribute | ea_attributes | EmakiAttribute PDC attributes written to equipment |
es_skill | es_skills | EmakiSkills skill attachments |
name_action | name_actions | Name operations applied to equipment |
lore_action | lore_actions | Lore operations applied to equipment |
Values under variables and ea_attributes may be numbers or expressions and can reference %level%; keys resolved earlier in the same block are available as variables to later expressions
Top-level form
Besides the effects list, the parser also accepts variables, ea_attributes, name_actions, and lore_actions written directly on the gem root:
yaml
variables:
physical_attack: 8
ea_attributes:
physical_attack: 8.0variables and ea_attributes merge both forms, with keys from effects overriding top-level keys. For name_actions and lore_actions, a top-level value takes precedence and the matching effects entry is ignored. Skills can only be declared through es_skill inside effects
Cost configuration
inlay_cost, extract_cost (and reroll.full_cost / reroll.value_cost) share the same structure, a cost object:
| Field | Type | Required | Default | Range | Description |
|---|---|---|---|---|---|
currencies | list | No | empty list | each entry is a currency entry | Currency cost list |
materials | list | No | empty list | each entry is a material entry | Material cost list |
Currency entry (currencies[]):
| Field | Type | Required | Default | Range | Description |
|---|---|---|---|---|---|
provider | string | No | "auto" | economy provider id | Currency source; lowercased on load |
currency_id | string | No | "" | — | Currency id (a sub-currency under the same provider) |
amount | double | No | unset (formula used) | a value > 0 is used as a fixed amount | Fixed amount; when omitted or ≤ 0 the cost is computed from cost_formula / base_cost |
base_cost | double | No | 0 | ≥ 0 | Value of %base_cost% inside cost_formula |
cost_formula | string | No | "" | expression using %base_cost%, %level%, and so on | Amount formula; blank with no amount falls back to base_cost |
display_name | string | No | "" | MiniMessage text | Display name of the cost |
Every currency entry must supply at least one of amount (> 0), base_cost (> 0), or cost_formula, or it is dropped; an entry whose resolved amount is ≤ 0 does not take effect either
Material entry (materials[]):
| Field | Type | Required | Default | Range | Description |
|---|---|---|---|---|---|
item_sources | list | Yes | — | item source shorthand | Material item source (syntax in Item Source); the entry is dropped when it cannot be parsed |
amount | integer | No | 1 | ≥ 1 | Amount consumed |
Cost example
yaml
inlay_cost:
currencies:
- provider: "vault"
currency_id: ""
base_cost: 1000
cost_formula: "%base_cost% * %level%"
display_name: "<gold>Coins</gold>"
materials:
- item_sources:
- "minecraft-gold_nugget"
amount: 1Upgrade stages
Gems support level-based upgrade stages. You can override the display name and the effects at each stage to unlock stronger stats or skills
There are two possible top-level keys: the parser takes stages first and only falls back to upgrade when that key is absent. Both have exactly the same structure and meaning; upgrade is only a legacy alias
WARNING
When a file declares both stages and upgrade, upgrade is ignored entirely (the two are not merged). Use stages in new configuration
Stage block fields
| Field | Type | Required | Default | Range | Description |
|---|---|---|---|---|---|
enabled | boolean | No | true when at least one level parsed, otherwise false | true / false | Whether upgrading is enabled |
max_level | integer | No | the highest configured level, or 1 when none parsed | ≥ 1 | Maximum level; also the level upper bound used by item-layer previews |
gui_template | string | No | "" | GUI template id | Parsed and retained, but currently has no consumer, so setting it has no effect. The upgrade view reuses gui.gem_template from the socket item definition |
levels | object | No | empty | keys are integer levels greater than 1 | Per-level configuration. When this key is omitted, the numeric keys of the stage block itself are read as the level table |
Level keys must parse as integers greater than 1; 1 and below, and non-numeric keys, are skipped
Level fields
| Field | Type | Required | Default | Range | Description |
|---|---|---|---|---|---|
display_name | string | No | "" | MiniMessage text | Display name for that level |
variables | object | No | empty | key/value pairs; values may be numbers or expressions | Expression variables for that level; keys are lowercased and an earlier-resolved key is available to later expressions |
ea_attributes | object | No | empty | key/value pairs; values may be numbers or expressions | PDC attributes for that level |
effects | list | No | empty list | see Effect types | Effect list for that level, same format as the base effects |
name_actions | object/list | No | empty | CoreLib name operations | Name operations for that level; takes precedence over the base name_actions when present |
lore_actions | object/list | No | empty | CoreLib lore operations | Lore operations for that level; takes precedence over the base lore_actions when present |
matrices | object | No | empty | string key/value pairs | String key/value table for that level; keys are lowercased |
DANGER
Neither the stage block nor a level block reads materials, economy, success_rate, success_rates, or failure_penalty. Writing those keys into a gem definition raises no error but has no effect at all. Upgrade materials, costs, and the success roll are decided by the matching EmakiStrengthen enhancement recipe; without a usable recipe, or when EmakiStrengthen is unavailable, the upgrade entry reports that upgrading is unavailable
Stage example
yaml
stages:
enabled: true
max_level: 4
gui_template: "upgrade/default"
levels:
2:
display_name: "<red>Ruby II</red>"
effects:
- type: "variables"
variables:
physical_attack: 12
- type: "ea_attribute"
ea_attributes:
physical_attack: 12.0Omitting levels and writing levels directly under the stage block is equivalent:
yaml
stages:
2:
display_name: "<red>Ruby II</red>"
3:
display_name: "<red>Ruby III</red>"Reroll
Reroll re-rolls a gem's affixes. Configure it in the reroll block of a gem definition; skip that block and reroll stays disabled for the gem
Reroll block fields
| Field | Type | Required | Default | Range | Description |
|---|---|---|---|---|---|
enabled | boolean | No | true when a reroll block is present; reroll is disabled when the block is absent | true / false | Whether reroll is enabled |
group | string | No | "default" | affix pool group name | When pools has no such group, the pool named default is used instead; with no default either the pool counts as empty and reroll fails |
max_affixes | integer | No | 1 | ≥ 1 | Upper bound on affixes generated by a full reroll |
pools | object | No | empty | keys are group names, values are affix entry lists | Affix pools. Fallback alias affixes (read only when pools is absent) |
full_cost | object | No | no cost | same structure as inlay_cost, see Cost configuration | Cost of a full reroll |
value_cost | object | No | no cost | same structure as inlay_cost, see Cost configuration | Cost of a value reroll |
Affix entry fields
| Field | Type | Required | Default | Range | Description |
|---|---|---|---|---|---|
id | string | No | the entry key in map form | — | Affix id; the entry is skipped in list form when no id can be found |
weight | double | No | 1 | ≥ 0; non-positive values are recorded as a diagnostic | Roll weight |
min / max | double | No | min = 0, max = min | a value range; min and max are swapped when max < min | Value range. Aliases min_value / max_value |
min_stage / max_stage | integer | No | 1 / unbounded | ≥ 1 and max_stage ≥ min_stage | Usable stage range; entries outside the range are filtered out by the gem's current stage before rolling |
display_name | string | No | id | MiniMessage text | Affix display name |
attribute_id | string | No | id | attribute id | Matching attribute id |
Reroll modes
| Mode | Behaviour | Cost key |
|---|---|---|
| Full reroll | Re-rolls the affixes themselves by weight. The count is the smaller of max_affixes and the existing affix count, or max_affixes when the gem has no affixes yet | full_cost |
| Value reroll | Keeps the existing affix ids and stages and only re-rolls values inside each affix's min/max range | value_cost |
Settlement rules
Reroll runs in two steps: generate a candidate first, then confirm it:
- Opening reads the gem in the main hand, generates a candidate, charges immediately, and opens a candidate session with a time-to-live
- Confirming validates the config fingerprint and the item instance; the candidate is written to the main-hand gem only when both match
WARNING
If the gem definition changed before confirmation (fingerprint mismatch), or the main-hand item changed, the session fails and is discarded. Every termination path other than a successful confirm refunds the charge; when the player is offline at that moment the refund becomes pending and runs once the player can be scheduled again
yaml
reroll:
enabled: true
group: "default"
max_affixes: 2
pools:
default:
- id: "physical_attack"
weight: 10
min: 5
max: 12
min_stage: 1
- id: "physical_crit_rate"
weight: 5
min: 1
max: 4
full_cost:
currencies:
- provider: "vault"
currency_id: ""
base_cost: 3000
display_name: "<gold>Coins</gold>"
value_cost:
currencies:
- provider: "vault"
currency_id: ""
base_cost: 800
display_name: "<gold>Coins</gold>"Reroll command entries and the session query API are documented in Commands and Permissions and API
Design notes
- Use stable
item_sourcesfor recognition instead of display names or lore matching, and keepbase_item_sourcepointing at the item you actually hand out - Keep
gem_typeandsocket_compatibilitysimple and easy to understand - Write real stats through
ea_attribute; use lore actions only for presentation - Use
extract_returncarefully on high-value gems