From a86a5de8c3abe55e7728f8469e7c6879e367f496 Mon Sep 17 00:00:00 2001
From: EpicKnarvik97 <kristian.knarvik@knett.no>
Date: Fri, 10 Sep 2021 21:32:58 +0200
Subject: [PATCH] Fixes the bug with teleporting horses, but introduces a bug
 with teleporting minecarts

---
 .../listener/PlayerEventListener.java         | 86 +++++++++++++------
 .../listener/VehicleEventListener.java        | 13 ---
 .../net/knarcraft/stargate/portal/Portal.java | 23 ++---
 3 files changed, 73 insertions(+), 49 deletions(-)

diff --git a/src/main/java/net/knarcraft/stargate/listener/PlayerEventListener.java b/src/main/java/net/knarcraft/stargate/listener/PlayerEventListener.java
index 298464a..e0f60f1 100644
--- a/src/main/java/net/knarcraft/stargate/listener/PlayerEventListener.java
+++ b/src/main/java/net/knarcraft/stargate/listener/PlayerEventListener.java
@@ -11,15 +11,17 @@ import org.bukkit.GameMode;
 import org.bukkit.World;
 import org.bukkit.block.Block;
 import org.bukkit.block.data.type.WallSign;
+import org.bukkit.entity.AbstractHorse;
 import org.bukkit.entity.Boat;
 import org.bukkit.entity.Entity;
-import org.bukkit.entity.Minecart;
 import org.bukkit.entity.Player;
 import org.bukkit.entity.Vehicle;
+import org.bukkit.entity.minecart.RideableMinecart;
 import org.bukkit.event.Event;
 import org.bukkit.event.EventHandler;
 import org.bukkit.event.Listener;
 import org.bukkit.event.block.Action;
+import org.bukkit.event.entity.EntityTeleportEvent;
 import org.bukkit.event.player.PlayerInteractEvent;
 import org.bukkit.event.player.PlayerJoinEvent;
 import org.bukkit.event.player.PlayerMoveEvent;
@@ -80,20 +82,15 @@ public class PlayerEventListener implements Listener {
                 && PortalHandler.getByAdjacentEntrance(event.getFrom()) != null) {
             event.setCancelled(true);
         }
-        if (event.isCancelled() || cause != PlayerTeleportEvent.TeleportCause.PLUGIN) {
-            return;
-        }
+    }
 
