mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-04-10 01:36:19 +00:00
Implement fauna configuration
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
package com.dfsek.terra;
|
||||
|
||||
import com.dfsek.terra.biome.TerraBiomeGrid;
|
||||
import com.dfsek.terra.config.WorldConfig;
|
||||
import com.dfsek.terra.population.FaunaPopulator;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
import org.bukkit.generator.ChunkGenerator.ChunkData;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.polydev.gaea.biome.BiomeGrid;
|
||||
@@ -11,6 +14,7 @@ import org.polydev.gaea.generation.GenerationPopulator;
|
||||
import org.polydev.gaea.math.FastNoise;
|
||||
import org.polydev.gaea.math.InterpolationType;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
@@ -23,10 +27,12 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
|
||||
@Override
|
||||
public ChunkData generateBase(@NotNull World world, @NotNull Random random, int chunkX, int chunkZ, FastNoise fastNoise) {
|
||||
ChunkData chunk = createChunkData(world);
|
||||
int sea = WorldConfig.fromWorld(world).seaLevel;
|
||||
for(byte x = 0; x < 16; x++) {
|
||||
for(int y = 0; y < 256; y++) {
|
||||
for(byte z = 0; z < 16; z++) {
|
||||
if(super.getInterpolatedNoise(x, y, z) > 0) chunk.setBlock(x, y, z, Material.STONE);
|
||||
else if(y < sea) chunk.setBlock(x, y, z, Material.WATER);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,4 +57,9 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
|
||||
public org.polydev.gaea.biome.BiomeGrid getBiomeGrid(World world) {
|
||||
return TerraBiomeGrid.fromWorld(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<BlockPopulator> getDefaultPopulators(@NotNull World world) {
|
||||
return Arrays.asList(new FaunaPopulator());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,23 +13,26 @@ public class BiomeZone {
|
||||
private final World w;
|
||||
private final FastNoise noise;
|
||||
private static final Map<World, BiomeZone> zones = new HashMap<>();
|
||||
private static final double[] normalMap = new double[] {-0.35662081837654114D, -0.30661869049072266D, -0.27095329761505127D, -0.24149227142333984D, -0.21537694334983826D, -0.19166918098926544D, -0.16956785321235657D, -0.14864568412303925D, -0.12845154106616974D, -0.10894706845283508D, -0.08996972441673279D, -0.0715663805603981D, -0.053535036742687225D, -0.03580872714519501D, -0.01817353256046772D, -7.577221258543432E-4D, 0.016616813838481903D, 0.03416096046566963D, 0.05187138542532921D, 0.06989025324583054D, 0.08827653527259827D, 0.10723070055246353D, 0.12675245106220245D, 0.14694781601428986D, 0.16793397068977356D, 0.18999846279621124D, 0.2138010412454605D, 0.24002985656261444D, 0.2696261405944824D, 0.30540621280670166D, 0.35551881790161133D, 0.653269350528717D};
|
||||
|
||||
|
||||
public BiomeZone(World w, float freq) {
|
||||
this.w = w;
|
||||
this.noise = new FastNoise((int) w.getSeed()+2);
|
||||
noise.setNoiseType(FastNoise.NoiseType.Value);
|
||||
noise.setNoiseType(FastNoise.NoiseType.SimplexFractal);
|
||||
noise.setFractalOctaves(5);
|
||||
noise.setFrequency(freq);
|
||||
setZones(WorldConfig.fromWorld(w).definedGrids);
|
||||
zones.put(w, this);
|
||||
}
|
||||
|
||||
public void setZones(BiomeGrid[] grids) {
|
||||
if(grids.length != 16) throw new IllegalArgumentException("Illegal number of grids!");
|
||||
if(grids.length != 32) throw new IllegalArgumentException("Illegal number of grids!");
|
||||
this.grids = grids;
|
||||
}
|
||||
|
||||
public BiomeGrid getGrid(int x, int z) {
|
||||
return grids[normalize(noise.getValue(x, z))];
|
||||
return grids[normalize(noise.getSimplexFractal(x, z))];
|
||||
}
|
||||
|
||||
public static BiomeZone fromWorld(World w) {
|
||||
@@ -38,14 +41,15 @@ public class BiomeZone {
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a noise input and normalizes it to a value between 0 and 15 inclusive.
|
||||
* Takes a noise input and normalizes it to a value between 0 and 31 inclusive.
|
||||
*
|
||||
* @param i - The noise value to normalize.
|
||||
* @param d - The noise value to normalize.
|
||||
* @return int - The normalized value.
|
||||
*/
|
||||
private static int normalize(double i) {
|
||||
if(i > 0) i = Math.pow(i, 0.8125); // Redistribute
|
||||
else i = -Math.pow(-i, 0.8125); // Redistribute
|
||||
return Math.min((int) Math.floor((i+1)*8), 15);
|
||||
public static int normalize(double d) {
|
||||
for(int i = 0; i < normalMap.length; i++) {
|
||||
if(d < normalMap[i]) return i;
|
||||
}
|
||||
return normalMap.length-1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,18 +10,30 @@ import org.polydev.gaea.math.parsii.eval.Parser;
|
||||
import org.polydev.gaea.math.parsii.eval.Scope;
|
||||
import org.polydev.gaea.math.parsii.tokenizer.ParseException;
|
||||
import org.polydev.gaea.structures.features.Feature;
|
||||
import org.polydev.gaea.world.BlockPalette;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class UserDefinedBiome implements Biome {
|
||||
private final UserDefinedGenerator gen;
|
||||
private final BiomeConfig config;
|
||||
private final UserDefinedDecorator decorator;
|
||||
public UserDefinedBiome(BiomeConfig config) throws ParseException {
|
||||
this.config = config;
|
||||
Scope s = Scope.create();
|
||||
gen = new UserDefinedGenerator(s, Parser.parse(Objects.requireNonNull(config.getString("noise-equation")), s), Collections.emptyList(), ConfigUtil.getPalette(config.getString("palette")).getPalette());
|
||||
TreeMap<Integer, BlockPalette> paletteMap = new TreeMap<>();
|
||||
for(Map.Entry<String, Object> e : config.getConfigurationSection("palette").getValues(false).entrySet()) {
|
||||
paletteMap.put((Integer) e.getValue(), ConfigUtil.getPalette(e.getKey()).getPalette());
|
||||
}
|
||||
|
||||
|
||||
this.decorator = new UserDefinedDecorator(config);
|
||||
|
||||
gen = new UserDefinedGenerator(s, Parser.parse(Objects.requireNonNull(config.getString("noise-equation")), s), Collections.emptyList(), paletteMap);
|
||||
}
|
||||
|
||||
public BiomeConfig getConfig() {
|
||||
@@ -35,7 +47,7 @@ public class UserDefinedBiome implements Biome {
|
||||
*/
|
||||
@Override
|
||||
public org.bukkit.block.Biome getVanillaBiome() {
|
||||
return org.bukkit.block.Biome.PLAINS;
|
||||
return config.getVanillaBiome();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,6 +77,6 @@ public class UserDefinedBiome implements Biome {
|
||||
*/
|
||||
@Override
|
||||
public Decorator getDecorator() {
|
||||
return null;
|
||||
return decorator;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.dfsek.terra.biome;
|
||||
|
||||
import com.dfsek.terra.config.BiomeConfig;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.polydev.gaea.biome.Decorator;
|
||||
import org.polydev.gaea.math.ProbabilityCollection;
|
||||
import org.polydev.gaea.tree.Tree;
|
||||
import org.polydev.gaea.world.Fauna;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class UserDefinedDecorator extends Decorator {
|
||||
|
||||
private final ProbabilityCollection<Fauna> fauna = new ProbabilityCollection<>();
|
||||
private int faunaChance;
|
||||
|
||||
public UserDefinedDecorator(BiomeConfig config) {
|
||||
if(config.contains("fauna")) {
|
||||
for(Map.Entry<String, Object> e : config.getConfigurationSection("fauna").getValues(false).entrySet()) {
|
||||
fauna.add(Fauna.valueOf(e.getKey()), (Integer) e.getValue());
|
||||
}
|
||||
}
|
||||
faunaChance = config.getInt("fauna-chance", 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProbabilityCollection<Tree> getTrees() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTreeDensity() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean overrideStructureChance() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldGenerateSnow() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome getVanillaBiome() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProbabilityCollection<Fauna> getFauna() {
|
||||
return fauna;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFaunaChance() {
|
||||
return faunaChance;
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,8 @@ import org.polydev.gaea.math.parsii.eval.Variable;
|
||||
import org.polydev.gaea.world.BlockPalette;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class UserDefinedGenerator extends BiomeTerrain {
|
||||
private final Expression noiseExp;
|
||||
@@ -17,13 +19,13 @@ public class UserDefinedGenerator extends BiomeTerrain {
|
||||
private final Variable xVar;
|
||||
private final Variable yVar;
|
||||
private final Variable zVar;
|
||||
private final BlockPalette p;
|
||||
private final TreeMap<Integer, BlockPalette> paletteMap;
|
||||
|
||||
|
||||
public UserDefinedGenerator(Scope s, Expression e, List<Variable> v, BlockPalette p) {
|
||||
public UserDefinedGenerator(Scope s, Expression e, List<Variable> v, TreeMap<Integer, BlockPalette> p) {
|
||||
this.noiseExp = e;
|
||||
this.vars = v;
|
||||
this.p = p;
|
||||
this.paletteMap = p;
|
||||
this.xVar = s.getVariable("x");
|
||||
this.yVar = s.getVariable("y");
|
||||
this.zVar = s.getVariable("z");
|
||||
@@ -72,6 +74,33 @@ public class UserDefinedGenerator extends BiomeTerrain {
|
||||
*/
|
||||
@Override
|
||||
public BlockPalette getPalette(int y) {
|
||||
return p;
|
||||
for(Map.Entry<Integer, BlockPalette> e : paletteMap.entrySet()) {
|
||||
if(e.getKey() >= y ) return e.getValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class Range {
|
||||
private final int min;
|
||||
private final int max;
|
||||
|
||||
/**
|
||||
* Instantiates a Range object with a minimum value (inclusive) and a maximum value (exclusive).
|
||||
* @param min The minimum value (inclusive).
|
||||
* @param max The maximum value (exclusive).
|
||||
*/
|
||||
public Range(int min, int max) {
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if a value is within range.
|
||||
* @param val The value to test.
|
||||
* @return boolean - Whether the value is within range.
|
||||
*/
|
||||
public boolean isInRange(int val) {
|
||||
return val >= min && val < max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,4 +9,8 @@ public class UserDefinedGrid extends BiomeGrid {
|
||||
super(w, freq1, freq2);
|
||||
super.setGrid(config.getBiomeGrid());
|
||||
}
|
||||
public UserDefinedGrid(World w, float freq1, float freq2, UserDefinedBiome[][] b) {
|
||||
super(w, freq1, freq2);
|
||||
super.setGrid(b);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ public class BiomeConfig extends YamlConfiguration {
|
||||
private UserDefinedBiome biome;
|
||||
private String biomeID;
|
||||
private String friendlyName;
|
||||
private org.bukkit.block.Biome vanillaBiome;
|
||||
private boolean isEnabled = false;
|
||||
|
||||
public BiomeConfig(File file) throws InvalidConfigurationException, IOException {
|
||||
@@ -37,6 +38,12 @@ public class BiomeConfig extends YamlConfiguration {
|
||||
this.biomeID = getString("id");
|
||||
if(!contains("name")) throw new InvalidConfigurationException("Biome Name unspecified!");
|
||||
this.friendlyName = getString("name");
|
||||
if(!contains("vanilla")) throw new InvalidConfigurationException("Vanila Biome unspecified!");
|
||||
try {
|
||||
this.vanillaBiome = org.bukkit.block.Biome.valueOf(getString("vanilla"));
|
||||
} catch(IllegalArgumentException e) {
|
||||
throw new InvalidConfigurationException("Invalid Vanilla biome: " + getString("vanilla"));
|
||||
}
|
||||
isEnabled = true;
|
||||
}
|
||||
|
||||
@@ -55,4 +62,8 @@ public class BiomeConfig extends YamlConfiguration {
|
||||
public String getFriendlyName() {
|
||||
return friendlyName;
|
||||
}
|
||||
|
||||
public org.bukkit.block.Biome getVanillaBiome() {
|
||||
return vanillaBiome;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ public class PaletteConfig extends YamlConfiguration {
|
||||
ProbabilityCollection<BlockData> layer = new ProbabilityCollection<>();
|
||||
for(Map.Entry<String, Integer> type : ((Map<String, Integer>) m.get("materials")).entrySet()) {
|
||||
layer.add(Bukkit.createBlockData(type.getKey()), type.getValue());
|
||||
Bukkit.getLogger().info("[Terra] Added" + type.getKey() + " with probability " + type.getValue());
|
||||
Bukkit.getLogger().info("[Terra] Added " + type.getKey() + " with probability " + type.getValue());
|
||||
}
|
||||
Bukkit.getLogger().info("[Terra] Added above materials for " + m.get("layers") + " layers.");
|
||||
palette.addBlockData(layer, (Integer) m.get("layers"));
|
||||
@@ -61,28 +61,4 @@ public class PaletteConfig extends YamlConfiguration {
|
||||
public String getPaletteID() {
|
||||
return paletteID;
|
||||
}
|
||||
|
||||
private static class Range {
|
||||
private final int min;
|
||||
private final int max;
|
||||
|
||||
/**
|
||||
* Instantiates a Range object with a minimum value (inclusive) and a maximum value (exclusive).
|
||||
* @param min The minimum value (inclusive).
|
||||
* @param max The maximum value (exclusive).
|
||||
*/
|
||||
public Range(int min, int max) {
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if a value is within range.
|
||||
* @param val The value to test.
|
||||
* @return boolean - Whether the value is within range.
|
||||
*/
|
||||
public boolean isInRange(int val) {
|
||||
return val >= min && val < max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package com.dfsek.terra.config;
|
||||
|
||||
import com.dfsek.terra.Terra;
|
||||
import com.dfsek.terra.biome.BiomeZone;
|
||||
import com.dfsek.terra.biome.TerraBiomeGrid;
|
||||
import com.dfsek.terra.biome.UserDefinedBiome;
|
||||
import com.dfsek.terra.biome.UserDefinedGrid;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
@@ -27,7 +26,10 @@ public class WorldConfig {
|
||||
private static final Map<World, WorldConfig> configs = new HashMap<>();
|
||||
private final Map<String, BiomeGridConfig> biomeGrids = new HashMap<>();
|
||||
public float zoneFreq = 1f/1536;
|
||||
public UserDefinedGrid[] definedGrids = new UserDefinedGrid[16];
|
||||
public float freq1 = 1f/256;
|
||||
public float freq2 = 1f/512;
|
||||
public int seaLevel;
|
||||
public UserDefinedGrid[] definedGrids = new UserDefinedGrid[32];
|
||||
|
||||
|
||||
public WorldConfig(World w, JavaPlugin main) {
|
||||
@@ -63,6 +65,7 @@ public class WorldConfig {
|
||||
main.getLogger().severe("Unable to load configuration for world " + w + ".");
|
||||
}
|
||||
|
||||
seaLevel = config.getInt("sea-level", 63);
|
||||
|
||||
try (Stream<Path> paths = Files.walk(Paths.get(main.getDataFolder() + File.separator + "grids"))) {
|
||||
paths
|
||||
@@ -85,8 +88,19 @@ public class WorldConfig {
|
||||
|
||||
|
||||
|
||||
for(int i = 0; i < 16; i++) {
|
||||
definedGrids[i] = biomeGrids.get(config.getStringList("grids").get(i)).getGrid();
|
||||
for(int i = 0; i < 32; i++) {
|
||||
String partName = config.getStringList("grids").get(i);
|
||||
if(partName.startsWith("BIOME:")) {
|
||||
UserDefinedBiome[][] temp = new UserDefinedBiome[16][16];
|
||||
UserDefinedBiome b = ConfigUtil.getBiome(partName.substring(6)).getBiome();
|
||||
for(int x = 0; x < 16; x++) {
|
||||
for(int z = 0; z < 16; z++) {
|
||||
temp[x][z] = b;
|
||||
}
|
||||
}
|
||||
definedGrids[i] = new UserDefinedGrid(w, freq1, freq2, temp);
|
||||
main.getLogger().info("Loaded single-biome grid " + partName);
|
||||
} else definedGrids[i] = biomeGrids.get(partName).getGrid();
|
||||
}
|
||||
|
||||
|
||||
|
||||
29
src/main/java/com/dfsek/terra/population/FaunaPopulator.java
Normal file
29
src/main/java/com/dfsek/terra/population/FaunaPopulator.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package com.dfsek.terra.population;
|
||||
|
||||
import com.dfsek.terra.biome.TerraBiomeGrid;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.polydev.gaea.biome.Biome;
|
||||
import org.polydev.gaea.world.Fauna;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class FaunaPopulator extends BlockPopulator {
|
||||
@Override
|
||||
public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk chunk) {
|
||||
for(int x = 0; x < 16; x++) {
|
||||
for(int z = 0; z < 16; z++) {
|
||||
Biome biome = TerraBiomeGrid.fromWorld(world).getBiome((chunk.getX() << 4) + x, (chunk.getZ() << 4) + z);
|
||||
if(biome.getDecorator().getFaunaChance() <= 0 || random.nextInt(100) > biome.getDecorator().getFaunaChance())
|
||||
continue;
|
||||
Block highest = Fauna.getHighestValidSpawnAt(chunk, x, z);
|
||||
try {
|
||||
if(highest != null) biome.getDecorator().getFauna().get(random).plant(highest.getLocation());
|
||||
} catch(NullPointerException ignored) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user