mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-06-14 04:41:13 +00:00
Look ma, no Bukkit API in the core package
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
package com.dfsek.terra.generation;
|
||||
|
||||
import com.dfsek.terra.api.gaea.generation.GenerationPhase;
|
||||
import com.dfsek.terra.api.gaea.math.Interpolator;
|
||||
import com.dfsek.terra.biome.grid.master.TerraBiomeGrid;
|
||||
import com.dfsek.terra.generation.config.WorldGenerator;
|
||||
|
||||
public class ElevationInterpolator {
|
||||
private final WorldGenerator[][] gens = new WorldGenerator[10][10];
|
||||
private final double[][] values = new double[18][18];
|
||||
private final int xOrigin;
|
||||
private final int zOrigin;
|
||||
private final TerraBiomeGrid grid;
|
||||
|
||||
public ElevationInterpolator(int chunkX, int chunkZ, TerraBiomeGrid grid) {
|
||||
this.xOrigin = chunkX << 4;
|
||||
this.zOrigin = chunkZ << 4;
|
||||
this.grid = grid;
|
||||
|
||||
for(int x = -2; x < 8; x++) {
|
||||
for(int z = -2; z < 8; z++) {
|
||||
gens[x + 2][z + 2] = (WorldGenerator) grid.getBiome(xOrigin + (x << 2), zOrigin + (z << 2), GenerationPhase.BASE).getGenerator();
|
||||
}
|
||||
}
|
||||
|
||||
for(byte x = -1; x <= 16; x++) {
|
||||
for(byte z = -1; z <= 16; z++) {
|
||||
WorldGenerator generator = getGenerator(x, z);
|
||||
if(compareGens((x / 4), (z / 4)) && generator.interpolateElevation()) {
|
||||
Interpolator interpolator = new Interpolator(biomeAvg(x / 4, z / 4),
|
||||
biomeAvg((x / 4) + 1, z / 4),
|
||||
biomeAvg(x / 4, (z / 4) + 1),
|
||||
biomeAvg((x / 4) + 1, (z / 4) + 1),
|
||||
Interpolator.Type.LINEAR);
|
||||
values[x + 1][z + 1] = interpolator.bilerp((double) (x % 4) / 4, (double) (z % 4) / 4);
|
||||
} else values[x + 1][z + 1] = elevate(generator, xOrigin + x, zOrigin + z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private WorldGenerator getGenerator(int x, int z) {
|
||||
return (WorldGenerator) grid.getBiome(xOrigin + x, zOrigin + z, GenerationPhase.BASE).getGenerator();
|
||||
}
|
||||
|
||||
private WorldGenerator getStoredGen(int x, int z) {
|
||||
return gens[x + 2][z + 2];
|
||||
}
|
||||
|
||||
private boolean compareGens(int x, int z) {
|
||||
WorldGenerator comp = getStoredGen(x, z);
|
||||
|
||||
for(int xi = x - 2; xi <= x + 2; xi++) {
|
||||
for(int zi = z - 2; zi <= z + 2; zi++) {
|
||||
if(!comp.equals(getStoredGen(xi, zi))) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private double biomeAvg(int x, int z) {
|
||||
return (elevate(getStoredGen(x + 1, z), (x << 2) + 4 + xOrigin, (z << 2) + zOrigin)
|
||||
+ elevate(getStoredGen(x - 1, z), (x << 2) - 4 + xOrigin, (z << 2) + zOrigin)
|
||||
+ elevate(getStoredGen(x, z + 1), (x << 2) + xOrigin, (z << 2) + 4 + zOrigin)
|
||||
+ elevate(getStoredGen(x, z - 1), (x << 2) + xOrigin, (z << 2) - 4 + zOrigin)
|
||||
+ elevate(getStoredGen(x, z), (x << 2) + xOrigin, (z << 2) + zOrigin)
|
||||
+ elevate(getStoredGen(x - 1, z - 1), (x << 2) + xOrigin, (z << 2) + zOrigin)
|
||||
+ elevate(getStoredGen(x - 1, z + 1), (x << 2) + xOrigin, (z << 2) + zOrigin)
|
||||
+ elevate(getStoredGen(x + 1, z - 1), (x << 2) + xOrigin, (z << 2) + zOrigin)
|
||||
+ elevate(getStoredGen(x + 1, z + 1), (x << 2) + xOrigin, (z << 2) + zOrigin)) / 9D;
|
||||
}
|
||||
|
||||
private double elevate(WorldGenerator g, int x, int z) {
|
||||
return g.getElevation(x, z);
|
||||
}
|
||||
|
||||
public double getElevation(int x, int z) {
|
||||
return values[x + 1][z + 1];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.dfsek.terra.generation;
|
||||
|
||||
import com.dfsek.terra.api.gaea.math.ChunkInterpolator3;
|
||||
import net.jafama.FastMath;
|
||||
|
||||
public class Sampler {
|
||||
private final ChunkInterpolator3 interpolator;
|
||||
private final ElevationInterpolator elevationInterpolator;
|
||||
|
||||
public Sampler(ChunkInterpolator3 interpolator, ElevationInterpolator elevationInterpolator) {
|
||||
this.interpolator = interpolator;
|
||||
this.elevationInterpolator = elevationInterpolator;
|
||||
}
|
||||
|
||||
public double sample(double x, double y, double z) {
|
||||
return interpolator.getNoise(x, y, z) + elevationInterpolator.getElevation(FastMath.roundToInt(x), FastMath.roundToInt(z));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
package com.dfsek.terra.generation;
|
||||
|
||||
import com.dfsek.terra.TerraWorld;
|
||||
import com.dfsek.terra.api.gaea.biome.Biome;
|
||||
import com.dfsek.terra.api.gaea.generation.GenerationPhase;
|
||||
import com.dfsek.terra.api.gaea.math.ChunkInterpolator3;
|
||||
import com.dfsek.terra.api.gaea.population.PopulationManager;
|
||||
import com.dfsek.terra.api.gaea.profiler.ProfileFuture;
|
||||
import com.dfsek.terra.api.gaea.profiler.WorldProfiler;
|
||||
import com.dfsek.terra.api.gaea.world.palette.Palette;
|
||||
import com.dfsek.terra.api.generic.TerraPlugin;
|
||||
import com.dfsek.terra.api.generic.generator.ChunkGenerator;
|
||||
import com.dfsek.terra.api.generic.generator.TerraBlockPopulator;
|
||||
import com.dfsek.terra.api.generic.world.BiomeGrid;
|
||||
import com.dfsek.terra.api.generic.world.Chunk;
|
||||
import com.dfsek.terra.api.generic.world.World;
|
||||
import com.dfsek.terra.api.generic.world.block.BlockData;
|
||||
import com.dfsek.terra.api.generic.world.vector.Vector3;
|
||||
import com.dfsek.terra.biome.UserDefinedBiome;
|
||||
import com.dfsek.terra.config.base.ConfigPack;
|
||||
import com.dfsek.terra.config.lang.LangUtil;
|
||||
import com.dfsek.terra.config.templates.BiomeTemplate;
|
||||
import com.dfsek.terra.debug.Debug;
|
||||
import com.dfsek.terra.population.CavePopulator;
|
||||
import com.dfsek.terra.population.FloraPopulator;
|
||||
import com.dfsek.terra.population.OrePopulator;
|
||||
import com.dfsek.terra.population.StructurePopulator;
|
||||
import com.dfsek.terra.population.TreePopulator;
|
||||
import com.dfsek.terra.util.PaletteUtil;
|
||||
import com.dfsek.terra.util.SlabUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class TerraChunkGenerator implements com.dfsek.terra.api.generic.generator.TerraChunkGenerator {
|
||||
private static final Map<World, PopulationManager> popMap = new HashMap<>();
|
||||
private final PopulationManager popMan;
|
||||
private final ConfigPack configPack;
|
||||
private final TerraPlugin main;
|
||||
private boolean needsLoad = true;
|
||||
|
||||
public TerraChunkGenerator(ConfigPack c, TerraPlugin main) {
|
||||
popMan = new PopulationManager(main);
|
||||
this.configPack = c;
|
||||
this.main = main;
|
||||
popMan.attach(new OrePopulator(main));
|
||||
popMan.attach(new TreePopulator(main));
|
||||
popMan.attach(new FloraPopulator(main));
|
||||
}
|
||||
|
||||
public static synchronized void saveAll() {
|
||||
for(Map.Entry<World, PopulationManager> e : popMap.entrySet()) {
|
||||
try {
|
||||
e.getValue().saveBlocks(e.getKey());
|
||||
Debug.info("Saved data for world " + e.getKey().getName());
|
||||
} catch(IOException ioException) {
|
||||
ioException.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized void fixChunk(Chunk c) {
|
||||
if(!(c.getWorld().getGenerator() instanceof TerraChunkGenerator)) throw new IllegalArgumentException();
|
||||
popMap.get(c.getWorld()).checkNeighbors(c.getX(), c.getZ(), c.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isParallelCapable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldGenerateCaves() {
|
||||
return configPack.getTemplate().vanillaCaves();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldGenerateDecorations() {
|
||||
return configPack.getTemplate().vanillaDecorations();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldGenerateMobs() {
|
||||
return configPack.getTemplate().vanillaMobs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldGenerateStructures() {
|
||||
return configPack.getTemplate().vanillaStructures();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigPack getConfigPack() {
|
||||
return configPack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TerraBlockPopulator> getPopulators() {
|
||||
return Arrays.asList(new CavePopulator(main), new StructurePopulator(main), popMan);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"try"})
|
||||
public ChunkGenerator.ChunkData generateChunkData(@NotNull World world, @NotNull Random random, int chunkX, int chunkZ, @NotNull BiomeGrid biome, ChunkGenerator.ChunkData chunk) {
|
||||
TerraWorld tw = main.getWorld(world);
|
||||
com.dfsek.terra.api.gaea.biome.BiomeGrid grid = tw.getGrid();
|
||||
try(ProfileFuture ignore = tw.getProfiler().measure("TotalChunkGenTime")) {
|
||||
ChunkInterpolator3 interp;
|
||||
try(ProfileFuture ignored = tw.getProfiler().measure("ChunkBaseGenTime")) {
|
||||
interp = new ChunkInterpolator3(world, chunkX, chunkZ, tw.getGrid());
|
||||
if(needsLoad) load(world); // Load population data for world.
|
||||
|
||||
if(!tw.isSafe()) return chunk;
|
||||
int xOrig = (chunkX << 4);
|
||||
int zOrig = (chunkZ << 4);
|
||||
|
||||
ElevationInterpolator elevationInterpolator;
|
||||
try(ProfileFuture ignored1 = tw.getProfiler().measure("ElevationTime")) {
|
||||
elevationInterpolator = new ElevationInterpolator(chunkX, chunkZ, tw.getGrid());
|
||||
}
|
||||
|
||||
Sampler sampler = new Sampler(interp, elevationInterpolator);
|
||||
|
||||
for(byte x = 0; x < 16; x++) {
|
||||
for(byte z = 0; z < 16; z++) {
|
||||
int paletteLevel = 0;
|
||||
|
||||
int cx = xOrig + x;
|
||||
int cz = zOrig + z;
|
||||
|
||||
Biome b = grid.getBiome(xOrig + x, zOrig + z, GenerationPhase.PALETTE_APPLY);
|
||||
BiomeTemplate c = ((UserDefinedBiome) b).getConfig();
|
||||
|
||||
int sea = c.getSeaLevel();
|
||||
Palette<BlockData> seaPalette = c.getOceanPalette();
|
||||
|
||||
boolean justSet = false;
|
||||
BlockData data = null;
|
||||
for(int y = world.getMaxHeight() - 1; y >= 0; y--) {
|
||||
if(sampler.sample(x, y, z) > 0) {
|
||||
justSet = true;
|
||||
data = PaletteUtil.getPalette(x, y, z, c, sampler).get(paletteLevel, cx, cz);
|
||||
chunk.setBlock(x, y, z, data);
|
||||
if(paletteLevel == 0 && c.doSlabs() && y < 255) {
|
||||
SlabUtil.prepareBlockPartFloor(data, chunk.getBlockData(x, y + 1, z), chunk, new Vector3(x, y + 1, z), c.getSlabPalettes(),
|
||||
c.getStairPalettes(), c.getSlabThreshold(), sampler);
|
||||
}
|
||||
paletteLevel++;
|
||||
} else if(y <= sea) {
|
||||
//chunk.setBlock(x, y, z, seaPalette.get(sea - y, x + xOrig, z + zOrig));
|
||||
if(justSet && c.doSlabs()) {
|
||||
SlabUtil.prepareBlockPartCeiling(data, chunk.getBlockData(x, y, z), chunk, new Vector3(x, y, z), c.getSlabPalettes(), c.getStairPalettes(), c.getSlabThreshold(), sampler);
|
||||
}
|
||||
justSet = false;
|
||||
paletteLevel = 0;
|
||||
} else {
|
||||
if(justSet && c.doSlabs()) {
|
||||
SlabUtil.prepareBlockPartCeiling(data, chunk.getBlockData(x, y, z), chunk, new Vector3(x, y, z), c.getSlabPalettes(), c.getStairPalettes(), c.getSlabThreshold(), sampler);
|
||||
}
|
||||
justSet = false;
|
||||
paletteLevel = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int xOrig = (chunkX << 4);
|
||||
int zOrig = (chunkZ << 4);
|
||||
for(int x = 0; x < 4; x++) {
|
||||
for(byte z = 0; z < 4; z++) {
|
||||
int cx = xOrig + (x << 2);
|
||||
int cz = zOrig + (z << 2);
|
||||
Biome b = grid.getBiome(cx, cz, GenerationPhase.PALETTE_APPLY);
|
||||
|
||||
biome.setBiome(x << 2, z << 2, b.getVanillaBiome());
|
||||
}
|
||||
}
|
||||
return chunk;
|
||||
}
|
||||
}
|
||||
|
||||
public void attachProfiler(WorldProfiler p) {
|
||||
popMan.attachProfiler(p);
|
||||
}
|
||||
|
||||
private void load(World w) {
|
||||
try {
|
||||
popMan.loadBlocks(w);
|
||||
} catch(FileNotFoundException e) {
|
||||
LangUtil.log("warning.no-population", Level.WARNING);
|
||||
} catch(IOException | ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
popMap.put(w, popMan);
|
||||
needsLoad = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.dfsek.terra.generation;
|
||||
|
||||
import com.dfsek.terra.api.gaea.biome.Decorator;
|
||||
import com.dfsek.terra.api.gaea.math.ProbabilityCollection;
|
||||
import com.dfsek.terra.api.gaea.tree.Tree;
|
||||
import com.dfsek.terra.api.gaea.world.Flora;
|
||||
|
||||
public class UserDefinedDecorator extends Decorator {
|
||||
|
||||
private final ProbabilityCollection<Flora> flora;
|
||||
private final ProbabilityCollection<Tree> trees;
|
||||
private final int floraChance;
|
||||
private final int treeDensity;
|
||||
|
||||
public UserDefinedDecorator(ProbabilityCollection<Flora> flora, ProbabilityCollection<Tree> trees, int floraChance, int treeDensity) {
|
||||
this.flora = flora;
|
||||
this.trees = trees;
|
||||
|
||||
this.floraChance = floraChance;
|
||||
this.treeDensity = treeDensity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProbabilityCollection<Tree> getTrees() {
|
||||
return trees;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTreeDensity() {
|
||||
return treeDensity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean overrideStructureChance() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProbabilityCollection<Flora> getFlora() {
|
||||
return flora;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFloraChance() {
|
||||
return floraChance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
package com.dfsek.terra.generation.config;
|
||||
|
||||
import com.dfsek.tectonic.annotations.Default;
|
||||
import com.dfsek.tectonic.annotations.Value;
|
||||
import com.dfsek.tectonic.config.ConfigTemplate;
|
||||
import com.dfsek.terra.api.gaea.math.FastNoiseLite;
|
||||
|
||||
public class NoiseBuilder implements ConfigTemplate {
|
||||
@Value("type")
|
||||
@Default
|
||||
private FastNoiseLite.NoiseType type = FastNoiseLite.NoiseType.OpenSimplex2;
|
||||
|
||||
@Value("fractal.octaves")
|
||||
@Default
|
||||
private int octaves = 1;
|
||||
|
||||
@Value("fractal.type")
|
||||
@Default
|
||||
private FastNoiseLite.FractalType fractalType = FastNoiseLite.FractalType.None;
|
||||
|
||||
@Value("frequency")
|
||||
@Default
|
||||
private double frequency = 0.02D;
|
||||
|
||||
@Value("fractal.gain")
|
||||
@Default
|
||||
private double fractalGain = 0.5D;
|
||||
|
||||
@Value("fractal.lacunarity")
|
||||
@Default
|
||||
private double fractalLacunarity = 2.0D;
|
||||
|
||||
@Value("fractal.ping-pong")
|
||||
@Default
|
||||
private double pingPong = 2.0D;
|
||||
|
||||
@Value("fractal.weighted-strength")
|
||||
@Default
|
||||
private double weightedStrength = 0.0D;
|
||||
|
||||
@Value("offset")
|
||||
@Default
|
||||
private int seedOffset = 0;
|
||||
|
||||
@Value("cellular.distance")
|
||||
@Default
|
||||
private FastNoiseLite.CellularDistanceFunction cellularDistanceFunction = FastNoiseLite.CellularDistanceFunction.EuclideanSq;
|
||||
|
||||
@Value("cellular.return")
|
||||
@Default
|
||||
private FastNoiseLite.CellularReturnType cellularReturnType = FastNoiseLite.CellularReturnType.Distance;
|
||||
|
||||
@Value("cellular.jitter")
|
||||
@Default
|
||||
private double cellularJitter = 1.0D;
|
||||
|
||||
@Value("domain-warp.type")
|
||||
@Default
|
||||
private FastNoiseLite.DomainWarpType domainWarpType = FastNoiseLite.DomainWarpType.OpenSimplex2;
|
||||
|
||||
@Value("domain-warp.amplitude")
|
||||
@Default
|
||||
private double domainWarpAmp = 1.0D;
|
||||
|
||||
@Value("rotation-type")
|
||||
@Default
|
||||
private FastNoiseLite.RotationType3D rotationType3D = FastNoiseLite.RotationType3D.None;
|
||||
|
||||
@Value("dimensions")
|
||||
@Default
|
||||
private int dimensions = 2;
|
||||
|
||||
public FastNoiseLite build(int seed) {
|
||||
FastNoiseLite noise = new FastNoiseLite(seed + seedOffset);
|
||||
if(!fractalType.equals(FastNoiseLite.FractalType.None)) {
|
||||
noise.setFractalType(fractalType);
|
||||
noise.setFractalOctaves(octaves);
|
||||
noise.setFractalGain(fractalGain);
|
||||
noise.setFractalLacunarity(fractalLacunarity);
|
||||
if(fractalType.equals(FastNoiseLite.FractalType.PingPong)) noise.setFractalPingPongStrength(pingPong);
|
||||
noise.setFractalWeightedStrength(weightedStrength);
|
||||
}
|
||||
if(type.equals(FastNoiseLite.NoiseType.Cellular)) {
|
||||
noise.setCellularDistanceFunction(cellularDistanceFunction);
|
||||
noise.setCellularReturnType(cellularReturnType);
|
||||
noise.setCellularJitter(cellularJitter);
|
||||
}
|
||||
|
||||
noise.setNoiseType(type);
|
||||
|
||||
noise.setDomainWarpType(domainWarpType);
|
||||
noise.setDomainWarpAmp(domainWarpAmp);
|
||||
|
||||
noise.setRotationType3D(rotationType3D);
|
||||
|
||||
noise.setFrequency(frequency);
|
||||
return noise;
|
||||
}
|
||||
|
||||
public FastNoiseLite.NoiseType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public NoiseBuilder setType(FastNoiseLite.NoiseType type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getSeedOffset() {
|
||||
return seedOffset;
|
||||
}
|
||||
|
||||
public void setSeedOffset(int seedOffset) {
|
||||
this.seedOffset = seedOffset;
|
||||
}
|
||||
|
||||
public FastNoiseLite.CellularDistanceFunction getCellularDistanceFunction() {
|
||||
return cellularDistanceFunction;
|
||||
}
|
||||
|
||||
public NoiseBuilder setCellularDistanceFunction(FastNoiseLite.CellularDistanceFunction cellularDistanceFunction) {
|
||||
this.cellularDistanceFunction = cellularDistanceFunction;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FastNoiseLite.CellularReturnType getCellularReturnType() {
|
||||
return cellularReturnType;
|
||||
}
|
||||
|
||||
public NoiseBuilder setCellularReturnType(FastNoiseLite.CellularReturnType cellularReturnType) {
|
||||
this.cellularReturnType = cellularReturnType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FastNoiseLite.DomainWarpType getDomainWarpType() {
|
||||
return domainWarpType;
|
||||
}
|
||||
|
||||
public NoiseBuilder setDomainWarpType(FastNoiseLite.DomainWarpType domainWarpType) {
|
||||
this.domainWarpType = domainWarpType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getCellularJitter() {
|
||||
return cellularJitter;
|
||||
}
|
||||
|
||||
public NoiseBuilder setCellularJitter(double cellularJitter) {
|
||||
this.cellularJitter = cellularJitter;
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getDomainWarpAmp() {
|
||||
return domainWarpAmp;
|
||||
}
|
||||
|
||||
public NoiseBuilder setDomainWarpAmp(double domainWarpAmp) {
|
||||
this.domainWarpAmp = domainWarpAmp;
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getFractalGain() {
|
||||
return fractalGain;
|
||||
}
|
||||
|
||||
public NoiseBuilder setFractalGain(double fractalGain) {
|
||||
this.fractalGain = fractalGain;
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getFractalLacunarity() {
|
||||
return fractalLacunarity;
|
||||
}
|
||||
|
||||
public NoiseBuilder setFractalLacunarity(double fractalLacunarity) {
|
||||
this.fractalLacunarity = fractalLacunarity;
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getFrequency() {
|
||||
return frequency;
|
||||
}
|
||||
|
||||
public NoiseBuilder setFrequency(double frequency) {
|
||||
this.frequency = frequency;
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getPingPong() {
|
||||
return pingPong;
|
||||
}
|
||||
|
||||
public NoiseBuilder setPingPong(double pingPong) {
|
||||
this.pingPong = pingPong;
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getWeightedStrength() {
|
||||
return weightedStrength;
|
||||
}
|
||||
|
||||
public NoiseBuilder setWeightedStrength(double weightedStrength) {
|
||||
this.weightedStrength = weightedStrength;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getOctaves() {
|
||||
return octaves;
|
||||
}
|
||||
|
||||
public NoiseBuilder setOctaves(int octaves) {
|
||||
this.octaves = octaves;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FastNoiseLite.FractalType getFractalType() {
|
||||
return fractalType;
|
||||
}
|
||||
|
||||
public NoiseBuilder setFractalType(FastNoiseLite.FractalType fractalType) {
|
||||
this.fractalType = fractalType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FastNoiseLite.RotationType3D getRotationType3D() {
|
||||
return rotationType3D;
|
||||
}
|
||||
|
||||
public NoiseBuilder setRotationType3D(FastNoiseLite.RotationType3D rotationType3D) {
|
||||
this.rotationType3D = rotationType3D;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getDimensions() {
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
public void setDimensions(int dimensions) {
|
||||
this.dimensions = dimensions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
package com.dfsek.terra.generation.config;
|
||||
|
||||
import com.dfsek.terra.api.gaea.biome.Generator;
|
||||
import com.dfsek.terra.api.gaea.math.Interpolator;
|
||||
import com.dfsek.terra.api.gaea.world.palette.Palette;
|
||||
import com.dfsek.terra.api.generic.world.World;
|
||||
import com.dfsek.terra.api.generic.world.block.BlockData;
|
||||
import com.dfsek.terra.biome.palette.PaletteHolder;
|
||||
import com.dfsek.terra.math.NoiseFunction2;
|
||||
import com.dfsek.terra.math.NoiseFunction3;
|
||||
import com.dfsek.terra.math.RandomFunction;
|
||||
import parsii.eval.Expression;
|
||||
import parsii.eval.Parser;
|
||||
import parsii.eval.Scope;
|
||||
import parsii.eval.Variable;
|
||||
import parsii.tokenizer.ParseException;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class WorldGenerator extends Generator {
|
||||
@SuppressWarnings({"unchecked", "rawtypes", "RedundantSuppression"})
|
||||
private final PaletteHolder palettes;
|
||||
@SuppressWarnings({"unchecked", "rawtypes", "RedundantSuppression"})
|
||||
private final PaletteHolder slantPalettes;
|
||||
|
||||
private final boolean preventSmooth;
|
||||
private final Expression noiseExp;
|
||||
private final Expression elevationExp;
|
||||
private final Variable xVar;
|
||||
private final Variable yVar;
|
||||
private final Variable zVar;
|
||||
private final Variable elevationXVar;
|
||||
private final Variable elevationZVar;
|
||||
private final boolean elevationInterpolation;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public WorldGenerator(long seed, String equation, String elevateEquation, Scope vScope, Map<String, NoiseBuilder> noiseBuilders, PaletteHolder palettes, PaletteHolder slantPalettes, boolean preventSmooth, boolean elevationInterpolation) {
|
||||
Parser p = new Parser();
|
||||
p.registerFunction("rand", new RandomFunction());
|
||||
Parser ep = new Parser();
|
||||
ep.registerFunction("rand", new RandomFunction());
|
||||
|
||||
Scope s = new Scope().withParent(vScope);
|
||||
xVar = s.create("x");
|
||||
yVar = s.create("y");
|
||||
zVar = s.create("z");
|
||||
s.create("seed").setValue(seed);
|
||||
|
||||
this.preventSmooth = preventSmooth;
|
||||
|
||||
this.palettes = palettes;
|
||||
this.slantPalettes = slantPalettes;
|
||||
|
||||
this.elevationInterpolation = elevationInterpolation;
|
||||
|
||||
for(Map.Entry<String, NoiseBuilder> e : noiseBuilders.entrySet()) {
|
||||
switch(e.getValue().getDimensions()) {
|
||||
case 2:
|
||||
p.registerFunction(e.getKey(), new NoiseFunction2(seed, e.getValue()));
|
||||
ep.registerFunction(e.getKey(), new NoiseFunction2(seed, e.getValue()));
|
||||
break;
|
||||
case 3:
|
||||
p.registerFunction(e.getKey(), new NoiseFunction3(seed, e.getValue()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
try {
|
||||
this.noiseExp = p.parse(equation, s).simplify();
|
||||
if(elevateEquation != null) {
|
||||
Scope es = new Scope().withParent(vScope);
|
||||
es.create("seed").setValue(seed);
|
||||
this.elevationXVar = es.create("x");
|
||||
this.elevationZVar = es.create("z");
|
||||
this.elevationExp = ep.parse(elevateEquation, es).simplify();
|
||||
} else {
|
||||
this.elevationExp = null;
|
||||
this.elevationXVar = null;
|
||||
this.elevationZVar = null;
|
||||
}
|
||||
} catch(ParseException e) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized double getElevation(int x, int z) {
|
||||
if(elevationExp == null) return 0;
|
||||
elevationXVar.setValue(x);
|
||||
elevationZVar.setValue(z);
|
||||
return elevationExp.evaluate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized double getNoise(World world, int x, int y, int z) {
|
||||
xVar.setValue(x);
|
||||
yVar.setValue(y);
|
||||
zVar.setValue(z);
|
||||
return noiseExp.evaluate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the BlockPalette to generate the biome with.
|
||||
*
|
||||
* @return BlockPalette - The biome's palette.
|
||||
*/
|
||||
@Override
|
||||
public Palette<BlockData> getPalette(int y) {
|
||||
return palettes.getPalette(y);
|
||||
}
|
||||
|
||||
public Palette<BlockData> getSlantPalette(int y) {
|
||||
return slantPalettes.getPalette(y);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean useMinimalInterpolation() {
|
||||
return preventSmooth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Interpolator.Type getInterpolationType() {
|
||||
return Interpolator.Type.LINEAR;
|
||||
}
|
||||
|
||||
public boolean interpolateElevation() {
|
||||
return elevationInterpolation;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.dfsek.terra.generation.items;
|
||||
|
||||
import com.dfsek.terra.api.gaea.math.FastNoiseLite;
|
||||
import com.dfsek.terra.api.gaea.math.ProbabilityCollection;
|
||||
import com.dfsek.terra.api.gaea.math.Range;
|
||||
import com.dfsek.terra.api.generic.world.Chunk;
|
||||
import com.dfsek.terra.api.generic.world.vector.Vector2;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public abstract class PlaceableLayer<T> {
|
||||
protected final double density;
|
||||
protected final Range level;
|
||||
protected final ProbabilityCollection<T> layer;
|
||||
protected final FastNoiseLite noise;
|
||||
|
||||
public PlaceableLayer(double density, Range level, ProbabilityCollection<T> layer, FastNoiseLite noise) {
|
||||
this.density = density;
|
||||
this.level = level;
|
||||
this.layer = layer;
|
||||
this.noise = noise;
|
||||
}
|
||||
|
||||
public FastNoiseLite getNoise() {
|
||||
return noise;
|
||||
}
|
||||
|
||||
public double getDensity() {
|
||||
return density;
|
||||
}
|
||||
|
||||
public Range getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public ProbabilityCollection<T> getLayer() {
|
||||
return layer;
|
||||
}
|
||||
|
||||
public abstract void place(Chunk chunk, Vector2 coords, Random random);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.dfsek.terra.generation.items;
|
||||
|
||||
import com.dfsek.terra.api.gaea.math.ProbabilityCollection;
|
||||
import com.dfsek.terra.api.gaea.math.Range;
|
||||
import com.dfsek.terra.api.gaea.structures.loot.LootTable;
|
||||
import com.dfsek.terra.config.templates.StructureTemplate;
|
||||
import com.dfsek.terra.procgen.GridSpawn;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
// TODO: implementation
|
||||
public class TerraStructure {
|
||||
private final ProbabilityCollection<Void> structures;
|
||||
private final Range bound;
|
||||
private final Range spawnStart;
|
||||
private final GridSpawn spawn;
|
||||
private final Map<Integer, LootTable> loot;
|
||||
private final StructureTemplate template;
|
||||
|
||||
public TerraStructure(ProbabilityCollection<Void> structures, Range bound, Range spawnStart, GridSpawn spawn, Map<Integer, LootTable> loot, StructureTemplate template) {
|
||||
this.structures = structures;
|
||||
this.bound = bound;
|
||||
this.spawnStart = spawnStart;
|
||||
this.spawn = spawn;
|
||||
this.loot = loot;
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
public StructureTemplate getTemplate() {
|
||||
return template;
|
||||
}
|
||||
|
||||
public ProbabilityCollection<Void> getStructures() {
|
||||
return structures;
|
||||
}
|
||||
|
||||
public Range getBound() {
|
||||
return bound;
|
||||
}
|
||||
|
||||
public Range getSpawnStart() {
|
||||
return spawnStart;
|
||||
}
|
||||
|
||||
public GridSpawn getSpawn() {
|
||||
return spawn;
|
||||
}
|
||||
|
||||
public Map<Integer, LootTable> getLoot() {
|
||||
return loot;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.dfsek.terra.generation.items.flora;
|
||||
|
||||
import com.dfsek.terra.api.gaea.math.Range;
|
||||
import com.dfsek.terra.api.gaea.util.GlueList;
|
||||
import com.dfsek.terra.api.gaea.world.Flora;
|
||||
import com.dfsek.terra.api.generic.world.Chunk;
|
||||
import com.dfsek.terra.api.generic.world.block.Block;
|
||||
import com.dfsek.terra.api.generic.world.block.BlockData;
|
||||
import com.dfsek.terra.api.generic.world.block.BlockFace;
|
||||
import com.dfsek.terra.api.generic.world.vector.Location;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Flora that is just 1 layer of a single block.
|
||||
*/
|
||||
public class BlockFlora implements Flora {
|
||||
|
||||
private final BlockData data;
|
||||
|
||||
public BlockFlora(BlockData data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Block> getValidSpawnsAt(Chunk chunk, int x, int z, Range range) {
|
||||
Block current = chunk.getBlock(x, range.getMin(), z);
|
||||
List<Block> blocks = new GlueList<>();
|
||||
for(int y : range) {
|
||||
if(y > 255 || y < 0) continue;
|
||||
current = current.getRelative(BlockFace.UP);
|
||||
if(current.getType().isSolid() && current.getRelative(BlockFace.UP).isEmpty()) {
|
||||
blocks.add(current); // Add all blocks that are solid with air directly above.
|
||||
}
|
||||
}
|
||||
return blocks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean plant(Location location) {
|
||||
location.add(0, 1, 0).getBlock().setBlockData(data, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.dfsek.terra.generation.items.flora;
|
||||
|
||||
import com.dfsek.terra.api.gaea.math.Range;
|
||||
import com.dfsek.terra.api.gaea.util.GlueList;
|
||||
import com.dfsek.terra.api.gaea.world.Flora;
|
||||
import com.dfsek.terra.api.generic.world.Chunk;
|
||||
import com.dfsek.terra.api.generic.world.block.Block;
|
||||
import com.dfsek.terra.api.generic.world.block.BlockData;
|
||||
import com.dfsek.terra.api.generic.world.block.BlockFace;
|
||||
import com.dfsek.terra.api.generic.world.vector.Location;
|
||||
import com.dfsek.terra.util.MaterialSet;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ConstantFlora implements Flora {
|
||||
private final List<BlockData> data;
|
||||
|
||||
private final MaterialSet spawns;
|
||||
|
||||
public ConstantFlora(MaterialSet spawns, List<BlockData> data) {
|
||||
this.data = data;
|
||||
this.spawns = spawns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Block> getValidSpawnsAt(Chunk chunk, int x, int z, Range check) {
|
||||
List<Block> blocks = new GlueList<>();
|
||||
for(int y : check) {
|
||||
Block block = chunk.getBlock(x, y, z);
|
||||
if(spawns.contains(block.getType()) && valid(block)) {
|
||||
blocks.add(chunk.getBlock(x, y, z));
|
||||
}
|
||||
}
|
||||
return blocks;
|
||||
}
|
||||
|
||||
private boolean valid(Block block) {
|
||||
for(int i = 1; i < data.size() + 1; i++) {
|
||||
block = block.getRelative(BlockFace.UP);
|
||||
if(!block.isEmpty()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean plant(Location l) {
|
||||
for(int i = 1; i < data.size() + 1; i++) {
|
||||
l.clone().add(0, i, 0).getBlock().setBlockData(data.get(i - 1), false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.dfsek.terra.generation.items.flora;
|
||||
|
||||
import com.dfsek.terra.api.gaea.math.FastNoiseLite;
|
||||
import com.dfsek.terra.api.gaea.math.ProbabilityCollection;
|
||||
import com.dfsek.terra.api.gaea.math.Range;
|
||||
import com.dfsek.terra.api.gaea.world.Flora;
|
||||
import com.dfsek.terra.api.generic.world.Chunk;
|
||||
import com.dfsek.terra.api.generic.world.vector.Vector2;
|
||||
import com.dfsek.terra.generation.items.PlaceableLayer;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class FloraLayer extends PlaceableLayer<Flora> {
|
||||
|
||||
public FloraLayer(double density, Range level, ProbabilityCollection<Flora> layer, FastNoiseLite noise) {
|
||||
super(density, level, layer, noise);
|
||||
}
|
||||
|
||||
public double getDensity() {
|
||||
return density;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void place(Chunk chunk, Vector2 coords, Random random) {
|
||||
Flora item = noise == null ? layer.get(random) : layer.get(noise, (chunk.getX() << 4) + coords.getX(), (chunk.getZ() << 4) + coords.getZ());
|
||||
item.getValidSpawnsAt(chunk, (int) coords.getX(), (int) coords.getZ(), level).forEach(block -> item.plant(block.getLocation()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package com.dfsek.terra.generation.items.flora;
|
||||
|
||||
import com.dfsek.terra.api.gaea.math.Range;
|
||||
import com.dfsek.terra.api.gaea.util.FastRandom;
|
||||
import com.dfsek.terra.api.gaea.util.GlueList;
|
||||
import com.dfsek.terra.api.gaea.world.Flora;
|
||||
import com.dfsek.terra.api.gaea.world.palette.Palette;
|
||||
import com.dfsek.terra.api.generic.TerraPlugin;
|
||||
import com.dfsek.terra.api.generic.world.Chunk;
|
||||
import com.dfsek.terra.api.generic.world.WorldHandle;
|
||||
import com.dfsek.terra.api.generic.world.block.Block;
|
||||
import com.dfsek.terra.api.generic.world.block.BlockData;
|
||||
import com.dfsek.terra.api.generic.world.block.BlockFace;
|
||||
import com.dfsek.terra.api.generic.world.block.data.Directional;
|
||||
import com.dfsek.terra.api.generic.world.block.data.MultipleFacing;
|
||||
import com.dfsek.terra.api.generic.world.block.data.Rotatable;
|
||||
import com.dfsek.terra.api.generic.world.vector.Location;
|
||||
import com.dfsek.terra.util.MaterialSet;
|
||||
import net.jafama.FastMath;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TerraFlora implements Flora {
|
||||
private final Palette<BlockData> floraPalette;
|
||||
private final boolean physics;
|
||||
private final boolean ceiling;
|
||||
|
||||
private final MaterialSet irrigable;
|
||||
|
||||
private final MaterialSet spawnable;
|
||||
private final MaterialSet replaceable;
|
||||
|
||||
private final MaterialSet testRotation;
|
||||
|
||||
private final int maxPlacements;
|
||||
|
||||
private final Search search;
|
||||
|
||||
private final boolean spawnBlacklist;
|
||||
|
||||
private final int irrigableOffset;
|
||||
|
||||
private final TerraPlugin main;
|
||||
|
||||
public TerraFlora(Palette<BlockData> floraPalette, boolean physics, boolean ceiling, MaterialSet irrigable, MaterialSet spawnable, MaterialSet replaceable, MaterialSet testRotation, int maxPlacements, Search search, boolean spawnBlacklist, int irrigableOffset, TerraPlugin main) {
|
||||
this.floraPalette = floraPalette;
|
||||
this.physics = physics;
|
||||
this.testRotation = testRotation;
|
||||
this.spawnBlacklist = spawnBlacklist;
|
||||
this.ceiling = ceiling;
|
||||
this.irrigable = irrigable;
|
||||
this.spawnable = spawnable;
|
||||
this.replaceable = replaceable;
|
||||
this.maxPlacements = maxPlacements;
|
||||
this.search = search;
|
||||
this.irrigableOffset = irrigableOffset;
|
||||
this.main = main;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Block> getValidSpawnsAt(Chunk chunk, int x, int z, Range range) {
|
||||
int size = floraPalette.getSize();
|
||||
Block current = chunk.getBlock(x, search.equals(Search.UP) ? range.getMin() : range.getMax(), z);
|
||||
List<Block> blocks = new ArrayList<>();
|
||||
for(int y : range) {
|
||||
if(y > 255 || y < 0) continue;
|
||||
current = current.getRelative(search.equals(Search.UP) ? BlockFace.UP : BlockFace.DOWN);
|
||||
if((spawnBlacklist != spawnable.contains(current.getType())) && isIrrigated(current.getRelative(BlockFace.UP, irrigableOffset)) && valid(size, current)) {
|
||||
blocks.add(current);
|
||||
if(maxPlacements > 0 && blocks.size() >= maxPlacements) break;
|
||||
}
|
||||
}
|
||||
return blocks;
|
||||
}
|
||||
|
||||
private boolean valid(int size, Block block) {
|
||||
for(int i = 0; i < size; i++) { // Down if ceiling, up if floor
|
||||
if(block.getY() + 1 > 255 || block.getY() < 0) return false;
|
||||
block = block.getRelative(ceiling ? BlockFace.DOWN : BlockFace.UP);
|
||||
if(!replaceable.contains(block.getType())) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isIrrigated(Block b) {
|
||||
if(irrigable == null) return true;
|
||||
return irrigable.contains(b.getRelative(BlockFace.NORTH).getType())
|
||||
|| irrigable.contains(b.getRelative(BlockFace.SOUTH).getType())
|
||||
|| irrigable.contains(b.getRelative(BlockFace.EAST).getType())
|
||||
|| irrigable.contains(b.getRelative(BlockFace.WEST).getType());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean plant(Location location) {
|
||||
WorldHandle handle = main.getWorldHandle();
|
||||
|
||||
boolean doRotation = testRotation.size() > 0;
|
||||
int size = floraPalette.getSize();
|
||||
int c = ceiling ? -1 : 1;
|
||||
|
||||
List<BlockFace> faces = doRotation ? getFaces(location.clone().add(0, c, 0).getBlock()) : new GlueList<>();
|
||||
if(doRotation && faces.size() == 0) return false; // Don't plant if no faces are valid.
|
||||
BlockFace oneFace = doRotation ? faces.get(new FastRandom(location.getBlockX() ^ location.getBlockZ()).nextInt(faces.size())) : null; // Get random face.
|
||||
|
||||
for(int i = 0; FastMath.abs(i) < size; i += c) { // Down if ceiling, up if floor
|
||||
int lvl = (FastMath.abs(i));
|
||||
BlockData data = floraPalette.get((ceiling ? lvl : size - lvl - 1), location.getBlockX(), location.getBlockZ()).clone();
|
||||
if(doRotation) {
|
||||
if(data instanceof Directional) {
|
||||
((Directional) data).setFacing(oneFace);
|
||||
} else if(data instanceof MultipleFacing) {
|
||||
MultipleFacing o = (MultipleFacing) data;
|
||||
for(BlockFace face : o.getFaces()) o.setFace(face, false);
|
||||
for(BlockFace face : faces) o.setFace(face, true);
|
||||
} else if(data instanceof Rotatable) {
|
||||
((Rotatable) data).setRotation(oneFace);
|
||||
}
|
||||
}
|
||||
handle.setBlockData(location.clone().add(0, i + c, 0).getBlock(), data, physics);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private List<BlockFace> getFaces(Block b) {
|
||||
List<BlockFace> faces = new GlueList<>();
|
||||
test(faces, BlockFace.NORTH, b);
|
||||
test(faces, BlockFace.SOUTH, b);
|
||||
test(faces, BlockFace.EAST, b);
|
||||
test(faces, BlockFace.WEST, b);
|
||||
return faces;
|
||||
}
|
||||
|
||||
private void test(List<BlockFace> faces, BlockFace f, Block b) {
|
||||
if(testRotation.contains(b.getRelative(f).getType())) faces.add(f);
|
||||
}
|
||||
|
||||
public enum Search {
|
||||
UP,
|
||||
DOWN
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.dfsek.terra.generation.items.ores;
|
||||
|
||||
import com.dfsek.terra.api.gaea.math.FastNoiseLite;
|
||||
import com.dfsek.terra.api.gaea.math.Range;
|
||||
import com.dfsek.terra.api.generic.TerraPlugin;
|
||||
import com.dfsek.terra.api.generic.world.Chunk;
|
||||
import com.dfsek.terra.api.generic.world.WorldHandle;
|
||||
import com.dfsek.terra.api.generic.world.block.Block;
|
||||
import com.dfsek.terra.api.generic.world.block.BlockData;
|
||||
import com.dfsek.terra.api.generic.world.vector.Vector3;
|
||||
import com.dfsek.terra.util.MaterialSet;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class DeformedSphereOre extends Ore {
|
||||
private final double deform;
|
||||
private final double deformFrequency;
|
||||
private final Range size;
|
||||
|
||||
public DeformedSphereOre(BlockData material, MaterialSet replaceable, boolean applyGravity, double deform, double deformFrequency, Range size, TerraPlugin main) {
|
||||
super(material, replaceable, applyGravity, main);
|
||||
this.deform = deform;
|
||||
this.deformFrequency = deformFrequency;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void generate(Vector3 origin, Chunk c, Random r) {
|
||||
WorldHandle handle = main.getWorldHandle();
|
||||
FastNoiseLite ore = new FastNoiseLite(r.nextInt());
|
||||
ore.setNoiseType(FastNoiseLite.NoiseType.OpenSimplex2);
|
||||
ore.setFrequency(deformFrequency);
|
||||
int rad = size.get(r);
|
||||
for(int x = -rad; x <= rad; x++) {
|
||||
for(int y = -rad; y <= rad; y++) {
|
||||
for(int z = -rad; z <= rad; z++) {
|
||||
Vector3 oreLoc = origin.clone().add(new Vector3(x, y, z));
|
||||
if(oreLoc.getBlockX() > 15 || oreLoc.getBlockZ() > 15 || oreLoc.getBlockY() > 255 || oreLoc.getBlockX() < 0 || oreLoc.getBlockZ() < 0 || oreLoc.getBlockY() < 0)
|
||||
continue;
|
||||
if(oreLoc.distance(origin) < (rad + 0.5) * ((ore.getNoise(x, y, z) + 1) * deform)) {
|
||||
Block b = c.getBlock(oreLoc.getBlockX(), oreLoc.getBlockY(), oreLoc.getBlockZ());
|
||||
if(getReplaceable().contains(b.getType()) && b.getLocation().getY() >= 0)
|
||||
handle.setBlockData(b, getMaterial(), isApplyGravity());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.dfsek.terra.generation.items.ores;
|
||||
|
||||
import com.dfsek.terra.api.generic.TerraPlugin;
|
||||
import com.dfsek.terra.api.generic.world.Chunk;
|
||||
import com.dfsek.terra.api.generic.world.block.BlockData;
|
||||
import com.dfsek.terra.api.generic.world.vector.Vector3;
|
||||
import com.dfsek.terra.util.MaterialSet;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public abstract class Ore {
|
||||
|
||||
private final BlockData material;
|
||||
private final MaterialSet replaceable;
|
||||
private final boolean applyGravity;
|
||||
protected TerraPlugin main;
|
||||
|
||||
public Ore(BlockData material, MaterialSet replaceable, boolean applyGravity, TerraPlugin main) {
|
||||
|
||||
this.material = material;
|
||||
this.replaceable = replaceable;
|
||||
this.applyGravity = applyGravity;
|
||||
this.main = main;
|
||||
}
|
||||
|
||||
public abstract void generate(Vector3 origin, Chunk c, Random r);
|
||||
|
||||
public BlockData getMaterial() {
|
||||
return material;
|
||||
}
|
||||
|
||||
public MaterialSet getReplaceable() {
|
||||
return replaceable;
|
||||
}
|
||||
|
||||
public boolean isApplyGravity() {
|
||||
return applyGravity;
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
VANILLA, SPHERE
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.dfsek.terra.generation.items.ores;
|
||||
|
||||
import com.dfsek.terra.api.gaea.math.Range;
|
||||
|
||||
public class OreConfig {
|
||||
private final Range amount;
|
||||
private final Range height;
|
||||
|
||||
public OreConfig(Range amount, Range height) {
|
||||
this.amount = amount;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public Range getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public Range getHeight() {
|
||||
return height;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.dfsek.terra.generation.items.ores;
|
||||
|
||||
import com.dfsek.terra.api.gaea.util.GlueList;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* Holds ordered list of ores mapped to their configs.
|
||||
*/
|
||||
public class OreHolder {
|
||||
private final List<Entry> entries = new GlueList<>();
|
||||
|
||||
public void forEach(BiConsumer<Ore, OreConfig> consumer) {
|
||||
entries.forEach(entry -> consumer.accept(entry.getOre(), entry.getConfig()));
|
||||
}
|
||||
|
||||
public OreHolder add(Ore ore, OreConfig config) {
|
||||
entries.add(new Entry(ore, config));
|
||||
return this;
|
||||
}
|
||||
|
||||
private static final class Entry {
|
||||
private final Ore ore;
|
||||
private final OreConfig config;
|
||||
|
||||
private Entry(Ore ore, OreConfig config) {
|
||||
this.ore = ore;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public OreConfig getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public Ore getOre() {
|
||||
return ore;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.dfsek.terra.generation.items.ores;
|
||||
|
||||
import com.dfsek.terra.api.gaea.math.Range;
|
||||
import com.dfsek.terra.api.generic.TerraPlugin;
|
||||
import com.dfsek.terra.api.generic.world.Chunk;
|
||||
import com.dfsek.terra.api.generic.world.WorldHandle;
|
||||
import com.dfsek.terra.api.generic.world.block.Block;
|
||||
import com.dfsek.terra.api.generic.world.block.BlockData;
|
||||
import com.dfsek.terra.api.generic.world.vector.Vector3;
|
||||
import com.dfsek.terra.util.MaterialSet;
|
||||
import net.jafama.FastMath;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
|
||||
public class VanillaOre extends Ore {
|
||||
private final Range sizeRange;
|
||||
|
||||
public VanillaOre(BlockData material, MaterialSet replaceable, boolean applyGravity, Range size, TerraPlugin main) {
|
||||
super(material, replaceable, applyGravity, main);
|
||||
this.sizeRange = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(Vector3 location, Chunk chunk, Random random) {
|
||||
WorldHandle handle = main.getWorldHandle();
|
||||
double size = sizeRange.get(random);
|
||||
|
||||
int centerX = location.getBlockX();
|
||||
int centerZ = location.getBlockZ();
|
||||
int centerY = location.getBlockY();
|
||||
|
||||
|
||||
float f = random.nextFloat() * (float) Math.PI;
|
||||
|
||||
double d1 = centerX + 8 + FastMath.sin(f) * size / 8.0F;
|
||||
double d2 = centerX + 8 - FastMath.sin(f) * size / 8.0F;
|
||||
double d3 = centerZ + 8 + FastMath.cos(f) * size / 8.0F;
|
||||
double d4 = centerZ + 8 - FastMath.cos(f) * size / 8.0F;
|
||||
|
||||
double d5 = centerY + random.nextInt(3) - 2D;
|
||||
double d6 = centerY + random.nextInt(3) - 2D;
|
||||
|
||||
for(int i = 0; i < size; i++) {
|
||||
float iFactor = (float) i / (float) size;
|
||||
|
||||
double d10 = random.nextDouble() * size / 16.0D;
|
||||
double d11 = (FastMath.sin(Math.PI * iFactor) + 1.0) * d10 + 1.0;
|
||||
double d12 = (FastMath.sin(Math.PI * iFactor) + 1.0) * d10 + 1.0;
|
||||
|
||||
int xStart = FastMath.roundToInt(FastMath.floor(d1 + (d2 - d1) * iFactor - d11 / 2.0D));
|
||||
int yStart = FastMath.roundToInt(FastMath.floor(d5 + (d6 - d5) * iFactor - d12 / 2.0D));
|
||||
int zStart = FastMath.roundToInt(FastMath.floor(d3 + (d4 - d3) * iFactor - d11 / 2.0D));
|
||||
|
||||
int xEnd = FastMath.roundToInt(FastMath.floor(d1 + (d2 - d1) * iFactor + d11 / 2.0D));
|
||||
int yEnd = FastMath.roundToInt(FastMath.floor(d5 + (d6 - d5) * iFactor + d12 / 2.0D));
|
||||
int zEnd = FastMath.roundToInt(FastMath.floor(d3 + (d4 - d3) * iFactor + d11 / 2.0D));
|
||||
|
||||
for(int x = xStart; x <= xEnd; x++) {
|
||||
double d13 = (x + 0.5D - (d1 + (d2 - d1) * iFactor)) / (d11 / 2.0D);
|
||||
|
||||
if(d13 * d13 < 1.0D) {
|
||||
for(int y = yStart; y <= yEnd; y++) {
|
||||
double d14 = (y + 0.5D - (d5 + (d6 - d5) * iFactor)) / (d12 / 2.0D);
|
||||
if(d13 * d13 + d14 * d14 < 1.0D) {
|
||||
for(int z = zStart; z <= zEnd; z++) {
|
||||
double d15 = (z + 0.5D - (d3 + (d4 - d3) * iFactor)) / (d11 / 2.0D);
|
||||
if(x > 15 || z > 15 || y > 255 || x < 0 || z < 0 || y < 0) continue;
|
||||
Block block = chunk.getBlock(x, y, z);
|
||||
if((d13 * d13 + d14 * d14 + d15 * d15 < 1.0D) && getReplaceable().contains(block.getType())) {
|
||||
handle.setBlockData(block, getMaterial(), isApplyGravity());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.dfsek.terra.generation.items.tree;
|
||||
|
||||
import com.dfsek.terra.api.gaea.math.ProbabilityCollection;
|
||||
import com.dfsek.terra.api.gaea.tree.Tree;
|
||||
import com.dfsek.terra.api.generic.TerraPlugin;
|
||||
import com.dfsek.terra.api.generic.world.vector.Location;
|
||||
import com.dfsek.terra.util.MaterialSet;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class TerraTree implements Tree {
|
||||
private final MaterialSet spawnable;
|
||||
private final int yOffset;
|
||||
private final ProbabilityCollection<Void> structure;
|
||||
|
||||
public TerraTree(MaterialSet spawnable, int yOffset, ProbabilityCollection<Void> structure) {
|
||||
this.spawnable = spawnable;
|
||||
this.yOffset = yOffset;
|
||||
this.structure = structure;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean plant(Location location, Random random) {
|
||||
/*
|
||||
Location mut = location.clone().subtract(0, yOffset, 0);
|
||||
if(!spawnable.contains(location.getBlock().getType())) return false;
|
||||
Structure struc = structure.get(random);
|
||||
Rotation rotation = Rotation.fromDegrees(random.nextInt(4) * 90);
|
||||
if(!struc.checkSpawns(mut, rotation, null)) return false;
|
||||
struc.paste(mut, rotation, null);*/
|
||||
return true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public MaterialSet getSpawnable() {
|
||||
return spawnable;
|
||||
}
|
||||
|
||||
public boolean plantBlockCheck(Location location, Random random, TerraPlugin main) {
|
||||
/*
|
||||
Location mut = location.clone().subtract(0, yOffset, 0);
|
||||
if(!spawnable.contains(location.getBlock().getType())) return false;
|
||||
Structure struc = structure.get(random);
|
||||
Rotation rotation = Rotation.fromDegrees(random.nextInt(4) * 90);
|
||||
StructureInfo info = struc.getStructureInfo();
|
||||
for(StructureContainedBlock spawn : struc.getSpawns()) {
|
||||
Vector2 rot = RotationUtil.getRotatedCoords(new Vector2(spawn.getX() - info.getCenterX(), spawn.getZ() - info.getCenterZ()), rotation);
|
||||
int x = (int) rot.getX();
|
||||
int z = (int) rot.getZ();
|
||||
switch(spawn.getRequirement()) {
|
||||
case AIR:
|
||||
if(!mut.clone().add(x, spawn.getY() - 1, z).getBlock().isPassable()) return false;
|
||||
break;
|
||||
case LAND:
|
||||
if(!mut.clone().add(x, spawn.getY() - 1, z).getBlock().getType().isSolid()) return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
struc.paste(mut, rotation, main);
|
||||
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.dfsek.terra.generation.items.tree;
|
||||
|
||||
import com.dfsek.terra.api.gaea.math.FastNoiseLite;
|
||||
import com.dfsek.terra.api.gaea.math.ProbabilityCollection;
|
||||
import com.dfsek.terra.api.gaea.math.Range;
|
||||
import com.dfsek.terra.api.gaea.tree.Tree;
|
||||
import com.dfsek.terra.api.generic.world.Chunk;
|
||||
import com.dfsek.terra.api.generic.world.block.Block;
|
||||
import com.dfsek.terra.api.generic.world.block.BlockFace;
|
||||
import com.dfsek.terra.api.generic.world.vector.Vector2;
|
||||
import com.dfsek.terra.generation.items.PlaceableLayer;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class TreeLayer extends PlaceableLayer<Tree> {
|
||||
|
||||
public TreeLayer(double density, Range level, ProbabilityCollection<Tree> layer, FastNoiseLite noise) {
|
||||
super(density, level, layer, noise);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void place(Chunk chunk, Vector2 coords, Random random) {
|
||||
Tree item = layer.get(random);
|
||||
Block current = chunk.getBlock((int) coords.getX(), level.getMax(), (int) coords.getZ());
|
||||
for(int ignored : level) {
|
||||
current = current.getRelative(BlockFace.DOWN);
|
||||
if(item.getSpawnable().contains(current.getType())) {
|
||||
item.plant(current.getLocation().add(0, 1, 0), random);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user