Clean up async lighting patch

This commit is contained in:
Byteflux 2015-07-01 00:27:58 -07:00
parent 5030643f4e
commit 16d34d5de1
4 changed files with 153 additions and 302 deletions

View file

@ -1,9 +1,59 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Roman Alexander <romanalexander@users.noreply.github.com>
Date: Wed, 25 Mar 2015 20:27:13 -0500
From: Byteflux <byte@byteflux.net>
Date: Wed, 1 Jul 2015 00:18:10 -0700
Subject: [PATCH] Configurable async light updates
diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/Chunk.java
+++ b/src/main/java/net/minecraft/server/Chunk.java
@@ -0,0 +0,0 @@ import java.util.Map;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.AtomicInteger; // PaperSpigot
+
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -0,0 +0,0 @@ public class Chunk {
private int v;
private ConcurrentLinkedQueue<BlockPosition> w;
protected gnu.trove.map.hash.TObjectIntHashMap<Class> entityCount = new gnu.trove.map.hash.TObjectIntHashMap<Class>(); // Spigot
+ // PaperSpigot start - Asynchronous light updates
+ public AtomicInteger pendingLightUpdates = new AtomicInteger();
+ public long lightUpdateTime;
+ // PaperSpigot end
// CraftBukkit start - Neighbor loaded cache for chunk lighting and entity ticking
private int neighbors = 0x1 << 12;
@@ -0,0 +0,0 @@ public class Chunk {
private void a(int i, int j, int k, int l) {
if (l > k && this.world.areChunksLoaded(new BlockPosition(i, 0, j), 16)) {
for (int i1 = k; i1 < l; ++i1) {
- this.world.c(EnumSkyBlock.SKY, new BlockPosition(i, i1, j));
+ this.world.updateLight(EnumSkyBlock.SKY, new BlockPosition(i, i1, j)); // PaperSpigot - Asynchronous lighting updates
}
this.q = true;
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
@@ -0,0 +0,0 @@ public class ChunkProviderServer implements IChunkProvider {
}
public void queueUnload(int i, int j) {
+ // PaperSpigot start - Asynchronous lighting updates
+ Chunk chunk = chunks.get(LongHash.toLong(i, j));
+ if (chunk != null && chunk.world.paperSpigotConfig.useAsyncLighting && (chunk.pendingLightUpdates.get() > 0 || chunk.world.getTime() - chunk.lightUpdateTime < 20)) {
+ return;
+ }
+ // PaperSpigot end
if (this.world.worldProvider.e()) {
if (!this.world.c(i, j)) {
// CraftBukkit start
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/World.java
@ -22,316 +72,116 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
// CraftBukkit end
@@ -0,0 +0,0 @@ public abstract class World implements IBlockAccess {
blockposition = new BlockPosition(blockposition.getX(), 0, blockposition.getZ());
}
public static boolean haveWeSilencedAPhysicsCrash;
public static String blockLocation;
private int tileTickPosition;
+ private ExecutorService lightingExecutor; // PaperSpigot - Asynchronous lighting updates
+ // PaperSpigot start - configurable async light updates
if (!this.isValidLocation(blockposition)) {
return enumskyblock.c;
- } else if (!this.isLoaded(blockposition)) {
+ }
+
+ Chunk chunk = this.getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4);
+ if (chunk == null) {
return enumskyblock.c;
} else {
- Chunk chunk = this.getChunkAtWorldCoords(blockposition);
-
+ // PaperSpigot end
return chunk.getBrightness(enumskyblock, blockposition);
}
}
public void a(EnumSkyBlock enumskyblock, BlockPosition blockposition, int i) {
if (this.isValidLocation(blockposition)) {
- if (this.isLoaded(blockposition)) {
- Chunk chunk = this.getChunkAtWorldCoords(blockposition);
-
+ // PaperSpigot start - Configurable async light updates
+ Chunk chunk = this.getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4);
+ if (chunk != null) {
+ // PaperSpigot end
chunk.a(enumskyblock, blockposition, i);
this.n(blockposition);
}
public static long chunkToKey(int x, int z)
{
@@ -0,0 +0,0 @@ public abstract class World implements IBlockAccess {
}
private int a(BlockPosition blockposition, EnumSkyBlock enumskyblock) {
- if (enumskyblock == EnumSkyBlock.SKY && this.i(blockposition)) {
+ // PaperSpigot start - Configurable async light updates
+ Chunk chunk = this.getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4);
+ if (chunk == null || (enumskyblock == EnumSkyBlock.SKY && chunk.d(blockposition))) {
+ // PaperSpigot end
return 15;
} else {
- Block block = this.getType(blockposition).getBlock();
+ Block block = chunk.getType(blockposition); // PaperSpigot - Configurable async light updates
int i = enumskyblock == EnumSkyBlock.SKY ? 0 : block.r();
int j = block.p();
if (!this.worldProvider.o()) {
for (i1 = k; i1 <= l; ++i1) {
- this.c(EnumSkyBlock.SKY, new BlockPosition(i, i1, j));
+ this.updateLight(EnumSkyBlock.SKY, new BlockPosition(i, i1, j)); // PaperSpigot - Asynchronous lighting updates
}
}
@@ -0,0 +0,0 @@ public abstract class World implements IBlockAccess {
boolean flag = false;
if (!this.worldProvider.o()) {
- flag |= this.c(EnumSkyBlock.SKY, blockposition);
+ flag |= this.updateLight(EnumSkyBlock.SKY, blockposition); // PaperSpigot - Asynchronous lighting updates
}
- flag |= this.c(EnumSkyBlock.BLOCK, blockposition);
+ flag |= this.updateLight(EnumSkyBlock.BLOCK, blockposition); // PaperSpigot - Asynchronous lighting updates
return flag;
}
@@ -0,0 +0,0 @@ public abstract class World implements IBlockAccess {
}
}
- public boolean c(EnumSkyBlock enumskyblock, BlockPosition blockposition) {
- // CraftBukkit start - Use neighbor cache instead of looking up
+ public boolean c(EnumSkyBlock enumskyblock, BlockPosition blockposition, Chunk chunk, List<Chunk> neighbors) { // PaperSpigot
// CraftBukkit start - Use neighbor cache instead of looking up
- Chunk chunk = this.getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4);
- if (chunk == null || !chunk.areNeighborsLoaded(1) /*!this.areChunksLoaded(blockposition, 17, false)*/) {
- // CraftBukkit end
- return false;
- } else {
- int i = 0;
- int j = 0;
-
- this.methodProfiler.a("getBrightness");
- int k = this.b(enumskyblock, blockposition);
- int l = this.a(blockposition, enumskyblock);
- int i1 = blockposition.getX();
- int j1 = blockposition.getY();
- int k1 = blockposition.getZ();
- int l1;
- int i2;
- int j2;
- int k2;
- int l2;
- int i3;
- int j3;
- int k3;
-
- if (l > k) {
- this.H[j++] = 133152;
- } else if (l < k) {
- this.H[j++] = 133152 | k << 18;
-
- while (i < j) {
- l1 = this.H[i++];
- i2 = (l1 & 63) - 32 + i1;
- j2 = (l1 >> 6 & 63) - 32 + j1;
- k2 = (l1 >> 12 & 63) - 32 + k1;
- int l3 = l1 >> 18 & 15;
- BlockPosition blockposition1 = new BlockPosition(i2, j2, k2);
-
- l2 = this.b(enumskyblock, blockposition1);
- if (l2 == l3) {
- this.a(enumskyblock, blockposition1, 0);
- if (l3 > 0) {
- i3 = MathHelper.a(i2 - i1);
- j3 = MathHelper.a(j2 - j1);
- k3 = MathHelper.a(k2 - k1);
- if (i3 + j3 + k3 < 17) {
- BlockPosition.MutableBlockPosition blockposition_mutableblockposition = new BlockPosition.MutableBlockPosition();
- EnumDirection[] aenumdirection = EnumDirection.values();
- int i4 = aenumdirection.length;
-
- for (int j4 = 0; j4 < i4; ++j4) {
- EnumDirection enumdirection = aenumdirection[j4];
- int k4 = i2 + enumdirection.getAdjacentX();
- int l4 = j2 + enumdirection.getAdjacentY();
- int i5 = k2 + enumdirection.getAdjacentZ();
-
- blockposition_mutableblockposition.c(k4, l4, i5);
- int j5 = Math.max(1, this.getType(blockposition_mutableblockposition).getBlock().p());
-
- l2 = this.b(enumskyblock, (BlockPosition) blockposition_mutableblockposition);
- if (l2 == l3 - j5 && j < this.H.length) {
- this.H[j++] = k4 - i1 + 32 | l4 - j1 + 32 << 6 | i5 - k1 + 32 << 12 | l3 - j5 << 18;
+ // PaperSpigot start - Configurable async light updates
+ private ExecutorService service = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("PaperSpigot - Lighting Thread").build());
+ public boolean c(final EnumSkyBlock enumskyblock, final BlockPosition blockposition) {
+ Callable<Boolean> callable = new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws Exception {
+ // CraftBukkit start - Use neighbor cache instead of looking up
+ Chunk chunk = World.this.getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4);
+ if (chunk == null || !chunk.areNeighborsLoaded(1) /*!this.areChunksLoaded(blockposition, 17, false)*/) {
+ // CraftBukkit end
+ return false;
+ } else {
+ int i = 0;
+ int j = 0;
+
+ World.this.methodProfiler.a("getBrightness");
+ int k = World.this.b(enumskyblock, blockposition);
+ int l = World.this.a(blockposition, enumskyblock);
+ int i1 = blockposition.getX();
+ int j1 = blockposition.getY();
+ int k1 = blockposition.getZ();
+ int l1;
+ int i2;
+ int j2;
+ int k2;
+ int l2;
+ int i3;
+ int j3;
+ int k3;
+
+ if (l > k) {
+ World.this.H[j++] = 133152;
+ } else if (l < k) {
+ World.this.H[j++] = 133152 | k << 18;
+
+ while (i < j) {
+ l1 = World.this.H[i++];
+ i2 = (l1 & 63) - 32 + i1;
+ j2 = (l1 >> 6 & 63) - 32 + j1;
+ k2 = (l1 >> 12 & 63) - 32 + k1;
+ int l3 = l1 >> 18 & 15;
+ BlockPosition blockposition1 = new BlockPosition(i2, j2, k2);
+
+ l2 = World.this.b(enumskyblock, blockposition1);
+ if (l2 == l3) {
+ World.this.a(enumskyblock, blockposition1, 0);
+ if (l3 > 0) {
+ i3 = MathHelper.a(i2 - i1);
+ j3 = MathHelper.a(j2 - j1);
+ k3 = MathHelper.a(k2 - k1);
+ if (i3 + j3 + k3 < 17) {
+ BlockPosition.MutableBlockPosition blockposition_mutableblockposition = new BlockPosition.MutableBlockPosition();
+ EnumDirection[] aenumdirection = EnumDirection.values();
+ int i4 = aenumdirection.length;
+
+ for (int j4 = 0; j4 < i4; ++j4) {
+ EnumDirection enumdirection = aenumdirection[j4];
+ int k4 = i2 + enumdirection.getAdjacentX();
+ int l4 = j2 + enumdirection.getAdjacentY();
+ int i5 = k2 + enumdirection.getAdjacentZ();
+
+ blockposition_mutableblockposition.c(k4, l4, i5);
+ Chunk lightChunk = World.this.getChunkIfLoaded(blockposition_mutableblockposition.getX() >> 4, blockposition_mutableblockposition.getZ() >> 4);
+ int j5;
+ if (lightChunk != null) {
+ j5 = Math.max(1, lightChunk.getType(blockposition_mutableblockposition).p());
+ } else {
+ j5 = 255;
+ }
+
+ l2 = World.this.b(enumskyblock, (BlockPosition) blockposition_mutableblockposition);
+ if (l2 == l3 - j5 && j < World.this.H.length) {
+ World.this.H[j++] = k4 - i1 + 32 | l4 - j1 + 32 << 6 | i5 - k1 + 32 << 12 | l3 - j5 << 18;
+ }
+ }
}
}
}
}
- }
- }
- i = 0;
- }
+ i = 0;
+ }
- this.methodProfiler.b();
- this.methodProfiler.a("checkedPosition < toCheckCount");
-
- while (i < j) {
- l1 = this.H[i++];
- i2 = (l1 & 63) - 32 + i1;
- j2 = (l1 >> 6 & 63) - 32 + j1;
- k2 = (l1 >> 12 & 63) - 32 + k1;
- BlockPosition blockposition2 = new BlockPosition(i2, j2, k2);
- int k5 = this.b(enumskyblock, blockposition2);
-
- l2 = this.a(blockposition2, enumskyblock);
- if (l2 != k5) {
- this.a(enumskyblock, blockposition2, l2);
- if (l2 > k5) {
- i3 = Math.abs(i2 - i1);
- j3 = Math.abs(j2 - j1);
- k3 = Math.abs(k2 - k1);
- boolean flag = j < this.H.length - 6;
-
- if (i3 + j3 + k3 < 17 && flag) {
- if (this.b(enumskyblock, blockposition2.west()) < l2) {
- this.H[j++] = i2 - 1 - i1 + 32 + (j2 - j1 + 32 << 6) + (k2 - k1 + 32 << 12);
- }
+ World.this.methodProfiler.b();
+ World.this.methodProfiler.a("checkedPosition < toCheckCount");
+
+ while (i < j) {
+ l1 = World.this.H[i++];
+ i2 = (l1 & 63) - 32 + i1;
+ j2 = (l1 >> 6 & 63) - 32 + j1;
+ k2 = (l1 >> 12 & 63) - 32 + k1;
+ BlockPosition blockposition2 = new BlockPosition(i2, j2, k2);
+ int k5 = World.this.b(enumskyblock, blockposition2);
+
+ l2 = World.this.a(blockposition2, enumskyblock);
+ if (l2 != k5) {
+ World.this.a(enumskyblock, blockposition2, l2);
+ if (l2 > k5) {
+ i3 = Math.abs(i2 - i1);
+ j3 = Math.abs(j2 - j1);
+ k3 = Math.abs(k2 - k1);
+ boolean flag = j < World.this.H.length - 6;
+
+ if (i3 + j3 + k3 < 17 && flag) {
+ if (World.this.b(enumskyblock, blockposition2.west()) < l2) {
+ World.this.H[j++] = i2 - 1 - i1 + 32 + (j2 - j1 + 32 << 6) + (k2 - k1 + 32 << 12);
+ }
- if (this.b(enumskyblock, blockposition2.east()) < l2) {
- this.H[j++] = i2 + 1 - i1 + 32 + (j2 - j1 + 32 << 6) + (k2 - k1 + 32 << 12);
- }
+ if (World.this.b(enumskyblock, blockposition2.east()) < l2) {
+ World.this.H[j++] = i2 + 1 - i1 + 32 + (j2 - j1 + 32 << 6) + (k2 - k1 + 32 << 12);
+ }
- if (this.b(enumskyblock, blockposition2.down()) < l2) {
- this.H[j++] = i2 - i1 + 32 + (j2 - 1 - j1 + 32 << 6) + (k2 - k1 + 32 << 12);
- }
+ if (World.this.b(enumskyblock, blockposition2.down()) < l2) {
+ World.this.H[j++] = i2 - i1 + 32 + (j2 - 1 - j1 + 32 << 6) + (k2 - k1 + 32 << 12);
+ }
- if (this.b(enumskyblock, blockposition2.up()) < l2) {
- this.H[j++] = i2 - i1 + 32 + (j2 + 1 - j1 + 32 << 6) + (k2 - k1 + 32 << 12);
- }
+ if (World.this.b(enumskyblock, blockposition2.up()) < l2) {
+ World.this.H[j++] = i2 - i1 + 32 + (j2 + 1 - j1 + 32 << 6) + (k2 - k1 + 32 << 12);
+ }
- if (this.b(enumskyblock, blockposition2.north()) < l2) {
- this.H[j++] = i2 - i1 + 32 + (j2 - j1 + 32 << 6) + (k2 - 1 - k1 + 32 << 12);
- }
+ if (World.this.b(enumskyblock, blockposition2.north()) < l2) {
+ World.this.H[j++] = i2 - i1 + 32 + (j2 - j1 + 32 << 6) + (k2 - 1 - k1 + 32 << 12);
+ }
- if (this.b(enumskyblock, blockposition2.south()) < l2) {
- this.H[j++] = i2 - i1 + 32 + (j2 - j1 + 32 << 6) + (k2 + 1 - k1 + 32 << 12);
+ if (World.this.b(enumskyblock, blockposition2.south()) < l2) {
+ World.this.H[j++] = i2 - i1 + 32 + (j2 - j1 + 32 << 6) + (k2 + 1 - k1 + 32 << 12);
+ }
+ }
}
}
}
+
+ World.this.methodProfiler.b();
+ return true;
+ //Chunk chunk = this.getChunkIfLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4);
+ if (chunk == null /*|| !chunk.areNeighborsLoaded(1)*/ /*!this.areChunksLoaded(blockposition, 17, false)*/) {
// CraftBukkit end
return false;
} else {
@@ -0,0 +0,0 @@ public abstract class World implements IBlockAccess {
}
}
-
- this.methodProfiler.b();
- return true;
+ };
+ if (paperSpigotConfig.useAsyncLighting) {
+ service.submit(callable);
+ } else {
+ try {
+ return callable.call();
+ } catch(Exception ignore) {
+ }
}
+ return true;
}
+ // PaperSpigot end
+ // PaperSpigot start - Asynchronous light updates
+ if (chunk.world.paperSpigotConfig.useAsyncLighting) {
+ chunk.pendingLightUpdates.decrementAndGet();
+ if (neighbors != null) {
+ for (Chunk neighbor : neighbors) {
+ neighbor.pendingLightUpdates.decrementAndGet();
+ }
+ }
+ }
+ // PaperSpigot end
this.methodProfiler.b();
return true;
}
}
+ /**
+ * PaperSpigot - Asynchronous lighting updates
+ */
+ public boolean updateLight(final EnumSkyBlock enumskyblock, final BlockPosition position) {
+ int x = position.getX();
+ int z = position.getZ();
+ final Chunk chunk = this.getChunkIfLoaded(x >> 4, z >> 4);
+ if (chunk == null || (!chunk.world.paperSpigotConfig.useAsyncLighting && !chunk.areNeighborsLoaded(1))) {
+ return false;
+ }
+
+ if (!chunk.world.paperSpigotConfig.useAsyncLighting) {
+ return this.c(enumskyblock, position, chunk, null);
+ }
+
+ if (lightingExecutor == null) {
+ lightingExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("PaperSpigot - Lighting Thread").build());
+ }
+
+ chunk.pendingLightUpdates.incrementAndGet();
+ chunk.lightUpdateTime = chunk.world.getTime();
+
+ final List<Chunk> neighbors = new ArrayList<Chunk>();
+ for (int cx = (x >> 4) - 1; cx < (x >> 4) + 1; ++cx) {
+ for (int cz = (z >> 4) - 1; cz < (z >> 4) + 1; ++cz) {
+ if (this.chunkProvider.isChunkLoaded(cx, cz)) {
+ Chunk neighbor = this.getChunkAt(cx, cz);
+ if (neighbor != chunk) {
+ neighbor.pendingLightUpdates.incrementAndGet();
+ neighbor.lightUpdateTime = chunk.world.getTime();
+ neighbors.add(neighbor);
+ }
+ }
+ }
+ }
+
+ lightingExecutor.submit(new Runnable() {
+ @Override
+ public void run() {
+ World.this.c(enumskyblock, position, chunk, neighbors);
+ }
+ });
+ return true;
+ }
+
public boolean a(boolean flag) {
return false;
}
diff --git a/src/main/java/org/github/paperspigot/PaperSpigotWorldConfig.java b/src/main/java/org/github/paperspigot/PaperSpigotWorldConfig.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/github/paperspigot/PaperSpigotWorldConfig.java

View file

@ -9,11 +9,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
@@ -0,0 +0,0 @@ public class ChunkProviderServer implements IChunkProvider {
}
public void queueUnload(int i, int j) {
return;
}
// PaperSpigot end
+ // PaperSpigot start - Don't unload chunk if it contains an entity that loads chunks
+ Chunk chunk = chunks.get(LongHash.toLong(i, j));
+ if (chunk != null) {
+ for (List<Entity> entities : chunk.entitySlices) {
+ for (Entity entity : entities) {

View file

@ -126,9 +126,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/src/main/java/net/minecraft/server/World.java
+++ b/src/main/java/net/minecraft/server/World.java
@@ -0,0 +0,0 @@ public abstract class World implements IBlockAccess {
public static boolean haveWeSilencedAPhysicsCrash;
public static String blockLocation;
private int tileTickPosition;
private ExecutorService lightingExecutor; // PaperSpigot - Asynchronous lighting updates
+ public final Map<Explosion.CacheKey, Float> explosionDensityCache = new HashMap<Explosion.CacheKey, Float>(); // PaperSpigot - Optimize explosions
public static long chunkToKey(int x, int z)

View file

@ -96,4 +96,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
return true;
}
--
--
1.9.5.msysgit.1