elevation tweaks & general cleanup

This commit is contained in:
dfsek
2020-12-30 00:03:02 -07:00
parent 7d0149b59d
commit a68b85c522
13 changed files with 66 additions and 186 deletions

View File

@@ -15,9 +15,6 @@ public class ChunkInterpolator3 {
private final Generator[][] gens = new Generator[7][7];
private final boolean[][] needsBiomeInterp = new boolean[5][5];
private final double[][][] noiseStorage = new double[7][7][65];
private final int xOrigin;
private final int zOrigin;
private final World w;
/**
* Instantiates a 3D ChunkInterpolator at a pair of chunk coordinates, with a BiomeGrid and FastNoiseLite instance.
@@ -27,9 +24,8 @@ public class ChunkInterpolator3 {
* @param grid BiomeGrid to use for noise fetching.
*/
public ChunkInterpolator3(World w, int chunkX, int chunkZ, BiomeGrid grid) {
this.xOrigin = chunkX << 4;
this.zOrigin = chunkZ << 4;
this.w = w;
int xOrigin = chunkX << 4;
int zOrigin = chunkZ << 4;
for(int x = -1; x < 6; x++) {
@@ -39,11 +35,17 @@ public class ChunkInterpolator3 {
}
for(int x = 0; x < 5; x++) {
for(int z = 0; z < 5; z++) {
needsBiomeInterp[x][z] = compareGens(x+1, z+1);
needsBiomeInterp[x][z] = compareGens(x + 1, z + 1);
}
}
storeNoise();
for(byte x = -1; x < 6; x++) {
for(byte z = -1; z < 6; z++) {
for(int y = 0; y < 65; y++) {
noiseStorage[x + 1][z + 1][y] = gens[x + 1][z + 1].getNoise(w, (x << 2) + xOrigin, y << 2, (z << 2) + zOrigin);
}
}
}
for(byte x = 0; x < 4; x++) {
for(byte z = 0; z < 4; z++) {
@@ -56,7 +58,7 @@ public class ChunkInterpolator3 {
biomeAvg(x, y, z + 1),
biomeAvg(x + 1, y, z + 1),
biomeAvg(x, y + 1, z + 1),
biomeAvg(x + 1, y + 1, z + 1), gens[x+1][z+1].getInterpolationType());
biomeAvg(x + 1, y + 1, z + 1));
}
}
}
@@ -80,15 +82,6 @@ public class ChunkInterpolator3 {
return !comp.equals(gens[x - 1][z + 1]);
}
private void storeNoise() {
for(byte x = - 1; x < 6; x++) {
for(byte z = - 1; z < 6; z++) {
for(int y = 0; y < 64; y++) {
noiseStorage[x + 1][z + 1][y] = gens[x + 1][z + 1].getNoise(w, (x << 2) + xOrigin, y << 2, (z << 2) + zOrigin);
}
}
}
}
private double biomeAvg(int x, int y, int z) {
if(needsBiomeInterp[x][z]) return (noiseStorage[x + 2][z + 1][y]

View File

@@ -1,13 +1,10 @@
package com.dfsek.terra.api.math.interpolation;
import net.jafama.FastMath;
/**
* Class for bilinear interpolation of values arranged on a unit square.
*/
public class Interpolator {
private final double v0, v1, v2, v3;
private final Type type;
/**
* Constructs an interpolator with given values as vertices of a unit square.
@@ -17,12 +14,11 @@ public class Interpolator {
* @param v2 - (0,1)
* @param v3 - (1,1)
*/
public Interpolator(double v0, double v1, double v2, double v3, Type type) {
public Interpolator(double v0, double v1, double v2, double v3) {
this.v0 = v0;
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
this.type = type;
}
/**
@@ -33,12 +29,9 @@ public class Interpolator {
* @param v1 - Value at v1.
* @return double - The interpolated value.
*/
public static double lerp(double t, double v0, double v1, Type type) {
switch(type) {
case LINEAR: return v0 + t * (v1 - v0);
case NEAREST_NEIGHBOR: return FastMath.abs(v0-t) > FastMath.abs(v1-t) ? v1 : v0;
default: throw new IllegalStateException();
}
public static double lerp(double t, double v0, double v1) {
return v0 + t * (v1 - v0);
}
/**
@@ -49,13 +42,8 @@ public class Interpolator {
* @return double - The interpolated value.
*/
public double bilerp(double s, double t) {
double v01 = lerp(s, v0, v1, type);
double v23 = lerp(s, v2, v3, type);
double v = lerp(t, v01, v23, type);
return v;
}
public enum Type {
LINEAR, NEAREST_NEIGHBOR
double v01 = lerp(s, v0, v1);
double v23 = lerp(s, v2, v3);
return lerp(t, v01, v23);
}
}

View File

@@ -5,7 +5,6 @@ package com.dfsek.terra.api.math.interpolation;
*/
public class Interpolator3 {
private final double _000, _100, _010, _110, _001, _101, _011, _111;
private final Interpolator.Type type;
/**
* Constructs an interpolator with given values as vertices of a unit cube.
@@ -20,7 +19,7 @@ public class Interpolator3 {
*/
public Interpolator3(double _000, double _100,
double _010, double _110, double _001, double _101,
double _011, double _111, Interpolator.Type type) {
double _011, double _111) {
this._000 = _000;
this._001 = _001;
this._010 = _010;
@@ -29,12 +28,11 @@ public class Interpolator3 {
this._101 = _101;
this._110 = _110;
this._111 = _111;
this.type = type;
}
public double trilerp(double x, double y, double z) {
Interpolator top = new Interpolator(_000, _010, _001, _011, type);
Interpolator bottom = new Interpolator(_100, _110, _101, _111, type);
return Interpolator.lerp(x, top.bilerp(y, z), bottom.bilerp(y, z), type);
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

@@ -23,13 +23,6 @@ public interface Biome {
*/
Generator getGenerator();
/**
* Returns the Decorator instance containing information about the population in the biome.
*
* @return Decorator - the Decorator instance.
*/
Decorator getDecorator();
/**
* Gets the BiomeTerrain instance used to generate the biome in this world.
*

View File

@@ -1,20 +0,0 @@
package com.dfsek.terra.api.world.biome;
import com.dfsek.terra.api.math.ProbabilityCollection;
import com.dfsek.terra.api.world.flora.Flora;
import com.dfsek.terra.api.world.tree.Tree;
public abstract class Decorator {
public abstract ProbabilityCollection<Tree> getTrees();
public abstract int getTreeDensity();
public abstract boolean overrideStructureChance();
public abstract ProbabilityCollection<Flora> getFlora();
public abstract int getFloraChance();
}

View File

@@ -1,11 +1,10 @@
package com.dfsek.terra.api.world.biome;
import com.dfsek.terra.api.math.interpolation.Interpolator;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.world.palette.Palette;
public abstract class Generator {
public interface Generator {
/**
* Gets the 3D noise at a pair of coordinates using the provided FastNoiseLite instance.
*
@@ -14,27 +13,19 @@ public abstract class Generator {
* @param z - The z coordinate.
* @return double - Noise value at the specified coordinates.
*/
public abstract double getNoise(World w, int x, int y, int z);
double getNoise(World w, int x, int y, int z);
/**
* Gets the BlocPalette to generate the biome with.
*
* @return BlocPalette - The biome's palette.
*/
public abstract Palette<BlockData> getPalette(int y);
Palette<BlockData> getPalette(int y);
/**
* Returns true if the biome should be interpolated just once, false to use advanced interpolation + blending.
*
* @return Whether biome should use minimal interpolation
*/
public abstract boolean useMinimalInterpolation();
/**
* Get the type of interpolation to use in this biome.
* @return Interpolation type
*/
public Interpolator.Type getInterpolationType() {
return Interpolator.Type.LINEAR;
}
boolean useMinimalInterpolation();
}

View File

@@ -2,19 +2,16 @@ package com.dfsek.terra.biome;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.Decorator;
import com.dfsek.terra.api.world.biome.Generator;
import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.builder.GeneratorBuilder;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.generation.UserDefinedDecorator;
/**
* Class representing a config-defined biome
*/
public class UserDefinedBiome implements Biome {
private final GeneratorBuilder gen;
private final UserDefinedDecorator decorator;
private final com.dfsek.terra.api.platform.world.Biome vanilla;
private final String id;
private final BiomeTemplate config;
@@ -22,9 +19,8 @@ public class UserDefinedBiome implements Biome {
private UserDefinedBiome erode;
public UserDefinedBiome(com.dfsek.terra.api.platform.world.Biome vanilla, UserDefinedDecorator dec, GeneratorBuilder gen, BiomeTemplate config, ConfigPack pack) {
public UserDefinedBiome(com.dfsek.terra.api.platform.world.Biome vanilla, GeneratorBuilder gen, BiomeTemplate config, ConfigPack pack) {
this.vanilla = vanilla;
this.decorator = dec;
this.gen = gen;
this.id = config.getID();
this.config = config;
@@ -52,16 +48,6 @@ public class UserDefinedBiome implements Biome {
}
/**
* Returns the Decorator instance containing information about the population in the biome.
*
* @return Decorator - the Decorator instance.
*/
@Override
public Decorator getDecorator() {
return decorator;
}
public String getID() {
return id;
}

View File

@@ -1,12 +1,10 @@
package com.dfsek.terra.config.factories;
import com.dfsek.terra.api.math.ProbabilityCollection;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.builder.GeneratorBuilder;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.generation.UserDefinedDecorator;
public class BiomeFactory implements TerraFactory<BiomeTemplate, UserDefinedBiome> {
private final ConfigPack pack;
@@ -17,7 +15,6 @@ public class BiomeFactory implements TerraFactory<BiomeTemplate, UserDefinedBiom
@Override
public UserDefinedBiome build(BiomeTemplate template, TerraPlugin main) {
UserDefinedDecorator decorator = new UserDefinedDecorator(new ProbabilityCollection<>(), new ProbabilityCollection<>(), 0, 0);
GeneratorBuilder generatorBuilder = new GeneratorBuilder();
generatorBuilder.setElevationEquation(template.getElevationEquation());
generatorBuilder.setNoiseEquation(template.getNoiseEquation());
@@ -28,6 +25,6 @@ public class BiomeFactory implements TerraFactory<BiomeTemplate, UserDefinedBiom
generatorBuilder.setInterpolateElevation(template.interpolateElevation());
return new UserDefinedBiome(template.getVanilla(), decorator, generatorBuilder, template, pack);
return new UserDefinedBiome(template.getVanilla(), generatorBuilder, template, pack);
}
}

View File

@@ -6,33 +6,35 @@ import com.dfsek.terra.biome.grid.master.TerraBiomeGrid;
import com.dfsek.terra.generation.config.WorldGenerator;
public class ElevationInterpolator {
private final WorldGenerator[][] gens = new WorldGenerator[10][10];
private final WorldGenerator[][] gens;
private final double[][] values = new double[18][18];
private final int xOrigin;
private final int zOrigin;
private final TerraBiomeGrid grid;
private final int smooth;
public ElevationInterpolator(int chunkX, int chunkZ, TerraBiomeGrid grid) {
public ElevationInterpolator(int chunkX, int chunkZ, TerraBiomeGrid grid, int smooth) {
this.xOrigin = chunkX << 4;
this.zOrigin = chunkZ << 4;
this.grid = grid;
this.smooth = smooth;
this.gens = new WorldGenerator[10][10];
for(int x = -2; x < 8; x++) {
for(int z = -2; z < 8; z++) {
gens[x + 2][z + 2] = (WorldGenerator) grid.getBiome(xOrigin + (x << 2), zOrigin + (z << 2), GenerationPhase.BASE).getGenerator();
gens[x + 2][z + 2] = (WorldGenerator) grid.getBiome(xOrigin + (x * smooth), zOrigin + (z * smooth), GenerationPhase.BASE).getGenerator();
}
}
for(byte x = -1; x <= 16; x++) {
for(byte z = -1; z <= 16; z++) {
WorldGenerator generator = getGenerator(x, z);
if(compareGens((x / 4), (z / 4)) && generator.interpolateElevation()) {
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 + 1][z + 1] = interpolator.bilerp((double) (x % 4) / 4, (double) (z % 4) / 4);
if(compareGens((x / smooth), (z / smooth), generator) && generator.interpolateElevation()) {
Interpolator interpolator = new Interpolator(biomeAvg(x / smooth, z / smooth),
biomeAvg((x / smooth) + 1, z / smooth),
biomeAvg(x / smooth, (z / smooth) + 1),
biomeAvg((x / smooth) + 1, (z / smooth) + 1));
values[x + 1][z + 1] = interpolator.bilerp((double) (x % smooth) / smooth, (double) (z % smooth) / smooth);
} else values[x + 1][z + 1] = elevate(generator, xOrigin + x, zOrigin + z);
}
}
@@ -46,9 +48,7 @@ public class ElevationInterpolator {
return gens[x + 2][z + 2];
}
private boolean compareGens(int x, int z) {
WorldGenerator comp = getStoredGen(x, z);
private boolean compareGens(int x, int z, WorldGenerator comp) {
for(int xi = x - 2; xi <= x + 2; xi++) {
for(int zi = z - 2; zi <= z + 2; zi++) {
if(!comp.equals(getStoredGen(xi, zi))) return true;
@@ -58,15 +58,15 @@ public class ElevationInterpolator {
}
private double biomeAvg(int x, int z) {
return (elevate(getStoredGen(x + 1, z), (x << 2) + 4 + xOrigin, (z << 2) + zOrigin)
+ elevate(getStoredGen(x - 1, z), (x << 2) - 4 + xOrigin, (z << 2) + zOrigin)
+ elevate(getStoredGen(x, z + 1), (x << 2) + xOrigin, (z << 2) + 4 + zOrigin)
+ elevate(getStoredGen(x, z - 1), (x << 2) + xOrigin, (z << 2) - 4 + zOrigin)
+ elevate(getStoredGen(x, z), (x << 2) + xOrigin, (z << 2) + zOrigin)
+ elevate(getStoredGen(x - 1, z - 1), (x << 2) + xOrigin, (z << 2) + zOrigin)
+ elevate(getStoredGen(x - 1, z + 1), (x << 2) + xOrigin, (z << 2) + zOrigin)
+ elevate(getStoredGen(x + 1, z - 1), (x << 2) + xOrigin, (z << 2) + zOrigin)
+ elevate(getStoredGen(x + 1, z + 1), (x << 2) + xOrigin, (z << 2) + zOrigin)) / 9D;
return (elevate(getStoredGen(x + 1, z), (x * smooth) + smooth + xOrigin, (z * smooth) + zOrigin)
+ elevate(getStoredGen(x - 1, z), (x * smooth) - smooth + xOrigin, (z * smooth) + zOrigin)
+ elevate(getStoredGen(x, z + 1), (x * smooth) + xOrigin, (z * smooth) + smooth + zOrigin)
+ elevate(getStoredGen(x, z - 1), (x * smooth) + xOrigin, (z * smooth) - smooth + zOrigin)
+ elevate(getStoredGen(x, z), (x * smooth) + xOrigin, (z * smooth) + zOrigin)
+ elevate(getStoredGen(x - 1, z - 1), (x * smooth) - smooth + xOrigin, (z * smooth) - smooth + zOrigin)
+ elevate(getStoredGen(x - 1, z + 1), (x * smooth) - smooth + xOrigin, (z * smooth) + smooth + zOrigin)
+ elevate(getStoredGen(x + 1, z - 1), (x * smooth) + smooth + xOrigin, (z * smooth) - smooth + zOrigin)
+ elevate(getStoredGen(x + 1, z + 1), (x * smooth) + smooth + xOrigin, (z * smooth) + smooth + zOrigin)) / 9D;
}
private double elevate(WorldGenerator g, int x, int z) {

View File

@@ -17,6 +17,7 @@ import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.profiler.ProfileFuture;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.generation.GenerationPhase;
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.biome.palette.SinglePalette;
@@ -28,7 +29,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.Map;
import java.util.Random;
public class MasterChunkGenerator implements com.dfsek.terra.api.world.generation.TerraChunkGenerator {
public class MasterChunkGenerator implements TerraChunkGenerator {
private final ConfigPack configPack;
@@ -95,7 +96,7 @@ public class MasterChunkGenerator implements com.dfsek.terra.api.world.generatio
ElevationInterpolator elevationInterpolator;
try(ProfileFuture ignored1 = tw.getProfiler().measure("ElevationTime")) {
elevationInterpolator = new ElevationInterpolator(chunkX, chunkZ, tw.getGrid());
elevationInterpolator = new ElevationInterpolator(chunkX, chunkZ, tw.getGrid(), 8);
}
Sampler sampler = new Sampler(interp, elevationInterpolator);

View File

@@ -1,47 +0,0 @@
package com.dfsek.terra.generation;
import com.dfsek.terra.api.math.ProbabilityCollection;
import com.dfsek.terra.api.world.biome.Decorator;
import com.dfsek.terra.api.world.flora.Flora;
import com.dfsek.terra.api.world.tree.Tree;
public class UserDefinedDecorator extends Decorator {
private final ProbabilityCollection<Flora> flora;
private final ProbabilityCollection<Tree> trees;
private final int floraChance;
private final int treeDensity;
public UserDefinedDecorator(ProbabilityCollection<Flora> flora, ProbabilityCollection<Tree> trees, int floraChance, int treeDensity) {
this.flora = flora;
this.trees = trees;
this.floraChance = floraChance;
this.treeDensity = treeDensity;
}
@Override
public ProbabilityCollection<Tree> getTrees() {
return trees;
}
@Override
public int getTreeDensity() {
return treeDensity;
}
@Override
public boolean overrideStructureChance() {
return false;
}
@Override
public ProbabilityCollection<Flora> getFlora() {
return flora;
}
@Override
public int getFloraChance() {
return floraChance;
}
}

View File

@@ -1,6 +1,5 @@
package com.dfsek.terra.generation.config;
import com.dfsek.terra.api.math.interpolation.Interpolator;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.world.biome.Generator;
@@ -17,7 +16,7 @@ import parsii.tokenizer.ParseException;
import java.util.Map;
public class WorldGenerator extends Generator {
public class WorldGenerator implements Generator {
@SuppressWarnings({"unchecked", "rawtypes", "RedundantSuppression"})
private final PaletteHolder palettes;
@SuppressWarnings({"unchecked", "rawtypes", "RedundantSuppression"})
@@ -33,7 +32,6 @@ public class WorldGenerator extends Generator {
private final Variable elevationZVar;
private final boolean elevationInterpolation;
@SuppressWarnings({"rawtypes", "unchecked"})
public WorldGenerator(long seed, String equation, String elevateEquation, Scope vScope, Map<String, NoiseBuilder> noiseBuilders, PaletteHolder palettes, PaletteHolder slantPalettes, boolean preventSmooth, boolean elevationInterpolation) {
Parser p = new Parser();
p.registerFunction("rand", new RandomFunction());
@@ -117,11 +115,6 @@ public class WorldGenerator extends Generator {
return preventSmooth;
}
@Override
public Interpolator.Type getInterpolationType() {
return Interpolator.Type.LINEAR;
}
public boolean interpolateElevation() {
return elevationInterpolation;
}

View File

@@ -8,6 +8,7 @@ import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.Sign;
import org.bukkit.block.data.BlockData;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@@ -59,6 +60,7 @@ public class ExportCommand extends PlayerCommand {
for(int x = l1.getBlockX(); x <= l2.getBlockX(); x++) {
for(int y = l1.getBlockY(); y <= l2.getBlockY(); y++) {
for(int z = l1.getBlockZ(); z <= l2.getBlockZ(); z++) {
String data;
Block block = new Location(l1.getWorld(), x, y, z).getBlock();
if(block.getType().equals(Material.STRUCTURE_VOID)) continue;
scriptBuilder.append("block(").append(x - l1.getBlockX() - centerX).append(", y + ").append(y - l1.getBlockY() - centerY).append(", ").append(z - l1.getBlockZ() - centerZ).append(", ")
@@ -67,12 +69,17 @@ public class ExportCommand extends PlayerCommand {
if(state instanceof Sign) {
Sign sign = (Sign) state;
if(sign.getLine(0).equals("[TERRA]")) {
scriptBuilder.append(Bukkit.createBlockData(sign.getLine(2) + sign.getLine(3)).getAsString(false));
} else scriptBuilder.append(block.getBlockData().getAsString(false));
data = sign.getLine(2) + sign.getLine(3);
BlockData data1 = Bukkit.createBlockData(sign.getLine(2) + sign.getLine(3));
if(data1.getMaterial().equals(Material.STRUCTURE_VOID)) continue;
scriptBuilder.append(data1.getAsString(false));
} else {
data = block.getBlockData().getAsString(false);
}
} else {
scriptBuilder.append(block.getBlockData().getAsString(false));
data = block.getBlockData().getAsString(false);
}
scriptBuilder.append("\");\n");
scriptBuilder.append(data).append("\");\n");
}
}
}