以异步方式加载世界或不阻塞主线程

时间:2015-11-13 18:55:29

标签: java multithreading bukkit

我正在制作迷你游戏插件。竞技场结束后应该重新生成 - 我使用卸载和加载技巧。它有一个明显的缺点 - 它冻结服务器一段时间来准备产卵区域。我决定将竞技场重置代码放入可运行的异步任务runTaskAsynchronously()中。但是,当服务器尝试在线程内运行代码时,它会抛出异常:

Caused by: java.lang.IllegalStateException: Asynchronous entity world add!

这是我的代码的一部分:

getServer().getScheduler().runTaskAsynchronously(this, new Runnable()
{
    @Override
    public void run()
    {
        String w_name = world.getName();
        getServer().unloadWorld(world.getName(), false);
        world = getServer().createWorld(new WorldCreator(w_name));
    }
});

有关如何处理此问题的任何建议吗?

2 个答案:

答案 0 :(得分:1)

当您尝试在异步任务中通过API编辑任何内容时,Bukkit不喜欢它。读取和处理很好但是bukkit在线程安全方面没有任何作用,因此用一个以上的线程影响世界可能会导致问题。

尝试将您的竞技场重置分成更小的块,并通过一系列同步任务将操作分散到几个刻度上,这可能有助于提高性能。

这不是我的代码,但它在展示这个想法方面做得不错https://gist.github.com/aadnk/5443172

答案 1 :(得分:0)

- 您可以使用以下方法加载世界异步:http://pastebin.com/K9CuVMS5 -

不,你不能,如果你尝试过它将有很大的世界腐败机会。但如果你不关心它,你可以这样做: Bukkit通过Bukkit.createWorld(WorldCreator)加载世界,激活Server.createWorld(WorldCreator)激活:

Validate.notNull(creator, "Creator may not be null");
    String name = creator.name();
    ChunkGenerator generator = creator.generator();
    File folder = new File(this.getWorldContainer(), name);
    World world = this.getWorld(name);
    WorldType type = WorldType.getType(creator.type().getName());
    boolean generateStructures = creator.generateStructures();
    if(world != null) {
        return world;
    } else if(folder.exists() && !folder.isDirectory()) {
        throw new IllegalArgumentException("File exists with the name \'" + name + "\' and isn\'t a folder");
    } else {
        if(generator == null) {
            generator = this.getGenerator(name);
        }

        WorldLoaderServer converter = new WorldLoaderServer(this.getWorldContainer());
        if(converter.isConvertable(name)) {
            this.getLogger().info("Converting world \'" + name + "\'");
            converter.convert(name, new ConvertProgressUpdater(this.console));
        }

        int dimension = 10 + this.console.worlds.size();
        boolean used = false;

        do {
            Iterator sdm = this.console.worlds.iterator();

            while(sdm.hasNext()) {
                WorldServer hardcore = (WorldServer)sdm.next();
                used = hardcore.dimension == dimension;
                if(used) {
                    ++dimension;
                    break;
                }
            }
        } while(used);

        boolean var25 = false;
        ServerNBTManager var24 = new ServerNBTManager(this.getWorldContainer(), name, true);
        WorldData worlddata = var24.getWorldData();
        if(worlddata == null) {
            WorldSettings internal = new WorldSettings(creator.seed(), EnumGamemode.getById(this.getDefaultGameMode().getValue()), generateStructures, var25, type);
            internal.setGeneratorSettings(creator.generatorSettings());
            worlddata = new WorldData(internal, name);
        }

        worlddata.checkName(name);
        WorldServer var26 = (WorldServer)(new WorldServer(this.console, var24, worlddata, dimension, this.console.methodProfiler, creator.environment(), generator)).b();
        if(!this.worlds.containsKey(name.toLowerCase())) {
            return null;
        } else {
            var26.scoreboard = this.getScoreboardManager().getMainScoreboard().getHandle();
            var26.tracker = new EntityTracker(var26);
            var26.addIWorldAccess(new WorldManager(this.console, var26));
            var26.worldData.setDifficulty(EnumDifficulty.EASY);
            var26.setSpawnFlags(true, true);
            this.console.worlds.add(var26);
            if(generator != null) {
                var26.getWorld().getPopulators().addAll(generator.getDefaultPopulators(var26.getWorld()));
            }

            this.pluginManager.callEvent(new WorldInitEvent(var26.getWorld()));
            System.out.print("Preparing start region for level " + (this.console.worlds.size() - 1) + " (Seed: " + var26.getSeed() + ")");
            if(var26.getWorld().getKeepSpawnInMemory()) {
                short short1 = 196;
                long i = System.currentTimeMillis();

                for(int j = -short1; j <= short1; j += 16) {
                    for(int k = -short1; k <= short1; k += 16) {
                        long l = System.currentTimeMillis();
                        if(l < i) {
                            i = l;
                        }

                        if(l > i + 1000L) {
                            int chunkcoordinates = (short1 * 2 + 1) * (short1 * 2 + 1);
                            int j1 = (j + short1) * (short1 * 2 + 1) + k + 1;
                            System.out.println("Preparing spawn area for " + name + ", " + j1 * 100 / chunkcoordinates + "%");
                            i = l;
                        }

                        BlockPosition var27 = var26.getSpawn();
                        var26.chunkProviderServer.getChunkAt(var27.getX() + j >> 4, var27.getZ() + k >> 4);
                    }
                }
            }

            this.pluginManager.callEvent(new WorldLoadEvent(var26.getWorld()));
            return var26.getWorld();
        }
    }

现在通过创建自己的世界加载器,你可以使它只在每个滴答器左右生成一个块。