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;
            }
        }
    }

关于这段代码我有很多话要说:

  1. e.getTo() 的值永远不会为空。所以 Objects.requireNonNull 代码是无用的导入。

  2. 你用Bukkit.getWorld("Void")多次获得同一个世界实例,但只有一次更好。

  3. 您可以直接检查之前给出的 x/y/z 值,而不是创建 Location 的对象。

  4. 问题:

当你离开 liquid 时,所有任务都会删除与玩家的 uuid 相关联的值。因此,您将无法使用 afkCountdown.get()afkCountdownTask.get() 获取 id。要修复它,您应该使用 afkCountdown.getOrDefault(p.getUniqueId(), 0).

  1. 对于计时器,您永远不会停止已经启动的计时器。因此,您的服务器因溢出而崩溃。当你做 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
  1. 您正在创建和重置散列图,每次移动 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();
    }
}