implementation of BiomePipeline

This commit is contained in:
dfsek
2021-01-13 00:19:57 -07:00
parent 5c9a9c7dfa
commit fb32531584
54 changed files with 240 additions and 1332 deletions
@@ -0,0 +1,26 @@
package com.dfsek.terra.biome;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.math.vector.Vector2;
import com.dfsek.terra.api.math.vector.Vector3;
import com.dfsek.terra.api.world.biome.TerraBiome;
public interface BiomeProvider {
TerraBiome getBiome(int x, int z);
default TerraBiome getBiome(Vector2 vector2) {
return getBiome(vector2.getBlockX(), vector2.getBlockZ());
}
default TerraBiome getBiome(Vector3 vector3) {
return getBiome(vector3.getBlockX(), vector3.getBlockZ());
}
default TerraBiome getBiome(Location location) {
return getBiome(location.getBlockX(), location.getBlockZ());
}
interface BiomeProviderBuilder {
BiomeProvider build(long seed);
}
}
@@ -1,78 +0,0 @@
package com.dfsek.terra.biome;
import com.dfsek.terra.api.math.noise.samplers.FastNoiseLite;
import com.dfsek.terra.api.world.biome.BiomeGrid;
import com.dfsek.terra.api.world.biome.NormalizationUtil;
import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.base.ConfigPackTemplate;
import com.dfsek.terra.image.ImageLoader;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
/**
* Holds 1D array of BiomeGrids.
*/
public class BiomeZone {
private final BiomeGrid[] grids;
private final FastNoiseLite noise;
@Nullable
private final ImageLoader imageLoader;
private final boolean useImage;
private final ImageLoader.Channel channel;
public BiomeZone(long seed, ConfigPack wc, BiomeGrid[] grids) {
this.noise = new FastNoiseLite((int) seed + 2);
this.noise.setNoiseType(FastNoiseLite.NoiseType.OpenSimplex2);
this.noise.setFractalType(FastNoiseLite.FractalType.FBm);
this.noise.setFractalOctaves(4);
ConfigPackTemplate t = wc.getTemplate();
this.noise.setFrequency(1D / (t.getZoneFreq() * grids.length));
this.grids = grids;
imageLoader = t.getImageLoader();
useImage = t.isFromImage();
channel = t.getZoneChannel();
}
/**
* Get BiomeGrid at location
*
* @param x X coordinate
* @param z Z coordinate
* @return BiomeGrid at coordinates.
*/
public BiomeGrid getGrid(int x, int z) {
return grids[getNoise(x, z)];
}
/**
* 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 useImage ? Objects.requireNonNull(imageLoader).getNoiseVal(x, z, getSize() - 1, channel) : NormalizationUtil.normalize(noise.getNoise(x, z), grids.length, 4);
}
/**
* 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, getSize() - 1, channel) : noise.getNoise(x, z);
}
}
@@ -0,0 +1,65 @@
package com.dfsek.terra.biome;
import com.dfsek.terra.api.math.vector.Vector2;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.biome.pipeline.BiomeHolder;
import com.dfsek.terra.biome.pipeline.BiomePipeline;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import net.jafama.FastMath;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.ExecutionException;
import java.util.function.Function;
public class StandardBiomeProvider implements BiomeProvider {
private final BiomePipeline pipeline;
private final LoadingCache<Vector2, BiomeHolder> cache = CacheBuilder.newBuilder()
.maximumSize(1024)
.build(
new CacheLoader<Vector2, BiomeHolder>() {
@Override
public BiomeHolder load(@NotNull Vector2 key) {
return pipeline.getBiomes(key.getBlockX(), key.getBlockZ());
}
}
);
private int resolution = 4;
protected StandardBiomeProvider(BiomePipeline pipeline) {
this.pipeline = pipeline;
}
@Override
public TerraBiome getBiome(int x, int z) {
x /= resolution;
z /= resolution;
try {
return cache.get(new Vector2(FastMath.floorDiv(x, pipeline.getSize()), FastMath.floorDiv(z, pipeline.getSize()))).getBiome(FastMath.floorMod(x, pipeline.getSize()), FastMath.floorMod(z, pipeline.getSize()));
} catch(ExecutionException e) {
throw new RuntimeException(e);
}
}
public int getResolution() {
return resolution;
}
public void setResolution(int resolution) {
this.resolution = resolution;
}
public static final class StandardBiomeProviderBuilder implements BiomeProviderBuilder {
private final Function<Long, BiomePipeline> pipelineBuilder;
public StandardBiomeProviderBuilder(Function<Long, BiomePipeline> pipelineBuilder) {
this.pipelineBuilder = pipelineBuilder;
}
@Override
public StandardBiomeProvider build(long seed) {
return new StandardBiomeProvider(pipelineBuilder.apply(seed));
}
}
}
@@ -7,6 +7,7 @@ import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.builder.GeneratorBuilder;
import com.dfsek.terra.config.templates.BiomeTemplate;
import java.util.HashSet;
import java.util.Set;
/**
@@ -30,7 +31,7 @@ public class UserDefinedBiome implements TerraBiome {
this.config = config;
this.pack = pack;
this.color = config.getColor();
this.tags = config.getTags();
this.tags = config.getTags() == null ? new HashSet<>() : config.getTags();
tags.add("BIOME:" + id);
}
@@ -1,28 +0,0 @@
package com.dfsek.terra.biome.grid;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.world.biome.BiomeGrid;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.generation.GenerationPhase;
/**
* BiomeGrid implementation that holds a single biome.
*/
public class SingleBiomeGrid extends BiomeGrid {
private final TerraBiome biome;
public SingleBiomeGrid(long seed, TerraBiome biome) {
super(seed, 0, 0, 1, 1);
this.biome = biome;
}
@Override
public TerraBiome getBiome(int x, int z, GenerationPhase phase) {
return biome;
}
@Override
public TerraBiome getBiome(Location l) {
return biome;
}
}
@@ -1,41 +0,0 @@
package com.dfsek.terra.biome.grid;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.world.biome.BiomeGrid;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.generation.GenerationPhase;
import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.base.ConfigPackTemplate;
import com.dfsek.terra.image.ImageLoader;
public class UserDefinedGrid extends BiomeGrid {
private final ImageLoader imageLoader;
private final boolean fromImage;
private final ImageLoader.Channel channelX;
private final ImageLoader.Channel channelZ;
public UserDefinedGrid(long seed, double freq1, double freq2, TerraBiome[][] b, ConfigPack c) {
super(seed, freq1, freq2, b.length, b[0].length);
super.setGrid(b);
ConfigPackTemplate t = c.getTemplate();
imageLoader = t.getImageLoader();
fromImage = t.isFromImage();
channelX = t.getBiomeXChannel();
channelZ = t.getBiomeZChannel();
}
@Override
public TerraBiome getBiome(int x, int z, GenerationPhase phase) {
if(fromImage) {
int xi = imageLoader.getNoiseVal(x, z, getSizeX() - 1, channelX);
int zi = imageLoader.getNoiseVal(x, z, getSizeZ() - 1, channelZ);
return super.getGrid()[xi][zi];
}
return super.getBiome(x, z, phase);
}
@Override
public TerraBiome getBiome(Location l, GenerationPhase phase) {
return this.getBiome(l.getBlockX(), l.getBlockZ(), phase);
}
}
@@ -1,70 +0,0 @@
package com.dfsek.terra.biome.grid.master;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.world.biome.BiomeGrid;
import com.dfsek.terra.biome.BiomeZone;
import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.base.ConfigPackTemplate;
import com.dfsek.terra.config.builder.biomegrid.BiomeGridBuilder;
import com.dfsek.terra.debug.Debug;
public abstract class TerraBiomeGrid extends BiomeGrid {
protected final BiomeZone zone;
public TerraBiomeGrid(long seed, int sizeX, int sizeZ, BiomeZone zone) {
super(seed, 0, 0, sizeX, sizeZ);
this.zone = zone;
}
public BiomeZone getZone() {
return zone;
}
public abstract BiomeGrid getGrid(int x, int z);
public enum Type {
RADIAL, STANDARD
}
public abstract boolean isEroded(int x, int z);
public static final class TerraBiomeGridBuilder {
private final long seed;
private final ConfigPack config;
private final TerraPlugin main;
public TerraBiomeGridBuilder(long seed, ConfigPack config, TerraPlugin main) {
this.seed = seed;
this.config = config;
this.main = main;
}
public TerraBiomeGrid build() {
ConfigPackTemplate template = config.getTemplate();
int zoneSize = template.getGrids().size();
BiomeGrid[] definedGrids = new BiomeGrid[zoneSize];
for(int i = 0; i < zoneSize; i++) {
String partName = template.getGrids().get(i);
try {
BiomeGridBuilder g = config.getBiomeGrid(partName);
BiomeGrid b = g.build(seed, config);
definedGrids[i] = b;
} catch(NullPointerException e) {
Debug.stack(e);
main.getLogger().severe("No such BiomeGrid " + partName);
main.getLogger().severe("Please check configuration files for errors. Configuration errors will have been reported during initialization.");
main.getLogger().severe("ONLY report this to Terra if you are SURE your config is error-free.");
main.getLogger().severe("Terrain will NOT generate properly at this point. Correct your config before using your server!");
}
}
BiomeZone zone = new BiomeZone(seed, config, definedGrids);
if(template.getGridType().equals(TerraBiomeGrid.Type.RADIAL)) {
BiomeGrid internal = config.getBiomeGrid(template.getRadialInternalGrid()).build(seed, config);
return new TerraRadialBiomeGrid(seed, zone, config, template.getRadialGridRadius(), internal);
} else return new TerraStandardBiomeGrid(seed, zone, config);
}
}
}
@@ -1,68 +0,0 @@
package com.dfsek.terra.biome.grid.master;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.math.vector.Vector2;
import com.dfsek.terra.api.world.biome.BiomeGrid;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.generation.GenerationPhase;
import com.dfsek.terra.biome.BiomeZone;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.biome.postprocessing.CoordinatePerturb;
import com.dfsek.terra.biome.postprocessing.ErosionNoise;
import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.base.ConfigPackTemplate;
import net.jafama.FastMath;
public class TerraRadialBiomeGrid extends TerraBiomeGrid {
private final double radiusSq;
private final BiomeGrid internal;
private CoordinatePerturb perturb;
private ErosionNoise erode;
public TerraRadialBiomeGrid(long seed, BiomeZone zone, ConfigPack c, double radius, BiomeGrid internal) {
super(seed, 0, 0, zone);
ConfigPackTemplate t = c.getTemplate();
if(c.getTemplate().isBlend()) {
perturb = new CoordinatePerturb(t.getBlendFreq(), t.getBlendAmp(), seed);
}
if(c.getTemplate().isErode()) {
erode = new ErosionNoise(t.getErodeFreq(), t.getErodeThresh(), t.getErodeOctaves(), seed);
}
this.radiusSq = FastMath.pow2(radius);
this.internal = internal;
}
@Override
public BiomeGrid getGrid(int x, int z) {
return zone.getGrid(x, z);
}
@Override
public boolean isEroded(int x, int z) {
return erode != null && erode.isEroded(x, z);
}
@Override
public TerraBiome getBiome(int x, int z, GenerationPhase phase) {
int xp = x, zp = z;
if(perturb != null && (phase.equals(GenerationPhase.PALETTE_APPLY) || phase.equals(GenerationPhase.POPULATE))) {
Vector2 perturbCoords = perturb.getShiftedCoords(x, z);
xp = (int) perturbCoords.getX();
zp = (int) perturbCoords.getZ();
}
UserDefinedBiome b;
if(x * x + z * z > radiusSq) {
b = (UserDefinedBiome) zone.getGrid(xp, zp).getBiome(xp, zp, phase);
} else {
b = (UserDefinedBiome) internal.getBiome(xp, zp, phase);
}
if(isEroded(xp, zp)) return b.getErode();
return b;
}
@Override
public TerraBiome getBiome(Location l, GenerationPhase phase) {
return getBiome(l.getBlockX(), l.getBlockZ(), phase);
}
}
@@ -1,59 +0,0 @@
package com.dfsek.terra.biome.grid.master;
import com.dfsek.terra.api.math.vector.Location;
import com.dfsek.terra.api.math.vector.Vector2;
import com.dfsek.terra.api.world.biome.BiomeGrid;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.generation.GenerationPhase;
import com.dfsek.terra.biome.BiomeZone;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.biome.postprocessing.CoordinatePerturb;
import com.dfsek.terra.biome.postprocessing.ErosionNoise;
import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.base.ConfigPackTemplate;
public class TerraStandardBiomeGrid extends TerraBiomeGrid {
private CoordinatePerturb perturb;
private ErosionNoise erode;
public TerraStandardBiomeGrid(long seed, BiomeZone zone, ConfigPack c) {
super(seed, 0, 0, zone);
ConfigPackTemplate t = c.getTemplate();
if(c.getTemplate().isBlend()) {
perturb = new CoordinatePerturb(t.getBlendFreq(), t.getBlendAmp(), seed);
}
if(c.getTemplate().isErode()) {
erode = new ErosionNoise(t.getErodeFreq(), t.getErodeThresh(), t.getErodeOctaves(), seed);
}
}
@Override
public BiomeGrid getGrid(int x, int z) {
return zone.getGrid(x, z);
}
@Override
public boolean isEroded(int x, int z) {
return erode != null && erode.isEroded(x, z);
}
@Override
public TerraBiome getBiome(int x, int z, GenerationPhase phase) {
int xp = x, zp = z;
if(perturb != null && (phase.equals(GenerationPhase.PALETTE_APPLY) || phase.equals(GenerationPhase.POPULATE))) {
Vector2 perturbCoords = perturb.getShiftedCoords(x, z);
xp = (int) perturbCoords.getX();
zp = (int) perturbCoords.getZ();
}
UserDefinedBiome b = (UserDefinedBiome) zone.getGrid(xp, zp).getBiome(xp, zp, phase);
if(isEroded(xp, zp)) return b.getErode();
return b;
}
@Override
public TerraBiome getBiome(Location l, GenerationPhase phase) {
return getBiome(l.getBlockX(), l.getBlockZ(), phase);
}
}
@@ -30,8 +30,6 @@ public class TerraBiomeHolder implements BiomeHolder {
biomes = new TerraBiome[newWidth][newWidth];
System.out.println(biomes.length);
for(int x = 0; x < width; x++) {
for(int z = 0; z < width; z++) {
biomes[x * 2][z * 2] = old[x][z];