diff --git a/paper-api/src/main/java/io/papermc/paper/event/player/PlayerPrepareTeleportEvent.java b/paper-api/src/main/java/io/papermc/paper/event/player/PlayerPrepareTeleportEvent.java new file mode 100644 index 000000000000..868d8a5054dd --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/event/player/PlayerPrepareTeleportEvent.java @@ -0,0 +1,98 @@ +package io.papermc.paper.event.player; + +import io.papermc.paper.entity.TeleportFlag; +import java.util.Collections; +import java.util.Set; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Unmodifiable; +import org.jspecify.annotations.NullMarked; + +/** + * Event that is fired before attempting to teleport a player (Allows for pre-teleport handling, such as dismounting passengers if teleporting cross-worlds etc.) + *

+ * After the handling of this event, the player will attempt to teleport to the given location. + */ +@NullMarked +public class PlayerPrepareTeleportEvent extends PlayerEvent { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private final Location to; + private final PlayerTeleportEvent.TeleportCause cause; + private final Set teleportFlags; + + @ApiStatus.Internal + public PlayerPrepareTeleportEvent(final Player player, Location to) { + super(player); + this.to = to; + this.cause = PlayerTeleportEvent.TeleportCause.PLUGIN; + this.teleportFlags = Collections.emptySet(); + } + + @ApiStatus.Internal + public PlayerPrepareTeleportEvent(final Player player, Location to, PlayerTeleportEvent.TeleportCause cause) { + super(player); + this.to = to; + this.cause = cause; + this.teleportFlags = Collections.emptySet(); + } + + @ApiStatus.Internal + public PlayerPrepareTeleportEvent(final Player player, Location to, PlayerTeleportEvent.TeleportCause cause, Set teleportFlags) { + super(player); + this.to = to; + this.cause = cause; + this.teleportFlags = Set.copyOf(teleportFlags); + } + + /** + * Gets the location this player is teleporting to + * + * @return A copy of the Location the player is teleporting to + */ + public Location getTo() { + return this.to.clone(); + } + + /** + * Gets the location this player is teleporting from + * + * @return A copy of the Location the player is moving from + */ + public Location getFrom() { + return this.getPlayer().getLocation(); + } + + /** + * Returns the relative teleportation flags used in this teleportation. + * This determines which axis the player will not lose their velocity in. + * + * @return an immutable set of relative teleportation flags + */ + public @Unmodifiable Set getRelativeTeleportationFlags() { + return this.teleportFlags; + } + + /** + * Gets the cause of this teleportation event + * + * @return Cause of the event + */ + public PlayerTeleportEvent.TeleportCause getCause() { + return this.cause; + } + + @Override + public HandlerList getHandlers() { + return HANDLER_LIST; + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } +} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index 596338c7c9b3..44bd4c4e40a2 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -18,6 +18,7 @@ import io.papermc.paper.entity.LookAnchor; import io.papermc.paper.entity.PaperPlayerGiveResult; import io.papermc.paper.entity.PlayerGiveResult; +import io.papermc.paper.event.player.PlayerPrepareTeleportEvent; import io.papermc.paper.math.Angle; import io.papermc.paper.math.Position; import io.papermc.paper.util.MCUtil; @@ -1316,6 +1317,12 @@ protected boolean teleport0(Location location, org.bukkit.event.player.PlayerTel if (this.getHandle().connection == null) { return false; } + + // Paper start - Add PlayerPrepareTeleportEvent + final PlayerPrepareTeleportEvent playerPrepareTeleportEvent = new PlayerPrepareTeleportEvent(this, location, cause, Set.of(flags)); + this.server.getPluginManager().callEvent(playerPrepareTeleportEvent); + // Paper end - Add PlayerPrepareTeleportEvent + // Minecraft does not currently support teleporting players between worlds with passengers. // It causes them to be dismounted, and causes weird behavior. if (location.getWorld() != this.getWorld() && this.getHandle().isVehicle()) {