From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <spottedleaf@spottedleaf.dev>
Date: Mon, 18 May 2020 00:30:48 -0700
Subject: [PATCH] Improve async tp to not load chunks when crossing worlds

Fixes an issue where a getCubes call would load neighbouring chunks.
Loads less chunks than paper's implementation

diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 2fc101869775711533a1e50f9ae608cd74d36d3a..2af3bee540ee25ea32a7548fd0d64dea16a0a268 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -509,27 +509,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
         entity.setHeadRotation(yaw);
     }
 
-    @Override// Paper start
-    public java.util.concurrent.CompletableFuture<Boolean> teleportAsync(Location loc, @javax.annotation.Nonnull org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause) {
-        net.minecraft.server.PlayerChunkMap playerChunkMap = ((CraftWorld) loc.getWorld()).getHandle().getChunkProvider().playerChunkMap;
-        java.util.concurrent.CompletableFuture<Boolean> future = new java.util.concurrent.CompletableFuture<>();
-
-        loc.getWorld().getChunkAtAsyncUrgently(loc).thenCompose(chunk -> {
-            net.minecraft.server.ChunkCoordIntPair pair = new net.minecraft.server.ChunkCoordIntPair(chunk.getX(), chunk.getZ());
-            ((CraftWorld) loc.getWorld()).getHandle().getChunkProvider().addTicketAtLevel(net.minecraft.server.TicketType.POST_TELEPORT, pair, 31, 0);
-            net.minecraft.server.PlayerChunk updatingChunk = playerChunkMap.getUpdatingChunk(pair.pair());
-            if (updatingChunk != null) {
-                return updatingChunk.getEntityTickingFuture();
-            } else {
-                return java.util.concurrent.CompletableFuture.completedFuture(com.mojang.datafixers.util.Either.left(((org.bukkit.craftbukkit.CraftChunk)chunk).getHandle()));
-            }
-        }).thenAccept((chunk) -> future.complete(teleport(loc, cause))).exceptionally(ex -> {
-            future.completeExceptionally(ex);
-            return null;
-        });
-        return future;
-    }
-    // Paper end
+    // Tuinity
 
     @Override
     public boolean teleport(Location location) {
@@ -563,6 +543,37 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
         return true;
     }
 
+    // Tuinity start - implement teleportAsync better
+    @Override
+    public java.util.concurrent.CompletableFuture<Boolean> teleportAsync(Location location, TeleportCause cause) {
+        Preconditions.checkArgument(location != null, "location");
+        location.checkFinite();
+        Location locationClone = location.clone(); // clone so we don't need to worry about mutations after this call.
+
+        net.minecraft.server.WorldServer world = ((CraftWorld)locationClone.getWorld()).getHandle();
+        java.util.concurrent.CompletableFuture<Boolean> ret = new java.util.concurrent.CompletableFuture<>();
+
+        world.loadChunksForMoveAsync(getHandle().getBoundingBoxAt(locationClone.getX(), locationClone.getY(), locationClone.getZ()), location.getX(), location.getZ(), (list) -> {
+            net.minecraft.server.ChunkProviderServer chunkProviderServer = world.getChunkProvider();
+            for (net.minecraft.server.IChunkAccess chunk : list) {
+                chunkProviderServer.addTicketAtLevel(net.minecraft.server.TicketType.POST_TELEPORT, chunk.getPos(), 33, CraftEntity.this.getEntityId());
+            }
+            net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> {
+                try {
+                    ret.complete(CraftEntity.this.teleport(locationClone, cause) ? Boolean.TRUE : Boolean.FALSE);
+                } catch (Throwable throwable) {
+                    if (throwable instanceof ThreadDeath) {
+                        throw (ThreadDeath)throwable;
+                    }
+                    ret.completeExceptionally(throwable);
+                }
+            });
+        });
+
+        return ret;
+    }
+    // Tuinity end - implement teleportAsync better
+
     @Override
     public boolean teleport(org.bukkit.entity.Entity destination) {
         return teleport(destination.getLocation());
