Implemented better biome system.

This commit is contained in:
2020-05-06 20:05:20 -05:00
parent d1cae3bf7f
commit a5cf40913b
13 changed files with 388 additions and 615 deletions

View File

@@ -0,0 +1,93 @@
package ca.recrown.islandsurvivalcraft.utilities.biomes;
import java.util.Arrays;
import org.bukkit.block.Biome;
import ca.recrown.islandsurvivalcraft.utilities.weighting.Weightable;
import ca.recrown.islandsurvivalcraft.utilities.weighting.WeightedSelector;
public enum BiomeClassifications implements Weightable {
SNOWY(0.2f, new OceanBiomeInfo(Biome.FROZEN_OCEAN, Biome.COLD_OCEAN, Biome.DEEP_FROZEN_OCEAN),
new LandBiomeInfo(Biome.SNOWY_TAIGA, null, Biome.SNOWY_TAIGA_HILLS, Biome.SNOWY_BEACH, 0.3f),
new LandBiomeInfo(Biome.SNOWY_TAIGA_MOUNTAINS, Biome.SNOWY_TAIGA, null, Biome.SNOWY_BEACH, 0.25f),
new LandBiomeInfo(Biome.SNOWY_TUNDRA, null, null, Biome.SNOWY_BEACH, 0.3f),
new LandBiomeInfo(Biome.ICE_SPIKES, null, null, Biome.SNOWY_BEACH, 0.15f)
),
COLD(0.3f, new OceanBiomeInfo(Biome.COLD_OCEAN, null, Biome.DEEP_COLD_OCEAN),
new LandBiomeInfo(Biome.MOUNTAINS, null, null, Biome.STONE_SHORE, 0.14f),
new LandBiomeInfo(Biome.GRAVELLY_MOUNTAINS, 0.1f),
new LandBiomeInfo(Biome.WOODED_MOUNTAINS, 0.08f),
new LandBiomeInfo(Biome.MODIFIED_GRAVELLY_MOUNTAINS, 0.08f),
new LandBiomeInfo(Biome.TAIGA, null, Biome.TAIGA_HILLS, Biome.BEACH, 0.15f),
new LandBiomeInfo(Biome.TAIGA_MOUNTAINS, 0.15f),
new LandBiomeInfo(Biome.GIANT_TREE_TAIGA, null, Biome.GIANT_TREE_TAIGA_HILLS, Biome.BEACH, 0.15f),
new LandBiomeInfo(Biome.GIANT_SPRUCE_TAIGA, null, Biome.GIANT_SPRUCE_TAIGA_HILLS, Biome.BEACH, 0.15f)
),
LUSH(0.3f, new OceanBiomeInfo(Biome.WARM_OCEAN, Biome.LUKEWARM_OCEAN, Biome.DEEP_LUKEWARM_OCEAN),
new LandBiomeInfo(Biome.PLAINS, 0.15f),
new LandBiomeInfo(Biome.SUNFLOWER_PLAINS, 0.075f),
new LandBiomeInfo(Biome.FOREST, null, Biome.WOODED_HILLS, Biome.BEACH, 0.1f),
new LandBiomeInfo(Biome.FLOWER_FOREST, 0.05f),
new LandBiomeInfo(Biome.BIRCH_FOREST, null, Biome.BIRCH_FOREST_HILLS, Biome.BEACH, 0.1f),
new LandBiomeInfo(Biome.TALL_BIRCH_FOREST, null, Biome.TALL_BIRCH_HILLS, Biome.BEACH, 0.075f),
new LandBiomeInfo(Biome.DARK_FOREST, null, Biome.DARK_FOREST_HILLS, Biome.BEACH, 0.075f),
new LandBiomeInfo(Biome.SWAMP, null, Biome.SWAMP_HILLS, null, 0.1f),
new LandBiomeInfo(Biome.JUNGLE, Biome.JUNGLE_EDGE, Biome.JUNGLE_HILLS, Biome.BEACH, 0.075f),
new LandBiomeInfo(Biome.MODIFIED_JUNGLE, Biome.MODIFIED_JUNGLE_EDGE, null, Biome.BEACH, 0.075f),
new LandBiomeInfo(Biome.BAMBOO_JUNGLE, null, Biome.BAMBOO_JUNGLE_HILLS, Biome.BEACH, 0.075f),
new LandBiomeInfo(Biome.MUSHROOM_FIELDS, null, null, Biome.MUSHROOM_FIELD_SHORE, 0.05f)
),
WARM(0.2f, new OceanBiomeInfo(Biome.OCEAN, null, Biome.DEEP_OCEAN),
new LandBiomeInfo(Biome.DESERT, null, Biome.DESERT_HILLS, Biome.BEACH, 0.2f),
new LandBiomeInfo(Biome.SAVANNA, 0.2f),
new LandBiomeInfo(Biome.SHATTERED_SAVANNA, 0.075f),
new LandBiomeInfo(Biome.BADLANDS, 0.075f),
new LandBiomeInfo(Biome.ERODED_BADLANDS, 0.075f),
new LandBiomeInfo(Biome.WOODED_BADLANDS_PLATEAU, 0.075f),
new LandBiomeInfo(Biome.MODIFIED_WOODED_BADLANDS_PLATEAU, 0.075f),
new LandBiomeInfo(Biome.BADLANDS_PLATEAU, 0.075f),
new LandBiomeInfo(Biome.SAVANNA_PLATEAU, 0.05f),
new LandBiomeInfo(Biome.MODIFIED_BADLANDS_PLATEAU, 0.05f),
new LandBiomeInfo(Biome.SHATTERED_SAVANNA_PLATEAU, 0.05f)
),
;
private final LandBiomeInfo[] biomeInfos;
private final float weight;
private final OceanBiomeInfo associatedOceanBiomeInfo;
private final WeightedSelector<LandBiomeInfo> selector;
BiomeClassifications(float weight, OceanBiomeInfo oceanBiomeInfo, LandBiomeInfo... biomeInfos) {
this.biomeInfos = biomeInfos;
this.weight = weight;
this.associatedOceanBiomeInfo = oceanBiomeInfo;
selector = new WeightedSelector<>(Arrays.asList(biomeInfos));
}
/**
* @return the biomes associated with this classification.
*/
public LandBiomeInfo[] getBiomeInfos() {
return biomeInfos;
}
@Override
public float getWeight() {
return weight;
}
/**
* @return the associatedOceanBiomeInfo
*/
public OceanBiomeInfo getAssociatedOceanBiomeInfo() {
return associatedOceanBiomeInfo;
}
/**
* @return the selector
*/
public WeightedSelector<LandBiomeInfo> getSelector() {
return selector;
}
}

