English
Item Definitions and Sets
Item files live under items/ (items/*.yml), set files under sets/ (sets/*.yml); every field in both file types is described below. With an item definition you decide how a stable item ID produces an in-game item (ItemStack); with a set definition you decide what bonuses players get when they wear several pieces at once
Watch for one exception under items/: pack.yml is not an item definition. It describes how its directory looks as an item pack in the browser and is skipped by the item loader. See Browser GUI for its fields
Item definition fields
Top-level fields
Before reading the table, keep two points in mind: "Required" asks whether the plugin falls back on its own when a key is missing; "Range" states the constraint the plugin actually enforces, with "—" meaning the plugin performs no validation
| Field | Type | Required | Default | Range | Description | Example |
|---|---|---|---|---|---|---|
id | string | Yes | — | — | Unique item ID used by other modules. A blank or missing value skips the file | example_item |
item | object | Yes | — | — | Base-item definition; only source and components are read. When absent the definition cannot build a base item and is skipped with a warning | see "item and item.components" |
effects | list | No | — | type values in "Effects system" | The only entry point for business effects: variables, EmakiAttribute attributes, EmakiSkills skills, accessory slot declarations, and name/lore operation chains all go here | see "Effects system" |
equip_slot | string | No | all | all / hand / main_hand / off_hand / helmet / chestplate / leggings / boots | Equipment slot used by business attributes and skills; it does not intercept vanilla drag-and-drop equipping. Unsupported values fall back to all with a warning | main_hand |
set | object | No | — | — | Set membership with id and piece | see "set" |
condition | object | No | — | — | Equipment condition block; fields in "Equipment conditions" | see "Equipment conditions" |
repair | object | No | — | — | Repair configuration; fields in Item Repair | see "Repair configuration" |
update | object | No | — | — | Auto-update configuration; fields in Item Update Strategy | see below |
actions | object | No | — | — | Trigger action configuration. Keys must be trigger names listed on the Triggers page | right_click: [...] |
Retired fields and syntaxes
The syntaxes below are no longer read: writing them has no effect at all and only logs one WARN on load (with the field names and file path). Rewrite them as shown
| Retired syntax | Location | Rewrite as |
|---|---|---|
variables, ea_attributes, es_skills, accessory_slots | root | the matching type entry inside effects |
es_skill_triggers, skill_triggers | root | es_skill_triggers inside a type: "es_skill" effect |
name_actions, lore_actions | root | a type: "name_action" / type: "lore_action" effect |
source, components | root | move into item.source / item.components |
amount | root and item.amount | definitions no longer carry a stack size; use /ei give <player> <id> [amount], which defaults to 1 |
material, display_name, item_name, lore | root | custom_name / item_name / lore components under item.components |
item_source, item | inside a repair.materials entry | item_sources |
skill_triggers | inside a type: "es_skill" effect | es_skill_triggers |
Why were they retired? The effect shorthands and effects were two entry points for the same data: when both were written, the merge result differed per field (override, union, or an action running twice), so you could not tell from the configuration which one took effect. amount was retired because the stack size can be given at give time instead
Sub-fields of set and update:
| Field | Type | Required | Default | Range | Description | Example |
|---|---|---|---|---|---|---|
set.id | string | No | "" | — | Owning set ID, matching sets/*.yml. Empty means the item takes no part in set calculation | example_set |
set.piece | string | No | "" | — | The item's piece identifier in the set; it must match a pieces key in the set definition | blade |
update.enabled | boolean | No | false | true / false | Whether item update is enabled; it only applies when true and version >= 1 | true |
update.version | integer | No | 0 | >= 0 (applies at >= 1) | Item version; the item is rebuilt only when it exceeds the version stored in item PDC | 1 |
update.preserve_amount | boolean | No | true | true / false | Preserve stack amount during the update | true |
update.preserve_damage | boolean | No | true | true / false | Preserve durability damage during the update | true |
update.preserve_unknown_attribute_sources | boolean | No | true | true / false | Preserve attributes from unknown sources during the update | true |
update.triggers | object | No | — | see Item Update Strategy | Update trigger switches; omitted entries default to true | join: true |
An item definition now has exactly two entry points: item (item.source + item.components) and effects; none of the legacy syntax from the list above is read any more. Definitions also no longer declare a stack size — with /ei give <player> <id> [amount] you get 1 when the amount is omitted, the browser GUI gives 1 on click and a full stack on shift-click, and other modules pass the amount they need
item and item.components
| Field | Type | Required | Default | Range | Description | Example |
|---|---|---|---|---|---|---|
item.source | string | No | — | any ItemSource registered by CoreLib | Base item source (ItemSource shorthand). When missing or unbuildable the definition is rejected from the cache | minecraft-diamond_sword |
item.components | map | No | — | — | Vanilla Data Component overrides. Keys may be namespaced component IDs or the EmakiItem shorthand keys below | see below |
EmakiItem shorthand keys for item.components (converted into the matching namespaced component):
| Field | Type | Required | Default | Range | Description | Example |
|---|---|---|---|---|---|---|
custom_model_data | scalar/map | No | — | — | Custom model data. A scalar is wrapped as floats: [value]; a map already carrying floats/flags/strings/colors is used as-is | floats: [1001.0] |
item_model | string | No | "" | — | Item model ID; blank means no patch | minecraft:custom/example_blade |
tooltip_style | string | No | "" | — | Tooltip style ID; blank means no patch | minecraft:custom/rare_tooltip |
enchantments | map | No | empty | values must be positive integers | Enchantment ID → level; non-positive or unparsable entries are dropped | minecraft:sharpness: 5 |
item_flags | list | No | empty | see below | Legacy hide flags, mapped into minecraft:tooltip_display.hidden_components | - HIDE_ATTRIBUTES |
hide_tooltip | boolean | No | false | true / false | Whether to hide everything in the tooltip (tooltip_display.hide_tooltip) | true |
unbreakable | boolean | No | false | true / false | Whether to write minecraft:unbreakable | true |
enchantment_glint_override | boolean | No | none | true / false | Whether to force the enchantment glint; omitting it leaves the component untouched | true |
max_stack_size | int | No | none | range allowed by the vanilla component | Maximum stack size | 1 |
rarity | string | No | "" | vanilla rarity names | Item rarity; blank means no patch | rare |
damage | int | No | none | range allowed by the vanilla component | Initial durability damage | 0 |
max_damage | int | No | none | range allowed by the vanilla component | Maximum durability | 1561 |
enchantable | int | No | none | — | Enchantability value, written as minecraft:enchantable.value | 15 |
attribute_modifiers | list | No | empty | — | Vanilla attribute modifier list. In the shorthand form each entry takes attribute (attribute ID), amount, operation (default add_number), slot (default any), and name (default emakiitem:<item id>/<attribute>); the namespaced component form uses the standard type/id/amount/operation/slot structure | see "Shared item definition and components" |
raw | string | No | "" | — | Reserved key: the source reads it, but the current version produces no component from it | — |
Here is the item_flags mapping to components: HIDE_ENCHANTS→enchantments, HIDE_ATTRIBUTES→attribute_modifiers, HIDE_UNBREAKABLE→unbreakable, HIDE_DESTROYS→can_break, HIDE_PLACED_ON→can_place_on, HIDE_ADDITIONAL_TOOLTIP (or HIDE_POTION_EFFECTS) →potion_contents, HIDE_DYE→dyed_color, HIDE_ARMOR_TRIM→trim; any other value is treated as a component ID verbatim
Automatic migration of legacy item definitions has been retired
Watch out after upgrading: items/*.{yml,yaml} definitions are no longer migrated before parsing: CoreLib has removed the item.migration.configureditem package and the runtime LegacyConfiguredItemConverter, and EmakiItem's loading entry point no longer invokes a migration runner. File-rewriting migration is retired, and the parser's compatibility reading of the root-level source / amount / components shorthand is retired as well — a base item can now only be declared under item:
item.sourcefor the source, for exampleminecraft-diamond_sworditem.componentsfor names, lore, model data, enchantments, and other components- The stack size is not declared in the definition; pass it to
/ei give <player> <id> [amount]
Back up the configuration directory before upgrading, then rewrite legacy fields by hand: they are not rewritten, filled in, or silently honoured — writing one logs a WARN on load. No plugins/EmakiItem/migration-backups/configured-item-format/ backup is produced any more, while backups written during the migration window stay in that directory and can be cleaned up manually
effects, equip_slot, set, condition, repair, update, and actions keep their existing semantics
Effects system
Write all item effects in one effects list and pick the kind with a type field:
| type | Description |
|---|---|
variables | Expression engine variables for placeholder rendering in names and lore; payload uses a variables map |
ea_attribute | EmakiAttribute PDC attributes written to item PDC; payload uses an ea_attributes map |
es_skill | EmakiSkills skill attachment, granted when equipped; payload uses the es_skills list and an optional es_skill_triggers map |
accessory_slot | Accessory slot declaration: writes the accessory slots this item may enter into item PDC so EmakiAccessory can decide placement; payload uses an accessory_slots list |
name_action | Name operation chain; payload uses a name_actions (or name_action) list |
lore_action | Lore operation chain; payload uses a lore_actions (or lore_action) list |
Besides these six built-in type values, you can register your own type through EmakiItemApi.extensions().registerEffectType(...); an entry whose type has no registered handler is skipped silently. See API
yaml
effects:
- type: "variables"
variables:
physical_attack: 12
physical_crit_rate: 5
- type: "ea_attribute"
ea_attributes:
physical_attack: 12.0
physical_crit_rate: 5.0
- type: "es_skill"
es_skills:
- "fireball"
- "flame_dash"
es_skill_triggers:
fireball: "right_click"
- type: "accessory_slot"
accessory_slots:
- "ring"Add the optional es_skill_triggers map (form skill_id: trigger_id) to an es_skill effect: it writes a forced equipment trigger, so the skill is cast by the given trigger while equipped and does not occupy a player skill slot
For real attribute output, put the values in the ea_attributes payload of a type: ea_attribute effect; current configs no longer use ea_attribute_meta. variables are only text/placeholder context and do not automatically become Attribute PDC attributes
When skill IDs and skill triggers are written to item PDC, the plugin does not check whether EmakiSkills is enabled; those keys are owned by a standalone protocol module
Accessory slot declaration (accessory_slot)
accessory_slot answers one question only: which accessory window cells this item may occupy. It does not participate in vanilla equipment slot matching and does not change equip_slot semantics. The list accepts two granularities:
| Value | Meaning | Example |
|---|---|---|
| Accessory part id | Any cell of that part accepts it | ring accepts both ring_1 and ring_2 |
| Slot instance id | Only that one cell accepts it | ring_2 accepts the second cell only |
Part ids live in EmakiAccessory's parts.yml (<partId>_<index> expands to slot instance ids). Values are normalized (trimmed, lowercased) and de-duplicated; an empty list means no declaration
The declaration lives under the item PDC key emakiitem:accessory_slots (string list). EmakiAccessory reads only that key as the only item-carried declaration source:
- An item without the key never enters the accessory window; the plugin reports
gui.not_declared - An item that declares the key but not the current cell is rejected, reporting
gui.slot_mismatch - An item already in a slot that stops matching is returned to the player's inventory with a message when the accessory window closes
This replaces the old behaviour: an unspecified slot used to fall back to all, so any EmakiItem item could enter any accessory cell. Your existing items gain the new key only when an update trigger rewrites them (see item update) or when you re-issue them; the accessory slot declaration participates in the definition signature, so adding it marks the definition as needing an update
The full accessory-side rules, condition gating and durability semantics live in attribute and skill integration
Shared item definition and components
yaml
item:
source: minecraft-netherite_sword
components:
custom_name: '<gradient:red:gold>%name%</gradient>'
lore:
- '<gray>Attack: %physical_attack%</gray>'
item_model: emaki:flame_blade
custom_model_data:
floats: [1001.0]
attribute_modifiers:
- type: minecraft:attack_damage
id: emakiitem:flame_blade/attack_damage
amount: 12.0
operation: add_value
slot: mainhand
rarity: rare
max_stack_size: 1
$unset:
- repairable
$reset:
- enchantmentsKeys under components are namespaced Minecraft data-component IDs. A missing namespace defaults to minecraft: — custom_name equals minecraft:custom_name — while explicit namespaces are preserved, and the same rule applies to $unset / $reset entries. Write JSON objects, arrays, and scalars directly as YAML maps, lists, and scalars: a normal value means SET, $unset removes a component, and $reset restores the material prototype default. Text components accept MiniMessage string shorthand. For the rare NBT value that JSON cannot represent losslessly, use the controlled {$snbt: '...'} escape hatch
Error and version behavior:
- Unknown component IDs are configuration errors and the definition is not cached
- Invalid values for components supported by the current server are configuration errors and the definition is not cached
- Known components introduced after the server version are skipped with a warning while the remaining components continue
- Third-party ItemSources retain source identity, PDC, and unknown components; only patches that the current Paper runtime can safely transfer are applied
item.source accepts every ItemSource registered by CoreLib, not only Bukkit materials. If the resolver is missing, the plugin is not installed, or the source cannot create a base item, the EmakiItem definition is rejected and never cached. The minimum supported runtime is Paper 26.1+; the maintained component catalog and runtime capabilities together determine availability
Item examples
Basic weapon
yaml
id: "beginner_blade"
item:
source: minecraft-iron_sword
components:
minecraft:custom_name: "<white>Beginner Longsword</white>"
minecraft:lore:
- "<gray>A steady, reliable starter weapon.</gray>"
- ""
- "<gray>Attack: <white>+10</white></gray>"
minecraft:unbreakable: {}
minecraft:tooltip_display:
hidden_components:
- minecraft:unbreakable
effects:
- type: "ea_attribute"
ea_attributes:
physical_attack: 10.0
set:
id: "beginner_set"
piece: "weapon"Advanced equipment with variables
yaml
id: "flame_blade"
item:
source: minecraft-netherite_sword
components:
minecraft:custom_name: "<gradient:red:gold>%name%</gradient>"
minecraft:lore:
- "<dark_gray>━━━━━━━━━━━━━━━━━━</dark_gray>"
- "<red>⚔ Physical attack: <white>+%physical_attack%</white></red>"
- "<yellow>✦ Crit rate: <white>+%physical_crit_rate%%</white></yellow>"
- "<dark_gray>━━━━━━━━━━━━━━━━━━</dark_gray>"
- "<gray>A legendary blade forged in dragon fire.</gray>"
minecraft:item_model: "emaki:flame_blade"
minecraft:enchantment_glint_override: true
minecraft:rarity: "rare"
minecraft:max_stack_size: 1
effects:
- type: "variables"
variables:
name: "Flame Blade"
physical_attack: 45
physical_crit_rate: 12
- type: "ea_attribute"
ea_attributes:
physical_attack: 45.0
physical_crit_rate: 0.12
- type: "es_skill"
es_skills:
- "flame_slash"
set:
id: "flame_set"
piece: "weapon"Consumable
yaml
id: "health_potion_large"
item:
source: minecraft-potion
components:
minecraft:custom_name: "<red>Large Health Potion</red>"
minecraft:lore:
- "<gray>Right-click to restore 50 health.</gray>"
- "<dark_gray>Consumed on use.</dark_gray>"
minecraft:max_stack_size: 16
minecraft:custom_model_data:
floats: [1001.0]
actions:
right_click:
- 'heal amount=50'
- 'play_sound sound=minecraft:entity.generic.drink volume=1 pitch=1'
- 'clear_item slot=mainhand source=emakiitem-health_potion_large'
- 'send_message text="<green>Restored 50 health.</green>"'Set definitions
Drop set files under sets/; subdirectories are loaded recursively. When id duplicates, only the first definition is kept and a warning is logged
| Field | Type | Required | Default | Range | Description | Example |
|---|---|---|---|---|---|---|
id | string | Yes | — | — | Unique set ID. The file is skipped when it is missing or invalid (normalizes to empty) | example_set |
display_name | string | No | the set ID | — | Set display name (MiniMessage); an empty value falls back to the set ID | <aqua>Example Guardian Set</aqua> |
pieces | map | No | empty | — | Set piece definitions, keyed by piece ID | see "Piece definitions" |
lore | object | No | see "Lore display configuration" | — | Lore rendering configuration for set status display | see "Lore display configuration" |
thresholds | map | No | empty | keys must be positive integers | Piece-count threshold effects; non-positive or non-section entries are skipped | 2: {...} |
Set bonuses refresh according to config.yml > set_bonus.refresh_triggers
Piece definitions
yaml
pieces:
blade:
item: "example_item"
slot: "main_hand"
display: "Example Blade"
helmet:
item: "example_guardian_helmet"
slot: "helmet"
display: "Guardian Helmet"| Field | Type | Required | Default | Range | Description | Example |
|---|---|---|---|---|---|---|
item | string | No | the piece key | — | The matching item ID from items/ | example_item |
slot | string | No | the piece key | main_hand / off_hand / helmet / chestplate / leggings / boots (the default falls back to the piece key itself) | Equipment slot | main_hand |
display | string | No | the piece key | — | Piece name shown in set lore | Example Blade |
You can also shorten a piece to piece_key: item_id; slot and display name then both fall back to the piece key
Lore display configuration
yaml
lore:
header: "<dark_gray>—— <aqua>Set Name</aqua> <gray>(%active%/%total%)</gray> ——</dark_gray>"
equipped_format: "<green>✔ %piece%</green>"
missing_format: "<gray>✘ %piece%</gray>"
active_threshold_format: "<green>%line%</green>"
inactive_threshold_format: "<dark_gray>%line%</dark_gray>"
separator: ""| Field | Type | Required | Default | Range | Description | Example |
|---|---|---|---|---|---|---|
header | string | No | <dark_gray>—— %set_name% <gray>(%active%/%total%)</gray> ——</dark_gray> | — | Set lore header template | see the snippet above |
equipped_format | string | No | <green>✔ %piece%</green> | — | Template for an equipped piece | see the snippet above |
missing_format | string | No | <gray>✘ %piece%</gray> | — | Template for a missing piece | see the snippet above |
active_threshold_format | string | No | <green>%line%</green> | — | Template for an active threshold line | see the snippet above |
inactive_threshold_format | string | No | <dark_gray>%line%</dark_gray> | — | Template for an inactive threshold line | see the snippet above |
separator | string | No | "" | — | Line separator; an empty string inserts no separator line | "" |
Threshold effects
A threshold key is simply the number of pieces needed to activate it
yaml
thresholds:
2:
lore:
- "[2-piece] Physical attack +5"
effects:
- type: "ea_attribute"
ea_attributes:
physical_attack: 5.0
- type: "es_skill"
es_skills:
- "guardian_dash"| Field | Type | Required | Default | Range | Description | Example |
|---|---|---|---|---|---|---|
lore | list | No | empty | — | Lore lines shown while the threshold is active | - "[2-piece] Physical attack +5" |
effects | list | No | empty | type values ea_attribute / es_skill / name_action / lore_action | Threshold effect list | see "Threshold effects" |
Note that the threshold top-level shorthands (ea_attributes, es_skills, name_actions, lore_actions, plus the never-effective name_action / lore_action) and the effect payload fallbacks (attributes for ea_attribute, es_skill for es_skill) are likewise no longer read; writing them only logs one WARN on load
State calculation and invalid slots
Set-membership visibility is calculated separately from the active piece count. Once an item definition declares a valid set.id, the state keeps that set even when every candidate is rejected by slot validation; Lore therefore displays 0/%total% instead of collapsing into a state with no set definition
Only pieces that meet all three conditions count toward activeCount and threshold activation:
- it resolves uniquely to a real piece in
sets/*.yml; - the actual equipment slot matches the item definition's
equip_slot; - the actual equipment slot also matches the set piece's
slot
Missing or unloadable set definitions are isolated for safety: they never enter visible state, never activate rewards, and never trigger destructive Lore writes. Runtime logging emits one warning per missing set ID; with set DEBUG enabled, it also reports [DEBUG:SET_STATE] state=missing_definition action=preserve. Paper and Folia use the same pure state-construction rule; Folia changes only the owner-thread scheduling boundary
Equipment conditions
You can declare equipment conditions on an item; when a player fails them, that item is disabled for the player entirely:
yaml
condition:
type: "at_least"
entries:
- "%emakilevel_level_main% >= 10"
- "%player_class% == 'warrior'"
required_count: 2
invalid_as_failure: true
on_pass:
actions:
- 'send_message text="<green>Equipment condition met.</green>"'
on_fail:
message: "<red>You do not meet the equipment requirements!</red>"
actions:
- 'send_message text="<red>Requires a level 10+ warrior.</red>"'| Field | Type | Required | Default | Range | Description | Example |
|---|---|---|---|---|---|---|
type | string | No | all_of | all_of / any_of / none_of / at_least / exactly | Combination mode | at_least |
entries | list | No | empty | — | Condition expression list. The key must be entries | - "%player_level% >= 10" |
required_count | int | No | 0 | — | Number of conditions that must hold; only at_least and exactly read it, and other modes ignore it completely | 2 |
invalid_as_failure | boolean | No | true | true / false | Whether an expression that fails to parse counts as unmet | true |
on_pass.actions | list | No | empty | — | Actions executed when the condition passes | - 'send_message ...' |
on_fail.message | string | No | "" | — | Message sent when the condition fails | <red>You do not meet the equipment requirements!</red> |
on_fail.actions | list | No | empty | — | Actions executed when the condition fails | — |
on_fail.block_output | boolean | No | false | true / false | Whether to block the item's output propagation when the condition fails | false |
WARNING
The condition list key must be written as entries. Any other name parses into an empty condition group, which silently disables the item's condition entirely without a warning
required_count is only read when type is at_least or exactly. all_of and any_of ignore it completely; adding it does not turn any_of into an "at least N" check
Gate scope
When the condition is not met, none of the following takes effect:
| Surface | Sources |
|---|---|
| EmakiAttribute attributes | Lore entries and PDC attributes are both dropped |
| Equipment skills | Lore and PDC sources are both dropped |
| Set attributes | The emakiitem and emakiitem_set PDC sources |
| Trigger actions | That trigger is blocked |
| Accessory contribution | Worn in the accessory window, the same item's attributes, skills and set piece count are dropped as well (evaluated by EmakiAccessory) |
What stays active outside this gate: the PDC attributes written by EmakiGem, EmakiForge and EmakiStrengthen. Those are owned by their own modules and do not expire with the host item's condition
When it is evaluated: trigger actions are evaluated before each trigger; attributes and skills are evaluated per player during every equipment collection, so a level or class change applies immediately without re-equipping. The attribute and skill gate evaluation never sends on_fail.message and never runs the on_pass / on_fail actions; those stay on the trigger path only
The attribute and skill gate is hosted by EmakiAttribute and requires EmakiAttribute to be enabled. With EmakiItem alone, the condition gates trigger actions only
The accessory side uses the silent condition query of EmakiItemApi (conditionSatisfied); the query emits no message and does not need EmakiAttribute. It runs when accessory contributions are recomputed, so a condition change reaches the accessory window only on the next recompute (equip or page swap, GUI edit, join load, reload, retrieval, durability break) — unlike the real-time equipment path. See accessory window for the unmet-condition marker
Repair configuration
When an item's durability runs out, you can repair it with materials or currency:
yaml
repair:
enabled: true
materials:
- item_sources:
- "minecraft-diamond"
amount: 1
restore: 250
economy:
enabled: true
restore: "100%"
currencies:
- provider: "vault"
currency_id: ""
base_cost: 100
cost_formula: "base_cost + missing_durability * 0.25"
display_name: "Coins"
on_disabled:
- 'send_message text="<red>Your weapon broke!</red>"'
on_repaired:
- 'send_message text="<green>Weapon repaired!</green>"'See Item Repair for field semantics and the full flow
Auto update
update decides when the item refreshes automatically:
yaml
update:
enabled: true
version: 1
triggers:
join: true
held_change: true
inventory_click: true
inventory_drag: true
pickup: true
interact: true
command: trueAfter changing an item definition, increment version to trigger an update. Get manual /ei update working first, then enable auto update step by step instead of turning on every high-frequency trigger at once. See Item Update Strategy for details