首页 > 解决方案 > IllegalStateException: TimeSkipEvent 只能同步触发

问题描述

尝试异步更改世界时间时收到此消息

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

需要更改什么以便异步线程更改时间而不会出现 IllegalStateException 错误?

标签: javabukkit

解决方案


异常是显式的,您不能异步调用同步方法。这是为了确保维护线程安全。要修复您的代码,您需要更改runTaskAsynchronously()runTask(),但是,使用您当前的代码,这会冻结主线程。

更好的解决方案是使用该runTaskTimer()方法。您可以创建一个扩展BukkitRunnable的新类。以下代码未经测试,但应该接近您的需要:

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

然后你可以像这样执行它:

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

推荐阅读