主题
这篇教程会手把手教你如何在 HNAttribute 中注册一个全新的属性,包括基础配置、别名设置、属性映射等完整流程。
我们将以 "雷元素攻击"、"雷元素抗性"和"智力" 为例,完整演示整个流程。
教程目标
完成本教程后,你将学会:
- 如何定义一个新的属性
- 如何配置属性的显示名称和别名
- 如何让属性在 Lore 中被识别
- 如何配置属性映射(主属性派生战斗属性)
- 如何测试和验证新属性
前置知识
在开始之前,建议先阅读:
第一步:定义基础属性
1.1 选择或创建属性配置文件
HNAttribute 支持在 plugins/HNAttribute/attributes/ 目录下创建任意 .yml 文件来定义属性。
推荐的文件组织方式:
attributes/base.yml- 基础战斗属性(攻击、防御、生命等)attributes/elemental.yml- 元素属性(火、冰、雷等)attributes/rpg-derived.yml- RPG 主属性(力量、智力、体质等)attributes/custom.yml- 你的自定义属性
你可以:
- 在现有文件中添加属性
- 创建新的
.yml文件(如attributes/my-attributes.yml)
示例: 我们创建 plugins/HNAttribute/attributes/elemental.yml 来存放元素属性。
1.2 添加攻击属性
在 attributes/elemental.yml 中添加雷元素攻击属性:
yml
thunder_damage:
display: "雷元素攻击"
description: "造成雷属性伤害的能力"
default: 0.0
min: 0.0
max: 999999.0
category: "攻击属性"
icon: "LIGHTNING_ROD"字段说明:
thunder_damage:属性 ID,用于内部引用(建议使用_damage后缀表示攻击属性)display:玩家看到的显示名称description:属性说明default:默认值(通常攻击属性默认为 0)min/max:属性的取值范围category:分类,用于属性面板分组显示icon:在 GUI 中显示的图标(Minecraft 材质名)
1.3 添加抗性属性
继续添加对应的抗性属性:
yml
thunder_resistance:
display: "雷元素抗性"
description: "减少受到的雷属性伤害"
default: 0.0
min: 0.0
max: 999999.0
category: "防御属性"
icon: "LIGHTNING_ROD"命名规范:
- 攻击属性:
xxx_damage - 抗性属性:
xxx_resistance - 主属性:直接使用名称(如
strength,intellect)
第二步:配置属性别名
属性别名决定了玩家在 Lore 中可以用什么文字来表示这个属性。
2.1 为什么需要别名
假设你定义了属性 ID thunder_damage,但玩家在装备 Lore 中可能会写:
雷元素攻击: +50雷伤: +50雷击: +50雷元素攻击 +50雷伤 50%
通过配置别名,这些不同的写法都能被正确识别为 thunder_damage 属性。
当前版本默认的 Lore 正则同时支持下面这些常见格式:
属性名: 数值属性名:数值属性名 数值属性名数值也就是说,像
雷元素攻击 +50、雷伤 50%这种“属性名 + 空格 + 数值”的写法,默认就是支持的。
2.2 配置别名
从当前版本开始,属性别名的正式字段是 names。
yml
# ✅ 推荐写法
thunder_damage:
display: "雷元素攻击"
names:
- "雷元素攻击"
- "雷伤"在属性配置文件中为属性添加 names 字段:
yml
thunder_damage:
display: "雷元素攻击"
description: "造成雷属性伤害的能力"
default: 0.0
min: 0.0
max: 999999.0
category: "攻击属性"
icon: "LIGHTNING_ROD"
names:
- "雷元素攻击"
- "雷伤"
- "雷击"
- "雷属性伤害"
- "Thunder Damage"别名配置说明:
names是一个列表,可以添加多个别名- 别名不区分大小写
- 建议至少包含
display作为别名 - 可以添加中文、英文、简写等多种形式
2.3 为抗性属性配置别名
同样为抗性属性添加别名:
yml
thunder_resistance:
display: "雷元素抗性"
description: "减少受到的雷属性伤害"
default: 0.0
min: 0.0
max: 999999.0
category: "防御属性"
icon: "LIGHTNING_ROD"
names:
- "雷元素抗性"
- "雷抗"
- "雷元素防御"
- "Thunder Resistance"第三步:配置主属性与映射
3.1 什么是属性映射
属性映射让你可以定义 "主属性" (如力量、智力)自动转换为 "战斗属性" (如攻击力、法力值)。
玩家只需要关注装备上的"智力"等主属性,系统会自动计算出法力值、魔法伤害等战斗属性。
3.2 为什么需要属性映射
传统方式的问题:
如果没有属性映射,你需要在装备上写:
text
智力: 10
最大法力值: 50
法力恢复: 1
魔法伤害: 15这样会导致:
- 装备 Lore 过长
- 数值调整困难
- 玩家难以理解属性关系
使用属性映射后:
装备上只需要写:
text
智力: 10系统会自动计算:
- 最大法力值 = 智力 × 5 = 50
- 法力恢复 = 智力 × 0.1 = 1
- 魔法伤害 = 智力 × 1.5 = 15
3.3 配置智力主属性
在 attributes.yml 中添加智力属性:
yml
intellect:
display: "智力"
description: "影响法力值和魔法伤害"
default: 0.0
min: 0.0
max: 999999.0
category: "主属性"
icon: "ENCHANTED_BOOK"
priority: 100 # 优先级,越高越先计算
names:
- "智力"
- "智慧"
- "Intellect"
mapping: # 映射配置
targets:
max_mana: # 目标属性 1: 最大法力值
operation: ADD # 操作类型
formula: "total * 5" # 智力 × 5 = 法力值(单行自动识别为 expression)
mana_regen: # 目标属性 2: 法力恢复
operation: ADD
formula: "total * 0.1" # 智力 × 0.1 = 法力恢复
magic_damage: # 目标属性 3: 魔法伤害
operation: ADD
formula: "total * 1.5" # 智力 × 1.5 = 魔法伤害映射配置说明:
priority:优先级,主属性应该设置较高的值(如 100),确保先于战斗属性计算mapping.targets:在targets下定义一个或多个目标属性formula:公式字符串,单行自动识别为 expression 模式total:公式中的变量,代表主属性的总值operation:派生属性的操作类型,通常使用 ADD
公式类型自动推断:
- 单行字符串 → 自动使用 expression 模式
- 多行字符串(
|-或|)→ 自动使用 groovy 模式
3.4 配置更多主属性
力量属性
yml
strength:
display: "力量"
description: "影响物理攻击力和暴击"
default: 0.0
min: 0.0
max: 999999.0
category: "主属性"
icon: "IRON_SWORD"
priority: 100
names:
- "力量"
- "Strength"
mapping:
targets:
attack_damage: # 攻击力
operation: ADD
formula: "total * 0.5"
crit_chance: # 暴击率
operation: ADD
formula: "total * 0.2"体质属性
yml
vitality:
display: "体质"
description: "影响生命值和防御"
default: 0.0
min: 0.0
max: 999999.0
category: "主属性"
icon: "GOLDEN_APPLE"
priority: 100
names:
- "体质"
- "Vitality"
mapping:
targets:
max_health: # 最大生命值
operation: ADD
formula: "total * 5"
health_regen: # 生命恢复
operation: ADD
formula: "total * 0.1"
defense: # 防御力
operation: ADD
formula: "total * 0.3"第四步:配置 Lore 读取规则(可选)
4.1 默认读取规则
HNAttribute 默认支持以下 Lore 格式:
属性名: +数值
属性名: 数值
属性名 +数值例如:
雷元素攻击: +50
智力: 30
雷抗 +204.2 自定义读取规则
如果需要自定义 Lore 格式,可以在属性配置文件中配置 read-pattern:
yml
thunder_damage:
# ... 其他配置 ...
read-pattern: "(?:雷元素攻击|雷伤|雷击)[::]?\\s*[+]?(\\d+(?:\\.\\d+)?)"正则表达式说明:
(?:雷元素攻击|雷伤|雷击):匹配任意一个别名[::]?:可选的冒号(中文或英文)\\s*:可选的空格[+]?:可选的加号(\\d+(?:\\.\\d+)?):捕获数值(支持小数)
第五步:保存并重载
5.1 保存配置文件
确保所有修改都已保存。
5.2 重载插件
text
/hnattr reload5.3 检查加载结果
查看控制台输出,确认属性加载成功:
[HNAttribute] Loaded attribute: thunder_damage (雷元素攻击)
[HNAttribute] Loaded attribute: thunder_resistance (雷元素抗性)
[HNAttribute] Loaded attribute: intellect (智力)
[HNAttribute] Loaded attribute: strength (力量)
[HNAttribute] Loaded attribute: vitality (体质)第六步:测试属性
6.1 测试基础属性
当前没有 /hnattr set 这种直接给玩家设属性值的命令。
正确测试方式是:先做一件测试装备,在 Lore 里写上你刚注册的属性,例如:
text
雷元素攻击: 100然后执行:
text
/hnattr inspect
/hnattr trace thunder_damage
/hnattr stats这样你就能确认:
- Lore 是否被正确读取
thunder_damage是否真的进入了玩家最终属性- 面板里是否能看到对应属性
6.2 测试属性映射
如果你还注册了 intellect,同样建议通过测试装备或其他真实来源(Buff / Mythic / PDC)来验证,而不是假设存在 /hnattr set。
例如做一件测试装备:
text
智力: 20然后查看最终属性:
text
/hnattr lookup
/hnattr trace max_mana你应该能看到类似结果:
- 智力: 20
- 最大法力值: 100(来自 20 智力 × 5)
- 法力恢复: 2(来自 20 智力 × 0.1)
- 魔法伤害: 30(来自 20 智力 × 1.5)
6.3 追踪属性来源
text
/hnattr trace max_mana你会看到类似:
text
mapping:intellect
+100.0 (来自 20 智力 × 5)6.4 测试 Lore 识别
创建一个测试物品,在 Lore 中添加:
智力: +30
雷元素攻击: +50
雷抗: +20手持物品后,使用命令查看是否被正确识别:
text
/hnattr inspect应该显示:
intellect: 30 (来源: equipment:mainhand)thunder_damage: 50 (来源: equipment:mainhand)thunder_resistance: 20 (来源: equipment:mainhand)
第七步:进阶配置
7.1 使用分段公式(Groovy 模式)
有时候你希望属性转换不是线性的,可以使用多行公式(自动识别为 Groovy 模式):
yml
intellect:
# ... 其他配置 ...
mapping:
targets:
magic_damage:
operation: ADD
formula: |-
if (total <= 50) {
return total * 0.8
} else if (total <= 100) {
return 40 + (total - 50) * 1.2
} else {
return 100 + (total - 100) * 1.5
}这个公式的含义:
- 0-50 智力:每点智力 = 0.8 魔法伤害
- 51-100 智力:每点智力 = 1.2 魔法伤害
- 100+ 智力:每点智力 = 1.5 魔法伤害
注意: 多行公式会自动识别为 Groovy 模式,需要使用 return 语句返回值。
7.2 链式派生:它到底是干什么的?
很多人第一次看到“链式派生”时都会困惑:
既然可以直接写
智力 -> 魔法伤害,为什么还要多绕一层?
先说结论:
链式派生不是新语法,它只是把多个普通映射串起来。
text
一层映射:主属性 → 最终属性
链式派生:主属性 → 中间属性 → 最终属性也就是说:
strength -> attack_damage是普通映射intellect -> spell_power -> magic_damage就是链式派生
7.2.1 它和普通映射的区别
普通映射
适合简单、直接的场景:
text
力量 → 攻击力
体质 → 最大生命值
智力 → 最大法力值优点是:
- 好理解
- 好配置
- 好调试
链式派生
适合你想把“成长逻辑”和“最终效果”拆开的场景:
text
智力 → 法术强度 → 魔法伤害
智力 → 神圣亲和 → 治疗强度
智力 → 召唤精通 → 宠物伤害这时候中间层(法术强度 / 神圣亲和 / 召唤精通)就不只是一个过渡值,而是一个可复用、可平衡、可被其他系统继续引用的专精层。
7.2.2 它存在的意义是什么
你可以把链式派生理解成“把一条成长路径拆成几段,每段只负责一件事”。
最常见的价值有 3 个:
1)把通用成长和职业专精拆开
比如所有法系职业都吃 intellect(智力),但不同职业的最终收益不一样:
- 法师更偏
magic_damage - 牧师更偏
heal_power - 召唤师更偏
pet_damage
如果全都直接从 intellect 映射到最终属性,后面会越来越乱。
但如果你拆成:
text
智力 → 法术强度 → 魔法伤害
智力 → 神圣亲和 → 治疗强度
智力 → 召唤精通 → 宠物伤害那“智力”负责通用成长,“中间属性”负责职业解释,“最终属性”负责真正进战斗或技能公式。
2)让多个最终属性复用同一个中间层
比如你先得到 spell_power(法术强度),然后再由它派生出:
magic_damagemana_regenchannel_mastery
这样以后你只要调 intellect -> spell_power 这一步,整条法系成长链都会一起变化。
3)更容易做平衡和版本迭代
如果你的配置全是“主属性直接打到最终属性”,后面一改就要改很多条公式。
但如果中间有一层:
text
主属性 → 专精属性 → 最终属性那你可以:
- 调整上游成长速度
- 调整中层转化效率
- 调整下游最终表现
每一层职责都更清晰。
7.2.3 一个最容易理解的例子
假设你想做一条“智力系法师”的成长链:
yml
intellect:
display: "智力"
priority: 200
mapping:
targets:
spell_power:
operation: ADD
formula: "total * 1.5"
spell_power:
display: "法术强度"
priority: 100
mapping:
targets:
magic_damage:
operation: ADD
formula: "total * 0.8"
mana_regen:
operation: ADD
formula: "total * 0.05"这表示:
- 玩家先获得
intellect intellect先换算成spell_powerspell_power再继续换算成magic_damage和mana_regen
如果玩家最终有 20 点智力,那么:
spell_power = 20 × 1.5 = 30magic_damage = 30 × 0.8 = 24mana_regen = 30 × 0.05 = 1.5
你会发现:
- 玩家表面只拿到了“智力”
- 系统内部却已经形成了一条完整成长链
- 后面你想强化法师,只需要改
spell_power这一层或它的下游
7.2.4 什么时候该用,什么时候不该用
适合用链式派生的情况
- 你要做职业专精
- 你想让多个最终属性共享一个中间层
- 你预期后面会频繁调平衡
- 你希望配置结构更接近“成长模型”,而不是一堆散乱公式
不适合强行上的情况
- 你只是做一个简单生存/RPG 服
- 主属性数量不多,关系也很直接
- 你暂时只需要
力量 -> 攻击力这种简单映射
一句话:
简单服优先用一层映射;复杂成长体系再上链式派生。
7.2.5 和“多个 mapping 目标”不是一回事
有些人会把下面两种情况混在一起:
情况 A:一个属性同时映射多个目标
text
智力 → 最大法力值
智力 → 魔法伤害
智力 → 法力恢复这只是一个属性映射到多个目标,还不算链式派生。
情况 B:映射结果继续参与下一轮映射
text
智力 → 法术强度 → 魔法伤害这才是链式派生。
区别就在于:
- A 是“一次展开”
- B 是“分层传递”
7.2.6 使用链式派生时最重要的注意点
1)上游 priority 必须更高
上游属性要先算,下游属性才能拿到结果。
例如:
intellect:priority: 200spell_power:priority: 100
如果顺序反了,下游可能在上游还没产出值时就先计算,导致结果不对。
2)中间属性最好有清晰命名
推荐这种命名思路:
- 主属性:
strength/vitality/intellect - 中间层:
spell_power/holy_affinity/summon_mastery - 最终层:
magic_damage/heal_power/pet_damage
这样你在 /hnattr trace 里一眼就能看懂整条链。
3)调试时一层一层 trace
不要一上来只看最终属性。
建议按顺序查:
text
/hnattr trace intellect
/hnattr trace spell_power
/hnattr trace magic_damage这样最容易看出:
- 是主属性根本没读到
- 还是中间层没派生出来
- 还是最终层公式写错了
7.2.7 再给你一句最好记的话
你可以把链式派生记成:
普通映射是在“把值算出来”;链式派生是在“把成长路径分层”。
如果你只是想把属性做出来,用普通映射就够;如果你想把职业成长做得更像 RPG,链式派生就会开始有价值。
完整配置示例
attributes/elemental.yml
yml
# 雷元素战斗属性
thunder_damage:
display: "雷元素攻击"
description: "造成雷属性伤害的能力"
default: 0.0
min: 0.0
max: 999999.0
category: "攻击属性"
icon: "LIGHTNING_ROD"
names:
- "雷元素攻击"
- "雷伤"
- "雷击"
- "Thunder Damage"
thunder_resistance:
display: "雷元素抗性"
description: "减少受到的雷属性伤害"
default: 0.0
min: 0.0
max: 999999.0
category: "防御属性"
icon: "LIGHTNING_ROD"
names:
- "雷元素抗性"
- "雷抗"
- "Thunder Resistance"attributes/rpg-derived.yml
yml
# RPG 主属性
intellect:
display: "智力"
description: "影响法力值和魔法伤害"
default: 0.0
min: 0.0
max: 999999.0
category: "主属性"
icon: "ENCHANTED_BOOK"
priority: 100
names:
- "智力"
- "Intellect"
mapping:
targets:
max_mana:
operation: ADD
formula: "total * 5"
mana_regen:
operation: ADD
formula: "total * 0.1"
magic_damage:
operation: ADD
formula: "total * 1.5"
strength:
display: "力量"
description: "影响物理攻击力和暴击"
default: 0.0
min: 0.0
max: 999999.0
category: "主属性"
icon: "IRON_SWORD"
priority: 100
names:
- "力量"
- "Strength"
mapping:
targets:
attack_damage:
operation: ADD
formula: "total * 0.5"
crit_chance:
operation: ADD
formula: "total * 0.2"
vitality:
display: "体质"
description: "影响生命值和防御"
default: 0.0
min: 0.0
max: 999999.0
category: "主属性"
icon: "GOLDEN_APPLE"
priority: 100
names:
- "体质"
- "Vitality"
mapping:
targets:
max_health:
operation: ADD
formula: "total * 5"
health_regen:
operation: ADD
formula: "total * 0.1"
defense:
operation: ADD
formula: "total * 0.3"常见问题
Q0: 为什么 GUI 中显示的最大值是 1.7976931348623157E308?
原因:
max没有正确配置- 系统回退到了非常大的默认边界值
- 这个值就是
Double.MAX_VALUE(1.7976931348623157E308)
解决: 把边界字段写完整:
yaml
thunder_damage:
default: 0.0
min: 0.0
max: 999999.0Q1: 属性配置文件必须叫 attributes.yml 吗?
不是。你可以在 attributes/ 目录下创建任意名称的 .yml 文件,插件会自动加载所有文件中的属性定义。
Q2: 新属性不显示在属性面板中?
检查:
- 属性配置文件是否在
attributes/目录下 - 文件扩展名是否为
.yml - YAML 语法是否正确(注意缩进)
- 是否执行了
/hnattr reload - 查看控制台是否有错误信息
Q3: Lore 中的属性没有被识别?
检查:
- 别名配置是否包含 Lore 中使用的文字
- Lore 格式是否符合默认规则
- 使用
/hnattr inspect查看物品是否被正确读取
Q4: 属性映射没有生效?
检查:
- 主属性的
priority是否足够高(建议 100+) - 是否执行了
/hnattr reload - 使用
/hnattr trace <属性ID>查看是否有mapping:<主属性>来源
Q5: 链式派生不工作?
检查:
- 上游属性的
priority是否高于下游属性 - 属性 ID 是否正确
- 使用
/hnattr trace按“上游 → 中间层 → 下游”顺序查看整条派生链
Q6: 可以为一个属性配置多个别名吗?
可以。names 是一个列表,可以添加任意数量的别名。
Q7: 多个文件中定义了相同的属性 ID 会怎样?
后加载的文件会覆盖先加载的定义。建议每个属性 ID 只在一个文件中定义。
属性在哪里使用
注册属性后,你可以在以下地方使用它们:
1. 创建伤害类型
如果你创建了攻击属性和抗性属性,下一步是创建对应的伤害类型:
→ 如何新增伤害类型
2. 配置战斗管线
将伤害类型接入战斗系统:
→ 如何配置战斗管线
3. 配置 Buff 效果
使用属性创建 Buff:
4. 配置周期效果
使用属性创建 DOT/HOT 效果:
5. 集成到技能系统
在 MythicMobs 技能中使用:
使用内置模板
HNAttribute 自带了一套 RPG 主属性模板,位于 attributes/rpg-derived.yml:
strength(力量) → 攻击力、暴击率agility(敏捷) → 攻击速度、闪避率vitality(体质) → 生命值、生命恢复、防御力intellect(智力) → 魔法伤害、魔法抗性、法力值magic_power(魔力) → 魔法伤害
你可以直接使用这些属性,或者参考它们的配置来创建自己的主属性。
扩展思路
掌握了基础流程后,你可以:
创建更多元素属性
- 风属性(wind_damage / wind_resistance)
- 暗属性(dark_damage / dark_resistance)
- 光属性(light_damage / light_resistance)
创建特殊属性
- 暴击率(crit_chance)
- 暴击伤害(crit_damage)
- 吸血(life_steal)
- 闪避(dodge_chance)
创建复合主属性
- 全能(影响所有战斗属性)
- 精通(提升特定类型伤害)
总结
注册属性的完整流程:
- ✅ 在
attributes.yml中定义属性 ID 和基础配置 - ✅ 配置
display和names让属性可被识别 - ✅ (可选)配置
mapping让主属性派生战斗属性 - ✅ (可选)配置
read-pattern自定义 Lore 格式 - ✅ 重载配置并测试
- ✅ 在伤害类型、Buff、技能等系统中使用
核心要点:
- 属性 ID 要有意义且保持一致性(推荐使用英文/拼音,不推荐中文)
- 别名要覆盖玩家可能使用的各种写法
- 主属性的 priority 要高于战斗属性
- 使用
/hnattr inspect和/hnattr trace是调试的最佳起手式
新版配置格式特性:
- ✅ 简化的 mapping 结构:直接在
mapping下定义目标属性,无需targets嵌套 - ✅ 公式自动推断:单行字符串自动识别为 expression,多行字符串自动识别为 groovy
- ✅ 更清晰的配置:减少冗余层级,提高可读性
属性 ID 命名建议:
- ✅ 推荐:
attack_damage、max_mana、fire_resistance(英文/拼音) - ❌ 不推荐:
攻击力、最大法力值(中文 ID) - ✅ 使用
display和names提供中文显示名和别名 - ✅ 玩家在装备 Lore 中可以写中文(通过别名识别) �,不推荐中文)
- 别名要覆盖玩家可能使用的各种写法
- 主属性的 priority 要高于战斗属性
- 使用
/hnattr inspect和/hnattr trace是调试的最佳起手式
新版配置格式特性:
- ✅ 简化的 mapping 结构:直接在
mapping下定义目标属性,无需targets嵌套 - ✅ 公式自动推断:单行字符串自动识别为 expression,多行字符串自动识别为 groovy
- ✅ 更清晰的配置:减少冗余层级,提高可读性
属性 ID 命名建议:
- ✅ 推荐:
attack_damage、max_mana、fire_resistance(英文/拼音) - ❌ 不推荐:
攻击力、最大法力值(中文 ID) - ✅ 使用
display和names提供中文显示名和别名 - ✅ 玩家在装备 Lore 中可以写中文(通过别名识别) ��
fire_resistance(英文/拼音) - ❌ 不推荐:
攻击力、最大法力值(中文 ID) - ✅ 使用
display和names提供中文显示名和别名 - ✅ 玩家在装备 Lore 中可以写中文(通过别名识别)
