summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTravis Watkins <amaranth@ubuntu.com>2014-06-16 19:01:55 -0500
committerTravis Watkins <amaranth@ubuntu.com>2014-06-21 21:12:46 -0500
commit5b9950b5f7f4143323c0edced82fce269d5e5ddc (patch)
tree999f04a0910a2e304a390e47b084251cea1af7d8 /src
parentea126f98adfb3a54c1b0defb262ff583127b52b3 (diff)
downloadcraftbukkit-5b9950b5f7f4143323c0edced82fce269d5e5ddc.tar
craftbukkit-5b9950b5f7f4143323c0edced82fce269d5e5ddc.tar.gz
craftbukkit-5b9950b5f7f4143323c0edced82fce269d5e5ddc.tar.lz
craftbukkit-5b9950b5f7f4143323c0edced82fce269d5e5ddc.tar.xz
craftbukkit-5b9950b5f7f4143323c0edced82fce269d5e5ddc.zip
Avoid checking for loaded chunks for lighting and entity ticking.
When a chunk is loaded the server tries to ensure it has its initial light calculations done before sending it to the player. When ticking entities the server tries to ensure the entity does not walk into an unloaded chunk. To accomplish these the server checks a one chunk radius around the chunk to be lit or a two chunk radius around the chunk the entity is in. These lookups happen every tick even though their result is unlikely to change that often. To reduce the cost of these checks we replace them with a system to keep track of what neighbor chunks a chunk has loaded and update it when chunks load or unload which is a much less frequent action. On a server with ten players this change removes about 100,000 calls a tick to LongObjectHashMap's containsKey method.
Diffstat (limited to 'src')
-rw-r--r--src/main/java/net/minecraft/server/Chunk.java28
-rw-r--r--src/main/java/net/minecraft/server/ChunkProviderServer.java38
-rw-r--r--src/main/java/net/minecraft/server/World.java14
-rw-r--r--src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java17
4 files changed, 92 insertions, 5 deletions
diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java
index ade0c35b..d770e4e6 100644
--- a/src/main/java/net/minecraft/server/Chunk.java
+++ b/src/main/java/net/minecraft/server/Chunk.java
@@ -41,6 +41,34 @@ public class Chunk {
public long s;
private int x;
+ // CraftBukkit start - Neighbor loaded cache for chunk lighting and entity ticking
+ private int neighbors = 0x1 << 12;
+
+ public boolean areNeighborsLoaded(final int radius) {
+ switch(radius) {
+ case 2:
+ return this.neighbors == Integer.MAX_VALUE >> 6;
+ case 1:
+ final int mask =
+ // x z offset x z offset x z offset
+ ( 0x1 << (1 * 5 + 1 + 12) ) | ( 0x1 << (0 * 5 + 1 + 12) ) | ( 0x1 << (-1 * 5 + 1 + 12) ) |
+ ( 0x1 << (1 * 5 + 0 + 12) ) | ( 0x1 << (0 * 5 + 0 + 12) ) | ( 0x1 << (-1 * 5 + 0 + 12) ) |
+ ( 0x1 << (1 * 5 + -1 + 12) ) | ( 0x1 << (0 * 5 + -1 + 12) ) | ( 0x1 << (-1 * 5 + -1 + 12) );
+ return (this.neighbors & mask) == mask;
+ default:
+ throw new UnsupportedOperationException(String.valueOf(radius));
+ }
+ }
+
+ public void setNeighborLoaded(final int x, final int z) {
+ this.neighbors |= 0x1 << (x * 5 + 12 + z);
+ }
+
+ public void setNeighborUnloaded(final int x, final int z) {
+ this.neighbors &= ~(0x1 << (x * 5 + 12 + z));
+ }
+ // CraftBukkit end
+
public Chunk(World world, int i, int j) {
this.sections = new ChunkSection[16];
this.v = new byte[256];
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
index 1b22934d..8cc2efd4 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
@@ -94,6 +94,10 @@ public class ChunkProviderServer implements IChunkProvider {
}
// CraftBukkit start - Add async variant, provide compatibility
+ public Chunk getChunkIfLoaded(int x, int z) {
+ return this.chunks.get(LongHash.toLong(x, z));
+ }
+
public Chunk getChunkAt(int i, int j) {
return getChunkAt(i, j, null);
}
@@ -166,6 +170,21 @@ public class ChunkProviderServer implements IChunkProvider {
*/
server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(chunk.bukkitChunk, newChunk));
}
+
+ // Update neighbor counts
+ for (int x = -2; x < 3; x++) {
+ for (int z = -2; z < 3; z++) {
+ if (x == 0 && z == 0) {
+ continue;
+ }
+
+ Chunk neighbor = this.getChunkIfLoaded(chunk.locX + x, chunk.locZ + z);
+ if (neighbor != null) {
+ neighbor.setNeighborLoaded(-x, -z);
+ chunk.setNeighborLoaded(x, z);
+ }
+ }
+ }
// CraftBukkit end
chunk.a(this, this, i, j);
}
@@ -327,6 +346,21 @@ public class ChunkProviderServer implements IChunkProvider {
// this.unloadQueue.remove(olong);
// this.chunks.remove(olong.longValue());
+
+ // Update neighbor counts
+ for (int x = -2; x < 3; x++) {
+ for (int z = -2; z < 3; z++) {
+ if (x == 0 && z == 0) {
+ continue;
+ }
+
+ Chunk neighbor = this.getChunkIfLoaded(chunk.locX + x, chunk.locZ + z);
+ if (neighbor != null) {
+ neighbor.setNeighborUnloaded(-x, -z);
+ chunk.setNeighborUnloaded(x, z);
+ }
+ }
+ }
}
}
// CraftBukkit end
@@ -357,8 +391,8 @@ public class ChunkProviderServer implements IChunkProvider {
}
public int getLoadedChunks() {
- // CraftBukkit - this.chunks.count() -> .values().size()
- return this.chunks.values().size();
+ // CraftBukkit - this.chunks.count() -> this.chunks.size()
+ return this.chunks.size();
}
public void recreateStructures(int i, int j) {}
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
index af7069cb..eb5da2af 100644
--- a/src/main/java/net/minecraft/server/World.java
+++ b/src/main/java/net/minecraft/server/World.java
@@ -115,6 +115,10 @@ public abstract class World implements IBlockAccess {
return (CraftServer) Bukkit.getServer();
}
+ public Chunk getChunkIfLoaded(int x, int z) {
+ return ((ChunkProviderServer) this.chunkProvider).getChunkIfLoaded(x, z);
+ }
+
// Changed signature - added gen and env
public World(IDataManager idatamanager, String s, WorldSettings worldsettings, WorldProvider worldprovider, MethodProfiler methodprofiler, ChunkGenerator gen, org.bukkit.World.Environment env) {
this.generator = gen;
@@ -1396,7 +1400,10 @@ public abstract class World implements IBlockAccess {
int j = MathHelper.floor(entity.locZ);
byte b0 = 32;
- if (!flag || this.b(i - b0, 0, j - b0, i + b0, 0, j + b0)) {
+ // CraftBukkit start - Use neighbor cache instead of looking up
+ Chunk startingChunk = this.getChunkIfLoaded(i >> 4, j >> 4);
+ if (!flag || (startingChunk != null && startingChunk.areNeighborsLoaded(2)) /* this.b(i - b0, 0, j - b0, i + b0, 0, j + b0) */) {
+ // CraftBukkit end
entity.S = entity.locX;
entity.T = entity.locY;
entity.U = entity.locZ;
@@ -2165,7 +2172,10 @@ public abstract class World implements IBlockAccess {
}
public boolean c(EnumSkyBlock enumskyblock, int i, int j, int k) {
- if (!this.areChunksLoaded(i, j, k, 17)) {
+ // CraftBukkit start - Use neighbor cache instead of looking up
+ Chunk chunk = this.getChunkIfLoaded(i >> 4, k >> 4);
+ if (chunk == null || !chunk.areNeighborsLoaded(1) /* !this.areChunksLoaded(i, j, k, 17)*/) {
+ // CraftBukkit end
return false;
} else {
int l = 0;
diff --git a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java
index 8feadd11..1440349b 100644
--- a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java
+++ b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java
@@ -28,7 +28,7 @@ class ChunkIOProvider implements AsynchronousExecutor.CallBackProvider<QueuedChu
// sync stuff
public void callStage2(QueuedChunk queuedChunk, Chunk chunk) throws RuntimeException {
- if(chunk == null) {
+ if (chunk == null) {
// If the chunk loading failed just do it synchronously (may generate)
queuedChunk.provider.originalGetChunkAt(queuedChunk.x, queuedChunk.z);
return;
@@ -48,6 +48,21 @@ class ChunkIOProvider implements AsynchronousExecutor.CallBackProvider<QueuedChu
server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(chunk.bukkitChunk, false));
}
+ // Update neighbor counts
+ for (int x = -2; x < 3; x++) {
+ for (int z = -2; z < 3; z++) {
+ if (x == 0 && z == 0) {
+ continue;
+ }
+
+ Chunk neighbor = queuedChunk.provider.getChunkIfLoaded(chunk.locX + x, chunk.locZ + z);
+ if (neighbor != null) {
+ neighbor.setNeighborLoaded(-x, -z);
+ chunk.setNeighborLoaded(x, z);
+ }
+ }
+ }
+
chunk.a(queuedChunk.provider, queuedChunk.provider, queuedChunk.x, queuedChunk.z);
}