属性来源 API
为实体添加、替换和移除外部属性与物品来源
sources 管理参与属性计算的外部数据。每个来源由 AttributeSourceKey 唯一标识;使用相同的键更新,会完整替换旧内容。
写入普通属性
效果消失时,使用原来的来源键移除:
不要为每次刷新生成随机来源键,否则旧数据无法替换,也无法在槽位清空或插件停用时准确移除。
从文字读取
replaceSourceFromLines 接收一个字符串列表,列表中的每个字符串表示一项属性修改。每行必须依次写完整属性 ID、运算方式和数值,三部分之间用一个或多个空格或制表符分隔:
| 部分 | 写法 | 说明 |
|---|---|---|
| 属性 ID | symphony:attack_damage | 必须写完整命名空间;这里不会把 attack_damage 自动补成 symphony:attack_damage |
| 运算方式 | add、multiply_base、multiply_total | 不区分大小写;后两种也可以写成 multiply-base、multiply-total |
| 数值 | 15、-3.5、0.2、20% | 必须是有限数字;末尾带 % 时先除以 100,因此 20% 的内部值是 0.2 |
三种运算的含义如下:
| 运算方式 | 计算方式 |
|---|---|
add | 当前值加上输入值 |
multiply_base | 当前值加上“属性基础值 × 输入值” |
multiply_total | 当前值乘以 1 + 输入值 |
例如,属性基础值为 100,依次提供 add 15、multiply_base 10% 和 multiply_total -5%,最终结果为 (100 + 15 + 100 × 0.10) × 0.95 = 118.75。运算阶段固定为 add、multiply_base、multiply_total,不由文字在列表中的先后顺序决定。
完整调用示例:
symphony:arcane_resistance add 20% 表示加上 0.2,不是增加基础值的 20%;要按基础值增加,应使用 multiply_base 20%。
解析时还需注意:
- 每行开头和结尾的空白会被去除;空行以及去除空白后以
#开头的整行注释会被忽略。 - 不支持行尾注释,例如
symphony:attack_damage add 15 # 注释会被判定为无效数字。 - 列表最多包含
512行,空行和注释也计入数量;每个原始字符串最多512个字符。 - 属性 ID 必须符合小写命名空间格式,并且已经注册。未知属性、未知运算方式、无效数字或任意一行格式错误,都会使本次调用返回
SourceUpdateResult.Rejected,不会写入部分结果。 - 每个有效行会生成一个
line-<原始行号>修改器,优先级固定为0,也不能在文字中设置有效期、持久标记或说明。
需要设置修改器 ID、优先级、有效期或说明时,应直接构造 AttributeModifier,不要使用文字格式。
从 ItemStack 写入
外部装备栏可以把 Overture 物品登记为完整来源:
物品中的属性、套装部件、词条、宝石、强化和技能会一起读取。套装数量会合并普通装备栏、主副手和所有外部物品来源。
外部槽位清空时,必须使用同一个来源键调用 removeSource。需要查看已经登记的外部物品时,可读取:
普通原版物品和没有 Symphony 组件的 Overture 物品不会产生有效内容。传入空气物品相当于清空该来源。
套装显示更新
外部物品改变套装数量后会触发 SetCountsChangedEvent。外部背包或额外装备界面应监听该事件,更新自己持有物品的 Lore:
普通背包中的显示由 Symphony 与 Overture 更新;不在 Bukkit 物品栏中的副本,由保存该副本的外部系统负责重建。显示规则见套装。
处理写入结果
四个写入方法都返回 SourceUpdateResult:
| 结果 | 含义 |
|---|---|
Applied | 来源已经改变,结果中包含实体修订号、受影响属性和套装档位变化 |
Unchanged | 新旧内容相同,没有产生新的属性快照 |
Rejected | 输入无法解析或不符合要求,可读取 reason 和 cause |
写入失败时不要自行修改 Symphony 的 NBT,也不要假定部分数据已经生效。
来源键的约定
namespace 应使用附属插件自己的小写名称,value 用来定位具体槽位或数据项,例如:
来源值最长 256 个字符,不能包含换行和空字符。多个独立槽位不能共用同一个键,否则后写入的物品会覆盖前一个。
线程要求
写入与移除来源必须在 Bukkit 主线程调用。数据库或网络读取应由附属插件提前完成,再把已经准备好的结果提交给 sources。
