Skip to content

属性脚本编写教程

CraneAttribute 的属性完全由脚本驱动。本教程将带你从零开始,逐步掌握属性脚本的编写方法。

前置知识

在开始之前,你需要了解:

  • 基本的编程概念(变量、函数、条件判断)
  • Groovy 或 JavaScript 其中一种语言的基本语法
  • 选择语言的建议:参考 脚本语言对比

如果你完全零基础,可以先看 0基础教程 学习 JavaScript 基础。

第一个属性

我们从一个最简单的属性开始,逐步理解整个流程。

1. 创建文件

plugins/CraneAttribute/scripts/attributes/ 目录下创建一个 .groovy 文件(例如 我的第一个属性.groovy),文件名可以自由命名。

警告

文件名不支持中文?请检查你的系统编码设置,或使用英文文件名。

2. 编写代码

下面是一个最简单的 Groovy 属性——它在攻击时向攻击者发送一条消息:

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 org.bukkit.entity.LivingEntity

@CompileStatic
class MyFirstAttribute extends GroovyAttribute {

    // 无参构造函数(必须提供)
    MyFirstAttribute() {
        // 调用父类构造:类型, ID, 名称, 优先级, 战斗力, 最大值
        super(AttributeTypes.ATTACK_AND_DEFENSE, "my_first", "我的第一个属性", 1, 1.0D, -1.0D)
    }

    @Override
    boolean onAttackAndDefense(LivingEntity attacker, LivingEntity entity, AttackAndDefenseHandler handler) {
        attacker.sendMessage("§a我的第一个属性触发啦!")
        return true
    }
}

逐行解释:

代码含义
package scripts.attributes声明包路径,对应 scripts/attributes/ 目录
@CompileStatic开启静态编译,大幅提升性能,强烈建议添加
extends GroovyAttribute继承属性基类
MyFirstAttribute()无参构造函数,插件通过它来创建属性实例
super(类型, ID, 名称, 优先级, 战斗力, 最大值)初始化属性基本信息
onAttackAndDefense(...)攻击时被调用的方法

3. 构造函数参数详解

Groovy
super(
    AttributeTypes.ATTACK_AND_DEFENSE,  // 属性类型:决定何时触发
    "my_first",                          // 属性ID:唯一标识(全小写+下划线)
    "我的第一个属性",                     // 属性名称:用于 Lore 显示
    1,                                   // 优先级:数字越小越先执行
    1.0D,                                // 战斗力:每1点属性提供的战斗力
    -1.0D                                // 最大值:-1 表示无上限
)
参数类型说明
typeAttributeType属性类型,决定「什么时候运行」
idString唯一ID,建议全小写+下划线
nameString显示名称,出现在 Lore 和变量中
priorityint优先级,数字越小越先执行
powerdouble战斗力系数,每1点属性=多少战斗力
maxdouble最大生效值,-1 表示不限制

4. 重载插件

保存文件后,在游戏内执行 /ca reload,属性就会生效。

验证方式:给一个物品写上 Lore 我的第一个属性: 100,装备后攻击生物,应该看到聊天栏出现「我的第一个属性触发啦!」。

JavaScript 版本

如果使用 JavaScript,在相同目录创建 .js 文件:

JavaScript
// 顶层变量(必须声明)
var type = "ATTACK_AND_DEFENSE"
var id = "my_first"
var name = "我的第一个属性"
var priority = 1
var power = 1.0
var max = -1.0

function onAttackAndDefense(attr, attacker, entity, handler) {
    attacker.sendMessage("§a我的第一个属性触发啦!")
    return true
}

注意区别:

  • JS 使用顶层变量而非构造函数参数
  • JS 的函数会额外传入 attr(属性对象本身)作为第一个参数
  • JS 不需要 @CompileStatic,也没有 package 声明

属性类型详解

属性类型决定了你的属性「在什么时候被触发」。选择正确的类型是编写属性的第一步。

七种属性类型

