diff --git a/paper-api/src/main/java/io/papermc/paper/event/player/PlayerPreTeleportEvent.java b/paper-api/src/main/java/io/papermc/paper/event/player/PlayerPreTeleportEvent.java new file mode 100644 index 000000000000..34ba5e2307bf --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/event/player/PlayerPreTeleportEvent.java @@ -0,0 +1,96 @@ +package io.papermc.paper.event.player; + +import io.papermc.paper.entity.TeleportFlag; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +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.NotNull; +import org.jspecify.annotations.NullMarked; +import java.util.Set; + +/** + * Event that is fired before attempting to teleport the player (Allows for pre-teleport handling, such as dismounting passengers if teleporting cross-worlds etc.) + * After the handling of this event, the player teleport will either proceed or cancel. + */ +@NullMarked +public class PlayerPreTeleportEvent extends PlayerEvent implements Cancellable { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private Location to; + private PlayerTeleportEvent.TeleportCause cause; + private Set allFlags; + + private boolean cancelled; + + @ApiStatus.Internal + public PlayerPreTeleportEvent(@NotNull Player player, @NotNull Location to, @NotNull PlayerTeleportEvent.TeleportCause cause, @NotNull Set allFlags) { + super(player); + this.to = to; + this.cause = cause; + this.allFlags = allFlags; + } + + /** + * Updates the destination location of the teleport + */ + public void setTo(Location location) { + this.to = location; + } + + /** + * The current location of the player (pre teleporting) + * @return the current location of the player + */ + public Location getFrom() { + return getPlayer().getLocation(); + } + + /** + * The location the player will be teleported to (if this event is not cancelled) {@link Location} + * @return the destination location the player will be teleported to + */ + public Location getTo() { + return this.to; + } + + /** + * The cause of the teleportation {@link PlayerTeleportEvent.TeleportCause} + * @return the cause for the teleportation (What causes this to trigger) + */ + public PlayerTeleportEvent.TeleportCause getCause() { + return this.cause; + } + + /** + * The teleport flags associated with this teleport {@link TeleportFlag} + * @return associated teleport flags + */ + public Set getFlags() { + return this.allFlags; + } + + @Override + public boolean isCancelled() { + return false; + } + + @Override + public void setCancelled(final boolean cancel) { + this.cancelled = cancel; + } + + @Override + public @NotNull 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 d4183bd69358..a67c34d0fa9a 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 @@ -15,6 +15,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.PlayerPreTeleportEvent; import io.papermc.paper.math.Position; import io.papermc.paper.util.MCUtil; import it.unimi.dsi.fastutil.shorts.ShortArraySet; @@ -1477,6 +1478,21 @@ public boolean teleport(Location location, org.bukkit.event.player.PlayerTelepor allFlags.add(flag); } } + + // Paper start - Add PlayerPreTeleportEvent + // Create & Call the PlayerPreTeleportEvent. + PlayerPreTeleportEvent preTeleportEvent = new PlayerPreTeleportEvent(this, location, cause, allFlags); // Paper - PreTeleport API + this.server.getPluginManager().callEvent(preTeleportEvent); + // Return False to inform the Plugin that the teleport was intercepted and the teleport should not proceed + if (preTeleportEvent.isCancelled()) { + return false; + } + // Updates the teleport location if the destination was changed in the PreTeleport event + if (!preTeleportEvent.getTo().equals(location)) { + location = preTeleportEvent.getTo(); + } + // Paper end - Add PlayerPreTeleportEvent + boolean dismount = !allFlags.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_VEHICLE); boolean ignorePassengers = allFlags.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_PASSENGERS); // Paper end - Teleport API