From cc4cc3c5874b1cdd1f1a1e5488d6b729f3b303ec Mon Sep 17 00:00:00 2001 From: Byteflux 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 7242d45..ab4de94 100644 --- a/src/main/java/net/minecraft/server/Chunk.java +++ b/src/main/java/net/minecraft/server/Chunk.java @@ -11,6 +11,8 @@ 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; @@ -43,6 +45,10 @@ public class Chunk { private int v; private ConcurrentLinkedQueue w; protected gnu.trove.map.hash.TObjectIntHashMap entityCount = new gnu.trove.map.hash.TObjectIntHashMap(); // 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; @@ -274,7 +280,7 @@ 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 975d666..ae0f276 100644 --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java @@ -53,6 +53,12 @@ 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 b681a9f..8ee0cec 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java @@ -18,6 +18,12 @@ import org.bukkit.generator.ChunkGenerator; import java.util.*; import java.util.concurrent.Callable; +// PaperSpigot start +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import com.google.common.util.concurrent.ThreadFactoryBuilder; +// PaperSpigot end + // CraftBukkit start // CraftBukkit end @@ -126,6 +132,7 @@ 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 static long chunkToKey(int x, int z) { @@ -493,7 +500,7 @@ public abstract class World implements IBlockAccess { 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 } } @@ -2308,10 +2315,10 @@ 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; } @@ -2358,10 +2365,10 @@ public abstract class World implements IBlockAccess { } } - public boolean c(EnumSkyBlock enumskyblock, BlockPosition blockposition) { + public boolean c(EnumSkyBlock enumskyblock, BlockPosition blockposition, Chunk chunk, List 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)*/) { + //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 { @@ -2479,11 +2486,66 @@ public abstract class World implements IBlockAccess { } } + // 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 neighbors = new ArrayList(); + 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 bcd8b65..fa9ae6c 100644 --- a/src/main/java/org/github/paperspigot/PaperSpigotWorldConfig.java +++ b/src/main/java/org/github/paperspigot/PaperSpigotWorldConfig.java @@ -244,4 +244,11 @@ public class PaperSpigotWorldConfig log( "WorldServer TickNextTick cap set at " + tickNextTickCap ); log( "WorldServer TickNextTickList cap always processes redstone: " + tickNextTickListCapIgnoresRedstone ); } + + public boolean useAsyncLighting; + private void useAsyncLighting() + { + useAsyncLighting = getBoolean( "use-async-lighting", false ); + log( "World async lighting: " + useAsyncLighting ); + } } -- 1.9.5.msysgit.1