Skip to content

Commit 53c7459

Browse files
committed
Add support for detecting PaperMC 26.1 folder migration
1 parent 112505b commit 53c7459

3 files changed

Lines changed: 81 additions & 11 deletions

File tree

src/main/java/org/mvplugins/multiverse/core/utils/compatibility/BukkitCompatibility.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
/**
1616
* Compatibility class used to handle API changes in {@link Bukkit} class.
17+
*
18+
* @since 5.6
1719
*/
1820
@ApiStatus.AvailableSince("5.6")
1921
public final class BukkitCompatibility {
@@ -26,6 +28,23 @@ public final class BukkitCompatibility {
2628
GET_WORLD_NAMESPACED_KEY_METHOD = Option.of(ReflectHelper.getMethod(Bukkit.class, "getWorld", NamespacedKey.class));
2729
}
2830

31+
/**
32+
* Check whether the server is using the new dimension storage system introduced in PaperMC 26.1.
33+
* <br />
34+
* This is based of whether getLevelDirectory method exists in the server class,which is the main API change for
35+
* the new dimension storage system.
36+
*
37+
* @return True if the server is using the new dimension storage system, else false.
38+
*
39+
* @since 5.6
40+
*/
41+
@ApiStatus.AvailableSince("5.6")
42+
public static boolean isUsingNewDimensionStorage() {
43+
return GET_LEVEL_DIRECTORY_METHOD
44+
.flatMap(method -> Option.of(ReflectHelper.invokeMethod(Bukkit.getServer(), method)))
45+
.isDefined();
46+
}
47+
2948
/**
3049
* Gets the folder where all the worlds will be store. Before 26.1, all worlds are stored in the root directory
3150
* of the server, which can be obtained by {@link Server#getWorldContainer()}.
@@ -34,6 +53,8 @@ public final class BukkitCompatibility {
3453
* level directory, which needs to be manually parsed.
3554
*
3655
* @return The location where all the worlds folders should be, depending on server's mc version.
56+
*
57+
* @since 5.6
3758
*/
3859
@ApiStatus.AvailableSince("5.6")
3960
@NotNull
@@ -55,6 +76,8 @@ public static Path getWorldFoldersDirectory() {
5576
*
5677
* @param nameOrKey Either a name or namespaced key string representation.
5778
* @return The world if it exists
79+
*
80+
* @since 5.6
5881
*/
5982
@ApiStatus.AvailableSince("5.6")
6083
@NotNull

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

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,17 @@ private Attempt<ImportWorldOptions, ImportFailureReason> validateImportWorldOpti
317317
String worldName = options.worldName();
318318
if (!worldNameChecker.isValidWorldName(worldName)) {
319319
return worldActionResult(ImportFailureReason.INVALID_WORLDNAME, worldName);
320-
} else if (options.doFolderCheck() && !worldNameChecker.isValidWorldFolder(worldName)) {
321-
return worldActionResult(ImportFailureReason.WORLD_FOLDER_INVALID, worldName);
320+
} else if (options.doFolderCheck()) {
321+
//todo This is a duplicate of folder check in load world
322+
WorldNameChecker.FolderStatus folderStatus = worldNameChecker.checkFolder(options.worldName());
323+
if (!folderStatus.isLoadable()) {
324+
return worldActionResult(ImportFailureReason.WORLD_FOLDER_INVALID, options.worldName());
325+
}
326+
if (folderStatus == WorldNameChecker.FolderStatus.REQUIRES_MIGRATION) {
327+
Logging.info("World '%s' will be automatically migrated by PaperMC to the new dimension " +
328+
"location. If you face any issue with migration, please contact PaperMC support!",
329+
options.worldName());
330+
}
322331
}
323332
return worldActionResult(options);
324333
}
@@ -480,8 +489,16 @@ private Attempt<LoadedMultiverseWorld, LoadFailureReason> doLoadWorld(@NotNull L
480489
return doLoadBukkitWorld(bukkitWorld, mvWorld);
481490
}
482491

483-
if (options.doFolderCheck() && !worldNameChecker.isValidWorldFolder(mvWorld.getName())) {
484-
return worldActionResult(LoadFailureReason.WORLD_FOLDER_INVALID, mvWorld.getName());
492+
if (options.doFolderCheck()) {
493+
WorldNameChecker.FolderStatus folderStatus = worldNameChecker.checkFolder(mvWorld.getName());
494+
if (!folderStatus.isLoadable()) {
495+
return worldActionResult(LoadFailureReason.WORLD_FOLDER_INVALID, mvWorld.getName());
496+
}
497+
if (folderStatus == WorldNameChecker.FolderStatus.REQUIRES_MIGRATION) {
498+
Logging.info("World '%s' will be automatically migrated by PaperMC to the new dimension " +
499+
"location. If you face any issue with migration, please contact PaperMC support!",
500+
mvWorld.getName());
501+
}
485502
}
486503

487504
WorldCreator worldCreator = WorldCreator.name(mvWorld.getName())

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

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
import java.util.Locale;
66
import java.util.Set;
77

8-
import com.dumptruckman.minecraft.util.Logging;
98
import io.vavr.control.Option;
9+
import org.bukkit.Bukkit;
10+
import org.jetbrains.annotations.ApiStatus;
1011
import org.jetbrains.annotations.NotNull;
1112
import org.jetbrains.annotations.Nullable;
1213
import org.jvnet.hk2.annotations.Service;
@@ -95,7 +96,7 @@ public boolean hasWorldFolder(@Nullable String worldName) {
9596
* @return True if check result is valid, else false.
9697
*/
9798
public boolean isValidWorldFolder(@Nullable String worldName) {
98-
return checkFolder(worldName) == FolderStatus.VALID;
99+
return checkFolder(worldName).loadable;
99100
}
100101

101102
/**
@@ -105,7 +106,7 @@ public boolean isValidWorldFolder(@Nullable String worldName) {
105106
* @return True if check result is valid, else false.
106107
*/
107108
public boolean isValidWorldFolder(@Nullable File worldFolder) {
108-
return checkFolder(worldFolder) == FolderStatus.VALID;
109+
return checkFolder(worldFolder).loadable;
109110
}
110111

111112
/**
@@ -120,7 +121,13 @@ public FolderStatus checkFolder(@Nullable String worldName) {
120121
return FolderStatus.DOES_NOT_EXIST;
121122
}
122123
File worldFolder = BukkitCompatibility.getWorldFoldersDirectory().resolve(worldName).toFile();
123-
Logging.finer("Checking valid folder for world '%s' at: '%s'", worldName, worldFolder.getPath());
124+
if (BukkitCompatibility.isUsingNewDimensionStorage()) {
125+
File oldWorldFolder = Bukkit.getWorldContainer().toPath().resolve(worldName).toFile();
126+
if (checkFolder(oldWorldFolder) == FolderStatus.VALID) {
127+
return FolderStatus.REQUIRES_MIGRATION;
128+
}
129+
}
130+
124131
return checkFolder(worldFolder);
125132
}
126133

@@ -230,16 +237,39 @@ public enum FolderStatus {
230237
/**
231238
* Folder is valid.
232239
*/
233-
VALID,
240+
VALID(true),
241+
242+
/**
243+
* This folder will cause PaperMC to migrate to new dimension world folder in 26.1+
244+
*/
245+
REQUIRES_MIGRATION(true),
234246

235247
/**
236248
* Folder exist, but contents in it doesnt look like a world.
237249
*/
238-
NOT_A_WORLD,
250+
NOT_A_WORLD(false),
239251

240252
/**
241253
* Folder does not exist.
242254
*/
243-
DOES_NOT_EXIST
255+
DOES_NOT_EXIST(false),
256+
;
257+
258+
private final boolean loadable;
259+
260+
FolderStatus(boolean loadable) {
261+
this.loadable = loadable;
262+
}
263+
264+
/**
265+
* Whether this folder status is loadable, meaning it has the basic world data and can be loaded as a world.
266+
* Note that this does not guarantee the server will definitely load the world with no errors.
267+
*
268+
* @return True if folder probably is loadable by the server, else false.
269+
*/
270+
@ApiStatus.AvailableSince("5.6")
271+
public boolean isLoadable() {
272+
return loadable;
273+
}
244274
}
245275
}

0 commit comments

Comments
 (0)