Bukkit中关于'冷却'的写法

前言

这个功能是针对每个玩家以及每个技能或者事件的冷却去编写的。
测试使用时用的是spigot1.16.5的api。
文章中看到技能或者事件,可以理解为一个意思,只是有时候表达为事件有时候表达为技能
:此文章仅是展示代码及代码用法,并不是教程!!

1.理论

既然是针对每个玩家及其技能或事件来的话,那就需要一个表来存储数据用于判断。

2.实践

首先创建一个存储数据的Map表:

1
private Map<UUID, Map<String, Long>> playerCooldowns;

这里的map键用的uuid会好区分,然后对应的值是另一个map,这个map存储的键是技能或事件名称,而值存储的是冷却所需要的时间,这样一个满足理论的变量就写好了。

然后创建一个类,就叫做CooldownSystem吧,顺便把构造函数写好:

1
2
3
4
5
6
7
8
public class CooldownSystem {
private Map<UUID, Map<String, Long>> playerCooldowns;

public CooldownSystem() {
playerCooldowns = new HashMap<>();
}
}
## 接口

我们再创建一个接口用于这个类的某某事件的开放处理,这里这个接口我就叫做OnCooldownInterFace了:

1
2
3
4
5
public interface OnCooldownInterFace {
void sendOnCooldownMsg(String skillName,long RemainingCooldownTime);
void createCooldownSkill(String skillName);
void sendLastCoolDownMsg(String skillName);
}

sendOnCooldownMsg这个方法用于处理事件处于冷却时发生的事情
createCooldownSkill用于冷却开始时发生的事情
sendLastCoolDownMsg用于冷却结时发生的事情

实际方法

接下来写创建一个冷却的方法startCooldown:

1
2
3
4
5
6
7
public void startCooldown(UUID playerId, String skillName, long cooldownSeconds) {
long cooldownEndTime = System.currentTimeMillis() + cooldownSeconds * 1000L;

Map<String, Long> playerCooldownsMap = playerCooldowns.getOrDefault(playerId, new HashMap<>());
playerCooldownsMap.put(skillName, cooldownEndTime);
playerCooldowns.put(playerId, playerCooldownsMap);
}

再就是是否正在冷却期间的方法isOnCooldown:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public boolean isOnCooldown(UUID playerId, String skillName) {
if (playerCooldowns.containsKey(playerId)) {
Map<String, Long> playerCooldownsMap = playerCooldowns.get(playerId);
if (playerCooldownsMap.containsKey(skillName)) {
long cooldownEndTime = playerCooldownsMap.get(skillName);
if (System.currentTimeMillis() < cooldownEndTime) {
return true;
} else {
playerCooldownsMap.remove(skillName);
if (playerCooldownsMap.isEmpty()) {
playerCooldowns.remove(playerId);
}
}
}
}
return false;
}

然后可以根据需求附加一些需要的方法,例如获取剩余冷却描述,清除冷却之类的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public long getRemainingCooldownTime(UUID playerId, String skillName) {
if (isOnCooldown(playerId, skillName)) {
long cooldownEndTime = playerCooldowns.get(playerId).get(skillName);
return (cooldownEndTime - System.currentTimeMillis()) / 1000L;
}
return 0;
}

public void clearCooldown(UUID playerId, String skillName) {
if (playerCooldowns.containsKey(playerId)) {
Map<String, Long> playerCooldownsMap = playerCooldowns.get(playerId);
playerCooldownsMap.remove(skillName);
if (playerCooldownsMap.isEmpty()) {
playerCooldowns.remove(playerId);
}
}
}

public void clearAllCooldowns(UUID playerId) {
playerCooldowns.remove(playerId);
}

getRemainingCooldownTime获取剩余描述
clearCooldown清除某个事件的冷却
clearAllCooldowns清除某个玩家的所有事件或者技能的冷却

活用

