From eb49ce845d69c51a0e3932f1458167be5b9b6a4a Mon Sep 17 00:00:00 2001 From: Sergey Shatunov Date: Wed, 6 Jan 2016 01:53:42 +0700 Subject: [PATCH] Make light asynchronous (close #231) --- .../network/NetworkManager.java.patch | 2 +- patches/net/minecraft/world/World.java.patch | 116 +++++++++++++++--- .../minecraft/world/chunk/Chunk.java.patch | 101 ++++++++++++--- .../world/gen/ChunkProviderServer.java.patch | 99 ++++++++++----- .../common/chunkio/ChunkIOProvider.java.patch | 18 ++- .../java/org/spigotmc/SpigotWorldConfig.java | 7 ++ 6 files changed, 277 insertions(+), 66 deletions(-) diff --git a/patches/net/minecraft/network/NetworkManager.java.patch b/patches/net/minecraft/network/NetworkManager.java.patch index e902315..64181b2 100644 --- a/patches/net/minecraft/network/NetworkManager.java.patch +++ b/patches/net/minecraft/network/NetworkManager.java.patch @@ -64,7 +64,7 @@ public void scheduleOutboundPacket(Packet p_150725_1_, GenericFutureListener ... p_150725_2_) { -+ if (p_150725_1_ == null || !field_152463_r) return; ++ if (p_150725_1_ == null) return; if (this.channel != null && this.channel.isOpen()) { this.flushOutboundQueue(); diff --git a/patches/net/minecraft/world/World.java.patch b/patches/net/minecraft/world/World.java.patch index 25d5987..d10e86c 100644 --- a/patches/net/minecraft/world/World.java.patch +++ b/patches/net/minecraft/world/World.java.patch @@ -1036,7 +1036,7 @@ } public void updateEntity(Entity p_72870_1_) -@@ -2036,21 +2609,33 @@ +@@ -2036,21 +2609,36 @@ public void updateEntityWithOptionalForce(Entity p_72866_1_, boolean p_72866_2_) { @@ -1045,7 +1045,11 @@ int j = MathHelper.floor_double(p_72866_1_.posZ); boolean isForced = getPersistentChunks().containsKey(new ChunkCoordIntPair(i >> 4, j >> 4)); byte b0 = isForced ? (byte)0 : 32; - boolean canUpdate = !p_72866_2_ || this.checkChunksExist(i - b0, 0, j - b0, i + b0, 0, j + b0); +- boolean canUpdate = !p_72866_2_ || this.checkChunksExist(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); ++ boolean canUpdate = !p_72866_2_ || (startingChunk != null && startingChunk.areNeighborsLoaded(2)); ++ // CraftBukkit end + boolean forceUpdate = false; // Cauldron if (!canUpdate) @@ -1071,7 +1075,7 @@ p_72866_1_.lastTickPosX = p_72866_1_.posX; p_72866_1_.lastTickPosY = p_72866_1_.posY; p_72866_1_.lastTickPosZ = p_72866_1_.posZ; -@@ -2134,6 +2719,7 @@ +@@ -2134,6 +2722,7 @@ p_72866_1_.riddenByEntity = null; } } @@ -1079,7 +1083,7 @@ } } -@@ -2570,7 +3156,7 @@ +@@ -2570,7 +3159,7 @@ return; } @@ -1088,7 +1092,7 @@ { if (this.field_147481_N) { -@@ -2718,7 +3304,15 @@ +@@ -2718,7 +3307,15 @@ if (i <= 0) { @@ -1105,7 +1109,7 @@ } } -@@ -2754,7 +3348,15 @@ +@@ -2754,7 +3351,15 @@ if (j <= 0) { @@ -1122,7 +1126,7 @@ } } -@@ -2777,8 +3379,41 @@ +@@ -2777,8 +3382,41 @@ protected void setActivePlayerChunksAndCheckLight() { this.activeChunkSet.clear(); @@ -1165,7 +1169,7 @@ int i; EntityPlayer entityplayer; int j; -@@ -2788,17 +3423,28 @@ +@@ -2788,17 +3426,28 @@ for (i = 0; i < this.playerEntities.size(); ++i) { entityplayer = (EntityPlayer)this.playerEntities.get(i); @@ -1200,7 +1204,7 @@ } this.theProfiler.endSection(); -@@ -2810,7 +3456,7 @@ +@@ -2810,7 +3459,7 @@ this.theProfiler.startSection("playerCheckLight"); @@ -1209,7 +1213,36 @@ { i = this.rand.nextInt(this.playerEntities.size()); entityplayer = (EntityPlayer)this.playerEntities.get(i); -@@ -3284,8 +3930,21 @@ +@@ -3034,9 +3683,9 @@ + } + } + +- public boolean updateLightByType(EnumSkyBlock p_147463_1_, int p_147463_2_, int p_147463_3_, int p_147463_4_) ++ public boolean updateLightByType(EnumSkyBlock p_147463_1_, int p_147463_2_, int p_147463_3_, int p_147463_4_, Chunk chunk, List neighbors) + { +- if (!this.doChunksNearChunkExist(p_147463_2_, p_147463_3_, p_147463_4_, 17)) ++ if (chunk == null) // CraftBukkit / PaperSpigot + { + return false; + } +@@ -3166,6 +3815,16 @@ + } + } + ++ // PaperSpigot start - Asynchronous light updates ++ if (chunk.worldObj.spigotConfig.useAsyncLighting) { ++ chunk.pendingLightUpdates.decrementAndGet(); ++ if (neighbors != null) { ++ for (Chunk neighbor : neighbors) { ++ neighbor.pendingLightUpdates.decrementAndGet(); ++ } ++ } ++ } ++ // PaperSpigot end + this.theProfiler.endSection(); + return true; + } +@@ -3284,8 +3943,21 @@ { Entity entity = (Entity)this.loadedEntityList.get(j); @@ -1232,7 +1265,7 @@ ++i; } } -@@ -3298,6 +3957,7 @@ +@@ -3298,6 +3970,7 @@ for (int i = 0; i < p_72868_1_.size(); ++i) { Entity entity = (Entity)p_72868_1_.get(i); @@ -1240,7 +1273,7 @@ if (!MinecraftForge.EVENT_BUS.post(new EntityJoinWorldEvent(entity, this))) { loadedEntityList.add(entity); -@@ -3314,8 +3974,17 @@ +@@ -3314,8 +3987,17 @@ public boolean canPlaceEntityOnSide(Block p_147472_1_, int p_147472_2_, int p_147472_3_, int p_147472_4_, boolean p_147472_5_, int p_147472_6_, Entity p_147472_7_, ItemStack p_147472_8_) { Block block1 = this.getBlock(p_147472_2_, p_147472_3_, p_147472_4_); @@ -1259,7 +1292,7 @@ } public PathEntity getPathEntityToEntity(Entity p_72865_1_, Entity p_72865_2_, float p_72865_3_, boolean p_72865_4_, boolean p_72865_5_, boolean p_72865_6_, boolean p_72865_7_) -@@ -3464,6 +4133,12 @@ +@@ -3464,6 +4146,12 @@ for (int i = 0; i < this.playerEntities.size(); ++i) { EntityPlayer entityplayer1 = (EntityPlayer)this.playerEntities.get(i); @@ -1272,7 +1305,7 @@ double d5 = entityplayer1.getDistanceSq(p_72977_1_, p_72977_3_, p_72977_5_); if ((p_72977_7_ < 0.0D || d5 < p_72977_7_ * p_72977_7_) && (d4 == -1.0D || d5 < d4)) -@@ -3489,7 +4164,12 @@ +@@ -3489,7 +4177,12 @@ for (int i = 0; i < this.playerEntities.size(); ++i) { EntityPlayer entityplayer1 = (EntityPlayer)this.playerEntities.get(i); @@ -1286,7 +1319,7 @@ if (!entityplayer1.capabilities.disableDamage && entityplayer1.isEntityAlive()) { double d5 = entityplayer1.getDistanceSq(p_72846_1_, p_72846_3_, p_72846_5_); -@@ -3660,6 +4340,18 @@ +@@ -3660,6 +4353,18 @@ public void updateAllPlayersSleepingFlag() {} @@ -1305,7 +1338,7 @@ public float getWeightedThunderStrength(float p_72819_1_) { return (this.prevThunderingStrength + (this.thunderingStrength - this.prevThunderingStrength) * p_72819_1_) * this.getRainStrength(p_72819_1_); -@@ -3932,8 +4624,8 @@ +@@ -3932,8 +4637,8 @@ */ public void addTileEntity(TileEntity entity) { @@ -1316,7 +1349,7 @@ { dest.add(entity); } -@@ -4029,4 +4721,73 @@ +@@ -4029,4 +4734,122 @@ } return count; } @@ -1389,4 +1422,53 @@ + return provider.dimensionId == Integer.MIN_VALUE; // Mystcraft + } + // Cauldron end ++ ++ public Chunk getChunkIfLoaded(int x, int z) { ++ return ((ChunkProviderServer) this.chunkProvider).getChunkIfLoaded(x, z); ++ } ++ ++ public java.util.concurrent.ExecutorService lightingExecutor = java.util.concurrent.Executors.newSingleThreadExecutor(new com.google.common.util.concurrent.ThreadFactoryBuilder().setNameFormat("PaperSpigot - Lighting Thread").build()); // PaperSpigot - Asynchronous lighting updates ++ ++ /** ++ * PaperSpigot - Asynchronous lighting updates ++ */ ++ public boolean updateLightByType(final EnumSkyBlock enumskyblock, final int x, final int y, final int z) { ++ final Chunk chunk = this.getChunkIfLoaded(x >> 4, z >> 4); ++ if (chunk == null || !chunk.areNeighborsLoaded(1)) { ++ return false; ++ } ++ ++ if (!chunk.worldObj.spigotConfig.useAsyncLighting) { ++ return this.updateLightByType(enumskyblock, x, y, z, chunk, null); ++ } ++ ++ chunk.pendingLightUpdates.incrementAndGet(); ++ chunk.lightUpdateTime = chunk.worldObj.getTotalWorldTime(); ++ ++ 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 (cx != x >> 4 && cz != z >> 4) { ++ Chunk neighbor = this.getChunkIfLoaded(cx, cz); ++ if (neighbor != null) { ++ neighbor.pendingLightUpdates.incrementAndGet(); ++ neighbor.lightUpdateTime = chunk.worldObj.getTotalWorldTime(); ++ neighbors.add(neighbor); ++ } ++ } ++ } ++ } ++ ++ if (!Bukkit.isPrimaryThread()) { ++ return this.updateLightByType(enumskyblock, x, y, z, chunk, neighbors); ++ } ++ ++ lightingExecutor.submit(new Runnable() { ++ @Override ++ public void run() { ++ World.this.updateLightByType(enumskyblock, x, y, z, chunk, neighbors); ++ } ++ }); ++ return true; ++ } } diff --git a/patches/net/minecraft/world/chunk/Chunk.java.patch b/patches/net/minecraft/world/chunk/Chunk.java.patch index b3cb8a3..683d166 100644 --- a/patches/net/minecraft/world/chunk/Chunk.java.patch +++ b/patches/net/minecraft/world/chunk/Chunk.java.patch @@ -18,16 +18,50 @@ public class Chunk { private static final Logger logger = LogManager.getLogger(); -@@ -62,6 +73,8 @@ +@@ -62,8 +73,42 @@ public int heightMapMinimum; public long inhabitedTime; private int queuedLightChecks; + public gnu.trove.map.hash.TObjectIntHashMap entityCount = new gnu.trove.map.hash.TObjectIntHashMap(); // Spigot (Cauldron protected -> public) ++ // PaperSpigot start - Asynchronous light updates ++ public java.util.concurrent.atomic.AtomicInteger pendingLightUpdates = new java.util.concurrent.atomic.AtomicInteger(); ++ public long lightUpdateTime; ++ // PaperSpigot end + public int lastAccessedTick; // Cauldron track last time the chunk was accessed private static final String __OBFID = "CL_00000373"; ++ // 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 p_i1995_1_, int p_i1995_2_, int p_i1995_3_) -@@ -80,13 +93,22 @@ + { + this.storageArrays = new ExtendedBlockStorage[16]; +@@ -80,13 +125,22 @@ for (int k = 0; k < this.entityLists.length; ++k) { @@ -51,7 +85,7 @@ public Chunk(World p_i45446_1_, Block[] p_i45446_2_, int p_i45446_3_, int p_i45446_4_) { this(p_i45446_1_, p_i45446_3_, p_i45446_4_); -@@ -512,10 +534,10 @@ +@@ -512,10 +566,10 @@ if (extendedblockstorage != null) { @@ -65,7 +99,7 @@ catch (Throwable throwable) { CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Getting block"); -@@ -529,7 +551,7 @@ +@@ -529,7 +583,7 @@ } }); throw new ReportedException(crashreport); @@ -74,7 +108,7 @@ } } -@@ -589,9 +611,10 @@ +@@ -589,9 +643,10 @@ if (!this.worldObj.isRemote) { @@ -86,7 +120,7 @@ extendedblockstorage.func_150818_a(p_150807_1_, p_150807_2_ & 15, p_150807_3_, p_150807_4_); extendedblockstorage.setExtBlockMetadata(p_150807_1_, p_150807_2_ & 15, p_150807_3_, p_150807_5_); // This line duplicates the one below, so breakBlock fires with valid worldstate -@@ -777,8 +800,20 @@ +@@ -777,8 +832,20 @@ if (i != this.xPosition || j != this.zPosition) { @@ -109,7 +143,7 @@ } int k = MathHelper.floor_double(p_76612_1_.posY / 16.0D); -@@ -799,6 +834,26 @@ +@@ -799,6 +866,26 @@ p_76612_1_.chunkCoordY = k; p_76612_1_.chunkCoordZ = this.zPosition; this.entityLists[k].add(p_76612_1_); @@ -136,7 +170,7 @@ } public void removeEntity(Entity p_76622_1_) -@@ -819,6 +874,26 @@ +@@ -819,6 +906,26 @@ } this.entityLists[p_76608_2_].remove(p_76608_1_); @@ -163,7 +197,7 @@ } public boolean canBlockSeeTheSky(int p_76619_1_, int p_76619_2_, int p_76619_3_) -@@ -874,9 +949,23 @@ +@@ -874,9 +981,23 @@ p_150812_4_.xCoord = this.xPosition * 16 + p_150812_1_; p_150812_4_.yCoord = p_150812_2_; p_150812_4_.zCoord = this.zPosition * 16 + p_150812_3_; @@ -188,7 +222,7 @@ { if (this.chunkTileEntityMap.containsKey(chunkposition)) { -@@ -886,6 +975,16 @@ +@@ -886,6 +1007,16 @@ p_150812_4_.validate(); this.chunkTileEntityMap.put(chunkposition, p_150812_4_); } @@ -205,7 +239,7 @@ } public void removeTileEntity(int p_150805_1_, int p_150805_2_, int p_150805_3_) -@@ -936,6 +1035,21 @@ +@@ -936,6 +1067,21 @@ for (int i = 0; i < this.entityLists.length; ++i) { @@ -227,7 +261,7 @@ this.worldObj.unloadEntities(this.entityLists[i]); } MinecraftForge.EVENT_BUS.post(new ChunkEvent.Unload(this)); -@@ -1025,7 +1139,7 @@ +@@ -1025,7 +1171,7 @@ public Random getRandomWithSeed(long p_76617_1_) { @@ -236,7 +270,7 @@ } public boolean isEmpty() -@@ -1035,6 +1149,7 @@ +@@ -1035,6 +1181,7 @@ public void populateChunk(IChunkProvider p_76624_1_, IChunkProvider p_76624_2_, int p_76624_3_, int p_76624_4_) { @@ -244,7 +278,7 @@ if (!this.isTerrainPopulated && p_76624_1_.chunkExists(p_76624_3_ + 1, p_76624_4_ + 1) && p_76624_1_.chunkExists(p_76624_3_, p_76624_4_ + 1) && p_76624_1_.chunkExists(p_76624_3_ + 1, p_76624_4_)) { p_76624_1_.populate(p_76624_2_, p_76624_3_, p_76624_4_); -@@ -1054,6 +1169,7 @@ +@@ -1054,6 +1201,7 @@ { p_76624_1_.populate(p_76624_2_, p_76624_3_ - 1, p_76624_4_ - 1); } @@ -252,7 +286,16 @@ } public int getPrecipitationHeight(int p_76626_1_, int p_76626_2_) -@@ -1184,8 +1300,10 @@ +@@ -1091,7 +1239,7 @@ + { + if (this.isGapLightingUpdated && !this.worldObj.provider.hasNoSky && !p_150804_1_) + { +- this.recheckGaps(this.worldObj.isRemote); ++ this.recheckGapsAsync(this.worldObj.isRemote); + } + + this.field_150815_m = true; +@@ -1184,8 +1332,10 @@ if ((p_76607_2_ & 1 << l) != 0 && this.storageArrays[l] != null) { nibblearray = this.storageArrays[l].getMetadataArray(); @@ -265,7 +308,7 @@ } } -@@ -1194,8 +1312,10 @@ +@@ -1194,8 +1344,10 @@ if ((p_76607_2_ & 1 << l) != 0 && this.storageArrays[l] != null) { nibblearray = this.storageArrays[l].getBlocklightArray(); @@ -278,7 +321,7 @@ } } -@@ -1206,8 +1326,10 @@ +@@ -1206,8 +1358,10 @@ if ((p_76607_2_ & 1 << l) != 0 && this.storageArrays[l] != null) { nibblearray = this.storageArrays[l].getSkylightArray(); @@ -291,7 +334,7 @@ } } } -@@ -1229,8 +1351,8 @@ +@@ -1229,8 +1383,8 @@ nibblearray = this.storageArrays[l].createBlockMSBArray(); } @@ -302,3 +345,25 @@ } } else if (p_76607_4_ && this.storageArrays[l] != null && this.storageArrays[l].getBlockMSBArray() != null) +@@ -1523,4 +1677,21 @@ + } + } + } ++ ++ /** ++ * PaperSpigot - Recheck gaps asynchronously. ++ */ ++ public void recheckGapsAsync(final boolean isStatic) { ++ if (!worldObj.spigotConfig.useAsyncLighting) { ++ this.recheckGaps(isStatic); ++ return; ++ } ++ ++ worldObj.lightingExecutor.submit(new Runnable() { ++ @Override ++ public void run() { ++ Chunk.this.recheckGaps(isStatic); ++ } ++ }); ++ } + } diff --git a/patches/net/minecraft/world/gen/ChunkProviderServer.java.patch b/patches/net/minecraft/world/gen/ChunkProviderServer.java.patch index f4b1663..b482d0d 100644 --- a/patches/net/minecraft/world/gen/ChunkProviderServer.java.patch +++ b/patches/net/minecraft/world/gen/ChunkProviderServer.java.patch @@ -80,7 +80,7 @@ this.defaultEmptyChunk = new EmptyChunk(p_i1520_1_, 0, 0); this.worldObj = p_i1520_1_; this.currentChunkLoader = p_i1520_2_; -@@ -57,10 +94,10 @@ +@@ -57,16 +94,22 @@ public boolean chunkExists(int p_73149_1_, int p_73149_2_) { @@ -93,7 +93,19 @@ { return this.loadedChunks; } -@@ -74,26 +111,45 @@ + + public void unloadChunksIfNotNearSpawn(int p_73241_1_, int p_73241_2_) + { ++ // PaperSpigot start - Asynchronous lighting updates ++ Chunk chunk = this.loadedChunkHashMap_KC.get(LongHash.toLong(p_73241_1_, p_73241_2_)); ++ if (chunk != null && chunk.worldObj.spigotConfig.useAsyncLighting && (chunk.pendingLightUpdates.get() > 0 || chunk.worldObj.getTotalWorldTime() - chunk.lightUpdateTime < 20)) { ++ return; ++ } ++ // PaperSpigot end + if (this.worldObj.provider.canRespawnHere() && DimensionManager.shouldLoadSpawn(this.worldObj.provider.dimensionId)) + { + ChunkCoordinates chunkcoordinates = this.worldObj.getSpawnPoint(); +@@ -74,26 +117,49 @@ int l = p_73241_2_ * 16 + 8 - chunkcoordinates.posZ; short short1 = 128; @@ -132,12 +144,6 @@ public void unloadAllChunks() { - Iterator iterator = this.loadedChunks.iterator(); -- -- while (iterator.hasNext()) -- { -- Chunk chunk = (Chunk)iterator.next(); -- this.unloadChunksIfNotNearSpawn(chunk.xPosition, chunk.zPosition); -- } + this.loadedChunkHashMap_KC.forEachValue(new TObjectProcedure() { + @Override + public boolean execute(Chunk chunk) { @@ -145,10 +151,19 @@ + return true; + } + }); ++ } + +- while (iterator.hasNext()) +- { +- Chunk chunk = (Chunk)iterator.next(); +- this.unloadChunksIfNotNearSpawn(chunk.xPosition, chunk.zPosition); +- } ++ public Chunk getChunkIfLoaded(int x, int z) { ++ return this.loadedChunkHashMap_KC.get(LongHash.toLong(x, z)); } public Chunk loadChunk(int p_73158_1_, int p_73158_2_) -@@ -103,9 +159,9 @@ +@@ -103,9 +169,9 @@ public Chunk loadChunk(int par1, int par2, Runnable runnable) { @@ -161,7 +176,7 @@ AnvilChunkLoader loader = null; if (this.currentChunkLoader instanceof AnvilChunkLoader) -@@ -113,6 +169,8 @@ +@@ -113,6 +179,8 @@ loader = (AnvilChunkLoader) this.currentChunkLoader; } @@ -170,7 +185,7 @@ // We can only use the queue for already generated chunks if (chunk == null && loader != null && loader.chunkExists(this.worldObj, par1, par2)) { -@@ -142,18 +200,19 @@ +@@ -142,18 +210,19 @@ public Chunk originalLoadChunk(int p_73158_1_, int p_73158_2_) { @@ -195,7 +210,7 @@ if (chunk == null) { chunk = this.safeLoadChunk(p_73158_1_, p_73158_2_); -@@ -176,18 +235,39 @@ +@@ -176,18 +245,53 @@ CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Exception generating new chunk"); CrashReportCategory crashreportcategory = crashreport.makeCategory("Chunk to be generated"); crashreportcategory.addCrashSection("Location", String.format("%d,%d", new Object[] {Integer.valueOf(p_73158_1_), Integer.valueOf(p_73158_2_)})); @@ -234,13 +249,27 @@ + 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.xPosition + x, chunk.zPosition + z); ++ if (neighbor != null) { ++ neighbor.setNeighborLoaded(-x, -z); ++ chunk.setNeighborLoaded(x, z); ++ } ++ } ++ } + // CraftBukkit end chunk.populateChunk(this, this, p_73158_1_, p_73158_2_); + worldObj.timings.syncChunkLoadTimer.stopTiming(); // Spigot } return chunk; -@@ -195,11 +275,29 @@ +@@ -195,11 +299,29 @@ public Chunk provideChunk(int p_73154_1_, int p_73154_2_) { @@ -273,7 +302,7 @@ { if (this.currentChunkLoader == null) { -@@ -209,6 +307,7 @@ +@@ -209,6 +331,7 @@ { try { @@ -281,7 +310,7 @@ Chunk chunk = this.currentChunkLoader.loadChunk(this.worldObj, p_73239_1_, p_73239_2_); if (chunk != null) -@@ -217,8 +316,11 @@ +@@ -217,8 +340,11 @@ if (this.currentChunkProvider != null) { @@ -293,7 +322,7 @@ } return chunk; -@@ -231,7 +333,7 @@ +@@ -231,7 +357,7 @@ } } @@ -302,7 +331,7 @@ { if (this.currentChunkLoader != null) { -@@ -246,7 +348,7 @@ +@@ -246,7 +372,7 @@ } } @@ -311,7 +340,7 @@ { if (this.currentChunkLoader != null) { -@@ -254,15 +356,18 @@ +@@ -254,15 +380,18 @@ { p_73242_1_.lastSaveTime = this.worldObj.getTotalWorldTime(); this.currentChunkLoader.saveChunk(this.worldObj, p_73242_1_); @@ -331,7 +360,7 @@ } } -@@ -277,6 +382,35 @@ +@@ -277,6 +406,35 @@ if (this.currentChunkProvider != null) { this.currentChunkProvider.populate(p_73153_1_, p_73153_2_, p_73153_3_); @@ -367,7 +396,7 @@ GameRegistry.generateWorld(p_73153_2_, p_73153_3_, worldObj, currentChunkProvider, p_73153_1_); chunk.setChunkModified(); } -@@ -286,11 +420,13 @@ +@@ -286,11 +444,13 @@ public boolean saveChunks(boolean p_73151_1_, IProgressUpdate p_73151_2_) { int i = 0; @@ -384,7 +413,7 @@ if (p_73151_1_) { -@@ -325,36 +461,60 @@ +@@ -325,36 +485,73 @@ { if (!this.worldObj.levelSaving) { @@ -426,8 +455,6 @@ - if(loadedChunks.size() == 0 && ForgeChunkManager.getPersistentChunksFor(this.worldObj).size() == 0 && !DimensionManager.shouldLoadSpawn(this.worldObj.provider.dimensionId)){ - DimensionManager.unloadWorld(this.worldObj.provider.dimensionId); - return currentChunkProvider.unloadQueuedChunks(); -- } -- } + // Cauldron static - check if the chunk was accessed recently and keep it loaded if there are players in world + /*if (!shouldUnloadChunk(chunk) && this.worldObj.playerEntities.size() > 0) + { @@ -435,9 +462,7 @@ + continue; + }*/ + // Cauldron end - -- this.chunksToUnload.remove(olong); -- this.loadedChunkHashMap.remove(olong.longValue()); ++ + + ChunkUnloadEvent event = new ChunkUnloadEvent(chunk.bukkitChunk); + server.getPluginManager().callEvent(event); @@ -449,7 +474,23 @@ + chunk.onChunkUnload(); + this.safeSaveChunk(chunk); + this.safeSaveExtraChunkData(chunk); -+ // this.unloadQueue.remove(olong); ++ // 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.xPosition + x, chunk.zPosition + z); ++ if (neighbor != null) { ++ neighbor.setNeighborUnloaded(-x, -z); ++ chunk.setNeighborUnloaded(x, z); ++ } + } + } +- +- this.chunksToUnload.remove(olong); +- this.loadedChunkHashMap.remove(olong.longValue()); + this.loadedChunkHashMap_KC.remove(chunkcoordinates); // CraftBukkit + this.loadedChunks.remove(chunk); // Cauldron - vanilla compatibility + ForgeChunkManager.putDormantChunk(chunkcoordinates, chunk); @@ -465,7 +506,7 @@ if (this.currentChunkLoader != null) { this.currentChunkLoader.chunkTick(); -@@ -371,7 +531,7 @@ +@@ -371,7 +568,7 @@ public String makeString() { @@ -474,7 +515,7 @@ } public List getPossibleCreatures(EnumCreatureType p_73155_1_, int p_73155_2_, int p_73155_3_, int p_73155_4_) -@@ -386,8 +546,31 @@ +@@ -386,8 +583,31 @@ public int getLoadedChunkCount() { diff --git a/patches/net/minecraftforge/common/chunkio/ChunkIOProvider.java.patch b/patches/net/minecraftforge/common/chunkio/ChunkIOProvider.java.patch index b97f5fb..8ab053a 100644 --- a/patches/net/minecraftforge/common/chunkio/ChunkIOProvider.java.patch +++ b/patches/net/minecraftforge/common/chunkio/ChunkIOProvider.java.patch @@ -10,7 +10,7 @@ class ChunkIOProvider implements AsynchronousExecutor.CallBackProvider { private final AtomicInteger threadNumber = new AtomicInteger(1); -@@ -41,13 +44,20 @@ +@@ -41,14 +44,36 @@ queuedChunk.loader.loadEntities(queuedChunk.world, queuedChunk.compound.getCompoundTag("Level"), chunk); MinecraftForge.EVENT_BUS.post(new ChunkDataEvent.Load(chunk, queuedChunk.compound)); // Don't call ChunkDataEvent.Load async chunk.lastSaveTime = queuedChunk.provider.worldObj.getTotalWorldTime(); @@ -30,5 +30,21 @@ + 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; ++ } ++ ++ net.minecraft.world.chunk.Chunk neighbor = queuedChunk.provider.getChunkIfLoaded(chunk.xPosition + x, chunk.zPosition + z); ++ if (neighbor != null) { ++ neighbor.setNeighborLoaded(-x, -z); ++ chunk.setNeighborLoaded(x, z); ++ } ++ } ++ } ++ chunk.populateChunk(queuedChunk.provider, queuedChunk.provider, queuedChunk.x, queuedChunk.z); } + diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java index 60f8ae8..86f60df 100644 --- a/src/main/java/org/spigotmc/SpigotWorldConfig.java +++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java @@ -298,4 +298,11 @@ public class SpigotWorldConfig maxTntTicksPerTick = getInt( "max-tnt-per-tick", 100 ); log( "Max TNT Explosions: " + maxTntTicksPerTick ); } + + public boolean useAsyncLighting; + private void useAsyncLighting() + { + useAsyncLighting = getBoolean( "use-async-lighting", true ); + log( "World async lighting: " + useAsyncLighting ); + } }