mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-30 16:19:03 +01:00
aa0de8d4b5
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.8 KiB
Diff
178 lines
9.8 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
|
--- a/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
|
+++ b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
|
|
@@ -0,0 +0,0 @@ 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
|
|
@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
|
--- a/src/main/java/net/minecraft/world/level/storage/LevelStorageSource.java
|
|
+++ b/src/main/java/net/minecraft/world/level/storage/LevelStorageSource.java
|
|
@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
|
--- a/src/main/java/net/minecraft/world/level/storage/McRegionUpgrader.java
|
|
+++ b/src/main/java/net/minecraft/world/level/storage/McRegionUpgrader.java
|
|
@@ -0,0 +0,0 @@ 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()) {
|
|
@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
|
--- a/src/main/java/net/minecraft/world/level/storage/PrimaryLevelData.java
|
|
+++ b/src/main/java/net/minecraft/world/level/storage/PrimaryLevelData.java
|
|
@@ -0,0 +0,0 @@ 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
|