diff --git a/patches/api-unmapped/Add-BlockSoundGroup-interface.patch b/patches/api/Add-BlockSoundGroup-interface.patch
similarity index 100%
rename from patches/api-unmapped/Add-BlockSoundGroup-interface.patch
rename to patches/api/Add-BlockSoundGroup-interface.patch
diff --git a/patches/api-unmapped/Amend-PlayerInteractAtEntityEvent-javadoc-for-ArmorS.patch b/patches/api/Amend-PlayerInteractAtEntityEvent-javadoc-for-ArmorS.patch
similarity index 100%
rename from patches/api-unmapped/Amend-PlayerInteractAtEntityEvent-javadoc-for-ArmorS.patch
rename to patches/api/Amend-PlayerInteractAtEntityEvent-javadoc-for-ArmorS.patch
diff --git a/patches/api-unmapped/Increase-custom-payload-channel-message-size.patch b/patches/api/Increase-custom-payload-channel-message-size.patch
similarity index 100%
rename from patches/api-unmapped/Increase-custom-payload-channel-message-size.patch
rename to patches/api/Increase-custom-payload-channel-message-size.patch
diff --git a/patches/server-remapped/Catch-exceptions-from-dispenser-entity-spawns.patch b/patches/server-remapped/Catch-exceptions-from-dispenser-entity-spawns.patch
deleted file mode 100644
index e84386e511..0000000000
--- a/patches/server-remapped/Catch-exceptions-from-dispenser-entity-spawns.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Shane Freeder <theboyetronic@gmail.com>
-Date: Mon, 10 Jun 2019 09:36:40 +0100
-Subject: [PATCH] Catch exceptions from dispenser entity spawns
-
-
-diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
-+++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
-@@ -0,0 +0,0 @@ import net.minecraft.core.BlockPos;
- import net.minecraft.core.BlockSource;
- import net.minecraft.core.Direction;
- import net.minecraft.core.Position;
-+import net.minecraft.server.MinecraftServer;
- import net.minecraft.server.level.ServerLevel;
- import net.minecraft.server.level.ServerPlayer;
- import net.minecraft.sounds.SoundEvents;
-@@ -0,0 +0,0 @@ public interface DispenseItemBehavior {
-                     }
-                 }
- 
-+                try { // Paper
-                 entitytypes.spawn(pointer.getLevel(), stack, (Player) null, pointer.getPos().relative(enumdirection), MobSpawnType.DISPENSER, enumdirection != Direction.UP, false);
-+                    // Paper start
-+                } catch (Exception ex){
-+                    MinecraftServer.LOGGER.warn("An exception occurred dispensing entity at {}[{}]", worldserver.getWorld().getName(), pointer.getPos(), ex);
-+                }
-+                // Paper end
-+
-                 // itemstack.subtract(1); // Handled during event processing
-                 // CraftBukkit end
-                 return stack;
diff --git a/patches/server-remapped/Chunk-debug-command.patch b/patches/server/Chunk-debug-command.patch
similarity index 96%
rename from patches/server-remapped/Chunk-debug-command.patch
rename to patches/server/Chunk-debug-command.patch
index 1b8577d975..e18b2272ef 100644
--- a/patches/server-remapped/Chunk-debug-command.patch
+++ b/patches/server/Chunk-debug-command.patch
@@ -256,10 +256,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  import java.util.concurrent.ExecutionException;
  import java.util.concurrent.LinkedBlockingQueue;
 @@ -0,0 +0,0 @@ public final class MCUtil {
- 
          return null;
      }
-+
+ 
 +    public static ChunkStatus getChunkStatus(ChunkHolder chunk) {
 +        List<ChunkStatus> statuses = ServerChunkCache.getPossibleChunkStatuses();
 +        for (int i = statuses.size() - 1; i >= 0; --i) {
@@ -425,20 +424,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +            out.print(fileData);
 +        }
 +    }
