diff --git a/patches/unapplied/api/Add-Mob-Goal-API.patch b/patches/api/Add-Mob-Goal-API.patch
similarity index 99%
rename from patches/unapplied/api/Add-Mob-Goal-API.patch
rename to patches/api/Add-Mob-Goal-API.patch
index 7340680210..9655a7612a 100644
--- a/patches/unapplied/api/Add-Mob-Goal-API.patch
+++ b/patches/api/Add-Mob-Goal-API.patch
@@ -428,6 +428,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    GoalKey<Raider> OBTAIN_RAID_LEADER_BANNER = GoalKey.of(Raider.class, NamespacedKey.minecraft("obtain_raid_leader_banner"));
 +    GoalKey<Raider> RAIDER_CELEBRATION = GoalKey.of(Raider.class, NamespacedKey.minecraft("raider_celebration"));
 +    GoalKey<Raider> RAIDER_MOVE_THROUGH_VILLAGE = GoalKey.of(Raider.class, NamespacedKey.minecraft("raider_move_through_village"));
++    GoalKey<Creature> PARROT_WANDER = GoalKey.of(Creature.class, NamespacedKey.minecraft("parrot_wander"));
 +
 +    /**
 +     * @deprecated removed in 1.16
diff --git a/patches/unapplied/api/Add-PlayerAttackEntityCooldownResetEvent.patch b/patches/api/Add-PlayerAttackEntityCooldownResetEvent.patch
similarity index 100%
rename from patches/unapplied/api/Add-PlayerAttackEntityCooldownResetEvent.patch
rename to patches/api/Add-PlayerAttackEntityCooldownResetEvent.patch
diff --git a/patches/unapplied/api/Add-item-slot-convenience-methods.patch b/patches/api/Add-item-slot-convenience-methods.patch
similarity index 100%
rename from patches/unapplied/api/Add-item-slot-convenience-methods.patch
rename to patches/api/Add-item-slot-convenience-methods.patch
diff --git a/patches/unapplied/api/Add-villager-reputation-API.patch b/patches/api/Add-villager-reputation-API.patch
similarity index 100%
rename from patches/unapplied/api/Add-villager-reputation-API.patch
rename to patches/api/Add-villager-reputation-API.patch
diff --git a/patches/unapplied/api/Expose-game-version.patch b/patches/api/Expose-game-version.patch
similarity index 100%
rename from patches/unapplied/api/Expose-game-version.patch
rename to patches/api/Expose-game-version.patch
diff --git a/patches/unapplied/api/Fix-Potion-toItemStack-swapping-the-extended-and-upg.patch b/patches/api/Fix-Potion-toItemStack-swapping-the-extended-and-upg.patch
similarity index 100%
rename from patches/unapplied/api/Fix-Potion-toItemStack-swapping-the-extended-and-upg.patch
rename to patches/api/Fix-Potion-toItemStack-swapping-the-extended-and-upg.patch
diff --git a/patches/unapplied/api/Potential-bed-API.patch b/patches/api/Potential-bed-API.patch
similarity index 100%
rename from patches/unapplied/api/Potential-bed-API.patch
rename to patches/api/Potential-bed-API.patch
diff --git a/patches/unapplied/api/Spawn-Reason-API.patch b/patches/api/Spawn-Reason-API.patch
similarity index 100%
rename from patches/unapplied/api/Spawn-Reason-API.patch
rename to patches/api/Spawn-Reason-API.patch
diff --git a/patches/unapplied/api/Villager-Restocks-API.patch b/patches/api/Villager-Restocks-API.patch
similarity index 100%
rename from patches/unapplied/api/Villager-Restocks-API.patch
rename to patches/api/Villager-Restocks-API.patch
diff --git a/patches/unapplied/server/Add-PlayerAttackEntityCooldownResetEvent.patch b/patches/server/Add-PlayerAttackEntityCooldownResetEvent.patch
similarity index 100%
rename from patches/unapplied/server/Add-PlayerAttackEntityCooldownResetEvent.patch
rename to patches/server/Add-PlayerAttackEntityCooldownResetEvent.patch
diff --git a/patches/unapplied/server/Add-option-for-console-having-all-permissions.patch b/patches/server/Add-option-for-console-having-all-permissions.patch
similarity index 100%
rename from patches/unapplied/server/Add-option-for-console-having-all-permissions.patch
rename to patches/server/Add-option-for-console-having-all-permissions.patch
diff --git a/patches/unapplied/server/Add-phantom-creative-and-insomniac-controls.patch b/patches/server/Add-phantom-creative-and-insomniac-controls.patch
similarity index 85%
rename from patches/unapplied/server/Add-phantom-creative-and-insomniac-controls.patch
rename to patches/server/Add-phantom-creative-and-insomniac-controls.patch
index 5a435e25ac..1be89534c3 100644
--- a/patches/unapplied/server/Add-phantom-creative-and-insomniac-controls.patch
+++ b/patches/server/Add-phantom-creative-and-insomniac-controls.patch
@@ -9,27 +9,25 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
 +++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
 @@ -0,0 +0,0 @@ public class PaperWorldConfig {
-         lightQueueSize = getInt("light-queue-size", lightQueueSize);
+         }
+         perPlayerMobSpawns = getBoolean("per-player-mob-spawns", true);
      }
- 
++
 +    public boolean phantomIgnoreCreative = true;
 +    public boolean phantomOnlyAttackInsomniacs = true;
 +    private void phantomSettings() {
 +        phantomIgnoreCreative = getBoolean("phantoms-do-not-spawn-on-creative-players", phantomIgnoreCreative);
 +        phantomOnlyAttackInsomniacs = getBoolean("phantoms-only-attack-insomniacs", phantomOnlyAttackInsomniacs);
 +    }
-+
-     public int noTickViewDistance;
-     private void viewDistance() {
-         this.noTickViewDistance = this.getInt("viewdistances.no-tick-view-distance", -1);
+ }
 diff --git a/src/main/java/net/minecraft/world/entity/EntitySelector.java b/src/main/java/net/minecraft/world/entity/EntitySelector.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/world/entity/EntitySelector.java
 +++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java
 @@ -0,0 +0,0 @@ public final class EntitySelector {
-     public static final Predicate<Entity> NO_SPECTATORS = (entity) -> {
          return !entity.isSpectator();
      };
+     public static final Predicate<Entity> CAN_BE_COLLIDED_WITH = EntitySelector.NO_SPECTATORS.and(Entity::canBeCollidedWith);
 +    public static Predicate<Player> isInsomniac = (player) -> net.minecraft.util.Mth.clamp(((net.minecraft.server.level.ServerPlayer) player).getStats().getValue(net.minecraft.stats.Stats.CUSTOM.get(net.minecraft.stats.Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE) >= 72000; // Paper
  
      private EntitySelector() {}
@@ -41,9 +39,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 @@ -0,0 +0,0 @@ public class Phantom extends FlyingMob implements Enemy {
                          Player entityhuman = (Player) iterator.next();
  
-                         if (Phantom.this.canAttack((LivingEntity) entityhuman, TargetingConditions.DEFAULT)) {
+                         if (Phantom.this.canAttack(entityhuman, TargetingConditions.DEFAULT)) {
 +                            if (!level.paperConfig.phantomOnlyAttackInsomniacs || EntitySelector.isInsomniac.test(entityhuman)) // Paper
-                             Phantom.this.setGoalTarget(entityhuman, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER, true); // CraftBukkit - reason
+                             Phantom.this.setTarget(entityhuman, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER, true); // CraftBukkit - reason
                              return true;
                          }
 diff --git a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java
diff --git a/patches/unapplied/server/Add-villager-reputation-API.patch b/patches/server/Add-villager-reputation-API.patch
similarity index 100%
rename from patches/unapplied/server/Add-villager-reputation-API.patch
rename to patches/server/Add-villager-reputation-API.patch
diff --git a/patches/unapplied/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch b/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch
similarity index 98%
rename from patches/unapplied/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch
rename to patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch
index 8233943c11..eae524289c 100644
--- a/patches/unapplied/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch
+++ b/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch
@@ -32,8 +32,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  
  dependencies {
 @@ -0,0 +0,0 @@ dependencies {
- 
-     implementation("io.netty:netty-all:4.1.65.Final") // Paper
+     runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.7.0")
+     runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.7.0")
  
 +    implementation("net.fabricmc:mapping-io:0.3.0") // Paper - needed to read mappings for stacktrace deobfuscation
 +
@@ -41,13 +41,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      testImplementation("org.hamcrest:hamcrest-library:1.3")
  }
 @@ -0,0 +0,0 @@ relocation {
+     relocate("org.bukkit.craftbukkit" to "org.bukkit.craftbukkit.v$packageVersion") {
+         exclude("org.bukkit.craftbukkit.Main*")
+     }
++    relocate("net.fabricmc.mapping-io" to "io.papermc.dependency.mappingio") // Paper
+ }
  
-     relocate("org.jline:jline-terminal-jansi", "org.jline" to cb("jline"))
-     sequenceOf(
-+        "net.fabricmc:mapping-io" to "net.fabricmc.mappingio", // Paper
-         "commons-codec:commons-codec" to "org.apache.commons.codec",
-         "commons-io:commons-io" to "org.apache.commons.io",
-         //"it.unimi.dsi:fastutil" to "it.unimi", // Paper - don't relocate fastutil
+ val generatePom = tasks.named<GenerateMavenPom>("generatePomFileForMavenPublication")
 @@ -0,0 +0,0 @@ tasks.shadowJar {
      transform(ModifiedLog4j2PluginsCacheFileTransformer::class.java)
  }
diff --git a/patches/unapplied/server/Don-t-fire-BlockFade-on-worldgen-threads.patch b/patches/server/Don-t-fire-BlockFade-on-worldgen-threads.patch
similarity index 100%
rename from patches/unapplied/server/Don-t-fire-BlockFade-on-worldgen-threads.patch
rename to patches/server/Don-t-fire-BlockFade-on-worldgen-threads.patch
diff --git a/patches/unapplied/server/Ensure-EntityRaider-respects-game-and-entity-rules-f.patch b/patches/server/Ensure-EntityRaider-respects-game-and-entity-rules-f.patch
similarity index 100%
rename from patches/unapplied/server/Ensure-EntityRaider-respects-game-and-entity-rules-f.patch
rename to patches/server/Ensure-EntityRaider-respects-game-and-entity-rules-f.patch
diff --git a/patches/unapplied/server/Ensure-safe-gateway-teleport.patch b/patches/server/Ensure-safe-gateway-teleport.patch
similarity index 100%
rename from patches/unapplied/server/Ensure-safe-gateway-teleport.patch
rename to patches/server/Ensure-safe-gateway-teleport.patch
diff --git a/patches/unapplied/server/ExperienceOrbMergeEvent.patch b/patches/server/ExperienceOrbMergeEvent.patch
similarity index 100%
rename from patches/unapplied/server/ExperienceOrbMergeEvent.patch
rename to patches/server/ExperienceOrbMergeEvent.patch
diff --git a/patches/unapplied/server/Expose-game-version.patch b/patches/server/Expose-game-version.patch
similarity index 100%
rename from patches/unapplied/server/Expose-game-version.patch
rename to patches/server/Expose-game-version.patch
diff --git a/patches/unapplied/server/Fix-Chunk-Post-Processing-deadlock-risk.patch b/patches/server/Fix-Chunk-Post-Processing-deadlock-risk.patch
similarity index 98%
rename from patches/unapplied/server/Fix-Chunk-Post-Processing-deadlock-risk.patch
rename to patches/server/Fix-Chunk-Post-Processing-deadlock-risk.patch
index 5d0905388f..71cb9cb2c5 100644
--- a/patches/unapplied/server/Fix-Chunk-Post-Processing-deadlock-risk.patch
+++ b/patches/server/Fix-Chunk-Post-Processing-deadlock-risk.patch
@@ -35,7 +35,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +    final CallbackExecutor chunkLoadConversionCallbackExecutor = new CallbackExecutor(); // Paper
      // Paper start - distance maps
      private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets<ServerPlayer> pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>();
-     // Paper start - no-tick view distance
+ 
 @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
                  return Either.left(chunk);
              });
diff --git a/patches/unapplied/server/Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch b/patches/server/Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch
similarity index 96%
rename from patches/unapplied/server/Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch
rename to patches/server/Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch
index 82c1ee921e..07f4670261 100644
--- a/patches/unapplied/server/Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch
+++ b/patches/server/Fix-Longstanding-Broken-behavior-of-PlayerJoinEvent.patch
@@ -57,7 +57,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +++ b/src/main/java/net/minecraft/server/players/PlayerList.java
 @@ -0,0 +0,0 @@ public abstract class PlayerList {
          this.playersByUUID.put(player.getUUID(), player);
-         // this.sendAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, new EntityPlayer[]{entityplayer})); // CraftBukkit - replaced with loop below
+         // this.broadcastAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, new EntityPlayer[]{entityplayer})); // CraftBukkit - replaced with loop below
  
 +        // Paper start - correctly register player BEFORE PlayerJoinEvent, so the entity is valid and doesn't require tick delay hacks
 +        player.supressTrackerForLogin = true;
@@ -69,7 +69,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
          CraftPlayer bukkitPlayer = player.getBukkitEntity();
  
 @@ -0,0 +0,0 @@ public abstract class PlayerList {
-             player.connection.send(new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.ADD_PLAYER, new ServerPlayer[] { entityplayer1}));
+             player.connection.send(new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.ADD_PLAYER, new ServerPlayer[]{entityplayer1}));
          }
          player.sentListPacket = true;
 +        player.supressTrackerForLogin = false; // Paper
diff --git a/patches/unapplied/server/Fix-PotionEffect-ignores-icon-flag.patch b/patches/server/Fix-PotionEffect-ignores-icon-flag.patch
similarity index 100%
rename from patches/unapplied/server/Fix-PotionEffect-ignores-icon-flag.patch
rename to patches/server/Fix-PotionEffect-ignores-icon-flag.patch
diff --git a/patches/unapplied/server/Fix-numerous-item-duplication-issues-and-teleport-is.patch b/patches/server/Fix-numerous-item-duplication-issues-and-teleport-is.patch
similarity index 96%
rename from patches/unapplied/server/Fix-numerous-item-duplication-issues-and-teleport-is.patch
rename to patches/server/Fix-numerous-item-duplication-issues-and-teleport-is.patch
index ec34effcbe..1d9a42b1f9 100644
--- a/patches/unapplied/server/Fix-numerous-item-duplication-issues-and-teleport-is.patch
+++ b/patches/server/Fix-numerous-item-duplication-issues-and-teleport-is.patch
@@ -19,7 +19,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 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i
          } else {
              // CraftBukkit start - Capture drops for death event
              if (this instanceof net.minecraft.world.entity.LivingEntity && !((net.minecraft.world.entity.LivingEntity) this).forceDrops) {
@@ -34,7 +34,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  
              entityitem.setDefaultPickUpDelay();
              // CraftBukkit start
-@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i
      @Nullable
      public Entity teleportTo(ServerLevel worldserver, BlockPos location) {
          // CraftBukkit end
@@ -47,7 +47,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
          if (this.level instanceof ServerLevel && !this.isRemoved()) {
              this.level.getProfiler().push("changeDimension");
              // CraftBukkit start
-@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i
                  // CraftBukkit end
  
                  this.level.getProfiler().popPush("reloading");
@@ -56,10 +56,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +                    ((Mob) this).dropLeash(true, true); // Paper drop lead
 +                }
 +                // Paper end
-                 Entity entity = this.getType().create((Level) worldserver);
+                 Entity entity = this.getType().create(worldserver);
  
                  if (entity != null) {
-@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i
                      // CraftBukkit start - Forward the CraftEntity to the new entity
                      this.getBukkitEntity().setHandle(entity);
                      entity.bukkitEntity = this.getBukkitEntity();
@@ -70,7 +70,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
                      // CraftBukkit end
                  }
  
-@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i
      }
  
      public boolean canChangeDimensions() {
diff --git a/patches/unapplied/server/Fix-villager-trading-demand-MC-163962.patch b/patches/server/Fix-villager-trading-demand-MC-163962.patch
similarity index 100%
rename from patches/unapplied/server/Fix-villager-trading-demand-MC-163962.patch
rename to patches/server/Fix-villager-trading-demand-MC-163962.patch
diff --git a/patches/unapplied/server/Implement-Mob-Goal-API.patch b/patches/server/Implement-Mob-Goal-API.patch
similarity index 99%
rename from patches/unapplied/server/Implement-Mob-Goal-API.patch
rename to patches/server/Implement-Mob-Goal-API.patch
index fd8adab167..0d8e7cef0d 100644
--- a/patches/unapplied/server/Implement-Mob-Goal-API.patch
+++ b/patches/server/Implement-Mob-Goal-API.patch
@@ -739,14 +739,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/main/java/com/destroystokyo/paper/util/set/OptimizedSmallEnumSet.java
 +++ b/src/main/java/com/destroystokyo/paper/util/set/OptimizedSmallEnumSet.java
 @@ -0,0 +0,0 @@ public final class OptimizedSmallEnumSet<E extends Enum<E>> {
-     public boolean hasCommonElements(final OptimizedSmallEnumSet<E> other) {
          return (other.backingSet & this.backingSet) != 0;
      }
-+
+ 
 +    public boolean hasElement(final E element) {
 +        return (this.backingSet & (1L << element.ordinal())) != 0;
 +    }
- }
++
+     public void forEach(final E[] values, final Consumer<E> action) {
+         long iterator = this.getBackingSet();
+         int wrappedGoalSize = this.size();
 diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java b/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java
@@ -778,7 +780,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
      }
  
 @@ -0,0 +0,0 @@ public abstract class Goal {
-         // Paper end - remove streams from pathfindergoalselector
+         return Mth.positiveCeilDiv(serverTicks, 2);
      }
  
 +    // Paper start - mob goal api
diff --git a/patches/unapplied/server/Load-Chunks-for-Login-Asynchronously.patch b/patches/server/Load-Chunks-for-Login-Asynchronously.patch
similarity index 98%
rename from patches/unapplied/server/Load-Chunks-for-Login-Asynchronously.patch
rename to patches/server/Load-Chunks-for-Login-Asynchronously.patch
index 4b5080012a..f7d37fbbac 100644
--- a/patches/unapplied/server/Load-Chunks-for-Login-Asynchronously.patch
+++ b/patches/server/Load-Chunks-for-Login-Asynchronously.patch
@@ -94,7 +94,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +            ServerPlayer entityplayer = this.server.getPlayerList().getActivePlayer(this.gameProfile.getId()); // Paper
  
              try {
-                 ServerPlayer entityplayer1 = this.server.getPlayerList().processLogin(this.gameProfile, s); // CraftBukkit - add player reference
+                 ServerPlayer entityplayer1 = this.server.getPlayerList().getPlayerForLogin(this.gameProfile, s); // CraftBukkit - add player reference
 diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -219,7 +219,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        // Paper end
  
          // CraftBukkit start
-         // this.sendAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, new EntityPlayer[]{entityplayer}));
+         // this.broadcastAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, new EntityPlayer[]{entityplayer}));
 @@ -0,0 +0,0 @@ public abstract class PlayerList {
          this.cserver.getScoreboardManager().removePlayer(entityplayer.getBukkitEntity());
          // CraftBukkit end
diff --git a/patches/unapplied/server/Maps-shouldn-t-load-chunks.patch b/patches/server/Maps-shouldn-t-load-chunks.patch
similarity index 100%
rename from patches/unapplied/server/Maps-shouldn-t-load-chunks.patch
rename to patches/server/Maps-shouldn-t-load-chunks.patch
diff --git a/patches/unapplied/server/Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch b/patches/server/Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch
similarity index 97%
rename from patches/unapplied/server/Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch
rename to patches/server/Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch
index bda4803387..141f340b70 100644
--- a/patches/unapplied/server/Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch
+++ b/patches/server/Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch
@@ -10,7 +10,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 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, i
                      bworld = server.getWorld(worldName);
                  }
  
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/Optimize-brigadier-child-sorting-performance.patch b/patches/server/Optimize-brigadier-child-sorting-performance.patch
similarity index 100%
rename from patches/unapplied/server/Optimize-brigadier-child-sorting-performance.patch
rename to patches/server/Optimize-brigadier-child-sorting-performance.patch
diff --git a/patches/unapplied/server/Option-for-maximum-exp-value-when-merging-orbs.patch b/patches/server/Option-for-maximum-exp-value-when-merging-orbs.patch
similarity index 93%
rename from patches/unapplied/server/Option-for-maximum-exp-value-when-merging-orbs.patch
rename to patches/server/Option-for-maximum-exp-value-when-merging-orbs.patch
index f7350d4804..5f4f3be4b3 100644
--- a/patches/unapplied/server/Option-for-maximum-exp-value-when-merging-orbs.patch
+++ b/patches/server/Option-for-maximum-exp-value-when-merging-orbs.patch
@@ -9,18 +9,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
 +++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
 @@ -0,0 +0,0 @@ public class PaperWorldConfig {
-         log("Creeper lingering effect: " + disableCreeperLingeringEffect);
+         phantomIgnoreCreative = getBoolean("phantoms-do-not-spawn-on-creative-players", phantomIgnoreCreative);
+         phantomOnlyAttackInsomniacs = getBoolean("phantoms-only-attack-insomniacs", phantomOnlyAttackInsomniacs);
      }
- 
++
 +    public int expMergeMaxValue;
 +    private void expMergeMaxValue() {
 +        expMergeMaxValue = getInt("experience-merge-max-value", -1);
 +        log("Experience Merge Max Value: " + expMergeMaxValue);
 +    }
-+
-     public double squidMaxSpawnHeight;
-     private void squidMaxSpawnHeight() {
-         squidMaxSpawnHeight = getDouble("squid-spawn-height.maximum", 0.0D);
+ }
 diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
diff --git a/patches/unapplied/server/Potential-bed-API.patch b/patches/server/Potential-bed-API.patch
similarity index 100%
rename from patches/unapplied/server/Potential-bed-API.patch
rename to patches/server/Potential-bed-API.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 98%
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 5c9255d8d0..7b8a957a30 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
@@ -176,7 +176,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 @@ -0,0 +0,0 @@ public class PortalForcer {
          for (int j = -1; j < 3; ++j) {
              for (int k = -1; k < 4; ++k) {
-                 temp.setWithOffset((Vec3i) pos, portalDirection.getStepX() * j + enumdirection1.getStepX() * distanceOrthogonalToPortal, k, portalDirection.getStepZ() * j + enumdirection1.getStepZ() * distanceOrthogonalToPortal);
+                 temp.setWithOffset(pos, portalDirection.getStepX() * j + enumdirection1.getStepX() * distanceOrthogonalToPortal, k, portalDirection.getStepZ() * j + enumdirection1.getStepZ() * distanceOrthogonalToPortal);
 +                // Paper start - prevent destroying unbreakable blocks
 +                if (!com.destroystokyo.paper.PaperConfig.allowBlockPermanentBreakingExploits) {
 +                    if (!this.level.getBlockState(temp).isDestroyable()) {
diff --git a/patches/unapplied/server/Reduce-MutableInt-allocations-from-light-engine.patch b/patches/server/Reduce-MutableInt-allocations-from-light-engine.patch
similarity index 100%
rename from patches/unapplied/server/Reduce-MutableInt-allocations-from-light-engine.patch
rename to patches/server/Reduce-MutableInt-allocations-from-light-engine.patch
diff --git a/patches/unapplied/server/Reduce-allocation-of-Vec3D-by-entity-tracker.patch b/patches/server/Reduce-allocation-of-Vec3D-by-entity-tracker.patch
similarity index 80%
rename from patches/unapplied/server/Reduce-allocation-of-Vec3D-by-entity-tracker.patch
rename to patches/server/Reduce-allocation-of-Vec3D-by-entity-tracker.patch
index e8d8a15032..2439ae5328 100644
--- a/patches/unapplied/server/Reduce-allocation-of-Vec3D-by-entity-tracker.patch
+++ b/patches/server/Reduce-allocation-of-Vec3D-by-entity-tracker.patch
@@ -8,23 +8,22 @@ diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/j
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java
 +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
-@@ -0,0 +0,0 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially
+@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
          public void updatePlayer(ServerPlayer player) {
              org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot
              if (player != this.entity) {
 -                Vec3 vec3d = player.position().subtract(this.entity.position()); // MC-155077, SPIGOT-5113
 +                // Paper start - remove allocation of Vec3D here
-+                //Vec3D vec3d = entityplayer.getPositionVector().d(this.tracker.getPositionVector()); // MC-155077, SPIGOT-5113
++                //Vec3 vec3d = player.position().subtract(this.entity.position()); // MC-155077, SPIGOT-5113
 +                double vec3d_dx = player.getX() - this.entity.getX();
-+                double vec3d_dy = player.getY() - this.entity.getY();
 +                double vec3d_dz = player.getZ() - this.entity.getZ();
 +                // Paper end - remove allocation of Vec3D here
-                 int i = Math.min(this.getEffectiveRange(), (ChunkMap.this.viewDistance - 1) * 16);
--                boolean flag = vec3d.x >= (double) (-i) && vec3d.x <= (double) i && vec3d.z >= (double) (-i) && vec3d.z <= (double) i && this.entity.broadcastToPlayer(player);
-+                boolean flag = vec3d_dx >= (double) (-i) && vec3d_dx <= (double) i && vec3d_dz >= (double) (-i) && vec3d_dz <= (double) i && this.entity.broadcastToPlayer(player); // Paper - remove allocation of Vec3D here
+                 double d0 = (double) Math.min(this.getEffectiveRange(), (ChunkMap.this.viewDistance - 1) * 16);
+-                double d1 = vec3d.x * vec3d.x + vec3d.z * vec3d.z;
++                double d1 = vec3d_dx * vec3d_dx + vec3d_dz * vec3d_dz; // Paper
+                 double d2 = d0 * d0;
+                 boolean flag = d1 <= d2 && this.entity.broadcastToPlayer(player);
  
-                 // CraftBukkit start - respect vanish API
-                 if (this.entity instanceof ServerPlayer) {
 diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/server/level/ServerEntity.java
diff --git a/patches/unapplied/server/Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch b/patches/server/Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch
similarity index 100%
rename from patches/unapplied/server/Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch
rename to patches/server/Set-cap-on-JDK-per-thread-native-byte-buffer-cache.patch
diff --git a/patches/unapplied/server/Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch b/patches/server/Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch
similarity index 58%
rename from patches/unapplied/server/Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch
rename to patches/server/Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch
index befe2c79c2..d9d7ad5b52 100644
--- a/patches/unapplied/server/Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch
+++ b/patches/server/Use-seed-based-lookup-for-Treasure-Maps-Fixes-lag-fr.patch
@@ -13,8 +13,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
  
                  for (l = 0; l < 128 * i; ++l) {
                      for (i1 = 0; i1 < 128 * i; ++i1) {
--                        abiomebase[l * 128 * i + i1] = world.getBiome(new BlockPos((j / i - 64) * i + i1, 0, (k / i - 64) * i + l));
-+                        abiomebase[l * 128 * i + i1] = world.getUncachedNoiseBiome((j / i - 64) * i + i1, 0, (k / i - 64) * i + l); // Paper
-                     }
-                 }
+-                        Biome.BiomeCategory biomebase_geography = world.getBiome(new BlockPos((j / i - 64) * i + i1, 0, (k / i - 64) * i + l)).getBiomeCategory();
++                        Biome.BiomeCategory biomebase_geography = world.getUncachedNoiseBiome((j / i - 64) * i + i1, 0, (k / i - 64) * i + l).getBiomeCategory(); // Paper
  
+                         aboolean[l * 128 * i + i1] = biomebase_geography == Biome.BiomeCategory.OCEAN || biomebase_geography == Biome.BiomeCategory.RIVER || biomebase_geography == Biome.BiomeCategory.SWAMP;
+                     }
diff --git a/patches/unapplied/server/Validate-PickItem-Packet-and-kick-for-invalid.patch b/patches/server/Validate-PickItem-Packet-and-kick-for-invalid.patch
similarity index 100%
rename from patches/unapplied/server/Validate-PickItem-Packet-and-kick-for-invalid.patch
rename to patches/server/Validate-PickItem-Packet-and-kick-for-invalid.patch
diff --git a/patches/unapplied/server/Villager-Restocks-API.patch b/patches/server/Villager-Restocks-API.patch
similarity index 100%
rename from patches/unapplied/server/Villager-Restocks-API.patch
rename to patches/server/Villager-Restocks-API.patch
diff --git a/patches/unapplied/server/Wait-for-Async-Tasks-during-shutdown.patch b/patches/server/Wait-for-Async-Tasks-during-shutdown.patch
similarity index 100%
rename from patches/unapplied/server/Wait-for-Async-Tasks-during-shutdown.patch
rename to patches/server/Wait-for-Async-Tasks-during-shutdown.patch
diff --git a/patches/unapplied/server/misc-debugging-dumps.patch b/patches/server/misc-debugging-dumps.patch
similarity index 97%
rename from patches/unapplied/server/misc-debugging-dumps.patch
rename to patches/server/misc-debugging-dumps.patch
index 380b737b89..d8d1bbbf7a 100644
--- a/patches/unapplied/server/misc-debugging-dumps.patch
+++ b/patches/server/misc-debugging-dumps.patch
@@ -62,8 +62,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
 +++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
 @@ -0,0 +0,0 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener
-                 }
              } catch (Exception exception) {
+                 ServerLoginPacketListenerImpl.LOGGER.error("Couldn't place player in world", exception);
                  TranslatableComponent chatmessage = new TranslatableComponent("multiplayer.disconnect.invalid_player_data");
 +                // Paper start
 +                if (MinecraftServer.getServer().isDebugging()) {
diff --git a/patches/unapplied/server/Delay-Chunk-Unloads-based-on-Player-Movement.patch b/patches/unapplied/server/Delay-Chunk-Unloads-based-on-Player-Movement.patch
deleted file mode 100644
index b747b0199c..0000000000
--- a/patches/unapplied/server/Delay-Chunk-Unloads-based-on-Player-Movement.patch
+++ /dev/null
@@ -1,109 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Aikar <aikar@aikar.co>
-Date: Sat, 18 Jun 2016 23:22:12 -0400
-Subject: [PATCH] Delay Chunk Unloads based on Player Movement
-
-When players are moving in the world, doing things such as building or exploring,
-they will commonly go back and forth in a small area. This causes a ton of chunk load
-and unload activity on the edge chunks of their view distance.
-
-A simple back and forth movement in 6 blocks could spam a chunk to thrash a
-loading and unload cycle over and over again.
-
-This is very wasteful. This system introduces a delay of inactivity on a chunk
-before it actually unloads, which will be handled by the ticket expiry process.
-
-This allows servers with smaller worlds who do less long distance exploring to stop
-wasting cpu cycles on saving/unloading/reloading chunks repeatedly.
-
-diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
-+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
-@@ -0,0 +0,0 @@ public class PaperWorldConfig {
-         this.noTickViewDistance = this.getInt("viewdistances.no-tick-view-distance", -1);
-     }
- 
-+    public long delayChunkUnloadsBy;
-+    private void delayChunkUnloadsBy() {
-+        delayChunkUnloadsBy = PaperConfig.getSeconds(getString("delay-chunk-unloads-by", "10s"));
-+        if (delayChunkUnloadsBy > 0) {
-+            log("Delaying chunk unloads by " + delayChunkUnloadsBy + " seconds");
-+            delayChunkUnloadsBy *= 20;
-+        }
-+    }
-+
-     public boolean altItemDespawnRateEnabled;
-     public java.util.Map<org.bukkit.Material, Integer> altItemDespawnRateMap;
-     private void altItemDespawnRate() {
-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
-+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
-@@ -0,0 +0,0 @@ public abstract class DistanceManager {
-         boolean removed = false; // CraftBukkit
-         if (arraysetsorted.remove(ticket)) {
-             removed = true; // CraftBukkit
-+            // Paper start - delay chunk unloads for player tickets
-+            long delayChunkUnloadsBy = chunkMap.level.paperConfig.delayChunkUnloadsBy;
-+            if (ticket.getType() == TicketType.PLAYER && delayChunkUnloadsBy > 0) {
-+                boolean hasPlayer = false;
-+                for (Ticket<?> ticket1 : arraysetsorted) {
-+                    if (ticket1.getType() == TicketType.PLAYER) {
-+                        hasPlayer = true;
-+                        break;
-+                    }
-+                }
-+                ChunkHolder playerChunk = chunkMap.getUpdatingChunkIfPresent(i);
-+                if (!hasPlayer && playerChunk != null && playerChunk.isFullChunkReady()) {
-+                    Ticket<Long> delayUnload = new Ticket<Long>(TicketType.DELAY_UNLOAD, 33, i);
-+                    delayUnload.delayUnloadBy = delayChunkUnloadsBy;
-+                    delayUnload.setCreatedTick(this.ticketTickCounter);
-+                    arraysetsorted.remove(delayUnload);
-+                    // refresh ticket
-+                    arraysetsorted.add(delayUnload);
-+                }
-+            }
-+            // Paper end
-         }
- 
-         if (arraysetsorted.isEmpty()) {
-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<?>> {
-     private final int ticketLevel;
-     public final T key;
-     public long createdTick;
-+    public long delayUnloadBy; // Paper
- 
-     protected Ticket(TicketType<T> type, int level, T argument) {
-         this.type = type;
-         this.ticketLevel = level;
-         this.key = argument;
-+        this.delayUnloadBy = type.timeout; // Paper
-     }
- 
-     @Override
-@@ -0,0 +0,0 @@ public final class Ticket<T> implements Comparable<Ticket<?>> {
-     }
- 
-     protected boolean timedOut(long currentTick) {
--        long l = this.type.timeout();
-+        long l = delayUnloadBy; // Paper
-         return l != 0L && currentTick - this.createdTick > l;
-     }
- }
-diff --git a/src/main/java/net/minecraft/server/level/TicketType.java b/src/main/java/net/minecraft/server/level/TicketType.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/level/TicketType.java
-+++ b/src/main/java/net/minecraft/server/level/TicketType.java
-@@ -0,0 +0,0 @@ public class TicketType<T> {
-     public static final TicketType<ChunkPos> UNKNOWN = TicketType.create("unknown", Comparator.comparingLong(ChunkPos::toLong), 1);
-     public static final TicketType<Unit> PLUGIN = TicketType.create("plugin", (a, b) -> 0); // CraftBukkit
-     public static final TicketType<org.bukkit.plugin.Plugin> PLUGIN_TICKET = TicketType.create("plugin_ticket", (plugin1, plugin2) -> plugin1.getClass().getName().compareTo(plugin2.getClass().getName())); // CraftBukkit
-+    public static final TicketType<Long> DELAY_UNLOAD = create("delay_unload", Long::compareTo, 300); // Paper
- 
-     public static <T> TicketType<T> create(String name, Comparator<T> argumentComparator) {
-         return new TicketType<>(name, argumentComparator, 0L);
diff --git a/patches/unapplied/server/Fix-Non-Full-Status-Chunk-NBT-Memory-Leak.patch b/patches/unapplied/server/Fix-Non-Full-Status-Chunk-NBT-Memory-Leak.patch
deleted file mode 100644
index e4009f1419..0000000000
--- a/patches/unapplied/server/Fix-Non-Full-Status-Chunk-NBT-Memory-Leak.patch
+++ /dev/null
@@ -1,99 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Aikar <aikar@aikar.co>
-Date: Sat, 23 May 2020 01:31:06 -0400
-Subject: [PATCH] Fix Non Full Status Chunk NBT Memory Leak
-
-Any full status chunk that was requested for any status less than full
-would hold onto their entire nbt tree and every variable in that function.
-
-This was due to use of a lambda that persists on the Chunk object
-until that chunk reaches FULL status.
-
-With introduction of no tick, we greatly increased the number of non
-full chunks so this was really starting to hurt.
-
-We further improve it by making a copy of the nbt tag with only the memory
-it needs, so that we dont have to hold a copy to the entire compound.
-
-diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
-+++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java
-@@ -0,0 +0,0 @@ import net.minecraft.nbt.CompoundTag;
- import net.minecraft.nbt.ListTag;
- import net.minecraft.nbt.LongArrayTag;
- import net.minecraft.nbt.ShortTag;
-+import net.minecraft.nbt.Tag;
- import net.minecraft.server.level.ServerChunkCache;
- import net.minecraft.server.level.ServerLevel;
- import net.minecraft.server.level.ThreadedLevelLightEngine;
-@@ -0,0 +0,0 @@ public class ChunkSerializer {
-                 object2 = protochunkticklist1;
-             }
- 
--            object = new LevelChunk(world.getLevel(), pos, biomestorage, chunkconverter, (TickList) object1, (TickList) object2, k, achunksection, (chunk) -> {
--                ChunkSerializer.postLoadChunk(world, nbttagcompound1, chunk);
--                // CraftBukkit start - load chunk persistent data from nbt
--                net.minecraft.nbt.Tag persistentBase = nbttagcompound1.get("ChunkBukkitValues");
--                if (persistentBase instanceof CompoundTag) {
--                    chunk.persistentDataContainer.putAll((CompoundTag) persistentBase);
--                }
--                // CraftBukkit end
--            });
-+            object = new LevelChunk(world.getLevel(), pos, biomestorage, chunkconverter, (TickList) object1, (TickList) object2, k, achunksection, // Paper start - fix massive nbt memory leak due to lambda. move lambda into a container method to not leak scope. Only clone needed NBT keys.
-+                createLoadEntitiesConsumer(new SafeNBTCopy(nbttagcompound1, "TileEntities", "Entities", "ChunkBukkitValues")) // Paper - move CB Chunk PDC into here
-+            );// Paper end
-         } else {
-             ProtoChunk protochunk = new ProtoChunk(pos, chunkconverter, achunksection, protochunkticklist, protochunkticklist1, world, world); // Paper - add level
- 
-@@ -0,0 +0,0 @@ public class ChunkSerializer {
-             return new InProgressChunkHolder(protochunk1, tasksToExecuteOnMain); // Paper - Async chunk loading
-         }
-     }
-+    // Paper start
-+
-+    /**
-+     * This wrapper will error out if any key is accessed that wasn't copied so we can catch it easy on an update
-+     */
-+    private static class SafeNBTCopy extends CompoundTag {
-+        private final java.util.Set<String> keys = new java.util.HashSet<String>();
-+        public SafeNBTCopy(CompoundTag base, String... keys) {
-+            for (String key : keys) {
-+                this.keys.add(key);
-+                final Tag nbtBase = base.get(key);
-+                if (nbtBase != null) {
-+                    this.put(key, nbtBase);
-+                }
-+            }
-+        }
-+
-+        @Override
-+        public boolean contains(String key) {
-+            if (super.contains(key)) {
-+                return true;
-+            } else if (keys.contains(key)) {
-+                return false;
-+            }
-+            throw new IllegalStateException("Missing Key " + key + " in SafeNBTCopy");
-+        }
-+
-+        @Override
-+        public boolean contains(String key, int type) {
-+            return contains(key) && super.contains(key, type);
-+        }
-+    }
-+    private static java.util.function.Consumer<LevelChunk> createLoadEntitiesConsumer(CompoundTag nbt) {
-+        return (chunk) -> {
-+            postLoadChunk(chunk.level, nbt, chunk);
-+            // CraftBukkit start - load chunk persistent data from nbt
-+            Tag persistentBase = nbt.get("ChunkBukkitValues");
-+            if (persistentBase instanceof CompoundTag) {
-+                chunk.persistentDataContainer.putAll((CompoundTag) persistentBase);
-+            }
-+            // CraftBukkit end
-+        };
-+    }
-+    // Paper end
- 
-     // Paper start - async chunk save for unload
-     public static final class AsyncSaveData {
diff --git a/patches/unapplied/server/Optimize-ServerLevels-chunk-level-checking-methods.patch b/patches/unapplied/server/Optimize-ServerLevels-chunk-level-checking-methods.patch
deleted file mode 100644
index ba64bfac46..0000000000
--- a/patches/unapplied/server/Optimize-ServerLevels-chunk-level-checking-methods.patch
+++ /dev/null
@@ -1,64 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Spottedleaf <Spottedleaf@users.noreply.github.com>
-Date: Thu, 16 Apr 2020 16:13:59 -0700
-Subject: [PATCH] Optimize ServerLevels chunk level checking methods
-
-These can be hot functions (i.e entity ticking and block ticking),
-so inline where possible, and avoid the abstraction of the
-Either class.
-
-diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/level/ServerLevel.java
-+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
-@@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel {
-     public boolean isPositionTickingWithEntitiesLoaded(BlockPos blockposition) {
-         long i = ChunkPos.asLong(blockposition);
- 
--        return this.chunkSource.isPositionTicking(i) && this.areEntitiesLoaded(i);
-+        // Paper start - optimize is ticking ready type functions
-+        ChunkHolder chunkHolder = this.chunkSource.chunkMap.getVisibleChunkIfPresent(i);
-+        return chunkHolder != null && chunkHolder.isTickingReady() && this.areEntitiesLoaded(i);
-+        // Paper end
-     }
- 
-     public boolean isPositionEntityTicking(BlockPos blockposition) {
--        return this.entityManager.isPositionTicking(blockposition);
-+        return this.entityManager.isPositionTicking(ChunkPos.asLong(blockposition)); // Paper
-     }
- 
-     public boolean isPositionEntityTicking(ChunkPos chunkcoordintpair) {
--        return this.entityManager.isPositionTicking(chunkcoordintpair);
-+        return this.entityManager.isPositionTicking(chunkcoordintpair.toLong()); // Paper
-     }
- 
-     private final class EntityCallbacks implements LevelCallback<Entity> {
-diff --git a/src/main/java/net/minecraft/world/level/ChunkPos.java b/src/main/java/net/minecraft/world/level/ChunkPos.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/world/level/ChunkPos.java
-+++ b/src/main/java/net/minecraft/world/level/ChunkPos.java
-@@ -0,0 +0,0 @@ public class ChunkPos {
-     }
- 
-     public static long asLong(BlockPos blockPos) {
--        return asLong(SectionPos.blockToSectionCoord(blockPos.getX()), SectionPos.blockToSectionCoord(blockPos.getZ()));
-+        return (((long)blockPos.getX() >> 4) & 4294967295L) | ((((long)blockPos.getZ() >> 4) & 4294967295L) << 32); // Paper - inline
-     }
- 
-     public static int getX(long pos) {
-diff --git a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
-+++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java
-@@ -0,0 +0,0 @@ public class PersistentEntitySectionManager<T extends EntityAccess> implements A
-     public LevelEntityGetter<T> getEntityGetter() {
-         return this.entityGetter;
-     }
-+    // Paper start
-+    public final boolean isPositionTicking(long position) {
-+        return this.chunkVisibility.get(position).isTicking();
-+    }
-+    // Paper end
- 
-     public boolean isPositionTicking(BlockPos blockposition) {
-         return ((Visibility) this.chunkVisibility.get(ChunkPos.asLong(blockposition))).isTicking();
diff --git a/patches/unapplied/server/Optimize-isOutsideRange-to-use-distance-maps.patch b/patches/unapplied/server/Optimize-isOutsideRange-to-use-distance-maps.patch
deleted file mode 100644
index a5829a290c..0000000000
--- a/patches/unapplied/server/Optimize-isOutsideRange-to-use-distance-maps.patch
+++ /dev/null
@@ -1,375 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Spottedleaf <Spottedleaf@users.noreply.github.com>
-Date: Tue, 5 May 2020 20:40:53 -0700
-Subject: [PATCH] Optimize isOutsideRange to use distance maps
-
-Use a distance map to find the players in range quickly
-
-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 {
-     }
-     // Paper end
- 
-+    // Paper start - optimise isOutsideOfRange
-+    // cached here to avoid a map lookup
-+    com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> playersInMobSpawnRange;
-+    com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> playersInChunkTickRange;
-+
-+    void updateRanges() {
-+        long key = net.minecraft.server.MCUtil.getCoordinateKey(this.pos);
-+        this.playersInMobSpawnRange = this.chunkMap.playerMobSpawnMap.getObjectsInRange(key);
-+        this.playersInChunkTickRange = this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(key);
-+    }
-+    // Paper end - optimise isOutsideOfRange
-+
-     public ChunkHolder(ChunkPos pos, int level, LevelHeightAccessor world, LevelLightEngine lightingProvider, ChunkHolder.LevelChangeListener levelUpdateListener, ChunkHolder.PlayerProvider playersWatchingChunkProvider) {
-         this.futures = new AtomicReferenceArray(ChunkHolder.CHUNK_STATUSES.size());
-         this.fullChunkFuture = ChunkHolder.UNLOADED_LEVEL_CHUNK_FUTURE;
-@@ -0,0 +0,0 @@ public class ChunkHolder {
-         this.setTicketLevel(level);
-         this.changedBlocksPerSection = new ShortSet[world.getSectionsCount()];
-         this.chunkMap = (ChunkMap)playersWatchingChunkProvider; // Paper
-+        this.updateRanges(); // Paper - optimise isOutsideOfRange
-     }
- 
-     // CraftBukkit start
-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
-+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-         return MinecraftServer.getServer().getScaledTrackingDistance(vanilla);
-     }
-     // Paper end - use distance map to optimise tracker
-+    // Paper start - optimise PlayerChunkMap#isOutsideRange
-+    // A note about the naming used here:
-+    // Previously, mojang used a "spawn range" of 8 for controlling both ticking and
-+    // mob spawn range. However, spigot makes the spawn range configurable by
-+    // checking if the chunk is in the tick range (8) and the spawn range
-+    // obviously this means a spawn range > 8 cannot be implemented
-+
-+    // these maps are named after spigot's uses
-+    public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobSpawnMap; // this map is absent from updateMaps since it's controlled at the start of the chunkproviderserver tick
-+    public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerChunkTickRangeMap;
-+    // Paper end - optimise PlayerChunkMap#isOutsideRange
- 
-     void addPlayerToDistanceMaps(ServerPlayer player) {
-         int chunkX = MCUtil.getChunkCoordinate(player.getX());
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-             trackMap.add(player, chunkX, chunkZ, Math.min(trackRange, this.getEffectiveViewDistance()));
-         }
-         // Paper end - use distance map to optimise entity tracker
-+        // Paper start - optimise PlayerChunkMap#isOutsideRange
-+        this.playerChunkTickRangeMap.update(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE);
-+        // Paper end - optimise PlayerChunkMap#isOutsideRange
-+        // Paper start - optimise PlayerChunkMap#isOutsideRange
-+        this.playerChunkTickRangeMap.add(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE);
-+        // Paper end - optimise PlayerChunkMap#isOutsideRange
-         // Paper start - no-tick view distance
-         int effectiveTickViewDistance = this.getEffectiveViewDistance();
-         int effectiveNoTickViewDistance = Math.max(this.getEffectiveNoTickViewDistance(), effectiveTickViewDistance);
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-             this.playerEntityTrackerTrackMaps[i].remove(player);
-         }
-         // Paper end - use distance map to optimise tracker
-+        // Paper start - optimise PlayerChunkMap#isOutsideRange
-+        this.playerMobSpawnMap.remove(player);
-+        this.playerChunkTickRangeMap.remove(player);
-+        // Paper end - optimise PlayerChunkMap#isOutsideRange
-         // Paper start - no-tick view distance
-         this.playerViewDistanceBroadcastMap.remove(player);
-         this.playerViewDistanceTickMap.remove(player);
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-             trackMap.update(player, chunkX, chunkZ, Math.min(trackRange, this.getEffectiveViewDistance()));
-         }
-         // Paper end - use distance map to optimise entity tracker
-+        // Paper start - optimise PlayerChunkMap#isOutsideRange
-+        this.playerChunkTickRangeMap.update(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE);
-+        // Paper end - optimise PlayerChunkMap#isOutsideRange
-         // Paper start - no-tick view distance
-         int effectiveTickViewDistance = this.getEffectiveViewDistance();
-         int effectiveNoTickViewDistance = Math.max(this.getEffectiveNoTickViewDistance(), effectiveTickViewDistance);
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-         this.mainThreadMailbox = this.queueSorter.getProcessor(mailbox, false);
-         this.mailboxLight = this.queueSorter.getProcessor(lightthreaded, false);// Paper
-         this.lightEngine = new ThreadedLevelLightEngine(chunkProvider, this, this.level.dimensionType().hasSkyLight(), threadedmailbox1, this.queueSorter.getProcessor(threadedmailbox1, false));
--        this.distanceManager = new ChunkMap.ChunkDistanceManager(executor, mainThreadExecutor);
-+        this.distanceManager = new ChunkMap.ChunkDistanceManager(executor, mainThreadExecutor); this.distanceManager.chunkMap = this; // Paper
-         this.overworldDataStorage = persistentStateManagerFactory;
-         this.poiManager = new PoiManager(new File(file, "poi"), dataFixer, dsync, world);
-         this.setViewDistance(viewDistance);
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-             this.playerEntityTrackerTrackMaps[ordinal] = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets);
-         }
-         // Paper end - use distance map to optimise entity tracker
-+        // Paper start - optimise PlayerChunkMap#isOutsideRange
-+        this.playerChunkTickRangeMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets,
-+            (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
-+             com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
-+                ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ));
-+                if (playerChunk != null) {
-+                    playerChunk.playersInChunkTickRange = newState;
-+                }
-+            },
-+            (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
-+             com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
-+                ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ));
-+                if (playerChunk != null) {
-+                    playerChunk.playersInChunkTickRange = newState;
-+                }
-+            });
-+        this.playerMobSpawnMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets,
-+            (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
-+             com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
-+                ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ));
-+                if (playerChunk != null) {
-+                    playerChunk.playersInMobSpawnRange = newState;
-+                }
-+            },
-+            (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
-+             com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
-+                ChunkHolder playerChunk = ChunkMap.this.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(rangeX, rangeZ));
-+                if (playerChunk != null) {
-+                    playerChunk.playersInMobSpawnRange = newState;
-+                }
-+            });
-+        // Paper end - optimise PlayerChunkMap#isOutsideRange
-     }
- 
-     // Paper start
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-         } else {
-             if (holder != null) {
-                 holder.setTicketLevel(level);
-+                holder.updateRanges(); // Paper - optimise isOutsideOfRange
-             }
- 
-             if (holder != null) {
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-         return this.isOutsideOfRange(chunkPos, false);
-     }
- 
--    boolean isOutsideOfRange(ChunkPos chunkcoordintpair, boolean reducedRange) {
--        int chunkRange = level.spigotConfig.mobSpawnRange;
--        chunkRange = (chunkRange > level.spigotConfig.viewDistance) ? (byte) level.spigotConfig.viewDistance : chunkRange;
--        chunkRange = (chunkRange > 8) ? 8 : chunkRange;
-+    // Paper start - optimise isOutsideOfRange
-+    final boolean isOutsideOfRange(ChunkPos chunkcoordintpair, boolean reducedRange) {
-+        return this.isOutsideOfRange(this.getUpdatingChunkIfPresent(chunkcoordintpair.toLong()), chunkcoordintpair, reducedRange);
-+    }
-+    final boolean isOutsideOfRange(ChunkHolder playerchunk, ChunkPos chunkcoordintpair, boolean reducedRange) {
-+        // this function is so hot that removing the map lookup call can have an order of magnitude impact on its performance
-+        // tested and confirmed via System.nanoTime()
-+        com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> playersInRange = reducedRange ? playerchunk.playersInMobSpawnRange : playerchunk.playersInChunkTickRange;
-+        if (playersInRange == null) {
-+            return true;
-+        }
-+        Object[] backingSet = playersInRange.getBackingSet();
- 
--        final int finalChunkRange = chunkRange; // Paper for lambda below
--        //double blockRange = (reducedRange) ? Math.pow(chunkRange << 4, 2) : 16384.0D; // Paper - use from event
--        // Spigot end
--        long i = chunkcoordintpair.toLong();
--
--        return !this.distanceManager.hasPlayersNearby(i) ? true : this.playerMap.getPlayers(i).noneMatch((entityplayer) -> {
--            // Paper start - add PlayerNaturallySpawnCreaturesEvent
--            com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event;
--            double blockRange = 16384.0D;
--            if (reducedRange) {
--                event = entityplayer.playerNaturallySpawnedEvent;
--                if (event == null || event.isCancelled()) return false;
--                blockRange = (double) ((event.getSpawnRadius() << 4) * (event.getSpawnRadius() << 4));
-+        if (reducedRange) {
-+            for (int i = 0, len = backingSet.length; i < len; ++i) {
-+                Object raw = backingSet[i];
-+                if (!(raw instanceof ServerPlayer)) {
-+                    continue;
-+                }
-+                ServerPlayer player = (ServerPlayer) raw;
-+                // don't check spectator and whatnot, already handled by mob spawn map update
-+                if (player.lastEntitySpawnRadiusSquared > euclideanDistanceSquared(chunkcoordintpair, player)) {
-+                    return false; // in range
-+                }
-             }
--            // Paper end
--            return !entityplayer.isSpectator() && ChunkMap.euclideanDistanceSquared(chunkcoordintpair, (Entity) entityplayer) < blockRange; // Spigot
--        });
-+        } else {
-+            final double range = (DistanceManager.MOB_SPAWN_RANGE * 16) * (DistanceManager.MOB_SPAWN_RANGE * 16);
-+            // before spigot, mob spawn range was actually mob spawn range + tick range, but it was split
-+            for (int i = 0, len = backingSet.length; i < len; ++i) {
-+                Object raw = backingSet[i];
-+                if (!(raw instanceof ServerPlayer)) {
-+                    continue;
-+                }
-+                ServerPlayer player = (ServerPlayer) raw;
-+                // don't check spectator and whatnot, already handled by mob spawn map update
-+                if (range > euclideanDistanceSquared(chunkcoordintpair, player)) {
-+                    return false; // in range
-+                }
-+            }
-+        }
-+        // no players in range
-+        return true;
-     }
-+    // Paper end - optimise isOutsideOfRange
- 
-     private boolean skipPlayer(ServerPlayer player) {
-         return player.isSpectator() && !this.level.getGameRules().getBoolean(GameRules.RULE_SPECTATORSGENERATECHUNKS);
-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
-+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
-@@ -0,0 +0,0 @@ public abstract class DistanceManager {
-     final Long2ObjectMap<ObjectSet<ServerPlayer>> playersPerChunk = new Long2ObjectOpenHashMap();
-     public final Long2ObjectOpenHashMap<SortedArraySet<Ticket<?>>> tickets = new Long2ObjectOpenHashMap();
-     private final DistanceManager.ChunkTicketTracker ticketTracker = new DistanceManager.ChunkTicketTracker();
--    private final DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter = new DistanceManager.FixedPlayerDistanceChunkTracker(8);
-+    public static final int MOB_SPAWN_RANGE = 8; // private final ChunkMapDistance.b f = new ChunkMapDistance.b(8); // Paper - no longer used
-     private final DistanceManager.PlayerTicketTracker playerTicketManager = new DistanceManager.PlayerTicketTracker(33);
-     // Paper start use a queue, but still keep unique requirement
-     public final java.util.Queue<ChunkHolder> pendingChunkUpdates = new java.util.ArrayDeque<ChunkHolder>() {
-@@ -0,0 +0,0 @@ public abstract class DistanceManager {
-     final Executor mainThreadExecutor;
-     private long ticketTickCounter;
- 
-+    ChunkMap chunkMap; // Paper
-+
-     protected DistanceManager(Executor workerExecutor, Executor mainThreadExecutor) {
-         Objects.requireNonNull(mainThreadExecutor);
-         ProcessorHandle<Runnable> mailbox = ProcessorHandle.of("player ticket throttler", mainThreadExecutor::execute);
-@@ -0,0 +0,0 @@ public abstract class DistanceManager {
-     protected abstract ChunkHolder updateChunkScheduling(long pos, int level, @Nullable ChunkHolder holder, int k);
- 
-     public boolean runAllUpdates(ChunkMap playerchunkmap) {
--        this.naturalSpawnChunkCounter.runAllUpdates();
-+        //this.f.a(); // Paper - no longer used
-         this.playerTicketManager.runAllUpdates();
-         int i = Integer.MAX_VALUE - this.ticketTracker.runDistanceUpdates(Integer.MAX_VALUE);
-         boolean flag = i != 0;
-@@ -0,0 +0,0 @@ public abstract class DistanceManager {
-         ((ObjectSet) this.playersPerChunk.computeIfAbsent(i, (j) -> {
-             return new ObjectOpenHashSet();
-         })).add(player);
--        this.naturalSpawnChunkCounter.update(i, 0, true);
-+        //this.f.update(i, 0, true); // Paper - no longer used
-         this.playerTicketManager.update(i, 0, true);
-     }
- 
-@@ -0,0 +0,0 @@ public abstract class DistanceManager {
-         if (objectset != null) objectset.remove(player); // Paper - some state corruption happens here, don't crash, clean up gracefully.
-         if (objectset == null || objectset.isEmpty()) { // Paper
-             this.playersPerChunk.remove(i);
--            this.naturalSpawnChunkCounter.update(i, Integer.MAX_VALUE, false);
-+            //this.f.update(i, Integer.MAX_VALUE, false); // Paper - no longer used
-             this.playerTicketManager.update(i, Integer.MAX_VALUE, false);
-         }
- 
-@@ -0,0 +0,0 @@ public abstract class DistanceManager {
-     }
- 
-     public int getNaturalSpawnChunkCount() {
--        this.naturalSpawnChunkCounter.runAllUpdates();
--        return this.naturalSpawnChunkCounter.chunks.size();
-+        // Paper start - use distance map to implement
-+        // note: this is the spawn chunk count
-+        return this.chunkMap.playerChunkTickRangeMap.size();
-+        // Paper end - use distance map to implement
-     }
- 
-     public boolean hasPlayersNearby(long i) {
--        this.naturalSpawnChunkCounter.runAllUpdates();
--        return this.naturalSpawnChunkCounter.chunks.containsKey(i);
-+        // Paper start - use distance map to implement
-+        // note: this is the is spawn chunk method
-+        return this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(i) != null;
-+        // Paper end - use distance map to implement
-     }
- 
-     public String getDebugStatus() {
-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
-+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
-@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
-         boolean flag1 = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit
- 
-         if (!flag) {
-+            // Paper start - optimize isOutisdeRange
-+            ChunkMap playerChunkMap = this.chunkMap;
-+            for (ServerPlayer player : this.level.players) {
-+                if (!player.affectsSpawning || player.isSpectator()) {
-+                    playerChunkMap.playerMobSpawnMap.remove(player);
-+                    continue;
-+                }
-+
-+                int viewDistance = this.chunkMap.getEffectiveViewDistance();
-+
-+                // copied and modified from isOutisdeRange
-+                int chunkRange = level.spigotConfig.mobSpawnRange;
-+                chunkRange = (chunkRange > viewDistance) ? (byte)viewDistance : chunkRange;
-+                chunkRange = (chunkRange > DistanceManager.MOB_SPAWN_RANGE) ? DistanceManager.MOB_SPAWN_RANGE : chunkRange;
-+
-+                com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(player.getBukkitEntity(), (byte)chunkRange);
-+                event.callEvent();
-+                if (event.isCancelled() || event.getSpawnRadius() < 0 || playerChunkMap.playerChunkTickRangeMap.getLastViewDistance(player) == -1) {
-+                    playerChunkMap.playerMobSpawnMap.remove(player);
-+                    continue;
-+                }
-+
-+                int range = Math.min(event.getSpawnRadius(), 32); // limit to max view distance
-+                int chunkX = net.minecraft.server.MCUtil.getChunkCoordinate(player.getX());
-+                int chunkZ = net.minecraft.server.MCUtil.getChunkCoordinate(player.getZ());
-+
-+                playerChunkMap.playerMobSpawnMap.addOrUpdate(player, chunkX, chunkZ, range);
-+                player.lastEntitySpawnRadiusSquared = (double)((range << 4) * (range << 4)); // used in isOutsideRange
-+                player.playerNaturallySpawnedEvent = event;
-+            }
-+            // Paper end - optimize isOutisdeRange
-             this.level.getProfiler().push("pollingChunks");
-             int k = this.level.getGameRules().getInt(GameRules.RULE_RANDOMTICKING);
-             boolean flag2 = level.ticksPerAnimalSpawns != 0L && worlddata.getGameTime() % level.ticksPerAnimalSpawns == 0L; // CraftBukkit
-@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
-             List<ChunkHolder> list = Lists.newArrayList(this.chunkMap.getChunks());
- 
-             Collections.shuffle(list);
--            // Paper start - call player naturally spawn event
--            int chunkRange = level.spigotConfig.mobSpawnRange;
--            chunkRange = (chunkRange > level.spigotConfig.viewDistance) ? (byte) level.spigotConfig.viewDistance : chunkRange;
--            chunkRange = Math.min(chunkRange, 8);
--            for (ServerPlayer entityPlayer : this.level.players()) {
--                entityPlayer.playerNaturallySpawnedEvent = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(entityPlayer.getBukkitEntity(), (byte) chunkRange);
--                entityPlayer.playerNaturallySpawnedEvent.callEvent();
--            };
--            // Paper end
-+            // Paper - moved natural spawn event up
-             this.level.timings.chunkTicks.startTiming(); // Paper
-             list.forEach((playerchunk) -> {
-                 Optional<LevelChunk> optional = ((Either) playerchunk.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left();
-@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
-                     LevelChunk chunk = (LevelChunk) optional.get();
-                     ChunkPos chunkcoordintpair = chunk.getPos();
- 
--                    if (this.level.isPositionEntityTicking(chunkcoordintpair) && !this.chunkMap.noPlayersCloseForSpawning(chunkcoordintpair)) {
-+                    if (this.level.isPositionEntityTicking(chunkcoordintpair) && !this.chunkMap.isOutsideOfRange(playerchunk, chunkcoordintpair, false)) { // Paper - optimise isOutsideOfRange
-                         chunk.setInhabitedTime(chunk.getInhabitedTime() + j);
--                        if (flag1 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunk.getPos()) && !this.chunkMap.isOutsideOfRange(chunkcoordintpair, true)) { // Spigot
-+                        if (flag1 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunk.getPos()) && !this.chunkMap.isOutsideOfRange(playerchunk, chunkcoordintpair, true)) { // Spigot // Paper - optimise isOutsideOfRange
-                             NaturalSpawner.spawnForChunk(this.level, chunk, spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag2);
-                         }
- 
-diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
-+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
-     // CraftBukkit end
-     public PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper
- 
-+    public double lastEntitySpawnRadiusSquared; // Paper - optimise isOutsideRange, this field is in blocks
-     public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> cachedSingleHashSet; // Paper
-     boolean needsChunkCenterUpdate; // Paper - no-tick view distance
- 
diff --git a/patches/unapplied/server/Optimize-sending-packets-to-nearby-locations-sounds-.patch b/patches/unapplied/server/Optimize-sending-packets-to-nearby-locations-sounds-.patch
deleted file mode 100644
index c0cfeb1f02..0000000000
--- a/patches/unapplied/server/Optimize-sending-packets-to-nearby-locations-sounds-.patch
+++ /dev/null
@@ -1,63 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Aikar <aikar@aikar.co>
-Date: Sat, 23 May 2020 17:03:41 -0400
-Subject: [PATCH] Optimize sending packets to nearby locations (sounds/effects)
-
-Instead of using the entire world or player list, use the distance
-maps to only iterate players who are even seeing the chunk the packet
-is originating from.
-
-This will drastically cut down on packet sending cost for worlds with
-lots of players in them.
-
-diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/players/PlayerList.java
-+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
-@@ -0,0 +0,0 @@ public abstract class PlayerList {
-     }
- 
-     public void broadcast(@Nullable net.minecraft.world.entity.player.Player player, double x, double y, double z, double distance, ResourceKey<Level> worldKey, Packet<?> packet) {
--        for (int i = 0; i < this.players.size(); ++i) {
--            ServerPlayer entityplayer = (ServerPlayer) this.players.get(i);
-+        ServerLevel world = null;
-+        if (player != null && player.level instanceof ServerLevel) {
-+            world = (ServerLevel) player.level;
-+        }
- 
--            // CraftBukkit start - Test if player receiving packet can see the source of the packet
--            if (player != null && player instanceof ServerPlayer && !entityplayer.getBukkitEntity().canSee(((ServerPlayer) player).getBukkitEntity())) {
--               continue;
-+        // Paper start
-+        if (world == null) {
-+            world = server.getLevel(worldKey);
-+        }
-+        net.minecraft.server.level.ChunkMap chunkMap = world != null ? world.getChunkSource().chunkMap : null;
-+        Object[] backingSet;
-+        if (chunkMap == null) {
-+            // Really shouldn't happen...
-+            backingSet = world != null ? world.players.toArray() : players.toArray();
-+        } else {
-+            com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> nearbyPlayers = chunkMap.playerViewDistanceBroadcastMap.getObjectsInRange(MCUtil.fastFloor(x) >> 4, MCUtil.fastFloor(z) >> 4);
-+            if (nearbyPlayers == null) {
-+                return;
-             }
-+            backingSet = nearbyPlayers.getBackingSet();
-+        }
-+
-+        for (Object object : backingSet) {
-+            if (!(object instanceof ServerPlayer)) continue;
-+            ServerPlayer entityplayer = (ServerPlayer) object;
-+            // Paper end
-+
-+            // CraftBukkit start - Test if player receiving packet can see the source of the packet
-+            //if (entityhuman != null && entityhuman instanceof EntityPlayer && !entityplayer.getBukkitEntity().canSee(((EntityPlayer) entityhuman).getBukkitEntity())) { // Paper
-+               //continue; // Paper
-+            //} // Paper
-             // CraftBukkit end
- 
--            if (entityplayer != player && entityplayer.level.dimension() == worldKey) {
-+            if (entityplayer != player && entityplayer.level.dimension() == worldKey && (!(player instanceof ServerPlayer) || entityplayer.getBukkitEntity().canSee(((ServerPlayer) player).getBukkitEntity()))) { // Paper
-                 double d4 = x - entityplayer.getX();
-                 double d5 = y - entityplayer.getY();
-                 double d6 = z - entityplayer.getZ();
diff --git a/patches/unapplied/server/Use-distance-map-to-optimise-entity-tracker.patch b/patches/unapplied/server/Use-distance-map-to-optimise-entity-tracker.patch
deleted file mode 100644
index 2bcc96b4a2..0000000000
--- a/patches/unapplied/server/Use-distance-map-to-optimise-entity-tracker.patch
+++ /dev/null
@@ -1,397 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Spottedleaf <Spottedleaf@users.noreply.github.com>
-Date: Tue, 5 May 2020 20:18:05 -0700
-Subject: [PATCH] Use distance map to optimise entity tracker
-
-Use the distance map to find candidate players for tracking.
-
-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
-+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
-@@ -0,0 +0,0 @@ import net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket;
- import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket;
- import net.minecraft.network.protocol.game.DebugPackets;
- import net.minecraft.server.MCUtil;
-+import net.minecraft.server.MinecraftServer;
- import net.minecraft.server.level.progress.ChunkProgressListener;
- import net.minecraft.server.network.ServerPlayerConnection;
- import net.minecraft.util.CsvOutput;
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-     public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerViewDistanceTickMap;
-     public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerViewDistanceNoTickMap;
-     // Paper end - no-tick view distance
-+    // Paper start - use distance map to optimise tracker
-+    public static boolean isLegacyTrackingEntity(Entity entity) {
-+        return entity.isLegacyTrackingEntity;
-+    }
-+
-+    // inlined EnumMap, TrackingRange.TrackingRangeType
-+    static final org.spigotmc.TrackingRange.TrackingRangeType[] TRACKING_RANGE_TYPES = org.spigotmc.TrackingRange.TrackingRangeType.values();
-+    public final com.destroystokyo.paper.util.misc.PlayerAreaMap[] playerEntityTrackerTrackMaps;
-+    final int[] entityTrackerTrackRanges;
-+    public final int getEntityTrackerRange(final int ordinal) {
-+        return this.entityTrackerTrackRanges[ordinal];
-+    }
-+
-+    private int convertSpigotRangeToVanilla(final int vanilla) {
-+        return MinecraftServer.getServer().getScaledTrackingDistance(vanilla);
-+    }
-+    // Paper end - use distance map to optimise tracker
- 
-     void addPlayerToDistanceMaps(ServerPlayer player) {
-         int chunkX = MCUtil.getChunkCoordinate(player.getX());
-         int chunkZ = MCUtil.getChunkCoordinate(player.getZ());
-         // Note: players need to be explicitly added to distance maps before they can be updated
-+        // Paper start - use distance map to optimise entity tracker
-+        for (int i = 0, len = TRACKING_RANGE_TYPES.length; i < len; ++i) {
-+            com.destroystokyo.paper.util.misc.PlayerAreaMap trackMap = this.playerEntityTrackerTrackMaps[i];
-+            int trackRange = this.entityTrackerTrackRanges[i];
-+
-+            trackMap.add(player, chunkX, chunkZ, Math.min(trackRange, this.getEffectiveViewDistance()));
-+        }
-+        // Paper end - use distance map to optimise entity tracker
-         // Paper start - no-tick view distance
-         int effectiveTickViewDistance = this.getEffectiveViewDistance();
-         int effectiveNoTickViewDistance = Math.max(this.getEffectiveNoTickViewDistance(), effectiveTickViewDistance);
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-     }
- 
-     void removePlayerFromDistanceMaps(ServerPlayer player) {
--
-+        // Paper start - use distance map to optimise tracker
-+        for (int i = 0, len = TRACKING_RANGE_TYPES.length; i < len; ++i) {
-+            this.playerEntityTrackerTrackMaps[i].remove(player);
-+        }
-+        // Paper end - use distance map to optimise tracker
-         // Paper start - no-tick view distance
-         this.playerViewDistanceBroadcastMap.remove(player);
-         this.playerViewDistanceTickMap.remove(player);
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-         int chunkX = MCUtil.getChunkCoordinate(player.getX());
-         int chunkZ = MCUtil.getChunkCoordinate(player.getZ());
-         // Note: players need to be explicitly added to distance maps before they can be updated
-+        // Paper start - use distance map to optimise entity tracker
-+        for (int i = 0, len = TRACKING_RANGE_TYPES.length; i < len; ++i) {
-+            com.destroystokyo.paper.util.misc.PlayerAreaMap trackMap = this.playerEntityTrackerTrackMaps[i];
-+            int trackRange = this.entityTrackerTrackRanges[i];
-+
-+            trackMap.update(player, chunkX, chunkZ, Math.min(trackRange, this.getEffectiveViewDistance()));
-+        }
-+        // Paper end - use distance map to optimise entity tracker
-         // Paper start - no-tick view distance
-         int effectiveTickViewDistance = this.getEffectiveViewDistance();
-         int effectiveNoTickViewDistance = Math.max(this.getEffectiveNoTickViewDistance(), effectiveTickViewDistance);
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-             });
-         // Paper end - no-tick view distance
-         this.playerMobDistanceMap = this.level.paperConfig.perPlayerMobSpawns ? new com.destroystokyo.paper.util.PlayerMobDistanceMap() : null; // Paper
-+        // Paper start - use distance map to optimise entity tracker
-+        this.playerEntityTrackerTrackMaps = new com.destroystokyo.paper.util.misc.PlayerAreaMap[TRACKING_RANGE_TYPES.length];
-+        this.entityTrackerTrackRanges = new int[TRACKING_RANGE_TYPES.length];
-+
-+        org.spigotmc.SpigotWorldConfig spigotWorldConfig = this.level.spigotConfig;
-+
-+        for (int ordinal = 0, len = TRACKING_RANGE_TYPES.length; ordinal < len; ++ordinal) {
-+            org.spigotmc.TrackingRange.TrackingRangeType trackingRangeType = TRACKING_RANGE_TYPES[ordinal];
-+            int configuredSpigotValue;
-+            switch (trackingRangeType) {
-+                case PLAYER:
-+                    configuredSpigotValue = spigotWorldConfig.playerTrackingRange;
-+                    break;
-+                case ANIMAL:
-+                    configuredSpigotValue = spigotWorldConfig.animalTrackingRange;
-+                    break;
-+                case MONSTER:
-+                    configuredSpigotValue = spigotWorldConfig.monsterTrackingRange;
-+                    break;
-+                case MISC:
-+                    configuredSpigotValue = spigotWorldConfig.miscTrackingRange;
-+                    break;
-+                case OTHER:
-+                    configuredSpigotValue = spigotWorldConfig.otherTrackingRange;
-+                    break;
-+                case ENDERDRAGON:
-+                    configuredSpigotValue = EntityType.ENDER_DRAGON.clientTrackingRange() * 16;
-+                    break;
-+                default:
-+                    throw new IllegalStateException("Missing case for enum " + trackingRangeType);
-+            }
-+            configuredSpigotValue = convertSpigotRangeToVanilla(configuredSpigotValue);
-+
-+            int trackRange = (configuredSpigotValue >>> 4) + ((configuredSpigotValue & 15) != 0 ? 1 : 0);
-+            this.entityTrackerTrackRanges[ordinal] = trackRange;
-+
-+            this.playerEntityTrackerTrackMaps[ordinal] = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets);
-+        }
-+        // Paper end - use distance map to optimise entity tracker
-     }
- 
-     // Paper start
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-     }
- 
-     public void move(ServerPlayer player) {
--        ObjectIterator objectiterator = this.entityMap.values().iterator();
--
--        while (objectiterator.hasNext()) {
--            ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next();
--
--            if (playerchunkmap_entitytracker.entity == player) {
--                playerchunkmap_entitytracker.updatePlayers(this.level.players());
--            } else {
--                playerchunkmap_entitytracker.updatePlayer(player);
--            }
--        }
-+        // Paper - delay this logic for the entity tracker tick, no need to duplicate it
- 
-         int i = SectionPos.blockToSectionCoord(player.getBlockX());
-         int j = SectionPos.blockToSectionCoord(player.getBlockZ());
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
- 
-                     entity.tracker = playerchunkmap_entitytracker; // Paper - Fast access to tracker
-                     this.entityMap.put(entity.getId(), playerchunkmap_entitytracker);
--                    playerchunkmap_entitytracker.updatePlayers(this.level.players());
-+                    playerchunkmap_entitytracker.updatePlayers(entity.getPlayersInTrackRange()); // Paper - don't search all players
-                     if (entity instanceof ServerPlayer) {
-                         ServerPlayer entityplayer = (ServerPlayer) entity;
- 
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-         entity.tracker = null; // Paper - We're no longer tracked
-     }
- 
-+    // Paper start - optimised tracker
-+    private final void processTrackQueue() {
-+        this.level.timings.tracker1.startTiming();
-+        try {
-+            for (TrackedEntity tracker : this.entityMap.values()) {
-+                // update tracker entry
-+                tracker.updatePlayers(tracker.entity.getPlayersInTrackRange());
-+            }
-+        } finally {
-+            this.level.timings.tracker1.stopTiming();
-+        }
-+
-+
-+        this.level.timings.tracker2.startTiming();
-+        try {
-+            for (TrackedEntity tracker : this.entityMap.values()) {
-+                tracker.serverEntity.sendChanges();
-+            }
-+        } finally {
-+            this.level.timings.tracker2.stopTiming();
-+        }
-+    }
-+    // Paper end - optimised tracker
-+
-     protected void tick() {
-+        // Paper start - optimized tracker
-+        if (true) {
-+            this.processTrackQueue();
-+            return;
-+        }
-+        // Paper end - optimized tracker
-         List<ServerPlayer> list = Lists.newArrayList();
-         List<ServerPlayer> list1 = this.level.players();
- 
-@@ -0,0 +0,0 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially
-         DebugPackets.sendPoiPacketsForChunk(this.level, chunk.getPos());
-         List<Entity> list = Lists.newArrayList();
-         List<Entity> list1 = Lists.newArrayList();
--        ObjectIterator objectiterator = this.entityMap.values().iterator();
-+        // Paper start - optimise entity tracker
-+        // use the chunk entity list, not the whole trackedEntities map...
-+        Entity[] entities = chunk.entities.getRawData();
-+        for (int i = 0, size = chunk.entities.size(); i < size; ++i) {
-+            Entity entity = entities[i];
-+            if (entity == player) {
-+                continue;
-+            }
-+            ChunkMap.TrackedEntity tracker = this.entityMap.get(entity.getId());
-+            if (tracker != null) { // dumb plugins... move on...
-+                tracker.updatePlayer(player);
-+            }
- 
--        while (objectiterator.hasNext()) {
--            ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next();
--            Entity entity = playerchunkmap_entitytracker.entity;
-+            // keep the vanilla logic here - this is REQUIRED or else passengers and their vehicles disappear!
-+            // (and god knows what the leash thing is)
- 
--            if (entity != player && entity.chunkPosition().equals(chunk.getPos())) {
--                playerchunkmap_entitytracker.updatePlayer(player);
--                if (entity instanceof Mob && ((Mob) entity).getLeashHolder() != null) {
--                    list.add(entity);
--                }
-+            if (entity instanceof Mob && ((Mob)entity).getLeashHolder() != null) {
-+                list.add(entity);
-+            }
- 
--                if (!entity.getPassengers().isEmpty()) {
--                    list1.add(entity);
--                }
-+            if (!entity.getPassengers().isEmpty()) {
-+                list1.add(entity);
-             }
-         }
-+        // Paper end - optimise entity tracker
- 
-         Iterator iterator;
-         Entity entity1;
-@@ -0,0 +0,0 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially
-             this.lastSectionPos = SectionPos.of(entity);
-         }
- 
-+        // Paper start - use distance map to optimise tracker
-+        com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> lastTrackerCandidates;
-+
-+        final void updatePlayers(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newTrackerCandidates) {
-+            com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> oldTrackerCandidates = this.lastTrackerCandidates;
-+            this.lastTrackerCandidates = newTrackerCandidates;
-+
-+            if (newTrackerCandidates != null) {
-+                Object[] rawData = newTrackerCandidates.getBackingSet();
-+                for (int i = 0, len = rawData.length; i < len; ++i) {
-+                    Object raw = rawData[i];
-+                    if (!(raw instanceof ServerPlayer)) {
-+                        continue;
-+                    }
-+                    ServerPlayer player = (ServerPlayer)raw;
-+                    this.updatePlayer(player);
-+                }
-+            }
-+
-+            if (oldTrackerCandidates == newTrackerCandidates) {
-+                // this is likely the case.
-+                // means there has been no range changes, so we can just use the above for tracking.
-+                return;
-+            }
-+
-+            // stuff could have been removed, so we need to check the trackedPlayers set
-+            // for players that were removed
-+
-+            for (ServerPlayerConnection conn : this.seenBy.toArray(new ServerPlayerConnection[0])) { // avoid CME
-+                if (newTrackerCandidates == null || !newTrackerCandidates.contains(conn.getPlayer())) {
-+                    this.updatePlayer(conn.getPlayer());
-+                }
-+            }
-+        }
-+        // Paper end - use distance map to optimise tracker
-+
-         public boolean equals(Object object) {
-             return object instanceof ChunkMap.TrackedEntity ? ((ChunkMap.TrackedEntity) object).entity.getId() == this.entity.getId() : false;
-         }
-diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
-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;
- import net.minecraft.network.syncher.SynchedEntityData;
- import net.minecraft.resources.ResourceKey;
- import net.minecraft.resources.ResourceLocation;
-+import net.minecraft.server.MCUtil;
- 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, n
-     }
-     // Paper end
- 
-+    // Paper start - optimise entity tracking
-+    final org.spigotmc.TrackingRange.TrackingRangeType trackingRangeType = org.spigotmc.TrackingRange.getTrackingRangeType(this);
-+
-+    public boolean isLegacyTrackingEntity = false;
-+
-+    public final void setLegacyTrackingEntity(final boolean isLegacyTrackingEntity) {
-+        this.isLegacyTrackingEntity = isLegacyTrackingEntity;
-+    }
-+
-+    public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> getPlayersInTrackRange() {
-+        // determine highest range of passengers
-+        if (this.passengers.isEmpty()) {
-+            return ((ServerLevel)this.level).getChunkSource().chunkMap.playerEntityTrackerTrackMaps[this.trackingRangeType.ordinal()]
-+                .getObjectsInRange(MCUtil.getCoordinateKey(this));
-+        }
-+        Iterable<Entity> passengers = this.getIndirectPassengers();
-+        net.minecraft.server.level.ChunkMap chunkMap = ((ServerLevel)this.level).getChunkSource().chunkMap;
-+        org.spigotmc.TrackingRange.TrackingRangeType type = this.trackingRangeType;
-+        int range = chunkMap.getEntityTrackerRange(type.ordinal());
-+
-+        for (Entity passenger : passengers) {
-+            org.spigotmc.TrackingRange.TrackingRangeType passengerType = passenger.trackingRangeType;
-+            int passengerRange = chunkMap.getEntityTrackerRange(passengerType.ordinal());
-+            if (passengerRange > range) {
-+                type = passengerType;
-+                range = passengerRange;
-+            }
-+        }
-+
-+        return chunkMap.playerEntityTrackerTrackMaps[type.ordinal()].getObjectsInRange(MCUtil.getCoordinateKey(this));
-+    }
-+    // Paper end - optimise entity tracking
-+
-     public Entity(EntityType<?> type, Level world) {
-         this.id = Entity.ENTITY_COUNTER.incrementAndGet();
-         this.passengers = ImmutableList.of();
-diff --git a/src/main/java/org/spigotmc/TrackingRange.java b/src/main/java/org/spigotmc/TrackingRange.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/org/spigotmc/TrackingRange.java
-+++ b/src/main/java/org/spigotmc/TrackingRange.java
-@@ -0,0 +0,0 @@ public class TrackingRange
-         {
-             return defaultRange;
-         }
-+        if (entity instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon) return defaultRange; // Paper - enderdragon is exempt
-         SpigotWorldConfig config = entity.level.spigotConfig;
-         if ( entity instanceof ServerPlayer )
-         {
-@@ -0,0 +0,0 @@ public class TrackingRange
-             return config.miscTrackingRange;
-         } else
-         {
--            if (entity instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon) return ((net.minecraft.server.level.ServerLevel)(entity.getCommandSenderWorld())).getChunkSource().chunkMap.getLoadViewDistance(); // Paper - enderdragon is exempt
-             return config.otherTrackingRange;
-         }
-     }
-+
-+    // Paper start - optimise entity tracking
-+    // copied from above, TODO check on update
-+    public static TrackingRangeType getTrackingRangeType(Entity entity)
-+    {
-+        if (entity instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon) return TrackingRangeType.ENDERDRAGON; // Paper - enderdragon is exempt
-+        if ( entity instanceof ServerPlayer )
-+        {
-+            return TrackingRangeType.PLAYER;
-+            // Paper start - Simplify and set water mobs to animal tracking range
-+        }
-+        switch (entity.activationType) {
-+            case RAIDER:
-+            case MONSTER:
-+            case FLYING_MONSTER:
-+                return TrackingRangeType.MONSTER;
-+            case WATER:
-+            case VILLAGER:
-+            case ANIMAL:
-+                return TrackingRangeType.ANIMAL;
-+            case MISC:
-+        }
-+        if ( entity instanceof ItemFrame || entity instanceof Painting || entity instanceof ItemEntity || entity instanceof ExperienceOrb )
-+        // Paper end
-+        {
-+            return TrackingRangeType.MISC;
-+        } else
-+        {
-+            return TrackingRangeType.OTHER;
-+        }
-+    }
-+
-+    public static enum TrackingRangeType {
-+        PLAYER,
-+        ANIMAL,
-+        MONSTER,
-+        MISC,
-+        OTHER,
-+        ENDERDRAGON;
-+    }
-+    // Paper end - optimise entity tracking
- }