From 37ba5ecc048805eb9e6ba0fdd583cc13f6b90d00 Mon Sep 17 00:00:00 2001 From: Ben Woo <30431861+benwoo1110@users.noreply.github.com> Date: Mon, 20 Jul 2026 19:59:07 +0800 Subject: [PATCH] Add support for searching potential world in nested sub-folders --- .../world/helpers/PotentialWorldFinder.java | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/mvplugins/multiverse/core/world/helpers/PotentialWorldFinder.java b/src/main/java/org/mvplugins/multiverse/core/world/helpers/PotentialWorldFinder.java index bb393513f..265f0822e 100644 --- a/src/main/java/org/mvplugins/multiverse/core/world/helpers/PotentialWorldFinder.java +++ b/src/main/java/org/mvplugins/multiverse/core/world/helpers/PotentialWorldFinder.java @@ -27,6 +27,9 @@ @Service public final class PotentialWorldFinder { + private static final int MAX_RECURSION_DEPTH = 3; + private static final int MAX_FOLDER_TRAVERSAL_LIMIT = 100; + private final WorldManager worldManager; private final WorldNameChecker worldNameChecker; @@ -56,6 +59,7 @@ public List findPotentialWorlds() { private Stream findFromRootFolder() { Path worldContainer = Bukkit.getWorldContainer().toPath(); return Arrays.stream(listFolders(worldContainer)) + .limit(MAX_FOLDER_TRAVERSAL_LIMIT) .filter(worldNameChecker::isValidWorldFolder) .map(File::getName) .filter(worldNameChecker::isValidWorldName) @@ -65,15 +69,29 @@ private Stream findFromRootFolder() { private Stream findFromDimensionsFolder() { Path worldContainer = BukkitCompatibility.getWorldFoldersDirectory(); return Arrays.stream(listFolders(worldContainer)) - .map(File::getName) - .flatMap(namespace -> Arrays.stream(listFolders(worldContainer.resolve(namespace))) - .filter(worldNameChecker::isValidWorldFolder) - .map(File::getName) - .map(key -> namespace + ":" + key)) + .limit(MAX_FOLDER_TRAVERSAL_LIMIT) + .flatMap(namespaceFile -> recursiveFindFromNamespaceFolder("", namespaceFile.toPath(), 0) + .map(worldKey -> namespaceFile.getName() + ":" + worldKey)) .filter(namespacedKey -> NamespacedKey.fromString(namespacedKey) != null) .filter(namespacedKey -> !worldManager.isWorld(namespacedKey)); } + private Stream recursiveFindFromNamespaceFolder(String prefix, Path subWorldContainer, int depth) { + if (depth >= MAX_RECURSION_DEPTH) { + return Stream.empty(); + } + return Arrays.stream(listFolders(subWorldContainer)) + .limit(MAX_FOLDER_TRAVERSAL_LIMIT) + .flatMap(folder -> worldNameChecker.isValidWorldFolder(folder) + ? Stream.of(concatPath(prefix, folder.getName())) + : recursiveFindFromNamespaceFolder( + concatPath(prefix, folder.getName()), folder.toPath(), depth + 1)); + } + + private String concatPath(String prefix, String folderName) { + return prefix.isEmpty() ? folderName : prefix + "/" + folderName; + } + private @NotNull File[] listFolders(Path folder) { return Option.of(folder.toFile().listFiles(File::isDirectory)) .getOrElse(() -> new File[0]);