类型触发时机典型用途处理方法
ATTACK_AND_DEFENSE实体攻击实体时伤害计算、暴击、吸血onAttackAndDefense
ACCIDENTAL_DAMAGED溺水、摔落、火焰等意外受伤环境伤害减免onAccidentalDamage
UPDATE_AFTER属性数据更新后生命值同步、移速加成onUpdateAfter
RUNTIME_AFTER每隔 N tick 自动运行生命恢复、buff刷新onRuntimeAfter
PLAYER_KILL_ENTITY玩家击杀实体时击杀奖励、掉落翻倍onPlayerKillEntity
REGAIN_HEALTH实体恢复生命时治疗加成、吸血修正onRegainHeal
DEFAULT不触发,仅作数值容器护甲、暴击率等辅助属性

如何选择类型?

问自己一个问题:「这个属性的效果应该在什么时候发生?」

  • 攻击时生效 → ATTACK_AND_DEFENSE
  • 被火烧/摔落时生效 → ACCIDENTAL_DAMAGED
  • 装备穿上就生效 → UPDATE_AFTER
  • 每几秒自动生效 → RUNTIME_AFTER
  • 杀死怪物时生效 → PLAYER_KILL_ENTITY
  • 回血时生效 → REGAIN_HEALTH
  • 不需要触发,只提供数值 → DEFAULT

处理器详解

每个属性类型对应一个 处理器(handler)。处理器是你的属性脚本与插件核心交互的桥梁——通过它,你可以获取属性值、修改伤害、添加消息等。

常用处理器方法

所有处理器都至少提供以下方法:

获取属性值

Groovy
// 获取某个属性的随机值(在最小值-最大值区间内随机)
double value = handler.getRandomValue(entity, "属性名")

// 获取某个实体的属性数据对象
AttributeData data = handler.getAttrData(entity)

操作伤害

Groovy
// 增加伤害(仅 ATTACK_AND_DEFENSE / ACCIDENTAL_DAMAGED 可用)
handler.addDamage(attacker, 50.0)           // 通用来源
handler.addDamage(attacker, "FIRE", 50.0)   // 指定来源

// 获取累计伤害
double dmg = handler.getDamage(entity)

// 翻倍伤害
handler.multiplyDamage(entity, 2.0)

发送消息

Groovy
// 添加消息到消息队列(处理器结束后统一发送)
handler.addMessage(entity, "你的消息")

// 也可以直接用 Bukkit API
entity.sendMessage("你的消息")

控制流程

Groovy
// 取消本次攻击
handler.setCancelled(true)

// 标记某个属性被触发(用于追踪和统计)
handler.trigger(entity, "属性名")

各类型处理器额外方法

不同属性类型的处理器实现了不同的接口,因此可用方法也不完全相同:

处理器接口提供的方法哪些类型可用
DamageTrackeraddDamage, getDamage, setDamage, multiplyDamageATTACK_AND_DEFENSE, ACCIDENTAL_DAMAGED
HealthTrackeraddHealth, getHealth, setHealth, multiplyHealthREGAIN_HEALTH
MessageTrackeraddMessageATTACK_AND_DEFENSE
ProjectileTrackerisProj(), getProj(), getProjRandomValue()ATTACK_AND_DEFENSE
MetadataTrackersetMeta, getMeta, hasMeta, removeMeta大部分类型
CancellablesetCancelled(true), isCancelled()ATTACK_AND_DEFENSE, ACCIDENTAL_DAMAGED, REGAIN_HEALTH

Groovy vs JavaScript

两种语言都能实现完全相同的功能。选择建议:

GroovyJavaScript
上手难度需要一些 Java 基础更容易入门
性能静态编译后接近 Java较慢(约 50% Java 性能)
类型安全编译时检查运行时检查
IDE 支持IntelliJ IDEA 完美支持基本支持
高级功能完整支持部分受限

建议:如果你打算长期维护和开发复杂属性,学习 Groovy。如果只是写几个简单属性,JavaScript 更省事。


教程章节

按推荐学习顺序:

  1. DEFAULT 类型 — 最简单的属性类型,理解属性注册
  2. ATTACK_AND_DEFENSE 类型 — 最常用的战斗属性
  3. UPDATE_AFTER 类型 — 属性更新后自动生效
  4. RUNTIME_AFTER 类型 — 周期性自动运行
  5. PLAYER_KILL_ENTITY 类型 — 击杀触发
  6. ACCIDENTAL_DAMAGED 类型 — 意外受伤处理
  7. REGAIN_HEALTH 类型 — 生命恢复处理
  8. 扩展属性类型 — 第三方属性类型

进阶话题: