From 954087b0c5c157501c4ce129bca7d34f70bd8a89 Mon Sep 17 00:00:00 2001 From: duranaaron Date: Wed, 29 Jul 2026 00:48:02 +0200 Subject: [PATCH] fix: read directory entries in name order so packs are reproducible --- .../minecraft/fs/DirectoryFileTreeReader.java | 12 +++++-- .../fs/DirectoryFileTreeReaderTest.java | 35 +++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/serializer-minecraft/src/main/java/team/unnamed/creative/serialize/minecraft/fs/DirectoryFileTreeReader.java b/serializer-minecraft/src/main/java/team/unnamed/creative/serialize/minecraft/fs/DirectoryFileTreeReader.java index 945b2b4a..f51c6341 100644 --- a/serializer-minecraft/src/main/java/team/unnamed/creative/serialize/minecraft/fs/DirectoryFileTreeReader.java +++ b/serializer-minecraft/src/main/java/team/unnamed/creative/serialize/minecraft/fs/DirectoryFileTreeReader.java @@ -31,6 +31,8 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; import java.util.List; import java.util.NoSuchElementException; @@ -61,11 +63,17 @@ public boolean hasNext() { } File folder = folders.get(folderCursor++); - files = folder.listFiles(); + File[] children = folder.listFiles(); - if (files == null) { + if (children == null) { throw new IllegalStateException("Null children from file " + folder); } + + // listFiles() returns entries in whatever order the file system + // stores them, which is not the same on every machine. sorting by + // name means the same folder is always read in the same order + Arrays.sort(children, Comparator.comparing(File::getName)); + files = children; } while (fileCursor < files.length) { diff --git a/serializer-minecraft/src/test/java/team/unnamed/creative/serialize/minecraft/fs/DirectoryFileTreeReaderTest.java b/serializer-minecraft/src/test/java/team/unnamed/creative/serialize/minecraft/fs/DirectoryFileTreeReaderTest.java index 73358dac..cfd3a005 100644 --- a/serializer-minecraft/src/test/java/team/unnamed/creative/serialize/minecraft/fs/DirectoryFileTreeReaderTest.java +++ b/serializer-minecraft/src/test/java/team/unnamed/creative/serialize/minecraft/fs/DirectoryFileTreeReaderTest.java @@ -23,7 +23,19 @@ */ package team.unnamed.creative.serialize.minecraft.fs; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; class DirectoryFileTreeReaderTest implements FileTreeReaderTest { @@ -32,4 +44,27 @@ public FileTreeReader createReader() { return FileTreeReader.directory(new File("src/test/resources/folder")); } + @Test + @DisplayName("Test that a directory is always read in the same order") + void test_read_order_is_sorted_by_name(final @TempDir Path root) throws IOException { + // written in an order that is not alphabetical, so a reader that follows + // the file system order is unlikely to match the expected list below + Files.write(root.resolve("z.txt"), "z".getBytes()); + Files.write(root.resolve("m.txt"), "m".getBytes()); + Files.write(root.resolve("a.txt"), "a".getBytes()); + + final Path sub = Files.createDirectory(root.resolve("sub")); + Files.write(sub.resolve("y.txt"), "y".getBytes()); + Files.write(sub.resolve("b.txt"), "b".getBytes()); + + final List paths = new ArrayList<>(); + try (FileTreeReader reader = FileTreeReader.directory(root.toFile())) { + while (reader.hasNext()) { + paths.add(reader.next()); + } + } + + assertEquals(Arrays.asList("a.txt", "m.txt", "z.txt", "sub/b.txt", "sub/y.txt"), paths); + } + }