简体中文
配置目录
EmakiAttribute 配置文件的位置, 主配置 config.yml 的字段含义, 以及改完配置后的排查顺序如下
EmakiAttribute 的配置分几块: 主配置, 属性定义, 伤害类型, 条件, Lore 格式和属性平衡文件. 建议你先定好属性 ID 和命名规则, 再去扩展伤害类型和装备来源
默认目录结构
text
plugins/EmakiAttribute/
├── config.yml
├── attribute_balance.yml
├── attributes/
├── damage_types/
├── conditions/
├── lore_formats/
├── presets/
├── gui/
├── lang/
└── data/| 路径 | 作用 |
|---|---|
config.yml | 主配置, 控制默认资源, 伤害接管, 自然回复, 衰减曲线和原版伤害映射 |
attribute_balance.yml | 属性战力分数与平衡参数 |
attributes/ | 单个属性的定义, 例如攻击, 防御, 暴击, 资源, 原版属性映射 |
damage_types/ | 伤害类型管线, 例如物理, 投射物, 法术 |
conditions/ | 属性读取条件 (也就是 PDC 读取规则) |
lore_formats/ | 属性展示格式模板 |
presets/ | 属性预设定义 |
gui/ | 属性点 GUI 配置 (attribute_points.yml) |
lang/ | 多语言文本, 内置 zh_CN.yml 与 en_US.yml |
data/ | 运行时数据目录, 例如 data/parent_attributes/<UUID>.yml, 不用手动改 |
建议修改顺序
- 先在
attributes/定义属性 ID, 展示名, 数值类型和上限 - 再在
lore_formats/定义旧物品 Lore 的读取或展示格式 - 接着在
damage_types/配置伤害阶段 - 最后接入 Item, Forge, Strengthen, Gem 等模块写入 PDC 属性
- 每次改完先运行
/ea lint, 再/ea reload和/ea resync <player>
主配置字段
下表覆盖 config.yml 的全部顶层键; 嵌套小节 (default_profile, shield, synthetic_hit_feedback, damage_indicator, scaling_curves, allowed_damage_causes) 的字段在各自小节列出
发货默认值 (只列顶层键; default_profile, shield, synthetic_hit_feedback, damage_indicator, allowed_damage_causes 的完整内容见各自小节):
yaml
version: "4.8.7"
language: "zh_CN"
release_default_data: true
attribute_sources:
read_lore_attributes: true
read_pdc_attributes: true
require_lore_pdc_match: false
hard_lock_damage: true
default_damage_type: physical
projectile_damage_type: projectile
vanilla_event_damage:
enabled: true
damage_type: physical
same_signature_ignores_invulnerability:
enabled: true
window_ms: 500
attack_speed:
scope: global
regen_interval_ticks: 20
sync_delay_ticks: 1
health_display_scaling:
enabled: false
target: 20.0
default_profile: # 见"默认资源与属性"
shield: # 见"盾牌格挡"
synthetic_hit_feedback: # 见"合成命中反馈"
damage_indicator: # 见"伤害飘字"
scaling_curves: {} # 默认空映射, 即不启用衰减
allowed_damage_causes: # 见"原版伤害映射", 默认 33 条 cause 映射| 字段 | 类型 | 必填 | 默认值 | 取值范围 | 说明 |
|---|---|---|---|---|---|
version | string | 否 | "4.8.7" | — | 配置版本号, 由内置资源同步流程维护, 不要手工改 |
language | string | 否 | "zh_CN" | — | 语言文件名, 对应 lang/<language>.yml |
release_default_data | boolean | 否 | true | true / false | 关掉后, 缺失的内置数据文件 (属性, 伤害类型, 条件, Lore 格式, 预设, GUI 等) 就不再自动生成 |
attribute_sources.read_lore_attributes | boolean | 否 | true | true / false | 要不要从物品 Lore 解析属性 |
attribute_sources.read_pdc_attributes | boolean | 否 | true | true / false | 要不要从物品 PDC (挂在物品上的原版附加数据) 读取属性 |
attribute_sources.require_lore_pdc_match | boolean | 否 | false | true / false | 启用后, 同一个属性必须在 Lore 和 PDC 两侧都存在且数值一致, 才计入一次; 只存在一侧或数值不一致, 这个属性就不生效 |
hard_lock_damage | boolean | 否 | true | true / false | 为了兼容旧配置保留的字段: 配置解析器会读它, 但运行时没有任何地方用它, 改了也不会改变任何行为. 没被 allowed_damage_causes 白名单命中的原版伤害, 由 vanilla_event_damage 决定怎么处理 |
default_damage_type | string | 否 | physical | — | 没指定伤害类型时使用的默认类型; 应该指向一个已经加载的伤害类型 ID, 没加载的话 /ea lint 会报出来 |
projectile_damage_type | string | 否 | projectile | — | 投射物发射时会先把攻击者的属性快照存下来, 命中时用这个伤害类型 ID 结算; 没加载的话 /ea lint 会报出来 |
vanilla_event_damage.enabled | boolean | 否 | true | true / false | 启用时保留原版事件并原地改写最终伤害 (完美接管); 关闭时取消事件, 由 EA 重施伤害 (兼容模式) |
vanilla_event_damage.damage_type | string | 否 | 同 default_damage_type (physical) | — | 没被单独映射的原版伤害用哪个伤害类型 ID; 只在上一个开关启用时才用得上, 没加载的话 /ea lint 会报出来 |
same_signature_ignores_invulnerability.enabled | boolean | 否 | true | true / false | 同一个攻击者, 属性快照签名和伤害类型都相同的多段命中, 要不要互相无视原版的受伤间隔 |
same_signature_ignores_invulnerability.window_ms | long | 否 | 500 | ≥ 0 | 同一批判定的时间窗, 单位毫秒 |
attack_speed.scope | string | 否 | global | global / attribute_only | 攻击速度冷却的接管范围, 填了别的值都按 global 处理. global 会接管所有攻击, 按 Bukkit ATTACK_SPEED 换算冷却; attribute_only 只接管 Lore/PDC 里明确带 EA 攻速的物品 |
regen_interval_ticks | integer | 否 | 20 | ≥ 1 | 资源自然回复的计算间隔, 单位是游戏刻 (1/20 秒), 20 个游戏刻就是 1 秒 |
sync_delay_ticks | integer | 否 | 1 | ≥ 0 | 属性同步到 Bukkit 的延迟, 单位是游戏刻 (1/20 秒) |
health_display_scaling.enabled | boolean | 否 | false | true / false | 要不要压缩客户端看到的血条显示; 这不改变真实生命值, 也不改变伤害结算 |
health_display_scaling.target | double | 否 | 20.0 | 有限数值且 > 0 | 客户端血条换算后的目标刻度; 20 就是一排红心. 填了非法值或 ≤ 0 时回退成 20.0 |
default_profile | object | 否 | 见"默认资源与属性" | — | 玩家的默认属性与资源基础值 |
shield | object | 否 | 见"盾牌格挡" | — | 盾牌格挡交给谁结算 |
synthetic_hit_feedback | object | 否 | 见"合成命中反馈" | — | 接管原版伤害之后, 用来补上击退和受伤音效 |
damage_indicator | object | 否 | 见"伤害飘字" | — | 伤害飘字的配置 |
scaling_curves | map | 否 | 空 (不启用衰减) | — | 属性超过阈值之后怎么衰减, 详见属性衰减曲线 |
allowed_damage_causes | list | 否 | 见"原版伤害映射" | — | 原版 DamageCause 到属性伤害类型的映射白名单 |
示例: 只从 PDC 读取物品属性, 并保留完美接管
yaml
attribute_sources:
read_lore_attributes: false
read_pdc_attributes: true
vanilla_event_damage:
enabled: true
damage_type: physical物品属性来源策略
attribute_sources 控制物品属性是否从 Lore, PDC 读取, 以及双来源是否需要互相校验:
yaml
attribute_sources:
read_lore_attributes: true
read_pdc_attributes: true
require_lore_pdc_match: false默认模式保持旧行为: 只要启用了 Lore 与 PDC 来源, 它们就会一起参与物品属性收集. 你开启 require_lore_pdc_match 后, 系统会按属性 ID 逐项比较:
- Lore 与 PDC 都存在且数值一致: 该属性只计入一次
- 两侧数值不一致: 该属性不计入
- 仅 Lore 或仅 PDC 存在: 该属性不计入
- 固定值与区间 (spread) 值都执行相同的一致性检查
注意, 一致模式要求两个读取开关同时打开. 关掉其中任何一个, 预检都会给出警告, 物品属性也无法形成双来源一致结果. 如果 Lore 与 PDC 都关掉, 玩家仍可拥有默认, 临时和其他实体来源属性, 只是装备物品不再贡献 Lore/PDC 属性
默认资源与属性
default_profile 定义玩家初始化时拥有的资源和属性基础值:
yaml
default_profile:
resources:
health:
display_name: "生命值"
default_max: 20.0
min_max: 1.0
max_max: 2048.0
sync_to_bukkit: true
full_on_init: true
mana:
display_name: "法力值"
default_max: 100.0
min_max: 0.0
max_max: 99999.0
sync_to_bukkit: false
full_on_init: true
attributes:
physical_attack: 0.0
physical_defense: 0.0
health_regen: 0.1
mana_regen: 0.1default_profile.resources.<id>
每个小节 key 就是资源 ID. 字段如下:
| 字段 | 类型 | 必填 | 默认值 | 取值范围 | 说明 |
|---|---|---|---|---|---|
<资源 id> (小节 key) | string | 否 | 小节 key | — | 资源 ID, 同时作为资源定义的 id (如 health, mana) |
display_name | string | 否 | 同资源 ID | — | 展示名称 |
default_max | double | 否 | 0 | 有限数值 (非法回退 0) | 默认最大值; 填了非法值会回退成 0 |
min_max | double | 否 | 0 | 有限数值 | 最大值下限; 上限值经过 clampMax 后不会低于这个值 |
max_max | double | 否 | Double.MAX_VALUE | 有限数值 | 最大值上限 |
sync_to_bukkit | boolean | 否 | false | true / false | 要不要把资源同步到 Bukkit (health 必须为 true); 填 false 的资源 (例如 mana) 始终以 PDC 为准 |
full_on_init | boolean | 否 | true | true / false | 初始化的时候要不要把资源填满 |
regen_per_second | double | 否 | 0 | ≥ 0 | 每秒自动回复多少; 实际回复按 regen_interval_ticks 分摊 |
is_health | boolean | 否 | false | true / false | 要不要把它标记为生命资源 |
default_profile 还识别可选的 id (默认 default), priority (默认 1000000), description (默认空) 三个节级键; 发货 config.yml 未写出它们
default_profile.attributes.<attribute_id>
| 字段 | 类型 | 必填 | 默认值 | 取值范围 | 说明 |
|---|---|---|---|---|---|
<属性 id> | double | 否 | 0 | 有限数值 (非法回退 0) | 玩家初始化时给该属性注入的基础值; 没列出来的属性不会得到默认值 |
内置默认资源:
health: 默认最大 20, 同步到 Bukkit, 最小上限 1, 最大上限 2048mana: 默认最大 100, 不同步到 Bukkit, 最小上限 0, 最大上限 99999
简单分: 资源管生命, 法力, 怒气这类会变化的数值, 属性管装备, 宝石, 强化, 技能和伤害计算. 设了 sync_to_bukkit: true 的资源会同步到 Bukkit 的对应表现, 生命值就靠它
yaml
# 新增一个每秒回复 5 点的怒气资源
default_profile:
resources:
rage:
display_name: "怒气"
default_max: 100.0
min_max: 0.0
max_max: 100.0
sync_to_bukkit: false
full_on_init: false
regen_per_second: 5.0盾牌格挡
shield 决定格挡由原版还是 EA 结算. 详见伤害系统的"盾牌格挡"
yaml
shield:
mode: vanilla
require_facing: true
facing_angle_degrees: 180| 字段 | 类型 | 必填 | 默认值 | 取值范围 | 说明 |
|---|---|---|---|---|---|
mode | string | 否 | vanilla | vanilla / attribute | vanilla 保留原版 BLOCKING; attribute 把它清零, 改由伤害类型的 block 阶段结算. 填了别的值都按 vanilla 处理 |
require_facing | boolean | 否 | true | true / false | 只在 attribute 模式生效, 要不要要求伤害来源位于正面. 环境伤害没有来源方向, 所以不算正面格挡 |
facing_angle_degrees | double | 否 | 180 | 0 ~ 180 (超出会被夹到区间内) | 正面判定的张角, 单位度; 180 表示以视线为中心的半平面 |
示例: 改为百分比格挡
yaml
shield:
mode: attribute
require_facing: true
facing_angle_degrees: 180
# 再把 default_profile.attributes.block_reduction 调低 (如 40) 即得到 40% 减伤合成命中反馈
synthetic_hit_feedback 只在兼容模式 (vanilla_event_damage.enabled: false) 下补发击退与受伤音效
yaml
synthetic_hit_feedback:
knockback: true
knockback_strength: 0.4
hurt_sound: true| 字段 | 类型 | 必填 | 默认值 | 取值范围 | 说明 |
|---|---|---|---|---|---|
knockback | boolean | 否 | true | true / false | 要不要补发击退 |
knockback_strength | double | 否 | 0.4 | ≥ 0 (负值按 0) | 击退强度; 数值越高, 位移越明显 |
hurt_sound | boolean | 否 | true | true / false | 要不要播放受伤音效 |
示例: 与自定义击退插件共存时关闭合成击退
yaml
synthetic_hit_feedback:
knockback: false
hurt_sound: true伤害飘字
damage_indicator 管伤害飘字. 用哪种渲染后端由 EmakiCoreLib 的 display.backend 决定: packet 后端只有下方 visible_to 指定的相关玩家能看到; bukkit 后端飘字是真实体, 附近所有玩家都能看到, visible_to 不生效
yaml
damage_indicator:
enabled: true
merge_window_ms: 500
max_per_target_per_second: 4
visible_to: "involved"
ignored_causes:
- FIRE_TICK
- POISON
- WITHER
- DROWNING
- FREEZE
- SUFFOCATION
- STARVATION
lifetime_ticks: 24
spawn:
offset:
x: 0.0
y: 2.0
z: 0.0
random_offset:
x: 0.4
y: 0.15
z: 0.4
motion:
enabled: true
step_ticks: 2
speed: 0.30
gravity: -0.030
direction:
mode: "random"
fixed:
x: 0.0
y: 1.0
z: 0.0
pitch:
min: 55.0
max: 85.0
yaw:
min: -180.0
max: 180.0
scale:
pop_from: 0.6
pop_ticks: 3
shrink_to: 0.0
shrink_ticks: 6
triggers:
normal:
enabled: true
critical:
enabled: true
heal:
enabled: true
dodge:
enabled: true| 字段 | 类型 | 必填 | 默认值 | 取值范围 | 说明 |
|---|---|---|---|---|---|
enabled | boolean | 否 | true | true / false | 要不要启用伤害飘字 |
merge_window_ms | integer | 否 | 500 | ≥ 0 | 同一个目标在这个时间窗 (毫秒) 内的多次伤害会合并成一个飘字; 0 表示不合并, 窗口内再次命中会重新开始计时 |
max_per_target_per_second | integer | 否 | 4 | ≥ 0 | 同一个目标每秒最多生成几个飘字; 0 表示不限 |
visible_to | string | 否 | involved | involved / all | 只在 packet 后端生效: involved 只有双方能看到, all 附近玩家都能看到; 填了别的值按 all 处理 |
ignored_causes | list<string> | 否 | 7 项 (FIRE_TICK, POISON, WITHER, DROWNING, FREEZE, SUFFOCATION, STARVATION) | 任意 Bukkit DamageCause 名 | 不显示飘字的伤害原因; 空列表会回退成默认的那 7 项 |
lifetime_ticks | integer | 否 | 24 | ≥ 1 | 存活与抛物运动的总时长, 单位是游戏刻 (1/20 秒); 到期后由 CoreLib 回收 |
spawn.offset.x / .y / .z | double | 否 | 0.0 / 2.0 / 0.0 | — | 相对目标脚部的固定偏移, 单位格 |
spawn.random_offset.x / .y / .z | double | 否 | 0.4 / 0.15 / 0.4 | — | 各轴随机散布范围是 ±该值, 单位格; 0 表示这个轴不散布 |
motion.enabled | boolean | 否 | true | true / false | 要不要启用抛物运动 |
motion.step_ticks | integer | 否 | 2 | ≥ 1 | 关键帧间隔 (游戏刻), 同时也是客户端插值时长; 1 最平滑, 值越大包越少, 折线感越强 |
motion.speed | double | 否 | 0.30 | ≥ 0 | 抛出初速度 (格/游戏刻) |
motion.gravity | double | 否 | -0.030 | — | 竖直加速度 (格/游戏刻²), 负值是下坠, 决定抛物线的弯曲程度 |
motion.direction.mode | string | 否 | random | random / fixed / away_from_attacker | 抛出方向模式; 填了别的值按 random 处理 |
motion.direction.fixed.x / .y / .z | double | 否 | 0.0 / 1.0 / 0.0 | — | mode: fixed 时使用的方向向量 |
motion.direction.pitch.min / .max | double | 否 | 55.0 / 85.0 | — (min > max 时自动交换) | 仰角区间 (度), 90 是正上方 |
motion.direction.yaw.min / .max | double | 否 | -180.0 / 180.0 | — (min > max 时自动交换) | 水平角区间 (度) |
motion.scale.pop_from | double | 否 | 0.6 | ≥ 0 | 出场起始缩放, 在前 pop_ticks 内线性放大到 1.0 |
motion.scale.pop_ticks | integer | 否 | 3 | ≥ 0 | 出场放大的时长 (游戏刻) |
motion.scale.shrink_to | double | 否 | 0.0 | ≥ 0 | 退场目标缩放, 在最后 shrink_ticks 内从 1.0 线性缩到这个值; 0 表示缩到看不见 |
motion.scale.shrink_ticks | integer | 否 | 6 | ≥ 0 | 退场缩小的时长 (游戏刻) |
triggers.<normal|critical|heal|dodge> | object 或 boolean | 否 | 各自 enabled: true | — | 四个触发器 (普通命中, 暴击, 治疗, 闪避). 可以只写要改的键 (enabled, lifetime_ticks, spawn.*, motion.*), 没写的键会继承上面的默认值; 也可以直接写布尔值, 那样只设置 enabled. dodge 还需要闪避判定本身被启用; 原版战斗默认不做闪避判定 |
示例: 暴击飘字更快, 并抑制持续伤害刷屏
yaml
damage_indicator:
enabled: true
max_per_target_per_second: 2
triggers:
critical:
enabled: true
motion:
speed: 0.42
gravity: -0.036
scale:
pop_from: 0.35
pop_ticks: 4原版伤害映射
allowed_damage_causes 决定哪些 Bukkit DamageCause 会进入 Attribute 结算:
yaml
allowed_damage_causes:
- cause: FALL
damage_type: physical
enabled: true
- cause: LAVA
damage_type: physical
enabled: true| 字段 | 类型 | 必填 | 默认值 | 取值范围 | 说明 |
|---|---|---|---|---|---|
cause | string | 是 | — | Bukkit EntityDamageEvent.DamageCause 名 | 要映射的原版伤害原因; 缺失时这条会被忽略 |
damage_type | string | 否 | default_damage_type | — | 使用的 damage_types/*.yml 伤害类型 ID; 没加载的话 /ea lint 会报出来 |
damage | double | 否 | 省略时用原版事件伤害 | ≥ 0 (负值按 0) | 进入属性管线前的基础伤害. 留空时直接使用服务端已经算好的原版伤害值, 适合摔落, 爆炸, 燃烧, 溺水这类随高度或状态变化的来源 |
enabled | boolean | 否 | true | true / false | 这条映射要不要生效; false 时不会参与匹配 |
context.<key> (或其它任意键) | 任意 | 否 | — | — | 注入到本次伤害的上下文里, 供阶段表达式和消息模板读取. cause, damage_type, damage, enabled, context 是保留键, 其余键直接当作上下文变量 |
示例: 让摔落伤害按原版数值走物理管线, 并单独指定岩浆伤害的基础值
yaml
allowed_damage_causes:
- cause: FALL
damage_type: physical
enabled: true # 省略 damage, 使用原版摔落伤害
- cause: LAVA
damage_type: spell
damage: 8 # 覆盖为固定 8 点基础伤害
enabled: true没被映射命中的原版伤害由 vanilla_event_damage 决定, 与 hard_lock_damage 无关: enabled: true 时按 vanilla_event_damage.damage_type 进入属性管线; enabled: false 时只有本表中允许的原因进入 EA, 其余保留原版行为
属性衰减曲线
scaling_curves 为高数值属性配置超阈值折算, 默认为空映射 (不启用):
yaml
scaling_curves:
physical_attack_cap:
attribute: "physical_attack"
threshold: 500
curve_type: "logarithmic"
factor: 100| 字段 | 类型 | 必填 | 默认值 | 取值范围 | 说明 |
|---|---|---|---|---|---|
<规则 id> (小节 key) | object | 否 | — | — | 规则 ID; 省略 attribute 时, key 本身就当作属性 ID |
attribute | string | 否 | 小节 key | — | 被衰减的属性 ID; 指向不存在的属性时这条规则不生效 |
threshold | number | 否 | 0 | ≥ 0 (负值按 0) | 衰减开始的阈值; 低于或等于这个值时保持原值 |
curve_type | string | 否 | logarithmic | logarithmic / sqrt / piecewise_linear (别名 linear) | 衰减函数类型; 填了识别不了的值按 logarithmic 处理, 并在配置预检时告警 |
factor | number | 否 | 1 | logarithmic / sqrt: > 0 (≤ 0 按 1); piecewise_linear / linear: ≥ 0 | 衰减系数: 前两者拿它当除数, 后者拿它当保留比例, 0 是合法值 (超出部分全部作废) |
完整曲线的含义和调参办法见属性衰减曲线
排查建议
- 属性不显示: 依次检查属性文件是否加载, Lore 格式是否匹配, 物品装配是否触发刷新
- 属性不生效: 检查属性 ID 是否与伤害类型, 条件或外部模块一致
- 环境伤害异常: 检查
vanilla_event_damage与allowed_damage_causes(hard_lock_damage没有运行时的作用, 不用排查) - 生命不同步: 先看资源是否设置了
sync_to_bukkit: true.health资源的天花板取修饰后的MAX_HEALTH: EA 自己算出的值写入 base,max_health_vanilla, 生命提升药水与第三方插件贴的 modifier 叠加在其上, 三者不再互相冲突. 若上限与预期不符, 开启resource调试查看生命上限解析与最大生命修饰器两行, 逐条定位修饰器来源 - 外部回血被撤销:
health的当前值以玩家实体血量为准, 因此其他插件或命令直接设置血量后, 不会被下一次同步抹掉. 若仍出现回落, 开启resource调试对比生命自然回复行的旧当前值与引擎基线值: 两者持续偏离, 说明该资源没有同步到 Bukkit, 或者血量被另一插件在同一个游戏刻内反复改写 - 数值膨胀: 给核心输出, 防御, 暴击等属性配上
scaling_curves