Revert to "Island world chunk generator now pre-generates island values."

This reverts commit e40bf74cb8.
This commit is contained in:
Harrison Deng 2020-04-29 19:14:20 -05:00
parent a119e6f596
commit c6fd9a833c
2 changed files with 42 additions and 54 deletions

View File

@ -1,13 +1,17 @@
package ca.recrown.islandsurvivalcraft.caching; package ca.recrown.islandsurvivalcraft.caching;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
public class Cache<K, V> { public class Cache<K, V> {
private final int maxSize; private final int maxSize;
private final ConcurrentHashMap<K, CacheValue<K, V>> data; private final ConcurrentHashMap<K, CacheValue<K, V>> data;
private final UsageStack<K, V> usage = new UsageStack<>(); private final UsageStack<K, V> usage = new UsageStack<>();
private final ReentrantLock lock = new ReentrantLock(); private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private final WriteLock writeLock = lock.writeLock();
private final ReadLock readLock = lock.readLock();
public Cache(int maxSize) { public Cache(int maxSize) {
data = new ConcurrentHashMap<>(maxSize + 1, 0.75f, 6); data = new ConcurrentHashMap<>(maxSize + 1, 0.75f, 6);
@ -29,7 +33,7 @@ public class Cache<K, V> {
if (data.containsKey(key)) { if (data.containsKey(key)) {
data.get(key).value = value; data.get(key).value = value;
} else { } else {
lock.lock(); writeLock.lock();
try { try {
CacheValue<K, V> val = new CacheValue<>(); CacheValue<K, V> val = new CacheValue<>();
val.key = key; val.key = key;
@ -40,7 +44,7 @@ public class Cache<K, V> {
data.remove(usage.pop().key); data.remove(usage.pop().key);
} }
} finally { } finally {
lock.unlock(); writeLock.unlock();
} }
} }
} }
@ -53,9 +57,15 @@ public class Cache<K, V> {
* @return the value associated to the key. * @return the value associated to the key.
*/ */
public V get(K key) { public V get(K key) {
CacheValue<K, V> value = data.get(key); readLock.lock();
if (value == null) return null; CacheValue<K, V> value = null;
try {
if (!data.containsKey(key)) return null;
value = data.get(key);
usage.tryMoveToTop(value); usage.tryMoveToTop(value);
} finally {
readLock.unlock();
}
return value.value; return value.value;
} }
@ -63,12 +73,12 @@ public class Cache<K, V> {
* Clears the cache of all values. * Clears the cache of all values.
*/ */
public void clearCache() { public void clearCache() {
lock.lock(); writeLock.lock();
try { try {
data.clear(); data.clear();
usage.clear(); usage.clear();
} finally { } finally {
lock.unlock(); writeLock.unlock();
} }
} }
} }

View File

@ -4,6 +4,7 @@ import java.util.LinkedList;
import java.util.Random; import java.util.Random;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import org.bukkit.Chunk; import org.bukkit.Chunk;
@ -27,83 +28,60 @@ public class IslandWorldChunkGenerator extends ChunkGenerator implements Listene
private final Cache<Point2, Double> blockValueCache = new Cache<>(102400); private final Cache<Point2, Double> blockValueCache = new Cache<>(102400);
private final Cache<Point2, Biome[]> biomeCache = new Cache<>(102400); private final Cache<Point2, Biome[]> biomeCache = new Cache<>(102400);
private final Cache<Point2, Boolean> chunkExistenceCache = new Cache<>(16384); private final Cache<Point2, Boolean> chunkExistenceCache = new Cache<>(16384);
private final BiomeSelector biomeSelector = new BiomeSelector();
private final ExecutorService executor = Utilities.ISC_EXECUTOR; private final ExecutorService executor = Utilities.ISC_EXECUTOR;
private volatile World currentWorld; private volatile World currentWorld;
public IslandWorldChunkGenerator() {
biomeSelector.initialize();
}
@Override @Override
public ChunkData generateChunkData(World world, Random random, int chunkX, int chunkZ, BiomeGrid biomeGrid) { public ChunkData generateChunkData(World world, Random random, int chunkX, int chunkZ, BiomeGrid biomeGrid) {
this.currentWorld = world; this.currentWorld = world;
IslandWorldMapper mapper = new IslandWorldMapper(random, blockValueCache); IslandWorldMapper mapper = new IslandWorldMapper(random, blockValueCache);
TemperatureMapGenerator temperatureMapGenerator = new TemperatureMapGenerator(world.getSeed()); TemperatureMapGenerator temperatureMapGenerator = new TemperatureMapGenerator(world.getSeed());
WorldHeightShader heightShader = new WorldHeightShader(world.getSeed(), mapper, world.getSeaLevel(), world.getMaxHeight(), 3); BiomeSelector biomeSelector = new BiomeSelector(random);
biomeSelector.initialize();
WorldHeightShader heightShader = new WorldHeightShader(world.getSeed(), mapper, world.getSeaLevel(),
world.getMaxHeight(), 3);
BiomeGenerator biomeGenerator = new UniBiomeIslandGenerator(); BiomeGenerator biomeGenerator = new UniBiomeIslandGenerator();
int maxHeight = world.getMaxHeight(); int maxHeight = world.getMaxHeight();
LinkedList<Future<Boolean>> tasks = new LinkedList<>(); LinkedList<Future<Boolean>> tasks = new LinkedList<>();
ChunkData chunkData = createChunkData(world); ChunkData chunkData = createChunkData(world);
Future<Boolean> preLoader = executor.submit(() -> {
for (int x = 0; x < Utilities.CHUNK_SIZE; x++) {
for (int z = 0; z < Utilities.CHUNK_SIZE; z++) {
if (Thread.currentThread().isInterrupted()) return false;
mapper.getWorldBlockValue(Utilities.CHUNK_SIZE * chunkX + x, Utilities.CHUNK_SIZE * chunkZ + z);
}
}
return true;
});
Biome[][] biomes = new Biome[Utilities.CHUNK_SIZE][Utilities.CHUNK_SIZE]; Biome[][] biomes = new Biome[Utilities.CHUNK_SIZE][Utilities.CHUNK_SIZE];
for (int x = 0; x < Utilities.CHUNK_SIZE; x++) { for (int localX = 0; localX < Utilities.CHUNK_SIZE; localX++) {
for (int z = 0; z < Utilities.CHUNK_SIZE; z++) { for (int localZ = 0; localZ < Utilities.CHUNK_SIZE; localZ++) {
final int desX = x; if (biomes[localX][localZ] == null) {
final int desZ = z; biomeGenerator.generateBiomeColumn(biomes, world, chunkX, chunkZ, localX, localZ, mapper, biomeSelector,
if (biomes[desX][desZ] == null) {
biomeGenerator.generateBiomeColumn(biomes, world, chunkX, chunkZ, desX, desZ, mapper, biomeSelector,
temperatureMapGenerator, biomeCache, chunkExistenceCache); temperatureMapGenerator, biomeCache, chunkExistenceCache);
} }
if (biomes[localX][localZ] == null) throw new IllegalStateException("Biome was null.");
if (biomes[desX][desZ] == null) throw new IllegalStateException("Biome was null."); final int biomeX = localX;
final int biomeZ = localZ;
tasks.add(executor.submit(() -> { tasks.add(executor.submit(() -> {
for (int y = 0; y < maxHeight; y++) { for (int y = 0; y < maxHeight; y++) {
biomeGrid.setBiome(desX, y, desZ, biomes[desX][desZ]); biomeGrid.setBiome(biomeX, y, biomeZ, biomes[biomeX][biomeZ]);
} }
return true; return true;
})); }));
final int worldX = Utilities.CHUNK_SIZE * chunkX + desX; final int worldX = 16 * chunkX + localX;
final int worldZ = Utilities.CHUNK_SIZE * chunkZ + desZ; final int worldZ = 16 * chunkZ + localZ;
int height = heightShader.getAltitude(worldX, worldZ, biomes[desX][desZ]); int height = heightShader.getAltitude(worldX, worldZ, biomes[localX][localZ]);
chunkData.setRegion(desX, 1, desZ, desX + 1, height, desZ + 1, Material.DIAMOND_BLOCK); chunkData.setRegion(localX, 1, localZ, localX + 1, height, localZ + 1, Material.DIAMOND_BLOCK);
} }
} }
chunkData.setRegion(0, 0, 0, 16, 1, 16, Material.BEDROCK); chunkData.setRegion(0, 0, 0, 16, 1, 16, Material.BEDROCK);
preLoader.cancel(true);
try {
while (!tasks.isEmpty()) { while (!tasks.isEmpty()) {
try {
tasks.poll().get(); tasks.poll().get();
}
} catch (ExecutionException | InterruptedException e) { } catch (ExecutionException | InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
throw new IllegalStateException(e.getCause().getMessage()); throw new IllegalStateException(e.getCause().getMessage());
} }
}
return chunkData; return chunkData;
} }
@Override
public boolean canSpawn(World world, int x, int z) {
return super.canSpawn(world, x, z);
}
@Override
public boolean isParallelCapable() {
return true;
}
@EventHandler(priority = EventPriority.MONITOR) @EventHandler(priority = EventPriority.MONITOR)
public void onChunkLoaded(ChunkLoadEvent event) { public void onChunkLoaded(ChunkLoadEvent event) {
if (event.isNewChunk()) { if (event.isNewChunk()) {