mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-11 09:23:42 +01:00
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
|