Skip to content

Attributes and Skills ​

Accessory attributes and skills reach EmakiAttribute and EmakiSkills; condition and durability decide whether an accessory contributes, and not every item can be placed in the accessory panel. Accessory attributes and skills are not computed by EmakiAccessory itself; they are registered into the public extension points of EmakiAttribute and EmakiSkills. Both are optional dependencies: when one is absent the corresponding half switches off while the accessory panel keeps working

Attributes into EmakiAttribute ​

EmakiAccessory registers a contribution provider with EmakiAttribute (id emakiaccessory:accessories, priority 100) to merge data into attribute computation: accessory attributes are fed in as a distinct source into the combat attribute snapshot. The provider registers no custom equipment slot and writes nothing onto the player's vanilla attributes

The reported source ids:

Source idMeaning
emakiaccessory:accessoryAttributes of an individual accessory
emakiaccessory:setAccessory set bonuses

Attribute values are read through EmakiAttribute's AttributeCatalog#itemSnapshot — the same parser the equipment path uses. An accessory and a helmet carrying identical data therefore produce identical numbers, and parent-attribute expansion plus range-spread companion keys come along with it

Range-spread companion keys are summed like any other key; otherwise a ranged accessory would keep its lower bound and lose its spread

When EmakiAttribute is unavailable (EmakiAttributeApi.status().usable() is false) no provider is registered, so accessories grant no attributes at all

Skills into EmakiSkills ​

EmakiAccessory registers a skill source with EmakiSkills (provider id accessories). Equipment skill payloads on an accessory are read by AccessorySkillPayloadCodec.read, the same PDC contract Item, Forge, Gem and Strengthen write

Skills listed in an accessory set's thresholds[].effects[].es_skills take effect through that same path

The source-slot field of each skill entry is the slot instance id for single-accessory skills and set:<setId> for set skills

With EmakiSkills absent the module still enables normally: AccessoryProviderRegistrar loads the integration class reflectively by name (emaki.jiuwu.craft.accessory.provider.AccessorySkillsProviderIntegration) and only does so while EmakiSkills is enabled, so a missing EmakiSkills cannot fail class loading — there is simply no skill source

Slot Restriction Criterion ​

The accessory window accepts only items that explicitly declare accessory slots. There is exactly one item-carried declaration source:

  1. type: "accessory_slot" inside an EmakiItem definition's effects, written by EmakiItem into item PDC under emakiitem:accessory_slots (string list)

On top of that, slot_sources.pdc and slot_sources.lore in config.yml are additional sources that operations staff opt into explicitly; both default to disabled. When enabled they are judged together with the item-carried declaration, and a hit on any one of them passes

The active_slot metadata of EmakiAttribute payloads and the EmakiSkills payload active_slot no longer take part in accessory matching. Under the old behaviour an unspecified slot was written as all, which let every EmakiItem item enter any accessory cell; such items are now rejected for having no accessory_slots declaration. Attribute and skill contributions use the same criterion, so for a cell whose declaration does not match, the item is refused and no contribution is produced

The matching rule: the item passes as soon as any single declaration hits the current cell (any-of)

The item's declared slotResult
A part id, such as ringActive in any cell of that part
A slot instance id, such as ring_1Active only in that cell
Anything else (such as the equipment slot names hand or main_hand)Hits no accessory slot, i.e. no declaration
No accessory_slots key (and no optional source matched either)Placement rejected with gui.not_declared, and the contribution is dropped entirely

Two container-level safeguards back this up:

  • A failing criterion at placement time rejects the item, leaving the cursor stack untouched on the cursor so it never enters the cell
  • Closing the window runs a validation pass over every page, taking items that are no longer inside their slot's declaration and returning them to the player's inventory (dropped at their feet when the inventory is full), with one gui.invalid_returned message per item. Orphan cells (slots the page no longer declares) are unaffected and keep their own retrieval flow

If the equipment-side rules ever change, this accessory-side implementation must be re-evaluated

Condition Gating ​

Accessories in the window are checked against their own definition's condition: when it fails, that accessory's attributes, skills and set piece count all stop contributing, while the item stays in its cell

The check runs through EmakiItemApi's silent query ItemCatalog#conditionSatisfied(player, itemStack) — the silent counterpart of conditionPasses: it never runs on_pass/on_fail actions and never sends on_fail.message, so it is safe to evaluate repeatedly during recomputation and rendering. The trigger context matches the equipment contribution gate: contribution

Evaluation happens on contribution recomputation: GUI edits, page switches, a completed data load, reload, /eacc retrieve, death drops, and durability break. A change to the condition itself (level, class, placeholders) therefore reaches the accessory window only on the next recompute — unlike the equipment path, which evaluates on every collection

When EmakiItem is absent, the player is offline, the call is off the player's owner thread, or the definition cannot be resolved, the query fails and the accessory side treats the accessory as satisfied (no gating), so a missing dependency never silently disables accessories

In the window, an accessory whose condition fails shows one extra gui.condition_unmet line; that line only exists in the rendered projection and is never written back to the item

Durability Gating ​

With durability.enabled turned on, accessories on the enabled page lose durability on player damage according to durability.damage_per_hit; once an accessory is exhausted its attributes, skills and set piece count all stop applying, the item stays in its cell and shows a gui.durability_broken marker. See main configuration and part definitions for the criterion and configuration details

When Recomputation Happens ​

Contribution snapshots are recomputed when accessory contents change: a GUI edit, a completed data load, a reload, a /eacc retrieve, or a death drop that clears the enabled page. Opening the window without changing data does not trigger a recompute. Both the condition and durability gates are evaluated on this path

Recomputation deliberately does not happen inside the provider callback. EmakiAttribute's combat snapshot collector calls the contribution provider while computing its cache signature, meaning the provider runs on every combat snapshot read; parsing PDC there would put item deserialisation on the combat hot path

Threading ​

Recomputation must run on the owner thread of the player holding the items: the attribute parser writes its result back into item PDC as a cache, so it is not safe off-thread. The condition query has the same requirement, and a wrong-thread call counts as satisfied

Behaviour With Modules Missing ​

Missing moduleEffect
EmakiAttributeNo attribute provider is registered, so accessories grant no attributes; the panel and set piece counting keep working (set counting depends on EmakiItem only)
EmakiSkillsNo skill source is registered, so neither accessory nor set skills are granted; everything else keeps working
EmakiItemItems carry no accessory_slots declaration any more (the key already present on existing items still counts), so nothing can be placed unless a slot_sources source matches; condition gating is skipped entirely (treated as satisfied); unique deduplication falls back to vanilla material matching and stays active; accessory sets relying on pieces[].item are entirely inactive (their piece count stays 0)
PlaceholderAPIPAPI placeholders in text are no longer replaced and pass through unchanged

EmakiAccessory itself has no PlaceholderAPI expansion and exposes no %emakiaccessory_*% placeholders; it only consumes PlaceholderAPI optionally. The module also registers no actions into the CoreLib action registry (the module's only super("accessory", …) is the config-precheck contributor's module id, not an action segment)