diff --git a/Core/pom.xml b/Core/pom.xml
index 280cd8b1a..4e53e831a 100644
--- a/Core/pom.xml
+++ b/Core/pom.xml
@@ -92,6 +92,12 @@
1.3.72
runtime
+
+ com.github.davidmoten
+ rtree
+ 0.8.7
+ runtime
+
junit
junit
diff --git a/Core/src/main/java/com/plotsquared/core/command/Area.java b/Core/src/main/java/com/plotsquared/core/command/Area.java
index f5d494868..fcb4993c7 100644
--- a/Core/src/main/java/com/plotsquared/core/command/Area.java
+++ b/Core/src/main/java/com/plotsquared/core/command/Area.java
@@ -33,6 +33,7 @@ import com.plotsquared.core.events.TeleportCause;
import com.plotsquared.core.generator.AugmentedUtils;
import com.plotsquared.core.generator.HybridPlotWorld;
import com.plotsquared.core.location.Location;
+import com.plotsquared.core.player.ConsolePlayer;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.PlotArea;
import com.plotsquared.core.plot.PlotAreaTerrainType;
@@ -50,9 +51,18 @@ import com.plotsquared.core.util.StringMan;
import com.plotsquared.core.util.WorldUtil;
import com.plotsquared.core.util.task.RunnableVal;
import com.plotsquared.core.util.task.RunnableVal3;
+import com.sk89q.worldedit.LocalSession;
+import com.sk89q.worldedit.WorldEdit;
+import com.sk89q.worldedit.entity.Player;
+import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
+import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat;
+import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.regions.CuboidRegion;
+import com.sk89q.worldedit.regions.Region;
+import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Objects;
@@ -74,6 +84,102 @@ public class Area extends SubCommand {
return false;
}
switch (args[0].toLowerCase()) {
+ case "single":
+ if (player instanceof ConsolePlayer) {
+ MainUtil.sendMessage(player, Captions.IS_CONSOLE);
+ return false;
+ }
+ if (!Permissions.hasPermission(player, Captions.PERMISSION_AREA_CREATE)) {
+ MainUtil.sendMessage(player, Captions.NO_PERMISSION, Captions.PERMISSION_AREA_CREATE);
+ return false;
+ }
+ if (args.length < 2) {
+ MainUtil.sendMessage(player, Captions.SINGLE_AREA_NEEDS_NAME);
+ return false;
+ }
+ if (PlotSquared.get().getPlotArea(player.getLocation().getWorld(), args[1]) != null) {
+ MainUtil.sendMessage(player, Captions.SINGLE_AREA_NAME_TAKEN);
+ return false;
+ }
+ final LocalSession localSession = WorldEdit.getInstance().getSessionManager().getIfPresent(player.toActor());
+ if (localSession == null) {
+ MainUtil.sendMessage(player, Captions.SINGLE_AREA_MISSING_SELECTION);
+ return false;
+ }
+ Region selectedRegion = null;
+ try {
+ selectedRegion = localSession.getSelection(((Player) player.toActor()).getWorld());
+ } catch (final Exception ignored) {}
+ if (selectedRegion == null) {
+ MainUtil.sendMessage(player, Captions.SINGLE_AREA_MISSING_SELECTION);
+ return false;
+ }
+ if (selectedRegion.getWidth() != selectedRegion.getLength()) {
+ MainUtil.sendMessage(player, Captions.SINGLE_AREA_NOT_SQUARE);
+ return false;
+ }
+ if (PlotSquared.get().getPlotAreaManager().getPlotAreas(
+ Objects.requireNonNull(selectedRegion.getWorld()).getName(), CuboidRegion.makeCuboid(selectedRegion)).length != 0) {
+ MainUtil.sendMessage(player, Captions.SINGLE_AREA_OVERLAPPING);
+ }
+ // There's only one plot in the area...
+ final PlotId plotId = new PlotId(1, 1);
+ final HybridPlotWorld hybridPlotWorld = new HybridPlotWorld(player.getLocation().getWorld(), args[1],
+ Objects.requireNonNull(PlotSquared.imp()).getDefaultGenerator(), plotId, plotId);
+ // Plot size is the same as the region width
+ hybridPlotWorld.SIZE = (short) selectedRegion.getWidth();
+ // We use a schematic generator
+ hybridPlotWorld.setTerrain(PlotAreaTerrainType.ALL);
+ // It is always a partial plot world
+ hybridPlotWorld.setType(PlotAreaType.PARTIAL);
+ // We save the schematic :D
+ final File parentFile = MainUtil.getFile(PlotSquared.imp().getDirectory(), "schematics" + File.separator +
+ "GEN_ROAD_SCHEMATIC" + File.separator + hybridPlotWorld.getWorldName() + File.separator +
+ hybridPlotWorld.getId());
+ if (!parentFile.exists() && !parentFile.mkdirs()) {
+ MainUtil.sendMessage(player, Captions.SINGLE_AREA_COULD_NOT_MAKE_DIRECTORIES);
+ return false;
+ }
+ final File file = new File(parentFile, "plot.schem");
+ try (final ClipboardWriter clipboardWriter = BuiltInClipboardFormat.SPONGE_SCHEMATIC.getWriter(new FileOutputStream(file))) {
+ final BlockArrayClipboard clipboard = new BlockArrayClipboard(selectedRegion);
+ clipboardWriter.write(clipboard);
+ } catch (final Exception e) {
+ MainUtil.sendMessage(player, Captions.SINGLE_AREA_FAILED_TO_SAVE);
+ e.printStackTrace();
+ return false;
+ }
+ // Now the schematic is saved, which is wonderful!
+ final SetupObject singleSetup = new SetupObject();
+ singleSetup.world = hybridPlotWorld.getWorldName();
+ singleSetup.id = hybridPlotWorld.getId();
+ singleSetup.terrain = hybridPlotWorld.getTerrain();
+ singleSetup.type = hybridPlotWorld.getType();
+ singleSetup.plotManager = PlotSquared.imp().getPluginName();
+ singleSetup.setupGenerator = PlotSquared.imp().getPluginName();
+ singleSetup.step = hybridPlotWorld.getSettingNodes();
+ singleSetup.max = plotId;
+ singleSetup.min = plotId;
+ Runnable singleRun = () -> {
+ final String world = SetupUtils.manager.setupWorld(singleSetup);
+ if (WorldUtil.IMP.isWorld(world)) {
+ PlotSquared.get().loadWorld(world, null);
+ Captions.SETUP_FINISHED.send(player);
+ player.teleport(WorldUtil.IMP.getSpawn(world),
+ TeleportCause.COMMAND);
+ } else {
+ MainUtil.sendMessage(player,
+ "An error occurred while creating the world: " + hybridPlotWorld
+ .getWorldName());
+ }
+ };
+ if (hasConfirmation(player)) {
+ CmdConfirm.addPending(player,
+ getCommandString() + " create pos2 (Creates world)", singleRun);
+ } else {
+ singleRun.run();
+ }
+ return true;
case "c":
case "setup":
case "create":
diff --git a/Core/src/main/java/com/plotsquared/core/configuration/Captions.java b/Core/src/main/java/com/plotsquared/core/configuration/Captions.java
index 6238ec066..4e1fc9482 100644
--- a/Core/src/main/java/com/plotsquared/core/configuration/Captions.java
+++ b/Core/src/main/java/com/plotsquared/core/configuration/Captions.java
@@ -783,6 +783,16 @@ public enum Captions implements Caption {
GENERIC_INVALID_CHOICE("invalid choice", "Generic"),
//
+ //
+ SINGLE_AREA_MISSING_SELECTION("$2Error! You need to select a square region", "Single"),
+ SINGLE_AREA_NOT_SQUARE("$2Error! Your selection needs to be a square", "Single"),
+ SINGLE_AREA_OVERLAPPING("$2Error! Your selection overlaps with an existing plot area", "Single"),
+ SINGLE_AREA_NEEDS_NAME("$2Error! Please specify a plot name: /plot area single ", "Single"),
+ SINGLE_AREA_NAME_TAKEN("$2Error! The plot name is already taken", "Single"),
+ SINGLE_AREA_FAILED_TO_SAVE("$2Error! Failed to save the area schematic", "Single"),
+ SINGLE_AREA_COULD_NOT_MAKE_DIRECTORIES("$2Error! Failed to create the schematic directory", "Single"),
+ //
+
/**
* Legacy Configuration Conversion
*/
diff --git a/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java b/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java
index da7f46a47..e8bb47f66 100644
--- a/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java
+++ b/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java
@@ -195,8 +195,16 @@ public class HybridPlotWorld extends ClassicPlotWorld {
public void setupSchematics() throws SchematicHandler.UnsupportedFormatException {
this.G_SCH = new HashMap<>();
this.G_SCH_B = new HashMap<>();
- File root = MainUtil.getFile(PlotSquared.get().IMP.getDirectory(),
- "schematics/GEN_ROAD_SCHEMATIC/" + this.getWorldName());
+
+ // Try to determine root. This means that plot areas can have separate schematic
+ // directories
+ File root;
+ if (!(root = MainUtil.getFile(PlotSquared.get().IMP.getDirectory(), "schematics/GEN_ROAD_SCHEMATIC/" +
+ this.getWorldName() + "/" + this.getId())).exists()) {
+ root = MainUtil.getFile(PlotSquared.get().IMP.getDirectory(),
+ "schematics/GEN_ROAD_SCHEMATIC/" + this.getWorldName());
+ }
+
File schematic1File = new File(root, "sideroad.schem");
if (!schematic1File.exists())
schematic1File = new File(root, "sideroad.schematic");