--- a/net/minecraft/server/level/ChunkMap.java
+++ b/net/minecraft/server/level/ChunkMap.java
@@ -1,11 +1,13 @@
 package net.minecraft.server.level;
 
+import co.aikar.timings.Timing; // Paper
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
 import com.google.common.collect.Iterables;
+import com.google.common.collect.ComparisonChain; // Paper
 import com.google.common.collect.Lists;
 import com.google.common.collect.Queues;
 import com.google.common.collect.Sets;
-import com.google.common.collect.ImmutableList.Builder;
 import com.mojang.datafixers.DataFixer;
 import com.mojang.logging.LogUtils;
 import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
@@ -15,16 +17,18 @@
 import it.unimi.dsi.fastutil.longs.Long2LongMap;
 import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap;
 import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
+import it.unimi.dsi.fastutil.longs.Long2ObjectMap.Entry;
 import it.unimi.dsi.fastutil.longs.LongIterator;
 import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
 import it.unimi.dsi.fastutil.longs.LongSet;
-import it.unimi.dsi.fastutil.longs.Long2ObjectMap.Entry;
+import it.unimi.dsi.fastutil.objects.ObjectBidirectionalIterator;
 import it.unimi.dsi.fastutil.objects.ObjectIterator;
 import java.io.IOException;
 import java.io.Writer;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -47,6 +51,7 @@
 import net.minecraft.CrashReportCategory;
 import net.minecraft.ReportedException;
 import net.minecraft.Util;
+import net.minecraft.core.HolderGetter;
 import net.minecraft.core.RegistryAccess;
 import net.minecraft.core.SectionPos;
 import net.minecraft.core.registries.Registries;
@@ -86,9 +91,11 @@
 import net.minecraft.world.level.chunk.storage.ChunkStorage;
 import net.minecraft.world.level.chunk.storage.RegionStorageInfo;
 import net.minecraft.world.level.entity.ChunkStatusUpdateListener;
+import net.minecraft.world.level.entity.EntityAccess;
 import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
 import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
 import net.minecraft.world.level.levelgen.RandomState;
+import net.minecraft.world.level.levelgen.blending.BlendingData;
 import net.minecraft.world.level.levelgen.structure.StructureStart;
 import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
 import net.minecraft.world.level.storage.DimensionDataStorage;
@@ -97,11 +104,14 @@
 import org.apache.commons.lang3.mutable.MutableBoolean;
 import org.slf4j.Logger;
 
+// CraftBukkit start
+import org.bukkit.craftbukkit.generator.CustomChunkGenerator;
+// CraftBukkit end
+
 public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider, GeneratingChunkMap {
+
     private static final ChunkResult<List<ChunkAccess>> UNLOADED_CHUNK_LIST_RESULT = ChunkResult.error("Unloaded chunks found in range");
-    private static final CompletableFuture<ChunkResult<List<ChunkAccess>>> UNLOADED_CHUNK_LIST_FUTURE = CompletableFuture.completedFuture(
-        UNLOADED_CHUNK_LIST_RESULT
-    );
+    private static final CompletableFuture<ChunkResult<List<ChunkAccess>>> UNLOADED_CHUNK_LIST_FUTURE = CompletableFuture.completedFuture(ChunkMap.UNLOADED_CHUNK_LIST_RESULT);
     private static final byte CHUNK_TYPE_REPLACEABLE = -1;
     private static final byte CHUNK_TYPE_UNKNOWN = 0;
     private static final byte CHUNK_TYPE_FULL = 1;
@@ -112,10 +122,7 @@
     public static final int MIN_VIEW_DISTANCE = 2;
     public static final int MAX_VIEW_DISTANCE = 32;
     public static final int FORCED_TICKET_LEVEL = ChunkLevel.byStatus(FullChunkStatus.ENTITY_TICKING);
-    public final Long2ObjectLinkedOpenHashMap<ChunkHolder> updatingChunkMap = new Long2ObjectLinkedOpenHashMap<>();
-    public volatile Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunkMap = this.updatingChunkMap.clone();
-    private final Long2ObjectLinkedOpenHashMap<ChunkHolder> pendingUnloads = new Long2ObjectLinkedOpenHashMap<>();
-    private final List<ChunkGenerationTask> pendingGenerationTasks = new ArrayList<>();
+    // Paper - rewrite chunk system
     public final ServerLevel level;
     private final ThreadedLevelLightEngine lightEngine;
     private final BlockableEventLoop<Runnable> mainThreadExecutor;
@@ -123,84 +130,199 @@
     private final ChunkGeneratorStructureState chunkGeneratorState;
     private final Supplier<DimensionDataStorage> overworldDataStorage;
     private final PoiManager poiManager;
-    public final LongSet toDrop = new LongOpenHashSet();
+    public final LongSet toDrop;
     private boolean modified;
-    private final ChunkTaskPriorityQueueSorter queueSorter;
-    private final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> worldgenMailbox;
-    private final ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> mainThreadMailbox;
+    // Paper - rewrite chunk system
     public final ChunkProgressListener progressListener;
     private final ChunkStatusUpdateListener chunkStatusListener;
-    public final ChunkMap.DistanceManager distanceManager;
-    private final AtomicInteger tickingGenerated = new AtomicInteger();
+    public final ChunkMap.ChunkDistanceManager distanceManager;
+    public final AtomicInteger tickingGenerated; // Paper - public
     private final String storageName;
-    private final PlayerMap playerMap = new PlayerMap();
-    public final Int2ObjectMap<ChunkMap.TrackedEntity> entityMap = new Int2ObjectOpenHashMap<>();
-    private final Long2ByteMap chunkTypeCache = new Long2ByteOpenHashMap();
-    private final Long2LongMap chunkSaveCooldowns = new Long2LongOpenHashMap();
-    private final Queue<Runnable> unloadQueue = Queues.newConcurrentLinkedQueue();
+    private final PlayerMap playerMap;
+    public final Int2ObjectMap<ChunkMap.TrackedEntity> entityMap;
+    private final Long2ByteMap chunkTypeCache;
+    private final Long2LongMap chunkSaveCooldowns;
+    // Paper - rewrite chunk system
     public int serverViewDistance;
-    private final WorldGenContext worldGenContext;
+    public final WorldGenContext worldGenContext; // Paper - public
 
-    public ChunkMap(
-        ServerLevel world,
-        LevelStorageSource.LevelStorageAccess session,
-        DataFixer dataFixer,
-        StructureTemplateManager structureTemplateManager,
-        Executor executor,
-        BlockableEventLoop<Runnable> mainThreadExecutor,
-        LightChunkGetter chunkProvider,
-        ChunkGenerator chunkGenerator,
-        ChunkProgressListener worldGenerationProgressListener,
-        ChunkStatusUpdateListener chunkStatusChangeListener,
-        Supplier<DimensionDataStorage> persistentStateManagerFactory,
-        int viewDistance,
-        boolean dsync
-    ) {
-        super(
-            new RegionStorageInfo(session.getLevelId(), world.dimension(), "chunk"),
-            session.getDimensionPath(world.dimension()).resolve("region"),
-            dataFixer,
-            dsync
-        );
+    // CraftBukkit start - recursion-safe executor for Chunk loadCallback() and unloadCallback()
+    public final CallbackExecutor callbackExecutor = new CallbackExecutor();
+    public static final class CallbackExecutor implements java.util.concurrent.Executor, Runnable {
+
+        private final java.util.Queue<Runnable> queue = new java.util.ArrayDeque<>();
+
+        @Override
+        public void execute(Runnable runnable) {
+            this.queue.add(runnable);
+        }
+
+        @Override
+        public void run() {
+            Runnable task;
+            while ((task = this.queue.poll()) != null) {
+                task.run();
+            }
+        }
+    };
+    // CraftBukkit end
+
+    // Paper start - distance maps
+    private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets<ServerPlayer> pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>();
+
+    void addPlayerToDistanceMaps(ServerPlayer player) {
+        int chunkX = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getX());
+        int chunkZ = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getZ());
+        // Note: players need to be explicitly added to distance maps before they can be updated
+        this.nearbyPlayers.addPlayer(player);
+    }
+
+    void removePlayerFromDistanceMaps(ServerPlayer player) {
+        int chunkX = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getX());
+        int chunkZ = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getZ());
+        // Note: players need to be explicitly added to distance maps before they can be updated
+        this.nearbyPlayers.removePlayer(player);
+    }
+
+    void updateMaps(ServerPlayer player) {
+        int chunkX = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getX());
+        int chunkZ = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getZ());
+        // Note: players need to be explicitly added to distance maps before they can be updated
+        this.nearbyPlayers.tickPlayer(player);
+    }
+    // Paper end
+    // Paper start
+    public final List<io.papermc.paper.chunk.SingleThreadChunkRegionManager> regionManagers = new java.util.ArrayList<>();
+    public final io.papermc.paper.chunk.SingleThreadChunkRegionManager dataRegionManager;
+
+    public static final class DataRegionData implements io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionData {
+    }
+
+    public static final class DataRegionSectionData implements io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionSectionData {
+
+        @Override
+        public void removeFromRegion(final io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionSection section,
+                                     final io.papermc.paper.chunk.SingleThreadChunkRegionManager.Region from) {
+            final DataRegionSectionData sectionData = (DataRegionSectionData)section.sectionData;
+            final DataRegionData fromData = (DataRegionData)from.regionData;
+        }
+
+        @Override
+        public void addToRegion(final io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionSection section,
+                                final io.papermc.paper.chunk.SingleThreadChunkRegionManager.Region oldRegion,
+                                final io.papermc.paper.chunk.SingleThreadChunkRegionManager.Region newRegion) {
+            final DataRegionSectionData sectionData = (DataRegionSectionData)section.sectionData;
+            final DataRegionData oldRegionData = oldRegion == null ? null : (DataRegionData)oldRegion.regionData;
+            final DataRegionData newRegionData = (DataRegionData)newRegion.regionData;
+        }
+    }
+
+    public final ChunkHolder getUnloadingChunkHolder(int chunkX, int chunkZ) {
+        return null; // Paper - rewrite chunk system
+    }
+    public final io.papermc.paper.util.player.NearbyPlayers nearbyPlayers;
+    // Paper end
+
+    public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor executor, BlockableEventLoop<Runnable> mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory, int viewDistance, boolean dsync) {
+        super(new RegionStorageInfo(session.getLevelId(), world.dimension(), "chunk"), session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync);
+        // Paper - rewrite chunk system
+        this.toDrop = new LongOpenHashSet();
+        this.tickingGenerated = new AtomicInteger();
+        this.playerMap = new PlayerMap();
+        this.entityMap = new Int2ObjectOpenHashMap();
+        this.chunkTypeCache = new Long2ByteOpenHashMap();
+        this.chunkSaveCooldowns = new Long2LongOpenHashMap();
+        // Paper - rewrite chunk system
         Path path = session.getDimensionPath(world.dimension());
+
         this.storageName = path.getFileName().toString();
         this.level = world;
-        RegistryAccess registryAccess = world.registryAccess();
-        long l = world.getSeed();
-        if (chunkGenerator instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) {
-            this.randomState = RandomState.create(noiseBasedChunkGenerator.generatorSettings().value(), registryAccess.lookupOrThrow(Registries.NOISE), l);
+        RegistryAccess iregistrycustom = world.registryAccess();
+        long j = world.getSeed();
+
+        // CraftBukkit start - SPIGOT-7051: It's a rigged game! Use delegate for random state creation, otherwise it is not so random.
+        ChunkGenerator randomGenerator = chunkGenerator;
+        if (randomGenerator instanceof CustomChunkGenerator customChunkGenerator) {
+            randomGenerator = customChunkGenerator.getDelegate();
+        }
+        if (randomGenerator instanceof NoiseBasedChunkGenerator chunkgeneratorabstract) {
+            // CraftBukkit end
+            this.randomState = RandomState.create((NoiseGeneratorSettings) chunkgeneratorabstract.generatorSettings().value(), (HolderGetter) iregistrycustom.lookupOrThrow(Registries.NOISE), j);
         } else {
-            this.randomState = RandomState.create(NoiseGeneratorSettings.dummy(), registryAccess.lookupOrThrow(Registries.NOISE), l);
+            this.randomState = RandomState.create(NoiseGeneratorSettings.dummy(), (HolderGetter) iregistrycustom.lookupOrThrow(Registries.NOISE), j);
         }
 
-        this.chunkGeneratorState = chunkGenerator.createState(registryAccess.lookupOrThrow(Registries.STRUCTURE_SET), this.randomState, l);
+        this.chunkGeneratorState = chunkGenerator.createState(iregistrycustom.lookupOrThrow(Registries.STRUCTURE_SET), this.randomState, j, world.spigotConfig); // Spigot
         this.mainThreadExecutor = mainThreadExecutor;
-        ProcessorMailbox<Runnable> processorMailbox = ProcessorMailbox.create(executor, "worldgen");
-        ProcessorHandle<Runnable> processorHandle = ProcessorHandle.of("main", mainThreadExecutor::tell);
+        ProcessorMailbox<Runnable> threadedmailbox = ProcessorMailbox.create(executor, "worldgen");
+
+        Objects.requireNonNull(mainThreadExecutor);
+        ProcessorHandle<Runnable> mailbox = ProcessorHandle.of("main", mainThreadExecutor::tell);
+
         this.progressListener = worldGenerationProgressListener;
         this.chunkStatusListener = chunkStatusChangeListener;
-        ProcessorMailbox<Runnable> processorMailbox2 = ProcessorMailbox.create(executor, "light");
-        this.queueSorter = new ChunkTaskPriorityQueueSorter(ImmutableList.of(processorMailbox, processorHandle, processorMailbox2), executor, Integer.MAX_VALUE);
-        this.worldgenMailbox = this.queueSorter.getProcessor(processorMailbox, false);
-        this.mainThreadMailbox = this.queueSorter.getProcessor(processorHandle, false);
-        this.lightEngine = new ThreadedLevelLightEngine(
-            chunkProvider, this, this.level.dimensionType().hasSkyLight(), processorMailbox2, this.queueSorter.getProcessor(processorMailbox2, false)
-        );
-        this.distanceManager = new ChunkMap.DistanceManager(executor, mainThreadExecutor);
+        ProcessorMailbox<Runnable> threadedmailbox1 = ProcessorMailbox.create(executor, "light");
+
+        // Paper - rewrite chunk system
+        this.lightEngine = new ThreadedLevelLightEngine(chunkProvider, this, this.level.dimensionType().hasSkyLight(), threadedmailbox1, null); // Paper - rewrite chunk system
+        this.distanceManager = new ChunkMap.ChunkDistanceManager(executor, mainThreadExecutor);
         this.overworldDataStorage = persistentStateManagerFactory;
-        this.poiManager = new PoiManager(
-            new RegionStorageInfo(session.getLevelId(), world.dimension(), "poi"),
-            path.resolve("poi"),
-            dataFixer,
-            dsync,
-            registryAccess,
-            world.getServer(),
-            world
-        );
+        this.poiManager = new PoiManager(new RegionStorageInfo(session.getLevelId(), world.dimension(), "poi"), path.resolve("poi"), dataFixer, dsync, iregistrycustom, world.getServer(), world);
         this.setServerViewDistance(viewDistance);
-        this.worldGenContext = new WorldGenContext(world, chunkGenerator, structureTemplateManager, this.lightEngine, this.mainThreadMailbox);
+        this.worldGenContext = new WorldGenContext(world, chunkGenerator, structureTemplateManager, this.lightEngine, null); // Paper - rewrite chunk system
+        // Paper start
+        this.dataRegionManager = new io.papermc.paper.chunk.SingleThreadChunkRegionManager(this.level, 2, (1.0 / 3.0), 1, 6, "Data", DataRegionData::new, DataRegionSectionData::new);
+        this.regionManagers.add(this.dataRegionManager);
+        this.nearbyPlayers = new io.papermc.paper.util.player.NearbyPlayers(this.level);
+        // Paper end
+    }
+
+    // Paper start
+    // always use accessor, so folia can override
+    public final io.papermc.paper.util.player.NearbyPlayers getNearbyPlayers() {
+        return this.nearbyPlayers;
     }
 
+    // Paper start - Optional per player mob spawns
+    public void updatePlayerMobTypeMap(final Entity entity) {
+        if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) {
+            return;
+        }
+        final int index = entity.getType().getCategory().ordinal();
+
+        final com.destroystokyo.paper.util.maplist.ReferenceList<ServerPlayer> inRange =
+            this.getNearbyPlayers().getPlayers(entity.chunkPosition(), io.papermc.paper.util.player.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE);
+        if (inRange == null) {
+            return;
+        }
+        final Object[] backingSet = inRange.getRawData();
+        for (int i = 0, len = inRange.size(); i < len; i++) {
+            ++((ServerPlayer)backingSet[i]).mobCounts[index];
+        }
+    }
+    // Paper start - per player mob count backoff
+    public void updateFailurePlayerMobTypeMap(int chunkX, int chunkZ, net.minecraft.world.entity.MobCategory mobCategory) {
+        if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) {
+            return;
+        }
+        int idx = mobCategory.ordinal();
+        final com.destroystokyo.paper.util.maplist.ReferenceList<ServerPlayer> inRange =
+            this.getNearbyPlayers().getPlayersByChunk(chunkX, chunkZ, io.papermc.paper.util.player.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE);
+        if (inRange == null) {
+            return;
+        }
+        final Object[] backingSet = inRange.getRawData();
+        for (int i = 0, len = inRange.size(); i < len; i++) {
+            ++((ServerPlayer)backingSet[i]).mobBackoffCounts[idx];
+        }
+    }
+    // Paper end - per player mob count backoff
+    public int getMobCountNear(final ServerPlayer player, final net.minecraft.world.entity.MobCategory mobCategory) {
+        return player.mobCounts[mobCategory.ordinal()] + player.mobBackoffCounts[mobCategory.ordinal()]; // Paper - per player mob count backoff
+        // Paper end - Optional per player mob spawns
+    }
+    // Paper end
+
     protected ChunkGenerator generator() {
         return this.worldGenContext.generator();
     }
