diff --git a/src/main/java/com/replaymod/core/SettingsRegistryBackend.java b/src/main/java/com/replaymod/core/SettingsRegistryBackend.java index eb996915..90f50d86 100644 --- a/src/main/java/com/replaymod/core/SettingsRegistryBackend.java +++ b/src/main/java/com/replaymod/core/SettingsRegistryBackend.java @@ -22,6 +22,7 @@ import java.nio.file.WatchService; import java.util.List; import java.util.Map; +import static com.replaymod.core.utils.Utils.ensureDirectoryExists; import static com.replaymod.core.versions.MCVer.getMinecraft; class SettingsRegistryBackend { @@ -179,7 +180,7 @@ class SettingsRegistryBackend { Gson gson = new GsonBuilder().setPrettyPrinting().create(); String config = gson.toJson(root); try { - Files.createDirectories(configFile.getParent()); + ensureDirectoryExists(configFile.getParent()); Files.write(configFile, config.getBytes(StandardCharsets.UTF_8)); } catch (IOException e) { e.printStackTrace(); diff --git a/src/main/java/com/replaymod/core/files/ReplayFoldersService.java b/src/main/java/com/replaymod/core/files/ReplayFoldersService.java index 6587704d..2803b891 100644 --- a/src/main/java/com/replaymod/core/files/ReplayFoldersService.java +++ b/src/main/java/com/replaymod/core/files/ReplayFoldersService.java @@ -10,6 +10,8 @@ import java.net.URLDecoder; import java.nio.file.Files; import java.nio.file.Path; +import static com.replaymod.core.utils.Utils.ensureDirectoryExists; + public class ReplayFoldersService { private final Path mcDir = MinecraftClient.getInstance().runDirectory.toPath(); private final SettingsRegistry settings; @@ -19,14 +21,14 @@ public class ReplayFoldersService { } public Path getReplayFolder() throws IOException { - return Files.createDirectories(mcDir.resolve(settings.get(Setting.RECORDING_PATH))); + return ensureDirectoryExists(mcDir.resolve(settings.get(Setting.RECORDING_PATH))); } /** * Folder into which replay backups are saved before the MarkerProcessor is unleashed. */ public Path getRawReplayFolder() throws IOException { - return Files.createDirectories(getReplayFolder().resolve("raw")); + return ensureDirectoryExists(getReplayFolder().resolve("raw")); } /** @@ -34,7 +36,7 @@ public class ReplayFoldersService { * 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")); + return ensureDirectoryExists(getReplayFolder().resolve("recording")); } /** @@ -42,7 +44,7 @@ public class ReplayFoldersService { * Distinct from the recording folder cause people kept confusing them with recordings. */ public Path getCacheFolder() throws IOException { - Path path = Files.createDirectories(mcDir.resolve(settings.get(Setting.CACHE_PATH))); + Path path = ensureDirectoryExists(mcDir.resolve(settings.get(Setting.CACHE_PATH))); try { Files.setAttribute(path, "dos:hidden", true); } catch (UnsupportedOperationException ignored) { diff --git a/src/main/java/com/replaymod/core/utils/Utils.java b/src/main/java/com/replaymod/core/utils/Utils.java index 50c328c8..b082c276 100644 --- a/src/main/java/com/replaymod/core/utils/Utils.java +++ b/src/main/java/com/replaymod/core/utils/Utils.java @@ -57,6 +57,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.FileAttribute; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; @@ -356,4 +359,14 @@ public class Utils { configure.accept(instance); return instance; } + + /** + * Like {@link Files#createDirectories(Path, FileAttribute[])} but doesn't explode if it's a symlink. + */ + public static Path ensureDirectoryExists(Path path) throws IOException { + // Who in their right mind thought the default behavior of throwing when the target is a link to a directory + // was the preferred behavior?! Everyone has to fall for this at least once to learn it... + // https://bugs.openjdk.java.net/browse/JDK-8130464 + return Files.createDirectories(Files.exists(path) ? path.toRealPath() : path); + } } diff --git a/src/main/java/com/replaymod/editor/gui/MarkerProcessor.java b/src/main/java/com/replaymod/editor/gui/MarkerProcessor.java index 0bce65f3..7231cecf 100644 --- a/src/main/java/com/replaymod/editor/gui/MarkerProcessor.java +++ b/src/main/java/com/replaymod/editor/gui/MarkerProcessor.java @@ -133,7 +133,6 @@ public class MarkerProcessor { for (int i = 1; Files.exists(inputPath); i++) { inputPath = inputPath.resolveSibling(replayName + "." + i + ".mcpr"); } - Files.createDirectories(inputPath.getParent()); Files.move(path, inputPath); try (ReplayFile inputReplayFile = mod.files.open(inputPath)) { diff --git a/src/main/java/com/replaymod/recording/packet/PacketListener.java b/src/main/java/com/replaymod/recording/packet/PacketListener.java index e37fefad..f99833a5 100644 --- a/src/main/java/com/replaymod/recording/packet/PacketListener.java +++ b/src/main/java/com/replaymod/recording/packet/PacketListener.java @@ -285,7 +285,6 @@ public class PacketListener extends ChannelInboundHandlerAdapter { for (int i = 1; Files.exists(rawPath); i++) { rawPath = rawPath.resolveSibling(replayName + "." + i + ".mcpr"); } - Files.createDirectories(rawPath.getParent()); replayFile.saveTo(rawPath.toFile()); replayFile.close();