Implement ocean palettes and improve biome abstraction.

This commit is contained in:
dfsek 2020-09-28 00:13:36 -07:00
parent cfbd6533dd
commit 12c0d561d1
5 changed files with 201 additions and 162 deletions

View File

@ -28,7 +28,6 @@ public class WorldConfig {
public float zoneFreq;
public float freq1;
public float freq2;
public int seaLevel;
public boolean fromImage;
public UserDefinedGrid[] definedGrids;
public ImageLoader.Channel biomeXChannel;
@ -72,7 +71,6 @@ public class WorldConfig {
// Get values from config.
seaLevel = config.getInt("sea-level", 63);
zoneFreq = 1f/config.getInt("frequencies.zone", 1536);
freq1 = 1f/config.getInt("frequencies.grid-x", 256);
freq2 = 1f/config.getInt("frequencies.grid-z", 512);

View File

@ -20,6 +20,7 @@ import org.polydev.gaea.world.palette.RandomPalette;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
@ -28,22 +29,25 @@ import java.util.TreeMap;
public class AbstractBiomeConfig extends TerraConfigObject {
private static final Map<String, AbstractBiomeConfig> biomes = new HashMap<>();
private String biomeID;
private Map<OreConfig, Range> ores;
private Map<OreConfig, Range> oreHeights;
private Map<CarverConfig, Integer> carvers;
private ProbabilityCollection<Flora> flora;
private ProbabilityCollection<Tree> trees;
private int floraChance;
private int treeChance;
private int treeDensity;
private String equation;
private int floraAttempts;
private Map<Flora, Range> floraHeights;
private TreeMap<Integer, Palette<BlockData>> paletteMap;
private double slabThreshold;
private Map<Material, Palette<BlockData>> slabs;
private Map<Material, Palette<BlockData>> stairs;
private boolean useStairs;
private boolean floraSimplex;
private int floraSeed;
private float floraFreq;
private String oceanPalette;
private int seaLevel;
private List<Map<?, ?>> paletteData;
private Map<String, Object> floraData;
private Map<String, Object> oreData;
private Map<String, Object> treeData;
private List<Map<?, ?>> carvingData;
public AbstractBiomeConfig(File file) throws IOException, InvalidConfigurationException {
super(file);
@ -54,101 +58,26 @@ public class AbstractBiomeConfig extends TerraConfigObject {
if(!contains("id")) throw new InvalidConfigurationException("Abstract Biome ID unspecified!");
this.biomeID = getString("id");
if(contains("palette")) {
paletteMap = new TreeMap<>();
for(Map<?, ?> e : getMapList("palette")) {
for(Map.Entry<?, ?> entry : e.entrySet()) {
try {
if(((String) entry.getKey()).startsWith("BLOCK:")) {
try {
paletteMap.put((Integer) entry.getValue(), new RandomPalette(new Random(0)).add(new ProbabilityCollection<BlockData>().add(Bukkit.createBlockData(((String) entry.getKey()).substring(6)), 1), 1));
} catch(IllegalArgumentException ex) {
throw new InvalidConfigurationException("SEVERE configuration error for Palettes in abstract biome, ID: " + biomeID + ". BlockData " + entry.getKey() + " is invalid!");
}
} else {
try {
paletteMap.put((Integer) entry.getValue(), PaletteConfig.fromID((String) entry.getKey()).getPalette());
} catch(NullPointerException ex) {
throw new InvalidConfigurationException("SEVERE configuration error for Palettes in abstract biome, ID: " + biomeID + "\n\nPalette " + entry.getKey() + " cannot be found!");
}
}
} catch(ClassCastException ex) {
throw new InvalidConfigurationException("SEVERE configuration error for Palettes in abstract biome, ID: " + biomeID);
}
}
}
}
if(contains("carving")) carvingData = getMapList("carving");
if(contains("carving")) {
carvers = new HashMap<>();
for(Map<?, ?> e : getMapList("carving")) {
for(Map.Entry<?, ?> entry : e.entrySet()) {
try {
//carvers.add(new UserDefinedCarver((Integer) entry.getValue(), ConfigUtil.getCarver((String) entry.getKey())));
CarverConfig c = CarverConfig.fromID((String) entry.getKey());
Bukkit.getLogger().info("Got carver " + c + ". Adding with weight " + entry.getValue());
carvers.put(c, (Integer) entry.getValue());
} catch(ClassCastException ex) {
throw new InvalidConfigurationException("SEVERE configuration error for Carvers in abstract biom, ID: " + biomeID);
} catch(NullPointerException ex) {
throw new InvalidConfigurationException("SEVERE configuration error for Carvers in abstract biome, ID: " + biomeID + "\n\n" + "No such carver " + entry.getKey());
}
}
}
}
if(contains("palette")) paletteData = getMapList("palette");
if(contains("flora")) floraData = Objects.requireNonNull(getConfigurationSection("flora")).getValues(false);
if(contains("trees")) treeData = Objects.requireNonNull(getConfigurationSection("trees")).getValues(false);
if(contains("ores")) oreData = Objects.requireNonNull(getConfigurationSection("ores")).getValues(false);
if(contains("flora")) {
floraHeights = new HashMap<>();
flora = new ProbabilityCollection<>();
try {
for(Map.Entry<String, Object> e : Objects.requireNonNull(getConfigurationSection("flora")).getValues(false).entrySet()) {
Map<?, ?> val = ((ConfigurationSection) e.getValue()).getValues(false);
Map<?, ?> y = ((ConfigurationSection) val.get("y")).getValues(false);
try {
Bukkit.getLogger().info("[Terra] Adding " + e.getKey() + " to biome's flora list with weight " + e.getValue());
Flora floraObj = FloraType.valueOf(e.getKey());
flora.add(floraObj, (Integer) val.get("weight"));
floraHeights.put(floraObj, new Range((Integer) y.get("min"), (Integer) y.get("max")));
} catch(IllegalArgumentException ex) {
try {
Bukkit.getLogger().info("[Terra] Is custom flora: true");
Flora floraCustom = FloraConfig.fromID(e.getKey());
flora.add(floraCustom, (Integer) val.get("weight"));
floraHeights.put(floraCustom, new Range((Integer) y.get("min"), (Integer) y.get("max")));
} catch(NullPointerException ex2) {
throw new InvalidConfigurationException("SEVERE configuration error for flora in biome, ID " + getID() + "\n\nFlora with ID " + e.getKey() + " cannot be found!");
}
}
}
} catch(ClassCastException e) {
if(ConfigUtil.debug) e.printStackTrace();
throw new InvalidConfigurationException("SEVERE configuration error for flora in biome, ID " + getID());
}
}
if(contains("trees")) {
trees = new ProbabilityCollection<>();
for(Map.Entry<String, Object> e : Objects.requireNonNull(getConfigurationSection("trees")).getValues(false).entrySet()) {
if(e.getKey().startsWith("TERRA:")) {
trees.add(TerraTree.valueOf(e.getKey().substring(6)), (Integer) e.getValue());
} else {
trees.add(TreeType.valueOf(e.getKey()), (Integer) e.getValue());
}
}
}
floraChance = getInt("flora-chance", 0);
floraAttempts = getInt("flora-attempts", 1);
treeChance = getInt("tree-chance", 0);
treeDensity = getInt("tree-density", 0);
equation = getString("noise-equation");
if(contains("ores")) {
ores = new HashMap<>();
oreHeights = new HashMap<>();
for(Map.Entry<String, Object> m : Objects.requireNonNull(getConfigurationSection("ores")).getValues(false).entrySet()) {
ores.put(OreConfig.fromID(m.getKey()), new Range(((ConfigurationSection) m.getValue()).getInt("min"), ((ConfigurationSection) m.getValue()).getInt("max")));
oreHeights.put(OreConfig.fromID(m.getKey()), new Range(((ConfigurationSection) m.getValue()).getInt("min-height"), ((ConfigurationSection) m.getValue()).getInt("max-height")));
}
}
floraSimplex = getBoolean("flora-simplex.enable", false);
floraFreq = (float) getDouble("flora-simplex.frequency", 0.1);
floraSeed = getInt("flora-simplex.seed", 0);
seaLevel = getInt("ocean.level", 62);
oceanPalette = getString("ocean.palette");
// Get slab stuff
useStairs = false;
@ -185,42 +114,10 @@ public class AbstractBiomeConfig extends TerraConfigObject {
return treeDensity;
}
public Map<CarverConfig, Integer> getCarvers() {
return carvers;
}
public Map<OreConfig, Range> getOreHeights() {
return oreHeights;
}
public Map<OreConfig, Range> getOres() {
return ores;
}
public Map<Flora, Range> getFloraHeights() {
return floraHeights;
}
public static Map<String, AbstractBiomeConfig> getBiomes() {
return biomes;
}
public ProbabilityCollection<Flora> getFlora() {
return flora;
}
public ProbabilityCollection<Tree> getTrees() {
return trees;
}
public String getEquation() {
return equation;
}
public TreeMap<Integer, Palette<BlockData>> getPaletteMap() {
return paletteMap;
}
public static AbstractBiomeConfig fromID(String id) {
return biomes.get(id);
}
@ -240,4 +137,44 @@ public class AbstractBiomeConfig extends TerraConfigObject {
public boolean shouldUseStairs() {
return useStairs;
}
public float getFloraFreq() {
return floraFreq;
}
public int getFloraSeed() {
return floraSeed;
}
public boolean isFloraSimplex() {
return floraSimplex;
}
public List<Map<?, ?>> getPaletteData() {
return paletteData;
}
public Map<String, Object> getFloraData() {
return floraData;
}
public Map<String, Object> getOreData() {
return oreData;
}
public Map<String, Object> getTreeData() {
return treeData;
}
public List<Map<?, ?>> getCarvingData() {
return carvingData;
}
public int getSeaLevel() {
return seaLevel;
}
public String getOceanPalette() {
return oceanPalette;
}
}

View File

@ -14,6 +14,7 @@ import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Stairs;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.InvalidConfigurationException;
import org.polydev.gaea.math.FastNoise;
import org.polydev.gaea.math.ProbabilityCollection;
import org.polydev.gaea.math.parsii.tokenizer.ParseException;
import org.polydev.gaea.tree.Tree;
@ -37,6 +38,7 @@ import java.util.TreeMap;
public class BiomeConfig extends TerraConfigObject {
private static final Map<String, BiomeConfig> biomes = new HashMap<>();
private static final Palette<BlockData> oceanDefault = new RandomPalette<BlockData>(new Random(0)).add(Material.WATER.createBlockData(), 1);
private UserDefinedBiome biome;
private String biomeID;
private String friendlyName;
@ -49,6 +51,10 @@ public class BiomeConfig extends TerraConfigObject {
private Map<Material, Palette<BlockData>> slabs;
private Map<Material, Palette<BlockData>> stairs;
private double slabThreshold;
private boolean floraSimplex;
private FastNoise floraNoise;
private Palette<BlockData> ocean;
private int seaLevel;
public BiomeConfig(File file) throws InvalidConfigurationException, IOException {
super(file);
@ -78,12 +84,18 @@ public class BiomeConfig extends TerraConfigObject {
TreeMap<Integer, Palette<BlockData>> paletteMap;
// Check if biome is extending abstract biome, only use abstract biome's palette if palette is NOT defined for current biome.
if(extending && abstractBiome.getPaletteMap() != null && !contains("palette")) {
paletteMap = abstractBiome.getPaletteMap();
Bukkit.getLogger().info("Using super palette");
} else if(contains("palette")) {
List<Map<?, ?>> paletteData;
try {
if(extending && abstractBiome.getPaletteData() != null && ! contains("palette")) {
paletteData = abstractBiome.getPaletteData();
Bukkit.getLogger().info("Using super palette");
} else paletteData = getMapList("palette");
} catch(NullPointerException e) {
paletteData = null;
}
if(paletteData != null) {
paletteMap = new TreeMap<>();
for(Map<?, ?> e : getMapList("palette")) {
for(Map<?, ?> e : paletteData) {
for(Map.Entry<?, ?> entry : e.entrySet()) {
try {
if(((String) entry.getKey()).startsWith("BLOCK:")) {
@ -108,12 +120,19 @@ public class BiomeConfig extends TerraConfigObject {
} else throw new InvalidConfigurationException("No palette specified in biome or super biome.");
// Check if carving should be handled by super biome.
if(extending && abstractBiome.getCarvers() != null && !contains("carving")) {
carvers = abstractBiome.getCarvers();
Bukkit.getLogger().info("Using super carvers");
} else if(contains("carving")) {
carvers = new HashMap<>();
for(Map<?, ?> e : getMapList("carving")) {
List<Map<?, ?>> carvingData;
try {
if(extending && abstractBiome.getCarvingData() != null && ! contains("carving")) {
carvingData = abstractBiome.getCarvingData();
Bukkit.getLogger().info("Using super carvers");
} else carvingData = getMapList("carving");
} catch(NullPointerException e) {
carvingData = null;
}
carvers = new HashMap<>();
if(carvingData != null) {
for(Map<?, ?> e : carvingData) {
for(Map.Entry<?, ?> entry : e.entrySet()) {
try {
CarverConfig c = CarverConfig.fromID((String) entry.getKey());
@ -126,17 +145,23 @@ public class BiomeConfig extends TerraConfigObject {
}
}
}
} else carvers = new HashMap<>();
}
int floraChance, treeChance, treeDensity;
// Get various simple values using getOrDefault config methods.
float floraFreq;
int floraSeed;
try {
slabThreshold = getDouble("slabs.threshold", Objects.requireNonNull(abstractBiome).getSlabThreshold());
floraChance = getInt("flora-chance", Objects.requireNonNull(abstractBiome).getFloraChance());
floraAttempts = getInt("flora-attempts", Objects.requireNonNull(abstractBiome).getFloraAttempts());
treeChance = getInt("tree-chance", Objects.requireNonNull(abstractBiome).getTreeChance());
treeDensity = getInt("tree-density", Objects.requireNonNull(abstractBiome).getTreeDensity());
floraSeed = getInt("flora-simplex.seed", Objects.requireNonNull(abstractBiome).getFloraSeed());
floraSimplex = getBoolean("flora-simplex.enable", Objects.requireNonNull(abstractBiome).isFloraSimplex());
floraFreq = (float) getDouble("flora-simplex.frequency", Objects.requireNonNull(abstractBiome).getFloraFreq());
seaLevel = getInt("ocean.level", Objects.requireNonNull(abstractBiome).getSeaLevel());
eq = getString("noise-equation", Objects.requireNonNull(abstractBiome).getEquation());
} catch(NullPointerException e) {
slabThreshold = getDouble("slabs.threshold", 0.1D);
@ -144,19 +169,34 @@ public class BiomeConfig extends TerraConfigObject {
floraAttempts = getInt("flora-attempts", 1);
treeChance = getInt("tree-chance", 0);
treeDensity = getInt("tree-density", 0);
floraSeed = getInt("flora-simplex.seed", 0);
floraSimplex = getBoolean("flora-simplex.enable", false);
floraFreq = (float) getDouble("flora-simplex.frequency", 0.1);
seaLevel = getInt("ocean.level", 62);
eq = getString("noise-equation", null);
}
if(floraSimplex) {
floraNoise = new FastNoise(floraSeed);
floraNoise.setNoiseType(FastNoise.NoiseType.Simplex);
floraNoise.setFrequency(floraFreq);
}
// Check if flora should be handled by super biome.
ProbabilityCollection<Flora> flora = new ProbabilityCollection<>();
if(extending && abstractBiome.getFlora() != null && !contains("flora")) {
flora = abstractBiome.getFlora();
floraHeights = abstractBiome.getFloraHeights();
Bukkit.getLogger().info("Using super flora (" + flora.size() + " entries, " + floraChance + " % chance)");
} else if(contains("flora")) {
Map<String, Object> floraData;
try {
if(extending && abstractBiome.getFloraData() != null && ! contains("flora")) {
floraData = abstractBiome.getFloraData();
Bukkit.getLogger().info("Using super flora (" + flora.size() + " entries, " + floraChance + " % chance)");
} else floraData = Objects.requireNonNull(getConfigurationSection("flora")).getValues(false);
} catch(NullPointerException e) {
floraData = null;
}
if(floraData != null) {
floraHeights = new HashMap<>();
try {
for(Map.Entry<String, Object> e : Objects.requireNonNull(getConfigurationSection("flora")).getValues(false).entrySet()) {
for(Map.Entry<String, Object> e : floraData.entrySet()) {
Map<?, ?> val = ((ConfigurationSection) e.getValue()).getValues(false);
Map<?, ?> y = ((ConfigurationSection) val.get("y")).getValues(false);
try {
@ -182,12 +222,18 @@ public class BiomeConfig extends TerraConfigObject {
} else flora = new ProbabilityCollection<>();
// Check if trees should be handled by super biome.
Map<String, Object> treeData;
ProbabilityCollection<Tree> trees = new ProbabilityCollection<>();
if(extending && abstractBiome.getTrees() != null && !contains("trees")) {
trees = abstractBiome.getTrees();
Bukkit.getLogger().info("Using super trees");
} else if(contains("trees")) {
for(Map.Entry<String, Object> e : Objects.requireNonNull(getConfigurationSection("trees")).getValues(false).entrySet()) {
try {
if(extending && abstractBiome.getTreeData() != null && ! contains("trees")) {
treeData = abstractBiome.getTreeData();
Bukkit.getLogger().info("Using super trees");
} else treeData = Objects.requireNonNull(getConfigurationSection("trees")).getValues(false);
} catch(NullPointerException e) {
treeData = null;
}
if(treeData != null) {
for(Map.Entry<String, Object> e : treeData.entrySet()) {
if(e.getKey().startsWith("TERRA:")) {
trees.add(TerraTree.valueOf(e.getKey().substring(6)), (Integer) e.getValue());
} else {
@ -214,13 +260,17 @@ public class BiomeConfig extends TerraConfigObject {
// Check if ores should be handled by super biome.
oreHeights = new HashMap<>();
ores = new HashMap<>();
if(extending && abstractBiome.getOres() != null && !contains("ores")) {
ores = abstractBiome.getOres();
oreHeights = abstractBiome.getOreHeights();
Bukkit.getLogger().info("Using super ores");
} else if(contains("ores")) {
ores.clear();
for(Map.Entry<String, Object> m : Objects.requireNonNull(getConfigurationSection("ores")).getValues(false).entrySet()) {
Map<String, Object> oreData;
try {
if(extending && abstractBiome.getOreData() != null && ! contains("ores")) {
oreData = abstractBiome.getOreData();
Bukkit.getLogger().info("Using super ores");
} else oreData = Objects.requireNonNull(getConfigurationSection("ores")).getValues(false);
} catch(NullPointerException e) {
oreData = null;
}
if(oreData != null) {
for(Map.Entry<String, Object> m : oreData.entrySet()) {
ores.put(OreConfig.fromID(m.getKey()), new Range(((ConfigurationSection) m.getValue()).getInt("min"), ((ConfigurationSection) m.getValue()).getInt("max")));
oreHeights.put(OreConfig.fromID(m.getKey()), new Range(((ConfigurationSection) m.getValue()).getInt("min-height"), ((ConfigurationSection) m.getValue()).getInt("max-height")));
}
@ -229,6 +279,29 @@ public class BiomeConfig extends TerraConfigObject {
oreHeights = new HashMap<>();
}
// Ocean stuff
String oceanPalette;
try {
oceanPalette = getString("ocean.palette", Objects.requireNonNull(abstractBiome).getOceanPalette());
} catch(NullPointerException e) {
oceanPalette = null;
}
if(contains("ocean") && oceanPalette != null) {
if(oceanPalette.startsWith("BLOCK:")) {
try {
ocean = new RandomPalette<BlockData>(new Random(0)).add(new ProbabilityCollection<BlockData>().add(Bukkit.createBlockData(oceanPalette.substring(6)), 1), 1);
} catch(IllegalArgumentException ex) {
throw new InvalidConfigurationException("SEVERE configuration error for Ocean Palette in biome " + getFriendlyName() + ", ID: " + biomeID + ". BlockData " + oceanPalette + " is invalid!");
}
} else {
try {
ocean = PaletteConfig.fromID(oceanPalette).getPalette();
} catch(NullPointerException ex) {
throw new InvalidConfigurationException("SEVERE configuration error for Ocean Palette in biome " + getFriendlyName() + ", ID: " + biomeID + "\n\nPalette " + oceanPalette + " cannot be found!");
}
}
} else ocean = oceanDefault;
// Get slab stuff
if(contains("slabs") && getBoolean("slabs.enable", false)) {
@ -338,4 +411,20 @@ public class BiomeConfig extends TerraConfigObject {
public Map<Material, Palette<BlockData>> getSlabs() {
return slabs;
}
public boolean isFloraSimplex() {
return floraSimplex;
}
public FastNoise getFloraNoise() {
return floraNoise;
}
public Palette<BlockData> getOceanPalette() {
return ocean;
}
public int getSeaLevel() {
return seaLevel;
}
}

View File

@ -1,7 +1,9 @@
package com.dfsek.terra.generation;
import com.dfsek.terra.biome.TerraBiomeGrid;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.config.WorldConfig;
import com.dfsek.terra.config.genconfig.BiomeConfig;
import com.dfsek.terra.population.CavePopulator;
import com.dfsek.terra.population.FloraPopulator;
import com.dfsek.terra.population.OrePopulator;
@ -13,11 +15,15 @@ import org.bukkit.World;
import org.bukkit.block.data.BlockData;
import org.bukkit.generator.BlockPopulator;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.biome.Biome;
import org.polydev.gaea.biome.BiomeGrid;
import org.polydev.gaea.generation.GaeaChunkGenerator;
import org.polydev.gaea.generation.GenerationPhase;
import org.polydev.gaea.generation.GenerationPopulator;
import org.polydev.gaea.math.ChunkInterpolator;
import org.polydev.gaea.math.FastNoise;
import org.polydev.gaea.population.PopulationManager;
import org.polydev.gaea.world.palette.Palette;
import java.io.FileNotFoundException;
import java.io.IOException;
@ -46,12 +52,19 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
public ChunkData generateBase(@NotNull World world, @NotNull Random random, int chunkX, int chunkZ, FastNoise fastNoise) {
if(needsLoad) load(world);
ChunkData chunk = createChunkData(world);
int sea = WorldConfig.fromWorld(world).seaLevel;
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);
for(byte x = 0; x < 16; x++) {
for(byte z = 0; z < 16; z++) {
Biome b = getBiomeGrid(world).getBiome(xOrig+x, zOrig+z, GenerationPhase.PALETTE_APPLY);
BiomeConfig c = BiomeConfig.fromBiome((UserDefinedBiome) b);
int sea = c.getSeaLevel();
Palette<BlockData> seaPalette = c.getOceanPalette();
for(int y = 0; y < 256; y++) {
if(super.getInterpolatedNoise(x, y, z) > 0) chunk.setBlock(x, y, z, STONE);
else if(y < sea) chunk.setBlock(x, y, z, WATER);
else if(y <= sea) {
chunk.setBlock(x, y, z, seaPalette.get(sea-y, x+xOrig, z+zOrig));
}
}
}
}

View File

@ -34,7 +34,9 @@ public class FloraPopulator extends GaeaBlockPopulator {
try {
BiomeConfig c = BiomeConfig.fromBiome(biome);
for(int i = 0; i < c.getFloraAttempts(); i++) {
Flora item = biome.getDecorator().getFlora().get(random);
Flora item;
if(c.isFloraSimplex()) item = biome.getDecorator().getFlora().get(c.getFloraNoise(), (chunk.getX() << 4) + x, (chunk.getZ() << 4) + z);
else item = biome.getDecorator().getFlora().get(random);
Block highest = item.getHighestValidSpawnAt(chunk, x, z);
if(highest != null && c.getFloraHeights(item).isInRange(highest.getY()))
item.plant(highest.getLocation());