View File

@@ -0,0 +1,69 @@
package ca.recrown.islandsurvivalcraft.utilities.biomes;
import org.bukkit.block.Biome;
import ca.recrown.islandsurvivalcraft.utilities.weighting.Weightable;
public class LandBiomeInfo implements Weightable {
private final Biome biome;
private final float weight;
private final Biome hillBiome;
private final Biome transitionBiome;
private final Biome preferredShore;
/**
* Creates a land biome information object.
* @param biome the main biome this object represents.
* @param transitionBiome the transition biome to go with this biome. May be null.
* @param hill the hill biome that goes with this biome. May be null.
* @param shore the preferred shore that goes with this biome. May be null.
* @param weight the weight, relative to the others, chance this biome spawns.
*/
public LandBiomeInfo(Biome biome, Biome transitionBiome, Biome hill, Biome shore, float weight) {
if (biome == null) throw new IllegalArgumentException("Argument biome may never be null.");
this.weight = weight;
this.biome = biome;
this.hillBiome = hill;
this.preferredShore = shore;
this.transitionBiome = transitionBiome;
}
public LandBiomeInfo(Biome biome, float weight) {
this(biome, null, null, Biome.BEACH, weight);
}
/**
* @return the weight
*/
public float getWeight() {
return weight;
}
/**
* @return the biome
*/
public Biome getBiome() {
return biome;
}
/**
* @return the hill biome. May be null.
*/
public Biome getHillBiome() {
return hillBiome;
}
/**
* @return the shore biome.
*/
public Biome getPreferredShore() {
return preferredShore;
}
/**
* @return the transition biome if it has one. May be null.
*/
public Biome getTransitionBiome() {
return transitionBiome;
}
}

View File

@@ -0,0 +1,37 @@
package ca.recrown.islandsurvivalcraft.utilities.biomes;
import org.bukkit.block.Biome;
public class OceanBiomeInfo {
private final Biome ocean;
private final Biome transitionOcean;
private final Biome deepAlternative;
public OceanBiomeInfo(Biome ocean, Biome transitionOcean, Biome deepAlternative) {
if (ocean == null || deepAlternative == null) throw new IllegalArgumentException("Neither argument ocean nor deepAlternative may be null.");
this.ocean = ocean;
this.transitionOcean = transitionOcean;
this.deepAlternative = deepAlternative;
}
/**
* @return the main ocean.
*/
public Biome getOcean() {
return ocean;
}
/**
* @return the transition ocean. May be null.
*/
public Biome getTransitionOcean() {
return transitionOcean;
}
/**
* @return the deep version of this ocean.
*/
public Biome getDeepAlternative() {
return deepAlternative;
}
}

View File

@@ -0,0 +1,5 @@
package ca.recrown.islandsurvivalcraft.utilities.weighting;
public interface Weightable {
public float getWeight();
}

View File

