diff --git a/Spigot-API-Patches/EntityMoveEvent.patch b/Spigot-API-Patches/EntityMoveEvent.patch
new file mode 100644
index 0000000000..6d323ee255
--- /dev/null
+++ b/Spigot-API-Patches/EntityMoveEvent.patch
@@ -0,0 +1,107 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: William Blake Galbreath <Blake.Galbreath@GMail.com>
+Date: Tue, 11 Feb 2020 21:56:38 -0600
+Subject: [PATCH] EntityMoveEvent
+
+
+diff --git a/src/main/java/io/papermc/paper/event/entity/EntityMoveEvent.java b/src/main/java/io/papermc/paper/event/entity/EntityMoveEvent.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/event/entity/EntityMoveEvent.java
+@@ -0,0 +0,0 @@
++package io.papermc.paper.event.entity;
++
++import com.google.common.base.Preconditions;
++import org.bukkit.Location;
++import org.bukkit.entity.LivingEntity;
++import org.bukkit.event.Cancellable;
++import org.bukkit.event.HandlerList;
++import org.bukkit.event.entity.EntityEvent;
++import org.jetbrains.annotations.NotNull;
++
++/**
++ * Holds information for living entity movement events
++ */
++public class EntityMoveEvent extends EntityEvent implements Cancellable {
++    private static final HandlerList handlers = new HandlerList();
++    private boolean canceled;
++    private Location from;
++    private Location to;
++
++    public EntityMoveEvent(@NotNull LivingEntity entity, @NotNull Location from, @NotNull Location to) {
++        super(entity);
++        this.from = from;
++        this.to = to;
++    }
++
++    @Override
++    @NotNull
++    public LivingEntity getEntity() {
++        return (LivingEntity) entity;
++    }
++
++    public boolean isCancelled() {
++        return canceled;
++    }
++
++    public void setCancelled(boolean cancel) {
++        canceled = cancel;
++    }
++
++    /**
++     * Gets the location this entity moved from
++     *
++     * @return Location the entity moved from
++     */
++    @NotNull
++    public Location getFrom() {
++        return from;
++    }
++
++    /**
++     * Sets the location to mark as where the entity moved from
++     *
++     * @param from New location to mark as the entity's previous location
++     */
++    public void setFrom(@NotNull Location from) {
++        validateLocation(from);
++        this.from = from;
++    }
++
++    /**
++     * Gets the location this entity moved to
++     *
++     * @return Location the entity moved to
++     */
++    @NotNull
++    public Location getTo() {
++        return to;
++    }
++
++    /**
++     * Sets the location that this entity will move to
++     *
++     * @param to New Location this entity will move to
++     */
++    public void setTo(@NotNull Location to) {
++        validateLocation(to);
++        this.to = to;
++    }
++
++    private void validateLocation(@NotNull Location loc) {
++        Preconditions.checkArgument(loc != null, "Cannot use null location!");
++        Preconditions.checkArgument(loc.getWorld() != null, "Cannot use null location with null world!");
++    }
++
++    @Override
++    @NotNull
++    public HandlerList getHandlers() {
++        return handlers;
++    }
++
++    @NotNull
++    public static HandlerList getHandlerList() {
++        return handlers;
++    }
++}
diff --git a/Spigot-Server-Patches/EntityMoveEvent.patch b/Spigot-Server-Patches/EntityMoveEvent.patch
new file mode 100644
index 0000000000..3d71671458
--- /dev/null
+++ b/Spigot-Server-Patches/EntityMoveEvent.patch
@@ -0,0 +1,71 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: William Blake Galbreath <Blake.Galbreath@GMail.com>
+Date: Tue, 11 Feb 2020 21:56:48 -0600
+Subject: [PATCH] EntityMoveEvent
+
+
+diff --git a/src/main/java/net/minecraft/server/EntityLiving.java b/src/main/java/net/minecraft/server/EntityLiving.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/main/java/net/minecraft/server/EntityLiving.java
++++ b/src/main/java/net/minecraft/server/EntityLiving.java
+@@ -0,0 +0,0 @@ import com.mojang.datafixers.util.Pair;
+ import com.mojang.serialization.DataResult;
+ import com.mojang.serialization.Dynamic;
+ import com.mojang.serialization.DynamicOps;
++import io.papermc.paper.event.entity.EntityMoveEvent;
+ import java.util.Collection;
+ import java.util.ConcurrentModificationException;
+ import java.util.Iterator;
+@@ -0,0 +0,0 @@ public abstract class EntityLiving extends Entity {
+ 
+         this.collideNearby();
+         this.world.getMethodProfiler().exit();
++        // Paper start
++        if (((WorldServer) world).hasEntityMoveEvent) {
++            if (lastX != locX() || lastY != locY() || lastZ != locZ() || lastYaw != yaw || lastPitch != pitch) {
++                Location from = new Location(world.getWorld(), lastX, lastY, lastZ, lastYaw, lastPitch);
++                Location to = new Location (world.getWorld(), locX(), locY(), locZ(), yaw, pitch);
++                EntityMoveEvent event = new EntityMoveEvent(getBukkitLivingEntity(), from, to.clone());
++                if (!event.callEvent()) {
++                    setLocation(from.getX(), from.getY(), from.getZ(), from.getYaw(), from.getPitch());
++                } else if (!to.equals(event.getTo())) {
++                    setLocation(event.getTo().getX(), event.getTo().getY(), event.getTo().getZ(), event.getTo().getYaw(), event.getTo().getPitch());
++                }
++            }
++        }
++        // Paper end
+         if (!this.world.isClientSide && this.dO() && this.aG()) {
+             this.damageEntity(DamageSource.DROWN, 1.0F);
+         }
+diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/main/java/net/minecraft/server/MinecraftServer.java
++++ b/src/main/java/net/minecraft/server/MinecraftServer.java
+@@ -0,0 +0,0 @@ import com.mojang.serialization.Lifecycle;
+ import io.netty.buffer.ByteBuf;
+ import io.netty.buffer.ByteBufOutputStream;
+ import io.netty.buffer.Unpooled;
++import io.papermc.paper.event.entity.EntityMoveEvent;
+ import it.unimi.dsi.fastutil.longs.LongIterator;
+ import java.awt.image.BufferedImage;
+ import java.io.BufferedWriter;
+@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
+         while (iterator.hasNext()) {
+             WorldServer worldserver = (WorldServer) iterator.next();
+             worldserver.hasPhysicsEvent =  org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper
++            worldserver.hasEntityMoveEvent =  EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper
+             TileEntityHopper.skipHopperEvents = worldserver.paperConfig.disableHopperMoveEvents || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper
+ 
+             this.methodProfiler.a(() -> {
+diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
+index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
+--- a/src/main/java/net/minecraft/server/WorldServer.java
++++ b/src/main/java/net/minecraft/server/WorldServer.java
+@@ -0,0 +0,0 @@ public class WorldServer extends World implements GeneratorAccessSeed {
+     public final Convertable.ConversionSession convertable;
+     public final UUID uuid;
+     boolean hasPhysicsEvent = true; // Paper
++    boolean hasEntityMoveEvent = false; // Paper
+     private static Throwable getAddToWorldStackTrace(Entity entity) {
+         return new Throwable(entity + " Added to world at " + new java.util.Date());
+     }