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
@@ -3,9 +3,11 @@ package com.dfsek.terra.biome.pipeline;
import com.dfsek.terra.api.math.vector.Vector2; import com.dfsek.terra.api.math.vector.Vector2;
import com.dfsek.terra.api.util.GlueList; import com.dfsek.terra.api.util.GlueList;
import com.dfsek.terra.biome.pipeline.source.BiomeSource; 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 com.dfsek.terra.biome.pipeline.stages.Stage;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
public class BiomePipeline { public class BiomePipeline {
private final BiomeSource source; private final BiomeSource source;
@@ -40,7 +42,7 @@ public class BiomePipeline {
public static final class BiomePipelineBuilder { public static final class BiomePipelineBuilder {
private final int init; private final int init;
List<Stage> stages = new GlueList<>(); List<SeededBuilder<Stage>> stages = new GlueList<>();
private int expand; private int expand;
public BiomePipelineBuilder(int init) { public BiomePipelineBuilder(int init) {
@@ -48,13 +50,18 @@ public class BiomePipeline {
expand = init; expand = init;
} }
public BiomePipeline build(BiomeSource source) { public BiomePipeline build(BiomeSource source, long seed) {
return new BiomePipeline(source, stages, expand, init); 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); stages.add(stage);
if(stage.isExpansion()) expand = expand * 2 - 1;
return this; return this;
} }
} }
@@ -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);
}
}
@@ -6,4 +6,5 @@ public interface Stage {
boolean isExpansion(); boolean isExpansion();
BiomeHolder apply(BiomeHolder in); BiomeHolder apply(BiomeHolder in);
} }
@@ -3,26 +3,15 @@ package com.dfsek.terra.config.loaders.config.biome;
import com.dfsek.tectonic.exception.LoadException; import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.ConfigLoader; import com.dfsek.tectonic.loading.ConfigLoader;
import com.dfsek.tectonic.loading.TypeLoader; 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.platform.TerraPlugin;
import com.dfsek.terra.api.world.biome.TerraBiome; import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.biome.BiomeProvider; import com.dfsek.terra.biome.BiomeProvider;
import com.dfsek.terra.biome.ImageBiomeProvider; import com.dfsek.terra.biome.ImageBiomeProvider;
import com.dfsek.terra.biome.StandardBiomeProvider; import com.dfsek.terra.biome.StandardBiomeProvider;
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.source.BiomeSource;
import com.dfsek.terra.biome.pipeline.mutator.BorderListMutator; import com.dfsek.terra.biome.pipeline.stages.SeededBuilder;
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.config.files.Loader; 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.config.loaders.config.NoiseBuilderLoader;
import com.dfsek.terra.debug.Debug; import com.dfsek.terra.debug.Debug;
import com.dfsek.terra.generation.config.NoiseBuilder; import com.dfsek.terra.generation.config.NoiseBuilder;
@@ -32,7 +21,6 @@ import javax.imageio.ImageIO;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -51,79 +39,37 @@ public class BiomeProviderBuilderLoader implements TypeLoader<BiomeProvider.Biom
@Override @Override
public BiomeProvider.BiomeProviderBuilder load(Type t, Object c, ConfigLoader loader) throws LoadException { // TODO: clean this up public BiomeProvider.BiomeProviderBuilder load(Type t, Object c, ConfigLoader loader) throws LoadException { // TODO: clean this up
Map<String, Object> map = (Map<String, Object>) c; Map<String, Object> map = (Map<String, Object>) c;
int resolution = 1; int resolution = 1;
if(map.containsKey("resolution")) resolution = Integer.parseInt(map.get("resolution").toString()); if(map.containsKey("resolution")) resolution = Integer.parseInt(map.get("resolution").toString());
if(map.get("type").equals("PIPELINE")) { if(map.get("type").equals("PIPELINE")) {
Map<String, Object> pipeline = (Map<String, Object>) map.get("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 -> { 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); BiomePipeline.BiomePipelineBuilder pipelineBuilder = new BiomePipeline.BiomePipelineBuilder(init);
for(Map<String, Object> stage : stages) { for(Map<String, Object> stage : stages) {
for(Map.Entry<String, Object> entry : stage.entrySet()) { for(Map.Entry<String, Object> entry : stage.entrySet()) {
Map<String, Object> mutator = (Map<String, Object>) entry.getValue(); pipelineBuilder.addStage(new StageBuilderLoader().load(SeededBuilder.class, entry, loader));
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() + "\"");
} }
} }
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()); Debug.info("Biome Pipeline scale factor: " + biomePipeline.getSize());
return biomePipeline; return biomePipeline;
}, main); }, main);
builder.setResolution(resolution); builder.setResolution(resolution);
if(map.containsKey("blend")) { if(map.containsKey("blend")) {
Map<String, Object> blend = (Map<String, Object>) map.get("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) { } catch(IOException e) {
throw new LoadException("Failed to load image", 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"));
} }
} }
@@ -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);
}
}
@@ -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() + "\"");
}
}
+16 -15
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.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.dfsek.terra.biome.pipeline.stages.SeededBuilder;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import javax.swing.*; import javax.swing.*;
@@ -63,21 +64,21 @@ public class BiomeTest {
BiomeProvider provider = new StandardBiomeProvider.StandardBiomeProviderBuilder((seed) -> new BiomePipeline.BiomePipelineBuilder(2) BiomeProvider provider = new StandardBiomeProvider.StandardBiomeProviderBuilder((seed) -> new BiomePipeline.BiomePipelineBuilder(2)
.addStage(new MutatorStage(new ReplaceMutator("LAND_TEMP", landBiomes, whiteNoise(243)))) .addStage(new SeededBuilder<>(s -> new MutatorStage(new ReplaceMutator("LAND_TEMP", landBiomes, whiteNoise(243)))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(2)))) .addStage(new SeededBuilder<>(s -> new ExpanderStage(new FractalExpander(whiteNoise(2)))))
.addStage(new MutatorStage(new ReplaceMutator("OCEAN_TEMP", oceanBiomes, whiteNoise(243)))) .addStage(new SeededBuilder<>(s -> new MutatorStage(new ReplaceMutator("OCEAN_TEMP", oceanBiomes, whiteNoise(243)))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(2)))) .addStage(new SeededBuilder<>(s -> new ExpanderStage(new FractalExpander(whiteNoise(2)))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(2)))) .addStage(new SeededBuilder<>(s -> new ExpanderStage(new FractalExpander(whiteNoise(2)))))
.addStage(new MutatorStage(new SmoothMutator(whiteNoise(3)))) .addStage(new SeededBuilder<>(s -> new MutatorStage(new SmoothMutator(whiteNoise(3)))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(4)))) .addStage(new SeededBuilder<>(s -> new ExpanderStage(new FractalExpander(whiteNoise(4)))))
.addStage(new MutatorStage(new SmoothMutator(whiteNoise(6)))) .addStage(new SeededBuilder<>(s -> new MutatorStage(new SmoothMutator(whiteNoise(6)))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(4)))) .addStage(new SeededBuilder<>(s -> new ExpanderStage(new FractalExpander(whiteNoise(4)))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(4)))) .addStage(new SeededBuilder<>(s -> new ExpanderStage(new FractalExpander(whiteNoise(4)))))
.addStage(new MutatorStage(new BorderMutator("OCEAN", "LAND", whiteNoise(1234), beachBiomes))) .addStage(new SeededBuilder<>(s -> new MutatorStage(new BorderMutator("OCEAN", "LAND", whiteNoise(1234), beachBiomes))))
.addStage(new ExpanderStage(new FractalExpander(whiteNoise(4)))) .addStage(new SeededBuilder<>(s -> new ExpanderStage(new FractalExpander(whiteNoise(4)))))
.addStage(new MutatorStage(new SmoothMutator(whiteNoise(6)))) .addStage(new SeededBuilder<>(s -> new MutatorStage(new SmoothMutator(whiteNoise(6)))))
.addStage(new MutatorStage(new SmoothMutator(whiteNoise(6)))) .addStage(new SeededBuilder<>(s -> new MutatorStage(new SmoothMutator(whiteNoise(6)))))
.build(source), null).build(0); .build(source, seed), null).build(0);
int size = 1000; int size = 1000;