属性脚本编写教程
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 表示无上限
)| 参数 | 类型 | 说明 |
|---|---|---|
type | AttributeType | 属性类型,决定「什么时候运行」 |
id | String | 唯一ID,建议全小写+下划线 |
name | String | 显示名称,出现在 Lore 和变量中 |
priority | int | 优先级,数字越小越先执行 |
power | double | 战斗力系数,每1点属性=多少战斗力 |
max | double | 最大生效值,-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, "属性名")各类型处理器额外方法
不同属性类型的处理器实现了不同的接口,因此可用方法也不完全相同:
| 处理器接口 | 提供的方法 | 哪些类型可用 |
|---|---|---|
DamageTracker | addDamage, getDamage, setDamage, multiplyDamage | ATTACK_AND_DEFENSE, ACCIDENTAL_DAMAGED |
HealthTracker | addHealth, getHealth, setHealth, multiplyHealth | REGAIN_HEALTH |
MessageTracker | addMessage | ATTACK_AND_DEFENSE |
ProjectileTracker | isProj(), getProj(), getProjRandomValue() | ATTACK_AND_DEFENSE |
MetadataTracker | setMeta, getMeta, hasMeta, removeMeta | 大部分类型 |
Cancellable | setCancelled(true), isCancelled() | ATTACK_AND_DEFENSE, ACCIDENTAL_DAMAGED, REGAIN_HEALTH |
Groovy vs JavaScript
两种语言都能实现完全相同的功能。选择建议:
| Groovy | JavaScript | |
|---|---|---|
| 上手难度 | 需要一些 Java 基础 | 更容易入门 |
| 性能 | 静态编译后接近 Java | 较慢(约 50% Java 性能) |
| 类型安全 | 编译时检查 | 运行时检查 |
| IDE 支持 | IntelliJ IDEA 完美支持 | 基本支持 |
| 高级功能 | 完整支持 | 部分受限 |
建议:如果你打算长期维护和开发复杂属性,学习 Groovy。如果只是写几个简单属性,JavaScript 更省事。
教程章节
按推荐学习顺序:
- DEFAULT 类型 — 最简单的属性类型,理解属性注册
- ATTACK_AND_DEFENSE 类型 — 最常用的战斗属性
- UPDATE_AFTER 类型 — 属性更新后自动生效
- RUNTIME_AFTER 类型 — 周期性自动运行
- PLAYER_KILL_ENTITY 类型 — 击杀触发
- ACCIDENTAL_DAMAGED 类型 — 意外受伤处理
- REGAIN_HEALTH 类型 — 生命恢复处理
- 扩展属性类型 — 第三方属性类型
进阶话题:
