Skip to content

这页帮你弄明白三件事:

  1. 装备属性是怎么被读进系统的
  2. 为什么有些 Lore 看起来像属性,但系统不认
  3. source 为什么是最重要的排查入口

一、属性读取的工作流程

HNAttribute 不是“看到数字就自动加属性”的插件。

它真正做的事情是:

  1. 先识别这段文本 / 标签是不是某个已注册属性
  2. 再根据读取规则把它转成修饰符
  3. 再按 source 写入玩家或实体的属性系统
  4. 最后才进入战斗、Buff、显示、原版属性同步等后续流程

所以你排查问题时,不应该只问:

  • “这段 Lore 看起来对不对?”

而应该问:

  • “它有没有匹配到已注册属性?”
  • “它用了哪种 read-pattern?”
  • “它最后是以哪个 source 进入系统的?”

二、先跟着做一个最小读取实验

先拿一件测试装备,写下面几行 Lore:

text
攻击力: 120
攻击速度: 15%
最大生命值: 60

然后装备到身上,执行:

text
/hnattr inspect
/hnattr lookup
/hnattr source
/hnattr trace attack_damage

你应该分别看到什么

/hnattr inspect

看的是“这件物品到底被读到了什么”。

你重点检查:

  • Lore 原文是不是这三行
  • 解析结果里有没有 attack_damage
  • 百分比那行有没有被识别出来
  • 当前物品是否已经带上标准 identity
  • attributeKind 是不是符合预期
  • 如果这是模板化 token / material,templateMatched / templateKey / templateCategory 是否正确

/hnattr lookup

看的是“这些属性最终有没有真的加到你身上”。

/hnattr source

看的是“这些值来自哪一个来源”。

你大概率会看到:

text
equipment:mainhand

/hnattr trace attack_damage

看的是“这个属性到底由哪些修饰符组成”。

如果这四个命令能对上,你就已经真正跑通了“读取层”。

如果你启用了属性映射 / 派生属性

现在 source / trace 还会把派生来源一起展示出来。

例如你定义了:

yml
strength:
  priority: 100
  mapping:
    targets:
      attack_damage:
        operation: ADD
        formula: "total * 0.5"

那么当 strength 生效后,/hnattr trace attack_damage 里除了装备、Buff 这类显式来源,还会看到类似:

text
mapping:strength

而且现在 trace 会继续把它往上展开,告诉你:

  • 这是从哪个源属性映射过来的
  • 这个源属性的 priority 是多少
  • 当前命中的公式模式与脚本内容
  • 上游属性本身又是被哪些来源撑起来的

这表示:

  • strength 已经先按自己的来源算出最终值
  • 然后它把结果继续派生到了 attack_damage
  • 这个派生值和普通来源一样,真的进入了最终结算链路

所以如果你发现某个属性"看起来没人加,但最终值却变了",第一时间就该想到有没有映射来源。

如果你需要一份能直接复制的完整示例,可以直接翻插件默认自带的:attributes/mapping-demo.yml

如果你想直接使用一套已经启用的经典主属性模板,也可以看:attributes/rpg-derived.yml

当前这套模板里,vitality -> health_regen 已经使用表达式分段公式实现,不依赖额外的 Groovy 映射脚本,默认启用时更稳。

新版配置格式: 已简化 mapping 结构,直接在 mapping 下定义目标属性,公式自动推断类型(单行=expression,多行=groovy)。


三、Lore 是怎么匹配成功的

Lore 能不能生效,不取决于“像不像属性”,而取决于两部分同时成立:

  1. 这个名字是否出现在属性定义的 names
  2. 这个属性使用的 read-pattern 是否能匹配当前文本

也就是说,Lore 识别本质上是:

属性别名 + 读取规则


四、默认属性别名从哪里来

当前默认属性主要在:

text
attributes/base.yml
attributes/combat.yml
attributes/element.yml

例如 attributes/base.yml 里就有:

  • attack_damage
  • max_health
  • health_regen

attack_damage 默认别名就会包括:

  • 攻击力
  • 物理伤害

所以:

text
攻击力: 120

是能被识别的。

但如果你写成:

text
攻击: 120

而你又没有把“攻击”加进 names,那系统不会自动猜它等于 attack_damage


五、默认 read-pattern 是怎么工作的

当前默认 read-patterns.yml 至少有两种模式:

default

适合单值:

text
攻击力: 100
攻击速度:15%

range

适合区间:

text
火焰伤害: 10-20

当前默认配置里,大部分属性用的是:

yml
read-pattern: default

新手最容易忽略的一点

下面这两行虽然都像属性,但意义不同:

text
攻击力: 100
攻击速度: 15%

因为带 % 的值,在系统里通常会被理解成百分比类修饰,而不是普通加法值。

也就是说,1515% 不只是显示差异,运算语义也不同


六、区间值什么时候适合用

如果你想让一件装备每次刷新时在范围内随机取值,就可以考虑 range

例如:

text
火焰伤害: 10-20

但要注意:

  • 不是所有属性默认都在用 range
  • 你要看这个属性自己的 read-pattern

如果某个属性还是:

yml
read-pattern: default

那你写区间,系统也不会自动按区间读。


七、条件系统是怎么挂在 Lore 上的

当前版本支持在属性行后面带条件。

例如:

text
攻击力: 100/Lv.10,权限: vip

意思是:

  • 主属性还是 攻击力: 100
  • 但只有满足等级和权限条件时,这条属性才生效

怎么理解最简单

可以把它理解成:

  • 先匹配属性
  • 再检查条件
  • 条件不满足,这整行就被忽略

排查这种问题时最稳的方法

如果你怀疑“为什么我这件装备看起来对,但加不上去”,优先查:

  1. Lore 有没有命中属性名
  2. 条件是不是不满足

这也是为什么:

text
/hnattr inspect

一定要优先用。


八、为什么有时整件 Lore 都被跳过了

当前 config.yml 里有一个很关键的开关:

yml
attribute-read:
  lore:
    skip-contains: []

它的行为不是“跳过某一行”,而是:

只要任意 Lore 行包含命中词,整件装备的 Lore 读取都跳过。

所以如果你把这些词放进去:

  • 绑定
  • 不可升级
  • 活动道具

而你的装备 Lore 里刚好又有这些文本,那整件装备的 Lore 属性都会失效。

这是很多“看起来完全没问题,但系统一条都没读到”的根本原因。


九、PDC / NBT 读取是怎么工作的

除了 Lore,当前系统还支持:

  • PDC
  • 原始 NBT / SNBT

默认读取 key 是:

text
attribute_tag

两种 key 写法

1)只写 key

text
attribute_tag

表示:

  • 任意 namespace 下,只要 key 叫 attribute_tag 都尝试读

2)完整 namespace:key

text
custom:attribute_tag

表示:

  • 只精确匹配这个 key

为什么这很重要

很多“我明明打了 PDC,但系统没读到”的问题,本质上是:

  • 你实际写入的 key 不叫这个名字
  • 或者 namespace 不一致

十、PDC / NBT 里可以放什么结构

当前实现支持的思路不只一种。

例如你可以理解成它能处理类似:

1)字符串

text
attribute_tag: "攻击力: 100"

2)对象

text
attribute_tag: {attack_damage: 100}

3)列表

text
attribute_tag: ["攻击力: 100", "火焰伤害: 20"]

所以它不只是会读单一纯文本,还能读更结构化的标签内容。


十一、source 为什么这么重要

这是这一页最关键的概念。

HNAttribute 里所有修饰符最终都会按 source 分组管理。

对于装备来说,默认通常会看到:

  • equipment:mainhand
  • equipment:offhand
  • equipment:helmet
  • equipment:chestplate
  • equipment:leggings
  • equipment:boots

对于 Buff,你会看到:

  • buff:力量提升
  • buff:钢铁护体

对于程序注入来源,你可能会看到:

  • custom:quest-reward
  • custom:artifact-bonus

source 的价值是什么

它至少有三个作用:

  1. 知道“值从哪来”
  2. 在换装或移除时精确删除旧来源
  3. /hnattr source/hnattr trace 能稳定排查

所以你可以把 source 理解成:

这个属性系统里真正的来源身份证。


十二、为什么 Buff 也属于“来源”问题

很多人会把 Buff 当成另一个完全独立的系统。

但在 HNAttribute 里,Buff 最终还是会被编译成修饰符,然后以:

text
buff:<key>

这样的来源进入系统。

这就是为什么当你排查 Buff 时,不应该只看:

text
/hnattr buffs

还应该配合:

text
/hnattr source
/hnattr trace <属性ID>

一起看。


十三、自动刷新是怎么发生的

当前玩家常见换装行为都会触发自动刷新,例如:

  • 切换主手
  • 主副手交换
  • 点击背包
  • 拖拽背包
  • 关闭背包
  • 丢弃物品
  • 捡起物品
  • 玩家加入服务器

刷新时,插件会:

  1. 先移除旧的槽位来源
  2. 再读取新的物品结果
  3. 再把新修饰符按对应 source 写回系统

所以它不是“直接覆盖全部值”,而是按来源做精确替换。


十四、最推荐的读取排查路线

情况 1:Lore 没生效

text
/hnattr inspect
/hnattr source
/hnattr trace <属性ID>

情况 2:PDC / NBT 没生效

text
/hnattr inspect

重点看:

  • PDC Keys
  • Raw NBT
  • 解析结果

情况 3:Buff 看起来挂上了,但属性不对

text
/hnattr buffs
/hnattr source
/hnattr trace <属性ID>

十五、这一页最该记住的重点

  1. Lore 能否生效,取决于 属性别名 + read-pattern + 条件
  2. PDC / NBT 与 Lore 可以同时生效,不是二选一。
  3. source 不是装饰文本,而是装备、Buff、外部注入统一管理的核心标识。
  4. 读取问题最稳的起手式永远是:
text
/hnattr inspect

HN 系列插件文档