diff --git a/src/main/java/com/dfsek/terra/Terra.java b/src/main/java/com/dfsek/terra/Terra.java index 027a59085..54d2dff75 100644 --- a/src/main/java/com/dfsek/terra/Terra.java +++ b/src/main/java/com/dfsek/terra/Terra.java @@ -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; diff --git a/src/main/java/com/dfsek/terra/WorldEditUtil.java b/src/main/java/com/dfsek/terra/WorldEditUtil.java index addad5f32..bfc7ed642 100644 --- a/src/main/java/com/dfsek/terra/WorldEditUtil.java +++ b/src/main/java/com/dfsek/terra/WorldEditUtil.java @@ -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}; + } } diff --git a/src/main/java/com/dfsek/terra/async/AsyncStructureFinder.java b/src/main/java/com/dfsek/terra/async/AsyncStructureFinder.java new file mode 100644 index 000000000..35730d9d2 --- /dev/null +++ b/src/main/java/com/dfsek/terra/async/AsyncStructureFinder.java @@ -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; + } +} diff --git a/src/main/java/com/dfsek/terra/carving/SimplexCarver.java b/src/main/java/com/dfsek/terra/carving/SimplexCarver.java new file mode 100644 index 000000000..2713d4ccb --- /dev/null +++ b/src/main/java/com/dfsek/terra/carving/SimplexCarver.java @@ -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); + } +} diff --git a/src/main/java/com/dfsek/terra/command/TerraCommand.java b/src/main/java/com/dfsek/terra/command/TerraCommand.java index 2072e9bd0..d822aeba7 100644 --- a/src/main/java/com/dfsek/terra/command/TerraCommand.java +++ b/src/main/java/com/dfsek/terra/command/TerraCommand.java @@ -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,21 +35,13 @@ 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"); - sender.sendMessage("ore - Generate an ore vein at the location you are facing (For debugging)"); - sender.sendMessage("save-data - Save population data"); - sender.sendMessage("structure - Load and export structures"); - sender.sendMessage("profile - Profiler options"); - } + sender.sendMessage("--------------------Terra--------------------"); + sender.sendMessage("reload - Reload configuration data"); + sender.sendMessage("biome - Get current biome"); + sender.sendMessage("ore - Generate an ore vein at the location you are facing (For debugging)"); + sender.sendMessage("save-data - Save population data"); + sender.sendMessage("structure - Load and export structures"); + sender.sendMessage("profile - Profiler options"); return true; } diff --git a/src/main/java/com/dfsek/terra/command/geometry/DeformedSphereCommand.java b/src/main/java/com/dfsek/terra/command/geometry/DeformedSphereCommand.java new file mode 100644 index 000000000..bfc3b679b --- /dev/null +++ b/src/main/java/com/dfsek/terra/command/geometry/DeformedSphereCommand.java @@ -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 getSubCommands() { + return Collections.emptyList(); + } + + @Override + public int arguments() { + return 3; + } + + @Override + public List getTabCompletions(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) { + return Collections.emptyList(); + } +} diff --git a/src/main/java/com/dfsek/terra/command/geometry/GeometryCommand.java b/src/main/java/com/dfsek/terra/command/geometry/GeometryCommand.java new file mode 100644 index 000000000..7422bf927 --- /dev/null +++ b/src/main/java/com/dfsek/terra/command/geometry/GeometryCommand.java @@ -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 getSubCommands() { + return Arrays.asList(new SphereCommand(), new TubeCommand(), new DeformedSphereCommand()); + } + + @Override + public int arguments() { + return 0; + } + + @Override + public List getTabCompletions(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) { + return Collections.emptyList(); + } +} diff --git a/src/main/java/com/dfsek/terra/command/geometry/SphereCommand.java b/src/main/java/com/dfsek/terra/command/geometry/SphereCommand.java new file mode 100644 index 000000000..08985e994 --- /dev/null +++ b/src/main/java/com/dfsek/terra/command/geometry/SphereCommand.java @@ -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 getSubCommands() { + return Collections.emptyList(); + } + + @Override + public int arguments() { + return 1; + } + + @Override + public List getTabCompletions(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) { + return Collections.emptyList(); + } +} diff --git a/src/main/java/com/dfsek/terra/command/geometry/TubeCommand.java b/src/main/java/com/dfsek/terra/command/geometry/TubeCommand.java new file mode 100644 index 000000000..8b610cc04 --- /dev/null +++ b/src/main/java/com/dfsek/terra/command/geometry/TubeCommand.java @@ -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 getSubCommands() { + return Collections.emptyList(); + } + + @Override + public int arguments() { + return 1; + } + + @Override + public List getTabCompletions(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) { + return Collections.emptyList(); + } +} diff --git a/src/main/java/com/dfsek/terra/command/structure/ExportCommand.java b/src/main/java/com/dfsek/terra/command/structure/ExportCommand.java index a0392c923..f70b68aed 100644 --- a/src/main/java/com/dfsek/terra/command/structure/ExportCommand.java +++ b/src/main/java/com/dfsek/terra/command/structure/ExportCommand.java @@ -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) { diff --git a/src/main/java/com/dfsek/terra/command/structure/LocateCommand.java b/src/main/java/com/dfsek/terra/command/structure/LocateCommand.java new file mode 100644 index 000000000..7ac79684b --- /dev/null +++ b/src/main/java/com/dfsek/terra/command/structure/LocateCommand.java @@ -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 getSubCommands() { + return Collections.emptyList(); + } + + @Override + public int arguments() { + return 2; + } + + @Override + public List getTabCompletions(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) { + if(!(sender instanceof Player) || !(((Player) sender).getWorld().getGenerator() instanceof TerraChunkGenerator)) return Collections.emptyList(); + List 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(); + } +} diff --git a/src/main/java/com/dfsek/terra/command/structure/StructureCommand.java b/src/main/java/com/dfsek/terra/command/structure/StructureCommand.java index 9e8af8806..c75ab5763 100644 --- a/src/main/java/com/dfsek/terra/command/structure/StructureCommand.java +++ b/src/main/java/com/dfsek/terra/command/structure/StructureCommand.java @@ -21,7 +21,7 @@ public class StructureCommand extends PlayerCommand { @Override public List 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 diff --git a/src/main/java/com/dfsek/terra/config/ConfigPack.java b/src/main/java/com/dfsek/terra/config/ConfigPack.java index cbed8eb5b..1ac30cf99 100644 --- a/src/main/java/com/dfsek/terra/config/ConfigPack.java +++ b/src/main/java/com/dfsek/terra/config/ConfigPack.java @@ -181,6 +181,14 @@ public class ConfigPack extends YamlConfiguration { return fill; } + public List getStructureIDs() { + List fill = new ArrayList<>(); + for(StructureConfig s : structures.values()) { + fill.add(s.getID()); + } + return fill; + } + public FloraConfig getFlora(String id) { return flora.get(id); } diff --git a/src/main/java/com/dfsek/terra/generation/TerraChunkGenerator.java b/src/main/java/com/dfsek/terra/generation/TerraChunkGenerator.java index 7d328a377..041a03d60 100644 --- a/src/main/java/com/dfsek/terra/generation/TerraChunkGenerator.java +++ b/src/main/java/com/dfsek/terra/generation/TerraChunkGenerator.java @@ -149,7 +149,7 @@ public class TerraChunkGenerator extends GaeaChunkGenerator { for(Map.Entry 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(); } diff --git a/src/main/java/com/dfsek/terra/population/CavePopulator.java b/src/main/java/com/dfsek/terra/population/CavePopulator.java index 5775cf6df..28f38a06c 100644 --- a/src/main/java/com/dfsek/terra/population/CavePopulator.java +++ b/src/main/java/com/dfsek/terra/population/CavePopulator.java @@ -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 shiftCandidate = new HashMap<>(); Set updateNeeded = new HashSet<>(); @@ -78,6 +80,10 @@ public class CavePopulator extends BlockPopulator { b.setBlockData(orig, true); } } + for(Map.Entry 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); + } } } diff --git a/src/main/java/com/dfsek/terra/procgen/GridSpawn.java b/src/main/java/com/dfsek/terra/procgen/GridSpawn.java index 47ed76bed..11dcec837 100644 --- a/src/main/java/com/dfsek/terra/procgen/GridSpawn.java +++ b/src/main/java/com/dfsek/terra/procgen/GridSpawn.java @@ -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; + } } diff --git a/src/main/java/com/dfsek/terra/procgen/voxel/Cylinder.java b/src/main/java/com/dfsek/terra/procgen/voxel/Cylinder.java new file mode 100644 index 000000000..dfe02f06a --- /dev/null +++ b/src/main/java/com/dfsek/terra/procgen/voxel/Cylinder.java @@ -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) { + + } +} diff --git a/src/main/java/com/dfsek/terra/procgen/voxel/VoxelGeometry.java b/src/main/java/com/dfsek/terra/procgen/voxel/VoxelGeometry.java index 264164084..289f20603 100644 --- a/src/main/java/com/dfsek/terra/procgen/voxel/VoxelGeometry.java +++ b/src/main/java/com/dfsek/terra/procgen/voxel/VoxelGeometry.java @@ -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 {} }