--- ../work/decompile-8eb82bde//net/minecraft/server/PlayerChunk.java 2014-11-28 17:43:43.321707430 +0000 +++ src/main/java/net/minecraft/server/PlayerChunk.java 2014-11-28 17:38:17.000000000 +0000 @@ -3,6 +3,11 @@ import com.google.common.collect.Lists; import java.util.List; +// CraftBukkit start +import org.bukkit.craftbukkit.chunkio.ChunkIOExecutor; +import java.util.HashMap; +// CraftBukkit end + class PlayerChunk { private final List b; @@ -12,16 +17,26 @@ private int f; private long g; final PlayerChunkMap playerChunkMap; + + // CraftBukkit start - add fields + private final HashMap players = new HashMap(); + private boolean loaded = false; + private Runnable loadedRunnable = new Runnable() { + public void run() { + PlayerChunk.this.loaded = true; + } + }; + // CraftBukkit end public PlayerChunk(PlayerChunkMap playerchunkmap, int i, int j) { this.playerChunkMap = playerchunkmap; this.b = Lists.newArrayList(); this.dirtyBlocks = new short[64]; this.location = new ChunkCoordIntPair(i, j); - playerchunkmap.a().chunkProviderServer.getChunkAt(i, j); + playerchunkmap.a().chunkProviderServer.getChunkAt(i, j, loadedRunnable); // CraftBukkit } - public void a(EntityPlayer entityplayer) { + public void a(final EntityPlayer entityplayer) { // CraftBukkit - added final to argument if (this.b.contains(entityplayer)) { PlayerChunkMap.c().debug("Failed to add player. {} already is in chunk {}, {}", new Object[] { entityplayer, Integer.valueOf(this.location.x), Integer.valueOf(this.location.z)}); } else { @@ -30,18 +45,50 @@ } this.b.add(entityplayer); - entityplayer.chunkCoordIntPairQueue.add(this.location); + // CraftBukkit start - use async chunk io + Runnable playerRunnable; + if (this.loaded) { + playerRunnable = null; + entityplayer.chunkCoordIntPairQueue.add(this.location); + } else { + playerRunnable = new Runnable() { + public void run() { + entityplayer.chunkCoordIntPairQueue.add(PlayerChunk.this.location); + } + }; + this.playerChunkMap.a().chunkProviderServer.getChunkAt(this.location.x, this.location.z, playerRunnable); + } + + this.players.put(entityplayer, playerRunnable); + // CraftBukkit end } } public void b(EntityPlayer entityplayer) { if (this.b.contains(entityplayer)) { + // CraftBukkit start - If we haven't loaded yet don't load the chunk just so we can clean it up + if (!this.loaded) { + ChunkIOExecutor.dropQueuedChunkLoad(this.playerChunkMap.a(), this.location.x, this.location.z, this.players.get(entityplayer)); + this.b.remove(entityplayer); + this.players.remove(entityplayer); + + if (this.b.isEmpty()) { + ChunkIOExecutor.dropQueuedChunkLoad(this.playerChunkMap.a(), this.location.x, this.location.z, this.loadedRunnable); + long i = (long) this.location.x + 2147483647L | (long) this.location.z + 2147483647L << 32; + PlayerChunkMap.b(this.playerChunkMap).remove(i); + PlayerChunkMap.c(this.playerChunkMap).remove(this); + } + + return; + } + // CraftBukkit end Chunk chunk = PlayerChunkMap.a(this.playerChunkMap).getChunkAt(this.location.x, this.location.z); if (chunk.isReady()) { entityplayer.playerConnection.sendPacket(new PacketPlayOutMapChunk(chunk, true, 0)); } + this.players.remove(entityplayer); // CraftBukkit this.b.remove(entityplayer); entityplayer.chunkCoordIntPairQueue.remove(this.location); if (this.b.isEmpty()) { @@ -122,7 +169,7 @@ if (this.dirtyCount == 64) { i = this.location.x * 16; j = this.location.z * 16; - this.a((Packet) (new PacketPlayOutMapChunk(PlayerChunkMap.a(this.playerChunkMap).getChunkAt(this.location.x, this.location.z), false, this.f))); + this.a((Packet) (new PacketPlayOutMapChunk(PlayerChunkMap.a(this.playerChunkMap).getChunkAt(this.location.x, this.location.z), (this.f == 0xFFFF), this.f))); // CraftBukkit - send everything (including biome) if all sections flagged for (k = 0; k < 16; ++k) { if ((this.f & 1 << k) != 0) {