mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-29 15:49:00 +01:00
411a5eed18
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.
178 lines
9.9 KiB
Diff
178 lines
9.9 KiB
Diff
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
|