Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restore vanilla teleportation logic for non-players #10734

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 22 Sep 2024 11:42:51 -0700
Subject: [PATCH] use vanilla logic for teleporting non-player entities

will be squashed into various patches before merge

diff --git a/src/main/java/net/minecraft/server/commands/TeleportCommand.java b/src/main/java/net/minecraft/server/commands/TeleportCommand.java
index 54851f6cc0d5fddb32a9a1e84a4f5ae41af18758..fa91f56d65c8c85256461506cd7e46e4cfd47021 100644
--- a/src/main/java/net/minecraft/server/commands/TeleportCommand.java
+++ b/src/main/java/net/minecraft/server/commands/TeleportCommand.java
@@ -161,31 +161,7 @@ public class TeleportCommand {
float f2 = Mth.wrapDegrees(yaw);
float f3 = Mth.wrapDegrees(pitch);

- // CraftBukkit start - Teleport event
- boolean result;
- if (target instanceof ServerPlayer player) {
- result = player.teleportTo(world, x, y, z, movementFlags, f2, f3, PlayerTeleportEvent.TeleportCause.COMMAND);
- } else {
- Location to = new Location(world.getWorld(), x, y, z, f2, f3);
- EntityTeleportEvent event = new EntityTeleportEvent(target.getBukkitEntity(), target.getBukkitEntity().getLocation(), to);
- world.getCraftServer().getPluginManager().callEvent(event);
- if (event.isCancelled() || event.getTo() == null) { // Paper
- return;
- }
- to = event.getTo(); // Paper - actually track new location
-
- x = to.getX();
- y = to.getY();
- z = to.getZ();
- f2 = to.getYaw();
- f3 = to.getPitch();
- world = ((CraftWorld) to.getWorld()).getHandle();
-
- result = target.teleportTo(world, x, y, z, movementFlags, f2, f3);
- }
-
- if (result) {
- // CraftBukkit end
+ if (target.teleportTo(world, x, y, z, movementFlags, f2, f3, PlayerTeleportEvent.TeleportCause.COMMAND)) { // Paper - restore vanilla logic
if (facingLocation != null) {
facingLocation.perform(source, target);
}
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index c396580a9cfd86ff261bed439bb4662ae88010b5..d3b6b609d856d5f1d6885946fc0ea6a8cca4992e 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -2127,6 +2127,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple
return this.teleportTo(world, destX, destY, destZ, flags, yaw, pitch, TeleportCause.UNKNOWN);
}

+ @Override // Paper
public boolean teleportTo(ServerLevel worldserver, double d0, double d1, double d2, Set<RelativeMovement> set, float f, float f1, TeleportCause cause) {
// CraftBukkit end
ChunkPos chunkcoordintpair = new ChunkPos(BlockPos.containing(d0, d1, d2));
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 9f68c0fda7f5526eb97619f1a35ed3b78d1b3751..3ccecc60d8c57a429d70fcb6a17c7c40220f4767 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -3758,6 +3758,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
// Paper end - Call EntityPortalExitEvent
// CraftBukkit end
ServerLevel worldserver1 = teleportTarget.newLevel();
+ if (teleportTarget.postDimensionTransition() == DimensionTransition.DONT_KEEP_PASSENGERS) this.ejectPassengers(); // Paper - eject passengers if requested
List<Entity> list = this.getPassengers();

this.unRide();
@@ -3985,6 +3986,18 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
// CraftBukkit end

public boolean teleportTo(ServerLevel world, double destX, double destY, double destZ, Set<RelativeMovement> flags, float yaw, float pitch) {
+ // Paper start - call EntityTeleportEvent
+ final org.bukkit.event.entity.EntityTeleportEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTeleportEvent(this, destX, destY, destZ, yaw, pitch);
+ if (event.isCancelled() || event.getTo() == null) {
+ return false;
+ }
+ world = ((org.bukkit.craftbukkit.CraftWorld) event.getTo().getWorld()).getHandle();
+ destX = event.getTo().getX();
+ destY = event.getTo().getY();
+ destZ = event.getTo().getZ();
+ yaw = event.getTo().getYaw();
+ pitch = event.getTo().getPitch();
+ // Paper end - call EntityTeleportEvent
float f2 = Mth.clamp(pitch, -90.0F, 90.0F);

if (world == this.level()) {
diff --git a/src/main/java/net/minecraft/world/level/portal/DimensionTransition.java b/src/main/java/net/minecraft/world/level/portal/DimensionTransition.java
index 36c8735312c885eb153f4ffdf0f2a5495e9c9f65..4b561d2aed0cf7a58ef5c24640add004c54b77df 100644
--- a/src/main/java/net/minecraft/world/level/portal/DimensionTransition.java
+++ b/src/main/java/net/minecraft/world/level/portal/DimensionTransition.java
@@ -18,6 +18,7 @@ public record DimensionTransition(ServerLevel newLevel, Vec3 pos, Vec3 speed, fl
// Paper - remove unused constructor (for safety)
// CraftBukkit end

+ public static final DimensionTransition.PostDimensionTransition DONT_KEEP_PASSENGERS = entity -> {}; // Paper - marker for dropping passengers
public static final DimensionTransition.PostDimensionTransition DO_NOTHING = (entity) -> {
};
public static final DimensionTransition.PostDimensionTransition PLAY_PORTAL_SOUND = DimensionTransition::playPortalSound;
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
index c9ecec5da937bc5458f69736b68ff6ae50aa5ebc..88b01ca62e788357f00be0a919110c063070161b 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
@@ -430,7 +430,7 @@ public abstract class CraftRegionAccessor implements RegionAccessor {
Preconditions.checkArgument(!entity.isInWorld(), "Entity has already been added to a world");
net.minecraft.world.entity.Entity nmsEntity = ((CraftEntity) entity).getHandle();
if (nmsEntity.level() != this.getHandle().getLevel()) {
- nmsEntity = nmsEntity.changeDimension(new DimensionTransition(this.getHandle().getLevel(), nmsEntity, DimensionTransition.DO_NOTHING));
+ throw new IllegalArgumentException(entity + " wasn't created with this world, you must create the entity with the world you want to add it to."); // Paper - throw instead of teleporting
}

this.addEntityWithPassengers(nmsEntity, CreatureSpawnEvent.SpawnReason.CUSTOM);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index cd789c235acf740ec29c30b180e7fbe1a140caa9..9b7e0ececf02388a014be4cb5b6524810f417e27 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -241,51 +241,26 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
location.checkFinite();
// Paper start - Teleport passenger API
Set<io.papermc.paper.entity.TeleportFlag> flagSet = Set.of(flags);
- boolean dismount = !flagSet.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_VEHICLE);
- boolean ignorePassengers = flagSet.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_PASSENGERS);
- // Don't allow teleporting between worlds while keeping passengers
- if (flagSet.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_PASSENGERS) && this.entity.isVehicle() && location.getWorld() != this.getWorld()) {
- return false;
- }
+ final boolean retainVehicle = flagSet.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_VEHICLE);
+ final boolean retainPassengers = flagSet.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_PASSENGERS);
+ final boolean sameWorld = location.getWorld() == this.getWorld();

- // Don't allow to teleport between worlds if remaining on vehicle
- if (!dismount && this.entity.isPassenger() && location.getWorld() != this.getWorld()) {
- return false;
+ if (this.entity.isPassenger() && retainVehicle) {
+ return false; // You can't teleport a passenger and keep the vehicle
}
// Paper end

- if ((!ignorePassengers && this.entity.isVehicle()) || this.entity.isRemoved()) { // Paper - Teleport passenger API
+ if (this.entity.isRemoved()) { // Paper - don't teleport if removed
return false;
}

- // Paper start - fix teleport event not being called
- org.bukkit.event.entity.EntityTeleportEvent event = new org.bukkit.event.entity.EntityTeleportEvent(
- this, this.getLocation(), location);
- // cancelling the event is handled differently for players and entities,
- // entities just stop teleporting, players will still teleport to the "from" location of the event
- if (!event.callEvent() || event.getTo() == null) {
- return false;
- }
- location = event.getTo();
- // Paper end
-
- // If this entity is riding another entity, we must dismount before teleporting.
- if (dismount) this.entity.stopRiding(); // Paper - Teleport passenger API
-
- // Let the server handle cross world teleports
- if (location.getWorld() != null && !location.getWorld().equals(this.getWorld())) {
+ if (!sameWorld) { // Paper - simplify teleportation logic
// Prevent teleportation to an other world during world generation
Preconditions.checkState(!this.entity.generation, "Cannot teleport entity to an other world during world generation");
- this.entity.changeDimension(new DimensionTransition(((CraftWorld) location.getWorld()).getHandle(), CraftLocation.toVec3D(location), Vec3.ZERO, location.getPitch(), location.getYaw(), DimensionTransition.DO_NOTHING, TeleportCause.PLUGIN));
- return true;
+ // Paper - use same teleportation logic regardless of origin/destination worlds (below)
}

- // entity.setLocation() throws no event, and so cannot be cancelled
- entity.moveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); // Paper - use proper moveTo, as per vanilla teleporting
- // SPIGOT-619: Force sync head rotation also
- this.entity.setYHeadRot(location.getYaw());
-
- return true;
+ return this.entity.changeDimension(new DimensionTransition(((CraftWorld) location.getWorld()).getHandle(), CraftLocation.toVec3D(location), Vec3.ZERO, location.getPitch(), location.getYaw(), !retainPassengers ? DimensionTransition.DONT_KEEP_PASSENGERS : DimensionTransition.DO_NOTHING, cause)) != null; // Paper - simplify teleportation logic
}

@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index 4632eb883e9f5efde520ee543bcad25827c0da2c..5e9a42d6cf9958653cff57ee62e4bc20eb2381ba 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -2096,8 +2096,13 @@ public class CraftEventFactory {
}

public static EntityTeleportEvent callEntityTeleportEvent(Entity nmsEntity, double x, double y, double z) {
+ // Paper start
+ return callEntityTeleportEvent(nmsEntity, x, y, z, nmsEntity.getYRot(), nmsEntity.getXRot());
+ }
+ public static EntityTeleportEvent callEntityTeleportEvent(Entity nmsEntity, double x, double y, double z, float yaw, float pitch) {
+ // Paper end
CraftEntity entity = nmsEntity.getBukkitEntity();
- Location to = new Location(entity.getWorld(), x, y, z, nmsEntity.getYRot(), nmsEntity.getXRot());
+ Location to = new Location(entity.getWorld(), x, y, z, yaw, pitch); // Paper
return CraftEventFactory.callEntityTeleportEvent(nmsEntity, to);
}

31 changes: 31 additions & 0 deletions test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
package io.papermc.testplugin;

import io.papermc.paper.event.player.ChatEvent;
import java.util.Collection;
import org.bukkit.entity.Pig;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityTeleportEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.plugin.java.JavaPlugin;

public final class TestPlugin extends JavaPlugin implements Listener {
Expand All @@ -12,4 +19,28 @@ public void onEnable() {
// io.papermc.testplugin.brigtests.Registration.registerViaOnEnable(this);
}

@EventHandler
public void onEvent(ChatEvent event) {
final Player player = event.getPlayer();
final Collection<Pig> nearby = player.getWorld().getNearbyEntitiesByType(Pig.class, player.getLocation(), 10);
for (final Pig pig : nearby) {
if (pig.getPassengers().isEmpty()) {
System.out.println("Teleport: " + pig.teleport(player.getLocation()));
}
}
}

@EventHandler
public void onEvent(EntityTeleportEvent event) {
System.out.println("EntityTeleportEvent");
System.out.println(event.getEntity());
System.out.println(event.getClass().getSimpleName());
}

@EventHandler
public void onEvent(PlayerTeleportEvent event) {
System.out.println("PlayerTeleportEvent");
System.out.println(event.getPlayer());
System.out.println(event.getClass().getSimpleName());
}
}
Loading