cleanup biome config loading

This commit is contained in:
dfsek
2021-01-21 22:20:40 -07:00
parent 25acda4410
commit 3318161c44
7 changed files with 187 additions and 93 deletions

View File

@@ -3,9 +3,11 @@ package com.dfsek.terra.biome.pipeline;
import com.dfsek.terra.api.math.vector.Vector2;
import com.dfsek.terra.api.util.GlueList;
import com.dfsek.terra.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.biome.pipeline.stages.SeededBuilder;
import com.dfsek.terra.biome.pipeline.stages.Stage;
import java.util.List;
import java.util.stream.Collectors;
public class BiomePipeline {
private final BiomeSource source;
@@ -40,7 +42,7 @@ public class BiomePipeline {
public static final class BiomePipelineBuilder {
private final int init;
List<Stage> stages = new GlueList<>();
List<SeededBuilder<Stage>> stages = new GlueList<>();
private int expand;
public BiomePipelineBuilder(int init) {
@@ -48,13 +50,18 @@ public class BiomePipeline {
expand = init;
}
public BiomePipeline build(BiomeSource source) {
return new BiomePipeline(source, stages, expand, init);
public BiomePipeline build(BiomeSource source, long seed) {
List<Stage> stagesBuilt = stages.stream().map(stageBuilder -> stageBuilder.build(seed)).collect(Collectors.toList());
for(Stage stage : stagesBuilt) {
if(stage.isExpansion()) expand = expand * 2 - 1;
}
return new BiomePipeline(source, stagesBuilt, expand, init);
}
public BiomePipelineBuilder addStage(Stage stage) {
public BiomePipelineBuilder addStage(SeededBuilder<Stage> stage) {
stages.add(stage);
if(stage.isExpansion()) expand = expand * 2 - 1;
return this;
}
}

View File

@@ -0,0 +1,15 @@
package com.dfsek.terra.biome.pipeline.stages;
import java.util.function.Function;
public class SeededBuilder<T> {
private final Function<Long, T> builder;
public SeededBuilder(Function<Long, T> builder) {
this.builder = builder;
}
public T build(long seed) {
return builder.apply(seed);
}
}

View File

@@ -6,4 +6,5 @@ public interface Stage {
boolean isExpansion();
BiomeHolder apply(BiomeHolder in);
}

View File

@@ -3,26 +3,15 @@ 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.NoiseSampler;
import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.biome.BiomeProvider;
import com.dfsek.terra.biome.ImageBiomeProvider;
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.BorderListMutator;
import com.dfsek.terra.biome.pipeline.mutator.BorderMutator;
import com.dfsek.terra.biome.pipeline.mutator.ReplaceListMutator;
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.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.biome.pipeline.stages.SeededBuilder;
import com.dfsek.terra.config.files.Loader;
import com.dfsek.terra.config.loaders.SelfProbabilityCollectionLoader;
import com.dfsek.terra.config.loaders.Types;
import com.dfsek.terra.config.loaders.config.NoiseBuilderLoader;
import com.dfsek.terra.debug.Debug;
import com.dfsek.terra.generation.config.NoiseBuilder;
@@ -32,7 +21,6 @@ import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -51,79 +39,37 @@ public class BiomeProviderBuilderLoader implements TypeLoader<BiomeProvider.Biom
@Override
public BiomeProvider.BiomeProviderBuilder load(Type t, Object c, ConfigLoader loader) throws LoadException { // TODO: clean this up
Map<String, Object> map = (Map<String, Object>) c;
int resolution = 1;
if(map.containsKey("resolution")) resolution = Integer.parseInt(map.get("resolution").toString());
if(map.get("type").equals("PIPELINE")) {
Map<String, Object> pipeline = (Map<String, Object>) map.get("pipeline");
List<Map<String, Object>> stages = (List<Map<String, Object>>) pipeline.get("stages");
if(stages == null) throw new LoadException("No pipeline stages defined!");
int init;
if(pipeline.containsKey("initial-size")) init = Integer.parseInt(pipeline.get("initial-size").toString());
else init = 3;
StandardBiomeProvider.StandardBiomeProviderBuilder builder = new StandardBiomeProvider.StandardBiomeProviderBuilder(seed -> {
Map<String, Object> source = (Map<String, Object>) pipeline.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((int) seed.longValue());
List<Map<String, Object>> stages = (List<Map<String, Object>>) pipeline.get("stages");
int init;
if(pipeline.containsKey("initial-size")) init = Integer.parseInt(pipeline.get("initial-size").toString());
else init = 3;
BiomePipeline.BiomePipelineBuilder pipelineBuilder = new BiomePipeline.BiomePipelineBuilder(init);
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((int) seed.longValue());
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 = new SelfProbabilityCollectionLoader<TerraBiome>().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, mutator.get("to"), loader);
pipelineBuilder.addStage(new MutatorStage(new ReplaceMutator(fromTag, replaceBiomes, mutatorNoise)));
} else if(mutator.get("type").equals("REPLACE_LIST")) {
String fromTag = mutator.get("default-from").toString();
ProbabilityCollection<TerraBiome> replaceBiomes = new SelfProbabilityCollectionLoader<TerraBiome>().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, mutator.get("default-to"), loader);
Map<TerraBiome, ProbabilityCollection<TerraBiome>> replace = new HashMap<>();
for(Map.Entry<String, Object> e : ((Map<String, Object>) mutator.get("to")).entrySet()) {
replace.put((TerraBiome) loader.loadType(TerraBiome.class, e.getKey()), new SelfProbabilityCollectionLoader<TerraBiome>().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, e.getValue(), loader));
}
pipelineBuilder.addStage(new MutatorStage(new ReplaceListMutator(replace, fromTag, replaceBiomes, mutatorNoise)));
} else if(mutator.get("type").equals("BORDER")) {
String fromTag = mutator.get("from").toString();
String replaceTag = mutator.get("replace").toString();
ProbabilityCollection<TerraBiome> replaceBiomes = new SelfProbabilityCollectionLoader<TerraBiome>().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, mutator.get("to"), loader);
pipelineBuilder.addStage(new MutatorStage(new BorderMutator(fromTag, replaceTag, mutatorNoise, replaceBiomes)));
} else if(mutator.get("type").equals("BORDER_LIST")) {
String fromTag = mutator.get("from").toString();
String replaceTag = mutator.get("default-replace").toString();
ProbabilityCollection<TerraBiome> replaceBiomes = new SelfProbabilityCollectionLoader<TerraBiome>().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, mutator.get("default-to"), loader);
Map<TerraBiome, ProbabilityCollection<TerraBiome>> replace = new HashMap<>();
for(Map.Entry<String, Object> e : ((Map<String, Object>) mutator.get("replace")).entrySet()) {
replace.put((TerraBiome) loader.loadType(TerraBiome.class, e.getKey()), new SelfProbabilityCollectionLoader<TerraBiome>().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, e.getValue(), loader));
}
pipelineBuilder.addStage(new MutatorStage(new BorderListMutator(replace, fromTag, replaceTag, mutatorNoise, replaceBiomes)));
} else throw new LoadException("No such mutator type \"" + mutator.get("type"));
} else throw new LoadException("No such mutator \"" + entry.getKey() + "\"");
pipelineBuilder.addStage(new StageBuilderLoader().load(SeededBuilder.class, entry, loader));
}
}
BiomePipeline biomePipeline = pipelineBuilder.build(new RandomSource(sourceBiomes, sourceNoise));
if(!pipeline.containsKey("source")) throw new LoadException("Biome Source not defined!");
SeededBuilder<BiomeSource> source = new SourceBuilderLoader().load(BiomeSource.class, pipeline.get("source"), loader);
BiomePipeline biomePipeline = pipelineBuilder.build(source.build(seed), seed);
Debug.info("Biome Pipeline scale factor: " + biomePipeline.getSize());
return biomePipeline;
}, main);
builder.setResolution(resolution);
if(map.containsKey("blend")) {
Map<String, Object> blend = (Map<String, Object>) map.get("blend");
@@ -141,6 +87,8 @@ public class BiomeProviderBuilderLoader implements TypeLoader<BiomeProvider.Biom
} catch(IOException e) {
throw new LoadException("Failed to load image", e);
}
} else throw new LoadException("No such biome provider type: " + map.get("type"));
}
throw new LoadException("No such biome provider type: " + map.get("type"));
}
}

