diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/RegionBackups.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/RegionBackups.java index f8577023..a3f95617 100644 --- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/RegionBackups.java +++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/region/RegionBackups.java @@ -25,12 +25,15 @@ import lombok.RequiredArgsConstructor; import javax.annotation.CheckReturnValue; import javax.annotation.Nullable; +import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Optional; import java.util.function.Function; public interface RegionBackups { + DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy.MM.dd' 'HH:mm:ss"); + @RequiredArgsConstructor enum BackupType { MANUAL(5), @@ -60,6 +63,10 @@ public interface RegionBackups { @CheckReturnValue public abstract boolean load(); + @Override + public final void save() { + } + public abstract long getCreationTime(); @Override @@ -67,6 +74,10 @@ public interface RegionBackups { return Long.compare(getCreationTime(), o.getCreationTime()); } + @Override + public final void load(RegionData regionData) { + } + @SuppressWarnings("java:S3038") // This forces everybody to implement 'deleteRegion' for Backups! @Override public abstract void delete(); diff --git a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionCommand.java b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionCommand.java index 2524fad2..136eabbd 100644 --- a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionCommand.java +++ b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionCommand.java @@ -50,7 +50,7 @@ public class DynamicRegionCommand extends SWCommand { // Check location! - Class regionClass = DynamicRegionSystem.identifierDataMap.get(regionType); + Class regionClass = DynamicRegionSystem.getRegionClassByIdentifier(regionType); DynamicRegion dynamicRegion = DynamicRegionRepository.constructRegion(regionClass, UUID.randomUUID(), tile.getMinX(), tile.getMinZ()); if (dynamicRegion == null) { // TODO: Give error to user @@ -73,7 +73,7 @@ public class DynamicRegionCommand extends SWCommand { return new TypeMapper<>() { @Override public String map(CommandSender commandSender, String[] previousArguments, String s) { - if (DynamicRegionSystem.identifierDataMap.containsKey(s)) { + if (DynamicRegionSystem.hasRegionClassForIdentifier(s)) { return s; } else { return null; @@ -82,7 +82,7 @@ public class DynamicRegionCommand extends SWCommand { @Override public Collection tabCompletes(CommandSender sender, PreviousArguments previousArguments, String s) { - return DynamicRegionSystem.identifierDataMap.keySet(); + return DynamicRegionSystem.allRegionIdentifiers(); } }; } diff --git a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionSystem.java b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionSystem.java index 97e8576d..a4413860 100644 --- a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionSystem.java +++ b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/DynamicRegionSystem.java @@ -62,8 +62,24 @@ public class DynamicRegionSystem implements RegionSystem { regionTypeMap.getOrDefault(region.getType(), Collections.emptySet()).remove(region); } - public static Map, RegionConstructorData> constructorDataMap = new HashMap<>(); - public static Map> identifierDataMap = new HashMap<>(); + private static Map, RegionConstructorData> constructorDataMap = new HashMap<>(); + private static Map> identifierDataMap = new HashMap<>(); + + public static RegionConstructorData getRegionConstructorByRegionClass(Class regionClass) { + return constructorDataMap.get(regionClass); + } + + public static Class getRegionClassByIdentifier(String identifier) { + return identifierDataMap.get(identifier); + } + + public static boolean hasRegionClassForIdentifier(String identifier) { + return identifierDataMap.containsKey(identifier); + } + + public static Set allRegionIdentifiers() { + return Collections.unmodifiableSet(identifierDataMap.keySet()); + } @Override public void load() { diff --git a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/DynamicRegionRepository.java b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/DynamicRegionRepository.java index ebe67445..99ec80e8 100644 --- a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/DynamicRegionRepository.java +++ b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/DynamicRegionRepository.java @@ -132,7 +132,7 @@ public class DynamicRegionRepository { } // TODO: Maybe add static method to DynamicRegionSystem - Class regionClass = DynamicRegionSystem.identifierDataMap.get(identifier); + Class regionClass = DynamicRegionSystem.getRegionClassByIdentifier(identifier); if (regionClass == null) { RegionSystem.LOGGER.log(Level.SEVERE, "Failed to read region metadata file (region no longer exists)"); continue; @@ -172,20 +172,28 @@ public class DynamicRegionRepository { } } + public static File getRegionDirectory(Region region) { + return new File(REGION_DATA_FOLDER, region.getID().toString()); + } + + public static File getBackupsTypeDirectory(Region region, RegionBackups.BackupType backupType) { + File regionDirectory = getRegionDirectory(region); + File backupsDirectory = new File(regionDirectory, BACKUPS_DIR_NAME); + return new File(backupsDirectory, backupType.name()); + } + + public static File getBackupDirectory(Region region, RegionBackups.Backup backup) { + return new File(getBackupsTypeDirectory(region, backup.getType()), backup.getName()); + } + public static void loadRegionData(Region region, RegionData regionData) { - File regionDirectory = new File(REGION_DATA_FOLDER, region.getID().toString()); + File regionDirectory = getRegionDirectory(region); if (!regionDirectory.exists()) return; loadRegionData(regionDirectory, regionData); } public static void loadRegionData(Region region, RegionBackups.Backup backup, RegionData regionData) { - File regionDirectory = new File(REGION_DATA_FOLDER, region.getID().toString()); - if (!regionDirectory.exists()) return; - File backupsDirectory = new File(regionDirectory, BACKUPS_DIR_NAME); - if (!backupsDirectory.exists()) return; - File backupsTypeDirectory = new File(backupsDirectory, backup.getType().name()); - if (!backupsTypeDirectory.exists()) return; - File backupDirectory = new File(backupsTypeDirectory, backup.getName()); + File backupDirectory = getBackupDirectory(region, backup); if (!backupDirectory.exists()) return; loadRegionData(backupDirectory, regionData); } @@ -234,7 +242,7 @@ public class DynamicRegionRepository { } if (!region.getType().isGlobal()) { - RegionConstructorData constructorData = DynamicRegionSystem.constructorDataMap.get(region.getClass()); + RegionConstructorData constructorData = DynamicRegionSystem.getRegionConstructorByRegionClass(region.getClass()); Point point = region.getArea().getMinPoint(false); Tile tile = Tile.fromPoint(point).get(); @@ -242,7 +250,14 @@ public class DynamicRegionRepository { } writeFlagsFile(regionDirectory, region.getRegionData()); - // TODO: Write backups -> Directly on create! + } + + public static void saveBackup(Region region, RegionBackups.Backup backup) { + File backupDirectory = getBackupDirectory(region, backup); + if (!backupDirectory.exists()) { + backupDirectory.mkdirs(); + } + writeFlagsFile(backupDirectory, backup.getRegionData()); } @SneakyThrows @@ -261,8 +276,8 @@ public class DynamicRegionRepository { } @SneakyThrows - private static void writeFlagsFile(File regionDirectory, RegionData regionData) { - JsonWriter jsonWriter = new JsonWriter(new FileWriter(new File(regionDirectory, FLAG_FILE_NAME))); + private static void writeFlagsFile(File directory, RegionData regionData) { + JsonWriter jsonWriter = new JsonWriter(new FileWriter(new File(directory, FLAG_FILE_NAME))); jsonWriter.setIndent(" "); jsonWriter.beginObject(); @@ -285,12 +300,15 @@ public class DynamicRegionRepository { } public static void deleteRegion(Region region) { - File regionDirectory = new File(REGION_DATA_FOLDER, region.getID().toString()); - deleteDir(regionDirectory); + deleteDir(getRegionDirectory(region)); + } + + public static void deleteBackup(Region region, RegionBackups.Backup backup) { + deleteDir(getBackupDirectory(region, backup)); } @SneakyThrows - public static void deleteDir(File file) { + private static void deleteDir(File file) { Files.walkFileTree(file.toPath(), new SimpleFileVisitor<>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { diff --git a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/modes/PlotRegionBackups.java b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/modes/PlotRegionBackups.java index 95b8c9f2..5df0bfa1 100644 --- a/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/modes/PlotRegionBackups.java +++ b/BauSystem/BauSystem_RegionDynamic/src/de/steamwar/bausystem/region/dynamic/modes/PlotRegionBackups.java @@ -20,17 +20,25 @@ package de.steamwar.bausystem.region.dynamic.modes; import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; import de.steamwar.bausystem.region.RegionBackups; import de.steamwar.bausystem.region.RegionData; import de.steamwar.bausystem.region.dynamic.DynamicRegion; import de.steamwar.bausystem.region.dynamic.DynamicRegionRepository; import de.steamwar.bausystem.region.dynamic.PasteUtils; import lombok.NonNull; +import org.bukkit.Bukkit; import org.jetbrains.annotations.Nullable; import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.time.LocalDateTime; import java.util.*; import java.util.function.Function; +import java.util.logging.Level; public class PlotRegionBackups implements RegionBackups { @@ -46,7 +54,18 @@ public class PlotRegionBackups implements RegionBackups { this.region = region; this.regionDataConstructor = regionDataConstructor; - // DynamicRegionRepository.loadRegionData(); + // Load all Backups of the Region + for (BackupType backupType : BackupType.values()) { + File backupsTypeDirectory = DynamicRegionRepository.getBackupsTypeDirectory(region, backupType); + if (!backupsTypeDirectory.exists()) continue; + File[] backupsDirectory = backupsTypeDirectory.listFiles(); + if (backupsDirectory == null) continue; + + List backupList = backups.computeIfAbsent(backupType, __ -> new ArrayList<>()); + for (File backupDirectory : backupsDirectory) { + backupList.add(new BackupImpl(backupType, region, backupDirectory)); + } + } } @Override @@ -60,11 +79,8 @@ public class PlotRegionBackups implements RegionBackups { } // Create backup and save! - Backup backup = new BackupImpl(this, backupType, "", regionDataConstructor, region); - // Create schematic and stuff? - backup.save(); + Backup backup = new BackupImpl(backupType, region); backupList.add(backup); - return Optional.of(backup); } @@ -90,20 +106,34 @@ public class PlotRegionBackups implements RegionBackups { private static final String SCHEM_FILE = "backup.schem"; - private final PlotRegionBackups parent; - private final File folder; private final DynamicRegion region; - public BackupImpl(PlotRegionBackups parent, @NonNull BackupType type, @NonNull String name, @NonNull Function regionDataConstructor, DynamicRegion region) { - super(type, name, regionDataConstructor); - this.parent = parent; - folder = new File(""); + public BackupImpl(@NonNull BackupType type, DynamicRegion region) { + super(type, LocalDateTime.now().format(FORMATTER), regionDataConstructor); + region.getRegionData().copyInto(regionData); this.region = region; + + File backupDirectory = DynamicRegionRepository.getBackupDirectory(region, this); + backupDirectory.mkdirs(); + + DynamicRegionRepository.saveBackup(region, this); + Clipboard clipboard = region.getArea().copy(false); + try (ClipboardWriter writer = BuiltInClipboardFormat.SPONGE_SCHEMATIC.getWriter(new FileOutputStream(new File(backupDirectory, SCHEM_FILE)))) { + writer.write(clipboard); + } catch (IOException e) { + Bukkit.getLogger().log(Level.SEVERE, e.getMessage(), e); + } + } + + public BackupImpl(@NonNull BackupType type, DynamicRegion region, File backupDirectory) { + super(type, backupDirectory.getName(), regionDataConstructor); + this.region = region; + DynamicRegionRepository.loadRegionData(region, this, regionData); } @Override public boolean load() { - File file = new File(folder, SCHEM_FILE); + File file = new File(DynamicRegionRepository.getBackupDirectory(region, this), SCHEM_FILE); if (!file.exists()) return false; EditSession editSession = PasteUtils.paste(file, region.getArea().getMinPoint(false), 0); if (editSession == null) return false; @@ -114,24 +144,14 @@ public class PlotRegionBackups implements RegionBackups { @Override public long getCreationTime() { - throw new UnsupportedOperationException(); + return DynamicRegionRepository.getBackupDirectory(region, this).lastModified(); } @Override public void delete() { - parent.backups.getOrDefault(type, Collections.emptyList()) + backups.getOrDefault(type, Collections.emptyList()) .remove(this); - DynamicRegionRepository.deleteDir(folder); - } - - @Override - public void save() { - throw new UnsupportedOperationException(); - } - - @Override - public void load(RegionData regionData) { - throw new UnsupportedOperationException(); + DynamicRegionRepository.deleteBackup(region, this); } } } diff --git a/BauSystem/BauSystem_RegionFixed/src/de/steamwar/bausystem/region/fixed/FixedRegion.java b/BauSystem/BauSystem_RegionFixed/src/de/steamwar/bausystem/region/fixed/FixedRegion.java index 8117420d..3620edc9 100644 --- a/BauSystem/BauSystem_RegionFixed/src/de/steamwar/bausystem/region/fixed/FixedRegion.java +++ b/BauSystem/BauSystem_RegionFixed/src/de/steamwar/bausystem/region/fixed/FixedRegion.java @@ -45,7 +45,6 @@ import java.util.stream.Collectors; public class FixedRegion implements Region { private static final File backupFolder = new File(Bukkit.getWorlds().get(0).getWorldFolder(), "backup"); - private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd' 'HH:mm:ss"); private final String name; private final UUID uuid; @@ -75,7 +74,7 @@ public class FixedRegion implements Region { while (files.size() >= 20) files.remove(0).delete(); } - final File backupFile = new File(definedBackupFolder, LocalDateTime.now().format(formatter) + ".schem"); + final File backupFile = new File(definedBackupFolder, LocalDateTime.now().format(FORMATTER) + ".schem"); Point minPoint = area.getMinPoint(false); Point maxPoint = area.getMaxPoint(false); if (!FlatteningWrapper.impl.backup(minPoint, maxPoint, backupFile)) { @@ -138,14 +137,6 @@ public class FixedRegion implements Region { return file.lastModified(); } - @Override - public void save() { - } - - @Override - public void load(RegionData regionData) { - } - @Override public void delete() { file.delete();