Solved Have a repeating task run multiple times at once

Discussion in 'Spigot Plugin Development' started by Hello1231, Mar 20, 2020.

  1. So I'm trying to make a joining countdown, but if 2 players run the join command at the same time, it will countdown at double speed and then one of the players will join and the other one will have their countdown canceled without joining. I know that the sped up time is caused by the 2 synchronized repeating tasks that are running each decreasing the integer time by 1 every second and I also know that only one of the players joining is caused by one synchronized repeating task canceling the other one when it ends, but how would I fix this?
    Code (Java):

    static int time;
    static int taskID;
    public static void setTimer(int amount) {
                time = amount;
            }

    public static void startTimer(Player player) {
                BukkitScheduler scheduler = Bukkit.getServer().getScheduler();
                taskID = scheduler.scheduleSyncRepeatingTask(BoatMain.getInstance(), new Runnable() {
                    @Override
                    public void run() {  
                if(time == 0) {
                        joining.remove(player.getUniqueId());
                        BoatMain.joinRace(player);
                        stopTimer(taskID);
                if (joining.contains(player.getUniqueId())) {
                    player.sendMessage(ChatColor.AQUA + "joining In "+time+" Seconds.");
                }
                else {
                    stopTimer(taskID);
                    player.sendMessage(ChatColor.RED + "You Were Unable To Join The Race Because You Moved Or Engaged In PVP.");
                    if (joining.contains(player.getUniqueId())) {
                        joining.remove(player.getUniqueId());
                    }
                }time = time - 1;
                    }
                }, 0L, 20L);
            }

    public static void stopTimer() {
                    Bukkit.getScheduler().cancelTask(taskID);
                }
     
     
  2. Why aren't you checking if the timer it's already running before starting it?
     
  3. If it's already running then I would still want it to run a second time as I want multiple players to be able to join at once.
     
  4. Use HashMap.
    HashMap will put Object per Object (in this case Integer per Player or Integer per UUID)
    The full version will look something like this:

    Code (Java):
    private static HashMap<UUID, Integer> time = new HashMap<>();
    private static HashMap<UUID, Integer> taskID = new HashMap<>();

    public static void startTimer(Player player) {
         BukkitScheduler scheduler = Bukkit.getServer().getScheduler();
         time.put(player.getUniqueID(), 30);
         taskID.put(player.getUniqueID(), scheduler.scheduleSyncRepeatingTask(BoatMain.getInstance(), () -> {
              if(time.get(player.getUniqueId()) == 0) {
                   joining.remove(player.getUniqueId());
                   BoatMain.joinRace(player);
                   Bukkit.getScheduler().cancelTask(taskID.get(player.getUniqueID()));
              }
              if (joining.contains(player.getUniqueId())) {
                    player.sendMessage(ChatColor.AQUA + "joining In "+time+" Seconds.");
              } else {
                    Bukkit.getScheduler().cancelTask(taskID.get(player.getUniqueID()));
                    player.sendMessage(ChatColor.RED + "You Were Unable To Join The Race Because You Moved Or Engaged In PVP.");
                    joining.remove(player.getUniqueId()); // btw you don't need check in .remove
              }
              time.put(player.getUniqueId(), time.get(player.getUniqueId()) - 1);
         }, 0L, 20L);
    }
     
     
    #4 Firegox258, Mar 20, 2020
    Last edited: Mar 20, 2020
    • Informative Informative x 1