View File

@@ -0,0 +1,33 @@
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.world.biome.TerraBiome;
import com.dfsek.terra.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.biome.pipeline.source.RandomSource;
import com.dfsek.terra.biome.pipeline.stages.SeededBuilder;
import com.dfsek.terra.config.loaders.Types;
import com.dfsek.terra.config.loaders.config.NoiseBuilderLoader;
import com.dfsek.terra.generation.config.NoiseBuilder;
import java.lang.reflect.Type;
import java.util.Map;
@SuppressWarnings("unchecked")
public class SourceBuilderLoader implements TypeLoader<SeededBuilder<BiomeSource>> {
@Override
public SeededBuilder<BiomeSource> load(Type t, Object c, ConfigLoader loader) throws LoadException {
Map<String, Object> source = (Map<String, Object>) c;
String type = source.get("type").toString();
if("NOISE".equals(type)) {
ProbabilityCollection<TerraBiome> sourceBiomes = (ProbabilityCollection<TerraBiome>) loader.loadType(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, source.get("biomes"));
NoiseBuilder sourceNoise = new NoiseBuilderLoader().load(NoiseBuilder.class, source.get("noise"), loader);
return new SeededBuilder<>(seed -> new RandomSource(sourceBiomes, sourceNoise.build((int) seed.longValue())));
}
throw new LoadException("No such loader type: " + type);
}
}