实际上到了这里这个冷却的方法已经算写好了,但为了更高的活用性别忘了之前创建的接口,根据之前的接口我们创建一个更简洁的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void OnColldownMenu(UUID playerId, String skillName, long cooldownSeconds,OnCooldownInterFace onCooldownInterFace){
if (isOnCooldown(playerId,skillName)){
onCooldownInterFace.sendOnCooldownMsg(skillName,getRemainingCooldownTime(playerId,skillName));//处于冷却时触发的事件
return;
}
startCooldown(playerId,skillName,cooldownSeconds);//创建一个冷却
onCooldownInterFace.createCooldownSkill(skillName);//冷却开始时触发的事件
//这里因为使用的是System.currentTimeMillis(),所以就创建了一个BukkitRunable来实现冷却结束触发事件的效果
new BukkitRunnable() {
@Override
public void run() {
onCooldownInterFace.sendLastCoolDownMsg(skillName);//冷却结束时发生的事件
}
}.runTaskLater(你插件的主类,20 * cooldownSeconds);
}

这样这个类就变得比较活用了,完整的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
public class CooldownSystem {
private Map<UUID, Map<String, Long>> playerCooldowns;

public CooldownSystem() {
playerCooldowns = new HashMap<>();
}
public void OnColldownMenu(UUID playerId, String skillName, long cooldownSeconds,OnCooldownInterFace onCooldownInterFace){
if (isOnCooldown(playerId,skillName)){
onCooldownInterFace.sendOnCooldownMsg(skillName,getRemainingCooldownTime(playerId,skillName));
return;
}
startCooldown(playerId,skillName,cooldownSeconds);
onCooldownInterFace.createCooldownSkill(skillName);
new BukkitRunnable() {
@Override
public void run() {
onCooldownInterFace.sendLastCoolDownMsg(skillName);
}
}.runTaskLater(aom.plugin,20 * cooldownSeconds);
}
public interface OnCooldownInterFace {
void sendOnCooldownMsg(String skillName,long RemainingCooldownTime);
void createCooldownSkill(String skillName);
void sendLastCoolDownMsg(String skillName);
}

public void startCooldown(UUID playerId, String skillName, long cooldownSeconds) {
long cooldownEndTime = System.currentTimeMillis() + cooldownSeconds * 1000L;

Map<String, Long> playerCooldownsMap = playerCooldowns.getOrDefault(playerId, new HashMap<>());
playerCooldownsMap.put(skillName, cooldownEndTime);
playerCooldowns.put(playerId, playerCooldownsMap);
}

public boolean isOnCooldown(UUID playerId, String skillName) {
if (playerCooldowns.containsKey(playerId)) {
Map<String, Long> playerCooldownsMap = playerCooldowns.get(playerId);
if (playerCooldownsMap.containsKey(skillName)) {
long cooldownEndTime = playerCooldownsMap.get(skillName);
if (System.currentTimeMillis() < cooldownEndTime) {
return true;
} else {
playerCooldownsMap.remove(skillName);
if (playerCooldownsMap.isEmpty()) {
playerCooldowns.remove(playerId);
}
}
}
}
return false;
}

public long getRemainingCooldownTime(UUID playerId, String skillName) {
if (isOnCooldown(playerId, skillName)) {
long cooldownEndTime = playerCooldowns.get(playerId).get(skillName);
return (cooldownEndTime - System.currentTimeMillis()) / 1000L;
}
return 0;
}

public void clearCooldown(UUID playerId, String skillName) {
if (playerCooldowns.containsKey(playerId)) {
Map<String, Long> playerCooldownsMap = playerCooldowns.get(playerId);
playerCooldownsMap.remove(skillName);
if (playerCooldownsMap.isEmpty()) {
playerCooldowns.remove(playerId);
}
}
}

public void clearAllCooldowns(UUID playerId) {
playerCooldowns.remove(playerId);
}
}

使用方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CooldownSystem cooldownSystem = new CooldownSystem();
cooldownSystem.OnColldownMenu("玩家的uid", "技能或事件名称", 冷却时间L, new CooldownSystem.OnCooldownInterFace() {
@Override
public void sendOnCooldownMsg(String skillName, long RemainingCooldownTime) {
//技能处于冷却期间事件
}

@Override
public void createCooldownSkill(String skillName) {
//技能冷却开始时发生的事件
}

@Override
public void sendLastCoolDownMsg(String skillName) {
//技能冷却结时发生的事件
}
});