--- a/net/minecraft/world/level/dimension/end/EndDragonFight.java
+++ b/net/minecraft/world/level/dimension/end/EndDragonFight.java
@@ -77,7 +_,7 @@
         .setPlayBossMusic(true)
         .setCreateWorldFog(true);
     public final ServerLevel level;
-    private final BlockPos origin;
+    public final BlockPos origin; // Folia - region threading
     public final ObjectArrayList<Integer> gateways = new ObjectArrayList<>();
     private final BlockPattern exitPortalPattern;
     private int ticksSinceDragonSeen;
@@ -162,7 +_,7 @@
 
         if (!this.dragonEvent.getPlayers().isEmpty()) {
             this.level.getChunkSource().addRegionTicket(TicketType.DRAGON, new ChunkPos(0, 0), 9, Unit.INSTANCE);
-            boolean isArenaLoaded = this.isArenaLoaded();
+            boolean isArenaLoaded = this.isArenaLoaded(); if (!isArenaLoaded) { return; } // Folia - region threading - don't tick if we don't own the entire region
             if (this.needsStateScanning && isArenaLoaded) {
                 this.scanState();
                 this.needsStateScanning = false;
@@ -208,6 +_,12 @@
         }
 
         List<? extends EnderDragon> dragons = this.level.getDragons();
+        // Folia start - region threading
+        // we do not want to deal with any dragons NOT nearby
+        dragons.removeIf((EnderDragon dragon) -> {
+            return !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(dragon);
+        });
+        // Folia end - region threading
         if (dragons.isEmpty()) {
             this.dragonKilled = true;
         } else {
@@ -323,8 +_,8 @@
 
             for (int i = -8 + chunkPos.x; i <= 8 + chunkPos.x; i++) {
                 for (int i1 = 8 + chunkPos.z; i1 <= 8 + chunkPos.z; i1++) {
-                    ChunkAccess chunk = this.level.getChunk(i, i1, ChunkStatus.FULL, false);
-                    if (!(chunk instanceof LevelChunk)) {
+                    ChunkAccess chunk = this.level.getChunkIfLoaded(i, i1); // Folia - region threading
+                    if (!(chunk instanceof LevelChunk) || !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.level, i, i1, this.level.regioniser.regionSectionChunkSize)) {
                         return false;
                     }
 
@@ -496,6 +_,11 @@
     }
 
     public void onCrystalDestroyed(EndCrystal crystal, DamageSource dmgSrc) {
+        // Folia start - region threading
+        if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.level, this.origin)) {
+            return;
+        }
+        // Folia end - region threading
         if (this.respawnStage != null && this.respawnCrystals.contains(crystal)) {
             LOGGER.debug("Aborting respawn sequence");
             this.respawnStage = null;
@@ -521,7 +_,7 @@
 
     public boolean tryRespawn(@Nullable BlockPos placedEndCrystalPos) { // placedEndCrystalPos is null if the tryRespawn() call was not caused by a placed end crystal
         // Paper end - Perf: Do crystal-portal proximity check before entity lookup
-        if (this.dragonKilled && this.respawnStage == null) {
+        if (this.dragonKilled && this.respawnStage == null && ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.level, this.origin)) { // Folia - region threading
             BlockPos blockPos = this.portalLocation;
             if (blockPos == null) {
                 LOGGER.debug("Tried to respawn, but need to find the portal first.");