View File

@@ -0,0 +1,89 @@
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.world.biome.TerraBiome;
import com.dfsek.terra.biome.pipeline.expand.FractalExpander;
import com.dfsek.terra.biome.pipeline.mutator.BorderListMutator;
import com.dfsek.terra.biome.pipeline.mutator.BorderMutator;
import com.dfsek.terra.biome.pipeline.mutator.ReplaceListMutator;
import com.dfsek.terra.biome.pipeline.mutator.ReplaceMutator;
import com.dfsek.terra.biome.pipeline.mutator.SmoothMutator;
import com.dfsek.terra.biome.pipeline.stages.ExpanderStage;
import com.dfsek.terra.biome.pipeline.stages.MutatorStage;
import com.dfsek.terra.biome.pipeline.stages.SeededBuilder;
import com.dfsek.terra.biome.pipeline.stages.Stage;
import com.dfsek.terra.config.loaders.SelfProbabilityCollectionLoader;
import com.dfsek.terra.config.loaders.Types;
import com.dfsek.terra.config.loaders.config.NoiseBuilderLoader;
import com.dfsek.terra.generation.config.NoiseBuilder;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
@SuppressWarnings("unchecked")
public class StageBuilderLoader implements TypeLoader<SeededBuilder<Stage>> {
@Override
public SeededBuilder<Stage> load(Type t, Object c, ConfigLoader loader) throws LoadException {
Map.Entry<String, Object> entry = (Map.Entry<String, Object>) c;
Map<String, Object> mutator = (Map<String, Object>) entry.getValue();
NoiseBuilder mutatorNoise = new NoiseBuilderLoader().load(NoiseBuilder.class, mutator.get("noise"), loader);
if(entry.getKey().equals("expand")) {
if(mutator.get("type").equals("FRACTAL"))
return new SeededBuilder<>(seed -> new ExpanderStage(new FractalExpander(mutatorNoise.build((int) seed.longValue()))));
else throw new LoadException("No such expander \"" + mutator.get("type"));
} else if(entry.getKey().equals("mutate")) {
switch(mutator.get("type").toString()) {
case "SMOOTH": {
return new SeededBuilder<>(seed -> new MutatorStage(new SmoothMutator(mutatorNoise.build((int) seed.longValue()))));
}
case "REPLACE": {
String fromTag = mutator.get("from").toString();
ProbabilityCollection<TerraBiome> replaceBiomes = new SelfProbabilityCollectionLoader<TerraBiome>().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, mutator.get("to"), loader);
return new SeededBuilder<>(seed -> new MutatorStage(new ReplaceMutator(fromTag, replaceBiomes, mutatorNoise.build((int) seed.longValue()))));
}
case "REPLACE_LIST": {
String fromTag = mutator.get("default-from").toString();
ProbabilityCollection<TerraBiome> replaceBiomes = new SelfProbabilityCollectionLoader<TerraBiome>().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, mutator.get("default-to"), loader);
Map<TerraBiome, ProbabilityCollection<TerraBiome>> replace = new HashMap<>();
for(Map.Entry<String, Object> e : ((Map<String, Object>) mutator.get("to")).entrySet()) {
replace.put((TerraBiome) loader.loadType(TerraBiome.class, e.getKey()), new SelfProbabilityCollectionLoader<TerraBiome>().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, e.getValue(), loader));
}
return new SeededBuilder<>(seed -> new MutatorStage(new ReplaceListMutator(replace, fromTag, replaceBiomes, mutatorNoise.build((int) seed.longValue()))));
}
case "BORDER": {
String fromTag = mutator.get("from").toString();
String replaceTag = mutator.get("replace").toString();
ProbabilityCollection<TerraBiome> replaceBiomes = new SelfProbabilityCollectionLoader<TerraBiome>().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, mutator.get("to"), loader);
return new SeededBuilder<>(seed -> new MutatorStage(new BorderMutator(fromTag, replaceTag, mutatorNoise.build((int) seed.longValue()), replaceBiomes)));
}
case "BORDER_LIST": {
String fromTag = mutator.get("from").toString();
String replaceTag = mutator.get("default-replace").toString();
ProbabilityCollection<TerraBiome> replaceBiomes = new SelfProbabilityCollectionLoader<TerraBiome>().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, mutator.get("default-to"), loader);
Map<TerraBiome, ProbabilityCollection<TerraBiome>> replace = new HashMap<>();
for(Map.Entry<String, Object> e : ((Map<String, Object>) mutator.get("replace")).entrySet()) {
replace.put((TerraBiome) loader.loadType(TerraBiome.class, e.getKey()), new SelfProbabilityCollectionLoader<TerraBiome>().load(Types.TERRA_BIOME_PROBABILITY_COLLECTION_TYPE, e.getValue(), loader));
}
return new SeededBuilder<>(seed -> new MutatorStage(new BorderListMutator(replace, fromTag, replaceTag, mutatorNoise.build((int) seed.longValue()), replaceBiomes)));
}
default:
throw new LoadException("No such mutator type \"" + mutator.get("type"));
}
}
throw new LoadException("No such mutator \"" + entry.getKey() + "\"");
}
}

