--- a/net/minecraft/server/ChunkRegionLoader.java +++ b/net/minecraft/server/ChunkRegionLoader.java @@ -29,7 +29,8 @@ private final File c; private final DataFixer d; private PersistentStructureLegacy e; - private boolean f; + // private boolean f; // CraftBukkit + public final LongSet blacklist = new LongOpenHashSet(); public ChunkRegionLoader(File file, DataFixer datafixer) { this.c = file; @@ -38,25 +39,69 @@ @Nullable private NBTTagCompound a(GeneratorAccess generatoraccess, int i, int j) throws IOException { - return this.a(generatoraccess.o().getDimensionManager(), generatoraccess.h(), i, j); + return this.a(generatoraccess.o().getDimensionManager(), generatoraccess.h(), i, j, generatoraccess); // CraftBukkit + } + + // CraftBukkit start + private boolean check(ChunkProviderServer cps, int x, int z) throws IOException { + if (cps != null) { + com.google.common.base.Preconditions.checkState(org.bukkit.Bukkit.isPrimaryThread(), "primary thread"); + if (cps.isLoaded(x, z)) { + return true; + } + } + + if (this.chunkExists(x, z)) { + NBTTagCompound nbt = RegionFileCache.read(this.c, x, z); + if (nbt != null) { + NBTTagCompound level = nbt.getCompound("Level"); + if (level.getBoolean("TerrainPopulated")) { + return true; + } + + ChunkStatus status = ChunkStatus.a(level.getString("Status")); + if (status != null && status.a(ChunkStatus.DECORATED)) { + return true; + } + } + } + + return false; + } + + public boolean chunkExists(int x, int z) { + return RegionFileCache.chunkExists(this.c, x, z); } @Nullable - private NBTTagCompound a(DimensionManager dimensionmanager, @Nullable PersistentCollection persistentcollection, int i, int j) throws IOException { + private NBTTagCompound a(DimensionManager dimensionmanager, @Nullable PersistentCollection persistentcollection, int i, int j, @Nullable GeneratorAccess generatoraccess) throws IOException { + // CraftBukkit start + if (blacklist.contains(ChunkCoordIntPair.a(i, j))) { + return null; + } + // CraftBukkit end NBTTagCompound nbttagcompound = (NBTTagCompound) this.b.get(new ChunkCoordIntPair(i, j)); if (nbttagcompound != null) { return nbttagcompound; } else { - DataInputStream datainputstream = RegionFileCache.read(this.c, i, j); + NBTTagCompound nbttagcompound1 = RegionFileCache.read(this.c, i, j); - if (datainputstream == null) { + if (nbttagcompound1 == null) { return null; } else { - NBTTagCompound nbttagcompound1 = NBTCompressedStreamTools.a(datainputstream); - - datainputstream.close(); int k = nbttagcompound1.hasKeyOfType("DataVersion", 99) ? nbttagcompound1.getInt("DataVersion") : -1; + // CraftBukkit start + if (k < 1466) { + NBTTagCompound level = nbttagcompound1.getCompound("Level"); + if (level.getBoolean("TerrainPopulated") && !level.getBoolean("LightPopulated")) { + ChunkProviderServer cps = (generatoraccess == null) ? null : ((WorldServer) generatoraccess).getChunkProvider(); + if (check(cps, i - 1, j) && check(cps, i - 1, j - 1) && check(cps, i, j - 1)) { + level.setBoolean("LightPopulated", true); + } + } + } + // CraftBukkit end if (k < 1493) { nbttagcompound1 = GameProfileSerializer.a(this.d, DataFixTypes.CHUNK, nbttagcompound1, k, 1493); @@ -84,13 +129,29 @@ } + // CraftBukkit start - Add async variant, provide compatibility @Nullable public Chunk a(GeneratorAccess generatoraccess, int i, int j, Consumer<Chunk> consumer) throws IOException { + Object[] data = loadChunk(generatoraccess, i, j, consumer); + if (data != null) { + Chunk chunk = (Chunk) data[0]; + NBTTagCompound nbttagcompound = (NBTTagCompound) data[1]; + consumer.accept(chunk); + this.loadEntities(nbttagcompound.getCompound("Level"), chunk); + return chunk; + } + + return null; + } + + public Object[] loadChunk(GeneratorAccess generatoraccess, int i, int j, Consumer<Chunk> consumer) throws IOException { + // CraftBukkit end NBTTagCompound nbttagcompound = this.a(generatoraccess, i, j); if (nbttagcompound == null) { return null; } else { + /* Chunk chunk = this.a(generatoraccess, i, j, nbttagcompound); if (chunk != null) { @@ -99,6 +160,9 @@ } return chunk; + */ + + return this.a(generatoraccess, i, j, nbttagcompound); } } @@ -130,7 +194,7 @@ } @Nullable - protected Chunk a(GeneratorAccess generatoraccess, int i, int j, NBTTagCompound nbttagcompound) { + protected Object[] a(GeneratorAccess generatoraccess, int i, int j, NBTTagCompound nbttagcompound) { // CraftBukkit - return Chunk -> Object[] if (nbttagcompound.hasKeyOfType("Level", 10) && nbttagcompound.getCompound("Level").hasKeyOfType("Status", 8)) { ChunkStatus.Type chunkstatus_type = this.a(nbttagcompound); @@ -149,10 +213,28 @@ ChunkRegionLoader.a.error("Chunk file at {},{} is in the wrong location; relocating. (Expected {}, {}, got {}, {})", i, j, i, j, chunk.locX, chunk.locZ); nbttagcompound1.setInt("xPos", i); nbttagcompound1.setInt("zPos", j); + + // CraftBukkit start - Have to move tile entities since we don't load them at this stage + NBTTagList tileEntities = nbttagcompound.getCompound("Level").getList("TileEntities", 10); + if (tileEntities != null) { + for (int te = 0; te < tileEntities.size(); te++) { + NBTTagCompound tileEntity = (NBTTagCompound) tileEntities.get(te); + int x = tileEntity.getInt("x") - chunk.locX * 16; + int z = tileEntity.getInt("z") - chunk.locZ * 16; + tileEntity.setInt("x", i * 16 + x); + tileEntity.setInt("z", j * 16 + z); + } + } + // CraftBukkit end chunk = this.a(generatoraccess, nbttagcompound1); } - return chunk; + // CraftBukkit start + Object[] data = new Object[2]; + data[0] = chunk; + data[1] = nbttagcompound; + return data; + // CraftBukkit end } } } else { @@ -167,7 +249,7 @@ ChunkStatus.Type chunkstatus_type = this.a(nbttagcompound); if (chunkstatus_type == ChunkStatus.Type.LEVELCHUNK) { - return new ProtoChunkExtension(this.a(generatoraccess, i, j, nbttagcompound)); + return new ProtoChunkExtension((IChunkAccess) this.a(generatoraccess, i, j, nbttagcompound)[0]); // CraftBukkit - fix up access } else { NBTTagCompound nbttagcompound1 = nbttagcompound.getCompound("Level"); @@ -215,10 +297,15 @@ } public boolean a() { + // CraftBukkit start + return this.processSaveQueueEntry(false); + } + + private boolean processSaveQueueEntry(boolean logCompletion) { Iterator<Entry<ChunkCoordIntPair, NBTTagCompound>> iterator = this.b.entrySet().iterator(); if (!iterator.hasNext()) { - if (this.f) { + if (logCompletion) { // CraftBukkit ChunkRegionLoader.a.info("ThreadedAnvilChunkStorage ({}): All chunks are saved", this.c.getName()); } @@ -234,10 +321,14 @@ return true; } else { try { - DataOutputStream dataoutputstream = RegionFileCache.write(this.c, chunkcoordintpair.x, chunkcoordintpair.z); + // CraftBukkit start + RegionFileCache.write(this.c, chunkcoordintpair.x, chunkcoordintpair.z, nbttagcompound); + /* NBTCompressedStreamTools.a(nbttagcompound, (DataOutput) dataoutputstream); dataoutputstream.close(); + */ + // CraftBukkit end if (this.e != null) { this.e.a(chunkcoordintpair.a()); } @@ -264,15 +355,16 @@ public void b() { try { - this.f = true; + // this.f = true; // CraftBukkit while (true) { - if (this.a()) { + if (this.processSaveQueueEntry(true)) { // CraftBukkit continue; } + break; // CraftBukkit - Fix infinite loop when saving chunks } } finally { - this.f = false; + // this.f = false; // CraftBukkit } } @@ -301,7 +393,7 @@ if (abiomebase != null) { for (int k = 0; k < abiomebase.length; ++k) { - aint[k] = IRegistry.BIOME.a((Object) abiomebase[k]); + aint[k] = IRegistry.BIOME.a(abiomebase[k]); // CraftBukkit - decompile error } } @@ -383,7 +475,7 @@ int[] aint = new int[abiomebase.length]; for (int i = 0; i < abiomebase.length; ++i) { - aint[i] = IRegistry.BIOME.a((Object) abiomebase[i]); + aint[i] = IRegistry.BIOME.a(abiomebase[i]); // CraftBukkit - decompile error } nbttagcompound.setIntArray("Biomes", aint); @@ -833,17 +925,29 @@ } @Nullable + // CraftBukkit start public static Entity a(NBTTagCompound nbttagcompound, World world, double d0, double d1, double d2, boolean flag) { + return spawnEntity(nbttagcompound, world, d0, d1, d2, flag, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT); + } + + public static Entity spawnEntity(NBTTagCompound nbttagcompound, World world, double d0, double d1, double d2, boolean flag, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) { + // CraftBukkit end return a(nbttagcompound, world, (entity) -> { entity.setPositionRotation(d0, d1, d2, entity.yaw, entity.pitch); - return flag && !world.addEntity(entity) ? null : entity; + return flag && !world.addEntity(entity, spawnReason) ? null : entity; }); } @Nullable + // CraftBukkit start public static Entity a(NBTTagCompound nbttagcompound, World world, boolean flag) { + return spawnEntity(nbttagcompound, world, flag, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT); + } + + public static Entity spawnEntity(NBTTagCompound nbttagcompound, World world, boolean flag, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) { + // CraftBukkit end return a(nbttagcompound, world, (entity) -> { - return flag && !world.addEntity(entity) ? null : entity; + return flag && !world.addEntity(entity, spawnReason) ? null : entity; // CraftBukkit }); } @@ -857,8 +961,14 @@ } } + // CraftBukkit start public static void a(Entity entity, GeneratorAccess generatoraccess) { - if (generatoraccess.addEntity(entity) && entity.isVehicle()) { + a(entity, generatoraccess, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT); + } + + public static void a(Entity entity, GeneratorAccess generatoraccess, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) { + if (generatoraccess.addEntity(entity, reason) && entity.isVehicle()) { + // CraftBukkit end Iterator iterator = entity.bP().iterator(); while (iterator.hasNext()) { @@ -874,7 +984,7 @@ boolean flag = false; try { - this.a(dimensionmanager, persistentcollection, chunkcoordintpair.x, chunkcoordintpair.z); + this.a(dimensionmanager, persistentcollection, chunkcoordintpair.x, chunkcoordintpair.z, null); // CraftBukkit while (this.a()) { flag = true;