Bukkit 中所有的药水效果都通过 PotionEffect
进行描述。
要使用一个已经存在的药水效果,我们只需要实例化 PotionEffect
并进行应用即可。
下面演示如何给一名玩家「迅捷 II」效果,首先创建药水效果的实例:
PotionEffect pe = new PotionEffect(PotionEffectType.SPEED, 100, 1);
其中,所有的药水效果种类都定义在 PotionEffectType
类中。可以通过 JavaDocs 查找可能的值。
我们来看看构造方法的签名:
public PotionEffect(
@NotNull PotionEffectType type,
int duration,
int amplifier,
boolean ambient, // 可选
boolean particles, // 可选
boolean icon // 可选
)
六个参数分别是:
- 药水类型,只能使用
PotionEffectType
中的静态成员变量 - 持续时间,单位刻
- 倍率,对于有等级的效果(如「力量」),该数字比等级小 1,对于没有等级的效果,设置为 0
- 是否进行渲染,可选,如果为
true
将产生更多的粒子,如果不填,默认为true
- 是否具有粒子,可选,似乎会影响客户端的渲染,具体作用尚不明确
- 是否具有图标,可选,似乎会影响客户端在背包界面是否显示该效果,具体作用尚不明确
一般而言,填写三个参数就足够了。
要使用这个药水效果,只需要在合适的时机进行应用:
pe.apply(Objects.requireNonNull(Bukkit.getPlayer("ThatRarityEG")));
药水效果实际上不仅能用于玩家,还能用于任何 LivingEntity
的实例。
Bukkit 没有提供自定义药水效果的方法,但我们可以自己创建。
下面演示如何创建「EEE」效果,该效果在玩家获取 10 秒之后发送大量的字母「e」。(致敬咏士)
首先,由于我们要创建的是药水效果,因此需要创建一个类来描述它。
public class EEEEffect extends PotionEffect {
public EEEEffect() {
super(PotionEffectType.BAD_OMEN, 100, 0);
}
}
super
指的是「使用父类的构造方法」,也就是「采用传统的方法」。
这里的 PotionEffectType
是药水类型(主要决定图标),插件无法修改(Bukkit 写死在代码里面了),因此只能选择一个已有的。这里我们选择的是「不祥之兆」。
持续时间和等级无所谓,因为我们不会用到它,随便传两个值就可以了。
下面是重中之重!
要实现我们自己的效果,需要重写 apply
方法。
示例如下:
public class EEEEffect extends PotionEffect {
public EEEEffect() {
super(PotionEffectType.BAD_OMEN, 100, 1);
}
@Override
public boolean apply(LivingEntity entity) {
if (entity instanceof Player) {
entity.sendMessage("您即将受到 EEE 效果的影响!");
// 计划任务,从此开始
new BukkitRunnable() {
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
entity.sendMessage("eeeeeeeeeeeeeeee(后略)");
// 发送消息
}
}
}.runTaskLaterAsynchronously(<插件主类名>.instance, 200);
// 到此结束
return true; // 可以被添加
}
return false; // 不可被添加
}
}
基本上只需要注意三个点:
- 如果这个效果成功被添加,返回
true
,否则返回false
,这似乎会影响到 Bukkit 的游戏判断,因此请如实返回 apply
方法只会在药水生效的瞬间被调用一次,如果要像「力量」那样持续生效,有几个办法:- 创建一个
List<UUID>
记录有这个效果的实体,并通过 Bukkit 的计划任务在一定时间后移除,然后监听事件,通过查询这个List
对实体的行为进行相应的修改 - 将数据通过 NBT 绑定到实体上,并通过 Bukkit 的计划任务在一定时间后移除,然后监听事件,通过查询 NBT 对实体的行为进行相应的修改
- 创建一个
- 一定要记得加
@Override
那什么是 Bukkit 的计划任务呢?
Bukkit 计划任务用于「在一段时间后执行某个操作」,我们在 4-2 和 AC-1-1 中见到过它的「异步执行」版本。计划任务的写法和异步执行非常相似:
new BukkitRunnable() {
@Override
public void run() {
// 要做之事……
}
}.runTaskLaterAsynchronously(<插件主类名>.instance, 200); // 200 是要推迟的时间,单位刻
这样就不难解释我们上面的效果了,我们让 Bukkit 向玩家发送许多「e」,并将这个操作推迟了 10 秒(200 刻)。
好啦!这样药水效果就创建完了,不需要注册!
将这个效果直接应用给玩家:
new EEEEffect().apply(Objects.requireNonNull(Bukkit.getPlayer("ThatRarityEG")));
现在重新看看 3-2 中的内容,是不是恍然大悟了?
其实,创建一瓶「咏 e」药水也不难嘛……唰唰唰就写出来了:
ItemStack ePotion = new ItemStack(Material.SPLASH_POTION);
// 喷溅型咏 E 药水,Minecraft 会自动判断受影响的实体,想想就很好玩啊!
PotionMeta pm = (PotionMeta) myPotion.getItemMeta();
pm.setColor(new Color(225, 0, 0)); // 危险的红色
pm.setBasePotionData(new PotionData(PotionType.WATER));
// 不需要任何预设效果,使用 WATER,请区分 PotionType 和 PotionEffectType!
pm.addCustomEffect(new EEEEffect()); // 加入我们自定义的药水效果
pm.setDisplayName("喷溅的咏 e 药水");
pm.setLore(Collections.singletonList(ChatColor.GRAY + "eee……eeee?"));
// 灰色的介绍
ePotion.setItemMeta(pm);
Collections.singletonList
创建一个单项只读列表。
对于药水究竟怎么「喷溅」,「喷溅」到谁身上,那是 Bukkit 来决定的啦~
现在 ePotion
就是一个「喷溅的咏 e 药水」啦!想怎么使用就由你决定啦~
例如,将它给予一个玩家:
Objects.requireNonNull(Bukkit.getPlayer("ThatRarityEG"))
.getInventory()
.addItem(ePotion);
将它对着自己丢出来试试吧!
效果大概是这样的(1.16.5 原版,资源包是 Love-And-Tolerance):