--- a/net/minecraft/server/level/ThreadedLevelLightEngine.java
+++ b/net/minecraft/server/level/ThreadedLevelLightEngine.java
@@ -23,23 +_,151 @@
 import net.minecraft.world.level.lighting.LevelLightEngine;
 import org.slf4j.Logger;
 
-public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCloseable {
+public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCloseable, ca.spottedleaf.moonrise.patches.starlight.light.StarLightLightingProvider { // Paper - rewrite chunk system
     public static final int DEFAULT_BATCH_SIZE = 1000;
     private static final Logger LOGGER = LogUtils.getLogger();
-    private final ConsecutiveExecutor consecutiveExecutor;
-    private final ObjectList<Pair<ThreadedLevelLightEngine.TaskType, Runnable>> lightTasks = new ObjectArrayList<>();
+    // Paper - rewrite chunk sytem
     private final ChunkMap chunkMap;
-    private final ChunkTaskDispatcher taskDispatcher;
+    // Paper - rewrite chunk sytem
     private final int taskPerBatch = 1000;
-    private final AtomicBoolean scheduled = new AtomicBoolean();
+    // Paper - rewrite chunk sytem
+
+    // Paper start - rewrite chunk system
+    private final java.util.concurrent.atomic.AtomicLong chunkWorkCounter = new java.util.concurrent.atomic.AtomicLong();
+    private void queueTaskForSection(final int chunkX, final int chunkY, final int chunkZ,
+                                     final java.util.function.Supplier<ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface.LightQueue.ChunkTasks> supplier) {
+        final ServerLevel world = (ServerLevel)this.starlight$getLightEngine().getWorld();
+
+        final ChunkAccess center = this.starlight$getLightEngine().getAnyChunkNow(chunkX, chunkZ);
+        if (center == null || !center.getPersistedStatus().isOrAfter(net.minecraft.world.level.chunk.status.ChunkStatus.LIGHT)) {
+            // do not accept updates in unlit chunks, unless we might be generating a chunk
+            return;
+        }
+
+        final ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface.ServerLightQueue.ServerChunkTasks scheduledTask = (ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface.ServerLightQueue.ServerChunkTasks)supplier.get();
+
+        if (scheduledTask == null) {
+            // not scheduled
+            return;
+        }
+
+        if (!scheduledTask.markTicketAdded()) {
+            // ticket already added
+            return;
+        }
+
+        final Long ticketId = Long.valueOf(this.chunkWorkCounter.getAndIncrement());
+        final ChunkPos pos = new ChunkPos(chunkX, chunkZ);
+        ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)world).moonrise$getChunkTaskScheduler().chunkHolderManager.addTicketAtLevel(ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface.CHUNK_WORK_TICKET, pos, ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface.LIGHT_TICKET_LEVEL, ticketId);
+
+        scheduledTask.queueOrRunTask(() -> {
+            ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)world).moonrise$getChunkTaskScheduler().chunkHolderManager.removeTicketAtLevel(ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface.CHUNK_WORK_TICKET, pos, ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface.LIGHT_TICKET_LEVEL, ticketId);
+        });
+    }
+
+    @Override
+    public final int starlight$serverRelightChunks(final java.util.Collection<net.minecraft.world.level.ChunkPos> chunks0,
+                                                   final java.util.function.Consumer<net.minecraft.world.level.ChunkPos> chunkLightCallback,
+                                                   final java.util.function.IntConsumer onComplete) {
+        final java.util.Set<net.minecraft.world.level.ChunkPos> chunks = new java.util.LinkedHashSet<>(chunks0);
+        final java.util.Map<net.minecraft.world.level.ChunkPos, Long> ticketIds = new java.util.HashMap<>();
+        final ServerLevel world = (ServerLevel)this.starlight$getLightEngine().getWorld();
+
+        if (chunks.isEmpty()) {
+            if (onComplete != null) {
+                onComplete.accept(0);
+            }
+            return 0;
+        }
+
+        int minX = Integer.MAX_VALUE;
+        int minZ = Integer.MAX_VALUE;
+        int maxZ = Integer.MIN_VALUE;
+        int maxX = Integer.MIN_VALUE;
+
+        for (final java.util.Iterator<net.minecraft.world.level.ChunkPos> iterator = chunks.iterator(); iterator.hasNext();) {
+            final ChunkPos pos = iterator.next();
+
+            minX = Math.min(pos.x, minX);
+            minZ = Math.min(pos.z, minZ);
+            maxX = Math.max(pos.x, maxX);
+            maxZ = Math.max(pos.z, maxZ);
+
+            final Long id = ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler.getNextChunkRelightId();
+            ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)world).moonrise$getChunkTaskScheduler().chunkHolderManager.addTicketAtLevel(ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler.CHUNK_RELIGHT, pos, ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface.LIGHT_TICKET_LEVEL, id);
+            ticketIds.put(pos, id);
+
+            final ChunkAccess chunk = (ChunkAccess)world.getChunkSource().getChunkForLighting(pos.x, pos.z);
+            if (chunk == null || !chunk.isLightCorrect() || !chunk.getPersistedStatus().isOrAfter(net.minecraft.world.level.chunk.status.ChunkStatus.LIGHT)) {
+                // cannot relight this chunk
+                iterator.remove();
+                ticketIds.remove(pos);
+                ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)world).moonrise$getChunkTaskScheduler().chunkHolderManager.removeTicketAtLevel(ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler.CHUNK_RELIGHT, pos, ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface.LIGHT_TICKET_LEVEL, id);
+                continue;
+            }
+        }
+
+        ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)world).moonrise$getChunkTaskScheduler().radiusAwareScheduler.queueTask(minX, minZ, maxX, maxZ, () -> {
+            ThreadedLevelLightEngine.this.starlight$getLightEngine().relightChunks(
+                chunks,
+                (final ChunkPos pos) -> {
+                    if (chunkLightCallback != null) {
+                        chunkLightCallback.accept(pos);
+                    }
+
+                    ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)world).moonrise$getChunkTaskScheduler().scheduleChunkTask(pos.x, pos.z, () -> {
+                        final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)world).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(
+                            pos.x, pos.z
+                        );
+
+                        if (chunkHolder == null) {
+                            return;
+                        }
+
+                        final java.util.List<ServerPlayer> players = ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkHolder)chunkHolder.vanillaChunkHolder).moonrise$getPlayers(false);
+
+                        if (players.isEmpty()) {
+                            return;
+                        }
+
+                        final net.minecraft.network.protocol.Packet<?> relightPacket = new net.minecraft.network.protocol.game.ClientboundLightUpdatePacket(
+                            pos, (ThreadedLevelLightEngine)(Object)ThreadedLevelLightEngine.this,
+                            null, null
+                        );
+
+                        for (final ServerPlayer player : players) {
+                            final net.minecraft.server.network.ServerGamePacketListenerImpl conn = player.connection;
+                            if (conn != null) {
+                                conn.send(relightPacket);
+                            }
+                        }
+                    });
+                },
+                (final int relight) -> {
+                    if (onComplete != null) {
+                        onComplete.accept(relight);
+                    }
+
+                    for (final java.util.Map.Entry<ChunkPos, Long> entry : ticketIds.entrySet()) {
+                        ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)world).moonrise$getChunkTaskScheduler().chunkHolderManager.removeTicketAtLevel(
+                            ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler.CHUNK_RELIGHT, entry.getKey(),
+                            ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface.LIGHT_TICKET_LEVEL, entry.getValue()
+                        );
+                    }
+                }
+            );
+        });
+
+        return chunks.size();
+    }
+    // Paper end - rewrite chunk system
 
     public ThreadedLevelLightEngine(
         LightChunkGetter lightChunkGetter, ChunkMap chunkMap, boolean skyLight, ConsecutiveExecutor consecutiveExecutor, ChunkTaskDispatcher taskDispatcher
     ) {
         super(lightChunkGetter, true, skyLight);
         this.chunkMap = chunkMap;
-        this.taskDispatcher = taskDispatcher;
-        this.consecutiveExecutor = consecutiveExecutor;
+        // Paper - rewrite chunk system
     }
 
     @Override
