Wrote a world information system and management for them.

Also large amounts of refactoring done.

The tests implement the new changes.

Island map test clears the cache now.
This commit is contained in:
Harrison Deng 2020-05-04 12:47:16 -05:00
parent fc9aca3bb1
commit 3a86bd1a12
15 changed files with 303 additions and 225 deletions

View File

@ -1,20 +1,21 @@
package ca.recrown.islandsurvivalcraft;
import org.bukkit.event.Listener;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import ca.recrown.islandsurvivalcraft.world.generation.IslandWorldChunkGenerator;
import ca.recrown.islandsurvivalcraft.world.WorldInfoManager;
public class IslandSurvivalCraft extends JavaPlugin {
public class IslandSurvivalCraft extends JavaPlugin implements Listener {
private PluginManager pluginManager;
private IslandWorldChunkGenerator chunkGenerator = new IslandWorldChunkGenerator();
private WorldInfoManager worldInfos;
@Override
public void onEnable() {
pluginManager = getServer().getPluginManager();
pluginManager.registerEvents(chunkGenerator, this);
worldInfos = new WorldInfoManager();
pluginManager.registerEvents(worldInfos, this);
super.onEnable();
}
@ -25,6 +26,7 @@ public class IslandSurvivalCraft extends JavaPlugin {
@Override
public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) {
return chunkGenerator;
return worldInfos.getChunkGenerator(getServer().getWorld(worldName));
}
}

View File

@ -6,20 +6,26 @@ import java.util.Random;
import java.util.Map.Entry;
import org.bukkit.block.Biome;
import org.bukkit.util.noise.SimplexOctaveGenerator;
import ca.recrown.islandsurvivalcraft.Utilities;
public class BiomeSelector {
private volatile boolean initialized = false;
private final HashMap<Biome, Float> lands = new HashMap<>();
public class BiomeMap {
private final SimplexOctaveGenerator noise;
private final HashMap<Biome, Float> landBiomeTemperatures = new HashMap<>();
private volatile HashMap<Float, ArrayList<Biome>> temperaturesForLand = new HashMap<>();
private final HashMap<Float, ArrayList<Biome>> temperaturePartitionedLandBiomes = new HashMap<>();
private final HashMap<Biome, Float> oceans = new HashMap<>();
private final HashMap<Biome, Float> oceanBiomeTemperatures = new HashMap<>();
private volatile HashMap<Float, ArrayList<Biome>> temperaturesForOcean = new HashMap<>();
private final HashMap<Float, ArrayList<Biome>> temperaturePartitionedOceanBiomes = new HashMap<>();
public BiomeMap(Random random) {
this(random, 0.08d);
}
public BiomeSelector() {
public BiomeMap(Random random, double scale) {
noise = new SimplexOctaveGenerator(random, 2);
noise.setScale(scale);
temperaturePartitionedLandBiomes.put(0.05f, new ArrayList<>());
temperaturePartitionedLandBiomes.put(0.30f, new ArrayList<>());
temperaturePartitionedLandBiomes.put(0.95f, new ArrayList<>());
@ -28,53 +34,47 @@ public class BiomeSelector {
temperaturePartitionedOceanBiomes.put(0.00f, new ArrayList<>());
temperaturePartitionedOceanBiomes.put(0.3f, new ArrayList<>());
temperaturePartitionedOceanBiomes.put(0.5f, new ArrayList<>());
}
public void initialize() {
if (initialized) throw new IllegalStateException("Biome selector is already initialized.");
initialized = true;
registerLandBiomeTemperatures();
registerOceanBiomeTemperatures();
}
private void registerLandBiomeTemperatures() {
lands.put(Biome.SNOWY_TUNDRA, 0.0f);
lands.put(Biome.ICE_SPIKES, 0.0f);
lands.put(Biome.SNOWY_TAIGA, -0.5f);
lands.put(Biome.SNOWY_TAIGA_MOUNTAINS, -0.5f);
lands.put(Biome.MOUNTAINS, 0.2f);
lands.put(Biome.GRAVELLY_MOUNTAINS, 0.2f);
lands.put(Biome.WOODED_MOUNTAINS, 0.2f);
lands.put(Biome.MODIFIED_GRAVELLY_MOUNTAINS, 0.2f);
lands.put(Biome.TAIGA, 0.25f);
lands.put(Biome.TAIGA_MOUNTAINS, 0.25f);
lands.put(Biome.GIANT_TREE_TAIGA, 0.3f);
lands.put(Biome.PLAINS, 0.8f);
lands.put(Biome.SUNFLOWER_PLAINS, 0.8f);
lands.put(Biome.FOREST, 0.7f);
lands.put(Biome.FLOWER_FOREST, 0.7f);
lands.put(Biome.BIRCH_FOREST, 0.6f);
lands.put(Biome.TALL_BIRCH_FOREST, 0.7f);
lands.put(Biome.DARK_FOREST, 0.7f);
lands.put(Biome.SWAMP, 0.8f);
lands.put(Biome.JUNGLE, 0.95f);
lands.put(Biome.MODIFIED_JUNGLE, 0.95f);
lands.put(Biome.BAMBOO_JUNGLE, 0.95f);
lands.put(Biome.MUSHROOM_FIELDS, 0.9f);
lands.put(Biome.DESERT, 2.0f);
lands.put(Biome.SAVANNA, 1.2f);
lands.put(Biome.SHATTERED_SAVANNA, 1.1f);
lands.put(Biome.BADLANDS, 2.0f);
lands.put(Biome.ERODED_BADLANDS, 2.0f);
lands.put(Biome.WOODED_BADLANDS_PLATEAU, 2.0f);
lands.put(Biome.MODIFIED_WOODED_BADLANDS_PLATEAU, 2.0f);
lands.put(Biome.SAVANNA_PLATEAU, 1.0f);
lands.put(Biome.BADLANDS_PLATEAU, 2.0f);
lands.put(Biome.MODIFIED_BADLANDS_PLATEAU, 2.0f);
lands.put(Biome.SHATTERED_SAVANNA_PLATEAU, 1.0f);
temperaturesForLand = Utilities.invertHashMap(lands);
landBiomeTemperatures.put(Biome.SNOWY_TUNDRA, 0.0f);
landBiomeTemperatures.put(Biome.ICE_SPIKES, 0.0f);
landBiomeTemperatures.put(Biome.SNOWY_TAIGA, -0.5f);
landBiomeTemperatures.put(Biome.SNOWY_TAIGA_MOUNTAINS, -0.5f);
landBiomeTemperatures.put(Biome.MOUNTAINS, 0.2f);
landBiomeTemperatures.put(Biome.GRAVELLY_MOUNTAINS, 0.2f);
landBiomeTemperatures.put(Biome.WOODED_MOUNTAINS, 0.2f);
landBiomeTemperatures.put(Biome.MODIFIED_GRAVELLY_MOUNTAINS, 0.2f);
landBiomeTemperatures.put(Biome.TAIGA, 0.25f);
landBiomeTemperatures.put(Biome.TAIGA_MOUNTAINS, 0.25f);
landBiomeTemperatures.put(Biome.GIANT_TREE_TAIGA, 0.3f);
landBiomeTemperatures.put(Biome.PLAINS, 0.8f);
landBiomeTemperatures.put(Biome.SUNFLOWER_PLAINS, 0.8f);
landBiomeTemperatures.put(Biome.FOREST, 0.7f);
landBiomeTemperatures.put(Biome.FLOWER_FOREST, 0.7f);
landBiomeTemperatures.put(Biome.BIRCH_FOREST, 0.6f);
landBiomeTemperatures.put(Biome.TALL_BIRCH_FOREST, 0.7f);
landBiomeTemperatures.put(Biome.DARK_FOREST, 0.7f);
landBiomeTemperatures.put(Biome.SWAMP, 0.8f);
landBiomeTemperatures.put(Biome.JUNGLE, 0.95f);
landBiomeTemperatures.put(Biome.MODIFIED_JUNGLE, 0.95f);
landBiomeTemperatures.put(Biome.BAMBOO_JUNGLE, 0.95f);
landBiomeTemperatures.put(Biome.MUSHROOM_FIELDS, 0.9f);
landBiomeTemperatures.put(Biome.DESERT, 2.0f);
landBiomeTemperatures.put(Biome.SAVANNA, 1.2f);
landBiomeTemperatures.put(Biome.SHATTERED_SAVANNA, 1.1f);
landBiomeTemperatures.put(Biome.BADLANDS, 2.0f);
landBiomeTemperatures.put(Biome.ERODED_BADLANDS, 2.0f);
landBiomeTemperatures.put(Biome.WOODED_BADLANDS_PLATEAU, 2.0f);
landBiomeTemperatures.put(Biome.MODIFIED_WOODED_BADLANDS_PLATEAU, 2.0f);
landBiomeTemperatures.put(Biome.SAVANNA_PLATEAU, 1.0f);
landBiomeTemperatures.put(Biome.BADLANDS_PLATEAU, 2.0f);
landBiomeTemperatures.put(Biome.MODIFIED_BADLANDS_PLATEAU, 2.0f);
landBiomeTemperatures.put(Biome.SHATTERED_SAVANNA_PLATEAU, 1.0f);
temperaturesForLand = Utilities.invertHashMap(landBiomeTemperatures);
for (Entry<Float, ArrayList<Biome>> entry : temperaturesForLand.entrySet()) {
if (entry.getKey() <= 0.05f) {
@ -90,12 +90,12 @@ public class BiomeSelector {
}
private void registerOceanBiomeTemperatures() {
oceans.put(Biome.WARM_OCEAN, 0.5f);
oceans.put(Biome.LUKEWARM_OCEAN, 0.5f);
oceans.put(Biome.OCEAN, 0.3f);
oceans.put(Biome.COLD_OCEAN, 0.3f);
oceans.put(Biome.FROZEN_OCEAN, 0f);
temperaturesForOcean = Utilities.invertHashMap(oceans);
oceanBiomeTemperatures.put(Biome.WARM_OCEAN, 0.5f);
oceanBiomeTemperatures.put(Biome.LUKEWARM_OCEAN, 0.5f);
oceanBiomeTemperatures.put(Biome.OCEAN, 0.3f);
oceanBiomeTemperatures.put(Biome.COLD_OCEAN, 0.3f);
oceanBiomeTemperatures.put(Biome.FROZEN_OCEAN, 0f);
temperaturesForOcean = Utilities.invertHashMap(oceanBiomeTemperatures);
for (Entry<Float, ArrayList<Biome>> entry : temperaturesForOcean.entrySet()) {
if (entry.getKey() <= 0.00f) {
temperaturePartitionedOceanBiomes.get(0.0f).addAll(entry.getValue());
@ -113,8 +113,6 @@ public class BiomeSelector {
* @return the Minecraft temperature.
*/
public float getBiomeTemperature(Biome biome) {
if (!initialized) throw new IllegalStateException("Biome selector is not initialized.");
String biomeName = biome.name().toLowerCase();
if (biomeName.endsWith("hills") || biomeName.endsWith("beach") || biomeName.endsWith("shore")) {
String biomeTypeName = biomeName;
@ -122,13 +120,13 @@ public class BiomeSelector {
biomeTypeName = biomeTypeName.replace("_beach", "");
biomeTypeName = biomeTypeName.replace("_shore", "");
for (Entry<Biome, Float> entry : lands.entrySet()) {
for (Entry<Biome, Float> entry : landBiomeTemperatures.entrySet()) {
if (entry.getKey().name().toLowerCase().startsWith(biomeTypeName)) {
return entry.getValue();
}
}
}
return lands.get(biome);
return landBiomeTemperatures.get(biome);
}
/**
@ -138,8 +136,6 @@ public class BiomeSelector {
* @return the resulting transition biome.
*/
public Biome getTransitionalBiome(Biome from) {
if (!initialized) throw new IllegalStateException("Biome selector is not initialized.");
String biomeName = from.name().toLowerCase();
if (biomeName.contains("jungle")) {
if (biomeName.contains("modified")) {
@ -160,8 +156,6 @@ public class BiomeSelector {
* @return the shore biome associated with it.
*/
public Biome getShoreBiome(Biome from, float temperature) {
if (!initialized) throw new IllegalStateException("Biome selector is not initialized.");
String biomeName = from.name().toLowerCase();
if (biomeName.contains("mushroom")) {
return Biome.MUSHROOM_FIELD_SHORE;
@ -175,12 +169,10 @@ public class BiomeSelector {
}
public boolean isOceanBiome(Biome biome) {
if (!initialized) throw new IllegalStateException("Biome selector is not initialized.");
return oceans.containsKey(biome);
return oceanBiomeTemperatures.containsKey(biome);
}
public boolean isLandBiome(Biome biome) {
if (!initialized) throw new IllegalStateException("Biome selector is not initialized.");
return !isOceanBiome(biome);
}
@ -190,8 +182,7 @@ public class BiomeSelector {
* @param seed The seed to use to select the biome.
* @return The randomly selected biome.
*/
public Biome getLandBiome(float temperature, long seed) {
if (!initialized) throw new IllegalStateException("Biome selector is not initialized.");
public Biome getLandBiome(float temperature, int worldX, int worldZ) {
ArrayList<Biome> biomes = null;
if (temperature <= 0.05f) {
biomes = temperaturePartitionedLandBiomes.get(0.05f);
@ -202,8 +193,7 @@ public class BiomeSelector {
} else {
biomes = temperaturePartitionedLandBiomes.get(2.00f);
}
Random random = new Random(seed);
return biomes.get((int) random.nextFloat() * biomes.size());
return biomes.get((int) ((noise.noise(worldX, worldZ, 0.5d, 0.5d, true) + 1d) / 2d) * biomes.size());
}
/**
@ -214,8 +204,7 @@ public class BiomeSelector {
* @param seed The seed to use to select the biome.
* @return The randomly selected biome.
*/
public Biome getOceanBiome(float temperature, boolean isDeep, long seed) {
if (!initialized) throw new IllegalStateException("Biome selector is not initialized.");
public Biome getOceanBiome(float temperature, boolean isDeep, int worldX, int worldZ) {
ArrayList<Biome> biomes = null;
if (temperature <= 0.00f) {
biomes = temperaturePartitionedOceanBiomes.get(0.0f);
@ -224,8 +213,7 @@ public class BiomeSelector {
} else {
biomes = temperaturePartitionedOceanBiomes.get(0.5f);
}
Random random = new Random(seed);
Biome oceanBiome = biomes.get((int) random.nextFloat() * biomes.size());
Biome oceanBiome = biomes.get((int) ((noise.noise(worldX, worldZ, 0.5d, 0.5d, true) + 1d) / 2d) * biomes.size());
if (isDeep) oceanBiome = Biome.valueOf("DEEP_" + oceanBiome.name());
return oceanBiome;
}

View File

@ -9,25 +9,25 @@ import ca.recrown.islandsurvivalcraft.caching.Cache;
import ca.recrown.islandsurvivalcraft.pathfinding.CoordinateValidatable;
import ca.recrown.islandsurvivalcraft.pathfinding.DepthFirstSearch;
public class IslandWorldMapper implements CoordinateValidatable {
public class IslandWorldMap implements CoordinateValidatable {
private final Cache<Point2, Double> blockValueCache;
private final SimplexOctaveGenerator noiseGenerator;
private final int noiseOctaves = 4;
private final float islandBlockGenerationPercent = 0.36f;
private final double noiseFrequency = 1.78D;
private final double noiseAmplitude = 0.47D;
private final float shoreFactor = 0.095f;
private final float shallowPortion = 0.07f;
private final double scale = 0.005D;
private final double deepOceanPortion = 0.6d;
private final int NOISE_OCTAVES = 4;
private final float ISLAND_PERCENT = 0.36f;
private final double NOISE_FREQ = 1.78D;
private final double NOISE_AMP = 0.47D;
private final float SHORE_PORTION = 0.095f;
private final float SHALLOW_PORTION = 0.07f;
private final double SCALE = 0.005D;
private final double DEEP_OCEAN_PORTION = 0.6d;
private final DepthFirstSearch dfs;
public IslandWorldMapper(long seed, Cache<Point2, Double> blockValueCache) {
public IslandWorldMap(Random random) {
dfs = new DepthFirstSearch(this);
this.noiseGenerator = new SimplexOctaveGenerator(new Random(seed), noiseOctaves);
noiseGenerator.setScale(scale);
this.blockValueCache = blockValueCache;
this.noiseGenerator = new SimplexOctaveGenerator(random, NOISE_OCTAVES);
noiseGenerator.setScale(SCALE);
this.blockValueCache = new Cache<>(131072);
}
/**
@ -67,7 +67,7 @@ public class IslandWorldMapper implements CoordinateValidatable {
*/
public boolean isShore(int worldX, int worldZ) {
if (!isIsland(worldX, worldZ)) return false;
if (isLand(worldX, worldZ) && getWorldValue(worldX, worldZ) <= shoreFactor) {
if (isLand(worldX, worldZ) && getWorldValue(worldX, worldZ) <= SHORE_PORTION) {
return true;
}
return false;
@ -94,7 +94,7 @@ public class IslandWorldMapper implements CoordinateValidatable {
* @return true if it is considered the shallow portion.
*/
public boolean isShallowPortion(int worldX, int worldZ) {
if (!isLand(worldX, worldZ) && getWorldValue(worldX, worldZ) >= -shallowPortion) {
if (!isLand(worldX, worldZ) && getWorldValue(worldX, worldZ) >= -SHALLOW_PORTION) {
return true;
}
return false;
@ -115,8 +115,8 @@ public class IslandWorldMapper implements CoordinateValidatable {
Double res = blockValueCache.get(p);
if (res == null) {
double shift = 1f - 2f * islandBlockGenerationPercent;
double rawNoise = noiseGenerator.noise(worldX, worldZ, noiseFrequency, noiseAmplitude, true) - shift;
double shift = 1f - 2f * ISLAND_PERCENT;
double rawNoise = noiseGenerator.noise(worldX, worldZ, NOISE_FREQ, NOISE_AMP, true) - shift;
double maxNeg = -1 - shift;
double maxPos = 1 - shift;
@ -152,7 +152,7 @@ public class IslandWorldMapper implements CoordinateValidatable {
}
public boolean isDeepOcean(int worldX, int worldZ) {
return getWorldValue(worldX, worldZ) <= -deepOceanPortion;
return getWorldValue(worldX, worldZ) <= -DEEP_OCEAN_PORTION;
}
@Override

View File

@ -14,18 +14,10 @@ public class TemperatureMap {
private volatile SimplexOctaveGenerator noiseGenerator;
public TemperatureMap() {
public TemperatureMap(Random random) {
temperatureCache = new Cache<>(1024);
}
public TemperatureMap(long seed) {
this();
setSeed(seed);
}
public void setSeed(long seed) {
noiseGenerator = new SimplexOctaveGenerator(new Random(seed), 2);
noiseGenerator.setScale(0.001D);
noiseGenerator = new SimplexOctaveGenerator(random, 2);
noiseGenerator.setScale(0.005D);
}
public float getTemperature(int worldX, int worldZ) {

View File

@ -0,0 +1,26 @@
package ca.recrown.islandsurvivalcraft.world;
import java.util.Random;
import org.bukkit.World;
import ca.recrown.islandsurvivalcraft.world.generation.IslandWorldChunkGenerator;
public class WorldInfo {
public final long seed;
public final BiomeMap biomeMap;
public final TemperatureMap tempMap;
public final IslandWorldMap islandMap;
public final IslandWorldChunkGenerator generator;
public WorldInfo(World world) {
this.seed = world.getSeed();
Random random = new Random(seed);
biomeMap = new BiomeMap(random);
tempMap = new TemperatureMap(random);
islandMap = new IslandWorldMap(random);
generator = new IslandWorldChunkGenerator(random, islandMap, tempMap, biomeMap, true, world.getSeaLevel(), world.getMaxHeight());
}
}

View File

@ -0,0 +1,58 @@
package ca.recrown.islandsurvivalcraft.world;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang.NullArgumentException;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.generator.ChunkGenerator;
import ca.recrown.islandsurvivalcraft.world.generation.PluginDefaultWorldGenerator;
public class WorldInfoManager implements Listener {
public final ConcurrentHashMap<UUID, WorldInfo> worldInformation = new ConcurrentHashMap<>();
private final PluginDefaultWorldGenerator worldGenerator = new PluginDefaultWorldGenerator(this);
/**
* Return the world info requested for the given world.
* Should not be null.
* @param world The world the associated info is to be requested for.
* @return The world info.
*/
public WorldInfo retrieve(World world) {
if (world == null) throw new NullArgumentException("world");
return worldInformation.computeIfAbsent(world.getUID(), (worldInfo) -> {
return new WorldInfo(world);
});
}
/**
* Resets the manager deleting all currently loaded world info from memory.
*/
public void reset() {
worldInformation.clear();
}
/**
* Returns a chunk generator.
* @param world The world the chunk generator is for. If it does not yet exist, it will be created.
* @return The chunk generator associated with the given world.
*/
public ChunkGenerator getChunkGenerator(World world) {
if (world == null) return worldGenerator;
return retrieve(world).generator;
}
@EventHandler(priority = EventPriority.MONITOR)
public void onChunkLoaded(ChunkLoadEvent event) {
if (event.isNewChunk()) {
Chunk chunk = event.getChunk();
retrieve(event.getWorld()).generator.updateChunkLoadedCache(chunk.getX(), chunk.getZ());
}
}
}

View File

@ -6,53 +6,59 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import org.bukkit.Chunk;
import org.apache.commons.lang.NotImplementedException;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.generator.ChunkGenerator;
import ca.recrown.islandsurvivalcraft.Utilities;
import ca.recrown.islandsurvivalcraft.caching.Cache;
import ca.recrown.islandsurvivalcraft.datatypes.Point2;
import ca.recrown.islandsurvivalcraft.world.BiomeSelector;
import ca.recrown.islandsurvivalcraft.world.IslandWorldMapper;
import ca.recrown.islandsurvivalcraft.world.BiomeMap;
import ca.recrown.islandsurvivalcraft.world.IslandWorldMap;
import ca.recrown.islandsurvivalcraft.world.TemperatureMap;
import ca.recrown.islandsurvivalcraft.world.generation.biomes.BiomeGenerator;
import ca.recrown.islandsurvivalcraft.world.generation.biomes.UniBiomeIslandGenerator;
import ca.recrown.islandsurvivalcraft.world.shaders.WorldHeightShader;
import ca.recrown.islandsurvivalcraft.world.shaders.WorldLayerShader;
import ca.recrown.islandsurvivalcraft.world.generation.biomes.UniqueBiomeGenerator;
import ca.recrown.islandsurvivalcraft.world.generation.shaders.WorldHeightShader;
import ca.recrown.islandsurvivalcraft.world.generation.shaders.WorldLayerShader;
public class IslandWorldChunkGenerator extends ChunkGenerator implements Listener {
private final Cache<Point2, Double> blockValueCache = new Cache<>(131072);
private final int BEDROCK_HEIGHT = 5;
private final IslandWorldMap islandMap;
private final TemperatureMap temperatureMap;
private final BiomeMap biomeMap;
private final BiomeGenerator biomeGenerator;
private final WorldHeightShader heightShader;
private final WorldLayerShader layerShader;
private final Cache<Point2, Biome[]> biomeCache = new Cache<>(131072);
private final Cache<Point2, Boolean> chunkExistenceCache = new Cache<>(131072);
private final BiomeSelector biomeSelector = new BiomeSelector();
private final Cache<Point2, Boolean> chunkLoadedCache = new Cache<>(4096);
private final ExecutorService exAlpha = Utilities.ISC_EXECUTOR_ALPHA;
private final ExecutorService exBeta = Utilities.ISC_EXECUTOR_BETA;
private volatile World currentWorld;
public IslandWorldChunkGenerator() {
biomeSelector.initialize();
public IslandWorldChunkGenerator(Random random, IslandWorldMap islandMap, TemperatureMap temperatureMap, BiomeMap biomeMap, boolean uniqueBiome, int seaLevel, int worldHeight) {
this.islandMap = islandMap;
this.temperatureMap = temperatureMap;
this.biomeMap = biomeMap;
this.heightShader = new WorldHeightShader(random, islandMap, seaLevel, worldHeight, BEDROCK_HEIGHT + 1);
this.layerShader = new WorldLayerShader(random, seaLevel, worldHeight, islandMap);
if (uniqueBiome) {
biomeGenerator = new UniqueBiomeGenerator();
} else {
throw new NotImplementedException();
}
}
@Override
public ChunkData generateChunkData(World world, Random random, int chunkX, int chunkZ, BiomeGrid biomeGrid) {
this.currentWorld = world;
long seed = world.getSeed();
int maxHeight = world.getMaxHeight();
int seaLevel = world.getSeaLevel();
IslandWorldMapper mapper = new IslandWorldMapper(seed, blockValueCache);
TemperatureMap temperatureMapGenerator = new TemperatureMap(seed);
WorldHeightShader heightShader = new WorldHeightShader(seed, mapper, seaLevel, world.getMaxHeight(), 3);
WorldLayerShader layerShader = new WorldLayerShader(seed, seaLevel, maxHeight, mapper);
BiomeGenerator biomeGenerator = new UniBiomeIslandGenerator();
LinkedList<Future<Boolean>> tasks = new LinkedList<>();
ChunkData chunkData = createChunkData(world);
@ -60,41 +66,41 @@ public class IslandWorldChunkGenerator extends ChunkGenerator implements Listene
for (int x = Utilities.CHUNK_SIZE - 1; x >= 0; x--) {
for (int z = Utilities.CHUNK_SIZE - 1; z >= 0; z--) {
if (Thread.currentThread().isInterrupted()) return false;
mapper.getWorldValue(Utilities.CHUNK_SIZE * chunkX + x, Utilities.CHUNK_SIZE * chunkZ + z);
islandMap.getWorldValue(Utilities.CHUNK_SIZE * chunkX + x, Utilities.CHUNK_SIZE * chunkZ + z);
}
}
return true;
});
Biome[][][] biomeSet = new Biome[Utilities.CHUNK_SIZE][Utilities.CHUNK_SIZE][4];
Biome[][][] biomeArraySet = new Biome[Utilities.CHUNK_SIZE][Utilities.CHUNK_SIZE][4];
for (int x = 0; x < Utilities.CHUNK_SIZE; x++) {
for (int z = 0; z < Utilities.CHUNK_SIZE; z++) {
final int localX = x;
final int localZ = z;
final int worldX = Utilities.CHUNK_SIZE * chunkX + localX;
final int worldZ = Utilities.CHUNK_SIZE * chunkZ + localZ;
if (biomeSet[localX][localZ][0] == null) {
biomeGenerator.generateBiomeColumn(biomeSet, world, chunkX, chunkZ, localX, localZ, mapper, biomeSelector,
temperatureMapGenerator, biomeCache, chunkExistenceCache, seed);
if (biomeArraySet[localX][localZ][0] == null) {
biomeGenerator.generateBiomeColumn(biomeArraySet, world, chunkX, chunkZ, localX, localZ, islandMap, biomeMap,
temperatureMap, biomeCache, chunkLoadedCache);
}
if (biomeSet[localX][localZ][0] == null) throw new IllegalStateException("Biome was null.");
if (biomeArraySet[localX][localZ][0] == null) throw new IllegalStateException("Biome was null.");
tasks.add(exBeta.submit(() -> {
for (int y = 0; y < maxHeight; y++) {
biomeGrid.setBiome(localX, y, localZ, biomeSet[localX][localZ][0]);
biomeGrid.setBiome(localX, y, localZ, biomeArraySet[localX][localZ][0]);
}
return true;
}));
Biome[] currentBiomeSet = biomeSet[localX][localZ];
Biome[] currentBiomeSet = biomeArraySet[localX][localZ];
int terrainHeight = heightShader.getTerrainHeight(worldX, worldZ, currentBiomeSet);
int currentTerrainHeight = terrainHeight - 1;
int bedrockHeight = random.nextInt(5) + 1;
if (layerShader.hasSpecialLayers(currentBiomeSet[0])) {
BlockData currentMaterial = layerShader.getMaterialForHeight(worldX, worldZ, currentTerrainHeight, terrainHeight - 1, currentBiomeSet);
BlockData currentMaterial = layerShader.getMaterialForHeight(seed, worldX, worldZ, currentTerrainHeight, terrainHeight - 1, currentBiomeSet);
while (currentMaterial != null) {
chunkData.setBlock(localX, currentTerrainHeight, localZ, currentMaterial);
currentTerrainHeight--;
currentMaterial = layerShader.getMaterialForHeight(worldX, worldZ, currentTerrainHeight, terrainHeight - 1, currentBiomeSet);
currentMaterial = layerShader.getMaterialForHeight(seed, worldX, worldZ, currentTerrainHeight, terrainHeight - 1, currentBiomeSet);
}
} else {
int surfaceThickness = layerShader.getSurfaceThickness(worldX, worldZ, currentBiomeSet[0]);
@ -132,28 +138,27 @@ public class IslandWorldChunkGenerator extends ChunkGenerator implements Listene
@Override
public boolean canSpawn(World world, int x, int z) {
IslandWorldMapper mapper = new IslandWorldMapper(world.getSeed(), blockValueCache);
return mapper.isLand(x, z);
return islandMap.isLand(x, z);
}
@Override
public boolean shouldGenerateCaves() {
return true;
return false;
}
@Override
public boolean shouldGenerateDecorations() {
return true;
return false;
}
@Override
public boolean shouldGenerateStructures() {
return true;
return false;
}
@Override
public boolean shouldGenerateMobs() {
return true;
return false;
}
@Override
@ -161,14 +166,7 @@ public class IslandWorldChunkGenerator extends ChunkGenerator implements Listene
return true;
}
@EventHandler(priority = EventPriority.MONITOR)
public void onChunkLoaded(ChunkLoadEvent event) {
if (event.isNewChunk()) {
if (currentWorld == event.getWorld()) {
Chunk chunk = event.getChunk();
chunkExistenceCache.set(new Point2(chunk.getX(), chunk.getZ()), true);
}
}
public void updateChunkLoadedCache(int chunkX, int chunkZ) {
this.chunkLoadedCache.set(new Point2(chunkX, chunkZ), true);
}
}

View File

@ -0,0 +1,25 @@
package ca.recrown.islandsurvivalcraft.world.generation;
import java.util.Random;
import org.bukkit.World;
import org.bukkit.generator.ChunkGenerator;
import ca.recrown.islandsurvivalcraft.world.WorldInfoManager;
public class PluginDefaultWorldGenerator extends ChunkGenerator {
private final WorldInfoManager worldInfos;
/**
* Creates a default world generator given a world info manager to associate the new world info with.
* @param worldInfoManager The manager to associate the newly created world info with.
*/
public PluginDefaultWorldGenerator(WorldInfoManager worldInfoManager) {
this.worldInfos = worldInfoManager;
}
@Override
public ChunkData generateChunkData(World world,Random random, int x, int z, BiomeGrid biome) {
return worldInfos.retrieve(world).generator.generateChunkData(world, random, x, z, biome);
}
}

View File

@ -5,8 +5,8 @@ import org.bukkit.block.Biome;
import ca.recrown.islandsurvivalcraft.caching.Cache;
import ca.recrown.islandsurvivalcraft.datatypes.Point2;
import ca.recrown.islandsurvivalcraft.world.BiomeSelector;
import ca.recrown.islandsurvivalcraft.world.IslandWorldMapper;
import ca.recrown.islandsurvivalcraft.world.BiomeMap;
import ca.recrown.islandsurvivalcraft.world.IslandWorldMap;
import ca.recrown.islandsurvivalcraft.world.TemperatureMap;
public interface BiomeGenerator {
@ -27,7 +27,6 @@ public interface BiomeGenerator {
* @param tempGenerator The temperature generator to be used.
* @param biomeCache Cache for biomes.
* @param chunkGenCache Cache for whether or not the chunk is generated.
* @param seed The seed to use for the biome for this column.
*/
public void generateBiomeColumn(Biome[][][] chunkBiomeSets, World world, int chunkX, int chunkZ, int localX, int localZ, IslandWorldMapper mapper, BiomeSelector biomeSelector, TemperatureMap tempGenerator, Cache<Point2, Biome[]> biomeCache, Cache<Point2, Boolean> chunkGenCache, long seed);
public void generateBiomeColumn(Biome[][][] chunkBiomeSets, World world, int chunkX, int chunkZ, int localX, int localZ, IslandWorldMap mapper, BiomeMap biomeSelector, TemperatureMap tempGenerator, Cache<Point2, Biome[]> biomeCache, Cache<Point2, Boolean> chunkGenCache);
}

View File

@ -10,13 +10,13 @@ import ca.recrown.islandsurvivalcraft.floodfill.Floodable;
import ca.recrown.islandsurvivalcraft.floodfill.Flooder;
import ca.recrown.islandsurvivalcraft.pathfinding.CoordinateTargetValidatable;
import ca.recrown.islandsurvivalcraft.pathfinding.DepthFirstSearch;
import ca.recrown.islandsurvivalcraft.world.BiomeSelector;
import ca.recrown.islandsurvivalcraft.world.IslandWorldMapper;
import ca.recrown.islandsurvivalcraft.world.BiomeMap;
import ca.recrown.islandsurvivalcraft.world.IslandWorldMap;
import ca.recrown.islandsurvivalcraft.world.TemperatureMap;
public class UniBiomeIslandGenerator implements BiomeGenerator {
public class UniqueBiomeGenerator implements BiomeGenerator {
@Override
public void generateBiomeColumn(Biome[][][] chunkBiomeSets, World world, int chunkX, int chunkZ, int localX, int localZ, IslandWorldMapper mapper, BiomeSelector biomeSelector, TemperatureMap tempGen, Cache<Point2, Biome[]> biomeCache, Cache<Point2, Boolean> chunkGenCache, long seed) {
public void generateBiomeColumn(Biome[][][] chunkBiomeSets, World world, int chunkX, int chunkZ, int localX, int localZ, IslandWorldMap mapper, BiomeMap biomeSelector, TemperatureMap tempGen, Cache<Point2, Biome[]> biomeCache, Cache<Point2, Boolean> chunkGenCache) {
int worldX = 16 * chunkX + localX;
int worldZ = 16 * chunkZ + localZ;
Point2 chunkCoords = Utilities.worldToChunkCoordinates(new Point2(worldX, worldZ));
@ -32,7 +32,7 @@ public class UniBiomeIslandGenerator implements BiomeGenerator {
//Fine, check if it's ocean.
if (!mapper.isIsland(worldX, worldZ)) {
biomeSet = chunkBiomeSets[localX][localZ];
biomeSet[0] = biomeSelector.getOceanBiome(tempGen.getTemperature(worldX, worldZ), mapper.isDeepOcean(worldX, worldZ), seed + worldX + worldZ);
biomeSet[0] = biomeSelector.getOceanBiome(tempGen.getTemperature(worldX, worldZ), mapper.isDeepOcean(worldX, worldZ), worldX, worldZ);
setCacheBiome(worldX, worldZ, biomeSet, chunkBiomeSets, biomeCache);
return;
}
@ -45,9 +45,9 @@ public class UniBiomeIslandGenerator implements BiomeGenerator {
search.setStartPosition(worldX, worldZ);
if (!search.findTarget(islandInfo)) {
float temp = tempGen.getTemperature(worldX, worldZ);
if (islandInfo.main == null) islandInfo.main = biomeSelector.getLandBiome(temp, seed + worldX + worldZ);
if (islandInfo.main == null) islandInfo.main = biomeSelector.getLandBiome(temp, worldX, worldZ);
if (islandInfo.shore == null) islandInfo.shore = biomeSelector.getShoreBiome(islandInfo.main, temp);
if (islandInfo.shallow == null) islandInfo.shallow = biomeSelector.getOceanBiome(temp, mapper.isDeepOcean(worldX, worldZ), seed + worldX + worldZ);
if (islandInfo.shallow == null) islandInfo.shallow = biomeSelector.getOceanBiome(temp, mapper.isDeepOcean(worldX, worldZ), worldX, worldZ);
}
PropagatorInfo propInfo = new PropagatorInfo(islandInfo, chunkBiomeSets, new Point2(chunkX, chunkZ), mapper, biomeCache);
@ -92,13 +92,13 @@ public class UniBiomeIslandGenerator implements BiomeGenerator {
}
private class IslandInfo implements CoordinateTargetValidatable {
public final IslandWorldMapper mapper;
public final IslandWorldMap mapper;
public final World world;
private final Cache<Point2, Biome[]> biomeCache;
private final Cache<Point2, Boolean> chunkGenCache;
public Biome main, shore, shallow;
public IslandInfo(IslandWorldMapper mapper, World world, Cache<Point2, Biome[]> biomeCache, Cache<Point2, Boolean> chunkGenCache) {
public IslandInfo(IslandWorldMap mapper, World world, Cache<Point2, Biome[]> biomeCache, Cache<Point2, Boolean> chunkGenCache) {
this.mapper = mapper;
this.world = world;
this.biomeCache = biomeCache;
@ -130,10 +130,10 @@ public class UniBiomeIslandGenerator implements BiomeGenerator {
private final Biome shallow, shore, main;
private final Biome[][][] biomes;
private final Point2 chunkCoords;
private final IslandWorldMapper mapper;
private final IslandWorldMap mapper;
private final Cache<Point2, Biome[]> biomeCache;
public PropagatorInfo(IslandInfo islandInfo, Biome[][][] biomes, Point2 chunkCoords, IslandWorldMapper mapper, Cache<Point2, Biome[]> biomeCache) {
public PropagatorInfo(IslandInfo islandInfo, Biome[][][] biomes, Point2 chunkCoords, IslandWorldMap mapper, Cache<Point2, Biome[]> biomeCache) {
this.shallow = islandInfo.shallow;
this.shore = islandInfo.shore;
this.main = islandInfo.main;

View File

@ -1,26 +1,26 @@
package ca.recrown.islandsurvivalcraft.world.shaders;
package ca.recrown.islandsurvivalcraft.world.generation.shaders;
import java.util.Random;
import org.bukkit.block.Biome;
import org.bukkit.util.noise.SimplexOctaveGenerator;
import ca.recrown.islandsurvivalcraft.world.IslandWorldMapper;
import ca.recrown.islandsurvivalcraft.world.IslandWorldMap;
public class WorldHeightShader {
private final IslandWorldMapper mapper;
private final SimplexOctaveGenerator shader;
private final IslandWorldMap mapper;
private final SimplexOctaveGenerator noiseGenerator;
private final int seaLevel;
private final int worldHeight;
private final int minimumHeight;
public WorldHeightShader(long seed, IslandWorldMapper islandLocator, int seaLevel, int worldHeight, int minimumHeight) {
public WorldHeightShader(Random random, IslandWorldMap islandLocator, int seaLevel, int worldHeight, int minimumHeight) {
this.mapper = islandLocator;
this.seaLevel = seaLevel;
this.worldHeight = worldHeight;
this.minimumHeight = minimumHeight;
this.shader = new SimplexOctaveGenerator(new Random(seed/2), 8);
this.shader.setScale(0.0225d);
this.noiseGenerator = new SimplexOctaveGenerator(random, 8);
this.noiseGenerator.setScale(0.0225d);
}
public int getTerrainHeight(int worldX, int worldZ, Biome[] biomeSet) {
@ -64,7 +64,7 @@ public class WorldHeightShader {
private double calculateTerrainFactor(int worldX, int worldZ, double heightFactor, double freq, double amplitude, double shift, double exaggerationFactor) {
double res = seaLevel;
double shapeValue = (shader.noise(worldX, worldZ, freq, amplitude, true) + shift) / (shift + 1d);
double shapeValue = (noiseGenerator.noise(worldX, worldZ, freq, amplitude, true) + shift) / (shift + 1d);
if (shift == 1d && exaggerationFactor != 1d) shapeValue = Math.pow(shapeValue, exaggerationFactor);
double islandValue = mapper.getWorldValue(worldX, worldZ);
res += (islandValue) * (shapeValue * heightFactor);

View File

@ -1,4 +1,4 @@
package ca.recrown.islandsurvivalcraft.world.shaders;
package ca.recrown.islandsurvivalcraft.world.generation.shaders;
import java.util.Random;
@ -9,16 +9,14 @@ import org.bukkit.util.noise.SimplexOctaveGenerator;
import ca.recrown.islandsurvivalcraft.caching.Cache;
import ca.recrown.islandsurvivalcraft.datatypes.Vector3;
import ca.recrown.islandsurvivalcraft.world.IslandWorldMapper;
import ca.recrown.islandsurvivalcraft.world.IslandWorldMap;
@SuppressWarnings("unused")
public class WorldLayerShader {
private final Cache<Vector3, Double> noiseCache = new Cache<>(256);
private final SimplexOctaveGenerator noise;
private final IslandWorldMapper mapper;
private final long seed;
private final SimplexOctaveGenerator noiseGenerator;
private final IslandWorldMap islandMap;
private final int seaLevel, maxHeight;
private final Random random;
private final Material[] badlandTerrocota = new Material[] {
@ -30,14 +28,12 @@ public class WorldLayerShader {
Material.WHITE_TERRACOTTA
};
public WorldLayerShader(long seed, int seaLevel, int maxHeight, IslandWorldMapper mapper) {
this.mapper = mapper;
this.seed = seed;
public WorldLayerShader(Random random, int seaLevel, int maxHeight, IslandWorldMap islandMap) {
this.islandMap = islandMap;
this.seaLevel = seaLevel;
this.maxHeight = maxHeight;
random = new Random(seed);
this.noise = new SimplexOctaveGenerator(new Random(seed), 4);
this.noise.setScale(0.03d);
this.noiseGenerator = new SimplexOctaveGenerator(random, 4);
this.noiseGenerator.setScale(0.05d);
}
public boolean hasSpecialLayers(Biome biome) {
@ -49,21 +45,24 @@ public class WorldLayerShader {
}
/**
* Figures out the type of material to be placed at a given world coordinate set.
* Returns null when special layering is done and should return to normal generation.
* @param worldX The world x coordinate.
* @param worldZ The world z coordinate.
* @param y The elevation.
* @param biomeSet the associated biome.
* @return the material for the layer. Returning null means no more special layers.
* Returns the material for the height. If there are no more special materials, this will return null.
*
* @param seed The seed to use for special layer generation.
* @param worldX The x world coordinate.
* @param worldZ The z world coordinate.
* @param y The current layer (AKA the y world coordinate).
* @param highestPoint The y level of the top layer.
* @param biomeSet The biomeset for the current column.
* @return The block data for the material, or null if there are no further special materials.
*/
public BlockData getMaterialForHeight(int worldX, int worldZ, int y, int highestPoint, Biome[] biomeSet) {
public BlockData getMaterialForHeight(long seed, int worldX, int worldZ, int y, int highestPoint, Biome[] biomeSet) {
Biome mainBiome = biomeSet[0];
String mainBiomeName = mainBiome.toString().toLowerCase();
BlockData res = null;
if (mainBiomeName.contains("badlands")) {
int seedOffset = (worldX + worldZ) / 1000;
Random random = new Random(seed + seedOffset);
random.setSeed(seed + seedOffset);
int yInterval = (int) (random.nextFloat() * 9) + 1;
int yBandInitial = (int) (seaLevel + random.nextDouble() * 50);
@ -137,7 +136,7 @@ public class WorldLayerShader {
Vector3 key = new Vector3(worldX, worldZ, freq);
Double res = noiseCache.get(key);
if (res == null) {
res = (noise.noise(worldX, worldZ, freq, 0.5d) + 1d) / 2d;
res = (noiseGenerator.noise(worldX, worldZ, freq, 0.5d) + 1d) / 2d;
noiseCache.set(key, res);
}
return res;

View File

@ -2,6 +2,8 @@ package ca.recrown.islandsurvivalcraft.world;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Random;
import org.bukkit.block.Biome;
import org.junit.jupiter.api.BeforeAll;
@ -10,14 +12,13 @@ import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
@TestInstance(Lifecycle.PER_CLASS)
public class BiomeSelectorTest {
BiomeSelector biomeSelector;
public class BiomeMapTest {
private final Random random = new Random(10320452);
BiomeMap biomeSelector;
@BeforeAll
public void setUp() {
biomeSelector = new BiomeSelector();
biomeSelector.initialize();
biomeSelector = new BiomeMap(random);
}
@Test

View File

@ -5,22 +5,17 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Random;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import ca.recrown.islandsurvivalcraft.caching.Cache;
import ca.recrown.islandsurvivalcraft.datatypes.Point2;
@TestInstance(Lifecycle.PER_CLASS)
public class IslandWorldMapperTest {
public final Cache<Point2, Double> blockValCache = new Cache<>(2048);
public class IslandWorldMapTest {
public final int SEED = 102385923;
public Random random = new Random(SEED);
public IslandWorldMapper mapper = new IslandWorldMapper(SEED, blockValCache);
public IslandWorldMap mapper = new IslandWorldMap(random);
public final double[][] answers = new double[2048][2048];
@BeforeAll
@ -32,16 +27,10 @@ public class IslandWorldMapperTest {
}
}
@AfterEach
public void individualCleanup() {
random.setSeed(SEED);
blockValCache.clearCache();
}
@BeforeEach
public void individualSetUp() {
random = new Random(SEED);
mapper = new IslandWorldMapper(SEED, blockValCache);
mapper = new IslandWorldMap(random);
}
@Test

View File

@ -3,6 +3,7 @@ package ca.recrown.islandsurvivalcraft.world.generation.biomes;
import static org.junit.jupiter.api.Assertions.assertFalse;
import java.util.LinkedList;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ -21,19 +22,19 @@ import org.junit.jupiter.api.TestInstance.Lifecycle;
import ca.recrown.islandsurvivalcraft.Utilities;
import ca.recrown.islandsurvivalcraft.caching.Cache;
import ca.recrown.islandsurvivalcraft.datatypes.Point2;
import ca.recrown.islandsurvivalcraft.world.BiomeSelector;
import ca.recrown.islandsurvivalcraft.world.IslandWorldMapper;
import ca.recrown.islandsurvivalcraft.world.BiomeMap;
import ca.recrown.islandsurvivalcraft.world.IslandWorldMap;
import ca.recrown.islandsurvivalcraft.world.TemperatureMap;
import ca.recrown.islandsurvivalcraft.world.generation.DummyWorld;
@TestInstance(Lifecycle.PER_CLASS)
public class UniBiomeIslandGeneratorTest {
public class UniqueBiomeGeneratorTest {
private final int SEED = 249398015;
private final DummyWorld dummyWorld = new DummyWorld();
private volatile Cache<Point2, Double> blockValueCache;
private volatile Cache<Point2, Biome[]> biomeCache;
private volatile Cache<Point2, Boolean> chunkExistenceCache;
private final BiomeSelector biomeSelector = new BiomeSelector();
private final BiomeMap biomeSelector = new BiomeMap(new Random(SEED));
private class BiomeGenTask implements Runnable {
@ -54,16 +55,17 @@ public class UniBiomeIslandGeneratorTest {
}
public void generateBiome(int chunkX, int chunkZ) {
IslandWorldMapper mapper = new IslandWorldMapper(SEED, blockValueCache);
TemperatureMap temperatureMapGenerator = new TemperatureMap(SEED);
BiomeGenerator biomeGenerator = new UniBiomeIslandGenerator();
Random random = new Random(SEED);
IslandWorldMap mapper = new IslandWorldMap(random);
TemperatureMap temperatureMapGenerator = new TemperatureMap(random);
BiomeGenerator biomeGenerator = new UniqueBiomeGenerator();
Biome[][][] biomes = new Biome[Utilities.CHUNK_SIZE][Utilities.CHUNK_SIZE][4];
for (int localX = 0; localX < Utilities.CHUNK_SIZE; localX++) {
for (int localZ = 0; localZ < Utilities.CHUNK_SIZE; localZ++) {
if (biomes[localX][localZ] == null) {
biomeGenerator.generateBiomeColumn(biomes, dummyWorld, chunkX, chunkZ, localX, localZ, mapper,
biomeSelector, temperatureMapGenerator, biomeCache, chunkExistenceCache, SEED);
biomeSelector, temperatureMapGenerator, biomeCache, chunkExistenceCache);
}
if (biomes[localX][localZ] == null)
throw new IllegalStateException("Biome was null.");
@ -74,7 +76,6 @@ public class UniBiomeIslandGeneratorTest {
@BeforeAll
public void setup() {
biomeSelector.initialize();
}
@BeforeEach