API
All public EmakiAttribute APIs live in the standalone EmakiAttributeApi module (Maven coordinate emaki.jiuwu.craft:emaki-attribute-api), under the packages emaki.jiuwu.craft.attribute.api and emaki.jiuwu.craft.attribute.model. It is the single authoritative entry point for the Attribute contract:
PdcAttributeApi— source registration and read/write for item PDC attribute payloads.EmakiAttributeApi— player resources, resolved attribute values, attribute damage, and equipment sync.
Other modules should use these static facades or the public events instead of parsing Attribute's internal data files or calling internal service classes.
PdcAttributeApi
PdcAttributeApi handles item attribute payloads. Equipment modules such as Forge, Strengthen, Gem, and Item use it to attach their own attribute source. Each payload is isolated by source id so sources never clobber one another.
Method signatures
| Method | Purpose |
|---|---|
static boolean available() | Whether Attribute has installed the PDC API bridge. |
static boolean registerSource(String sourceId) | Register an attribute source such as forge, strengthen, gem, or item. |
static void unregisterSource(String sourceId) | Unregister a source. |
static boolean isRegisteredSource(String sourceId) | Whether a source is registered. |
static Set<String> registeredSources() | All registered sources; empty set when unavailable. |
static boolean write(ItemStack, PdcAttributePayload) | Write or replace the payload for its source. |
static boolean write(ItemStack, String sourceId, Map<String, Double> attributes, Map<String, String> meta) | Build a payload from raw maps and write it. |
static PdcAttributePayload read(ItemStack, String sourceId) | Read one source payload; null when absent. |
static Map<String, PdcAttributePayload> readAll(ItemStack) | Read every source payload; never null. |
static boolean clear(ItemStack, String sourceId) | Remove one source payload. |
static void clearAll(ItemStack) | Remove all Attribute payloads. |
static void copy(ItemStack fromItem, ItemStack toItem, Set<String> excludedSourceIds) | Copy payloads per source id. |
PdcAttributePayload fields
PdcAttributePayload is an immutable record that normalizes keys on construction:
| Field | Type | Description |
|---|---|---|
sourceId() | String | Owning source id. |
attributes() | Map<String, Double> | Attribute id to value. |
meta() | Map<String, String> | Arbitrary string metadata. |
conditions() | Map<String, String> | Per-attribute activation conditions. |
schemaVersion() | int | Payload schema version; CURRENT_SCHEMA_VERSION = 2. |
updatedAt() | long | Epoch millis of the last update. |
Supporting methods: of(sourceId, attributes, meta), of(sourceId, attributes, meta, conditions), conditionFor(attributeId), hasDurabilityScaling(), toMap(), fromMap(Map).
Full-fidelity copy semantics
copy moves payloads source by source and preserves every field of each payload, including conditions, schemaVersion, and updatedAt; matching sources on the destination item are overwritten. Sources listed in excludedSourceIds keep whatever the destination already holds.
Use copy when upgrading, reforging, or duplicating items. Do not read out attributes and write them back, since that discards conditions and schema information.
Source isolation
Each module should only write and clear its own source. Strengthen clears only the strengthen source, Gem only the gem source. This prevents a strengthen refresh from deleting gem attributes, or gem extraction from deleting forge attributes.
Source registration check
Writes validate that the source id is registered, so call registerSource before write.
EmakiAttributeApi
EmakiAttributeApi is the canonical entry point for player runtime state and damage. Every method degrades to the documented value below when Attribute is absent, disabled, or reloading, so callers need no guard beyond avoiding class loading.
| Method | Value when unavailable | Purpose |
|---|---|---|
static boolean available() | false | Whether the gameplay API bridge is installed. |
static double readResourceCurrent(Player, String resourceId) | -1 | Read a player's current resource value. |
static double readResourceMax(Player, String resourceId) | -1 | Read a player's current resource maximum. |
static boolean consumeResource(Player, String resourceId, double amount) | false | Consume a resource; fires PlayerResourceConsumeEvent. |
static double readAttributeValue(Player, String attributeId) | 0 | Read a player's resolved attribute value. |
static void scheduleEquipmentSync(Player) | no-op | Request an equipment attribute resync. |
static boolean applyDamage(LivingEntity attacker, LivingEntity target, String damageTypeId, double baseDamage, Map<String, Object> context) | false | Resolve and apply damage through the attribute pipeline; a blank damageTypeId uses the configured default. |
Do not cache the internal
Bridgeinstance. Always resolve through the static methods, otherwise a reloaded or disabled Attribute may be called through a stale bridge.
Deprecated CoreLib mirrors
Earlier versions exposed Attribute mirrors on the CoreLib side. They now merely delegate to the canonical facades above and are marked @Deprecated(forRemoval = true); they will be removed at the end of the deprecation window:
| Deprecated entry point | Replacement |
|---|---|
emaki.jiuwu.craft.corelib.api.integration.PdcAttributeApi | emaki.jiuwu.craft.attribute.api.PdcAttributeApi |
emaki.jiuwu.craft.corelib.api.integration.EmakiAttributeBridge | emaki.jiuwu.craft.attribute.api.EmakiAttributeApi |
CoreLib's PdcAttributeGateway | Either of the two above |
On the Attribute side these deprecated interfaces are implemented by the single compatibility adapter LegacyCoreAttributeCompatibility, which holds no business rules and only delegates to the canonical facades. New code must not use these mirrors; depend on emaki-attribute-api directly.
Integration guidance
- Call
PdcAttributeApi.available()/EmakiAttributeApi.available()(orPdcAttributeApiProvider.available()) after your plugin is enabled to avoid load-order issues. - Degrade gracefully when the API is unavailable; do not crash a soft-dependent module.
- Do not cache long-lived attribute snapshots; re-read after equipment changes, reloads, or resync.
- Write real payloads; lore is display only. Do not parse lore for real attribute state.
- Use
copywhen duplicating item attributes so conditions and schema version survive. - Consume resources through
EmakiAttributeApi.consumeResourcerather than bypassing Attribute's resource state management.
Write example
PdcAttributeApi.registerSource("forge");
boolean changed = PdcAttributeApi.write(itemStack, "forge", attributes, meta);
// attributes: Map<String, Double> — attribute id to value
// meta: Map<String, String> — metadata entriesPdcAttributeApiProvider.available() / requireAvailable() can also be used for availability checks; the latter throws IllegalStateException when the API is unavailable.
JavaScript access
CoreLib JavaScript scripts can access item PDC attribute payloads through emaki.module("attribute"). Always check available() first when Attribute is an optional dependency.
| Method | Description |
|---|---|
available() | Whether the Attribute API is registered. |
registerSource(sourceId) / unregisterSource(sourceId) / isRegisteredSource(sourceId) | Source registration management. |
registeredSources() | List registered sources. |
read(itemKey, sourceId) | Read one payload from a contextual item. |
readAll(itemKey) | Read all Attribute payloads from a contextual item. |
write(itemKey, sourceId, attributes, meta) | Write an attribute payload. |
clear(itemKey, sourceId) | Clear one source payload. |
clearAll(itemKey) | Clear all Attribute payloads. |
applyDamage(...) / calculateDamage(...) / setDamageTypeOverride(...) | Apply damage, calculate without applying, or override the next damage type. |
The payload projection seen by scripts contains six fields —
sourceId,attributes,meta,conditions,schemaVersion, andupdatedAt— produced by Attribute's ownscript/ScriptAttributeDtoMapper.
function main(ctx) {
if (!emaki.module("attribute").available()) {
return { skipped: true, message: "Attribute not installed" };
}
emaki.module("attribute").registerSource("js_bonus");
return emaki.module("attribute").write("target_item", "js_bonus", {
physical_attack: 8,
physical_defense: 10
}, {
reason: "script_bonus"
});
}JavaScript dynamic attributes and damage hooks
Extension scripts placed under extensions/attribute/ in the CoreLib script root can use register() to register runtime attributes, attribute providers, damage types, damage pipelines, and damage hooks. Runtime attributes are rebuilt on Attribute reload and participate in attribute lookup, snapshot signatures, and damage calculation.
See JavaScript for the full registration API, definition fields, and the event / ctx callback methods.
Call Attribute through CoreLib's MythicMobs JS mechanic
emaki_js is not registered by Attribute. It is registered by CoreLib with aliases corelib_js and emakicorelib_js. Attribute provides the emaki.module("attribute") script module and example scripts that can be called from CoreLib's generic JS mechanic.
Attribute's own MythicMobs integrations are the attribute damage mechanic emaki_damage (aliases emakiattribute_damage, attribute_damage) and the attribute condition emaki_attribute (aliases emakiattribute_attribute, attribute_value, attribute_resource). See MythicMobs integration.
Use CoreLib's generic JS mechanic to call the Attribute example script:
Skills:
JsFireDamage:
Skills:
- emaki_js{script="mythic/mythic_js_damage.js";function="mythicDamage";damage=12;damage_type=fire} @targetThe JavaScript function receives meta,args:
function mythicDamage(meta, args) {
const caster = meta.caster();
const target = meta.firstTarget();
return emaki.module("attribute").applyDamage(caster, target, args.damage_type || "default", Number(args.damage || 1), {
source: "mythic_js",
mythic_mechanic: meta.mechanic()
});
}Attribute releases scripts/mythic/mythic_js_damage.js into the CoreLib script repository as an example; existing target files are not overwritten.