@@ -53,167 +_,73 @@
 
     @Override
     public void checkBlock(BlockPos pos) {
-        BlockPos blockPos = pos.immutable();
-        this.addTask(
-            SectionPos.blockToSectionCoord(pos.getX()),
-            SectionPos.blockToSectionCoord(pos.getZ()),
-            ThreadedLevelLightEngine.TaskType.PRE_UPDATE,
-            Util.name(() -> super.checkBlock(blockPos), () -> "checkBlock " + blockPos)
-        );
+        // Paper start - rewrite chunk system
+        final BlockPos posCopy = pos.immutable();
+        this.queueTaskForSection(posCopy.getX() >> 4, posCopy.getY() >> 4, posCopy.getZ() >> 4, () -> {
+            return ThreadedLevelLightEngine.this.starlight$getLightEngine().blockChange(posCopy);
+        });
+        // Paper end - rewrite chunk system
     }
 
     protected void updateChunkStatus(ChunkPos chunkPos) {
-        this.addTask(chunkPos.x, chunkPos.z, () -> 0, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> {
-            super.retainData(chunkPos, false);
-            super.setLightEnabled(chunkPos, false);
-
-            for (int lightSection = this.getMinLightSection(); lightSection < this.getMaxLightSection(); lightSection++) {
-                super.queueSectionData(LightLayer.BLOCK, SectionPos.of(chunkPos, lightSection), null);
-                super.queueSectionData(LightLayer.SKY, SectionPos.of(chunkPos, lightSection), null);
-            }
-
-            for (int lightSection = this.levelHeightAccessor.getMinSectionY(); lightSection <= this.levelHeightAccessor.getMaxSectionY(); lightSection++) {
-                super.updateSectionStatus(SectionPos.of(chunkPos, lightSection), true);
-            }
-        }, () -> "updateChunkStatus " + chunkPos + " true"));
+        // Paper - rewrite chunk system
     }
 
     @Override
     public void updateSectionStatus(SectionPos pos, boolean isEmpty) {
-        this.addTask(
-            pos.x(),
-            pos.z(),
-            () -> 0,
-            ThreadedLevelLightEngine.TaskType.PRE_UPDATE,
-            Util.name(() -> super.updateSectionStatus(pos, isEmpty), () -> "updateSectionStatus " + pos + " " + isEmpty)
-        );
+        // Paper start - rewrite chunk system
+        this.queueTaskForSection(pos.getX(), pos.getY(), pos.getZ(), () -> {
+            return ThreadedLevelLightEngine.this.starlight$getLightEngine().sectionChange(pos, isEmpty);
+        });
+        // Paper end - rewrite chunk system
     }
 
     @Override
     public void propagateLightSources(ChunkPos chunkPos) {
-        this.addTask(
-            chunkPos.x,
-            chunkPos.z,
-            ThreadedLevelLightEngine.TaskType.PRE_UPDATE,
-            Util.name(() -> super.propagateLightSources(chunkPos), () -> "propagateLight " + chunkPos)
-        );
+        // Paper - rewrite chunk system
     }
 
     @Override
     public void setLightEnabled(ChunkPos chunkPos, boolean lightEnabled) {
-        this.addTask(
-            chunkPos.x,
-            chunkPos.z,
-            ThreadedLevelLightEngine.TaskType.PRE_UPDATE,
-            Util.name(() -> super.setLightEnabled(chunkPos, lightEnabled), () -> "enableLight " + chunkPos + " " + lightEnabled)
-        );
+        // Paper start - rewrite chunk system
     }
 
     @Override
     public void queueSectionData(LightLayer lightLayer, SectionPos sectionPos, @Nullable DataLayer dataLayer) {
-        this.addTask(
-            sectionPos.x(),
-            sectionPos.z(),
-            () -> 0,
-            ThreadedLevelLightEngine.TaskType.PRE_UPDATE,
-            Util.name(() -> super.queueSectionData(lightLayer, sectionPos, dataLayer), () -> "queueData " + sectionPos)
-        );
+        // Paper start - rewrite chunk system
     }
 
     private void addTask(int chunkX, int chunkZ, ThreadedLevelLightEngine.TaskType type, Runnable task) {
-        this.addTask(chunkX, chunkZ, this.chunkMap.getChunkQueueLevel(ChunkPos.asLong(chunkX, chunkZ)), type, task);
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     private void addTask(int chunkX, int chunkZ, IntSupplier queueLevelSupplier, ThreadedLevelLightEngine.TaskType type, Runnable task) {
-        this.taskDispatcher.submit(() -> {
-            this.lightTasks.add(Pair.of(type, task));
-            if (this.lightTasks.size() >= 1000) {
-                this.runUpdate();
-            }
-        }, ChunkPos.asLong(chunkX, chunkZ), queueLevelSupplier);
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     @Override
     public void retainData(ChunkPos pos, boolean retain) {
-        this.addTask(
-            pos.x, pos.z, () -> 0, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> super.retainData(pos, retain), () -> "retainData " + pos)
-        );
+        // Paper start - rewrite chunk system
     }
 
     public CompletableFuture<ChunkAccess> initializeLight(ChunkAccess chunk, boolean lightEnabled) {
-        ChunkPos pos = chunk.getPos();
-        this.addTask(pos.x, pos.z, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> {
-            LevelChunkSection[] sections = chunk.getSections();
-
-            for (int i = 0; i < chunk.getSectionsCount(); i++) {
-                LevelChunkSection levelChunkSection = sections[i];
-                if (!levelChunkSection.hasOnlyAir()) {
-                    int sectionYFromSectionIndex = this.levelHeightAccessor.getSectionYFromSectionIndex(i);
-                    super.updateSectionStatus(SectionPos.of(pos, sectionYFromSectionIndex), false);
-                }
-            }
-        }, () -> "initializeLight: " + pos));
-        return CompletableFuture.supplyAsync(() -> {
-            super.setLightEnabled(pos, lightEnabled);
-            super.retainData(pos, false);
-            return chunk;
-        }, task -> this.addTask(pos.x, pos.z, ThreadedLevelLightEngine.TaskType.POST_UPDATE, task));
+        return CompletableFuture.completedFuture(chunk); // Paper start - rewrite chunk system
     }
 
     public CompletableFuture<ChunkAccess> lightChunk(ChunkAccess chunk, boolean isLighted) {
-        ChunkPos pos = chunk.getPos();
-        chunk.setLightCorrect(false);
-        this.addTask(pos.x, pos.z, ThreadedLevelLightEngine.TaskType.PRE_UPDATE, Util.name(() -> {
-            if (!isLighted) {
-                super.propagateLightSources(pos);
-            }
-
-            if (SharedConstants.DEBUG_VERBOSE_SERVER_EVENTS) {
-                LOGGER.debug("LIT {}", pos);
-            }
-        }, () -> "lightChunk " + pos + " " + isLighted));
-        return CompletableFuture.supplyAsync(() -> {
-            chunk.setLightCorrect(true);
-            return chunk;
-        }, task -> this.addTask(pos.x, pos.z, ThreadedLevelLightEngine.TaskType.POST_UPDATE, task));
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     public void tryScheduleUpdate() {
-        if ((!this.lightTasks.isEmpty() || super.hasLightWork()) && this.scheduled.compareAndSet(false, true)) {
-            this.consecutiveExecutor.schedule(() -> {
-                this.runUpdate();
-                this.scheduled.set(false);
-            });
-        }
+        // Paper - rewrite chunk system
     }
 
     private void runUpdate() {
-        int min = Math.min(this.lightTasks.size(), 1000);
-        ObjectListIterator<Pair<ThreadedLevelLightEngine.TaskType, Runnable>> objectListIterator = this.lightTasks.iterator();
-
-        int i;
-        for (i = 0; objectListIterator.hasNext() && i < min; i++) {
-            Pair<ThreadedLevelLightEngine.TaskType, Runnable> pair = objectListIterator.next();
-            if (pair.getFirst() == ThreadedLevelLightEngine.TaskType.PRE_UPDATE) {
-                pair.getSecond().run();
-            }
-        }
-
-        objectListIterator.back(i);
-        super.runLightUpdates();
-
-        for (int var5 = 0; objectListIterator.hasNext() && var5 < min; var5++) {
-            Pair<ThreadedLevelLightEngine.TaskType, Runnable> pair = objectListIterator.next();
-            if (pair.getFirst() == ThreadedLevelLightEngine.TaskType.POST_UPDATE) {
-                pair.getSecond().run();
-            }
-
-            objectListIterator.remove();
-        }
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     public CompletableFuture<?> waitForPendingTasks(int x, int z) {
-        return CompletableFuture.runAsync(() -> {}, task -> this.addTask(x, z, ThreadedLevelLightEngine.TaskType.POST_UPDATE, task));
+        throw new UnsupportedOperationException(); // Paper - rewrite chunk system
     }
 
     static enum TaskType {
