diff --git a/patches/unapplied/server/Attempt-to-recalculate-regionfile-header-if-it-is-co.patch b/patches/server/Attempt-to-recalculate-regionfile-header-if-it-is-co.patch
similarity index 93%
rename from patches/unapplied/server/Attempt-to-recalculate-regionfile-header-if-it-is-co.patch
rename to patches/server/Attempt-to-recalculate-regionfile-header-if-it-is-co.patch
index a188298a88..4cf82ff216 100644
--- a/patches/unapplied/server/Attempt-to-recalculate-regionfile-header-if-it-is-co.patch
+++ b/patches/server/Attempt-to-recalculate-regionfile-header-if-it-is-co.patch
@@ -47,10 +47,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java
 @@ -0,0 +0,0 @@ public class ChunkStorage implements AutoCloseable {
  
-     public ChunkStorage(Path directory, DataFixer dataFixer, boolean dsync) {
+     public ChunkStorage(RegionStorageInfo storageKey, Path directory, DataFixer dataFixer, boolean dsync) {
          this.fixerUpper = dataFixer;
--        this.regionFileCache = new RegionFileStorage(directory, dsync); // Paper - rewrite chunk system; async chunk IO
-+        this.regionFileCache = new RegionFileStorage(directory, dsync, true); // Paper - rewrite chunk system; async chunk IO & Attempt to recalculate regionfile header if it is corrupt
+-        this.regionFileCache = new RegionFileStorage(storageKey, directory, dsync); // Paper - rewrite chunk system; async chunk IO
++        this.regionFileCache = new RegionFileStorage(storageKey, directory, dsync, true); // Paper - rewrite chunk system; async chunk IO & Attempt to recalculate regionfile header if it is corrupt
      }
  
      public boolean isOldChunkAround(ChunkPos chunkPos, int checkRadius) {
@@ -91,9 +91,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
 +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
 @@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
+     protected final RegionBitmap usedSectors;
      public final java.util.concurrent.locks.ReentrantLock fileLock = new java.util.concurrent.locks.ReentrantLock(); // Paper
      public final Path regionFile; // Paper
- 
++
 +    // Paper start - Attempt to recalculate regionfile header if it is corrupt
 +    private static long roundToSectors(long bytes) {
 +        long sectors = bytes >>> 12; // 4096 = 2^12
@@ -447,31 +448,30 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      private final net.minecraft.world.level.chunk.ChunkStatus[] statuses = new net.minecraft.world.level.chunk.ChunkStatus[32 * 32];
  
 @@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
-     public RegionFile(Path file, Path directory, boolean dsync) throws IOException {
-         this(file, directory, RegionFileVersion.getCompressionFormat(), dsync); // Paper - Configurable region compression format
+     public RegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync) throws IOException {
+         this(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync); // Paper - Configurable region compression format
      }
 +    // Paper start - add can recalc flag
-+    public RegionFile(Path file, Path directory, boolean dsync, boolean canRecalcHeader) throws IOException {
-+        this(file, directory, RegionFileVersion.getCompressionFormat(), dsync, canRecalcHeader);
++    public RegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync, boolean canRecalcHeader) throws IOException {
++        this(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync, canRecalcHeader);
 +    }
-+    // Paper end - add can recalc flag
  
-     public RegionFile(Path file, Path directory, RegionFileVersion outputChunkStreamVersion, boolean dsync) throws IOException {
-+        // Paper start - add can recalc flag
-+        this(file, directory, outputChunkStreamVersion, dsync, false);
+     public RegionFile(RegionStorageInfo storageKey, Path path, Path directory, RegionFileVersion compressionFormat, boolean dsync) throws IOException {
++        this(storageKey, path, directory, compressionFormat, dsync, true);
 +    }
-+    public RegionFile(Path file, Path directory, RegionFileVersion outputChunkStreamVersion, boolean dsync, boolean canRecalcHeader) throws IOException {
++
++    public RegionFile(RegionStorageInfo storageKey, Path path, Path directory, RegionFileVersion compressionFormat, boolean dsync, boolean canRecalcHeader) throws IOException {
 +        this.canRecalcHeader = canRecalcHeader;
 +        // Paper end - add can recalc flag
          this.header = ByteBuffer.allocateDirect(8192);
          this.regionFile = file; // Paper
          initOversizedState(); // Paper
 @@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
-                     RegionFile.LOGGER.warn("Region file {} has truncated header: {}", file, i);
+                     RegionFile.LOGGER.warn("Region file {} has truncated header: {}", path, i);
                  }
  
--                long j = Files.size(file);
-+                final long j = Files.size(file); final long regionFileSize = j; // Paper - recalculate header on header corruption
+-                long j = Files.size(path);
++                final long j = Files.size(path); final long regionFileSize = j; // Paper - recalculate header on header corruption
  
 -                for (int k = 0; k < 1024; ++k) {
 -                    int l = this.offsets.get(k);
@@ -495,15 +495,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +                        sectorLength = j1; // Paper - diff on change, we expect this to be sector length of region
  
                          if (i1 < 2) {
-                             RegionFile.LOGGER.warn("Region file {} has invalid sector at index: {}; sector {} overlaps with header", new Object[]{file, k, i1});
+                             RegionFile.LOGGER.warn("Region file {} has invalid sector at index: {}; sector {} overlaps with header", new Object[]{path, k, i1});
 -                            this.offsets.put(k, 0);
 +                            //this.offsets.put(k, 0); // Paper - we catch this, but need it in the header for the summary change
                          } else if (j1 == 0) {
-                             RegionFile.LOGGER.warn("Region file {} has an invalid sector at index: {}; size has to be > 0", file, k);
+                             RegionFile.LOGGER.warn("Region file {} has an invalid sector at index: {}; size has to be > 0", path, k);
 -                            this.offsets.put(k, 0);
 +                            //this.offsets.put(k, 0); // Paper - we catch this, but need it in the header for the summary change
                          } else if ((long) i1 * 4096L > j) {
-                             RegionFile.LOGGER.warn("Region file {} has an invalid sector at index: {}; sector {} is out of bounds", new Object[]{file, k, i1});
+                             RegionFile.LOGGER.warn("Region file {} has an invalid sector at index: {}; sector {} is out of bounds", new Object[]{path, k, i1});
 -                            this.offsets.put(k, 0);
 +                            //this.offsets.put(k, 0); // Paper - we catch this, but need it in the header for the summary change
                          } else {
@@ -559,6 +559,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
              }
  
          }
+@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable {
      }
  
      private Path getExternalChunkPath(ChunkPos chunkPos) {
@@ -656,6 +657,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +                        // Paper end - recalculate header on regionfile corruption
                          return null;
                      } else {
+                         JvmProfiler.INSTANCE.onRegionFileRead(this.info, pos, this.version, j1);
 -                        return this.createChunkInputStream(pos, b0, RegionFile.createStream(bytebuffer, j1));
 +                        // Paper start - recalculate header on regionfile corruption
 +                        final DataInputStream ret = this.createChunkInputStream(pos, b0, RegionFile.createStream(bytebuffer, j1));
@@ -689,7 +691,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
 +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
 @@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable {
-     public final Long2ObjectLinkedOpenHashMap<RegionFile> regionCache = new Long2ObjectLinkedOpenHashMap();
+     private final RegionStorageInfo info;
      private final Path folder;
      private final boolean sync;
 +    private final boolean isChunkData; // Paper
@@ -699,16 +701,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 @@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable {
      // Paper end - cache regionfile does not exist state
  
-     protected RegionFileStorage(Path directory, boolean dsync) { // Paper - protected constructor
+     protected RegionFileStorage(RegionStorageInfo storageKey, Path directory, boolean dsync) { // Paper - protected constructor
 +        // Paper start - add isChunkData param
-+        this(directory, dsync, false);
++        this(storageKey, directory, dsync, false);
 +    }
-+    RegionFileStorage(Path directory, boolean dsync, boolean isChunkData) {
++    RegionFileStorage(RegionStorageInfo storageKey, Path directory, boolean dsync, boolean isChunkData) {
 +        this.isChunkData = isChunkData;
 +        // Paper end - add isChunkData param
          this.folder = directory;
          this.sync = dsync;
-     }
+         this.info = storageKey;
 @@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable {
              // Paper - only create directory if not existing only - moved down
              Path path = this.folder;
@@ -722,8 +724,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
              }
              // Paper end - cache regionfile does not exist state
              FileUtil.createDirectoriesSafe(this.folder); // Paper - only create directory if not existing only - moved from above
--            RegionFile regionfile1 = new RegionFile(path1, this.folder, this.sync);
-+            RegionFile regionfile1 = new RegionFile(path1, this.folder, this.sync, this.isChunkData); // Paper - allow for chunk regionfiles to regen header
+-            RegionFile regionfile1 = new RegionFile(this.info, path1, this.folder, this.sync);
++            RegionFile regionfile1 = new RegionFile(this.info, path1, this.folder, this.sync, this.isChunkData); // Paper - allow for chunk regionfiles to regen header
  
              this.regionCache.putAndMoveToFirst(i, regionfile1);
              // Paper start
@@ -766,12 +768,12 @@ diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVer
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
 +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileVersion.java
-@@ -0,0 +0,0 @@ import javax.annotation.Nullable;
- import net.minecraft.util.FastBufferedInputStream;
+@@ -0,0 +0,0 @@ import org.slf4j.Logger;
  
  public class RegionFileVersion {
+     private static final Logger LOGGER = LogUtils.getLogger();
 -    private static final Int2ObjectMap<RegionFileVersion> VERSIONS = new Int2ObjectOpenHashMap<>();
 +    public static final Int2ObjectMap<RegionFileVersion> VERSIONS = new Int2ObjectOpenHashMap<>(); // Paper - private -> public
+     private static final Object2ObjectMap<String, RegionFileVersion> VERSIONS_BY_NAME = new Object2ObjectOpenHashMap<>();
      public static final RegionFileVersion VERSION_GZIP = register(
          new RegionFileVersion(
-             1, stream -> new FastBufferedInputStream(new GZIPInputStream(stream)), stream -> new BufferedOutputStream(new GZIPOutputStream(stream))
diff --git a/patches/unapplied/server/Custom-table-implementation-for-blockstate-state-loo.patch b/patches/server/Custom-table-implementation-for-blockstate-state-loo.patch
similarity index 98%
rename from patches/unapplied/server/Custom-table-implementation-for-blockstate-state-loo.patch
rename to patches/server/Custom-table-implementation-for-blockstate-state-loo.patch
index 4adbbb6ff4..cfe59c2249 100644
--- a/patches/unapplied/server/Custom-table-implementation-for-blockstate-state-loo.patch
+++ b/patches/server/Custom-table-implementation-for-blockstate-state-loo.patch
@@ -177,14 +177,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/main/java/net/minecraft/world/level/block/state/StateHolder.java
 +++ b/src/main/java/net/minecraft/world/level/block/state/StateHolder.java
 @@ -0,0 +0,0 @@ public abstract class StateHolder<O, S> {
-     private final ImmutableMap<Property<?>, Comparable<?>> values;
+     private final Reference2ObjectArrayMap<Property<?>, Comparable<?>> values;
      private Table<Property<?>, Comparable<?>, S> neighbours;
      protected final MapCodec<S> propertiesCodec;
 +    protected final io.papermc.paper.util.table.ZeroCollidingReferenceStateTable optimisedTable; // Paper - optimise state lookup
  
-     protected StateHolder(O owner, ImmutableMap<Property<?>, Comparable<?>> entries, MapCodec<S> codec) {
+     protected StateHolder(O owner, Reference2ObjectArrayMap<Property<?>, Comparable<?>> propertyMap, MapCodec<S> codec) {
          this.owner = owner;
-         this.values = entries;
+         this.values = propertyMap;
          this.propertiesCodec = codec;
 +        this.optimisedTable = new io.papermc.paper.util.table.ZeroCollidingReferenceStateTable(this, entries); // Paper - optimise state lookup
      }
diff --git a/patches/unapplied/server/Eigencraft-redstone-implementation.patch b/patches/server/Eigencraft-redstone-implementation.patch
similarity index 99%
rename from patches/unapplied/server/Eigencraft-redstone-implementation.patch
rename to patches/server/Eigencraft-redstone-implementation.patch
index d5aa9977a1..2551e39666 100644
--- a/patches/unapplied/server/Eigencraft-redstone-implementation.patch
+++ b/patches/server/Eigencraft-redstone-implementation.patch
@@ -1117,7 +1117,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      }
 @@ -0,0 +0,0 @@ public class RedStoneWireBlock extends Block {
      @Override
-     public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) {
+     protected void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) {
          if (!oldState.is(state.getBlock()) && !world.isClientSide) {
 -            this.updatePowerStrength(world, pos, state);
 +            this.updateSurroundingRedstone(world, pos, state, null); // Paper - Optimize redstone
@@ -1134,7 +1134,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
              }
          }
 @@ -0,0 +0,0 @@ public class RedStoneWireBlock extends Block {
-     public void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) {
+     protected void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) {
          if (!world.isClientSide) {
              if (state.canSurvive(world, pos)) {
 -                this.updatePowerStrength(world, pos, state);
diff --git a/patches/unapplied/server/Execute-chunk-tasks-mid-tick.patch b/patches/server/Execute-chunk-tasks-mid-tick.patch
similarity index 100%
rename from patches/unapplied/server/Execute-chunk-tasks-mid-tick.patch
rename to patches/server/Execute-chunk-tasks-mid-tick.patch
diff --git a/patches/server/Fix-DamageSource-API.patch b/patches/server/Fix-DamageSource-API.patch
index e9040be07a..eb4d63f59a 100644
--- a/patches/server/Fix-DamageSource-API.patch
+++ b/patches/server/Fix-DamageSource-API.patch
@@ -95,7 +95,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
              // CraftBukkit end
              this.dead = true;
 -            this.level().explode(this, net.minecraft.world.level.Explosion.getDefaultDamageSource(this.level(), this).customCausingEntity(this.entityIgniter), null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); // CraftBukkit
-+            this.level().explode(this, net.minecraft.world.level.Explosion.getDefaultDamageSource(this.level(), this).customEventDamager(this.entityIgniter), null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); // CraftBukkit
++            this.level().explode(this, net.minecraft.world.level.Explosion.getDefaultDamageSource(this.level(), this).customEventDamager(this.entityIgniter), null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); // CraftBukkit // Paper - fix DamageSource API
              this.discard(EntityRemoveEvent.Cause.EXPLODE); // CraftBukkit - add Bukkit remove cause
              this.spawnLingeringCloud();
              // CraftBukkit start
diff --git a/patches/unapplied/server/Improve-boat-collision-performance.patch b/patches/server/Improve-boat-collision-performance.patch
similarity index 100%
rename from patches/unapplied/server/Improve-boat-collision-performance.patch
rename to patches/server/Improve-boat-collision-performance.patch
diff --git a/patches/unapplied/server/Improved-Watchdog-Support.patch b/patches/server/Improved-Watchdog-Support.patch
similarity index 98%
rename from patches/unapplied/server/Improved-Watchdog-Support.patch
rename to patches/server/Improved-Watchdog-Support.patch
index 64e2efee46..06655df6d1 100644
--- a/patches/unapplied/server/Improved-Watchdog-Support.patch
+++ b/patches/server/Improved-Watchdog-Support.patch
@@ -218,14 +218,14 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  
 @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
              this.worldData.setDataConfiguration(worlddataconfiguration);
-             this.resources.managers.updateRegistryTags(this.registryAccess());
-             net.minecraft.world.item.alchemy.PotionBrewing.reload(); // Paper - Custom Potion Mixes
+             this.resources.managers.updateRegistryTags();
+             this.potionBrewing.reload(this.worldData.enabledFeatures()); // Paper - Custom Potion Mixes
 -            this.getPlayerList().saveAll();
 +            // Paper start
 +            if (Thread.currentThread() != this.serverThread) {
 +                return;
 +            }
-+            // this.getPlayerList().saveAll(); // Paper - we don't need to save everything, just advancements
++            // this.getPlayerList().saveAll(); // Paper - we don't need to save everything, just advancements // TODO Move this to a different patch
 +            for (ServerPlayer player : this.getPlayerList().getPlayers()) {
 +                player.getAdvancements().save();
 +            }
@@ -537,8 +537,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +++ b/src/main/resources/log4j2.xml
 @@ -0,0 +0,0 @@
  <?xml version="1.0" encoding="UTF-8"?>
--<Configuration status="WARN" packages="com.mojang.util">
-+<Configuration status="WARN" packages="com.mojang.util" shutdownHook="disable">
+-<Configuration status="WARN">
++<Configuration status="WARN" shutdownHook="disable">
      <Appenders>
          <Queue name="ServerGuiConsole">
-             <PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg%n" />
+             <PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg{nolookups}%n" />
diff --git a/patches/unapplied/server/Optimise-general-POI-access.patch b/patches/server/Optimise-general-POI-access.patch
similarity index 100%
rename from patches/unapplied/server/Optimise-general-POI-access.patch
rename to patches/server/Optimise-general-POI-access.patch
diff --git a/patches/unapplied/server/Optimise-random-block-ticking.patch b/patches/server/Optimise-random-block-ticking.patch
similarity index 99%
rename from patches/unapplied/server/Optimise-random-block-ticking.patch
rename to patches/server/Optimise-random-block-ticking.patch
index 8a6f9859ce..4be93dc764 100644
--- a/patches/unapplied/server/Optimise-random-block-ticking.patch
+++ b/patches/server/Optimise-random-block-ticking.patch
@@ -389,7 +389,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 -            public int tickingBlockCount;
 -            public int tickingFluidCount;
 -
--            a() {}
+-            a(final LevelChunkSection chunksection) {}
 -
 -            public void accept(BlockState iblockdata, int i) {
 +        // Paper start - unfuck this
@@ -425,13 +425,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +            });
          }
 -
--        a a0 = new a();
+-        a a0 = new a(this);
 -
 -        this.states.count(a0);
 -        this.nonEmptyBlockCount = (short) a0.nonEmptyBlockCount;
 -        this.tickingBlockCount = (short) a0.tickingBlockCount;
 -        this.tickingFluidCount = (short) a0.tickingFluidCount;
-+        // Paper end
++        // Paper end - unfuck this
      }
  
      public PalettedContainer<BlockState> getStates() {
diff --git a/patches/unapplied/server/Optimize-Bit-Operations-by-inlining.patch b/patches/server/Optimize-Bit-Operations-by-inlining.patch
similarity index 99%
rename from patches/unapplied/server/Optimize-Bit-Operations-by-inlining.patch
rename to patches/server/Optimize-Bit-Operations-by-inlining.patch
index f1e502a1c2..9e77b0a62c 100644
--- a/patches/unapplied/server/Optimize-Bit-Operations-by-inlining.patch
+++ b/patches/server/Optimize-Bit-Operations-by-inlining.patch
@@ -11,7 +11,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/main/java/net/minecraft/core/BlockPos.java
 +++ b/src/main/java/net/minecraft/core/BlockPos.java
 @@ -0,0 +0,0 @@ public class BlockPos extends Vec3i {
-         .stable();
+     };
      private static final Logger LOGGER = LogUtils.getLogger();
      public static final BlockPos ZERO = new BlockPos(0, 0, 0);
 -    private static final int PACKED_X_LENGTH = 1 + Mth.log2(Mth.smallestEncompassingPowerOfTwo(30000000));
diff --git a/patches/unapplied/server/Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch b/patches/server/Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch
similarity index 96%
rename from patches/unapplied/server/Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch
rename to patches/server/Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch
index 91b5b9344b..e0d4f9a991 100644
--- a/patches/unapplied/server/Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch
+++ b/patches/server/Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch
@@ -24,11 +24,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
              return null;
          } else {
 -            Map<Target, BlockPos> map = positions.stream()
--                .collect(Collectors.toMap(pos -> this.nodeEvaluator.getGoal((double)pos.getX(), (double)pos.getY(), (double)pos.getZ()), Function.identity()));
+-                .collect(Collectors.toMap(pos -> this.nodeEvaluator.getTarget((double)pos.getX(), (double)pos.getY(), (double)pos.getZ()), Function.identity()));
 +            // Paper start - Perf: remove streams and optimize collection
 +            List<Map.Entry<Target, BlockPos>> map = Lists.newArrayList();
-+            for (BlockPos pos : positions) {
-+                map.add(new java.util.AbstractMap.SimpleEntry<>(this.nodeEvaluator.getGoal(pos.getX(), pos.getY(), pos.getZ()), pos));
++            for (final BlockPos pos : positions) {
++                map.add(new java.util.AbstractMap.SimpleEntry<>(this.nodeEvaluator.getTarget(pos.getX(), pos.getY(), pos.getZ()), pos));
 +            }
 +            // Paper end - Perf: remove streams and optimize collection
              Path path = this.findPath(world.getProfiler(), node, map, followRange, distance, rangeMultiplier);
diff --git a/patches/unapplied/server/Optimize-Voxel-Shape-Merging.patch b/patches/server/Optimize-Voxel-Shape-Merging.patch
similarity index 100%
rename from patches/unapplied/server/Optimize-Voxel-Shape-Merging.patch
rename to patches/server/Optimize-Voxel-Shape-Merging.patch
diff --git a/patches/unapplied/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch b/patches/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch
similarity index 96%
rename from patches/unapplied/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch
rename to patches/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch
index 1ec6f838b0..8bb502418a 100644
--- a/patches/unapplied/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch
+++ b/patches/server/Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch
@@ -69,7 +69,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +++ b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
 @@ -0,0 +0,0 @@ public class PistonBaseBlock extends DirectionalBlock {
      @Override
-     public boolean triggerEvent(BlockState state, Level world, BlockPos pos, int type, int data) {
+     protected boolean triggerEvent(BlockState state, Level world, BlockPos pos, int type, int data) {
          Direction enumdirection = (Direction) state.getValue(PistonBaseBlock.FACING);
 +        // Paper start - Protect Bedrock and End Portal/Frames from being destroyed; prevent retracting when we're facing the wrong way (we were replaced before retraction could occur)
 +        Direction directionQueuedAs = Direction.from3DDataValue(data & 7); // Paper - copied from below
@@ -110,23 +110,23 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
 +++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
 @@ -0,0 +0,0 @@ public abstract class BlockBehaviour implements FeatureElement {
-     /** @deprecated */
-     @Deprecated
-     public void onExplosionHit(BlockState state, Level world, BlockPos pos, Explosion explosion, BiConsumer<ItemStack, BlockPos> stackMerger) {
+     }
+ 
+     protected void onExplosionHit(BlockState state, Level world, BlockPos pos, Explosion explosion, BiConsumer<ItemStack, BlockPos> stackMerger) {
 -        if (!state.isAir() && explosion.getBlockInteraction() != Explosion.BlockInteraction.TRIGGER_BLOCK) {
 +        if (!state.isAir() && explosion.getBlockInteraction() != Explosion.BlockInteraction.TRIGGER_BLOCK && state.isDestroyable()) { // Paper - Protect Bedrock and End Portal/Frames from being destroyed
              Block block = state.getBlock();
              boolean flag = explosion.getIndirectSourceEntity() instanceof Player;
  
 @@ -0,0 +0,0 @@ public abstract class BlockBehaviour implements FeatureElement {
-     /** @deprecated */
-     @Deprecated
-     public boolean canBeReplaced(BlockState state, BlockPlaceContext context) {
+     }
+ 
+     protected boolean canBeReplaced(BlockState state, BlockPlaceContext context) {
 -        return state.canBeReplaced() && (context.getItemInHand().isEmpty() || !context.getItemInHand().is(this.asItem()));
 +        return state.canBeReplaced() && (context.getItemInHand().isEmpty() || !context.getItemInHand().is(this.asItem())) && (state.isDestroyable() || (context.getPlayer() != null && context.getPlayer().getAbilities().instabuild)); // Paper - Protect Bedrock and End Portal/Frames from being destroyed
      }
  
-     /** @deprecated */
+     protected boolean canBeReplaced(BlockState state, Fluid fluid) {
 @@ -0,0 +0,0 @@ public abstract class BlockBehaviour implements FeatureElement {
              return this.legacySolid;
          }
diff --git a/patches/unapplied/server/Remove-streams-from-hot-code.patch b/patches/server/Remove-streams-from-hot-code.patch
similarity index 100%
rename from patches/unapplied/server/Remove-streams-from-hot-code.patch
rename to patches/server/Remove-streams-from-hot-code.patch
diff --git a/patches/unapplied/server/Use-distance-map-to-optimise-entity-tracker.patch b/patches/server/Use-distance-map-to-optimise-entity-tracker.patch
similarity index 98%
rename from patches/unapplied/server/Use-distance-map-to-optimise-entity-tracker.patch
rename to patches/server/Use-distance-map-to-optimise-entity-tracker.patch
index 51b3f5f6be..ac9eea090a 100644
--- a/patches/unapplied/server/Use-distance-map-to-optimise-entity-tracker.patch
+++ b/patches/server/Use-distance-map-to-optimise-entity-tracker.patch
@@ -239,7 +239,7 @@ diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/jav
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/world/entity/Entity.java
 +++ b/src/main/java/net/minecraft/world/entity/Entity.java
-@@ -0,0 +0,0 @@ import net.minecraft.network.syncher.EntityDataSerializers;
+@@ -0,0 +0,0 @@ import net.minecraft.network.syncher.SyncedDataHolder;
  import net.minecraft.network.syncher.SynchedEntityData;
  import net.minecraft.resources.ResourceKey;
  import net.minecraft.resources.ResourceLocation;
@@ -247,7 +247,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  import net.minecraft.server.MinecraftServer;
  import net.minecraft.server.level.ServerLevel;
  import net.minecraft.server.level.ServerPlayer;
-@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S
+@@ -0,0 +0,0 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
          this.teleportTo(worldserver, null);
      }
      // Paper end - make end portalling safe
diff --git a/patches/unapplied/server/Write-SavedData-IO-async.patch b/patches/server/Write-SavedData-IO-async.patch
similarity index 74%
rename from patches/unapplied/server/Write-SavedData-IO-async.patch
rename to patches/server/Write-SavedData-IO-async.patch
index 3bd690831d..cde49336c4 100644
--- a/patches/unapplied/server/Write-SavedData-IO-async.patch
+++ b/patches/server/Write-SavedData-IO-async.patch
@@ -5,26 +5,6 @@ Subject: [PATCH] Write SavedData IO async
 
 Co-Authored-By: Shane Freeder <theboyetronic@gmail.com>
 
-diff --git a/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java b/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java
-+++ b/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java
-@@ -0,0 +0,0 @@ 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -85,20 +65,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
 +++ b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
 @@ -0,0 +0,0 @@ public class WorldUpgrader {
-                 }
-             }
- 
--            this.overworldDataStorage.save();
-+            // Paper start - Write SavedData IO async
-+            try {
-+                this.overworldDataStorage.close();
-+            } catch (IOException exception) {
-+                LOGGER.error("Failed to close persistent world data", exception);
-+            }
-+            // Paper end - Write SavedData IO async
-             i = Util.getMillis() - i;
-             WorldUpgrader.LOGGER.info("World optimizaton finished after {} ms", i);
-             this.finished = true;
+         (new WorldUpgrader.PoiUpgrader(this)).upgrade();
+         WorldUpgrader.LOGGER.info("Upgrading blocks");
+         (new WorldUpgrader.ChunkUpgrader()).upgrade();
+-        this.overworldDataStorage.save();
++        // Paper start - Write SavedData IO async
++        try {
++            this.overworldDataStorage.close();
++        } catch (final IOException e) {
++            LOGGER.error("Failed to close persistent world data", e);
++        }
++        // Paper end - Write SavedData IO async
+         i = Util.getMillis() - i;
+         WorldUpgrader.LOGGER.info("World optimizaton finished after {} seconds", i / 1000L);
+         this.finished = true;
 diff --git a/src/main/java/net/minecraft/world/level/saveddata/SavedData.java b/src/main/java/net/minecraft/world/level/saveddata/SavedData.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/world/level/saveddata/SavedData.java
@@ -107,22 +87,24 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
          return this.dirty;
      }
  
-+    @io.papermc.paper.annotation.DoNotUse // Paper - Write SavedData IO async - This is dead
-     public void save(File file) {
-+        save(file, null).join(); // Paper - Write SavedData IO async - joining is evil, but we assume the old blocking behavior here just for safety
++    // Paper start - Write SavedData IO async - joining is evil, but we assume the old blocking behavior here just for safety
++    @io.papermc.paper.annotation.DoNotUse
+     public void save(File file, HolderLookup.Provider registryLookup) {
++        save(file, registryLookup, null).join();
 +    }
 +
-+    public java.util.concurrent.CompletableFuture<Void> save(File file, @org.jetbrains.annotations.Nullable java.util.concurrent.ExecutorService ioExecutor) { // Paper - Write SavedData IO async
++    public java.util.concurrent.CompletableFuture<Void> save(File file, HolderLookup.Provider registryLookup, @org.jetbrains.annotations.Nullable java.util.concurrent.ExecutorService ioExecutor) {
++        // Paper end - Write SavedData IO async
          if (this.isDirty()) {
              CompoundTag compoundTag = new CompoundTag();
-             compoundTag.put("data", this.save(new CompoundTag()));
+             compoundTag.put("data", this.save(new CompoundTag(), registryLookup));
              NbtUtils.addCurrentDataVersion(compoundTag);
  
 +            Runnable writeRunnable = () -> { // Paper - Write SavedData IO async
              try {
                  NbtIo.writeCompressed(compoundTag, file.toPath());
-             } catch (IOException var4) {
-                 LOGGER.error("Could not save data {}", this, var4);
+             } catch (IOException var5) {
+                 LOGGER.error("Could not save data {}", this, var5);
              }
 +            }; // Paper - Write SavedData IO async
  
@@ -137,7 +119,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        // Paper end - Write SavedData IO async
      }
  
-     public static record Factory<T extends SavedData>(Supplier<T> constructor, Function<CompoundTag, T> deserializer, DataFixTypes type) {
+     public static record Factory<T extends SavedData>(
 diff --git a/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java b/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java
@@ -151,14 +133,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      private static final Logger LOGGER = LogUtils.getLogger();
      public final Map<String, SavedData> cache = Maps.newHashMap();
      private final DataFixer fixerUpper;
+     private final HolderLookup.Provider registries;
      private final File dataFolder;
 +    protected final java.util.concurrent.ExecutorService ioExecutor; // Paper - Write SavedData IO async
  
-     public DimensionDataStorage(File directory, DataFixer dataFixer) {
+     public DimensionDataStorage(File directory, DataFixer dataFixer, HolderLookup.Provider registryLookup) {
          this.fixerUpper = dataFixer;
          this.dataFolder = directory;
-+        String worldFolder = dataFolder.getParent(); // Paper - Write SavedData IO async
-+        this.ioExecutor = java.util.concurrent.Executors.newSingleThreadExecutor(new com.google.common.util.concurrent.ThreadFactoryBuilder().setNameFormat("DimensionDataIO - " + worldFolder + " - %d").setDaemon(true).build()); // Paper - Write SavedData IO async
+         this.registries = registryLookup;
++        this.ioExecutor = java.util.concurrent.Executors.newSingleThreadExecutor(new com.google.common.util.concurrent.ThreadFactoryBuilder().setNameFormat("DimensionDataIO - " + dataFolder.getParent() + " - %d").setDaemon(true).build()); // Paper - Write SavedData IO async
      }
  
      private File getDataFile(String id) {
@@ -178,9 +161,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    public void save(boolean async) { // Paper - Write SavedData IO async
          this.cache.forEach((id, state) -> {
              if (state != null) {
--                state.save(this.getDataFile(id));
+-                state.save(this.getDataFile(id), this.registries);
 +                // Paper start - Write SavedData IO async
-+                final java.util.concurrent.CompletableFuture<Void> save = state.save(this.getDataFile(id), ioExecutor);
++                final java.util.concurrent.CompletableFuture<Void> save = state.save(this.getDataFile(id), this.registries, this.ioExecutor);
 +                if (!async) {
 +                    save.join();
 +                }