1.8.8 Need help with countdown! 3... 2... 1... START!

Discussion in 'Spigot Plugin Development' started by Alcachofra, Apr 4, 2020.

  1. Hello, fellow coders.

    I'm very new to this whole Minecraft plugin dev, even to java itself, but I hope I can get some help.

    So here's what I'm trying to do in the onCommand() method in my Main class:

    if (label.equalsIgnoreCase("start")) {
    // INSERT TIMER HERE
    myMethod();
    }

    My plan was: A player types "/start" and the plugin waits 5 seconds before executing method "myMethod()".

    The problem is: I want it to send a message in the chat for every second passed.
    So the output would be something like:

    Starting in 5...
    Starting in 4...
    Starting in 3...
    Starting in 2...
    Starting in 1...
    *execute myMethod here*

    Thanks in advance!
     
  2. I would take a look at this: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/scheduler/BukkitScheduler.html

    I'd recommend using this alongside a HashMap (https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html)
    You can use the hashmap to save the id of the scheduled task as the key and the seconds until the method should be run as the value.
    Code (Java):
    Map<Integer, Integer> countdowns = new HashMap<>();
    Then once the value gets to 0 in the scheduler, you can remove the key from the HashMap and cancel the repeating task and run the method you want to run.
     
  3. Thanks for the fast input, guys! Although i already got it to work. I did a little research and found out about the Thread.sleep() method. I just threw it inside a loop, and it turned out pretty good! I come from C, so i don't really know about these available methods.

    I'll check your links out, anyways!
     
  4. Don't `Thread.sleep()` - this will cause issues down the line. You should use the BukkitScheduler.
     
  5. As a good rule of thumb, you never want to use Thread.sleep() when it comes to Minecraft plugins. This will likely halt most of the other processes happening on the server.
    The BukkitScheduler as mentioned previously is what you want to use, the BukkitRunnable class is nice to use.

    The following example should do what you want:
    [​IMG]
    Make sure you read through the code and understand it before using any of it.
    The BukkitRunnable#runTaskTimer will let you specify the delay and period that the runnable will be executed with. The numbers are in server ticks, with 20 ticks being 1 second in the normal case.
    So this code will execute the Runnable immediately, and repeat it every second (20 ticks) and when the secondsRemaining reaches zero the runnable will execute your method and then stop the runnable from executing anymore.

    If you have any questions feel free to ask.
     
  6. I just want to point out that you should be using >= 0 rather than <= 0 because you're starting with the number 5 which will never be less than or equal to 0
     
  7. Right you are, so it should read "> 0" rather than "<= 0".
     
  8. You can use this class.
    Code (Java):
    public class CountdownTimer implements Runnable {

        @NotNull
        private JavaPlugin plugin;
        @Nullable
        private Integer assignedTaskId;

        private int seconds;
        private int secondsLeft;

        @NotNull private Consumer<CountdownTimer> everySecond;
        @Nullable private Runnable beforeTimer;
        @Nullable private Runnable afterTimer;

        public CountdownTimer(@NotNull JavaPlugin plugin, int seconds, @Nullable Runnable beforeTimer, @NotNull    Consumer<CountdownTimer> everySecond, @Nullable Runnable afterTimer) {
            this.plugin = plugin;
            this.seconds = seconds;
            this.secondsLeft = seconds;
            this.beforeTimer = beforeTimer;
            this.afterTimer = afterTimer;
            this.everySecond = everySecond;
        }

        public CountdownTimer(@NotNull JavaPlugin plugin, int seconds, @NotNull Consumer<CountdownTimer> everySecond, @Nullable Runnable afterTimer) {
            this.plugin = plugin;
            this.seconds = seconds;
            this.secondsLeft = seconds;
            this.beforeTimer = null;
            this.afterTimer = afterTimer;
            this.everySecond = everySecond;
        }

        public CountdownTimer(@NotNull JavaPlugin plugin, int seconds, @Nullable Runnable beforeTimer, @NotNull Consumer<CountdownTimer> everySecond) {
            this.plugin = plugin;
            this.seconds = seconds;
            this.secondsLeft = seconds;
            this.beforeTimer = beforeTimer;
            this.afterTimer = null;
            this.everySecond = everySecond;
        }

        public CountdownTimer(@NotNull JavaPlugin plugin, int seconds, @NotNull Consumer<CountdownTimer> everySecond) {
            this.plugin = plugin;
            this.seconds = seconds;
            this.secondsLeft = seconds;
            this.beforeTimer = null;
            this.afterTimer = null;
            this.everySecond = everySecond;
        }

        @Override
        public void run() {
            if (secondsLeft < 1) {
                if (afterTimer != null) afterTimer.run();
                if (assignedTaskId != null) Bukkit.getScheduler().cancelTask(assignedTaskId);
                return;
            }

            if (secondsLeft == seconds && beforeTimer != null) beforeTimer.run();

            everySecond.accept(this);

            secondsLeft--;
        }

        public int getTotalSeconds() {
            return seconds;
        }

        public int getSecondsLeft() {
            return secondsLeft;
        }

        public Integer getAssignedTaskId() {
            return assignedTaskId;
        }

        public void cancelCountdown() {
            Bukkit.getScheduler().cancelTask(assignedTaskId);
        }

        public void scheduleTimer() {
            this.assignedTaskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, this, 0L, 20L);
        }

        public boolean isImportantSecond() {
            return ((this.secondsLeft % 15) == 0) || (this.secondsLeft < 11 && this.secondsLeft >= 1);
        }