Skip to content

属性与技能接入 ​

饰品属性与技能如何接入 EmakiAttribute 与 EmakiSkills, 哪些物品能被放进饰品栏, 以及条件与耐久如何决定饰品是否生效

饰品的属性和技能不由 EmakiAccessory 计算, 而是注册到 EmakiAttribute 与 EmakiSkills 的对外接入点上. 这两个模块是软依赖: 缺失时对应的一半自动失效, 饰品栏本身照常可用

属性接入 EmakiAttribute ​

EmakiAccessory 向 EmakiAttribute 注册一个贡献提供者 (id emakiaccessory:accessories, 优先级 100), 用于把数据并入属性计算: 饰品带来的属性作为独立来源并入战斗时使用的属性快照. 该提供者不注册自定义装备槽位, 也不写入玩家身上的原版属性

上报的来源 id:

来源 id含义
emakiaccessory:accessory单件饰品自身的属性
emakiaccessory:set饰品套装的加成

属性值通过 EmakiAttribute 的 AttributeCatalog#itemSnapshot 读取 -- 与装备路径同一个解析器. 因此一件饰品和一顶数据相同的头盔产出完全相同的数值, 父属性展开与范围伴生键 (给带范围的属性记录配套数据的键) 一并生效

范围伴生键与普通键一样参与求和, 否则带范围的饰品会只保留下界而丢掉浮动区间

EmakiAttribute 不可用时 (EmakiAttributeApi.status().usable() 为 false) 不注册提供者, 饰品属性整体不生效

技能接入 EmakiSkills ​

EmakiAccessory 向 EmakiSkills 注册一个技能来源 (提供者 id accessories). 饰品上的装备技能载荷 (写在物品 PDC 里的技能数据) 由 AccessorySkillPayloadCodec.read 读取, 与 Item / Forge / Gem / Strengthen 写入时用的是同一套 PDC 规则

饰品套装 thresholds[].effects[].es_skills 里列出的技能也经由同一条路径生效

技能条目记录来源的那一项: 单件饰品的技能填槽位实例 id, 套装技能填 set:<套装id>

未安装 EmakiSkills 时模块照常启用: 技能集成类由 AccessoryProviderRegistrar 按类名 emaki.jiuwu.craft.accessory.provider.AccessorySkillsProviderIntegration 查找并加载, 只有在 EmakiSkills 已启用时才会加载它, 因此 EmakiSkills 缺失不会造成类加载失败, 只是没有技能来源

槽位限制判据 ​

饰品栏只接受显式声明了饰品槽的物品. 物品自带的声明来源只有一条:

  1. EmakiItem 物品定义里 effects 的 type: "accessory_slot", 由 EmakiItem 写入物品 PDC 的 emakiitem:accessory_slots (字符串列表)

在此基础上, config.yml 里的 slot_sources.pdc 与 slot_sources.lore 是由运维显式开启的追加来源, 默认都关闭; 开启后与物品自带的声明一起判断, 命中其中任意一条即通过

EmakiAttribute 载荷的 active_slot 元数据与 EmakiSkills 载荷的 active_slot 不再参与饰品栏判定. 旧行为下物品未指定槽位时会被写成 all, 于是任何 EmakiItem 物品都能放进任意饰品格; 现在这类物品会因为没有任何 accessory_slots 声明而被拒绝. 属性与技能贡献使用同一套规则, 声明不匹配的格既放不进, 也不产生贡献

匹配规则: 声明的槽位里只要有任意一条命中当前格就通过

物品声明的槽位结果
部位 id, 如 ring该部位的任意一格生效
槽位实例 id, 如 ring_1只有这一格生效
其他值 (如 hand, main_hand 等装备槽名)命中不了任何饰品槽, 等同未声明
没有 accessory_slots 键 (且追加来源也没读到)拒绝放入, 提示 gui.not_declared, 贡献被整体丢弃

