我正在制作迷你游戏插件。竞技场结束后应该重新生成 - 我使用卸载和加载技巧。它有一个明显的缺点 - 它冻结服务器一段时间来准备产卵区域。我决定将竞技场重置代码放入可运行的异步任务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));
}
});
有关如何处理此问题的任何建议吗?
答案 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();
}
}
现在通过创建自己的世界加载器,你可以使它只在每个滴答器左右生成一个块。