Skip to content

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

FieldTypeRequiredDefaultDescription
idstringYesUnique item ID used by other modules.
itemobjectYesShared base-item definition with source, amount, and components.
name_actionslist/objectNoName operation chain applied after base components are built.
lore_actionslist/objectNoLore operation chain applied after base components are built.
effectslistNoBusiness effects such as variables, EmakiAttribute attributes, and EmakiSkills skills.
equip_slotstringNoallEquipment 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.
setobjectNoSet membership info (id and piece).
conditionobjectNoEquipment condition block.
repairobjectNoRepair configuration.
updateobjectNoAuto-update configuration.
actionsobjectNoTrigger 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 fieldCanonical field / behavior
materialNormalized to lowercase underscore form and written to item.source, for example DIAMOND_SWORDminecraft-diamond_sword.
source, item_source, item_sources, scalar itemA usable source is written to item.source; source lists retain the runtime converter's first-source preference.
amountWritten to item.amount.
display_name, item_name, loreWritten to item.components.custom_name, item.components.item_name, and item.components.lore.
custom_model_dataWritten to item.components.custom_model_data; 1.21.5+ structures such as floats are supported.
enchantmentsWritten to the direct enchantment ID → level map at item.components.enchantments; legacy hidden-enchantment flags also update tooltip_display.hidden_components.
item_flags, hidden_componentsMapped to the 1.21.5+ item.components.tooltip_display structure.
Legacy fields such as unbreakableConverted to the corresponding namespaced component structure while preserving canonical component precedence.

Safety boundaries:

  • Existing item.source, item.amount, and item.components values always win; legacy fields only fill missing values.
  • A node containing components.raw or item.components.raw is skipped as a whole instead of being partially migrated.
  • Business fields such as effects, equip_slot, set, condition, repair, update, and actions remain 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 to items/.
  • 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:

typeDescription
variablesExpression engine variables for display_name and lore placeholder rendering.
ea_attributeEmakiAttribute PDC attributes written to item PDC.
es_skillEmakiSkills skill attachment, granted when equipped; payload uses the es_skills list.
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"

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

yaml
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:
      - enchantments

components 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.

FieldTypeRequiredDescription
idstringYesUnique set ID. The file is skipped when it is missing or invalid.
display_namestringNoSet display name (MiniMessage); falls back to the set ID.
piecesmapNoSet piece definitions, keyed by piece ID.
loreobjectNoLore rendering configuration for set status display.
thresholdsmapNoPiece-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

yaml
pieces:
  blade:
    item: "example_item"
    slot: "main_hand"
    display: "Example Blade"
  helmet:
    item: "example_guardian_helmet"
    slot: "helmet"
    display: "Guardian Helmet"
FieldDescription
itemThe matching item ID from items/; falls back to the piece key.
slotEquipment slot (main_hand/off_hand/helmet/chestplate/leggings/boots); falls back to the piece key.
displayPiece 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

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: ""

Threshold effects

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"

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:

  1. it resolves uniquely to a real piece in sets/*.yml;
  2. the actual equipment slot matches the item definition's equip_slot;
  3. 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.

yaml
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>"'
FieldDescription
entriesCondition expression list. conditions is also accepted.
typeCombination mode: all_of or any_of; defaults to all_of.
required_countMinimum number of conditions that must pass.
invalid_as_failureWhether an expression that fails to parse counts as unmet.
on_pass.actionsActions executed when the condition passes.
on_fail.messageMessage sent when the condition fails.
on_fail.actionsActions executed when the condition fails.

Gate scope

A failing condition disables all of the following:

SurfaceSources
EmakiAttribute attributesLore entries and PDC attributes are both dropped
Equipment skillsLore and PDC sources are both dropped
Set attributesThe emakiitem and emakiitem_set PDC sources
Trigger actionsThat 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:

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:
    - '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:

yaml
update:
  enabled: true
  version: 1
  triggers:
    join: true
    held_change: true
    inventory_click: true
    inventory_drag: true
    pickup: true
    interact: true
    command: true

Increment version after changing an item definition to trigger updates. See Item Update Strategy for details.