mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2025-07-18 10:32:30 +00:00
Implement erosion
This commit is contained in:
parent
0e760ec87e
commit
2659577322
@ -7,12 +7,14 @@ import com.dfsek.terra.biome.UserDefinedGrid;
|
||||
import com.dfsek.terra.config.base.ConfigPack;
|
||||
import com.dfsek.terra.config.base.ConfigUtil;
|
||||
import com.dfsek.terra.config.base.WorldConfig;
|
||||
import com.dfsek.terra.config.exception.ConfigException;
|
||||
import com.dfsek.terra.config.genconfig.BiomeGridConfig;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class TerraWorld {
|
||||
private static final Map<World, TerraWorld> map = new HashMap<>();
|
||||
@ -20,6 +22,7 @@ public class TerraWorld {
|
||||
private final BiomeZone zone;
|
||||
private final ConfigPack config;
|
||||
private final WorldConfig worldConfig;
|
||||
|
||||
private TerraWorld(World w) {
|
||||
worldConfig = new WorldConfig(w, Terra.getInstance());
|
||||
config = worldConfig.getConfig();
|
||||
@ -39,15 +42,37 @@ public class TerraWorld {
|
||||
definedGrids[i] = g.getGrid(w, worldConfig);
|
||||
}
|
||||
} catch(NullPointerException e) {
|
||||
if(ConfigUtil.debug) e.printStackTrace();
|
||||
Debug.stack(e);
|
||||
Bukkit.getLogger().severe("No such BiomeGrid " + partName);
|
||||
Bukkit.getLogger().severe("Please check configuration files for errors. Configuration errors will have been reported during initialization.");
|
||||
Bukkit.getLogger().severe("ONLY report this to Terra if you are SURE your config is error-free.");
|
||||
Bukkit.getLogger().severe("Terrain will NOT generate properly at this point. Correct your config before using your server!");
|
||||
}
|
||||
}
|
||||
UserDefinedGrid erosion = null;
|
||||
if(config.erosionEnable) {
|
||||
try {
|
||||
if(config.erosionName.startsWith("BIOME:")) {
|
||||
UserDefinedBiome[][] temp = new UserDefinedBiome[1][1];
|
||||
UserDefinedBiome b = Objects.requireNonNull(config.getBiome(config.erosionName.substring(6)).getBiome());
|
||||
temp[0][0] = b;
|
||||
erosion = new UserDefinedGrid(w, config.freq1, config.freq2, temp, worldConfig);
|
||||
Debug.info("Loaded single-biome erosion grid " + config.erosionName);
|
||||
} else {
|
||||
BiomeGridConfig g = Objects.requireNonNull(config.getBiomeGrid(config.erosionName));
|
||||
Debug.info("Loaded BiomeGrid " + g.getID());
|
||||
erosion = g.getGrid(w, worldConfig);
|
||||
}
|
||||
} catch(NullPointerException e) {
|
||||
Debug.stack(e);
|
||||
Bukkit.getLogger().severe("No such BiomeGrid (erosion): " + config.erosionName);
|
||||
Bukkit.getLogger().severe("Please check configuration files for errors. Configuration errors will have been reported during initialization.");
|
||||
Bukkit.getLogger().severe("ONLY report this to Terra if you are SURE your config is error-free.");
|
||||
Bukkit.getLogger().severe("Terrain will NOT generate properly at this point. Correct your config before using your server!");
|
||||
}
|
||||
}
|
||||
zone = new BiomeZone(w, worldConfig, definedGrids);
|
||||
grid = new TerraBiomeGrid(w, config.freq1, config.freq2, zone, config);
|
||||
grid = new TerraBiomeGrid(w, config.freq1, config.freq2, zone, config, erosion);
|
||||
}
|
||||
|
||||
public static synchronized TerraWorld getWorld(World w) {
|
||||
|
@ -10,6 +10,9 @@ import org.polydev.gaea.math.FastNoise;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Holds 1D array of BiomeGrids.
|
||||
*/
|
||||
public class BiomeZone {
|
||||
private final BiomeGrid[] grids;
|
||||
private final FastNoise noise;
|
||||
@ -29,18 +32,40 @@ public class BiomeZone {
|
||||
channel = wc.zoneChannel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get BiomeGrid at location
|
||||
* @param x X coordinate
|
||||
* @param z Z coordinate
|
||||
* @return BiomeGrid at coordinates.
|
||||
*/
|
||||
protected BiomeGrid getGrid(int x, int z) {
|
||||
return grids[NormalizationUtil.normalize(useImage ? Objects.requireNonNull(imageLoader).getNoiseVal(x, z, channel) : noise.getNoise(x, z), grids.length)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of BiomeGrids this BiomeZone holds.
|
||||
* @return Number of grids
|
||||
*/
|
||||
public int getSize() {
|
||||
return grids.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the normalized grid noise at location
|
||||
* @param x X coordinate
|
||||
* @param z Z coordinate
|
||||
* @return Normalized noise at coordinates
|
||||
*/
|
||||
public int getNoise(int x, int z) {
|
||||
return NormalizationUtil.normalize(useImage ? Objects.requireNonNull(imageLoader).getNoiseVal(x, z, channel) : noise.getNoise(x, z), grids.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get raw grid noise at location
|
||||
* @param x X coordinate
|
||||
* @param z Z coordinate
|
||||
* @return Raw noise at coordinates
|
||||
*/
|
||||
public double getRawNoise(int x, int z) {
|
||||
return useImage ? Objects.requireNonNull(imageLoader).getNoiseVal(x, z, channel) : noise.getNoise(x, z);
|
||||
}
|
||||
|
30
src/main/java/com/dfsek/terra/biome/ErosionNoise.java
Normal file
30
src/main/java/com/dfsek/terra/biome/ErosionNoise.java
Normal file
@ -0,0 +1,30 @@
|
||||
package com.dfsek.terra.biome;
|
||||
|
||||
import org.polydev.gaea.math.FastNoise;
|
||||
|
||||
/**
|
||||
* Class to hold noise function to determine erosion.
|
||||
*/
|
||||
public class ErosionNoise {
|
||||
private final double thresh;
|
||||
private final FastNoise noise;
|
||||
public ErosionNoise(float freq1, double thresh, long seed) {
|
||||
FastNoise main = new FastNoise((int) (seed+1));
|
||||
main.setNoiseType(FastNoise.NoiseType.SimplexFractal);
|
||||
main.setFractalOctaves(2);
|
||||
main.setFrequency(freq1);
|
||||
this.thresh = thresh;
|
||||
this.noise = main;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether a location is eroded
|
||||
* @param x X coordinate
|
||||
* @param z Z coordinate
|
||||
* @return Whether location is eroded
|
||||
*/
|
||||
boolean isEroded(int x, int z) {
|
||||
double abs = Math.pow(noise.getNoise(x, z), 2);
|
||||
return abs < thresh;
|
||||
}
|
||||
}
|
@ -9,20 +9,29 @@ import org.polydev.gaea.biome.Biome;
|
||||
import org.polydev.gaea.biome.BiomeGrid;
|
||||
import org.polydev.gaea.generation.GenerationPhase;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class TerraBiomeGrid extends BiomeGrid {
|
||||
private static int failNum = 0;
|
||||
private CoordinatePerturb perturb;
|
||||
private ErosionNoise erode;
|
||||
private UserDefinedGrid erosionGrid;
|
||||
|
||||
private final BiomeZone zone;
|
||||
private final boolean perturbPaletteOnly;
|
||||
|
||||
public TerraBiomeGrid(World w, float freq1, float freq2, BiomeZone zone, ConfigPack c) {
|
||||
public TerraBiomeGrid(World w, float freq1, float freq2, BiomeZone zone, ConfigPack c, UserDefinedGrid erosion) {
|
||||
super(w, freq1, freq2);
|
||||
if(c.biomeBlend) {
|
||||
perturb = new CoordinatePerturb(c.blendFreq, c.blendAmp, w.getSeed());
|
||||
}
|
||||
perturbPaletteOnly = c.perturbPaletteOnly;
|
||||
this.zone = zone;
|
||||
if(c.erosionEnable) {
|
||||
erode = new ErosionNoise(c.erosionFreq, c.erosionThresh, w.getSeed());
|
||||
this.erosionGrid = erosion;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -35,14 +44,19 @@ public class TerraBiomeGrid extends BiomeGrid {
|
||||
zp = perturbCoords[1];
|
||||
}
|
||||
|
||||
UserDefinedBiome b;
|
||||
try {
|
||||
return zone.getGrid(xp, zp).getBiome(xp, zp, phase);
|
||||
b = (UserDefinedBiome) zone.getGrid(xp, zp).getBiome(xp, zp, phase);
|
||||
} catch(NullPointerException e) {
|
||||
if(ConfigUtil.debug) e.printStackTrace();
|
||||
if(failNum % 256 == 0) Bukkit.getLogger().severe("[Terra] A severe configuration error has prevented Terra from properly generating terrain at coordinates: " + x + ", " + z + ". Please check your configuration for errors. Any config errors will have been reported above.");
|
||||
failNum++;
|
||||
return null;
|
||||
}
|
||||
if(erode != null && b.isErodible() && erode.isEroded(xp, zp)) {
|
||||
return erosionGrid.getBiome(xp, zp, phase);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -14,13 +14,15 @@ public class UserDefinedBiome implements Biome {
|
||||
private final UserDefinedDecorator decorator;
|
||||
private final org.bukkit.block.Biome vanilla;
|
||||
private final String id;
|
||||
private final boolean erode;
|
||||
|
||||
|
||||
public UserDefinedBiome(org.bukkit.block.Biome vanilla, UserDefinedDecorator dec, UserDefinedGenerator gen, String id) {
|
||||
public UserDefinedBiome(org.bukkit.block.Biome vanilla, UserDefinedDecorator dec, UserDefinedGenerator gen, boolean erode, String id) {
|
||||
this.vanilla = vanilla;
|
||||
this.decorator = dec;
|
||||
this.gen = gen;
|
||||
this.id = id;
|
||||
this.erode = erode;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,4 +68,8 @@ public class UserDefinedBiome implements Biome {
|
||||
public String getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean isErodible() {
|
||||
return erode;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.dfsek.terra.config.base;
|
||||
|
||||
import com.dfsek.terra.Debug;
|
||||
import com.dfsek.terra.biome.UserDefinedBiome;
|
||||
import com.dfsek.terra.biome.UserDefinedGrid;
|
||||
import com.dfsek.terra.carving.UserDefinedCarver;
|
||||
import com.dfsek.terra.config.ConfigLoader;
|
||||
import com.dfsek.terra.config.exception.ConfigException;
|
||||
@ -50,6 +52,11 @@ public class ConfigPack extends YamlConfiguration {
|
||||
public float freq1;
|
||||
public float freq2;
|
||||
|
||||
public float erosionFreq;
|
||||
public double erosionThresh;
|
||||
public boolean erosionEnable;
|
||||
public String erosionName;
|
||||
|
||||
public int blendAmp;
|
||||
public boolean biomeBlend;
|
||||
public float blendFreq;
|
||||
@ -89,6 +96,12 @@ public class ConfigPack extends YamlConfiguration {
|
||||
blendFreq = (float) getDouble("blend.frequency", 0.01);
|
||||
perturbPaletteOnly = getBoolean("blend.ignore-terrain", true);
|
||||
|
||||
erosionEnable = getBoolean("erode.enable", false);
|
||||
erosionFreq = (float) getDouble("erode.frequency", 0.01);
|
||||
erosionThresh = getDouble("erode.threshold", 0.04);
|
||||
|
||||
erosionName = getString("erode.grid");
|
||||
|
||||
// Load BiomeGrids from BiomeZone
|
||||
biomeList = getStringList("grids");
|
||||
|
||||
|
@ -36,8 +36,8 @@ public class OreConfig extends TerraConfig {
|
||||
if(!contains("replace")) throw new ConfigException("Ore replaceable materials not found!", getID());
|
||||
min = getInt("radius.min", 1);
|
||||
max = getInt("radius.max", 1);
|
||||
deform = getDouble("deform");
|
||||
deformFrequency = getDouble("deform-frequency");
|
||||
deform = getDouble("deform", 0.75);
|
||||
deformFrequency = getDouble("deform-frequency", 0.1);
|
||||
update = getBoolean("update", false);
|
||||
|
||||
replaceable = ConfigUtil.toBlockData(getStringList("replace"), "replaceable", getID());
|
||||
|
@ -17,6 +17,7 @@ public class AbstractBiomeConfig extends TerraConfig {
|
||||
private final int treeDensity;
|
||||
private final String equation;
|
||||
private final int floraAttempts;
|
||||
private final int snowChance;
|
||||
private double slabThreshold;
|
||||
private BiomeSlabConfig slabs;
|
||||
private boolean useStairs;
|
||||
@ -51,6 +52,7 @@ public class AbstractBiomeConfig extends TerraConfig {
|
||||
floraFreq = (float) getDouble("flora-simplex.frequency", 0.1);
|
||||
floraSeed = getInt("flora-simplex.seed", 0);
|
||||
seaLevel = getInt("ocean.level", 62);
|
||||
snowChance = getInt("snow-chance", 0);
|
||||
oceanPalette = getString("ocean.palette");
|
||||
useStairs = getBoolean("slabs.use-stairs-if-available", false);
|
||||
|
||||
@ -145,4 +147,8 @@ public class AbstractBiomeConfig extends TerraConfig {
|
||||
public List<String> getStructureConfigs() {
|
||||
return structureConfigs;
|
||||
}
|
||||
|
||||
public int getSnowChance() {
|
||||
return snowChance;
|
||||
}
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ public class BiomeConfig extends TerraConfig {
|
||||
private FastNoise floraNoise;
|
||||
private final Palette<BlockData> ocean;
|
||||
private int seaLevel;
|
||||
private int snowChance;
|
||||
private final List<StructureConfig> structures;
|
||||
private final ConfigPack config;
|
||||
|
||||
@ -87,6 +88,7 @@ public class BiomeConfig extends TerraConfig {
|
||||
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());
|
||||
snowChance = getInt("snow-chance", Objects.requireNonNull(abstractBiome).getSnowChance());
|
||||
eq = getString("noise-equation", Objects.requireNonNull(abstractBiome).getEquation());
|
||||
} catch(NullPointerException e) {
|
||||
slabThreshold = getDouble("slabs.threshold", 0.1D);
|
||||
@ -98,6 +100,7 @@ public class BiomeConfig extends TerraConfig {
|
||||
floraSimplex = getBoolean("flora-simplex.enable", false);
|
||||
floraFreq = (float) getDouble("flora-simplex.frequency", 0.1);
|
||||
seaLevel = getInt("ocean.level", 62);
|
||||
snowChance = getInt("snow-chance", 0);
|
||||
eq = getString("noise-equation", null);
|
||||
}
|
||||
|
||||
@ -203,7 +206,7 @@ public class BiomeConfig extends TerraConfig {
|
||||
|
||||
try {
|
||||
// Get UserDefinedBiome instance representing this config.
|
||||
this.biome = new UserDefinedBiome(vanillaBiome, dec, new UserDefinedGenerator(eq, Collections.emptyList(), palette.getPaletteMap()), biomeID);
|
||||
this.biome = new UserDefinedBiome(vanillaBiome, dec, new UserDefinedGenerator(eq, Collections.emptyList(), palette.getPaletteMap()), getBoolean("erodible", false), biomeID);
|
||||
} catch(ParseException e) {
|
||||
e.printStackTrace();
|
||||
throw new ConfigException("Unable to parse noise equation!", getID());
|
||||
@ -278,4 +281,8 @@ public class BiomeConfig extends TerraConfig {
|
||||
public Range getTreeRange(Tree t) {
|
||||
return tree.getTreeHeights().getOrDefault(t, new Range(-1, -1));
|
||||
}
|
||||
|
||||
public int getSnowChance() {
|
||||
return snowChance;
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,9 @@ import org.polydev.gaea.world.palette.RandomPalette;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class Util {
|
||||
public class DataUtil {
|
||||
public static final BlockData STONE = Material.STONE.createBlockData();
|
||||
public static final BlockData SNOW = Material.SNOW.createBlockData();
|
||||
public static final BlockData WATER = Material.WATER.createBlockData();
|
||||
public static final BlockData AIR = Material.AIR.createBlockData();
|
||||
public static final Palette<BlockData> BLANK_PALETTE = new RandomPalette<BlockData>(new Random(2403)).add(AIR, 1);
|
@ -9,6 +9,7 @@ import com.dfsek.terra.config.genconfig.biome.BiomeConfig;
|
||||
import com.dfsek.terra.population.CavePopulator;
|
||||
import com.dfsek.terra.population.FloraPopulator;
|
||||
import com.dfsek.terra.population.OrePopulator;
|
||||
import com.dfsek.terra.population.SnowPopulator;
|
||||
import com.dfsek.terra.population.StructurePopulator;
|
||||
import com.dfsek.terra.population.TreePopulator;
|
||||
import com.dfsek.terra.structure.StructureSpawnRequirement;
|
||||
@ -52,6 +53,7 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
|
||||
popMan.attach(new TreePopulator());
|
||||
popMan.attach(new FloraPopulator());
|
||||
popMan.attach(new OrePopulator());
|
||||
popMan.attach(new SnowPopulator());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -102,16 +104,16 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
|
||||
BlockData stair = stairPalette.get(0, block.getBlockX(), block.getBlockZ());
|
||||
Stairs finalStair = getStair(new double[] {_01, _10, _12, _21}, (Stairs) stair, thresh);
|
||||
if(finalStair != null) {
|
||||
if(orig.matches(Util.WATER)) finalStair.setWaterlogged(true);
|
||||
if(orig.matches(DataUtil.WATER)) finalStair.setWaterlogged(true);
|
||||
chunk.setBlock(block.getBlockX(), block.getBlockY(), block.getBlockZ(), finalStair);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
BlockData slab = slabs.getOrDefault(down.getMaterial(), Util.BLANK_PALETTE).get(0, block.getBlockX(), block.getBlockZ());
|
||||
BlockData slab = slabs.getOrDefault(down.getMaterial(), DataUtil.BLANK_PALETTE).get(0, block.getBlockX(), block.getBlockZ());
|
||||
if(slab instanceof Waterlogged) {
|
||||
((Waterlogged) slab).setWaterlogged(orig.matches(Util.WATER));
|
||||
} else if(orig.matches(Util.WATER)) return;
|
||||
((Waterlogged) slab).setWaterlogged(orig.matches(DataUtil.WATER));
|
||||
} else if(orig.matches(DataUtil.WATER)) return;
|
||||
chunk.setBlock(block.getBlockX(), block.getBlockY(), block.getBlockZ(), slab);
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ public class UserDefinedGenerator extends Generator {
|
||||
p.registerFunction("noise2", n2);
|
||||
p.registerFunction("noise3", n3);
|
||||
for(int y = 0; y < 256; y++) {
|
||||
Palette<BlockData> d = Util.BLANK_PALETTE;
|
||||
Palette<BlockData> d = DataUtil.BLANK_PALETTE;
|
||||
for(Map.Entry<Integer, Palette<BlockData>> e : pa.entrySet()) {
|
||||
if(e.getKey() >= y) {
|
||||
d = e.getValue();
|
||||
|
@ -1,15 +1,64 @@
|
||||
package com.dfsek.terra.population;
|
||||
|
||||
import com.dfsek.terra.TerraWorld;
|
||||
import com.dfsek.terra.biome.TerraBiomeGrid;
|
||||
import com.dfsek.terra.biome.UserDefinedBiome;
|
||||
import com.dfsek.terra.config.base.ConfigUtil;
|
||||
import com.dfsek.terra.generation.DataUtil;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.polydev.gaea.generation.GenerationPhase;
|
||||
import org.polydev.gaea.population.GaeaBlockPopulator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
public class SnowPopulator extends GaeaBlockPopulator {
|
||||
private static final Set<Material> blacklistSpawn = new HashSet<>();
|
||||
private static final BlockData snow = Material.SNOW.createBlockData();
|
||||
static {
|
||||
for(Material m : Material.values()) {
|
||||
String name = m.toString().toLowerCase();
|
||||
if(name.contains("slab")
|
||||
|| name.contains("stair")
|
||||
|| name.contains("wall")
|
||||
|| name.contains("fence")
|
||||
|| name.contains("lantern")
|
||||
|| name.contains("chest")
|
||||
|| name.contains("door")
|
||||
|| name.contains("repeater")
|
||||
|| name.equals("lily_pad")
|
||||
|| name.equals("snow")) blacklistSpawn.add(m);
|
||||
}
|
||||
blacklistSpawn.add(Material.END_STONE);
|
||||
if(ConfigUtil.debug)
|
||||
Bukkit.getLogger().info("Added " + blacklistSpawn.size() + " materials to snow blacklist");
|
||||
}
|
||||
@Override
|
||||
public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk chunk) {
|
||||
|
||||
int origX = chunk.getX() << 4;
|
||||
int origZ = chunk.getZ() << 4;
|
||||
TerraWorld w = TerraWorld.getWorld(world);
|
||||
TerraBiomeGrid g = w.getGrid();
|
||||
for(int x = 0; x < 16; x++) {
|
||||
for(int z = 0; z < 16; z++) {
|
||||
if(random.nextInt(100) >= w.getConfig().getBiome((UserDefinedBiome) g.getBiome(origX+x, origZ+z, GenerationPhase.PALETTE_APPLY)).getSnowChance()) continue;
|
||||
int y;
|
||||
Block b = null;
|
||||
for(y = 254; y > 0; y--) {
|
||||
b = chunk.getBlock(x, y, z);
|
||||
if(!b.getType().isAir()) break;
|
||||
}
|
||||
if(blacklistSpawn.contains(b.getType()) || b.isPassable()) continue;
|
||||
chunk.getBlock(x, ++y, z).setBlockData(DataUtil.SNOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user