@@ -0,0 +1,27 @@
package ca.recrown.islandsurvivalcraft.utilities.weighting;
import java.util.Random;
import java.util.TreeMap;
public class WeightedSelector<T extends Weightable> {
private final TreeMap<Float, T> map;
private final float totalWeights;
public WeightedSelector(Iterable<T> set) {
float totalWeights = 0;
map = new TreeMap<>();
for (T t : set) {
totalWeights += t.getWeight();
map.put(totalWeights, t);
}
this.totalWeights = totalWeights;
}
public T selectRandom(Random random) {
return map.ceilingEntry(random.nextFloat() * totalWeights).getValue();
}
public T selectRandom(float selector) {
return map.ceilingEntry(selector * totalWeights).getValue();
}
}

View File

@@ -1,275 +1,25 @@
package ca.recrown.islandsurvivalcraft.world;
import java.util.ArrayList;
import java.util.HashMap;
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.GeneralUtilities;
import ca.recrown.islandsurvivalcraft.world.TemperatureMap.TemperatureRegion;
import ca.recrown.islandsurvivalcraft.utilities.biomes.BiomeClassifications;
import ca.recrown.islandsurvivalcraft.utilities.biomes.LandBiomeInfo;
import ca.recrown.islandsurvivalcraft.utilities.biomes.OceanBiomeInfo;
public class BiomeMap {
public enum MainBiomes {
SNOWY_TUNDRA(0.0f, TemperatureRegion.SNOWY, ShoreBiomes.SNOWY_BEACH),
ICE_SPIKES(0.0f, TemperatureRegion.SNOWY, ShoreBiomes.SNOWY_BEACH),
SNOWY_TAIGA(-0.5f, TemperatureRegion.SNOWY, ShoreBiomes.SNOWY_BEACH),
SNOWY_TAIGA_MOUNTAINS(-0.5f, TemperatureRegion.SNOWY, ShoreBiomes.SNOWY_BEACH),
MOUNTAINS(0.2f, TemperatureRegion.COLD, ShoreBiomes.STONE_SHORE),
GRAVELLY_MOUNTAINS(0.2f, TemperatureRegion.COLD),
WOODED_MOUNTAINS(0.2f, TemperatureRegion.COLD, ShoreBiomes.STONE_SHORE),
MODIFIED_GRAVELLY_MOUNTAINS(0.2f, TemperatureRegion.COLD),
TAIGA(0.25f, TemperatureRegion.COLD),
TAIGA_MOUNTAINS(0.25f, TemperatureRegion.COLD),
GIANT_TREE_TAIGA(0.3f, TemperatureRegion.COLD),
GIANT_SPRUCE_TAIGA(0.25f, TemperatureRegion.COLD),
PLAINS(0.8f, TemperatureRegion.LUSH),
SUNFLOWER_PLAINS(0.8f, TemperatureRegion.LUSH),
FOREST(0.7f, TemperatureRegion.LUSH),
FLOWER_FOREST(0.7f, TemperatureRegion.LUSH),
BIRCH_FOREST(0.6f, TemperatureRegion.LUSH),
TALL_BIRCH_FOREST(0.7f, TemperatureRegion.LUSH),
DARK_FOREST(0.7f, TemperatureRegion.LUSH),
DARK_FOREST_HILLS(0.7f, TemperatureRegion.LUSH),
SWAMP(0.8f, TemperatureRegion.LUSH),
SWAMP_HILLS(0.8f, TemperatureRegion.LUSH),
JUNGLE(0.95f, TemperatureRegion.LUSH),
MODIFIED_JUNGLE(0.95f, TemperatureRegion.LUSH),
JUNGLE_EDGE(0.95f, TemperatureRegion.LUSH),
MODIFIED_JUNGLE_EDGE(0.95f, TemperatureRegion.LUSH),
BAMBOO_JUNGLE(0.95f, TemperatureRegion.LUSH),
MUSHROOM_FIELDS(0.9f, TemperatureRegion.LUSH, ShoreBiomes.MUSHROOM_SHORE),
DESERT(2.0f, TemperatureRegion.WARM),
SAVANNA(1.2f, TemperatureRegion.WARM),
SHATTERED_SAVANNA(1.1f, TemperatureRegion.WARM),
BADLANDS(2.0f, TemperatureRegion.WARM),
ERODED_BADLANDS(2.0f, TemperatureRegion.WARM),
WOODED_BADLANDS_PLATEAU(2.0f, TemperatureRegion.WARM),
MODIFIED_WOODED_BADLANDS_PLATEAU(2.0f, TemperatureRegion.WARM),
BADLANDS_PLATEAU(2.0f, TemperatureRegion.WARM),
SAVANNA_PLATEAU(1.0f, TemperatureRegion.WARM),
MODIFIED_BADLANDS_PLATEAU(2.0f, TemperatureRegion.WARM),
SHATTERED_SAVANNA_PLATEAU(1.0f, TemperatureRegion.WARM),
;
private final float temperature;
private final TemperatureRegion temperatureRegion;
private final ShoreBiomes[] preferredShores;
private MainBiomes(float temperature, TemperatureRegion temperatureRegion, ShoreBiomes... preferredShore) {
this.temperature = temperature;
this.preferredShores = preferredShore;
this.temperatureRegion = temperatureRegion;
}
/**
* @return the temperature
*/
public float getTemperature() {
return temperature;
}
/**
* @return the preferredShore
*/
public ShoreBiomes[] getPreferredShores() {
return preferredShores;
}
/**
* @return the temperatureRegion
*/
public TemperatureRegion getTemperatureRegion() {
return temperatureRegion;
}
}
public enum OceanBiomes {
WARM_OCEAN(0.5f, TemperatureRegion.WARM),
LUKEWARM_OCEAN(0.5f, TemperatureRegion.LUSH),
OCEAN(0.5f, TemperatureRegion.LUSH),
COLD_OCEAN(0.5f, TemperatureRegion.COLD),
FROZEN_OCEAN(0.0f, TemperatureRegion.SNOWY);
private final float temperature;
private final TemperatureRegion temperatureRegion;
private OceanBiomes(float temperature, TemperatureRegion temperatureRegion) {
this.temperature = temperature;
this.temperatureRegion = temperatureRegion;
}
/**
* @return the temperature
*/
public float getTemperature() {
return temperature;
}
/**
* @return the temperatureRegion
*/
public TemperatureRegion getTemperatureRegion() {
return temperatureRegion;
}
}
public enum ShoreBiomes {
BEACH(0.8f, TemperatureRegion.LUSH),
SNOWY_BEACH(0.05f, TemperatureRegion.SNOWY),
MUSHROOM_SHORE(0.05f, TemperatureRegion.LUSH, true),
STONE_SHORE(0.2f, TemperatureRegion.COLD);
private final float temperature;
private final TemperatureRegion temperatureRegion;
private final boolean special;
private ShoreBiomes(float temperature, TemperatureRegion associatedTemperatureRegion, boolean special) {
this.temperature = temperature;
this.temperatureRegion = associatedTemperatureRegion;
this.special = special;
}
private ShoreBiomes(float temperature, TemperatureRegion associatedTemperatureRegion) {
this(temperature, associatedTemperatureRegion, false);
}
/**
* @return the temperature
*/
public float getTemperature() {
return temperature;
}
/**
* @return the temperatureRegion
*/
public TemperatureRegion getTemperatureRegion() {
return temperatureRegion;
}
/**
* @return the special
*/
public boolean isSpecial() {
return special;
}
}
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> 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.05d);
this(random, 0.02d);
}
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<>());
temperaturePartitionedLandBiomes.put(2f, new ArrayList<>());
temperaturePartitionedOceanBiomes.put(0.00f, new ArrayList<>());
temperaturePartitionedOceanBiomes.put(0.3f, new ArrayList<>());
temperaturePartitionedOceanBiomes.put(0.5f, new ArrayList<>());
registerLandBiomeTemperatures();
registerOceanBiomeTemperatures();
}
private void registerLandBiomeTemperatures() {
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 = GeneralUtilities.invertHashMap(landBiomeTemperatures);
for (Entry<Float, ArrayList<Biome>> entry : temperaturesForLand.entrySet()) {
if (entry.getKey() <= 0.05f) {
temperaturePartitionedLandBiomes.get(0.05f).addAll(entry.getValue());
} else if (entry.getKey() <= 0.3) {
temperaturePartitionedLandBiomes.get(0.3f).addAll(entry.getValue());
} else if (entry.getKey() <= 0.85f) {
temperaturePartitionedLandBiomes.get(0.95f).addAll(entry.getValue());
} else {
temperaturePartitionedLandBiomes.get(2.00f).addAll(entry.getValue());
}
}
}
private void registerOceanBiomeTemperatures() {
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 = GeneralUtilities.invertHashMap(oceanBiomeTemperatures);
for (Entry<Float, ArrayList<Biome>> entry : temperaturesForOcean.entrySet()) {
if (entry.getKey() <= 0.00f) {
temperaturePartitionedOceanBiomes.get(0.0f).addAll(entry.getValue());
} else if (entry.getKey() <= 0.3f) {
temperaturePartitionedOceanBiomes.get(0.3f).addAll(entry.getValue());
} else {
temperaturePartitionedOceanBiomes.get(0.5f).addAll(entry.getValue());
}
}
}
/**
* Obtains the normal temperature for the given biome.
* @param biome The given biome.
* @return the Minecraft temperature.
*/
public float getBiomeTemperature(Biome biome) {
String biomeName = biome.name().toLowerCase();
if (biomeName.endsWith("hills") || biomeName.endsWith("beach") || biomeName.endsWith("shore")) {
String biomeTypeName = biomeName;
biomeTypeName = biomeTypeName.replace("_hills", "");
biomeTypeName = biomeTypeName.replace("_beach", "");
biomeTypeName = biomeTypeName.replace("_shore", "");
for (Entry<Biome, Float> entry : landBiomeTemperatures.entrySet()) {
if (entry.getKey().name().toLowerCase().startsWith(biomeTypeName)) {
return entry.getValue();
}
}
}
return landBiomeTemperatures.get(biome);
}
/**
@@ -286,57 +36,25 @@ public class BiomeMap {
}
return Biome.JUNGLE_EDGE;
} else if (biomeName.contains("mountain")) {
//return Biome.MOUNTAIN_EDGE;
return null;
}
return null;
}
/**
* Finds the shore biome from the given information.
* @param from land biome that connects to it.
* @param temperature the Minecraft temperature of this shore.
* @return the shore biome associated with it.
*/
public Biome getShoreBiome(Biome from, float temperature) {
String biomeName = from.name().toLowerCase();
if (biomeName.contains("mushroom")) {
return Biome.MUSHROOM_FIELD_SHORE;
} else if (biomeName.contains("mountains")) {
return Biome.STONE_SHORE;
}
if (temperature < 0.05) {
return Biome.SNOWY_BEACH;
}
return Biome.BEACH;
}
public boolean isOceanBiome(Biome biome) {
return oceanBiomeTemperatures.containsKey(biome);
}
public boolean isLandBiome(Biome biome) {
return !isOceanBiome(biome);
}
/**
* Randomly selects a land biome that fits in given temperature.
* @param temperature Minecraft temperature to select biome from.
* @param seed The seed to use to select the biome.
* @return The randomly selected biome.
*/
public Biome getLandBiome(float temperature, int worldX, int worldZ) {
ArrayList<Biome> biomes = null;
if (temperature <= 0.05f) {
biomes = temperaturePartitionedLandBiomes.get(0.05f);
} else if (temperature <= 0.3) {
biomes = temperaturePartitionedLandBiomes.get(0.3f);
} else if (temperature <= 0.85f) {
biomes = temperaturePartitionedLandBiomes.get(0.95f);
public BiomeClassifications getClassification(float temperature) {
if (temperature <= 0.1f) {
return BiomeClassifications.SNOWY;
} else if (temperature <= 0.3f) {
return BiomeClassifications.COLD;
} else if (temperature <= 1f) {
return BiomeClassifications.LUSH;
} else {
biomes = temperaturePartitionedLandBiomes.get(2.00f);
return BiomeClassifications.WARM;
}
return biomes.get((int) ((noise.noise(worldX, worldZ, 0.5d, 0.5d, true) + 1d) / 2d) * biomes.size());
}
public LandBiomeInfo getLandBiomeInfo(float temperature, int worldX, int worldZ) {
return getClassification(temperature).getSelector().selectRandom((float) noise.noise(worldX, worldZ, 0.5d, 0.5d, true));
}
/**
@@ -347,18 +65,9 @@ public class BiomeMap {
* @param seed The seed to use to select the biome.
* @return The randomly selected biome.
*/
public Biome getOceanBiome(float temperature, boolean isDeep, int worldX, int worldZ) {
ArrayList<Biome> biomes = null;
if (temperature <= 0.00f) {
biomes = temperaturePartitionedOceanBiomes.get(0.0f);
} else if (temperature <= 0.3) {
biomes = temperaturePartitionedOceanBiomes.get(0.3f);
} else {
biomes = temperaturePartitionedOceanBiomes.get(0.5f);
}
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;
public OceanBiomeInfo getOceanBiome(float temperature) {
BiomeClassifications classification = getClassification(temperature);
return classification.getAssociatedOceanBiomeInfo();
}
}

View File

@@ -20,9 +20,8 @@ public class IslandWorldMap {
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 float SHALLOW_PORTION = 0.06f;
private final double SCALE = 0.005D;
private final double DEEP_OCEAN_PORTION = 0.6d;
private final DepthFirstSearch dfs;
public IslandWorldMap(Random random) {
@@ -159,10 +158,6 @@ public class IslandWorldMap {
return res;
}
public boolean isDeepOcean(int worldX, int worldZ) {
return getWorldValue(worldX, worldZ) <= -DEEP_OCEAN_PORTION;
}
/**
* Find the island's origin block. Will call the coordinate target validatable to end early if nessecary.
* @param worldX The x coordinate of the island block in question.

View File

@@ -8,12 +8,7 @@ import ca.recrown.islandsurvivalcraft.utilities.caching.Cache;
import ca.recrown.islandsurvivalcraft.utilities.datatypes.Point2;
public class TemperatureMap {
public enum TemperatureRegion {
SNOWY,
COLD,
LUSH,
WARM,
}
private final Cache<Point2, Float> temperatureCache;
private final double frequency = 0.5D;
private final double amplitude = 0.5D;
@@ -23,14 +18,14 @@ public class TemperatureMap {
public TemperatureMap(Random random) {
temperatureCache = new Cache<>(1024);
noiseGenerator = new SimplexOctaveGenerator(random, 2);
noiseGenerator.setScale(0.002D);
noiseGenerator.setScale(0.0009D);
}
public float getTemperature(int worldX, int worldZ) {
Point2 loc = new Point2(worldX, worldZ);
Float val = temperatureCache.get(loc);
if (val == null) {
val = (float) noiseGenerator.noise(worldX, worldZ, frequency, amplitude, true);
val = (float) (((noiseGenerator.noise(worldX, worldZ, frequency, amplitude, true) + 1D) / 2D) * 3D - 1D);
temperatureCache.set(loc, val);
}
return val;

View File

@@ -1,9 +1,13 @@
package ca.recrown.islandsurvivalcraft.world.generation.biomes;
import java.util.Arrays;
import org.bukkit.World;
import org.bukkit.block.Biome;
import ca.recrown.islandsurvivalcraft.utilities.GeneralUtilities;
import ca.recrown.islandsurvivalcraft.utilities.biomes.LandBiomeInfo;
import ca.recrown.islandsurvivalcraft.utilities.biomes.OceanBiomeInfo;
import ca.recrown.islandsurvivalcraft.utilities.caching.Cache;
import ca.recrown.islandsurvivalcraft.utilities.datatypes.Point2;
import ca.recrown.islandsurvivalcraft.utilities.floodfill.Floodable;
@@ -15,6 +19,9 @@ import ca.recrown.islandsurvivalcraft.world.IslandWorldMap;
import ca.recrown.islandsurvivalcraft.world.TemperatureMap;
public class UniqueBiomeGenerator implements BiomeGenerator {
private final double DEEP_OCEAN_PORTION = 0.5d;
private final double HILL_PORTION = 0.4;
@Override
public void generateBiomeColumn(Biome[][][] chunkBiomeSets, World world, int chunkX, int chunkZ, int localX, int localZ, IslandWorldMap islandMap, BiomeMap biomeSelector, TemperatureMap tempGen, Cache<Point2, Biome[]> biomeCache) {
int worldX = 16 * chunkX + localX;
@@ -30,7 +37,8 @@ public class UniqueBiomeGenerator implements BiomeGenerator {
//Fine, check if it's ocean.
if (!islandMap.isIsland(worldX, worldZ)) {
biomeSet = chunkBiomeSets[localX][localZ];
biomeSet[0] = biomeSelector.getOceanBiome(tempGen.getTemperature(worldX, worldZ), islandMap.isDeepOcean(worldX, worldZ), worldX, worldZ);
OceanBiomeInfo ocean = biomeSelector.getOceanBiome(tempGen.getTemperature(worldX, worldZ));
biomeSet[0] = islandMap.getWorldValue(worldX, worldZ) >= -DEEP_OCEAN_PORTION ? ocean.getOcean() : ocean.getDeepAlternative();
setCacheBiome(worldX, worldZ, biomeSet, chunkBiomeSets, biomeCache);
return;
}
@@ -39,13 +47,16 @@ public class UniqueBiomeGenerator implements BiomeGenerator {
IslandInfo islandInfo = new IslandInfo(islandMap, world, biomeCache);
Point2 islandOrigin = islandMap.findIslandOrigin(worldX, worldZ, islandInfo);
if (!islandInfo.isComplete()) {
float temp = tempGen.getTemperature(worldX, worldZ);
if (islandInfo.main == null) islandInfo.main = biomeSelector.getLandBiome(temp, islandOrigin.x, islandOrigin.y);
if (islandInfo.shore == null) islandInfo.shore = biomeSelector.getShoreBiome(islandInfo.main, temp);
if (islandInfo.shallow == null) islandInfo.shallow = biomeSelector.getOceanBiome(temp, islandMap.isDeepOcean(islandOrigin.x, islandOrigin.y), islandOrigin.x, islandOrigin.y);
float temp = tempGen.getTemperature(islandOrigin.x, islandOrigin.y);
LandBiomeInfo biomeInfo = biomeSelector.getLandBiomeInfo(temp, islandOrigin.x, islandOrigin.y);
islandInfo.biomeset = new Biome[5];
islandInfo.biomeset[1] = biomeInfo.getBiome();
islandInfo.biomeset[2] = biomeInfo.getPreferredShore() == null ? Biome.BEACH : biomeInfo.getPreferredShore();
islandInfo.biomeset[4] = biomeInfo.getHillBiome() == null ? islandInfo.biomeset[1] : biomeInfo.getHillBiome();
islandInfo.biomeset[3] = islandInfo.biomeset[2];
}
PropagatorInfo propInfo = new PropagatorInfo(islandInfo, chunkBiomeSets, new Point2(chunkX, chunkZ), islandMap, biomeCache);
PropagatorInfo propInfo = new PropagatorInfo(islandInfo.biomeset, chunkBiomeSets, new Point2(chunkX, chunkZ), islandMap, biomeCache);
Flooder flooder = new Flooder(new Point2(worldX, worldZ), propInfo);
flooder.start();
}
@@ -76,7 +87,7 @@ public class UniqueBiomeGenerator implements BiomeGenerator {
public final IslandWorldMap mapper;
public final World world;
private final Cache<Point2, Biome[]> biomeCache;
public Biome main, shore, shallow;
private Biome[] biomeset;
public IslandInfo(IslandWorldMap mapper, World world, Cache<Point2, Biome[]> biomeCache) {
this.mapper = mapper;
@@ -86,22 +97,12 @@ public class UniqueBiomeGenerator implements BiomeGenerator {
@Override
public boolean isCoordinateTarget(int x, int y) {
Biome[] biomeSet = attemptGetBiomeSet(world, x, y, biomeCache, null);
if (biomeSet != null) {
main = biomeSet[1];
shore = biomeSet[2];
shallow = biomeSet[3];
if ((main == null || shore == null) && mapper.isLand(x, y)) {
if (shore == null && mapper.isShore(x, y)) {
main = biomeSet[0];
} else if (main == null && !mapper.isShore(x, y)) {
shore = biomeSet[0];
}
} else if (shallow == null) {
shallow = biomeSet[0];
}
biomeset = attemptGetBiomeSet(world, x, y, biomeCache, null);
if (biomeset != null) {
if (!isComplete()) throw new IllegalStateException("There was an incomplete biome set.");
return true;
}
return isComplete();
return false;
}
@Override
@@ -110,21 +111,19 @@ public class UniqueBiomeGenerator implements BiomeGenerator {
}
public boolean isComplete() {
return main != null && shore != null && shallow != null;
return !(biomeset == null || biomeset[1] == null || biomeset[2] == null || biomeset[3] == null || biomeset[4] == null);
}
}
private class PropagatorInfo implements Floodable {
private final Biome shallow, shore, main;
private final Biome[] biomeset;
private final Biome[][][] biomes;
private final Point2 chunkCoords;
private final IslandWorldMap mapper;
private final 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;
public PropagatorInfo(Biome[] biomeset, Biome[][][] biomes, Point2 chunkCoords, IslandWorldMap mapper, Cache<Point2, Biome[]> biomeCache) {
this.biomeset = biomeset;
this.biomes = biomes;
this.chunkCoords = chunkCoords;
this.mapper = mapper;
@@ -137,18 +136,17 @@ public class UniqueBiomeGenerator implements BiomeGenerator {
if (!this.chunkCoords.fastEquals(chunkCoords) || !mapper.isIsland(point.x, point.y)) return false;
int x = point.x;
int y = point.y;
Biome[] biomeSet = new Biome[4];
biomeSet[1] = main;
biomeSet[2] = shore;
biomeSet[3] = shallow;
Biome[] biomeSet = Arrays.copyOf(biomeset, biomeset.length);
if (mapper.isLand(x, y)) {
if (mapper.isShore(x, y)) {
biomeSet[0] = shore;
biomeSet[0] = biomeset[2];
} else if (mapper.getWorldValue(x, y) >= HILL_PORTION) {
biomeSet[0] = biomeset[4];
} else {
biomeSet[0] = main;
biomeSet[0] = biomeset[1];
}
} else {
biomeSet[0] = shallow;
biomeSet[0] = biomeset[3];
}
setCacheBiome(x, y, biomeSet, biomes, biomeCache);

View File

@@ -1,8 +1,6 @@
package ca.recrown.islandsurvivalcraft.world.generation.chunks;
import java.util.LinkedList;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
@@ -40,8 +38,7 @@ public class IslandWorldChunkGenerator extends ChunkGenerator implements Listene
private volatile WorldHeightShader heightShader;
private volatile WorldLayerShader layerShader;
private volatile Cache<Point2, Biome[]> biomeCache = new Cache<>(131072);
private volatile ExecutorService exAlpha = GeneralUtilities.ISC_EXECUTOR_ALPHA;
private volatile ExecutorService exBeta = GeneralUtilities.ISC_EXECUTOR_BETA;
private final ExecutorService exAlpha = GeneralUtilities.ISC_EXECUTOR_ALPHA;
public void initialize() {
if (initialized) throw new IllegalStateException("This generator has already been initialized.");
@@ -77,9 +74,6 @@ public class IslandWorldChunkGenerator extends ChunkGenerator implements Listene
worldInfo.initialize(world, this);
}
if (!initialized) throw new IllegalStateException("This generator has not been initialized.");
LinkedList<Future<Boolean>> tasks = new LinkedList<>();
ChunkData chunkData = createChunkData(world);
Future<Boolean> preLoader = exAlpha.submit(() -> {
for (int x = GeneralUtilities.CHUNK_SIZE - 1; x >= 0; x--) {
for (int z = GeneralUtilities.CHUNK_SIZE - 1; z >= 0; z--) {
@@ -90,7 +84,9 @@ public class IslandWorldChunkGenerator extends ChunkGenerator implements Listene
return true;
});
Biome[][][] biomeArraySet = new Biome[GeneralUtilities.CHUNK_SIZE][GeneralUtilities.CHUNK_SIZE][4];
ChunkData chunkData = createChunkData(world);
Biome[][][] biomeArraySet = new Biome[GeneralUtilities.CHUNK_SIZE][GeneralUtilities.CHUNK_SIZE][5];
for (int x = 0; x < GeneralUtilities.CHUNK_SIZE; x++) {
for (int z = 0; z < GeneralUtilities.CHUNK_SIZE; z++) {
final int localX = x;
@@ -101,13 +97,10 @@ public class IslandWorldChunkGenerator extends ChunkGenerator implements Listene
biomeGenerator.generateBiomeColumn(biomeArraySet, world, chunkX, chunkZ, localX, localZ, islandMap, biomeMap,
temperatureMap, biomeCache);
}
if (biomeArraySet[localX][localZ][0] == null) throw new IllegalStateException("Biome was null.");
tasks.add(exBeta.submit(() -> {
for (int y = 0; y < worldInfo.getWorldHeight(); y++) {
biomeGrid.setBiome(localX, y, localZ, biomeArraySet[localX][localZ][0]);
}
return true;
}));
for (int y = 0; y < worldInfo.getWorldHeight(); y++) {
biomeGrid.setBiome(localX, y, localZ, biomeArraySet[localX][localZ][0]);
}
Biome[] currentBiomeSet = biomeArraySet[localX][localZ];
int terrainHeight = heightShader.getTerrainHeight(worldX, worldZ, currentBiomeSet);
@@ -135,16 +128,7 @@ public class IslandWorldChunkGenerator extends ChunkGenerator implements Listene
chunkData.setRegion(localX, 0, localZ, localX + 1, bedrockHeight, localZ + 1, Material.BEDROCK);
}
}
preLoader.cancel(false);
try {
while (!tasks.isEmpty()) {
tasks.poll().get();
}
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
throw new IllegalStateException(e.getCause().getMessage());
}
return chunkData;
}

View File

@@ -27,11 +27,15 @@ public class WorldHeightShader {
int height = 0;
String biomeName = biomeSet[0].name().toLowerCase();
if (!mapper.isLand(worldX, worldZ)) {
height = (int) calculateTerrainFactor(worldX, worldZ, seaLevel * 0.8d, 1.7d, 0.5d, 1d, 0.1d);
height = (int) Math.floor(calculateTerrainFactor(worldX, worldZ, seaLevel * 0.8d, 1.7d, 0.5d, 1d, 0.09d));
} else if (biomeName.contains("beach")) {
height = (int) (getIslandBiomeHeight(worldX, worldZ, biomeSet[1], 10d));
if (biomeSet[1].name().toLowerCase().contains("mountains")) {
height = (int) (getIslandBiomeHeight(worldX, worldZ, biomeSet[1], -15d));
} else {
height = (int) (getIslandBiomeHeight(worldX, worldZ, biomeSet[1], 0d));
}
} else if (biomeName.contains("shore")) {
height = (int) (getIslandBiomeHeight(worldX, worldZ, biomeSet[1], -30d));
height = (int) (getIslandBiomeHeight(worldX, worldZ, biomeSet[1], -15d));
} else {
height = getIslandBiomeHeight(worldX, worldZ, biomeSet[0], 0d) + 1;
}
@@ -44,10 +48,8 @@ public class WorldHeightShader {
private int getIslandBiomeHeight(int worldX, int worldZ, Biome biome, double heightModifier) {
int res = 0;
String biomeName = biome.name().toLowerCase();
if (biomeName.contains("hills")) {
res = (int) calculateTerrainFactor(worldX, worldZ, 60d + heightModifier, 1.5d, 0.5d);
} else if (biomeName.contains("mountains")) {
res = (int) calculateTerrainFactor(worldX, worldZ, 200d + heightModifier, 1.8d, 0.5d);
if (biomeName.contains("mountains")) {
res = (int) calculateTerrainFactor(worldX, worldZ, 180d + heightModifier, 1.88d, 0.5d);
} else if (biomeName.contains("plateau")) {
res = (int) Math.min(calculateTerrainFactor(worldX, worldZ, 60d + heightModifier), seaLevel + 30d);
} else if (biomeName.contains("modified")) {