Item Definitions and Sets
Item files are stored under items/*.yml; set files are stored under sets/*.yml. Item definitions determine how a stable item ID generates an ItemStack. Set definitions determine bonuses when multiple set pieces are equipped.
Item definition fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id | string | Yes | — | Unique item ID used by other modules. |
item | object | Yes | — | Shared base-item definition with source, amount, and components. |
name_actions | list/object | No | — | Name operation chain applied after base components are built. |
lore_actions | list/object | No | — | Lore operation chain applied after base components are built. |
effects | list | No | — | Business effects such as variables, EmakiAttribute attributes, and EmakiSkills skills. |
equip_slot | string | No | all | Equipment slot used by business attributes and skills: all, hand, main_hand, off_hand, helmet, chestplate, leggings, boots. Unsupported values fall back to all with a warning. |
set | object | No | — | Set membership info (id and piece). |
condition | object | No | — | Equipment condition block. |
repair | object | No | — | Repair configuration. |
update | object | No | — | Auto-update configuration. |
actions | object | No | — | Trigger action configuration. Keys must be trigger names listed on the Triggers page, such as right_click, consume, attack, or give; unlisted keys never run. |
Legacy top-level material, display_name, item_name, lore, components, and amount are still readable and converted into the shared definition. New configs, bundled defaults, and JavaScript examples only write nested item; when both forms exist, nested item wins.
Automatic migration of legacy item definitions
items/*.{yml,yaml} definitions run through a configured-item migration before normal definition parsing. The migration transforms YAML nodes only and never creates a Bukkit ItemStack, so its output does not depend on players, worlds, or third-party item plugins being available.
Major mappings include:
| Legacy field | Canonical field / behavior |
|---|---|
material | Normalized to lowercase underscore form and written to item.source, for example DIAMOND_SWORD → minecraft-diamond_sword. |
source, item_source, item_sources, scalar item | A usable source is written to item.source; source lists retain the runtime converter's first-source preference. |
amount | Written to item.amount. |
display_name, item_name, lore | Written to item.components.custom_name, item.components.item_name, and item.components.lore. |
custom_model_data | Written to item.components.custom_model_data; 1.21.5+ structures such as floats are supported. |
enchantments | Written to the direct enchantment ID → level map at item.components.enchantments; legacy hidden-enchantment flags also update tooltip_display.hidden_components. |
item_flags, hidden_components | Mapped to the 1.21.5+ item.components.tooltip_display structure. |
Legacy fields such as unbreakable | Converted to the corresponding namespaced component structure while preserving canonical component precedence. |
Safety boundaries:
- Existing
item.source,item.amount, anditem.componentsvalues always win; legacy fields only fill missing values. - A node containing
components.raworitem.components.rawis skipped as a whole instead of being partially migrated. - Business fields such as
effects,equip_slot,set,condition,repair,update, andactionsremain unchanged. - Before changed files are replaced, their exact original text is backed up under
plugins/EmakiItem/migration-backups/configured-item-format/<timestamp>/, preserving paths relative toitems/. - The new YAML is written to a sibling temporary file and parsed again. Replacement occurs only after validation succeeds; failures leave or restore the original file and reject the unverified migration result.
- The migration is idempotent, so successfully migrated files are not rewritten on later starts.
The migration does not read EmakiItem, CoreLib, configuration, or language-file version values and does not depend on a historical version number. If a candidate still contains legacy fields, the same conversion rules apply. The conversion rules are owned by EmakiItem itself and only invoke CoreLib's generic migration runner at definition loading, so that entry point can be removed after the transition without changing shared ConfiguredItemDefinition or canonical parsers.
Effects system
Item effects use a unified effects list with a type field:
| type | Description |
|---|---|
variables | Expression engine variables for display_name and lore placeholder rendering. |
ea_attribute | EmakiAttribute PDC attributes written to item PDC. |
es_skill | EmakiSkills skill attachment, granted when equipped; payload uses the es_skills list. |
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"The es_skill effect accepts an optional es_skill_triggers map (skill_triggers is also accepted) in the form skill_id: trigger_id. It writes forced equipment triggers so the skill is cast by the given trigger while equipped, without occupying a player skill slot.
Current configs no longer use ea_attribute_meta. Put real attribute output in explicit ea_attributes. variables are only text/placeholder context and do not automatically become Attribute PDC attributes.
Writing skill IDs and skill triggers to item PDC does not check whether EmakiSkills is enabled; those keys are owned by a standalone protocol module.
Shared item definition and components
item:
source: minecraft-netherite_sword
amount: 1
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:
- enchantmentscomponents uses namespaced Minecraft data-component IDs. IDs without a namespace default to minecraft:—for example, custom_name is equivalent to minecraft:custom_name—while explicit namespaces are preserved. The same rule applies to $unset / $reset entries. JSON objects, arrays, and scalars map directly to 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. Rare NBT values that cannot be represented losslessly as JSON may 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. Missing resolvers, unavailable plugins, or sources that cannot create a base item cause the EmakiItem definition to be rejected. The minimum supported runtime is Paper 1.21.8+; the maintained component catalog and runtime capabilities together determine availability.
Set definitions
Set files live under sets/ and are loaded recursively from subdirectories. Duplicate id values keep the first definition and log a warning.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique set ID. The file is skipped when it is missing or invalid. |
display_name | string | No | Set display name (MiniMessage); falls back to the set ID. |
pieces | map | No | Set piece definitions, keyed by piece ID. |
lore | object | No | Lore rendering configuration for set status display. |
thresholds | map | No | Piece-count threshold effects. Keys are the required piece counts and must be positive integers. |
Set bonuses are refreshed based on config.yml > set_bonus.refresh_triggers.
Piece definitions
pieces:
blade:
item: "example_item"
slot: "main_hand"
display: "Example Blade"
helmet:
item: "example_guardian_helmet"
slot: "helmet"
display: "Guardian Helmet"| Field | Description |
|---|---|
item | The matching item ID from items/; falls back to the piece key. |
slot | Equipment slot (main_hand/off_hand/helmet/chestplate/leggings/boots); falls back to the piece key. |
display | Piece name shown in set lore; falls back to the piece key. |
A piece may also be written as piece_key: item_id, in which case both slot and display name fall back to the piece key.
Lore display configuration
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: ""Threshold effects
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"State calculation and invalid slots
Set-membership visibility is calculated separately from the active piece count. If an item definition declares an available 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.
A piece contributes to activeCount and threshold activation only when all of these are true:
- 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 from visible state, never activate rewards, and do not 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
An item can declare equipment conditions. A failing condition disables that item entirely for the player.
condition:
type: "all_of"
entries:
- "%emakilevel_level_main% >= 10"
- "%player_class% == 'warrior'"
required_count: 2
invalid_as_failure: true
on_pass:
actions:
- 'sendmessage text="<green>Equipment condition met.</green>"'
on_fail:
message: "<red>You do not meet the equipment requirements!</red>"
actions:
- 'sendmessage text="<red>Requires a level 10+ warrior.</red>"'| Field | Description |
|---|---|
entries | Condition expression list. conditions is also accepted. |
type | Combination mode: all_of or any_of; defaults to all_of. |
required_count | Minimum number of conditions that must pass. |
invalid_as_failure | Whether an expression that fails to parse counts as unmet. |
on_pass.actions | Actions executed when the condition passes. |
on_fail.message | Message sent when the condition fails. |
on_fail.actions | Actions executed when the condition fails. |
Gate scope
A failing condition disables all of the following:
| 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 |
Not gated by this condition: 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.
Evaluation timing: trigger actions are evaluated before each trigger; attributes and skills are evaluated per player during every equipment collection, so level or class changes apply 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 it to be enabled. With EmakiItem alone, the condition only gates trigger actions.
Repair configuration
Items whose durability is depleted can be repaired with materials or currency:
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:
- 'sendmessage text="<red>Your weapon broke!</red>"'
on_repaired:
- 'sendmessage text="<green>Weapon repaired!</green>"'See Item Repair for field semantics and the full flow.
Auto update
update controls when an item is refreshed automatically:
update:
enabled: true
version: 1
triggers:
join: true
held_change: true
inventory_click: true
inventory_drag: true
pickup: true
interact: true
command: trueIncrement version after changing an item definition to trigger updates. See Item Update Strategy for details.