BukkitRunnable 给我一个 NPE
BukkitRunnable gives me a NPE
基本上,这段代码可以按我的需要工作,非常好,但是,如果我移动一点点或离开水面,我的控制台就会收到 NPE 的垃圾邮件...我做错了什么我的代码?我想要做的是,如果玩家在特定位置,在水中,它将开始倒计时,在本例中为 5 秒。 5 秒后,意思是“测试”等。那部分有效,只是在我移动或走出水面时无效。是的,我知道代码很草率而且是一堆垃圾,但我不想只为一个事件为长方体创建一个完整的 class。
private HashMap<UUID, Integer> afkCountdown;
private HashMap<UUID, BukkitRunnable> afkCountdownTask;
@EventHandler
public void onPlayerMoveEvent(PlayerMoveEvent e) {
afkCountdown = new HashMap<UUID, Integer>();
afkCountdownTask = new HashMap<UUID, BukkitRunnable>();
Player p = e.getPlayer();
int x = 52;
int y = 80;
int z = 255;
int x1 = 72;
int y1 = 100;
int z1 = 275;
Location l1 = new Location(Bukkit.getWorld("Void"), x, y, z);
Location l2 = new Location(Bukkit.getWorld("Void"), x1, y1, z1);
Location loc = new Location(Bukkit.getWorld("Void"), p.getLocation().getBlockX(), p.getLocation().getBlockY(), p.getLocation().getBlockZ());
if (p.getWorld().equals(loc.getWorld())) {
if (Objects.requireNonNull(e.getTo()).getBlock().isLiquid()) {
if (loc.getX() > l1.getX() && loc.getX() < l2.getX()) {
if (loc.getY() > l1.getY() && loc.getY() < l2.getY()) {
if (loc.getZ() > l1.getZ() && loc.getZ() < l2.getZ()) {
if (!afkCountdown.containsKey(p.getUniqueId())) {
afkCountdown.put(p.getUniqueId(), 5);
afkCountdownTask.put(p.getUniqueId(), new BukkitRunnable() {
@Override
public void run() {
afkCountdown.put(p.getUniqueId(), afkCountdown.get(p.getUniqueId()) - 1);
if (afkCountdown.get(p.getUniqueId()) == 0) {
p.sendMessage("Testing");
afkCountdown.remove(p.getUniqueId());
afkCountdownTask.remove(p.getUniqueId());
afkCountdown.put(p.getUniqueId(), 5);
} else if (!afkCountdown.containsKey(p.getUniqueId())) {
cancel();
}
}
});
afkCountdownTask.get(p.getUniqueId()).runTaskTimer(plugin, 20, 20);
} else {
return;
}
} else {
if (afkCountdown.containsKey(p.getUniqueId())) {
afkCountdown.remove(p.getUniqueId());
afkCountdownTask.remove(p.getUniqueId());
} else {
return;
}
}
} else {
if (afkCountdown.containsKey(p.getUniqueId())) {
afkCountdown.remove(p.getUniqueId());
afkCountdownTask.remove(p.getUniqueId());
} else {
return;
}
}
} else {
if (afkCountdown.containsKey(p.getUniqueId())) {
afkCountdown.remove(p.getUniqueId());
afkCountdownTask.remove(p.getUniqueId());
} else {
return;
}
}
} else {
if (afkCountdown.containsKey(p.getUniqueId())) {
afkCountdown.remove(p.getUniqueId());
afkCountdownTask.remove(p.getUniqueId());
} else {
return;
}
}
} else {
if (afkCountdown.containsKey(p.getUniqueId())) {
afkCountdown.remove(p.getUniqueId());
afkCountdownTask.remove(p.getUniqueId());
} else {
return;
}
}
}
关于这段代码我有很多话要说:
e.getTo()
的值永远不会为空。所以 Objects.requireNonNull
代码是无用的导入。
你用Bukkit.getWorld("Void")
多次获得同一个世界实例,但只有一次更好。
您可以直接检查之前给出的 x/y/z
值,而不是创建 Location 的对象。
问题:
当你离开 liquid 时,所有任务都会删除与玩家的 uuid 相关联的值。因此,您将无法使用 afkCountdown.get()
或 afkCountdownTask.get()
获取 id。要修复它,您应该使用 afkCountdown.getOrDefault(p.getUniqueId(), 0)
.
- 对于计时器,您永远不会停止已经启动的计时器。因此,您的服务器因溢出而崩溃。当你做
afkCountdownTask.remove()
你应该做 :
BukkitRunnable task = afkCountdownTask.remove(p.getUniqueId()); // return the removed one, or null if nothing removed
if(task != null) // if was existing
task.cancel(); // cancel task
- 您正在创建和重置散列图,每次移动
afkCountdown = new HashMap<UUID, Integer>()
。你应该只做一次。
最后,这是我建议修复所有问题的代码:
private final HashMap<UUID, Integer> afkCountdown = new HashMap<>();
private final HashMap<UUID, BukkitRunnable> afkCountdownTask = new HashMap<>();
@EventHandler
public void onPlayerMoveEvent(PlayerMoveEvent e) {
Player p = e.getPlayer();
int x = 52;
int y = 80;
int z = 255;
int x1 = 72;
int y1 = 100;
int z1 = 275;
Location loc = e.getTo();
if (p.getWorld().getName().equals("Void")) {
if (loc.getBlock().isLiquid()) {
if (loc.getX() > x && loc.getX() < x1) {
if (loc.getY() > y && loc.getY() < y1) {
if (loc.getZ() > z && loc.getZ() < z1) {
if (!afkCountdown.containsKey(p.getUniqueId())) {
afkCountdown.put(p.getUniqueId(), 5);
afkCountdownTask.put(p.getUniqueId(), new BukkitRunnable() {
@Override
public void run() {
int amount = afkCountdown.getOrDefault(p.getUniqueId(), 0) - 1;
afkCountdown.put(p.getUniqueId(), amount);
if (amount <= 0) {
p.sendMessage("Testing");
afkCountdown.put(p.getUniqueId(), 5);
} else if (!afkCountdown.containsKey(p.getUniqueId())) {
cancel();
}
}
});
afkCountdownTask.get(p.getUniqueId()).runTaskTimer(Main.getInstance(), 20, 20);
}
return; // don't want to remove, so end method now
}
}
}
}
}
if (afkCountdown.containsKey(p.getUniqueId())) {
afkCountdown.remove(p.getUniqueId());
BukkitRunnable task = afkCountdownTask.remove(p.getUniqueId());
if(task != null)
task.cancel();
}
}
基本上,这段代码可以按我的需要工作,非常好,但是,如果我移动一点点或离开水面,我的控制台就会收到 NPE 的垃圾邮件...我做错了什么我的代码?我想要做的是,如果玩家在特定位置,在水中,它将开始倒计时,在本例中为 5 秒。 5 秒后,意思是“测试”等。那部分有效,只是在我移动或走出水面时无效。是的,我知道代码很草率而且是一堆垃圾,但我不想只为一个事件为长方体创建一个完整的 class。
private HashMap<UUID, Integer> afkCountdown;
private HashMap<UUID, BukkitRunnable> afkCountdownTask;
@EventHandler
public void onPlayerMoveEvent(PlayerMoveEvent e) {
afkCountdown = new HashMap<UUID, Integer>();
afkCountdownTask = new HashMap<UUID, BukkitRunnable>();
Player p = e.getPlayer();
int x = 52;
int y = 80;
int z = 255;
int x1 = 72;
int y1 = 100;
int z1 = 275;
Location l1 = new Location(Bukkit.getWorld("Void"), x, y, z);
Location l2 = new Location(Bukkit.getWorld("Void"), x1, y1, z1);
Location loc = new Location(Bukkit.getWorld("Void"), p.getLocation().getBlockX(), p.getLocation().getBlockY(), p.getLocation().getBlockZ());
if (p.getWorld().equals(loc.getWorld())) {
if (Objects.requireNonNull(e.getTo()).getBlock().isLiquid()) {
if (loc.getX() > l1.getX() && loc.getX() < l2.getX()) {
if (loc.getY() > l1.getY() && loc.getY() < l2.getY()) {
if (loc.getZ() > l1.getZ() && loc.getZ() < l2.getZ()) {
if (!afkCountdown.containsKey(p.getUniqueId())) {
afkCountdown.put(p.getUniqueId(), 5);
afkCountdownTask.put(p.getUniqueId(), new BukkitRunnable() {
@Override
public void run() {
afkCountdown.put(p.getUniqueId(), afkCountdown.get(p.getUniqueId()) - 1);
if (afkCountdown.get(p.getUniqueId()) == 0) {
p.sendMessage("Testing");
afkCountdown.remove(p.getUniqueId());
afkCountdownTask.remove(p.getUniqueId());
afkCountdown.put(p.getUniqueId(), 5);
} else if (!afkCountdown.containsKey(p.getUniqueId())) {
cancel();
}
}
});
afkCountdownTask.get(p.getUniqueId()).runTaskTimer(plugin, 20, 20);
} else {
return;
}
} else {
if (afkCountdown.containsKey(p.getUniqueId())) {
afkCountdown.remove(p.getUniqueId());
afkCountdownTask.remove(p.getUniqueId());
} else {
return;
}
}
} else {
if (afkCountdown.containsKey(p.getUniqueId())) {
afkCountdown.remove(p.getUniqueId());
afkCountdownTask.remove(p.getUniqueId());
} else {
return;
}
}
} else {
if (afkCountdown.containsKey(p.getUniqueId())) {
afkCountdown.remove(p.getUniqueId());
afkCountdownTask.remove(p.getUniqueId());
} else {
return;
}
}
} else {
if (afkCountdown.containsKey(p.getUniqueId())) {
afkCountdown.remove(p.getUniqueId());
afkCountdownTask.remove(p.getUniqueId());
} else {
return;
}
}
} else {
if (afkCountdown.containsKey(p.getUniqueId())) {
afkCountdown.remove(p.getUniqueId());
afkCountdownTask.remove(p.getUniqueId());
} else {
return;
}
}
}
关于这段代码我有很多话要说:
e.getTo()
的值永远不会为空。所以Objects.requireNonNull
代码是无用的导入。你用
Bukkit.getWorld("Void")
多次获得同一个世界实例,但只有一次更好。您可以直接检查之前给出的
x/y/z
值,而不是创建 Location 的对象。问题:
当你离开 liquid 时,所有任务都会删除与玩家的 uuid 相关联的值。因此,您将无法使用 afkCountdown.get()
或 afkCountdownTask.get()
获取 id。要修复它,您应该使用 afkCountdown.getOrDefault(p.getUniqueId(), 0)
.
- 对于计时器,您永远不会停止已经启动的计时器。因此,您的服务器因溢出而崩溃。当你做
afkCountdownTask.remove()
你应该做 :
BukkitRunnable task = afkCountdownTask.remove(p.getUniqueId()); // return the removed one, or null if nothing removed
if(task != null) // if was existing
task.cancel(); // cancel task
- 您正在创建和重置散列图,每次移动
afkCountdown = new HashMap<UUID, Integer>()
。你应该只做一次。
最后,这是我建议修复所有问题的代码:
private final HashMap<UUID, Integer> afkCountdown = new HashMap<>();
private final HashMap<UUID, BukkitRunnable> afkCountdownTask = new HashMap<>();
@EventHandler
public void onPlayerMoveEvent(PlayerMoveEvent e) {
Player p = e.getPlayer();
int x = 52;
int y = 80;
int z = 255;
int x1 = 72;
int y1 = 100;
int z1 = 275;
Location loc = e.getTo();
if (p.getWorld().getName().equals("Void")) {
if (loc.getBlock().isLiquid()) {
if (loc.getX() > x && loc.getX() < x1) {
if (loc.getY() > y && loc.getY() < y1) {
if (loc.getZ() > z && loc.getZ() < z1) {
if (!afkCountdown.containsKey(p.getUniqueId())) {
afkCountdown.put(p.getUniqueId(), 5);
afkCountdownTask.put(p.getUniqueId(), new BukkitRunnable() {
@Override
public void run() {
int amount = afkCountdown.getOrDefault(p.getUniqueId(), 0) - 1;
afkCountdown.put(p.getUniqueId(), amount);
if (amount <= 0) {
p.sendMessage("Testing");
afkCountdown.put(p.getUniqueId(), 5);
} else if (!afkCountdown.containsKey(p.getUniqueId())) {
cancel();
}
}
});
afkCountdownTask.get(p.getUniqueId()).runTaskTimer(Main.getInstance(), 20, 20);
}
return; // don't want to remove, so end method now
}
}
}
}
}
if (afkCountdown.containsKey(p.getUniqueId())) {
afkCountdown.remove(p.getUniqueId());
BukkitRunnable task = afkCountdownTask.remove(p.getUniqueId());
if(task != null)
task.cancel();
}
}