mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-02-16 10:30:42 +00:00
implement UserDefinedFunction
This commit is contained in:
@@ -1,17 +1,20 @@
|
||||
package com.dfsek.terra.api.math.noise.samplers;
|
||||
|
||||
import com.dfsek.terra.api.math.noise.NoiseSampler;
|
||||
import com.dfsek.terra.api.math.parsii.RandomFunction;
|
||||
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
|
||||
@@ -22,7 +25,7 @@ public class ExpressionSampler implements NoiseSampler {
|
||||
private final Variable y;
|
||||
private final Variable z;
|
||||
|
||||
public ExpressionSampler(String equation, Scope parent, long seed, Map<String, NoiseSeeded> functions) throws ParseException {
|
||||
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);
|
||||
|
||||
@@ -41,7 +44,15 @@ public class ExpressionSampler implements NoiseSampler {
|
||||
}
|
||||
});
|
||||
|
||||
parser.registerFunction("rand", new RandomFunction());
|
||||
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));
|
||||
}
|
||||
|
||||
this.expression = parser.parse(equation, scope);
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.dfsek.terra.api.math.parsii;
|
||||
|
||||
import com.dfsek.terra.api.util.FastRandom;
|
||||
import parsii.eval.Expression;
|
||||
import parsii.eval.Function;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Provides access to a PRNG ({@link com.dfsek.terra.api.util.FastRandom})
|
||||
* <p>
|
||||
* Takes 1 argument, which sets the seed
|
||||
*/
|
||||
public class RandomFunction implements Function {
|
||||
@Override
|
||||
public int getNumberOfArguments() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double eval(List<Expression> list) {
|
||||
long seed = (long) list.get(0).evaluate();
|
||||
return new FastRandom(seed).nextDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNaturalFunction() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.dfsek.terra.api.math.parsii.defined;
|
||||
|
||||
import com.dfsek.terra.api.util.seeded.SeededBuilder;
|
||||
|
||||
public class DefinedFunctionTemplate implements SeededBuilder<UserDefinedFunction> {
|
||||
@Override
|
||||
public UserDefinedFunction apply(Long aLong) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.dfsek.terra.api.math.parsii.defined;
|
||||
|
||||
import parsii.eval.Expression;
|
||||
import parsii.eval.Function;
|
||||
import parsii.eval.Variable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class UserDefinedFunction implements Function {
|
||||
private final Expression expression;
|
||||
private final List<Variable> variables;
|
||||
|
||||
public UserDefinedFunction(Expression expression, List<Variable> variables) {
|
||||
this.expression = expression;
|
||||
this.variables = variables;
|
||||
}
|
||||
|
||||
@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() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import com.dfsek.terra.config.loaders.config.biome.templates.stage.mutator.Borde
|
||||
import com.dfsek.terra.config.loaders.config.biome.templates.stage.mutator.ReplaceListMutatorTemplate;
|
||||
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;
|
||||
@@ -77,6 +78,7 @@ public class GenericLoaders implements LoaderRegistrar {
|
||||
.registerLoader(ReplaceListMutatorTemplate.class, ReplaceListMutatorTemplate::new)
|
||||
.registerLoader(BorderMutatorTemplate.class, BorderMutatorTemplate::new)
|
||||
.registerLoader(BorderListMutatorTemplate.class, BorderListMutatorTemplate::new)
|
||||
.registerLoader(FunctionTemplate.class, FunctionTemplate::new)
|
||||
.registerLoader(ImageSampler.Channel.class, (t, object, cf) -> ImageSampler.Channel.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))
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.dfsek.terra.api.math.noise.samplers.ConstantSampler;
|
||||
import com.dfsek.terra.api.math.noise.samplers.ExpressionSampler;
|
||||
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;
|
||||
@@ -26,6 +27,8 @@ public class GeneratorBuilder {
|
||||
|
||||
private Map<String, NoiseSeeded> noiseBuilderMap;
|
||||
|
||||
private Map<String, FunctionTemplate> functionTemplateMap;
|
||||
|
||||
private PaletteHolder palettes;
|
||||
|
||||
private PaletteHolder slantPalettes;
|
||||
@@ -51,9 +54,9 @@ public class GeneratorBuilder {
|
||||
NoiseSampler elevation;
|
||||
NoiseSampler carving;
|
||||
try {
|
||||
noise = new ExpressionSampler(noiseEquation, varScope, seed, noiseBuilderMap);
|
||||
elevation = elevationEquation == null ? new ConstantSampler(0) : new ExpressionSampler(elevationEquation, varScope, seed, noiseBuilderMap);
|
||||
carving = new ExpressionSampler(carvingEquation, varScope, seed, noiseBuilderMap);
|
||||
noise = new ExpressionSampler(noiseEquation, varScope, seed, noiseBuilderMap, functionTemplateMap);
|
||||
elevation = elevationEquation == null ? new ConstantSampler(0) : new ExpressionSampler(elevationEquation, varScope, seed, noiseBuilderMap, functionTemplateMap);
|
||||
carving = new ExpressionSampler(carvingEquation, varScope, seed, noiseBuilderMap, functionTemplateMap);
|
||||
} catch(ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -66,6 +69,10 @@ public class GeneratorBuilder {
|
||||
this.blendWeight = blendWeight;
|
||||
}
|
||||
|
||||
public void setFunctionTemplateMap(Map<String, FunctionTemplate> functionTemplateMap) {
|
||||
this.functionTemplateMap = functionTemplateMap;
|
||||
}
|
||||
|
||||
public void setBlendStep(int blendStep) {
|
||||
this.blendStep = blendStep;
|
||||
}
|
||||
|
||||
@@ -4,10 +4,14 @@ import com.dfsek.terra.api.core.TerraPlugin;
|
||||
import com.dfsek.terra.biome.TerraBiome;
|
||||
import com.dfsek.terra.biome.UserDefinedBiome;
|
||||
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.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class BiomeFactory implements TerraFactory<BiomeTemplate, TerraBiome> {
|
||||
private final ConfigPack pack;
|
||||
|
||||
@@ -21,7 +25,12 @@ public class BiomeFactory implements TerraFactory<BiomeTemplate, TerraBiome> {
|
||||
generatorBuilder.setElevationEquation(template.getElevationEquation());
|
||||
generatorBuilder.setNoiseEquation(template.getNoiseEquation());
|
||||
generatorBuilder.setCarvingEquation(template.getCarvingEquation());
|
||||
generatorBuilder.setNoiseBuilderMap(template.getPack().getTemplate().getNoiseBuilderMap());
|
||||
generatorBuilder.setNoiseBuilderMap(pack.getTemplate().getNoiseBuilderMap());
|
||||
|
||||
Map<String, FunctionTemplate> functions = new HashMap<>(pack.getTemplate().getFunctions());
|
||||
functions.putAll(template.getFunctions());
|
||||
generatorBuilder.setFunctionTemplateMap(functions);
|
||||
|
||||
generatorBuilder.setPalettes(template.getPalette());
|
||||
generatorBuilder.setSlantPalettes(template.getSlantPalette());
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.dfsek.terra.config.loaders.config.function;
|
||||
|
||||
import com.dfsek.tectonic.annotations.Value;
|
||||
import com.dfsek.tectonic.loading.object.ObjectTemplate;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class FunctionTemplate implements ObjectTemplate<FunctionTemplate> {
|
||||
@Value("arguments")
|
||||
private List<String> args;
|
||||
|
||||
@Value("function")
|
||||
private String function;
|
||||
|
||||
public List<String> getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
public String getFunction() {
|
||||
return function;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionTemplate get() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ 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;
|
||||
import java.util.Map;
|
||||
@@ -21,6 +22,10 @@ public class ConfigPackTemplate implements ConfigTemplate {
|
||||
@Default
|
||||
private Map<String, Double> variables = new HashMap<>();
|
||||
|
||||
@Value("functions")
|
||||
@Default
|
||||
private Map<String, FunctionTemplate> functions = new HashMap<>();
|
||||
|
||||
@Value("structures.locatable")
|
||||
@Default
|
||||
private Map<String, String> locatable = new HashMap<>();
|
||||
@@ -80,6 +85,10 @@ public class ConfigPackTemplate implements ConfigTemplate {
|
||||
return providerBuilder;
|
||||
}
|
||||
|
||||
public Map<String, FunctionTemplate> getFunctions() {
|
||||
return functions;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ 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.math.parsii.BlankFunction;
|
||||
import com.dfsek.terra.api.math.parsii.defined.UserDefinedFunction;
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
import com.dfsek.terra.api.platform.block.MaterialData;
|
||||
import com.dfsek.terra.api.platform.world.Biome;
|
||||
@@ -18,6 +19,7 @@ import com.dfsek.terra.api.util.seeded.NoiseSeeded;
|
||||
import com.dfsek.terra.api.world.palette.Palette;
|
||||
import com.dfsek.terra.api.world.palette.SinglePalette;
|
||||
import com.dfsek.terra.api.world.palette.holder.PaletteHolder;
|
||||
import com.dfsek.terra.config.loaders.config.function.FunctionTemplate;
|
||||
import com.dfsek.terra.config.loaders.config.sampler.templates.FastNoiseTemplate;
|
||||
import com.dfsek.terra.config.pack.ConfigPack;
|
||||
import com.dfsek.terra.world.population.items.TerraStructure;
|
||||
@@ -26,12 +28,14 @@ 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.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@SuppressWarnings({"FieldMayBeFinal", "unused"})
|
||||
public class BiomeTemplate extends AbstractableTemplate implements ValidatedConfigTemplate {
|
||||
@@ -50,6 +54,11 @@ public class BiomeTemplate extends AbstractableTemplate implements ValidatedConf
|
||||
@Default
|
||||
private Map<String, Double> variables = new HashMap<>();
|
||||
|
||||
@Value("functions")
|
||||
@Default
|
||||
@Abstractable
|
||||
private Map<String, FunctionTemplate> functions = new HashMap<>();
|
||||
|
||||
@Value("carving.equation")
|
||||
@Abstractable
|
||||
@Default
|
||||
@@ -180,6 +189,10 @@ public class BiomeTemplate extends AbstractableTemplate implements ValidatedConf
|
||||
return tags;
|
||||
}
|
||||
|
||||
public Map<String, FunctionTemplate> getFunctions() {
|
||||
return functions;
|
||||
}
|
||||
|
||||
public double getBlendWeight() {
|
||||
return blendWeight;
|
||||
}
|
||||
@@ -316,7 +329,7 @@ public class BiomeTemplate extends AbstractableTemplate implements ValidatedConf
|
||||
|
||||
@Override
|
||||
public boolean validate() throws ValidationException {
|
||||
color |= 0x1fe00000; // Alpha adjustment
|
||||
color |= 0xff000000; // Alpha adjustment
|
||||
Parser tester = new Parser();
|
||||
Scope testScope = new Scope().withParent(pack.getVarScope());
|
||||
|
||||
@@ -329,6 +342,22 @@ public class BiomeTemplate extends AbstractableTemplate implements ValidatedConf
|
||||
|
||||
pack.getTemplate().getNoiseBuilderMap().forEach((id, builder) -> tester.registerFunction(id, new BlankFunction(builder.getDimensions()))); // Register dummy functions
|
||||
|
||||
Map<String, FunctionTemplate> testFunctions = new HashMap<>(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));
|
||||
} catch(ParseException e) {
|
||||
throw new ValidationException("Invalid function: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
tester.parse(noiseEquation, testScope);
|
||||
} catch(ParseException e) {
|
||||
|
||||
Reference in New Issue
Block a user