-        Entity playerVehicle = event.getPlayer().getVehicle();
-        Portal portal = PortalHandler.getByAdjacentEntrance(event.getFrom());
-        if (playerVehicle != null && portal != null &&
-                !(playerVehicle instanceof Minecart) &&
-                !(playerVehicle instanceof Boat)) {
-            Portal destinationPortal = portal.getDestination();
-            if (destinationPortal != null) {
-                VehicleEventListener.teleportVehicleAfterPlayer((Vehicle) playerVehicle, destinationPortal,
-                        event.getPlayer(), portal);
-            }
+    @EventHandler
+    public void onEntityTeleport(EntityTeleportEvent event) {
+        //Prevent any entities from teleporting through stargates
+        Portal entryPortal = PortalHandler.getByAdjacentEntrance(event.getFrom());
+        Portal exitPortal = PortalHandler.getByAdjacentEntrance(event.getTo());
+        if (!event.isCancelled() && entryPortal != null && exitPortal != null && exitPortal == entryPortal.getDestination()) {
+            event.setCancelled(true);
         }
     }
 
@@ -108,34 +105,73 @@ public class PlayerEventListener implements Listener {
             return;
         }
 
-        //Check to see if the player moved to another block
         BlockLocation fromLocation = new BlockLocation(event.getFrom().getBlock());
         BlockLocation toLocation = new BlockLocation(event.getTo().getBlock());
-        if (fromLocation.equals(toLocation)) {
+        Player player = event.getPlayer();
+
+        //Check whether the event needs to be considered
+        if (!isRelevantMoveEvent(event, player, fromLocation, toLocation)) {
             return;
         }
+        Portal entrancePortal = PortalHandler.getByEntrance(toLocation);
+        Portal destination = entrancePortal.getDestination(player);
 
-        Player player = event.getPlayer();
+        //Teleport the vehicle to the player
+        Entity playerVehicle = player.getVehicle();
+        if (playerVehicle != null && !(playerVehicle instanceof Boat) && !(playerVehicle instanceof RideableMinecart)) {
+
+            //Make sure the horse can be sat on
+            if (playerVehicle instanceof AbstractHorse) {
+                AbstractHorse horse = ((AbstractHorse) playerVehicle);
+                if (!horse.isTamed()) {
+                    horse.setOwner(player);
+                }
+            }
+            destination.teleport((Vehicle) playerVehicle, entrancePortal);
+        } else {
+            destination.teleport(player, entrancePortal, event);
+        }
+        Stargate.sendMessage(player, Stargate.getString("teleportMsg"), false);
+        entrancePortal.close(false);
+    }
+
+    /**
+     * Checks whether a player move event is relevant for this plugin
+     * @param event <p>The player move event to check</p>
+     * @param player <p>The player which moved</p>
+     * @param fromLocation <p>The location the player is moving from</p>
+     * @param toLocation <p>The location the player is moving to</p>
+     * @return <p>True if the event is relevant</p>
+     */
+    private boolean isRelevantMoveEvent(PlayerMoveEvent event, Player player, BlockLocation fromLocation, BlockLocation toLocation) {
+        //Check to see if the player moved to another block
+        if (fromLocation.equals(toLocation)) {
+            return false;
+        }
+
+        //Check if the player moved from a portal
         Portal entrancePortal = PortalHandler.getByEntrance(toLocation);
         if (entrancePortal == null) {
-            return;
+            return false;
         }
 
         Portal destination = entrancePortal.getDestination(player);
 
         //Decide if the anything stops the player from teleport
         if (!playerCanTeleport(entrancePortal, destination, player, event)) {
-            return;
+            return false;
         }
 
-        Stargate.sendMessage(player, Stargate.getString("teleportMsg"), false);
-
         //Decide if the user should be teleported to another bungee server
-        if (entrancePortal.isBungee() && bungeeTeleport(player, entrancePortal, event)) {
-            return;
+        if (entrancePortal.isBungee()) {
+            if (bungeeTeleport(player, entrancePortal, event)) {
+                Stargate.sendMessage(player, Stargate.getString("teleportMsg"), false);
+                return true;
+            } else {
+                return false;
+            }
         }
-        destination.teleport(player, entrancePortal, event);
-        entrancePortal.close(false);
+        return true;
     }
 
     /**
diff --git a/src/main/java/net/knarcraft/stargate/listener/VehicleEventListener.java b/src/main/java/net/knarcraft/stargate/listener/VehicleEventListener.java
index 8ab5b3a..6154b97 100644
--- a/src/main/java/net/knarcraft/stargate/listener/VehicleEventListener.java
+++ b/src/main/java/net/knarcraft/stargate/listener/VehicleEventListener.java
@@ -20,19 +20,6 @@ import java.util.List;
 @SuppressWarnings("unused")
 public class VehicleEventListener implements Listener {
 
-    /**
-     * If the player teleported, but its vehicle was left behind, make the vehicle teleport to the player
-     *
-     * @param vehicle <p>The vehicle to teleport</p>
-     * @param destinationPortal <p>The portal the player teleported to</p>
-     * @param player <p>The player who teleported</p>
-     * @param origin <p>The portal the player entered</p>
-     */
-    public static void teleportVehicleAfterPlayer(Vehicle vehicle, Portal destinationPortal, Player player, Portal origin) {
-        destinationPortal.teleport(vehicle, origin);
-        Stargate.server.getScheduler().scheduleSyncDelayedTask(Stargate.stargate, () -> vehicle.addPassenger(player), 6);
-    }
-
     /**
      * Check for a vehicle moving through a portal
      *
diff --git a/src/main/java/net/knarcraft/stargate/portal/Portal.java b/src/main/java/net/knarcraft/stargate/portal/Portal.java
index ba44784..ee3c2c6 100644
--- a/src/main/java/net/knarcraft/stargate/portal/Portal.java
+++ b/src/main/java/net/knarcraft/stargate/portal/Portal.java
@@ -699,7 +699,7 @@ public class Portal {
      * Teleports a vehicle to this portal
      *
      * @param vehicle <p>The vehicle to teleport</p>
-     * @param origin <p>The portal the vehicle entered</p>
+     * @param origin  <p>The portal the vehicle entered</p>
      */
     public void teleport(final Vehicle vehicle, Portal origin) {
         Location traveller = vehicle.getLocation();
@@ -734,7 +734,8 @@ public class Portal {
             }
         } else {
             vehicle.teleport(exit);
-            Stargate.server.getScheduler().scheduleSyncDelayedTask(Stargate.stargate, () -> vehicle.setVelocity(newVelocity), 1);
+            Stargate.server.getScheduler().scheduleSyncDelayedTask(Stargate.stargate,
+                    () -> vehicle.setVelocity(newVelocity), 1);
         }
     }
 
@@ -748,7 +749,7 @@ public class Portal {
     private void teleportLivingVehicle(Vehicle vehicle, Location exit, List<Entity> passengers) {
         vehicle.eject();
         vehicle.teleport(exit);
-        handleVehiclePassengers(passengers, vehicle, exit);
+        handleVehiclePassengers(passengers, vehicle);
     }
 
     /**
@@ -766,7 +767,7 @@ public class Portal {
         vehicle.eject();
         vehicle.remove();
         vehicle.setRotation(exit.getYaw(), exit.getPitch());
-        handleVehiclePassengers(passengers, newVehicle, exit);
+        handleVehiclePassengers(passengers, newVehicle);
         Stargate.server.getScheduler().scheduleSyncDelayedTask(Stargate.stargate, () -> newVehicle.setVelocity(newVelocity), 1);
     }
 
@@ -775,16 +776,16 @@ public class Portal {
      *
      * @param passengers    <p>The passengers to handle</p>
      * @param targetVehicle <p>The vehicle the passengers should be put into</p>
-     * @param exit          <p>The exit location to teleport the passengers to</p>
      */
-    private void handleVehiclePassengers(List<Entity> passengers, Vehicle targetVehicle, Location exit) {
+    private void handleVehiclePassengers(List<Entity> passengers, Vehicle targetVehicle) {
         for (Entity passenger : passengers) {
             passenger.eject();
             //TODO: Fix random java.lang.IllegalStateException: Removing entity while ticking!
-            if (!passenger.teleport(exit)) {
+            if (!passenger.teleport(targetVehicle.getLocation())) {
                 Stargate.debug("handleVehiclePassengers", "Failed to teleport passenger");
             }
-            Stargate.server.getScheduler().scheduleSyncDelayedTask(Stargate.stargate, () -> targetVehicle.addPassenger(passenger), 1);
+            Stargate.server.getScheduler().scheduleSyncDelayedTask(Stargate.stargate,
+                    () -> targetVehicle.addPassenger(passenger), 6);
         }
     }
 
@@ -823,7 +824,7 @@ public class Portal {
      *
      * @param relativeExit <p>The relative exit defined as the portal's exit</p>
      * @param exitLocation <p>The currently calculated portal exit</p>
-     * @param entity <p>The travelling entity</p>
+     * @param entity       <p>The travelling entity</p>
      * @return <p>A location which won't suffocate the entity inside the portal</p>
      */
     private Location preventExitSuffocation(RelativeBlockVector relativeExit, Location exitLocation, Entity entity) {
@@ -862,7 +863,7 @@ public class Portal {
      * Gets one of the edges of a portal's opening/exit
      *
      * @param relativeExit <p>The known exit to start from</p>
-     * @param direction <p>The direction to move (+1 for right, -1 for left)</p>
+     * @param direction    <p>The direction to move (+1 for right, -1 for left)</p>
      * @return <p>The right or left edge of the opening</p>
      */
     private RelativeBlockVector getPortalExitEdge(RelativeBlockVector relativeExit, int direction) {
@@ -882,7 +883,7 @@ public class Portal {
     /**
      * Adjusts an exit location with rotation and slab height incrementation
      *
-     * @param traveller <p>The location of the travelling entity</p>
+     * @param traveller    <p>The location of the travelling entity</p>
      * @param exitLocation <p>The exit location generated</p>
      * @return <p>The location the travelling entity should be teleported to</p>
      */