--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkTaskScheduler.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkTaskScheduler.java
@@ -122,7 +_,7 @@
     public final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor compressionExecutor;
     public final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor saveExecutor;
 
-    private final PrioritisedTaskQueue mainThreadExecutor = new PrioritisedTaskQueue();
+    // Folia - regionised ticking
 
     public final ChunkHolderManager chunkHolderManager;
 
@@ -337,14 +_,13 @@
         };
 
         // this may not be good enough, specifically thanks to stupid ass plugins swallowing exceptions
-        this.scheduleChunkTask(chunkX, chunkZ, crash, Priority.BLOCKING);
+        this.scheduleChunkTaskEventually(chunkX, chunkZ, crash, Priority.BLOCKING); // Folia - region threading
         // so, make the main thread pick it up
         ((ChunkSystemMinecraftServer)this.world.getServer()).moonrise$setChunkSystemCrash(new RuntimeException("Chunk system crash propagated from unrecoverableChunkSystemFailure", reportedException));
     }
 
     public boolean executeMainThreadTask() {
-        TickThread.ensureTickThread("Cannot execute main thread task off-main");
-        return this.mainThreadExecutor.executeTask();
+        throw new UnsupportedOperationException("Use regionised ticking hooks"); // Folia - regionised ticking
     }
 
     public void raisePriority(final int x, final int z, final Priority priority) {
@@ -829,7 +_,7 @@
      */
     @Deprecated
     public PrioritisedExecutor.PrioritisedTask scheduleChunkTask(final Runnable run, final Priority priority) {
-        return this.mainThreadExecutor.queueTask(run, priority);
+        throw new UnsupportedOperationException(); // Folia - regionised ticking
     }
 
     public PrioritisedExecutor.PrioritisedTask createChunkTask(final int chunkX, final int chunkZ, final Runnable run) {
@@ -838,7 +_,7 @@
 
     public PrioritisedExecutor.PrioritisedTask createChunkTask(final int chunkX, final int chunkZ, final Runnable run,
                                                                final Priority priority) {
-        return this.mainThreadExecutor.createTask(run, priority);
+        return io.papermc.paper.threadedregions.RegionizedServer.getInstance().taskQueue.createChunkTask(this.world, chunkX, chunkZ, run, priority); // Folia - regionised ticking
     }
 
     public PrioritisedExecutor.PrioritisedTask scheduleChunkTask(final int chunkX, final int chunkZ, final Runnable run) {
@@ -847,8 +_,26 @@
 
     public PrioritisedExecutor.PrioritisedTask scheduleChunkTask(final int chunkX, final int chunkZ, final Runnable run,
                                                                  final Priority priority) {
-        return this.mainThreadExecutor.queueTask(run, priority);
-    }
+        return io.papermc.paper.threadedregions.RegionizedServer.getInstance().taskQueue.queueChunkTask(this.world, chunkX, chunkZ, run, priority); // Folia - regionised ticking
+    }
+
+    // Folia start - region threading
+    // this function is guaranteed to never touch the ticket lock or schedule lock
+    // yes, this IS a hack so that we can avoid deadlock due to region threading introducing the
+    // ticket lock in the schedule logic
+    public PrioritisedExecutor.PrioritisedTask scheduleChunkTaskEventually(final int chunkX, final int chunkZ, final Runnable run) {
+        return this.scheduleChunkTaskEventually(chunkX, chunkZ, run, Priority.NORMAL);
+    }
+
+    public PrioritisedExecutor.PrioritisedTask scheduleChunkTaskEventually(final int chunkX, final int chunkZ, final Runnable run,
+                                                                           final Priority priority) {
+        final PrioritisedExecutor.PrioritisedTask ret = this.createChunkTask(chunkX, chunkZ, run, priority);
+        this.world.taskQueueRegionData.pushGlobalChunkTask(() -> {
+            io.papermc.paper.threadedregions.RegionizedServer.getInstance().taskQueue.queueChunkTask(ChunkTaskScheduler.this.world, chunkX, chunkZ, run, priority);
+        });
+        return ret;
+    }
+    // Folia end - region threading
 
     public boolean halt(final boolean sync, final long maxWaitNS) {
         this.radiusAwareGenExecutor.halt();
