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
@@ -1,5 +1,6 @@
package com.dfsek.terra.biome; package com.dfsek.terra.biome;
import com.dfsek.tectonic.exception.ConfigException;
import com.dfsek.terra.api.math.vector.Vector2; import com.dfsek.terra.api.math.vector.Vector2;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.biome.pipeline.BiomeHolder; import com.dfsek.terra.biome.pipeline.BiomeHolder;
@@ -11,11 +12,10 @@ import net.jafama.FastMath;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.function.Function;
public class StandardBiomeProvider implements BiomeProvider { public class StandardBiomeProvider implements BiomeProvider {
private final BiomePipeline pipeline; private final BiomePipeline pipeline;
private final LoadingCache<Vector2, BiomeHolder> cache = CacheBuilder.newBuilder() private final LoadingCache<Vector2, BiomeHolder> holderCache = CacheBuilder.newBuilder()
.maximumSize(1024) .maximumSize(1024)
.build( .build(
new CacheLoader<Vector2, BiomeHolder>() { 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; private int resolution = 4;
protected StandardBiomeProvider(BiomePipeline pipeline) { protected StandardBiomeProvider(BiomePipeline pipeline) {
@@ -33,10 +49,8 @@ public class StandardBiomeProvider implements BiomeProvider {
@Override @Override
public TerraBiome getBiome(int x, int z) { public TerraBiome getBiome(int x, int z) {
x /= resolution;
z /= resolution;
try { 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) { } catch(ExecutionException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -50,16 +64,24 @@ public class StandardBiomeProvider implements BiomeProvider {
this.resolution = resolution; this.resolution = resolution;
} }
public static final class StandardBiomeProviderBuilder implements BiomeProviderBuilder { public interface ExceptionalFunction<I, O> {
private final Function<Long, BiomePipeline> pipelineBuilder; 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; this.pipelineBuilder = pipelineBuilder;
} }
@Override @Override
public StandardBiomeProvider build(long seed) { 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);
}
} }
} }
} }
@@ -29,7 +29,7 @@ import com.dfsek.terra.config.files.FolderLoader;
import com.dfsek.terra.config.files.Loader; import com.dfsek.terra.config.files.Loader;
import com.dfsek.terra.config.files.ZIPLoader; import com.dfsek.terra.config.files.ZIPLoader;
import com.dfsek.terra.config.lang.LangUtil; 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.AbstractableTemplate;
import com.dfsek.terra.config.templates.BiomeTemplate; import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.config.templates.CarverTemplate; import com.dfsek.terra.config.templates.CarverTemplate;
@@ -3,6 +3,7 @@ package com.dfsek.terra.config.loaders;
import com.dfsek.terra.api.math.ProbabilityCollection; import com.dfsek.terra.api.math.ProbabilityCollection;
import com.dfsek.terra.api.platform.block.BlockData; import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.MaterialData; 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.flora.Flora;
import com.dfsek.terra.api.world.palette.Palette; import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.api.world.tree.Tree; 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 BLOCK_DATA_PROBABILITY_COLLECTION_TYPE;
public static final Type FLORA_PROBABILITY_COLLECTION_TYPE; public static final Type FLORA_PROBABILITY_COLLECTION_TYPE;
public static final Type TREE_PROBABILITY_COLLECTION_TYPE; public static final Type TREE_PROBABILITY_COLLECTION_TYPE;
public static final Type TERRA_BIOME_PROBABILITY_COLLECTION_TYPE;
static { static {
MATERIAL_SET_TYPE = getType("materialSet"); MATERIAL_SET_TYPE = getType("materialSet");
@@ -29,6 +31,7 @@ public final class Types {
BLOCK_DATA_PROBABILITY_COLLECTION_TYPE = getType("blockDataProbabilityCollection"); BLOCK_DATA_PROBABILITY_COLLECTION_TYPE = getType("blockDataProbabilityCollection");
FLORA_PROBABILITY_COLLECTION_TYPE = getType("floraProbabilityCollection"); FLORA_PROBABILITY_COLLECTION_TYPE = getType("floraProbabilityCollection");
TREE_PROBABILITY_COLLECTION_TYPE = getType("treeProbabilityCollection"); TREE_PROBABILITY_COLLECTION_TYPE = getType("treeProbabilityCollection");
TERRA_BIOME_PROBABILITY_COLLECTION_TYPE = getType("terraBiomeProbabilityCollection");
} }
private Set<MaterialData> materialSet; private Set<MaterialData> materialSet;
@@ -37,6 +40,7 @@ public final class Types {
private ProbabilityCollection<BlockData> blockDataProbabilityCollection; private ProbabilityCollection<BlockData> blockDataProbabilityCollection;
private ProbabilityCollection<Flora> floraProbabilityCollection; private ProbabilityCollection<Flora> floraProbabilityCollection;
private ProbabilityCollection<Tree> treeProbabilityCollection; private ProbabilityCollection<Tree> treeProbabilityCollection;
private ProbabilityCollection<TerraBiome> terraBiomeProbabilityCollection;
private static Type getType(String dummyFieldName) { private static Type getType(String dummyFieldName) {
try { try {
@@ -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;
});
}
}
@@ -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));
});
}
}
+8 -20
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.BiomeHolder;
import com.dfsek.terra.biome.pipeline.BiomePipeline; import com.dfsek.terra.biome.pipeline.BiomePipeline;
import com.dfsek.terra.biome.pipeline.expand.FractalExpander; 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.mutator.SmoothMutator;
import com.dfsek.terra.biome.pipeline.source.BiomeSource; import com.dfsek.terra.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.biome.pipeline.source.RandomSource; import com.dfsek.terra.biome.pipeline.source.RandomSource;
import com.dfsek.terra.biome.pipeline.stages.ExpanderStage; import com.dfsek.terra.biome.pipeline.stages.ExpanderStage;
import com.dfsek.terra.biome.pipeline.stages.MutatorStage; import com.dfsek.terra.biome.pipeline.stages.MutatorStage;
import com.google.common.collect.Sets;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import javax.swing.*; import javax.swing.*;
@@ -41,7 +44,7 @@ public class BiomeTest {
ProbabilityCollection<TerraBiome> climate = new ProbabilityCollection<>(); ProbabilityCollection<TerraBiome> climate = new ProbabilityCollection<>();
climate.add(ocean, 1); climate.add(ocean, 1);
climate.add(land, 3); climate.add(land, 2);
oceanBiomes.add(new TestBiome(Color.BLUE, "OCEAN"), 10); oceanBiomes.add(new TestBiome(Color.BLUE, "OCEAN"), 10);
@@ -61,9 +64,13 @@ public class BiomeTest {
BiomePipeline pipeline = new BiomePipeline.BiomePipelineBuilder(20) BiomePipeline pipeline = new BiomePipeline.BiomePipelineBuilder(20)
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(1)))) .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 ExpanderStage(new FractalExpander(whiteNoise(2))))
.addStage(new MutatorStage(new SmoothMutator(whiteNoise(3)))) .addStage(new MutatorStage(new SmoothMutator(whiteNoise(3))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(4)))) .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 ExpanderStage(new FractalExpander(whiteNoise(5))))
.addStage(new MutatorStage(new SmoothMutator(whiteNoise(6)))) .addStage(new MutatorStage(new SmoothMutator(whiteNoise(6))))
.build(source); .build(source);
@@ -73,25 +80,6 @@ public class BiomeTest {
BiomeHolder holder3 = pipeline.getBiomes(0, 1); BiomeHolder holder3 = pipeline.getBiomes(0, 1);
BiomeHolder holder4 = pipeline.getBiomes(1, 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(); long e = System.nanoTime();
int size = pipeline.getSize(); int size = pipeline.getSize();