From c8844fa5e672a7a5901ae620a4644adb79e27aca Mon Sep 17 00:00:00 2001 From: HyperGaming99 <130169800+HyperGaming99@users.noreply.github.com> Date: Tue, 18 Aug 2026 05:49:13 +0200 Subject: [PATCH] Support wildcards in world name lists (#807) World lists in the config now accept '*' as a wildcard, so 'hub*' or '*hub*' can be used instead of listing every world by name. Entries without '*' keep matching exactly. --- .../org/dreeam/leaf/config/WorldList.java | 72 +++++++++++++++++++ .../modules/misc/DisableWorldDataSaving.java | 14 ++-- 2 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 leaf-server/src/main/java/org/dreeam/leaf/config/WorldList.java diff --git a/leaf-server/src/main/java/org/dreeam/leaf/config/WorldList.java b/leaf-server/src/main/java/org/dreeam/leaf/config/WorldList.java new file mode 100644 index 0000000000..600ab2e0dc --- /dev/null +++ b/leaf-server/src/main/java/org/dreeam/leaf/config/WorldList.java @@ -0,0 +1,72 @@ +package org.dreeam.leaf.config; + +import org.jspecify.annotations.NullMarked; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; + +/// A world name list read from the config, matching either exact names or `*` wildcard patterns. +/// +/// `*` matches any (possibly empty) sequence of characters, so `hub*` matches `hub01` and `hub02`, +/// and `*hub*` matches every world whose name contains `hub`. Entries without `*` are matched +/// exactly, as before. Matching is case sensitive, like world folder names. +@NullMarked +public final class WorldList { + + private static final Pattern[] NO_PATTERNS = {}; + + public static final WorldList EMPTY = new WorldList(List.of()); + + private final Set names = new HashSet<>(); + private final Pattern[] patterns; + + public WorldList(List entries) { + List patterns = new ArrayList<>(); + for (String entry : entries) { + if (entry == null || entry.isBlank()) { + continue; + } + String trimmed = entry.trim(); + if (trimmed.indexOf('*') == -1) { + this.names.add(trimmed); + } else { + patterns.add(compile(trimmed)); + } + } + this.patterns = patterns.toArray(NO_PATTERNS); + } + + public boolean isEmpty() { + return this.names.isEmpty() && this.patterns.length == 0; + } + + public boolean contains(String worldName) { + if (this.names.contains(worldName)) { + return true; + } + for (Pattern pattern : this.patterns) { + if (pattern.matcher(worldName).matches()) { + return true; + } + } + return false; + } + + private static Pattern compile(String glob) { + String[] literals = glob.split("\\*", -1); + StringBuilder regex = new StringBuilder(glob.length() + 8); + for (int i = 0; i < literals.length; i++) { + if (i != 0) { + regex.append(".*"); + } + if (!literals[i].isEmpty()) { + regex.append(Pattern.quote(literals[i])); + } + } + // DOTALL so '*' also covers line terminators, world names are not required to be single line + return Pattern.compile(regex.toString(), Pattern.DOTALL); + } +} diff --git a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/misc/DisableWorldDataSaving.java b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/misc/DisableWorldDataSaving.java index 36b790b7d1..a2ee530086 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/misc/DisableWorldDataSaving.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/misc/DisableWorldDataSaving.java @@ -3,13 +3,13 @@ import net.minecraft.server.level.ServerLevel; import org.dreeam.leaf.config.ConfigModule; import org.dreeam.leaf.config.ConfigCategory; +import org.dreeam.leaf.config.WorldList; import java.util.ArrayList; -import java.util.List; public class DisableWorldDataSaving extends ConfigModule { - public static List worlds = new ArrayList<>(); + public static WorldList worlds = WorldList.EMPTY; public String basePath() { return ConfigCategory.MISC.basePath() + ".disable-world-data-saving"; @@ -17,13 +17,17 @@ public String basePath() { @Override public void onLoaded() { - worlds = globalConfig.getList(basePath() + ".worlds", worlds, + worlds = new WorldList(globalConfig.getList(basePath() + ".worlds", new ArrayList<>(), globalConfig.pickStringRegionBased(""" Worlds listed here will skip world data persistence. - Changes in chunks/entities remain in memory until unload/restart and are not written to disk.""", + Changes in chunks/entities remain in memory until unload/restart and are not written to disk. + '*' works as a wildcard, e.g. 'hub*' matches hub01 and hub02, '*hub*' matches every world + whose name contains 'hub'. Entries without '*' are matched exactly.""", """ 此处列出的世界将跳过世界数据持久化。 - 区块/实体更改仅保留在内存中直到卸载或重启,不会写入磁盘。""")); + 区块/实体更改仅保留在内存中直到卸载或重启,不会写入磁盘。 + '*' 可作为通配符使用, 例如 'hub*' 匹配 hub01 和 hub02, '*hub*' 匹配名称中包含 'hub' 的所有世界。 + 不含 '*' 的条目按完整名称精确匹配。"""))); } public static boolean shouldSkipSave(ServerLevel serverLevel) {