implement biome pipeline config loader

This commit is contained in:
dfsek
2021-01-13 10:48:45 -07:00
parent fb32531584
commit 54f732176d
6 changed files with 121 additions and 86 deletions

View File

@@ -1,5 +1,6 @@
package com.dfsek.terra.biome;
import com.dfsek.tectonic.exception.ConfigException;
import com.dfsek.terra.api.math.vector.Vector2;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.biome.pipeline.BiomeHolder;
@@ -11,11 +12,10 @@ 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()
private final LoadingCache<Vector2, BiomeHolder> holderCache = CacheBuilder.newBuilder()
.maximumSize(1024)
.build(
new CacheLoader<Vector2, BiomeHolder>() {
@@ -25,6 +25,22 @@ public class StandardBiomeProvider implements BiomeProvider {
}
}
);
private final LoadingCache<Vector2, TerraBiome> biomeCache = CacheBuilder.newBuilder()
.maximumSize(1024)
.build(
new CacheLoader<Vector2, TerraBiome>() {
@Override
public TerraBiome load(@NotNull Vector2 key) throws ExecutionException {
int x = FastMath.floorToInt(key.getX());
int z = FastMath.floorToInt(key.getZ());
x /= resolution;
z /= resolution;
int fdX = FastMath.floorDiv(x, pipeline.getSize());
int fdZ = FastMath.floorDiv(z, pipeline.getSize());
return holderCache.get(new Vector2(fdX, fdZ)).getBiome(x - fdX * pipeline.getSize(), z - fdZ * pipeline.getSize());
}
}
);
private int resolution = 4;
protected StandardBiomeProvider(BiomePipeline pipeline) {
@@ -33,10 +49,8 @@ public class StandardBiomeProvider implements BiomeProvider {
@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()));
return biomeCache.get(new Vector2(x, z));
} catch(ExecutionException e) {
throw new RuntimeException(e);
}
@@ -50,16 +64,24 @@ public class StandardBiomeProvider implements BiomeProvider {
this.resolution = resolution;
}
public static final class StandardBiomeProviderBuilder implements BiomeProviderBuilder {
private final Function<Long, BiomePipeline> pipelineBuilder;
public interface ExceptionalFunction<I, O> {
O apply(I in) throws ConfigException;
}
public StandardBiomeProviderBuilder(Function<Long, BiomePipeline> pipelineBuilder) {
public static final class StandardBiomeProviderBuilder implements BiomeProviderBuilder {
private final ExceptionalFunction<Long, BiomePipeline> pipelineBuilder;
public StandardBiomeProviderBuilder(ExceptionalFunction<Long, BiomePipeline> pipelineBuilder) {
this.pipelineBuilder = pipelineBuilder;
}
@Override
public StandardBiomeProvider build(long seed) {
return new StandardBiomeProvider(pipelineBuilder.apply(seed));
try {
return new StandardBiomeProvider(pipelineBuilder.apply(seed));
} catch(ConfigException e) {
throw new RuntimeException(e);
}
}
}
}

View File

@@ -29,7 +29,7 @@ import com.dfsek.terra.config.files.FolderLoader;
import com.dfsek.terra.config.files.Loader;
import com.dfsek.terra.config.files.ZIPLoader;
import com.dfsek.terra.config.lang.LangUtil;
import com.dfsek.terra.config.loaders.config.BiomeProviderBuilderLoader;
import com.dfsek.terra.config.loaders.config.biome.BiomeProviderBuilderLoader;
import com.dfsek.terra.config.templates.AbstractableTemplate;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.config.templates.CarverTemplate;

View File

@@ -3,6 +3,7 @@ package com.dfsek.terra.config.loaders;
import com.dfsek.terra.api.math.ProbabilityCollection;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.MaterialData;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.flora.Flora;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.api.world.tree.Tree;
@@ -21,6 +22,7 @@ public final class Types {
public static final Type BLOCK_DATA_PROBABILITY_COLLECTION_TYPE;
public static final Type FLORA_PROBABILITY_COLLECTION_TYPE;
public static final Type TREE_PROBABILITY_COLLECTION_TYPE;
public static final Type TERRA_BIOME_PROBABILITY_COLLECTION_TYPE;
static {
MATERIAL_SET_TYPE = getType("materialSet");
@@ -29,6 +31,7 @@ public final class Types {
BLOCK_DATA_PROBABILITY_COLLECTION_TYPE = getType("blockDataProbabilityCollection");
FLORA_PROBABILITY_COLLECTION_TYPE = getType("floraProbabilityCollection");
TREE_PROBABILITY_COLLECTION_TYPE = getType("treeProbabilityCollection");
TERRA_BIOME_PROBABILITY_COLLECTION_TYPE = getType("terraBiomeProbabilityCollection");
}
private Set<MaterialData> materialSet;
@@ -37,6 +40,7 @@ public final class Types {
private ProbabilityCollection<BlockData> blockDataProbabilityCollection;
private ProbabilityCollection<Flora> floraProbabilityCollection;
private ProbabilityCollection<Tree> treeProbabilityCollection;
private ProbabilityCollection<TerraBiome> terraBiomeProbabilityCollection;
private static Type getType(String dummyFieldName) {
try {

View File

@@ -1,56 +0,0 @@
package com.dfsek.terra.config.loaders.config;
import com.dfsek.tectonic.loading.ConfigLoader;
import com.dfsek.tectonic.loading.TypeLoader;
import com.dfsek.terra.api.math.ProbabilityCollection;
import com.dfsek.terra.api.math.noise.samplers.FastNoiseLite;
import com.dfsek.terra.api.math.noise.samplers.NoiseSampler;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.biome.BiomeProvider;
import com.dfsek.terra.biome.StandardBiomeProvider;
import com.dfsek.terra.biome.pipeline.BiomePipeline;
import com.dfsek.terra.biome.pipeline.expand.FractalExpander;
import com.dfsek.terra.biome.pipeline.mutator.SmoothMutator;
import com.dfsek.terra.biome.pipeline.source.RandomSource;
import com.dfsek.terra.biome.pipeline.stages.ExpanderStage;
import com.dfsek.terra.biome.pipeline.stages.MutatorStage;
import com.dfsek.terra.config.base.ConfigPack;
import net.jafama.FastMath;
import java.lang.reflect.Type;
public class BiomeProviderBuilderLoader implements TypeLoader<BiomeProvider.BiomeProviderBuilder> {
private final ConfigPack pack;
public BiomeProviderBuilderLoader(ConfigPack pack) {
this.pack = pack;
}
private static NoiseSampler whiteNoise(int seed) {
FastNoiseLite noiseLite = new FastNoiseLite(seed);
noiseLite.setNoiseType(FastNoiseLite.NoiseType.WhiteNoise);
return noiseLite;
}
@Override
public BiomeProvider.BiomeProviderBuilder load(Type t, Object c, ConfigLoader loader) {
return new StandardBiomeProvider.StandardBiomeProviderBuilder(seed -> {
ProbabilityCollection<TerraBiome> biomes = new ProbabilityCollection<>();
biomes.add(pack.getBiome("PLAINS"), 1)
.add(pack.getBiome("SAVANNA"), 2);
BiomePipeline pipeline = new BiomePipeline.BiomePipelineBuilder(2)
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(FastMath.toInt(seed)))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(FastMath.toInt(seed + 1)))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(FastMath.toInt(seed + 2)))))
.addStage(new MutatorStage(new SmoothMutator(whiteNoise(FastMath.toInt(seed + 3)))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(FastMath.toInt(seed + 4)))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(FastMath.toInt(seed + 5)))))
.build(new RandomSource(biomes, whiteNoise(FastMath.toInt(seed) + 4)));
System.out.println(pipeline.getSize());
return pipeline;
});
}
}

