--- a/net/minecraft/server/PlayerChunk.java +++ b/net/minecraft/server/PlayerChunk.java @@ -4,35 +4,48 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.bukkit.craftbukkit.chunkio.ChunkIOExecutor; public class PlayerChunk { private static final Logger a = LogManager.getLogger(); private final PlayerChunkMap playerChunkMap; - private final List<EntityPlayer> c = Lists.newArrayList(); + public final List<EntityPlayer> c = Lists.newArrayList(); // CraftBukkit - public private final ChunkCoordIntPair location; private final short[] dirtyBlocks = new short[64]; - private Chunk chunk; + public Chunk chunk; // CraftBukkit - public private int dirtyCount; private int h; private long i; private boolean done; + // CraftBukkit start - add fields + private final HashMap<EntityPlayer, Runnable> players = new HashMap<EntityPlayer, Runnable>(); + private Runnable loadedRunnable = new Runnable() { + public void run() { + PlayerChunk.this.chunk = PlayerChunk.this.playerChunkMap.getWorld().getChunkProviderServer().getOrLoadChunkAt(location.x, location.z); + } + }; + // CraftBukkit end + public PlayerChunk(PlayerChunkMap playerchunkmap, int i, int j) { this.playerChunkMap = playerchunkmap; this.location = new ChunkCoordIntPair(i, j); - this.chunk = playerchunkmap.getWorld().getChunkProviderServer().getOrLoadChunkAt(i, j); + // CraftBukkit start + this.chunk = playerchunkmap.getWorld().getChunkProviderServer().getChunkAt(i, j, loadedRunnable); + // CraftBukkit end } public ChunkCoordIntPair a() { return this.location; } - public void a(EntityPlayer entityplayer) { + public void a(final EntityPlayer entityplayer) { // CraftBukkit - added final to argument if (this.c.contains(entityplayer)) { PlayerChunk.a.debug("Failed to add player. {} already is in chunk {}, {}", new Object[] { entityplayer, Integer.valueOf(this.location.x), Integer.valueOf(this.location.z)}); } else { @@ -41,19 +54,50 @@ } this.c.add(entityplayer); + // CraftBukkit start - use async chunk io + // if (this.j) { + // this.sendChunk(entityplayer); + // } + Runnable playerRunnable; if (this.done) { - this.sendChunk(entityplayer); + playerRunnable = null; + sendChunk(entityplayer); + } else { + playerRunnable = new Runnable() { + public void run() { + sendChunk(entityplayer); + } + }; + playerChunkMap.getWorld().getChunkProviderServer().getChunkAt(this.location.x, this.location.z, playerRunnable); } + this.players.put(entityplayer, playerRunnable); + // CraftBukkit end + } } public void b(EntityPlayer entityplayer) { if (this.c.contains(entityplayer)) { + // CraftBukkit start - If we haven't loaded yet don't load the chunk just so we can clean it up + if (!this.done) { + ChunkIOExecutor.dropQueuedChunkLoad(this.playerChunkMap.getWorld(), this.location.x, this.location.z, this.players.get(entityplayer)); + this.c.remove(entityplayer); + this.players.remove(entityplayer); + + if (this.c.isEmpty()) { + ChunkIOExecutor.dropQueuedChunkLoad(this.playerChunkMap.getWorld(), this.location.x, this.location.z, this.loadedRunnable); + this.playerChunkMap.b(this); + } + + return; + } + // CraftBukkit end if (this.done) { entityplayer.playerConnection.sendPacket(new PacketPlayOutUnloadChunk(this.location.x, this.location.z)); } + this.players.remove(entityplayer); // CraftBukkit this.c.remove(entityplayer); if (this.c.isEmpty()) { this.playerChunkMap.b(this); @@ -63,8 +107,8 @@ } public boolean a(boolean flag) { - if (this.chunk != null) { - return true; + if (this.chunk != null || true) { // CraftBukkit + return done; // CraftBukkit } else { if (flag) { this.chunk = this.playerChunkMap.getWorld().getChunkProviderServer().getChunkAt(this.location.x, this.location.z);