@@ -214,31 +336,20 @@
     }
 
     private static double euclideanDistanceSquared(ChunkPos pos, Entity entity) {
-        double d = (double)SectionPos.sectionToBlockCoord(pos.x, 8);
-        double e = (double)SectionPos.sectionToBlockCoord(pos.z, 8);
-        double f = d - entity.getX();
-        double g = e - entity.getZ();
-        return f * f + g * g;
+        double d0 = (double) SectionPos.sectionToBlockCoord(pos.x, 8);
+        double d1 = (double) SectionPos.sectionToBlockCoord(pos.z, 8);
+        double d2 = d0 - entity.getX();
+        double d3 = d1 - entity.getZ();
+
+        return d2 * d2 + d3 * d3;
     }
 
     boolean isChunkTracked(ServerPlayer player, int chunkX, int chunkZ) {
-        return player.getChunkTrackingView().contains(chunkX, chunkZ) && !player.connection.chunkSender.isPending(ChunkPos.asLong(chunkX, chunkZ));
+        return ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getPlayerChunkLoader().isChunkSent(player, chunkX, chunkZ); // Paper - rewrite chunk system
     }
 
     private boolean isChunkOnTrackedBorder(ServerPlayer player, int chunkX, int chunkZ) {
-        if (!this.isChunkTracked(player, chunkX, chunkZ)) {
-            return false;
-        } else {
-            for (int i = -1; i <= 1; i++) {
-                for (int j = -1; j <= 1; j++) {
-                    if ((i != 0 || j != 0) && !this.isChunkTracked(player, chunkX + i, chunkZ + j)) {
-                        return true;
-                    }
-                }
-            }
-
-            return false;
-        }
+        return ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getPlayerChunkLoader().isChunkSent(player, chunkX, chunkZ, true); // Paper - rewrite chunk system
     }
 
     protected ThreadedLevelLightEngine getLightEngine() {
@@ -247,315 +358,132 @@
 
     @Nullable
     protected ChunkHolder getUpdatingChunkIfPresent(long pos) {
-        return this.updatingChunkMap.get(pos);
+        // Paper start - rewrite chunk system
+        final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder holder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(pos);
+        return holder == null ? null : holder.vanillaChunkHolder;
+        // Paper end - rewrite chunk system
     }
 
     @Nullable
     public ChunkHolder getVisibleChunkIfPresent(long pos) {
-        return this.visibleChunkMap.get(pos);
+        // Paper start - rewrite chunk system
+        final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder holder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(pos);
+        return holder == null ? null : holder.vanillaChunkHolder;
+        // Paper end - rewrite chunk system
     }
 
     protected IntSupplier getChunkQueueLevel(long pos) {
-        return () -> {
-            ChunkHolder chunkHolder = this.getVisibleChunkIfPresent(pos);
-            return chunkHolder == null
-                ? ChunkTaskPriorityQueue.PRIORITY_LEVEL_COUNT - 1
-                : Math.min(chunkHolder.getQueueLevel(), ChunkTaskPriorityQueue.PRIORITY_LEVEL_COUNT - 1);
-        };
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     public String getChunkDebugData(ChunkPos chunkPos) {
-        ChunkHolder chunkHolder = this.getVisibleChunkIfPresent(chunkPos.toLong());
-        if (chunkHolder == null) {
+        ChunkHolder playerchunk = this.getVisibleChunkIfPresent(chunkPos.toLong());
+
+        if (playerchunk == null) {
             return "null";
         } else {
-            String string = chunkHolder.getTicketLevel() + "\n";
-            ChunkStatus chunkStatus = chunkHolder.getLatestStatus();
-            ChunkAccess chunkAccess = chunkHolder.getLatestChunk();
-            if (chunkStatus != null) {
-                string = string + "St: §" + chunkStatus.getIndex() + chunkStatus + "§r\n";
+            String s = playerchunk.getTicketLevel() + "\n";
+            ChunkStatus chunkstatus = playerchunk.getLatestStatus();
+            ChunkAccess ichunkaccess = playerchunk.getLatestChunk();
+
+            if (chunkstatus != null) {
+                s = s + "St: \u00a7" + chunkstatus.getIndex() + String.valueOf(chunkstatus) + "\u00a7r\n";
             }
 
-            if (chunkAccess != null) {
-                string = string + "Ch: §" + chunkAccess.getPersistedStatus().getIndex() + chunkAccess.getPersistedStatus() + "§r\n";
+            if (ichunkaccess != null) {
+                s = s + "Ch: \u00a7" + ichunkaccess.getPersistedStatus().getIndex() + String.valueOf(ichunkaccess.getPersistedStatus()) + "\u00a7r\n";
             }
 
-            FullChunkStatus fullChunkStatus = chunkHolder.getFullStatus();
-            string = string + '§' + fullChunkStatus.ordinal() + fullChunkStatus;
-            return string + "§r";
+            FullChunkStatus fullchunkstatus = playerchunk.getFullStatus();
+
+            s = s + String.valueOf('\u00a7') + fullchunkstatus.ordinal() + String.valueOf(fullchunkstatus);
+            return s + "\u00a7r";
         }
     }
 
-    private CompletableFuture<ChunkResult<List<ChunkAccess>>> getChunkRangeFuture(
-        ChunkHolder centerChunk, int margin, IntFunction<ChunkStatus> distanceToStatus
-    ) {
-        if (margin == 0) {
-            ChunkStatus chunkStatus = distanceToStatus.apply(0);
-            return centerChunk.scheduleChunkGenerationTask(chunkStatus, this).thenApply(chunkResult -> chunkResult.map(List::of));
-        } else {
-            List<CompletableFuture<ChunkResult<ChunkAccess>>> list = new ArrayList<>();
-            ChunkPos chunkPos = centerChunk.getPos();
-
-            for (int i = -margin; i <= margin; i++) {
-                for (int j = -margin; j <= margin; j++) {
-                    int k = Math.max(Math.abs(j), Math.abs(i));
-                    long l = ChunkPos.asLong(chunkPos.x + j, chunkPos.z + i);
-                    ChunkHolder chunkHolder = this.getUpdatingChunkIfPresent(l);
-                    if (chunkHolder == null) {
-                        return UNLOADED_CHUNK_LIST_FUTURE;
-                    }
-
-                    ChunkStatus chunkStatus2 = distanceToStatus.apply(k);
-                    list.add(chunkHolder.scheduleChunkGenerationTask(chunkStatus2, this));
-                }
-            }
-
-            return Util.sequence(list).thenApply(listx -> {
-                List<ChunkAccess> list2 = Lists.newArrayList();
-
-                for (ChunkResult<ChunkAccess> chunkResult : listx) {
-                    if (chunkResult == null) {
-                        throw this.debugFuturesAndCreateReportedException(new IllegalStateException("At least one of the chunk futures were null"), "n/a");
-                    }
+    private CompletableFuture<ChunkResult<List<ChunkAccess>>> getChunkRangeFuture(ChunkHolder centerChunk, int margin, IntFunction<ChunkStatus> distanceToStatus) {
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
+    }
 
-                    ChunkAccess chunkAccess = chunkResult.orElse(null);
-                    if (chunkAccess == null) {
-                        return UNLOADED_CHUNK_LIST_RESULT;
-                    }
+    public ReportedException debugFuturesAndCreateReportedException(IllegalStateException exception, String details) {
+        StringBuilder stringbuilder = new StringBuilder();
+        Consumer<ChunkHolder> consumer = (playerchunk) -> {
+            playerchunk.getAllFutures().forEach((pair) -> {
+                ChunkStatus chunkstatus = (ChunkStatus) pair.getFirst();
+                CompletableFuture<ChunkResult<ChunkAccess>> completablefuture = (CompletableFuture) pair.getSecond();
 
-                    list2.add(chunkAccess);
+                if (completablefuture != null && completablefuture.isDone() && completablefuture.join() == null) {
+                    stringbuilder.append(playerchunk.getPos()).append(" - status: ").append(chunkstatus).append(" future: ").append(completablefuture).append(System.lineSeparator());
                 }
 
-                return ChunkResult.of(list2);
             });
-        }
-    }
+        };
 
-    public ReportedException debugFuturesAndCreateReportedException(IllegalStateException exception, String details) {
-        StringBuilder stringBuilder = new StringBuilder();
-        Consumer<ChunkHolder> consumer = chunkHolder -> chunkHolder.getAllFutures()
-                .forEach(
-                    pair -> {
-                        ChunkStatus chunkStatus = pair.getFirst();
-                        CompletableFuture<ChunkResult<ChunkAccess>> completableFuture = pair.getSecond();
-                        if (completableFuture != null && completableFuture.isDone() && completableFuture.join() == null) {
-                            stringBuilder.append(chunkHolder.getPos())
-                                .append(" - status: ")
-                                .append(chunkStatus)
-                                .append(" future: ")
-                                .append(completableFuture)
-                                .append(System.lineSeparator());
-                        }
-                    }
-                );
-        stringBuilder.append("Updating:").append(System.lineSeparator());
-        this.updatingChunkMap.values().forEach(consumer);
-        stringBuilder.append("Visible:").append(System.lineSeparator());
-        this.visibleChunkMap.values().forEach(consumer);
-        CrashReport crashReport = CrashReport.forThrowable(exception, "Chunk loading");
-        CrashReportCategory crashReportCategory = crashReport.addCategory("Chunk loading");
-        crashReportCategory.setDetail("Details", details);
-        crashReportCategory.setDetail("Futures", stringBuilder);
-        return new ReportedException(crashReport);
+        stringbuilder.append("Updating:").append(System.lineSeparator());
+        io.papermc.paper.chunk.system.ChunkSystem.getUpdatingChunkHolders(this.level).forEach(consumer); // Paper
+        stringbuilder.append("Visible:").append(System.lineSeparator());
+        io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).forEach(consumer); // Paper
+        CrashReport crashreport = CrashReport.forThrowable(exception, "Chunk loading");
+        CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Chunk loading");
+
+        crashreportsystemdetails.setDetail("Details", (Object) details);
+        crashreportsystemdetails.setDetail("Futures", (Object) stringbuilder);
+        return new ReportedException(crashreport);
     }
 
     public CompletableFuture<ChunkResult<LevelChunk>> prepareEntityTickingChunk(ChunkHolder holder) {
-        return this.getChunkRangeFuture(holder, 2, distance -> ChunkStatus.FULL)
-            .thenApplyAsync(chunk -> chunk.map(chunks -> (LevelChunk)chunks.get(chunks.size() / 2)), this.mainThreadExecutor);
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     @Nullable
-    ChunkHolder updateChunkScheduling(long pos, int level, @Nullable ChunkHolder holder, int i) {
-        if (!ChunkLevel.isLoaded(i) && !ChunkLevel.isLoaded(level)) {
-            return holder;
-        } else {
-            if (holder != null) {
-                holder.setTicketLevel(level);
-            }
-
-            if (holder != null) {
-                if (!ChunkLevel.isLoaded(level)) {
-                    this.toDrop.add(pos);
-                } else {
-                    this.toDrop.remove(pos);
-                }
-            }
-
-            if (ChunkLevel.isLoaded(level) && holder == null) {
-                holder = this.pendingUnloads.remove(pos);
-                if (holder != null) {
-                    holder.setTicketLevel(level);
-                } else {
-                    holder = new ChunkHolder(new ChunkPos(pos), level, this.level, this.lightEngine, this.queueSorter, this);
-                }
-
-                this.updatingChunkMap.put(pos, holder);
-                this.modified = true;
-            }
-
-            return holder;
-        }
+    ChunkHolder updateChunkScheduling(long pos, int level, @Nullable ChunkHolder holder, int k) {
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     @Override
     public void close() throws IOException {
-        try {
-            this.queueSorter.close();
-            this.poiManager.close();
-        } finally {
-            super.close();
-        }
+        throw new UnsupportedOperationException("Use ServerChunkCache#close"); // Paper - rewrite chunk system
     }
 
     protected void saveAllChunks(boolean flush) {
-        if (flush) {
-            List<ChunkHolder> list = this.visibleChunkMap
-                .values()
-                .stream()
-                .filter(ChunkHolder::wasAccessibleSinceLastSave)
-                .peek(ChunkHolder::refreshAccessibility)
-                .toList();
-            MutableBoolean mutableBoolean = new MutableBoolean();
-
-            do {
-                mutableBoolean.setFalse();
-                list.stream()
-                    .map(holder -> {
-                        this.mainThreadExecutor.managedBlock(holder::isReadyForSaving);
-                        return holder.getLatestChunk();
-                    })
-                    .filter(chunk -> chunk instanceof ImposterProtoChunk || chunk instanceof LevelChunk)
-                    .filter(this::save)
-                    .forEach(chunk -> mutableBoolean.setTrue());
-            } while (mutableBoolean.isTrue());
-
-            this.processUnloads(() -> true);
-            this.flushWorker();
-        } else {
-            this.visibleChunkMap.values().forEach(this::saveChunkIfNeeded);
-        }
+        ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.saveAllChunks(
+            flush, false, false
+        );
     }
 
     protected void tick(BooleanSupplier shouldKeepTicking) {
-        ProfilerFiller profilerFiller = this.level.getProfiler();
-        profilerFiller.push("poi");
+        ProfilerFiller gameprofilerfiller = this.level.getProfiler();
+
+        gameprofilerfiller.push("poi");
         this.poiManager.tick(shouldKeepTicking);
-        profilerFiller.popPush("chunk_unload");
+        gameprofilerfiller.popPush("chunk_unload");
         if (!this.level.noSave()) {
             this.processUnloads(shouldKeepTicking);
         }
 
-        profilerFiller.pop();
+        gameprofilerfiller.pop();
     }
 
     public boolean hasWork() {
-        return this.lightEngine.hasLightWork()
-            || !this.pendingUnloads.isEmpty()
-            || !this.updatingChunkMap.isEmpty()
-            || this.poiManager.hasWork()
-            || !this.toDrop.isEmpty()
-            || !this.unloadQueue.isEmpty()
-            || this.queueSorter.hasWork()
-            || this.distanceManager.hasTickets();
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     private void processUnloads(BooleanSupplier shouldKeepTicking) {
-        LongIterator longIterator = this.toDrop.iterator();
-        int i = 0;
-
-        while (longIterator.hasNext() && (shouldKeepTicking.getAsBoolean() || i < 200 || this.toDrop.size() > 2000)) {
-            long l = longIterator.nextLong();
-            ChunkHolder chunkHolder = this.updatingChunkMap.get(l);
-            if (chunkHolder != null) {
-                if (chunkHolder.getGenerationRefCount() != 0) {
-                    continue;
-                }
-
-                this.updatingChunkMap.remove(l);
-                this.pendingUnloads.put(l, chunkHolder);
-                this.modified = true;
-                i++;
-                this.scheduleUnload(l, chunkHolder);
-            }
-
-            longIterator.remove();
-        }
-
-        int j = Math.max(0, this.unloadQueue.size() - 2000);
-
-        Runnable runnable;
-        while ((shouldKeepTicking.getAsBoolean() || j > 0) && (runnable = this.unloadQueue.poll()) != null) {
-            j--;
-            runnable.run();
-        }
-
-        int k = 0;
-        ObjectIterator<ChunkHolder> objectIterator = this.visibleChunkMap.values().iterator();
+        ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.processUnloads(); // Paper - rewrite chunk system
+        ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.autoSave(); // Paper - rewrite chunk system
 
-        while (k < 20 && shouldKeepTicking.getAsBoolean() && objectIterator.hasNext()) {
-            if (this.saveChunkIfNeeded(objectIterator.next())) {
-                k++;
-            }
-        }
     }
 
     private void scheduleUnload(long pos, ChunkHolder holder) {
-        holder.getSaveSyncFuture().thenRunAsync(() -> {
-            if (!holder.isReadyForSaving()) {
-                this.scheduleUnload(pos, holder);
-            } else {
-                ChunkAccess chunkAccess = holder.getLatestChunk();
-                if (this.pendingUnloads.remove(pos, holder) && chunkAccess != null) {
-                    if (chunkAccess instanceof LevelChunk levelChunk) {
-                        levelChunk.setLoaded(false);
-                    }
-
-                    this.save(chunkAccess);
-                    if (chunkAccess instanceof LevelChunk levelChunk2) {
-                        this.level.unload(levelChunk2);
-                    }
-
-                    this.lightEngine.updateChunkStatus(chunkAccess.getPos());
-                    this.lightEngine.tryScheduleUpdate();
-                    this.progressListener.onStatusChange(chunkAccess.getPos(), null);
-                    this.chunkSaveCooldowns.remove(chunkAccess.getPos().toLong());
-                }
-            }
-        }, this.unloadQueue::add).whenComplete((void_, throwable) -> {
-            if (throwable != null) {
-                LOGGER.error("Failed to save chunk {}", holder.getPos(), throwable);
-            }
-        });
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     protected boolean promoteChunkMap() {
-        if (!this.modified) {
-            return false;
-        } else {
-            this.visibleChunkMap = this.updatingChunkMap.clone();
-            this.modified = false;
-            return true;
-        }
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     private CompletableFuture<ChunkAccess> scheduleChunkLoad(ChunkPos pos) {
-        return this.readChunk(pos).thenApply(nbt -> nbt.filter(nbt2 -> {
-                boolean bl = isChunkDataValid(nbt2);
-                if (!bl) {
-                    LOGGER.error("Chunk file at {} is missing level data, skipping", pos);
-                }
-
-                return bl;
-            })).thenApplyAsync(nbt -> {
-            this.level.getProfiler().incrementCounter("chunkLoad");
-            if (nbt.isPresent()) {
-                ChunkAccess chunkAccess = ChunkSerializer.read(this.level, this.poiManager, this.storageInfo(), pos, nbt.get());
-                this.markPosition(pos, chunkAccess.getPersistedStatus().getChunkType());
-                return chunkAccess;
-            } else {
-                return this.createEmptyChunk(pos);
-            }
-        }, this.mainThreadExecutor).exceptionallyAsync(throwable -> this.handleChunkLoadFailure(throwable, pos), this.mainThreadExecutor);
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     private static boolean isChunkDataValid(CompoundTag nbt) {
@@ -563,143 +491,96 @@
     }
 
     private ChunkAccess handleChunkLoadFailure(Throwable throwable, ChunkPos chunkPos) {
-        Throwable throwable2 = throwable instanceof CompletionException completionException ? completionException.getCause() : throwable;
-        Throwable throwable3 = throwable2 instanceof ReportedException reportedException ? reportedException.getCause() : throwable2;
-        boolean bl = throwable3 instanceof Error;
-        boolean bl2 = throwable3 instanceof IOException || throwable3 instanceof NbtException;
-        if (!bl) {
-            if (!bl2) {
+        Throwable throwable1;
+
+        if (throwable instanceof CompletionException completionexception) {
+            throwable1 = completionexception.getCause();
+        } else {
+            throwable1 = throwable;
+        }
+
+        Throwable throwable2 = throwable1;
+
+        if (throwable2 instanceof ReportedException reportedexception) {
+            throwable1 = reportedexception.getCause();
+        } else {
+            throwable1 = throwable2;
+        }
+
+        Throwable throwable3 = throwable1;
+        boolean flag = throwable3 instanceof Error;
+        boolean flag1 = throwable3 instanceof IOException || throwable3 instanceof NbtException;
+
+        if (!flag) {
+            if (!flag1) {
+                ;
             }
 
             this.level.getServer().reportChunkLoadFailure(throwable3, this.storageInfo(), chunkPos);
             return this.createEmptyChunk(chunkPos);
         } else {
-            CrashReport crashReport = CrashReport.forThrowable(throwable, "Exception loading chunk");
-            CrashReportCategory crashReportCategory = crashReport.addCategory("Chunk being loaded");
-            crashReportCategory.setDetail("pos", chunkPos);
+            CrashReport crashreport = CrashReport.forThrowable(throwable, "Exception loading chunk");
+            CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Chunk being loaded");
+
+            crashreportsystemdetails.setDetail("pos", (Object) chunkPos);
             this.markPositionReplaceable(chunkPos);
-            throw new ReportedException(crashReport);
+            throw new ReportedException(crashreport);
         }
     }
 
     private ChunkAccess createEmptyChunk(ChunkPos chunkPos) {
         this.markPositionReplaceable(chunkPos);
-        return new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.level, this.level.registryAccess().registryOrThrow(Registries.BIOME), null);
+        return new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.level, this.level.registryAccess().registryOrThrow(Registries.BIOME), (BlendingData) null);
     }
 
     private void markPositionReplaceable(ChunkPos pos) {
-        this.chunkTypeCache.put(pos.toLong(), (byte)-1);
+        this.chunkTypeCache.put(pos.toLong(), (byte) -1);
     }
 
     private byte markPosition(ChunkPos pos, ChunkType type) {
-        return this.chunkTypeCache.put(pos.toLong(), (byte)(type == ChunkType.PROTOCHUNK ? -1 : 1));
+        return this.chunkTypeCache.put(pos.toLong(), (byte) (type == ChunkType.PROTOCHUNK ? -1 : 1));
     }
 
     @Override
     public GenerationChunkHolder acquireGeneration(long pos) {
-        ChunkHolder chunkHolder = this.updatingChunkMap.get(pos);
-        chunkHolder.increaseGenerationRefCount();
-        return chunkHolder;
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     @Override
     public void releaseGeneration(GenerationChunkHolder chunkHolder) {
-        chunkHolder.decreaseGenerationRefCount();
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     @Override
     public CompletableFuture<ChunkAccess> applyStep(GenerationChunkHolder chunkHolder, ChunkStep step, StaticCache2D<GenerationChunkHolder> chunks) {
-        ChunkPos chunkPos = chunkHolder.getPos();
-        if (step.targetStatus() == ChunkStatus.EMPTY) {
-            return this.scheduleChunkLoad(chunkPos);
-        } else {
-            try {
-                GenerationChunkHolder generationChunkHolder = chunks.get(chunkPos.x, chunkPos.z);
-                ChunkAccess chunkAccess = generationChunkHolder.getChunkIfPresentUnchecked(step.targetStatus().getParent());
-                if (chunkAccess == null) {
-                    throw new IllegalStateException("Parent chunk missing");
-                } else {
-                    CompletableFuture<ChunkAccess> completableFuture = step.apply(this.worldGenContext, chunks, chunkAccess);
-                    this.progressListener.onStatusChange(chunkPos, step.targetStatus());
-                    return completableFuture;
-                }
-            } catch (Exception var8) {
-                var8.getStackTrace();
-                CrashReport crashReport = CrashReport.forThrowable(var8, "Exception generating new chunk");
-                CrashReportCategory crashReportCategory = crashReport.addCategory("Chunk to be generated");
-                crashReportCategory.setDetail("Status being generated", () -> step.targetStatus().getName());
-                crashReportCategory.setDetail("Location", String.format(Locale.ROOT, "%d,%d", chunkPos.x, chunkPos.z));
-                crashReportCategory.setDetail("Position hash", ChunkPos.asLong(chunkPos.x, chunkPos.z));
-                crashReportCategory.setDetail("Generator", this.generator());
-                this.mainThreadExecutor.execute(() -> {
-                    throw new ReportedException(crashReport);
-                });
-                throw new ReportedException(crashReport);
-            }
-        }
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     @Override
     public ChunkGenerationTask scheduleGenerationTask(ChunkStatus requestedStatus, ChunkPos pos) {
-        ChunkGenerationTask chunkGenerationTask = ChunkGenerationTask.create(this, requestedStatus, pos);
-        this.pendingGenerationTasks.add(chunkGenerationTask);
-        return chunkGenerationTask;
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     private void runGenerationTask(ChunkGenerationTask chunkLoader) {
-        this.worldgenMailbox.tell(ChunkTaskPriorityQueueSorter.message(chunkLoader.getCenter(), () -> {
-            CompletableFuture<?> completableFuture = chunkLoader.runUntilWait();
-            if (completableFuture != null) {
-                completableFuture.thenRun(() -> this.runGenerationTask(chunkLoader));
-            }
-        }));
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     @Override
     public void runGenerationTasks() {
-        this.pendingGenerationTasks.forEach(this::runGenerationTask);
-        this.pendingGenerationTasks.clear();
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     public CompletableFuture<ChunkResult<LevelChunk>> prepareTickingChunk(ChunkHolder holder) {
-        CompletableFuture<ChunkResult<List<ChunkAccess>>> completableFuture = this.getChunkRangeFuture(holder, 1, distance -> ChunkStatus.FULL);
-        CompletableFuture<ChunkResult<LevelChunk>> completableFuture2 = completableFuture.<ChunkResult<LevelChunk>>thenApplyAsync(
-                optionalChunks -> optionalChunks.map(cs -> (LevelChunk)cs.get(cs.size() / 2)),
-                task -> this.mainThreadMailbox.tell(ChunkTaskPriorityQueueSorter.message(holder, task))
-            )
-            .thenApplyAsync(optionalChunk -> optionalChunk.ifSuccess(chunk -> {
-                    chunk.postProcessGeneration();
-                    this.level.startTickingChunk(chunk);
-                    CompletableFuture<?> completableFuturex = holder.getSendSyncFuture();
-                    if (completableFuturex.isDone()) {
-                        this.onChunkReadyToSend(chunk);
-                    } else {
-                        completableFuturex.thenAcceptAsync(v -> this.onChunkReadyToSend(chunk), this.mainThreadExecutor);
-                    }
-                }), this.mainThreadExecutor);
-        completableFuture2.handle((chunk, throwable) -> {
-            this.tickingGenerated.getAndIncrement();
-            return null;
-        });
-        return completableFuture2;
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     private void onChunkReadyToSend(LevelChunk chunk) {
-        ChunkPos chunkPos = chunk.getPos();
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
 
-        for (ServerPlayer serverPlayer : this.playerMap.getAllPlayers()) {
-            if (serverPlayer.getChunkTrackingView().contains(chunkPos)) {
-                markChunkPendingToSend(serverPlayer, chunk);
-            }
-        }
     }
 
     public CompletableFuture<ChunkResult<LevelChunk>> prepareAccessibleChunk(ChunkHolder holder) {
-        return this.getChunkRangeFuture(holder, 1, ChunkLevel::getStatusAroundFullChunk)
-            .thenApplyAsync(
-                optionalChunks -> optionalChunks.map(chunks -> (LevelChunk)chunks.get(chunks.size() / 2)),
-                task -> this.mainThreadMailbox.tell(ChunkTaskPriorityQueueSorter.message(holder, task))
-            );
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     public int getTickingGenerated() {
@@ -707,233 +588,210 @@
     }
 
     private boolean saveChunkIfNeeded(ChunkHolder chunkHolder) {
-        if (chunkHolder.wasAccessibleSinceLastSave() && chunkHolder.isReadyForSaving()) {
-            ChunkAccess chunkAccess = chunkHolder.getLatestChunk();
-            if (!(chunkAccess instanceof ImposterProtoChunk) && !(chunkAccess instanceof LevelChunk)) {
-                return false;
-            } else {
-                long l = chunkAccess.getPos().toLong();
-                long m = this.chunkSaveCooldowns.getOrDefault(l, -1L);
-                long n = System.currentTimeMillis();
-                if (n < m) {
-                    return false;
-                } else {
-                    boolean bl = this.save(chunkAccess);
-                    chunkHolder.refreshAccessibility();
-                    if (bl) {
-                        this.chunkSaveCooldowns.put(l, n + 10000L);
-                    }
-
-                    return bl;
-                }
-            }
-        } else {
-            return false;
-        }
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     public boolean save(ChunkAccess chunk) {
-        this.poiManager.flush(chunk.getPos());
-        if (!chunk.isUnsaved()) {
-            return false;
-        } else {
-            chunk.setUnsaved(false);
-            ChunkPos chunkPos = chunk.getPos();
-
-            try {
-                ChunkStatus chunkStatus = chunk.getPersistedStatus();
-                if (chunkStatus.getChunkType() != ChunkType.LEVELCHUNK) {
-                    if (this.isExistingChunkFull(chunkPos)) {
-                        return false;
-                    }
-
-                    if (chunkStatus == ChunkStatus.EMPTY && chunk.getAllStarts().values().stream().noneMatch(StructureStart::isValid)) {
-                        return false;
-                    }
-                }
-
-                this.level.getProfiler().incrementCounter("chunkSave");
-                CompoundTag compoundTag = ChunkSerializer.write(this.level, chunk);
-                this.write(chunkPos, compoundTag).exceptionally(throwable -> {
-                    this.level.getServer().reportChunkSaveFailure(throwable, this.storageInfo(), chunkPos);
-                    return null;
-                });
-                this.markPosition(chunkPos, chunkStatus.getChunkType());
-                return true;
-            } catch (Exception var5) {
-                this.level.getServer().reportChunkSaveFailure(var5, this.storageInfo(), chunkPos);
-                return false;
-            }
-        }
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     private boolean isExistingChunkFull(ChunkPos pos) {
-        byte b = this.chunkTypeCache.get(pos.toLong());
-        if (b != 0) {
-            return b == 1;
-        } else {
-            CompoundTag compoundTag;
-            try {
-                compoundTag = this.readChunk(pos).join().orElse(null);
-                if (compoundTag == null) {
-                    this.markPositionReplaceable(pos);
-                    return false;
-                }
-            } catch (Exception var5) {
-                LOGGER.error("Failed to read chunk {}", pos, var5);
-                this.markPositionReplaceable(pos);
-                return false;
-            }
-
-            ChunkType chunkType = ChunkSerializer.getChunkTypeFromTag(compoundTag);
-            return this.markPosition(pos, chunkType) == 1;
-        }
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
-    protected void setServerViewDistance(int watchDistance) {
-        int i = Mth.clamp(watchDistance, 2, 32);
-        if (i != this.serverViewDistance) {
-            this.serverViewDistance = i;
-            this.distanceManager.updatePlayerTickets(this.serverViewDistance);
-
-            for (ServerPlayer serverPlayer : this.playerMap.getAllPlayers()) {
-                this.updateChunkTracking(serverPlayer);
-            }
+    public void setServerViewDistance(int watchDistance) { // Paper - public
+        // Paper start - rewrite chunk system
+        final int clamped = Mth.clamp(watchDistance, 2, ca.spottedleaf.moonrise.common.util.MoonriseConstants.MAX_VIEW_DISTANCE);
+        if (clamped == this.serverViewDistance) {
+            return;
         }
+
+        this.serverViewDistance = clamped;
+        ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getPlayerChunkLoader().setLoadDistance(this.serverViewDistance + 1);
+        // Paper end - rewrite chunk system
     }
 
-    int getPlayerViewDistance(ServerPlayer player) {
-        return Mth.clamp(player.requestedViewDistance(), 2, this.serverViewDistance);
+    public int getPlayerViewDistance(ServerPlayer player) { // Paper - public
+        return ca.spottedleaf.moonrise.patches.chunk_system.ChunkSystem.getSendViewDistance(player); // Paper - rewrite chunk system
     }
 
     private void markChunkPendingToSend(ServerPlayer player, ChunkPos pos) {
-        LevelChunk levelChunk = this.getChunkToSend(pos.toLong());
-        if (levelChunk != null) {
-            markChunkPendingToSend(player, levelChunk);
-        }
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
+
     }
 
     private static void markChunkPendingToSend(ServerPlayer player, LevelChunk chunk) {
-        player.connection.chunkSender.markChunkPendingToSend(chunk);
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     private static void dropChunk(ServerPlayer player, ChunkPos pos) {
-        player.connection.chunkSender.dropChunk(player, pos);
+        // Paper - rewrite chunk system
     }
 
+    // Paper start - rewrite chunk system
+    @Override
+    public CompletableFuture<Optional<CompoundTag>> read(final ChunkPos pos) {
+        if (!ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread.isRegionFileThread()) {
+            try {
+                return CompletableFuture.completedFuture(
+                        Optional.ofNullable(
+                            ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread.loadData(
+                                        this.level, pos.x, pos.z, ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread.RegionFileType.CHUNK_DATA,
+                                         ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread.getIOBlockingPriorityForCurrentThread()
+                                )
+                        )
+                );
+            } catch (final Throwable thr) {
+                return CompletableFuture.failedFuture(thr);
+            }
+        }
+        return super.read(pos);
+    }
+
+    @Override
+    public CompletableFuture<Void> write(final ChunkPos pos, final CompoundTag tag) {
+        if (!ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread.isRegionFileThread()) {
+            ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread.scheduleSave(
+                this.level, pos.x, pos.z, tag,
+                ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread.RegionFileType.CHUNK_DATA);
+            return null;
+        }
+        super.write(pos, tag);
+        return null;
+    }
+
+    @Override
+    public void flushWorker() {
+        ca.spottedleaf.moonrise.patches.chunk_system.io.RegionFileIOThread.flush();
+    }
+    // Paper end - rewrite chunk system
+
     @Nullable
     public LevelChunk getChunkToSend(long pos) {
-        ChunkHolder chunkHolder = this.getVisibleChunkIfPresent(pos);
-        return chunkHolder == null ? null : chunkHolder.getChunkToSend();
+        ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos);
+
+        return playerchunk == null ? null : playerchunk.getChunkToSend();
     }
 
     public int size() {
-        return this.visibleChunkMap.size();
+        return io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolderCount(this.level); // Paper
     }
 
-    public net.minecraft.server.level.DistanceManager getDistanceManager() {
+    public DistanceManager getDistanceManager() {
         return this.distanceManager;
     }
 
     protected Iterable<ChunkHolder> getChunks() {
-        return Iterables.unmodifiableIterable(this.visibleChunkMap.values());
+        return Iterables.unmodifiableIterable(io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level)); // Paper
     }
 
     void dumpChunks(Writer writer) throws IOException {
-        CsvOutput csvOutput = 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")
-            .addColumn("ticking_ticket")
-            .addColumn("ticking_level")
-            .addColumn("block_ticks")
-            .addColumn("fluid_ticks")
-            .build(writer);
-        TickingTracker tickingTracker = this.distanceManager.tickingTracker();
+        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").addColumn("ticking_ticket").addColumn("ticking_level").addColumn("block_ticks").addColumn("fluid_ticks").build(writer);
+        TickingTracker tickingtracker = this.distanceManager.tickingTracker();
+        Iterator<ChunkHolder> objectbidirectionaliterator = io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper
 
-        for (Entry<ChunkHolder> entry : this.visibleChunkMap.long2ObjectEntrySet()) {
-            long l = entry.getLongKey();
-            ChunkPos chunkPos = new ChunkPos(l);
-            ChunkHolder chunkHolder = entry.getValue();
-            Optional<ChunkAccess> optional = Optional.ofNullable(chunkHolder.getLatestChunk());
-            Optional<LevelChunk> optional2 = optional.flatMap(chunk -> chunk instanceof LevelChunk ? Optional.of((LevelChunk)chunk) : Optional.empty());
-            csvOutput.writeRow(
-                chunkPos.x,
-                chunkPos.z,
-                chunkHolder.getTicketLevel(),
-                optional.isPresent(),
-                optional.map(ChunkAccess::getPersistedStatus).orElse(null),
-                optional2.map(LevelChunk::getFullStatus).orElse(null),
-                printFuture(chunkHolder.getFullChunkFuture()),
-                printFuture(chunkHolder.getTickingChunkFuture()),
-                printFuture(chunkHolder.getEntityTickingChunkFuture()),
-                this.distanceManager.getTicketDebugString(l),
-                this.anyPlayerCloseEnoughForSpawning(chunkPos),
-                optional2.<Integer>map(chunk -> chunk.getBlockEntities().size()).orElse(0),
-                tickingTracker.getTicketDebugString(l),
-                tickingTracker.getLevel(l),
-                optional2.<Integer>map(chunk -> chunk.getBlockTicks().count()).orElse(0),
-                optional2.<Integer>map(chunk -> chunk.getFluidTicks().count()).orElse(0)
-            );
+        while (objectbidirectionaliterator.hasNext()) {
+            ChunkHolder playerchunk = objectbidirectionaliterator.next(); // Paper
+            long i = playerchunk.pos.toLong(); // Paper
+            ChunkPos chunkcoordintpair = new ChunkPos(i);
+            // Paper - move up
+            Optional<ChunkAccess> optional = Optional.ofNullable(playerchunk.getLatestChunk());
+            Optional<LevelChunk> optional1 = optional.flatMap((ichunkaccess) -> {
+                return ichunkaccess instanceof LevelChunk ? Optional.of((LevelChunk) ichunkaccess) : Optional.empty();
+            });
+
+            // CraftBukkit - decompile error
+            csvwriter.writeRow(chunkcoordintpair.x, chunkcoordintpair.z, playerchunk.getTicketLevel(), optional.isPresent(), optional.map(ChunkAccess::getPersistedStatus).orElse(null), optional1.map(LevelChunk::getFullStatus).orElse(null), ChunkMap.printFuture(playerchunk.getFullChunkFuture()), ChunkMap.printFuture(playerchunk.getTickingChunkFuture()), ChunkMap.printFuture(playerchunk.getEntityTickingChunkFuture()), this.distanceManager.getTicketDebugString(i), this.anyPlayerCloseEnoughForSpawning(chunkcoordintpair), optional1.map((chunk) -> {
+                return chunk.getBlockEntities().size();
+            }).orElse(0), tickingtracker.getTicketDebugString(i), tickingtracker.getLevel(i), optional1.map((chunk) -> {
+                return chunk.getBlockTicks().count();
+            }).orElse(0), optional1.map((chunk) -> {
+                return chunk.getFluidTicks().count();
+            }).orElse(0));
         }
+
     }
 
     private static String printFuture(CompletableFuture<ChunkResult<LevelChunk>> future) {
         try {
-            ChunkResult<LevelChunk> chunkResult = future.getNow(null);
-            if (chunkResult != null) {
-                return chunkResult.isSuccess() ? "done" : "unloaded";
-            } else {
-                return "not completed";
-            }
-        } catch (CompletionException var2) {
-            return "failed " + var2.getCause().getMessage();
-        } catch (CancellationException var3) {
+            ChunkResult<LevelChunk> chunkresult = (ChunkResult) future.getNow(null); // CraftBukkit - decompile error
+
+            return chunkresult != null ? (chunkresult.isSuccess() ? "done" : "unloaded") : "not completed";
+        } catch (CompletionException completionexception) {
+            return "failed " + completionexception.getCause().getMessage();
+        } catch (CancellationException cancellationexception) {
             return "cancelled";
         }
     }
 
     private CompletableFuture<Optional<CompoundTag>> readChunk(ChunkPos chunkPos) {
-        return this.read(chunkPos).thenApplyAsync(nbt -> nbt.map(this::upgradeChunkTag), Util.backgroundExecutor());
+        return this.read(chunkPos).thenApplyAsync((optional) -> {
+            return optional.map((nbttagcompound) -> this.upgradeChunkTag(nbttagcompound, chunkPos)); // CraftBukkit
+        }, Util.backgroundExecutor());
     }
 
-    private CompoundTag upgradeChunkTag(CompoundTag nbt) {
-        return this.upgradeChunkTag(this.level.dimension(), this.overworldDataStorage, nbt, this.generator().getTypeNameForDataFixer());
+    // CraftBukkit start
+    public CompoundTag upgradeChunkTag(CompoundTag nbttagcompound, ChunkPos chunkcoordintpair) { // Paper - public
+        return this.upgradeChunkTag(this.level.getTypeKey(), this.overworldDataStorage, nbttagcompound, this.generator().getTypeNameForDataFixer(), chunkcoordintpair, this.level);
+        // CraftBukkit end
     }
 
-    boolean anyPlayerCloseEnoughForSpawning(ChunkPos pos) {
-        if (!this.distanceManager.hasPlayersNearby(pos.toLong())) {
+    public boolean anyPlayerCloseEnoughForSpawning(ChunkPos pos) { // Paper - public
+        // Spigot start
+        return this.anyPlayerCloseEnoughForSpawning(pos, false);
+    }
+
+    boolean anyPlayerCloseEnoughForSpawning(ChunkPos chunkcoordintpair, boolean reducedRange) {
+        int chunkRange = this.level.spigotConfig.mobSpawnRange;
+        chunkRange = (chunkRange > this.level.spigotConfig.viewDistance) ? (byte) this.level.spigotConfig.viewDistance : chunkRange;
+        chunkRange = (chunkRange > 8) ? 8 : chunkRange;
+
+        final int finalChunkRange = chunkRange; // Paper for lambda below
+        //double blockRange = (reducedRange) ? Math.pow(chunkRange << 4, 2) : 16384.0D; // Paper - use from event
+        double blockRange = 16384.0D; // Paper
+        // Spigot end
+        if (!this.distanceManager.hasPlayersNearby(chunkcoordintpair.toLong())) {
             return false;
         } else {
-            for (ServerPlayer serverPlayer : this.playerMap.getAllPlayers()) {
-                if (this.playerIsCloseEnoughForSpawning(serverPlayer, pos)) {
-                    return true;
+            Iterator iterator = this.playerMap.getAllPlayers().iterator();
+
+            ServerPlayer entityplayer;
+
+            do {
+                if (!iterator.hasNext()) {
+                    return false;
                 }
-            }
 
-            return false;
+                entityplayer = (ServerPlayer) iterator.next();
+                // Paper start - PlayerNaturallySpawnCreaturesEvent
+                com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event;
+                blockRange = 16384.0D;
+                if (reducedRange) {
+                    event = entityplayer.playerNaturallySpawnedEvent;
+                    if (event == null || event.isCancelled()) return false;
+                    blockRange = (double) ((event.getSpawnRadius() << 4) * (event.getSpawnRadius() << 4));
+                }
+                // Paper end - PlayerNaturallySpawnCreaturesEvent
+            } while (!this.playerIsCloseEnoughForSpawning(entityplayer, chunkcoordintpair, blockRange)); // Spigot
+
+            return true;
         }
     }
 
     public List<ServerPlayer> getPlayersCloseForSpawning(ChunkPos pos) {
-        long l = pos.toLong();
-        if (!this.distanceManager.hasPlayersNearby(l)) {
+        long i = pos.toLong();
+
+        if (!this.distanceManager.hasPlayersNearby(i)) {
             return List.of();
         } else {
             Builder<ServerPlayer> builder = ImmutableList.builder();
+            Iterator iterator = this.playerMap.getAllPlayers().iterator();
 
-            for (ServerPlayer serverPlayer : this.playerMap.getAllPlayers()) {
-                if (this.playerIsCloseEnoughForSpawning(serverPlayer, pos)) {
-                    builder.add(serverPlayer);
+            while (iterator.hasNext()) {
+                ServerPlayer entityplayer = (ServerPlayer) iterator.next();
+
+                if (this.playerIsCloseEnoughForSpawning(entityplayer, pos, 16384.0D)) { // Spigot
+                    builder.add(entityplayer);
                 }
             }
 
@@ -941,12 +799,13 @@
         }
     }
 
-    private boolean playerIsCloseEnoughForSpawning(ServerPlayer player, ChunkPos pos) {
-        if (player.isSpectator()) {
+    private boolean playerIsCloseEnoughForSpawning(ServerPlayer entityplayer, ChunkPos chunkcoordintpair, double range) { // Spigot
+        if (entityplayer.isSpectator()) {
             return false;
         } else {
-            double d = euclideanDistanceSquared(pos, player);
-            return d < 16384.0;
+            double d0 = ChunkMap.euclideanDistanceSquared(chunkcoordintpair, entityplayer);
+
+            return d0 < range; // Spigot
         }
     }
 
@@ -955,218 +814,263 @@
     }
 
     void updatePlayerStatus(ServerPlayer player, boolean added) {
-        boolean bl = this.skipPlayer(player);
-        boolean bl2 = this.playerMap.ignoredOrUnknown(player);
+        boolean flag1 = this.skipPlayer(player);
+        boolean flag2 = this.playerMap.ignoredOrUnknown(player);
+
         if (added) {
-            this.playerMap.addPlayer(player, bl);
+            this.playerMap.addPlayer(player, flag1);
             this.updatePlayerPos(player);
-            if (!bl) {
-                this.distanceManager.addPlayer(SectionPos.of(player), player);
+            if (!flag1) {
+                this.distanceManager.addPlayer(SectionPos.of((EntityAccess) player), player);
             }
 
             player.setChunkTrackingView(ChunkTrackingView.EMPTY);
-            this.updateChunkTracking(player);
+            ca.spottedleaf.moonrise.patches.chunk_system.ChunkSystem.addPlayerToDistanceMaps(this.level, player); // Paper - rewrite chunk system
+            this.addPlayerToDistanceMaps(player); // Paper - distance maps
         } else {
-            SectionPos sectionPos = player.getLastSectionPos();
+            SectionPos sectionposition = player.getLastSectionPos();
+
             this.playerMap.removePlayer(player);
-            if (!bl2) {
-                this.distanceManager.removePlayer(sectionPos, player);
+            if (!flag2) {
+                this.distanceManager.removePlayer(sectionposition, player);
             }
 
-            this.applyChunkTrackingView(player, ChunkTrackingView.EMPTY);
+            this.removePlayerFromDistanceMaps(player); // Paper - distance maps
+            ca.spottedleaf.moonrise.patches.chunk_system.ChunkSystem.removePlayerFromDistanceMaps(this.level, player); // Paper - rewrite chunk system
         }
+
     }
 
     private void updatePlayerPos(ServerPlayer player) {
-        SectionPos sectionPos = SectionPos.of(player);
-        player.setLastSectionPos(sectionPos);
+        SectionPos sectionposition = SectionPos.of((EntityAccess) player);
+
+        player.setLastSectionPos(sectionposition);
     }
 
     public void move(ServerPlayer player) {
-        for (ChunkMap.TrackedEntity trackedEntity : this.entityMap.values()) {
-            if (trackedEntity.entity == player) {
-                trackedEntity.updatePlayers(this.level.players());
+        ObjectIterator objectiterator = this.entityMap.values().iterator();
+
+        while (objectiterator.hasNext()) {
+            ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next();
+
+            if (playerchunkmap_entitytracker.entity == player) {
+                playerchunkmap_entitytracker.updatePlayers(this.level.players());
             } else {
-                trackedEntity.updatePlayer(player);
+                playerchunkmap_entitytracker.updatePlayer(player);
             }
         }
 
-        SectionPos sectionPos = player.getLastSectionPos();
-        SectionPos sectionPos2 = SectionPos.of(player);
-        boolean bl = this.playerMap.ignored(player);
-        boolean bl2 = this.skipPlayer(player);
-        boolean bl3 = sectionPos.asLong() != sectionPos2.asLong();
-        if (bl3 || bl != bl2) {
+        SectionPos sectionposition = player.getLastSectionPos();
+        SectionPos sectionposition1 = SectionPos.of((EntityAccess) player);
+        boolean flag = this.playerMap.ignored(player);
+        boolean flag1 = this.skipPlayer(player);
+        boolean flag2 = sectionposition.asLong() != sectionposition1.asLong();
+
+        if (flag2 || flag != flag1) {
             this.updatePlayerPos(player);
-            if (!bl) {
-                this.distanceManager.removePlayer(sectionPos, player);
+            if (!flag) {
+                this.distanceManager.removePlayer(sectionposition, player);
             }
 
-            if (!bl2) {
-                this.distanceManager.addPlayer(sectionPos2, player);
+            if (!flag1) {
+                this.distanceManager.addPlayer(sectionposition1, player);
             }
 
-            if (!bl && bl2) {
+            if (!flag && flag1) {
                 this.playerMap.ignorePlayer(player);
             }
 
-            if (bl && !bl2) {
+            if (flag && !flag1) {
                 this.playerMap.unIgnorePlayer(player);
             }
 
-            this.updateChunkTracking(player);
+            // Paper - rewrite chunk system
         }
+
+        this.updateMaps(player); // Paper - distance maps
+        ca.spottedleaf.moonrise.patches.chunk_system.ChunkSystem.updateMaps(this.level, player); // Paper - rewrite chunk system
     }
 
     private void updateChunkTracking(ServerPlayer player) {
-        ChunkPos chunkPos = player.chunkPosition();
-        int i = this.getPlayerViewDistance(player);
-        if (player.getChunkTrackingView() instanceof ChunkTrackingView.Positioned positioned
-            && positioned.center().equals(chunkPos)
-            && positioned.viewDistance() == i) {
-            return;
-        }
-
-        this.applyChunkTrackingView(player, ChunkTrackingView.of(chunkPos, i));
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     private void applyChunkTrackingView(ServerPlayer player, ChunkTrackingView chunkFilter) {
-        if (player.level() == this.level) {
-            ChunkTrackingView chunkTrackingView = player.getChunkTrackingView();
-            if (chunkFilter instanceof ChunkTrackingView.Positioned positioned
-                && (!(chunkTrackingView instanceof ChunkTrackingView.Positioned positioned2) || !positioned2.center().equals(positioned.center()))) {
-                player.connection.send(new ClientboundSetChunkCacheCenterPacket(positioned.center().x, positioned.center().z));
-            }
-
-            ChunkTrackingView.difference(
-                chunkTrackingView, chunkFilter, chunkPos -> this.markChunkPendingToSend(player, chunkPos), chunkPos -> dropChunk(player, chunkPos)
-            );
-            player.setChunkTrackingView(chunkFilter);
-        }
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     @Override
     public List<ServerPlayer> getPlayers(ChunkPos chunkPos, boolean onlyOnWatchDistanceEdge) {
-        Set<ServerPlayer> set = this.playerMap.getAllPlayers();
-        Builder<ServerPlayer> builder = ImmutableList.builder();
-
-        for (ServerPlayer serverPlayer : set) {
-            if (onlyOnWatchDistanceEdge && this.isChunkOnTrackedBorder(serverPlayer, chunkPos.x, chunkPos.z)
-                || !onlyOnWatchDistanceEdge && this.isChunkTracked(serverPlayer, chunkPos.x, chunkPos.z)) {
-                builder.add(serverPlayer);
-            }
+        // Paper start - rewrite chunk system
+        final ChunkHolder holder = this.getVisibleChunkIfPresent(chunkPos.toLong());
+        if (holder == null) {
+            return new ArrayList<>();
+        } else {
+            return ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkHolder)holder).moonrise$getPlayers(onlyOnWatchDistanceEdge);
         }
-
-        return builder.build();
+        // Paper end - rewrite chunk system
     }
 
     public void addEntity(Entity entity) {
+        org.spigotmc.AsyncCatcher.catchOp("entity track"); // Spigot
+        // Paper start - ignore and warn about illegal addEntity calls instead of crashing server
+        if (!entity.valid || entity.level() != this.level || this.entityMap.containsKey(entity.getId())) {
+            LOGGER.error("Illegal ChunkMap::addEntity for world " + this.level.getWorld().getName()
+                + ": " + entity  + (this.entityMap.containsKey(entity.getId()) ? " ALREADY CONTAINED (This would have crashed your server)" : ""), new Throwable());
+            return;
+        }
+        // Paper end - ignore and warn about illegal addEntity calls instead of crashing server
+        if (entity instanceof ServerPlayer && ((ServerPlayer) entity).supressTrackerForLogin) return; // Paper - Fire PlayerJoinEvent when Player is actually ready; Delay adding to tracker until after list packets
         if (!(entity instanceof EnderDragonPart)) {
-            EntityType<?> entityType = entity.getType();
-            int i = entityType.clientTrackingRange() * 16;
+            EntityType<?> entitytypes = entity.getType();
+            int i = entitytypes.clientTrackingRange() * 16;
+            i = org.spigotmc.TrackingRange.getEntityTrackingRange(entity, i); // Spigot
+
             if (i != 0) {
-                int j = entityType.updateInterval();
+                int j = entitytypes.updateInterval();
+
                 if (this.entityMap.containsKey(entity.getId())) {
-                    throw (IllegalStateException)Util.pauseInIde(new IllegalStateException("Entity is already tracked!"));
+                    throw (IllegalStateException) Util.pauseInIde(new IllegalStateException("Entity is already tracked!"));
                 } else {
-                    ChunkMap.TrackedEntity trackedEntity = new ChunkMap.TrackedEntity(entity, i, j, entityType.trackDeltas());
-                    this.entityMap.put(entity.getId(), trackedEntity);
-                    trackedEntity.updatePlayers(this.level.players());
-                    if (entity instanceof ServerPlayer serverPlayer) {
-                        this.updatePlayerStatus(serverPlayer, true);
+                    ChunkMap.TrackedEntity playerchunkmap_entitytracker = new ChunkMap.TrackedEntity(entity, i, j, entitytypes.trackDeltas());
 
-                        for (ChunkMap.TrackedEntity trackedEntity2 : this.entityMap.values()) {
-                            if (trackedEntity2.entity != serverPlayer) {
-                                trackedEntity2.updatePlayer(serverPlayer);
+                    entity.tracker = playerchunkmap_entitytracker; // Paper - Fast access to tracker
+                    this.entityMap.put(entity.getId(), playerchunkmap_entitytracker);
+                    playerchunkmap_entitytracker.updatePlayers(this.level.players());
+                    if (entity instanceof ServerPlayer) {
+                        ServerPlayer entityplayer = (ServerPlayer) entity;
+
+                        this.updatePlayerStatus(entityplayer, true);
+                        ObjectIterator objectiterator = this.entityMap.values().iterator();
+
+                        while (objectiterator.hasNext()) {
+                            ChunkMap.TrackedEntity playerchunkmap_entitytracker1 = (ChunkMap.TrackedEntity) objectiterator.next();
+
+                            if (playerchunkmap_entitytracker1.entity != entityplayer) {
+                                playerchunkmap_entitytracker1.updatePlayer(entityplayer);
                             }
                         }
                     }
+
                 }
             }
         }
     }
 
     protected void removeEntity(Entity entity) {
-        if (entity instanceof ServerPlayer serverPlayer) {
-            this.updatePlayerStatus(serverPlayer, false);
+        org.spigotmc.AsyncCatcher.catchOp("entity untrack"); // Spigot
+        if (entity instanceof ServerPlayer entityplayer) {
+            this.updatePlayerStatus(entityplayer, false);
+            ObjectIterator objectiterator = this.entityMap.values().iterator();
 
-            for (ChunkMap.TrackedEntity trackedEntity : this.entityMap.values()) {
-                trackedEntity.removePlayer(serverPlayer);
+            while (objectiterator.hasNext()) {
+                ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next();
+
+                playerchunkmap_entitytracker.removePlayer(entityplayer);
             }
         }
 
-        ChunkMap.TrackedEntity trackedEntity2 = this.entityMap.remove(entity.getId());
-        if (trackedEntity2 != null) {
-            trackedEntity2.broadcastRemoved();
+        ChunkMap.TrackedEntity playerchunkmap_entitytracker1 = (ChunkMap.TrackedEntity) this.entityMap.remove(entity.getId());
+
+        if (playerchunkmap_entitytracker1 != null) {
+            playerchunkmap_entitytracker1.broadcastRemoved();
         }
+        entity.tracker = null; // Paper - We're no longer tracked
     }
 
     protected void tick() {
-        for (ServerPlayer serverPlayer : this.playerMap.getAllPlayers()) {
-            this.updateChunkTracking(serverPlayer);
-        }
+        // Paper - rewrite chunk system
 
         List<ServerPlayer> list = Lists.newArrayList();
-        List<ServerPlayer> list2 = this.level.players();
+        List<ServerPlayer> list1 = this.level.players();
+        ObjectIterator objectiterator = this.entityMap.values().iterator();
+        level.timings.tracker1.startTiming(); // Paper
+
+        ChunkMap.TrackedEntity playerchunkmap_entitytracker;
+
+        while (objectiterator.hasNext()) {
+            playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next();
+            SectionPos sectionposition = playerchunkmap_entitytracker.lastSectionPos;
+            SectionPos sectionposition1 = SectionPos.of((EntityAccess) playerchunkmap_entitytracker.entity);
+            boolean flag = !Objects.equals(sectionposition, sectionposition1);
+
+            if (flag) {
+                playerchunkmap_entitytracker.updatePlayers(list1);
+                Entity entity = playerchunkmap_entitytracker.entity;
 
-        for (ChunkMap.TrackedEntity trackedEntity : this.entityMap.values()) {
-            SectionPos sectionPos = trackedEntity.lastSectionPos;
-            SectionPos sectionPos2 = SectionPos.of(trackedEntity.entity);
-            boolean bl = !Objects.equals(sectionPos, sectionPos2);
-            if (bl) {
-                trackedEntity.updatePlayers(list2);
-                Entity entity = trackedEntity.entity;
                 if (entity instanceof ServerPlayer) {
-                    list.add((ServerPlayer)entity);
+                    list.add((ServerPlayer) entity);
                 }
 
-                trackedEntity.lastSectionPos = sectionPos2;
+                playerchunkmap_entitytracker.lastSectionPos = sectionposition1;
             }
 
-            if (bl || this.distanceManager.inEntityTickingRange(sectionPos2.chunk().toLong())) {
-                trackedEntity.serverEntity.sendChanges();
+            if (flag || this.distanceManager.inEntityTickingRange(sectionposition1.chunk().toLong())) {
+                playerchunkmap_entitytracker.serverEntity.sendChanges();
             }
         }
+        level.timings.tracker1.stopTiming(); // Paper
 
         if (!list.isEmpty()) {
-            for (ChunkMap.TrackedEntity trackedEntity2 : this.entityMap.values()) {
-                trackedEntity2.updatePlayers(list);
+            objectiterator = this.entityMap.values().iterator();
+
+            level.timings.tracker2.startTiming(); // Paper
+            while (objectiterator.hasNext()) {
+                playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next();
+                playerchunkmap_entitytracker.updatePlayers(list);
             }
+            level.timings.tracker2.stopTiming(); // Paper
         }
+
     }
 
     public void broadcast(Entity entity, Packet<?> packet) {
-        ChunkMap.TrackedEntity trackedEntity = this.entityMap.get(entity.getId());
-        if (trackedEntity != null) {
-            trackedEntity.broadcast(packet);
+        ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) this.entityMap.get(entity.getId());
+
+        if (playerchunkmap_entitytracker != null) {
+            playerchunkmap_entitytracker.broadcast(packet);
         }
+
     }
 
     protected void broadcastAndSend(Entity entity, Packet<?> packet) {
-        ChunkMap.TrackedEntity trackedEntity = this.entityMap.get(entity.getId());
-        if (trackedEntity != null) {
-            trackedEntity.broadcastAndSend(packet);
+        ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) this.entityMap.get(entity.getId());
+
+        if (playerchunkmap_entitytracker != null) {
+            playerchunkmap_entitytracker.broadcastAndSend(packet);
         }
+
     }
 
     public void resendBiomesForChunks(List<ChunkAccess> chunks) {
-        Map<ServerPlayer, List<LevelChunk>> map = new HashMap<>();
+        Map<ServerPlayer, List<LevelChunk>> map = new HashMap();
+        Iterator iterator = chunks.iterator();
 
-        for (ChunkAccess chunkAccess : chunks) {
-            ChunkPos chunkPos = chunkAccess.getPos();
-            LevelChunk levelChunk2;
-            if (chunkAccess instanceof LevelChunk levelChunk) {
-                levelChunk2 = levelChunk;
+        while (iterator.hasNext()) {
+            ChunkAccess ichunkaccess = (ChunkAccess) iterator.next();
+            ChunkPos chunkcoordintpair = ichunkaccess.getPos();
+            LevelChunk chunk;
+
+            if (ichunkaccess instanceof LevelChunk chunk1) {
+                chunk = chunk1;
             } else {
-                levelChunk2 = this.level.getChunk(chunkPos.x, chunkPos.z);
+                chunk = this.level.getChunk(chunkcoordintpair.x, chunkcoordintpair.z);
             }
 
-            for (ServerPlayer serverPlayer : this.getPlayers(chunkPos, false)) {
-                map.computeIfAbsent(serverPlayer, player -> new ArrayList<>()).add(levelChunk2);
+            Iterator iterator1 = this.getPlayers(chunkcoordintpair, false).iterator();
+
+            while (iterator1.hasNext()) {
+                ServerPlayer entityplayer = (ServerPlayer) iterator1.next();
+
+                ((List) map.computeIfAbsent(entityplayer, (entityplayer1) -> {
+                    return new ArrayList();
+                })).add(chunk);
             }
         }
 
-        map.forEach((player, chunksx) -> player.connection.send(ClientboundChunksBiomesPacket.forChunks((List<LevelChunk>)chunksx)));
+        map.forEach((entityplayer1, list1) -> {
+            entityplayer1.connection.send(ClientboundChunksBiomesPacket.forChunks(list1));
+        });
     }
 
     protected PoiManager getPoiManager() {
@@ -1182,23 +1086,25 @@
     }
 
     public void waitForLightBeforeSending(ChunkPos centerPos, int radius) {
-        int i = radius + 1;
-        ChunkPos.rangeClosed(centerPos, i).forEach(pos -> {
-            ChunkHolder chunkHolder = this.getVisibleChunkIfPresent(pos.toLong());
-            if (chunkHolder != null) {
-                chunkHolder.addSendDependency(this.lightEngine.waitForPendingTasks(pos.x, pos.z));
-            }
-        });
+        // Paper - rewrite chunk system
     }
 
-    class DistanceManager extends net.minecraft.server.level.DistanceManager {
-        protected DistanceManager(final Executor workerExecutor, final Executor mainThreadExecutor) {
-            super(workerExecutor, mainThreadExecutor);
+    public class ChunkDistanceManager extends DistanceManager implements ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemDistanceManager { // Paper - public // Paper - rewrite chunk system
+
+        protected ChunkDistanceManager(final Executor workerExecutor, final Executor mainThreadExecutor) {
+            super(workerExecutor, mainThreadExecutor, ChunkMap.this); // Paper
+        }
+
+        // Paper start - rewrite chunk system
+        @Override
+        public final ChunkMap moonrise$getChunkMap() {
+            return ChunkMap.this;
         }
+        // Paper end - rewrite chunk system
 
         @Override
         protected boolean isChunkToRemove(long pos) {
-            return ChunkMap.this.toDrop.contains(pos);
+            throw new UnsupportedOperationException(); // Paper - rewrite chunk system
         }
 
         @Nullable
@@ -1209,77 +1115,112 @@
 
         @Nullable
         @Override
-        protected ChunkHolder updateChunkScheduling(long pos, int level, @Nullable ChunkHolder holder, int i) {
-            return ChunkMap.this.updateChunkScheduling(pos, level, holder, i);
+        protected ChunkHolder updateChunkScheduling(long pos, int level, @Nullable ChunkHolder holder, int k) {
+            return ChunkMap.this.updateChunkScheduling(pos, level, holder, k);
         }
     }
 
     public class TrackedEntity {
+
         public final ServerEntity serverEntity;
         final Entity entity;
         private final int range;
         SectionPos lastSectionPos;
-        public final Set<ServerPlayerConnection> seenBy = Sets.newIdentityHashSet();
+        public final Set<ServerPlayerConnection> seenBy = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); // Paper - Perf: optimise map impl
 
-        public TrackedEntity(final Entity entity, final int maxDistance, final int tickInterval, final boolean alwaysUpdateVelocity) {
-            this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, tickInterval, alwaysUpdateVelocity, this::broadcast);
+        public TrackedEntity(final Entity entity, final int i, final int j, final boolean flag) {
+            this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, j, flag, this::broadcast, this.seenBy); // CraftBukkit
             this.entity = entity;
-            this.range = maxDistance;
-            this.lastSectionPos = SectionPos.of(entity);
+            this.range = i;
+            this.lastSectionPos = SectionPos.of((EntityAccess) entity);
         }
 
-        @Override
         public boolean equals(Object object) {
-            return object instanceof ChunkMap.TrackedEntity && ((ChunkMap.TrackedEntity)object).entity.getId() == this.entity.getId();
+            return object instanceof ChunkMap.TrackedEntity ? ((ChunkMap.TrackedEntity) object).entity.getId() == this.entity.getId() : false;
         }
 
-        @Override
         public int hashCode() {
             return this.entity.getId();
         }
 
         public void broadcast(Packet<?> packet) {
-            for (ServerPlayerConnection serverPlayerConnection : this.seenBy) {
-                serverPlayerConnection.send(packet);
+            Iterator iterator = this.seenBy.iterator();
+
+            while (iterator.hasNext()) {
+                ServerPlayerConnection serverplayerconnection = (ServerPlayerConnection) iterator.next();
+
+                serverplayerconnection.send(packet);
             }
+
         }
 
         public void broadcastAndSend(Packet<?> packet) {
             this.broadcast(packet);
             if (this.entity instanceof ServerPlayer) {
-                ((ServerPlayer)this.entity).connection.send(packet);
+                ((ServerPlayer) this.entity).connection.send(packet);
             }
+
         }
 
         public void broadcastRemoved() {
-            for (ServerPlayerConnection serverPlayerConnection : this.seenBy) {
-                this.serverEntity.removePairing(serverPlayerConnection.getPlayer());
+            Iterator iterator = this.seenBy.iterator();
+
+            while (iterator.hasNext()) {
+                ServerPlayerConnection serverplayerconnection = (ServerPlayerConnection) iterator.next();
+
+                this.serverEntity.removePairing(serverplayerconnection.getPlayer());
             }
+
         }
 
         public void removePlayer(ServerPlayer player) {
+            org.spigotmc.AsyncCatcher.catchOp("player tracker clear"); // Spigot
             if (this.seenBy.remove(player.connection)) {
                 this.serverEntity.removePairing(player);
             }
+
         }
 
         public void updatePlayer(ServerPlayer player) {
+            org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot
             if (player != this.entity) {
-                Vec3 vec3 = player.position().subtract(this.entity.position());
+                // Paper start - remove allocation of Vec3D here
+                // Vec3 vec3d = player.position().subtract(this.entity.position());
+                double vec3d_dx = player.getX() - this.entity.getX();
+                double vec3d_dz = player.getZ() - this.entity.getZ();
+                // Paper end - remove allocation of Vec3D here
                 int i = ChunkMap.this.getPlayerViewDistance(player);
-                double d = (double)Math.min(this.getEffectiveRange(), i * 16);
-                double e = vec3.x * vec3.x + vec3.z * vec3.z;
-                double f = d * d;
-                boolean bl = e <= f
-                    && this.entity.broadcastToPlayer(player)
-                    && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z);
-                if (bl) {
+                double d0 = (double) Math.min(this.getEffectiveRange(), i * 16);
+                double d1 = vec3d_dx * vec3d_dx + vec3d_dz * vec3d_dz; // Paper
+                double d2 = d0 * d0;
+                boolean flag = d1 <= d2 && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z);
+                // Paper start - Configurable entity tracking range by Y
+                if (flag && level.paperConfig().entities.trackingRangeY.enabled) {
+                    double rangeY = level.paperConfig().entities.trackingRangeY.get(this.entity, -1);
+                    if (rangeY != -1) {
+                        double vec3d_dy = player.getY() - this.entity.getY();
+                        flag = vec3d_dy * vec3d_dy <= rangeY * rangeY;
+                    }
+                }
+                // Paper end - Configurable entity tracking range by Y
+
+                // CraftBukkit start - respect vanish API
+                if (flag && !player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { // Paper - only consider hits
+                    flag = false;
+                }
+                // CraftBukkit end
+                if (flag) {
                     if (this.seenBy.add(player.connection)) {
+                        // Paper start - entity tracking events
+                        if (io.papermc.paper.event.player.PlayerTrackEntityEvent.getHandlerList().getRegisteredListeners().length == 0 || new io.papermc.paper.event.player.PlayerTrackEntityEvent(player.getBukkitEntity(), this.entity.getBukkitEntity()).callEvent()) {
                         this.serverEntity.addPairing(player);
+                        }
+                        // Paper end - entity tracking events
                     }
                 } else if (this.seenBy.remove(player.connection)) {
                     this.serverEntity.removePairing(player);
                 }
+
             }
         }
 
@@ -1289,9 +1230,13 @@
 
         private int getEffectiveRange() {
             int i = this.range;
+            Iterator iterator = this.entity.getIndirectPassengers().iterator();
 
-            for (Entity entity : this.entity.getIndirectPassengers()) {
+            while (iterator.hasNext()) {
+                Entity entity = (Entity) iterator.next();
                 int j = entity.getType().clientTrackingRange() * 16;
+                j = org.spigotmc.TrackingRange.getEntityTrackingRange(entity, j); // Paper
+
                 if (j > i) {
                     i = j;
                 }
@@ -1301,9 +1246,14 @@
         }
 
         public void updatePlayers(List<ServerPlayer> players) {
-            for (ServerPlayer serverPlayer : players) {
-                this.updatePlayer(serverPlayer);
+            Iterator iterator = players.iterator();
+
+            while (iterator.hasNext()) {
+                ServerPlayer entityplayer = (ServerPlayer) iterator.next();
+
+                this.updatePlayer(entityplayer);
             }
+
         }
     }
 }
