API
EmakiAttribute 的公开 API 全部位于独立的 EmakiAttributeApi 模块(Maven 坐标 emaki.jiuwu.craft:emaki-attribute-api),包名 emaki.jiuwu.craft.attribute.api 与 emaki.jiuwu.craft.attribute.model。它是 Attribute 契约的唯一权威入口:
PdcAttributeApi— 物品 PDC 属性 payload 的来源注册与读写。EmakiAttributeApi— 玩家资源、已解析属性值、属性伤害与装备同步。
其他模块如果需要和属性系统联动,应使用这两个静态门面或公开事件,而不是直接解析 Attribute 内部数据文件或调用内部 service 类。
PdcAttributeApi
PdcAttributeApi 面向“物品属性 payload”的读写。Forge、Strengthen、Gem、Item 这类装备模块可以通过它向装备写入自己的属性来源。每个 payload 按 source id 隔离存放,互不覆盖。
方法签名
| 方法 | 用途 |
|---|---|
static boolean available() | 判断 Attribute 是否已安装 PDC API 桥接。 |
static boolean registerSource(String sourceId) | 注册一个属性来源,例如 forge、strengthen、gem、item。 |
static void unregisterSource(String sourceId) | 注销属性来源。 |
static boolean isRegisteredSource(String sourceId) | 判断来源是否已注册。 |
static Set<String> registeredSources() | 查看当前已注册来源;不可用时返回空集合。 |
static boolean write(ItemStack, PdcAttributePayload) | 写入或替换该 payload 所属来源的属性。 |
static boolean write(ItemStack, String sourceId, Map<String, Double> attributes, Map<String, String> meta) | 由原始 Map 构造 payload 后写入。 |
static PdcAttributePayload read(ItemStack, String sourceId) | 读取指定来源属性;缺失时返回 null。 |
static Map<String, PdcAttributePayload> readAll(ItemStack) | 读取物品上所有来源属性;永不为 null。 |
static boolean clear(ItemStack, String sourceId) | 清理指定来源属性。 |
static void clearAll(ItemStack) | 清理全部 Attribute payload。 |
static void copy(ItemStack fromItem, ItemStack toItem, Set<String> excludedSourceIds) | 按来源整体复制 payload。 |
PdcAttributePayload 字段
PdcAttributePayload 是不可变 record,构造时会规范化各级 key:
| 字段 | 类型 | 说明 |
|---|---|---|
sourceId() | String | 所属来源 ID。 |
attributes() | Map<String, Double> | 属性 ID → 数值。 |
meta() | Map<String, String> | 任意字符串元数据。 |
conditions() | Map<String, String> | 按属性 ID 指定的激活条件。 |
schemaVersion() | int | payload 结构版本;当前 CURRENT_SCHEMA_VERSION = 2。 |
updatedAt() | long | 最后更新的 epoch 毫秒。 |
配套方法:of(sourceId, attributes, meta)、of(sourceId, attributes, meta, conditions)、conditionFor(attributeId)、hasDurabilityScaling()、toMap()、fromMap(Map)。
copy 的完整保真语义
copy 会逐个来源整体搬运 payload,并完整保留每个 payload 的全部字段,包括 conditions、schemaVersion 和 updatedAt;目标物品上的同名来源会被覆盖。列入 excludedSourceIds 的来源保持目标物品原有内容不变。
升级、重铸、复制物品时应使用 copy,不要用「读出 attributes 再写回」的方式,那样会丢失条件与版本信息。
来源隔离原则
每个模块应写入自己的 source,不要覆盖其他来源。例如 Strengthen 只清理 strengthen 来源,Gem 只清理 gem 来源。这样可以避免强化刷新时误删宝石属性,或宝石提取时误删锻造属性。
来源注册校验
写入前会校验 sourceId 是否已注册。确保在 write 之前调用 registerSource。
EmakiAttributeApi
EmakiAttributeApi 是玩家运行时状态与伤害能力的规范入口。每个方法在 Attribute 缺失、禁用或重载期间都会退化为下表中的固定返回值,因此调用方除避免类加载外无需额外守卫。
| 方法 | 不可用时返回 | 用途 |
|---|---|---|
static boolean available() | false | 判断玩法 API 桥接是否就绪。 |
static double readResourceCurrent(Player, String resourceId) | -1 | 读取玩家资源当前值。 |
static double readResourceMax(Player, String resourceId) | -1 | 读取玩家资源当前上限。 |
static boolean consumeResource(Player, String resourceId, double amount) | false | 消耗资源;会触发 PlayerResourceConsumeEvent。 |
static double readAttributeValue(Player, String attributeId) | 0 | 读取玩家已解析的属性值。 |
static void scheduleEquipmentSync(Player) | 无操作 | 请求一次装备属性重新同步。 |
static boolean applyDamage(LivingEntity attacker, LivingEntity target, String damageTypeId, double baseDamage, Map<String, Object> context) | false | 按属性管线结算并施加伤害;damageTypeId 留空使用默认伤害类型。 |
不要缓存内部
Bridge实例,始终通过静态方法调用,否则重载或禁用后可能通过失效桥接调用。
已废弃的 CoreLib 镜像入口
早期版本在 CoreLib 侧提供了 Attribute 的镜像入口。它们现在只是委托到上面的规范门面,并已标记 @Deprecated(forRemoval = true),将随废弃窗口结束一并移除:
| 废弃入口 | 替代 |
|---|---|
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 的 PdcAttributeGateway | 同上两者 |
Attribute 侧由唯一的兼容适配器 LegacyCoreAttributeCompatibility 实现这些废弃接口,它本身不含任何业务规则,只逐一委托到规范门面。新代码不应使用这些镜像入口,请直接依赖 emaki-attribute-api。
接入建议
- 插件启动后再调用
PdcAttributeApi.available()/EmakiAttributeApi.available()(或PdcAttributeApiProvider.available()),避免加载顺序问题。 - 查询不到 API 时降级运行,不要让 softdepend 模块直接崩溃。
- 不要缓存长期属性快照,装备变化、重载或 resync 后应重新读取。
- 写属性时写真实 payload,Lore 只作为展示。
- 复制物品属性时使用
copy,保留条件与结构版本。 - 消耗资源时使用
EmakiAttributeApi.consumeResource,不要绕过 Attribute 的资源状态管理。
常见接入场景
- Skills 释放技能前检查和消耗法力。
- Gem 镶嵌后写入宝石属性。
- Strengthen 根据星级写入强化属性。
- Forge 根据品质写入锻造属性。
- 外部插件读取玩家当前攻击、防御或资源。
- 监听
EmakiAttributeDamageEvent拦截或修改属性伤害(详见伤害事件 API 文档)。
写入示例
PdcAttributeApi.registerSource("forge");
boolean changed = PdcAttributeApi.write(itemStack, "forge", attributes, meta);
// attributes: Map<String, Double> — 属性 ID → 值
// meta: Map<String, String> — 元数据键值对也可以配合 PdcAttributeApiProvider.available() / requireAvailable() 做可用性检查;后者在 API 不可用时抛出 IllegalStateException。
EmakiAttributeDamageEvent
属性伤害计算完成后触发的 Bukkit 事件。可取消、可修改最终伤害。详见伤害事件 API 文档。
JavaScript 调用
CoreLib JavaScript 脚本中可通过 emaki.module("attribute") 调用 PdcAttributeApi 的物品属性 payload 能力。调用前先检查 available(),避免服务器未安装 Attribute 时脚本失败。
| 方法 | 说明 |
|---|---|
available() | 判断 Attribute API 是否可用。 |
registerSource(sourceId) / unregisterSource(sourceId) / isRegisteredSource(sourceId) | 来源注册管理。 |
registeredSources() | 查看已注册来源。 |
read(itemKey, sourceId) | 读取上下文物品指定来源 payload。 |
readAll(itemKey) | 读取上下文物品全部 Attribute payload。 |
write(itemKey, sourceId, attributes, meta) | 写入属性 payload。 |
clear(itemKey, sourceId) | 清理指定来源 payload。 |
clearAll(itemKey) | 清理全部 Attribute payload。 |
applyDamage(...) / calculateDamage(...) / setDamageTypeOverride(...) | 伤害施加、试算与类型覆盖。 |
脚本读到的 payload 投影包含
sourceId、attributes、meta、conditions、schemaVersion、updatedAt六个字段,由 Attribute 侧的script/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 动态属性与伤害流
在 CoreLib 脚本根目录的 extensions/attribute/ 下,扩展脚本可通过 register() 注册运行时属性、属性提供者、伤害类型、伤害管线和伤害钩子。脚本注册的属性会在 Attribute 重载时重建,参与属性读取、快照签名和伤害计算。
完整的注册 API、definition 字段与 event / ctx 回调方法见 JavaScript 脚本。
通过 CoreLib MythicMobs JS mechanic 调用 Attribute
emaki_js 不是 Attribute 注册的 mechanic。它由 CoreLib 注册,注册名为 emaki_js,别名为 corelib_js、emakicorelib_js。Attribute 只提供 emaki.module("attribute") 脚本模块和示例脚本,供 CoreLib 的通用 JS mechanic 调用。
Attribute 自己注册的 MythicMobs 能力是属性伤害 mechanic emaki_damage(别名 emakiattribute_damage、attribute_damage)和属性条件 emaki_attribute(别名 emakiattribute_attribute、attribute_value、attribute_resource),详见 MythicMobs 集成。
用 CoreLib 通用 JS mechanic 调用 Attribute 示例脚本:
Skills:
JsFireDamage:
Skills:
- emaki_js{script="mythic/mythic_js_damage.js";function="mythicDamage";damage=12;damage_type=fire} @target对应 JS 函数接收 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 会把 scripts/mythic/mythic_js_damage.js 示例释放到 CoreLib 脚本仓库;目标文件已存在时不会覆盖。