diff --git a/src/main/java/com/intellectualcrafters/plot/BukkitMain.java b/src/main/java/com/intellectualcrafters/plot/BukkitMain.java index 9bba2387c..d583241fa 100644 --- a/src/main/java/com/intellectualcrafters/plot/BukkitMain.java +++ b/src/main/java/com/intellectualcrafters/plot/BukkitMain.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.UUID; import com.intellectualcrafters.plot.commands.*; + import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; @@ -183,6 +184,8 @@ public class BukkitMain extends JavaPlugin implements Listener, IPlotMain { @Override public void registerCommands() { new MainCommand(); + MainCommand.subCommands.add(new Save()); + MainCommand.subCommands.add(new Load()); MainCommand.subCommands.add(new Download()); MainCommand.subCommands.add(new Disable()); MainCommand.subCommands.add(new Update()); @@ -611,4 +614,9 @@ public class BukkitMain extends JavaPlugin implements Listener, IPlotMain { public InventoryUtil initInventoryUtil() { return new BukkitInventoryUtil(); } + + @Override + public String getServerName() { + return Bukkit.getServerName(); + } } diff --git a/src/main/java/com/intellectualcrafters/plot/IPlotMain.java b/src/main/java/com/intellectualcrafters/plot/IPlotMain.java index 9e5880565..6ec7bc26e 100644 --- a/src/main/java/com/intellectualcrafters/plot/IPlotMain.java +++ b/src/main/java/com/intellectualcrafters/plot/IPlotMain.java @@ -77,6 +77,8 @@ public interface IPlotMain { public void registerWorldEvents(); public PlayerManager initPlayerManager(); + + public String getServerName(); public boolean checkVersion(int major, int minor, int minor2); } diff --git a/src/main/java/com/intellectualcrafters/plot/commands/Command.java b/src/main/java/com/intellectualcrafters/plot/commands/Command.java index 7b8df7b2c..e3e77c214 100644 --- a/src/main/java/com/intellectualcrafters/plot/commands/Command.java +++ b/src/main/java/com/intellectualcrafters/plot/commands/Command.java @@ -43,6 +43,8 @@ public enum Command { UNDENY("undeny", "ud"), TOGGLE("toggle", "attribute"), DOWNLOAD("download", "dl"), + SAVE("save", "backup"), + LOAD("load", "restore"), MOVE("move"), FLAG("flag", "f"), TARGET("target"), diff --git a/src/main/java/com/intellectualcrafters/plot/commands/Download.java b/src/main/java/com/intellectualcrafters/plot/commands/Download.java index 60af149da..e729e4db5 100644 --- a/src/main/java/com/intellectualcrafters/plot/commands/Download.java +++ b/src/main/java/com/intellectualcrafters/plot/commands/Download.java @@ -10,6 +10,7 @@ import com.intellectualcrafters.plot.object.Plot; import com.intellectualcrafters.plot.object.PlotPlayer; import com.intellectualcrafters.plot.object.RunnableVal; import com.intellectualcrafters.plot.util.MainUtil; +import com.intellectualcrafters.plot.util.Permissions; import com.intellectualcrafters.plot.util.SchematicHandler; import com.intellectualcrafters.plot.util.TaskManager; @@ -32,6 +33,14 @@ public class Download extends SubCommand { if (plot == null) { return !sendMessage(plr, C.NOT_IN_PLOT); } + if (!plot.hasOwner()) { + MainUtil.sendMessage(plr, C.PLOT_UNOWNED); + return false; + } + if (!plot.isOwner(plr.getUUID()) && !Permissions.hasPermission(plr, "plots.admin.command.download")) { + MainUtil.sendMessage(plr, C.NO_PLOT_PERMS); + return false; + } if (MainUtil.runners.containsKey(plot)) { MainUtil.sendMessage(plr, C.WAIT_FOR_TIMER); return false; @@ -44,7 +53,7 @@ public class Download extends SubCommand { TaskManager.runTaskAsync(new Runnable() { @Override public void run() { - URL url = SchematicHandler.manager.upload(value, null); + URL url = SchematicHandler.manager.upload(value, null, null); if (url == null) { MainUtil.sendMessage(plr, C.GENERATING_LINK_FAILED); MainUtil.runners.remove(plot); diff --git a/src/main/java/com/intellectualcrafters/plot/commands/Load.java b/src/main/java/com/intellectualcrafters/plot/commands/Load.java new file mode 100644 index 000000000..b56ca3341 --- /dev/null +++ b/src/main/java/com/intellectualcrafters/plot/commands/Load.java @@ -0,0 +1,205 @@ +package com.intellectualcrafters.plot.commands; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; +import java.util.UUID; + +import com.intellectualcrafters.jnbt.CompoundTag; +import com.intellectualcrafters.plot.PS; +import com.intellectualcrafters.plot.config.C; +import com.intellectualcrafters.plot.config.Settings; +import com.intellectualcrafters.plot.object.Plot; +import com.intellectualcrafters.plot.object.PlotId; +import com.intellectualcrafters.plot.object.PlotPlayer; +import com.intellectualcrafters.plot.object.RunnableVal; +import com.intellectualcrafters.plot.util.MainUtil; +import com.intellectualcrafters.plot.util.Permissions; +import com.intellectualcrafters.plot.util.SchematicHandler; +import com.intellectualcrafters.plot.util.SchematicHandler.Schematic; +import com.intellectualcrafters.plot.util.TaskManager; + +public class Load extends SubCommand { + public Load() { + super(Command.LOAD, "Load your plot", "restore", CommandCategory.ACTIONS, true); + } + + @Override + public boolean execute(final PlotPlayer plr, String... args) { + if (!Settings.METRICS) { + MainUtil.sendMessage(plr, "&cPlease enable metrics in order to use this command.\n&7 - Or host it yourself if you don't like the free service"); + return false; + } + final String world = plr.getLocation().getWorld(); + if (!PS.get().isPlotWorld(world)) { + return !sendMessage(plr, C.NOT_IN_PLOT_WORLD); + } + final Plot plot = MainUtil.getPlot(plr.getLocation()); + if (plot == null) { + return !sendMessage(plr, C.NOT_IN_PLOT); + } + if (!plot.hasOwner()) { + MainUtil.sendMessage(plr, C.PLOT_UNOWNED); + return false; + } + if (!plot.isOwner(plr.getUUID()) && !Permissions.hasPermission(plr, "plots.admin.command.load")) { + MainUtil.sendMessage(plr, C.NO_PLOT_PERMS); + return false; + } + if (MainUtil.runners.containsKey(plot)) { + MainUtil.sendMessage(plr, C.WAIT_FOR_TIMER); + return false; + } + + if (args.length != 0) { + if (args.length == 1) { + // TODO load save here + List schematics = (List) plr.getMeta("plot_schematics"); + if (schematics == null) { + // No schematics found: + MainUtil.sendMessage(plr, C.LOAD_NULL); + return false; + } + String schem; + try { + schem = schematics.get(Integer.parseInt(args[0]) - 1); + } + catch (Exception e) { + // use /plot load + MainUtil.sendMessage(plr, C.NOT_VALID_NUMBER, "(1, " + schematics.size() + ")"); + return false; + } + final URL url; + try { + url = new URL(Settings.WEB_URL + "saves/" + plr.getUUID() + "/" + schem); + } catch (MalformedURLException e) { + e.printStackTrace(); + MainUtil.sendMessage(plr, C.LOAD_FAILED); + return false; + } + + MainUtil.runners.put(plot, 1); + MainUtil.sendMessage(plr, C.GENERATING_COMPONENT); + TaskManager.runTaskAsync(new Runnable() { + @Override + public void run() { + Schematic schematic = SchematicHandler.manager.getSchematic(url); + if (schematic == null) { + MainUtil.runners.remove(plot); + sendMessage(plr, C.SCHEMATIC_INVALID, "non-existent or not in gzip format"); + return; + } + SchematicHandler.manager.paste(schematic, plot, 0, 0, new RunnableVal() { + @Override + public void run() { + MainUtil.runners.remove(plot); + if (this.value) { + sendMessage(plr, C.SCHEMATIC_PASTE_SUCCESS); + } + else { + sendMessage(plr, C.SCHEMATIC_PASTE_FAILED); + } + } + }); + } + }); + return true; + } + MainUtil.runners.remove(plot); + MainUtil.sendMessage(plr, C.COMMAND_SYNTAX, "/plot load "); + return false; + } + + // list schematics + + List schematics = (List) plr.getMeta("plot_schematics"); + if (schematics == null) { + MainUtil.runners.put(plot, 1); + TaskManager.runTaskAsync(new Runnable() { + @Override + public void run() { + List schematics = SchematicHandler.manager.getSaves(plr.getUUID()); + MainUtil.runners.remove(plot); + if (schematics == null || schematics.size() == 0) { + MainUtil.sendMessage(plr, C.LOAD_FAILED); + return; + } + plr.setMeta("plot_schematics", schematics); + displaySaves(plr, 0); + } + }); + } + else { + displaySaves(plr, 0); + } + return true; + } + + public void displaySaves(PlotPlayer player, int page) { + List schematics = (List) player.getMeta("plot_schematics"); + for (int i = 0; i < Math.min(schematics.size(), 32); i++) { + try { + String schem = schematics.get(i); + String[] split = schem.split("_"); + if (split.length != 6) { + continue; + } + String time = secToTime((System.currentTimeMillis() / 1000) - (Long.parseLong(split[0]))); + String world = split[1]; + PlotId id = PlotId.fromString(split[2] + ";" + split[3]); + String size = split[4]; + String server = split[5].replaceAll(".schematic", ""); + String color; + if (PS.get().IMP.getServerName().replaceAll("[^A-Za-z0-9]", "").equals(server)) { + color = "$4"; + } + else { + color = "$1"; + } + MainUtil.sendMessage(player, "$3[$2" + (i + 1) + "$3] " + color + time + "$3 | " + color + world + ";" + id + "$3 | " + color + size + "x" + size); + } + catch (Exception e) { + e.printStackTrace(); + } + } + MainUtil.sendMessage(player, C.LOAD_LIST); + } + + public String secToTime(long time) { + StringBuilder toreturn = new StringBuilder(); + int years = 0; + int weeks = 0; + int days = 0; + int hours = 0; + int minutes = 0; + if (time>=33868800) { + years = (int) (time/33868800); + time-=years*33868800; + toreturn.append(years+"y "); + } + if (time>=604800) { + weeks = (int) (time/604800); + time-=weeks*604800; + toreturn.append(weeks+"w "); + } + if (time>=86400) { + days = (int) (time/86400); + time-=days*86400; + toreturn.append(days+"d "); + } + if (time>=3600) { + hours = (int) (time/3600); + time-=hours*3600; + toreturn.append(hours+"h "); + } + if (time>=60) { + minutes = (int) (time/60); + time-=minutes*60; + toreturn.append(minutes+"m "); + } + if (toreturn.equals("")||time>0){ + toreturn.append((time)+"s "); + } + return toreturn.toString().trim(); + } +} diff --git a/src/main/java/com/intellectualcrafters/plot/commands/Save.java b/src/main/java/com/intellectualcrafters/plot/commands/Save.java new file mode 100644 index 000000000..d940d6e3a --- /dev/null +++ b/src/main/java/com/intellectualcrafters/plot/commands/Save.java @@ -0,0 +1,84 @@ +package com.intellectualcrafters.plot.commands; + +import java.net.URL; +import java.util.List; +import java.util.UUID; + +import com.intellectualcrafters.jnbt.CompoundTag; +import com.intellectualcrafters.plot.PS; +import com.intellectualcrafters.plot.config.C; +import com.intellectualcrafters.plot.config.Settings; +import com.intellectualcrafters.plot.object.Plot; +import com.intellectualcrafters.plot.object.PlotId; +import com.intellectualcrafters.plot.object.PlotPlayer; +import com.intellectualcrafters.plot.object.RunnableVal; +import com.intellectualcrafters.plot.util.MainUtil; +import com.intellectualcrafters.plot.util.Permissions; +import com.intellectualcrafters.plot.util.SchematicHandler; +import com.intellectualcrafters.plot.util.TaskManager; + +public class Save extends SubCommand { + public Save() { + super(Command.SAVE, "Save your plot", "backup", CommandCategory.ACTIONS, true); + } + + @Override + public boolean execute(final PlotPlayer plr, String... args) { + if (!Settings.METRICS) { + MainUtil.sendMessage(plr, "&cPlease enable metrics in order to use this command.\n&7 - Or host it yourself if you don't like the free service"); + return false; + } + final String world = plr.getLocation().getWorld(); + if (!PS.get().isPlotWorld(world)) { + return !sendMessage(plr, C.NOT_IN_PLOT_WORLD); + } + final Plot plot = MainUtil.getPlot(plr.getLocation()); + if (plot == null) { + return !sendMessage(plr, C.NOT_IN_PLOT); + } + if (!plot.hasOwner()) { + MainUtil.sendMessage(plr, C.PLOT_UNOWNED); + return false; + } + if (!plot.isOwner(plr.getUUID()) && !Permissions.hasPermission(plr, "plots.admin.command.save")) { + MainUtil.sendMessage(plr, C.NO_PLOT_PERMS); + return false; + } + if (MainUtil.runners.containsKey(plot)) { + MainUtil.sendMessage(plr, C.WAIT_FOR_TIMER); + return false; + } + MainUtil.runners.put(plot, 1); + SchematicHandler.manager.getCompoundTag(plot.world, plot.id, new RunnableVal() { + @Override + public void run() { + TaskManager.runTaskAsync(new Runnable() { + @Override + public void run() { + String time = (System.currentTimeMillis() / 1000) + ""; + String name = PS.get().IMP.getServerName().replaceAll("[^A-Za-z0-9]", ""); + int size = plot.getTop().getX() - plot.getBottom().getX() + 1; + PlotId id = plot.id; + String world = plot.world.replaceAll("[^A-Za-z0-9]", ""); + String file = time + "_" + world + "_" + id.x + "_" + id.y + "_" + size + "_" + name; + UUID uuid = plr.getUUID(); + + URL url = SchematicHandler.manager.upload(value, uuid, file); + if (url == null) { + MainUtil.sendMessage(plr, C.SAVE_FAILED); + MainUtil.runners.remove(plot); + return; + } + MainUtil.sendMessage(plr, C.SAVE_SUCCESS); + List schematics = (List) plr.getMeta("plot_schematics"); + if (schematics != null) { + schematics.add(file); + } + MainUtil.runners.remove(plot); + } + }); + } + }); + return true; + } +} diff --git a/src/main/java/com/intellectualcrafters/plot/commands/SchematicCmd.java b/src/main/java/com/intellectualcrafters/plot/commands/SchematicCmd.java index e02fbc016..f6a0a2c00 100644 --- a/src/main/java/com/intellectualcrafters/plot/commands/SchematicCmd.java +++ b/src/main/java/com/intellectualcrafters/plot/commands/SchematicCmd.java @@ -81,7 +81,14 @@ public class SchematicCmd extends SubCommand { final Location loc = plr.getLocation(); final Plot plot = MainUtil.getPlot(loc); if (plot == null) { - sendMessage(plr, C.NOT_IN_PLOT); + return !sendMessage(plr, C.NOT_IN_PLOT); + } + if (!plot.hasOwner()) { + MainUtil.sendMessage(plr, C.PLOT_UNOWNED); + return false; + } + if (!plot.isOwner(plr.getUUID()) && !Permissions.hasPermission(plr, "plots.admin.command.schematic.paste")) { + MainUtil.sendMessage(plr, C.NO_PLOT_PERMS); return false; } if (this.running) { @@ -218,8 +225,12 @@ public class SchematicCmd extends SubCommand { if (plot == null) { return !sendMessage(plr, C.NOT_IN_PLOT); } - if (!plot.isAdded(plr.getUUID())) { - sendMessage(plr, C.NO_PLOT_PERMS); + if (!plot.hasOwner()) { + MainUtil.sendMessage(plr, C.PLOT_UNOWNED); + return false; + } + if (!plot.isOwner(plr.getUUID()) && !Permissions.hasPermission(plr, "plots.admin.command.schematic.save")) { + MainUtil.sendMessage(plr, C.NO_PLOT_PERMS); return false; } p2 = plot; diff --git a/src/main/java/com/intellectualcrafters/plot/config/C.java b/src/main/java/com/intellectualcrafters/plot/config/C.java index 92bd133c7..c531a20d6 100644 --- a/src/main/java/com/intellectualcrafters/plot/config/C.java +++ b/src/main/java/com/intellectualcrafters/plot/config/C.java @@ -58,6 +58,11 @@ public enum C { */ GENERATING_LINK("$1Processing plot...", "Web"), GENERATING_LINK_FAILED("$2Failed to generate download link!", "Web"), + SAVE_FAILED("$2Failed to save", "Web"), + LOAD_NULL("$2Please use $4/plot load $2to get a list of schematics", "Web"), + LOAD_FAILED("$2Failed to load schematic", "Web"), + LOAD_LIST("$2To load a schematic, use $1/plot load #", "Web"), + SAVE_SUCCESS("$1Successfully saved!", "Web"), /* * Compass */ diff --git a/src/main/java/com/intellectualcrafters/plot/util/BukkitSchematicHandler.java b/src/main/java/com/intellectualcrafters/plot/util/BukkitSchematicHandler.java index 63f40e158..c80ec882c 100644 --- a/src/main/java/com/intellectualcrafters/plot/util/BukkitSchematicHandler.java +++ b/src/main/java/com/intellectualcrafters/plot/util/BukkitSchematicHandler.java @@ -39,7 +39,6 @@ import com.intellectualcrafters.jnbt.ListTag; import com.intellectualcrafters.jnbt.ShortTag; import com.intellectualcrafters.jnbt.StringTag; import com.intellectualcrafters.jnbt.Tag; -import com.intellectualcrafters.plot.PS; import com.intellectualcrafters.plot.object.ChunkLoc; import com.intellectualcrafters.plot.object.Location; import com.intellectualcrafters.plot.object.RunnableVal; diff --git a/src/main/java/com/intellectualcrafters/plot/util/SchematicHandler.java b/src/main/java/com/intellectualcrafters/plot/util/SchematicHandler.java index 559c83a35..56140f347 100644 --- a/src/main/java/com/intellectualcrafters/plot/util/SchematicHandler.java +++ b/src/main/java/com/intellectualcrafters/plot/util/SchematicHandler.java @@ -1,18 +1,22 @@ package com.intellectualcrafters.plot.util; +import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; +import java.io.Reader; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -24,6 +28,7 @@ import java.util.UUID; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; +import com.google.common.collect.Lists; import com.intellectualcrafters.jnbt.ByteArrayTag; import com.intellectualcrafters.jnbt.CompoundTag; import com.intellectualcrafters.jnbt.IntTag; @@ -33,6 +38,8 @@ import com.intellectualcrafters.jnbt.NBTOutputStream; import com.intellectualcrafters.jnbt.ShortTag; import com.intellectualcrafters.jnbt.StringTag; import com.intellectualcrafters.jnbt.Tag; +import com.intellectualcrafters.json.JSONArray; +import com.intellectualcrafters.json.JSONObject; import com.intellectualcrafters.plot.PS; import com.intellectualcrafters.plot.config.Settings; import com.intellectualcrafters.plot.object.ChunkLoc; @@ -497,7 +504,6 @@ public abstract class SchematicHandler { ReadableByteChannel rbc = Channels.newChannel(url.openStream()); InputStream is = Channels.newInputStream(rbc); return getSchematic(is); -// fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); } catch (final Exception e) { e.printStackTrace(); } @@ -523,7 +529,36 @@ public abstract class SchematicHandler { return null; } - public URL upload(final CompoundTag tag, UUID uuid) { + public List getSaves(UUID uuid) { + try { + String website = Settings.WEB_URL + "list.php?" + uuid.toString(); + URL url = new URL(website); + URLConnection connection = new URL(url.toString()).openConnection(); + connection.setRequestProperty("User-Agent", "Mozilla/5.0"); + BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + String line; + StringBuilder rawJSON = new StringBuilder(); + while ((line = reader.readLine()) != null) { + rawJSON.append(line); + } + reader.close(); + System.out.print(rawJSON); + JSONArray array = new JSONArray(rawJSON.toString()); + List schematics = new ArrayList<>(); + for (int i = 0; i < array.length(); i++) { + String schematic = array.getString(i); + System.out.print(schematic); + schematics.add(schematic); + } + return Lists.reverse(schematics); + } + catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public URL upload(final CompoundTag tag, UUID uuid, String file) { if (tag == null) { PS.log("&cCannot save empty tag"); return null; @@ -533,6 +568,7 @@ public abstract class SchematicHandler { if (uuid == null) { uuid = UUID.randomUUID(); website = Settings.WEB_URL + "upload.php?" + uuid; + file = "plot"; } else { website = Settings.WEB_URL + "save.php?" + uuid; @@ -553,8 +589,8 @@ public abstract class SchematicHandler { writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF); writer.append(CRLF).append(param).append(CRLF).flush(); writer.append("--" + boundary).append(CRLF); - writer.append("Content-Disposition: form-data; name=\"schematicFile\"; filename=\"" + "plot.schematic" + "\"").append(CRLF); - writer.append("Content-Type: " + URLConnection.guessContentTypeFromName("plot.schematic")).append(CRLF); + writer.append("Content-Disposition: form-data; name=\"schematicFile\"; filename=\"" + file + ".schematic" + "\"").append(CRLF); + writer.append("Content-Type: " + URLConnection.guessContentTypeFromName(file + ".schematic")).append(CRLF); writer.append("Content-Transfer-Encoding: binary").append(CRLF); writer.append(CRLF).flush(); GZIPOutputStream gzip = new GZIPOutputStream(output); @@ -568,23 +604,21 @@ public abstract class SchematicHandler { nos.close(); output.close(); } -// try (Reader response = new InputStreamReader(con.getInputStream(), StandardCharsets.UTF_8)) { -// final char[] buffer = new char[256]; -// StringBuilder result = new StringBuilder(); -// while (true) { -// int r = response.read(buffer); -// if (r < 0) { -// break; -// } -// result.append(buffer, 0, r); -// } -// if (!result.equals("The file plot.schematic has been uploaded.")) { -// return null; -// } -// } -// catch (Exception e) { -// -// } + try (Reader response = new InputStreamReader(con.getInputStream(), StandardCharsets.UTF_8)) { + final char[] buffer = new char[256]; + StringBuilder result = new StringBuilder(); + while (true) { + int r = response.read(buffer); + if (r < 0) { + break; + } + result.append(buffer, 0, r); + } + System.out.print(result); + } + catch (Exception e) { + e.printStackTrace(); + } int responseCode = ((HttpURLConnection) con).getResponseCode(); if (responseCode != 200) { return null; diff --git a/src/main/java/com/intellectualcrafters/plot/util/bukkit/BukkitEconHandler.java b/src/main/java/com/intellectualcrafters/plot/util/bukkit/BukkitEconHandler.java index 17d48641f..9384b7696 100644 --- a/src/main/java/com/intellectualcrafters/plot/util/bukkit/BukkitEconHandler.java +++ b/src/main/java/com/intellectualcrafters/plot/util/bukkit/BukkitEconHandler.java @@ -40,7 +40,6 @@ public class BukkitEconHandler extends EconHandler { if (economyProvider != null) { econ = economyProvider.getProvider(); } - return (econ != null); }