From 678928ad40e27acfde18750dfa36f325e677ffca Mon Sep 17 00:00:00 2001 From: Ross Allan Date: Tue, 5 Feb 2013 23:36:34 +0000 Subject: [PATCH] Don't attempt to notify chunk updates while generating Signed-off-by: Ross Allan --- .../patched/PatchChunkProviderServer.java | 61 ++++++++++--------- .../patched/PatchPlayerManagerForge.java | 5 +- .../me/nallar/patched/PatchWorldServer.java | 22 +++++++ 3 files changed, 58 insertions(+), 30 deletions(-) diff --git a/src/common/me/nallar/patched/PatchChunkProviderServer.java b/src/common/me/nallar/patched/PatchChunkProviderServer.java index 340b525d..8e2ddfe9 100644 --- a/src/common/me/nallar/patched/PatchChunkProviderServer.java +++ b/src/common/me/nallar/patched/PatchChunkProviderServer.java @@ -192,42 +192,47 @@ public Chunk loadChunk(int x, int z) { // Lock the generation lock - ChunkProviderGenerate isn't threadsafe at all // TODO: Possibly make ChunkProviderGenerate threadlocal? Would need many changes to // structure code to get it to work properly. - synchronized (genLock) { - synchronized (lock) { - var5 = (Chunk) this.loadedChunkHashMap.getValueByKey(var3); - if (var5 != null) { - return var5; - } - var5 = (Chunk) this.loadingChunkHashMap.getValueByKey(var3); - if (var5 == null) { - if (this.currentChunkProvider == null) { - var5 = this.defaultEmptyChunk; + try { + synchronized (genLock) { + synchronized (lock) { + worldObj.worldGenInProgress.set(true); + var5 = (Chunk) this.loadedChunkHashMap.getValueByKey(var3); + if (var5 != null) { + return var5; + } + var5 = (Chunk) this.loadingChunkHashMap.getValueByKey(var3); + if (var5 == null) { + if (this.currentChunkProvider == null) { + var5 = this.defaultEmptyChunk; + } else { + try { + var5 = this.currentChunkProvider.provideChunk(x, z); + } catch (Throwable var9) { + Log.severe("Failed to generate a chunk in " + Log.name(worldObj) + " at chunk coords " + x + ',' + z); + UnsafeAccess.$.throwException(var9); + } + } } else { - try { - var5 = this.currentChunkProvider.provideChunk(x, z); - } catch (Throwable var9) { - Log.severe("Failed to generate a chunk in " + Log.name(worldObj) + " at chunk coords " + x + ',' + z); - UnsafeAccess.$.throwException(var9); + if (this.currentChunkProvider != null) { + this.currentChunkProvider.recreateStructures(x, z); } } - } else { - if (this.currentChunkProvider != null) { - this.currentChunkProvider.recreateStructures(x, z); + + if (var5 == null) { + throw new IllegalStateException("Null chunk was provided!"); } - } - if (var5 == null) { - throw new IllegalStateException("Null chunk was provided!"); - } + this.loadingChunkHashMap.remove(var3); + this.loadedChunkHashMap.add(var3, var5); + synchronized (loadedChunks) { + this.loadedChunks.add(var5); + } - this.loadingChunkHashMap.remove(var3); - this.loadedChunkHashMap.add(var3, var5); - synchronized (loadedChunks) { - this.loadedChunks.add(var5); + var5.populateChunk(this, this, x, z); } - - var5.populateChunk(this, this, x, z); } + } finally { + worldObj.worldGenInProgress.set(false); } // TODO: Do initial mob spawning here - doing it while locked is stupid and can cause deadlocks with some bukkit plugins diff --git a/src/common/me/nallar/patched/PatchPlayerManagerForge.java b/src/common/me/nallar/patched/PatchPlayerManagerForge.java index b2acbb68..347390b2 100644 --- a/src/common/me/nallar/patched/PatchPlayerManagerForge.java +++ b/src/common/me/nallar/patched/PatchPlayerManagerForge.java @@ -5,15 +5,16 @@ import me.nallar.tickthreading.Log; import me.nallar.tickthreading.patcher.Declare; +import me.nallar.tickthreading.util.concurrent.TwoWayReentrantReadWriteLock; import net.minecraft.server.management.PlayerInstance; import net.minecraft.server.management.PlayerManager; import net.minecraft.world.WorldServer; public abstract class PatchPlayerManagerForge extends PlayerManager { @Declare - public java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock playerUpdateLock_; + public java.util.concurrent.locks.Lock playerUpdateLock_; @Declare - public java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock playersUpdateLock_; + public java.util.concurrent.locks.Lock playersUpdateLock_; public void construct() { ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(); diff --git a/src/common/me/nallar/patched/PatchWorldServer.java b/src/common/me/nallar/patched/PatchWorldServer.java index dd609756..4cc8b990 100644 --- a/src/common/me/nallar/patched/PatchWorldServer.java +++ b/src/common/me/nallar/patched/PatchWorldServer.java @@ -21,6 +21,7 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.util.ReportedException; import net.minecraft.world.ChunkCoordIntPair; +import net.minecraft.world.IWorldAccess; import net.minecraft.world.NextTickListEntry; import net.minecraft.world.SpawnerAnimals; import net.minecraft.world.Teleporter; @@ -37,6 +38,8 @@ public abstract class PatchWorldServer extends WorldServer implements Runnable { private ThreadManager threadManager; private ThreadLocal randoms; @Declare + public ThreadLocal worldGenInProgress_; + @Declare public int tickCount_; public PatchWorldServer(MinecraftServer par1MinecraftServer, ISaveHandler par2ISaveHandler, String par3Str, int par4, WorldSettings par5WorldSettings, Profiler par6Profiler) { @@ -48,6 +51,7 @@ public void construct() { threadManager = new ThreadManager(TickThreading.instance.getThreadCount(), "Chunk Updates for " + Log.name(this)); field_73064_N = null; pendingTickListEntries = new TreeHashSet(); + worldGenInProgress = new BooleanThreadLocal(); } @Override @@ -376,4 +380,22 @@ public Random initialValue() { return new Random(); } } + + @Override + public void markBlockForUpdate(int par1, int par2, int par3) + { + if (!worldGenInProgress.get()) { + for (int var4 = 0; var4 < this.worldAccesses.size(); ++var4) + { + ((IWorldAccess)this.worldAccesses.get(var4)).markBlockForUpdate(par1, par2, par3); + } + } + } + + public static class BooleanThreadLocal extends ThreadLocal { + @Override + public Boolean initialValue() { + return false; + } + } }