package kcauldron; import java.util.List; import java.util.Queue; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import com.google.common.collect.Lists; import com.google.common.collect.Queues; import net.minecraft.server.MinecraftServer; import net.minecraft.util.LongHashMap; import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.gen.ChunkProviderServer; public enum ChunkGenerator { INSTANCE; private final Queue queue = Queues.newArrayDeque(); private final LongHashMap map = new LongHashMap(); private final ReadWriteLock lock = new ReentrantReadWriteLock(); public void queueChunkGeneration(ChunkProviderServer provider, int cx, int cz, ChunkCallback callback) { long key = ChunkCoordIntPair.chunkXZ2Int(cx, cz); QueuedChunk chunk; lock.readLock().lock(); try { chunk = (QueuedChunk) map.getValueByKey(key); } finally { lock.readLock().unlock(); } if (chunk != null) { chunk.callbacks.add(callback); } else { chunk = new QueuedChunk(provider, cx, cz, callback); lock.writeLock().lock(); try { map.add(key, chunk); queue.add(chunk); } finally { lock.writeLock().unlock(); } } } public void chunkGeneratorCycle() { int max = MinecraftServer.kcauldronConfig.commonMaxChunkGenPerTick.getValue(); lock.writeLock().lock(); try { for (int i = 0; i < max && internalGenerate(); i++) ; } finally { lock.writeLock().unlock(); } } public boolean generate() { lock.writeLock().lock(); try { return internalGenerate(); } finally { lock.writeLock().unlock(); } } private boolean internalGenerate() { for (QueuedChunk chunk; (chunk = queue.poll()) != null;) { map.remove(ChunkCoordIntPair.chunkXZ2Int(chunk.cx, chunk.cz)); if (chunk.provider.loadAsync(chunk.cx, chunk.cz, false, chunk)) continue; chunk.onChunkLoaded(chunk.provider.originalLoadChunk(chunk.cx, chunk.cz)); return true; } return false; } private static class QueuedChunk implements ChunkCallback { public final ChunkProviderServer provider; public final int cx; public final int cz; public final List callbacks = Lists.newArrayListWithCapacity(1); public QueuedChunk(ChunkProviderServer provider, int cx, int cz, ChunkCallback callback) { this.provider = provider; this.cx = cx; this.cz = cz; this.callbacks.add(callback); } @Override public void onChunkLoaded(Chunk chunk) { for (ChunkCallback cb : callbacks) cb.onChunkLoaded(chunk); } } }