- }
-diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
-+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
-@@ -0,0 +0,0 @@ public class ChunkHolder {
-     public int oldTicketLevel;
-     private int ticketLevel;
-     private int queueLevel;
--    private final ChunkPos pos;
-+    final ChunkPos pos; // Paper - private -> package
-     private boolean hasChangedSections;
-     private final ShortSet[] changedBlocksPerSection;
-     private int blockChangedLightSectionFilter;
++
+     public static int getTicketLevelFor(net.minecraft.world.level.chunk.ChunkStatus status) {
+         return net.minecraft.server.level.ChunkMap.MAX_VIEW_DISTANCE + net.minecraft.world.level.chunk.ChunkStatus.getDistance(status);
+     }
 diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -464,13 +453,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    private static final List<ChunkStatus> CHUNK_STATUSES = ChunkStatus.getStatusList(); public static final List<ChunkStatus> getPossibleChunkStatuses() { return ServerChunkCache.CHUNK_STATUSES; } // Paper - OBFHELPER
      private final DistanceManager distanceManager;
      public final ChunkGenerator generator;
-     private final ServerLevel level;
+     final ServerLevel level;
 diff --git a/src/main/java/net/minecraft/server/level/Ticket.java b/src/main/java/net/minecraft/server/level/Ticket.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/server/level/Ticket.java
 +++ b/src/main/java/net/minecraft/server/level/Ticket.java
-@@ -0,0 +0,0 @@ public final class Ticket<T> implements Comparable<Ticket<?>> {
- 
+@@ -0,0 +0,0 @@ import java.util.Objects;
+ public final class Ticket<T> implements Comparable<Ticket<?>> {
      private final TicketType<T> type;
      private final int ticketLevel;
 -    public final T key;
diff --git a/patches/server-remapped/ChunkMapDistance-CME.patch b/patches/server/ChunkMapDistance-CME.patch
similarity index 63%
rename from patches/server-remapped/ChunkMapDistance-CME.patch
rename to patches/server/ChunkMapDistance-CME.patch
index 0ae1ffaf11..8e14449633 100644
--- a/patches/server-remapped/ChunkMapDistance-CME.patch
+++ b/patches/server/ChunkMapDistance-CME.patch
@@ -9,13 +9,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
 +++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
 @@ -0,0 +0,0 @@ public class ChunkHolder {
-     private static final CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>> UNLOADED_LEVEL_CHUNK_FUTURE = CompletableFuture.completedFuture(ChunkHolder.UNLOADED_LEVEL_CHUNK);
-     private static final List<ChunkStatus> CHUNK_STATUSES = ChunkStatus.getStatusList();
-     private static final ChunkHolder.FullChunkStatus[] FULL_CHUNK_STATUSES = ChunkHolder.FullChunkStatus.values();
+     private boolean resendLight;
+     private CompletableFuture<Void> pendingFullStateConfirmation;
+ 
 +    boolean isUpdateQueued = false; // Paper
-     private final AtomicReferenceArray<CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>> futures;
-     private volatile CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>> fullChunkFuture; private int fullChunkCreateCount; private volatile boolean isFullChunkReady; // Paper - cache chunk ticking stage
-     private volatile CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>> tickingChunkFuture; private volatile boolean isTickingReady; // Paper - cache chunk ticking stage
+     private final ChunkMap chunkMap; // Paper
+ 
+     public ChunkHolder(ChunkPos pos, int level, LevelHeightAccessor world, LevelLightEngine lightingProvider, ChunkHolder.LevelChangeListener levelUpdateListener, ChunkHolder.PlayerProvider playersWatchingChunkProvider) {
 diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/server/level/DistanceManager.java
@@ -24,7 +24,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      private final DistanceManager.ChunkTicketTracker ticketTracker = new DistanceManager.ChunkTicketTracker();
      private final DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter = new DistanceManager.FixedPlayerDistanceChunkTracker(8);
      private final DistanceManager.PlayerTicketTracker playerTicketManager = new DistanceManager.PlayerTicketTracker(33);
--    private final Set<ChunkHolder> chunksToUpdateFutures = Sets.newHashSet();
+-    final Set<ChunkHolder> chunksToUpdateFutures = Sets.newHashSet();
 +    // Paper start use a queue, but still keep unique requirement
 +    public final java.util.Queue<ChunkHolder> pendingChunkUpdates = new java.util.ArrayDeque<ChunkHolder>() {
 +        @Override
@@ -35,9 +35,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        }
 +    };
 +    // Paper end
-     private final ChunkTaskPriorityQueueSorter ticketThrottler;
-     private final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> ticketThrottlerInput;
-     private final ProcessorHandle<ChunkTaskPriorityQueueSorter.Release> ticketThrottlerReleaser;
+     final ChunkTaskPriorityQueueSorter ticketThrottler;
+     final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> ticketThrottlerInput;
+     final ProcessorHandle<ChunkTaskPriorityQueueSorter.Release> ticketThrottlerReleaser;
 @@ -0,0 +0,0 @@ public abstract class DistanceManager {
              ;
          }
@@ -52,7 +52,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 -                iter.remove();
 -                expectedSize--;
 -
--                playerchunk.updateFutures(chunkStorage);
+-                playerchunk.updateFutures(playerchunkmap, this.mainThreadExecutor);
 -
 -                // Reset iterator if set was modified using add()
 -                if (this.chunksToUpdateFutures.size() != expectedSize) {
@@ -67,7 +67,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +            while(!this.pendingChunkUpdates.isEmpty()) {
 +                ChunkHolder remove = this.pendingChunkUpdates.remove();
 +                remove.isUpdateQueued = false;
-+                remove.updateFutures(chunkStorage);
++                remove.updateFutures(playerchunkmap, this.mainThreadExecutor);
 +            }
 +            // Paper end
              return true;
@@ -82,12 +82,3 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
                  }
  
              }
-@@ -0,0 +0,0 @@ public abstract class DistanceManager {
-             ObjectIterator objectiterator = this.chunks.long2ByteEntrySet().iterator();
- 
-             while (objectiterator.hasNext()) {
--                it.unimi.dsi.fastutil.longs.Long2ByteMap.Entry it_unimi_dsi_fastutil_longs_long2bytemap_entry = (it.unimi.dsi.fastutil.longs.Long2ByteMap.Entry) objectiterator.next();
-+                Long2ByteMap.Entry it_unimi_dsi_fastutil_longs_long2bytemap_entry = (Long2ByteMap.Entry) objectiterator.next(); // Paper - decompile fix
-                 byte b0 = it_unimi_dsi_fastutil_longs_long2bytemap_entry.getByteValue();
-                 long j = it_unimi_dsi_fastutil_longs_long2bytemap_entry.getLongKey();
- 
diff --git a/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch b/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch
index 356dea6c76..6ee5c5f094 100644
--- a/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch
+++ b/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch
@@ -174,7 +174,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      public void setDefaultSpawnPos(BlockPos pos, float angle) {
 -        ChunkPos chunkcoordintpair = new ChunkPos(new BlockPos(this.levelData.getXSpawn(), 0, this.levelData.getZSpawn()));
 +        // Paper - configurable spawn radius
-+        BlockPos prevSpawn = this.getSpawn();
++        BlockPos prevSpawn = this.getSharedSpawnPos();
 +        //ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(new BlockPosition(this.worldData.a(), 0, this.worldData.c()));
  
          this.levelData.setSpawn(pos, angle);
diff --git a/patches/server-remapped/Fix-World-isChunkGenerated-calls.patch b/patches/server/Fix-World-isChunkGenerated-calls.patch
similarity index 100%
rename from patches/server-remapped/Fix-World-isChunkGenerated-calls.patch
rename to patches/server/Fix-World-isChunkGenerated-calls.patch
diff --git a/patches/server-remapped/Implement-CraftBlockSoundGroup.patch b/patches/server/Implement-CraftBlockSoundGroup.patch
similarity index 88%
rename from patches/server-remapped/Implement-CraftBlockSoundGroup.patch
rename to patches/server/Implement-CraftBlockSoundGroup.patch
index f23ee03cef..cd8b9c07e2 100644
--- a/patches/server-remapped/Implement-CraftBlockSoundGroup.patch
+++ b/patches/server/Implement-CraftBlockSoundGroup.patch
@@ -53,7 +53,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/main/java/net/minecraft/world/level/block/SoundType.java
 +++ b/src/main/java/net/minecraft/world/level/block/SoundType.java
 @@ -0,0 +0,0 @@ public class SoundType {
-     public static final SoundType GILDED_BLACKSTONE = new SoundType(1.0F, 1.0F, SoundEvents.GILDED_BLACKSTONE_BREAK, SoundEvents.GILDED_BLACKSTONE_STEP, SoundEvents.GILDED_BLACKSTONE_PLACE, SoundEvents.GILDED_BLACKSTONE_HIT, SoundEvents.GILDED_BLACKSTONE_FALL);
+     public static final SoundType POLISHED_DEEPSLATE = new SoundType(1.0F, 1.0F, SoundEvents.POLISHED_DEEPSLATE_BREAK, SoundEvents.POLISHED_DEEPSLATE_STEP, SoundEvents.POLISHED_DEEPSLATE_PLACE, SoundEvents.POLISHED_DEEPSLATE_HIT, SoundEvents.POLISHED_DEEPSLATE_FALL);
      public final float volume;
      public final float pitch;
 -    public final SoundEvent breakSound;
@@ -71,7 +71,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
 @@ -0,0 +0,0 @@ public class CraftBlock implements Block {
          AABB aabb = shape.bounds();
-         return new BoundingBox(getX() + aabb.minX, getY() + aabb.minY, getZ() + aabb.minZ, getX() + aabb.maxX, getY() + aabb.maxY, getZ() + aabb.maxZ);
+         return new BoundingBox(this.getX() + aabb.minX, this.getY() + aabb.minY, this.getZ() + aabb.minZ, this.getX() + aabb.maxX, this.getY() + aabb.maxY, this.getZ() + aabb.maxZ);
      }
 +
 +    // Paper start