From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 25 Aug 2020 20:45:36 -0400
Subject: [PATCH] Fix Entity Teleportation and cancel velocity if teleported

Uses correct setPositionRotation for Entity teleporting instead of setLocation
as this is how Vanilla teleports entities.

Cancel any pending motion when teleported.

diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 82ef4b4f99216eee00c867565d55e133bf7d8bcb..9d073564faa0f8dbd46ea6f9590a8260368fcbb0 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -689,7 +689,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
     public void handleAcceptTeleportPacket(ServerboundAcceptTeleportationPacket packet) {
         PacketUtils.ensureRunningOnSameThread(packet, this, this.player.getLevel());
         if (packet.getId() == this.awaitingTeleport && this.awaitingPositionFromClient != null) { // CraftBukkit
-            this.player.absMoveTo(this.awaitingPositionFromClient.x, this.awaitingPositionFromClient.y, this.awaitingPositionFromClient.z, this.player.getYRot(), this.player.getXRot());
+            this.player.moveTo(this.awaitingPositionFromClient.x, this.awaitingPositionFromClient.y, this.awaitingPositionFromClient.z, this.player.getYRot(), this.player.getXRot()); // Paper - use proper setPositionRotation for teleportation
             this.lastGoodX = this.awaitingPositionFromClient.x;
             this.lastGoodY = this.awaitingPositionFromClient.y;
             this.lastGoodZ = this.awaitingPositionFromClient.z;
@@ -1573,7 +1573,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
         // CraftBukkit end
 
         this.awaitingTeleportTime = this.tickCount;
-        this.player.absMoveTo(d0, d1, d2, f, f1);
+        this.player.moveTo(d0, d1, d2, f, f1); // Paper - use proper setPositionRotation for teleportation
         this.player.connection.send(new ClientboundPlayerPositionPacket(d0 - d3, d1 - d4, d2 - d5, f - f2, f1 - f3, set, this.awaitingTeleport, flag));
     }
 
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 731cd8167eed50ac066734e97d3670df363a67d7..1412f0dc93a417b41e8f8c615c44a8eeb70dc133 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -154,6 +154,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
 
     // CraftBukkit start
     private static final int CURRENT_LEVEL = 2;
+    public boolean preserveMotion = true; // Paper - keep initial motion on first setPositionRotation
     static boolean isLevelAtLeast(CompoundTag tag, int level) {
         return tag.contains("Bukkit.updateLevel") && tag.getInt("Bukkit.updateLevel") >= level;
     }
@@ -1567,6 +1568,13 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
     }
 
     public void moveTo(double x, double y, double z, float yaw, float pitch) {
+        // Paper - cancel entity velocity if teleported
+        if (!preserveMotion) {
+            this.deltaMovement = Vec3.ZERO;
+        } else {
+            this.preserveMotion = false;
+        }
+        // Paper end
         this.setPosRaw(x, y, z);
         this.setYRot(yaw);
         this.setXRot(pitch);
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
index 70e1f9bd9e4711aaf45ff8b7214726de646997ab..4bfebbb2e87464cd47a38a5da6275b2c662fa052 100644
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
@@ -161,6 +161,7 @@ public abstract class BaseSpawner {
                             return;
                         }
 
+                        entity.preserveMotion = true; // Paper - preserve entity motion from tag
                         entity.moveTo(entity.getX(), entity.getY(), entity.getZ(), world.random.nextFloat() * 360.0F, 0.0F);
                         if (entity instanceof Mob) {
                             Mob entityinsentient = (Mob) entity;
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 1f2503748e0534d48db558d09997683d563b649c..8ec7cd4ea41c28c1f730df649b7cf73d57d60b55 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -579,7 +579,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
         }
 
         // entity.setLocation() throws no event, and so cannot be cancelled
-        this.entity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
+        entity.moveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); // Paper - use proper setPosition, as per vanilla teleporting
         // SPIGOT-619: Force sync head rotation also
         this.entity.setYHeadRot(location.getYaw());
 
