diff --git a/Core/src/main/java/com/plotsquared/core/backup/PlayerBackupProfile.java b/Core/src/main/java/com/plotsquared/core/backup/PlayerBackupProfile.java index b1d7f43a9..0b551fcd6 100644 --- a/Core/src/main/java/com/plotsquared/core/backup/PlayerBackupProfile.java +++ b/Core/src/main/java/com/plotsquared/core/backup/PlayerBackupProfile.java @@ -41,6 +41,7 @@ import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -106,8 +107,24 @@ public class PlayerBackupProfile implements BackupProfile { } @NotNull public Path getBackupDirectory() { - return backupManager.getBackupPath().resolve(plot.getArea().getId()) - .resolve(plot.getId().toCommaSeparatedString()).resolve(owner.toString()); + return resolve(resolve(resolve(backupManager.getBackupPath(), Objects.requireNonNull(plot.getArea().toString(), "plot area id")), + Objects.requireNonNull(plot.getId().toDashSeparatedString(), "plot id")), Objects.requireNonNull(owner.toString(), "owner")); + } + + private static Path resolve(@NotNull final Path parent, final String child) { + Path path = parent; + try { + if (!Files.exists(parent)) { + Files.createDirectory(parent); + } + path = parent.resolve(child); + if (!Files.exists(path)) { + Files.createDirectory(path); + } + } catch (final Exception e) { + e.printStackTrace(); + } + return path; } @Override @NotNull public CompletableFuture createBackup() { @@ -118,7 +135,8 @@ public class PlayerBackupProfile implements BackupProfile { backups.get(backups.size() - 1).delete(); } final List plots = Collections.singletonList(plot); - final boolean result = SchematicHandler.manager.exportAll(plots, null, null, () -> + final boolean result = SchematicHandler.manager.exportAll(plots, getBackupDirectory().toFile(), + "%world%-%id%-%owner%-" + System.currentTimeMillis(), () -> future.complete(new Backup(this, System.currentTimeMillis(), null))); if (!result) { future.completeExceptionally(new RuntimeException("Failed to complete the backup")); diff --git a/Core/src/main/java/com/plotsquared/core/command/Backup.java b/Core/src/main/java/com/plotsquared/core/command/Backup.java index 60cba6d6c..948722e32 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Backup.java +++ b/Core/src/main/java/com/plotsquared/core/command/Backup.java @@ -37,6 +37,10 @@ import com.plotsquared.core.util.task.RunnableVal2; import com.plotsquared.core.util.task.RunnableVal3; import java.nio.file.Files; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -77,11 +81,11 @@ public final class Backup extends Command { @Override public Collection tab(PlotPlayer player, String[] args, boolean space) { if (args.length == 1) { - return Stream.of("save", "list", "save") + return Stream.of("save", "list", "load") .filter(value -> value.startsWith(args[0].toLowerCase(Locale.ENGLISH))) .map(value -> new Command(null, false, value, "", RequiredType.NONE, null) {}) .collect(Collectors.toList()); - } else if (args[0].equalsIgnoreCase("load") && args.length == 2) { + } else if (args[0].equalsIgnoreCase("load")) { final Plot plot = player.getCurrentPlot(); if (plot != null) { @@ -129,6 +133,7 @@ public final class Backup extends Command { backupProfile.createBackup().whenComplete((backup, throwable) -> { if (throwable != null) { sendMessage(player, Captions.BACKUP_SAVE_FAILED, throwable.getMessage()); + throwable.printStackTrace(); } else { sendMessage(player, Captions.BACKUP_SAVE_SUCCESS); } @@ -161,7 +166,22 @@ public final class Backup extends Command { sendMessage(player, Captions.BACKUP_IMPOSSIBLE, Captions.GENERIC_OTHER.getTranslated()); } else { backupProfile.listBackups().whenComplete((backups, throwable) -> { - // TODO: List backups + if (throwable != null) { + sendMessage(player, Captions.BACKUP_LIST_FAILED, throwable.getMessage()); + throwable.printStackTrace(); + } else { + sendMessage(player, Captions.BACKUP_LIST_HEADER, plot.getId().toCommaSeparatedString()); + try { + for (int i = 0; i < backups.size(); i++) { + sendMessage(player, Captions.BACKUP_LIST_ENTRY, Integer.toString(i + 1), + DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime + .ofInstant(Instant.ofEpochMilli(backups.get(i).getCreationTime()), ZoneId + .systemDefault()))); + } + } catch (final Exception e) { + e.printStackTrace(); + } + } }); } } @@ -203,6 +223,7 @@ public final class Backup extends Command { backupProfile.listBackups().whenComplete((backups, throwable) -> { if (throwable != null) { sendMessage(player, Captions.BACKUP_LOAD_FAILURE, throwable.getMessage()); + throwable.printStackTrace(); } else { if (number < 1 || number > backups.size()) { sendMessage(player, Captions.BACKUP_LOAD_FAILURE, Captions.GENERIC_INVALID_CHOICE.getTranslated()); 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 3d8897629..5626d877b 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/Captions.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/Captions.java @@ -756,6 +756,9 @@ public enum Captions implements Caption { BACKUP_LOAD_SUCCESS("$1The backup was restored successfully", "Backups"), BACKUP_LOAD_FAILURE("$2The backup could not be restored: %s", "Backups"), BACKUP_LOAD_USAGE("$1Usage: $2/plot backup load [#]", "Backups"), + BACKUP_LIST_HEADER("$1Available backups for plot $2%s", "Backups"), + BACKUP_LIST_ENTRY("$3- $1#%s0 $2%s1", "Backups"), + BACKUP_LIST_FAILED("$2Backup listing failed: %s", "Backups"), // // diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotId.java b/Core/src/main/java/com/plotsquared/core/plot/PlotId.java index 3421de833..146c311c6 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/PlotId.java +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotId.java @@ -198,6 +198,9 @@ public class PlotId { return this.x + "," + this.y; } + public String toDashSeparatedString() { + return this.x + "-" + this.y; + } /**