View File

@@ -18,6 +18,7 @@ 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.dfsek.terra.biome.pipeline.stages.SeededBuilder;
import org.junit.jupiter.api.Test;
import javax.swing.*;
@@ -63,21 +64,21 @@ public class BiomeTest {
BiomeProvider provider = new StandardBiomeProvider.StandardBiomeProviderBuilder((seed) -> new BiomePipeline.BiomePipelineBuilder(2)
.addStage(new MutatorStage(new ReplaceMutator("LAND_TEMP", landBiomes, whiteNoise(243))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(2))))
.addStage(new MutatorStage(new ReplaceMutator("OCEAN_TEMP", oceanBiomes, 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 SmoothMutator(whiteNoise(6))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(4))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(4))))
.addStage(new MutatorStage(new BorderMutator("OCEAN", "LAND", whiteNoise(1234), beachBiomes)))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(4))))
.addStage(new MutatorStage(new SmoothMutator(whiteNoise(6))))
.addStage(new MutatorStage(new SmoothMutator(whiteNoise(6))))
.build(source), null).build(0);
.addStage(new SeededBuilder<>(s -> new MutatorStage(new ReplaceMutator("LAND_TEMP", landBiomes, whiteNoise(243)))))
.addStage(new SeededBuilder<>(s -> new ExpanderStage(new FractalExpander(whiteNoise(2)))))
.addStage(new SeededBuilder<>(s -> new MutatorStage(new ReplaceMutator("OCEAN_TEMP", oceanBiomes, whiteNoise(243)))))
.addStage(new SeededBuilder<>(s -> new ExpanderStage(new FractalExpander(whiteNoise(2)))))
.addStage(new SeededBuilder<>(s -> new ExpanderStage(new FractalExpander(whiteNoise(2)))))
.addStage(new SeededBuilder<>(s -> new MutatorStage(new SmoothMutator(whiteNoise(3)))))
.addStage(new SeededBuilder<>(s -> new ExpanderStage(new FractalExpander(whiteNoise(4)))))
.addStage(new SeededBuilder<>(s -> new MutatorStage(new SmoothMutator(whiteNoise(6)))))
.addStage(new SeededBuilder<>(s -> new ExpanderStage(new FractalExpander(whiteNoise(4)))))
.addStage(new SeededBuilder<>(s -> new ExpanderStage(new FractalExpander(whiteNoise(4)))))
.addStage(new SeededBuilder<>(s -> new MutatorStage(new BorderMutator("OCEAN", "LAND", whiteNoise(1234), beachBiomes))))
.addStage(new SeededBuilder<>(s -> new ExpanderStage(new FractalExpander(whiteNoise(4)))))
.addStage(new SeededBuilder<>(s -> new MutatorStage(new SmoothMutator(whiteNoise(6)))))
.addStage(new SeededBuilder<>(s -> new MutatorStage(new SmoothMutator(whiteNoise(6)))))
.build(source, seed), null).build(0);
int size = 1000;