View File

@@ -0,0 +1,77 @@
package com.dfsek.terra.config.loaders.config.biome;
import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.ConfigLoader;
import com.dfsek.tectonic.loading.TypeLoader;
import com.dfsek.terra.api.math.ProbabilityCollection;
import com.dfsek.terra.api.math.noise.samplers.FastNoiseLite;
import com.dfsek.terra.api.math.noise.samplers.NoiseSampler;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.biome.BiomeProvider;
import com.dfsek.terra.biome.StandardBiomeProvider;
import com.dfsek.terra.biome.pipeline.BiomePipeline;
import com.dfsek.terra.biome.pipeline.expand.FractalExpander;
import com.dfsek.terra.biome.pipeline.mutator.ReplaceMutator;
import com.dfsek.terra.biome.pipeline.mutator.SmoothMutator;
import com.dfsek.terra.biome.pipeline.source.RandomSource;
import com.dfsek.terra.biome.pipeline.stages.ExpanderStage;
import com.dfsek.terra.biome.pipeline.stages.MutatorStage;
import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.loaders.Types;
import com.dfsek.terra.config.loaders.config.NoiseBuilderLoader;
import com.dfsek.terra.generation.config.NoiseBuilder;
import net.jafama.FastMath;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
@SuppressWarnings("unchecked")
public class BiomeProviderBuilderLoader implements TypeLoader<BiomeProvider.BiomeProviderBuilder> {
private final ConfigPack pack;
public BiomeProviderBuilderLoader(ConfigPack pack) {
this.pack = pack;
}
private static NoiseSampler whiteNoise(int seed) {
FastNoiseLite noiseLite = new FastNoiseLite(seed);
noiseLite.setNoiseType(FastNoiseLite.NoiseType.WhiteNoise);
return noiseLite;
}
@Override
public BiomeProvider.BiomeProviderBuilder load(Type t, Object c, ConfigLoader loader) {
Map<String, Object> map = (Map<String, Object>) c;
return new StandardBiomeProvider.StandardBiomeProviderBuilder(seed -> {
Map<String, Object> source = (Map<String, Object>) map.get("source");
ProbabilityCollection<TerraBiome> sourceBiomes = (ProbabilityCollection<TerraBiome>) loader.loadType(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, source.get("biomes"));
NoiseSampler sourceNoise = new NoiseBuilderLoader().load(NoiseBuilder.class, source.get("noise"), loader).build(FastMath.toInt(seed));
List<Map<String, Object>> stages = (List<Map<String, Object>>) map.get("pipeline");
BiomePipeline.BiomePipelineBuilder pipelineBuilder = new BiomePipeline.BiomePipelineBuilder(2);
for(Map<String, Object> stage : stages) {
for(Map.Entry<String, Object> entry : stage.entrySet()) {
Map<String, Object> mutator = (Map<String, Object>) entry.getValue();
NoiseSampler mutatorNoise = new NoiseBuilderLoader().load(NoiseBuilder.class, mutator.get("noise"), loader).build(FastMath.toInt(seed));
if(entry.getKey().equals("expand")) {
if(mutator.get("type").equals("FRACTAL"))
pipelineBuilder.addStage(new ExpanderStage(new FractalExpander(mutatorNoise)));
else throw new LoadException("No such expander \"" + mutator.get("type"));
} else if(entry.getKey().equals("mutate")) {
if(mutator.get("type").equals("SMOOTH"))
pipelineBuilder.addStage(new MutatorStage(new SmoothMutator(mutatorNoise)));
else if(mutator.get("type").equals("REPLACE")) {
String fromTag = mutator.get("from").toString();
ProbabilityCollection<TerraBiome> replaceBiomes = (ProbabilityCollection<TerraBiome>) loader.loadType(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, mutator.get("to"));
pipelineBuilder.addStage(new MutatorStage(new ReplaceMutator(fromTag, replaceBiomes, mutatorNoise)));
} else throw new LoadException("No such mutator type \"" + mutator.get("type"));
} else throw new LoadException("No such mutator \"" + entry.getKey() + "\"");
}
}
return pipelineBuilder.build(new RandomSource(sourceBiomes, sourceNoise));
});
}
}

