mirror of
https://github.com/PaperMC/Paper.git
synced 2024-11-22 10:35:38 +01:00
Fix and optimize legacy world conversion (#6473)
CraftBukkit breaks legacy world conversion in three ways: - Writes userdata to the path of the userdata folder rather than to the correct file inside the aforementioned folder. This causes the userdata folder to fail to be created as a file already exists at its path. - Makes changes to how multiworld works, without modifying McRegionUpgrader to be aware of these changes. - Calls methods on Bukkit before the server is initialized. This patch fixes all of these issues, and also threads the McRegionUpgrader to improve performance.
This commit is contained in:
parent
1c4f87a258
commit
411a5eed18
@ -0,0 +1,178 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
|
||||
Date: Sun, 22 Aug 2021 23:03:33 -0700
|
||||
Subject: [PATCH] Fix and optimize legacy world conversion
|
||||
|
||||
CraftBukkit breaks legacy world conversion in three ways:
|
||||
- Writes userdata to the path of the userdata folder rather than to
|
||||
the correct file inside the aforementioned folder. This causes the
|
||||
userdata folder to fail to be created as a file already exists at
|
||||
its path.
|
||||
- Makes changes to how multiworld works, without modifying
|
||||
McRegionUpgrader to be aware of these changes.
|
||||
- Calls methods on Bukkit before the server is initialized.
|
||||
|
||||
This patch fixes all of these issues, and also threads the
|
||||
McRegionUpgrader to improve performance.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/players/OldUsersConverter.java b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
||||
index 8703f97dc2f392b136c6851aa09b607cbfdfa5de..ade010fe3b62a4624b009c6d665e9909b2d314ac 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
||||
@@ -355,14 +355,14 @@ public class OldUsersConverter {
|
||||
}
|
||||
|
||||
private void movePlayerFile(File playerDataFolder, String fileName, String uuid) {
|
||||
- File file5 = new File(file, fileName + ".dat");
|
||||
+ File file5 = new File(file, fileName + ".dat"); // Paper - diff on change
|
||||
File file6 = new File(playerDataFolder, uuid + ".dat");
|
||||
|
||||
// CraftBukkit start - Use old file name to seed lastKnownName
|
||||
CompoundTag root = null;
|
||||
|
||||
try {
|
||||
- root = NbtIo.readCompressed(new java.io.FileInputStream(file5));
|
||||
+ root = NbtIo.readCompressed(new java.io.FileInputStream(file5)); // Paper - diff on change
|
||||
} catch (Exception exception) {
|
||||
exception.printStackTrace();
|
||||
ServerInternalException.reportInternalException(exception); // Paper
|
||||
@@ -376,7 +376,7 @@ public class OldUsersConverter {
|
||||
data.putString("lastKnownName", fileName);
|
||||
|
||||
try {
|
||||
- NbtIo.writeCompressed(root, new java.io.FileOutputStream(file2));
|
||||
+ NbtIo.writeCompressed(root, new java.io.FileOutputStream(file5)); // Paper - write to correct path (diff on change)
|
||||
} catch (Exception exception) {
|
||||
exception.printStackTrace();
|
||||
ServerInternalException.reportInternalException(exception); // Paper
|
||||
diff --git a/src/main/java/net/minecraft/world/level/storage/LevelStorageSource.java b/src/main/java/net/minecraft/world/level/storage/LevelStorageSource.java
|
||||
index af8a555c777b5abbaa2615d2ff03f03a9a93847e..b794c02ea36bdc901b1f6a160095abb3fcfe9b60 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/storage/LevelStorageSource.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/storage/LevelStorageSource.java
|
||||
@@ -348,6 +348,12 @@ public class LevelStorageSource {
|
||||
});
|
||||
}
|
||||
|
||||
+ // Paper start - copied from vanilla before below CB diff
|
||||
+ public File getDimensionPathForLegacyConversion(ResourceKey<Level> key) {
|
||||
+ return DimensionType.getStorageFolder(key, this.levelPath.toFile());
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public File getDimensionPath(ResourceKey<Level> key) {
|
||||
return LevelStorageSource.getFolder(this.levelPath.toFile(), this.dimensionType); // CraftBukkit
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/storage/McRegionUpgrader.java b/src/main/java/net/minecraft/world/level/storage/McRegionUpgrader.java
|
||||
index 87705fc8ee32016bf5ca533eb278bf32df08d3a3..b9bcbcf509ebb59d15082ce0faef8e405c16bdcc 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/storage/McRegionUpgrader.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/storage/McRegionUpgrader.java
|
||||
@@ -35,13 +35,29 @@ public class McRegionUpgrader {
|
||||
private static final String MCREGION_EXTENSION = ".mcr";
|
||||
|
||||
static boolean convertLevel(LevelStorageSource.LevelStorageAccess storageSession, ProgressListener progressListener) {
|
||||
+ // Paper start
|
||||
+ progressListener = new ProgressListener() {
|
||||
+ @Override
|
||||
+ public void progressStartNoAbort(net.minecraft.network.chat.Component title) {}
|
||||
+ @Override
|
||||
+ public void progressStart(net.minecraft.network.chat.Component title) {}
|
||||
+ @Override
|
||||
+ public void progressStage(net.minecraft.network.chat.Component task) {}
|
||||
+ @Override
|
||||
+ public void progressStagePercentage(int percentage) {}
|
||||
+ @Override
|
||||
+ public void stop() {}
|
||||
+ };
|
||||
+ // Paper end
|
||||
progressListener.progressStagePercentage(0);
|
||||
List<File> list = Lists.newArrayList();
|
||||
List<File> list2 = Lists.newArrayList();
|
||||
List<File> list3 = Lists.newArrayList();
|
||||
- File file = storageSession.getDimensionPath(Level.OVERWORLD);
|
||||
- File file2 = storageSession.getDimensionPath(Level.NETHER);
|
||||
- File file3 = storageSession.getDimensionPath(Level.END);
|
||||
+ // Paper start
|
||||
+ File file = storageSession.getDimensionPathForLegacyConversion(Level.OVERWORLD);
|
||||
+ File file2 = storageSession.getDimensionPathForLegacyConversion(Level.NETHER);
|
||||
+ File file3 = storageSession.getDimensionPathForLegacyConversion(Level.END);
|
||||
+ // Paper end
|
||||
LOGGER.info("Scanning folders...");
|
||||
addRegionFiles(file, list);
|
||||
if (file2.exists()) {
|
||||
@@ -88,14 +104,58 @@ public class McRegionUpgrader {
|
||||
}
|
||||
|
||||
private static void convertRegions(RegistryAccess.RegistryHolder registryManager, File directory, Iterable<File> files, BiomeSource biomeSource, int i, int j, ProgressListener progressListener) {
|
||||
- for(File file : files) {
|
||||
- convertRegion(registryManager, directory, file, biomeSource, i, j, progressListener);
|
||||
- ++i;
|
||||
- int k = (int)Math.round(100.0D * (double)i / (double)j);
|
||||
- progressListener.progressStagePercentage(k);
|
||||
+ // Paper start - thread this because it's dead simple
|
||||
+ convertRegionsThreaded(registryManager, directory, files, biomeSource, i, j, progressListener);
|
||||
+ }
|
||||
+
|
||||
+ private static void convertRegionsThreaded(RegistryAccess.RegistryHolder registryManager, File directory, Iterable<File> files, BiomeSource biomeSource, int progress, int total, ProgressListener progressListener) {
|
||||
+ if (!files.iterator().hasNext()) {
|
||||
+ return;
|
||||
}
|
||||
|
||||
+ final int threads = Runtime.getRuntime().availableProcessors() / 2;
|
||||
+ final java.util.concurrent.ExecutorService threadPool = java.util.concurrent.Executors.newFixedThreadPool(Math.max(1, threads), new java.util.concurrent.ThreadFactory() {
|
||||
+ private final java.util.concurrent.atomic.AtomicInteger threadCounter = new java.util.concurrent.atomic.AtomicInteger();
|
||||
+
|
||||
+ @Override
|
||||
+ public Thread newThread(final Runnable run) {
|
||||
+ final Thread ret = new Thread(run);
|
||||
+
|
||||
+ ret.setName("World upgrader thread for directory " + directory + " #" + this.threadCounter.getAndIncrement());
|
||||
+ ret.setUncaughtExceptionHandler((thread, throwable) -> {
|
||||
+ LOGGER.fatal("Error upgrading world", throwable);
|
||||
+ });
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+ });
|
||||
+ final java.util.concurrent.atomic.AtomicInteger converted = new java.util.concurrent.atomic.AtomicInteger(progress);
|
||||
+
|
||||
+ final long start = System.nanoTime();
|
||||
+
|
||||
+ for (final File file : files) {
|
||||
+ threadPool.execute(() -> {
|
||||
+ convertRegion(registryManager, directory, file, biomeSource, 0, total, progressListener);
|
||||
+ converted.incrementAndGet();
|
||||
+ });
|
||||
+ }
|
||||
+ threadPool.shutdown();
|
||||
+
|
||||
+ final java.text.DecimalFormat format = new java.text.DecimalFormat("#0.00");
|
||||
+ while (!threadPool.isTerminated()) {
|
||||
+ final int getConverted = converted.get();
|
||||
+ LOGGER.info("Converting... {}/{} ({}%)", getConverted, total, format.format(100.0D * (double) getConverted / (double) total));
|
||||
+ try {
|
||||
+ Thread.sleep(1000L);
|
||||
+ } catch (final InterruptedException ignored) {}
|
||||
+ }
|
||||
+
|
||||
+ final long end = System.nanoTime();
|
||||
+
|
||||
+ final double durationSeconds = Math.ceil((end - start) * 1.0e-9);
|
||||
+ LOGGER.info("Conversion for {} completed in {}s", directory, durationSeconds);
|
||||
}
|
||||
+ // Paper end
|
||||
|
||||
private static void convertRegion(RegistryAccess.RegistryHolder registryManager, File directory, File file, BiomeSource biomeSource, int i, int j, ProgressListener progressListener) {
|
||||
String string = file.getName();
|
||||
diff --git a/src/main/java/net/minecraft/world/level/storage/PrimaryLevelData.java b/src/main/java/net/minecraft/world/level/storage/PrimaryLevelData.java
|
||||
index 4d0af984490b556a9911c3b8fdca1e168e6fe932..c20e5d69b4ad8adcdaffb56e4e2a24596ae16edf 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/storage/PrimaryLevelData.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/storage/PrimaryLevelData.java
|
||||
@@ -212,7 +212,7 @@ public class PrimaryLevelData implements ServerLevelData, WorldData {
|
||||
levelTag.putUUID("WanderingTraderId", this.wanderingTraderId);
|
||||
}
|
||||
|
||||
- levelTag.putString("Bukkit.Version", Bukkit.getName() + "/" + Bukkit.getVersion() + "/" + Bukkit.getBukkitVersion()); // CraftBukkit
|
||||
+ if (Bukkit.getServer() != null) levelTag.putString("Bukkit.Version", Bukkit.getName() + "/" + Bukkit.getVersion() + "/" + Bukkit.getBukkitVersion()); // CraftBukkit // Paper - server may not be started yet
|
||||
}
|
||||
|
||||
@Override
|
Loading…
Reference in New Issue
Block a user