diff --git a/patches/server/ChunkMap.mainInvokingExecutor.patch b/patches/server/ChunkMap.mainInvokingExecutor.patch
new file mode 100644
index 0000000000..ee34df28f5
--- /dev/null
+++ b/patches/server/ChunkMap.mainInvokingExecutor.patch
@@ -0,0 +1,36 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Shane Freeder <theboyetronic@gmail.com>
+Date: Sat, 14 Aug 2021 14:49:45 +0100
+Subject: [PATCH] ChunkMap.mainInvokingExecutor
+
+This is a temp patch, this should maybe be moved to a more generic map or potentially wrapped into mcutil for the sake of this being such a generic concept
+anyways
+
+diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
+@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
+     public final ServerLevel level;
+     private final ThreadedLevelLightEngine lightEngine;
+     private final BlockableEventLoop<Runnable> mainThreadExecutor;
++    final java.util.concurrent.Executor mainInvokingExecutor; // Paper // Paper - Move to MCUtil?
+     public final ChunkGenerator generator;
+     public final Supplier<DimensionDataStorage> overworldDataStorage;
+     private final PoiManager poiManager;
+@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
+         this.level = world;
+         this.generator = chunkGenerator;
+         this.mainThreadExecutor = mainThreadExecutor;
++        // Paper start
++        this.mainInvokingExecutor = (run) -> {
++            if (MCUtil.isMainThread()) {
++                run.run();
++            } else {
++                mainThreadExecutor.execute(run);
++            }
++        };
++        // Paper end
+         ProcessorMailbox<Runnable> threadedmailbox = ProcessorMailbox.create(executor, "worldgen");
+ 
+         Objects.requireNonNull(mainThreadExecutor);
diff --git a/patches/server/Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch b/patches/server/Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch
index 0c7be35d3b..c4ee2d8add 100644
--- a/patches/server/Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch
+++ b/patches/server/Fix-Entity-Teleportation-and-cancel-velocity-if-tele.patch
@@ -27,9 +27,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
          this.awaitingTeleportTime = this.tickCount;
 -        this.player.absMoveTo(d0, d1, d2, f, f1);
 +        this.player.moveTo(d0, d1, d2, f, f1); // Paper - use proper setPositionRotation for teleportation
-         this.player.forceCheckHighPriority(); // Paper
          this.player.connection.send(new ClientboundPlayerPositionPacket(d0 - d3, d1 - d4, d2 - d5, f - f2, f1 - f3, set, this.awaitingTeleport, flag));
      }
+ 
 diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/world/entity/Entity.java