View File

@@ -9,11 +9,14 @@ import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.biome.pipeline.BiomeHolder;
import com.dfsek.terra.biome.pipeline.BiomePipeline;
import com.dfsek.terra.biome.pipeline.expand.FractalExpander;
import com.dfsek.terra.biome.pipeline.mutator.BorderMutator;
import com.dfsek.terra.biome.pipeline.mutator.ReplaceMutator;
import com.dfsek.terra.biome.pipeline.mutator.SmoothMutator;
import com.dfsek.terra.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.biome.pipeline.source.RandomSource;
import com.dfsek.terra.biome.pipeline.stages.ExpanderStage;
import com.dfsek.terra.biome.pipeline.stages.MutatorStage;
import com.google.common.collect.Sets;
import org.junit.jupiter.api.Test;
import javax.swing.*;
@@ -41,7 +44,7 @@ public class BiomeTest {
ProbabilityCollection<TerraBiome> climate = new ProbabilityCollection<>();
climate.add(ocean, 1);
climate.add(land, 3);
climate.add(land, 2);
oceanBiomes.add(new TestBiome(Color.BLUE, "OCEAN"), 10);
@@ -61,9 +64,13 @@ public class BiomeTest {
BiomePipeline pipeline = new BiomePipeline.BiomePipelineBuilder(20)
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(1))))
.addStage(new MutatorStage(new ReplaceMutator("OCEAN_TEMP", oceanBiomes, whiteNoise(243))))
.addStage(new MutatorStage(new ReplaceMutator("LAND_TEMP", landBiomes, whiteNoise(243))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(2))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(2))))
.addStage(new MutatorStage(new SmoothMutator(whiteNoise(3))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(4))))
.addStage(new MutatorStage(new BorderMutator(Sets.newHashSet("OCEAN"), "LAND", whiteNoise(1234), beachBiomes)))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(5))))
.addStage(new MutatorStage(new SmoothMutator(whiteNoise(6))))
.build(source);
@@ -73,25 +80,6 @@ public class BiomeTest {
BiomeHolder holder3 = pipeline.getBiomes(0, 1);
BiomeHolder holder4 = pipeline.getBiomes(1, 1);
//holder = holder.expand(new FractalExpander(whiteNoise(4)));
//holder.mutate(new ReplaceMutator("OCEAN_TEMP", oceanBiomes, whiteNoise(234)));
//holder.mutate(new ReplaceMutator("LAND_TEMP", landBiomes, whiteNoise(235)));
//holder = holder.expand(new FractalExpander(whiteNoise(3)));
//holder = holder.expand(new FractalExpander(whiteNoise(2)));
//holder.mutate(new SmoothMutator(whiteNoise(34)));
//holder = holder.expand(new FractalExpander(whiteNoise(5)));
//holder = holder.expand(new FractalExpander(whiteNoise(7)));
//holder.mutate(new BorderMutator(Sets.newHashSet("OCEAN"), "LAND", whiteNoise(2356), beachBiomes));
//holder = holder.expand(new FractalExpander(whiteNoise(6)));
//holder.mutate(new SmoothMutator(whiteNoise(35)));
long e = System.nanoTime();
int size = pipeline.getSize();