summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/net/minecraft/server/ChunkProviderServer.java24
-rw-r--r--src/main/java/net/minecraft/server/ChunkRegionLoader.java50
-rw-r--r--src/main/java/net/minecraft/server/MinecraftServer.java2
-rw-r--r--src/main/java/net/minecraft/server/PlayerInstance.java25
-rw-r--r--src/main/java/net/minecraft/server/PlayerManager.java73
-rw-r--r--src/main/java/net/minecraft/server/RegionFile.java47
-rw-r--r--src/main/java/net/minecraft/server/ServerConfigurationManagerAbstract.java5
-rw-r--r--src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOExecutor.java32
-rw-r--r--src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java73
-rw-r--r--src/main/java/org/bukkit/craftbukkit/chunkio/QueuedChunk.java36
10 files changed, 345 insertions, 22 deletions
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
index f0f4e1e4..c0bab0fa 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
@@ -11,6 +11,7 @@ import java.util.Set;
import java.util.Random;
import org.bukkit.Server;
+import org.bukkit.craftbukkit.chunkio.ChunkIOExecutor;
import org.bukkit.craftbukkit.util.LongHash;
import org.bukkit.craftbukkit.util.LongHashSet;
import org.bukkit.craftbukkit.util.LongObjectHashMap;
@@ -79,11 +80,26 @@ public class ChunkProviderServer implements IChunkProvider {
}
}
+ // CraftBukkit start - add async variant, provide compatibility
public Chunk getChunkAt(int i, int j) {
- // CraftBukkit start
+ return getChunkAt(i, j, null);
+ }
+
+ public Chunk getChunkAt(int i, int j, Runnable runnable) {
this.unloadQueue.remove(i, j);
Chunk chunk = (Chunk) this.chunks.get(LongHash.toLong(i, j));
boolean newChunk = false;
+ ChunkRegionLoader loader = null;
+
+ if (this.e instanceof ChunkRegionLoader) {
+ loader = (ChunkRegionLoader) this.e;
+ }
+
+ // If the chunk exists but isn't loaded do it async
+ if (chunk == null && runnable != null && loader != null && loader.chunkExists(this.world, i, j)) {
+ ChunkIOExecutor.queueChunkLoad(this.world, loader, this, i, j, runnable);
+ return null;
+ }
// CraftBukkit end
if (chunk == null) {
@@ -127,6 +143,12 @@ public class ChunkProviderServer implements IChunkProvider {
chunk.a(this, this, i, j);
}
+ // CraftBukkit start - If we didn't need to load the chunk run the callback now
+ if (runnable != null) {
+ runnable.run();
+ }
+ // CraftBukkit end
+
return chunk;
}
diff --git a/src/main/java/net/minecraft/server/ChunkRegionLoader.java b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
index 21ade175..7926c1dc 100644
--- a/src/main/java/net/minecraft/server/ChunkRegionLoader.java
+++ b/src/main/java/net/minecraft/server/ChunkRegionLoader.java
@@ -22,7 +22,39 @@ public class ChunkRegionLoader implements IAsyncChunkSaver, IChunkLoader {
this.d = file1;
}
+ // CraftBukkit start
+ public boolean chunkExists(World world, int i, int j) {
+ ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(i, j);
+
+ synchronized (this.c) {
+ if (this.b.contains(chunkcoordintpair)) {
+ for (int k = 0; k < this.a.size(); ++k) {
+ if (((PendingChunkToSave) this.a.get(k)).a.equals(chunkcoordintpair)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return RegionFileCache.a(this.d, i, j).chunkExists(i & 31, j & 31);
+ }
+ // CraftBukkit end
+
+ // CraftBukkit start - add async variant, provide compatibility
public Chunk a(World world, int i, int j) {
+ Object[] data = this.loadChunk(world, i, j);
+ if (data != null) {
+ Chunk chunk = (Chunk) data[0];
+ NBTTagCompound nbttagcompound = (NBTTagCompound) data[1];
+ this.loadEntities(chunk, nbttagcompound.getCompound("Level"), world);
+ return chunk;
+ }
+
+ return null;
+ }
+
+ public Object[] loadChunk(World world, int i, int j) {
+ // CraftBukkit end
NBTTagCompound nbttagcompound = null;
ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(i, j);
Object object = this.c;
@@ -51,7 +83,7 @@ public class ChunkRegionLoader implements IAsyncChunkSaver, IChunkLoader {
return this.a(world, i, j, nbttagcompound);
}
- protected Chunk a(World world, int i, int j, NBTTagCompound nbttagcompound) {
+ protected Object[] a(World world, int i, int j, NBTTagCompound nbttagcompound) { // CraftBukkit - return Chunk -> Object[]
if (!nbttagcompound.hasKey("Level")) {
System.out.println("Chunk file at " + i + "," + j + " is missing level data, skipping");
return null;
@@ -68,7 +100,12 @@ public class ChunkRegionLoader implements IAsyncChunkSaver, IChunkLoader {
chunk = this.a(world, nbttagcompound.getCompound("Level"));
}
- return chunk;
+ // CraftBukkit start
+ Object[] data = new Object[2];
+ data[0] = chunk;
+ data[1] = nbttagcompound;
+ return data;
+ // CraftBukkit end
}
}
@@ -271,6 +308,13 @@ public class ChunkRegionLoader implements IAsyncChunkSaver, IChunkLoader {
chunk.a(nbttagcompound.getByteArray("Biomes"));
}
+ // CraftBukkit start - end this method here and split off entity loading to another method
+ return chunk;
+ }
+
+ public void loadEntities(Chunk chunk, NBTTagCompound nbttagcompound, World world) {
+ // CraftBukkit end
+
NBTTagList nbttaglist1 = nbttagcompound.getList("Entities");
if (nbttaglist1 != null) {
@@ -310,6 +354,6 @@ public class ChunkRegionLoader implements IAsyncChunkSaver, IChunkLoader {
}
}
- return chunk;
+ // return chunk; // CraftBukkit
}
}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index f0e6cf73..6b10bfcb 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -533,6 +533,8 @@ public abstract class MinecraftServer implements ICommandListener, Runnable, IMo
processQueue.remove().run();
}
+ org.bukkit.craftbukkit.chunkio.ChunkIOExecutor.tick();
+
// Send timeupdates to everyone, it will get the right time from the world the player is in.
if (this.ticks % 20 == 0) {
for (int i = 0; i < this.getServerConfigurationManager().players.size(); ++i) {
diff --git a/src/main/java/net/minecraft/server/PlayerInstance.java b/src/main/java/net/minecraft/server/PlayerInstance.java
index ba0797bf..a4d90475 100644
--- a/src/main/java/net/minecraft/server/PlayerInstance.java
+++ b/src/main/java/net/minecraft/server/PlayerInstance.java
@@ -10,6 +10,7 @@ class PlayerInstance {
private short[] dirtyBlocks;
private int dirtyCount;
private int f;
+ private boolean loaded = false; // CraftBukkit
final PlayerManager playerManager;
@@ -19,15 +20,33 @@ class PlayerInstance {
this.dirtyBlocks = new short[64];
this.dirtyCount = 0;
this.location = new ChunkCoordIntPair(i, j);
- playermanager.a().chunkProviderServer.getChunkAt(i, j);
+ // CraftBukkit start
+ playermanager.a().chunkProviderServer.getChunkAt(i, j, new Runnable() {
+ public void run() {
+ PlayerInstance.this.loaded = true;
+ }
+ });
+ // CraftBukkit end
}
- public void a(EntityPlayer entityplayer) {
+ public void a(final EntityPlayer entityplayer) { // CraftBukkit - added final to argument
if (this.b.contains(entityplayer)) {
throw new IllegalStateException("Failed to add player. " + entityplayer + " already is in chunk " + this.location.x + ", " + this.location.z);
} else {
this.b.add(entityplayer);
- entityplayer.chunkCoordIntPairQueue.add(this.location);
+
+ // CraftBukkit start
+ if (this.loaded) {
+ entityplayer.chunkCoordIntPairQueue.add(this.location);
+ } else {
+ // Abuse getChunkAt to add another callback
+ this.playerManager.a().chunkProviderServer.getChunkAt(this.location.x, this.location.z, new Runnable() {
+ public void run() {
+ entityplayer.chunkCoordIntPairQueue.add(PlayerInstance.this.location);
+ }
+ });
+ }
+ // CraftBukkit end
}
}
diff --git a/src/main/java/net/minecraft/server/PlayerManager.java b/src/main/java/net/minecraft/server/PlayerManager.java
index 2b4f8849..3b776fad 100644
--- a/src/main/java/net/minecraft/server/PlayerManager.java
+++ b/src/main/java/net/minecraft/server/PlayerManager.java
@@ -4,8 +4,10 @@ import java.util.ArrayList;
import java.util.List;
// CraftBukkit start
+import java.util.Collections;
import java.util.Queue;
import java.util.Iterator;
+import java.util.LinkedList;
// CraftBukkit end
public class PlayerManager {
@@ -98,12 +100,20 @@ public class PlayerManager {
entityplayer.d = entityplayer.locX;
entityplayer.e = entityplayer.locZ;
+ // CraftBukkit start - load nearby chunks first
+ List<ChunkCoordIntPair> chunkList = new LinkedList<ChunkCoordIntPair>();
for (int k = i - this.e; k <= i + this.e; ++k) {
for (int l = j - this.e; l <= j + this.e; ++l) {
- this.a(k, l, true).a(entityplayer);
+ chunkList.add(new ChunkCoordIntPair(k, l));
}
}
+ Collections.sort(chunkList, new ChunkCoordComparator(entityplayer));
+ for (ChunkCoordIntPair pair : chunkList) {
+ this.a(pair.x, pair.z, true).a(entityplayer);
+ }
+ // CraftBukkit end
+
this.managedPlayers.add(entityplayer);
this.b(entityplayer);
}
@@ -189,12 +199,13 @@ public class PlayerManager {
int i1 = this.e;
int j1 = i - k;
int k1 = j - l;
+ List<ChunkCoordIntPair> chunksToLoad = new LinkedList<ChunkCoordIntPair>(); // CraftBukkit
if (j1 != 0 || k1 != 0) {
for (int l1 = i - i1; l1 <= i + i1; ++l1) {
for (int i2 = j - i1; i2 <= j + i1; ++i2) {
if (!this.a(l1, i2, k, l, i1)) {
- this.a(l1, i2, true).a(entityplayer);
+ chunksToLoad.add(new ChunkCoordIntPair(l1, i2)); // CraftBukkit
}
if (!this.a(l1 - j1, i2 - k1, i, j, i1)) {
@@ -212,16 +223,13 @@ public class PlayerManager {
entityplayer.e = entityplayer.locZ;
// CraftBukkit start - send nearest chunks first
- if (i1 > 1 || i1 < -1 || j1 > 1 || j1 < -1) {
- final int x = i;
- final int z = j;
- List<ChunkCoordIntPair> chunksToSend = entityplayer.chunkCoordIntPairQueue;
+ Collections.sort(chunksToLoad, new ChunkCoordComparator(entityplayer));
+ for (ChunkCoordIntPair pair : chunksToLoad) {
+ this.a(pair.x, pair.z, true).a(entityplayer);
+ }
- java.util.Collections.sort(chunksToSend, new java.util.Comparator<ChunkCoordIntPair>() {
- public int compare(ChunkCoordIntPair a, ChunkCoordIntPair b) {
- return Math.max(Math.abs(a.x - x), Math.abs(a.z - z)) - Math.max(Math.abs(b.x - x), Math.abs(b.z - z));
- }
- });
+ if (i1 > 1 || i1 < -1 || j1 > 1 || j1 < -1) {
+ Collections.sort(entityplayer.chunkCoordIntPairQueue, new ChunkCoordComparator(entityplayer));
}
// CraftBukkit end
}
@@ -249,4 +257,47 @@ public class PlayerManager {
static Queue c(PlayerManager playermanager) { // CraftBukkit List -> Queue
return playermanager.d;
}
+
+ // CraftBukkit start - sorter to load nearby chunks first
+ private static class ChunkCoordComparator implements java.util.Comparator<ChunkCoordIntPair> {
+ private int x;
+ private int z;
+
+ public ChunkCoordComparator (EntityPlayer entityplayer) {
+ x = (int) entityplayer.locX >> 4;
+ z = (int) entityplayer.locZ >> 4;
+ }
+
+ public int compare(ChunkCoordIntPair a, ChunkCoordIntPair b) {
+ if (a.equals(b)) {
+ return 0;
+ }
+
+ // Subtract current position to set center point
+ int ax = a.x - this.x;
+ int az = a.z - this.z;
+ int bx = b.x - this.x;
+ int bz = b.z - this.z;
+
+ int result = ((ax - bx) * (ax + bx)) + ((az - bz) * (az + bz));
+ if (result != 0) {
+ return result;
+ }
+
+ if (ax < 0) {
+ if (bx < 0) {
+ return bz - az;
+ } else {
+ return -1;
+ }
+ } else {
+ if (bx < 0) {
+ return 1;
+ } else {
+ return az - bz;
+ }
+ }
+ }
+ }
+ // CraftBukkit end
}
diff --git a/src/main/java/net/minecraft/server/RegionFile.java b/src/main/java/net/minecraft/server/RegionFile.java
index 016397fc..07a8888f 100644
--- a/src/main/java/net/minecraft/server/RegionFile.java
+++ b/src/main/java/net/minecraft/server/RegionFile.java
@@ -87,6 +87,45 @@ public class RegionFile {
}
}
+ // CraftBukkit start - this is a copy (sort of) of the method below it, make sure they stay in sync
+ public synchronized boolean chunkExists(int i, int j) {
+ if (this.d(i, j)) {
+ return false;
+ } else {
+ try {
+ int k = this.e(i, j);
+
+ if (k == 0) {
+ return false;
+ } else {
+ int l = k >> 8;
+ int i1 = k & 255;
+
+ if (l + i1 > this.f.size()) {
+ return false;
+ }
+
+ this.c.seek((long) (l * 4096));
+ int j1 = this.c.readInt();
+
+ if (j1 > 4096 * i1 || j1 <= 0) {
+ return false;
+ }
+
+ byte b0 = this.c.readByte();
+ if (b0 == 1 || b0 == 2) {
+ return true;
+ }
+ }
+ } catch (IOException ioexception) {
+ return false;
+ }
+ }
+
+ return false;
+ }
+ // CraftBukkit end
+
public synchronized DataInputStream a(int i, int j) {
if (this.d(i, j)) {
return null;
@@ -211,7 +250,7 @@ public class RegionFile {
}
}
- private void a(int i, byte[] abyte, int j) {
+ private void a(int i, byte[] abyte, int j) throws IOException { // CraftBukkit - added throws
this.c.seek((long) (i * 4096));
this.c.writeInt(j + 1);
this.c.writeByte(2);
@@ -230,19 +269,19 @@ public class RegionFile {
return this.e(i, j) != 0;
}
- private void a(int i, int j, int k) {
+ private void a(int i, int j, int k) throws IOException { // CraftBukkit - added throws
this.d[i + j * 32] = k;
this.c.seek((long) ((i + j * 32) * 4));
this.c.writeInt(k);
}
- private void b(int i, int j, int k) {
+ private void b(int i, int j, int k) throws IOException { // CraftBukkit - added throws
this.e[i + j * 32] = k;
this.c.seek((long) (4096 + (i + j * 32) * 4));
this.c.writeInt(k);
}
- public void c() {
+ public void c() throws IOException { // CraftBukkit - added throws
if (this.c != null) {
this.c.close();
}
diff --git a/src/main/java/net/minecraft/server/ServerConfigurationManagerAbstract.java b/src/main/java/net/minecraft/server/ServerConfigurationManagerAbstract.java
index 12f8dfc3..367cada1 100644
--- a/src/main/java/net/minecraft/server/ServerConfigurationManagerAbstract.java
+++ b/src/main/java/net/minecraft/server/ServerConfigurationManagerAbstract.java
@@ -15,6 +15,7 @@ import java.util.logging.Logger;
import org.bukkit.Location;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.craftbukkit.chunkio.ChunkIOExecutor;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerPortalEvent;
@@ -149,6 +150,7 @@ public abstract class ServerConfigurationManagerAbstract {
this.players.add(entityplayer);
WorldServer worldserver = this.server.getWorldServer(entityplayer.dimension);
+ // CraftBukkit start
PlayerJoinEvent playerJoinEvent = new PlayerJoinEvent(this.cserver.getPlayer(entityplayer), "\u00A7e" + entityplayer.name + " joined the game.");
this.cserver.getPluginManager().callEvent(playerJoinEvent);
@@ -158,6 +160,8 @@ public abstract class ServerConfigurationManagerAbstract {
this.server.getServerConfigurationManager().sendAll(new Packet3Chat(joinMessage));
}
this.cserver.onPlayerJoin(playerJoinEvent.getPlayer());
+
+ ChunkIOExecutor.adjustPoolSize(this.getPlayerCount());
// CraftBukkit end
// CraftBukkit start - only add if the player wasn't moved in the event
@@ -207,6 +211,7 @@ public abstract class ServerConfigurationManagerAbstract {
worldserver.kill(entityplayer);
worldserver.getPlayerManager().removePlayer(entityplayer);
this.players.remove(entityplayer);
+ ChunkIOExecutor.adjustPoolSize(this.getPlayerCount()); // CraftBukkit
// CraftBukkit start - .name -> .listName, replace sendAll with loop
Packet201PlayerInfo packet = new Packet201PlayerInfo(entityplayer.listName, false, 9999);
diff --git a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOExecutor.java b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOExecutor.java
new file mode 100644
index 00000000..92fbc4f9
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOExecutor.java
@@ -0,0 +1,32 @@
+package org.bukkit.craftbukkit.chunkio;
+
+import net.minecraft.server.Chunk;
+import net.minecraft.server.ChunkProviderServer;
+import net.minecraft.server.ChunkRegionLoader;
+import net.minecraft.server.World;
+import org.bukkit.craftbukkit.util.AsynchronousExecutor;
+import org.bukkit.craftbukkit.util.LongHash;
+
+public class ChunkIOExecutor {
+ static final int BASE_THREADS = 1;
+ static final int PLAYERS_PER_THREAD = 50;
+
+ private static final AsynchronousExecutor<QueuedChunk, Chunk, Runnable, RuntimeException> instance = new AsynchronousExecutor<QueuedChunk, Chunk, Runnable, RuntimeException>(new ChunkIOProvider(), BASE_THREADS);
+
+ public static void waitForChunkLoad(World world, int x, int z) {
+ instance.get(new QueuedChunk(LongHash.toLong(x, z), null, world, null));
+ }
+
+ public static void queueChunkLoad(World world, ChunkRegionLoader loader, ChunkProviderServer provider, int x, int z, Runnable runnable) {
+ instance.add(new QueuedChunk(LongHash.toLong(x, z), loader, world, provider), runnable);
+ }
+
+ public static void adjustPoolSize(int players) {
+ int size = Math.max(BASE_THREADS, (int) Math.ceil(players / PLAYERS_PER_THREAD));
+ instance.setActiveThreads(size);
+ }
+
+ public static void tick() {
+ instance.finishActive();
+ }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java
new file mode 100644
index 00000000..48cf5bac
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java
@@ -0,0 +1,73 @@
+package org.bukkit.craftbukkit.chunkio;
+
+import net.minecraft.server.Chunk;
+import net.minecraft.server.ChunkRegionLoader;
+import net.minecraft.server.NBTTagCompound;
+
+import org.bukkit.Server;
+import org.bukkit.craftbukkit.util.AsynchronousExecutor;
+import org.bukkit.craftbukkit.util.LongHash;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+class ChunkIOProvider implements AsynchronousExecutor.CallBackProvider<QueuedChunk, Chunk, Runnable, RuntimeException> {
+ private final AtomicInteger threadNumber = new AtomicInteger(1);
+
+ // async stuff
+ public Chunk callStage1(QueuedChunk queuedChunk) throws RuntimeException {
+ ChunkRegionLoader loader = queuedChunk.loader;
+ Object[] data = loader.loadChunk(queuedChunk.world, LongHash.msw(queuedChunk.coords), LongHash.lsw(queuedChunk.coords));
+
+ if (data != null) {
+ queuedChunk.compound = (NBTTagCompound) data[1];
+ return (Chunk) data[0];
+ }
+
+ return null;
+ }
+
+ // sync stuff
+ public void callStage2(QueuedChunk queuedChunk, Chunk chunk) throws RuntimeException {
+ if(chunk == null) {
+ // If the chunk loading failed just do it synchronously (may generate)
+ queuedChunk.provider.getChunkAt(LongHash.msw(queuedChunk.coords), LongHash.lsw(queuedChunk.coords));
+ return;
+ }
+
+ int x = LongHash.msw(queuedChunk.coords);
+ int z = LongHash.lsw(queuedChunk.coords);
+
+ // See if someone already loaded this chunk while we were working on it (API, etc)
+ if (queuedChunk.provider.chunks.containsKey(queuedChunk.coords)) {
+ // Make sure it isn't queued for unload, we need it
+ queuedChunk.provider.unloadQueue.remove(queuedChunk.coords);
+ return;
+ }
+
+ queuedChunk.loader.loadEntities(chunk, queuedChunk.compound.getCompound("Level"), queuedChunk.world);
+ chunk.n = queuedChunk.provider.world.getTime();
+ queuedChunk.provider.chunks.put(queuedChunk.coords, chunk);
+ chunk.addEntities();
+
+ if (queuedChunk.provider.chunkProvider != null) {
+ queuedChunk.provider.chunkProvider.recreateStructures(x, z);
+ }
+
+ Server server = queuedChunk.provider.world.getServer();
+ if (server != null) {
+ server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(chunk.bukkitChunk, false));
+ }
+
+ chunk.a(queuedChunk.provider, queuedChunk.provider, x, z);
+ }
+
+ public void callStage3(QueuedChunk queuedChunk, Chunk chunk, Runnable runnable) throws RuntimeException {
+ runnable.run();
+ }
+
+ public Thread newThread(Runnable runnable) {
+ Thread thread = new Thread(runnable, "Chunk I/O Executor Thread-" + threadNumber.getAndIncrement());
+ thread.setDaemon(true);
+ return thread;
+ }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/chunkio/QueuedChunk.java b/src/main/java/org/bukkit/craftbukkit/chunkio/QueuedChunk.java
new file mode 100644
index 00000000..299b1d8a
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/chunkio/QueuedChunk.java
@@ -0,0 +1,36 @@
+package org.bukkit.craftbukkit.chunkio;
+
+import net.minecraft.server.ChunkProviderServer;
+import net.minecraft.server.ChunkRegionLoader;
+import net.minecraft.server.NBTTagCompound;
+import net.minecraft.server.World;
+
+class QueuedChunk {
+ long coords;
+ ChunkRegionLoader loader;
+ World world;
+ ChunkProviderServer provider;
+ NBTTagCompound compound;
+
+ public QueuedChunk(long coords, ChunkRegionLoader loader, World world, ChunkProviderServer provider) {
+ this.coords = coords;
+ this.loader = loader;
+ this.world = world;
+ this.provider = provider;
+ }
+
+ @Override
+ public int hashCode() {
+ return (int) coords ^ world.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof QueuedChunk) {
+ QueuedChunk other = (QueuedChunk) object;
+ return coords == other.coords && world == other.world;
+ }
+
+ return false;
+ }
+}