diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
index 25e81a323..82abc63ef 100644
--- a/.idea/jarRepositories.xml
+++ b/.idea/jarRepositories.xml
@@ -11,6 +11,11 @@
+
+
+
+
+
@@ -26,6 +31,11 @@
+
+
+
+
+
diff --git a/pom.xml b/pom.xml
index c0310d534..5d075155d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -68,6 +68,10 @@
gaea
file:/home/dfsek/Documents/Gaea/repo
+
+ enginehub-maven
+ http://maven.enginehub.org/repo/
+
@@ -110,6 +114,12 @@
commons-imaging
1.0-alpha2
+
+ com.sk89q.worldedit
+ worldedit-bukkit
+ 7.2.0-SNAPSHOT
+ provided
+
\ No newline at end of file
diff --git a/src/main/java/com/dfsek/terra/TerraCommand.java b/src/main/java/com/dfsek/terra/TerraCommand.java
index c78e4fda0..0f00152cf 100644
--- a/src/main/java/com/dfsek/terra/TerraCommand.java
+++ b/src/main/java/com/dfsek/terra/TerraCommand.java
@@ -2,23 +2,29 @@ package com.dfsek.terra;
import com.dfsek.terra.biome.TerraBiomeGrid;
import com.dfsek.terra.biome.UserDefinedBiome;
+import com.dfsek.terra.config.ConfigUtil;
import com.dfsek.terra.config.WorldConfig;
import com.dfsek.terra.config.genconfig.BiomeConfig;
-import com.dfsek.terra.config.ConfigUtil;
import com.dfsek.terra.config.genconfig.OreConfig;
import com.dfsek.terra.image.WorldImageGenerator;
+import com.dfsek.terra.structure.GaeaStructure;
+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.block.Block;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
-import org.bukkit.command.TabCompleter;
import org.bukkit.command.TabExecutor;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.polydev.gaea.profiler.WorldProfiler;
import java.io.File;
-import java.util.Arrays;
+import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Random;
@@ -26,90 +32,148 @@ import java.util.Random;
public class TerraCommand implements CommandExecutor, TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
- switch(args[0]) {
- case "reload":
- ConfigUtil.loadConfig(Terra.getInstance());
- sender.sendMessage("Reloaded Terra config.");
- return true;
- case "biome":
- if(!(sender instanceof Player)) return false;
- sender.sendMessage("You are in " + BiomeConfig.fromBiome((UserDefinedBiome) TerraBiomeGrid.fromWorld(((Player) sender).getWorld()).getBiome(((Player) sender).getLocation())).getFriendlyName());
- return true;
- case "profile":
- if(! (sender instanceof Player)) {
- sender.sendMessage("Command is for players only.");
+ try {
+ switch(args[0]) {
+ case "reload":
+ ConfigUtil.loadConfig(Terra.getInstance());
+ sender.sendMessage("Reloaded Terra config.");
return true;
- }
- Player p = (Player) sender;
- if(p.getWorld().getGenerator() instanceof TerraChunkGenerator) {
- WorldProfiler profile = TerraProfiler.fromWorld(p.getWorld());
- if(args.length > 1 && "query".equals(args[1])) {
- sender.sendMessage(profile.getResultsFormatted());
- return true;
- } else if(args.length > 1 && "reset".equals(args[1])) {
- profile.reset();
- sender.sendMessage("Profiler has been reset.");
- return true;
- } else if(args.length > 1 && "start".equals(args[1])) {
- profile.setProfiling(true);
- sender.sendMessage("Profiler has started.");
- return true;
- } else if(args.length > 1 && "stop".equals(args[1])) {
- profile.setProfiling(false);
- sender.sendMessage("Profiler has stopped.");
- return true;
- }
- } else sender.sendMessage("World is not a Terra world!");
- break;
- case "ore":
- if(! (sender instanceof Player)) {
- sender.sendMessage("Command is for players only.");
+ case "biome":
+ if(! (sender instanceof Player)) return false;
+ sender.sendMessage("You are in " + BiomeConfig.fromBiome((UserDefinedBiome) TerraBiomeGrid.fromWorld(((Player) sender).getWorld()).getBiome(((Player) sender).getLocation())).getFriendlyName());
return true;
- }
- Block bl = ((Player) sender).getTargetBlockExact(25);
- OreConfig ore = OreConfig.fromID(args[1]);
- if(ore == null) {
- sender.sendMessage("Unable to find Ore");
- return true;
- }
- ore.doVein(bl.getLocation(), new Random());
- return true;
- case "image":
- if("render".equals(args[1])) {
+ case "profile":
if(! (sender instanceof Player)) {
sender.sendMessage("Command is for players only.");
return true;
}
- Player pl = (Player) sender;
- if(args.length != 4) return false;
- try {
- WorldImageGenerator g = new WorldImageGenerator(pl.getWorld(), Integer.parseInt(args[2]), Integer.parseInt(args[3]));
- g.drawWorld(pl.getLocation().getBlockX(), pl.getLocation().getBlockZ());
- File file = new File(Terra.getInstance().getDataFolder() + File.separator + "map_export" + File.separator + "map_" + System.currentTimeMillis() + ".png");
- file.mkdirs();
- file.createNewFile();
- g.save(file);
- sender.sendMessage("Saved image to " + file.getPath());
- return true;
- } catch(Exception e) {
- e.printStackTrace();
- return false;
- }
- } else if("gui".equals(args[1])) {
+ Player p = (Player) sender;
+ if(p.getWorld().getGenerator() instanceof TerraChunkGenerator) {
+ WorldProfiler profile = TerraProfiler.fromWorld(p.getWorld());
+ if(args.length > 1 && "query".equals(args[1])) {
+ sender.sendMessage(profile.getResultsFormatted());
+ return true;
+ } else if(args.length > 1 && "reset".equals(args[1])) {
+ profile.reset();
+ sender.sendMessage("Profiler has been reset.");
+ return true;
+ } else if(args.length > 1 && "start".equals(args[1])) {
+ profile.setProfiling(true);
+ sender.sendMessage("Profiler has started.");
+ return true;
+ } else if(args.length > 1 && "stop".equals(args[1])) {
+ profile.setProfiling(false);
+ sender.sendMessage("Profiler has stopped.");
+ return true;
+ }
+ } else sender.sendMessage("World is not a Terra world!");
+ break;
+ case "ore":
if(! (sender instanceof Player)) {
sender.sendMessage("Command is for players only.");
return true;
}
- Player pl = (Player) sender;
- try {
- if("raw".equals(args[2])) WorldConfig.fromWorld(pl.getWorld()).imageLoader.debug(false, pl.getWorld());
- else if("step".equals(args[2])) WorldConfig.fromWorld(pl.getWorld()).imageLoader.debug(true, pl.getWorld());
- else return false;
+ Block bl = ((Player) sender).getTargetBlockExact(25);
+ OreConfig ore = OreConfig.fromID(args[1]);
+ if(ore == null) {
+ sender.sendMessage("Unable to find Ore");
return true;
- } catch(NullPointerException e) {
- return false;
}
- }
+ ore.doVein(bl.getLocation(), new Random());
+ return true;
+ case "image":
+ if("render".equals(args[1])) {
+ if(! (sender instanceof Player)) {
+ sender.sendMessage("Command is for players only.");
+ return true;
+ }
+ Player pl = (Player) sender;
+ if(args.length != 4) return false;
+ try {
+ WorldImageGenerator g = new WorldImageGenerator(pl.getWorld(), Integer.parseInt(args[2]), Integer.parseInt(args[3]));
+ g.drawWorld(pl.getLocation().getBlockX(), pl.getLocation().getBlockZ());
+ File file = new File(Terra.getInstance().getDataFolder() + File.separator + "export" + File.separator + "map" + File.separator + "map_" + System.currentTimeMillis() + ".png");
+ file.mkdirs();
+ file.createNewFile();
+ g.save(file);
+ sender.sendMessage("Saved image to " + file.getPath());
+ return true;
+ } catch(Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ } else if("gui".equals(args[1])) {
+ if(! (sender instanceof Player)) {
+ sender.sendMessage("Command is for players only.");
+ return true;
+ }
+ Player pl = (Player) sender;
+ try {
+ if("raw".equals(args[2]))
+ WorldConfig.fromWorld(pl.getWorld()).imageLoader.debug(false, pl.getWorld());
+ else if("step".equals(args[2]))
+ WorldConfig.fromWorld(pl.getWorld()).imageLoader.debug(true, pl.getWorld());
+ else return false;
+ return true;
+ } catch(NullPointerException e) {
+ return false;
+ }
+ }
+ break;
+ case "structure":
+ if(! (sender instanceof Player)) {
+ sender.sendMessage("Command is for players only.");
+ return true;
+ }
+
+ Player pl = (Player) sender;
+ if("export".equals(args[1])) {
+ 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(pl).getSelection(BukkitAdapter.adapt(pl.getWorld()));
+ } catch(IncompleteRegionException e) {
+ sender.sendMessage("Invalid/incomplete selection!");
+ return true;
+ }
+ BukkitAdapter.adapt(pl);
+ 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(pl.getWorld(), min.getBlockX(), min.getBlockY(), min.getBlockZ());
+ Location l2 = new Location(pl.getWorld(), max.getBlockX(), max.getBlockY(), max.getBlockZ());
+ GaeaStructure structure = new GaeaStructure(l1, l2);
+ try {
+ File file = new File(Terra.getInstance().getDataFolder() + File.separator + "export" + File.separator + "structures", args[2] + ".tstructure");
+ file.getParentFile().mkdirs();
+ file.createNewFile();
+ structure.save(file);
+ sender.sendMessage("Saved to " + file.getPath());
+ } catch(IOException e) {
+ e.printStackTrace();
+ }
+ return true;
+ } else if("load".equals(args[1])) {
+ try {
+ GaeaStructure struc = GaeaStructure.load(new File(Terra.getInstance().getDataFolder() + File.separator + "export" + File.separator + "structures", args[2] + ".tstructure"));
+ if("true".equals(args[3])) struc.paste(pl.getLocation());
+ else struc.paste(pl.getLocation(), pl.getLocation().getChunk());
+ } catch(IOException e) {
+ e.printStackTrace();
+ sender.sendMessage("Structure not found.");
+ }
+ return true;
+ }
+ }
+ } catch(ArrayIndexOutOfBoundsException e) {
+ e.printStackTrace();
}
return false;
}
diff --git a/src/main/java/com/dfsek/terra/WorldEditUtil.java b/src/main/java/com/dfsek/terra/WorldEditUtil.java
new file mode 100644
index 000000000..addad5f32
--- /dev/null
+++ b/src/main/java/com/dfsek/terra/WorldEditUtil.java
@@ -0,0 +1,14 @@
+package com.dfsek.terra;
+
+import com.sk89q.worldedit.bukkit.WorldEditPlugin;
+import org.bukkit.Bukkit;
+import org.bukkit.plugin.Plugin;
+
+public class WorldEditUtil {
+ public static WorldEditPlugin getWorldEdit() {
+ Plugin p = Bukkit.getServer().getPluginManager().getPlugin("WorldEdit");
+ if (p instanceof WorldEditPlugin) return (WorldEditPlugin) p;
+ Bukkit.getLogger().severe("[Terra] a command requiring WorldEdit was executed, but WorldEdit was not detected!");
+ return null;
+ }
+}
diff --git a/src/main/java/com/dfsek/terra/config/ConfigLoader.java b/src/main/java/com/dfsek/terra/config/ConfigLoader.java
index 6a900cdc6..da8528cbe 100644
--- a/src/main/java/com/dfsek/terra/config/ConfigLoader.java
+++ b/src/main/java/com/dfsek/terra/config/ConfigLoader.java
@@ -20,7 +20,7 @@ public class ConfigLoader {
}
public void load(JavaPlugin main, Class clazz) {
- File folder = new File(main.getDataFolder() + File.separator + path);
+ File folder = new File(main.getDataFolder() + File.separator + "config" + File.separator + path);
folder.mkdirs();
try (Stream paths = Files.walk(folder.toPath())) {
paths
diff --git a/src/main/java/com/dfsek/terra/config/WorldConfig.java b/src/main/java/com/dfsek/terra/config/WorldConfig.java
index c1e8b19c4..d53d03e2b 100644
--- a/src/main/java/com/dfsek/terra/config/WorldConfig.java
+++ b/src/main/java/com/dfsek/terra/config/WorldConfig.java
@@ -73,19 +73,25 @@ public class WorldConfig {
freq1 = 1f/config.getInt("frequencies.grid-1", 256);
freq2 = 1f/config.getInt("frequencies.grid-2", 512);
fromImage = config.getBoolean("image.use-image", false);
- biomeXChannel = ImageLoader.Channel.valueOf(Objects.requireNonNull(config.getString("image.channels.biome-x", "red")).toUpperCase());
- biomeZChannel = ImageLoader.Channel.valueOf(Objects.requireNonNull(config.getString("image.channels.biome-z", "green")).toUpperCase());
- if(biomeZChannel.equals(biomeXChannel)) throw new InvalidConfigurationException("2 objects share the same image channels: biome-x and biome-z");
- zoneChannel = ImageLoader.Channel.valueOf(Objects.requireNonNull(config.getString("image.channels.zone", "blue")).toUpperCase());
- if(zoneChannel.equals(biomeXChannel) || zoneChannel.equals(biomeZChannel)) throw new InvalidConfigurationException("2 objects share the same image channels: zone and biome-x/z");
- if(fromImage) {
- try {
- imageLoader = new ImageLoader(new File(Objects.requireNonNull(config.getString("image.image-location"))));
- Bukkit.getLogger().info("[Terra] Loading world from image.");
- } catch(IOException | NullPointerException e) {
- e.printStackTrace();
- fromImage = false;
+ try {
+ biomeXChannel = ImageLoader.Channel.valueOf(Objects.requireNonNull(config.getString("image.channels.biome-x", "red")).toUpperCase());
+ biomeZChannel = ImageLoader.Channel.valueOf(Objects.requireNonNull(config.getString("image.channels.biome-z", "green")).toUpperCase());
+ if(biomeZChannel.equals(biomeXChannel))
+ throw new InvalidConfigurationException("2 objects share the same image channels: biome-x and biome-z");
+ zoneChannel = ImageLoader.Channel.valueOf(Objects.requireNonNull(config.getString("image.channels.zone", "blue")).toUpperCase());
+ if(zoneChannel.equals(biomeXChannel) || zoneChannel.equals(biomeZChannel))
+ throw new InvalidConfigurationException("2 objects share the same image channels: zone and biome-x/z");
+ if(fromImage) {
+ try {
+ imageLoader = new ImageLoader(new File(Objects.requireNonNull(config.getString("image.image-location"))), ImageLoader.Align.valueOf(config.getString("image.align", "center").toUpperCase()));
+ Bukkit.getLogger().info("[Terra] Loading world from image.");
+ } catch(IOException | NullPointerException e) {
+ e.printStackTrace();
+ fromImage = false;
+ }
}
+ } catch(IllegalArgumentException e) {
+ throw new InvalidConfigurationException(e.getCause());
}
diff --git a/src/main/java/com/dfsek/terra/config/genconfig/StructureConfig.java b/src/main/java/com/dfsek/terra/config/genconfig/StructureConfig.java
new file mode 100644
index 000000000..0f1a4f2c1
--- /dev/null
+++ b/src/main/java/com/dfsek/terra/config/genconfig/StructureConfig.java
@@ -0,0 +1,23 @@
+package com.dfsek.terra.config.genconfig;
+
+import com.dfsek.terra.config.TerraConfigObject;
+import org.bukkit.configuration.InvalidConfigurationException;
+
+import java.io.File;
+import java.io.IOException;
+
+public class StructureConfig extends TerraConfigObject {
+ public StructureConfig(File file) throws IOException, InvalidConfigurationException {
+ super(file);
+ }
+
+ @Override
+ public void init() throws InvalidConfigurationException {
+
+ }
+
+ @Override
+ public String getID() {
+ return null;
+ }
+}
diff --git a/src/main/java/com/dfsek/terra/image/DebugFrame.java b/src/main/java/com/dfsek/terra/image/DebugFrame.java
index 47dd79fcd..cbead300f 100644
--- a/src/main/java/com/dfsek/terra/image/DebugFrame.java
+++ b/src/main/java/com/dfsek/terra/image/DebugFrame.java
@@ -1,8 +1,10 @@
package com.dfsek.terra.image;
import com.dfsek.terra.Terra;
+import com.dfsek.terra.TerraChunkGenerator;
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 org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@@ -29,17 +31,22 @@ public class DebugFrame extends JFrame implements ActionListener {
public void paint(Graphics g) {
super.paintComponents(g);
for(Player p : Bukkit.getOnlinePlayers()) {
- int xp = (int) (((double) Math.floorMod(p.getLocation().getBlockX(), x)/x)*getWidth());
- int zp = (int) (((double) Math.floorMod(p.getLocation().getBlockZ(), z)/z)*getHeight());
+ if(! (p.getWorld().getGenerator() instanceof TerraChunkGenerator)) break;
+ int xp = (int) (((double) Math.floorMod(p.getLocation().getBlockX(), x) / x) * getWidth());
+ int zp = (int) (((double) Math.floorMod(p.getLocation().getBlockZ(), z) / z) * getHeight());
+ if(WorldConfig.fromWorld(p.getWorld()).imageLoader.getAlign().equals(ImageLoader.Align.CENTER)) {
+ xp = (int) (((double) Math.floorMod(p.getLocation().getBlockX() - (img.getWidth() / 2), x) / x) * getWidth());
+ zp = (int) (((double) Math.floorMod(p.getLocation().getBlockZ() - (img.getHeight() / 2), z) / z) * getHeight());
+ }
String str = BiomeConfig.fromBiome((UserDefinedBiome) TerraBiomeGrid.fromWorld(p.getWorld()).getBiome(p.getLocation())).getID();
g.setColor(new Color(255, 255, 255, 128));
- g.fillRect(xp+13, zp-13, (int) (8 + 8.25*str.length()), 33);
+ g.fillRect(xp + 13, zp - 13, (int) (8 + 8.25 * str.length()), 33);
g.setColor(Color.BLACK);
- g.drawString(p.getName(), xp+15, zp);
- g.drawString(str, xp+15, zp+15);
+ g.drawString(p.getName(), xp + 15, zp);
+ g.drawString(str, xp + 15, zp + 15);
g.fillOval(xp, zp, 10, 10);
g.setColor(Color.RED);
- g.fillOval(xp+3, zp+3, 5, 5);
+ g.fillOval(xp + 3, zp + 3, 5, 5);
}
}
diff --git a/src/main/java/com/dfsek/terra/image/ImageLoader.java b/src/main/java/com/dfsek/terra/image/ImageLoader.java
index f8d4e5bc9..f041ca41c 100644
--- a/src/main/java/com/dfsek/terra/image/ImageLoader.java
+++ b/src/main/java/com/dfsek/terra/image/ImageLoader.java
@@ -18,20 +18,17 @@ import javax.imageio.ImageIO;
public class ImageLoader {
private final BufferedImage image;
+ private final Align align;
double inverseRoot2 = 0.7071067811865475;
- public ImageLoader(File file) throws IOException {
+ public ImageLoader(File file, Align align) throws IOException {
image = ImageIO.read(file);
+ this.align = align;
}
public int getChannel(int x, int y, Channel channel) {
int rgb;
- try {
- rgb = image.getRGB(Math.floorMod(x, image.getWidth()), Math.floorMod(y, image.getHeight()));
- } catch(ArrayIndexOutOfBoundsException e) {
- e.printStackTrace();
- throw new IllegalArgumentException("Index " + x + "/" + x + "out of bounds for size " + image.getWidth() + "/" + image.getHeight());
- }
+ rgb = align.getRGB(image, x, y);
switch(channel) {
case RED: return rgb >> 16 & 0xff;
case GREEN: return rgb >> 8 & 0xff;
@@ -63,7 +60,7 @@ public class ImageLoader {
public double getNoiseVal(int x, int y, Channel channel) {
return ((double) (getChannel(x, y, channel) - 128)/128)*inverseRoot2;
}
- private static BufferedImage copyImage(BufferedImage source){
+ private static BufferedImage copyImage(BufferedImage source) {
BufferedImage b = new BufferedImage(source.getWidth(), source.getHeight(), source.getType());
Graphics g = b.getGraphics();
g.drawImage(source, 0, 0, null);
@@ -71,7 +68,29 @@ public class ImageLoader {
return b;
}
+ public Align getAlign() {
+ return align;
+ }
+
public enum Channel {
RED, GREEN, BLUE, ALPHA
}
+ public enum Align {
+ CENTER {
+ @Override
+ public int getRGB(BufferedImage image, int x, int y) {
+ return Align.getRGBNoAlign(image, x-(image.getWidth()/2), y-(image.getHeight()/2));
+ }
+ },
+ NONE {
+ @Override
+ public int getRGB(BufferedImage image, int x, int y) {
+ return image.getRGB(Math.floorMod(x, image.getWidth()), Math.floorMod(y, image.getHeight()));
+ }
+ };
+ public abstract int getRGB(BufferedImage image, int x, int y);
+ private static int getRGBNoAlign(BufferedImage image, int x, int y) {
+ return image.getRGB(Math.floorMod(x, image.getWidth()), Math.floorMod(y, image.getHeight()));
+ }
+ }
}
diff --git a/src/main/java/com/dfsek/terra/structure/GaeaStructure.java b/src/main/java/com/dfsek/terra/structure/GaeaStructure.java
new file mode 100644
index 000000000..79222c73f
--- /dev/null
+++ b/src/main/java/com/dfsek/terra/structure/GaeaStructure.java
@@ -0,0 +1,90 @@
+package com.dfsek.terra.structure;
+
+import org.bukkit.Chunk;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.block.data.BlockData;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Objects;
+
+public class GaeaStructure implements Serializable {
+ public static final long serialVersionUID = -6664585217063842034L;
+ private final StructureContainedBlock[][][] structure;
+
+ public static GaeaStructure load(File f) throws IOException {
+ try {
+ return fromFile(f);
+ } catch(ClassNotFoundException e) {
+ throw new IllegalArgumentException("Provided file does not contain a GaeaStructure.");
+ }
+ }
+
+ public GaeaStructure(Location l1, Location l2) {
+ if(l1.getX() > l2.getX() || l1.getY() > l2.getY() || l1.getZ() > l2.getZ()) throw new IllegalArgumentException("Invalid locations provided!");
+ structure = new StructureContainedBlock[l2.getBlockX()-l1.getBlockX()+1][l2.getBlockY()-l1.getBlockY()+1][l2.getBlockZ()-l1.getBlockZ()+1];
+ for(int x = 0; x <= l2.getBlockX()-l1.getBlockX(); x++) {
+ for(int y = 0; y <= l2.getBlockY()-l1.getBlockY(); y++) {
+ for(int z = 0; z <= l2.getBlockZ()-l1.getBlockZ(); z++) {
+ structure[x][y][z] = new StructureContainedBlock(x, y, z, Objects.requireNonNull(l1.getWorld()).getBlockAt(l1.clone().add(x, y, z)));
+ }
+ }
+ }
+ }
+
+ public void paste(Location origin) {
+ for(StructureContainedBlock[][] bList2 : structure) {
+ for(StructureContainedBlock[] bList1 : bList2) {
+ for(StructureContainedBlock block : bList1) {
+ BlockData data = block.getBlockData();
+ Block worldBlock = origin.clone().add(block.getX(), block.getY(), block.getZ()).getBlock();
+ if(!data.getMaterial().equals(Material.STRUCTURE_VOID)) worldBlock.setBlockData(data);
+ }
+ }
+ }
+ }
+
+ public void paste(Location origin, Chunk c) {
+ for(StructureContainedBlock[][] bList2 : structure) {
+ for(StructureContainedBlock[] bList1 : bList2) {
+ for(StructureContainedBlock block : bList1) {
+ Location newLoc = origin.clone().add(block.getX(), block.getY(), block.getZ());
+ BlockData data = block.getBlockData();
+ if(newLoc.getChunk().equals(c) && !data.getMaterial().equals(Material.STRUCTURE_VOID)) newLoc.getBlock().setBlockData(block.getBlockData());
+ }
+ }
+ }
+ }
+
+ public void save(File f) throws IOException {
+ toFile(this, f);
+ }
+
+ private static GaeaStructure fromFile(File f) throws IOException, ClassNotFoundException {
+ ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f));
+ Object o = ois.readObject();
+ ois.close();
+ return (GaeaStructure) o;
+ }
+
+ public static GaeaStructure fromStream(InputStream f) throws IOException, ClassNotFoundException {
+ ObjectInputStream ois = new ObjectInputStream(f);
+ Object o = ois.readObject();
+ ois.close();
+ return (GaeaStructure) o;
+ }
+
+ private static void toFile(Serializable o, File f) throws IOException {
+ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f));
+ oos.writeObject(o);
+ oos.close();
+ }
+}
diff --git a/src/main/java/com/dfsek/terra/structure/MultiPartStructure.java b/src/main/java/com/dfsek/terra/structure/MultiPartStructure.java
deleted file mode 100644
index d609071b3..000000000
--- a/src/main/java/com/dfsek/terra/structure/MultiPartStructure.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package com.dfsek.terra.structure;
-
-public class MultiPartStructure {
-}
diff --git a/src/main/java/com/dfsek/terra/structure/StructureContainedBlock.java b/src/main/java/com/dfsek/terra/structure/StructureContainedBlock.java
new file mode 100644
index 000000000..0b91683ba
--- /dev/null
+++ b/src/main/java/com/dfsek/terra/structure/StructureContainedBlock.java
@@ -0,0 +1,44 @@
+package com.dfsek.terra.structure;
+
+import org.bukkit.Bukkit;
+import org.bukkit.block.Block;
+import org.bukkit.block.data.BlockData;
+import org.bukkit.entity.Entity;
+
+import java.io.Serializable;
+
+public class StructureContainedBlock implements Serializable {
+ public static final long serialVersionUID = 6143969483382710947L;
+ private final transient BlockData bl;
+ private final String dataString;
+ private final int x;
+ private final int y;
+ private final int z;
+ public StructureContainedBlock(int x, int y, int z, Block block) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.bl = block.getBlockData();
+ dataString = bl.getAsString(false);
+ }
+
+ public int getX() {
+ return x;
+ }
+
+ public int getY() {
+ return y;
+ }
+
+ public int getZ() {
+ return z;
+ }
+
+ public BlockData getBlockData() {
+ return bl == null ? Bukkit.createBlockData(dataString) : bl;
+ }
+
+ public String getDataAsString() {
+ return dataString;
+ }
+}
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index ee7c00467..8cdccb56d 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -3,6 +3,7 @@ main: com.dfsek.terra.Terra
version: 1.0.0
load: STARTUP
api-version: "1.15"
+softdepend: ["WorldEdit"]
commands:
terra:
description: Terra base command
diff --git a/src/main/resources/terra.commodore b/src/main/resources/terra.commodore
index 57c59cafc..65c37ca8d 100644
--- a/src/main/resources/terra.commodore
+++ b/src/main/resources/terra.commodore
@@ -24,4 +24,14 @@ terra {
step;
}
}
+ structure {
+ export {
+ structure brigadier:string single_word;
+ }
+ load {
+ structure brigadier:string single_word {
+ respect_chunk brigadier:bool;
+ }
+ }
+ }
}
\ No newline at end of file