Search code examples
javabukkit

IllegalStateException: TimeSkipEvent may only be triggered synchronously


I get this message when trying to change the world time asynchronously

java.lang.IllegalStateException: TimeSkipEvent may only be triggered synchronously.
        at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:595) ~[patched_1.16.3.jar:git-Paper-253]
        at org.bukkit.craftbukkit.v1_16_R2.CraftWorld.setFullTime(CraftWorld.java:948) ~[patched_1.16.3.jar:git-Paper-253]
        at org.bukkit.craftbukkit.v1_16_R2.CraftWorld.setTime(CraftWorld.java:936) ~[patched_1.16.3.jar:git-Paper-253]
        at ru.lmpx.lmpxserverkit.handlers.NightSkipHandler.lambda$onPlayerSleep$0(NightSkipHandler.java:29) ~[?:?]
        at org.bukkit.craftbukkit.v1_16_R2.scheduler.CraftTask.run(CraftTask.java:99) ~[patched_1.16.3.jar:git-Paper-253]
        at org.bukkit.craftbukkit.v1_16_R2.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:54) ~[patched_1.16.3.jar:git-Paper-253]
        at com.destroystokyo.paper.ServerSchedulerReportingWrapper.run(ServerSchedulerReportingWrapper.java:22) ~[patched_1.16.3.jar:git-Paper-253]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [?:1.8.0_271]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [?:1.8.0_271]
        at java.lang.Thread.run(Unknown Source) [?:1.8.0_271]
@EventHandler
    public void onPlayerSleep(PlayerBedEnterEvent e) {
        if (!(plugin.getConfig().getBoolean("skipNight.enable"))) return;
        if (e.getBedEnterResult().equals(PlayerBedEnterEvent.BedEnterResult.OK)) {
            if (plugin.getConfig().getBoolean("skipNight.instantSkip")) {
                Bukkit.getWorld("world").setTime(0);
                Bukkit.getWorld("world").setStorm(false);
            } else {
                Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
                    while (Bukkit.getWorld("world").getTime() < 24000) {
                        Bukkit.getWorld("world").setTime(Bukkit.getWorld("world").getTime() + 10);
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException ex) {
                            ex.printStackTrace();
                        }
                    }
                });
            }
        }
    }

What needs to be changed so that the asynchronous thread changes time without an IllegalStateException error?


Solution

  • The exception is explicit, you cannot call a synchronous method asynchronously. This is to ensure that thread safety is upheld. To fix your code, you would need to change out runTaskAsynchronously() with runTask(), however, with your current code, this would freeze the main thread.

    A better solution is to use the runTaskTimer() method. You can create a new class that extends BukkitRunnable. The below code is untested but it should be close to what you need:

    import org.bukkit.Bukkit;
    import org.bukkit.World;
    import org.bukkit.scheduler.BukkitRunnable;
    
    public class BedTask extends BukkitRunnable {
        @Override
        public void run() {
            World world = Bukkit.getWorld("world");
            if(world.getTime() >= 24000){
                this.cancel();
                return;
            }
            world.setTime(world.getTime() + 10);
        }
    }
    

    And you could then execute it like:

    int sleepWaitPeriod = 10;
    new BedTask().runTaskTimer(plugin, 0L, sleepWaitPeriod * 20);