diff --git a/patches/api-unmapped/0187-Add-ThrownEggHatchEvent.patch b/patches/api/0188-Add-ThrownEggHatchEvent.patch
similarity index 100%
rename from patches/api-unmapped/0187-Add-ThrownEggHatchEvent.patch
rename to patches/api/0188-Add-ThrownEggHatchEvent.patch
diff --git a/patches/api-unmapped/0188-Entity-Jump-API.patch b/patches/api/0189-Entity-Jump-API.patch
similarity index 100%
rename from patches/api-unmapped/0188-Entity-Jump-API.patch
rename to patches/api/0189-Entity-Jump-API.patch
diff --git a/patches/api-unmapped/0189-add-hand-to-BlockMultiPlaceEvent.patch b/patches/api/0190-add-hand-to-BlockMultiPlaceEvent.patch
similarity index 100%
rename from patches/api-unmapped/0189-add-hand-to-BlockMultiPlaceEvent.patch
rename to patches/api/0190-add-hand-to-BlockMultiPlaceEvent.patch
diff --git a/patches/server-remapped/0420-Ensure-Entity-is-never-double-registered.patch b/patches/removed/1.17/0420-Ensure-Entity-is-never-double-registered.patch
similarity index 99%
rename from patches/server-remapped/0420-Ensure-Entity-is-never-double-registered.patch
rename to patches/removed/1.17/0420-Ensure-Entity-is-never-double-registered.patch
index 0c956bdb7..a10ff17d7 100644
--- a/patches/server-remapped/0420-Ensure-Entity-is-never-double-registered.patch
+++ b/patches/removed/1.17/0420-Ensure-Entity-is-never-double-registered.patch
@@ -10,6 +10,8 @@ Vs behavior of non ticking of just overwriting state.
 
 We will now simply log a warning when this happens instead of crashing the server.
 
+1.17: Probably not needed?
+
 diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
 index 9da0d98bc2ed7876a00a734690ed42f01b9a9a9b..9898d5c8fab63c576831bd416ccf1854ed077b0d 100644
 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java
diff --git a/patches/server-remapped/0421-Fix-unregistering-entities-from-unloading-chunks.patch b/patches/removed/1.17/0421-Fix-unregistering-entities-from-unloading-chunks.patch
similarity index 98%
rename from patches/server-remapped/0421-Fix-unregistering-entities-from-unloading-chunks.patch
rename to patches/removed/1.17/0421-Fix-unregistering-entities-from-unloading-chunks.patch
index 110790b17..8d30f4e4f 100644
--- a/patches/server-remapped/0421-Fix-unregistering-entities-from-unloading-chunks.patch
+++ b/patches/removed/1.17/0421-Fix-unregistering-entities-from-unloading-chunks.patch
@@ -14,6 +14,8 @@ This then results in dead entities lingering in the Chunk.
 Combine that with a buggy detail of the previous implementation of
 the Dupe UUID patch, then this was the likely source of the "Ghost entities"
 
+1.17: Probably not needed?
+
 diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
 index 9898d5c8fab63c576831bd416ccf1854ed077b0d..c5dc41a3cf499038bd33451a189913cd3978b230 100644
 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java
