Skip to content

默认类属性(DEFAULT)

什么是 DEFAULT 类型?

DEFAULT 是最简单的属性类型——它不做任何事情。它唯一的作用就是提供一个数值,让其他属性来读取。

你可以把 DEFAULT 属性理解为「配置项」或「数据字段」。比如:

  • 物理护甲 是 DEFAULT 属性,它本身没有任何效果
  • 物理攻击(ATTACK_AND_DEFENSE 类型)在处理伤害时读取 物理护甲 的值来计算减免

什么时候用 DEFAULT?

简单来说:如果一个属性不需要主动触发效果,只是作为数值供其他属性读取,那就用 DEFAULT。

常见例子:

  • 护甲值、穿透值、暴击率、暴击伤害——这些数值的意义由「物理攻击」这个主属性决定
  • 战斗力——纯数值,由插件面板自动读取
  • 你的自定义辅助数值

纯 DEFAULT 属性

先看最简单的例子——一个只提供战斗力、无任何逻辑的属性:

Groovy
package scripts.attributes

import cn.org.bukkit.craneattribute.core.attribute.AttributeTypes
import groovy.transform.CompileStatic
import scripts.libs.GroovyAttribute

@CompileStatic
class MyPowerAttribute extends GroovyAttribute {

    MyPowerAttribute() {
        // 类型=DEFAULT, ID, 名称, 优先级, 战斗力系数, 最大值
        super(AttributeTypes.DEFAULT, "my_power", "我的战斗力", 1, 1.0D, -1.0D)
    }
}

你没有看错,这个属性只需要构造函数,不需要重写任何方法。它就静静地存在于属性面板中,提供战斗力数值。

属性注册后:

  • 在物品 Lore 上写 我的战斗力: 100 即可生效
  • 实体会获得 100 * 1.0 = 100 点战斗力
  • 可以通过 %ca_我的战斗力% 变量查询

注册 DEFAULT 子属性

更常见的用法是:在主属性(如 ATTACK_AND_DEFENSE)的构造函数中注册 DEFAULT 子属性。

为什么要注册子属性?

假设你正在写「物理攻击」属性,你需要:

  • 物理攻击 本身(ATTACK_AND_DEFENSE 类型)——负责计算伤害
  • 物理护甲(DEFAULT 类型)——防御方的减免数值
  • 物理穿透(DEFAULT 类型)——攻击方的穿透数值

后两者不需要主动触发任何效果,它们只是「物理攻击」计算过程中的参数。所以它们应该是 DEFAULT 类型。

完整示例

Groovy
package scripts.attributes

import cn.org.bukkit.craneattribute.core.attribute.AttributeTypes
import cn.org.bukkit.craneattribute.core.attribute.handler.AttackAndDefenseHandler
import groovy.transform.CompileStatic
import scripts.libs.GroovyAttribute
import scripts.libs.Utils
import org.bukkit.entity.LivingEntity

@CompileStatic
class MyPhysicalAttack extends GroovyAttribute {

    MyPhysicalAttack() {
        // 主属性是 ATTACK_AND_DEFENSE 类型
        super(AttributeTypes.ATTACK_AND_DEFENSE, "my_attack", "我的物理攻击", 1, 1.0D, -1.0D)

        // 注册子属性(DEFAULT 类型)
        Utils.registerDefaultAttribute("my_armor", "我的物理护甲", 0.0D, -1.0D)
        Utils.registerDefaultAttribute("my_penetration", "我的物理穿透", 0.0D, -1.0D)
    }

    @Override
    boolean onAttackAndDefense(LivingEntity attacker, LivingEntity entity, AttackAndDefenseHandler handler) {
        // 获取攻击力
        double attack = handler.getRandomValue(attacker, "我的物理攻击")

        // 获取穿透和护甲
        double penetration = handler.getRandomValue(attacker, "我的物理穿透")
        double armor = handler.getRandomValue(entity, "我的物理护甲")

        // 计算:攻击 - (护甲 - 穿透),护甲可以被穿透抵消
        double effectiveArmor = Math.max(0, armor - penetration)
        double damage = attack - effectiveArmor

        if (damage > 0) {
            handler.addDamage(attacker, damage)
            handler.addMessage(attacker, "§f造成 ${String.format("%.2f", damage)} 点伤害")
            // 护甲被穿透则防御方看到穿透提示
            if (penetration > 0 && armor > 0) {
                handler.addMessage(entity, "§7被穿透 ${String.format("%.2f", penetration)} 点护甲")
            }
            return true
        }
        return false
    }
}

关键点:

  1. 主属性(我的物理攻击)是 ATTACK_AND_DEFENSE 类型 —— 它负责触发
  2. 子属性(我的物理护甲我的物理穿透)是 DEFAULT 类型 —— 它们只提供数值
  3. onAttackAndDefense 中通过 handler.getRandomValue() 读取子属性的值
  4. Utils.registerDefaultAttribute(id, name, power, max) 注册子属性

JavaScript 版本

JavaScript
var type = "ATTACK_AND_DEFENSE"
var id = "my_attack"
var name = "我的物理攻击"
var priority = 1
var power = 1.0
var max = -1.0

// 在 init 函数中注册子属性
function init(attr) {
    AttributeAPI.registerDefaultAttribute("my_armor", "我的物理护甲", 0.0, -1.0)
    AttributeAPI.registerDefaultAttribute("my_penetration", "我的物理穿透", 0.0, -1.0)
}

function onAttackAndDefense(attr, attacker, entity, handler) {
    var attack = handler.getRandomValue(attacker, "我的物理攻击")
    var penetration = handler.getRandomValue(attacker, "我的物理穿透")
    var armor = handler.getRandomValue(entity, "我的物理护甲")

    var effectiveArmor = Math.max(0, armor - penetration)
    var damage = attack - effectiveArmor

    if (damage > 0) {
        handler.addDamage(attacker, damage)
        attacker.sendMessage("造成 " + damage.toFixed(2) + " 点伤害")
        return true
    }
    return false
}

注册 vs 不注册

你可能会问:「我直接在代码里用 handler.getRandomValue(entity, "某个名字") 读取,不注册行不行?」

不行。 必须注册后,插件才知道这个属性存在,物品上的 Lore 才能被正确解析。不注册的话,即使物品上写了 某个名字: 100,插件也不会识别它。

注册的本质是告诉插件:「有一个属性叫这个名字,请你在解析物品时注意它。」

常见错误

忘记注册子属性

Groovy
// 错误!物理护甲没注册,物品上的 "物理护甲: 50" 不会被识别
@CompileStatic
class BadAttack extends GroovyAttribute {
    BadAttack() {
        super(AttributeTypes.ATTACK_AND_DEFENSE, "bad", "错误示范", 1, 1.0D, -1.0D)
        // 缺少: Utils.registerDefaultAttribute("armor", "物理护甲", 0.0D, -1.0D)
    }

    boolean onAttackAndDefense(LivingEntity attacker, LivingEntity entity, AttackAndDefenseHandler handler) {
        // 读取到的永远是 0,因为插件不知道 "物理护甲" 这个属性
        double armor = handler.getRandomValue(entity, "物理护甲")
        return true
    }
}

给 DEFAULT 属性写处理方法

Groovy
// 错误!DEFAULT 类型不会调用 onAttackAndDefense,写了也白写
@CompileStatic
class BadDefault extends GroovyAttribute {
    BadDefault() {
        super(AttributeTypes.DEFAULT, "bad_default", "错误默认", 1, 0.0D, -1.0D)
    }

    @Override
    boolean onAttackAndDefense(...) {
        // 这段代码永远不会被执行!
        return true
    }
}