Performance improvements

This commit is contained in:
dfsek 2020-09-30 21:18:30 -07:00
parent ca5accafa2
commit 0f29a506d0
20 changed files with 281 additions and 109 deletions

View File

@ -95,7 +95,7 @@
<dependency>
<groupId>org.polydev</groupId>
<artifactId>gaea</artifactId>
<version>1.10.48</version>
<version>1.10.80</version>
</dependency>
<dependency>
<groupId>me.lucko</groupId>

View File

@ -10,14 +10,13 @@ import com.dfsek.terra.generation.TerraChunkGenerator;
import com.dfsek.terra.image.WorldImageGenerator;
import com.dfsek.terra.structure.GaeaStructure;
import com.dfsek.terra.structure.InitializationException;
import com.dfsek.terra.structure.StructureSpawn;
import com.dfsek.terra.procgen.GridSpawn;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
@ -33,7 +32,6 @@ import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Random;
public class TerraCommand implements CommandExecutor, TabExecutor {
@ -189,7 +187,7 @@ public class TerraCommand implements CommandExecutor, TabExecutor {
}
return true;
} else if("getspawn".equals(args[1])) {
Vector v = new StructureSpawn(250, 250).getNearestSpawn(pl.getLocation().getBlockX(), pl.getLocation().getBlockZ(), pl.getWorld().getSeed());
Vector v = new GridSpawn(250, 250).getNearestSpawn(pl.getLocation().getBlockX(), pl.getLocation().getBlockZ(), pl.getWorld().getSeed());
sender.sendMessage(v.getBlockX() + ":" + v.getBlockZ());
}
}

View File