diff --git a/patches/server-remapped/0404-Bees-get-gravity-in-void.-Fixes-MC-167279.patch b/patches/server-remapped/0404-Bees-get-gravity-in-void.-Fixes-MC-167279.patch
deleted file mode 100644
index f19be75b5..000000000
--- a/patches/server-remapped/0404-Bees-get-gravity-in-void.-Fixes-MC-167279.patch
+++ /dev/null
@@ -1,55 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: William Blake Galbreath <Blake.Galbreath@GMail.com>
-Date: Sun, 26 Jan 2020 16:30:19 -0600
-Subject: [PATCH] Bees get gravity in void. Fixes MC-167279
-
-
-diff --git a/src/main/java/net/minecraft/world/entity/ai/control/FlyingMoveControl.java b/src/main/java/net/minecraft/world/entity/ai/control/FlyingMoveControl.java
-index 2c9e3dd1b9dd7bb8825a2eb9fecc2b2be348d055..868e9cdeb3c7effb398cef6f6f9c1e4fffa2db8c 100644
---- a/src/main/java/net/minecraft/world/entity/ai/control/FlyingMoveControl.java
-+++ b/src/main/java/net/minecraft/world/entity/ai/control/FlyingMoveControl.java
-@@ -16,7 +16,7 @@ public class FlyingMoveControl extends MoveControl {
-     }
- 
-     @Override
--    public void tick() {
-+    public void tick() { tick(); } public void tick() { // Paper - OBFHELPER
-         if (this.operation == MoveControl.Operation.MOVE_TO) {
-             this.operation = MoveControl.Operation.WAIT;
-             this.mob.setNoGravity(true);
-diff --git a/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java b/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java
-index ab65f0327766463a5e53fdd723e243464319fdbe..f4984d601d14c684e75f887f5f5d2f5a29326b15 100644
---- a/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java
-+++ b/src/main/java/net/minecraft/world/entity/ai/control/MoveControl.java
-@@ -16,7 +16,7 @@ import net.minecraft.world.phys.shapes.VoxelShape;
- 
- public class MoveControl {
- 
--    protected final Mob mob;
-+    protected final Mob mob; public final Mob getEntity() { return mob; } // Paper - OBFHELPER
-     protected double wantedX;
-     protected double wantedY;
-     protected double wantedZ;
-diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java
-index edd6d63f715acef1a77eba0cf46ff8267228f4c6..9b68809b91910d2bbb82cafe23d1de5dfff4221c 100644
---- a/src/main/java/net/minecraft/world/entity/animal/Bee.java
-+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java
-@@ -111,7 +111,17 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
- 
-     public Bee(EntityType<? extends Bee> type, Level world) {
-         super(type, world);
--        this.moveControl = new FlyingMoveControl(this, 20, true);
-+        // Paper start - apply gravity to bees when they get stuck in the void, fixes MC-167279
-+        this.moveControl = new FlyingMoveControl(this, 20, true) {
-+            @Override
-+            public void tick() {
-+                if (getEntity().getY() <= 0) {
-+                    getEntity().setNoGravity(false);
-+                }
-+                super.tick();
-+            }
-+        };
-+        // Paper end
-         this.lookControl = new Bee.BeeLookControl(this);
-         this.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, -1.0F);
-         this.setPathfindingMalus(BlockPathTypes.WATER, -1.0F);
diff --git a/patches/server-remapped/0425-Optimize-Collision-to-not-load-chunks.patch b/patches/server-remapped/0425-Optimize-Collision-to-not-load-chunks.patch
deleted file mode 100644
index 58edb5460..000000000
--- a/patches/server-remapped/0425-Optimize-Collision-to-not-load-chunks.patch
+++ /dev/null
@@ -1,185 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Aikar <aikar@aikar.co>
-Date: Thu, 2 Apr 2020 02:37:57 -0400
-Subject: [PATCH] Optimize Collision to not load chunks
-
-The collision code takes an AABB and generates a cuboid of checks rather
-than a cylinder, so at high velocity this can generate a lot of chunk checks.
-
-Treat an unloaded chunk as a collision for entities, and also for players if
-the "prevent moving into unloaded chunks" setting is enabled.
-
-If that serting is not enabled, collisions will be ignored for players, since
-movement will load only the chunk the player enters anyways and avoids loading
-massive amounts of surrounding chunks due to large AABB lookups.
-
-diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
-index dfdde9722bc0d83916779014b7718eef2c01b3db..86c5549196a4e9011c5240e7918b466c299be4a3 100644
---- a/src/main/java/net/minecraft/server/players/PlayerList.java
-+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
-@@ -59,12 +59,23 @@ import net.minecraft.server.MCUtil;
- import net.minecraft.server.MinecraftServer;
- import net.minecraft.server.PlayerAdvancements;
- import net.minecraft.server.ServerScoreboard;
-+import net.minecraft.server.level.ServerLevel;
-+import net.minecraft.server.level.ServerPlayer;
-+import net.minecraft.server.level.ServerPlayerGameMode;
-+import net.minecraft.server.level.TicketType;
-+import net.minecraft.server.network.ServerGamePacketListenerImpl;
-+import net.minecraft.server.network.ServerLoginPacketListenerImpl;
-+import net.minecraft.sounds.SoundEvents;
-+import net.minecraft.sounds.SoundSource;
-+import net.minecraft.stats.ServerStatsCounter;
-+import net.minecraft.stats.Stats;
- import net.minecraft.tags.BlockTags;
- import net.minecraft.tags.Tag;
- import net.minecraft.util.Mth;
- import net.minecraft.world.effect.MobEffectInstance;
- import net.minecraft.world.entity.Entity;
- import net.minecraft.world.entity.EntityType;
-+import net.minecraft.world.level.ChunkPos;
- import net.minecraft.world.level.GameRules;
- import net.minecraft.world.level.GameType;
- import net.minecraft.world.level.Level;
-@@ -90,15 +101,6 @@ import io.papermc.paper.adventure.PaperAdventure; // Paper
- import com.google.common.base.Predicate;
- import com.google.common.collect.Iterables;
- import net.minecraft.server.dedicated.DedicatedServer;
--import net.minecraft.server.level.ServerLevel;
--import net.minecraft.server.level.ServerPlayer;
--import net.minecraft.server.level.ServerPlayerGameMode;
--import net.minecraft.server.network.ServerGamePacketListenerImpl;
--import net.minecraft.server.network.ServerLoginPacketListenerImpl;
--import net.minecraft.sounds.SoundEvents;
--import net.minecraft.sounds.SoundSource;
--import net.minecraft.stats.ServerStatsCounter;
--import net.minecraft.stats.Stats;
- import org.bukkit.craftbukkit.CraftServer;
- import org.bukkit.craftbukkit.CraftWorld;
- 
-@@ -805,6 +807,7 @@ public abstract class PlayerList {
-         entityplayer1.forceSetPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
-         // CraftBukkit end
- 
-+        worldserver1.getChunkSource().addRegionTicket(TicketType.POST_TELEPORT, new ChunkPos(location.getBlockX() >> 4, location.getBlockZ() >> 4), 1, entityplayer.getId()); // Paper
-         while (avoidSuffocation && !worldserver1.noCollision(entityplayer1) && entityplayer1.getY() < 256.0D) {
-             entityplayer1.setPos(entityplayer1.getX(), entityplayer1.getY() + 1.0D, entityplayer1.getZ());
-         }
-diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
-index 7e198b94f349d4c4d61502f5ad8c60686800d88f..b8dcc91a191f25ca578e0858abf6c1b874fee15d 100644
---- a/src/main/java/net/minecraft/world/entity/Entity.java
-+++ b/src/main/java/net/minecraft/world/entity/Entity.java
-@@ -168,6 +168,7 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
-     private CraftEntity bukkitEntity;
- 
-     ChunkMap.TrackedEntity tracker; // Paper
-+    public boolean collisionLoadChunks = false; // Paper
-     public Throwable addedToWorldStack; // Paper - entity debug
-     public CraftEntity getBukkitEntity() {
-         if (bukkitEntity == null) {
-diff --git a/src/main/java/net/minecraft/world/level/CollisionGetter.java b/src/main/java/net/minecraft/world/level/CollisionGetter.java
-index d9e69195ee0af4dfb90bf0e8f4cc65e63f7ecf5b..1b52f2a0ce9cb847d7d57b38f4b8b6bed8de2cd9 100644
---- a/src/main/java/net/minecraft/world/level/CollisionGetter.java
-+++ b/src/main/java/net/minecraft/world/level/CollisionGetter.java
-@@ -54,7 +54,9 @@ public interface CollisionGetter extends BlockGetter {
-     }
- 
-     default boolean noCollision(@Nullable Entity entity, AABB axisalignedbb, Predicate<Entity> predicate) {
-+        try { if (entity != null) entity.collisionLoadChunks = true; // Paper
-         return this.getCollisions(entity, axisalignedbb, predicate).allMatch(VoxelShape::isEmpty);
-+        } finally { if (entity != null) entity.collisionLoadChunks = false; } // Paper
-     }
- 
-     Stream<VoxelShape> getEntityCollisions(@Nullable Entity entity, AABB axisalignedbb, Predicate<Entity> predicate);
-diff --git a/src/main/java/net/minecraft/world/level/CollisionSpliterator.java b/src/main/java/net/minecraft/world/level/CollisionSpliterator.java
-index 7208c61da48ce5e735810b6268490584e1d5c260..feca9ff34936686c0665ae0dbc926869087df3a7 100644
---- a/src/main/java/net/minecraft/world/level/CollisionSpliterator.java
-+++ b/src/main/java/net/minecraft/world/level/CollisionSpliterator.java
-@@ -7,6 +7,9 @@ import java.util.function.Consumer;
- import javax.annotation.Nullable;
- import net.minecraft.core.BlockPos;
- import net.minecraft.core.Cursor3D;
-+import net.minecraft.server.MCUtil;
-+import net.minecraft.server.level.ServerPlayer;
-+import net.minecraft.server.level.WorldGenRegion;
- import net.minecraft.util.Mth;
- import net.minecraft.world.entity.Entity;
- import net.minecraft.world.level.block.Blocks;
-@@ -21,13 +24,13 @@ import net.minecraft.world.phys.shapes.VoxelShape;
- public class CollisionSpliterator extends AbstractSpliterator<VoxelShape> {
- 
-     @Nullable
--    private final Entity source;
-+    private final Entity source; final Entity getEntity() { return this.source; } // Paper - OBFHELPER
-     private final AABB box;
-     private final CollisionContext context;
-     private final Cursor3D cursor;
--    private final BlockPos.MutableBlockPos pos;
-+    private final BlockPos.MutableBlockPos pos; final BlockPos.MutableBlockPos getMutablePos() { return this.pos; } // Paper - OBFHELPER
-     private final VoxelShape entityShape;
--    private final CollisionGetter collisionGetter;
-+    private final CollisionGetter collisionGetter; final CollisionGetter getCollisionAccess() { return this.collisionGetter; } // Paper - OBFHELPER
-     private boolean needsBorderCheck;
-     private final BiPredicate<BlockState, BlockPos> predicate;
- 
-@@ -64,23 +67,37 @@ public class CollisionSpliterator extends AbstractSpliterator<VoxelShape> {
-     boolean collisionCheck(Consumer<? super VoxelShape> consumer) {
-         while (true) {
-             if (this.cursor.advance()) {
--                int i = this.cursor.nextX();
--                int j = this.cursor.nextY();
--                int k = this.cursor.nextZ();
-+                int i = this.cursor.nextX(); final int x = i;
-+                int j = this.cursor.nextY(); final int y = j;
-+                int k = this.cursor.nextZ(); final int z = k;
-                 int l = this.cursor.getNextType();
- 
-                 if (l == 3) {
-                     continue;
-                 }
- 
--                BlockGetter iblockaccess = this.getChunk(i, k);
--
--                if (iblockaccess == null) {
-+                // Paper start - ensure we don't load chunks
-+                Entity entity = this.getEntity();
-+                BlockPos.MutableBlockPos blockposition_mutableblockposition = this.getMutablePos();
-+                boolean far = entity != null && MCUtil.distanceSq(entity.getX(), y, entity.getZ(), x, y, z) > 14;
-+                blockposition_mutableblockposition.setValues(x, y, z);
-+
-+                boolean isRegionLimited = this.getCollisionAccess() instanceof WorldGenRegion;
-+                BlockState iblockdata = isRegionLimited ? Blocks.VOID_AIR.defaultBlockState() : ((!far && entity instanceof ServerPlayer) || (entity != null && entity.collisionLoadChunks)
-+                    ? this.getCollisionAccess().getBlockState(blockposition_mutableblockposition)
-+                    : this.getCollisionAccess().getTypeIfLoaded(blockposition_mutableblockposition)
-+                );
-+
-+                if (iblockdata == null) {
-+                    if (!(entity instanceof ServerPlayer) || entity.level.paperConfig.preventMovingIntoUnloadedChunks) {
-+                        VoxelShape voxelshape3 = Shapes.of(far ? entity.getBoundingBox() : new AABB(new BlockPos(x, y, z)));
-+                        consumer.accept(voxelshape3);
-+                        return true;
-+                    }
-                     continue;
-                 }
--
--                this.pos.set(i, j, k);
--                BlockState iblockdata = iblockaccess.getBlockState(this.pos);
-+                // Paper - moved up
-+                // Paper end
- 
-                 if (!this.predicate.test(iblockdata, this.pos) || l == 1 && !iblockdata.hasLargeCollisionShape() || l == 2 && !iblockdata.is(Blocks.MOVING_PISTON)) {
-                     continue;
-diff --git a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
-index fa2942d0b0424390daee2121f8959034c5352e0b..c14d5ebe16a693834ed218af8f737714065b2e17 100644
---- a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
-+++ b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
-@@ -249,7 +249,8 @@ public final class Shapes {
- 
-                             if (k2 < 3) {
-                                 blockposition_mutableblockposition.set(enumaxiscycle1, i2, j2, l1);
--                                BlockState iblockdata = world.getBlockState(blockposition_mutableblockposition);
-+                                BlockState iblockdata = world.getTypeIfLoaded(blockposition_mutableblockposition); // Paper
-+                                if (iblockdata == null) return 0.0D; // Paper
- 
-                                 if ((k2 != 1 || iblockdata.hasLargeCollisionShape()) && (k2 != 2 || iblockdata.is(Blocks.MOVING_PISTON))) {
-                                     initial = iblockdata.getCollisionShape((BlockGetter) world, blockposition_mutableblockposition, context).collide(enumdirection_enumaxis2, box.move((double) (-blockposition_mutableblockposition.getX()), (double) (-blockposition_mutableblockposition.getY()), (double) (-blockposition_mutableblockposition.getZ())), initial);
diff --git a/patches/server-remapped/0401-Tracking-Range-Improvements.patch b/patches/server/0362-Tracking-Range-Improvements.patch
similarity index 90%
rename from patches/server-remapped/0401-Tracking-Range-Improvements.patch
rename to patches/server/0362-Tracking-Range-Improvements.patch
index ec1d0a178..b4d6875ed 100644
--- a/patches/server-remapped/0401-Tracking-Range-Improvements.patch
+++ b/patches/server/0362-Tracking-Range-Improvements.patch
@@ -8,10 +8,10 @@ Sets tracking range of watermobs to animals instead of misc and simplifies code
 Also ignores Enderdragon, defaulting it to Mojang's setting
 
 diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
-index 190ddd4d9ef3472c33d46c2ead72fa0dc918054a..6da406c8403797a1cd9276ac06577c3c080a8a22 100644
+index fdf5d8ede4b01e399272ddebfbd49258b166f00b..273cd2e0fc38801a5ecb26579e4d0e9ee017bb3c 100644
 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java
 +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
-@@ -1795,6 +1795,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
+@@ -1791,6 +1791,7 @@ Sections go from 0..16. Now whenever a section is not empty, it can potentially
              while (iterator.hasNext()) {
                  Entity entity = (Entity) iterator.next();
                  int j = entity.getType().clientTrackingRange() * 16;
@@ -20,7 +20,7 @@ index 190ddd4d9ef3472c33d46c2ead72fa0dc918054a..6da406c8403797a1cd9276ac06577c3c
                  if (j > i) {
                      i = j;
 diff --git a/src/main/java/org/spigotmc/TrackingRange.java b/src/main/java/org/spigotmc/TrackingRange.java
-index 8e3e36a8739a7dea1feb3785e96b7b9f19720446..b03fa9024c7f0238e1379f6ae4486db5300a70e9 100644
+index 2d5cb8991e368372f1ab227735aac0c060deb199..24b1dfcf91d36947c87e9e5c2524317f8775ba95 100644
 --- a/src/main/java/org/spigotmc/TrackingRange.java
 +++ b/src/main/java/org/spigotmc/TrackingRange.java
 @@ -6,7 +6,6 @@ import net.minecraft.world.entity.ExperienceOrb;
@@ -31,7 +31,7 @@ index 8e3e36a8739a7dea1feb3785e96b7b9f19720446..b03fa9024c7f0238e1379f6ae4486db5
  
  public class TrackingRange
  {
-@@ -25,26 +24,26 @@ public class TrackingRange
+@@ -29,26 +28,26 @@ public class TrackingRange
          if ( entity instanceof ServerPlayer )
          {
              return config.playerTrackingRange;
diff --git a/patches/server-remapped/0403-Fix-items-vanishing-through-end-portal.patch b/patches/server/0363-Fix-items-vanishing-through-end-portal.patch
similarity index 77%
rename from patches/server-remapped/0403-Fix-items-vanishing-through-end-portal.patch
rename to patches/server/0363-Fix-items-vanishing-through-end-portal.patch
index 283ad7000..e32fc1978 100644
--- a/patches/server-remapped/0403-Fix-items-vanishing-through-end-portal.patch
+++ b/patches/server/0363-Fix-items-vanishing-through-end-portal.patch
@@ -13,16 +13,16 @@ Quickly loading the exact world spawn chunk before searching the
 heightmap resolves the issue without having to load all spawn chunks.
 
 diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
-index c6881a9a5da2caed77dea30e4906d2dd99a624c1..efc9cb6def2f4ee327329dc090d2918ff60d8e19 100644
+index fffeba61e9af5c69876921b48241edb881af2a64..3d3286070c9c4db6d6487e119070794dadf493bd 100644
 --- a/src/main/java/net/minecraft/world/entity/Entity.java
 +++ b/src/main/java/net/minecraft/world/entity/Entity.java
-@@ -2734,6 +2734,9 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
+@@ -2983,6 +2983,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
              BlockPos blockposition1;
  
              if (flag1) {
 +                // Paper start - Ensure spawn chunk is always loaded before calculating Y coordinate
-+                this.level.getChunkAt(this.level.getSpawn());
++                this.level.getChunkAt(this.level.getSharedSpawnPos());
 +                // Paper end
                  blockposition1 = ServerLevel.END_SPAWN_POINT;
              } else {
-                 blockposition1 = destination.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, destination.getSpawn());
+                 blockposition1 = destination.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, destination.getSharedSpawnPos());
diff --git a/patches/server/0364-Bees-get-gravity-in-void.-Fixes-MC-167279.patch b/patches/server/0364-Bees-get-gravity-in-void.-Fixes-MC-167279.patch
new file mode 100644
index 000000000..adb34b3de
--- /dev/null
+++ b/patches/server/0364-Bees-get-gravity-in-void.-Fixes-MC-167279.patch
@@ -0,0 +1,29 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: William Blake Galbreath <Blake.Galbreath@GMail.com>
+Date: Sun, 26 Jan 2020 16:30:19 -0600
+Subject: [PATCH] Bees get gravity in void. Fixes MC-167279
+
+
+diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java
+index f3ba4b26553915917c79f013ed9dd7c87d9f65a4..b4cd490a1b2a2a118dc5f49bcb0fb755fbad853b 100644
+--- a/src/main/java/net/minecraft/world/entity/animal/Bee.java
++++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java
+@@ -143,7 +143,17 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
+     public Bee(EntityType<? extends Bee> type, Level world) {
+         super(type, world);
+         this.remainingCooldownBeforeLocatingNewFlower = Mth.nextInt(this.random, 20, 60);
+-        this.moveControl = new FlyingMoveControl(this, 20, true);
++        // Paper start - apply gravity to bees when they get stuck in the void, fixes MC-167279
++        this.moveControl = new FlyingMoveControl(this, 20, true) {
++            @Override
++            public void tick() {
++                if (this.mob.getY() <= 0) {
++                    this.mob.setNoGravity(false);
++                }
++                super.tick();
++            }
++        };
++        // Paper end
+         this.lookControl = new Bee.BeeLookControl(this);
+         this.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, -1.0F);
+         this.setPathfindingMalus(BlockPathTypes.WATER, -1.0F);
diff --git a/patches/server-remapped/0405-Optimise-getChunkAt-calls-for-loaded-chunks.patch b/patches/server/0365-Optimise-getChunkAt-calls-for-loaded-chunks.patch
similarity index 92%
rename from patches/server-remapped/0405-Optimise-getChunkAt-calls-for-loaded-chunks.patch
rename to patches/server/0365-Optimise-getChunkAt-calls-for-loaded-chunks.patch
index 009a0fad6..5eea71802 100644
--- a/patches/server-remapped/0405-Optimise-getChunkAt-calls-for-loaded-chunks.patch
+++ b/patches/server/0365-Optimise-getChunkAt-calls-for-loaded-chunks.patch
@@ -7,10 +7,10 @@ bypass the need to get a player chunk, then get the either,
 then unwrap it...
 
 diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
-index eac5e799c4d26e53286a27c54b56899ba0b9ffb2..3aeb8426b0461ec572c1499116be80f968bb4104 100644
+index c47d1772044913475a60292162ef4be594bed4c6..7cbd3db81c73d466a6e6012c1c91698b53a0cb86 100644
 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
 +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
-@@ -470,6 +470,12 @@ public class ServerChunkCache extends ChunkSource {
+@@ -451,6 +451,12 @@ public class ServerChunkCache extends ChunkSource {
                  return this.getChunk(x, z, leastStatus, create);
              }, this.mainThreadProcessor).join();
          } else {
@@ -23,7 +23,7 @@ index eac5e799c4d26e53286a27c54b56899ba0b9ffb2..3aeb8426b0461ec572c1499116be80f9
              ProfilerFiller gameprofilerfiller = this.level.getProfiler();
  
              gameprofilerfiller.incrementCounter("getChunk");
-@@ -520,39 +526,7 @@ public class ServerChunkCache extends ChunkSource {
+@@ -502,39 +508,7 @@ public class ServerChunkCache extends ChunkSource {
          if (Thread.currentThread() != this.mainThread) {
              return null;
          } else {
diff --git a/patches/server-remapped/0406-Allow-overriding-the-java-version-check.patch b/patches/server/0366-Allow-overriding-the-java-version-check.patch
similarity index 76%
rename from patches/server-remapped/0406-Allow-overriding-the-java-version-check.patch
rename to patches/server/0366-Allow-overriding-the-java-version-check.patch
index 04082e9a3..983fc278c 100644
--- a/patches/server-remapped/0406-Allow-overriding-the-java-version-check.patch
+++ b/patches/server/0366-Allow-overriding-the-java-version-check.patch
@@ -6,11 +6,11 @@ Subject: [PATCH] Allow overriding the java version check
 -DPaper.IgnoreJavaVersion=true
 
 diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
-index 808a7688ed81bdfef623ee0a151ff8f94df2a3d7..c519ceca6f7788ca7c5d74ad1001dbc09f62681c 100644
+index f68d44721c91c20a7e4abffe26dabff8b5d2c3ce..fd48cfe3dfaf7c867becfbf90246af2f33a74612 100644
 --- a/src/main/java/org/bukkit/craftbukkit/Main.java
 +++ b/src/main/java/org/bukkit/craftbukkit/Main.java
-@@ -181,7 +181,7 @@ public class Main {
-             float javaVersion = Float.parseFloat(System.getProperty("java.class.version"));
+@@ -185,7 +185,7 @@ public class Main {
+             }
              if (javaVersion > 60.0) {
                  System.err.println("Unsupported Java detected (" + javaVersion + "). Only up to Java 16 is supported.");
 -                return;
diff --git a/patches/server-remapped/0407-Add-ThrownEggHatchEvent.patch b/patches/server/0367-Add-ThrownEggHatchEvent.patch
similarity index 85%
rename from patches/server-remapped/0407-Add-ThrownEggHatchEvent.patch
rename to patches/server/0367-Add-ThrownEggHatchEvent.patch
index 5bc9d2e68..c02642759 100644
--- a/patches/server-remapped/0407-Add-ThrownEggHatchEvent.patch
+++ b/patches/server/0367-Add-ThrownEggHatchEvent.patch
@@ -7,10 +7,10 @@ Adds a new event similar to PlayerEggThrowEvent, but without the Player requirem
 (dispensers can throw eggs to hatch them, too).
 
 diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java
-index f3808a5e9155e1bf6c6219fc494864bb7dc61117..520eace73b569c2c77e76e0dfd18eb9c7188ec30 100644
+index 4e083dcd07e5975c7379035e72ac2f3469e919fd..77941e3981e49cf5662b3e3c86a9c419080b17c8 100644
 --- a/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java
 +++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownEgg.java
-@@ -63,6 +63,16 @@ public class ThrownEgg extends ThrowableItemProjectile {
+@@ -77,6 +77,14 @@ public class ThrownEgg extends ThrowableItemProjectile {
                      hatchingType = event.getHatchingType();
                  }
  
@@ -22,8 +22,6 @@ index f3808a5e9155e1bf6c6219fc494864bb7dc61117..520eace73b569c2c77e76e0dfd18eb9c
 +                hatching = event.isHatching();
 +                hatchingType = event.getHatchingType();
 +                // Paper end
-+
-+
                  if (hatching) {
                      for (int i = 0; i < b0; ++i) {
-                         Entity entity = level.getWorld().createEntity(new org.bukkit.Location(level.getWorld(), this.getX(), this.getY(), this.getZ(), this.yRot, 0.0F), hatchingType.getEntityClass());
+                         Entity entity = level.getWorld().createEntity(new org.bukkit.Location(level.getWorld(), this.getX(), this.getY(), this.getZ(), this.getYRot(), 0.0F), hatchingType.getEntityClass());
diff --git a/patches/server-remapped/0408-Optimise-random-block-ticking.patch b/patches/server/0368-Optimise-random-block-ticking.patch
similarity index 74%
rename from patches/server-remapped/0408-Optimise-random-block-ticking.patch
rename to patches/server/0368-Optimise-random-block-ticking.patch
index 881f7be3f..e6d451fad 100644
--- a/patches/server-remapped/0408-Optimise-random-block-ticking.patch
+++ b/patches/server/0368-Optimise-random-block-ticking.patch
@@ -70,23 +70,11 @@ index 0000000000000000000000000000000000000000..3edc8e52e06a62ce9f8cc734fd7458b3
 +        return fastRandomBounded(this.next(32) & 0xFFFFFFFFL, bound);
 +    }
 +}
-diff --git a/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java
-index b13e5d05d862ea8c6031b8071f525f00bc48f7e7..3db77d9eda98eacb099135643aff5e94751f4c7c 100644
---- a/src/main/java/net/minecraft/core/BlockPos.java
-+++ b/src/main/java/net/minecraft/core/BlockPos.java
-@@ -468,6 +468,7 @@ public class BlockPos extends Vec3i {
-             return this.set(Mth.floor(x), Mth.floor(y), Mth.floor(z));
-         }
- 
-+        public final BlockPos.MutableBlockPos setValues(final Vec3i baseblockposition) { return this.set(baseblockposition); } // Paper - OBFHELPER
-         public BlockPos.MutableBlockPos set(Vec3i pos) {
-             return this.set(pos.getX(), pos.getY(), pos.getZ());
-         }
 diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
-index bf1bb1530037ebcacc8d5a491789909bddb8b697..5d85895456b5d65954889cadf932027ea23b400b 100644
+index 67b9daee8d7e55fdf2015e6616f393f176b1ca96..ecb9c5a1958c89494417bdb3e6c6363f3fc84534 100644
 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java
 +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
-@@ -669,7 +669,12 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
+@@ -664,7 +664,12 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
          });
      }
  
@@ -100,7 +88,7 @@ index bf1bb1530037ebcacc8d5a491789909bddb8b697..5d85895456b5d65954889cadf932027e
          ChunkPos chunkcoordintpair = chunk.getPos();
          boolean flag = this.isRaining();
          int j = chunkcoordintpair.getMinBlockX();
-@@ -677,10 +682,10 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
+@@ -672,10 +677,10 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
          ProfilerFiller gameprofilerfiller = this.getProfiler();
  
          gameprofilerfiller.push("thunder");
@@ -108,12 +96,12 @@ index bf1bb1530037ebcacc8d5a491789909bddb8b697..5d85895456b5d65954889cadf932027e
 +        final BlockPos.MutableBlockPos blockposition = this.chunkTickMutablePosition; // Paper - use mutable to reduce allocation rate, final to force compile fail on change
  
          if (!this.paperConfig.disableThunder && flag && this.isThundering() && this.random.nextInt(100000) == 0) { // Paper - Disable thunder
--            blockposition = this.findLightingTargetAround(this.getBlockRandomPos(j, 0, k, 15));
-+            blockposition.setValues(this.findLightingTargetAround(this.getBlockRandomPos(j, 0, k, 15))); // Paper
+-            blockposition = this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15));
++            blockposition.set(this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15))); // Paper
              if (this.isRainingAt(blockposition)) {
                  DifficultyInstance difficultydamagescaler = this.getCurrentDifficultyAt(blockposition);
-                 boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * paperConfig.skeleHorseSpawnChance; // Paper
-@@ -703,59 +708,77 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
+                 boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * paperConfig.skeleHorseSpawnChance && !this.getBlockState(blockposition.below()).is(Blocks.LIGHTNING_ROD); // Paper
+@@ -698,66 +703,81 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
          }
  
          gameprofilerfiller.popPush("iceandsnow");
@@ -129,7 +117,7 @@ index bf1bb1530037ebcacc8d5a491789909bddb8b697..5d85895456b5d65954889cadf932027e
 +            // Paper end
              Biome biomebase = this.getBiome(blockposition);
  
--            if (biomebase.shouldFreeze(this, blockposition1)) {
+-            if (biomebase.shouldFreeze((LevelReader) this, blockposition1)) {
 -                org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition1, Blocks.ICE.defaultBlockState(), null); // CraftBukkit
 +            // Paper start - optimise chunk ticking
 +            blockposition.setY(downY);
@@ -138,18 +126,24 @@ index bf1bb1530037ebcacc8d5a491789909bddb8b697..5d85895456b5d65954889cadf932027e
 +                // Paper end
              }
  
-+            blockposition.setY(normalY); // Paper
-             if (flag && biomebase.shouldSnow(this, blockposition)) {
-                 org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition, Blocks.SNOW.defaultBlockState(), null); // CraftBukkit
-             }
+             if (flag) {
++                blockposition.setY(normalY); // Paper
+                 if (biomebase.shouldSnow(this, blockposition)) {
+                     org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition, Blocks.SNOW.defaultBlockState(), null); // CraftBukkit
+                 }
  
--            if (flag && this.getBiome(blockposition1).getPrecipitation() == Biome.Precipitation.RAIN) {
--                this.getBlockState(blockposition1).getBlock().handleRain((net.minecraft.world.level.Level) this, blockposition1);
-+            // Paper start - optimise chunk ticking
-+            blockposition.setY(downY);
-+            if (flag && this.getBiome(blockposition).getPrecipitation() == Biome.Precipitation.RAIN) {
-+                chunk.getBlockState(blockposition).getBlock().handleRain((net.minecraft.world.level.Level) this, blockposition);
-+                // Paper end
+-                BlockState iblockdata = this.getBlockState(blockposition1);
++                blockposition.setY(downY); // Paper
++                BlockState iblockdata = this.getBlockState(blockposition); // Paper
+                 Biome.Precipitation biomebase_precipitation = this.getBiome(blockposition).getPrecipitation();
+ 
+-                if (biomebase_precipitation == Biome.Precipitation.RAIN && biomebase.isColdEnoughToSnow(blockposition1)) {
++                if (biomebase_precipitation == Biome.Precipitation.RAIN && biomebase.isColdEnoughToSnow(blockposition)) { // Paper
+                     biomebase_precipitation = Biome.Precipitation.SNOW;
+                 }
+ 
+-                iblockdata.getBlock().handlePrecipitation(iblockdata, (net.minecraft.world.level.Level) this, blockposition1, biomebase_precipitation);
++                iblockdata.getBlock().handlePrecipitation(iblockdata, (net.minecraft.world.level.Level) this, blockposition, biomebase_precipitation); // Paper
              }
          }
  
@@ -160,27 +154,27 @@ index bf1bb1530037ebcacc8d5a491789909bddb8b697..5d85895456b5d65954889cadf932027e
          if (randomTickSpeed > 0) {
 -            LevelChunkSection[] achunksection = chunk.getSections();
 -            int l = achunksection.length;
+-
+-            for (int i1 = 0; i1 < l; ++i1) {
+-                LevelChunkSection chunksection = achunksection[i1];
 +            gameprofilerfiller.push("randomTick");
 +            timings.chunkTicksBlocks.startTiming(); // Paper
  
--            for (int i1 = 0; i1 < l; ++i1) {
--                LevelChunkSection chunksection = achunksection[i1];
-+            LevelChunkSection[] sections = chunk.getSections();
- 
 -                if (chunksection != LevelChunk.EMPTY_SECTION && chunksection.isRandomlyTicking()) {
 -                    int j1 = chunksection.bottomBlockY();
++            LevelChunkSection[] sections = chunk.getSections();
+ 
+-                    for (int k1 = 0; k1 < randomTickSpeed; ++k1) {
+-                        BlockPos blockposition2 = this.getBlockRandomPos(j, j1, k, 15);
 +            for (int sectionIndex = 0; sectionIndex < 16; ++sectionIndex) {
 +                LevelChunkSection section = sections[sectionIndex];
 +                if (section == null || section.tickingList.size() == 0) {
 +                    continue;
 +                }
  
--                    for (int k1 = 0; k1 < randomTickSpeed; ++k1) {
--                        BlockPos blockposition2 = this.getBlockRandomPos(j, j1, k, 15);
-+                int yPos = sectionIndex << 4;
- 
 -                        gameprofilerfiller.push("randomTick");
--                        BlockState iblockdata = chunksection.getBlockState(blockposition2.getX() - j, blockposition2.getY() - j1, blockposition2.getZ() - k);
+-                        BlockState iblockdata1 = chunksection.getBlockState(blockposition2.getX() - j, blockposition2.getY() - j1, blockposition2.getZ() - k);
++                int yPos = sectionIndex << 4;
 +                for (int a = 0; a < randomTickSpeed1; ++a) {
 +                    int tickingBlocks = section.tickingList.size();
 +                    int index = this.randomTickRandom.nextInt(16 * 16 * 16);
@@ -188,8 +182,8 @@ index bf1bb1530037ebcacc8d5a491789909bddb8b697..5d85895456b5d65954889cadf932027e
 +                        continue;
 +                    }
  
--                        if (iblockdata.isRandomlyTicking()) {
--                            iblockdata.randomTick(this, blockposition2, this.random);
+-                        if (iblockdata1.isRandomlyTicking()) {
+-                            iblockdata1.randomTick(this, blockposition2, this.random);
 -                        }
 +                    long raw = section.tickingList.getRaw(index);
 +                    int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw);
@@ -197,7 +191,7 @@ index bf1bb1530037ebcacc8d5a491789909bddb8b697..5d85895456b5d65954889cadf932027e
 +                    int randomY = ((location >>> (4 + 4)) & 255) | yPos;
 +                    int randomZ = (location >>> 4) & 15;
  
--                        FluidState fluid = iblockdata.getFluidState();
+-                        FluidState fluid = iblockdata1.getFluidState();
 +                    BlockPos blockposition2 = blockposition.setValues(j + randomX, randomY, k + randomZ);
 +                    BlockState iblockdata = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw);
  
@@ -220,12 +214,12 @@ index bf1bb1530037ebcacc8d5a491789909bddb8b697..5d85895456b5d65954889cadf932027e
 -        gameprofilerfiller.pop();
      }
  
-     protected BlockPos findLightingTargetAround(BlockPos pos) {
+     private Optional<BlockPos> findLightningRod(BlockPos pos) {
 diff --git a/src/main/java/net/minecraft/util/BitStorage.java b/src/main/java/net/minecraft/util/BitStorage.java
-index dd84984f28484cf7129c294222696784e128221a..9ea72751354e893cd3820befaa5df3e5e503de6e 100644
+index 9b955a027bd2c3cbcfa659a41a6687221c5fea63..6c036335b28258cd8c268173d73707af00d12bf9 100644
 --- a/src/main/java/net/minecraft/util/BitStorage.java
 +++ b/src/main/java/net/minecraft/util/BitStorage.java
-@@ -112,4 +112,32 @@ public class BitStorage {
+@@ -105,4 +105,32 @@ public class BitStorage {
          }
  
      }
@@ -259,7 +253,7 @@ index dd84984f28484cf7129c294222696784e128221a..9ea72751354e893cd3820befaa5df3e5
 +    // Paper end
  }
 diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java
-index 42b636c4ebb6eb83c8a9f3f5f9a766d37d065dc3..0e15ca2fb9cd1aeb4a075b8d50350dd7fd463c72 100644
+index e638d982b4bd1d261a7282cad6dab98ad0b55213..e305173fd1652a8b88ae8a9b94d0fae083e2da95 100644
 --- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java
 +++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java
 @@ -91,7 +91,7 @@ public class Turtle extends Animal {
@@ -272,10 +266,10 @@ index 42b636c4ebb6eb83c8a9f3f5f9a766d37d065dc3..0e15ca2fb9cd1aeb4a075b8d50350dd7
  
      public BlockPos getHomePos() { // Paper - public
 diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
-index 1d536d77518a70bdc1a23924aea99df1042b3cd5..632f32405053fbcff2fd26fa99f98c6add9f9dc7 100644
+index 07e81fa1119bba4981e34e70b9e67f43280f8071..5fccec12c0325dd9873905c5c3559128c3b4d9ad 100644
 --- a/src/main/java/net/minecraft/world/level/Level.java
 +++ b/src/main/java/net/minecraft/world/level/Level.java
-@@ -1472,10 +1472,18 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+@@ -1299,10 +1299,18 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
      public abstract TagContainer getTagManager();
  
      public BlockPos getBlockRandomPos(int x, int y, int z, int l) {
@@ -296,27 +290,24 @@ index 1d536d77518a70bdc1a23924aea99df1042b3cd5..632f32405053fbcff2fd26fa99f98c6a
  
      public boolean noSave() {
 diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
-index 4fef3abe4b416cbebe1b456468b5c3e162de18f1..87d7a87a2925f2c062658e960bb5128738828d9f 100644
+index 922026da8c234427e0322443004d3c32993adfce..88b053d8181d2a5abdb2c5527529a81855e1de7c 100644
 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
 +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
-@@ -639,8 +639,8 @@ public class LevelChunk implements ChunkAccess {
-         this.entities.remove(entity); // Paper
-     }
+@@ -568,6 +568,7 @@ public class LevelChunk implements ChunkAccess {
+     @Override
+     public void addEntity(Entity entity) {}
  
--    @Override
--    public int getHeight(Heightmap.Types type, int x, int z) {
 +    public final int getHighestBlockY(Heightmap.Types heightmap_type, int i, int j) { return this.getHeight(heightmap_type, i, j) + 1; } // Paper - sort of an obfhelper, but without -1
-+    @Override public int getHeight(Heightmap.Types type, int x, int z) { // Paper
+     @Override
+     public int getHeight(Heightmap.Types type, int x, int z) {
          return ((Heightmap) this.heightmaps.get(type)).getFirstAvailable(x & 15, z & 15) - 1;
-     }
- 
 diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
-index 38c7c5f18fc84d4a1de2da1ddc6d3ac37c25f341..c44d32f966c61497b4a8892eb51da3a71ad031d9 100644
+index 5fd66020a937b641e2a060cf38df731a43f3bf55..b5497272bc03a290298b5a829bdf653ac986866b 100644
 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
 +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
-@@ -14,12 +14,14 @@ import net.minecraft.world.level.material.FluidState;
- public class LevelChunkSection {
- 
+@@ -14,11 +14,12 @@ public class LevelChunkSection {
+     public static final int SECTION_HEIGHT = 16;
+     public static final int SECTION_SIZE = 4096;
      public static final Palette<BlockState> GLOBAL_BLOCKSTATE_PALETTE = new GlobalPalette<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState());
 -    private final int bottomBlockY;
 +    final int bottomBlockY; // Paper - private -> package-private
@@ -325,15 +316,13 @@ index 38c7c5f18fc84d4a1de2da1ddc6d3ac37c25f341..c44d32f966c61497b4a8892eb51da3a7
 +    short tickingBlockCount; // Paper - private -> package-private
      private short tickingFluidCount;
      final PalettedContainer<BlockState> states; // Paper - package-private
- 
 +    public final com.destroystokyo.paper.util.maplist.IBlockDataList tickingList = new com.destroystokyo.paper.util.maplist.IBlockDataList(); // Paper
-+
-     // Paper start - Anti-Xray - Add parameters
-     @Deprecated public LevelChunkSection(int yOffset) { this(yOffset, null, null, true); } // Notice for updates: Please make sure this constructor isn't used anywhere
-     public LevelChunkSection(int i, ChunkAccess chunk, Level world, boolean initializeBlocks) {
-@@ -74,6 +76,9 @@ public class LevelChunkSection {
+ 
+     public LevelChunkSection(int yOffset) {
+         this(yOffset, (short)0, (short)0, (short)0);
+@@ -70,6 +71,9 @@ public class LevelChunkSection {
              --this.nonEmptyBlockCount;
-             if (iblockdata1.isRandomlyTicking()) {
+             if (blockState.isRandomlyTicking()) {
                  --this.tickingBlockCount;
 +                // Paper start
 +                this.tickingList.remove(x, y, z);
@@ -341,7 +330,7 @@ index 38c7c5f18fc84d4a1de2da1ddc6d3ac37c25f341..c44d32f966c61497b4a8892eb51da3a7
              }
          }
  
-@@ -85,6 +90,9 @@ public class LevelChunkSection {
+@@ -81,6 +85,9 @@ public class LevelChunkSection {
              ++this.nonEmptyBlockCount;
              if (state.isRandomlyTicking()) {
                  ++this.tickingBlockCount;
@@ -351,7 +340,7 @@ index 38c7c5f18fc84d4a1de2da1ddc6d3ac37c25f341..c44d32f966c61497b4a8892eb51da3a7
              }
          }
  
-@@ -120,23 +128,29 @@ public class LevelChunkSection {
+@@ -116,22 +123,28 @@ public class LevelChunkSection {
      }
  
      public void recalcBlockCounts() {
@@ -361,36 +350,35 @@ index 38c7c5f18fc84d4a1de2da1ddc6d3ac37c25f341..c44d32f966c61497b4a8892eb51da3a7
          this.nonEmptyBlockCount = 0;
          this.tickingBlockCount = 0;
          this.tickingFluidCount = 0;
--        this.states.count((iblockdata, i) -> {
-+        this.states.forEachLocation((iblockdata, location) -> { // Paper
-             FluidState fluid = iblockdata.getFluidState();
- 
-             if (!iblockdata.isAir()) {
--                this.nonEmptyBlockCount = (short) (this.nonEmptyBlockCount + i);
-+                this.nonEmptyBlockCount = (short) (this.nonEmptyBlockCount + 1);
-                 if (iblockdata.isRandomlyTicking()) {
--                    this.tickingBlockCount = (short) (this.tickingBlockCount + i);
-+                    this.tickingBlockCount = (short) (this.tickingBlockCount + 1);
+-        this.states.count((state, count) -> {
++        this.states.forEachLocation((state, location) -> { // Paper
+             FluidState fluidState = state.getFluidState();
+             if (!state.isAir()) {
+-                this.nonEmptyBlockCount = (short)(this.nonEmptyBlockCount + count);
++                this.nonEmptyBlockCount = (short)(this.nonEmptyBlockCount + 1); // Paper
+                 if (state.isRandomlyTicking()) {
+-                    this.tickingBlockCount = (short)(this.tickingBlockCount + count);
 +                    // Paper start
-+                    this.tickingList.add(location, iblockdata);
++                    this.tickingBlockCount = (short)(this.tickingBlockCount + 1);
++                    this.tickingList.add(location, state);
 +                    // Paper end
                  }
              }
  
-             if (!fluid.isEmpty()) {
--                this.nonEmptyBlockCount = (short) (this.nonEmptyBlockCount + i);
-+                this.nonEmptyBlockCount = (short) (this.nonEmptyBlockCount + 1);
-                 if (fluid.isRandomlyTicking()) {
--                    this.tickingFluidCount = (short) (this.tickingFluidCount + i);
-+                    this.tickingFluidCount = (short) (this.tickingFluidCount + 1);
+             if (!fluidState.isEmpty()) {
+-                this.nonEmptyBlockCount = (short)(this.nonEmptyBlockCount + count);
++                this.nonEmptyBlockCount = (short) (this.nonEmptyBlockCount + 1); // Paper
+                 if (fluidState.isRandomlyTicking()) {
+-                    this.tickingFluidCount = (short)(this.tickingFluidCount + count);
++                    this.tickingFluidCount = (short) (this.tickingFluidCount + 1); // Paper
                  }
              }
  
 diff --git a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
-index dd252372e1e380674b1191e9ea265cbb10de437b..f93316b3ae5cd5fb960fa24f8c921b5b9276d9f3 100644
+index 5ea60bbb56450502f1ceb41959239ab579458ac2..5ac948b5b82f3144cdf402af440251cb8c7369d7 100644
 --- a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
 +++ b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java
-@@ -285,6 +285,14 @@ public class PalettedContainer<T> implements PaletteResize<T> {
+@@ -259,6 +259,14 @@ public class PalettedContainer<T> implements PaletteResize<T> {
          });
      }
  
@@ -404,4 +392,4 @@ index dd252372e1e380674b1191e9ea265cbb10de437b..f93316b3ae5cd5fb960fa24f8c921b5b
 +
      @FunctionalInterface
      public interface CountConsumer<T> {
- 
+         void accept(T object, int count);
diff --git a/patches/server-remapped/0409-Entity-Jump-API.patch b/patches/server/0369-Entity-Jump-API.patch
similarity index 87%
rename from patches/server-remapped/0409-Entity-Jump-API.patch
rename to patches/server/0369-Entity-Jump-API.patch
index 15c22b27a..9a2250744 100644
--- a/patches/server-remapped/0409-Entity-Jump-API.patch
+++ b/patches/server/0369-Entity-Jump-API.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Entity Jump API
 
 
 diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
-index b84dab1043c56e2deb58aec8639226f98db165d1..43fbe7d220f61802ae0cb0620ad078c5df7b69bc 100644
+index bd1cc5e6fea4b9a171718c1249f652782b7ce13e..6cc2d26403aa5074218b4b76e2d8ed9e8409a0ae 100644
 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
 +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
-@@ -2873,8 +2873,10 @@ public abstract class LivingEntity extends Entity {
+@@ -3159,8 +3159,10 @@ public abstract class LivingEntity extends Entity {
              } else if (this.isInLava() && (!this.onGround || d7 > d8)) {
                  this.jumpInLiquid((Tag) FluidTags.LAVA);
              } else if ((this.onGround || flag && d7 <= d8) && this.noJumpDelay == 0) {
@@ -20,10 +20,10 @@ index b84dab1043c56e2deb58aec8639226f98db165d1..43fbe7d220f61802ae0cb0620ad078c5
          } else {
              this.noJumpDelay = 0;
 diff --git a/src/main/java/net/minecraft/world/entity/animal/Panda.java b/src/main/java/net/minecraft/world/entity/animal/Panda.java
-index 1621d8748e96c6e1abb33b699a1273bb698f67d2..423bdbe25b6f2261cb5092378b0564a82faeecb4 100644
+index 2d59eab846db2c0a624cf6d06a570b2313aa6b13..851ee58e52c6003d6ae7b58c9b6b9a9a9795fa85 100644
 --- a/src/main/java/net/minecraft/world/entity/animal/Panda.java
 +++ b/src/main/java/net/minecraft/world/entity/animal/Panda.java
-@@ -489,7 +489,9 @@ public class Panda extends Animal {
+@@ -514,7 +514,9 @@ public class Panda extends Animal {
              Panda entitypanda = (Panda) iterator.next();
  
              if (!entitypanda.isBaby() && entitypanda.onGround && !entitypanda.isInWater() && entitypanda.canPerformAction()) {
@@ -34,7 +34,7 @@ index 1621d8748e96c6e1abb33b699a1273bb698f67d2..423bdbe25b6f2261cb5092378b0564a8
          }
  
 diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
-index a01bd035846df0e2e28dc55e2ef2f5f35b83f905..5dac3bf5a117bfbf57798238f0614558deafcd1b 100644
+index 5477f288db57d63051f4579b8cd3c19e3af430ee..76e9977f7b2f7fb50631fc56f3318d59d04b1398 100644
 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
 +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
 @@ -792,5 +792,19 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
diff --git a/patches/server-remapped/0410-Add-option-to-nerf-pigmen-from-nether-portals.patch b/patches/server/0370-Add-option-to-nerf-pigmen-from-nether-portals.patch
similarity index 58%
rename from patches/server-remapped/0410-Add-option-to-nerf-pigmen-from-nether-portals.patch
rename to patches/server/0370-Add-option-to-nerf-pigmen-from-nether-portals.patch
index d66918d01..ede8b0de9 100644
--- a/patches/server-remapped/0410-Add-option-to-nerf-pigmen-from-nether-portals.patch
+++ b/patches/server/0370-Add-option-to-nerf-pigmen-from-nether-portals.patch
@@ -5,24 +5,26 @@ Subject: [PATCH] Add option to nerf pigmen from nether portals
 
 
 diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
-index 7fbd501d70dccf869a4454e2789a5d68f2e15754..9e4591ddc4b755f4ff5a6f1078b51cb13db80480 100644
+index 3cd8895adecd345c3bdfb8b5e3e9fdf0ef9097db..e70e0b1115422b9b901c2879138433da2d4f94d8 100644
 --- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
 +++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
-@@ -594,4 +594,9 @@ public class PaperWorldConfig {
-         disableHopperMoveEvents = getBoolean("hopper.disable-move-event", disableHopperMoveEvents);
+@@ -441,6 +441,11 @@ public class PaperWorldConfig {
          log("Hopper Move Item Events: " + (disableHopperMoveEvents ? "disabled" : "enabled"));
      }
-+
+ 
 +    public boolean nerfNetherPortalPigmen = false;
 +    private void nerfNetherPortalPigmen() {
 +        nerfNetherPortalPigmen = getBoolean("game-mechanics.nerf-pigmen-from-nether-portals", nerfNetherPortalPigmen);
 +    }
- }
++
+     public int lightQueueSize = 20;
+     private void lightQueueSize() {
+         lightQueueSize = getInt("light-queue-size", lightQueueSize);
 diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
-index efc9cb6def2f4ee327329dc090d2918ff60d8e19..43f77d01fceab107d3502d282205aa579d64cc4b 100644
+index 3d3286070c9c4db6d6487e119070794dadf493bd..facb09e49d92d22dbcde7d187d4ba1c9a04202a9 100644
 --- a/src/main/java/net/minecraft/world/entity/Entity.java
 +++ b/src/main/java/net/minecraft/world/entity/Entity.java
-@@ -277,6 +277,7 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
+@@ -307,6 +307,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
      public long activatedTick = Integer.MIN_VALUE;
      public boolean isTemporarilyActive = false; // Paper
      public boolean spawnedViaMobSpawner; // Paper - Yes this name is similar to above, upstream took the better one
@@ -30,42 +32,34 @@ index efc9cb6def2f4ee327329dc090d2918ff60d8e19..43f77d01fceab107d3502d282205aa57
      protected int numCollisions = 0; // Paper
      public void inactiveTick() { }
      // Spigot end
-@@ -1693,6 +1694,9 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
+@@ -1861,6 +1862,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
              if (spawnedViaMobSpawner) {
-                 tag.putBoolean("Paper.FromMobSpawner", true);
+                 nbt.putBoolean("Paper.FromMobSpawner", true);
              }
 +            if (fromNetherPortal) {
-+                tag.putBoolean("Paper.FromNetherPortal", true);
++                nbt.putBoolean("Paper.FromNetherPortal", true);
 +            }
              // Paper end
-             return tag;
+             return nbt;
          } catch (Throwable throwable) {
-@@ -1827,6 +1831,7 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
+@@ -1999,6 +2003,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
              }
  
-             spawnedViaMobSpawner = tag.getBoolean("Paper.FromMobSpawner"); // Restore entity's from mob spawner status
-+            fromNetherPortal = tag.getBoolean("Paper.FromNetherPortal");
-             if (tag.contains("Paper.SpawnReason")) {
-                 String spawnReasonName = tag.getString("Paper.SpawnReason");
+             spawnedViaMobSpawner = nbt.getBoolean("Paper.FromMobSpawner"); // Restore entity's from mob spawner status
++            fromNetherPortal = nbt.getBoolean("Paper.FromNetherPortal");
+             if (nbt.contains("Paper.SpawnReason")) {
+                 String spawnReasonName = nbt.getString("Paper.SpawnReason");
                  try {
 diff --git a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java
-index 805d83a93bce20910d17c3f419bc085251b6cfc1..ae58929886921d0714bf811de92f99dc0dc120dc 100644
+index e34716f2a19eb578fef3f19182c124d359deb88f..cfea29f5bf1c5e74a0292c1344baaaa49c2f4403 100644
 --- a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java
 +++ b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java
-@@ -8,6 +8,7 @@ import net.minecraft.network.chat.Component;
- import net.minecraft.server.level.ServerLevel;
- import net.minecraft.world.entity.Entity;
- import net.minecraft.world.entity.EntityType;
-+import net.minecraft.world.entity.Mob;
- import net.minecraft.world.entity.MobSpawnType;
- import net.minecraft.world.entity.player.Player;
- import net.minecraft.world.level.BlockGetter;
-@@ -61,6 +62,8 @@ public class NetherPortalBlock extends Block {
+@@ -66,6 +66,8 @@ public class NetherPortalBlock extends Block {
  
                  if (entity != null) {
                      entity.setPortalCooldown();
 +                    entity.fromNetherPortal = true; // Paper
-+                    if (world.paperConfig.nerfNetherPortalPigmen) ((Mob) entity).aware = false; // Paper
++                    if (world.paperConfig.nerfNetherPortalPigmen) ((net.minecraft.world.entity.Mob) entity).aware = false; // Paper
                  }
              }
          }
diff --git a/patches/server-remapped/0411-Make-the-GUI-graph-fancier.patch b/patches/server/0371-Make-the-GUI-graph-fancier.patch
similarity index 80%
rename from patches/server-remapped/0411-Make-the-GUI-graph-fancier.patch
rename to patches/server/0371-Make-the-GUI-graph-fancier.patch
index c98d2918e..202d52ab0 100644
--- a/patches/server-remapped/0411-Make-the-GUI-graph-fancier.patch
+++ b/patches/server/0371-Make-the-GUI-graph-fancier.patch
@@ -109,7 +109,7 @@ index 0000000000000000000000000000000000000000..186fc722965e403f76b1480e1c2381fc
 +}
 diff --git a/src/main/java/com/destroystokyo/paper/gui/GuiStatsComponent.java b/src/main/java/com/destroystokyo/paper/gui/GuiStatsComponent.java
 new file mode 100644
-index 0000000000000000000000000000000000000000..0f29ad583e798c09b2fe3f568ed50cbc719e40e2
+index 0000000000000000000000000000000000000000..537bc6213545e8ff1b7b51bc4b27fd5b2a740883
 --- /dev/null
 +++ b/src/main/java/com/destroystokyo/paper/gui/GuiStatsComponent.java
 @@ -0,0 +1,41 @@
@@ -149,14 +149,14 @@ index 0000000000000000000000000000000000000000..0f29ad583e798c09b2fe3f568ed50cbc
 +        return new Dimension(350, 200);
 +    }
 +
-+    public void stop() { a(); } public void a() {
++    public void close() {
 +        timer.stop();
 +        ramGraph.stop();
 +    }
 +}
 diff --git a/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java
 new file mode 100644
-index 0000000000000000000000000000000000000000..c0923ec75ecced2e0a1c0d3ec2c046d69af3e9a9
+index 0000000000000000000000000000000000000000..23239679d6584f1088b2b94c46eb9a5c1f9ad91d
 --- /dev/null
 +++ b/src/main/java/com/destroystokyo/paper/gui/RAMDetails.java
 @@ -0,0 +1,73 @@
@@ -176,7 +176,7 @@ index 0000000000000000000000000000000000000000..c0923ec75ecced2e0a1c0d3ec2c046d6
 +import java.util.Vector;
 +
 +public class RAMDetails extends JList<String> {
-+    public static final DecimalFormat DECIMAL_FORMAT = Util.peek(new DecimalFormat("########0.000"), (format)
++    public static final DecimalFormat DECIMAL_FORMAT = Util.make(new DecimalFormat("########0.000"), (format)
 +        -> format.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ROOT)));
 +
 +    private final MinecraftServer server;
@@ -221,7 +221,7 @@ index 0000000000000000000000000000000000000000..c0923ec75ecced2e0a1c0d3ec2c046d6
 +        Vector<String> vector = new Vector<>();
 +        vector.add("Memory use: " + (data.getUsedMem() / 1024L / 1024L) + " mb (" + (data.getFree() * 100L / data.getMax()) + "% free)");
 +        vector.add("Heap: " + (data.getTotal() / 1024L / 1024L) + " / " + (data.getMax() / 1024L / 1024L) + " mb");
-+        vector.add("Avg tick: " + DECIMAL_FORMAT.format(getAverage(server.getTickTimes())) + " ms");
++        vector.add("Avg tick: " + DECIMAL_FORMAT.format(getAverage(server.tickTimes)) + " ms");
 +        setListData(vector);
 +    }
 +
@@ -383,57 +383,16 @@ index 0000000000000000000000000000000000000000..c3e54da4ab6440811aab2f9dd1e21880
 +        timer.stop();
 +    }
 +}
-diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java
-index cec5ad5052c8cf6059e9b117117846bdb217748f..c2f747226f10479c826849af898538610a2dd659 100644
---- a/src/main/java/net/minecraft/Util.java
-+++ b/src/main/java/net/minecraft/Util.java
-@@ -259,6 +259,7 @@ public class Util {
-         return factory.get();
-     }
- 
-+    public static <T> T peek(T t0, Consumer<T> consumer) { return make(t0, consumer); } // Paper - OBFHELPER
-     public static <T> T make(T object, Consumer<T> initializer) {
-         initializer.accept(object);
-         return object;
-diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
-index 7038897b8fb4c18ca97b95a3b24c30b40b62b005..e33189dc8375a3034910087654607fb531061636 100644
---- a/src/main/java/net/minecraft/server/MinecraftServer.java
-+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
-@@ -216,7 +216,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
-     private String motd;
-     private int maxBuildHeight;
-     private int playerIdleTimeout;
--    public final long[] tickTimes;
-+    public final long[] tickTimes; public long[] getTickTimes() { return tickTimes; } // Paper - OBFHELPER
-     @Nullable
-     private KeyPair keyPair;
-     @Nullable
 diff --git a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java
-index 2299349e701ffd5ee53cc5fe25f4d1e271cc3d65..2567c588a1dcf732800e6cf87352b020c7bb84d6 100644
+index 737ae68ab486a324628e994586862ef7397ae278..703d2bb93d6ab76fc117a320f155570addcc543c 100644
 --- a/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java
 +++ b/src/main/java/net/minecraft/server/gui/MinecraftServerGui.java
-@@ -91,9 +91,9 @@ public class MinecraftServerGui extends JComponent {
+@@ -95,7 +95,7 @@ public class MinecraftServerGui extends JComponent {
  
      private JComponent buildInfoPanel() {
          JPanel jpanel = new JPanel(new BorderLayout());
 -        StatsComponent guistatscomponent = new StatsComponent(this.server);
 +        com.destroystokyo.paper.gui.GuiStatsComponent guistatscomponent = new com.destroystokyo.paper.gui.GuiStatsComponent(this.server); // Paper
+         Collection<Runnable> collection = this.finalizers; // CraftBukkit - decompile error
  
--        this.finalizers.add(guistatscomponent::close);
-+        this.finalizers.add(guistatscomponent::a);
-         jpanel.add(guistatscomponent, "North");
-         jpanel.add(this.buildPlayerPanel(), "Center");
-         jpanel.setBorder(new TitledBorder(new EtchedBorder(), "Stats"));
-diff --git a/src/main/java/net/minecraft/server/gui/StatsComponent.java b/src/main/java/net/minecraft/server/gui/StatsComponent.java
-index 30960738de03edf7aa8745a176b3a2be86eaf282..09414d04208a843f8d337569b53f61b34e64ed92 100644
---- a/src/main/java/net/minecraft/server/gui/StatsComponent.java
-+++ b/src/main/java/net/minecraft/server/gui/StatsComponent.java
-@@ -13,7 +13,7 @@ import net.minecraft.server.MinecraftServer;
- 
- public class StatsComponent extends JComponent {
- 
--    private static final DecimalFormat DECIMAL_FORMAT = (DecimalFormat) Util.make((Object) (new DecimalFormat("########0.000")), (decimalformat) -> {
-+    private static final DecimalFormat DECIMAL_FORMAT = (DecimalFormat) Util.make(new DecimalFormat("########0.000"), (decimalformat) -> { // Paper - decompile error
-         decimalformat.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ROOT));
-     });
-     private final int[] values = new int[256];
+         Objects.requireNonNull(guistatscomponent);
diff --git a/patches/server-remapped/0412-add-hand-to-BlockMultiPlaceEvent.patch b/patches/server/0372-add-hand-to-BlockMultiPlaceEvent.patch
similarity index 89%
rename from patches/server-remapped/0412-add-hand-to-BlockMultiPlaceEvent.patch
rename to patches/server/0372-add-hand-to-BlockMultiPlaceEvent.patch
index e93352bf0..02e47511b 100644
--- a/patches/server-remapped/0412-add-hand-to-BlockMultiPlaceEvent.patch
+++ b/patches/server/0372-add-hand-to-BlockMultiPlaceEvent.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] add hand to BlockMultiPlaceEvent
 
 
 diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
-index e696d2e52532df25d74a1f559e2c9ca0f3d5058d..7d9a3b65b2d6b294d3a11414289e64fac88665f0 100644
+index c3341d1c4e9cda85b0b236461b0a00cbebc9a856..98bec353d6dbd85c7b329f75e09f4d0bfcfdaa6c 100644
 --- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
 +++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
-@@ -337,13 +337,18 @@ public class CraftEventFactory {
+@@ -339,13 +339,18 @@ public class CraftEventFactory {
          }
  
          org.bukkit.inventory.ItemStack item;
diff --git a/patches/server-remapped/0413-Prevent-teleporting-dead-entities.patch b/patches/server/0373-Prevent-teleporting-dead-entities.patch
similarity index 67%
rename from patches/server-remapped/0413-Prevent-teleporting-dead-entities.patch
rename to patches/server/0373-Prevent-teleporting-dead-entities.patch
index ef6164bd2..59a60c41a 100644
--- a/patches/server-remapped/0413-Prevent-teleporting-dead-entities.patch
+++ b/patches/server/0373-Prevent-teleporting-dead-entities.patch
@@ -5,15 +5,15 @@ Subject: [PATCH] Prevent teleporting dead entities
 
 
 diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index 2b79413bb8a592a7b7093e11d3a0cce895286c8f..09a663cc53cdf8ae45352b280200c8170dbbcdfc 100644
+index 9240064a17e7ac2492fe157b759d1f724105cd0e..fcfd57fd7af655aafb330986e8f6f9cc55819165 100644
 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
 +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-@@ -1468,6 +1468,10 @@ public class ServerGamePacketListenerImpl implements ServerGamePacketListener {
+@@ -1501,6 +1501,10 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
      }
  
-     private void internalTeleport(double d0, double d1, double d2, float f, float f1, Set<ClientboundPlayerPositionPacket.RelativeArgument> set) {
-+        if (player.removed) {
-+            LOGGER.info("Attempt to teleport dead player {} restricted", player.getScoreboardName());
+     private void internalTeleport(double d0, double d1, double d2, float f, float f1, Set<ClientboundPlayerPositionPacket.RelativeArgument> set, boolean flag) {
++        if (player.isRemoved()) {
++            LOGGER.info("Attempt to teleport removed player {} restricted", player.getScoreboardName());
 +            return;
 +        }
          // CraftBukkit start
diff --git a/patches/server-remapped/0414-Validate-tripwire-hook-placement-before-update.patch b/patches/server/0374-Validate-tripwire-hook-placement-before-update.patch
similarity index 85%
rename from patches/server-remapped/0414-Validate-tripwire-hook-placement-before-update.patch
rename to patches/server/0374-Validate-tripwire-hook-placement-before-update.patch
index 8fbefb7ae..37fe80e7f 100644
--- a/patches/server-remapped/0414-Validate-tripwire-hook-placement-before-update.patch
+++ b/patches/server/0374-Validate-tripwire-hook-placement-before-update.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Validate tripwire hook placement before update
 
 
 diff --git a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
-index f44d4809fe87c832e4d3bda429af2254e8c746d6..20428aff54527b664d988a6a0f54236b693fda89 100644
+index 3a5252afa9681fb1956493bead27e6cdb13679ca..0cfa1abca2c5744a4147b05905983ae4acaa569a 100644
 --- a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
 +++ b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java
-@@ -169,6 +169,7 @@ public class TripWireHookBlock extends Block {
+@@ -174,6 +174,7 @@ public class TripWireHookBlock extends Block {
  
          this.playSound(world, pos, flag4, flag5, flag2, flag3);
          if (!beingRemoved) {
diff --git a/patches/server-remapped/0415-Add-option-to-allow-iron-golems-to-spawn-in-air.patch b/patches/server/0375-Add-option-to-allow-iron-golems-to-spawn-in-air.patch
similarity index 85%
rename from patches/server-remapped/0415-Add-option-to-allow-iron-golems-to-spawn-in-air.patch
rename to patches/server/0375-Add-option-to-allow-iron-golems-to-spawn-in-air.patch
index 163f5b924..35a64d65e 100644
--- a/patches/server-remapped/0415-Add-option-to-allow-iron-golems-to-spawn-in-air.patch
+++ b/patches/server/0375-Add-option-to-allow-iron-golems-to-spawn-in-air.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Add option to allow iron golems to spawn in air
 
 
 diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
-index 9e4591ddc4b755f4ff5a6f1078b51cb13db80480..fe1c9dd8258ec8c3fdf343d4a44de2be2ae3d35f 100644
+index e70e0b1115422b9b901c2879138433da2d4f94d8..19e0532ea296d6862ab6508658726e96e05346c9 100644
 --- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
 +++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
-@@ -387,6 +387,11 @@ public class PaperWorldConfig {
+@@ -380,6 +380,11 @@ public class PaperWorldConfig {
          scanForLegacyEnderDragon = getBoolean("game-mechanics.scan-for-legacy-ender-dragon", true);
      }
  
@@ -21,10 +21,10 @@ index 9e4591ddc4b755f4ff5a6f1078b51cb13db80480..fe1c9dd8258ec8c3fdf343d4a44de2be
      private void armorStandEntityLookups() {
          armorStandEntityLookups = getBoolean("armor-stands-do-collision-entity-lookups", true);
 diff --git a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java
-index 9cedac83304847bdc92c2e97c4e6e119664c3bd0..59f0224b6a743408a03b642dd7cbe545f406c57e 100644
+index b5481299f551b7150425a4a1b1c21b43d8a1d382..ec00c2dd8f969eb99ec6a014e3bcd09c7484b237 100644
 --- a/src/main/java/net/minecraft/world/entity/animal/IronGolem.java
 +++ b/src/main/java/net/minecraft/world/entity/animal/IronGolem.java
-@@ -297,7 +297,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob {
+@@ -322,7 +322,7 @@ public class IronGolem extends AbstractGolem implements NeutralMob {
          BlockPos blockposition1 = blockposition.below();
          BlockState iblockdata = world.getBlockState(blockposition1);
  
diff --git a/patches/server-remapped/0416-Configurable-chance-of-villager-zombie-infection.patch b/patches/server/0376-Configurable-chance-of-villager-zombie-infection.patch
similarity index 63%
rename from patches/server-remapped/0416-Configurable-chance-of-villager-zombie-infection.patch
rename to patches/server/0376-Configurable-chance-of-villager-zombie-infection.patch
index 1bf93843e..7c01b2f51 100644
--- a/patches/server-remapped/0416-Configurable-chance-of-villager-zombie-infection.patch
+++ b/patches/server/0376-Configurable-chance-of-villager-zombie-infection.patch
@@ -8,37 +8,38 @@ This allows you to solve an issue in vanilla behavior where:
 * On normal difficulty they will have a 50% of getting infected or dying.
 
 diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
-index fe1c9dd8258ec8c3fdf343d4a44de2be2ae3d35f..525d702d78a609af987ebd2c32169b873e5c05ed 100644
+index 19e0532ea296d6862ab6508658726e96e05346c9..b57d9c84db5685b86cb077e3b42db7a8578d6f62 100644
 --- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
 +++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
-@@ -604,4 +604,9 @@ public class PaperWorldConfig {
-     private void nerfNetherPortalPigmen() {
+@@ -451,6 +451,11 @@ public class PaperWorldConfig {
          nerfNetherPortalPigmen = getBoolean("game-mechanics.nerf-pigmen-from-nether-portals", nerfNetherPortalPigmen);
      }
-+
+ 
 +    public double zombieVillagerInfectionChance = -1.0;
 +    private void zombieVillagerInfectionChance() {
 +        zombieVillagerInfectionChance = getDouble("zombie-villager-infection-chance", zombieVillagerInfectionChance);
 +    }
- }
++
+     public int lightQueueSize = 20;
+     private void lightQueueSize() {
+         lightQueueSize = getInt("light-queue-size", lightQueueSize);
 diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
-index 6fecf4188fc0247143edc688c03e645376960687..1e7c2c603b967c8c606efd94ce95a17c856f78d7 100644
+index ee17cba501e0cc4822bd1278d18b561c77fe9674..b036cbb9a1b6bcac91ffc8ee659fc95d6e04d5d4 100644
 --- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java
 +++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
-@@ -447,10 +447,14 @@ public class Zombie extends Monster {
+@@ -453,10 +453,13 @@ public class Zombie extends Monster {
      @Override
-     public void killed(ServerLevel worldserver, LivingEntity entityliving) {
-         super.killed(worldserver, entityliving);
--        if ((worldserver.getDifficulty() == Difficulty.NORMAL || worldserver.getDifficulty() == Difficulty.HARD) && entityliving instanceof Villager) {
--            if (worldserver.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) {
-+        // Paper start
-+        if (level.paperConfig.zombieVillagerInfectionChance != 0.0 && (level.paperConfig.zombieVillagerInfectionChance != -1.0 || worldserver.getDifficulty() == Difficulty.NORMAL || worldserver.getDifficulty() == Difficulty.HARD) && entityliving instanceof Villager) {
-+            if (level.paperConfig.zombieVillagerInfectionChance == -1.0 && worldserver.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) {
+     public void killed(ServerLevel world, LivingEntity other) {
+         super.killed(world, other);
+-        if ((world.getDifficulty() == Difficulty.NORMAL || world.getDifficulty() == Difficulty.HARD) && other instanceof Villager) {
+-            if (world.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) {
++        if (level.paperConfig.zombieVillagerInfectionChance != 0.0 && (level.paperConfig.zombieVillagerInfectionChance != -1.0 || world.getDifficulty() == Difficulty.NORMAL || world.getDifficulty() == Difficulty.HARD) && other instanceof Villager) {
++            if (level.paperConfig.zombieVillagerInfectionChance == -1.0 && world.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) {
                  return;
              }
 +            if (level.paperConfig.zombieVillagerInfectionChance != -1.0 && (this.random.nextDouble() * 100.0) > level.paperConfig.zombieVillagerInfectionChance) {
 +                return;
 +            } // Paper end
  
-             Villager entityvillager = (Villager) entityliving;
+             Villager entityvillager = (Villager) other;
              // CraftBukkit start
diff --git a/patches/server-remapped/0417-Optimise-Chunk-getFluid.patch b/patches/server/0377-Optimise-Chunk-getFluid.patch
similarity index 58%
rename from patches/server-remapped/0417-Optimise-Chunk-getFluid.patch
rename to patches/server/0377-Optimise-Chunk-getFluid.patch
index 2ba043c07..13d826375 100644
--- a/patches/server-remapped/0417-Optimise-Chunk-getFluid.patch
+++ b/patches/server/0377-Optimise-Chunk-getFluid.patch
@@ -8,22 +8,24 @@ faster on its own, however removing the try catch makes it
 easier to inline due to code size
 
 diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
-index 87d7a87a2925f2c062658e960bb5128738828d9f..8a14bdda4a408ec1e2b51efeb35467835f62b42c 100644
+index 88b053d8181d2a5abdb2c5527529a81855e1de7c..59a77541bbda880ae8f84e3535a2b6112caa78fb 100644
 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
 +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
-@@ -430,25 +430,29 @@ public class LevelChunk implements ChunkAccess {
+@@ -461,18 +461,20 @@ public class LevelChunk implements ChunkAccess {
      }
  
      public FluidState getFluidState(int x, int y, int z) {
 -        try {
--            if (y >= 0 && y >> 4 < this.sections.length) {
--                LevelChunkSection chunksection = this.sections[y >> 4];
+-            int l = this.getSectionIndex(y);
+-
+-            if (l >= 0 && l < this.sections.length) {
+-                LevelChunkSection chunksection = this.sections[l];
 -
 -                if (!LevelChunkSection.isEmpty(chunksection)) {
 -                    return chunksection.getFluidState(x & 15, y & 15, z & 15);
-+        //try {  // Paper - remove try catch
++        // try {  // Paper - remove try catch
 +        // Paper start - reduce the number of ops in this call
-+        int index = y >> 4;
++        int index = this.getSectionIndex(y);
 +            if (index >= 0 && index < this.sections.length) {
 +                LevelChunkSection chunksection = this.sections[index];
 +
@@ -34,17 +36,11 @@ index 87d7a87a2925f2c062658e960bb5128738828d9f..8a14bdda4a408ec1e2b51efeb3546783
              }
  
              return Fluids.EMPTY.defaultFluidState();
--        } catch (Throwable throwable) {
--            CrashReport crashreport = CrashReport.forThrowable(throwable, "Getting fluid state");
--            CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Block being got");
-+        /*} catch (Throwable throwable) { // Paper - remove try catch
-+            CrashReport crashreport = CrashReport.a(throwable, "Getting fluid state");
-+            CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Block being got");
- 
--            crashreportsystemdetails.setDetail("Location", () -> {
--                return CrashReportCategory.formatLocation(x, y, z);
-+            crashreportsystemdetails.a("Location", () -> {
-+                return CrashReportSystemDetails.a(i, j, k);
++        /* // Paper - remove try catch
+         } catch (Throwable throwable) {
+             CrashReport crashreport = CrashReport.forThrowable(throwable, "Getting fluid state");
+             CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Block being got");
+@@ -482,6 +484,7 @@ public class LevelChunk implements ChunkAccess {
              });
              throw new ReportedException(crashreport);
          }
@@ -53,15 +49,15 @@ index 87d7a87a2925f2c062658e960bb5128738828d9f..8a14bdda4a408ec1e2b51efeb3546783
  
      // CraftBukkit start
 diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
-index c44d32f966c61497b4a8892eb51da3a71ad031d9..5e7f6000df129100ef306703f325af9f60da8ae6 100644
+index b5497272bc03a290298b5a829bdf653ac986866b..fa350db3f4ada07a385d9f57b46aa799effb6039 100644
 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
 +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
-@@ -45,7 +45,7 @@ public class LevelChunkSection {
+@@ -42,7 +42,7 @@ public class LevelChunkSection {
      }
  
      public FluidState getFluidState(int x, int y, int z) {
--        return ((BlockState) this.states.get(x, y, z)).getFluidState();
-+        return ((BlockState) this.states.get(x, y, z)).getFluidState(); // Paper - diff on change - we expect this to be effectively just getType(x, y, z).getFluid(). If this changes we need to check other patches that use IBlockData#getFluid.
+-        return this.states.get(x, y, z).getFluidState();
++        return this.states.get(x, y, z).getFluidState(); // Paper - diff on change - we expect this to be effectively just getType(x, y, z).getFluid(). If this changes we need to check other patches that use IBlockData#getFluid.
      }
  
      public void acquire() {
diff --git a/patches/server-remapped/0418-Optimise-TickListServer-by-rewriting-it.patch b/patches/server/0378-Optimise-TickListServer-by-rewriting-it.patch
similarity index 66%
rename from patches/server-remapped/0418-Optimise-TickListServer-by-rewriting-it.patch
rename to patches/server/0378-Optimise-TickListServer-by-rewriting-it.patch
index 6cf945010..b5d38ff41 100644
--- a/patches/server-remapped/0418-Optimise-TickListServer-by-rewriting-it.patch
+++ b/patches/server/0378-Optimise-TickListServer-by-rewriting-it.patch
@@ -61,7 +61,7 @@ index 8bf4d2b8c38c02d6a5b2fea37113689a252f1571..da93d38fe63035e4ff198ada84a4431f
          ConfigurationSection section;
 diff --git a/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java b/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java
 new file mode 100644
-index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2d579909b
+index 0000000000000000000000000000000000000000..da13ff17609b7bc8076d9297edf8decf01a2ed88
 --- /dev/null
 +++ b/src/main/java/com/destroystokyo/paper/server/ticklist/PaperTickList.java
 @@ -0,0 +1,628 @@
@@ -168,7 +168,7 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +
 +    private void queueEntryForTick(final TickNextTickData<T> entry, final ServerChunkCache chunkProvider) {
 +        if (entry.tickState == STATE_SCHEDULED) {
-+            if (chunkProvider.isTickingReadyMainThread(entry.getPosition())) {
++            if (chunkProvider.isTickingReadyMainThread(entry.pos)) {
 +                this.toTickThisTick.add(entry);
 +                entry.tickState = STATE_PENDING_TICK;
 +            } else {
@@ -179,13 +179,13 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +    }
 +
 +    private void addToNotTickingReady(final TickNextTickData<T> entry) {
-+        this.pendingChunkTickLoad.computeIfAbsent(MCUtil.getCoordinateKey(entry.getPosition()), (long keyInMap) -> {
++        this.pendingChunkTickLoad.computeIfAbsent(MCUtil.getCoordinateKey(entry.pos), (long keyInMap) -> {
 +            return new ArrayList<>();
 +        }).add(entry);
 +    }
 +
 +    private void addToSchedule(final TickNextTickData<T> entry) {
-+        long delay = entry.getTargetTick() - (this.currentTick + 1);
++        long delay = entry.triggerTick - (this.currentTick + 1);
 +        if (delay < SHORT_SCHEDULE_TICK_THRESHOLD) {
 +            if (delay < 0) {
 +                // longScheduled orders by tick time, short scheduled does not
@@ -202,7 +202,7 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +        entry.tickState = STATE_CANCELLED_TICK;
 +        // short/long scheduled will skip the entry
 +
-+        final BlockPos pos = entry.getPosition();
++        final BlockPos pos = entry.pos;
 +        final long blockKey = MCUtil.getBlockKey(pos);
 +
 +        final ArrayList<TickNextTickData<T>> currentEntries = this.entriesByBlock.get(blockKey);
@@ -221,7 +221,7 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +            }
 +        }
 +
-+        final long chunkKey = MCUtil.getCoordinateKey(entry.getPosition());
++        final long chunkKey = MCUtil.getCoordinateKey(entry.pos);
 +
 +        ObjectRBTreeSet<TickNextTickData<T>> set = this.entriesByChunk.get(chunkKey);
 +
@@ -246,7 +246,7 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +            }
 +        }
 +
-+        long delay = entry.getTargetTick() - (this.currentTick + 1);
++        long delay = entry.triggerTick - (this.currentTick + 1);
 +        if (delay >= SHORT_SCHEDULE_TICK_THRESHOLD) {
 +            this.longScheduled.remove(entry);
 +        }
@@ -274,7 +274,7 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +
 +        // we don't remove items from shortScheduled (but do from longScheduled) because they're cleared at the end of
 +        // this tick
-+        if (this.longScheduled.isEmpty() || this.longScheduled.first().getTargetTick() > currentTick) {
++        if (this.longScheduled.isEmpty() || this.longScheduled.first().triggerTick > currentTick) {
 +            // nothing in longScheduled to worry about
 +            final TickListServerInterval<T> interval = this.shortScheduled[this.shortScheduledIndex];
 +            for (int i = 0, len = interval.byPriority.length; i < len; ++i) {
@@ -300,7 +300,7 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +                            longScheduledIterator.remove();
 +                            if (longScheduledIterator.hasNext()) {
 +                                longCurrent = longScheduledIterator.next();
-+                                if (longCurrent.getTargetTick() > currentTick) {
++                                if (longCurrent.triggerTick > currentTick) {
 +                                    longCurrent = null;
 +                                    break;
 +                                }
@@ -316,7 +316,7 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +
 +            // add remaining from long scheduled
 +            for (;;) {
-+                if (longCurrent == null || longCurrent.getTargetTick() > currentTick) {
++                if (longCurrent == null || longCurrent.triggerTick > currentTick) {
 +                    break;
 +                }
 +                longScheduledIterator.remove();
@@ -368,7 +368,7 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +                continue;
 +            }
 +            try {
-+                if (chunkProvider.isTickingReadyMainThread(toTick.getPosition())) {
++                if (chunkProvider.isTickingReadyMainThread(toTick.pos)) {
 +                    toTick.tickState = STATE_TICKING;
 +                    this.tickFunction.accept(toTick);
 +                    if (toTick.tickState == STATE_TICKING) {
@@ -384,7 +384,7 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +                CrashReport crashreport = CrashReport.forThrowable(thr, "Exception while ticking");
 +                CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Block being ticked");
 +
-+                CrashReportCategory.populateBlockDetails(crashreportsystemdetails, toTick.getPosition(), (BlockState) null);
++                CrashReportCategory.populateBlockDetails(crashreportsystemdetails, this.world, toTick.pos, (BlockState) null);
 +                throw new ReportedException(crashreport);
 +                // end copy from TickListServer
 +            }
@@ -413,7 +413,7 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +        }
 +        entry.tickState = STATE_UNSCHEDULED;
 +
-+        final BlockPos pos = entry.getPosition();
++        final BlockPos pos = entry.pos;
 +        final long blockKey = MCUtil.getBlockKey(pos);
 +
 +        final ArrayList<TickNextTickData<T>> currentEntries = this.entriesByBlock.get(blockKey);
@@ -432,7 +432,7 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +            }
 +        }
 +
-+        final long chunkKey = MCUtil.getCoordinateKey(entry.getPosition());
++        final long chunkKey = MCUtil.getCoordinateKey(entry.pos);
 +
 +        ObjectRBTreeSet<TickNextTickData<T>> set = this.entriesByChunk.get(chunkKey);
 +
@@ -446,7 +446,7 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +    }
 +
 +    @Override
-+    public boolean isPendingTickThisTick(final BlockPos blockposition, final T data) {
++    public boolean willTickThisTick(final BlockPos blockposition, final T data) {
 +        final ArrayList<TickNextTickData<T>> entries = this.entriesByBlock.get(MCUtil.getBlockKey(blockposition));
 +
 +        if (entries == null) {
@@ -455,7 +455,7 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +
 +        for (int i = 0, size = entries.size(); i < size; ++i) {
 +            final TickNextTickData<T> entry = entries.get(i);
-+            if (entry.getData() == data && entry.tickState == STATE_PENDING_TICK) {
++            if (entry.getType() == data && entry.tickState == STATE_PENDING_TICK) {
 +                return true;
 +            }
 +        }
@@ -464,7 +464,7 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +    }
 +
 +    @Override
-+    public boolean isScheduledForTick(final BlockPos blockposition, final T data) {
++    public boolean hasScheduledTick(final BlockPos blockposition, final T data) {
 +        final ArrayList<TickNextTickData<T>> entries = this.entriesByBlock.get(MCUtil.getBlockKey(blockposition));
 +
 +        if (entries == null) {
@@ -473,7 +473,7 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +
 +        for (int i = 0, size = entries.size(); i < size; ++i) {
 +            final TickNextTickData<T> entry = entries.get(i);
-+            if (entry.getData() == data && entry.tickState == STATE_SCHEDULED) {
++            if (entry.getType() == data && entry.tickState == STATE_SCHEDULED) {
 +                return true;
 +            }
 +        }
@@ -482,22 +482,22 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +    }
 +
 +    @Override
-+    public void schedule(BlockPos blockPosition, T t, int i, TickPriority tickListPriority) {
++    public void scheduleTick(BlockPos blockPosition, T t, int i, TickPriority tickListPriority) {
 +        this.schedule(blockPosition, t, i + this.currentTick, tickListPriority);
 +    }
 +
 +    public void schedule(final TickNextTickData<T> entry) {
-+        this.schedule(entry.getPosition(), entry.getData(), entry.getTargetTick(), entry.getPriority());
++        this.schedule(entry.pos, entry.getType(), entry.triggerTick, entry.priority);
 +    }
 +
 +    public void schedule(final BlockPos pos, final T data, final long targetTick, final TickPriority priority) {
 +        final TickNextTickData<T> entry = new TickNextTickData<>(pos, data, targetTick, priority);
-+        if (this.excludeFromScheduling.test(entry.getData())) {
++        if (this.excludeFromScheduling.test(entry.getType())) {
 +            return;
 +        }
 +
 +        if (WARN_ON_EXCESSIVE_DELAY) {
-+            final long delay = entry.getTargetTick() - this.currentTick;
++            final long delay = entry.triggerTick - this.currentTick;
 +            if (delay >= EXCESSIVE_DELAY_THRESHOLD) {
 +                MinecraftServer.LOGGER.warn("Entry " + entry.toString() + " has been scheduled with an excessive delay of: " + delay, new Throwable());
 +            }
@@ -514,7 +514,7 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +                final TickNextTickData<T> currentEntry = currentEntries.get(i);
 +
 +                // entries are only blocked from scheduling if currentEntry.equals(toSchedule) && currentEntry is scheduled to tick (NOT including pending)
-+                if (currentEntry.getData() == entry.getData() && currentEntry.tickState == STATE_SCHEDULED) {
++                if (currentEntry.getType() == entry.getType() && currentEntry.tickState == STATE_SCHEDULED) {
 +                    // can't add
 +                    return;
 +                }
@@ -524,7 +524,7 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +
 +        entry.tickState = STATE_SCHEDULED;
 +
-+        this.entriesByChunk.computeIfAbsent(MCUtil.getCoordinateKey(entry.getPosition()), (final long keyInMap) -> {
++        this.entriesByChunk.computeIfAbsent(MCUtil.getCoordinateKey(entry.pos), (final long keyInMap) -> {
 +            return new ObjectRBTreeSet<>(TickListServerInterval.ENTRY_COMPARATOR);
 +        }).add(entry);
 +
@@ -541,19 +541,19 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +    // i.e the y value is ignored? the x, z calc isn't correct?
 +    // however for the copy op they use the correct intersection, after using this one of course...
 +    private static boolean isBlockInSortof(final BoundingBox boundingBox, final BlockPos pos) {
-+        return pos.getX() >= boundingBox.getMinX() && pos.getX() < boundingBox.getMaxX() && pos.getZ() >= boundingBox.getMinZ() && pos.getZ() < boundingBox.getMaxZ();
++        return pos.getX() >= boundingBox.minX() && pos.getX() < boundingBox.maxX() && pos.getZ() >= boundingBox.minZ() && pos.getZ() < boundingBox.maxZ();
 +    }
 +
 +    @Override
-+    public List<TickNextTickData<T>> getEntriesInBoundingBox(final BoundingBox structureboundingbox, final boolean removeReturned, final boolean excludeTicked) {
-+        if (structureboundingbox.getMinX() == structureboundingbox.getMaxX() || structureboundingbox.getMinZ() == structureboundingbox.getMaxZ()) {
++    public List<TickNextTickData<T>> fetchTicksInArea(final BoundingBox structureboundingbox, final boolean removeReturned, final boolean excludeTicked) {
++        if (structureboundingbox.minX() == structureboundingbox.maxX() || structureboundingbox.minZ() == structureboundingbox.maxZ()) {
 +            return Collections.emptyList(); // vanilla behaviour, check isBlockInSortof above
 +        }
 +
-+        final int lowerChunkX = structureboundingbox.getMinX() >> 4;
-+        final int upperChunkX = (structureboundingbox.getMaxX() - 1) >> 4; // subtract 1 since maxX is exclusive
-+        final int lowerChunkZ = structureboundingbox.getMinZ() >> 4;
-+        final int upperChunkZ = (structureboundingbox.getMaxZ() - 1) >> 4; // subtract 1 since maxZ is exclusive
++        final int lowerChunkX = structureboundingbox.minX() >> 4;
++        final int upperChunkX = (structureboundingbox.maxX() - 1) >> 4; // subtract 1 since maxX is exclusive
++        final int lowerChunkZ = structureboundingbox.minZ() >> 4;
++        final int upperChunkZ = (structureboundingbox.maxZ() - 1) >> 4; // subtract 1 since maxZ is exclusive
 +
 +        final int xChunksLength = (upperChunkX - lowerChunkX + 1);
 +        final int zChunksLength = (upperChunkZ - lowerChunkZ + 1);
@@ -579,7 +579,7 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +        final int matchOne = (STATE_SCHEDULED | STATE_PENDING_TICK) | (excludeTicked ? 0 : (STATE_TICKING | STATE_TICKED));
 +
 +        MCUtil.mergeSortedSets((TickNextTickData<T> entry) -> {
-+            if (!isBlockInSortof(structureboundingbox, entry.getPosition())) {
++            if (!isBlockInSortof(structureboundingbox, entry.pos)) {
 +                return;
 +            }
 +            final int tickState = entry.tickState;
@@ -603,24 +603,24 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +    @Override
 +    public void copy(BoundingBox structureboundingbox, BlockPos blockposition) {
 +        // start copy from TickListServer // TODO check on update
-+        List<TickNextTickData<T>> list = this.getEntriesInBoundingBox(structureboundingbox, false, false);
++        List<TickNextTickData<T>> list = this.fetchTicksInArea(structureboundingbox, false, false);
 +        Iterator<TickNextTickData<T>> iterator = list.iterator();
 +
 +        while (iterator.hasNext()) {
 +            TickNextTickData<T> nextticklistentry = iterator.next();
 +
-+            if (structureboundingbox.hasPoint( nextticklistentry.getPosition())) {
-+                BlockPos blockposition1 = nextticklistentry.getPosition().add(blockposition);
-+                T t0 = nextticklistentry.getData();
++            if (structureboundingbox.isInside( nextticklistentry.pos)) {
++                BlockPos blockposition1 = nextticklistentry.pos.offset(blockposition);
++                T t0 = nextticklistentry.getType();
 +
-+                this.schedule(new TickNextTickData<>(blockposition1, t0, nextticklistentry.getTargetTick(), nextticklistentry.getPriority()));
++                this.schedule(new TickNextTickData<>(blockposition1, t0, nextticklistentry.triggerTick, nextticklistentry.priority));
 +            }
 +        }
 +        // end copy from TickListServer
 +    }
 +
 +    @Override
-+    public List<TickNextTickData<T>> getEntriesInChunk(ChunkPos chunkPos, boolean removeReturned, boolean excludeTicked) {
++    public List<TickNextTickData<T>> fetchTicksInChunk(ChunkPos chunkPos, boolean removeReturned, boolean excludeTicked) {
 +        // Vanilla DOES get the entries 2 blocks out of the chunk too, but that doesn't matter since we ignore chunks
 +        // not at ticking status, and ticking status requires neighbours loaded
 +        // so with this method we will reduce scheduler churning
@@ -651,16 +651,16 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +    }
 +
 +    @Override
-+    public ListTag serialize(ChunkPos chunkcoordintpair) {
++    public ListTag save(ChunkPos chunkcoordintpair) {
 +        // start copy from TickListServer  // TODO check on update
-+        List<TickNextTickData<T>> list = this.getEntriesInChunk(chunkcoordintpair, false, true);
++        List<TickNextTickData<T>> list = this.fetchTicksInChunk(chunkcoordintpair, false, true);
 +
-+        return ServerTickList.serialize(this.getMinecraftKeyFrom, list, this.currentTick);
++        return ServerTickList.saveTickList(this.getMinecraftKeyFrom, list, this.currentTick);
 +        // end copy from TickListServer
 +    }
 +
 +    @Override
-+    public int getTotalScheduledEntries() {
++    public int size() {
 +        // good thing this is only used in debug reports // TODO check on update
 +        int ret = 0;
 +
@@ -695,7 +695,7 @@ index 0000000000000000000000000000000000000000..1ce556fb808a8c93106e26da7b24f9a2
 +}
 diff --git a/src/main/java/com/destroystokyo/paper/server/ticklist/TickListServerInterval.java b/src/main/java/com/destroystokyo/paper/server/ticklist/TickListServerInterval.java
 new file mode 100644
-index 0000000000000000000000000000000000000000..d40a7aff6c27883f3ae8ba878a94c97242619f2c
+index 0000000000000000000000000000000000000000..a1e6f49274a7ae8057a9112e0dd6597a8e58e6da
 --- /dev/null
 +++ b/src/main/java/com/destroystokyo/paper/server/ticklist/TickListServerInterval.java
 @@ -0,0 +1,41 @@
@@ -713,7 +713,7 @@ index 0000000000000000000000000000000000000000..d40a7aff6c27883f3ae8ba878a94c972
 +    public static final Comparator<TickNextTickData<?>> ENTRY_COMPARATOR_BY_ID = (entry1, entry2) -> {
 +        return Long.compare(entry1.getId(), entry2.getId());
 +    };
-+    public static final Comparator<TickNextTickData<?>> ENTRY_COMPARATOR = (Comparator)TickNextTickData.comparator();
++    public static final Comparator<TickNextTickData<?>> ENTRY_COMPARATOR = (Comparator)TickNextTickData.createTimeComparator();
 +
 +    // we do not record the interval, this class is meant to be used on a ring buffer
 +
@@ -727,11 +727,11 @@ index 0000000000000000000000000000000000000000..d40a7aff6c27883f3ae8ba878a94c972
 +    }
 +
 +    public void addEntryLast(final TickNextTickData<T> entry) {
-+        this.byPriority[entry.getPriority().ordinal()].addLast(entry);
++        this.byPriority[entry.priority.ordinal()].addLast(entry);
 +    }
 +
 +    public void addEntryFirst(final TickNextTickData<T> entry) {
-+        this.byPriority[entry.getPriority().ordinal()].addFirst(entry);
++        this.byPriority[entry.priority.ordinal()].addFirst(entry);
 +    }
 +
 +    public void clear() {
@@ -888,64 +888,63 @@ index 0000000000000000000000000000000000000000..118988c39e58f28e8a2851792b9c014f
 +        }
 +    }
 +}
-diff --git a/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java
-index 3db77d9eda98eacb099135643aff5e94751f4c7c..595abf528a7862478100770987906af1b13439fe 100644
---- a/src/main/java/net/minecraft/core/BlockPos.java
-+++ b/src/main/java/net/minecraft/core/BlockPos.java
-@@ -111,6 +111,7 @@ public class BlockPos extends Vec3i {
-         return x == 0 && y == 0 && z == 0 ? this : new BlockPos(this.getX() + x, this.getY() + y, this.getZ() + z);
-     }
- 
-+    public final BlockPos add(Vec3i baseblockposition) { return this.offset(baseblockposition); } // Paper - OBFHELPER
-     public BlockPos offset(Vec3i pos) {
-         return this.offset(pos.getX(), pos.getY(), pos.getZ());
-     }
 diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
-index 77d3969200ac6f88f3af9add05def0b627ce6db3..d12d5459c847d3f0d655c85e31d81c27b7a2face 100644
+index 995d7977233f0d7683c00a75c3833f9a1eba7f92..58369d70bcd8b2c25609b6f101d9cbe2031df352 100644
 --- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
 +++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
-@@ -495,7 +495,9 @@ public class ChunkHolder {
+@@ -86,6 +86,19 @@ public class ChunkHolder {
+         return null;
+     }
+     // Paper end - no-tick view distance
++    // Paper start
++    public final boolean isEntityTickingReady() {
++        return this.isEntityTickingReady;
++    }
++
++    public final boolean isTickingReady() {
++        return this.isTickingReady;
++    }
++
++    public final boolean isFullChunkReady() {
++        return this.isFullChunkReady;
++    }
++    // Paper end
+ 
+     public ChunkHolder(ChunkPos pos, int level, LevelHeightAccessor world, LevelLightEngine lightingProvider, ChunkHolder.LevelChangeListener levelUpdateListener, ChunkHolder.PlayerProvider playersWatchingChunkProvider) {
+         this.futures = new AtomicReferenceArray(ChunkHolder.CHUNK_STATUSES.size());
+@@ -547,6 +560,10 @@ public class ChunkHolder {
+                 either.ifLeft(chunk -> {
+                     // note: Here is a very good place to add callbacks to logic waiting on this.
                      ChunkHolder.this.isTickingReady = true;
- 
- 
--
++
 +                    // Paper start - rewrite ticklistserver
 +                    ChunkHolder.this.chunkMap.level.onChunkSetTicking(ChunkHolder.this.pos.x, ChunkHolder.this.pos.z);
 +                    // Paper end - rewrite ticklistserver
- 
-                 }
+                 });
              });
+             // Paper end
 diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
-index 3aeb8426b0461ec572c1499116be80f968bb4104..e2b1541042bceac965411e3176d08c61f217c07f 100644
+index 7cbd3db81c73d466a6e6012c1c91698b53a0cb86..382a68c76e8946840de62f05483870689de80278 100644
 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
 +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
-@@ -21,6 +21,7 @@ import net.minecraft.Util;
- import net.minecraft.core.BlockPos;
- import net.minecraft.core.SectionPos;
- import net.minecraft.network.protocol.Packet;
-+import net.minecraft.server.MCUtil;
- import net.minecraft.server.level.progress.ChunkProgressListener;
- import net.minecraft.util.Mth;
- import net.minecraft.util.profiling.ProfilerFiller;
-@@ -217,6 +218,13 @@ public class ServerChunkCache extends ChunkSource {
+@@ -220,6 +220,12 @@ public class ServerChunkCache extends ChunkSource {
+         }, this.mainThreadProcessor);
      }
      // Paper end
- 
 +    // Paper start - rewrite ticklistserver
 +    public final boolean isTickingReadyMainThread(BlockPos pos) {
-+        ChunkHolder chunk = this.chunkMap.getUpdatingChunkIfPresent(MCUtil.getCoordinateKey(pos));
++        ChunkHolder chunk = this.chunkMap.getUpdatingChunkIfPresent(net.minecraft.server.MCUtil.getCoordinateKey(pos));
 +        return chunk != null && chunk.isTickingReady();
 +    }
 +    // Paper end - rewrite ticklistserver
-+
-     public ServerChunkCache(ServerLevel worldserver, LevelStorageSource.LevelStorageAccess convertable_conversionsession, DataFixer dataFixer, StructureManager structureManager, Executor workerExecutor, ChunkGenerator chunkGenerator, int viewDistance, boolean flag, ChunkProgressListener worldloadlistener, Supplier<DimensionDataStorage> supplier) {
-         this.level = worldserver;
-         this.mainThreadProcessor = new ServerChunkCache.MainThreadExecutor(worldserver);
+ 
+     public ServerChunkCache(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureManager structureManager, Executor workerExecutor, ChunkGenerator chunkGenerator, int viewDistance, boolean flag, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkstatusupdatelistener, Supplier<DimensionDataStorage> supplier) {
+         this.level = world;
 diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
-index 5d85895456b5d65954889cadf932027ea23b400b..9da0d98bc2ed7876a00a734690ed42f01b9a9a9b 100644
+index ecb9c5a1958c89494417bdb3e6c6363f3fc84534..385b8e707406173ea5258aff87af719ce93aecf3 100644
 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java
 +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
-@@ -292,6 +292,15 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
+@@ -286,6 +286,15 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
      }
      // Paper end
  
@@ -960,273 +959,127 @@ index 5d85895456b5d65954889cadf932027ea23b400b..9da0d98bc2ed7876a00a734690ed42f0
 +
      // Add env and gen to constructor, WorldData -> WorldDataServer
      public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, ServerLevelData iworlddataserver, ResourceKey<net.minecraft.world.level.Level> resourcekey, DimensionType dimensionmanager, ChunkProgressListener worldloadlistener, ChunkGenerator chunkgenerator, boolean flag, long i, List<CustomSpawner> list, boolean flag1, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) {
-         super(iworlddataserver, resourcekey, dimensionmanager, minecraftserver::getProfiler, false, flag, i, gen, env, executor); // Paper pass executor
-@@ -299,12 +308,21 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
-         convertable = convertable_conversionsession;
-         uuid = WorldUUID.getUUID(convertable_conversionsession.levelPath.toFile());
-         // CraftBukkit end
--        this.blockTicks = new ServerTickList<>(this, (block) -> {
--            return block == null || block.defaultBlockState().isAir();
--        }, Registry.BLOCK::getKey, this::tickBlock, "Blocks"); // Paper - Timings
--        this.liquidTicks = new ServerTickList<>(this, (fluidtype) -> {
--            return fluidtype == null || fluidtype == Fluids.EMPTY;
--        }, Registry.FLUID::getKey, this::tickLiquid, "Fluids"); // Paper - Timings
+         // Objects.requireNonNull(minecraftserver); // CraftBukkit - decompile error
+@@ -302,13 +311,19 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
+         DefaultedRegistry registryblocks = Registry.BLOCK;
+ 
+         Objects.requireNonNull(registryblocks);
+-        this.blockTicks = new ServerTickList<>(this, predicate, Registry.BLOCK::getKey, this::tickBlock, "Blocks"); // CraftBukkit - decompile error // Paper - Timings
++        // this.blockTicks = new ServerTickList<>(this, predicate, Registry.BLOCK::getKey, this::tickBlock, "Blocks"); // CraftBukkit - decompile error // Paper - Timings // Paper - copied down
+         Predicate<Fluid> predicate2 = (fluidtype) -> { // CraftBukkit - decompile error
+             return fluidtype == null || fluidtype == Fluids.EMPTY;
+         };
+         registryblocks = Registry.FLUID;
+         Objects.requireNonNull(registryblocks);
 +        if (com.destroystokyo.paper.PaperConfig.useOptimizedTickList) {
-+            this.blockTicks = new com.destroystokyo.paper.server.ticklist.PaperTickList<>(this, (block) -> {
-+                return block == null || block.defaultBlockState().isAir();
-+            }, Registry.BLOCK::getKey, this::tickBlock, "Blocks"); // Paper - Timings
-+            this.liquidTicks = new com.destroystokyo.paper.server.ticklist.PaperTickList<>(this, (fluidtype) -> {
-+                return fluidtype == null || fluidtype == Fluids.EMPTY;
-+            }, Registry.FLUID::getKey, this::tickLiquid, "Fluids"); // Paper - Timings
++            this.blockTicks = new com.destroystokyo.paper.server.ticklist.PaperTickList<>(this, predicate, Registry.BLOCK::getKey, this::tickBlock, "Blocks"); // Paper - Timings
++            this.liquidTicks = new com.destroystokyo.paper.server.ticklist.PaperTickList<>(this, predicate2, Registry.FLUID::getKey, this::tickLiquid, "Fluids"); // Paper timings
 +        } else {
-+            this.blockTicks = new ServerTickList<>(this, (block) -> {
-+                return block == null || block.defaultBlockState().isAir();
-+            }, Registry.BLOCK::getKey, this::tickBlock, "Blocks"); // Paper - Timings
-+            this.liquidTicks = new ServerTickList<>(this, (fluidtype) -> {
-+                return fluidtype == null || fluidtype == Fluids.EMPTY;
-+            }, Registry.FLUID::getKey, this::tickLiquid, "Fluids"); // Paper - Timings
++            this.blockTicks = new ServerTickList<>(this, predicate, Registry.BLOCK::getKey, this::tickBlock, "Blocks"); // CraftBukkit - decompile error // Paper - Timings & copied from above
+         this.liquidTicks = new ServerTickList<>(this, predicate2, Registry.FLUID::getKey, this::tickLiquid, "Fluids"); // CraftBukkit - decompile error // Paper - Timings
 +        }
-         this.navigations = Sets.newHashSet();
+         this.navigatingMobs = new ObjectOpenHashSet();
          this.blockEvents = new ObjectLinkedOpenHashSet();
-         this.tickTime = flag1;
-@@ -639,7 +657,9 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
+         this.dragonParts = new Int2ObjectOpenHashMap();
+@@ -629,7 +644,9 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
          if (this.tickTime) {
              long i = this.levelData.getGameTime() + 1L;
  
--            this.worldDataServer.setGameTime(i);
-+            this.worldDataServer.setGameTime(i); // Paper - diff on change, we want the below to be ran right after this
+-            this.serverLevelData.setGameTime(i);
++            this.serverLevelData.setGameTime(i); ; // Paper - diff on change, we want the below to be ran right after this
 +            this.blockTicks.nextTick(); // Paper
 +            this.liquidTicks.nextTick(); // Paper
-             this.worldDataServer.getScheduledEvents().tick(this.server, i);
+             this.serverLevelData.getScheduledEvents().tick(this.server, i);
              if (this.levelData.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)) {
                  this.setDayTime(this.levelData.getDayTime() + 1L);
 diff --git a/src/main/java/net/minecraft/world/level/ChunkTickList.java b/src/main/java/net/minecraft/world/level/ChunkTickList.java
-index 16757eb9c03c0dab51a7a1b569daff81cf9654f3..3008e0c42efe908e45dba1a1437928d4d4378f24 100644
+index 1a05edf041cf4aeee7c165fec564ce45adbdd5c7..febc837d324cbe2cd83aea6c1e0d298c70f45f78 100644
 --- a/src/main/java/net/minecraft/world/level/ChunkTickList.java
 +++ b/src/main/java/net/minecraft/world/level/ChunkTickList.java
-@@ -9,6 +9,7 @@ import net.minecraft.core.BlockPos;
- import net.minecraft.nbt.CompoundTag;
- import net.minecraft.nbt.ListTag;
- import net.minecraft.resources.ResourceLocation;
-+import net.minecraft.server.MinecraftServer;
+@@ -15,7 +15,7 @@ public class ChunkTickList<T> implements TickList<T> {
  
- public class ChunkTickList<T> implements TickList<T> {
+     public ChunkTickList(Function<T, ResourceLocation> identifierProvider, List<TickNextTickData<T>> scheduledTicks, long startTime) {
+         this(identifierProvider, scheduledTicks.stream().map((tickNextTickData) -> {
+-            return new ChunkTickList.ScheduledTick(tickNextTickData.getType(), tickNextTickData.pos, (int)(tickNextTickData.triggerTick - startTime), tickNextTickData.priority);
++            return new ChunkTickList.ScheduledTick<>(tickNextTickData.getType(), tickNextTickData.pos, (int)(tickNextTickData.triggerTick - startTime), tickNextTickData.priority); // Paper - decompile error
+         }).collect(Collectors.toList()));
+     }
  
-@@ -61,6 +62,8 @@ public class ChunkTickList<T> implements TickList<T> {
-         return nbttaglist;
+@@ -56,6 +56,7 @@ public class ChunkTickList<T> implements TickList<T> {
+         return listTag;
      }
  
 +    private static final int MAX_TICK_DELAY = Integer.getInteger("paper.ticklist-max-tick-delay", -1).intValue(); // Paper - clean up broken entries
-+
-     public static <T> ChunkTickList<T> create(ListTag ticks, Function<T, ResourceLocation> function, Function<ResourceLocation, T> function1) {
+     public static <T> ChunkTickList<T> create(ListTag ticks, Function<T, ResourceLocation> function, Function<ResourceLocation, T> function2) {
          List<ChunkTickList.ScheduledTick<T>> list = Lists.newArrayList();
  
-@@ -71,7 +74,14 @@ public class ChunkTickList<T> implements TickList<T> {
-             if (t0 != null) {
-                 BlockPos blockposition = new BlockPos(nbttagcompound.getInt("x"), nbttagcompound.getInt("y"), nbttagcompound.getInt("z"));
- 
--                list.add(new ChunkTickList.ScheduledTick<>(t0, blockposition, nbttagcompound.getInt("t"), TickPriority.byValue(nbttagcompound.getInt("p"))));
+@@ -64,7 +65,14 @@ public class ChunkTickList<T> implements TickList<T> {
+             T object = function2.apply(new ResourceLocation(compoundTag.getString("i")));
+             if (object != null) {
+                 BlockPos blockPos = new BlockPos(compoundTag.getInt("x"), compoundTag.getInt("y"), compoundTag.getInt("z"));
+-                list.add(new ChunkTickList.ScheduledTick<>(object, blockPos, compoundTag.getInt("t"), TickPriority.byValue(compoundTag.getInt("p"))));
 +                // Paper start - clean up broken entries
-+                int delay = nbttagcompound.getInt("t");
++                int delay = compoundTag.getInt("t");
 +                if (MAX_TICK_DELAY > 0 && delay > MAX_TICK_DELAY) {
-+                    MinecraftServer.LOGGER.warn("Dropping tick for pos " + blockposition + ", tick delay " + delay);
++                    net.minecraft.server.MinecraftServer.LOGGER.warn("Dropping tick for pos " + blockPos + ", tick delay " + delay);
 +                    continue;
 +                }
-+                list.add(new ChunkTickList.ScheduledTick<>(t0, blockposition, delay, TickPriority.byValue(nbttagcompound.getInt("p"))));
 +                // Paper end - clean up broken entries
++                list.add(new ChunkTickList.ScheduledTick<>(object, blockPos, delay, TickPriority.byValue(compoundTag.getInt("p"))));
              }
          }
  
 diff --git a/src/main/java/net/minecraft/world/level/ServerTickList.java b/src/main/java/net/minecraft/world/level/ServerTickList.java
-index 10ac1ba0a3d192486f22c2127d5bc30353f0edb6..65b3a16f40a295c2916be2a9fd019b452fb65e4f 100644
+index 702203f4a4fa4fc03c35ec974a97e08ed0f3c67c..609c8ece9e9f151875bf8191cc671206ee1e5f68 100644
 --- a/src/main/java/net/minecraft/world/level/ServerTickList.java
 +++ b/src/main/java/net/minecraft/world/level/ServerTickList.java
-@@ -50,7 +50,16 @@ public class ServerTickList<T> implements TickList<T> {
+@@ -49,6 +49,9 @@ public class ServerTickList<T> implements TickList<T> {
      private final co.aikar.timings.Timing timingTicking; // Paper
      // Paper end
  
 +    // Paper start
 +    public void nextTick() {}
 +    // Paper end
-+
-+    public void tick() {
-+        // Paper start - allow overriding
-+        this.tick();
-+    }
      public void tick() {
-+        // Paper end
          int i = this.tickNextTickList.size();
  
-         if (false) { // CraftBukkit
-@@ -118,28 +127,43 @@ public class ServerTickList<T> implements TickList<T> {
- 
-     @Override
-     public boolean willTickThisTick(BlockPos pos, T object) {
--        return this.currentlyTicking.contains(new TickNextTickData<>(pos, object));
-+        // Paper start - allow overriding
-+        return this.isPendingTickThisTick(pos, object);
-+    }
-+    public boolean isPendingTickThisTick(BlockPos blockposition, T t0) {
-+        // Paper end
-+        return this.currentlyTicking.contains(new TickNextTickData<>(blockposition, t0));
+@@ -190,7 +193,7 @@ public class ServerTickList<T> implements TickList<T> {
+         return ServerTickList.saveTickList(this.toId, list, this.level.getGameTime());
      }
  
-     public List<TickNextTickData<T>> fetchTicksInChunk(ChunkPos chunkcoordintpair, boolean updateState, boolean getStaleTicks) {
-+        // Paper start - allow overriding
-+        return this.getEntriesInChunk(chunkcoordintpair, updateState, getStaleTicks);
-+    }
-+    public List<TickNextTickData<T>> getEntriesInChunk(ChunkPos chunkcoordintpair, boolean flag, boolean flag1) {
-+        // Paper end
-         int i = (chunkcoordintpair.x << 4) - 2;
-         int j = i + 16 + 2;
-         int k = (chunkcoordintpair.z << 4) - 2;
-         int l = k + 16 + 2;
- 
--        return this.fetchTicksInArea(new BoundingBox(i, 0, k, j, 256, l), updateState, getStaleTicks);
-+        return this.fetchTicksInArea(new BoundingBox(i, 0, k, j, 256, l), flag, flag1);
-     }
- 
-     public List<TickNextTickData<T>> fetchTicksInArea(BoundingBox bounds, boolean updateState, boolean getStaleTicks) {
--        List<TickNextTickData<T>> list = this.fetchTicksInArea((List) null, this.tickNextTickList, bounds, updateState);
-+        // Paper start - allow overriding
-+        return this.getEntriesInBoundingBox(bounds, updateState, getStaleTicks);
-+    }
-+    public List<TickNextTickData<T>> getEntriesInBoundingBox(BoundingBox structureboundingbox, boolean flag, boolean flag1) {
-+        // Paper end
-+        List<TickNextTickData<T>> list = this.fetchTicksInArea((List) null, this.tickNextTickList, structureboundingbox, flag);
- 
--        if (updateState && list != null) {
-+        if (flag && list != null) {
-             this.tickNextTickSet.removeAll(list);
-         }
- 
--        list = this.fetchTicksInArea(list, this.currentlyTicking, bounds, updateState);
--        if (!getStaleTicks) {
--            list = this.fetchTicksInArea(list, this.alreadyTicked, bounds, updateState);
-+        list = this.fetchTicksInArea(list, this.currentlyTicking, structureboundingbox, flag);
-+        if (!flag1) {
-+            list = this.fetchTicksInArea(list, this.alreadyTicked, structureboundingbox, flag);
-         }
- 
-         return list == null ? Collections.emptyList() : list;
-@@ -170,14 +194,19 @@ public class ServerTickList<T> implements TickList<T> {
-     }
- 
-     public void copy(BoundingBox box, BlockPos offset) {
--        List<TickNextTickData<T>> list = this.fetchTicksInArea(box, false, false);
-+        // Paper start - allow overriding
-+        this.copy(box, offset);
-+    }
-+    public void copy(BoundingBox structureboundingbox, BlockPos blockposition) {
-+        // Paper end
-+        List<TickNextTickData<T>> list = this.fetchTicksInArea(structureboundingbox, false, false);
-         Iterator iterator = list.iterator();
- 
-         while (iterator.hasNext()) {
-             TickNextTickData<T> nextticklistentry = (TickNextTickData) iterator.next();
- 
--            if (box.isInside((Vec3i) nextticklistentry.pos)) {
--                BlockPos blockposition1 = nextticklistentry.pos.offset((Vec3i) offset);
-+            if (structureboundingbox.isInside((Vec3i) nextticklistentry.pos)) {
-+                BlockPos blockposition1 = nextticklistentry.pos.offset((Vec3i) blockposition);
-                 T t0 = nextticklistentry.getType();
- 
-                 this.addTickData(new TickNextTickData<>(blockposition1, t0, nextticklistentry.triggerTick, nextticklistentry.priority));
-@@ -187,11 +216,17 @@ public class ServerTickList<T> implements TickList<T> {
-     }
- 
-     public ListTag save(ChunkPos chunkcoordintpair) {
-+        // Paper start - allow overriding
-+        return this.serialize(chunkcoordintpair);
-+    }
-+    public ListTag serialize(ChunkPos chunkcoordintpair) {
-+        // Paper end
-         List<TickNextTickData<T>> list = this.fetchTicksInChunk(chunkcoordintpair, false, true);
- 
-         return saveTickList(this.toId, list, this.level.getGameTime());
-     }
- 
-+    public static <T> ListTag serialize(Function<T, ResourceLocation> function, Iterable<TickNextTickData<T>> iterable, long i) { return ServerTickList.saveTickList(function, iterable, i); } // Paper - OBFHELPER
-     private static <T> ListTag saveTickList(Function<T, ResourceLocation> identifierProvider, Iterable<TickNextTickData<T>> scheduledTicks, long time) {
+-    private static <T> ListTag saveTickList(Function<T, ResourceLocation> identifierProvider, Iterable<TickNextTickData<T>> scheduledTicks, long time) {
++    public static <T> ListTag saveTickList(Function<T, ResourceLocation> identifierProvider, Iterable<TickNextTickData<T>> scheduledTicks, long time) { // Paper - private -> public
          ListTag nbttaglist = new ListTag();
          Iterator iterator = scheduledTicks.iterator();
-@@ -214,13 +249,23 @@ public class ServerTickList<T> implements TickList<T> {
  
-     @Override
-     public boolean hasScheduledTick(BlockPos pos, T object) {
--        return this.tickNextTickSet.contains(new TickNextTickData<>(pos, object));
-+        // Paper start - allow overriding
-+        return this.isScheduledForTick(pos, object);
-+    }
-+    public boolean isScheduledForTick(BlockPos blockposition, T t0) {
-+        // Paper end
-+        return this.tickNextTickSet.contains(new TickNextTickData<>(blockposition, t0));
-     }
- 
-     @Override
-     public void scheduleTick(BlockPos pos, T object, int delay, TickPriority priority) {
--        if (!this.ignore.test(object)) {
--            this.addTickData(new TickNextTickData<>(pos, object, (long) delay + this.level.getGameTime(), priority));
-+        // Paper start - allow overriding
-+        this.schedule(pos, object, delay, priority);
-+    }
-+    public void schedule(BlockPos blockposition, T t0, int i, TickPriority ticklistpriority) {
-+        // Paper end
-+        if (!this.ignore.test(t0)) {
-+            this.addTickData(new TickNextTickData<>(blockposition, t0, (long) i + this.level.getGameTime(), ticklistpriority));
-         }
- 
-     }
-@@ -234,6 +279,11 @@ public class ServerTickList<T> implements TickList<T> {
-     }
- 
-     public int size() {
-+        // Paper start - allow overriding
-+        return this.getTotalScheduledEntries();
-+    }
-+    public int getTotalScheduledEntries() {
-+        // Paper end
-         return this.tickNextTickSet.size();
-     }
- }
 diff --git a/src/main/java/net/minecraft/world/level/TickNextTickData.java b/src/main/java/net/minecraft/world/level/TickNextTickData.java
-index 90833389022d7412bdda8868a356b84f62a00e03..61cdaf45368dcc40f3311e8b7f8637a6c93a2d76 100644
+index 3b8c04f6ffd7e6c197465aa1caf633ba92529472..6b4b7c290b623a9821734ef74a2e566343e3c5bd 100644
 --- a/src/main/java/net/minecraft/world/level/TickNextTickData.java
 +++ b/src/main/java/net/minecraft/world/level/TickNextTickData.java
-@@ -6,11 +6,13 @@ import net.minecraft.core.BlockPos;
- public class TickNextTickData<T> {
- 
-     private static final java.util.concurrent.atomic.AtomicLong COUNTER = new java.util.concurrent.atomic.AtomicLong(); // Paper - async chunk loading
--    private final T type;
--    public final BlockPos pos;
--    public final long triggerTick;
--    public final TickPriority priority;
+@@ -9,7 +9,9 @@ public class TickNextTickData<T> {
+     public final BlockPos pos;
+     public final long triggerTick;
+     public final TickPriority priority;
 -    private final long c;
-+    private final T type; public final T getData() { return this.type; } // Paper - OBFHELPER
-+    public final BlockPos pos; public final BlockPos getPosition() { return this.pos; } // Paper - OBFHELPER
-+    public final long triggerTick; public final long getTargetTick() { return this.triggerTick; } // Paper - OBFHELPER
-+    public final TickPriority priority; public final TickPriority getPriority() { return this.priority; } // Paper - OBFHELPER
 +    private final long c; public final long getId() { return this.c; } // Paper - OBFHELPER
 +    private final int hash; // Paper
 +    public int tickState; // Paper
  
      public TickNextTickData(BlockPos pos, T t) {
          this(pos, t, 0L, TickPriority.NORMAL);
-@@ -22,6 +24,7 @@ public class TickNextTickData<T> {
+@@ -21,6 +23,7 @@ public class TickNextTickData<T> {
          this.type = t;
          this.triggerTick = time;
          this.priority = priority;
 +        this.hash = this.computeHash(); // Paper
      }
  
-     public boolean equals(Object object) {
-@@ -34,19 +37,31 @@ public class TickNextTickData<T> {
-         }
-     }
+     @Override
+@@ -35,17 +38,27 @@ public class TickNextTickData<T> {
  
-+    // Paper start - optimize hashcode
-+    @Override
+     @Override
      public int hashCode() {
++        // Paper start - optimize hashcode
 +        return this.hash;
 +    }
 +    public final int computeHash() {
@@ -1234,68 +1087,26 @@ index 90833389022d7412bdda8868a356b84f62a00e03..61cdaf45368dcc40f3311e8b7f8637a6
          return this.pos.hashCode();
      }
  
--    public static <T> Comparator<Object> createTimeComparator() { // Paper - decompile fix
--        return Comparator.comparingLong((nextticklistentry) -> {
--            return ((TickNextTickData<T>) nextticklistentry).triggerTick; // Paper - decompile fix
--        }).thenComparing((nextticklistentry) -> {
--            return ((TickNextTickData<T>) nextticklistentry).priority; // Paper - decompile fix
--        }).thenComparingLong((nextticklistentry) -> {
--            return ((TickNextTickData<T>) nextticklistentry).c; // Paper - decompile fix
+     public static <T> Comparator<TickNextTickData<T>> createTimeComparator() {
+-        return Comparator.<TickNextTickData<T>>comparingLong((tickNextTickData) -> { // Paper - decompile fix
+-            return tickNextTickData.triggerTick;
+-        }).thenComparing((tickNextTickData) -> {
+-            return tickNextTickData.priority;
+-        }).thenComparingLong((tickNextTickData) -> {
+-            return tickNextTickData.c;
 -        });
-+    // Paper start - let's not use more functional code for no reason.
-+    public static <T> Comparator<Object> comparator() { return TickNextTickData.createTimeComparator(); } // Paper - OBFHELPER
-+    public static <T> Comparator<Object> createTimeComparator() {
-+        return (Comparator)(Comparator<TickNextTickData>)(TickNextTickData nextticklistentry, TickNextTickData nextticklistentry1) -> {
-+            int i = Long.compare(nextticklistentry.getTargetTick(), nextticklistentry1.getTargetTick());
++        // Paper start - let's not use more functional code for no reason.
++        return (Comparator) (Comparator<TickNextTickData>) (TickNextTickData nextticklistentry, TickNextTickData nextticklistentry1) -> {
++            int i = Long.compare(nextticklistentry.triggerTick, nextticklistentry1.triggerTick);
 +
 +            if (i != 0) {
 +                return i;
 +            } else {
-+                i = nextticklistentry.getPriority().compareTo(nextticklistentry1.getPriority());
++                i = nextticklistentry.priority.compareTo(nextticklistentry1.priority);
 +                return i != 0 ? i : Long.compare(nextticklistentry.getId(), nextticklistentry1.getId());
 +            }
 +        };
-     }
-+    // Paper end - let's not use more functional code for no reason.
- 
-     public String toString() {
-         return this.type + ": " + this.pos + ", " + this.triggerTick + ", " + this.priority + ", " + this.c;
-diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/BoundingBox.java b/src/main/java/net/minecraft/world/level/levelgen/structure/BoundingBox.java
-index 76bea58d35d352ee6f3d4bd0d10af3b6d615ae2c..4288fa253668196e6c32a876f18ec496fb3abad6 100644
---- a/src/main/java/net/minecraft/world/level/levelgen/structure/BoundingBox.java
-+++ b/src/main/java/net/minecraft/world/level/levelgen/structure/BoundingBox.java
-@@ -8,12 +8,12 @@ import net.minecraft.nbt.IntArrayTag;
- 
- public class BoundingBox {
- 
--    public int x0;
--    public int y0;
--    public int z0;
--    public int x1;
--    public int y1;
--    public int z1;
-+    public int x0; public final int getMinX() { return this.x0; } // Paper - OBFHELPER
-+    public int y0; public final int getMinY() { return this.y0; } // Paper - OBFHELPER
-+    public int z0; public final int getMinZ() { return this.z0; } // Paper - OBFHELPER
-+    public int x1; public final int getMaxX() { return this.x1; } // Paper - OBFHELPER
-+    public int y1; public final int getMaxY() { return this.y1; } // Paper - OBFHELPER
-+    public int z1; public final int getMaxZ() { return this.z1; } // Paper - OBFHELPER
- 
-     public BoundingBox() {}
- 
-@@ -92,6 +92,7 @@ public class BoundingBox {
-         this.y1 = 512;
++        // Paper end - let's not use more functional code for no reason.
      }
  
-+    public final boolean intersects(BoundingBox boundingBox) { return this.intersects(boundingBox); } // Paper - OBFHELPER
-     public boolean intersects(BoundingBox other) {
-         return this.x1 >= other.x0 && this.x0 <= other.x1 && this.z1 >= other.z0 && this.z0 <= other.z1 && this.y1 >= other.y0 && this.y0 <= other.y1;
-     }
-@@ -126,6 +127,7 @@ public class BoundingBox {
-         this.move(baseblockposition.getX(), baseblockposition.getY(), baseblockposition.getZ());
-     }
- 
-+    public final boolean hasPoint(Vec3i baseblockposition) { return this.isInside(baseblockposition); } // Paper - OBFHELPER
-     public boolean isInside(Vec3i vec) {
-         return vec.getX() >= this.x0 && vec.getX() <= this.x1 && vec.getZ() >= this.z0 && vec.getZ() <= this.z1 && vec.getY() >= this.y0 && vec.getY() <= this.y1;
-     }
+     @Override
diff --git a/patches/server-remapped/0419-Pillager-patrol-spawn-settings-and-per-player-option.patch b/patches/server/0379-Pillager-patrol-spawn-settings-and-per-player-option.patch
similarity index 85%
rename from patches/server-remapped/0419-Pillager-patrol-spawn-settings-and-per-player-option.patch
rename to patches/server/0379-Pillager-patrol-spawn-settings-and-per-player-option.patch
index 6e0269c7f..ff68539cd 100644
--- a/patches/server-remapped/0419-Pillager-patrol-spawn-settings-and-per-player-option.patch
+++ b/patches/server/0379-Pillager-patrol-spawn-settings-and-per-player-option.patch
@@ -10,10 +10,10 @@ When not per player it will use the Vanilla mechanic of one delay per
 world and the world age for the start day.
 
 diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
-index 525d702d78a609af987ebd2c32169b873e5c05ed..6c8e9d498c9a30a1aa88494ba09c3cae012a8fa1 100644
+index b57d9c84db5685b86cb077e3b42db7a8578d6f62..9664786d471b949880030f5c6271bf9c12529326 100644
 --- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
 +++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
-@@ -582,10 +582,21 @@ public class PaperWorldConfig {
+@@ -428,10 +428,21 @@ public class PaperWorldConfig {
      }
  
      public boolean disablePillagerPatrols = false;
@@ -36,10 +36,10 @@ index 525d702d78a609af987ebd2c32169b873e5c05ed..6c8e9d498c9a30a1aa88494ba09c3cae
      private void entitiesTargetWithFollowRange() {
          entitiesTargetWithFollowRange = getBoolean("entities-target-with-follow-range", entitiesTargetWithFollowRange);
 diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-index 7f4e81ee3339e90b8525541dccf6dea187853cf7..a469016c43251f16913a365c4131b2448eaa4c48 100644
+index bffc897cb88a54c36432c98264f3416051aeab17..5b5a0c0db79452ee07c40bf7693b6701dbe0b615 100644
 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
 +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-@@ -213,6 +213,7 @@ public class ServerPlayer extends Player implements ContainerListener {
+@@ -219,6 +219,7 @@ public class ServerPlayer extends Player {
      public boolean wonGame;
      private int containerUpdateDelay; // Paper
      public long loginTime; // Paper
@@ -47,20 +47,8 @@ index 7f4e81ee3339e90b8525541dccf6dea187853cf7..a469016c43251f16913a365c4131b244
      // Paper start - cancellable death event
      public boolean queueHealthUpdatePacket = false;
      public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket;
-diff --git a/src/main/java/net/minecraft/stats/StatType.java b/src/main/java/net/minecraft/stats/StatType.java
-index ba48795a7b7cbf4622e64273ab488e26d7a862e2..b85987910cf80b1d1a04a7b772e19200f4ce4372 100644
---- a/src/main/java/net/minecraft/stats/StatType.java
-+++ b/src/main/java/net/minecraft/stats/StatType.java
-@@ -28,6 +28,7 @@ public class StatType<T> implements Iterable<Stat<T>> {
-         return this.map.values().iterator();
-     }
- 
-+    public final Stat<T> get(T t) { return this.get(t); }; // Paper - OBFHELPER
-     public Stat<T> get(T key) {
-         return this.get(key, StatFormatter.DEFAULT);
-     }
 diff --git a/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java b/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java
-index 48efe133d294bb1b17e8ac8b44eea8a29f15845f..dcbe74bdb1b6e07f7b8845182576ef544493d377 100644
+index 744b58d59a5f34ed3bd6f2d4a0f876acfa6a7135..d75a04e7a70b7fb2527fdd7d1a45a101d064824f 100644
 --- a/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java
 +++ b/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java
 @@ -4,11 +4,12 @@ import java.util.Random;
@@ -127,7 +115,7 @@ index 48efe133d294bb1b17e8ac8b44eea8a29f15845f..dcbe74bdb1b6e07f7b8845182576ef54
 +            } else {
 +                long days;
 +                if (world.paperConfig.patrolPerPlayerStart) {
-+                    days = entityhuman.getStats().getValue(Stats.CUSTOM.get(Stats.PLAY_ONE_MINUTE)) / 24000L; // PLAY_ONE_MINUTE is actually counting in ticks, a misnomer by Mojang
++                    days = entityhuman.getStats().getValue(Stats.CUSTOM.get(Stats.PLAY_TIME)) / 24000L; // PLAY_ONE_MINUTE is actually counting in ticks, a misnomer by Mojang
 +                } else {
 +                    days = world.getDayTime() / 24000L;
 +                }
diff --git a/patches/server-remapped/0422-Remote-Connections-shouldn-t-hold-up-shutdown.patch b/patches/server/0380-Remote-Connections-shouldn-t-hold-up-shutdown.patch
similarity index 86%
rename from patches/server-remapped/0422-Remote-Connections-shouldn-t-hold-up-shutdown.patch
rename to patches/server/0380-Remote-Connections-shouldn-t-hold-up-shutdown.patch
index a83d55935..64931753e 100644
--- a/patches/server-remapped/0422-Remote-Connections-shouldn-t-hold-up-shutdown.patch
+++ b/patches/server/0380-Remote-Connections-shouldn-t-hold-up-shutdown.patch
@@ -6,10 +6,10 @@ Subject: [PATCH] Remote Connections shouldn't hold up shutdown
 Bugs in the connection logic appears to leave stale connections even, preventing shutdown
 
 diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
-index 4862a9519d4ba5f05b634a0335837bea9812edee..f8ddc0aa98874c7879a51e76d1a629cbdaf58812 100644
+index 6f9b7c3cf22d0c44f31b81bcbfa3cb1f8c065083..0511f1921193b78cbf4d8426136bf1f79746f955 100644
 --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
 +++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
-@@ -397,11 +397,11 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
+@@ -439,11 +439,11 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
          }
  
          if (this.rconThread != null) {
diff --git a/patches/server-remapped/0423-Do-not-allow-bees-to-load-chunks-for-beehives.patch b/patches/server/0381-Do-not-allow-bees-to-load-chunks-for-beehives.patch
similarity index 85%
rename from patches/server-remapped/0423-Do-not-allow-bees-to-load-chunks-for-beehives.patch
rename to patches/server/0381-Do-not-allow-bees-to-load-chunks-for-beehives.patch
index 044507e1b..bbc752cdd 100644
--- a/patches/server-remapped/0423-Do-not-allow-bees-to-load-chunks-for-beehives.patch
+++ b/patches/server/0381-Do-not-allow-bees-to-load-chunks-for-beehives.patch
@@ -5,10 +5,10 @@ Subject: [PATCH] Do not allow bees to load chunks for beehives
 
 
 diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java
-index 9b68809b91910d2bbb82cafe23d1de5dfff4221c..81291a1174538d6d4073c6fa886b10e99b45d887 100644
+index b4cd490a1b2a2a118dc5f49bcb0fb755fbad853b..4aeffd9efe6f845007f35a3fd23fdfda2d1f20aa 100644
 --- a/src/main/java/net/minecraft/world/entity/animal/Bee.java
 +++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java
-@@ -358,6 +358,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
+@@ -404,6 +404,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
          if (this.hivePos == null) {
              return false;
          } else {
@@ -16,7 +16,7 @@ index 9b68809b91910d2bbb82cafe23d1de5dfff4221c..81291a1174538d6d4073c6fa886b10e9
              BlockEntity tileentity = this.level.getBlockEntity(this.hivePos);
  
              return tileentity instanceof BeehiveBlockEntity && ((BeehiveBlockEntity) tileentity).isFireNearby();
-@@ -390,6 +391,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
+@@ -436,6 +437,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
      }
  
      private boolean doesHiveHaveSpace(BlockPos pos) {
@@ -24,7 +24,7 @@ index 9b68809b91910d2bbb82cafe23d1de5dfff4221c..81291a1174538d6d4073c6fa886b10e9
          BlockEntity tileentity = this.level.getBlockEntity(pos);
  
          return tileentity instanceof BeehiveBlockEntity ? !((BeehiveBlockEntity) tileentity).isFull() : false;
-@@ -632,6 +634,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
+@@ -909,6 +911,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
          @Override
          public boolean canBeeUse() {
              if (Bee.this.hasHive() && Bee.this.wantsToEnterHive() && Bee.this.hivePos.closerThan((Position) Bee.this.position(), 2.0D)) {
@@ -32,7 +32,7 @@ index 9b68809b91910d2bbb82cafe23d1de5dfff4221c..81291a1174538d6d4073c6fa886b10e9
                  BlockEntity tileentity = Bee.this.level.getBlockEntity(Bee.this.hivePos);
  
                  if (tileentity instanceof BeehiveBlockEntity) {
-@@ -655,6 +658,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
+@@ -932,6 +935,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
  
          @Override
          public void start() {
diff --git a/patches/server-remapped/0424-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch b/patches/server/0382-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch
similarity index 62%
rename from patches/server-remapped/0424-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch
rename to patches/server/0382-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch
index 720e9dcff..60f46ed4f 100644
--- a/patches/server-remapped/0424-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch
+++ b/patches/server/0382-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch
@@ -7,10 +7,10 @@ Suspected case would be around the technique used in .stopRiding
 Stack will identify any causer of this and warn instead of crashing.
 
 diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
-index 6da406c8403797a1cd9276ac06577c3c080a8a22..e6eeca5834a164d87f5b0e564fe6237902edaa6a 100644
+index 273cd2e0fc38801a5ecb26579e4d0e9ee017bb3c..d06c6828180b7864bf4d3736a65ea0a2dc7804e2 100644
 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java
 +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
-@@ -1501,6 +1501,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
+@@ -1445,6 +1445,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
  
      protected void addEntity(Entity entity) {
          org.spigotmc.AsyncCatcher.catchOp("entity track"); // Spigot
@@ -26,23 +26,23 @@ index 6da406c8403797a1cd9276ac06577c3c080a8a22..e6eeca5834a164d87f5b0e564fe62379
              EntityType<?> entitytypes = entity.getType();
              int i = entitytypes.clientTrackingRange() * 16;
 diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
-index c5dc41a3cf499038bd33451a189913cd3978b230..5127bce423a83711cea94e387b3ae7866215ded5 100644
+index 385b8e707406173ea5258aff87af719ce93aecf3..5944c44eadca550671d7740af5756985afede39d 100644
 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java
 +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
-@@ -1525,7 +1525,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
-                 }
+@@ -2100,7 +2100,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
+ 
+         public void onTrackingStart(Entity entity) {
+             org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot
+-            ServerLevel.this.getChunkSource().addEntity(entity);
++            // ServerLevel.this.getChunkSource().addEntity(entity); // Paper - moved down below valid=true
+             if (entity instanceof ServerPlayer) {
+                 ServerLevel.this.players.add((ServerPlayer) entity);
+                 ServerLevel.this.updateSleepingPlayerList();
+@@ -2122,6 +2122,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
              }
  
--            this.getChunkSource().addEntity(entity);
-+            // this.getChunkProvider().addEntity(entity); // Paper - moved down below valid=true
-             // CraftBukkit start - SPIGOT-5278
-             if (entity instanceof Drowned) {
-                 this.navigations.add(((Drowned) entity).waterNavigation);
-@@ -1536,6 +1536,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
-                 this.navigations.add(((Mob) entity).getNavigation());
-             }
              entity.valid = true; // CraftBukkit
-+            this.getChunkSource().addEntity(entity); // Paper - from above to be below valid=true
-             // Paper start - Set origin location when the entity is being added to the world
-             if (entity.origin == null) {
-                 entity.origin = entity.getBukkitEntity().getLocation();
++            ServerLevel.this.getChunkSource().addEntity(entity);
+         }
+ 
+         public void onTrackingEnd(Entity entity) {
diff --git a/patches/server/0383-Optimize-Collision-to-not-load-chunks.patch b/patches/server/0383-Optimize-Collision-to-not-load-chunks.patch
new file mode 100644
index 000000000..d2e15c682
--- /dev/null
+++ b/patches/server/0383-Optimize-Collision-to-not-load-chunks.patch
@@ -0,0 +1,133 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Aikar <aikar@aikar.co>
+Date: Thu, 2 Apr 2020 02:37:57 -0400
+Subject: [PATCH] Optimize Collision to not load chunks
+
+The collision code takes an AABB and generates a cuboid of checks rather
+than a cylinder, so at high velocity this can generate a lot of chunk checks.
+
+Treat an unloaded chunk as a collision for entities, and also for players if
+the "prevent moving into unloaded chunks" setting is enabled.
+
+If that serting is not enabled, collisions will be ignored for players, since
+movement will load only the chunk the player enters anyways and avoids loading
+massive amounts of surrounding chunks due to large AABB lookups.
+
+diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
+index 2730923bd0bf3b0f928765b9e09e2299fa9a393d..f98a1c32e0c209473cf7268cbd8245ab9c134d28 100644
+--- a/src/main/java/net/minecraft/server/players/PlayerList.java
++++ b/src/main/java/net/minecraft/server/players/PlayerList.java
+@@ -783,6 +783,7 @@ public abstract class PlayerList {
+         entityplayer1.forceSetPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
+         // CraftBukkit end
+ 
++        worldserver1.getChunkSource().addRegionTicket(net.minecraft.server.level.TicketType.POST_TELEPORT, new net.minecraft.world.level.ChunkPos(location.getBlockX() >> 4, location.getBlockZ() >> 4), 1, entityplayer.getId()); // Paper
+         while (avoidSuffocation && !worldserver1.noCollision(entityplayer1) && entityplayer1.getY() < (double) worldserver1.getMaxBuildHeight()) {
+             entityplayer1.setPos(entityplayer1.getX(), entityplayer1.getY() + 1.0D, entityplayer1.getZ());
+         }
+diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
+index facb09e49d92d22dbcde7d187d4ba1c9a04202a9..85c0656ee8c91cab1e269daea631977c4284295f 100644
+--- a/src/main/java/net/minecraft/world/entity/Entity.java
++++ b/src/main/java/net/minecraft/world/entity/Entity.java
+@@ -172,6 +172,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
+     // Paper end
+ 
+     public com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData; // Paper
++    public boolean collisionLoadChunks = false; // Paper
+     private CraftEntity bukkitEntity;
+ 
+     public CraftEntity getBukkitEntity() {
+diff --git a/src/main/java/net/minecraft/world/level/CollisionGetter.java b/src/main/java/net/minecraft/world/level/CollisionGetter.java
+index b980c26ab5cac02e03525177a9dc4fb0b6a2f9f6..2a784a8342e708e0813c7076a2ca8e429446ffd3 100644
+--- a/src/main/java/net/minecraft/world/level/CollisionGetter.java
++++ b/src/main/java/net/minecraft/world/level/CollisionGetter.java
+@@ -55,7 +55,9 @@ public interface CollisionGetter extends BlockGetter {
+     }
+ 
+     default boolean noCollision(@Nullable Entity entity, AABB box, Predicate<Entity> filter) {
++        try { if (entity != null) entity.collisionLoadChunks = true; // Paper
+         return this.getCollisions(entity, box, filter).allMatch(VoxelShape::isEmpty);
++        } finally { if (entity != null) entity.collisionLoadChunks = false; } // Paper
+     }
+ 
+     Stream<VoxelShape> getEntityCollisions(@Nullable Entity entity, AABB box, Predicate<Entity> predicate);
+diff --git a/src/main/java/net/minecraft/world/level/CollisionSpliterator.java b/src/main/java/net/minecraft/world/level/CollisionSpliterator.java
+index e6190bfb893de12e87e1da49001ebd963b3d6318..90039d01ef481ba206f2e952c99a755e94201ea3 100644
+--- a/src/main/java/net/minecraft/world/level/CollisionSpliterator.java
++++ b/src/main/java/net/minecraft/world/level/CollisionSpliterator.java
+@@ -21,13 +21,13 @@ import net.minecraft.world.phys.shapes.VoxelShape;
+ 
+ public class CollisionSpliterator extends AbstractSpliterator<VoxelShape> {
+     @Nullable
+-    private final Entity source;
++    private final Entity source; final Entity getEntity() { return this.source; } // Paper - OBFHELPER
+     private final AABB box;
+     private final CollisionContext context;
+     private final Cursor3D cursor;
+-    private final BlockPos.MutableBlockPos pos;
++    private final BlockPos.MutableBlockPos pos; final BlockPos.MutableBlockPos getMutablePos() { return this.pos; } // Paper - OBFHELPER
+     private final VoxelShape entityShape;
+-    private final CollisionGetter collisionGetter;
++    private final CollisionGetter collisionGetter; final CollisionGetter getCollisionAccess() { return this.collisionGetter; } // Paper - OBFHELPER
+     private boolean needsBorderCheck;
+     private final BiPredicate<BlockState, BlockPos> predicate;
+ 
+@@ -64,21 +64,37 @@ public class CollisionSpliterator extends AbstractSpliterator<VoxelShape> {
+     boolean collisionCheck(Consumer<? super VoxelShape> action) {
+         while(true) {
+             if (this.cursor.advance()) {
+-                int i = this.cursor.nextX();
+-                int j = this.cursor.nextY();
+-                int k = this.cursor.nextZ();
++                int i = this.cursor.nextX(); final int x = i;
++                int j = this.cursor.nextY(); final int y = j;
++                int k = this.cursor.nextZ(); final int z = k;
+                 int l = this.cursor.getNextType();
+                 if (l == 3) {
+                     continue;
+                 }
+ 
+-                BlockGetter blockGetter = this.getChunk(i, k);
+-                if (blockGetter == null) {
++                // Paper start - ensure we don't load chunks
++                Entity entity = this.getEntity();
++                BlockPos.MutableBlockPos blockposition_mutableblockposition = this.getMutablePos();
++                boolean far = entity != null && net.minecraft.server.MCUtil.distanceSq(entity.getX(), y, entity.getZ(), x, y, z) > 14;
++                blockposition_mutableblockposition.setValues(x, y, z);
++
++                boolean isRegionLimited = this.getCollisionAccess() instanceof net.minecraft.server.level.WorldGenRegion;
++                BlockState blockState = isRegionLimited ? Blocks.VOID_AIR.defaultBlockState() : ((!far && entity instanceof net.minecraft.server.level.ServerPlayer) || (entity != null && entity.collisionLoadChunks)
++                    ? this.getCollisionAccess().getBlockState(blockposition_mutableblockposition)
++                    : this.getCollisionAccess().getTypeIfLoaded(blockposition_mutableblockposition)
++                );
++
++                if (blockState == null) {
++                    if (!(entity instanceof net.minecraft.server.level.ServerPlayer) || entity.level.paperConfig.preventMovingIntoUnloadedChunks) {
++                        VoxelShape voxelshape3 = Shapes.create(far ? entity.getBoundingBox() : new AABB(new BlockPos(x, y, z)));
++                        action.accept(voxelshape3);
++                        return true;
++                    }
+                     continue;
+                 }
++                // Paper - moved up
++                // Paper end
+ 
+-                this.pos.set(i, j, k);
+-                BlockState blockState = blockGetter.getBlockState(this.pos);
+                 if (!this.predicate.test(blockState, this.pos) || l == 1 && !blockState.hasLargeCollisionShape() || l == 2 && !blockState.is(Blocks.MOVING_PISTON)) {
+                     continue;
+                 }
+diff --git a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
+index 5d4d953f197afc402248ab73daeb6ef59134f48f..95428f13dae909bb7de552aa65e4256bd4049c65 100644
+--- a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
++++ b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
+@@ -238,7 +238,8 @@ public final class Shapes {
+ 
+                             if (s < 3) {
+                                 mutableBlockPos.set(axisCycle, q, r, p);
+-                                BlockState blockState = world.getBlockState(mutableBlockPos);
++                                BlockState blockState = world.getTypeIfLoaded(mutableBlockPos); // Paper
++                                if (blockState == null) return 0.0D; // Paper
+                                 if ((s != 1 || blockState.hasLargeCollisionShape()) && (s != 2 || blockState.is(Blocks.MOVING_PISTON))) {
+                                     initial = blockState.getCollisionShape(world, mutableBlockPos, context).collide(axis3, box.move((double)(-mutableBlockPos.getX()), (double)(-mutableBlockPos.getY()), (double)(-mutableBlockPos.getZ())), initial);
+                                     if (Math.abs(initial) < 1.0E-7D) {
diff --git a/patches/server-remapped/0426-Don-t-tick-dead-players.patch b/patches/server/0384-Don-t-tick-dead-players.patch
similarity index 59%
rename from patches/server-remapped/0426-Don-t-tick-dead-players.patch
rename to patches/server/0384-Don-t-tick-dead-players.patch
index b748ace1a..d831e3b2b 100644
--- a/patches/server-remapped/0426-Don-t-tick-dead-players.patch
+++ b/patches/server/0384-Don-t-tick-dead-players.patch
@@ -7,15 +7,15 @@ Causes sync chunk loads and who knows what all else.
 This is safe because Spectators are skipped in unloaded chunks too in vanilla.
 
 diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-index a469016c43251f16913a365c4131b2448eaa4c48..286b75a27103a084a9f9d79a90716ebcad65d813 100644
+index 5b5a0c0db79452ee07c40bf7693b6701dbe0b615..2822d493500dcd01c26ff5b205da83d8d356e119 100644
 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
 +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-@@ -606,7 +606,7 @@ public class ServerPlayer extends Player implements ContainerListener {
+@@ -637,7 +637,7 @@ public class ServerPlayer extends Player {
  
      public void doTick() {
          try {
--            if (!this.isSpectator() || this.level.hasChunkAt(this.blockPosition())) {
-+            if (valid && !this.isSpectator() || this.level.hasChunkAt(this.blockPosition())) { // Paper - don't tick dead players that are not in the world currently (pending respawn)
+-            if (!this.isSpectator() || !this.touchingUnloadedChunk()) {
++            if (valid && !this.isSpectator() || !this.touchingUnloadedChunk()) { // Paper - don't tick dead players that are not in the world currently (pending respawn)
                  super.tick();
              }
  
diff --git a/patches/server-remapped/0427-Dead-Player-s-shouldn-t-be-able-to-move.patch b/patches/server/0385-Dead-Player-s-shouldn-t-be-able-to-move.patch
similarity index 70%
rename from patches/server-remapped/0427-Dead-Player-s-shouldn-t-be-able-to-move.patch
rename to patches/server/0385-Dead-Player-s-shouldn-t-be-able-to-move.patch
index 3e2b8e535..51a1431c6 100644
--- a/patches/server-remapped/0427-Dead-Player-s-shouldn-t-be-able-to-move.patch
+++ b/patches/server/0385-Dead-Player-s-shouldn-t-be-able-to-move.patch
@@ -7,15 +7,15 @@ This fixes a lot of game state issues where packets were delayed for processing
 due to 1.15's new queue but processed while dead.
 
 diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
-index 0685920073a6a2b2c6a80018d0c9009b2ef860c4..32f1b180e82f41f3ce1b49ea7d67b7d55d2b9ca7 100644
+index 4c9261c68518ab7429325f0366dfb2930663288c..a3d31cec6d1b8de700b6cd2f7f51398debef5b6d 100644
 --- a/src/main/java/net/minecraft/world/entity/player/Player.java
 +++ b/src/main/java/net/minecraft/world/entity/player/Player.java
-@@ -1046,7 +1046,7 @@ public abstract class Player extends LivingEntity {
+@@ -1106,7 +1106,7 @@ public abstract class Player extends LivingEntity {
  
      @Override
      protected boolean isImmobile() {
 -        return super.isImmobile() || this.isSleeping();
-+        return super.isImmobile() || this.isSleeping() || removed || !valid; // Paper - player's who are dead or not in a world shouldn't move...
++        return super.isImmobile() || this.isSleeping() || this.isRemoved() || !valid; // Paper - player's who are dead or not in a world shouldn't move...
      }
  
      @Override
diff --git a/patches/server-remapped/0428-Optimize-PlayerChunkMap-memory-use-for-visibleChunks.patch b/patches/server/0386-Optimize-PlayerChunkMap-memory-use-for-visibleChunks.patch
similarity index 84%
rename from patches/server-remapped/0428-Optimize-PlayerChunkMap-memory-use-for-visibleChunks.patch
rename to patches/server/0386-Optimize-PlayerChunkMap-memory-use-for-visibleChunks.patch
index a211d40a2..71138d108 100644
--- a/patches/server-remapped/0428-Optimize-PlayerChunkMap-memory-use-for-visibleChunks.patch
+++ b/patches/server/0386-Optimize-PlayerChunkMap-memory-use-for-visibleChunks.patch
@@ -57,10 +57,10 @@ index 0000000000000000000000000000000000000000..f6ff4d8132a95895680f5bc81f8f873e
 +    }
 +}
 diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java
-index 99c3337eec552ba47d3b8b2d8feaaa80acf2a86f..9abef8550a89df5e15ac28de1a5549d064f29122 100644
+index 9c88426ab1275ee5fb6e28be8b213533dc4ab859..87c9a5c1b43f6010898d72136b5eb9973299b723 100644
 --- a/src/main/java/net/minecraft/server/MCUtil.java
 +++ b/src/main/java/net/minecraft/server/MCUtil.java
-@@ -616,7 +616,7 @@ public final class MCUtil {
+@@ -614,7 +614,7 @@ public final class MCUtil {
  
              ServerLevel world = ((org.bukkit.craftbukkit.CraftWorld)bukkitWorld).getHandle();
              ChunkMap chunkMap = world.getChunkSource().chunkMap;
@@ -70,15 +70,13 @@ index 99c3337eec552ba47d3b8b2d8feaaa80acf2a86f..9abef8550a89df5e15ac28de1a5549d0
              List<ChunkHolder> allChunks = new ArrayList<>(visibleChunks.values());
              List<ServerPlayer> players = world.players;
 diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
-index e6eeca5834a164d87f5b0e564fe6237902edaa6a..99eee56d6e66b79dd48ecbd1eeebc08174003f4a 100644
+index d06c6828180b7864bf4d3736a65ea0a2dc7804e2..c304c57a572b7e154362b39065ab8cb30a7e112e 100644
 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java
 +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
-@@ -104,8 +104,33 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
- 
-     private static final Logger LOGGER = LogManager.getLogger();
+@@ -107,9 +107,36 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
+     private static final int MIN_VIEW_DISTANCE = 3;
+     public static final int MAX_VIEW_DISTANCE = 33;
      public static final int MAX_CHUNK_DISTANCE = 33 + ChunkStatus.maxDistance();
--    public final Long2ObjectLinkedOpenHashMap<ChunkHolder> updatingChunkMap = new Long2ObjectLinkedOpenHashMap();
--    public volatile Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunkMap;
 +    // Paper start - faster copying
 +    public final Long2ObjectLinkedOpenHashMap<ChunkHolder> updatingChunkMap = new com.destroystokyo.paper.util.map.Long2ObjectLinkedOpenHashMapFastCopy<>(); // Paper - faster copying
 +    public final Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunkMap = new ProtectedVisibleChunksMap(); // Paper - faster copying
@@ -106,19 +104,24 @@ index e6eeca5834a164d87f5b0e564fe6237902edaa6a..99eee56d6e66b79dd48ecbd1eeebc081
 +    // Paper end
 +    public final com.destroystokyo.paper.util.map.Long2ObjectLinkedOpenHashMapFastCopy<ChunkHolder> pendingVisibleChunks = new com.destroystokyo.paper.util.map.Long2ObjectLinkedOpenHashMapFastCopy<ChunkHolder>(); // Paper - this is used if the visible chunks is updated while iterating only
 +    public transient com.destroystokyo.paper.util.map.Long2ObjectLinkedOpenHashMapFastCopy<ChunkHolder> visibleChunksClone; // Paper - used for async access of visible chunks, clone and cache only when needed
+     public static final int FORCED_TICKET_LEVEL = 31;
+-    public final Long2ObjectLinkedOpenHashMap<ChunkHolder> updatingChunkMap = new Long2ObjectLinkedOpenHashMap();
+-    public volatile Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunkMap;
++    // public final Long2ObjectLinkedOpenHashMap<ChunkHolder> updatingChunkMap = new Long2ObjectLinkedOpenHashMap(); // Paper - moved up
++    // public volatile Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunkMap; // Paper - moved up
      private final Long2ObjectLinkedOpenHashMap<ChunkHolder> pendingUnloads;
      public final LongSet entitiesInLevel; // Paper - private -> public
      public final ServerLevel level;
-@@ -178,7 +203,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
+@@ -231,7 +258,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
  
-     public ChunkMap(ServerLevel worldserver, LevelStorageSource.LevelStorageAccess convertable_conversionsession, DataFixer dataFixer, StructureManager definedstructuremanager, Executor workerExecutor, BlockableEventLoop<Runnable> mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, Supplier<DimensionDataStorage> supplier, int i, boolean flag) {
-         super(new File(convertable_conversionsession.getDimensionPath(worldserver.dimension()), "region"), dataFixer, flag);
+     public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureManager structureManager, Executor executor, BlockableEventLoop<Runnable> mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory, int viewDistance, boolean dsync) {
+         super(new File(session.getDimensionPath(world.dimension()), "region"), dataFixer, dsync);
 -        this.visibleChunkMap = this.updatingChunkMap.clone();
 +        //this.visibleChunks = this.updatingChunks.clone(); // Paper - no more cloning
          this.pendingUnloads = new Long2ObjectLinkedOpenHashMap();
          this.entitiesInLevel = new LongOpenHashSet();
          this.toDrop = new LongOpenHashSet();
-@@ -270,9 +295,52 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
+@@ -350,9 +377,52 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
          return (ChunkHolder) this.updatingChunkMap.get(pos);
      }
  
@@ -159,7 +162,7 @@ index e6eeca5834a164d87f5b0e564fe6237902edaa6a..99eee56d6e66b79dd48ecbd1eeebc081
 +    // Paper end
 +
      @Nullable
-     public ChunkHolder getVisibleChunkIfPresent(long pos) { // Paper - protected -> public
+     public final ChunkHolder getVisibleChunkIfPresent(long pos) { // Paper - protected -> public
 -        return (ChunkHolder) this.visibleChunkMap.get(pos);
 +        // Paper start - mt safe get
 +        if (Thread.currentThread() != this.level.thread) {
@@ -172,8 +175,8 @@ index e6eeca5834a164d87f5b0e564fe6237902edaa6a..99eee56d6e66b79dd48ecbd1eeebc081
      }
  
      protected IntSupplier getChunkQueueLevel(long pos) {
-@@ -460,8 +528,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-     // Paper end
+@@ -509,8 +579,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
+     }
  
      protected void saveAllChunks(boolean flush) {
 +        Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunks = this.getVisibleChunks(); // Paper remove clone of visible Chunks unless saving off main thread (watchdog kill)
@@ -183,7 +186,7 @@ index e6eeca5834a164d87f5b0e564fe6237902edaa6a..99eee56d6e66b79dd48ecbd1eeebc081
              MutableBoolean mutableboolean = new MutableBoolean();
  
              do {
-@@ -489,7 +558,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
+@@ -541,7 +612,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
  //            this.i(); // Paper - nuke IOWorker
              ChunkMap.LOGGER.info("ThreadedAnvilChunkStorage ({}): All chunks are saved", this.storageFolder.getName());
          } else {
@@ -192,7 +195,7 @@ index e6eeca5834a164d87f5b0e564fe6237902edaa6a..99eee56d6e66b79dd48ecbd1eeebc081
                  ChunkAccess ichunkaccess = (ChunkAccess) playerchunk.getChunkToSave().getNow(null); // CraftBukkit - decompile error
  
                  if (ichunkaccess instanceof ImposterProtoChunk || ichunkaccess instanceof LevelChunk) {
-@@ -660,7 +729,20 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
+@@ -701,7 +772,20 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
          if (!this.modified) {
              return false;
          } else {
@@ -214,7 +217,7 @@ index e6eeca5834a164d87f5b0e564fe6237902edaa6a..99eee56d6e66b79dd48ecbd1eeebc081
              this.modified = false;
              return true;
          }
-@@ -1139,12 +1221,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
+@@ -1110,12 +1194,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
      }
  
      protected Iterable<ChunkHolder> getChunks() {
@@ -223,17 +226,17 @@ index e6eeca5834a164d87f5b0e564fe6237902edaa6a..99eee56d6e66b79dd48ecbd1eeebc081
      }
  
      void dumpChunks(Writer writer) throws IOException {
-         CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("z").addColumn("level").addColumn("in_memory").addColumn("status").addColumn("full_status").addColumn("accessible_ready").addColumn("ticking_ready").addColumn("entity_ticking_ready").addColumn("ticket").addColumn("spawning").addColumn("entity_count").addColumn("block_entity_count").build(writer);
+         CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("z").addColumn("level").addColumn("in_memory").addColumn("status").addColumn("full_status").addColumn("accessible_ready").addColumn("ticking_ready").addColumn("entity_ticking_ready").addColumn("ticket").addColumn("spawning").addColumn("block_entity_count").build(writer);
 -        ObjectBidirectionalIterator objectbidirectionaliterator = this.visibleChunkMap.long2ObjectEntrySet().iterator();
 +        ObjectBidirectionalIterator objectbidirectionaliterator = this.getVisibleChunks().long2ObjectEntrySet().iterator(); // Paper
  
          while (objectbidirectionaliterator.hasNext()) {
              Entry<ChunkHolder> entry = (Entry) objectbidirectionaliterator.next();
 diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
-index e2b1541042bceac965411e3176d08c61f217c07f..f5de878020be9465739fba07fd7dea46b0a3ae34 100644
+index 382a68c76e8946840de62f05483870689de80278..8523fbd66ed42cd5b959d57cab515fa4a774a575 100644
 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
 +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
-@@ -782,7 +782,7 @@ public class ServerChunkCache extends ChunkSource {
+@@ -751,7 +751,7 @@ public class ServerChunkCache extends ChunkSource {
              };
              // Paper end
              this.level.timings.chunkTicks.startTiming(); // Paper
@@ -243,41 +246,43 @@ index e2b1541042bceac965411e3176d08c61f217c07f..f5de878020be9465739fba07fd7dea46
  
                  if (optional.isPresent()) {
 diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
-index fb74bdcf4c2935b56e92717cc5a1504fbc853d0a..1a839242e359fa32f32d0e571c6e918ac39642e9 100644
+index 1d22119b962840dff789a0619fd2188958f924d0..1023a0d5d1699b28d380e017b386a9b3986f1250 100644
 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
 +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
-@@ -276,6 +276,7 @@ public class CraftWorld implements World {
-         return ret;
-     }
+@@ -286,6 +286,7 @@ public class CraftWorld implements World {
+ 
+     @Override
      public int getTileEntityCount() {
 +        return net.minecraft.server.MCUtil.ensureMain(() -> {
          // We don't use the full world tile entity list, so we must iterate chunks
          Long2ObjectLinkedOpenHashMap<ChunkHolder> chunks = world.getChunkSource().chunkMap.visibleChunkMap;
          int size = 0;
-@@ -287,11 +288,13 @@ public class CraftWorld implements World {
+@@ -297,6 +298,7 @@ public class CraftWorld implements World {
              size += chunk.blockEntities.size();
          }
          return size;
 +        });
      }
-     public int getTickableTileEntityCount() {
-         return world.tickableBlockEntities.size();
-     }
+ 
+     @Override
+@@ -306,6 +308,7 @@ public class CraftWorld implements World {
+ 
+     @Override
      public int getChunkCount() {
 +        return net.minecraft.server.MCUtil.ensureMain(() -> {
          int ret = 0;
  
          for (ChunkHolder chunkHolder : world.getChunkSource().chunkMap.visibleChunkMap.values()) {
-@@ -300,7 +303,7 @@ public class CraftWorld implements World {
+@@ -314,7 +317,7 @@ public class CraftWorld implements World {
              }
          }
  
 -        return ret;
 +        return ret; });
      }
-     public int getPlayerCount() {
-         return world.players.size();
-@@ -425,6 +428,14 @@ public class CraftWorld implements World {
+ 
+     @Override
+@@ -441,6 +444,14 @@ public class CraftWorld implements World {
  
      @Override
      public Chunk[] getLoadedChunks() {
@@ -289,6 +294,6 @@ index fb74bdcf4c2935b56e92717cc5a1504fbc853d0a..1a839242e359fa32f32d0e571c6e918a
 +            }
 +        }
 +        // Paper end
-         Long2ObjectLinkedOpenHashMap<ChunkHolder> chunks = world.getChunkSource().chunkMap.visibleChunkMap;
+         Long2ObjectLinkedOpenHashMap<ChunkHolder> chunks = this.world.getChunkSource().chunkMap.visibleChunkMap;
          return chunks.values().stream().map(ChunkHolder::getFullChunk).filter(Objects::nonNull).map(net.minecraft.world.level.chunk.LevelChunk::getBukkitChunk).toArray(Chunk[]::new);
      }
diff --git a/patches/server-remapped/0430-Mid-Tick-Chunk-Tasks-Speed-up-processing-of-chunk-lo.patch b/patches/server/0387-Mid-Tick-Chunk-Tasks-Speed-up-processing-of-chunk-lo.patch
similarity index 79%
rename from patches/server-remapped/0430-Mid-Tick-Chunk-Tasks-Speed-up-processing-of-chunk-lo.patch
rename to patches/server/0387-Mid-Tick-Chunk-Tasks-Speed-up-processing-of-chunk-lo.patch
index b0f42e94c..395f0c27c 100644
--- a/patches/server-remapped/0430-Mid-Tick-Chunk-Tasks-Speed-up-processing-of-chunk-lo.patch
+++ b/patches/server/0387-Mid-Tick-Chunk-Tasks-Speed-up-processing-of-chunk-lo.patch
@@ -30,10 +30,10 @@ In a view distance of 15, chunk loading performance was visually faster on the c
 Flying at high speed in spectator mode was able to keep up with chunk loading (as long as they are already generated)
 
 diff --git a/src/main/java/co/aikar/timings/MinecraftTimings.java b/src/main/java/co/aikar/timings/MinecraftTimings.java
-index be3a62f543a5fec4739c14821fe5a443c1fa3f5b..6bff5317939635b925bb41eb7a67d1fd95715078 100644
+index 72f9e1978394afb6e5cc1c0d085d41586d69b84e..aa0698508de8fba6e84c20ac4d3aebb99a075c25 100644
 --- a/src/main/java/co/aikar/timings/MinecraftTimings.java
 +++ b/src/main/java/co/aikar/timings/MinecraftTimings.java
-@@ -17,6 +17,7 @@ import java.util.Map;
+@@ -16,6 +16,7 @@ import java.util.Map;
  public final class MinecraftTimings {
  
      public static final Timing serverOversleep = Timings.ofSafe("Server Oversleep");
@@ -56,18 +56,18 @@ index da93d38fe63035e4ff198ada84a4431f52d97c01..ddbc8cb712c50038922eded75dd6ca85
 +    }
  }
 diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
-index 11c6e8ce10c53dcb639145fbda32c5426eb6b3d9..087f31ac0cc7816b1cbeffc45be6927b174dee62 100644
+index 494a3afaaa0e3496d30e8d97edbab62b21610dfe..fa3a9d763f7072c68b126ce95fee191aab576e43 100644
 --- a/src/main/java/net/minecraft/server/MinecraftServer.java
 +++ b/src/main/java/net/minecraft/server/MinecraftServer.java
-@@ -1055,6 +1055,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
+@@ -1112,6 +1112,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
                          // Paper end
                          tickSection = curTime;
                      }
 +                    midTickChunksTasksRan = 0; // Paper
                      // Spigot end
  
-                     //MinecraftServer.currentTick = (int) (System.currentTimeMillis() / 50); // CraftBukkit // Paper - don't overwrite current tick time
-@@ -1124,7 +1125,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
+                     if (this.debugCommandProfilerDelayStart) {
+@@ -1186,7 +1187,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
  
      }
  
@@ -76,7 +76,7 @@ index 11c6e8ce10c53dcb639145fbda32c5426eb6b3d9..087f31ac0cc7816b1cbeffc45be6927b
          // CraftBukkit start
          if (isOversleep) return canOversleep();// Paper - because of our changes, this logic is broken
          return this.forceTicks || this.runningTask() || Util.getMillis() < (this.mayHaveDelayedTasks ? this.delayedTasksMaxNextTickTime : this.nextTickTime);
-@@ -1154,6 +1155,23 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
+@@ -1216,6 +1217,23 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
          });
      }
  
@@ -100,7 +100,7 @@ index 11c6e8ce10c53dcb639145fbda32c5426eb6b3d9..087f31ac0cc7816b1cbeffc45be6927b
      @Override
      public TickTask wrapRunnable(Runnable runnable) {
          return new TickTask(this.tickCount, runnable);
-@@ -1240,6 +1258,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
+@@ -1311,6 +1329,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
          // Paper start - move oversleep into full server tick
          isOversleep = true;MinecraftTimings.serverOversleep.startTiming();
          this.managedBlock(() -> {
@@ -108,10 +108,10 @@ index 11c6e8ce10c53dcb639145fbda32c5426eb6b3d9..087f31ac0cc7816b1cbeffc45be6927b
              return !this.canOversleep();
          });
          isOversleep = false;MinecraftTimings.serverOversleep.stopTiming();
-@@ -1318,13 +1337,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
+@@ -1379,13 +1398,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
      }
  
-     protected void tickChildren(BooleanSupplier shouldKeepTicking) {
+     public void tickChildren(BooleanSupplier shouldKeepTicking) {
 +        midTickLoadChunks(); // Paper
          MinecraftTimings.bukkitSchedulerTimer.startTiming(); // Spigot // Paper
          this.server.getScheduler().mainThreadHeartbeat(this.tickCount); // CraftBukkit
@@ -125,8 +125,8 @@ index 11c6e8ce10c53dcb639145fbda32c5426eb6b3d9..087f31ac0cc7816b1cbeffc45be6927b
          this.profiler.popPush("levels");
          Iterator iterator = this.getAllLevels().iterator();
  
-@@ -1335,7 +1357,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
-             processQueue.remove().run();
+@@ -1396,7 +1418,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
+             this.processQueue.remove().run();
          }
          MinecraftTimings.processQueueTimer.stopTiming(); // Spigot
 -
@@ -134,7 +134,7 @@ index 11c6e8ce10c53dcb639145fbda32c5426eb6b3d9..087f31ac0cc7816b1cbeffc45be6927b
          MinecraftTimings.timeUpdateTimer.startTiming(); // Spigot // Paper
          // Send time updates to everyone, it will get the right time from the world the player is in.
          // Paper start - optimize time updates
-@@ -1377,9 +1399,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
+@@ -1438,9 +1460,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
              this.profiler.push("tick");
  
              try {
@@ -147,18 +147,10 @@ index 11c6e8ce10c53dcb639145fbda32c5426eb6b3d9..087f31ac0cc7816b1cbeffc45be6927b
                  // Spigot Start
                  CrashReport crashreport;
 diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
-index f5de878020be9465739fba07fd7dea46b0a3ae34..3744cce8611ac01b1b6c76cd3c4890795c1f06a2 100644
+index 8523fbd66ed42cd5b959d57cab515fa4a774a575..751454ad5a2c374c01ff360535428db36c0aa1b3 100644
 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
 +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
-@@ -22,6 +22,7 @@ import net.minecraft.core.BlockPos;
- import net.minecraft.core.SectionPos;
- import net.minecraft.network.protocol.Packet;
- import net.minecraft.server.MCUtil;
-+import net.minecraft.server.MinecraftServer;
- import net.minecraft.server.level.progress.ChunkProgressListener;
- import net.minecraft.util.Mth;
- import net.minecraft.util.profiling.ProfilerFiller;
-@@ -719,6 +720,7 @@ public class ServerChunkCache extends ChunkSource {
+@@ -703,6 +703,7 @@ public class ServerChunkCache extends ChunkSource {
          this.level.getProfiler().push("purge");
          this.level.timings.doChunkMap.startTiming(); // Spigot
          this.distanceManager.purgeStaleTickets();
@@ -166,15 +158,15 @@ index f5de878020be9465739fba07fd7dea46b0a3ae34..3744cce8611ac01b1b6c76cd3c489079
          this.runDistanceManagerUpdates();
          this.level.timings.doChunkMap.stopTiming(); // Spigot
          this.level.getProfiler().popPush("chunks");
-@@ -728,6 +730,7 @@ public class ServerChunkCache extends ChunkSource {
+@@ -712,6 +713,7 @@ public class ServerChunkCache extends ChunkSource {
          this.level.timings.doChunkUnload.startTiming(); // Spigot
          this.level.getProfiler().popPush("unload");
-         this.chunkMap.tick(shouldKeepTicking);
+         this.chunkMap.tick(booleansupplier);
 +        this.level.getServer().midTickLoadChunks(); // Paper
          this.level.timings.doChunkUnload.stopTiming(); // Spigot
          this.level.getProfiler().pop();
          this.clearCache();
-@@ -782,7 +785,7 @@ public class ServerChunkCache extends ChunkSource {
+@@ -751,7 +753,7 @@ public class ServerChunkCache extends ChunkSource {
              };
              // Paper end
              this.level.timings.chunkTicks.startTiming(); // Paper
@@ -183,15 +175,15 @@ index f5de878020be9465739fba07fd7dea46b0a3ae34..3744cce8611ac01b1b6c76cd3c489079
                  Optional<LevelChunk> optional = ((Either) playerchunk.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left();
  
                  if (optional.isPresent()) {
-@@ -806,6 +809,7 @@ public class ServerChunkCache extends ChunkSource {
-                             //this.world.timings.chunkTicks.startTiming(); // Spigot // Paper
-                             this.level.tickChunk(chunk, k);
-                             //this.world.timings.chunkTicks.stopTiming(); // Spigot // Paper
+@@ -768,6 +770,7 @@ public class ServerChunkCache extends ChunkSource {
+                         chunk.setInhabitedTime(chunk.getInhabitedTime() + j);
+                         if (flag1 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunk.getPos()) && !this.chunkMap.isOutsideOfRange(chunkcoordintpair, true)) { // Spigot
+                             NaturalSpawner.spawnForChunk(this.level, chunk, spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag2);
 +                            if (chunksTicked[0]++ % 10 == 0) this.level.getServer().midTickLoadChunks(); // Paper
                          }
-                     }
-                 }
-@@ -963,6 +967,41 @@ public class ServerChunkCache extends ChunkSource {
+ 
+                         // this.level.timings.doTickTiles.startTiming(); // Spigot // Paper
+@@ -935,6 +938,41 @@ public class ServerChunkCache extends ChunkSource {
              super.doRunTask(task);
          }
  
@@ -210,7 +202,7 @@ index f5de878020be9465739fba07fd7dea46b0a3ae34..3744cce8611ac01b1b6c76cd3c489079
 +            return false;
 +        }
 +        public void midTickLoadChunks() {
-+            MinecraftServer server = ServerChunkCache.this.level.getServer();
++            net.minecraft.server.MinecraftServer server = ServerChunkCache.this.level.getServer();
 +            // always try to load chunks, restrain generation/other updates only. don't count these towards tick count
 +            //noinspection StatementWithEmptyBody
 +            while (pollChunkLoadTasks()) {}
@@ -231,13 +223,13 @@ index f5de878020be9465739fba07fd7dea46b0a3ae34..3744cce8611ac01b1b6c76cd3c489079
 +        // Paper end
 +
          @Override
-         protected boolean pollTask() {
          // CraftBukkit start - process pending Chunk loadCallback() and unloadCallback() after each run task
+         public boolean pollTask() {
 diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
-index 5127bce423a83711cea94e387b3ae7866215ded5..4e75cc5e52a5295e32ccadb371702a405bb518bb 100644
+index 5944c44eadca550671d7740af5756985afede39d..fd3159f7767faaa55ed49eba237e30a2dbd4fa92 100644
 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java
 +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
-@@ -565,6 +565,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
+@@ -578,6 +578,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
          }
          timings.scheduledBlocks.stopTiming(); // Paper
  
@@ -245,27 +237,24 @@ index 5127bce423a83711cea94e387b3ae7866215ded5..4e75cc5e52a5295e32ccadb371702a40
          gameprofilerfiller.popPush("raid");
          this.timings.raids.startTiming(); // Paper - timings
          this.raids.tick();
-@@ -573,6 +574,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
+@@ -586,6 +587,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
          timings.doSounds.startTiming(); // Spigot
          this.runBlockEvents();
          timings.doSounds.stopTiming(); // Spigot
 +        this.getServer().midTickLoadChunks(); // Paper
          this.handlingTick = false;
-         gameprofilerfiller.popPush("entities");
+         gameprofilerfiller.pop();
          boolean flag3 = true || !this.players.isEmpty() || !this.getForcedChunks().isEmpty(); // CraftBukkit - this prevents entity cleanup, other issues on servers with no players
-@@ -639,6 +641,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
+@@ -632,10 +634,12 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
              timings.entityTick.stopTiming(); // Spigot
- 
-             this.tickingEntities = false;
-+            this.getServer().midTickLoadChunks(); // Paper
- 
-             Entity entity2;
- 
-@@ -648,6 +651,7 @@ public class ServerLevel extends net.minecraft.world.level.Level implements Worl
-             }
- 
              timings.tickEntities.stopTiming(); // Spigot
+             gameprofilerfiller.pop();
 +            this.getServer().midTickLoadChunks(); // Paper
              this.tickBlockEntities();
          }
  
+         gameprofilerfiller.push("entityManagement");
++        this.getServer().midTickLoadChunks(); // Paper
+         this.entityManager.tick();
+         gameprofilerfiller.pop();
+     }
diff --git a/patches/server-remapped/0431-Don-t-move-existing-players-to-world-spawn.patch b/patches/server/0388-Don-t-move-existing-players-to-world-spawn.patch
similarity index 65%
rename from patches/server-remapped/0431-Don-t-move-existing-players-to-world-spawn.patch
rename to patches/server/0388-Don-t-move-existing-players-to-world-spawn.patch
index 02f8b575b..6b5d0a25e 100644
--- a/patches/server-remapped/0431-Don-t-move-existing-players-to-world-spawn.patch
+++ b/patches/server/0388-Don-t-move-existing-players-to-world-spawn.patch
@@ -10,28 +10,29 @@ larger than the keep loaded range.
 By skipping this, we avoid potential for a large spike on server start.
 
 diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-index 286b75a27103a084a9f9d79a90716ebcad65d813..162b1a8c6ab57aafa4f6deefc842755a8e14208e 100644
+index 2822d493500dcd01c26ff5b205da83d8d356e119..bfa91166c18110877f751a5325e59623a05325d0 100644
 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
 +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-@@ -251,7 +251,7 @@ public class ServerPlayer extends Player implements ContainerListener {
+@@ -309,7 +309,7 @@ public class ServerPlayer extends Player {
          this.stats = server.getPlayerList().getStatisticManager(this);
          this.advancements = server.getPlayerList().getPlayerAdvancements(this);
          this.maxUpStep = 1.0F;
 -        this.fudgeSpawnLocation(world);
 +        //this.c(worldserver); // Paper - don't move to spawn on login, only first join
-         this.textFilter = server.createTextFilterForPlayer(this);
  
          this.cachedSingleHashSet = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<>(this); // Paper
-@@ -303,6 +303,7 @@ public class ServerPlayer extends Player implements ContainerListener {
+ 
+@@ -359,7 +359,7 @@ public class ServerPlayer extends Player {
      }
      // CraftBukkit end
  
-+    public final void moveToSpawn(ServerLevel worldserver) { fudgeSpawnLocation(worldserver); } // Paper - OBFHELPER
-     private void fudgeSpawnLocation(ServerLevel world) {
-         BlockPos blockposition = world.getSpawn();
+-    private void fudgeSpawnLocation(ServerLevel world) {
++    public void fudgeSpawnLocation(ServerLevel world) { // Paper - private -> public
+         BlockPos blockposition = world.getSharedSpawnPos();
  
-@@ -480,7 +481,7 @@ public class ServerPlayer extends Player implements ContainerListener {
-                 position = Vec3.atCenterOf(((ServerLevel) world).getSpawn());
+         if (world.dimensionType().hasSkyLight() && world.serverLevelData.getGameType() != GameType.ADVENTURE) { // CraftBukkit
+@@ -527,7 +527,7 @@ public class ServerPlayer extends Player {
+                 position = Vec3.atCenterOf(((ServerLevel) world).getSharedSpawnPos());
              }
              this.level = world;
 -            this.setPos(position.x(), position.y(), position.z());
@@ -40,15 +41,15 @@ index 286b75a27103a084a9f9d79a90716ebcad65d813..162b1a8c6ab57aafa4f6deefc842755a
          this.gameMode.setLevel((ServerLevel) world);
      }
 diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
-index 86c5549196a4e9011c5240e7918b466c299be4a3..30666fca36b683158ff60302684b5093f5536e24 100644
+index f98a1c32e0c209473cf7268cbd8245ab9c134d28..18485689bcbf7818c3ca5b82086acef51888603b 100644
 --- a/src/main/java/net/minecraft/server/players/PlayerList.java
 +++ b/src/main/java/net/minecraft/server/players/PlayerList.java
-@@ -204,6 +204,8 @@ public abstract class PlayerList {
+@@ -207,6 +207,8 @@ public abstract class PlayerList {
              worldserver1 = worldserver;
          }
  
-+        if (nbttagcompound == null) player.moveToSpawn(worldserver1); // Paper - only move to spawn on first login, otherwise, stay where you are....
++        if (nbttagcompound == null) player.fudgeSpawnLocation(worldserver1); // Paper - only move to spawn on first login, otherwise, stay where you are....
 +
          player.setLevel(worldserver1);
-         player.gameMode.setLevel((ServerLevel) player.level);
          String s1 = "local";
+