diff --git a/paper-server/patches/sources/net/minecraft/util/filefix/FileFixerUpper.java.patch b/paper-server/patches/sources/net/minecraft/util/filefix/FileFixerUpper.java.patch index 934e40c3fc7d..a8f926e45d06 100644 --- a/paper-server/patches/sources/net/minecraft/util/filefix/FileFixerUpper.java.patch +++ b/paper-server/patches/sources/net/minecraft/util/filefix/FileFixerUpper.java.patch @@ -1,5 +1,14 @@ --- a/net/minecraft/util/filefix/FileFixerUpper.java +++ b/net/minecraft/util/filefix/FileFixerUpper.java +@@ -48,7 +_,7 @@ + import org.slf4j.Logger; + + public class FileFixerUpper { +- private static final int FILE_FIXER_INTRODUCTION_VERSION = 4772; ++ public static final int FILE_FIXER_INTRODUCTION_VERSION = 4772; // Paper - public for world migration checks + private static final Gson GSON = new Gson().newBuilder().setPrettyPrinting().create(); + private static final String FILE_FIX_DIRECTORY_NAME = "filefix"; + private static final String NEW_WORLD_TEMP_NAME = "new_world"; @@ -82,6 +_,7 @@ ) throws FileFixException { int loadedVersion = NbtUtils.getDataVersion(levelDataTag); diff --git a/paper-server/src/main/java/io/papermc/paper/world/PaperWorldLoader.java b/paper-server/src/main/java/io/papermc/paper/world/PaperWorldLoader.java index cd3e7cc8cf08..a9590c6df0e3 100644 --- a/paper-server/src/main/java/io/papermc/paper/world/PaperWorldLoader.java +++ b/paper-server/src/main/java/io/papermc/paper/world/PaperWorldLoader.java @@ -5,8 +5,10 @@ import io.papermc.paper.world.saveddata.PaperWorldMetadata; import io.papermc.paper.world.saveddata.PaperWorldPDC; import java.io.IOException; +import java.nio.file.Files; import java.util.Locale; import java.util.UUID; +import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.resources.Identifier; import net.minecraft.resources.ResourceKey; @@ -128,15 +130,15 @@ public static LoadedWorldData loadWorldData( } public void loadInitialWorlds() { - final var levelStemRegistry = this.server.registryAccess().lookupOrThrow(Registries.LEVEL_STEM); - final boolean hasWorldData = this.server.storageSource.hasWorldData(); + final Registry levelStemRegistry = this.server.registryAccess().lookupOrThrow(Registries.LEVEL_STEM); final LevelStem overworldStem = requireNonNull(levelStemRegistry.getValue(LevelStem.OVERWORLD), "Overworld stem missing"); + final boolean hasWorldData = this.hasDimensionData(overworldStem); this.loadInitialWorld(overworldStem, hasWorldData); for (final LevelStem stem : levelStemRegistry) { if (stem == overworldStem) { continue; } - this.loadInitialWorld(stem, hasWorldData); + this.loadInitialWorld(stem, this.hasDimensionData(stem)); } // ((DedicatedServer) this.server).forceDifficulty(); @@ -174,6 +176,12 @@ private void loadInitialWorld(final LevelStem stem, final boolean hasWorldData) this.server.createLevel(stem, loading, worldDataAndGenSettings); } + private boolean hasDimensionData(final LevelStem stem) { + final ResourceKey stemKey = this.server.registryAccess().lookupOrThrow(Registries.LEVEL_STEM).getResourceKey(stem).orElseThrow(); + final ResourceKey dimensionKey = dimensionKey(stemKey); + return Files.isDirectory(this.server.storageSource.getDimensionPath(dimensionKey)); + } + public static WorldGenSettings loadWorldGenSettings( final LevelStorageSource.LevelStorageAccess access, final net.minecraft.core.HolderLookup.Provider registryAccess, final ResourceKey dimension ) { diff --git a/paper-server/src/main/java/io/papermc/paper/world/migration/WorldFolderMigration.java b/paper-server/src/main/java/io/papermc/paper/world/migration/WorldFolderMigration.java index 77fb09a15bce..4539381d4cc6 100644 --- a/paper-server/src/main/java/io/papermc/paper/world/migration/WorldFolderMigration.java +++ b/paper-server/src/main/java/io/papermc/paper/world/migration/WorldFolderMigration.java @@ -7,7 +7,12 @@ import java.nio.file.Files; import java.nio.file.Path; import net.minecraft.core.HolderLookup; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtAccounter; +import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.NbtUtils; import net.minecraft.resources.ResourceKey; +import net.minecraft.util.filefix.FileFixerUpper; import net.minecraft.world.level.Level; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.WorldGenSettings; @@ -91,7 +96,24 @@ private static MigrationMode classifyStartupMigration(final WorldMigrationContex if (!context.rootAccess().getLevelId().equals(context.worldName()) && Files.isDirectory(context.rootAccess().parent().getLevelPath(context.worldName()))) { return MigrationMode.LEGACY_CRAFTBUKKIT_MIGRATION; } - return hasCurrentPaperData(context.rootAccess(), context.dimensionKey()) ? MigrationMode.NO_OP : MigrationMode.VANILLA_MIGRATION; + if (hasCurrentPaperData(context.rootAccess(), context.dimensionKey())) { + return MigrationMode.NO_OP; + } + // the dimension was deleted + if (!Files.isDirectory(context.rootAccess().getDimensionPath(context.dimensionKey()))) { + try { + final CompoundTag rawLevelData = NbtIo.readCompressed( + context.rootAccess().levelDirectory.dataFile(), NbtAccounter.uncompressedQuota() + ); + final int dataVersion = NbtUtils.getDataVersion(rawLevelData.getCompoundOrEmpty("Data")); + if (dataVersion >= FileFixerUpper.FILE_FIXER_INTRODUCTION_VERSION) { + return MigrationMode.NO_OP; + } + } catch (final IOException ex) { + throw new RuntimeException("Failed to read level data for world migration classification", ex); + } + } + return MigrationMode.VANILLA_MIGRATION; } static boolean hasCurrentPaperData(final LevelStorageSource.LevelStorageAccess rootAccess, final ResourceKey dimensionKey) {