Skip to content

Commit 8ab9993

Browse files
authored
Merge pull request #3394 from Multiverse/feat/case-insensitive
Make world name matching case-insensitive to follow papermc behvaiour
2 parents 2b41c13 + 13b949c commit 8ab9993

File tree

4 files changed

+95
-29
lines changed

4 files changed

+95
-29
lines changed

src/main/java/org/mvplugins/multiverse/core/world/WorldManager.java

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import java.util.Collections;
99
import java.util.HashMap;
1010
import java.util.List;
11+
import java.util.Locale;
1112
import java.util.Map;
1213
import java.util.Objects;
1314
import java.util.concurrent.atomic.AtomicReference;
@@ -344,7 +345,7 @@ private Attempt<LoadedMultiverseWorld, ImportFailureReason> doImportBukkitWorld(
344345

345346
private MultiverseWorld newMultiverseWorld(String worldName, WorldConfig worldConfig) {
346347
MultiverseWorld mvWorld = new MultiverseWorld(worldName, worldConfig, config);
347-
worldsMap.put(mvWorld.getName(), mvWorld);
348+
worldsMap.put(mvWorld.getName().toLowerCase(Locale.ENGLISH), mvWorld);
348349
corePermissions.addWorldPermissions(mvWorld);
349350
return mvWorld;
350351
}
@@ -381,7 +382,7 @@ private LoadedMultiverseWorld newLoadedMultiverseWorld(
381382
locationManipulation,
382383
entityPurger
383384
);
384-
loadedWorldsMap.put(loadedWorld.getName(), loadedWorld);
385+
loadedWorldsMap.put(loadedWorld.getName().toLowerCase(Locale.ENGLISH), loadedWorld);
385386
saveWorldsConfig();
386387
pluginManager.callEvent(new MVWorldLoadedEvent(loadedWorld));
387388
return loadedWorld;
@@ -500,7 +501,7 @@ private Attempt<LoadedMultiverseWorld, LoadFailureReason> newLoadedMultiverseWor
500501
locationManipulation,
501502
entityPurger
502503
);
503-
loadedWorldsMap.put(loadedWorld.getName(), loadedWorld);
504+
loadedWorldsMap.put(loadedWorld.getName().toLowerCase(Locale.ENGLISH), loadedWorld);
504505
saveWorldsConfig();
505506
pluginManager.callEvent(new MVWorldLoadedEvent(loadedWorld));
506507
return Attempt.success(loadedWorld);
@@ -967,7 +968,9 @@ public Option<MultiverseWorld> getWorld(@Nullable World world) {
967968
* @return The world if it exists.
968969
*/
969970
public Option<MultiverseWorld> getWorld(@Nullable String worldName) {
970-
return getLoadedWorld(worldName).fold(() -> getUnloadedWorld(worldName), Option::of);
971+
return getLoadedWorld(worldName)
972+
.map(world -> (MultiverseWorld) world)
973+
.orElse(() -> getUnloadedWorld(worldName));
971974
}
972975

973976
/**
@@ -979,7 +982,8 @@ public Option<MultiverseWorld> getWorld(@Nullable String worldName) {
979982
*/
980983
public Option<MultiverseWorld> getWorldByNameOrAlias(@Nullable String worldNameOrAlias) {
981984
return getLoadedWorldByNameOrAlias(worldNameOrAlias)
982-
.fold(() -> getUnloadedWorldByNameOrAlias(worldNameOrAlias), Option::of);
985+
.map(world -> (MultiverseWorld) world)
986+
.orElse(() -> getUnloadedWorldByNameOrAlias(worldNameOrAlias));
983987
}
984988

985989
/**
@@ -994,7 +998,8 @@ public Option<MultiverseWorld> getWorldByNameOrAlias(@Nullable String worldNameO
994998
public Collection<MultiverseWorld> getWorlds() {
995999
return worldsMap.values().stream()
9961000
.map(world -> getLoadedWorld(world)
997-
.fold(() -> world, loadedWorld -> loadedWorld))
1001+
.map(loadedWorld -> (MultiverseWorld) loadedWorld)
1002+
.getOrElse(world))
9981003
.toList();
9991004
}
10001005

@@ -1005,7 +1010,7 @@ public Collection<MultiverseWorld> getWorlds() {
10051010
* @return True if the world is a world is known to multiverse, but may or may not be loaded.
10061011
*/
10071012
public boolean isWorld(@Nullable String worldName) {
1008-
return worldsMap.containsKey(worldName);
1013+
return worldName != null && worldsMap.containsKey(worldName.toLowerCase(Locale.ENGLISH));
10091014
}
10101015

10111016
/**
@@ -1015,7 +1020,9 @@ public boolean isWorld(@Nullable String worldName) {
10151020
* @return The world if it exists.
10161021
*/
10171022
public Option<MultiverseWorld> getUnloadedWorld(@Nullable String worldName) {
1018-
return isLoadedWorld(worldName) ? Option.none() : Option.of(worldsMap.get(worldName));
1023+
return isLoadedWorld(worldName)
1024+
? Option.none()
1025+
: Option.of(worldName).flatMap(name -> Option.of(worldsMap.get(name.toLowerCase(Locale.ENGLISH))));
10191026
}
10201027

10211028
/**
@@ -1067,7 +1074,7 @@ public boolean isUnloadedWorld(@Nullable String worldName) {
10671074
* @return The multiverse world if it exists.
10681075
*/
10691076
public Option<LoadedMultiverseWorld> getLoadedWorld(@Nullable World world) {
1070-
return world == null ? Option.none() : Option.of(loadedWorldsMap.get(world.getName()));
1077+
return Option.of(world).flatMap(notNullWorld -> getLoadedWorld(notNullWorld.getName()));
10711078
}
10721079

10731080
/**
@@ -1077,7 +1084,7 @@ public Option<LoadedMultiverseWorld> getLoadedWorld(@Nullable World world) {
10771084
* @return The multiverse world if it exists.
10781085
*/
10791086
public Option<LoadedMultiverseWorld> getLoadedWorld(@Nullable MultiverseWorld world) {
1080-
return world == null ? Option.none() : Option.of(loadedWorldsMap.get(world.getName()));
1087+
return Option.of(world).flatMap(notNullWorld -> getLoadedWorld(notNullWorld.getName()));
10811088
}
10821089

10831090
/**
@@ -1087,7 +1094,8 @@ public Option<LoadedMultiverseWorld> getLoadedWorld(@Nullable MultiverseWorld wo
10871094
* @return The multiverse world if it exists.
10881095
*/
10891096
public Option<LoadedMultiverseWorld> getLoadedWorld(@Nullable String worldName) {
1090-
return Option.of(loadedWorldsMap.get(worldName));
1097+
return Option.of(worldName)
1098+
.flatMap(name -> Option.of(loadedWorldsMap.get(name.toLowerCase(Locale.ENGLISH))));
10911099
}
10921100

10931101
/**
@@ -1148,7 +1156,7 @@ public boolean isLoadedWorld(@Nullable MultiverseWorld world) {
11481156
* @return True if the world is a multiverse world that is loaded.
11491157
*/
11501158
public boolean isLoadedWorld(@Nullable String worldName) {
1151-
return loadedWorldsMap.containsKey(worldName);
1159+
return worldName != null && loadedWorldsMap.containsKey(worldName.toLowerCase(Locale.ENGLISH));
11521160
}
11531161

11541162
/**

src/main/java/org/mvplugins/multiverse/core/world/helpers/WorldNameChecker.java

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
import java.io.File;
44
import java.util.Locale;
55
import java.util.Set;
6-
import java.util.regex.Pattern;
76

87
import io.vavr.control.Option;
98
import org.bukkit.Bukkit;
109
import org.jetbrains.annotations.NotNull;
1110
import org.jetbrains.annotations.Nullable;
1211
import org.jvnet.hk2.annotations.Service;
12+
import org.mvplugins.multiverse.core.utils.REPatterns;
1313

1414
/**
1515
* <p>Utility class in helping to check the status of a world name and it's associated world folder.</p>
@@ -20,11 +20,11 @@
2020
@Service
2121
public final class WorldNameChecker {
2222

23-
private static final Pattern WORLD_NAME_PATTERN = Pattern.compile("[a-zA-Z0-9/._-]+");
2423
private static final Set<String> BLACKLIST_NAMES = Set.of(
2524
"cache",
2625
"config",
2726
"crash-reports",
27+
"libraries",
2828
"logs",
2929
"plugins",
3030
"versions");
@@ -47,18 +47,21 @@ public boolean isValidWorldName(@Nullable String worldName) {
4747
*/
4848
@NotNull
4949
public NameStatus checkName(@Nullable String worldName) {
50-
return Option.of(worldName).map(name -> {
51-
if (name.isEmpty()) {
52-
return NameStatus.EMPTY;
53-
}
54-
if (BLACKLIST_NAMES.contains(name)) {
55-
return NameStatus.BLACKLISTED;
56-
}
57-
if (!WORLD_NAME_PATTERN.matcher(name).matches()) {
58-
return NameStatus.INVALID_CHARS;
59-
}
60-
return NameStatus.VALID;
61-
}).getOrElse(NameStatus.EMPTY);
50+
return Option.of(worldName)
51+
.map(name -> name.toLowerCase(Locale.ENGLISH))
52+
.map(name -> {
53+
if (name.isEmpty()) {
54+
return NameStatus.EMPTY;
55+
}
56+
if (BLACKLIST_NAMES.contains(name)) {
57+
return NameStatus.BLACKLISTED;
58+
}
59+
if (!REPatterns.NAMESPACE_KEY.matcher(name).matches()) {
60+
return NameStatus.INVALID_CHARS;
61+
}
62+
return NameStatus.VALID;
63+
})
64+
.getOrElse(NameStatus.EMPTY);
6265
}
6366

6467
/**

src/test/java/org/mvplugins/multiverse/core/world/WorldManagerTest.kt

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,19 @@ class WorldManagerTest : TestWithMockBukkit() {
4343
@Test
4444
fun `Create world with custom options`() {
4545
assertTrue(worldManager.createWorld(
46-
CreateWorldOptions.worldName("world_nether")
46+
CreateWorldOptions.worldName("Section/my-nether_world")
4747
.environment(World.Environment.NETHER)
4848
.generateStructures(false)
4949
.seed(1234L)
5050
.useSpawnAdjust(false)
5151
.worldType(WorldType.FLAT)
5252
).isSuccess)
5353

54-
val getWorld = worldManager.getLoadedWorld("world_nether")
54+
val getWorld = worldManager.getLoadedWorld("Section/my-nether_world")
5555
assertTrue(getWorld.isDefined)
5656
val world = getWorld.get()
5757
assertNotNull(world)
58-
assertEquals("world_nether", world.name)
58+
assertEquals("Section/my-nether_world", world.name)
5959
assertEquals(World.Environment.NETHER, world.environment)
6060
assertFalse(world.canGenerateStructures().get())
6161
assertEquals(1234L, world.seed)
@@ -84,6 +84,18 @@ class WorldManagerTest : TestWithMockBukkit() {
8484
)
8585
}
8686

87+
@Test
88+
fun `Create world failed - world exists and loaded (case insensitive)`() {
89+
assertEquals(
90+
CreateFailureReason.WORLD_EXIST_LOADED,
91+
worldManager.createWorld(CreateWorldOptions.worldName("WoRld2")).failureReason
92+
)
93+
assertEquals(
94+
CreateFailureReason.WORLD_EXIST_LOADED,
95+
worldManager.createWorld(CreateWorldOptions.worldName("WORLD2")).failureReason
96+
)
97+
}
98+
8799
@Test
88100
fun `Create world failed - world exists but unloaded`() {
89101
assertTrue(worldManager.unloadWorld(UnloadWorldOptions.world(world)).isSuccess)
@@ -255,4 +267,46 @@ class WorldManagerTest : TestWithMockBukkit() {
255267
assertEquals(world, worldManager.getWorldByNameOrAlias("testalias").orNull)
256268
assertNull(worldManager.getUnloadedWorldByNameOrAlias("testalias").orNull)
257269
}
270+
271+
@Test
272+
fun `Get world`() {
273+
assertEquals(world, worldManager.getLoadedWorld("world").orNull)
274+
assertNull(worldManager.getUnloadedWorld("world").orNull)
275+
assertEquals(world, worldManager.getWorld("world").orNull)
276+
277+
assertTrue(worldManager.isLoadedWorld("world"))
278+
assertFalse(worldManager.isUnloadedWorld("world"))
279+
assertTrue(worldManager.isWorld("world"))
280+
281+
val unloadedWorld = worldManager.unloadWorld(UnloadWorldOptions.world(world)).get()
282+
283+
assertNull(worldManager.getLoadedWorld("world").orNull)
284+
assertEquals(unloadedWorld, worldManager.getUnloadedWorld("world").orNull)
285+
assertEquals(unloadedWorld, worldManager.getWorld("world").orNull)
286+
287+
assertFalse(worldManager.isLoadedWorld("world"))
288+
assertTrue(worldManager.isUnloadedWorld("world"))
289+
assertTrue(worldManager.isWorld("world"))
290+
}
291+
292+
@Test
293+
fun `Get world is case insensitive`() {
294+
assertEquals(world2, worldManager.getLoadedWorld("WORLD2").orNull)
295+
assertNull(worldManager.getUnloadedWorld("wOrld2").orNull)
296+
assertEquals(world2, worldManager.getWorld("wOrld2").orNull)
297+
298+
assertTrue(worldManager.isLoadedWorld("WoRlD2"))
299+
assertFalse(worldManager.isUnloadedWorld("WoRlD2"))
300+
assertTrue(worldManager.isWorld("wORLD2"))
301+
302+
val unloadedWorld2 = worldManager.unloadWorld(UnloadWorldOptions.world(world2)).get()
303+
304+
assertNull(worldManager.getLoadedWorld("wOrld2").orNull)
305+
assertEquals(unloadedWorld2, worldManager.getUnloadedWorld("wOrld2").orNull)
306+
assertEquals(unloadedWorld2, worldManager.getWorld("wORLD2").orNull)
307+
308+
assertFalse(worldManager.isLoadedWorld("WoRlD2"))
309+
assertTrue(worldManager.isUnloadedWorld("WoRlD2"))
310+
assertTrue(worldManager.isWorld("wORLD2"))
311+
}
258312
}

src/test/java/org/mvplugins/multiverse/core/world/WorldNameCheckerTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class WorldNameCheckerTest : TestWithMockBukkit() {
3838
fun `Blacklisted world name`() {
3939
assertEquals(WorldNameChecker.NameStatus.BLACKLISTED, worldNameChecker.checkName("logs"))
4040
assertEquals(WorldNameChecker.NameStatus.BLACKLISTED, worldNameChecker.checkName("plugins"))
41+
assertEquals(WorldNameChecker.NameStatus.BLACKLISTED, worldNameChecker.checkName("CACHE"))
4142
}
4243

4344
@Test

0 commit comments

Comments
 (0)