Begin work on structure /locate, fix voxel geometry and add test commands, begin work on simplex caves

This commit is contained in:
dfsek 2020-10-04 02:23:35 -07:00
parent 188cf612fb
commit c80e65cce9
18 changed files with 583 additions and 46 deletions

View File

@ -6,7 +6,6 @@ import com.dfsek.terra.generation.TerraChunkGenerator;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
import org.bukkit.command.PluginCommand;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;

View File

@ -1,7 +1,15 @@
package com.dfsek.terra;
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.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionSelector;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
public class WorldEditUtil {
@ -11,4 +19,50 @@ public class WorldEditUtil {
Bukkit.getLogger().severe("[Terra] a command requiring WorldEdit was executed, but WorldEdit was not detected!");
return null;
}
public static Location[] getSelectionLocations(Player sender) {
WorldEditPlugin we = WorldEditUtil.getWorldEdit();
if(we == null) {
sender.sendMessage("WorldEdit is not installed! Please install WorldEdit before attempting to export structures.");
return null;
}
Region selection;
try {
selection = we.getSession(sender).getSelection(BukkitAdapter.adapt(sender.getWorld()));
} catch(IncompleteRegionException |ClassCastException e) {
sender.sendMessage("Invalid/incomplete selection!");
return null;
}
if(selection == null) {
sender.sendMessage("Please make a selection before attempting to export!");
return null;
}
BlockVector3 min = selection.getMinimumPoint();
BlockVector3 max = selection.getMaximumPoint();
Location l1 = new Location(sender.getWorld(), min.getBlockX(), min.getBlockY(), min.getBlockZ());
Location l2 = new Location(sender.getWorld(), max.getBlockX(), max.getBlockY(), max.getBlockZ());
return new Location[] {l1, l2};
}
public static Location[] getSelectionPositions(Player sender) {
WorldEditPlugin we = WorldEditUtil.getWorldEdit();
if(we == null) {
sender.sendMessage("WorldEdit is not installed! Please install WorldEdit before attempting to export structures.");
return null;
}
CuboidRegion selection;
try {
selection = (CuboidRegion) we.getSession(sender).getSelection(BukkitAdapter.adapt(sender.getWorld()));
} catch(IncompleteRegionException |ClassCastException e) {
sender.sendMessage("Invalid/incomplete selection!");
return null;
}
if(selection == null) {
sender.sendMessage("Please make a selection before attempting to export!");
return null;
}
BlockVector3 min = selection.getPos1();
BlockVector3 max = selection.getPos2();
Location l1 = new Location(sender.getWorld(), min.getBlockX(), min.getBlockY(), min.getBlockZ());
Location l2 = new Location(sender.getWorld(), max.getBlockX(), max.getBlockY(), max.getBlockZ());
return new Location[] {l1, l2};
}
}

View File

@ -0,0 +1,103 @@
package com.dfsek.terra.async;
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.StructureConfig;
import com.dfsek.terra.structure.GaeaStructure;
import com.dfsek.terra.structure.StructureSpawnRequirement;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import org.polydev.gaea.generation.GenerationPhase;
import org.polydev.gaea.profiler.ProfileFuture;
import java.util.Collections;
import java.util.Random;
public class AsyncStructureFinder implements Runnable {
private final TerraBiomeGrid grid;
private final StructureConfig target;
private final Player p;
private final int startRadius;
private final int maxRadius;
private final boolean tp;
private final int centerX;
private final int centerZ;
private final long seed;
private final World world;
public AsyncStructureFinder(TerraBiomeGrid grid, StructureConfig target, Player p, int startRadius, int maxRadius, boolean tp) {
this.grid = grid;
this.target = target;
this.p = p;
this.startRadius = startRadius;
this.maxRadius = maxRadius;
this.tp = tp;
this.centerX = p.getLocation().getBlockX();
this.centerZ = p.getLocation().getBlockZ();
this.seed = p.getWorld().getSeed();
this.world = p.getWorld();
}
@Override
public void run() {
int x = centerX;
int z = centerZ;
int wid = target.getSpawn().getWidth() + 2*target.getSpawn().getSeparation();
int run = 1;
boolean toggle = true;
boolean found = false;
main: for(int i = startRadius; i < maxRadius; i++) {
for(int j = 0; j < run; j++) {
if(toggle) x += 16;
else x -= 16;
if(hasValidSpawn(x, z)) {
found = true;
break main;
}
}
for(int j = 0; j < run; j++) {
if(toggle) z += 16;
else z -= 16;
if(hasValidSpawn(x, z)) {
found = true;
break main;
}
}
run++;
toggle = !toggle;
}
if(found) {
Vector v = target.getSpawn().getNearestSpawn(x, z, seed);
x = v.getBlockX();
z = v.getBlockZ();
p.sendMessage("Located structure at (" + x + ", " + z + ").");
if(tp) {
int finalX = x;
int finalZ = z;
Bukkit.getScheduler().runTask(Terra.getInstance(), () -> p.teleport(new Location(p.getWorld(), finalX, p.getLocation().getY(), finalZ)));
}
} else if(p.isOnline()) p.sendMessage("Unable to locate structure.");
}
private boolean hasValidSpawn(int x, int z) {
UserDefinedBiome b = (UserDefinedBiome) grid.getBiome(x, z, GenerationPhase.POPULATE);
Location spawn = target.getSpawn().getNearestSpawn(x, z, seed).toLocation(world); // Probably(tm) async safe
Random r2 = new Random(spawn.hashCode());
GaeaStructure struc = target.getStructure(r2);
main: for(int y = target.getSearchStart().get(r2); y > 0; y--) {
if(y > target.getBound().getMax() || y < target.getBound().getMin()) return false;
spawn.setY(y);
for(StructureSpawnRequirement s : struc.getSpawns()) {
if(! s.isValidSpawn(spawn)) continue main; // Probably(tm) async safe
if(!b.equals(grid.getBiome(spawn.clone().add(s.getX(), s.getY(), s.getZ()), GenerationPhase.POPULATE))) return false;
}
}
return true;
}
}

