aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorSpottedleaf <[email protected]>2024-05-21 08:21:28 -0700
committerSpottedleaf <[email protected]>2024-05-21 08:21:28 -0700
commit66cb880754c72ea79f9abde4128fefa6d89a13ca (patch)
tree20a258c5f17db46b7c5693d19a923ed4af449b3c
parent9bf48555241dc03246c67258fe66eaf6c7a4a044 (diff)
downloadPaper-66cb880754c72ea79f9abde4128fefa6d89a13ca.tar.gz
Paper-66cb880754c72ea79f9abde4128fefa6d89a13ca.zip
Remove ThreadedWorldUpgrader patch
The patch does not implement Vanilla forceUpgrade behavior. Specifically, poi/entity conversion and regionfile recreation. The Vanilla force upgrader is also no longer broken by CB, so the bug fixes from this patch are not relevant anymore.
-rw-r--r--patches/server/1025-API-for-checking-sent-chunks.patch (renamed from patches/server/1026-API-for-checking-sent-chunks.patch)2
-rw-r--r--patches/server/1025-Fix-and-optimise-world-force-upgrading.patch395
-rw-r--r--patches/server/1026-Add-config-for-mobs-immune-to-default-effects.patch (renamed from patches/server/1027-Add-config-for-mobs-immune-to-default-effects.patch)0
-rw-r--r--patches/server/1027-Deep-clone-nbt-tags-in-PDC.patch (renamed from patches/server/1028-Deep-clone-nbt-tags-in-PDC.patch)0
-rw-r--r--patches/server/1028-Support-old-UUID-format-for-NBT.patch (renamed from patches/server/1029-Support-old-UUID-format-for-NBT.patch)0
-rw-r--r--patches/server/1029-Fix-shield-disable-inconsistency.patch (renamed from patches/server/1030-Fix-shield-disable-inconsistency.patch)2
-rw-r--r--patches/server/1030-Write-SavedData-IO-async.patch (renamed from patches/server/1031-Write-SavedData-IO-async.patch)22
-rw-r--r--patches/server/1031-Don-t-lose-removed-data-components-in-ItemMeta.patch (renamed from patches/server/1032-Don-t-lose-removed-data-components-in-ItemMeta.patch)0
-rw-r--r--patches/server/1032-Add-experimental-improved-give-command.patch (renamed from patches/server/1033-Add-experimental-improved-give-command.patch)0
-rw-r--r--patches/server/1033-Handle-Large-Packets-disconnecting-client.patch (renamed from patches/server/1034-Handle-Large-Packets-disconnecting-client.patch)0
-rw-r--r--patches/server/1034-Fix-ItemFlags.patch (renamed from patches/server/1035-Fix-ItemFlags.patch)0
-rw-r--r--patches/server/1035-Fix-helmet-damage-reduction-inconsistencies.patch (renamed from patches/server/1036-Fix-helmet-damage-reduction-inconsistencies.patch)0
-rw-r--r--patches/server/1036-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch (renamed from patches/server/1037-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch)2
-rw-r--r--patches/server/1037-improve-checking-handled-tags-in-itemmeta.patch (renamed from patches/server/1038-improve-checking-handled-tags-in-itemmeta.patch)0
-rw-r--r--patches/server/1038-General-ItemMeta-fixes.patch (renamed from patches/server/1039-General-ItemMeta-fixes.patch)0
-rw-r--r--patches/server/1039-Expose-hasColor-to-leather-armor.patch (renamed from patches/server/1040-Expose-hasColor-to-leather-armor.patch)0
-rw-r--r--patches/server/1040-Added-API-to-get-player-ha-proxy-address.patch (renamed from patches/server/1041-Added-API-to-get-player-ha-proxy-address.patch)2
-rw-r--r--patches/server/1041-More-Chest-Block-API.patch (renamed from patches/server/1042-More-Chest-Block-API.patch)0
-rw-r--r--patches/server/1042-Print-data-component-type-on-encoding-error.patch (renamed from patches/server/1043-Print-data-component-type-on-encoding-error.patch)0
-rw-r--r--patches/server/1043-Fix-entity-tracker-desync-when-new-players-are-added.patch (renamed from patches/server/1044-Fix-entity-tracker-desync-when-new-players-are-added.patch)0
-rw-r--r--patches/server/1044-Brigadier-based-command-API.patch (renamed from patches/server/1045-Brigadier-based-command-API.patch)10
-rw-r--r--patches/server/1045-Fix-issues-with-Recipe-API.patch (renamed from patches/server/1046-Fix-issues-with-Recipe-API.patch)0
22 files changed, 10 insertions, 425 deletions
diff --git a/patches/server/1026-API-for-checking-sent-chunks.patch b/patches/server/1025-API-for-checking-sent-chunks.patch
index a08ada1670..01ec0b2993 100644
--- a/patches/server/1026-API-for-checking-sent-chunks.patch
+++ b/patches/server/1025-API-for-checking-sent-chunks.patch
@@ -21,7 +21,7 @@ index ee58c67cb2bd78159cce19ec75f13dc6168a0e7a..149cfb0587299f72fcfddf395fb71b70
// TODO rebase into util patch
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
-index 6f8999df04e6ad4d4d52e87b05a187f586d60c74..a9aa3dca65aca86cf535d6616f5d5db3e1e8fc8b 100644
+index 2d373be107a610522db9b3ce8ae446b848d92580..84ed5dc8c82e28aa93fa0440d90ddb44dc5f3d40 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -3446,6 +3446,35 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
diff --git a/patches/server/1025-Fix-and-optimise-world-force-upgrading.patch b/patches/server/1025-Fix-and-optimise-world-force-upgrading.patch
deleted file mode 100644
index ce0b75bfbb..0000000000
--- a/patches/server/1025-Fix-and-optimise-world-force-upgrading.patch
+++ /dev/null
@@ -1,395 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Spottedleaf <[email protected]>
-Date: Thu, 20 May 2021 07:02:22 -0700
-Subject: [PATCH] Fix and optimise world force upgrading
-
-The WorldUpgrader class was incorrectly modified by
-CB. It will store an IChunkLoader instance for all
-dimension types in the world, but obviously with how
-CB shifts around worlds only one dimension type exists
-per world. But this would be OK if CB did this
-change correctly. All IChunkLoader instances
-will point to the same regionfiles. And all
-IChunkLoader instances are going to be read from.
-
-This problem hasn't really been reported because
-it relies on the persistent legacy data to be converted
-as well to cause corruption. Why? Because the legacy
-data is also shared, it will result in different
-outputs from conversion (as once conversion for legacy
-persistent data takes place, it is REMOVED - so the next
-convert will _not_ have the data). Which means different
-sizes on disk. Which means different regionfile sector
-allocations. Which means there are 3 different possible
-regionfile sector allocations in memory, and none of them
-are going to be correct.
-
-I've fixed this by writing a world upgrader suited to
-CB's changes to world folder format. It was brain dead
-easy to add threading, so I did.
-
-== AT ==
-public net.minecraft.util.worldupdate.WorldUpgrader REGEX
-
-diff --git a/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java b/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java
-new file mode 100644
-index 0000000000000000000000000000000000000000..e049fbe4038aaea896f45b11ce9ce8f05922c898
---- /dev/null
-+++ b/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java
-@@ -0,0 +1,222 @@
-+package io.papermc.paper.world;
-+
-+import com.mojang.datafixers.DataFixer;
-+import com.mojang.serialization.MapCodec;
-+import net.minecraft.SharedConstants;
-+import net.minecraft.core.RegistryAccess;
-+import net.minecraft.core.registries.Registries;
-+import net.minecraft.nbt.CompoundTag;
-+import net.minecraft.resources.ResourceKey;
-+import net.minecraft.util.worldupdate.WorldUpgrader;
-+import net.minecraft.world.level.ChunkPos;
-+import net.minecraft.world.level.Level;
-+import net.minecraft.world.level.chunk.ChunkGenerator;
-+import net.minecraft.world.level.chunk.storage.ChunkStorage;
-+import net.minecraft.world.level.chunk.storage.RegionFileStorage;
-+import net.minecraft.world.level.chunk.storage.RegionStorageInfo;
-+import net.minecraft.world.level.dimension.LevelStem;
-+import net.minecraft.world.level.storage.DimensionDataStorage;
-+import net.minecraft.world.level.storage.LevelStorageSource;
-+import org.apache.logging.log4j.LogManager;
-+import org.apache.logging.log4j.Logger;
-+import java.io.File;
-+import java.io.IOException;
-+import java.text.DecimalFormat;
-+import java.util.Optional;
-+import java.util.concurrent.ExecutorService;
-+import java.util.concurrent.Executors;
-+import java.util.concurrent.ThreadFactory;
-+import java.util.concurrent.atomic.AtomicInteger;
-+import java.util.concurrent.atomic.AtomicLong;
-+import java.util.function.Supplier;
-+
-+public class ThreadedWorldUpgrader {
-+
-+ private static final Logger LOGGER = LogManager.getLogger();
-+
-+ private final ResourceKey<LevelStem> dimensionType;
-+ private final String worldName;
-+ private final File worldDir;
-+ private final ExecutorService threadPool;
-+ private final DataFixer dataFixer;
-+ private final RegistryAccess registryLookup;
-+ private final Optional<ResourceKey<MapCodec<? extends ChunkGenerator>>> generatorKey;
-+ private final boolean removeCaches;
-+ private final boolean recreateRegionFiles; // TODO
-+
-+ public ThreadedWorldUpgrader(final ResourceKey<LevelStem> dimensionType, final String worldName, final File worldDir, final int threads,
-+ final DataFixer dataFixer, final RegistryAccess registryLookup, final Optional<ResourceKey<MapCodec<? extends ChunkGenerator>>> generatorKey,
-+ final boolean removeCaches, final boolean recreateRegionFiles) {
-+ this.dimensionType = dimensionType;
-+ this.worldName = worldName;
-+ this.worldDir = worldDir;
-+ this.threadPool = Executors.newFixedThreadPool(Math.max(1, threads), new ThreadFactory() {
-+ private final AtomicInteger threadCounter = new AtomicInteger();
-+
-+ @Override
-+ public Thread newThread(final Runnable run) {
-+ final Thread ret = new Thread(run);
-+
-+ ret.setName("World upgrader thread for world " + ThreadedWorldUpgrader.this.worldName + " #" + this.threadCounter.getAndIncrement());
-+ ret.setUncaughtExceptionHandler((thread, throwable) -> {
-+ LOGGER.fatal("Error upgrading world", throwable);
-+ });
-+
-+ return ret;
-+ }
-+ });
-+ this.dataFixer = dataFixer;
-+ this.registryLookup = registryLookup;
-+ this.generatorKey = generatorKey;
-+ this.removeCaches = removeCaches;
-+ this.recreateRegionFiles = recreateRegionFiles;
-+ }
-+
-+ public void convert() {
-+ final File worldFolder = LevelStorageSource.getStorageFolder(this.worldDir.toPath(), this.dimensionType).toFile();
-+ final DimensionDataStorage worldPersistentData = new DimensionDataStorage(new File(worldFolder, "data"), this.dataFixer, this.registryLookup);
-+
-+ final File regionFolder = new File(worldFolder, "region");
-+
-+ LOGGER.info("Force upgrading {}", this.worldName);
-+ LOGGER.info("Counting regionfiles for {}", this.worldName);
-+ final File[] regionFiles = regionFolder.listFiles((final File dir, final String name) -> {
-+ return WorldUpgrader.REGEX.matcher(name).matches();
-+ });
-+ if (regionFiles == null) {
-+ LOGGER.info("Found no regionfiles to convert for world {}", this.worldName);
-+ return;
-+ }
-+ LOGGER.info("Found {} regionfiles to convert", regionFiles.length);
-+ LOGGER.info("Starting conversion now for world {}", this.worldName);
-+
-+ // Only used for profiling, let's fill it anyways just in case
-+ final RegionStorageInfo storageInfo = new RegionStorageInfo(
-+ this.worldName,
-+ ResourceKey.create(Registries.DIMENSION, this.dimensionType.location()),
-+ "region"
-+ );
-+
-+ final WorldInfo info = new WorldInfo(() -> worldPersistentData,
-+ new ChunkStorage(storageInfo, regionFolder.toPath(), this.dataFixer, false), this.removeCaches, this.dimensionType, this.generatorKey);
-+
-+ long expectedChunks = (long)regionFiles.length * (32L * 32L);
-+
-+ for (final File regionFile : regionFiles) {
-+ final ChunkPos regionPos = RegionFileStorage.getRegionFileCoordinates(regionFile.toPath());
-+ if (regionPos == null) {
-+ expectedChunks -= (32L * 32L);
-+ continue;
-+ }
-+
-+ this.threadPool.execute(new ConvertTask(info, regionPos.x >> 5, regionPos.z >> 5));
-+ }
-+ this.threadPool.shutdown();
-+
-+ final DecimalFormat format = new DecimalFormat("#0.00");
-+
-+ final long start = System.nanoTime();
-+
-+ while (!this.threadPool.isTerminated()) {
-+ final long current = info.convertedChunks.get();
-+
-+ LOGGER.info("{}% completed ({} / {} chunks)...", format.format((double)current / (double)expectedChunks * 100.0), current, expectedChunks);
-+
-+ try {
-+ Thread.sleep(1000L);
-+ } catch (final InterruptedException ignore) {}
-+ }
-+
-+ final long end = System.nanoTime();
-+
-+ try {
-+ info.loader.close();
-+ } catch (final IOException ex) {
-+ LOGGER.fatal("Failed to close chunk loader", ex);
-+ }
-+ LOGGER.info("Completed conversion. Took {}s, {} out of {} chunks needed to be converted/modified ({}%)",
-+ (int)Math.ceil((end - start) * 1.0e-9), info.modifiedChunks.get(), expectedChunks, format.format((double)info.modifiedChunks.get() / (double)expectedChunks * 100.0));
-+ }
-+
-+ private static final class WorldInfo {
-+
-+ public final Supplier<DimensionDataStorage> persistentDataSupplier;
-+ public final ChunkStorage loader;
-+ public final boolean removeCaches;
-+ public final ResourceKey<LevelStem> worldKey;
-+ public final Optional<ResourceKey<MapCodec<? extends ChunkGenerator>>> generatorKey;
-+ public final AtomicLong convertedChunks = new AtomicLong();
-+ public final AtomicLong modifiedChunks = new AtomicLong();
-+
-+ private WorldInfo(final Supplier<DimensionDataStorage> persistentDataSupplier, final ChunkStorage loader, final boolean removeCaches,
-+ final ResourceKey<LevelStem> worldKey, Optional<ResourceKey<MapCodec<? extends ChunkGenerator>>> generatorKey) {
-+ this.persistentDataSupplier = persistentDataSupplier;
-+ this.loader = loader;
-+ this.removeCaches = removeCaches;
-+ this.worldKey = worldKey;
-+ this.generatorKey = generatorKey;
-+ }
-+ }
-+
-+ private static final class ConvertTask implements Runnable {
-+
-+ private final WorldInfo worldInfo;
-+ private final int regionX;
-+ private final int regionZ;
-+
-+ public ConvertTask(final WorldInfo worldInfo, final int regionX, final int regionZ) {
-+ this.worldInfo = worldInfo;
-+ this.regionX = regionX;
-+ this.regionZ = regionZ;
-+ }
-+
-+ @Override
-+ public void run() {
-+ final int regionCX = this.regionX << 5;
-+ final int regionCZ = this.regionZ << 5;
-+
-+ final Supplier<DimensionDataStorage> persistentDataSupplier = this.worldInfo.persistentDataSupplier;
-+ final ChunkStorage loader = this.worldInfo.loader;
-+ final boolean removeCaches = this.worldInfo.removeCaches;
-+ final ResourceKey<LevelStem> worldKey = this.worldInfo.worldKey;
-+
-+ for (int cz = regionCZ; cz < (regionCZ + 32); ++cz) {
-+ for (int cx = regionCX; cx < (regionCX + 32); ++cx) {
-+ final ChunkPos chunkPos = new ChunkPos(cx, cz);
-+ try {
-+ // no need to check the coordinate of the chunk, the regionfilecache does that for us
-+
-+ CompoundTag chunkNBT = (loader.read(chunkPos).join()).orElse(null);
-+
-+ if (chunkNBT == null) {
-+ continue;
-+ }
-+
-+ final int versionBefore = ChunkStorage.getVersion(chunkNBT);
-+
-+ chunkNBT = loader.upgradeChunkTag(worldKey, persistentDataSupplier, chunkNBT, this.worldInfo.generatorKey, chunkPos, null);
-+
-+ boolean modified = versionBefore < SharedConstants.getCurrentVersion().getDataVersion().getVersion();
-+
-+ if (removeCaches) {
-+ final CompoundTag level = chunkNBT.getCompound("Level");
-+ modified |= level.contains("Heightmaps");
-+ level.remove("Heightmaps");
-+ modified |= level.contains("isLightOn");
-+ level.remove("isLightOn");
-+ }
-+
-+ if (modified) {
-+ this.worldInfo.modifiedChunks.getAndIncrement();
-+ loader.write(chunkPos, chunkNBT);
-+ }
-+ } catch (final Exception ex) {
-+ LOGGER.error("Error upgrading chunk {}", chunkPos, ex);
-+ } finally {
-+ this.worldInfo.convertedChunks.getAndIncrement();
-+ }
-+ }
-+ }
-+ }
-+ }
-+}
-diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
-index 244a19ecd0234fa1d7a6ecfea20751595688605d..5443013060b62e3bfcc51cddca96d1c0bc59fe72 100644
---- a/src/main/java/net/minecraft/server/Main.java
-+++ b/src/main/java/net/minecraft/server/Main.java
-@@ -392,6 +392,15 @@ public class Main {
- return new WorldLoader.InitConfig(worldloader_d, Commands.CommandSelection.DEDICATED, serverPropertiesHandler.functionPermissionLevel);
- }
-
-+ // Paper start - fix and optimise world upgrading
-+ public static void convertWorldButItWorks(net.minecraft.resources.ResourceKey<net.minecraft.world.level.dimension.LevelStem> dimensionType, net.minecraft.world.level.storage.LevelStorageSource.LevelStorageAccess worldSession,
-+ DataFixer dataFixer, RegistryAccess registryLookup, Optional<net.minecraft.resources.ResourceKey<com.mojang.serialization.MapCodec<? extends net.minecraft.world.level.chunk.ChunkGenerator>>> generatorKey, boolean removeCaches, boolean recreateRegionFiles) {
-+ int threads = Runtime.getRuntime().availableProcessors() * 3 / 8;
-+ final io.papermc.paper.world.ThreadedWorldUpgrader worldUpgrader = new io.papermc.paper.world.ThreadedWorldUpgrader(dimensionType, worldSession.getLevelId(), worldSession.levelDirectory.path().toFile(), threads, dataFixer, registryLookup, generatorKey, removeCaches, recreateRegionFiles);
-+ worldUpgrader.convert();
-+ }
-+ // Paper end - fix and optimise world upgrading
-+
- public static void forceUpgrade(LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, boolean eraseCache, BooleanSupplier continueCheck, RegistryAccess dynamicRegistryManager, boolean recreateRegionFiles) {
- Main.LOGGER.info("Forcing world upgrade! {}", session.getLevelId()); // CraftBukkit
- WorldUpgrader worldupgrader = new WorldUpgrader(session, dataFixer, dynamicRegistryManager, eraseCache, recreateRegionFiles);
-diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
-index 0408d5d54fef7767ecf70e70686ad520d890ff26..f525a8735e5cf5eb1278e2a3002ac81d9fff7b1a 100644
---- a/src/main/java/net/minecraft/server/MinecraftServer.java
-+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
-@@ -596,11 +596,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
- worlddata = new PrimaryLevelData(worldsettings, worldoptions, worlddimensions_b.specialWorldProperty(), lifecycle);
- }
- worlddata.checkName(name); // CraftBukkit - Migration did not rewrite the level.dat; This forces 1.8 to take the last loaded world as respawn (in this case the end)
-- if (this.options.has("forceUpgrade")) {
-- net.minecraft.server.Main.forceUpgrade(worldSession, DataFixers.getDataFixer(), this.options.has("eraseCache"), () -> {
-- return true;
-- }, iregistrycustom_dimension, this.options.has("recreateRegionFiles"));
-- }
-+ // Paper - fix and optimise world upgrading; move down
-
- PrimaryLevelData iworlddataserver = worlddata;
- boolean flag = worlddata.isDebugWorld();
-@@ -615,6 +611,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
- biomeProvider = gen.getDefaultBiomeProvider(worldInfo);
- }
-
-+ // Paper start - fix and optimise world upgrading
-+ if (options.has("forceUpgrade")) {
-+ net.minecraft.server.Main.convertWorldButItWorks(
-+ dimensionKey, worldSession, DataFixers.getDataFixer(), iregistrycustom_dimension, worlddimension.generator().getTypeNameForDataFixer(), options.has("eraseCache"), options.has("recreateRegionFiles")
-+ );
-+ }
-+ // Paper end - fix and optimise world upgrading
- ResourceKey<Level> worldKey = ResourceKey.create(Registries.DIMENSION, dimensionKey.location());
-
- if (dimensionKey == LevelStem.OVERWORLD) {
-diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
-index 0a8eeebb2d702ebcefd9f26cc0f41d1eab497902..b4ef3ad2c17168085372f1fe46809f02d9dfe74a 100644
---- a/src/main/java/net/minecraft/world/level/Level.java
-+++ b/src/main/java/net/minecraft/world/level/Level.java
-@@ -178,6 +178,15 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
- public final Map<Explosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions
- public java.util.ArrayDeque<net.minecraft.world.level.block.RedstoneTorchBlock.Toggle> redstoneUpdateInfos; // Paper - Faster redstone torch rapid clock removal; Move from Map in BlockRedstoneTorch to here
-
-+ // Paper start - fix and optimise world upgrading
-+ // copied from below
-+ public static ResourceKey<DimensionType> getDimensionKey(DimensionType manager) {
-+ return ((org.bukkit.craftbukkit.CraftServer)org.bukkit.Bukkit.getServer()).getHandle().getServer().registryAccess().registryOrThrow(net.minecraft.core.registries.Registries.DIMENSION_TYPE).getResourceKey(manager).orElseThrow(() -> {
-+ return new IllegalStateException("Unregistered dimension type: " + manager);
-+ });
-+ }
-+ // Paper end - fix and optimise world upgrading
-+
- public CraftWorld getWorld() {
- return this.world;
- }
-diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
-index 249705ec1b8b692ef1d7fec34a04918afe6486bc..f6e3b745fc417354380d4a969f83aee430bad785 100644
---- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
-+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
-@@ -69,6 +69,29 @@ public class RegionFileStorage implements AutoCloseable {
- }
-
- // Paper start
-+ @Nullable
-+ public static ChunkPos getRegionFileCoordinates(Path file) {
-+ String fileName = file.getFileName().toString();
-+ if (!fileName.startsWith("r.") || !fileName.endsWith(".mca")) {
-+ return null;
-+ }
-+
-+ String[] split = fileName.split("\\.");
-+
-+ if (split.length != 4) {
-+ return null;
-+ }
-+
-+ try {
-+ int x = Integer.parseInt(split[1]);
-+ int z = Integer.parseInt(split[2]);
-+
-+ return new ChunkPos(x << 5, z << 5);
-+ } catch (NumberFormatException ex) {
-+ return null;
-+ }
-+ }
-+
- public synchronized RegionFile getRegionFileIfLoaded(ChunkPos chunkcoordintpair) {
- return this.regionCache.getAndMoveToFirst(ChunkPos.asLong(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ()));
- }
-diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
-index 8e0b0e4b177f1bcf23e174dfca6eaa0f7203a95a..b63dc96d2b387bd0a6bd3c703853b40a337bb33f 100644
---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
-+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
-@@ -1361,9 +1361,7 @@ public final class CraftServer implements Server {
- worlddata.checkName(name);
- worlddata.setModdedInfo(this.console.getServerModName(), this.console.getModdedStatus().shouldReportAsModified());
-
-- if (this.console.options.has("forceUpgrade")) {
-- net.minecraft.server.Main.forceUpgrade(worldSession, DataFixers.getDataFixer(), this.console.options.has("eraseCache"), () -> true, iregistrycustom_dimension, this.console.options.has("recreateRegionFiles"));
-- }
-+ // Paper - fix and optimise world upgrading; move down
-
- long j = BiomeManager.obfuscateSeed(worlddata.worldGenOptions().seed()); // Paper - use world seed
- List<CustomSpawner> list = ImmutableList.of(new PhantomSpawner(), new PatrolSpawner(), new CatSpawner(), new VillageSiege(), new WanderingTraderSpawner(worlddata));
-@@ -1374,6 +1372,13 @@ public final class CraftServer implements Server {
- biomeProvider = generator.getDefaultBiomeProvider(worldInfo);
- }
-
-+ // Paper start - fix and optimise world upgrading
-+ if (this.console.options.has("forceUpgrade")) {
-+ net.minecraft.server.Main.convertWorldButItWorks(
-+ actualDimension, worldSession, DataFixers.getDataFixer(), iregistrycustom_dimension, worlddimension.generator().getTypeNameForDataFixer(), this.console.options.has("eraseCache"), this.console.options.has("recreateRegionFiles")
-+ );
-+ }
-+ // Paper end - fix and optimise world upgrading
- ResourceKey<net.minecraft.world.level.Level> worldKey;
- String levelName = this.getServer().getProperties().levelName;
- if (name.equals(levelName + "_nether")) {
diff --git a/patches/server/1027-Add-config-for-mobs-immune-to-default-effects.patch b/patches/server/1026-Add-config-for-mobs-immune-to-default-effects.patch
index 7bf145751f..7bf145751f 100644
--- a/patches/server/1027-Add-config-for-mobs-immune-to-default-effects.patch
+++ b/patches/server/1026-Add-config-for-mobs-immune-to-default-effects.patch
diff --git a/patches/server/1028-Deep-clone-nbt-tags-in-PDC.patch b/patches/server/1027-Deep-clone-nbt-tags-in-PDC.patch
index 96cc14f9db..96cc14f9db 100644
--- a/patches/server/1028-Deep-clone-nbt-tags-in-PDC.patch
+++ b/patches/server/1027-Deep-clone-nbt-tags-in-PDC.patch
diff --git a/patches/server/1029-Support-old-UUID-format-for-NBT.patch b/patches/server/1028-Support-old-UUID-format-for-NBT.patch
index a38c2a7f7b..a38c2a7f7b 100644
--- a/patches/server/1029-Support-old-UUID-format-for-NBT.patch
+++ b/patches/server/1028-Support-old-UUID-format-for-NBT.patch
diff --git a/patches/server/1030-Fix-shield-disable-inconsistency.patch b/patches/server/1029-Fix-shield-disable-inconsistency.patch
index 757be91657..bcc617a146 100644
--- a/patches/server/1030-Fix-shield-disable-inconsistency.patch
+++ b/patches/server/1029-Fix-shield-disable-inconsistency.patch
@@ -8,7 +8,7 @@ it will not disable the shield if the attacker is holding
an axe item.
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
-index ca242ba1312263ec095fa2850dc0f02351e844ab..2338e41fde55559249d5f212697235e789b20b2a 100644
+index d6a7642697c08bcdc69b4f1d4475f0532e131b80..a1a72712e9acd4023c4b6832e5ec09dcc3676b6e 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -2341,7 +2341,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
diff --git a/patches/server/1031-Write-SavedData-IO-async.patch b/patches/server/1030-Write-SavedData-IO-async.patch
index 365011d581..66e24700a5 100644
--- a/patches/server/1031-Write-SavedData-IO-async.patch
+++ b/patches/server/1030-Write-SavedData-IO-async.patch
@@ -5,26 +5,6 @@ Subject: [PATCH] Write SavedData IO async
Co-Authored-By: Shane Freeder <[email protected]>
-diff --git a/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java b/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java
-index e049fbe4038aaea896f45b11ce9ce8f05922c898..7f6d1ccd147e5593412567bb2934ce5662da7ef0 100644
---- a/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java
-+++ b/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java
-@@ -110,6 +110,15 @@ public class ThreadedWorldUpgrader {
- }
-
- this.threadPool.execute(new ConvertTask(info, regionPos.x >> 5, regionPos.z >> 5));
-+ // Paper start - Write SavedData IO async
-+ this.threadPool.execute(() -> {
-+ try {
-+ worldPersistentData.close();
-+ } catch (IOException exception) {
-+ LOGGER.error("Failed to close persistent world data", exception);
-+ }
-+ });
-+ // Paper end - Write SavedData IO async
- }
- this.threadPool.shutdown();
-
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
index 36caf354634d6675a3f1ec6829f4778e1d0623bc..b99f50604bafecbc68835974c9ed0caa91911a40 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -81,7 +61,7 @@ index aab652174a8175765cad548f7c61ce353ca74803..ca56a0b596976448da6bb2a0e82b3d5c
public <T extends Entity> List<? extends T> getEntities(EntityTypeTest<Entity, T> filter, Predicate<? super T> predicate) {
diff --git a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
-index 639f72618a7c22fa94effa9d0406b97fffc64cb5..3e582c49069f2a820ba3baac03917493877d9875 100644
+index ffbb3bf9ff3fc968ef69d4f889b0baf7e8ab691b..954d468459fe167ede0e7fca5b9f99da565d59e1 100644
--- a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
+++ b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
@@ -116,7 +116,13 @@ public class WorldUpgrader {
diff --git a/patches/server/1032-Don-t-lose-removed-data-components-in-ItemMeta.patch b/patches/server/1031-Don-t-lose-removed-data-components-in-ItemMeta.patch
index d64eaac093..d64eaac093 100644
--- a/patches/server/1032-Don-t-lose-removed-data-components-in-ItemMeta.patch
+++ b/patches/server/1031-Don-t-lose-removed-data-components-in-ItemMeta.patch
diff --git a/patches/server/1033-Add-experimental-improved-give-command.patch b/patches/server/1032-Add-experimental-improved-give-command.patch
index fd226dcb27..fd226dcb27 100644
--- a/patches/server/1033-Add-experimental-improved-give-command.patch
+++ b/patches/server/1032-Add-experimental-improved-give-command.patch
diff --git a/patches/server/1034-Handle-Large-Packets-disconnecting-client.patch b/patches/server/1033-Handle-Large-Packets-disconnecting-client.patch
index 49f2553189..49f2553189 100644
--- a/patches/server/1034-Handle-Large-Packets-disconnecting-client.patch
+++ b/patches/server/1033-Handle-Large-Packets-disconnecting-client.patch
diff --git a/patches/server/1035-Fix-ItemFlags.patch b/patches/server/1034-Fix-ItemFlags.patch
index df5328f3a8..df5328f3a8 100644
--- a/patches/server/1035-Fix-ItemFlags.patch
+++ b/patches/server/1034-Fix-ItemFlags.patch
diff --git a/patches/server/1036-Fix-helmet-damage-reduction-inconsistencies.patch b/patches/server/1035-Fix-helmet-damage-reduction-inconsistencies.patch
index af975bb004..af975bb004 100644
--- a/patches/server/1036-Fix-helmet-damage-reduction-inconsistencies.patch
+++ b/patches/server/1035-Fix-helmet-damage-reduction-inconsistencies.patch
diff --git a/patches/server/1037-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch b/patches/server/1036-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch
index e471865c85..84ae9df20b 100644
--- a/patches/server/1037-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch
+++ b/patches/server/1036-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch
@@ -5,7 +5,7 @@ Subject: [PATCH] Revert to vanilla handling of LivingEntity#actuallyHurt
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
-index 2338e41fde55559249d5f212697235e789b20b2a..517e10c3d8b1549cd30fd0e7cf2bcb35e88eb8ed 100644
+index a1a72712e9acd4023c4b6832e5ec09dcc3676b6e..ef0f118aecf0893e45cb9423a677d7e42496324b 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -2226,7 +2226,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
diff --git a/patches/server/1038-improve-checking-handled-tags-in-itemmeta.patch b/patches/server/1037-improve-checking-handled-tags-in-itemmeta.patch
index 72204e0a32..72204e0a32 100644
--- a/patches/server/1038-improve-checking-handled-tags-in-itemmeta.patch
+++ b/patches/server/1037-improve-checking-handled-tags-in-itemmeta.patch
diff --git a/patches/server/1039-General-ItemMeta-fixes.patch b/patches/server/1038-General-ItemMeta-fixes.patch
index d39c8fd518..d39c8fd518 100644
--- a/patches/server/1039-General-ItemMeta-fixes.patch
+++ b/patches/server/1038-General-ItemMeta-fixes.patch
diff --git a/patches/server/1040-Expose-hasColor-to-leather-armor.patch b/patches/server/1039-Expose-hasColor-to-leather-armor.patch
index df08de2a92..df08de2a92 100644
--- a/patches/server/1040-Expose-hasColor-to-leather-armor.patch
+++ b/patches/server/1039-Expose-hasColor-to-leather-armor.patch
diff --git a/patches/server/1041-Added-API-to-get-player-ha-proxy-address.patch b/patches/server/1040-Added-API-to-get-player-ha-proxy-address.patch
index 364197b03e..a9b47406aa 100644
--- a/patches/server/1041-Added-API-to-get-player-ha-proxy-address.patch
+++ b/patches/server/1040-Added-API-to-get-player-ha-proxy-address.patch
@@ -35,7 +35,7 @@ index 52f537b7bfbdeaad9d17c0e88a1ed1c8925a833f..8aff5129f85ab5729b3da2e465871be6
} else {
super.channelRead(ctx, msg);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
-index a9aa3dca65aca86cf535d6616f5d5db3e1e8fc8b..561a7a8e96e2d91bbb87fe6230e94b5f38073d27 100644
+index 84ed5dc8c82e28aa93fa0440d90ddb44dc5f3d40..7e6116963d835d4606ef3d93b69d3e44b61288e1 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -273,6 +273,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
diff --git a/patches/server/1042-More-Chest-Block-API.patch b/patches/server/1041-More-Chest-Block-API.patch
index 7a9542665a..7a9542665a 100644
--- a/patches/server/1042-More-Chest-Block-API.patch
+++ b/patches/server/1041-More-Chest-Block-API.patch
diff --git a/patches/server/1043-Print-data-component-type-on-encoding-error.patch b/patches/server/1042-Print-data-component-type-on-encoding-error.patch
index 78cb82fa00..78cb82fa00 100644
--- a/patches/server/1043-Print-data-component-type-on-encoding-error.patch
+++ b/patches/server/1042-Print-data-component-type-on-encoding-error.patch
diff --git a/patches/server/1044-Fix-entity-tracker-desync-when-new-players-are-added.patch b/patches/server/1043-Fix-entity-tracker-desync-when-new-players-are-added.patch
index a39b2bf46f..a39b2bf46f 100644
--- a/patches/server/1044-Fix-entity-tracker-desync-when-new-players-are-added.patch
+++ b/patches/server/1043-Fix-entity-tracker-desync-when-new-players-are-added.patch
diff --git a/patches/server/1045-Brigadier-based-command-API.patch b/patches/server/1044-Brigadier-based-command-API.patch
index 638a5b18f4..61d00aaac5 100644
--- a/patches/server/1045-Brigadier-based-command-API.patch
+++ b/patches/server/1044-Brigadier-based-command-API.patch
@@ -2154,7 +2154,7 @@ index 982b2bab27e3d55d0ba07060862c0c3183ad91b0..5fa8a3343ffc11e82c20b78a73205fd8
Component component = message.resolveComponent(commandSourceStack);
CommandSigningContext commandSigningContext = commandSourceStack.getSigningContext();
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
-index f525a8735e5cf5eb1278e2a3002ac81d9fff7b1a..dbc86b8d4d2af6e5f7e678f2bb77fd39b85c04c5 100644
+index 0408d5d54fef7767ecf70e70686ad520d890ff26..0ed42fa899721f83b598db05be1b5f321af3614a 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -299,7 +299,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2174,7 +2174,7 @@ index f525a8735e5cf5eb1278e2a3002ac81d9fff7b1a..dbc86b8d4d2af6e5f7e678f2bb77fd39
// Paper start - Handled by TerminalConsoleAppender
// Try to see if we're actually running in a terminal, disable jline if not
/*
-@@ -678,6 +677,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
+@@ -675,6 +674,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.POSTWORLD);
if (io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper != null) io.papermc.paper.plugin.PluginInitializerManager.instance().pluginRemapper.pluginsEnabled(); // Paper - Remap plugins
@@ -2184,7 +2184,7 @@ index f525a8735e5cf5eb1278e2a3002ac81d9fff7b1a..dbc86b8d4d2af6e5f7e678f2bb77fd39
this.server.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.STARTUP));
this.connection.acceptConnections();
}
-@@ -2299,9 +2301,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
+@@ -2296,9 +2298,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
return new MinecraftServer.ReloadableResources(resourcemanager, datapackresources);
});
}).thenAcceptAsync((minecraftserver_reloadableresources) -> {
@@ -2195,7 +2195,7 @@ index f525a8735e5cf5eb1278e2a3002ac81d9fff7b1a..dbc86b8d4d2af6e5f7e678f2bb77fd39
this.packRepository.setSelected(dataPacks);
WorldDataConfiguration worlddataconfiguration = new WorldDataConfiguration(MinecraftServer.getSelectedPacks(this.packRepository, true), this.worldData.enabledFeatures());
-@@ -2320,8 +2322,17 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
+@@ -2317,8 +2319,17 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.getPlayerList().reloadResources();
this.functionManager.replaceLibrary(this.resources.managers.getFunctionLibrary());
this.structureTemplateManager.onResourceManagerReload(this.resources.resourceManager);
@@ -2318,7 +2318,7 @@ index 3faf80fca51d66480265eaf3cc89149e53ceb215..b9b3277c8ed94e0cd30b20b9c00a33ea
// CraftBukkit end
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
-index b63dc96d2b387bd0a6bd3c703853b40a337bb33f..2fa5507aa2153a05208077f9547c165a1099b5bb 100644
+index ac57c3a63bbf234e83f538e4a06ab794c7a0965a..af015237214cebc4d1c4bb9e9c5f939d433e365c 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -270,11 +270,11 @@ public final class CraftServer implements Server {
diff --git a/patches/server/1046-Fix-issues-with-Recipe-API.patch b/patches/server/1045-Fix-issues-with-Recipe-API.patch
index a5312e5dc7..a5312e5dc7 100644
--- a/patches/server/1046-Fix-issues-with-Recipe-API.patch
+++ b/patches/server/1045-Fix-issues-with-Recipe-API.patch