Solved Bukkit Scheduler (error)

Discussion in 'Spigot Plugin Development' started by KnaxelBaby, Jun 26, 2018.

  1. Hello! I am having a weird error while handling a bukkit runnable. I saved it's reference to an object. When the object's information is loaded, init() is called so the task can start spawning particles at its location.

    This is when my issue comes in. Whenever I need to update the information, I call the stop method that ultimately calls the cancel method for the bukkit runnable BEFORE calling init() again with the new location. So, I am not sure why it's giving me this error. (says the task is already scheduled).

    I tried looking if there was a difference between canceling the runnable and "un-scheduling" it again. I had no luck, but don't think there is a difference. Let me know please I'm just curious as this structure would make api easier for others.

    heres a code snippet causing the issue :
    (ik theres static plugin reference)

    Code (Java):

    new PadEffect((TelePads) Bukkit.getPluginManager().getPlugin("TelePads")) {
        BukkitRunnable runnable;
        public void init(Location location, double radius) {
            int particles = (int) radius * 4;
            Location loc = new Location(location.getWorld(), location.getX(), location.getY() + .15, location.getZ(), location.getYaw(), location.getPitch());
            if (runnable == null) {
                runnable = new BukkitRunnable() {
                    public void run() {
                        double increment = (2 * Math.PI) / particles;
                        for (int i = 0; i < particles; i++) {
                            double angle = i * increment;
                            double x = loc.getX() + ((radius - .75) * Math.cos(angle));
                            double z = loc.getZ() + ((radius - .75) * Math.sin(angle));
                            loc.getWorld().spawnParticle(Particle.SPELL, new Location(loc.getWorld(), x, loc.getY(), z), 3 * plugin.getConfig().getInt("settings.particle"), .35F, .01F, .35F, 0.00007F);
                            //loc.getWorld().spawnParticle(Particle.CRIT_MAGIC, loc, 25 * plugin.particle, (float)radius/3.5, .1F, (float)radius/3.5, 0.0F);
            runnable.runTaskTimerAsynchronously(plugin, 20L, 8L);
        public void stop() {
    heres the console error:
    Code (Text):
    [09:39:34 ERROR]: null
    org.bukkit.command.CommandException: Unhandled exception executing command 'tpads' in plugin TelePads v1.2.1
            at org.bukkit.command.PluginCommand.execute( ~[spigot.jar:git-Spigot-2086bb0-8cc5a7e]
            at org.bukkit.command.SimpleCommandMap.dispatch( ~[spigot.jar:git-Spigot-2086bb0-8cc5a7e]
            at org.bukkit.craftbukkit.v1_12_R1.CraftServer.dispatchCommand( ~[spigot.jar:git-Spigot-2086bb0-8cc5a7e]
            at net.minecraft.server.v1_12_R1.PlayerConnection.handleCommand( [spigot.jar:git-Spigot-2086bb0-8cc5a7e]
            at net.minecraft.server.v1_12_R1.PlayerConnection.a( [spigot.jar:git-Spigot-2086bb0-8cc5a7e]
            at net.minecraft.server.v1_12_R1.PacketPlayInChat.a( [spigot.jar:git-Spigot-2086bb0-8cc5a7e]
            at net.minecraft.server.v1_12_R1.PacketPlayInChat.a( [spigot.jar:git-Spigot-2086bb0-8cc5a7e]
            at net.minecraft.server.v1_12_R1.PlayerConnectionUtils$ [spigot.jar:git-Spigot-2086bb0-8cc5a7e]
            at java.util.concurrent.Executors$ Source) [?:1.8.0_151]
            at Source) [?:1.8.0_151]
            at net.minecraft.server.v1_12_R1.SystemUtils.a(SourceFile:46) [spigot.jar:git-Spigot-2086bb0-8cc5a7e]
            at net.minecraft.server.v1_12_R1.MinecraftServer.D( [spigot.jar:git-Spigot-2086bb0-8cc5a7e]
            at net.minecraft.server.v1_12_R1.DedicatedServer.D( [spigot.jar:git-Spigot-2086bb0-8cc5a7e]
            at net.minecraft.server.v1_12_R1.MinecraftServer.C( [spigot.jar:git-Spigot-2086bb0-8cc5a7e]
            at [spigot.jar:git-Spigot-2086bb0-8cc5a7e]
            at Source) [?:1.8.0_151]
    Caused by: java.lang.IllegalStateException: Already scheduled as 6
            at org.bukkit.scheduler.BukkitRunnable.checkNotYetScheduled( ~[spigot.jar:git-Spigot-2086bb0-8cc5a7e]
            at org.bukkit.scheduler.BukkitRunnable.runTaskTimerAsynchronously( ~[spigot.jar:git-Spigot-2086bb0-8cc5a7e]
            at net.knaxel.www.telepads.pad.TelePadEffect$1.init( ~[?:?]
            at net.knaxel.www.telepads.command.TelePadsCommand$UpdateCommand.execute( ~[?:?]
            at net.knaxel.www.telepads.command.PluginCommand.onCommand( ~[?:?]
            at net.knaxel.www.telepads.command.PluginCommand.onCommand( ~[?:?]
            at org.bukkit.command.PluginCommand.execute( ~[spigot.jar:git-Spigot-2086bb0-8cc5a7e]
            ... 15 more
  2. You cannot schedule your same BukkitRunnable instance more than once. But you are doing execatly that if you call init(..) multiple times, because the scheduling ("runnable.runTaskTimerAsynchronously(plugin, 20L, 8L);") happens after the "if (runnable == null) {"-check.

    To fix: Maybe set the runnable back to null when you stop the task. And you can then also move the scheudling part inside the "if (runnable == null)"-block.
  3. I am able to "fix" the problem by re initiating an entire object in the init() method.
    just by setting the runnable to null in the stop() method (since the location in the runnable would change anyway)
    But, it would definetely be best to create a class that extends BukkitRunnable. That way I would be able to update class variables instead of re initiating a new runnable each time the variables change.
    #3 KnaxelBaby, Jun 26, 2018
    Last edited: Jun 26, 2018
  4. I call init() once. Init is not called unless its the first time, or stop() was called just before hand. I know I can't schedule more than one task, thats exactly what the error says.. i was only thrown off because I thought cancel() would un-schedule the task. But apparently not.
  5. cancel() does 'unschedule' the task. The problem is that you cannot re-schedule the same BukkitRunnable object again, even if you stopped/cancelled the previous task beforehand. You always have to create a new BukkitRunnable instance. That's why I suggested you set the runnable variable to null after you have cancelled the task. That way the next time you call init() afterwards a new BukkitRunnable object will be created.
    Your solution (creating a whole new PadEffect every time) works as well of course (because it forces a new BukkitRunnable to be created as well).