package com.intellectualcrafters.plot.commands; import com.intellectualcrafters.configuration.ConfigurationSection; import com.intellectualcrafters.plot.PS; import com.intellectualcrafters.plot.config.C; import com.intellectualcrafters.plot.config.Configuration; import com.intellectualcrafters.plot.generator.AugmentedUtils; import com.intellectualcrafters.plot.generator.HybridPlotWorld; import com.intellectualcrafters.plot.object.ChunkLoc; import com.intellectualcrafters.plot.object.Location; import com.intellectualcrafters.plot.object.PlotArea; import com.intellectualcrafters.plot.object.PlotId; import com.intellectualcrafters.plot.object.PlotMessage; import com.intellectualcrafters.plot.object.PlotPlayer; import com.intellectualcrafters.plot.object.RegionWrapper; import com.intellectualcrafters.plot.object.RunnableVal; import com.intellectualcrafters.plot.object.RunnableVal3; import com.intellectualcrafters.plot.object.SetupObject; import com.intellectualcrafters.plot.util.ChunkManager; import com.intellectualcrafters.plot.util.CmdConfirm; import com.intellectualcrafters.plot.util.MainUtil; import com.intellectualcrafters.plot.util.MathMan; import com.intellectualcrafters.plot.util.Permissions; import com.intellectualcrafters.plot.util.SetupUtils; import com.intellectualcrafters.plot.util.StringMan; import com.intellectualcrafters.plot.util.WorldUtil; import com.plotsquared.general.commands.CommandDeclaration; import java.io.IOException; import java.util.ArrayList; import java.util.Objects; import java.util.Set; @CommandDeclaration(command = "area", permission = "plots.area", category = CommandCategory.ADMINISTRATION, requiredType = RequiredType.NONE, description = "Create a new PlotArea", aliases = "world", usage = "/plot area <create|info|list|tp|regen>", confirmation = true) public class Area extends SubCommand { @Override public boolean onCommand(final PlotPlayer player, String[] args) { if (args.length == 0) { C.COMMAND_SYNTAX.send(player, getUsage()); return false; } switch (args[0].toLowerCase()) { case "c": case "setup": case "create": if (!Permissions.hasPermission(player, C.PERMISSION_AREA_CREATE)) { C.NO_PERMISSION.send(player, C.PERMISSION_AREA_CREATE); return false; } switch (args.length) { case 1: C.COMMAND_SYNTAX.send(player, "/plot area create [world[:id]] [<modifier>=<value>]..."); return false; case 2: switch (args[1].toLowerCase()) { case "pos1": { // Set position 1 HybridPlotWorld area = player.getMeta("area_create_area"); if (area == null) { C.COMMAND_SYNTAX.send(player, "/plot area create [world[:id]] [<modifier>=<value>]..."); return false; } Location location = player.getLocation(); player.setMeta("area_pos1", location); C.SET_ATTRIBUTE.send(player, "area_pos1", location.getX() + "," + location.getZ()); MainUtil.sendMessage(player, "You will now set pos2: /plot area create pos2" + "\nNote: The chosen plot size may result in the created area not exactly matching your second position."); return true; } case "pos2": // Set position 2 and finish creation for type=2 (partial) final HybridPlotWorld area = player.getMeta("area_create_area"); if (area == null) { C.COMMAND_SYNTAX.send(player, "/plot area create [world[:id]] [<modifier>=<value>]..."); return false; } Location pos1 = player.getLocation(); Location pos2 = player.getMeta("area_pos1"); int dx = Math.abs(pos1.getX() - pos2.getX()); int dz = Math.abs(pos1.getZ() - pos2.getZ()); int numX = Math.max(1, (dx + 1 + area.ROAD_WIDTH + area.SIZE / 2) / area.SIZE); int numZ = Math.max(1, (dz + 1 + area.ROAD_WIDTH + area.SIZE / 2) / area.SIZE); int ddx = dx - (numX * area.SIZE - area.ROAD_WIDTH); int ddz = dz - (numZ * area.SIZE - area.ROAD_WIDTH); int bx = Math.min(pos1.getX(), pos2.getX()) + ddx; int bz = Math.min(pos1.getZ(), pos2.getZ()) + ddz; int tx = Math.max(pos1.getX(), pos2.getX()) - ddx; int tz = Math.max(pos1.getZ(), pos2.getZ()) - ddz; int lower = (area.ROAD_WIDTH & 1) == 0 ? area.ROAD_WIDTH / 2 - 1 : area.ROAD_WIDTH / 2; final int offsetX = bx - (area.ROAD_WIDTH == 0 ? 0 : lower); final int offsetZ = bz - (area.ROAD_WIDTH == 0 ? 0 : lower); final RegionWrapper region = new RegionWrapper(bx, tx, bz, tz); Set<PlotArea> areas = PS.get().getPlotAreas(area.worldname, region); if (!areas.isEmpty()) { C.CLUSTER_INTERSECTION.send(player, areas.iterator().next().toString()); return false; } final SetupObject object = new SetupObject(); object.world = area.worldname; object.id = area.id; object.terrain = area.TERRAIN; object.type = area.TYPE; object.min = new PlotId(1, 1); object.max = new PlotId(numX, numZ); object.plotManager = PS.imp().getPluginName(); object.setupGenerator = PS.imp().getPluginName(); object.step = area.getSettingNodes(); final String path = "worlds." + area.worldname + ".areas." + area.id + '-' + object.min + '-' + object.max; Runnable run = new Runnable() { @Override public void run() { if (offsetX != 0) { PS.get().worlds.set(path + ".road.offset.x", offsetX); } if (offsetZ != 0) { PS.get().worlds.set(path + ".road.offset.z", offsetZ); } final String world = SetupUtils.manager.setupWorld(object); if (WorldUtil.IMP.isWorld(world)) { PS.get().loadWorld(world, null); C.SETUP_FINISHED.send(player); player.teleport(WorldUtil.IMP.getSpawn(world)); if (area.TERRAIN != 3) { ChunkManager.largeRegionTask(world, region, new RunnableVal<ChunkLoc>() { @Override public void run(ChunkLoc value) { AugmentedUtils.generate(world, value.x, value.z, null); } }, null); } } else { MainUtil.sendMessage(player, "An error occurred while creating the world: " + area.worldname); } } }; if (hasConfirmation(player)) { CmdConfirm.addPending(player, getCommandString() + " create pos2 (Creates world)", run); } else { run.run(); } return true; } default: // Start creation final SetupObject object = new SetupObject(); String[] split = args[1].split(":"); String id; if (split.length == 2) { id = split[1]; } else { id = null; } object.world = split[0]; final HybridPlotWorld pa = new HybridPlotWorld(object.world, id, PS.get().IMP.getDefaultGenerator(), null, null); PlotArea other = PS.get().getPlotArea(pa.worldname, id); if (other != null && Objects.equals(pa.id, other.id)) { C.SETUP_WORLD_TAKEN.send(player, pa.toString()); return false; } Set<PlotArea> areas = PS.get().getPlotAreas(pa.worldname); if (!areas.isEmpty()) { PlotArea area = areas.iterator().next(); pa.TYPE = area.TYPE; } pa.SIZE = (short) (pa.PLOT_WIDTH + pa.ROAD_WIDTH); for (int i = 2; i < args.length; i++) { String[] pair = args[i].split("="); if (pair.length != 2) { C.COMMAND_SYNTAX.send(player, getCommandString() + " create [world[:id]] [<modifier>=<value>]..."); return false; } switch (pair[0].toLowerCase()) { case "s": case "size": pa.PLOT_WIDTH = Integer.parseInt(pair[1]); pa.SIZE = (short) (pa.PLOT_WIDTH + pa.ROAD_WIDTH); break; case "g": case "gap": pa.ROAD_WIDTH = Integer.parseInt(pair[1]); pa.SIZE = (short) (pa.PLOT_WIDTH + pa.ROAD_WIDTH); break; case "h": case "height": int value = Integer.parseInt(pair[1]); pa.PLOT_HEIGHT = value; pa.ROAD_HEIGHT = value; pa.WALL_HEIGHT = value; break; case "f": case "floor": pa.TOP_BLOCK = Configuration.BLOCKLIST.parseString(pair[1]); break; case "m": case "main": pa.MAIN_BLOCK = Configuration.BLOCKLIST.parseString(pair[1]); break; case "w": case "wall": pa.WALL_FILLING = Configuration.BLOCK.parseString(pair[1]); break; case "b": case "border": pa.WALL_BLOCK = Configuration.BLOCK.parseString(pair[1]); break; case "terrain": pa.TERRAIN = Integer.parseInt(pair[1]); object.terrain = pa.TERRAIN; break; case "type": pa.TYPE = Integer.parseInt(pair[1]); object.type = pa.TYPE; break; default: C.COMMAND_SYNTAX.send(player, getCommandString() + " create [world[:id]] [<modifier>=<value>]..."); return false; } } if (pa.TYPE != 2) { if (WorldUtil.IMP.isWorld(pa.worldname)) { C.SETUP_WORLD_TAKEN.send(player, pa.worldname); return false; } Runnable run = new Runnable() { @Override public void run() { String path = "worlds." + pa.worldname; if (!PS.get().worlds.contains(path)) { PS.get().worlds.createSection(path); } ConfigurationSection section = PS.get().worlds.getConfigurationSection(path); pa.saveConfiguration(section); pa.loadConfiguration(section); object.plotManager = PS.imp().getPluginName(); object.setupGenerator = PS.imp().getPluginName(); String world = SetupUtils.manager.setupWorld(object); if (WorldUtil.IMP.isWorld(world)) { C.SETUP_FINISHED.send(player); player.teleport(WorldUtil.IMP.getSpawn(world)); } else { MainUtil.sendMessage(player, "An error occurred while creating the world: " + pa.worldname); } try { PS.get().worlds.save(PS.get().worldsFile); } catch (IOException e) { e.printStackTrace(); } } }; if (hasConfirmation(player)) { CmdConfirm.addPending(player, getCommandString() + ' ' + StringMan.join(args, " "), run); } else { run.run(); } return true; } if (pa.id == null) { C.COMMAND_SYNTAX.send(player, getCommandString() + " create [world[:id]] [<modifier>=<value>]..."); return false; } if (WorldUtil.IMP.isWorld(pa.worldname)) { if (!player.getLocation().getWorld().equals(pa.worldname)) { player.teleport(WorldUtil.IMP.getSpawn(pa.worldname)); } } else { object.terrain = 0; object.type = 0; SetupUtils.manager.setupWorld(object); player.teleport(WorldUtil.IMP.getSpawn(pa.worldname)); } player.setMeta("area_create_area", pa); MainUtil.sendMessage(player, "$1Go to the first corner and use: $2 " + getCommandString() + " create pos1"); break; } return true; case "i": case "info": { if (!Permissions.hasPermission(player, C.PERMISSION_AREA_INFO)) { C.NO_PERMISSION.send(player, C.PERMISSION_AREA_INFO); return false; } PlotArea area; switch (args.length) { case 1: area = player.getApplicablePlotArea(); break; case 2: area = PS.get().getPlotAreaByString(args[1]); break; default: C.COMMAND_SYNTAX.send(player, getCommandString() + " info [area]"); return false; } if (area == null) { if (args.length == 2) { C.NOT_VALID_PLOT_WORLD.send(player, args[1]); } else { C.NOT_IN_PLOT_WORLD.send(player); } return false; } String name; double percent; int claimed = area.getPlotCount(); int clusters = area.getClusters().size(); String region; String generator = String.valueOf(area.getGenerator()); if (area.TYPE == 2) { PlotId min = area.getMin(); PlotId max = area.getMax(); name = area.worldname + ';' + area.id + ';' + min + ';' + max; int size = (max.x - min.x + 1) * (max.y - min.y + 1); percent = claimed == 0 ? 0 : size / (double) claimed; region = area.getRegion().toString(); } else { name = area.worldname; percent = claimed == 0 ? 0 : 100d * claimed / Integer.MAX_VALUE; region = "N/A"; } String value = "&r$1NAME: " + name + "\n$1Type: $2" + area.TYPE + "\n$1Terrain: $2" + area.TERRAIN + "\n$1Usage: $2" + String.format("%.2f", percent) + '%' + "\n$1Claimed: $2" + claimed + "\n$1Clusters: $2" + clusters + "\n$1Region: $2" + region + "\n$1Generator: $2" + generator; MainUtil.sendMessage(player, C.PLOT_INFO_HEADER.s() + '\n' + value + '\n' + C.PLOT_INFO_FOOTER.s(), false); return true; } case "l": case "list": if (!Permissions.hasPermission(player, C.PERMISSION_AREA_LIST)) { C.NO_PERMISSION.send(player, C.PERMISSION_AREA_LIST); return false; } int page; switch (args.length) { case 1: page = 0; break; case 2: if (MathMan.isInteger(args[1])) { page = Integer.parseInt(args[1]) - 1; break; } default: C.COMMAND_SYNTAX.send(player, getCommandString() + " list [#]"); return false; } ArrayList<PlotArea> areas = new ArrayList<>(PS.get().getPlotAreas()); paginate(player, areas, 8, page, new RunnableVal3<Integer, PlotArea, PlotMessage>() { @Override public void run(Integer i, PlotArea area, PlotMessage message) { String name; double percent; int claimed = area.getPlotCount(); int clusters = area.getClusters().size(); String region; String generator = String.valueOf(area.getGenerator()); if (area.TYPE == 2) { PlotId min = area.getMin(); PlotId max = area.getMax(); name = area.worldname + ';' + area.id + ';' + min + ';' + max; int size = (max.x - min.x + 1) * (max.y - min.y + 1); percent = claimed == 0 ? 0 : size / (double) claimed; region = area.getRegion().toString(); } else { name = area.worldname; percent = claimed == 0 ? 0 : Short.MAX_VALUE * Short.MAX_VALUE / (double) claimed; region = "N/A"; } PlotMessage tooltip = new PlotMessage() .text("Claimed=").color("$1").text(String.valueOf(claimed)).color("$2") .text("\nUsage=").color("$1").text(String.format("%.2f", percent) + '%').color("$2") .text("\nClusters=").color("$1").text(String.valueOf(clusters)).color("$2") .text("\nRegion=").color("$1").text(region).color("$2") .text("\nGenerator=").color("$1").text(generator).color("$2"); // type / terrain String visit = "/plot area tp " + area.toString(); message.text("[").color("$3") .text(String.valueOf(i)).command(visit).tooltip(visit).color("$1") .text("]").color("$3") .text(' ' + name).tooltip(tooltip).command(getCommandString() + " info " + area).color("$1").text(" - ") .color("$2") .text(area.TYPE + ":" + area.TERRAIN).color("$3"); } }, "/plot area list", C.AREA_LIST_HEADER_PAGED.s()); return true; case "regen": case "clear": case "reset": case "regenerate": { if (!Permissions.hasPermission(player, C.PERMISSION_AREA_REGEN)) { C.NO_PERMISSION.send(player, C.PERMISSION_AREA_REGEN); return false; } final PlotArea area = player.getApplicablePlotArea(); if (area == null) { C.NOT_IN_PLOT_WORLD.send(player); return false; } if (area.TYPE != 2) { MainUtil.sendMessage(player, "$4Stop the server and delete: " + area.worldname + "/region"); return false; } ChunkManager.largeRegionTask(area.worldname, area.getRegion(), new RunnableVal<ChunkLoc>() { @Override public void run(ChunkLoc value) { AugmentedUtils.generate(area.worldname, value.x, value.z, null); } }, null); return true; } case "goto": case "v": case "teleport": case "visit": case "tp": if (!Permissions.hasPermission(player, C.PERMISSION_AREA_TP)) { C.NO_PERMISSION.send(player, C.PERMISSION_AREA_TP); return false; } if (args.length != 2) { C.COMMAND_SYNTAX.send(player, "/plot visit [area]"); return false; } PlotArea area = PS.get().getPlotAreaByString(args[1]); if (area == null) { C.NOT_VALID_PLOT_WORLD.send(player, args[1]); return false; } Location center; if (area.TYPE != 2) { center = WorldUtil.IMP.getSpawn(area.worldname); } else { RegionWrapper region = area.getRegion(); center = new Location(area.worldname, region.minX + (region.maxX - region.minX) / 2, 0, region.minZ + (region.maxZ - region.minZ) / 2); center.setY(WorldUtil.IMP.getHighestBlock(area.worldname, center.getX(), center.getZ())); } player.teleport(center); return true; case "delete": case "remove": MainUtil.sendMessage(player, "$1World creation settings may be stored in multiple locations:" + "\n$3 - $2Bukkit bukkit.yml" + "\n$3 - $2" + PS.imp().getPluginName() + " settings.yml" + "\n$3 - $2Multiverse worlds.yml (or any world management plugin)" + "\n$1Stop the server and delete it from these locations."); return true; } C.COMMAND_SYNTAX.send(player, getUsage()); return false; } }