View File

@ -0,0 +1,72 @@
package com.dfsek.terra.carving;
import org.bukkit.World;
import org.bukkit.util.Vector;
import org.polydev.gaea.math.FastNoise;
import org.polydev.gaea.world.carving.Carver;
import org.polydev.gaea.world.carving.CarvingData;
import org.polydev.gaea.world.carving.Worm;
import java.util.Random;
public class SimplexCarver extends Carver {
private final FastNoise noise;
private final FastNoise height;
private final FastNoise column;
private final FastNoise hasCaves;
private final double root2inverse = 1D/Math.sqrt(2);
public SimplexCarver(int minY, int maxY) {
super(minY, maxY);
noise = new FastNoise(2403);
noise.setNoiseType(FastNoise.NoiseType.SimplexFractal);
noise.setFractalOctaves(3);
noise.setFrequency(0.02f);
height = new FastNoise(2404);
height.setNoiseType(FastNoise.NoiseType.Simplex);
height.setFrequency(0.01f);
column = new FastNoise(2404);
column.setNoiseType(FastNoise.NoiseType.SimplexFractal);
column.setFractalOctaves(5);
column.setFrequency(0.05f);
hasCaves = new FastNoise(2405);
hasCaves.setNoiseType(FastNoise.NoiseType.Simplex);
hasCaves.setFrequency(0.005f);
}
@Override
public Worm getWorm(long l, Vector vector) {
return null;
}
@Override
public boolean isChunkCarved(World world, int i, int i1, Random random) {
return true;
}
@Override
public CarvingData carve(int chunkX, int chunkZ, World w) {
CarvingData c = new CarvingData(chunkX, chunkZ);
int ox = chunkX << 4;
int oz = chunkZ << 4;
for(int x = ox; x < ox+16; x++) {
for(int z = oz; z < oz+16; z++) {
double heightNoise = height.getNoise(x, z);
double mainNoise = noise.getNoise(x, z)*2;
double columnNoise = Math.pow(Math.max(column.getNoise(x, z), 0)*2, 3);
double hc = (acot(16*(hasCaves.getNoise(x, z)-0.2))/Math.PI)-0.1;
for(int y = 0; y < 64; y++) {
double finalNoise = (-0.05*Math.abs(y-(heightNoise*16 + 24))+1 - (Math.pow(mainNoise + root2inverse, 3)/2 + columnNoise)) * hc;
if(finalNoise > 0.5) c.carve(x-ox, y, z-oz, CarvingData.CarvingType.CENTER);
}
}
}
return c;
}
private static double acot(double x) {
return Math.PI / 2 - Math.atan(x);
}
}

View File

