restore vanilla teleportation logic for non-players

This commit is contained in:
Jake Potrebic 2024-09-22 11:44:11 -07:00
parent 1cb2bf466f
commit 8a2ec8c1fb
No known key found for this signature in database
GPG key ID: ECE0B3C133C016C5
2 changed files with 227 additions and 0 deletions

View file

@ -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);
}

View file

@ -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 {
@ -12,4 +19,28 @@ public final class TestPlugin extends JavaPlugin implements Listener {
// 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());
}
}