1.4 护甲模组:响应协议伤害¶
协议为护甲模组提供了两种接入路径。路径A是让实体实现 BFHurtTarget 接口——适合自定义生物、载具等"实体自身就是装甲目标"的场景。路径B是让护甲物品实现 BFArmorMaterial 接口——适合防弹胸甲、头盔、护腿等"物品给穿戴者提供防护"的场景。
两条路径在协议管线中享有对等的判定能力:简易模式下只需声明等级即可,精密模式下都可以逐层覆写穿深修正、跳弹判定和自定义伤害计算。差异在于操作粒度——BFHurtTarget 以"命中部位"为单位(一次命中走完整管线),BFArmorMaterial 以"装备槽位"为单位(按命中点映射到具体槽位后走管线)。
路径A:实体实现 BFHurtTarget¶
让自定义实体声明"我会自行处理穿甲判定和伤害后果"。简易模式只需覆写两个方法——getArmorLevel 和 hurt:
public class ArmoredZombie extends Zombie implements BFHurtTarget {
@Override
public ArmorLevel getArmorLevel(BFDamageContext ctx) {
// 根据命中部位返回不同等级,此处简化为固定值
return ArmorLevel.HEAVY; // 40~80mm,相当于步战车正面装甲
}
@Override
public boolean hurt(DamageSource source, float amount) {
// 经协议计算后的最终伤害量,委托给原版管线
return super.hurt(source, amount);
}
@Override
@Nullable
public BFDamageContext createContextFromVanilla(DamageSource source, float amount) {
// 返回 null 表示原版伤害不走协议管线
return null;
}
}
这就是护甲侧最简实现。当武器侧通过 BFDamageApi.hurt() 发起协议伤害时,协议调用 getArmorLevel 获取离散护甲等级,自动完成穿甲判定和伤害计算——基于等级比较(等于算击穿)、默认三级伤害模型(刚好击穿 65%、越级击穿 100%、未击穿 0)。
深入的 BFHurtTarget 内容——精密模式覆写、跳弹判定、钝伤计算、原版伤害兼容、以及不委托 super.hurt() 的自定义处理——将在第三章逐一展开。下面进入本页的核心:路径B——护甲物品。
路径B:护甲物品实现 BFArmorMaterial¶
如果你的模组是一个防弹衣模组——玩家穿上胸甲就获得弹道防护——你无法修改 Player 类让它实现 BFHurtTarget。BFArmorMaterial 正是为此而设计:让你的护甲物品类实现此接口,协议层便自动识别穿戴了该物品的实体,将其纳入穿甲判定管线。零事件订阅、零手动拦截。
最简示例¶
让一件胸甲物品获得弹道防护,只需覆写一个方法:
public class HeavyChestplate extends ChestplateItem implements BFArmorMaterial {
public HeavyChestplate(Properties properties) {
super(ArmorMaterials.IRON, Type.CHESTPLATE, properties);
}
@Override
public ArmorLevel getArmorLevel(EquipmentSlot slot, @Nullable BFDamageContext ctx) {
if (slot == EquipmentSlot.CHEST) {
return ArmorLevel.HEAVY; // 躯干:20~40mm 防护
}
return ArmorLevel.UNARMORED_1; // 其他槽位不由胸甲保护
}
}
这就是全部。玩家穿上这件胸甲后,任何协议伤害命中玩家时,协议层会自动识别、映射槽位、做穿甲判定并执行伤害。
多件护甲共存¶
玩家通常会同时穿戴头盔、胸甲、护腿和靴子。协议适配器在处理一次命中时,按以下顺序确定"哪个槽位的护甲参与判定":
- 精确匹配:遍历四个槽位,调用每件护甲物品的
mapHitToSlot(wearer, ctx)。返回的槽位与当前槽位一致时,该护甲物品被选中。默认实现按命中点高度占比划分——头部(>85%身高)、躯干(55%~85%)、腿部(35%~55%)、脚部(<35%)。 - 兜底策略:如果命中点无效(如原版爆炸伤害的零值命中点),所有
mapHitToSlot返回 null,适配器取四个槽位 RHA 的加权平均作为整体防护值(胸甲 35%、头盔 30%、护腿 25%、靴子 10%)。未穿戴协议护甲的槽位贡献 RHA=0——爆炸冲击波会找到全身最薄弱的地方。
控制原版伤害接管¶
默认情况下,穿戴了协议护甲的实体会拦截所有原版伤害(僵尸攻击、TNT 爆炸等)并走穿甲管线——穿深估算为原版伤害量的一半。如果你需要让某些伤害类型绕过护甲(例如魔法伤害不应被钢板阻挡),覆写 createContextFromVanilla 返回 null:
@Override
@Nullable
public BFDamageContext createContextFromVanilla(DamageSource source, float amount) {
// 魔法、虚空、溺水——这些不应该被钢板阻挡,放行原版流程
if (source.is(DamageTypes.MAGIC)
|| source.is(DamageTypes.OUT_OF_WORLD)) {
return null;
}
// 物理伤害走穿甲判定
return BFDamageContext.builder()
.source(source)
.baseDamage(amount)
.penetration(amount / 2f)
.build();
}
适配器遍历所有槽位:所有护甲物品的 createContextFromVanilla 都返回 null 时,原版伤害才退回原版流程;任一护甲物品返回非 null 则整次伤害被接管。
何时需要精密模式¶
与 BFHurtTarget 完全对称,BFArmorMaterial 也提供简易/精密双模式:
| 方法 | 默认行为 | 覆写场景 |
|---|---|---|
getArmorLevel(slot, ctx) |
返回 UNARMORED_1 | 简易模式入口——声明槽位等级 |
getRHA(slot, ctx) |
取 getArmorLevel 的中位值 |
需要精确 mm 级等效厚度 |
modifyPenetration(slot, ctx) |
直接返回 ctx.penetration() |
爆反拦截(ERA)、间隙衰减 |
resolvePenetration(slot, ctx) |
仅区分 PENETRATED/BLOCKED | 跳弹判定(入射角过大 → RICOCHET) |
calculateFinalDamage(slot, ctx, result) |
三级模型:65%/100%/0 | 钝伤、超匹配加成 |
第三章的 3.6 节将详细展开每个方法的设计空间,包括完整精密模式示例(ERA 爆反胸甲)和双层串联管线的运行原理。
护甲不替代原版护甲¶
BFArmorMaterial 处理的是"穿甲判定"——弹头能否穿透这层护甲。协议层计算出的最终伤害值,在 hurt 执行时仍会经过原版护甲属性(ARMOR / ARMOR_TOUGHNESS)和保护附魔的二次减免。这是一项刻意保留的设计——协议层判"穿不穿",原版数值判"多疼"。
两种路径对比¶
| 场景 | 推荐路径 | 理由 |
|---|---|---|
| 自定义生物、载具 | BFHurtTarget |
实体类可控,一次实现覆盖全生命周期的防护 |
| 给玩家/原版实体添加防弹衣 | BFArmorMaterial |
无法修改 Player 类,物品接口是唯一接入点 |
| 实体 + 护甲同时存在 | 两者叠加 | 协议自动按双层串联管线处理——护甲先拦截,本体后判定 |
下一步¶
你已经掌握了护甲侧的两种接入方式。如果希望深入了解装甲等级体系和管线覆写策略,可以跳转到第三章——其中 3.1\~3.5 覆盖 BFHurtTarget 的精密模式,3.6 覆盖 BFArmorMaterial 的完整开发指南。下一节将用一张全景图汇总协议的全部 API 类及其职责。