Not_A_Dev
Not_A_Dev

Reputation: 91

BukkitRunnable gives me a NPE

Basically, this code works as I need it to, perfectly fine, however, If I move even the slightest bit or get out of the water, my console gets SPAMMED with NPE's... What have I done wrong with my code? What I'm trying to do is, if a player is in a specific location, inside of water, it will start a countdown, in this case, of 5 seconds. And after the 5 seconds, it's meant to say "Testing", etc. That part works, just not when I move or step out of the water. And yes, I'm aware that the code is sloppy and a bunch of junk but I don't want to create a whole class for cuboid for just one event.

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

Upvotes: 0

Views: 71

Answers (1)

Elikill58
Elikill58

Reputation: 4908

I have multiple things to say about this code :

  1. The value of e.getTo() will never be null. So the Objects.requireNonNull code is a useless import.

  2. You get multiple time the same world instance with Bukkit.getWorld("Void"), but only one time is better.

  3. Instead of create Location's object, you can check directly the x/y/z values that are given just before.

  4. For the issue :

When you left liquid, all task will remove the value linked with the player's uuid. So, you will not be able to get id with afkCountdown.get() or afkCountdownTask.get(). To fix it, you should use afkCountdown.getOrDefault(p.getUniqueId(), 0).

  1. For timers, you never stop already started timer. So, your server with crash because of overflow. When you do afkCountdownTask.remove() you should do :
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. You are creating and resetting hashmap EACH move with afkCountdown = new HashMap<UUID, Integer>(). You should do it only one time.

Finally, this is the code that I propose to fix everything :

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

Upvotes: 1

Related Questions