English
JS Scripting
Since 4.8.2, EmakiAttribute supports declaring attribute definitions in JavaScript. Drop .js files into plugins/EmakiAttribute/scripts/ and register them via attributes.register({...}); script attributes have equal standing with attributes from attributes/*.yml: they can be consumed by the item ea_attribute effect, Lore parsing, placeholders, and attribute snapshot collection
The host mechanism, directory load order, evaluation timeout, and fully open sandbox rules are identical to CoreLib; the contract is in the safety notice and thread semantics sections of CoreLib JS Scripting
attributes Binding API
Payload fields
Fields align with the attributes/*.yml schema:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id | string | Yes | — | Attribute id; missing or blank entries are skipped with an error |
display_name | string | No | — | Display name, the basis for Lore keyword and alias matching |
value_kind | string | No | "FLAT" | FLAT / PERCENT / CHANCE / REGEN / RESOURCE / DERIVED; invalid values skip the entry |
target_type | string | No | "GENERIC" | DAMAGE / RESOURCE / GENERIC / VANILLA; invalid values skip the entry |
target_id | string | No | — | Target id: for DAMAGE the damage type id, for RESOURCE the resource id, for VANILLA the vanilla attribute name |
mmoitems_stat | string | No | — | MMOItems stat mapping |
default_value | number | No | 0 | Default value; non-numeric values skip the entry |
min_value | number | No | — | Lower bound; non-numeric values skip the entry |
max_value | number | No | — | Upper bound; non-numeric values skip the entry |
allow_negative | boolean | No | true | Whether negative values are allowed |
priority | number | No | 0 | Lore read priority, higher wins (truncated to int) |
lore_format_id | string | No | — | Lore format (e.g. default_flat / default_percent / default_regen / default_resource) |
lore_patterns | string array | No | [] | Custom Lore regex templates (%Key% and %Value% placeholders); non-arrays skip the entry |
description | string | No | — | Description text |
attribute_power | number | No | 1 | Combat power coefficient; non-numeric values skip the entry |
tags | string array | No | [] | Tag list |
temporary_stack_mode | string | No | "REPLACE" | Temporary attribute stacking mode: REPLACE / STACK; invalid values skip the entry |
Input contract for numeric fields: both numbers and strings parseable as numbers are accepted
Registration & override semantics
- Validated payloads are mapped to attribute definitions and registered through the internal registry with source
"script" - Duplicate registration of the same id (same file or across files): the later registration overrides the earlier one and the load report notes it (
script.register_override) - If any field fails validation, the entire entry is skipped (the error report includes file, field, and value); other entries in the same file and other files are unaffected
- Registered attributes are consumed by the attribute system exactly like YAML attributes
Threading & Exception Isolation
- Attribute registration happens during script loading (serialized through the host lock); afterwards the attribute system consumes definitions through its existing logic — there are no JS callbacks at runtime and no script hot path
- Per-file compile/evaluation failures are isolated by the host (that file is skipped, the rest continue); per-entry payload validation failures skip only that entry (see above)
Configuration & Reload
The scripts section in config.yml:
yaml
scripts:
enabled: true
timeout_ms: 5000| Field | Type | Required | Default | Allowed values | Description |
|---|---|---|---|---|---|
scripts.enabled | boolean | No | true | true / false | When disabled, no scripts are scanned or loaded and script attributes registered so far are unregistered |
scripts.timeout_ms | integer | No | 5000 | Positive integer | Timeout in milliseconds for a single evaluation; non-positive values fall back to 5000 |
Reload semantics: scripts reload with EmakiAttribute's existing reload flow — first all script attribute registrations are cleared by source "script", then the JS context is rebuilt and all files are re-evaluated and re-registered in file order. Modified definitions take effect immediately; attributes from deleted files are gone. When the GraalJS runtime is missing, a single warning is logged and script loading is skipped; other features are unaffected
Troubleshooting
| Console output | Cause | Fix |
|---|---|---|
script.engine_unavailable: "[Script] GraalJS engine unavailable, script attributes skipped: %reason%" | GraalJS runtime missing or host creation failed | Inspect %reason%; other features are unaffected |
script.disabled: "[Script] Script attribute support is disabled (scripts.enabled = false)" | scripts.enabled: false | Enable it if desired, then reload |
script.loaded: "[Script] Script attributes loaded: %loaded% succeeded, %skipped% skipped" | Summary of every load/reload | Check the following file_error / register_error entries when counts look wrong |
script.file_error: "[Script] Script %file% failed to load: %error%" | Syntax error, evaluation timeout, or runtime exception in one file | Fix that file per %error%; other files are unaffected |
script.register_error: "[Script] Attribute registration skipped: %error%" | Payload validation failure (maps to the payload_* messages below) | Correct the fields per %error% |
script.register_override: "[Script] Script attribute %id% overrides a registered attribute with the same id" | Duplicate registration of the same id | Confirm the override is intended; otherwise change the id |
script.payload_missing_id: "%file% is missing the required id field" | Registration object lacks id | Add id |
script.payload_invalid_enum: "%file% field %field% has invalid enum value: %value%" | Misspelled value_kind / target_type / temporary_stack_mode | Use a valid enum value (see the payload table) |
script.payload_invalid_number: "%file% field %field% is not a valid number: %value%" | Numeric field contains invalid text | Provide a number or numeric string |
script.payload_invalid_list: "%file% field %field% must be a list of strings" | lore_patterns / tags is not an array | Provide an array |
Safety Notice
The script environment is a fully open sandbox (any Java class and server API reachable) with the same privileges as the server process — only load scripts you have reviewed yourself; reload rebuilds the context and clears top-level script state. See CoreLib JS Scripting for the full statement
Example Script
The example below ships with the plugin into scripts/attributes/example_attribute.js on first release; modify or delete it freely
js
// EmakiAttribute 脚本属性示例 (attributes 绑定)
// attributes.register ({...}) 以字段声明一个属性定义, 注册后与 attributes/*.yml 中的属性同权:
// 可被物品 ea_attribute 效果, Lore 解析, 占位符与属性快照收集消费
//
// 字段说明 (与 attributes/*.yml schema 对齐):
// id 必填, 属性 ID (同 ID 重复注册时后注册者覆盖并在报告中提示)
// display_name 显示名, 作为 Lore 关键字与别名匹配的基础
// value_kind 数值类型: FLAT / PERCENT / CHANCE / REGEN / RESOURCE / DERIVED
// target_type 目标类型: DAMAGE / RESOURCE / GENERIC / VANILLA
// target_id 目标 ID (资源或原版属性标识, 可选)
// mmoitems_stat MMOItems 统计项映射 (可选)
// default_value 默认值; min_value / max_value 为可选上下限
// allow_negative 是否允许负值, 默认 true
// priority Lore 读取优先级, 数值越大越优先, 默认 0
// lore_format_id 词条格式 (default_flat / default_percent / default_regen / default_resource)
// lore_patterns 自定义 Lore 正则模板 (可选, %Key% 与 %Value% 占位)
// description 描述文本 (可选)
// attribute_power 战力系数, 默认 1
// tags 标签列表 (可选)
// temporary_stack_mode 临时属性叠加模式: REPLACE / STACK
//
// 本文件随插件首次释放; 已存在的 scripts/ 目录不会被升级覆盖, 可自由修改或删除
attributes.register({
id: "script_example_mana_cost",
display_name: "施法消耗减免",
value_kind: "FLAT",
target_type: "GENERIC",
target_id: "mana_cost",
default_value: 0.0,
min_value: 0.0,
max_value: 100.0,
allow_negative: false,
priority: 10,
lore_format_id: "default_flat",
lore_patterns: ["%Key%.*?: ?%Value%$"],
description: "脚本示例属性:降低施法消耗。",
tags: ["script", "example"],
temporary_stack_mode: "REPLACE"
});Related Pages
- Attributes: full semantics of attribute fields and the
value_kind/target_typeenums - CoreLib JS Scripting: host mechanism, directory layout, thread semantics, and the safety notice