move more things to new modules

This commit is contained in:
dfsek
2021-07-02 07:44:30 -07:00
parent 215a1e0e86
commit 62520af8e7
88 changed files with 300 additions and 313 deletions
@@ -0,0 +1,19 @@
package com.dfsek.terra.addons.biome;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.config.ConfigFactory;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.util.seeded.BiomeBuilder;
public class BiomeFactory implements ConfigFactory<BiomeTemplate, BiomeBuilder> {
private final ConfigPack pack;
public BiomeFactory(ConfigPack pack) {
this.pack = pack;
}
@Override
public BiomeBuilder build(BiomeTemplate template, TerraPlugin main) {
return new UserDefinedBiomeBuilder(template, pack);
}
}
@@ -0,0 +1,338 @@
package com.dfsek.terra.addons.biome;
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;
import com.dfsek.tectonic.config.ValidatedConfigTemplate;
import com.dfsek.tectonic.exception.ValidationException;
import com.dfsek.terra.addons.biome.holder.PaletteHolder;
import com.dfsek.terra.addons.biome.slant.SlantHolder;
import com.dfsek.terra.api.TerraPlugin;
import com.dfsek.terra.api.block.BlockType;
import com.dfsek.terra.api.config.AbstractableTemplate;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.math.paralithic.BlankFunction;
import com.dfsek.terra.api.structure.ConfiguredStructure;
import com.dfsek.terra.api.util.GlueList;
import com.dfsek.terra.api.util.ProbabilityCollection;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.generator.Palette;
import com.dfsek.terra.carving.UserDefinedCarver;
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 java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@SuppressWarnings({"FieldMayBeFinal", "unused"})
public class BiomeTemplate implements AbstractableTemplate, ValidatedConfigTemplate {
private final ConfigPack pack;
@Value("id")
private String id;
@Value("extends")
@Default
private List<String> extended = Collections.emptyList();
@Value("variables")
@Abstractable
@Default
private Map<String, Double> variables = new HashMap<>();
@Value("beta.carving.equation")
@Abstractable
@Default
private NoiseSeeded carvingEquation = NoiseSeeded.zero(2);
@Value("palette")
@Abstractable
private PaletteHolder palette;
@Value("slant")
@Abstractable
@Default
private SlantHolder slant = null;
@Value("vanilla")
@Abstractable
private ProbabilityCollection<Biome> vanilla;
@Value("biome-noise")
@Default
@Abstractable
private NoiseSeeded biomeNoise = NoiseSeeded.zero(2);
@Value("blend.distance")
@Abstractable
@Default
private int blendDistance = 3;
@Value("blend.weight")
@Abstractable
@Default
private double blendWeight = 1;
@Value("blend.step")
@Abstractable
@Default
private int blendStep = 4;
@Value("structures")
@Abstractable
@Default
private List<ConfiguredStructure> structures = new ArrayList<>();
@Value("noise")
@Abstractable
private NoiseSeeded noiseEquation;
@Value("ores")
@Abstractable
@Default
private OreHolder oreHolder = new OreHolder();
@Value("ocean.level")
@Abstractable
@Default
private int seaLevel = 62;
@Value("ocean.palette")
@Abstractable
private Palette oceanPalette;
@Value("elevation.equation")
@Default
@Abstractable
private String elevationEquation = null;
@Value("elevation.weight")
@Default
@Abstractable
private double elevationWeight = 1;
@Value("flora")
@Abstractable
@Default
private List<FloraLayer> flora = new GlueList<>();
@Value("trees")
@Abstractable
@Default
private List<TreeLayer> trees = new GlueList<>();
@Value("slabs.enable")
@Abstractable
@Default
private boolean doSlabs = false;
@Value("slabs.threshold")
@Abstractable
@Default
private double slabThreshold = 0.0075D;
@Value("slabs.palettes")
@Abstractable
@Default
private Map<BlockType, Palette> slabPalettes;
@Value("slabs.stair-palettes")
@Abstractable
@Default
private Map<BlockType, Palette> stairPalettes;
@Value("interpolate-elevation")
@Abstractable
@Default
private boolean interpolateElevation = true;
@Value("color")
@Default
private int color = 0;
@Value("tags")
@Default
@Abstractable
private Set<String> tags = new HashSet<>();
@Value("carving")
@Abstractable
@Default
private Map<UserDefinedCarver, Integer> carvers = new HashMap<>();
@Value("colors")
@Abstractable
@Default
private Map<String, Integer> colors = new HashMap<>(); // Plain ol' map, so platforms can decide what to do with colors (if anything).
public List<String> getExtended() {
return extended;
}
public Set<String> getTags() {
return tags;
}
public Map<String, Integer> getColors() {
return colors;
}
public Map<UserDefinedCarver, Integer> getCarvers() {
return carvers;
}
public double getBlendWeight() {
return blendWeight;
}
public int getColor() {
return color;
}
public int getBlendDistance() {
return blendDistance;
}
public boolean interpolateElevation() {
return interpolateElevation;
}
public SlantHolder getSlant() {
return slant;
}
public double getSlabThreshold() {
return slabThreshold;
}
public List<FloraLayer> getFlora() {
return flora;
}
public boolean doSlabs() {
return doSlabs;
}
public BiomeTemplate(ConfigPack pack, TerraPlugin main) {
this.pack = pack;
}
public Map<BlockType, Palette> getSlabPalettes() {
return slabPalettes;
}
public Map<BlockType, Palette> getStairPalettes() {
return stairPalettes;
}
public NoiseSeeded getBiomeNoise() {
return biomeNoise;
}
public String getElevationEquation() {
return elevationEquation;
}
public String getCarvingEquation() {
return carvingEquation;
}
public ConfigPack getPack() {
return pack;
}
public int getSeaLevel() {
return seaLevel;
}
public Palette getOceanPalette() {
return oceanPalette;
}
public String getID() {
return id;
}
public PaletteHolder getPalette() {
return palette;
}
public List<TreeLayer> getTrees() {
return trees;
}
public ProbabilityCollection<Biome> getVanilla() {
return vanilla;
}
public List<ConfiguredStructure> getStructures() {
return structures;
}
public NoiseSeeded getNoiseEquation() {
return noiseEquation;
}
public OreHolder getOreHolder() {
return oreHolder;
}
public double getElevationWeight() {
return elevationWeight;
}
public int getBlendStep() {
return blendStep;
}
public Map<String, Double> getVariables() {
return variables;
}
@Override
public boolean validate() throws ValidationException {
color |= 0xff000000; // Alpha adjustment
Parser tester = new Parser();
Scope testScope = new Scope().withParent(pack.getVarScope());
variables.forEach(testScope::create);
testScope.addInvocationVariable("x");
testScope.addInvocationVariable("y");
testScope.addInvocationVariable("z");
pack.getTemplate().getNoiseBuilderMap().forEach((id, builder) -> tester.registerFunction(id, new BlankFunction(builder.getDimensions()))); // Register dummy functions
try {
tester.parse(noiseEquation, testScope);
} catch(ParseException e) {
throw new ValidationException("Invalid noise equation: ", e);
}
try {
tester.parse(carvingEquation, testScope);
} catch(ParseException e) {
throw new ValidationException("Invalid carving equation: ", e);
}
try {
if(elevationEquation != null) tester.parse(elevationEquation, testScope);
} catch(ParseException e) {
throw new ValidationException("Invalid elevation equation: ", e);
}
return true;
}
}
@@ -0,0 +1,73 @@
package com.dfsek.terra.addons.biome;
import com.dfsek.terra.api.util.ProbabilityCollection;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.Generator;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.world.generation.WorldGenerator;
import java.util.Set;
/**
* Class representing a config-defined biome
*/
public class UserDefinedBiome implements TerraBiome {
private final WorldGenerator gen;
private final ProbabilityCollection<Biome> vanilla;
private final String id;
private final BiomeTemplate config;
private final int color;
private final Set<String> tags;
public UserDefinedBiome(ProbabilityCollection<Biome> vanilla, WorldGenerator gen, BiomeTemplate config) {
this.vanilla = vanilla;
this.gen = gen;
this.id = config.getID();
this.config = config;
this.color = config.getColor();
this.tags = config.getTags();
tags.add("BIOME:" + id);
}
/**
* Gets the Vanilla biomes to represent the custom biome.
*
* @return Collection of biomes to represent the custom biome.
*/
@Override
public ProbabilityCollection<Biome> getVanillaBiomes() {
return vanilla;
}
@Override
public String getID() {
return id;
}
public BiomeTemplate getConfig() {
return config;
}
@Override
public Generator getGenerator(World w) {
return gen;
}
@Override
public int getColor() {
return color;
}
@Override
public Set<String> getTags() {
return tags;
}
@Override
public String toString() {
return "{BIOME:" + getID() + "}";
}
}
@@ -0,0 +1,68 @@
package com.dfsek.terra.addons.biome;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.ProbabilityCollection;
import com.dfsek.terra.api.util.seeded.BiomeBuilder;
import com.dfsek.terra.api.util.seeded.NoiseSeeded;
import com.dfsek.terra.api.world.biome.Biome;
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
import com.dfsek.terra.config.loaders.config.function.FunctionTemplate;
import com.dfsek.terra.config.pack.ConfigPackImpl;
import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.noise.samplers.ExpressionSampler;
import com.dfsek.terra.world.generation.WorldGenerator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class UserDefinedBiomeBuilder implements BiomeBuilder {
private final BiomeTemplate template;
private final ConfigPack pack;
private final Map<Long, UserDefinedBiome> biomeMap = new ConcurrentHashMap<>();
public UserDefinedBiomeBuilder(BiomeTemplate template, ConfigPack pack) {
this.template = template;
this.pack = pack;
}
@Override
public UserDefinedBiome apply(Long seed) {
synchronized(biomeMap) {
return biomeMap.computeIfAbsent(seed,
s -> {
NoiseSampler noise;
NoiseSampler elevation;
NoiseSampler carving;
Scope varScope = new Scope().withParent(pack.getVarScope());
template.getVariables().forEach(varScope::create);
Map<String, NoiseSeeded> noiseBuilderMap = pack.getTemplate().getNoiseBuilderMap();
try {
noise = new ExpressionSampler(template.getNoiseEquation(), varScope, seed, noiseBuilderMap);
elevation = template.getElevationEquation() == null ? NoiseSampler.zero() : new ExpressionSampler(template.getElevationEquation(), varScope, seed, noiseBuilderMap);
carving = new ExpressionSampler(template.getCarvingEquation(), varScope, seed, noiseBuilderMap);
} catch(ParseException e) {
throw new RuntimeException(e);
}
WorldGenerator generator = new WorldGenerator(template.getPalette(), template.getSlant(), noise, elevation, carving, template.getBiomeNoise().apply(seed), template.getElevationWeight(),
template.getBlendDistance(), template.getBlendStep(), template.getBlendWeight());
return new UserDefinedBiome(template.getVanilla(), generator, template);
}
);
}
}
@Override
public ProbabilityCollection<Biome> getVanillaBiomes() {
return template.getVanilla();
}
}
@@ -0,0 +1,88 @@
package com.dfsek.terra.addons.biome;
import com.dfsek.terra.addons.biome.holder.PaletteHolder;
import com.dfsek.terra.addons.biome.slant.SlantHolder;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.world.biome.Generator;
import com.dfsek.terra.api.world.generator.Palette;
public class WorldGenerator implements Generator {
@SuppressWarnings({"unchecked", "rawtypes", "RedundantSuppression"})
private final PaletteHolder palettes;
@SuppressWarnings({"unchecked", "rawtypes", "RedundantSuppression"})
private final SlantHolder slantPalettes;
private final NoiseSampler noise;
private final NoiseSampler elevation;
private final NoiseSampler carving;
private final NoiseSampler biomeNoise;
private final double elevationWeight;
private final int blendDistance;
private final int blendStep;
private final double blendWeight;
public WorldGenerator(PaletteHolder palettes, SlantHolder slantPalettes, NoiseSampler noise, NoiseSampler elevation, NoiseSampler carving, NoiseSampler biomeNoise, double elevationWeight, int blendDistance, int blendStep, double blendWeight) {
this.palettes = palettes;
this.slantPalettes = slantPalettes;
this.noise = noise;
this.elevation = elevation;
this.carving = carving;
this.biomeNoise = biomeNoise;
this.elevationWeight = elevationWeight;
this.blendDistance = blendDistance;
this.blendStep = blendStep;
this.blendWeight = blendWeight;
}
@Override
public NoiseSampler getBaseSampler() {
return noise;
}
@Override
public NoiseSampler getElevationSampler() {
return elevation;
}
@Override
public NoiseSampler getCarver() {
return carving;
}
@Override
public int getBlendDistance() {
return blendDistance;
}
@Override
public double getWeight() {
return blendWeight;
}
/**
* Gets the BlockPalette to generate the biome with.
*
* @return BlockPalette - The biome's palette.
*/
@Override
public Palette getPalette(int y) {
return palettes.getPalette(y);
}
@Override
public NoiseSampler getBiomeNoise() {
return biomeNoise;
}
@Override
public double getElevationWeight() {
return elevationWeight;
}
@Override
public int getBlendStep() {
return blendStep;
}
}
@@ -0,0 +1,22 @@
package com.dfsek.terra.addons.biome.holder;
import com.dfsek.terra.api.world.generator.Palette;
public class PaletteHolder {
private final Palette[] palettes;
private final int offset;
protected PaletteHolder(Palette[] palettes, int offset) {
this.palettes = palettes;
this.offset = offset;
}
public Palette getPalette(int y) {
int index = y + offset;
return index >= 0
? index < palettes.length
? palettes[index]
: palettes[palettes.length - 1]
: palettes[0];
}
}
@@ -0,0 +1,37 @@
package com.dfsek.terra.addons.biome.holder;
import com.dfsek.terra.api.world.generator.Palette;
import net.jafama.FastMath;
import java.util.Map;
import java.util.TreeMap;
public class PaletteHolderBuilder {
private final TreeMap<Integer, Palette> paletteMap = new TreeMap<>();
public PaletteHolderBuilder add(int y, Palette palette) {
paletteMap.put(y, palette);
return this;
}
@SuppressWarnings({"unchecked", "rawtypes", "RedundantSuppression"})
public PaletteHolder build() {
int min = FastMath.min(paletteMap.keySet().stream().min(Integer::compareTo).orElse(0), 0);
int max = FastMath.max(paletteMap.keySet().stream().max(Integer::compareTo).orElse(255), 255);
Palette[] palettes = new Palette[paletteMap.lastKey() + 1 - min];
for(int y = min; y <= FastMath.max(paletteMap.lastKey(), max); y++) {
Palette d = null;
for(Map.Entry<Integer, Palette> e : paletteMap.entrySet()) {
if(e.getKey() >= y) {
d = e.getValue();
break;
}
}
if(d == null) throw new IllegalArgumentException("No palette for Y=" + y);
palettes[y - min] = d;
}
return new PaletteHolder(palettes, -min);
}
}
@@ -0,0 +1,31 @@
package com.dfsek.terra.addons.biome.holder;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.noise.NoiseSampler;
import com.dfsek.terra.api.util.ProbabilityCollection;
import org.jetbrains.annotations.NotNull;
public class PaletteLayerHolder {
private final ProbabilityCollection<BlockState> layer;
private final NoiseSampler sampler;
private final int size;
public PaletteLayerHolder(@NotNull ProbabilityCollection<BlockState> layer, NoiseSampler sampler, int size) {
this.layer = layer;
this.sampler = sampler;
this.size = size;
}
@NotNull
public ProbabilityCollection<BlockState> getLayer() {
return layer;
}
public int getSize() {
return size;
}
public NoiseSampler getSampler() {
return sampler;
}
}
@@ -0,0 +1,23 @@
package com.dfsek.terra.addons.biome.slant;
import com.dfsek.terra.addons.biome.holder.PaletteHolder;
import java.util.TreeMap;
public class SlantHolder {
private final TreeMap<Double, PaletteHolder> layers;
private final double minSlope;
public SlantHolder(TreeMap<Double, PaletteHolder> layers, double minSlope) {
this.layers = layers;
this.minSlope = minSlope;
}
public PaletteHolder getPalette(double slope) {
return layers.floorEntry(slope).getValue();
}
public double getMinSlope() {
return minSlope;
}
}