@ -1,6 +1,7 @@
package com.dfsek.terra.command;
import com.dfsek.terra.command.biome.BiomeCommand;
import com.dfsek.terra.command.geometry.GeometryCommand;
import com.dfsek.terra.command.image.ImageCommand;
import com.dfsek.terra.command.profile.ProfileCommand;
import com.dfsek.terra.command.structure.StructureCommand;
@ -19,7 +20,8 @@ public class TerraCommand extends Command {
new ProfileCommand(),
new SaveDataCommand(),
new StructureCommand(),
new ImageCommand());
new ImageCommand(),
new GeometryCommand());
@Override
public String getName() {
@ -33,13 +35,6 @@ public class TerraCommand extends Command {
@Override
public boolean execute(@NotNull CommandSender sender, org.bukkit.command.@NotNull Command command, @NotNull String label, @NotNull String[] args) {
if(args.length > 0) {
for(com.dfsek.terra.command.type.Command c : commands) {
if(c.getName().equals(args[0])) return c.execute(sender, command, label, Arrays.stream(args, 1, args.length).toArray(String[]::new));
}
sender.sendMessage("Invalid command.");
return true;
} else {
sender.sendMessage("--------------------Terra--------------------");
sender.sendMessage("reload - Reload configuration data");
sender.sendMessage("biome - Get current biome");
@ -47,7 +42,6 @@ public class TerraCommand extends Command {
sender.sendMessage("save-data - Save population data");
sender.sendMessage("structure - Load and export structures");
sender.sendMessage("profile - Profiler options");
}
return true;
}

View File

@ -0,0 +1,71 @@
package com.dfsek.terra.command.geometry;
import com.dfsek.terra.command.type.PlayerCommand;
import com.dfsek.terra.procgen.voxel.DeformedSphere;
import com.dfsek.terra.procgen.voxel.Sphere;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.math.FastNoise;
import java.util.Collections;
import java.util.List;
public class DeformedSphereCommand extends PlayerCommand {
@Override
public boolean execute(@NotNull Player sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
int radius;
try {
radius = Integer.parseInt(args[0]);
} catch(NumberFormatException e) {
sender.sendMessage("Invalid radius: " + args[0]);
return true;
}
double deform;
try {
deform = Double.parseDouble(args[1]);
} catch(NumberFormatException e) {
sender.sendMessage("Invalid deform: " + args[1]);
return true;
}
float freq;
try {
freq = Float.parseFloat(args[2]);
} catch(NumberFormatException e) {
sender.sendMessage("Invalid frequency: " + args[2]);
return true;
}
FastNoise n = new FastNoise((int) sender.getWorld().getSeed());
n.setNoiseType(FastNoise.NoiseType.Simplex);
n.setFrequency(freq);
DeformedSphere sphere = new DeformedSphere(sender.getLocation().toVector(), radius, deform, n);
for(Vector v : sphere.getGeometry()) {
v.toLocation(sender.getWorld()).getBlock().setType(Material.STONE);
}
return true;
}
@Override
public String getName() {
return "deformedsphere";
}
@Override
public List<com.dfsek.terra.command.type.Command> getSubCommands() {
return Collections.emptyList();
}
@Override
public int arguments() {
return 3;
}
@Override
public List<String> getTabCompletions(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) {
return Collections.emptyList();
}
}

View File

@ -0,0 +1,43 @@
package com.dfsek.terra.command.geometry;
import com.dfsek.terra.command.type.PlayerCommand;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class GeometryCommand extends PlayerCommand {
@Override
public boolean execute(@NotNull Player sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
sender.sendMessage("---------------Terra/geometry----------------");
sender.sendMessage("Various voxel geometry debugging commands");
sender.sendMessage("sphere - Generate a sphere");
sender.sendMessage("deformsphere - Generate a deformed sphere");
sender.sendMessage("tube - Generate a tube");
return true;
}
@Override
public String getName() {
return "geometry";
}
@Override
public List<com.dfsek.terra.command.type.Command> getSubCommands() {
return Arrays.asList(new SphereCommand(), new TubeCommand(), new DeformedSphereCommand());
}
@Override
public int arguments() {
return 0;
}
@Override
public List<String> getTabCompletions(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) {
return Collections.emptyList();
}
}

View File

@ -0,0 +1,51 @@
package com.dfsek.terra.command.geometry;
import com.dfsek.terra.command.type.PlayerCommand;
import com.dfsek.terra.procgen.voxel.Sphere;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
public class SphereCommand extends PlayerCommand {
@Override
public boolean execute(@NotNull Player sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
int radius;
try {
radius = Integer.parseInt(args[0]);
} catch(NumberFormatException e) {
sender.sendMessage("Invalid radius: " + args[0]);
return true;
}
Sphere sphere = new Sphere(sender.getLocation().toVector(), radius);
for(Vector v : sphere.getGeometry()) {
v.toLocation(sender.getWorld()).getBlock().setType(Material.STONE);
}
return true;
}
@Override
public String getName() {
return "sphere";
}
@Override
public List<com.dfsek.terra.command.type.Command> getSubCommands() {
return Collections.emptyList();
}
@Override
public int arguments() {
return 1;
}
@Override
public List<String> getTabCompletions(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) {
return Collections.emptyList();
}
}

View File

@ -0,0 +1,60 @@
package com.dfsek.terra.command.geometry;
import com.dfsek.terra.WorldEditUtil;
import com.dfsek.terra.command.type.PlayerCommand;
import com.dfsek.terra.procgen.voxel.Tube;
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.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
public class TubeCommand extends PlayerCommand {
@Override
public boolean execute(@NotNull Player sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
Location[] l = WorldEditUtil.getSelectionPositions(sender);
if(l == null) return true;
int radius;
try {
radius = Integer.parseInt(args[0]);
} catch(NumberFormatException e) {
sender.sendMessage("Invalid radius: " + args[0]);
return true;
}
Tube tube = new Tube(l[0].toVector(), l[1].toVector(), radius);
for(Vector v : tube.getGeometry()) {
v.toLocation(sender.getWorld()).getBlock().setType(Material.STONE);
}
return true;
}
@Override
public String getName() {
return "tube";
}
@Override
public List<com.dfsek.terra.command.type.Command> getSubCommands() {
return Collections.emptyList();
}
@Override
public int arguments() {
return 1;
}
@Override
public List<String> getTabCompletions(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) {
return Collections.emptyList();
}
}

View File

@ -24,28 +24,11 @@ import java.util.List;
public class ExportCommand extends PlayerCommand {
@Override
public boolean execute(@NotNull Player sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
WorldEditPlugin we = WorldEditUtil.getWorldEdit();
if(we == null) {
sender.sendMessage("WorldEdit is not installed! Please install WorldEdit before attempting to export structures.");
return true;
}
Region selection;
try {
selection = we.getSession(sender).getSelection(BukkitAdapter.adapt(sender.getWorld()));
} catch(IncompleteRegionException e) {
sender.sendMessage("Invalid/incomplete selection!");
return true;
}
BukkitAdapter.adapt(sender);
if(selection == null) {
sender.sendMessage("Please make a selection before attempting to export!");
return true;
}
BlockVector3 min = selection.getMinimumPoint();
BlockVector3 max = selection.getMaximumPoint();
Location l1 = new Location(sender.getWorld(), min.getBlockX(), min.getBlockY(), min.getBlockZ());
Location l2 = new Location(sender.getWorld(), max.getBlockX(), max.getBlockY(), max.getBlockZ());
GaeaStructure structure = null;
Location[] l = WorldEditUtil.getSelectionLocations(sender);
if(l == null) return true;
Location l1 = l[0];
Location l2 = l[1];
GaeaStructure structure;
try {
structure = new GaeaStructure(l1, l2, args[0]);
} catch(InitializationException e) {

View File

@ -0,0 +1,74 @@
package com.dfsek.terra.command.structure;
import com.dfsek.terra.Terra;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.async.AsyncStructureFinder;
import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.command.type.WorldCommand;
import com.dfsek.terra.config.genconfig.StructureConfig;
import com.dfsek.terra.generation.TerraChunkGenerator;
import com.dfsek.terra.procgen.GridSpawn;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.structures.UserDefinedStructure;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
public class LocateCommand extends WorldCommand {
private final boolean tp;
public LocateCommand(boolean tp) {
this.tp = tp;
}
@Override
public boolean execute(@NotNull Player sender, @NotNull Command command, @NotNull String label, @NotNull String[] args, World world) {
String id = args[0];
int maxRadius;
try {
maxRadius = Integer.parseInt(args[1]);
} catch(NumberFormatException e) {
sender.sendMessage("Invalid radius: " + args[1]);
return true;
}
StructureConfig s;
try {
s = Objects.requireNonNull(TerraWorld.getWorld(world).getConfig().getStructure(id));
} catch(IllegalArgumentException | NullPointerException e) {
sender.sendMessage("Invalid biome ID: " + id);
return true;
}
Bukkit.getScheduler().runTaskAsynchronously(Terra.getInstance(), new AsyncStructureFinder(TerraWorld.getWorld(world).getGrid(), s, sender, 0, maxRadius, tp));
return true;
}
@Override
public String getName() {
return tp ? "tp" : "locate";
}
@Override
public List<com.dfsek.terra.command.type.Command> getSubCommands() {
return Collections.emptyList();
}
@Override
public int arguments() {
return 2;
}
@Override
public List<String> getTabCompletions(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) {
if(!(sender instanceof Player) || !(((Player) sender).getWorld().getGenerator() instanceof TerraChunkGenerator)) return Collections.emptyList();
List<String> ids = TerraWorld.getWorld(((Player) sender).getWorld()).getConfig().getStructureIDs();
if(args.length == 1) return ids.stream().filter(string -> string.toUpperCase().startsWith(args[0].toUpperCase())).collect(Collectors.toList());
return Collections.emptyList();
}
}

View File

@ -21,7 +21,7 @@ public class StructureCommand extends PlayerCommand {
@Override
public List<com.dfsek.terra.command.type.Command> getSubCommands() {
return Arrays.asList(new ExportCommand(), new LoadCommand());
return Arrays.asList(new ExportCommand(), new LoadCommand(), new LocateCommand(false), new LocateCommand(true));
}
@Override
@ -31,7 +31,7 @@ public class StructureCommand extends PlayerCommand {
@Override
public int arguments() {
return 1;
return 0;
}
@Override

View File

@ -181,6 +181,14 @@ public class ConfigPack extends YamlConfiguration {
return fill;
}
public List<String> getStructureIDs() {
List<String> fill = new ArrayList<>();
for(StructureConfig s : structures.values()) {
fill.add(s.getID());
}
return fill;
}
public FloraConfig getFlora(String id) {
return flora.get(id);
}

View File

@ -149,7 +149,7 @@ public class TerraChunkGenerator extends GaeaChunkGenerator {
for(Map.Entry<World, PopulationManager> e : popMap.entrySet()) {
try {
e.getValue().saveBlocks(e.getKey());
Debug.info("[Terra] Saved data for world " + e.getKey().getName());
Debug.info("Saved data for world " + e.getKey().getName());
} catch(IOException ioException) {
ioException.printStackTrace();
}

View File

@ -2,6 +2,7 @@ package com.dfsek.terra.population;
import com.dfsek.terra.TerraProfiler;
import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.carving.SimplexCarver;
import com.dfsek.terra.config.ConfigPack;
import com.dfsek.terra.config.base.ConfigUtil;
import com.dfsek.terra.config.genconfig.CarverConfig;
@ -31,6 +32,7 @@ public class CavePopulator extends BlockPopulator {
if(ConfigUtil.masterDisableCaves) return;
try(ProfileFuture ignored = TerraProfiler.fromWorld(world).measure("CaveTime")) {
ConfigPack config = TerraWorld.getWorld(world).getConfig();
for(CarverConfig c : config.getCarvers().values()) {
Map<Location, Material> shiftCandidate = new HashMap<>();
Set<Block> updateNeeded = new HashSet<>();
@ -78,6 +80,10 @@ public class CavePopulator extends BlockPopulator {
b.setBlockData(orig, true);
}
}
for(Map.Entry<Vector, CarvingData.CarvingType> e : new SimplexCarver(chunk.getX(), chunk.getZ()).carve(chunk.getX(), chunk.getZ(), world).getCarvedBlocks().entrySet()) {
Vector v = e.getKey();
chunk.getBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ()).setBlockData(AIR, false);
}
}
}

View File

@ -7,6 +7,9 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* Class to procedurally determine the spawn point of an object based on a grid with padding between cells.
*/
public class GridSpawn {
private final int separation;
private final int width;
@ -16,7 +19,7 @@ public class GridSpawn {
}
/**
* Get nearest spawnpoint
* Get nearest spawn point
* @param x X coordinate
* @param z Z coordinate
* @param seed Seed for RNG
@ -40,7 +43,7 @@ public class GridSpawn {
}
/**
* Get the X/Z coordinates of the spawnpoint in the nearest Chunk (not Minecraft chunk)
* Get the X/Z coordinates of the spawn point in the nearest Chunk (not Minecraft chunk)
* @param structureChunkX Chunk X coordinate
* @param structureChunkZ Chunk Z coordinate
* @param seed Seed for RNG
@ -54,4 +57,12 @@ public class GridSpawn {
int sz = structureChunkZ * (width + 2*separation) + offsetZ;
return new Vector(sx, 0, sz);
}
public int getWidth() {
return width;
}
public int getSeparation() {
return separation;
}
}

View File

@ -0,0 +1,9 @@
package com.dfsek.terra.procgen.voxel;
import org.bukkit.util.Vector;
public class Cylinder extends VoxelGeometry {
public Cylinder(Vector start, int rad, int height) {
}
}

View File

@ -20,7 +20,6 @@ public abstract class VoxelGeometry {
geometry.addAll(other.getGeometry());
}
public static VoxelGeometry getBlank() {
return new Blank();
return new VoxelGeometry() {};
}
private static class Blank extends VoxelGeometry {}
}