Implement Elevation

This commit is contained in:
dfsek 2020-11-11 02:28:44 -07:00
parent 48e45dfe23
commit 922f971c8e
8 changed files with 165 additions and 13 deletions

View File

@ -19,6 +19,6 @@ public final class FailoverGenerator extends UserDefinedGenerator {
} }
public FailoverGenerator() throws ParseException { public FailoverGenerator() throws ParseException {
super("0", Collections.emptyList(), palette, false); super("0", null, Collections.emptyList(), palette, false);
} }
} }

View File

@ -168,9 +168,12 @@ public class BiomeConfig extends TerraConfig {
} }
} }
String elevation = getString("elevation-equation", null);
try { try {
// Get UserDefinedBiome instance representing this config. // Get UserDefinedBiome instance representing this config.
this.biome = new UserDefinedBiome(vanillaBiome, dec, new UserDefinedGenerator(eq, Collections.emptyList(), palette.getPaletteMap(), getBoolean("prevent-smooth", false)), getBoolean("erodible", false), biomeID); UserDefinedGenerator gen = new UserDefinedGenerator(eq, elevation, Collections.emptyList(), palette.getPaletteMap(), getBoolean("prevent-smooth", false));
this.biome = new UserDefinedBiome(vanillaBiome, dec, gen, getBoolean("erodible", false), biomeID);
} catch(ParseException e) { } catch(ParseException e) {
e.printStackTrace(); e.printStackTrace();
throw new ConfigException("Unable to parse noise equation!", getID()); throw new ConfigException("Unable to parse noise equation!", getID());

View File

@ -0,0 +1,35 @@
package com.dfsek.terra.generation;
import com.dfsek.terra.math.NoiseFunction2;
import org.polydev.gaea.math.FastNoiseLite;
import parsii.eval.Expression;
import parsii.eval.Parser;
import parsii.eval.Scope;
import parsii.eval.Variable;
import parsii.tokenizer.ParseException;
public class ElevationEquation {
private static final Object noiseLock = new Object();
private final Expression delegate;
private final Scope s = new Scope();
private final NoiseFunction2 n2 = new NoiseFunction2();
private final Variable xVar = s.getVariable("x");
private final Variable zVar = s.getVariable("z");
public ElevationEquation(String equation) throws ParseException {
Parser p = new Parser();
p.registerFunction("noise2", n2);
delegate = p.parse(equation, s);
}
public double getNoise(double x, double z, FastNoiseLite noiseLite) {
synchronized(noiseLock) {
xVar.setValue(x);
zVar.setValue(z);
n2.setNoise(noiseLite);
return delegate.evaluate();
}
}
}

View File

@ -0,0 +1,77 @@
package com.dfsek.terra.generation;
import com.dfsek.terra.biome.TerraBiomeGrid;
import org.bukkit.World;
import org.polydev.gaea.biome.Generator;
import org.polydev.gaea.generation.GenerationPhase;
import org.polydev.gaea.math.FastNoiseLite;
import org.polydev.gaea.math.Interpolator;
public class ElevationInterpolator {
private final UserDefinedGenerator[][] gens = new UserDefinedGenerator[7][7];
private final double[][] values = new double[16][16];
private final FastNoiseLite noise;
private final int xOrigin;
private final int zOrigin;
public ElevationInterpolator(World w, int chunkX, int chunkZ, TerraBiomeGrid grid, FastNoiseLite noise) {
this.xOrigin = chunkX << 4;
this.zOrigin = chunkZ << 4;
this.noise = noise;
for(int x = -1; x < 6; x++) {
for(int z = -1; z < 6; z++) {
gens[x + 1][z + 1] = (UserDefinedGenerator) grid.getBiome(xOrigin + x * 4, zOrigin + z * 4, GenerationPhase.BASE).getGenerator();
}
}
for(byte x = 0; x < 16; x++) {
for(byte z = 0; z < 16; z++) {
if(compareGens((x / 4) + 1, (z / 4) + 1)) {
Interpolator interpolator = new Interpolator(biomeAvg(x / 4, z / 4),
biomeAvg((x / 4) + 1, z / 4),
biomeAvg(x / 4, (z / 4) + 1),
biomeAvg((x / 4) + 1, (z / 4) + 1),
Interpolator.Type.LINEAR);
values[x][z] = interpolator.bilerp((double) (x % 4) / 4, (double) (z % 4) / 4);
} else values[x][z] = elevate(gens[x / 4][z / 4], xOrigin + x, zOrigin + z);
}
}
}
private boolean compareGens(int x, int z) {
Generator comp = gens[x][z];
if(!comp.equals(gens[x + 1][z])) return true;
if(!comp.equals(gens[x][z + 1])) return true;
if(!comp.equals(gens[x - 1][z])) return true;
if(!comp.equals(gens[x][z - 1])) return true;
if(!comp.equals(gens[x + 1][z + 1])) return true;
if(!comp.equals(gens[x - 1][z - 1])) return true;
if(!comp.equals(gens[x + 1][z - 1])) return true;
return !comp.equals(gens[x - 1][z + 1]);
}
private double biomeAvg(int x, int z) {
return (elevate(gens[x + 2][z + 1], x * 4 + 4 + xOrigin, z * 4 + zOrigin)
+ elevate(gens[x][z + 1], x * 4 - 4 + xOrigin, z * 4 + zOrigin)
+ elevate(gens[x + 1][z + 2], x * 4 + xOrigin, z * 4 + 4 + zOrigin)
+ elevate(gens[x + 1][z], x * 4 + xOrigin, z * 4 - 4 + zOrigin)
+ elevate(gens[x + 1][z + 1], x * 4 + xOrigin, z * 4 + zOrigin)) / 5D;
}
private double elevate(UserDefinedGenerator g, int x, int z) {
if(g.getElevationEquation() != null) return g.getElevationEquation().getNoise(x, z, noise);
return 0;
}
public double getElevation(int x, int z) {
return values[x][z];
}
}

View File

@ -80,19 +80,19 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
popMan.attachProfiler(p); popMan.attachProfiler(p);
} }
private static Palette<BlockData> getPalette(int x, int y, int z, BiomeConfig c, ChunkInterpolator interpolator) { private static Palette<BlockData> getPalette(int x, int y, int z, BiomeConfig c, ChunkInterpolator interpolator, int elevate) {
Palette<BlockData> slant = c.getSlant(); Palette<BlockData> slant = c.getSlant();
if(slant != null) { if(slant != null) {
double xzOffset = c.getXZSlantOffset(); double xzOffset = c.getXZSlantOffset();
boolean north = interpolator.getNoise(x, y, z + xzOffset) > 0; boolean north = interpolator.getNoise(x, y + elevate, z + xzOffset) > 0;
boolean south = interpolator.getNoise(x, y, z - xzOffset) > 0; boolean south = interpolator.getNoise(x, y + elevate, z - xzOffset) > 0;
boolean east = interpolator.getNoise(x + xzOffset, y, z) > 0; boolean east = interpolator.getNoise(x + xzOffset, y + elevate, z) > 0;
boolean west = interpolator.getNoise(x - xzOffset, y, z) > 0; boolean west = interpolator.getNoise(x - xzOffset, y + elevate, z) > 0;
double ySlantOffsetTop = c.getYSlantOffsetTop(); double ySlantOffsetTop = c.getYSlantOffsetTop();
double ySlantOffsetBottom = c.getYSlantOffsetBottom(); double ySlantOffsetBottom = c.getYSlantOffsetBottom();
boolean top = interpolator.getNoise(x, y + ySlantOffsetTop, z) > 0; boolean top = interpolator.getNoise(x, y + ySlantOffsetTop + elevate, z) > 0;
boolean bottom = interpolator.getNoise(x, y - ySlantOffsetBottom, z) > 0; boolean bottom = interpolator.getNoise(x, y - ySlantOffsetBottom + elevate, z) > 0;
if((top && bottom) && (north || south || east || west) && (!(north && south && east && west))) return slant; if((top && bottom) && (north || south || east || west) && (!(north && south && east && west))) return slant;
} }
@ -141,19 +141,27 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
int xOrig = (chunkX << 4); int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4); int zOrig = (chunkZ << 4);
org.polydev.gaea.biome.BiomeGrid grid = getBiomeGrid(world); org.polydev.gaea.biome.BiomeGrid grid = getBiomeGrid(world);
ElevationInterpolator elevationInterpolator = new ElevationInterpolator(world, chunkX, chunkZ, tw.getGrid(), getNoiseGenerator());
for(byte x = 0; x < 16; x++) { for(byte x = 0; x < 16; x++) {
for(byte z = 0; z < 16; z++) { for(byte z = 0; z < 16; z++) {
int paletteLevel = 0; int paletteLevel = 0;
int cx = xOrig + x; int cx = xOrig + x;
int cz = zOrig + z; int cz = zOrig + z;
Biome b = grid.getBiome(xOrig + x, zOrig + z, GenerationPhase.PALETTE_APPLY); Biome b = grid.getBiome(xOrig + x, zOrig + z, GenerationPhase.PALETTE_APPLY);
BiomeConfig c = config.getBiome((UserDefinedBiome) b); BiomeConfig c = config.getBiome((UserDefinedBiome) b);
int elevate = (int) elevationInterpolator.getElevation(x, z);
BiomeSlabConfig slab = c.getSlabs(); BiomeSlabConfig slab = c.getSlabs();
int sea = c.getOcean().getSeaLevel(); int sea = c.getOcean().getSeaLevel();
Palette<BlockData> seaPalette = c.getOcean().getOcean(); Palette<BlockData> seaPalette = c.getOcean().getOcean();
for(int y = world.getMaxHeight() - 1; y >= 0; y--) { for(int y = world.getMaxHeight() - 1; y >= 0; y--) {
if(interpolator.getNoise(x, y, z) > 0) { if(interpolator.getNoise(x, y - elevate, z) > 0) {
BlockData data = getPalette(x, y, z, c, interpolator).get(paletteLevel, cx, cz); BlockData data = getPalette(x, y, z, c, interpolator, elevate).get(paletteLevel, cx, cz);
chunk.setBlock(x, y, z, data); chunk.setBlock(x, y, z, data);
if(paletteLevel == 0 && slab != null && y < 255) { if(paletteLevel == 0 && slab != null && y < 255) {
prepareBlockPart(data, chunk.getBlockData(x, y + 1, z), chunk, new Vector(x, y + 1, z), slab.getSlabs(), prepareBlockPart(data, chunk.getBlockData(x, y + 1, z), chunk, new Vector(x, y + 1, z), slab.getSlabs(),

View File

@ -1,10 +1,12 @@
package com.dfsek.terra.generation; package com.dfsek.terra.generation;
import com.dfsek.terra.Debug;
import com.dfsek.terra.math.NoiseFunction2; import com.dfsek.terra.math.NoiseFunction2;
import com.dfsek.terra.math.NoiseFunction3; import com.dfsek.terra.math.NoiseFunction3;
import com.dfsek.terra.util.DataUtil; import com.dfsek.terra.util.DataUtil;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.jetbrains.annotations.Nullable;
import org.polydev.gaea.biome.Generator; import org.polydev.gaea.biome.Generator;
import org.polydev.gaea.math.FastNoiseLite; import org.polydev.gaea.math.FastNoiseLite;
import org.polydev.gaea.math.Interpolator; import org.polydev.gaea.math.Interpolator;
@ -30,10 +32,11 @@ public class UserDefinedGenerator extends Generator {
private final Palette<BlockData>[] palettes = new Palette[256]; private final Palette<BlockData>[] palettes = new Palette[256];
private final NoiseFunction2 n2 = new NoiseFunction2(); private final NoiseFunction2 n2 = new NoiseFunction2();
private final NoiseFunction3 n3 = new NoiseFunction3(); private final NoiseFunction3 n3 = new NoiseFunction3();
private final ElevationEquation elevationEquation;
private final boolean preventSmooth; private final boolean preventSmooth;
public UserDefinedGenerator(String equation, List<Variable> userVariables, Map<Integer, Palette<BlockData>> paletteMap, boolean preventSmooth) public UserDefinedGenerator(String equation, @Nullable String elevateEquation, List<Variable> userVariables, Map<Integer, Palette<BlockData>> paletteMap, boolean preventSmooth)
throws ParseException { throws ParseException {
Parser p = new Parser(); Parser p = new Parser();
p.registerFunction("noise2", n2); p.registerFunction("noise2", n2);
@ -48,6 +51,10 @@ public class UserDefinedGenerator extends Generator {
} }
palettes[y] = d; palettes[y] = d;
} }
if(elevateEquation != null) {
Debug.info("Using elevation equation");
this.elevationEquation = new ElevationEquation(elevateEquation);
} else this.elevationEquation = null;
this.noiseExp = p.parse(equation, s); this.noiseExp = p.parse(equation, s);
this.preventSmooth = preventSmooth; this.preventSmooth = preventSmooth;
} }
@ -112,4 +119,8 @@ public class UserDefinedGenerator extends Generator {
public Interpolator.Type getInterpolationType() { public Interpolator.Type getInterpolationType() {
return Interpolator.Type.LINEAR; return Interpolator.Type.LINEAR;
} }
public ElevationEquation getElevationEquation() {
return elevationEquation;
}
} }

View File

@ -1,4 +1,5 @@
noise-equation: "((-((y / 64)^2)) + 1) + min(floor(((|noise2(x/2.5, z/2.5)|) + 0.1)*4), 3)/2.5 + |noise2(x/2.5, z/2.5)|" noise-equation: "((-((y / 64)^2)) + 1) + |noise2(x/2.5, z/2.5)|"
elevation-equation: "min(floor(((|noise2(x/2.5, z/2.5)|) + 0.1)*4)*5, 15)"
id: "ARID_MOUNTAINS" id: "ARID_MOUNTAINS"
extends: "BASIC_ORES" extends: "BASIC_ORES"

View File

@ -0,0 +1,17 @@
import org.junit.jupiter.api.Test;
import org.polydev.gaea.math.FastNoiseLite;
public class NoiseInstancePerformanceTest {
@Test
public void performance() {
FastNoiseLite noiseLite = new FastNoiseLite(2403);
long l = System.nanoTime();
for(int i = 0; i < 10000000; i++) noiseLite.getNoise(i, i);
System.out.println("No instantiation: " + (System.nanoTime() - l) / 1000000 + "ms");
for(int i = 0; i < 10000000; i++) {
FastNoiseLite noiseLite1 = new FastNoiseLite(2403);
noiseLite1.getNoise(i, i);
}
System.out.println("Instantiation: " + (System.nanoTime() - l) / 1000000 + "ms");
}
}