diff --git a/patches/server/Implement-Chunk-Priority-Urgency-System-for-Chunks.patch b/patches/server/Implement-Chunk-Priority-Urgency-System-for-Chunks.patch
deleted file mode 100644
index 361a411e76..0000000000
--- a/patches/server/Implement-Chunk-Priority-Urgency-System-for-Chunks.patch
+++ /dev/null
@@ -1,1196 +0,0 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Aikar <aikar@aikar.co>
-Date: Sat, 11 Apr 2020 03:56:07 -0400
-Subject: [PATCH] Implement Chunk Priority / Urgency System for Chunks
-
-Mark chunks that are blocking main thread for world generation as urgent
-
-Implements a general priority system so that chunks that are sorted in
-the generator queues can prioritize certain chunks over another.
-
-Urgent chunks will jump to the front of the line, ensuring that a
-sync chunk load on an ungenerated chunk does not lag the server for
-a long period of time if the servers generator queues are filled with
-lots of chunks already.
-
-This massively reduces the lag spikes from sync chunk gens.
-
-Then we further prioritize loading order so nearby chunks have higher
-priority than distant chunks, reducing the pressure a high no tick
-view distance holds on you.
-
-Chunks in front of the player have higher priority, to help with
-fast traveling players keep up with their movement.
-
-diff --git a/src/main/java/com/destroystokyo/paper/io/chunk/ChunkTaskManager.java b/src/main/java/com/destroystokyo/paper/io/chunk/ChunkTaskManager.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/com/destroystokyo/paper/io/chunk/ChunkTaskManager.java
-+++ b/src/main/java/com/destroystokyo/paper/io/chunk/ChunkTaskManager.java
-@@ -0,0 +0,0 @@ public final class ChunkTaskManager {
-     }
- 
-     static void dumpChunkInfo(Set<ChunkHolder> seenChunks, ChunkHolder chunkHolder, int x, int z) {
--        dumpChunkInfo(seenChunks, chunkHolder, x, z, 0, 1);
-+        dumpChunkInfo(seenChunks, chunkHolder, x, z, 0, 4); // Paper - 1->4
-     }
- 
-     static void dumpChunkInfo(Set<ChunkHolder> seenChunks, ChunkHolder chunkHolder, int x, int z, int indent, int maxDepth) {
-@@ -0,0 +0,0 @@ public final class ChunkTaskManager {
-             PaperFileIOThread.LOGGER.log(Level.ERROR, indentStr + "Chunk Status - " + ((chunk == null) ? "null chunk" : chunk.getStatus().toString()));
-             PaperFileIOThread.LOGGER.log(Level.ERROR, indentStr + "Chunk Ticket Status - "  + ChunkHolder.getStatus(chunkHolder.getTicketLevel()));
-             PaperFileIOThread.LOGGER.log(Level.ERROR, indentStr + "Chunk Holder Status - " + ((holderStatus == null) ? "null" : holderStatus.toString()));
-+            // Paper start
-+            PaperFileIOThread.LOGGER.log(Level.ERROR, indentStr + "Chunk Holder Priority - " + chunkHolder.queueLevel);
-+
-+            if (!chunkHolder.neighbors.isEmpty()) {
-+                if (indent >= maxDepth) {
-+                    PaperFileIOThread.LOGGER.log(Level.ERROR, indentStr + "Chunk Neighbors: (Can't show, too deeply nested)");
-+                    return;
-+                }
-+                PaperFileIOThread.LOGGER.log(Level.ERROR, indentStr + "Chunk Neighbors: ");
-+                for (ChunkHolder neighbor : chunkHolder.neighbors.keySet()) {
-+                    ChunkStatus status = neighbor.getChunkHolderStatus();
-+                    if (status != null && status.isOrAfter(ChunkHolder.getStatus(neighbor.getTicketLevel()))) {
-+                        continue;
-+                    }
-+                    int nx = neighbor.pos.x;
-+                    int nz = neighbor.pos.z;
-+                    if (seenChunks.contains(neighbor)) {
-+                        PaperFileIOThread.LOGGER.log(Level.ERROR, indentStr + "  " + nx + "," + nz + " in " + chunkHolder.getWorld().getWorld().getName() + " (CIRCULAR)");
-+                        continue;
-+                    }
-+                    PaperFileIOThread.LOGGER.log(Level.ERROR, indentStr + "  " + nx + "," + nz + " in " + chunkHolder.getWorld().getWorld().getName() + ":");
-+                    dumpChunkInfo(seenChunks, neighbor, nx, nz, indent + 1, maxDepth);
-+                }
-+            }
-+            // Paper end
-         }
-     }
- 
-diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/MCUtil.java
-+++ b/src/main/java/net/minecraft/server/MCUtil.java
-@@ -0,0 +0,0 @@ public final class MCUtil {
-                 chunkData.addProperty("x", playerChunk.pos.x);
-                 chunkData.addProperty("z", playerChunk.pos.z);
-                 chunkData.addProperty("ticket-level", playerChunk.getTicketLevel());
-+                chunkData.addProperty("priority", playerChunk.queueLevel); // Paper - priority
-                 chunkData.addProperty("state", ChunkHolder.getFullChunkStatus(playerChunk.getTicketLevel()).toString());
-                 chunkData.addProperty("queued-for-unload", chunkMap.toDrop.contains(playerChunk.pos.longKey));
-                 chunkData.addProperty("status", status == null ? "unloaded" : status.toString());
-diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
-+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
-@@ -0,0 +0,0 @@ public class ChunkHolder {
-     private final DebugBuffer<ChunkHolder.ChunkSaveDebug> chunkToSaveHistory;
-     public int oldTicketLevel;
-     private int ticketLevel;
--    private int queueLevel;
-+    public volatile int queueLevel; // Paper - private->public, make volatile since this is concurrently accessed
-     public final ChunkPos pos;
-     private boolean hasChangedSections;
-     private final ShortSet[] changedBlocksPerSection;
-@@ -0,0 +0,0 @@ public class ChunkHolder {
- 
-     boolean isUpdateQueued = false; // Paper
-     private final ChunkMap chunkMap; // Paper
-+    public ServerLevel getWorld() { return chunkMap.level; } // Paper
-     // Paper start - no-tick view distance
-     public final LevelChunk getSendingChunk() {
-         // it's important that we use getChunkAtIfLoadedImmediately to mirror the chunk sending logic used
-@@ -0,0 +0,0 @@ public class ChunkHolder {
-     }
-     // Paper end
- 
-+    // Paper start - Chunk gen/load priority system
-+    volatile int neighborPriority = -1;
-+    volatile int priorityBoost = 0;
-+    public final java.util.concurrent.ConcurrentHashMap<ChunkHolder, ChunkStatus> neighbors = new java.util.concurrent.ConcurrentHashMap<>();
-+    public final it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<Integer> neighborPriorities = new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>();
-+
-+    private int getDemandedPriority() {
-+        int priority = neighborPriority; // if we have a neighbor priority, use it
-+        int myPriority = getMyPriority();
-+
-+        if (priority == -1 || (ticketLevel <= 33 && priority > myPriority)) {
-+            priority = myPriority;
-+        }
-+
-+        return Math.max(1, Math.min(Math.max(ticketLevel, ChunkMap.MAX_CHUNK_DISTANCE), priority));
-+    }
-+
-+    private int getMyPriority() {
-+        if (priorityBoost == DistanceManager.URGENT_PRIORITY) {
-+            return 2; // Urgent - ticket level isn't always 31 so 33-30 = 3, but allow 1 more tasks to go below this for dependents
-+        }
-+        return ticketLevel - priorityBoost;
-+    }
-+
-+    private int getNeighborsPriority() {
-+        return (neighborPriorities.isEmpty() ? getMyPriority() : getDemandedPriority()) + 1;
-+    }
-+
-+    public void onNeighborRequest(ChunkHolder neighbor, ChunkStatus status) {
-+        neighbor.setNeighborPriority(this, getNeighborsPriority());
-+        this.neighbors.compute(neighbor, (playerChunk, currentWantedStatus) -> {
-+            if (currentWantedStatus == null || !currentWantedStatus.isOrAfter(status)) {
-+                //System.out.println(this + " request " + neighbor + " at " + status + " currently " + currentWantedStatus);
-+                return status;
-+            } else {
-+                //System.out.println(this + " requested " + neighbor + " at " + status + " but thats lower than other wanted status " + currentWantedStatus);
-+                return currentWantedStatus;
-+            }
-+        });
-+
-+    }
-+
-+    public void onNeighborDone(ChunkHolder neighbor, ChunkStatus chunkstatus, ChunkAccess chunk) {
-+        this.neighbors.compute(neighbor, (playerChunk, wantedStatus) -> {
-+            if (wantedStatus != null && chunkstatus.isOrAfter(wantedStatus)) {
-+                //System.out.println(this + " neighbor done at " + neighbor + " for status " + chunkstatus + " wanted " + wantedStatus);
-+                neighbor.removeNeighborPriority(this);
-+                return null;
-+            } else {
-+                //System.out.println(this + " neighbor finished our previous request at " + neighbor + " for status " + chunkstatus + " but we now want instead " + wantedStatus);
-+                return wantedStatus;
-+            }
-+        });
-+    }
-+
-+    private void removeNeighborPriority(ChunkHolder requester) {
-+        synchronized (neighborPriorities) {
-+            neighborPriorities.remove(requester.pos.toLong());
-+            recalcNeighborPriority();
-+        }
-+        checkPriority();
-+    }
-+
-+
-+    private void setNeighborPriority(ChunkHolder requester, int priority) {
-+        synchronized (neighborPriorities) {
-+            neighborPriorities.put(requester.pos.toLong(), Integer.valueOf(priority));
-+            recalcNeighborPriority();
-+        }
-+        checkPriority();
-+    }
-+
-+    private void recalcNeighborPriority() {
-+        neighborPriority = -1;
-+        if (!neighborPriorities.isEmpty()) {
-+            synchronized (neighborPriorities) {
-+                for (Integer neighbor : neighborPriorities.values()) {
-+                    if (neighbor < neighborPriority || neighborPriority == -1) {
-+                        neighborPriority = neighbor;
-+                    }
-+                }
-+            }
-+        }
-+    }
-+    private void checkPriority() {
-+        if (queueLevel != getDemandedPriority()) this.chunkMap.queueHolderUpdate(this);
-+    }
-+
-+    public final double getDistance(ServerPlayer player) {
-+        return getDistance(player.getX(), player.getZ());
-+    }
-+    public final double getDistance(double blockX, double blockZ) {
-+        int cx = net.minecraft.server.MCUtil.fastFloor(blockX) >> 4;
-+        int cz = net.minecraft.server.MCUtil.fastFloor(blockZ) >> 4;
-+        final double x = pos.x - cx;
-+        final double z = pos.z - cz;
-+        return (x * x) + (z * z);
-+    }
-+
-+    public final double getDistanceFrom(BlockPos pos) {
-+        return getDistance(pos.getX(), pos.getZ());
-+    }
-+
-+    public static ChunkStatus getNextStatus(ChunkStatus status) {
-+        if (status == ChunkStatus.FULL) {
-+            return status;
-+        }
-+        return CHUNK_STATUSES.get(status.getIndex() + 1);
-+    }
-+    public CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> getStatusFutureUncheckedMain(ChunkStatus chunkstatus) {
-+        return ensureMain(getFutureIfPresentUnchecked(chunkstatus));
-+    }
-+    public <T> CompletableFuture<T> ensureMain(CompletableFuture<T> future) {
-+        return future.thenApplyAsync(r -> r, chunkMap.mainInvokingExecutor);
-+    }
-+
-+    @Override
-+    public String toString() {
-+        return "PlayerChunk{" +
-+            "location=" + pos +
-+            ", ticketLevel=" + ticketLevel + "/" + getStatus(this.ticketLevel) +
-+            ", chunkHolderStatus=" + getChunkHolderStatus() +
-+            ", neighborPriority=" + getNeighborsPriority() +
-+            ", priority=(" + ticketLevel + " - " + priorityBoost +" vs N " + neighborPriority + ") = " + getDemandedPriority() + " A " + queueLevel +
-+            '}';
-+    }
-+    // Paper end
-+
-     // Paper start - optimise isOutsideOfRange
-     // cached here to avoid a map lookup
-     com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> playersInMobSpawnRange;
-@@ -0,0 +0,0 @@ public class ChunkHolder {
-         // CraftBukkit start
-         // ChunkUnloadEvent: Called before the chunk is unloaded: isChunkLoaded is still true and chunk can still be modified by plugins.
-         if (playerchunk_state.isOrAfter(ChunkHolder.FullChunkStatus.BORDER) && !playerchunk_state1.isOrAfter(ChunkHolder.FullChunkStatus.BORDER)) {
--            this.getFutureIfPresentUnchecked(ChunkStatus.FULL).thenAccept((either) -> {
-+            this.getStatusFutureUncheckedMain(ChunkStatus.FULL).thenAccept((either) -> { // Paper - ensure main
-                 LevelChunk chunk = (LevelChunk)either.left().orElse(null);
-                 if (chunk != null) {
-                     chunkStorage.callbackExecutor.execute(() -> {
-@@ -0,0 +0,0 @@ public class ChunkHolder {
-             this.fullChunkFuture = chunkStorage.prepareAccessibleChunk(this);
-             this.scheduleFullChunkPromotion(chunkStorage, this.fullChunkFuture, executor, ChunkHolder.FullChunkStatus.BORDER);
-             // Paper start - cache ticking ready status
--            this.fullChunkFuture.thenAccept(either -> {
-+            ensureMain(this.fullChunkFuture).thenAccept(either -> { // Paper - ensure main
-                 final Optional<LevelChunk> left = either.left();
-                 if (left.isPresent() && ChunkHolder.this.fullChunkCreateCount == expectCreateCount) {
-                     // note: Here is a very good place to add callbacks to logic waiting on this.
-                     LevelChunk fullChunk = either.left().get();
-                     ChunkHolder.this.isFullChunkReady = true;
-                     fullChunk.playerChunk = ChunkHolder.this;
-+                    this.chunkMap.distanceManager.clearPriorityTickets(pos);
-                 }
-             });
-             this.updateChunkToSave(this.fullChunkFuture, "full");
-@@ -0,0 +0,0 @@ public class ChunkHolder {
-             this.tickingChunkFuture = chunkStorage.prepareTickingChunk(this);
-             this.scheduleFullChunkPromotion(chunkStorage, this.tickingChunkFuture, executor, ChunkHolder.FullChunkStatus.TICKING);
-             // Paper start - cache ticking ready status
--            this.tickingChunkFuture.thenAccept(either -> {
-+            ensureMain(this.tickingChunkFuture).thenAccept(either -> { // Paper - ensure main
-                 either.ifLeft(chunk -> {
-                     // note: Here is a very good place to add callbacks to logic waiting on this.
-                     ChunkHolder.this.isTickingReady = true;
-@@ -0,0 +0,0 @@ public class ChunkHolder {
-             this.entityTickingChunkFuture = chunkStorage.prepareEntityTickingChunk(this.pos);
-             this.scheduleFullChunkPromotion(chunkStorage, this.entityTickingChunkFuture, executor, ChunkHolder.FullChunkStatus.ENTITY_TICKING);
-             // Paper start - cache ticking ready status
--            this.entityTickingChunkFuture.thenAccept(either -> {
-+            ensureMain(this.entityTickingChunkFuture).thenAccept(either -> { // Paper ensureMain
-                 either.ifLeft(chunk -> {
-                     ChunkHolder.this.isEntityTickingReady = true;
-                 });
-@@ -0,0 +0,0 @@ public class ChunkHolder {
-             this.demoteFullChunk(chunkStorage, playerchunk_state1);
-         }
- 
--        this.onLevelChange.onLevelChange(this.pos, this::getQueueLevel, this.ticketLevel, this::setQueueLevel);
-+        //this.onLevelChange.onLevelChange(this.pos, this::getQueueLevel, this.ticketLevel, this::setQueueLevel);
-+        // Paper start - raise IO/load priority if priority changes, use our preferred priority
-+        priorityBoost = chunkMap.distanceManager.getChunkPriority(pos);
-+        int priority = getDemandedPriority();
-+        if (this.queueLevel > priority) {
-+            int ioPriority = com.destroystokyo.paper.io.PrioritizedTaskQueue.NORMAL_PRIORITY;
-+            if (priority <= 10) {
-+                ioPriority = com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGHEST_PRIORITY;
-+            } else if (priority <= 20) {
-+                ioPriority = com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGH_PRIORITY;
-+            }
-+            chunkMap.level.asyncChunkTaskManager.raisePriority(pos.x, pos.z, ioPriority);
-+        }
-+        if (this.queueLevel != priority) {
-+            this.onLevelChange.onLevelChange(this.pos, () -> this.queueLevel, priority, p -> this.queueLevel = p); // use preferred priority
-+            int neighborsPriority = getNeighborsPriority();
-+            this.neighbors.forEach((neighbor, neighborDesired) -> neighbor.setNeighborPriority(this, neighborsPriority));
-+        }
-+        // Paper end
-         this.oldTicketLevel = this.ticketLevel;
-         // CraftBukkit start
-         // ChunkLoadEvent: Called after the chunk is loaded: isChunkLoaded returns true and chunk is ready to be modified by plugins.
-         if (!playerchunk_state.isOrAfter(ChunkHolder.FullChunkStatus.BORDER) && playerchunk_state1.isOrAfter(ChunkHolder.FullChunkStatus.BORDER)) {
--            this.getFutureIfPresentUnchecked(ChunkStatus.FULL).thenAccept((either) -> {
-+            this.getStatusFutureUncheckedMain(ChunkStatus.FULL).thenAccept((either) -> { // Paper - ensure main
-                 LevelChunk chunk = (LevelChunk)either.left().orElse(null);
-                 if (chunk != null) {
-                     chunkStorage.callbackExecutor.execute(() -> {
-diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/level/ChunkMap.java
-+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-     public final ServerLevel level;
-     private final ThreadedLevelLightEngine lightEngine;
-     private final BlockableEventLoop<Runnable> mainThreadExecutor;
-+    final java.util.concurrent.Executor mainInvokingExecutor; // Paper
-     public final ChunkGenerator generator;
-     public final Supplier<DimensionDataStorage> overworldDataStorage;
-     private final PoiManager poiManager;
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
- 
-         @Override
-         public void execute(Runnable runnable) {
-+            org.spigotmc.AsyncCatcher.catchOp("Callback Executor execute");
-             if (this.queue == null) {
-                 this.queue = new java.util.ArrayDeque<>();
-             }
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
- 
-         @Override
-         public void run() {
-+            org.spigotmc.AsyncCatcher.catchOp("Callback Executor run");
-             if (this.queue == null) {
-                 return;
-             }
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-         this.level = world;
-         this.generator = chunkGenerator;
-         this.mainThreadExecutor = mainThreadExecutor;
-+        // Paper start
-+        this.mainInvokingExecutor = (run) -> {
-+            if (MCUtil.isMainThread()) {
-+                run.run();
-+            } else {
-+                mainThreadExecutor.execute(run);
-+            }
-+        };
-+        // Paper end
-         ProcessorMailbox<Runnable> threadedmailbox = ProcessorMailbox.create(executor, "worldgen");
- 
-         Objects.requireNonNull(mainThreadExecutor);
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-         this.playerViewDistanceTickMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets,
-             (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
-              com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newState) -> {
-+                checkHighPriorityChunks(player);
-                 if (newState.size() != 1) {
-                     return;
-                 }
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-                 }
-                 ChunkPos chunkPos = new ChunkPos(rangeX, rangeZ);
-                 ChunkMap.this.level.getChunkSource().removeTicketAtLevel(TicketType.PLAYER, chunkPos, 31, chunkPos); // entity ticking level, TODO check on update
--            });
-+                // Paper start
-+                ChunkMap.this.level.getChunkSource().clearPriorityTickets(chunkPos);
-+            },
-+            (player, prevPos, newPos) -> {
-+            player.lastHighPriorityChecked = -1; // reset and recheck
-+            checkHighPriorityChunks(player);
-+        });
-+        // Paper end
-         this.playerViewDistanceNoTickMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets);
-         this.playerViewDistanceBroadcastMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets,
-             (ServerPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ,
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-         // Paper end - no-tick view distance
-     }
- 
-+    // Paper start - Chunk Prioritization
-+    public void queueHolderUpdate(ChunkHolder playerchunk) {
-+        Runnable runnable = () -> {
-+            if (isUnloading(playerchunk)) {
-+                return; // unloaded
-+            }
-+            distanceManager.pendingChunkUpdates.add(playerchunk);
-+            if (!distanceManager.pollingPendingChunkUpdates) {
-+                level.getChunkSource().runDistanceManagerUpdates();
-+            }
-+        };
-+        if (MCUtil.isMainThread()) {
-+            // We can't use executor here because it will not execute tasks if its currently in the middle of executing tasks...
-+            runnable.run();
-+        } else {
-+            mainThreadExecutor.execute(runnable);
-+        }
-+    }
-+
-+    private boolean isUnloading(ChunkHolder playerchunk) {
-+        return playerchunk == null || toDrop.contains(playerchunk.pos.toLong());
-+    }
-+
-+    private void updateChunkPriorityMap(it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap map, long chunk, int level) {
-+        int prev = map.getOrDefault(chunk, -1);
-+        if (level > prev) {
-+            map.put(chunk, level);
-+        }
-+    }
-+
-+    public void checkHighPriorityChunks(ServerPlayer player) {
-+        int currentTick = MinecraftServer.currentTick;
-+        if (currentTick - player.lastHighPriorityChecked < 20 || !player.isRealPlayer) { // weed out fake players
-+            return;
-+        }
-+        player.lastHighPriorityChecked = currentTick;
-+        it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap priorities = new it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap();
-+
-+        int viewDistance = getEffectiveNoTickViewDistance();
-+        net.minecraft.core.BlockPos.MutableBlockPos pos = new net.minecraft.core.BlockPos.MutableBlockPos();
-+
-+        // Prioritize circular near
-+        double playerChunkX = Mth.floor(player.getX()) >> 4;
-+        double playerChunkZ = Mth.floor(player.getZ()) >> 4;
-+        pos.set(player.getX(), 0, player.getZ());
-+        double twoThirdModifier = 2D / 3D;
-+        MCUtil.getSpiralOutChunks(pos, Math.min(6, viewDistance)).forEach(coord -> {
-+            if (shouldSkipPrioritization(coord)) return;
-+
-+            double dist = MCUtil.distance(playerChunkX, 0, playerChunkZ, coord.x, 0, coord.z);
-+            // Prioritize immediate
-+            if (dist <= 4) {
-+                updateChunkPriorityMap(priorities, coord.toLong(), (int) (27 - dist));
-+                return;
-+            }
-+
-+            // Prioritize nearby chunks
-+            updateChunkPriorityMap(priorities, coord.toLong(), (int) (20 - dist * twoThirdModifier));
-+        });
-+
-+        // Prioritize Frustum near 3
-+        ChunkPos front3 = player.getChunkInFront(3);
-+        pos.set(front3.x << 4, 0, front3.z << 4);
-+        MCUtil.getSpiralOutChunks(pos, Math.min(5, viewDistance)).forEach(coord -> {
-+            if (shouldSkipPrioritization(coord)) return;
-+
-+            double dist = MCUtil.distance(playerChunkX, 0, playerChunkZ, coord.x, 0, coord.z);
-+            updateChunkPriorityMap(priorities, coord.toLong(), (int) (25 - dist * twoThirdModifier));
-+        });
-+
-+        // Prioritize Frustum near 5
-+        if (viewDistance > 4) {
-+            ChunkPos front5 = player.getChunkInFront(5);
-+            pos.set(front5.x << 4, 0, front5.z << 4);
-+            MCUtil.getSpiralOutChunks(pos, 4).forEach(coord -> {
-+                if (shouldSkipPrioritization(coord)) return;
-+
-+                double dist = MCUtil.distance(playerChunkX, 0, playerChunkZ, coord.x, 0, coord.z);
-+                updateChunkPriorityMap(priorities, coord.toLong(), (int) (25 - dist * twoThirdModifier));
-+            });
-+        }
-+
-+        // Prioritize Frustum far 7
-+        if (viewDistance > 6) {
-+            ChunkPos front7 = player.getChunkInFront(7);
-+            pos.set(front7.x << 4, 0, front7.z << 4);
-+            MCUtil.getSpiralOutChunks(pos, 3).forEach(coord -> {
-+                if (shouldSkipPrioritization(coord)) {
-+                    return;
-+                }
-+                double dist = MCUtil.distance(playerChunkX, 0, playerChunkZ, coord.x, 0, coord.z);
-+                updateChunkPriorityMap(priorities, coord.toLong(), (int) (25 - dist * twoThirdModifier));
-+            });
-+        }
-+
-+        if (priorities.isEmpty()) return;
-+        distanceManager.delayDistanceManagerTick = true;
-+        priorities.long2IntEntrySet().fastForEach(entry -> distanceManager.markHighPriority(new ChunkPos(entry.getLongKey()), entry.getIntValue()));
-+        distanceManager.delayDistanceManagerTick = false;
-+        level.getChunkSource().runDistanceManagerUpdates();
-+
-+    }
-+
-+    private boolean shouldSkipPrioritization(ChunkPos coord) {
-+        if (playerViewDistanceNoTickMap.getObjectsInRange(coord.toLong()) == null) return true;
-+        ChunkHolder chunk = getUpdatingChunkIfPresent(coord.toLong());
-+        return chunk != null && (chunk.isFullChunkReady());
-+    }
-+    // Paper end
-+
-     // Paper start
-     public void updatePlayerMobTypeMap(Entity entity) {
-         if (!this.level.paperConfig.perPlayerMobSpawns) {
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-         List<CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>> list = Lists.newArrayList();
-         int j = centerChunk.x;
-         int k = centerChunk.z;
-+        ChunkHolder requestingNeighbor = getUpdatingChunkIfPresent(centerChunk.toLong()); // Paper
- 
-         for (int l = -margin; l <= margin; ++l) {
-             for (int i1 = -margin; i1 <= margin; ++i1) {
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
- 
-                 ChunkStatus chunkstatus = (ChunkStatus) distanceToStatus.apply(j1);
-                 CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> completablefuture = playerchunk.getOrScheduleFuture(chunkstatus, this);
-+                // Paper start
-+                if (requestingNeighbor != null && requestingNeighbor != playerchunk && !completablefuture.isDone()) {
-+                    requestingNeighbor.onNeighborRequest(playerchunk, chunkstatus);
-+                    completablefuture.thenAccept(either -> {
-+                        requestingNeighbor.onNeighborDone(playerchunk, chunkstatus, either.left().orElse(null));
-+                    });
-+                }
-+                // Paper end
- 
-                 list.add(completablefuture);
-             }
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-         };
- 
-         CompletableFuture<CompoundTag> chunkSaveFuture = this.level.asyncChunkTaskManager.getChunkSaveFuture(pos.x, pos.z);
-+        // Paper start
-+        ChunkHolder playerChunk = getUpdatingChunkIfPresent(pos.toLong());
-+        int chunkPriority = playerChunk != null ? playerChunk.queueLevel : 33;
-+        int priority = com.destroystokyo.paper.io.PrioritizedTaskQueue.NORMAL_PRIORITY;
-+
-+        if (chunkPriority <= 10) {
-+            priority = com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGHEST_PRIORITY;
-+        } else if (chunkPriority <= 20) {
-+            priority = com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGH_PRIORITY;
-+        }
-+        boolean isHighestPriority = priority == com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGHEST_PRIORITY;
-+        // Paper end
-         if (chunkSaveFuture != null) {
--            this.level.asyncChunkTaskManager.scheduleChunkLoad(pos.x, pos.z,
--                com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGH_PRIORITY, chunkHolderConsumer, false, chunkSaveFuture);
--            this.level.asyncChunkTaskManager.raisePriority(pos.x, pos.z, com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGH_PRIORITY);
-+            this.level.asyncChunkTaskManager.scheduleChunkLoad(pos.x, pos.z, priority, chunkHolderConsumer, isHighestPriority, chunkSaveFuture); // Paper
-         } else {
--            this.level.asyncChunkTaskManager.scheduleChunkLoad(pos.x, pos.z,
--                com.destroystokyo.paper.io.PrioritizedTaskQueue.NORMAL_PRIORITY, chunkHolderConsumer, false);
-+            this.level.asyncChunkTaskManager.scheduleChunkLoad(pos.x, pos.z, priority, chunkHolderConsumer, isHighestPriority); // Paper
-         }
-+        this.level.asyncChunkTaskManager.raisePriority(pos.x, pos.z, priority); // Paper
-         return ret;
-         // Paper end
-     }
-@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
-             long i = playerchunk.getPos().toLong();
- 
-             Objects.requireNonNull(playerchunk);
--            mailbox.tell(ChunkTaskPriorityQueueSorter.message(runnable, i, playerchunk::getTicketLevel));
-+            mailbox.tell(ChunkTaskPriorityQueueSorter.message(runnable, i, () -> 1)); // Paper - final loads are always urgent!
-         });
-     }
- 
-diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/level/DistanceManager.java
-+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
-@@ -0,0 +0,0 @@ public abstract class DistanceManager {
-     }
- 
-     private static int getTicketLevelAt(SortedArraySet<Ticket<?>> arraysetsorted) {
-+        org.spigotmc.AsyncCatcher.catchOp("ChunkMapDistance::getLowestTicketLevel"); // Paper
-         return !arraysetsorted.isEmpty() ? ((Ticket) arraysetsorted.first()).getTicketLevel() : ChunkMap.MAX_CHUNK_DISTANCE + 1;
-     }
- 
-@@ -0,0 +0,0 @@ public abstract class DistanceManager {
- 
-     public boolean runAllUpdates(ChunkMap playerchunkmap) {
-         //this.f.a(); // Paper - no longer used
-+        org.spigotmc.AsyncCatcher.catchOp("DistanceManagerTick"); // Paper
-         this.playerTicketManager.runAllUpdates();
-         int i = Integer.MAX_VALUE - this.ticketTracker.runDistanceUpdates(Integer.MAX_VALUE);
-         boolean flag = i != 0;
-@@ -0,0 +0,0 @@ public abstract class DistanceManager {
- 
-         // Paper start
-         if (!this.pendingChunkUpdates.isEmpty()) {
-+            this.pollingPendingChunkUpdates = true; try { // Paper - Chunk priority
-             while(!this.pendingChunkUpdates.isEmpty()) {
-                 ChunkHolder remove = this.pendingChunkUpdates.remove();
-                 remove.isUpdateQueued = false;
-                 remove.updateFutures(playerchunkmap, this.mainThreadExecutor);
-             }
-+            } finally { this.pollingPendingChunkUpdates = false; } // Paper - Chunk priority
-             // Paper end
-             return true;
-         } else {
-@@ -0,0 +0,0 @@ public abstract class DistanceManager {
-             return flag;
-         }
-     }
-+    boolean pollingPendingChunkUpdates = false; // Paper - Chunk priority
- 
-     boolean addTicket(long i, Ticket<?> ticket) { // CraftBukkit - void -> boolean
-+        org.spigotmc.AsyncCatcher.catchOp("ChunkMapDistance::addTicket"); // Paper
-         SortedArraySet<Ticket<?>> arraysetsorted = this.getTickets(i);
-         int j = DistanceManager.getTicketLevelAt(arraysetsorted);
-         Ticket<?> ticket1 = (Ticket) arraysetsorted.addOrGet(ticket); // CraftBukkit - decompile error
-@@ -0,0 +0,0 @@ public abstract class DistanceManager {
-     }
- 
-     boolean removeTicket(long i, Ticket<?> ticket) { // CraftBukkit - void -> boolean
-+        org.spigotmc.AsyncCatcher.catchOp("ChunkMapDistance::removeTicket"); // Paper
-         SortedArraySet<Ticket<?>> arraysetsorted = this.getTickets(i);
-+        int oldLevel = getTicketLevelAt(arraysetsorted); // Paper
- 
-         boolean removed = false; // CraftBukkit
-         if (arraysetsorted.remove(ticket)) {
-@@ -0,0 +0,0 @@ public abstract class DistanceManager {
-             this.tickets.remove(i);
-         }
- 
--        this.ticketTracker.update(i, DistanceManager.getTicketLevelAt(arraysetsorted), false);
-+        // Paper start - Chunk priority
-+        int newLevel = getTicketLevelAt(arraysetsorted);
-+        if (newLevel > oldLevel) {
-+            this.ticketTracker.update(i, newLevel, false);
-+        }
-+        // Paper end
-         return removed; // CraftBukkit
-     }
- 
-@@ -0,0 +0,0 @@ public abstract class DistanceManager {
-         });
-     }
- 
-+    // Paper start - Chunk priority
-+    public static final int PRIORITY_TICKET_LEVEL = ChunkMap.MAX_CHUNK_DISTANCE;
-+    public static final int URGENT_PRIORITY = 29;
-+    public boolean delayDistanceManagerTick = false;
-+    public boolean markUrgent(ChunkPos coords) {
-+        return addPriorityTicket(coords, TicketType.URGENT, URGENT_PRIORITY);
-+    }
-+    public boolean markHighPriority(ChunkPos coords, int priority) {
-+        priority = Math.min(URGENT_PRIORITY - 1, Math.max(1, priority));
-+        return addPriorityTicket(coords, TicketType.PRIORITY, priority);
-+    }
-+
-+    public void markAreaHighPriority(ChunkPos center, int priority, int radius) {
-+        delayDistanceManagerTick = true;
-+        priority = Math.min(URGENT_PRIORITY - 1, Math.max(1, priority));
-+        int finalPriority = priority;
-+        net.minecraft.server.MCUtil.getSpiralOutChunks(center.getWorldPosition(), radius).forEach(coords -> {
-+            addPriorityTicket(coords, TicketType.PRIORITY, finalPriority);
-+        });
-+        delayDistanceManagerTick = false;
-+        chunkMap.level.getChunkSource().runDistanceManagerUpdates();
-+    }
-+
-+    public void clearAreaPriorityTickets(ChunkPos center, int radius) {
-+        delayDistanceManagerTick = true;
-+        net.minecraft.server.MCUtil.getSpiralOutChunks(center.getWorldPosition(), radius).forEach(coords -> {
-+            this.removeTicket(coords.toLong(), new Ticket<ChunkPos>(TicketType.PRIORITY, PRIORITY_TICKET_LEVEL, coords));
-+        });
-+        delayDistanceManagerTick = false;
-+        chunkMap.level.getChunkSource().runDistanceManagerUpdates();
-+    }
-+
-+    private boolean hasPlayerTicket(ChunkPos coords, int level) {
-+        SortedArraySet<Ticket<?>> tickets = this.tickets.get(coords.toLong());
-+        if (tickets == null || tickets.isEmpty()) {
-+            return false;
-+        }
-+        for (Ticket<?> ticket : tickets) {
-+            if (ticket.getType() == TicketType.PLAYER && ticket.getTicketLevel() == level) {
-+                return true;
-+            }
-+        }
-+
-+        return false;
-+    }
-+
-+    private boolean addPriorityTicket(ChunkPos coords, TicketType<ChunkPos> ticketType, int priority) {
-+        org.spigotmc.AsyncCatcher.catchOp("ChunkMapDistance::addPriorityTicket");
-+        long pair = coords.toLong();
-+        ChunkHolder chunk = chunkMap.getUpdatingChunkIfPresent(pair);
-+        boolean needsTicket = chunkMap.playerViewDistanceNoTickMap.getObjectsInRange(pair) != null && !hasPlayerTicket(coords, 33);
-+
-+        if (needsTicket) {
-+            Ticket<?> ticket = new Ticket<>(TicketType.PLAYER, 33, coords);
-+            this.ticketsToRelease.add(pair);
-+            addTicket(pair, ticket);
-+        }
-+        if ((chunk != null && chunk.isFullChunkReady())) {
-+            if (needsTicket) {
-+                chunkMap.level.getChunkSource().runDistanceManagerUpdates();
-+            }
-+            return needsTicket;
-+        }
-+
-+        boolean success;
-+        if (!(success = updatePriorityTicket(coords, ticketType, priority))) {
-+            Ticket<ChunkPos> ticket = new Ticket<ChunkPos>(ticketType, PRIORITY_TICKET_LEVEL, coords);
-+            ticket.priority = priority;
-+            success = this.addTicket(pair, ticket);
-+        } else {
-+            if (chunk == null) {
-+                chunk = chunkMap.getUpdatingChunkIfPresent(pair);
-+            }
-+            chunkMap.queueHolderUpdate(chunk);
-+        }
-+
-+        //chunkMap.world.getWorld().spawnParticle(priority <= 15 ? org.bukkit.Particle.EXPLOSION_HUGE : org.bukkit.Particle.EXPLOSION_NORMAL, chunkMap.world.getWorld().getPlayers(), null, coords.x << 4, 70, coords.z << 4, 2, 0, 0, 0, 1, null, true);
-+
-+        chunkMap.level.getChunkSource().runDistanceManagerUpdates();
-+
-+        return success;
-+    }
-+
-+    private boolean updatePriorityTicket(ChunkPos coords, TicketType<ChunkPos> type, int priority) {
-+        SortedArraySet<Ticket<?>> tickets = this.tickets.get(coords.toLong());
-+        if (tickets == null) {
-+            return false;
-+        }
-+        for (Ticket<?> ticket : tickets) {
-+            if (ticket.getType() == type) {
-+                // We only support increasing, not decreasing, too complicated
-+                ticket.setCreatedTick(this.ticketTickCounter);
-+                ticket.priority = Math.max(ticket.priority, priority);
-+                return true;
-+            }
-+        }
-+
-+        return false;
-+    }
-+
-+    public int getChunkPriority(ChunkPos coords) {
-+        org.spigotmc.AsyncCatcher.catchOp("ChunkMapDistance::getChunkPriority");
-+        SortedArraySet<Ticket<?>> tickets = this.tickets.get(coords.toLong());
-+        if (tickets == null) {
-+            return 0;
-+        }
-+        for (Ticket<?> ticket : tickets) {
-+            if (ticket.getType() == TicketType.URGENT) {
-+                return URGENT_PRIORITY;
-+            }
-+        }
-+        for (Ticket<?> ticket : tickets) {
-+            if (ticket.getType() == TicketType.PRIORITY && ticket.priority > 0) {
-+                return ticket.priority;
-+            }
-+        }
-+        return 0;
-+    }
-+
-+    public void clearPriorityTickets(ChunkPos coords) {
-+        org.spigotmc.AsyncCatcher.catchOp("ChunkMapDistance::clearPriority");
-+        this.removeTicket(coords.toLong(), new Ticket<ChunkPos>(TicketType.PRIORITY, PRIORITY_TICKET_LEVEL, coords));
-+    }
-+
-+    public void clearUrgent(ChunkPos coords) {
-+        org.spigotmc.AsyncCatcher.catchOp("ChunkMapDistance::clearUrgent");
-+        this.removeTicket(coords.toLong(), new Ticket<ChunkPos>(TicketType.URGENT, PRIORITY_TICKET_LEVEL, coords));
-+    }
-+    // Paper end
-+
-     protected void updateChunkForced(ChunkPos pos, boolean forced) {
-         Ticket<ChunkPos> ticket = new Ticket<>(TicketType.FORCED, 31, pos);
- 
-@@ -0,0 +0,0 @@ public abstract class DistanceManager {
- 
-         public void updateViewDistance(int watchDistance) {
-             ObjectIterator objectiterator = this.chunks.long2ByteEntrySet().iterator();
-+            // Paper start - set the view distance before scheduling chunk loads/unloads
-+            int lastViewDistance = this.viewDistance;
-+            this.viewDistance = watchDistance;
-+            // Paper end
- 
-             while (objectiterator.hasNext()) {
-                 it.unimi.dsi.fastutil.longs.Long2ByteMap.Entry it_unimi_dsi_fastutil_longs_long2bytemap_entry = (it.unimi.dsi.fastutil.longs.Long2ByteMap.Entry) objectiterator.next();
-                 byte b0 = it_unimi_dsi_fastutil_longs_long2bytemap_entry.getByteValue();
-                 long j = it_unimi_dsi_fastutil_longs_long2bytemap_entry.getLongKey();
- 
--                this.onLevelChange(j, b0, this.haveTicketFor(b0), b0 <= watchDistance - 2);
-+                this.onLevelChange(j, b0, b0 <= lastViewDistance - 2, this.haveTicketFor(b0)); // Paper
-             }
- 
--            this.viewDistance = watchDistance;
-+            // this.viewDistance = watchDistance; // Paper - view distance is now set further up
-         }
- 
-         private void onLevelChange(long pos, int distance, boolean oldWithinViewDistance, boolean withinViewDistance) {
-             if (oldWithinViewDistance != withinViewDistance) {
--                Ticket<?> ticket = new Ticket<>(TicketType.PLAYER, 33, new ChunkPos(pos)); // Paper - no-tick view distance
-+                ChunkPos coords = new ChunkPos(pos); // Paper - reuse variable
-+                Ticket<?> ticket = new Ticket<>(TicketType.PLAYER, 33, coords); // Paper - no-tick view distance
- 
-                 if (withinViewDistance) {
-+                    scheduleChunkLoad(pos, net.minecraft.server.MinecraftServer.currentTick, distance, (priority) -> { // Paper - smarter ticket delay based on frustum and distance
-+                    // Paper start - recheck its still valid if not cancel
-+                    if (!isChunkInRange(pos)) {
-+                        DistanceManager.this.ticketThrottlerReleaser.tell(ChunkTaskPriorityQueueSorter.release(() -> {
-+                            DistanceManager.this.mainThreadExecutor.execute(() -> {
-+                                DistanceManager.this.removeTicket(pos, ticket);
-+                                DistanceManager.this.clearPriorityTickets(coords);
-+                            });
-+                        }, pos, false));
-+                        return;
-+                    }
-+                    // abort early if we got a ticket already
-+                    if (hasPlayerTicket(coords, 33)) return;
-+                    // skip player ticket throttle for near chunks
-+                    if (priority <= 3) {
-+                        DistanceManager.this.addTicket(pos, ticket);
-+                        DistanceManager.this.ticketsToRelease.add(pos);
-+                        return;
-+                    }
-+                    // Paper end
-                     DistanceManager.this.ticketThrottlerInput.tell(ChunkTaskPriorityQueueSorter.message(() -> {
-                         DistanceManager.this.mainThreadExecutor.execute(() -> {
--                            if (this.haveTicketFor(this.getLevel(pos))) {
-+                            if (isChunkInRange(pos)) { if (!hasPlayerTicket(coords, 33)) { // Paper - high priority might of already added it
-                                 DistanceManager.this.addTicket(pos, ticket);
-                                 DistanceManager.this.ticketsToRelease.add(pos);
--                            } else {
-+                            }} else { // Paper
-                                 DistanceManager.this.ticketThrottlerReleaser.tell(ChunkTaskPriorityQueueSorter.release(() -> {
-                                 }, pos, false));
-                             }
- 
-                         });
-                     }, pos, () -> {
--                        return distance;
-+                        return Math.min(ChunkMap.MAX_CHUNK_DISTANCE, priority); // Paper - Chunk priority
-                     }));
-+                    }); // Paper
-                 } else {
-                     DistanceManager.this.ticketThrottlerReleaser.tell(ChunkTaskPriorityQueueSorter.release(() -> {
-                         DistanceManager.this.mainThreadExecutor.execute(() -> {
-                             DistanceManager.this.removeTicket(pos, ticket);
-+                            DistanceManager.this.clearPriorityTickets(coords); // Paper - Chunk priority
-                         });
-                     }, pos, true));
-                 }
-@@ -0,0 +0,0 @@ public abstract class DistanceManager {
-         private boolean haveTicketFor(int distance) {
-             return distance <= this.viewDistance - 2;
-         }
-+
-+        // Paper start - smart scheduling of player tickets
-+        private boolean isChunkInRange(long i) {
-+            return this.haveTicketFor(this.getLevel(i));
-+        }
-+        public void scheduleChunkLoad(long i, long startTick, int initialDistance, java.util.function.Consumer<Integer> task) {
-+            long elapsed = net.minecraft.server.MinecraftServer.currentTick - startTick;
-+            ChunkPos chunkPos = new ChunkPos(i);
-+            ChunkHolder updatingChunk = chunkMap.getUpdatingChunkIfPresent(i);
-+            if ((updatingChunk != null && updatingChunk.isFullChunkReady()) || !isChunkInRange(i) || getChunkPriority(chunkPos) > 0) { // Copied from above
-+                // no longer needed
-+                task.accept(1);
-+                return;
-+            }
-+
-+            int desireDelay = 0;
-+            double minDist = Double.MAX_VALUE;
-+            com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> players = chunkMap.playerViewDistanceNoTickMap.getObjectsInRange(i);
-+            if (elapsed == 0 && initialDistance <= 4) {
-+                // Aim for no delay on initial 6 chunk radius tickets save on performance of the below code to only > 6
-+                minDist = initialDistance;
-+            } else if (players != null) {
-+                Object[] backingSet = players.getBackingSet();
-+
-+                net.minecraft.core.BlockPos blockPos = chunkPos.getWorldPosition();
-+
-+                boolean isFront = false;
-+                net.minecraft.core.BlockPos.MutableBlockPos pos = new net.minecraft.core.BlockPos.MutableBlockPos();
-+                for (int index = 0, len = backingSet.length; index < len; ++index) {
-+                    if (!(backingSet[index] instanceof ServerPlayer)) {
-+                        continue;
-+                    }
-+                    ServerPlayer player = (ServerPlayer) backingSet[index];
-+
-+                    ChunkPos pointInFront = player.getChunkInFront(5);
-+                    pos.set(pointInFront.x << 4, 0, pointInFront.z << 4);
-+                    double frontDist = net.minecraft.server.MCUtil.distanceSq(pos, blockPos);
-+
-+                    pos.set(player.getX(), 0, player.getZ());
-+                    double center = net.minecraft.server.MCUtil.distanceSq(pos, blockPos);
-+
-+                    double dist = Math.min(frontDist, center);
-+                    if (!isFront) {
-+                        ChunkPos pointInBack = player.getChunkInFront(-7);
-+                        pos.set(pointInBack.x << 4, 0, pointInBack.z << 4);
-+                        double backDist = net.minecraft.server.MCUtil.distanceSq(pos, blockPos);
-+                        if (frontDist < backDist) {
-+                            isFront = true;
-+                        }
-+                    }
-+                    if (dist < minDist) {
-+                        minDist = dist;
-+                    }
-+                }
-+                if (minDist == Double.MAX_VALUE) {
-+                    minDist = 15;
-+                } else {
-+                    minDist = Math.sqrt(minDist) / 16;
-+                }
-+                if (minDist > 4) {
-+                    int desiredTimeDelayMax = isFront ?
-+                        (minDist < 10 ? 7 : 15) : // Front
-+                        (minDist < 10 ? 15 : 45); // Back
-+                    desireDelay += (desiredTimeDelayMax * 20) * (minDist / 32);
-+                }
-+            } else {
-+                minDist = initialDistance;
-+                desireDelay = 1;
-+            }
-+            long delay = desireDelay - elapsed;
-+            if (delay <= 0 && minDist > 4 && minDist < Double.MAX_VALUE) {
-+                boolean hasAnyNeighbor = false;
-+                for (int x = -1; x <= 1; x++) {
-+                    for (int z = -1; z <= 1; z++) {
-+                        if (x == 0 && z == 0) continue;
-+                        long pair = ChunkPos.asLong(chunkPos.x + x, chunkPos.z + z);
-+                        ChunkHolder neighbor = chunkMap.getUpdatingChunkIfPresent(pair);
-+                        ChunkStatus current = neighbor != null ? neighbor.getChunkHolderStatus() : null;
-+                        if (current != null && current.isOrAfter(ChunkStatus.LIGHT)) {
-+                            hasAnyNeighbor = true;
-+                        }
-+                    }
-+                }
-+                if (!hasAnyNeighbor) {
-+                    delay += 20;
-+                }
-+            }
-+            if (delay <= 0) {
-+                task.accept((int) minDist);
-+            } else {
-+                int taskDelay = (int) Math.min(delay, minDist >= 10 ? 40 : (minDist < 6 ? 5 : 20));
-+                net.minecraft.server.MCUtil.scheduleTask(taskDelay, () -> scheduleChunkLoad(i, startTick, initialDistance, task), "Player Ticket Delayer");
-+            }
-+        }
-+        // 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
-+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
-@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
-     public <T> void removeTicketAtLevel(TicketType<T> ticketType, ChunkPos chunkPos, int ticketLevel, T identifier) {
-         this.distanceManager.removeTicketAtLevel(ticketType, chunkPos, ticketLevel, identifier);
-     }
-+
-+    public boolean markUrgent(ChunkPos coords) {
-+        return this.distanceManager.markUrgent(coords);
-+    }
-+
-+    public boolean markHighPriority(ChunkPos coords, int priority) {
-+        return this.distanceManager.markHighPriority(coords, priority);
-+    }
-+
-+    public void markAreaHighPriority(ChunkPos center, int priority, int radius) {
-+        this.distanceManager.markAreaHighPriority(center, priority, radius);
-+    }
-+
-+    public void clearAreaPriorityTickets(ChunkPos center, int radius) {
-+        this.distanceManager.clearAreaPriorityTickets(center, radius);
-+    }
-+
-+    public void clearPriorityTickets(ChunkPos coords) {
-+        this.distanceManager.clearPriorityTickets(coords);
-+    }
-     // Paper end - async chunk io
- 
-     @Nullable
-@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
-             Objects.requireNonNull(completablefuture);
-             if (!completablefuture.isDone()) { // Paper
-                 // Paper start - async chunk io/loading
-+                ChunkPos pair = new ChunkPos(x1, z1); // Paper - Chunk priority
-+                this.distanceManager.markUrgent(pair); // Paper - Chunk priority
-                 this.level.asyncChunkTaskManager.raisePriority(x1, z1, com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGHEST_PRIORITY);
-                 com.destroystokyo.paper.io.chunk.ChunkTaskManager.pushChunkWait(this.level, x1, z1);
-                 // Paper end
-@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
-             chunkproviderserver_a.managedBlock(completablefuture::isDone);
-                 com.destroystokyo.paper.io.chunk.ChunkTaskManager.popChunkWait(); // Paper - async chunk debug
-                 this.level.timings.syncChunkLoad.stopTiming(); // Paper
-+                this.distanceManager.clearPriorityTickets(pair); // Paper - Chunk priority
-+                this.distanceManager.clearUrgent(pair); // Paper - Chunk priority
-             } // Paper
-             ichunkaccess = (ChunkAccess) ((Either) completablefuture.join()).map((ichunkaccess1) -> {
-                 return ichunkaccess1;
-@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
-         if (flag && !currentlyUnloading) {
-             // CraftBukkit end
-             this.distanceManager.addTicket(TicketType.UNKNOWN, chunkcoordintpair, l, chunkcoordintpair);
-+            if (isUrgent) this.distanceManager.markUrgent(chunkcoordintpair); // Paper - Chunk priority
-             if (this.chunkAbsent(playerchunk, l)) {
-                 ProfilerFiller gameprofilerfiller = this.level.getProfiler();
- 
-                 gameprofilerfiller.push("chunkLoad");
-+                distanceManager.delayDistanceManagerTick = false; // Paper - Chunk priority - ensure this is never false
-                 this.runDistanceManagerUpdates();
-                 playerchunk = this.getVisibleChunkIfPresent(k);
-                 gameprofilerfiller.pop();
-@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
-                 }
-             }
-         }
--
--        return this.chunkAbsent(playerchunk, l) ? ChunkHolder.UNLOADED_CHUNK_FUTURE : playerchunk.getOrScheduleFuture(chunkstatus, this.chunkMap);
-+        // Paper start - Chunk priority
-+        CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> future = this.chunkAbsent(playerchunk, l) ? ChunkHolder.UNLOADED_CHUNK_FUTURE : playerchunk.getOrScheduleFuture(chunkstatus, this.chunkMap);
-+        if (isUrgent) {
-+            future.thenAccept(either -> this.distanceManager.clearUrgent(chunkcoordintpair));
-+        }
-+        return future;
-+        // Paper end
-     }
- 
-     private boolean chunkAbsent(@Nullable ChunkHolder holder, int maxLevel) {
-@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource {
-     }
- 
-     public boolean runDistanceManagerUpdates() {
-+        if (distanceManager.delayDistanceManagerTick) return false; // Paper - Chunk priority
-         boolean flag = this.distanceManager.runAllUpdates(this.chunkMap);
-         boolean flag1 = this.chunkMap.promoteChunkMap();
- 
-diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
-+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
-@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
-     private int lastRecordedArmor = Integer.MIN_VALUE;
-     private int lastRecordedLevel = Integer.MIN_VALUE;
-     private int lastRecordedExperience = Integer.MIN_VALUE;
-+    // Paper start - Chunk priority
-+    public long lastHighPriorityChecked;
-+    public void forceCheckHighPriority() {
-+        lastHighPriorityChecked = -1;
-+        getLevel().getChunkSource().chunkMap.checkHighPriorityChunks(this);
-+    }
-+    public boolean isRealPlayer;
-+    // Paper end
-     private float lastSentHealth = -1.0E8F;
-     private int lastSentFood = -99999999;
-     private boolean lastFoodSaturationZero = true;
-@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
-         this.maxHealthCache = this.getMaxHealth();
-         this.cachedSingleMobDistanceMap = new com.destroystokyo.paper.util.PooledHashSets.PooledObjectLinkedOpenHashSet<>(this); // Paper
-     }
-+    // Paper start - Chunk priority
-+    public BlockPos getPointInFront(double inFront) {
-+        double rads = Math.toRadians(net.minecraft.server.MCUtil.normalizeYaw(this.yRot + 90)); // MC rotates yaw 90 for some odd reason
-+        final double x = getX() + inFront * Math.cos(rads);
-+        final double z = getZ() + inFront * Math.sin(rads);
-+        return new BlockPos(x, getY(), z);
-+    }
-+
-+    public ChunkPos getChunkInFront(double inFront) {
-+        double rads = Math.toRadians(net.minecraft.server.MCUtil.normalizeYaw(this.yRot + 90)); // MC rotates yaw 90 for some odd reason
-+        final double x = getX() + (inFront * 16) * Math.cos(rads);
-+        final double z = getZ() + (inFront * 16) * Math.sin(rads);
-+        return new ChunkPos(Mth.floor(x) >> 4, Mth.floor(z) >> 4);
-+    }
-+    // Paper end
- 
-     // Yes, this doesn't match Vanilla, but it's the best we can do for now.
-     // If this is an issue, PRs are welcome
-@@ -0,0 +0,0 @@ public class ServerPlayer extends Player {
-             if (valid && !this.isSpectator() || !this.touchingUnloadedChunk()) { // Paper - don't tick dead players that are not in the world currently (pending respawn)
-                 super.tick();
-             }
-+            if (valid && isAlive() && connection != null) ((ServerLevel)level).getChunkSource().chunkMap.checkHighPriorityChunks(this); // Paper - Chunk priority
- 
-             for (int i = 0; i < this.getInventory().getContainerSize(); ++i) {
-                 ItemStack itemstack = this.getInventory().getItem(i);
-diff --git a/src/main/java/net/minecraft/server/level/Ticket.java b/src/main/java/net/minecraft/server/level/Ticket.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/level/Ticket.java
-+++ b/src/main/java/net/minecraft/server/level/Ticket.java
-@@ -0,0 +0,0 @@ public final class Ticket<T> implements Comparable<Ticket<?>> {
-     public final T key;
-     public long createdTick;
-     public long delayUnloadBy; // Paper
-+    public int priority; // Paper - Chunk priority
- 
-     protected Ticket(TicketType<T> type, int level, T argument) {
-         this.type = type;
-diff --git a/src/main/java/net/minecraft/server/level/TicketType.java b/src/main/java/net/minecraft/server/level/TicketType.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/level/TicketType.java
-+++ b/src/main/java/net/minecraft/server/level/TicketType.java
-@@ -0,0 +0,0 @@ import net.minecraft.world.level.ChunkPos;
- public class TicketType<T> {
-     public static final TicketType<Long> FUTURE_AWAIT = create("future_await", Long::compareTo); // Paper
-     public static final TicketType<Long> ASYNC_LOAD = create("async_load", Long::compareTo); // Paper
-+    public static final TicketType<ChunkPos> PRIORITY = create("priority", Comparator.comparingLong(ChunkPos::toLong), 300); // Paper
-+    public static final TicketType<ChunkPos> URGENT = create("urgent", Comparator.comparingLong(ChunkPos::toLong), 300); // Paper
- 
-     private final String name;
-     private final Comparator<T> comparator;
-diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
-@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
- 
-         this.awaitingTeleportTime = this.tickCount;
-         this.player.absMoveTo(d0, d1, d2, f, f1);
-+        this.player.forceCheckHighPriority(); // Paper
-         this.player.connection.send(new ClientboundPlayerPositionPacket(d0 - d3, d1 - d4, d2 - d5, f - f2, f1 - f3, set, this.awaitingTeleport, flag));
-     }
- 
-diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/server/players/PlayerList.java
-+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
-@@ -0,0 +0,0 @@ public abstract class PlayerList {
-         net.minecraft.server.level.ChunkMap playerChunkMap = worldserver1.getChunkSource().chunkMap;
-         net.minecraft.server.level.DistanceManager distanceManager = playerChunkMap.distanceManager;
-         distanceManager.addTicketAtLevel(net.minecraft.server.level.TicketType.LOGIN, pos, 31, pos.toLong());
--        worldserver1.getChunkSource().runDistanceManagerUpdates();
--        worldserver1.getChunkSource().getChunkAtAsynchronously(chunkX, chunkZ, true, true).thenApply(chunk -> {
-+        worldserver1.getChunkSource().markAreaHighPriority(pos, 28, 3); // Paper - Chunk priority
-+        worldserver1.getChunkSource().getChunkAtAsynchronously(chunkX, chunkZ, true, false).thenApply(chunk -> { // Paper - Chunk priority
-             net.minecraft.server.level.ChunkHolder updatingChunk = playerChunkMap.getUpdatingChunkIfPresent(pos.toLong());
-             if (updatingChunk != null) {
-                 return updatingChunk.getEntityTickingChunkFuture();
-@@ -0,0 +0,0 @@ public abstract class PlayerList {
-         SocketAddress socketaddress = loginlistener.connection.getRemoteAddress();
- 
-         ServerPlayer entity = new ServerPlayer(this.server, this.server.getLevel(Level.OVERWORLD), gameprofile);
-+        entity.isRealPlayer = true; // Paper - Chunk priority
-         Player player = entity.getBukkitEntity();
-         PlayerLoginEvent event = new PlayerLoginEvent(player, hostname, ((java.net.InetSocketAddress) socketaddress).getAddress(), ((java.net.InetSocketAddress) loginlistener.connection.getRawAddress()).getAddress());
- 
-@@ -0,0 +0,0 @@ public abstract class PlayerList {
-         // 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
-+        entityplayer1.forceCheckHighPriority(); // Player - Chunk priority
-         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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/net/minecraft/world/entity/Entity.java
-+++ b/src/main/java/net/minecraft/world/entity/Entity.java
-@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
-     private Vec3 position;
-     private BlockPos blockPosition;
-     private Vec3 deltaMovement;
--    private float yRot;
-+    public float yRot; // Paper - private->public
-     private float xRot;
-     public float yRotO;
-     public float xRotO;
-diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
-+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
-@@ -0,0 +0,0 @@ public class CraftWorld implements World {
-             return future;
-         }
- 
-+        // Paper start - Chunk priority
-+        if (!urgent) {
-+            // If not urgent, at least use a slightly boosted priority
-+            world.getChunkSource().markHighPriority(new ChunkPos(x, z), 1);
-+        }
-+        // Paper end
-         return this.world.getChunkSource().getChunkAtAsynchronously(x, z, gen, urgent).thenComposeAsync((either) -> {
-             net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk) either.left().orElse(null);
-             if (chunk != null) addTicket(x, z); // Paper
-diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
-index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
-+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
-@@ -0,0 +0,0 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
-         throw new UnsupportedOperationException("Cannot set rotation of players. Consider teleporting instead.");
-     }
- 
-+    // Paper start - Chunk priority
-+    @Override
-+    public java.util.concurrent.CompletableFuture<Boolean> teleportAsync(Location loc, @javax.annotation.Nonnull PlayerTeleportEvent.TeleportCause cause) {
-+        ((CraftWorld)loc.getWorld()).getHandle().getChunkSource().markAreaHighPriority(
-+            new net.minecraft.world.level.ChunkPos(net.minecraft.util.Mth.floor(loc.getX()) >> 4,
-+            net.minecraft.util.Mth.floor(loc.getZ()) >> 4), 28, 3); // Load area high priority
-+        return super.teleportAsync(loc, cause);
-+    }
-+    // Paper end
-+
-     @Override
-     public boolean teleport(Location location, PlayerTeleportEvent.TeleportCause cause) {
-         Preconditions.checkArgument(location != null, "location");
diff --git a/patches/server/Improve-Chunk-Status-Transition-Speed.patch b/patches/server/Improve-Chunk-Status-Transition-Speed.patch
index 8606e368f0..d6aab78c2f 100644
--- a/patches/server/Improve-Chunk-Status-Transition-Speed.patch
+++ b/patches/server/Improve-Chunk-Status-Transition-Speed.patch
@@ -49,6 +49,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        ChunkAccess chunk = getAvailableChunkNow();
 +        return chunk != null && (status == null || chunk.getStatus().isOrAfter(getNextStatus(status)));
 +    }
++    // Yanked from chunk priotisation patch - remove?
++    public static ChunkStatus getNextStatus(ChunkStatus status) {
++        if (status == ChunkStatus.FULL) {
++            return status;
++        }
++        return CHUNK_STATUSES.get(status.getIndex() + 1);
++    }
 +    // Paper end
  
      public ChunkHolder(ChunkPos pos, int level, LevelHeightAccessor world, LevelLightEngine lightingProvider, ChunkHolder.LevelChangeListener levelUpdateListener, ChunkHolder.PlayerProvider playersWatchingChunkProvider) {
diff --git a/patches/server/Optimize-Light-Engine.patch b/patches/server/Optimize-Light-Engine.patch
index e4a07f018e..7bd65d800e 100644
--- a/patches/server/Optimize-Light-Engine.patch
+++ b/patches/server/Optimize-Light-Engine.patch
@@ -29,13 +29,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 --- a/src/main/java/net/minecraft/server/level/ChunkHolder.java
 +++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java
 @@ -0,0 +0,0 @@ public class ChunkHolder {
-                 ioPriority = com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGH_PRIORITY;
-             }
-             chunkMap.level.asyncChunkTaskManager.raisePriority(pos.x, pos.z, ioPriority);
-+            chunkMap.level.getChunkSource().getLightEngine().queue.changePriority(pos.toLong(), this.queueLevel, priority); // Paper
-         }
-         if (this.queueLevel != priority) {
-             this.onLevelChange.onLevelChange(this.pos, () -> this.queueLevel, priority, p -> this.queueLevel = p); // use preferred priority
+ 
+         this.onLevelChange.onLevelChange(this.pos, this::getQueueLevel, this.ticketLevel, this::setQueueLevel);
+         this.oldTicketLevel = this.ticketLevel;
++        //chunkMap.level.getChunkSource().getLightEngine().queue.changePriority(pos.toLong(), this.queueLevel, priority); // Paper // Restore this in chunk priority later?
+         // CraftBukkit start
+         // ChunkLoadEvent: Called after the chunk is loaded: isChunkLoaded returns true and chunk is ready to be modified by plugins.
+         if (!playerchunk_state.isOrAfter(ChunkHolder.FullChunkStatus.BORDER) && playerchunk_state1.isOrAfter(ChunkHolder.FullChunkStatus.BORDER)) {
 diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java