rework chunkgenerator API to allow easier extension

This commit is contained in:
dfsek 2021-02-21 14:19:42 -07:00
parent 03e9f6b882
commit e00209c99c
19 changed files with 322 additions and 101 deletions

View File

@ -1,7 +1,7 @@
package com.dfsek.terra.api.math;
import com.dfsek.terra.api.util.FastRandom;
import com.dfsek.terra.world.generation.math.Sampler;
import com.dfsek.terra.world.generation.math.samplers.Sampler;
import net.jafama.FastMath;
import java.util.List;

View File

@ -14,7 +14,7 @@ import com.dfsek.terra.config.loaders.config.function.FunctionTemplate;
import java.util.Map;
/**
* Sampler implementation using Paralithic expression
* Sampler3D implementation using Paralithic expression
*/
public class ExpressionSampler implements NoiseSampler {
private final Expression expression;

View File

@ -1,7 +1,7 @@
package com.dfsek.terra.api.math.noise.samplers.noise;
/**
* Sampler implementation that returns a constant.
* Sampler3D implementation that returns a constant.
*/
public class ConstantSampler extends NoiseFunction {
private final double constant;

View File

@ -5,7 +5,7 @@ import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.api.world.palette.holder.PaletteHolder;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.world.generation.math.Sampler;
import com.dfsek.terra.world.generation.math.samplers.Sampler;
public final class PaletteUtil {
public static Palette<BlockData> getPalette(int x, int y, int z, BiomeTemplate c, Sampler sampler) {

View File

@ -4,8 +4,10 @@ import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.platform.world.BiomeGrid;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.platform.world.generator.ChunkData;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.world.generation.math.SamplerCache;
import com.dfsek.terra.world.generation.math.samplers.Sampler;
import org.jetbrains.annotations.NotNull;
import java.util.Random;
@ -30,4 +32,6 @@ public interface TerraChunkGenerator {
TerraPlugin getMain();
SamplerCache getCache();
Sampler createSampler(int chunkX, int chunkZ, BiomeProvider provider, World world, int elevationSmooth);
}

View File

@ -9,10 +9,11 @@ import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.platform.world.generator.ChunkGenerator;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.profiler.WorldProfiler;
import com.dfsek.terra.world.generation.math.Sampler;
import com.dfsek.terra.world.generation.math.samplers.Sampler;
import net.jafama.FastMath;
public class TerraWorld {
@ -25,6 +26,7 @@ public class TerraWorld {
public TerraWorld(World w, ConfigPack c, TerraPlugin main) {
if(!isTerraWorld(w)) throw new IllegalArgumentException("World " + w + " is not a Terra World!");
c.getBiomeRegistry().forEach(biome -> biome.getGenerator(w)); // Load all gens to cache
config = c;
profiler = new WorldProfiler(w);
@ -35,6 +37,10 @@ public class TerraWorld {
safe = true;
}
public TerraChunkGenerator getGenerator() {
return (TerraChunkGenerator) ((ChunkGenerator) world.getGenerator().getHandle()).getHandle();
}
public World getWorld() {
return world;
}

View File

@ -6,8 +6,8 @@ import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.world.ChunkAccess;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.world.Carver;
import com.dfsek.terra.world.generation.math.interpolation.BiomeChunkInterpolator;
import com.dfsek.terra.world.generation.math.interpolation.ChunkInterpolator;
import com.dfsek.terra.world.generation.math.interpolation.ChunkInterpolator3D;
public class NoiseCarver implements Carver {
private final Range range;
@ -22,7 +22,7 @@ public class NoiseCarver implements Carver {
@Override
public void carve(World world, int chunkX, int chunkZ, ChunkAccess chunk) {
ChunkInterpolator interpolator = new BiomeChunkInterpolator(world, chunkX, chunkZ, main.getWorld(world).getBiomeProvider(), (gen, coord) -> gen.getCarver().getNoise(coord.setY(coord.getY())));
ChunkInterpolator interpolator = new ChunkInterpolator3D(world, chunkX, chunkZ, main.getWorld(world).getBiomeProvider(), (gen, coord) -> gen.getCarver().getNoise(coord.setY(coord.getY())));
for(int y : range) {
for(int x = 0; x < 16; x++) {
for(int z = 0; z < 16; z++) {

View File

@ -0,0 +1,139 @@
package com.dfsek.terra.world.generation.generators;
import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.math.Range;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.MaterialData;
import com.dfsek.terra.api.platform.world.BiomeGrid;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.platform.world.generator.ChunkData;
import com.dfsek.terra.api.util.world.PaletteUtil;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.api.world.palette.SinglePalette;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.world.Carver;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.carving.NoiseCarver;
import com.dfsek.terra.world.generation.math.SamplerCache;
import com.dfsek.terra.world.generation.math.samplers.Sampler;
import com.dfsek.terra.world.generation.math.samplers.Sampler2D;
import net.jafama.FastMath;
import org.jetbrains.annotations.NotNull;
import java.util.Random;
public class DefaultChunkGenerator2D implements TerraChunkGenerator {
private final ConfigPack configPack;
private final TerraPlugin main;
private final MaterialData water;
private final SinglePalette<BlockData> blank;
private final Carver carver;
private final SamplerCache cache;
public DefaultChunkGenerator2D(ConfigPack c, TerraPlugin main, SamplerCache cache) {
this.configPack = c;
this.main = main;
carver = new NoiseCarver(new Range(0, 255), main.getWorldHandle().createBlockData("minecraft:air"), main);
water = main.getWorldHandle().createMaterialData("minecraft:water");
blank = new SinglePalette<>(main.getWorldHandle().createBlockData("minecraft:air"));
this.cache = cache;
}
@Override
public boolean isParallelCapable() {
return true;
}
@Override
public boolean shouldGenerateCaves() {
return configPack.getTemplate().vanillaCaves();
}
@Override
public boolean shouldGenerateDecorations() {
return configPack.getTemplate().vanillaDecorations();
}
@Override
public boolean shouldGenerateMobs() {
return configPack.getTemplate().vanillaMobs();
}
@Override
public boolean shouldGenerateStructures() {
return configPack.getTemplate().vanillaStructures();
}
@Override
public ConfigPack getConfigPack() {
return configPack;
}
@Override
public TerraPlugin getMain() {
return main;
}
@Override
@SuppressWarnings({"try"})
public ChunkData generateChunkData(@NotNull World world, Random random, int chunkX, int chunkZ, ChunkData chunk) {
TerraWorld tw = main.getWorld(world);
BiomeProvider grid = tw.getBiomeProvider();
try(ProfileFuture ignore = tw.getProfiler().measure("TotalChunkGenTime")) {
if(!tw.isSafe()) return chunk;
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);
Sampler sampler = cache.getChunk(world, chunkX, chunkZ);
for(int x = 0; x < 16; x++) {
for(int z = 0; z < 16; z++) {
int paletteLevel = 0;
int seaPaletteLevel = 0;
int cx = xOrig + x;
int cz = zOrig + z;
TerraBiome b = grid.getBiome(xOrig + x, zOrig + z);
BiomeTemplate c = ((UserDefinedBiome) b).getConfig();
Palette<BlockData> seaPalette = c.getOceanPalette();
int height = FastMath.min((int) sampler.sample(x, 0, z), world.getMaxHeight() - 1);
for(int y = FastMath.max(height, c.getSeaLevel()); y >= 0; y--) {
BlockData data = y > height ? seaPalette.get(seaPaletteLevel++, cx, y, cz) : PaletteUtil.getPalette(x, y, z, c, sampler).get(paletteLevel++, cx, y, cz);
chunk.setBlock(x, y, z, data);
}
}
}
if(configPack.getTemplate().doBetaCarvers()) {
carver.carve(world, chunkX, chunkZ, chunk);
}
return chunk;
}
}
@Override
public void generateBiomes(@NotNull World world, @NotNull Random random, int chunkX, int chunkZ, @NotNull BiomeGrid biome) {
DefaultChunkGenerator3D.biomes(world, chunkX, chunkZ, biome, main);
}
@Override
public SamplerCache getCache() {
return cache;
}
@Override
public Sampler createSampler(int chunkX, int chunkZ, BiomeProvider provider, World world, int elevationSmooth) {
return new Sampler2D(chunkX, chunkZ, provider, world, elevationSmooth);
}
}

View File

@ -26,8 +26,9 @@ import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.world.Carver;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.carving.NoiseCarver;
import com.dfsek.terra.world.generation.math.Sampler;
import com.dfsek.terra.world.generation.math.SamplerCache;
import com.dfsek.terra.world.generation.math.samplers.Sampler;
import com.dfsek.terra.world.generation.math.samplers.Sampler3D;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
@ -214,8 +215,7 @@ public class DefaultChunkGenerator3D implements TerraChunkGenerator {
return false;
}
@Override
public void generateBiomes(@NotNull World world, @NotNull Random random, int chunkX, int chunkZ, @NotNull BiomeGrid biome) {
static void biomes(@NotNull World world, int chunkX, int chunkZ, @NotNull BiomeGrid biome, TerraPlugin main) {
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);
BiomeProvider grid = main.getWorld(world).getBiomeProvider();
@ -230,8 +230,18 @@ public class DefaultChunkGenerator3D implements TerraChunkGenerator {
}
}
@Override
public void generateBiomes(@NotNull World world, @NotNull Random random, int chunkX, int chunkZ, @NotNull BiomeGrid biome) {
biomes(world, chunkX, chunkZ, biome, main);
}
@Override
public SamplerCache getCache() {
return cache;
}
@Override
public Sampler createSampler(int chunkX, int chunkZ, BiomeProvider provider, World world, int elevationSmooth) {
return new Sampler3D(chunkX, chunkZ, provider, world, elevationSmooth);
}
}

View File

@ -4,6 +4,7 @@ import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.math.MathUtil;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.world.TerraWorld;
import com.dfsek.terra.world.generation.math.samplers.Sampler;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
@ -39,7 +40,7 @@ public class SamplerCache {
containerMap.clear();
}
private class Container {
private final class Container {
private final TerraWorld terraWorld;
private final LoadingCache<Long, Sampler> cache;
@ -50,7 +51,7 @@ public class SamplerCache {
public Sampler load(@NotNull Long key) {
int cx = (int) (key >> 32);
int cz = (int) key.longValue();
return new Sampler(cx, cz, terraWorld.getBiomeProvider(), world, terraWorld.getConfig().getTemplate().getElevationBlend());
return terraWorld.getGenerator().createSampler(cx, cz, terraWorld.getBiomeProvider(), world, terraWorld.getConfig().getTemplate().getElevationBlend());
}
});
terraWorld = main.getWorld(world);

View File

@ -1,5 +1,10 @@
package com.dfsek.terra.world.generation.math.interpolation;
import com.dfsek.terra.api.util.mutable.MutableInteger;
import com.dfsek.terra.api.world.biome.Generator;
import java.util.Map;
public interface ChunkInterpolator {
/**
* Gets the noise at a pair of internal chunk coordinates.
@ -9,4 +14,20 @@ public interface ChunkInterpolator {
* @return double - The interpolated noise at the coordinates.
*/
double getNoise(double x, double y, double z);
default double computeNoise(Map<Generator, MutableInteger> gens, double x, double y, double z) {
double n = 0;
double div = 0;
for(Map.Entry<Generator, MutableInteger> entry : gens.entrySet()) {
Generator gen = entry.getKey();
int weight = entry.getValue().get();
double noise = computeNoise(gen, x, y, z);
n += noise * weight;
div += gen.getWeight() * weight;
}
return n / div;
}
double computeNoise(Generator generator, double x, double y, double z);
}

View File

@ -0,0 +1,84 @@
package com.dfsek.terra.world.generation.math.interpolation;
import com.dfsek.terra.api.math.vector.Vector3;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.util.mutable.MutableInteger;
import com.dfsek.terra.api.world.biome.Generator;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import net.jafama.FastMath;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
/**
* Class to abstract away the Interpolators needed to generate a chunk.<br>
* Contains method to get interpolated noise at a coordinate within the chunk.
*/
public class ChunkInterpolator2D implements ChunkInterpolator {
private final Interpolator[][] interpGrid = new Interpolator[4][4];
private final BiFunction<Generator, Vector3, Double> noiseGetter;
/**
* Instantiates a 3D ChunkInterpolator3D at a pair of chunk coordinates.
*
* @param chunkX X coordinate of the chunk.
* @param chunkZ Z coordinate of the chunk.
* @param provider Biome Provider to use for biome fetching.
*/
public ChunkInterpolator2D(World w, int chunkX, int chunkZ, BiomeProvider provider, BiFunction<Generator, Vector3, Double> noiseGetter) {
this.noiseGetter = noiseGetter;
int xOrigin = chunkX << 4;
int zOrigin = chunkZ << 4;
double[][] noiseStorage = new double[5][5];
for(int x = 0; x < 5; x++) {
for(int z = 0; z < 5; z++) {
Generator generator = provider.getBiome(xOrigin + (x << 2), zOrigin + (z << 2)).getGenerator(w);
Map<Generator, MutableInteger> genMap = new HashMap<>();
int step = generator.getBlendStep();
int blend = generator.getBlendDistance();
for(int xi = -blend; xi <= blend; xi++) {
for(int zi = -blend; zi <= blend; zi++) {
genMap.computeIfAbsent(provider.getBiome(xOrigin + (x << 2) + (xi * step), zOrigin + (z << 2) + (zi * step)).getGenerator(w), g -> new MutableInteger(0)).increment(); // Increment by 1
}
}
noiseStorage[x][z] = computeNoise(genMap, (x << 2) + xOrigin, 0, (z << 2) + zOrigin);
}
}
for(int x = 0; x < 4; x++) {
for(int z = 0; z < 4; z++) {
interpGrid[x][z] = new Interpolator(
noiseStorage[x][z],
noiseStorage[x + 1][z],
noiseStorage[x][z + 1],
noiseStorage[x + 1][z + 1]);
}
}
}
private static int reRange(int value, int high) {
return FastMath.max(FastMath.min(value, high), 0);
}
public double computeNoise(Generator generator, double x, double y, double z) {
return noiseGetter.apply(generator, new Vector3(x, y, z));
}
/**
* Gets the noise at a pair of internal chunk coordinates.
*
* @param x The internal X coordinate (0-15).
* @param z The internal Z coordinate (0-15).
* @return double - The interpolated noise at the coordinates.
*/
@Override
public double getNoise(double x, double y, double z) {
return interpGrid[reRange(((int) x) / 4, 3)][reRange(((int) z) / 4, 3)].bilerp((x % 4) / 4, (z % 4) / 4);
}
}

View File

@ -15,18 +15,18 @@ import java.util.function.BiFunction;
* Class to abstract away the Interpolators needed to generate a chunk.<br>
* Contains method to get interpolated noise at a coordinate within the chunk.
*/
public class BiomeChunkInterpolator implements ChunkInterpolator {
public class ChunkInterpolator3D implements ChunkInterpolator {
private final Interpolator3[][][] interpGrid = new Interpolator3[4][64][4];
private final BiFunction<Generator, Vector3, Double> noiseGetter;
/**
* Instantiates a 3D BiomeChunkInterpolator at a pair of chunk coordinates.
* Instantiates a 3D ChunkInterpolator3D at a pair of chunk coordinates.
*
* @param chunkX X coordinate of the chunk.
* @param chunkZ Z coordinate of the chunk.
* @param provider Biome Provider to use for biome fetching.
*/
public BiomeChunkInterpolator(World w, int chunkX, int chunkZ, BiomeProvider provider, BiFunction<Generator, Vector3, Double> noiseGetter) {
public ChunkInterpolator3D(World w, int chunkX, int chunkZ, BiomeProvider provider, BiFunction<Generator, Vector3, Double> noiseGetter) {
this.noiseGetter = noiseGetter;
int xOrigin = chunkX << 4;
int zOrigin = chunkZ << 4;
@ -70,21 +70,7 @@ public class BiomeChunkInterpolator implements ChunkInterpolator {
}
}
private double computeNoise(Map<Generator, MutableInteger> gens, double x, double y, double z) {
double n = 0;
double div = 0;
for(Map.Entry<Generator, MutableInteger> entry : gens.entrySet()) {
Generator gen = entry.getKey();
int weight = entry.getValue().get();
double noise = computeNoise(gen, x, y, z);
n += noise * weight;
div += gen.getWeight() * weight;
}
return n / div;
}
private double computeNoise(Generator generator, double x, double y, double z) {
public double computeNoise(Generator generator, double x, double y, double z) {
return noiseGetter.apply(generator, new Vector3(x, y, z));
}

View File

@ -31,7 +31,6 @@ public class Interpolator {
*/
public static double lerp(double t, double v0, double v1) {
return v0 + t * (v1 - v0);
}
/**

View File

@ -4,7 +4,8 @@ package com.dfsek.terra.world.generation.math.interpolation;
* Class for bilinear interpolation of values arranged on a unit square.
*/
public class Interpolator3 {
private final double _000, _100, _010, _110, _001, _101, _011, _111;
private final Interpolator bottom;
private final Interpolator top;
/**
* Constructs an interpolator with given values as vertices of a unit cube.
@ -18,21 +19,14 @@ public class Interpolator3 {
* * @param _111 The value at <code>(t, u, v) = (1, 1, 1)</code>.
*/
public Interpolator3(double _000, double _100,
double _010, double _110, double _001, double _101,
double _010, double _110,
double _001, double _101,
double _011, double _111) {
this._000 = _000;
this._001 = _001;
this._010 = _010;
this._011 = _011;
this._100 = _100;
this._101 = _101;
this._110 = _110;
this._111 = _111;
this.top = new Interpolator(_000, _010, _001, _011);
this.bottom = new Interpolator(_100, _110, _101, _111);
}
public double trilerp(double x, double y, double z) {
Interpolator top = new Interpolator(_000, _010, _001, _011);
Interpolator bottom = new Interpolator(_100, _110, _101, _111);
return Interpolator.lerp(x, top.bilerp(y, z), bottom.bilerp(y, z));
}
}

View File

@ -1,48 +0,0 @@
package com.dfsek.terra.world.generation.math.interpolation;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import net.jafama.FastMath;
public class NoiseChunkInterpolator implements ChunkInterpolator {
private final Interpolator3[][][] interpGrid = new Interpolator3[4][64][4];
public NoiseChunkInterpolator(int chunkX, int chunkZ, NoiseSampler noise) {
int xOrigin = chunkX << 4;
int zOrigin = chunkZ << 4;
double[][][] noiseStorage = new double[5][5][65];
for(int x = 0; x < 5; x++) {
for(int z = 0; z < 5; z++) {
for(int y = 0; y < 65; y++) {
noiseStorage[x][z][y] = noise.getNoise((x << 2) + xOrigin, y << 2, (z << 2) + zOrigin);
}
}
}
for(int x = 0; x < 4; x++) {
for(int z = 0; z < 4; z++) {
for(int y = 0; y < 64; y++) {
interpGrid[x][y][z] = new Interpolator3(
noiseStorage[x][z][y],
noiseStorage[x + 1][z][y],
noiseStorage[x][z][y + 1],
noiseStorage[x + 1][z][y + 1],
noiseStorage[x][z + 1][y],
noiseStorage[x + 1][z + 1][y],
noiseStorage[x][z + 1][y + 1],
noiseStorage[x + 1][z + 1][y + 1]);
}
}
}
}
private static int reRange(int value, int high) {
return FastMath.max(FastMath.min(value, high), 0);
}
@Override
public double getNoise(double x, double y, double z) {
return interpGrid[reRange(((int) x) / 4, 3)][reRange(((int) y) / 4, 63)][reRange(((int) z) / 4, 3)].trilerp((x % 4) / 4, (y % 4) / 4, (z % 4) / 4);
}
}

View File

@ -0,0 +1,6 @@
package com.dfsek.terra.world.generation.math.samplers;
@FunctionalInterface
public interface Sampler {
double sample(double x, double y, double z);
}

View File

@ -0,0 +1,22 @@
package com.dfsek.terra.world.generation.math.samplers;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.world.generation.math.interpolation.ChunkInterpolator2D;
import com.dfsek.terra.world.generation.math.interpolation.ElevationInterpolator;
import net.jafama.FastMath;
public class Sampler2D implements Sampler {
private final ChunkInterpolator2D interpolator;
private final ElevationInterpolator elevationInterpolator;
public Sampler2D(int x, int z, BiomeProvider provider, World world, int elevationSmooth) {
this.interpolator = new ChunkInterpolator2D(world, x, z, provider, (generator, coord) -> generator.getBaseSampler().getNoise(coord));
this.elevationInterpolator = new ElevationInterpolator(world, x, z, provider, elevationSmooth);
}
@Override
public double sample(double x, double y, double z) {
return interpolator.getNoise(x, 0, z) + elevationInterpolator.getElevation(FastMath.roundToInt(x), FastMath.roundToInt(z));
}
}

View File

@ -1,25 +1,22 @@
package com.dfsek.terra.world.generation.math;
package com.dfsek.terra.world.generation.math.samplers;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
import com.dfsek.terra.world.generation.math.interpolation.BiomeChunkInterpolator;
import com.dfsek.terra.world.generation.math.interpolation.ChunkInterpolator3D;
import com.dfsek.terra.world.generation.math.interpolation.ElevationInterpolator;
import net.jafama.FastMath;
public class Sampler {
private final BiomeChunkInterpolator interpolator;
public class Sampler3D implements Sampler {
private final ChunkInterpolator3D interpolator;
private final ElevationInterpolator elevationInterpolator;
public Sampler(int x, int z, BiomeProvider provider, World world, int elevationSmooth) {
this.interpolator = new BiomeChunkInterpolator(world, x, z, provider, (generator, coord) -> generator.getBaseSampler().getNoise(coord));
public Sampler3D(int x, int z, BiomeProvider provider, World world, int elevationSmooth) {
this.interpolator = new ChunkInterpolator3D(world, x, z, provider, (generator, coord) -> generator.getBaseSampler().getNoise(coord));
this.elevationInterpolator = new ElevationInterpolator(world, x, z, provider, elevationSmooth);
}
@Override
public double sample(double x, double y, double z) {
return interpolator.getNoise(x, y, z) + elevationInterpolator.getElevation(FastMath.roundToInt(x), FastMath.roundToInt(z));
}
public static double noise2dExtrude(double y, double base) {
return ((-FastMath.pow2((y / base))) + 1);
}
}