容器行为上的两道保险:

  • 放入时判断规则不通过即拒绝, 光标物品原样留在光标上, 不会进入槽位;
  • 关闭界面时对全部页做一次校验, 把"已不在槽位声明内"的物品取出并退回玩家背包 (背包放不下就掉在脚下), 逐件提示 gui.invalid_returned. 孤儿格 (该页已不再声明的槽位) 不受影响, 仍按孤儿取回流程处理

如果装备侧的判断规则将来发生变化, 饰品侧这份实现需要同步评估

条件门控 ​

饰品栏中的饰品按其定义的 condition 检查: 条件不满足时, 该饰品的属性, 技能与套装件数全部停止参与贡献, 物品仍留在槽内

判断走 EmakiItemApi 的一个不会触发额外动作的查询 ItemCatalog#conditionSatisfied(player, itemStack) -- 它和 conditionPasses 用同一套判断, 但不执行 on_pass/on_fail 动作, 也不发 on_fail.message, 因此可以在重算贡献与界面显示时反复求值. 触发上下文与装备路径的贡献检查一致, 都是 contribution

求值时机是重新计算贡献: GUI 编辑, 页切换, 数据加载完成, reload, /eacc retrieve, 死亡掉落, 耐久扣满. 条件本身 (等级, 职业, 占位符) 变化后不会立刻反映到饰品栏, 要等下一次重算才生效; 这与装备路径"每次收集实时求值"不同

EmakiItem 未安装, 玩家离线, 调用线程不是玩家 owner 线程或定义无法解析时, 查询返回失败, 饰品侧按"条件满足"处理 (这里按不做检查处理), 避免因为依赖缺失误伤饰品

界面上的状态标识: 条件不满足的饰品在饰品栏里额外显示一行 gui.condition_unmet 提示; 该行只在界面里显示, 不会写回物品本身

耐久度门控 ​

durability.enabled 打开后, 生效页上的饰品会在玩家受伤时按 durability.damage_per_hit 扣除耐久; 扣满后该饰品的属性, 技能与套装件数全部停止生效, 物品保留在槽内并显示 gui.durability_broken 标识. 判断规则与配置细节见主配置与部位定义

重算时机 ​

属性与技能的快照在饰品内容发生变化时重算: GUI 编辑, 数据加载完成, reload, /eacc retrieve 取回, 死亡掉落清空生效页. 只打开窗口而不改数据, 不触发重算. 条件检查与耐久检查都在这条路径上求值

重算不在提供者回调里进行. EmakiAttribute 的战斗快照收集器会在计算自己的缓存签名时调用贡献提供者, 每次读取战斗快照都会调用一次; 把 PDC 解析放在那里等于把物品反序列化搬到战斗时最常走的那段逻辑上

线程要求 ​

重算必须在持有这些物品的玩家的 owner 线程执行: 属性解析器会把结果写回物品 PDC 作为缓存, 不在该线程上执行不安全. 条件检查的查询同样要求玩家 owner 线程, 不满足时按"条件满足"处理

缺失模块时的行为 ​

缺失的模块影响
EmakiAttribute不注册属性提供者, 饰品不提供属性; 饰品栏与套装件数统计照常工作 (套装件数只依赖 EmakiItem)
EmakiSkills不注册技能来源, 饰品与套装的技能都不提供; 其余功能照常
EmakiItem物品不再带 accessory_slots 声明 (已有物品上的该键仍在), 因此除 slot_sources 追加来源命中的物品外都无法放入; 条件检查整体跳过 (按满足处理); unique 去重回退为原版材质判定; 依赖 pieces[].item 的饰品套装整体不生效 (件数恒为 0)
PlaceholderAPI文本中的 PAPI 占位符不再替换, 原样输出

EmakiAccessory 本身没有 PlaceholderAPI 扩展, 不对外提供 %emakiaccessory_*% 占位符; 它只是可选地消费 PlaceholderAPI. 本模块也没有向 CoreLib 动作注册表注册任何动作 (模块内唯一的 super("accessory", …) 是配置预检贡献者的模块 id, 不是动作段)