@ -45,8 +45,8 @@ public enum TerraTree implements Tree {
}
@Override
public void plant(Location location, Random random, boolean b, JavaPlugin javaPlugin) {
if(!validSpawns.contains(location.clone().subtract(0, 1, 0).getBlock().getType())) return;
public boolean plant(Location location, Random random, boolean b, JavaPlugin javaPlugin) {
if(!validSpawns.contains(location.clone().subtract(0, 1, 0).getBlock().getType())) return false;
NMSStructure temp = getInstance(location, random);
int[] size = temp.getDimensions();
switch(random.nextInt(4)) {
@ -67,6 +67,6 @@ public enum TerraTree implements Tree {
break;
}
temp.paste();
//location.getBlock().setType(Material.GOLD_BLOCK);
return true;
}
}

View File

@ -0,0 +1,50 @@
package com.dfsek.terra.carving;
import com.dfsek.terra.procgen.GridSpawn;
import com.dfsek.terra.procgen.voxel.DeformedSphere;
import com.dfsek.terra.procgen.voxel.Tube;
import com.dfsek.terra.procgen.voxel.VoxelGeometry;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.util.Vector;
import org.polydev.gaea.math.FastNoise;
import org.polydev.gaea.math.MathUtil;
import org.polydev.gaea.world.carving.CarvingData;
import java.util.Random;
public class Cavern {
private final Node node;
private final long seed;
public Cavern(World w) {
this.node = new Node(w);
this.seed = w.getSeed();
}
public VoxelGeometry carveChunk(int chunkX, int chunkZ) {
long seedC = MathUtil.getCarverChunkSeed(chunkX, chunkZ, seed);
Random chunk = new Random(seedC);
Vector org = node.getNodeLocation((chunkX << 4)+8, (chunkZ << 4)+8).clone().setY(chunk.nextInt(128));
VoxelGeometry carve = VoxelGeometry.getBlank();
FastNoise smpl = new FastNoise((int) seedC);
smpl.setFrequency(0.01f);
smpl.setNoiseType(FastNoise.NoiseType.Simplex);
Bukkit.getLogger().info("Cavern: " + org.toString());
carve.merge(new DeformedSphere(org.clone(), chunk.nextInt(4)+3, 0.75, smpl));
Vector _00 = new Vector(org.getX()+16, new Random(MathUtil.getCarverChunkSeed(chunkX+1, chunkZ, seed)).nextInt(128), org.getZ());
carve.merge(new Tube(org, _00, 4));
return carve;
}
public static class Node {
private final long seed;
private final GridSpawn spawn = new GridSpawn(16, 0);
public Node(World w) {
this.seed = w.getSeed();
}
public Vector getNodeLocation(int x, int z) {
return spawn.getNearestSpawn(x, z, seed);
}
}
}

View File

@ -10,6 +10,8 @@ import org.polydev.gaea.generation.GenerationPhase;
import org.polydev.gaea.world.carving.Carver;
import org.polydev.gaea.world.carving.Worm;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class UserDefinedCarver extends Carver {
@ -21,6 +23,7 @@ public class UserDefinedCarver extends Carver {
private final int hash;
private final int topCut;
private final int bottomCut;
public UserDefinedCarver(Range height, Range radius, Range length, double[] start, double[] mutate, double[] radiusMultiplier, int hash, int topCut, int bottomCut) {
super(height.getMin(), height.getMax());
this.radius = radius;
@ -36,7 +39,7 @@ public class UserDefinedCarver extends Carver {
@Override
public Worm getWorm(long l, Vector vector) {
Random r = new Random(l+hash);
return new UserDefinedWorm(length.get(r), r, vector, radius.getMax(), topCut, bottomCut);
return new UserDefinedWorm((int) (length.get(r)/2), r, vector, radius.getMax(), topCut, bottomCut);
}
@Override
@ -54,7 +57,7 @@ public class UserDefinedCarver extends Carver {
super.setBottomCut(bottomCut);
runningRadius = radius.get(r);
this.maxRad = maxRad;
direction = new Vector((r.nextDouble()-0.5D)*start[0], (r.nextDouble()-0.5D)*start[1], (r.nextDouble()-0.5D)*start[2]).normalize();
direction = new Vector((r.nextDouble()-0.5D)*start[0], (r.nextDouble()-0.5D)*start[1], (r.nextDouble()-0.5D)*start[2]).normalize().multiply(2);
}
@Override
@ -62,9 +65,9 @@ public class UserDefinedCarver extends Carver {
setRadius(new int[] {(int) (runningRadius*radiusMultiplier[0]), (int) (runningRadius*radiusMultiplier[1]), (int) (runningRadius*radiusMultiplier[2])});
runningRadius += (getRandom().nextDouble()-0.5)*mutate[3];
runningRadius = Math.max(Math.min(runningRadius, maxRad), 1);
direction.rotateAroundX(Math.toRadians(getRandom().nextDouble()*mutate[0]));
direction.rotateAroundY(Math.toRadians(getRandom().nextDouble()*mutate[1]));
direction.rotateAroundZ(Math.toRadians(getRandom().nextDouble()*mutate[2]));
direction.rotateAroundX(Math.toRadians(getRandom().nextDouble()*mutate[0]*2));
direction.rotateAroundY(Math.toRadians(getRandom().nextDouble()*mutate[1]*2));
direction.rotateAroundZ(Math.toRadians(getRandom().nextDouble()*mutate[2]*2));
getRunning().add(direction);
}
}

View File

@ -1,6 +1,5 @@
package com.dfsek.terra.config.genconfig;
import com.dfsek.terra.config.ConfigLoader;
import com.dfsek.terra.config.ConfigUtil;
import com.dfsek.terra.config.TerraConfigObject;
import org.bukkit.Bukkit;
@ -9,7 +8,6 @@ import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.plugin.java.JavaPlugin;
import org.polydev.gaea.math.FastNoise;
import java.io.File;

View File

@ -6,9 +6,7 @@ import com.dfsek.terra.config.ConfigUtil;
import com.dfsek.terra.config.TerraConfigObject;
import com.dfsek.terra.population.StructurePopulator;
import com.dfsek.terra.structure.GaeaStructure;
import com.dfsek.terra.structure.StructureSpawn;
import com.dfsek.terra.structure.StructureSpawnRequirement;
import org.bukkit.Bukkit;
import com.dfsek.terra.procgen.GridSpawn;
import org.bukkit.configuration.InvalidConfigurationException;
import java.io.File;
@ -20,7 +18,7 @@ import java.util.Objects;
public class StructureConfig extends TerraConfigObject {
private static final Map<String, StructureConfig> configs = new HashMap<>();
private GaeaStructure structure;
private StructureSpawn spawn;
private GridSpawn spawn;
private String id;
private Range searchStart;
private Range bound;
@ -42,7 +40,7 @@ public class StructureConfig extends TerraConfigObject {
}
if(!contains("id")) throw new InvalidConfigurationException("No ID specified!");
id = getString("id");
spawn = new StructureSpawn(getInt("spawn.width", 500), getInt("spawn.padding", 100));
spawn = new GridSpawn(getInt("spawn.width", 500), getInt("spawn.padding", 100));
searchStart = new Range(getInt("spawn.start.min", 72), getInt("spawn.start.max", 72));
bound = new Range(getInt("spawn.bound.min", 48), getInt("spawn.bound.max", 72));
try {
@ -62,7 +60,7 @@ public class StructureConfig extends TerraConfigObject {
return structure;
}
public StructureSpawn getSpawn() {
public GridSpawn getSpawn() {
return spawn;
}

View File

@ -37,59 +37,13 @@ public class SlabGenerator extends GenerationPopulator {
if(config.getSlabs() == null) continue;
double thresh = config.getSlabThreshold();
for(int y = 0; y < world.getMaxHeight(); y++) {
if(chunk.getType(x, y, z).isSolid()) continue;
prepareBlockPart(interp, chunk, new Vector(x, y, z), config.getSlabs(), config.getStairs(), thresh);
}
}
}
return chunk;
}
private static void prepareBlockPart(ChunkInterpolator interp, ChunkGenerator.ChunkData chunk, Vector block, Map<Material, Palette<BlockData>> slabs, Map<Material, Palette<BlockData>> stairs, double thresh) {
BlockData down = chunk.getBlockData(block.getBlockX(), block.getBlockY()-1, block.getBlockZ());
double _11 = interp.getNoise(block.getBlockX(), block.getBlockY() - 0.4, block.getBlockZ());
if(_11 > thresh) {
BlockData orig = chunk.getBlockData(block.getBlockX(), block.getBlockY(), block.getBlockZ());
//double _00 = interp.getNoise(block.getBlockX() - 0.5, block.getBlockY(), block.getBlockZ() - 0.5);
double _01 = interp.getNoise(block.getBlockX() - 0.5, block.getBlockY(), block.getBlockZ());
//double _02 = interp.getNoise(block.getBlockX() - 0.5, block.getBlockY(), block.getBlockZ() + 0.5);
double _10 = interp.getNoise(block.getBlockX(), block.getBlockY(), block.getBlockZ() - 0.5);
double _12 = interp.getNoise(block.getBlockX(), block.getBlockY(), block.getBlockZ() + 0.5);
//double _20 = interp.getNoise(block.getBlockX() + 0.5, block.getBlockY(), block.getBlockZ() - 0.5);
double _21 = interp.getNoise(block.getBlockX() + 0.5, block.getBlockY(), block.getBlockZ());
//double _22 = interp.getNoise(block.getBlockX() + 0.5, block.getBlockY(), block.getBlockZ() + 0.5);
if(stairs != null) {
Palette<BlockData> stairPalette = stairs.get(down.getMaterial());
if(stairPalette != null) {
BlockData stair = stairPalette.get(0, block.getBlockX(), block.getBlockZ());
Stairs finalStair = getStair(new double[] {_01, _10, _12, _21}, (Stairs) stair, thresh);
if(finalStair != null) {
if(orig.matches(WATER)) finalStair.setWaterlogged(true);
chunk.setBlock(block.getBlockX(), block.getBlockY(), block.getBlockZ(), finalStair);
return;
}
}
}
BlockData slab = slabs.getOrDefault(down.getMaterial(), AIRPALETTE).get(0, block.getBlockX(), block.getBlockZ());
if(slab instanceof Waterlogged) {
((Waterlogged) slab).setWaterlogged(orig.matches(WATER));
} else if(orig.matches(WATER)) return;
chunk.setBlock(block.getBlockX(), block.getBlockY(), block.getBlockZ(), slab);
}
}
private static Stairs getStair(double[] vals, Stairs stair, double thresh) {
if(vals.length != 4) throw new IllegalArgumentException();
Stairs stairNew = (Stairs) stair.clone();
if(vals[0] > thresh) {
stairNew.setFacing(BlockFace.WEST);
} else if(vals[1] > thresh) {
stairNew.setFacing(BlockFace.NORTH);
} else if(vals[2] > thresh) {
stairNew.setFacing(BlockFace.SOUTH);
} else if(vals[3] > thresh) {
stairNew.setFacing(BlockFace.EAST);
} else return null;
return stairNew;
}
}

View File

@ -1,8 +1,8 @@
package com.dfsek.terra.generation;
import com.dfsek.terra.Terra;
import com.dfsek.terra.biome.TerraBiomeGrid;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.config.WorldConfig;
import com.dfsek.terra.config.genconfig.BiomeConfig;
import com.dfsek.terra.population.CavePopulator;
import com.dfsek.terra.population.FloraPopulator;
@ -13,11 +13,15 @@ import com.dfsek.terra.structure.StructureSpawnRequirement;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.block.data.type.Stairs;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.biome.Biome;
import org.polydev.gaea.biome.BiomeGrid;
import org.polydev.gaea.generation.GaeaChunkGenerator;
import org.polydev.gaea.generation.GenerationPhase;
import org.polydev.gaea.generation.GenerationPopulator;
@ -25,6 +29,7 @@ import org.polydev.gaea.math.ChunkInterpolator;
import org.polydev.gaea.math.FastNoise;
import org.polydev.gaea.population.PopulationManager;
import org.polydev.gaea.world.palette.Palette;
import org.polydev.gaea.world.palette.RandomPalette;
import java.io.FileNotFoundException;
import java.io.IOException;
@ -36,10 +41,10 @@ import java.util.Map;
import java.util.Random;
public class TerraChunkGenerator extends GaeaChunkGenerator {
private static final BlockData STONE = Material.STONE.createBlockData();
private static final BlockData WATER = Material.WATER.createBlockData();
private final PopulationManager popMan = new PopulationManager();
private final PopulationManager popMan = new PopulationManager(Terra.getInstance());
private boolean needsLoad = true;
private static final Map<World, PopulationManager> popMap = new HashMap<>();
public TerraChunkGenerator() {
@ -58,21 +63,79 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
int zOrig = (chunkZ << 4);
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 = getBiomeGrid(world).getBiome(xOrig+x, zOrig+z, GenerationPhase.PALETTE_APPLY);
BiomeConfig c = BiomeConfig.fromBiome((UserDefinedBiome) b);
int sea = c.getSeaLevel();
Palette<BlockData> seaPalette = c.getOceanPalette();
for(int y = 0; y < 256; y++) {
if(super.getInterpolatedNoise(x, y, z) > 0) chunk.setBlock(x, y, z, STONE);
else if(y <= sea) {
for(int y = world.getMaxHeight()-1; y >= 0; y--) {
BlockData data;
if(super.getInterpolatedNoise(x, y, z) > 0) {
data = b.getGenerator().getPalette(y).get(paletteLevel, cx, cz);
chunk.setBlock(x, y, z, data);
if(paletteLevel == 0 && c.getSlabs() != null) {
prepareBlockPart(data, chunk.getBlockData(x, y+1, z), chunk, new Vector(x, y+1, z), c.getSlabs(), c.getStairs(), c.getSlabThreshold());
}
paletteLevel++;
} else if(y <= sea) {
chunk.setBlock(x, y, z, seaPalette.get(sea-y, x+xOrig, z+zOrig));
}
paletteLevel = 0;
} else paletteLevel = 0;
}
}
}
return chunk;
}
private void prepareBlockPart(BlockData down, BlockData orig, ChunkData chunk, Vector block, Map<Material, Palette<BlockData>> slabs, Map<Material, Palette<BlockData>> stairs, double thresh) {
double _11 = getInterpolatedNoise(block.getBlockX(), block.getBlockY() - 0.4, block.getBlockZ());
if(_11 > thresh) {
//double _00 = interp.getNoise(block.getBlockX() - 0.5, block.getBlockY(), block.getBlockZ() - 0.5);
double _01 = getInterpolatedNoise(block.getBlockX() - 0.5, block.getBlockY(), block.getBlockZ());
//double _02 = interp.getNoise(block.getBlockX() - 0.5, block.getBlockY(), block.getBlockZ() + 0.5);
double _10 = getInterpolatedNoise(block.getBlockX(), block.getBlockY(), block.getBlockZ() - 0.5);
double _12 = getInterpolatedNoise(block.getBlockX(), block.getBlockY(), block.getBlockZ() + 0.5);
//double _20 = interp.getNoise(block.getBlockX() + 0.5, block.getBlockY(), block.getBlockZ() - 0.5);
double _21 = getInterpolatedNoise(block.getBlockX() + 0.5, block.getBlockY(), block.getBlockZ());
//double _22 = interp.getNoise(block.getBlockX() + 0.5, block.getBlockY(), block.getBlockZ() + 0.5);
if(stairs != null) {
Palette<BlockData> stairPalette = stairs.get(down.getMaterial());
if(stairPalette != null) {
BlockData stair = stairPalette.get(0, block.getBlockX(), block.getBlockZ());
Stairs finalStair = getStair(new double[] {_01, _10, _12, _21}, (Stairs) stair, thresh);
if(finalStair != null) {
if(orig.matches(Util.WATER)) finalStair.setWaterlogged(true);
chunk.setBlock(block.getBlockX(), block.getBlockY(), block.getBlockZ(), finalStair);
return;
}
}
}
BlockData slab = slabs.getOrDefault(down.getMaterial(), Util.BLANK_PALETTE).get(0, block.getBlockX(), block.getBlockZ());
if(slab instanceof Waterlogged) {
((Waterlogged) slab).setWaterlogged(orig.matches(Util.WATER));
} else if(orig.matches(Util.WATER)) return;
chunk.setBlock(block.getBlockX(), block.getBlockY(), block.getBlockZ(), slab);
}
}
private static Stairs getStair(double[] vals, Stairs stair, double thresh) {
if(vals.length != 4) throw new IllegalArgumentException();
Stairs stairNew = (Stairs) stair.clone();
if(vals[0] > thresh) {
stairNew.setFacing(BlockFace.WEST);
} else if(vals[1] > thresh) {
stairNew.setFacing(BlockFace.NORTH);
} else if(vals[2] > thresh) {
stairNew.setFacing(BlockFace.SOUTH);
} else if(vals[3] > thresh) {
stairNew.setFacing(BlockFace.EAST);
} else return null;
return stairNew;
}
private void load(World w) {
try {
popMan.loadBlocks(w);

View File

@ -23,19 +23,29 @@ public class UserDefinedGenerator extends Generator {
private final Variable xVar = s.getVariable("x");
private final Variable yVar = s.getVariable("y");
private final Variable zVar = s.getVariable("z");
private final TreeMap<Integer, Palette<BlockData>> paletteMap;
@SuppressWarnings("unchecked")
private final Palette<BlockData>[] palettes = new Palette[256];
private final NoiseFunction2 n2 = new NoiseFunction2();
private final NoiseFunction3 n3 = new NoiseFunction3();
private static final Object noiseLock = new Object();
public UserDefinedGenerator(String e, List<Variable> v, TreeMap<Integer, Palette<BlockData>> pa) throws ParseException {
public UserDefinedGenerator(String equation, List<Variable> v, TreeMap<Integer, Palette<BlockData>> pa) throws ParseException {
Parser p = new Parser();
p.registerFunction("noise2", n2);
p.registerFunction("noise3", n3);
this.paletteMap = pa;
this.noiseExp = p.parse(e, s);
for(int y = 0; y < 256; y++) {
Palette<BlockData> d = Util.BLANK_PALETTE;
for(Map.Entry<Integer, Palette<BlockData>> e : pa.entrySet()) {
if(e.getKey() >= y) {
d = e.getValue();
break;
}
}
palettes[y] = d;
}
this.noiseExp = p.parse(equation, s);
}
/**
* Gets the 2D noise at a pair of coordinates using the provided FastNoise instance.
@ -85,9 +95,6 @@ public class UserDefinedGenerator extends Generator {
*/
@Override
public Palette<BlockData> getPalette(int y) {
for(Map.Entry<Integer, Palette<BlockData>> e : paletteMap.entrySet()) {
if(e.getKey() >= y ) return e.getValue();
}
return null;
return palettes[y];
}
}

View File

@ -0,0 +1,15 @@
package com.dfsek.terra.generation;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.polydev.gaea.world.palette.Palette;
import org.polydev.gaea.world.palette.RandomPalette;
import java.util.Random;
public class Util {
public static final BlockData STONE = Material.STONE.createBlockData();
public static final BlockData WATER = Material.WATER.createBlockData();
public static final BlockData AIR = Material.AIR.createBlockData();
public static final Palette<BlockData> BLANK_PALETTE = new RandomPalette<BlockData>(new Random(2403)).add(AIR, 1);
}

View File

@ -16,6 +16,7 @@ import org.polydev.gaea.world.carving.CarvingData;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

View File

@ -22,8 +22,7 @@ public class OrePopulator extends GaeaBlockPopulator {
@Override
public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk chunk) {
try (ProfileFuture ignored = TerraProfiler.fromWorld(world).measure("OreTime")) {
Location l = chunk.getBlock(8, 0, 0).getLocation();
Biome b = TerraBiomeGrid.fromWorld(world).getBiome(l.getBlockX(), l.getBlockZ(), GenerationPhase.POPULATE);
Biome b = TerraBiomeGrid.fromWorld(world).getBiome((chunk.getX() << 4)+8, (chunk.getZ() << 4) + 8, GenerationPhase.POPULATE);
for(Map.Entry<OreConfig, Range> e : BiomeConfig.fromBiome((UserDefinedBiome) b).getOres().entrySet()) {
int num = e.getValue().get(random);
for(int i = 0; i < num; i++) {

View File

@ -1,13 +1,11 @@
package com.dfsek.terra.population;
import com.dfsek.terra.Terra;
import com.dfsek.terra.TerraProfiler;
import com.dfsek.terra.biome.TerraBiomeGrid;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.config.genconfig.BiomeConfig;
import com.dfsek.terra.config.genconfig.StructureConfig;
import com.dfsek.terra.structure.GaeaStructure;
import com.dfsek.terra.structure.StructureSpawn;
import com.dfsek.terra.structure.StructureSpawnRequirement;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
@ -16,16 +14,10 @@ import org.bukkit.World;
import org.bukkit.generator.BlockPopulator;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.generation.GenerationPhase;
import org.polydev.gaea.population.GaeaBlockPopulator;
import org.polydev.gaea.profiler.ProfileFuture;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
public class StructurePopulator extends BlockPopulator {

View File

@ -25,18 +25,18 @@ public class TreePopulator extends GaeaBlockPopulator {
Location origin = chunk.getBlock(x, 0, z).getLocation();
Biome b = TerraBiomeGrid.fromWorld(world).getBiome(origin, GenerationPhase.POPULATE);
if(((UserDefinedDecorator) b.getDecorator()).getTreeChance() < random.nextInt(100)) return;
int numTrees = 0;
for(int i = 0; i < 48; i++) {
int max = 50;
int att = 0;
for(int i = 0; i < b.getDecorator().getTreeDensity() && att < max; ) {
att++;
int y = WorldUtil.getHighestValidSpawnAt(chunk, x, z);
if(y <= 0) continue;
origin = chunk.getBlock(x, y, z).getLocation().add(0, 1, 0);
b = TerraBiomeGrid.fromWorld(world).getBiome(origin, GenerationPhase.POPULATE);
numTrees++;
try {
b.getDecorator().getTrees().get(random).plant(origin, random, false, Terra.getInstance());
if(b.getDecorator().getTrees().get(random).plant(origin, random, false, Terra.getInstance())) i++;
} catch(NullPointerException ignore) {}
if(numTrees >= b.getDecorator().getTreeDensity()) break;
x = random.nextInt(16); // Decrease chances of chunk-crossing trees
x = random.nextInt(16);
z = random.nextInt(16);
}
}

View File

@ -1,7 +1,5 @@
package com.dfsek.terra.structure;
package com.dfsek.terra.procgen;
import com.dfsek.terra.config.ConfigUtil;
import org.bukkit.Bukkit;
import org.bukkit.util.Vector;
import org.polydev.gaea.math.MathUtil;
@ -9,20 +7,28 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class StructureSpawn {
public class GridSpawn {
private final int separation;
private final int width;
public StructureSpawn(int width, int separation) {
public GridSpawn(int width, int separation) {
this.separation = separation;
this.width = width;
}
/**
* Get nearest spawnpoint
* @param x X coordinate
* @param z Z coordinate
* @param seed Seed for RNG
* @return Vector representing nearest spawnpoint
*/
public Vector getNearestSpawn(int x, int z, long seed) {
int structureChunkX = x / (width + 2*separation);
int structureChunkZ = z / (width + 2*separation);
List<Vector> zones = new ArrayList<>();
for(int xi = structureChunkX-1; xi <= structureChunkX+1; xi++) {
for(int zi = structureChunkZ-1; zi <= structureChunkZ+1; zi++) {
zones.add(getStructureChunkSpawn(xi, zi, seed));
zones.add(getChunkSpawn(xi, zi, seed));
}
}
Vector shortest = zones.get(0);
@ -32,7 +38,15 @@ public class StructureSpawn {
}
return shortest;
}
private Vector getStructureChunkSpawn(int structureChunkX, int structureChunkZ, long seed) {
/**
* Get the X/Z coordinates of the spawnpoint in the nearest Chunk (not Minecraft chunk)
* @param structureChunkX Chunk X coordinate
* @param structureChunkZ Chunk Z coordinate
* @param seed Seed for RNG
* @return Vector representing spawnpoint
*/
private Vector getChunkSpawn(int structureChunkX, int structureChunkZ, long seed) {
Random r = new Random(MathUtil.getCarverChunkSeed(structureChunkX, structureChunkZ, seed));
int offsetX = r.nextInt(width);
int offsetZ = r.nextInt(width);

View File

@ -0,0 +1,20 @@
package com.dfsek.terra.procgen.voxel;
import org.bukkit.block.Block;
import org.bukkit.util.Vector;
import org.polydev.gaea.math.FastNoise;
public class DeformedSphere extends VoxelGeometry {
public DeformedSphere(Vector start, int rad, double deform, FastNoise noise) {
for(int x = -rad; x <= rad; x++) {
for(int y = -rad; y <= rad; y++) {
for(int z = -rad; z <= rad; z++) {
Vector c = new Vector(x, y, z);
if(c.length() < (rad + 0.5) * ((noise.getNoise(x, y, z)+1)*deform)) {
addVector(c.add(start));
}
}
}
}
}
}

View File

@ -0,0 +1,19 @@
package com.dfsek.terra.procgen.voxel;
import org.bukkit.util.Vector;
import org.polydev.gaea.math.FastNoise;
public class Sphere extends VoxelGeometry {
public Sphere(Vector start, int rad) {
for(int x = -rad; x <= rad; x++) {
for(int y = -rad; y <= rad; y++) {
for(int z = -rad; z <= rad; z++) {
Vector c = new Vector(x, y, z);
if(c.length() < rad + 0.5) {
addVector(c.add(start));
}
}
}
}
}
}

View File

@ -0,0 +1,15 @@
package com.dfsek.terra.procgen.voxel;
import org.bukkit.util.Vector;
public class Tube extends VoxelGeometry {
public Tube(Vector start, Vector end, int radius) {
Vector step = start.clone().subtract(end).normalize();
Vector run = start.clone();
int steps = (int) start.distance(end);
for(int i = 0; i < steps; i++) {
merge(new Sphere(run, radius));
run.add(step);
}
}
}

View File

@ -0,0 +1,26 @@
package com.dfsek.terra.procgen.voxel;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.List;
public abstract class VoxelGeometry {
public List<Vector> geometry = new ArrayList<>();
public List<Vector> getGeometry() {
return geometry;
}
protected void addVector(Vector v) {
geometry.add(v);
}
public void merge(VoxelGeometry other) {
geometry.addAll(other.getGeometry());
}
public static VoxelGeometry getBlank() {
return new Blank();
}
private static class Blank extends VoxelGeometry {}
}