diff --git a/src/main/java/com/replaymod/core/ReplayMod.java b/src/main/java/com/replaymod/core/ReplayMod.java index 29a5dccc..7e90cb10 100644 --- a/src/main/java/com/replaymod/core/ReplayMod.java +++ b/src/main/java/com/replaymod/core/ReplayMod.java @@ -1,6 +1,5 @@ package com.replaymod.core; -import com.google.common.io.Files; import com.replaymod.compat.ReplayModCompat; import com.replaymod.core.gui.GuiBackgroundProcesses; import com.replaymod.core.gui.GuiReplaySettings; @@ -27,6 +26,7 @@ import net.minecraft.text.LiteralText; import net.minecraft.text.TranslatableText; import net.minecraft.util.Formatting; import net.minecraft.util.crash.CrashException; +import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FileUtils; //#if MC>=11400 @@ -89,6 +89,9 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -216,11 +219,24 @@ public class ReplayMod implements return settingsRegistry; } - public File getReplayFolder() throws IOException { - String path = getSettingsRegistry().get(Setting.RECORDING_PATH); - File folder = new File(path.startsWith("./") ? getMinecraft().runDirectory : null, path); - FileUtils.forceMkdir(folder); - return folder; + public Path getReplayFolder() throws IOException { + String str = getSettingsRegistry().get(Setting.RECORDING_PATH); + return Files.createDirectories(getMinecraft().runDirectory.toPath().resolve(str)); + } + + /** + * Folder into which replay backups are saved before the MarkerProcessor is unleashed. + */ + public Path getRawReplayFolder() throws IOException { + return Files.createDirectories(getReplayFolder().resolve("raw")); + } + + /** + * Folder into which replays are recorded. + * Distinct from the main folder, so they cannot be opened while they are still saving. + */ + public Path getRecordingFolder() throws IOException { + return Files.createDirectories(getReplayFolder().resolve("recording")); } public static final DirectoryResourcePack jGuiResourcePack; @@ -347,30 +363,39 @@ public class ReplayMod implements final long DAYS = 24 * 60 * 60 * 1000; // Cleanup raw folder content three weeks after creation (these are pretty valuable for debugging) - try { - File[] files = new File(getReplayFolder(), "raw").listFiles(); - if (files != null) { - for (File file : files) { - if (file.lastModified() + 21 * DAYS < System.currentTimeMillis()) { - FileUtils.forceDelete(file); - } + try (DirectoryStream paths = Files.newDirectoryStream(getRawReplayFolder())) { + for (Path path : paths) { + if (Files.getLastModifiedTime(path).toMillis() + 21 * DAYS < System.currentTimeMillis()) { + Files.delete(path); } } } catch (IOException e) { e.printStackTrace(); } + // Move anything which is still in the recording folder into the regular replay folder + // so it can be opened and/or recovered + try (DirectoryStream paths = Files.newDirectoryStream(getRecordingFolder())) { + for (Path path : paths) { + Path destination = getReplayFolder().resolve(path.getFileName()); + if (Files.exists(destination)) { + continue; // better play it save + } + Files.move(path, destination); + } + } catch (IOException e) { + e.printStackTrace(); + } + // Cleanup cache folders 7 days after last modification or when its replay is gone - try { - File[] files = getReplayFolder().listFiles(); - if (files != null) { - for (File file : files) { - String name = file.getName(); - if (file.isDirectory() && name.endsWith(".mcpr.cache")) { - File replay = new File(getReplayFolder(), name.substring(0, name.length() - ".cache".length())); - if (file.lastModified() + 7 * DAYS < System.currentTimeMillis() || !replay.exists()) { - FileUtils.deleteDirectory(file); - } + try (DirectoryStream paths = Files.newDirectoryStream(getReplayFolder())) { + for (Path path : paths) { + String name = path.getFileName().toString(); + if (name.endsWith(".mcpr.cache") && Files.isDirectory(path)) { + Path replay = path.resolveSibling(FilenameUtils.getBaseName(name)); + long lastModified = Files.getLastModifiedTime(path).toMillis(); + if (lastModified + 7 * DAYS < System.currentTimeMillis() || !Files.exists(replay)) { + FileUtils.deleteDirectory(path.toFile()); } } } @@ -379,14 +404,13 @@ public class ReplayMod implements } // Cleanup deleted corrupted replays - try { - File[] files = getReplayFolder().listFiles(); - if (files != null) { - for (File file : files) { - if (file.isDirectory() && file.getName().endsWith(".mcpr.del")) { - if (file.lastModified() + 2 * DAYS < System.currentTimeMillis()) { - FileUtils.deleteDirectory(file); - } + try (DirectoryStream paths = Files.newDirectoryStream(getReplayFolder())) { + for (Path path : paths) { + String name = path.getFileName().toString(); + if (name.endsWith(".mcpr.del") && Files.isDirectory(path)) { + long lastModified = Files.getLastModifiedTime(path).toMillis(); + if (lastModified + 2 * DAYS < System.currentTimeMillis()) { + FileUtils.deleteDirectory(path.toFile()); } } } @@ -395,14 +419,12 @@ public class ReplayMod implements } // Restore corrupted replays - try { - File[] files = getReplayFolder().listFiles(); - if (files != null) { - for (File file : files) { - if (file.isDirectory() && file.getName().endsWith(".mcpr.tmp")) { - File origFile = new File(file.getParentFile(), Files.getNameWithoutExtension(file.getName())); - new RestoreReplayGui(this, GuiScreen.wrap(mc.currentScreen), origFile).display(); - } + try (DirectoryStream paths = Files.newDirectoryStream(getReplayFolder())) { + for (Path path : paths) { + String name = path.getFileName().toString(); + if (name.endsWith(".mcpr.tmp") && Files.isDirectory(path)) { + Path original = path.resolveSibling(FilenameUtils.getBaseName(name)); + new RestoreReplayGui(this, GuiScreen.wrap(mc.currentScreen), original.toFile()).display(); } } } catch (IOException e) { diff --git a/src/main/java/com/replaymod/editor/gui/MarkerProcessor.java b/src/main/java/com/replaymod/editor/gui/MarkerProcessor.java index b9d560c6..efa40cb0 100644 --- a/src/main/java/com/replaymod/editor/gui/MarkerProcessor.java +++ b/src/main/java/com/replaymod/editor/gui/MarkerProcessor.java @@ -1,5 +1,6 @@ package com.replaymod.editor.gui; +import com.replaymod.core.ReplayMod; import com.replaymod.core.versions.MCVer; import com.replaymod.replaystudio.PacketData; import com.replaymod.replaystudio.Studio; @@ -126,7 +127,8 @@ public class MarkerProcessor { List> outputPaths = new ArrayList<>(); - Path inputPath = path.resolveSibling("raw").resolve(path.getFileName()); + Path rawFolder = ReplayMod.instance.getRawReplayFolder(); + Path inputPath = rawFolder.resolve(path.getFileName()); for (int i = 1; Files.exists(inputPath); i++) { inputPath = inputPath.resolveSibling(replayName + "." + i + ".mcpr"); } diff --git a/src/main/java/com/replaymod/recording/gui/GuiSavingReplay.java b/src/main/java/com/replaymod/recording/gui/GuiSavingReplay.java index eb595f65..3cbf609e 100644 --- a/src/main/java/com/replaymod/recording/gui/GuiSavingReplay.java +++ b/src/main/java/com/replaymod/recording/gui/GuiSavingReplay.java @@ -109,13 +109,7 @@ public class GuiSavingReplay { .addElements(null, textField, clearButton); panel.addElements(new VerticalLayout.Data(0.5), row); - apply.add(() -> { - String newName = textField.getText(); - if (newName.equals(originalName)) { - return; - } - applyOutput(path, newName); - }); + apply.add(() -> applyOutput(path, textField.getText())); return textField; } @@ -151,12 +145,12 @@ public class GuiSavingReplay { return; } - Path newPath = path.resolveSibling(Utils.replayNameToFileName(newName)); - if (Files.exists(newPath)) { - return; - } - try { + Path replaysFolder = core.getReplayFolder(); + Path newPath = replaysFolder.resolve(Utils.replayNameToFileName(newName)); + for (int i = 1; Files.exists(newPath); i++) { + newPath = replaysFolder.resolve(Utils.replayNameToFileName(newName + " (" + i + ")")); + } Files.move(path, newPath); } catch (IOException e) { logger.error("Renaming replay file:", e); diff --git a/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java b/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java index ba6fdec0..d066e080 100644 --- a/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java +++ b/src/main/java/com/replaymod/recording/handler/ConnectionEventHandler.java @@ -32,7 +32,7 @@ import net.minecraft.world.World; //#endif //#endif -import java.io.File; +import java.nio.file.Path; import java.text.SimpleDateFormat; import java.util.Calendar; @@ -121,11 +121,9 @@ public class ConnectionEventHandler { autoStart = true; } - File folder = core.getReplayFolder(); - String name = sdf.format(Calendar.getInstance().getTime()); - File currentFile = new File(folder, Utils.replayNameToFileName(name)); - ReplayFile replayFile = new ZipReplayFile(new ReplayStudio(), currentFile); + Path outputPath = core.getRecordingFolder().resolve(Utils.replayNameToFileName(name)); + ReplayFile replayFile = new ZipReplayFile(new ReplayStudio(), outputPath.toFile()); replayFile.writeModInfo(ModCompat.getInstalledNetworkMods()); @@ -135,7 +133,7 @@ public class ConnectionEventHandler { metaData.setGenerator("ReplayMod v" + ReplayMod.instance.getVersion()); metaData.setDate(System.currentTimeMillis()); metaData.setMcVersion(ReplayMod.getMinecraftVersion()); - packetListener = new PacketListener(core, currentFile.toPath(), replayFile, metaData); + packetListener = new PacketListener(core, outputPath, replayFile, metaData); Channel channel = ((NetworkManagerAccessor) networkManager).getChannel(); channel.pipeline().addBefore(packetHandlerKey, "replay_recorder", packetListener); diff --git a/src/main/java/com/replaymod/replay/gui/screen/GuiReplayViewer.java b/src/main/java/com/replaymod/replay/gui/screen/GuiReplayViewer.java index e65466f2..014b70ed 100644 --- a/src/main/java/com/replaymod/replay/gui/screen/GuiReplayViewer.java +++ b/src/main/java/com/replaymod/replay/gui/screen/GuiReplayViewer.java @@ -121,7 +121,7 @@ public class GuiReplayViewer extends GuiScreen { @Override public void run() { try { - File folder = mod.getCore().getReplayFolder(); + File folder = mod.getCore().getReplayFolder().toFile(); MCVer.openFile(folder); } catch (IOException e) { @@ -245,7 +245,7 @@ public class GuiReplayViewer extends GuiScreen { this.mod = mod; try { - list.setFolder(mod.getCore().getReplayFolder()); + list.setFolder(mod.getCore().getReplayFolder().toFile()); } catch (IOException e) { throw new CrashException(CrashReport.create(e, "Getting replay folder")); }