Merge pull request #72 from PolyhedralDev/asmparser

Implement Paralithic expression parser
This commit is contained in:
dfsek
2021-02-15 18:01:00 -07:00
committed by GitHub
61 changed files with 612 additions and 613 deletions

View File

@@ -1,6 +1,6 @@
import com.dfsek.terra.getGitHash
val versionObj = Version("4", "0", "1", true)
val versionObj = Version("4", "1", "0", true)
allprojects {
version = versionObj

View File

@@ -13,10 +13,11 @@ dependencies {
"shadedApi"("org.apache.commons:commons-rng-core:1.3")
"shadedApi"("commons-io:commons-io:2.4")
"shadedApi"("com.scireum:parsii:1.2.1")
"shadedApi"("com.dfsek:Paralithic:0.3.2")
"shadedApi"("com.dfsek:Tectonic:1.2.3")
"shadedApi"("net.jafama:jafama:2.3.2")
"shadedApi"("org.yaml:snakeyaml:1.27")
"shadedApi"("org.ow2.asm:asm:9.0")
"compileOnly"("com.googlecode.json-simple:json-simple:1.1")

View File

@@ -0,0 +1,20 @@
package com.dfsek.terra.api.math.noise.normalizer;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import net.jafama.FastMath;
public class ClampNormalizer extends Normalizer {
private final double min;
private final double max;
public ClampNormalizer(NoiseSampler sampler, double min, double max) {
super(sampler);
this.min = min;
this.max = max;
}
@Override
public double normalize(double in) {
return FastMath.max(FastMath.min(in, max), min);
}
}

View File

@@ -0,0 +1,33 @@
package com.dfsek.terra.api.math.noise.normalizer;
import com.dfsek.paralithic.Expression;
import com.dfsek.paralithic.eval.parser.Parser;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.math.parsii.noise.NoiseFunction2;
import com.dfsek.terra.api.math.parsii.noise.NoiseFunction3;
import java.util.Map;
public class ExpressionNormalizer extends Normalizer {
private final Expression expression;
public ExpressionNormalizer(NoiseSampler sampler, String eq, Map<String, Double> vars) throws ParseException {
super(sampler);
Parser p = new Parser();
Scope scope = new Scope();
scope.addInvocationVariable("in");
vars.forEach(scope::create);
p.registerFunction("super2", new NoiseFunction2(sampler));
p.registerFunction("super3", new NoiseFunction3(sampler));
expression = p.parse(eq);
}
@Override
public double normalize(double in) {
return expression.evaluate(in);
}
}

View File

@@ -30,8 +30,4 @@ public abstract class Normalizer implements NoiseSampler {
public double getNoiseSeeded(int seed, double x, double y, double z) {
return normalize(sampler.getNoiseSeeded(seed, x, y, z));
}
public enum NormalType {
LINEAR, NORMAL
}
}

View File

@@ -1,73 +1,58 @@
package com.dfsek.terra.api.math.noise.samplers;
import com.dfsek.paralithic.Expression;
import com.dfsek.paralithic.eval.parser.Parser;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.math.parsii.defined.UserDefinedFunction;
import com.dfsek.terra.api.math.parsii.noise.NoiseFunction2;
import com.dfsek.terra.api.math.parsii.noise.NoiseFunction3;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.config.loaders.config.function.FunctionTemplate;
import parsii.eval.Expression;
import parsii.eval.Parser;
import parsii.eval.Scope;
import parsii.eval.Variable;
import parsii.tokenizer.ParseException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Sampler implementation using parsii expression
*/
public class ExpressionSampler implements NoiseSampler {
private final Expression expression;
private final Variable x;
private final Variable y;
private final Variable z;
public ExpressionSampler(String equation, Scope parent, long seed, Map<String, NoiseSeeded> functions, Map<String, FunctionTemplate> definedFunctions) throws ParseException {
Parser parser = new Parser();
Scope scope = new Scope().withParent(parent);
this.x = scope.create("x");
this.y = scope.create("y");
this.z = scope.create("z");
scope.addInvocationVariable("x");
scope.addInvocationVariable("y");
scope.addInvocationVariable("z");
functions.forEach((id, noise) -> {
switch(noise.getDimensions()) {
case 2:
parser.registerFunction(id, new NoiseFunction2(seed, noise));
parser.registerFunction(id, new NoiseFunction2(noise.apply(seed)));
break;
case 3:
parser.registerFunction(id, new NoiseFunction3(seed, noise));
parser.registerFunction(id, new NoiseFunction3(noise.apply(seed)));
break;
}
});
for(Map.Entry<String, FunctionTemplate> entry : definedFunctions.entrySet()) {
String id = entry.getKey();
FunctionTemplate fun = entry.getValue();
Scope functionScope = new Scope().withParent(parent);
List<Variable> variables = fun.getArgs().stream().map(functionScope::create).collect(Collectors.toList());
parser.registerFunction(id, new UserDefinedFunction(parser.parse(fun.getFunction(), functionScope), variables));
parser.registerFunction(entry.getKey(), UserDefinedFunction.newInstance(entry.getValue(), parser, parent));
}
this.expression = parser.parse(equation, scope);
}
@Override
public synchronized double getNoise(double x, double y) {
public double getNoise(double x, double y) {
return getNoise(x, 0, y);
}
@Override
public synchronized double getNoise(double x, double y, double z) {
this.x.setValue(x);
this.y.setValue(y);
this.z.setValue(z);
return expression.evaluate();
public double getNoise(double x, double y, double z) {
return expression.evaluate(x, y, z);
}
@Override

View File

@@ -1,11 +1,9 @@
package com.dfsek.terra.api.math.parsii;
import parsii.eval.Expression;
import parsii.eval.Function;
import java.util.List;
import com.dfsek.paralithic.functions.dynamic.DynamicFunction;
public class BlankFunction implements Function {
public class BlankFunction implements DynamicFunction {
private final int args;
public BlankFunction(int args) {
@@ -13,17 +11,17 @@ public class BlankFunction implements Function {
}
@Override
public int getNumberOfArguments() {
public int getArgNumber() {
return args;
}
@Override
public double eval(List<Expression> list) {
public double eval(double... d) {
return 0;
}
@Override
public boolean isNaturalFunction() {
public boolean isStateless() {
return true;
}
}

View File

@@ -1,35 +1,44 @@
package com.dfsek.terra.api.math.parsii.defined;
import parsii.eval.Expression;
import parsii.eval.Function;
import parsii.eval.Variable;
import com.dfsek.paralithic.Expression;
import com.dfsek.paralithic.eval.parser.Parser;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.paralithic.functions.dynamic.DynamicFunction;
import com.dfsek.terra.config.loaders.config.function.FunctionTemplate;
import java.util.List;
public class UserDefinedFunction implements Function {
public class UserDefinedFunction implements DynamicFunction {
private final Expression expression;
private final List<Variable> variables;
private final int args;
public UserDefinedFunction(Expression expression, List<Variable> variables) {
protected UserDefinedFunction(Expression expression, int args) {
this.expression = expression;
this.variables = variables;
this.args = args;
}
@Override
public double eval(double... args) {
return expression.evaluate(args);
}
@Override
public int getNumberOfArguments() {
return variables.size();
}
@Override
public synchronized double eval(List<Expression> args) {
for(int i = 0; i < variables.size(); i++) {
variables.get(i).setValue(args.get(i).evaluate());
}
return expression.evaluate();
}
@Override
public boolean isNaturalFunction() {
public boolean isStateless() {
return true;
}
@Override
public int getArgNumber() {
return args;
}
public static UserDefinedFunction newInstance(FunctionTemplate template, Parser parser, Scope parent) throws ParseException {
Scope functionScope = new Scope().withParent(parent);
template.getArgs().forEach(functionScope::addInvocationVariable);
return new UserDefinedFunction(parser.parse(template.getFunction(), functionScope), template.getArgs().size());
}
}

View File

@@ -1,6 +1,7 @@
package com.dfsek.terra.api.math.parsii.noise;
import parsii.eval.Function;
public interface NoiseFunction extends Function {
import com.dfsek.paralithic.functions.dynamic.DynamicFunction;
public interface NoiseFunction extends DynamicFunction {
}

View File

@@ -1,42 +1,30 @@
package com.dfsek.terra.api.math.parsii.noise;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.util.hash.HashMapDoubleDouble;
import parsii.eval.Expression;
import java.util.List;
public class NoiseFunction2 implements NoiseFunction {
private final NoiseSampler gen;
private final Cache cache = new Cache();
public NoiseFunction2(long seed, NoiseSeeded builder) {
this.gen = builder.apply(seed);
public NoiseFunction2(NoiseSampler gen) {
this.gen = gen;
}
@Override
public int getNumberOfArguments() {
public int getArgNumber() {
return 2;
}
@Override
public double eval(List<Expression> list) {
return cache.get(gen, list.get(0).evaluate(), list.get(1).evaluate());
}
/**
* Evaluate without cache. For testing.
*
* @param list Parameters.
* @return Result.
*/
public double evalNoCache(List<Expression> list) {
return gen.getNoise(list.get(0).evaluate(), list.get(1).evaluate());
public double eval(double... args) {
return cache.get(gen, args[0], args[1]);
}
@Override
public boolean isNaturalFunction() {
public boolean isStateless() {
return true;
}
@@ -44,6 +32,10 @@ public class NoiseFunction2 implements NoiseFunction {
private static final long serialVersionUID = 8915092734723467010L;
private static final int cacheSize = 384;
public Cache() {
super(cacheSize);
}
public double get(NoiseSampler noise, double x, double z) {
double xx = x >= 0 ? x * 2 : x * -2 - 1;
double zz = z >= 0 ? z * 2 : z * -2 - 1;
@@ -55,7 +47,7 @@ public class NoiseFunction2 implements NoiseFunction {
return (value == 4.9E-324D ? addAndReturn(noise.getNoise(x, z), key) : value);
}
private double addAndReturn(double value, double key) {
private synchronized double addAndReturn(double value, double key) {
this.put(key, value);
return value;
}

View File

@@ -1,30 +1,26 @@
package com.dfsek.terra.api.math.parsii.noise;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import parsii.eval.Expression;
import java.util.List;
public class NoiseFunction3 implements NoiseFunction {
private final NoiseSampler gen;
public NoiseFunction3(long seed, NoiseSeeded builder) {
this.gen = builder.apply(seed);
public NoiseFunction3(NoiseSampler gen) {
this.gen = gen;
}
@Override
public int getNumberOfArguments() {
public int getArgNumber() {
return 3;
}
@Override
public double eval(List<Expression> list) {
return gen.getNoise(list.get(0).evaluate(), list.get(1).evaluate(), list.get(2).evaluate());
public double eval(double... args) {
return gen.getNoise(args[0], args[1], args[2]);
}
@Override
public boolean isNaturalFunction() {
public boolean isStateless() {
return true;
}
}

View File

@@ -28,8 +28,8 @@ import com.dfsek.terra.api.structures.structure.Rotation;
import com.dfsek.terra.api.structures.structure.buffer.Buffer;
import com.dfsek.terra.api.structures.structure.buffer.DirectBuffer;
import com.dfsek.terra.api.structures.structure.buffer.StructureBuffer;
import com.dfsek.terra.registry.LootRegistry;
import com.dfsek.terra.registry.ScriptRegistry;
import com.dfsek.terra.registry.config.LootRegistry;
import com.dfsek.terra.registry.config.ScriptRegistry;
import com.dfsek.terra.world.generation.math.SamplerCache;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

View File

@@ -5,7 +5,7 @@ import com.dfsek.terra.api.structures.parser.lang.Returnable;
import com.dfsek.terra.api.structures.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.api.structures.script.functions.LootFunction;
import com.dfsek.terra.api.structures.tokenizer.Position;
import com.dfsek.terra.registry.LootRegistry;
import com.dfsek.terra.registry.config.LootRegistry;
import java.util.List;

View File

@@ -6,7 +6,7 @@ import com.dfsek.terra.api.structures.parser.lang.Returnable;
import com.dfsek.terra.api.structures.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.api.structures.script.functions.StructureFunction;
import com.dfsek.terra.api.structures.tokenizer.Position;
import com.dfsek.terra.registry.ScriptRegistry;
import com.dfsek.terra.registry.config.ScriptRegistry;
import java.util.List;
import java.util.stream.Collectors;

View File

@@ -12,7 +12,7 @@ import com.dfsek.terra.api.structures.script.TerraImplementationArguments;
import com.dfsek.terra.api.structures.structure.RotationUtil;
import com.dfsek.terra.api.structures.structure.buffer.items.BufferedLootApplication;
import com.dfsek.terra.api.structures.tokenizer.Position;
import com.dfsek.terra.registry.LootRegistry;
import com.dfsek.terra.registry.config.LootRegistry;
import net.jafama.FastMath;
import java.util.Map;

View File

@@ -13,7 +13,7 @@ import com.dfsek.terra.api.structures.structure.Rotation;
import com.dfsek.terra.api.structures.structure.RotationUtil;
import com.dfsek.terra.api.structures.structure.buffer.IntermediateBuffer;
import com.dfsek.terra.api.structures.tokenizer.Position;
import com.dfsek.terra.registry.ScriptRegistry;
import com.dfsek.terra.registry.config.ScriptRegistry;
import net.jafama.FastMath;
import java.util.List;

View File

@@ -0,0 +1,6 @@
package com.dfsek.terra.api.util.seeded;
import com.dfsek.terra.biome.pipeline.source.BiomeSource;
public interface SourceSeeded extends SeededBuilder<BiomeSource> {
}

View File

@@ -0,0 +1,6 @@
package com.dfsek.terra.api.util.seeded;
import com.dfsek.terra.biome.pipeline.stages.Stage;
public interface StageSeeded extends SeededBuilder<Stage> {
}

View File

@@ -2,7 +2,7 @@ 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.api.util.seeded.SeededBuilder;
import com.dfsek.terra.api.util.seeded.StageSeeded;
import com.dfsek.terra.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.biome.pipeline.stages.Stage;
@@ -42,7 +42,7 @@ public class BiomePipeline {
public static final class BiomePipelineBuilder {
private final int init;
List<SeededBuilder<Stage>> stages = new GlueList<>();
List<StageSeeded> stages = new GlueList<>();
private int expand;
public BiomePipelineBuilder(int init) {
@@ -60,7 +60,7 @@ public class BiomePipeline {
return new BiomePipeline(source, stagesBuilt, expand, init);
}
public BiomePipelineBuilder addStage(SeededBuilder<Stage> stage) {
public BiomePipelineBuilder addStage(StageSeeded stage) {
stages.add(stage);
return this;
}

View File

@@ -23,4 +23,8 @@ public interface BiomeProvider {
interface BiomeProviderBuilder {
BiomeProvider build(long seed);
}
enum Type {
IMAGE, PIPELINE, SINGLE
}
}

View File

@@ -9,14 +9,16 @@ import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
public class ImageBiomeProvider implements BiomeProvider {
public class ImageBiomeProvider implements BiomeProvider, BiomeProvider.BiomeProviderBuilder { // This provider does not need a seed, so it is its own builder.
private final Map<Color, TerraBiome> colorBiomeMap = new HashMap<>();
private final BufferedImage image;
private final int resolution;
private final Align align;
public ImageBiomeProvider(TerraRegistry<TerraBiome> registry, BufferedImage image, int resolution) {
public ImageBiomeProvider(TerraRegistry<TerraBiome> registry, BufferedImage image, int resolution, Align align) {
this.image = image;
this.resolution = resolution;
this.align = align;
registry.forEach(biome -> colorBiomeMap.put(new Color(biome.getColor()), biome));
}
@@ -26,7 +28,9 @@ public class ImageBiomeProvider implements BiomeProvider {
@Override
public TerraBiome getBiome(int x, int z) {
Color color = new Color(image.getRGB(FastMath.floorMod(x / resolution, image.getWidth()), FastMath.floorMod(z / resolution, image.getHeight())));
x /= resolution;
z /= resolution;
Color color = align.getColor(image, x, z);
return colorBiomeMap.get(colorBiomeMap.keySet().stream().reduce(colorBiomeMap.keySet().stream().findAny().orElseThrow(IllegalStateException::new), (running, element) -> {
int d1 = distance(color, running);
int d2 = distance(color, element);
@@ -34,20 +38,24 @@ public class ImageBiomeProvider implements BiomeProvider {
}));
}
public static class ImageBiomeProviderBuilder implements BiomeProviderBuilder {
private final BufferedImage image;
private final int resolution;
private final TerraRegistry<TerraBiome> registry;
@Override
public BiomeProvider build(long seed) {
return this;
}
public ImageBiomeProviderBuilder(BufferedImage image, int resolution, TerraRegistry<TerraBiome> registry) {
this.image = image;
this.resolution = resolution;
this.registry = registry;
}
public enum Align {
CENTER {
@Override
public Color getColor(BufferedImage image, int x, int z) {
return new Color(image.getRGB(FastMath.floorMod(x - image.getWidth() / 2, image.getWidth()), FastMath.floorMod(z - image.getHeight() / 2, image.getHeight())));
}
}, NONE {
@Override
public Color getColor(BufferedImage image, int x, int z) {
return new Color(image.getRGB(FastMath.floorMod(x, image.getWidth()), FastMath.floorMod(z, image.getHeight())));
}
};
@Override
public BiomeProvider build(long seed) {
return new ImageBiomeProvider(registry, image, resolution);
}
public abstract Color getColor(BufferedImage image, int x, int z);
}
}

View File

@@ -2,7 +2,7 @@ package com.dfsek.terra.biome.provider;
import com.dfsek.terra.biome.TerraBiome;
public class SingleBiomeProvider implements BiomeProvider {
public class SingleBiomeProvider implements BiomeProvider, BiomeProvider.BiomeProviderBuilder {
private final TerraBiome biome;
public SingleBiomeProvider(TerraBiome biome) {
@@ -14,5 +14,8 @@ public class SingleBiomeProvider implements BiomeProvider {
return biome;
}
@Override
public BiomeProvider build(long seed) {
return this;
}
}

View File

@@ -1,10 +1,8 @@
package com.dfsek.terra.biome.provider;
import com.dfsek.tectonic.exception.ConfigException;
import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.math.vector.Vector2;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.biome.TerraBiome;
import com.dfsek.terra.biome.pipeline.BiomeHolder;
import com.dfsek.terra.biome.pipeline.BiomePipeline;
@@ -17,12 +15,13 @@ import org.jetbrains.annotations.NotNull;
public class StandardBiomeProvider implements BiomeProvider {
private final LoadingCache<Vector2, BiomeHolder> holderCache;
private final BiomePipeline pipeline;
private int resolution = 1;
private final int resolution;
private final NoiseSampler mutator;
private final double noiseAmp;
private final int seed;
protected StandardBiomeProvider(BiomePipeline pipeline, TerraPlugin main, NoiseSampler mutator, double noiseAmp, int seed) {
public StandardBiomeProvider(BiomePipeline pipeline, TerraPlugin main, int resolution, NoiseSampler mutator, double noiseAmp, int seed) {
this.resolution = resolution;
this.mutator = mutator;
this.noiseAmp = noiseAmp;
this.seed = seed;
@@ -53,52 +52,4 @@ public class StandardBiomeProvider implements BiomeProvider {
int fdZ = FastMath.floorDiv(z, pipeline.getSize());
return holderCache.getUnchecked(new Vector2(fdX, fdZ)).getBiome(x - fdX * pipeline.getSize(), z - fdZ * pipeline.getSize());
}
public int getResolution() {
return resolution;
}
public void setResolution(int resolution) {
this.resolution = resolution;
}
public interface ExceptionalFunction<I, O> {
O apply(I in) throws ConfigException;
}
public static final class StandardBiomeProviderBuilder implements BiomeProviderBuilder {
private final ExceptionalFunction<Long, BiomePipeline> pipelineBuilder;
private final TerraPlugin main;
private int resolution = 1;
private double noiseAmp = 2;
private NoiseSeeded builder;
public StandardBiomeProviderBuilder(ExceptionalFunction<Long, BiomePipeline> pipelineBuilder, TerraPlugin main) {
this.pipelineBuilder = pipelineBuilder;
this.main = main;
}
public void setResolution(int resolution) {
this.resolution = resolution;
}
public void setBlender(NoiseSeeded builder) {
this.builder = builder;
}
public void setNoiseAmp(double noiseAmp) {
this.noiseAmp = noiseAmp;
}
@Override
public StandardBiomeProvider build(long seed) {
try {
StandardBiomeProvider provider = new StandardBiomeProvider(pipelineBuilder.apply(seed), main, builder.apply(seed), noiseAmp, (int) seed);
provider.setResolution(resolution);
return provider;
} catch(ConfigException e) {
throw new RuntimeException(e);
}
}
}
}

View File

@@ -34,7 +34,6 @@ public class CarverCache {
BiomeProvider provider = main.getWorld(w).getBiomeProvider();
if(CarverCache.this.carver.isChunkCarved(w, chunkX, chunkZ, new FastRandom(MathUtil.getCarverChunkSeed(chunkX, chunkZ, w.getSeed() + CarverCache.this.carver.hashCode())))) {
long seed = MathUtil.getCarverChunkSeed(chunkX, chunkZ, w.getSeed());
CarverCache.this.carver.getSeedVar().setValue(seed);
Random r = new FastRandom(seed);
Worm carving = CarverCache.this.carver.getWorm(seed, new Vector3((chunkX << 4) + r.nextInt(16), CarverCache.this.carver.getConfig().getHeight().get(r), (chunkZ << 4) + r.nextInt(16)));
List<Worm.WormPoint> points = new GlueList<>();

View File

@@ -1,5 +1,9 @@
package com.dfsek.terra.carving;
import com.dfsek.paralithic.Expression;
import com.dfsek.paralithic.eval.parser.Parser;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.math.Range;
import com.dfsek.terra.api.math.parsii.defined.UserDefinedFunction;
@@ -16,18 +20,12 @@ import com.dfsek.terra.config.loaders.config.function.FunctionTemplate;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.config.templates.CarverTemplate;
import net.jafama.FastMath;
import parsii.eval.Expression;
import parsii.eval.Parser;
import parsii.eval.Scope;
import parsii.eval.Variable;
import parsii.tokenizer.ParseException;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
public class UserDefinedCarver extends Carver {
private final double[] start; // 0, 1, 2 = x, y, z.
@@ -40,13 +38,6 @@ public class UserDefinedCarver extends Carver {
private final Expression xRad;
private final Expression yRad;
private final Expression zRad;
private final Variable lengthVar;
private final Variable position;
private final Variable seedVar;
private final Variable xOrigin;
private final Variable yOrigin;
private final Variable zOrigin;
private final Map<World, CarverCache> cacheMap = new ConcurrentHashMap<>();
private final TerraPlugin main;
@@ -70,33 +61,28 @@ public class UserDefinedCarver extends Carver {
functions.forEach((id, noise) -> {
switch(noise.getDimensions()) {
case 2:
p.registerFunction(id, new NoiseFunction2(hash, noise));
p.registerFunction(id, new NoiseFunction2(noise.apply(hash)));
break;
case 3:
p.registerFunction(id, new NoiseFunction3(hash, noise));
p.registerFunction(id, new NoiseFunction3(noise.apply(hash)));
break;
}
});
for(Map.Entry<String, FunctionTemplate> entry : definedFunctions.entrySet()) {
String id = entry.getKey();
FunctionTemplate fun = entry.getValue();
Scope functionScope = new Scope().withParent(parent);
List<Variable> variables = fun.getArgs().stream().map(functionScope::create).collect(Collectors.toList());
p.registerFunction(id, new UserDefinedFunction(p.parse(fun.getFunction(), functionScope), variables));
p.registerFunction(entry.getKey(), UserDefinedFunction.newInstance(entry.getValue(), p, parent));
}
Scope s = new Scope().withParent(parent);
lengthVar = s.create("length");
position = s.create("position");
seedVar = s.create("seed");
xOrigin = s.create("x");
yOrigin = s.create("y");
zOrigin = s.create("z");
s.addInvocationVariable("x");
s.addInvocationVariable("y");
s.addInvocationVariable("z");
s.addInvocationVariable("length");
s.addInvocationVariable("position");
s.addInvocationVariable("seed");
xRad = p.parse(radii.get(0), s);
@@ -108,19 +94,7 @@ public class UserDefinedCarver extends Carver {
@Override
public Worm getWorm(long l, Vector3 vector) {
Random r = new FastRandom(l + hash);
return new UserDefinedWorm(length.get(r) / 2, r, vector, topCut, bottomCut);
}
protected Variable getSeedVar() {
return seedVar;
}
protected Variable getLengthVar() {
return lengthVar;
}
protected Variable getPosition() {
return position;
return new UserDefinedWorm(length.get(r) / 2, r, vector, topCut, bottomCut, l);
}
public void setStep(double step) {
@@ -168,21 +142,21 @@ public class UserDefinedCarver extends Carver {
private class UserDefinedWorm extends Worm {
private final Vector3 direction;
private final Vector3 origin;
private int steps;
private int nextDirection = 0;
private double[] currentRotation = new double[3];
private final long seed;
public UserDefinedWorm(int length, Random r, Vector3 origin, int topCut, int bottomCut) {
public UserDefinedWorm(int length, Random r, Vector3 origin, int topCut, int bottomCut, long seed) {
super(length, r, origin);
this.origin = origin;
this.seed = seed;
super.setTopCut(topCut);
super.setBottomCut(bottomCut);
direction = new Vector3((r.nextDouble() - 0.5D) * start[0], (r.nextDouble() - 0.5D) * start[1], (r.nextDouble() - 0.5D) * start[2]).normalize().multiply(step);
position.setValue(0);
lengthVar.setValue(length);
xOrigin.setValue(origin.getX());
yOrigin.setValue(origin.getY());
zOrigin.setValue(origin.getZ());
setRadius(new int[] {(int) (xRad.evaluate()), (int) (yRad.evaluate()), (int) (zRad.evaluate())});
double[] args = {origin.getX(), origin.getY(), origin.getZ(), length, 0, seed};
setRadius(new int[] {(int) (xRad.evaluate(args)), (int) (yRad.evaluate(args)), (int) (zRad.evaluate(args))});
}
@Override
@@ -191,7 +165,7 @@ public class UserDefinedCarver extends Carver {
}
@Override
public synchronized void step() {
public void step() {
if(steps == nextDirection) {
direction.rotateAroundX(FastMath.toRadians((getRandom().nextGaussian()) * mutate[0] * recalcMagnitude));
direction.rotateAroundY(FastMath.toRadians((getRandom().nextGaussian()) * mutate[1] * recalcMagnitude));
@@ -202,8 +176,8 @@ public class UserDefinedCarver extends Carver {
nextDirection += recalc.get(getRandom());
}
steps++;
position.setValue(steps);
setRadius(new int[] {(int) (xRad.evaluate()), (int) (yRad.evaluate()), (int) (zRad.evaluate())});
double[] args = {origin.getX(), origin.getY(), origin.getZ(), getLength(), steps, seed};
setRadius(new int[] {(int) (xRad.evaluate(args)), (int) (yRad.evaluate(args)), (int) (zRad.evaluate(args))});
direction.rotateAroundX(FastMath.toRadians(currentRotation[0] * mutate[0]));
direction.rotateAroundY(FastMath.toRadians(currentRotation[1] * mutate[1]));
direction.rotateAroundZ(FastMath.toRadians(currentRotation[2] * mutate[2]));

View File

@@ -6,14 +6,16 @@ import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.math.GridSpawn;
import com.dfsek.terra.api.math.ProbabilityCollection;
import com.dfsek.terra.api.math.Range;
import com.dfsek.terra.api.math.noise.normalizer.Normalizer;
import com.dfsek.terra.api.math.noise.samplers.FastNoiseLite;
import com.dfsek.terra.api.math.noise.samplers.ImageSampler;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.api.util.seeded.SourceSeeded;
import com.dfsek.terra.api.util.seeded.StageSeeded;
import com.dfsek.terra.api.world.palette.holder.PaletteHolder;
import com.dfsek.terra.api.world.palette.holder.PaletteLayerHolder;
import com.dfsek.terra.biome.pipeline.stages.ExpanderStage;
import com.dfsek.terra.biome.pipeline.stages.MutatorStage;
import com.dfsek.terra.biome.provider.BiomeProvider;
import com.dfsek.terra.biome.provider.ImageBiomeProvider;
import com.dfsek.terra.carving.CarverPalette;
import com.dfsek.terra.config.loaders.LinkedHashMapLoader;
import com.dfsek.terra.config.loaders.MaterialSetLoader;
@@ -24,6 +26,9 @@ import com.dfsek.terra.config.loaders.config.GridSpawnLoader;
import com.dfsek.terra.config.loaders.config.OreConfigLoader;
import com.dfsek.terra.config.loaders.config.OreHolderLoader;
import com.dfsek.terra.config.loaders.config.TreeLayerLoader;
import com.dfsek.terra.config.loaders.config.biome.BiomeProviderBuilderLoader;
import com.dfsek.terra.config.loaders.config.biome.SourceBuilderLoader;
import com.dfsek.terra.config.loaders.config.biome.StageBuilderLoader;
import com.dfsek.terra.config.loaders.config.biome.templates.stage.expander.ExpanderStageTemplate;
import com.dfsek.terra.config.loaders.config.biome.templates.stage.mutator.BorderListMutatorTemplate;
import com.dfsek.terra.config.loaders.config.biome.templates.stage.mutator.BorderMutatorTemplate;
@@ -31,10 +36,10 @@ import com.dfsek.terra.config.loaders.config.biome.templates.stage.mutator.Repla
import com.dfsek.terra.config.loaders.config.biome.templates.stage.mutator.ReplaceMutatorTemplate;
import com.dfsek.terra.config.loaders.config.biome.templates.stage.mutator.SmoothMutatorTemplate;
import com.dfsek.terra.config.loaders.config.function.FunctionTemplate;
import com.dfsek.terra.config.loaders.config.sampler.NoiseSamplerBuilderLoader;
import com.dfsek.terra.config.loaders.config.sampler.templates.DomainWarpTemplate;
import com.dfsek.terra.config.loaders.config.sampler.templates.FastNoiseTemplate;
import com.dfsek.terra.config.loaders.config.sampler.templates.ImageSamplerTemplate;
import com.dfsek.terra.config.loaders.config.sampler.templates.normalizer.ClampNormalizerTemplate;
import com.dfsek.terra.config.loaders.config.sampler.templates.normalizer.LinearNormalizerTemplate;
import com.dfsek.terra.config.loaders.config.sampler.templates.normalizer.NormalNormalizerTemplate;
import com.dfsek.terra.config.loaders.palette.CarverPaletteLoader;
@@ -75,8 +80,7 @@ public class GenericLoaders implements LoaderRegistrar {
.registerLoader(DomainWarpTemplate.class, DomainWarpTemplate::new)
.registerLoader(LinearNormalizerTemplate.class, LinearNormalizerTemplate::new)
.registerLoader(NormalNormalizerTemplate.class, NormalNormalizerTemplate::new)
.registerLoader(FastNoiseTemplate.class, FastNoiseTemplate::new)
.registerLoader(NoiseSeeded.class, new NoiseSamplerBuilderLoader())
.registerLoader(ClampNormalizerTemplate.class, ClampNormalizerTemplate::new)
.registerLoader(ReplaceMutatorTemplate.class, ReplaceMutatorTemplate::new)
.registerLoader(ExpanderStageTemplate.class, ExpanderStageTemplate::new)
.registerLoader(SmoothMutatorTemplate.class, SmoothMutatorTemplate::new)
@@ -86,7 +90,12 @@ public class GenericLoaders implements LoaderRegistrar {
.registerLoader(FunctionTemplate.class, FunctionTemplate::new)
.registerLoader(LinkedHashMap.class, new LinkedHashMapLoader())
.registerLoader(CarverPalette.class, new CarverPaletteLoader())
.registerLoader(SourceSeeded.class, new SourceBuilderLoader())
.registerLoader(StageSeeded.class, new StageBuilderLoader())
.registerLoader(BiomeProvider.BiomeProviderBuilder.class, new BiomeProviderBuilderLoader())
.registerLoader(ImageSampler.Channel.class, (t, object, cf) -> ImageSampler.Channel.valueOf((String) object))
.registerLoader(BiomeProvider.Type.class, (t, object, cf) -> BiomeProvider.Type.valueOf((String) object))
.registerLoader(ImageBiomeProvider.Align.class, (t, object, cf) -> ImageBiomeProvider.Align.valueOf((String) object))
.registerLoader(ExpanderStage.Type.class, (t, object, cf) -> ExpanderStage.Type.valueOf((String) object))
.registerLoader(MutatorStage.Type.class, (t, object, cf) -> MutatorStage.Type.valueOf((String) object))
.registerLoader(FastNoiseLite.NoiseType.class, (t, object, cf) -> FastNoiseLite.NoiseType.valueOf((String) object))
@@ -95,8 +104,6 @@ public class GenericLoaders implements LoaderRegistrar {
.registerLoader(FastNoiseLite.RotationType3D.class, (t, object, cf) -> FastNoiseLite.RotationType3D.valueOf((String) object))
.registerLoader(FastNoiseLite.CellularReturnType.class, (t, object, cf) -> FastNoiseLite.CellularReturnType.valueOf((String) object))
.registerLoader(FastNoiseLite.CellularDistanceFunction.class, (t, object, cf) -> FastNoiseLite.CellularDistanceFunction.valueOf((String) object))
.registerLoader(Normalizer.NormalType.class, (t, o, l) -> Normalizer.NormalType.valueOf(o.toString().toUpperCase()))
.registerLoader(TerraFlora.Search.class, (t, o, l) -> TerraFlora.Search.valueOf(o.toString()))
.registerLoader(Normalizer.NormalType.class, (t, o, l) -> Normalizer.NormalType.valueOf(o.toString().toUpperCase()));
.registerLoader(TerraFlora.Search.class, (t, o, l) -> TerraFlora.Search.valueOf(o.toString()));
}
}

View File

@@ -1,5 +1,7 @@
package com.dfsek.terra.config.builder;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.math.noise.samplers.ConstantSampler;
import com.dfsek.terra.api.math.noise.samplers.ExpressionSampler;
@@ -7,8 +9,6 @@ import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.api.world.palette.holder.PaletteHolder;
import com.dfsek.terra.config.loaders.config.function.FunctionTemplate;
import com.dfsek.terra.world.generation.WorldGenerator;
import parsii.eval.Scope;
import parsii.tokenizer.ParseException;
import java.util.Collections;
import java.util.HashMap;

View File

@@ -1,5 +1,6 @@
package com.dfsek.terra.config.factories;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.biome.TerraBiome;
import com.dfsek.terra.biome.UserDefinedBiome;
@@ -7,7 +8,6 @@ import com.dfsek.terra.config.builder.GeneratorBuilder;
import com.dfsek.terra.config.loaders.config.function.FunctionTemplate;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.templates.BiomeTemplate;
import parsii.eval.Scope;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -35,7 +35,7 @@ public class BiomeFactory implements TerraFactory<BiomeTemplate, TerraBiome> {
generatorBuilder.setSlantPalettes(template.getSlantPalette());
Scope vars = new Scope().withParent(pack.getVarScope());
template.getVariables().forEach((id, val) -> vars.create(id).setValue(val));
template.getVariables().forEach(vars::create);
generatorBuilder.setVarScope(vars);
generatorBuilder.setInterpolateElevation(template.interpolateElevation());

View File

@@ -1,12 +1,12 @@
package com.dfsek.terra.config.factories;
import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.math.MathUtil;
import com.dfsek.terra.carving.UserDefinedCarver;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.templates.CarverTemplate;
import parsii.tokenizer.ParseException;
import java.util.Arrays;
import java.util.List;

View File

@@ -3,94 +3,31 @@ 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.core.TerraPlugin;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.api.util.seeded.SeededBuilder;
import com.dfsek.terra.biome.TerraBiome;
import com.dfsek.terra.biome.pipeline.BiomePipeline;
import com.dfsek.terra.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.biome.provider.BiomeProvider;
import com.dfsek.terra.biome.provider.ImageBiomeProvider;
import com.dfsek.terra.biome.provider.SingleBiomeProvider;
import com.dfsek.terra.biome.provider.StandardBiomeProvider;
import com.dfsek.terra.config.fileloaders.Loader;
import com.dfsek.terra.registry.TerraRegistry;
import com.dfsek.terra.config.loaders.config.biome.templates.source.BiomePipelineTemplate;
import com.dfsek.terra.config.loaders.config.biome.templates.source.ImageProviderTemplate;
import com.dfsek.terra.config.loaders.config.biome.templates.source.SingleBiomeProviderTemplate;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
@SuppressWarnings("unchecked")
public class BiomeProviderBuilderLoader implements TypeLoader<BiomeProvider.BiomeProviderBuilder> {
private final TerraPlugin main;
private final TerraRegistry<TerraBiome> biomeRegistry;
private final Loader fileLoader;
public BiomeProviderBuilderLoader(TerraPlugin main, TerraRegistry<TerraBiome> biomeRegistry, Loader fileLoader) {
this.main = main;
this.biomeRegistry = biomeRegistry;
this.fileLoader = fileLoader;
public BiomeProviderBuilderLoader() {
}
@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 = (Integer) map.getOrDefault("resolution", 1);
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 = (Integer) pipeline.getOrDefault("initial-size", 2);
StandardBiomeProvider.StandardBiomeProviderBuilder builder = new StandardBiomeProvider.StandardBiomeProviderBuilder(seed -> {
BiomePipeline.BiomePipelineBuilder pipelineBuilder = new BiomePipeline.BiomePipelineBuilder(init);
for(Map<String, Object> stage : stages) {
for(Map.Entry<String, Object> entry : stage.entrySet()) {
pipelineBuilder.addStage(new StageBuilderLoader().load(SeededBuilder.class, entry, loader));
}
}
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.apply(seed), seed);
main.getDebugLogger().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");
if(blend.containsKey("amplitude")) builder.setNoiseAmp(Double.parseDouble(blend.get("amplitude").toString()));
if(blend.containsKey("noise"))
builder.setBlender(loader.loadClass(NoiseSeeded.class, blend.get("noise")));
}
return builder;
} else if(map.get("type").equals("IMAGE")) {
Map<String, Object> imageMap = (Map<String, Object>) map.get("image");
try {
main.getLogger().info("Using image " + imageMap.get("name") + " for biome distribution.");
BufferedImage image = ImageIO.read(fileLoader.get(imageMap.get("name").toString()));
return new ImageBiomeProvider.ImageBiomeProviderBuilder(image, resolution, biomeRegistry);
} catch(IOException e) {
throw new LoadException("Failed to load image", e);
}
} else if(map.get("type").equals("SINGLE")) {
return seed -> {
try {
return new SingleBiomeProvider(loader.loadClass(TerraBiome.class, map.get("biome")));
} catch(LoadException e) {
throw new RuntimeException(e);
}
};
switch(loader.loadClass(BiomeProvider.Type.class, map.get("type"))) {
case IMAGE:
return loader.loadClass(ImageProviderTemplate.class, map);
case PIPELINE:
return loader.loadClass(BiomePipelineTemplate.class, map);
case SINGLE:
return loader.loadClass(SingleBiomeProviderTemplate.class, map);
}
throw new LoadException("No such biome provider type: " + map.get("type"));

View File

@@ -5,9 +5,8 @@ import com.dfsek.tectonic.loading.ConfigLoader;
import com.dfsek.tectonic.loading.TypeLoader;
import com.dfsek.terra.api.math.ProbabilityCollection;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.api.util.seeded.SeededBuilder;
import com.dfsek.terra.api.util.seeded.SourceSeeded;
import com.dfsek.terra.biome.TerraBiome;
import com.dfsek.terra.biome.pipeline.source.BiomeSource;
import com.dfsek.terra.biome.pipeline.source.RandomSource;
import com.dfsek.terra.config.loaders.Types;
@@ -15,9 +14,9 @@ import java.lang.reflect.Type;
import java.util.Map;
@SuppressWarnings("unchecked")
public class SourceBuilderLoader implements TypeLoader<SeededBuilder<BiomeSource>> {
public class SourceBuilderLoader implements TypeLoader<SourceSeeded> {
@Override
public SeededBuilder<BiomeSource> load(Type t, Object c, ConfigLoader loader) throws LoadException {
public SourceSeeded load(Type t, Object c, ConfigLoader loader) throws LoadException {
Map<String, Object> source = (Map<String, Object>) c;
String type = source.get("type").toString();

View File

@@ -3,10 +3,9 @@ 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.util.seeded.SeededBuilder;
import com.dfsek.terra.api.util.seeded.StageSeeded;
import com.dfsek.terra.biome.pipeline.stages.ExpanderStage;
import com.dfsek.terra.biome.pipeline.stages.MutatorStage;
import com.dfsek.terra.biome.pipeline.stages.Stage;
import com.dfsek.terra.config.loaders.config.biome.templates.stage.expander.ExpanderStageTemplate;
import com.dfsek.terra.config.loaders.config.biome.templates.stage.mutator.BorderListMutatorTemplate;
import com.dfsek.terra.config.loaders.config.biome.templates.stage.mutator.BorderMutatorTemplate;
@@ -18,33 +17,40 @@ import java.lang.reflect.Type;
import java.util.Map;
@SuppressWarnings("unchecked")
public class StageBuilderLoader implements TypeLoader<SeededBuilder<Stage>> {
public class StageBuilderLoader implements TypeLoader<StageSeeded> {
@Override
public SeededBuilder<Stage> load(Type t, Object c, ConfigLoader loader) throws LoadException {
Map.Entry<String, Object> entry = (Map.Entry<String, Object>) c;
public StageSeeded load(Type t, Object c, ConfigLoader loader) throws LoadException {
Map<String, Object> raw = (Map<String, Object>) c;
if(raw.size() != 1) throw new LoadException("Illegal stage map size: " + raw.size());
Map.Entry<String, Object> entry = null;
for(Map.Entry<String, Object> e : raw.entrySet()) {
entry = e;
}
Map<String, Object> mutator = (Map<String, Object>) entry.getValue();
if(entry.getKey().equals("expand")) {
ExpanderStage.Type stageType = loader.loadClass(ExpanderStage.Type.class, mutator.get("type"));
if(stageType.equals(ExpanderStage.Type.FRACTAL)) {
return loader.loadClass(ExpanderStageTemplate.class, mutator).get();
return loader.loadClass(ExpanderStageTemplate.class, mutator);
} else throw new LoadException("No such expander \"" + stageType + "\"");
} else if(entry.getKey().equals("mutate")) {
switch(loader.loadClass(MutatorStage.Type.class, mutator.get("type"))) {
case SMOOTH:
return loader.loadClass(SmoothMutatorTemplate.class, mutator).get();
return loader.loadClass(SmoothMutatorTemplate.class, mutator);
case REPLACE:
return loader.loadClass(ReplaceMutatorTemplate.class, mutator).get();
return loader.loadClass(ReplaceMutatorTemplate.class, mutator);
case REPLACE_LIST:
return loader.loadClass(ReplaceListMutatorTemplate.class, mutator).get();
return loader.loadClass(ReplaceListMutatorTemplate.class, mutator);
case BORDER:
return loader.loadClass(BorderMutatorTemplate.class, mutator).get();
return loader.loadClass(BorderMutatorTemplate.class, mutator);
case BORDER_LIST:
return loader.loadClass(BorderListMutatorTemplate.class, mutator).get();
return loader.loadClass(BorderListMutatorTemplate.class, mutator);
default:
throw new LoadException("No such mutator type \"" + mutator.get("type"));
}
}
throw new LoadException("No such mutator \"" + entry.getKey() + "\"");

View File

@@ -0,0 +1,40 @@
package com.dfsek.terra.config.loaders.config.biome.templates.source;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.util.seeded.SourceSeeded;
import com.dfsek.terra.api.util.seeded.StageSeeded;
import com.dfsek.terra.biome.pipeline.BiomePipeline;
import com.dfsek.terra.biome.provider.BiomeProvider;
import com.dfsek.terra.biome.provider.StandardBiomeProvider;
import com.dfsek.terra.registry.config.BiomeRegistry;
import java.util.List;
@SuppressWarnings({"FieldMayBeFinal", "unused"})
public class BiomePipelineTemplate extends BiomeProviderTemplate {
private final TerraPlugin main;
@Value("pipeline.initial-size")
@Default
private int initialSize = 2;
@Value("pipeline.stages")
private List<StageSeeded> stages;
@Value("pipeline.source")
private SourceSeeded source;
public BiomePipelineTemplate(BiomeRegistry registry, TerraPlugin main) {
super(registry);
this.main = main;
}
@Override
public BiomeProvider build(long seed) {
BiomePipeline.BiomePipelineBuilder biomePipelineBuilder = new BiomePipeline.BiomePipelineBuilder(initialSize);
stages.forEach(biomePipelineBuilder::addStage);
BiomePipeline pipeline = biomePipelineBuilder.build(source.apply(seed), seed);
return new StandardBiomeProvider(pipeline, main, resolution, blend.apply(seed), blendAmp, (int) seed);
}
}

View File

@@ -0,0 +1,44 @@
package com.dfsek.terra.config.loaders.config.biome.templates.source;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.math.noise.samplers.ConstantSampler;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.biome.provider.BiomeProvider;
import com.dfsek.terra.registry.config.BiomeRegistry;
public abstract class BiomeProviderTemplate implements ObjectTemplate<BiomeProvider.BiomeProviderBuilder>, BiomeProvider.BiomeProviderBuilder {
protected final BiomeRegistry registry;
@Value("resolution")
@Default
protected int resolution = 1;
@Value("blend.noise")
@Default
protected NoiseSeeded blend = new NoiseSeeded() {
@Override
public NoiseSampler apply(Long seed) {
return new ConstantSampler(0);
}
@Override
public int getDimensions() {
return 2;
}
};
@Value("blend.amplitude")
@Default
protected double blendAmp = 0d;
@Value("type")
BiomeProvider.Type type;
protected BiomeProviderTemplate(BiomeRegistry registry) {
this.registry = registry;
}
@Override
public BiomeProvider.BiomeProviderBuilder get() {
return this;
}
}

View File

@@ -0,0 +1,25 @@
package com.dfsek.terra.config.loaders.config.biome.templates.source;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.biome.provider.BiomeProvider;
import com.dfsek.terra.biome.provider.ImageBiomeProvider;
import com.dfsek.terra.registry.config.BiomeRegistry;
import java.awt.image.BufferedImage;
public class ImageProviderTemplate extends BiomeProviderTemplate {
@Value("image.name")
private BufferedImage image;
@Value("image.align")
private ImageBiomeProvider.Align align;
public ImageProviderTemplate(BiomeRegistry registry) {
super(registry);
}
@Override
public BiomeProvider build(long seed) {
return new ImageBiomeProvider(registry, image, resolution, align);
}
}

View File

@@ -0,0 +1,21 @@
package com.dfsek.terra.config.loaders.config.biome.templates.source;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.biome.TerraBiome;
import com.dfsek.terra.biome.provider.BiomeProvider;
import com.dfsek.terra.biome.provider.SingleBiomeProvider;
import com.dfsek.terra.registry.config.BiomeRegistry;
public class SingleBiomeProviderTemplate extends BiomeProviderTemplate {
@Value("biome")
private TerraBiome biome;
public SingleBiomeProviderTemplate(BiomeRegistry registry) {
super(registry);
}
@Override
public BiomeProvider build(long seed) {
return new SingleBiomeProvider(biome);
}
}

View File

@@ -4,14 +4,15 @@ import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.api.util.seeded.SeededBuilder;
import com.dfsek.terra.api.util.seeded.StageSeeded;
import com.dfsek.terra.biome.pipeline.stages.Stage;
public abstract class StageTemplate implements ObjectTemplate<SeededBuilder<Stage>>, SeededBuilder<Stage> {
public abstract class StageTemplate implements ObjectTemplate<SeededBuilder<Stage>>, StageSeeded {
@Value("noise")
protected NoiseSeeded noise;
@Override
public SeededBuilder<Stage> get() {
public StageSeeded get() {
return this;
}
}

View File

@@ -1,21 +1,27 @@
package com.dfsek.terra.config.loaders.config.sampler;
import com.dfsek.tectonic.config.Configuration;
import com.dfsek.tectonic.exception.ConfigException;
import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.ConfigLoader;
import com.dfsek.tectonic.loading.TypeLoader;
import com.dfsek.terra.api.math.noise.normalizer.Normalizer;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.config.loaders.config.sampler.templates.DomainWarpTemplate;
import com.dfsek.terra.config.loaders.config.sampler.templates.FastNoiseTemplate;
import com.dfsek.terra.config.loaders.config.sampler.templates.ImageSamplerTemplate;
import com.dfsek.terra.config.loaders.config.sampler.templates.normalizer.LinearNormalizerTemplate;
import com.dfsek.terra.config.loaders.config.sampler.templates.normalizer.NormalNormalizerTemplate;
import com.dfsek.terra.config.loaders.config.sampler.templates.normalizer.NormalizerTemplate;
import com.dfsek.terra.registry.config.NormalizerRegistry;
import java.lang.reflect.Type;
import java.util.Map;
@SuppressWarnings("unchecked")
public class NoiseSamplerBuilderLoader implements TypeLoader<NoiseSeeded> {
private final NormalizerRegistry normalizerRegistry;
public NoiseSamplerBuilderLoader(NormalizerRegistry normalizerRegistry) {
this.normalizerRegistry = normalizerRegistry;
}
@Override
public NoiseSeeded load(Type t, Object c, ConfigLoader loader) throws LoadException {
@@ -31,12 +37,12 @@ public class NoiseSamplerBuilderLoader implements TypeLoader<NoiseSeeded> {
case "NOISE":
return loader.loadClass(FastNoiseTemplate.class, map).get();
case "NORMALIZER":
Normalizer.NormalType normalType = loader.loadClass(Normalizer.NormalType.class, map.get("type"));
switch(normalType) {
case LINEAR:
return loader.loadClass(LinearNormalizerTemplate.class, map).get();
case NORMAL:
return loader.loadClass(NormalNormalizerTemplate.class, map).get();
try {
NormalizerTemplate<?> normalizerTemplate = normalizerRegistry.get((String) map.get("type")).get();
loader.load(normalizerTemplate, new Configuration(map));
return normalizerTemplate;
} catch(ConfigException e) {
throw new LoadException("Unable to load normalizer: ", e);
}
case "IMAGE": {
return loader.loadClass(ImageSamplerTemplate.class, map).get();

View File

@@ -0,0 +1,20 @@
package com.dfsek.terra.config.loaders.config.sampler.templates.normalizer;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.math.noise.normalizer.ClampNormalizer;
import com.dfsek.terra.api.math.noise.normalizer.LinearNormalizer;
@SuppressWarnings({"unused", "FieldMayBeFinal"})
public class ClampNormalizerTemplate extends NormalizerTemplate<LinearNormalizer> {
@Value("max")
private double max;
@Value("min")
private double min;
@Override
public NoiseSampler apply(Long seed) {
return new ClampNormalizer(function.apply(seed), min, max);
}
}

View File

@@ -1,5 +1,6 @@
package com.dfsek.terra.config.pack;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.tectonic.abstraction.AbstractConfigLoader;
import com.dfsek.tectonic.exception.ConfigException;
import com.dfsek.tectonic.exception.LoadException;
@@ -9,6 +10,7 @@ import com.dfsek.terra.api.LoaderRegistrar;
import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.structures.loot.LootTable;
import com.dfsek.terra.api.structures.script.StructureScript;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.api.world.flora.Flora;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.api.world.tree.Tree;
@@ -29,7 +31,11 @@ import com.dfsek.terra.config.fileloaders.Loader;
import com.dfsek.terra.config.fileloaders.ZIPLoader;
import com.dfsek.terra.config.lang.LangUtil;
import com.dfsek.terra.config.loaders.config.BufferedImageLoader;
import com.dfsek.terra.config.loaders.config.biome.BiomeProviderBuilderLoader;
import com.dfsek.terra.config.loaders.config.biome.templates.source.BiomePipelineTemplate;
import com.dfsek.terra.config.loaders.config.biome.templates.source.ImageProviderTemplate;
import com.dfsek.terra.config.loaders.config.biome.templates.source.SingleBiomeProviderTemplate;
import com.dfsek.terra.config.loaders.config.sampler.NoiseSamplerBuilderLoader;
import com.dfsek.terra.config.loaders.config.sampler.templates.ImageSamplerTemplate;
import com.dfsek.terra.config.templates.AbstractableTemplate;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.config.templates.CarverTemplate;
@@ -38,22 +44,22 @@ import com.dfsek.terra.config.templates.OreTemplate;
import com.dfsek.terra.config.templates.PaletteTemplate;
import com.dfsek.terra.config.templates.StructureTemplate;
import com.dfsek.terra.config.templates.TreeTemplate;
import com.dfsek.terra.registry.BiomeRegistry;
import com.dfsek.terra.registry.CarverRegistry;
import com.dfsek.terra.registry.FloraRegistry;
import com.dfsek.terra.registry.LootRegistry;
import com.dfsek.terra.registry.OreRegistry;
import com.dfsek.terra.registry.PaletteRegistry;
import com.dfsek.terra.registry.ScriptRegistry;
import com.dfsek.terra.registry.StructureRegistry;
import com.dfsek.terra.registry.TerraRegistry;
import com.dfsek.terra.registry.TreeRegistry;
import com.dfsek.terra.registry.config.BiomeRegistry;
import com.dfsek.terra.registry.config.CarverRegistry;
import com.dfsek.terra.registry.config.FloraRegistry;
import com.dfsek.terra.registry.config.LootRegistry;
import com.dfsek.terra.registry.config.NormalizerRegistry;
import com.dfsek.terra.registry.config.OreRegistry;
import com.dfsek.terra.registry.config.PaletteRegistry;
import com.dfsek.terra.registry.config.ScriptRegistry;
import com.dfsek.terra.registry.config.StructureRegistry;
import com.dfsek.terra.registry.config.TreeRegistry;
import com.dfsek.terra.world.generation.math.SamplerCache;
import com.dfsek.terra.world.population.items.TerraStructure;
import com.dfsek.terra.world.population.items.ores.Ore;
import org.apache.commons.io.IOUtils;
import org.json.simple.parser.ParseException;
import parsii.eval.Scope;
import java.awt.image.BufferedImage;
import java.io.File;
@@ -88,6 +94,8 @@ public class ConfigPack implements LoaderRegistrar {
private final CarverRegistry carverRegistry = new CarverRegistry();
private final NormalizerRegistry normalizerRegistry = new NormalizerRegistry();
private final AbstractConfigLoader abstractConfigLoader = new AbstractConfigLoader();
private final ConfigLoader selfLoader = new ConfigLoader();
private final Scope varScope = new Scope();
@@ -97,74 +105,98 @@ public class ConfigPack implements LoaderRegistrar {
private final TerraPlugin main;
private final Loader loader;
private final BiomeProvider.BiomeProviderBuilder biomeProviderBuilder;
public ConfigPack(File folder, TerraPlugin main) throws ConfigException {
this.loader = new FolderLoader(folder.toPath());
this.main = main;
long l = System.nanoTime();
this.samplerCache = new SamplerCache(main);
floraRegistry = new FloraRegistry(main);
paletteRegistry = new PaletteRegistry(main);
treeRegistry = new TreeRegistry(main);
register(abstractConfigLoader);
register(selfLoader);
main.register(selfLoader);
main.register(abstractConfigLoader);
File pack = new File(folder, "pack.yml");
try {
selfLoader.load(template, new FileInputStream(pack));
} catch(FileNotFoundException e) {
throw new FileMissingException("No pack.yml file found in " + folder.getAbsolutePath(), e);
this.loader = new FolderLoader(folder.toPath());
this.main = main;
long l = System.nanoTime();
this.samplerCache = new SamplerCache(main);
floraRegistry = new FloraRegistry(main);
paletteRegistry = new PaletteRegistry(main);
treeRegistry = new TreeRegistry(main);
register(abstractConfigLoader);
register(selfLoader);
main.register(selfLoader);
main.register(abstractConfigLoader);
File pack = new File(folder, "pack.yml");
try {
selfLoader.load(template, new FileInputStream(pack));
main.getLogger().info("Loading config pack \"" + template.getID() + "\"");
load(l, main);
ConfigPackPostTemplate packPostTemplate = new ConfigPackPostTemplate();
selfLoader.load(packPostTemplate, new FileInputStream(pack));
biomeProviderBuilder = packPostTemplate.getProviderBuilder();
biomeProviderBuilder.build(0); // Build dummy provider to catch errors at load time.
} catch(FileNotFoundException e) {
throw new FileMissingException("No pack.yml file found in " + folder.getAbsolutePath(), e);
}
} catch(Exception e) {
main.getLogger().severe("Failed to load config pack from folder \"" + folder.getAbsolutePath() + "\"");
throw e;
}
load(l, main);
}
public ConfigPack(ZipFile file, TerraPlugin main) throws ConfigException {
this.loader = new ZIPLoader(file);
this.main = main;
long l = System.nanoTime();
this.samplerCache = new SamplerCache(main);
floraRegistry = new FloraRegistry(main);
paletteRegistry = new PaletteRegistry(main);
treeRegistry = new TreeRegistry(main);
register(abstractConfigLoader);
register(selfLoader);
main.register(selfLoader);
main.register(abstractConfigLoader);
InputStream stream = null;
try {
Enumeration<? extends ZipEntry> entries = file.entries();
while(entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if(entry.getName().equals("pack.yml")) stream = file.getInputStream(entry);
this.loader = new ZIPLoader(file);
this.main = main;
long l = System.nanoTime();
this.samplerCache = new SamplerCache(main);
floraRegistry = new FloraRegistry(main);
paletteRegistry = new PaletteRegistry(main);
treeRegistry = new TreeRegistry(main);
register(abstractConfigLoader);
register(selfLoader);
main.register(selfLoader);
main.register(abstractConfigLoader);
try {
ZipEntry pack = null;
Enumeration<? extends ZipEntry> entries = file.entries();
while(entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if(entry.getName().equals("pack.yml")) pack = entry;
}
if(pack == null) throw new FileMissingException("No pack.yml file found in " + file.getName());
selfLoader.load(template, file.getInputStream(pack));
main.getLogger().info("Loading config pack \"" + template.getID() + "\"");
load(l, main);
ConfigPackPostTemplate packPostTemplate = new ConfigPackPostTemplate();
selfLoader.load(packPostTemplate, file.getInputStream(pack));
biomeProviderBuilder = packPostTemplate.getProviderBuilder();
biomeProviderBuilder.build(0); // Build dummy provider to catch errors at load time.
} catch(IOException e) {
throw new LoadException("Unable to load pack.yml from ZIP file", e);
}
} catch(IOException e) {
throw new LoadException("Unable to load pack.yml from ZIP file", e);
} catch(Exception e) {
main.getLogger().severe("Failed to load config pack from ZIP archive \"" + file.getName() + "\"");
throw e;
}
if(stream == null) throw new FileMissingException("No pack.yml file found in " + file.getName());
}
selfLoader.load(template, stream);
load(l, main);
template.getProviderBuilder().build(0); // Build dummy provider to catch errors at load time.
public static <C extends AbstractableTemplate, O> void buildAll(TerraFactory<C, O> factory, TerraRegistry<O> registry, List<C> configTemplates, TerraPlugin main) throws LoadException {
for(C template : configTemplates) registry.add(template.getID(), factory.build(template, main));
}
private void load(long start, TerraPlugin main) throws ConfigException {
main.packPreLoadCallback(this);
for(Map.Entry<String, Double> var : template.getVariables().entrySet()) {
varScope.create(var.getKey()).setValue(var.getValue());
varScope.create(var.getKey(), var.getValue());
}
loader.open("structures/data", ".tstructure")
.thenNames(ids -> ids.forEach(id -> main.getLogger().severe("Found .tstructure file \"" + id + "\". This file must be updated to the newer .tesf format to work properly. See version 3.0 release notes for instructions.")))
.close();
loader.open("structures/data", ".tesf").thenEntries(entries -> {
for(Map.Entry<String, InputStream> entry : entries) {
@@ -197,10 +229,6 @@ public class ConfigPack implements LoaderRegistrar {
LangUtil.log("config-pack.loaded", Level.INFO, template.getID(), String.valueOf((System.nanoTime() - start) / 1000000D), template.getAuthor(), template.getVersion());
}
public static <C extends AbstractableTemplate, O> void buildAll(TerraFactory<C, O> factory, TerraRegistry<O> registry, List<C> configTemplates, TerraPlugin main) throws LoadException {
for(C template : configTemplates) registry.add(template.getID(), factory.build(template, main));
}
public TerraBiome getBiome(String id) {
return biomeRegistry.get(id);
}
@@ -247,7 +275,10 @@ public class ConfigPack implements LoaderRegistrar {
.registerLoader(LootTable.class, lootRegistry)
.registerLoader(UserDefinedCarver.class, carverRegistry)
.registerLoader(BufferedImage.class, new BufferedImageLoader(loader))
.registerLoader(BiomeProvider.BiomeProviderBuilder.class, new BiomeProviderBuilderLoader(main, biomeRegistry, loader));
.registerLoader(NoiseSeeded.class, new NoiseSamplerBuilderLoader(normalizerRegistry))
.registerLoader(SingleBiomeProviderTemplate.class, () -> new SingleBiomeProviderTemplate(biomeRegistry))
.registerLoader(BiomePipelineTemplate.class, () -> new BiomePipelineTemplate(biomeRegistry, main))
.registerLoader(ImageSamplerTemplate.class, () -> new ImageProviderTemplate(biomeRegistry));
}
public ScriptRegistry getScriptRegistry() {
@@ -265,4 +296,8 @@ public class ConfigPack implements LoaderRegistrar {
public Set<UserDefinedCarver> getCarvers() {
return carverRegistry.entries();
}
public BiomeProvider.BiomeProviderBuilder getBiomeProviderBuilder() {
return biomeProviderBuilder;
}
}

View File

@@ -0,0 +1,14 @@
package com.dfsek.terra.config.pack;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.config.ConfigTemplate;
import com.dfsek.terra.biome.provider.BiomeProvider;
public class ConfigPackPostTemplate implements ConfigTemplate {
@Value("biomes")
private BiomeProvider.BiomeProviderBuilder providerBuilder;
public BiomeProvider.BiomeProviderBuilder getProviderBuilder() {
return providerBuilder;
}
}

View File

@@ -4,7 +4,6 @@ import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.config.ConfigTemplate;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.biome.provider.BiomeProvider;
import com.dfsek.terra.config.loaders.config.function.FunctionTemplate;
import java.util.HashMap;
@@ -67,13 +66,6 @@ public class ConfigPackTemplate implements ConfigTemplate {
@Default
private String version = "0.1.0";
@Value("biomes")
private BiomeProvider.BiomeProviderBuilder providerBuilder;
public BiomeProvider.BiomeProviderBuilder getProviderBuilder() {
return providerBuilder;
}
public Map<String, FunctionTemplate> getFunctions() {
return functions;
}

View File

@@ -1,5 +1,8 @@
package com.dfsek.terra.config.templates;
import com.dfsek.paralithic.eval.parser.Parser;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.tectonic.annotations.Abstractable;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
@@ -27,17 +30,12 @@ import com.dfsek.terra.world.population.items.TerraStructure;
import com.dfsek.terra.world.population.items.flora.FloraLayer;
import com.dfsek.terra.world.population.items.ores.OreHolder;
import com.dfsek.terra.world.population.items.tree.TreeLayer;
import parsii.eval.Parser;
import parsii.eval.Scope;
import parsii.eval.Variable;
import parsii.tokenizer.ParseException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@SuppressWarnings({"FieldMayBeFinal", "unused"})
public class BiomeTemplate extends AbstractableTemplate implements ValidatedConfigTemplate {
@@ -344,26 +342,20 @@ public class BiomeTemplate extends AbstractableTemplate implements ValidatedConf
Parser tester = new Parser();
Scope testScope = new Scope().withParent(pack.getVarScope());
variables.forEach((id, val) -> testScope.create(id).setValue(val));
variables.forEach(testScope::create);
testScope.addInvocationVariable("x");
testScope.addInvocationVariable("y");
testScope.addInvocationVariable("z");
testScope.create("x");
testScope.create("y");
testScope.create("z");
testScope.create("seed");
pack.getTemplate().getNoiseBuilderMap().forEach((id, builder) -> tester.registerFunction(id, new BlankFunction(builder.getDimensions()))); // Register dummy functions
Map<String, FunctionTemplate> testFunctions = new LinkedHashMap<>(pack.getTemplate().getFunctions());
testFunctions.putAll(functions);
for(Map.Entry<String, FunctionTemplate> entry : testFunctions.entrySet()) {
String id = entry.getKey();
FunctionTemplate fun = entry.getValue();
Scope functionScope = new Scope().withParent(testScope);
List<Variable> variables = fun.getArgs().stream().map(functionScope::create).collect(Collectors.toList());
try {
tester.registerFunction(id, new UserDefinedFunction(tester.parse(fun.getFunction(), functionScope), variables));
tester.registerFunction(entry.getKey(), UserDefinedFunction.newInstance(entry.getValue(), tester, testScope));
} catch(ParseException e) {
throw new ValidationException("Invalid function: ", e);
}

View File

@@ -1,8 +1,9 @@
package com.dfsek.terra.registry;
package com.dfsek.terra.registry.config;
import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.ConfigLoader;
import com.dfsek.terra.biome.TerraBiome;
import com.dfsek.terra.registry.TerraRegistry;
import java.lang.reflect.Type;

View File

@@ -1,6 +1,7 @@
package com.dfsek.terra.registry;
package com.dfsek.terra.registry.config;
import com.dfsek.terra.carving.UserDefinedCarver;
import com.dfsek.terra.registry.TerraRegistry;
public class CarverRegistry extends TerraRegistry<UserDefinedCarver> {
}

View File

@@ -1,9 +1,10 @@
package com.dfsek.terra.registry;
package com.dfsek.terra.registry.config;
import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.block.MaterialData;
import com.dfsek.terra.api.world.flora.Flora;
import com.dfsek.terra.registry.TerraRegistry;
import com.dfsek.terra.util.MaterialSet;
import com.dfsek.terra.world.population.items.flora.ConstantFlora;
@@ -37,7 +38,7 @@ public class FloraRegistry extends TerraRegistry<Flora> {
create("minecraft:light_gray_terracotta"), create("minecraft:lime_terracotta"), create("minecraft:magenta_terracotta"),
create("minecraft:orange_terracotta"), create("minecraft:pink_terracotta"), create("minecraft:purple_terracotta"),
create("minecraft:red_terracotta"), create("minecraft:white_terracotta"), create("minecraft:yellow_terracotta"),
create("minecraft:red_sand"), create("minecraft:sand")), Collections.singletonList(data("minecraft:dead_bush"))));
create("minecraft:red_sand"), create("minecraft:sand"), create("minecraft:coarse_dirt")), Collections.singletonList(data("minecraft:dead_bush"))));
addItem("RED_TULIP", () -> new ConstantFlora(grassy, Collections.singletonList(data("minecraft:red_tulip"))));
addItem("ORANGE_TULIP", () -> new ConstantFlora(grassy, Collections.singletonList(data("minecraft:orange_tulip"))));
addItem("WHITE_TULIP", () -> new ConstantFlora(grassy, Collections.singletonList(data("minecraft:white_tulip"))));

View File

@@ -1,6 +1,7 @@
package com.dfsek.terra.registry;
package com.dfsek.terra.registry.config;
import com.dfsek.terra.api.structures.loot.LootTable;
import com.dfsek.terra.registry.TerraRegistry;
public class LootRegistry extends TerraRegistry<LootTable> {
}

View File

@@ -0,0 +1,17 @@
package com.dfsek.terra.registry.config;
import com.dfsek.terra.config.loaders.config.sampler.templates.normalizer.ClampNormalizerTemplate;
import com.dfsek.terra.config.loaders.config.sampler.templates.normalizer.LinearNormalizerTemplate;
import com.dfsek.terra.config.loaders.config.sampler.templates.normalizer.NormalNormalizerTemplate;
import com.dfsek.terra.config.loaders.config.sampler.templates.normalizer.NormalizerTemplate;
import com.dfsek.terra.registry.TerraRegistry;
import java.util.function.Supplier;
public class NormalizerRegistry extends TerraRegistry<Supplier<NormalizerTemplate<?>>> {
public NormalizerRegistry() {
add("LINEAR", LinearNormalizerTemplate::new);
add("NORMAL", NormalNormalizerTemplate::new);
add("CLAMP", ClampNormalizerTemplate::new);
}
}

View File

@@ -1,5 +1,6 @@
package com.dfsek.terra.registry;
package com.dfsek.terra.registry.config;
import com.dfsek.terra.registry.TerraRegistry;
import com.dfsek.terra.world.population.items.ores.Ore;
public class OreRegistry extends TerraRegistry<Ore> {

View File

@@ -1,9 +1,10 @@
package com.dfsek.terra.registry;
package com.dfsek.terra.registry.config;
import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.api.world.palette.SinglePalette;
import com.dfsek.terra.registry.TerraRegistry;
public class PaletteRegistry extends TerraRegistry<Palette<BlockData>> {
private final TerraPlugin main;

View File

@@ -1,6 +1,7 @@
package com.dfsek.terra.registry;
package com.dfsek.terra.registry.config;
import com.dfsek.terra.api.structures.script.StructureScript;
import com.dfsek.terra.registry.TerraRegistry;
public class ScriptRegistry extends TerraRegistry<StructureScript> {
}

View File

@@ -1,5 +1,6 @@
package com.dfsek.terra.registry;
package com.dfsek.terra.registry.config;
import com.dfsek.terra.registry.TerraRegistry;
import com.dfsek.terra.world.population.items.TerraStructure;
public class StructureRegistry extends TerraRegistry<TerraStructure> {

View File

@@ -1,4 +1,4 @@
package com.dfsek.terra.registry;
package com.dfsek.terra.registry.config;
import com.dfsek.terra.api.core.TerraPlugin;
import com.dfsek.terra.api.math.vector.Location;
@@ -14,6 +14,7 @@ import com.dfsek.terra.api.world.tree.fractal.trees.ShatteredTree;
import com.dfsek.terra.api.world.tree.fractal.trees.SmallShatteredPillar;
import com.dfsek.terra.api.world.tree.fractal.trees.SmallShatteredTree;
import com.dfsek.terra.api.world.tree.fractal.trees.SpruceTree;
import com.dfsek.terra.registry.TerraRegistry;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

View File

@@ -24,9 +24,10 @@ public class TerraWorld {
public TerraWorld(World w, ConfigPack c, TerraPlugin main) {
c.getBiomeRegistry().forEach(biome -> biome.getGenerator(w)); // Load all gens to cache
config = c;
profiler = new WorldProfiler(w);
this.provider = config.getTemplate().getProviderBuilder().build(w.getSeed());
this.provider = config.getBiomeProviderBuilder().build(w.getSeed());
this.world = w;
air = main.getWorldHandle().createBlockData("minecraft:air");
safe = true;

View File

@@ -1,160 +0,0 @@
package biome;
import com.dfsek.terra.api.math.ProbabilityCollection;
import com.dfsek.terra.api.math.noise.NoiseSampler;
import com.dfsek.terra.api.math.noise.samplers.FastNoiseLite;
import com.dfsek.terra.api.platform.world.Biome;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.world.biome.Generator;
import com.dfsek.terra.biome.TerraBiome;
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.dfsek.terra.biome.provider.BiomeProvider;
import com.dfsek.terra.biome.provider.StandardBiomeProvider;
import org.junit.jupiter.api.Test;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
public class BiomeTest {
@Test
public static void main(String... args) {
ProbabilityCollection<TerraBiome> oceanBiomes = new ProbabilityCollection<>();
ProbabilityCollection<TerraBiome> landBiomes = new ProbabilityCollection<>();
ProbabilityCollection<TerraBiome> beachBiomes = new ProbabilityCollection<>();
TestBiome ocean = new TestBiome(Color.BLUE, "OCEAN_TEMP");
TestBiome land = new TestBiome(Color.GREEN, "LAND_TEMP");
TestBiome beach = new TestBiome(Color.YELLOW, "BEACH");
beachBiomes.add(beach, 1);
ProbabilityCollection<TerraBiome> climate = new ProbabilityCollection<>();
climate.add(ocean, 1);
climate.add(land, 2);
oceanBiomes.add(new TestBiome(Color.BLUE, "OCEAN"), 10);
oceanBiomes.add(new TestBiome(Color.CYAN, "OCEAN"), 1);
landBiomes.add(new TestBiome(Color.GREEN, "LAND"), 8);
landBiomes.add(new TestBiome(Color.ORANGE, "LAND"), 5);
landBiomes.add(new TestBiome(Color.RED, "LAND"), 1);
landBiomes.add(new TestBiome(Color.GRAY, "LAND"), 1);
FastNoiseLite sourceSampler = new FastNoiseLite(123);
sourceSampler.setNoiseType(FastNoiseLite.NoiseType.WhiteNoise);
BiomeSource source = new RandomSource(climate, sourceSampler);
BiomeProvider provider = new StandardBiomeProvider.StandardBiomeProviderBuilder((seed) -> new BiomePipeline.BiomePipelineBuilder(2)
.addStage(s -> new MutatorStage(new ReplaceMutator("LAND_TEMP", landBiomes, whiteNoise(243))))
.addStage(s -> new ExpanderStage(new FractalExpander(whiteNoise(2))))
.addStage(s -> new MutatorStage(new ReplaceMutator("OCEAN_TEMP", oceanBiomes, whiteNoise(243))))
.addStage(s -> new ExpanderStage(new FractalExpander(whiteNoise(2))))
.addStage(s -> new ExpanderStage(new FractalExpander(whiteNoise(2))))
.addStage(s -> new MutatorStage(new SmoothMutator(whiteNoise(3))))
.addStage(s -> new ExpanderStage(new FractalExpander(whiteNoise(4))))
.addStage(s -> new MutatorStage(new SmoothMutator(whiteNoise(6))))
.addStage(s -> new ExpanderStage(new FractalExpander(whiteNoise(4))))
.addStage(s -> new ExpanderStage(new FractalExpander(whiteNoise(4))))
.addStage(s -> new MutatorStage(new BorderMutator("OCEAN", "LAND", whiteNoise(1234), beachBiomes)))
.addStage(s -> new ExpanderStage(new FractalExpander(whiteNoise(4))))
.addStage(s -> new MutatorStage(new SmoothMutator(whiteNoise(6))))
.addStage(s -> new MutatorStage(new SmoothMutator(whiteNoise(6))))
.build(source, seed), null).build(0);
int size = 1000;
BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
System.out.println(size);
long s = System.nanoTime();
for(int x = 0; x < size; x++) {
for(int z = 0; z < size; z++) {
image.setRGB(x, z, provider.getBiome(x, z).getColor());
}
}
long e = System.nanoTime();
double time = e - s;
time /= 1000000;
System.out.println(time + "ms for " + size + "x" + size);
JFrame frame = new JFrame("TerraBiome Viewer");
frame.setResizable(false);
frame.add(new JLabel(new ImageIcon(image)));
frame.pack();
System.out.println("Done");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private static NoiseSampler whiteNoise(int seed) {
FastNoiseLite noiseLite = new FastNoiseLite(seed);
noiseLite.setNoiseType(FastNoiseLite.NoiseType.WhiteNoise);
return noiseLite;
}
private final static class TestBiome implements TerraBiome {
private final Color color;
private final Set<String> tags;
private TestBiome(Color color, String... tags) {
this.color = color;
this.tags = Arrays.stream(tags).collect(Collectors.toSet());
}
@Override
public ProbabilityCollection<Biome> getVanillaBiomes() {
return null;
}
@Override
public Generator getGenerator(World w) {
return null;
}
@Override
public int getColor() {
return color.getRGB();
}
@Override
public Set<String> getTags() {
return tags;
}
@Override
public String getID() {
return null;
}
}
}

View File

@@ -24,13 +24,18 @@ import com.dfsek.terra.config.PluginConfig;
import com.dfsek.terra.config.fileloaders.FolderLoader;
import com.dfsek.terra.config.lang.Language;
import com.dfsek.terra.config.loaders.ProbabilityCollectionLoader;
import com.dfsek.terra.config.loaders.config.BufferedImageLoader;
import com.dfsek.terra.config.loaders.config.biome.BiomeProviderBuilderLoader;
import com.dfsek.terra.config.loaders.config.biome.templates.source.BiomePipelineTemplate;
import com.dfsek.terra.config.loaders.config.biome.templates.source.ImageProviderTemplate;
import com.dfsek.terra.config.loaders.config.biome.templates.source.SingleBiomeProviderTemplate;
import com.dfsek.terra.config.loaders.config.sampler.NoiseSamplerBuilderLoader;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.config.templates.AbstractableTemplate;
import com.dfsek.terra.debug.DebugLogger;
import com.dfsek.terra.registry.BiomeRegistry;
import com.dfsek.terra.registry.ConfigRegistry;
import com.dfsek.terra.registry.config.BiomeRegistry;
import com.dfsek.terra.registry.config.NormalizerRegistry;
import com.dfsek.terra.world.TerraWorld;
import javax.swing.*;
@@ -141,12 +146,16 @@ public class DistributionTest {
BiomeProviderTemplate template = new BiomeProviderTemplate();
ConfigLoader pipeLoader = new ConfigLoader()
.registerLoader(BiomeProvider.BiomeProviderBuilder.class, new BiomeProviderBuilderLoader(MAIN, biomeRegistry, folderLoader))
.registerLoader(BiomeProvider.BiomeProviderBuilder.class, new BiomeProviderBuilderLoader())
.registerLoader(ProbabilityCollection.class, new ProbabilityCollectionLoader())
.registerLoader(TerraBiome.class, biomeRegistry);
.registerLoader(TerraBiome.class, biomeRegistry)
.registerLoader(BufferedImage.class, new BufferedImageLoader(folderLoader))
.registerLoader(SingleBiomeProviderTemplate.class, () -> new SingleBiomeProviderTemplate(biomeRegistry))
.registerLoader(BiomePipelineTemplate.class, () -> new BiomePipelineTemplate(biomeRegistry, MAIN))
.registerLoader(ImageProviderTemplate.class, () -> new ImageProviderTemplate(biomeRegistry));
new GenericLoaders(null).register(pipeLoader);
pipeLoader.registerLoader(NoiseSeeded.class, new NoiseSamplerBuilderLoader());
pipeLoader.registerLoader(NoiseSeeded.class, new NoiseSamplerBuilderLoader(new NormalizerRegistry()));
pipeLoader.load(template, folderLoader.get("pack.yml"));
return template.getBiomeProviderBuilder().build(seed);

View File

@@ -48,7 +48,7 @@ public class ImageTest {
};
folderLoader.open("biomes", ".yml").then(inputStreams -> ConfigPack.buildAll((template, main) -> template, biomeRegistry, loader.load(inputStreams, TestBiome::new), null));
return new ImageBiomeProvider(biomeRegistry, ImageIO.read(ImageTest.class.getResourceAsStream("/map.jpg")), 1);
return new ImageBiomeProvider(biomeRegistry, ImageIO.read(ImageTest.class.getResourceAsStream("/map.jpg")), 1, ImageBiomeProvider.Align.CENTER);
}
@Test

View File

@@ -10,6 +10,7 @@ import com.dfsek.terra.config.fileloaders.FolderLoader;
import com.dfsek.terra.config.loaders.ProbabilityCollectionLoader;
import com.dfsek.terra.config.loaders.config.BufferedImageLoader;
import com.dfsek.terra.config.loaders.config.sampler.NoiseSamplerBuilderLoader;
import com.dfsek.terra.registry.config.NormalizerRegistry;
import org.apache.commons.io.FileUtils;
import javax.swing.*;
@@ -96,7 +97,7 @@ public class NoiseTool {
FolderLoader folderLoader = new FolderLoader(Paths.get("./"));
ConfigLoader loader = new ConfigLoader();
loader.registerLoader(NoiseSeeded.class, new NoiseSamplerBuilderLoader())
loader.registerLoader(NoiseSeeded.class, new NoiseSamplerBuilderLoader(new NormalizerRegistry()))
.registerLoader(BufferedImage.class, new BufferedImageLoader(folderLoader))
.registerLoader(ProbabilityCollection.class, new ProbabilityCollectionLoader());

View File

@@ -33,7 +33,7 @@ public class TerraCommand extends Command {
@Override
public String getName() {
return "com/dfsek/terra";
return "terra";
}
@Override

View File

@@ -9,13 +9,14 @@ import com.dfsek.terra.api.util.FastRandom;
import com.dfsek.terra.api.world.tree.Tree;
import com.dfsek.terra.bukkit.world.BukkitAdapter;
import com.dfsek.terra.config.pack.ConfigPack;
import com.dfsek.terra.registry.TreeRegistry;
import com.dfsek.terra.registry.config.TreeRegistry;
import com.dfsek.terra.world.TerraWorld;
import org.bukkit.Material;
import org.bukkit.TreeType;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.world.StructureGrowEvent;
@@ -40,7 +41,7 @@ public class CommonListener implements Listener {
.add(TreeType.SWAMP, "SWAMP_OAK"))
.addTransform(TreeType::toString).build();
@EventHandler
@EventHandler(priority = EventPriority.HIGHEST)
public void onSaplingGrow(StructureGrowEvent e) {
if(e.isCancelled()) return;
World bukkit = BukkitAdapter.adapt(e.getWorld());

View File

@@ -34,7 +34,7 @@ public class TerraBiomeSource extends BiomeSource {
super(biomes.stream().collect(Collectors.toList()));
this.biomeRegistry = biomes;
this.seed = seed;
this.grid = pack.getTemplate().getProviderBuilder().build(seed);
this.grid = pack.getBiomeProviderBuilder().build(seed);
this.pack = pack;
}