From a9f8ec56b9c25325dd3de7fb59ccd8accfd5336f Mon Sep 17 00:00:00 2001 From: Bjarne Koll Date: Sun, 23 Nov 2025 17:44:42 +0000 Subject: [PATCH 1/2] Position riders before API teleportation The previous teleportation logic would call Entity#positionRider for the "teleportation" of passengers in the same dimension. This prevented plugins that aggressively teleport entities on a per-tick basis from allowing players to get out of sync with their vehicles as the vanilla teleport logic simply performs a relative repositioning of the passengers to the vehicle location. The introduced diff now repositions the passengers onto their vehicle before computing their relative offset and repositioning. --- .../0001-Moonrise-optimisation-patches.patch | 16 +- ...026-Optimise-EntityScheduler-ticking.patch | 4 +- .../server/level/ServerPlayer.java.patch | 29 +-- .../minecraft/world/entity/Entity.java.patch | 19 +- .../projectile/ThrownEnderpearl.java.patch | 2 +- .../level/block/EndGatewayBlock.java.patch | 11 +- .../level/block/EndPortalBlock.java.patch | 11 +- .../level/block/NetherPortalBlock.java.patch | 2 +- .../portal/TeleportTransition.java.patch | 168 +++++++++++++----- .../craftbukkit/entity/CraftEntity.java | 5 +- 10 files changed, 166 insertions(+), 101 deletions(-) diff --git a/paper-server/patches/features/0001-Moonrise-optimisation-patches.patch b/paper-server/patches/features/0001-Moonrise-optimisation-patches.patch index bb3b428fc387..a341ef4e3365 100644 --- a/paper-server/patches/features/0001-Moonrise-optimisation-patches.patch +++ b/paper-server/patches/features/0001-Moonrise-optimisation-patches.patch @@ -27037,7 +27037,7 @@ index 704733ff5e558a12f2f9dde924ab4c507745595d..5e305c9a64e856de70ed787901c01d09 } diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index 8ecbcfb5f4e2d1cfcde694e9c57b74bbae4b2ac9..8b3efe83166e73dea6545384883c8db74f04cea7 100644 +index a9dde8ce02effc0e2f72825667dea37e1e959d03..7a7bd02937f1db6a2d2b9040d398d98ffb9fa1fc 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java @@ -202,7 +202,7 @@ import net.minecraft.world.scores.Team; @@ -28135,7 +28135,7 @@ index 8cc5c0716392ba06501542ff5cbe71ee43979e5d..09fd99c9cbd23b5f3c899bfb00c9b896 + // Paper end - block counting } diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index a91d8e7d26cea116b0f58d84c84854bbd8cee05c..d5a38c3464539b05453ead3dfd77f4cf4b672617 100644 +index 30618f5fc053d1e3edde1fab49c02c54d1608d71..40b309955932261ad2ce311e9f1fd6ed1c9af7d3 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -149,7 +149,7 @@ import net.minecraft.world.waypoints.WaypointTransmitter; @@ -28610,7 +28610,7 @@ index a91d8e7d26cea116b0f58d84c84854bbd8cee05c..d5a38c3464539b05453ead3dfd77f4cf } public InteractionResult interact(Player player, InteractionHand hand) { -@@ -4298,15 +4535,17 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -4304,15 +4541,17 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name } public Iterable getIndirectPassengers() { @@ -28636,7 +28636,7 @@ index a91d8e7d26cea116b0f58d84c84854bbd8cee05c..d5a38c3464539b05453ead3dfd77f4cf } public int countPlayerPassengers() { -@@ -4449,77 +4688,126 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -4455,77 +4694,126 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name return Mth.lerp(partialTick, this.yRotO, this.yRot); } @@ -28821,7 +28821,7 @@ index a91d8e7d26cea116b0f58d84c84854bbd8cee05c..d5a38c3464539b05453ead3dfd77f4cf public boolean touchingUnloadedChunk() { AABB aabb = this.getBoundingBox().inflate(1.0); -@@ -4675,6 +4963,15 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -4681,6 +4969,15 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name } public final void setPosRaw(double x, double y, double z, boolean forceBoundingBoxUpdate) { @@ -28837,7 +28837,7 @@ index a91d8e7d26cea116b0f58d84c84854bbd8cee05c..d5a38c3464539b05453ead3dfd77f4cf if (!checkPosition(this, x, y, z)) { return; } -@@ -4826,6 +5123,12 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -4832,6 +5129,12 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name @Override public final void setRemoved(Entity.RemovalReason removalReason, @Nullable org.bukkit.event.entity.EntityRemoveEvent.Cause cause) { // CraftBukkit - add Bukkit remove cause @@ -28850,7 +28850,7 @@ index a91d8e7d26cea116b0f58d84c84854bbd8cee05c..d5a38c3464539b05453ead3dfd77f4cf org.bukkit.craftbukkit.event.CraftEventFactory.callEntityRemoveEvent(this, cause); // CraftBukkit final boolean alreadyRemoved = this.removalReason != null; // Paper - Folia schedulers if (this.removalReason == null) { -@@ -4836,7 +5139,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -4842,7 +5145,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name this.stopRiding(); } @@ -28859,7 +28859,7 @@ index a91d8e7d26cea116b0f58d84c84854bbd8cee05c..d5a38c3464539b05453ead3dfd77f4cf this.levelCallback.onRemove(removalReason); this.onRemoval(removalReason); // Paper start - Folia schedulers -@@ -4870,7 +5173,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -4876,7 +5179,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name public boolean shouldBeSaved() { return (this.removalReason == null || this.removalReason.shouldSave()) && !this.isPassenger() diff --git a/paper-server/patches/features/0026-Optimise-EntityScheduler-ticking.patch b/paper-server/patches/features/0026-Optimise-EntityScheduler-ticking.patch index 62505d9e534a..c1c6155c5006 100644 --- a/paper-server/patches/features/0026-Optimise-EntityScheduler-ticking.patch +++ b/paper-server/patches/features/0026-Optimise-EntityScheduler-ticking.patch @@ -67,10 +67,10 @@ index ff6fc300e9e7d1dbf4b0fa1e59bffe94e1f51259..d58ee455467b2c8307ea20f8a9d88f0f io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.DIALOG_CLICK_MANAGER.handleQueue(this.tickCount); // Paper profilerFiller.push("commandFunctions"); diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 7ab250350027543adc3926632b0d68a2254c6ad3..2e3e038874757049445a91bf590d5a1a427a3f6d 100644 +index 01e472d0e6de4e0d2fdf90878c364e0f5ceb483e..5ebe15e2aaf8a45192750776532057e0313a717a 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -5190,6 +5190,11 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -5196,6 +5196,11 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name this.getBukkitEntity().taskScheduler.retire(); } // Paper end - Folia schedulers diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch index 749a6ba25710..bf55660fc41e 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch @@ -609,7 +609,7 @@ } } -@@ -992,25 +_,95 @@ +@@ -992,25 +_,84 @@ } private boolean isPvpAllowed() { @@ -694,18 +694,7 @@ + location = respawnEvent.getRespawnLocation(); + + return new RespawnResult( -+ new TeleportTransition( -+ ((org.bukkit.craftbukkit.CraftWorld) location.getWorld()).getHandle(), -+ org.bukkit.craftbukkit.util.CraftLocation.toVec3(location), -+ teleportTransition.deltaMovement(), -+ location.getYaw(), -+ location.getPitch(), -+ teleportTransition.missingRespawnBlock(), -+ teleportTransition.asPassenger(), -+ teleportTransition.relatives(), -+ teleportTransition.postTeleportTransition(), -+ teleportTransition.cause() -+ ), ++ teleportTransition.withChangedLocation(location), + isBedSpawn, + isAnchorSpawn + ); @@ -750,7 +739,7 @@ if (this.isRemoved()) { return null; } else { -@@ -1085,13 +_,48 @@ +@@ -1085,13 +_,38 @@ ServerLevel level = teleportTransition.newLevel(); ServerLevel serverLevel = this.level(); @@ -776,17 +765,7 @@ + } + if (!newExit.equals(exit)) { + level = ((org.bukkit.craftbukkit.CraftWorld) newExit.getWorld()).getHandle(); -+ teleportTransition = new TeleportTransition( -+ level, -+ org.bukkit.craftbukkit.util.CraftLocation.toVec3(newExit), -+ Vec3.ZERO, -+ newExit.getYaw(), -+ newExit.getPitch(), -+ teleportTransition.missingRespawnBlock(), -+ teleportTransition.asPassenger(), -+ Set.of(), -+ teleportTransition.postTeleportTransition(), -+ teleportTransition.cause()); ++ teleportTransition = teleportTransition.withChangedLocation(newExit).withVelocity(Vec3.ZERO).withRelatives(Set.of()); + } + // CraftBukkit end if (!teleportTransition.asPassenger()) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch index f4ed7d2fec50..057462ca7820 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch @@ -1492,7 +1492,7 @@ + } + if (!to.equals(teleEvent.getTo())) { + to = teleEvent.getTo(); -+ teleportTransition = new TeleportTransition(((org.bukkit.craftbukkit.CraftWorld) to.getWorld()).getHandle(), org.bukkit.craftbukkit.util.CraftLocation.toVec3(to), Vec3.ZERO, to.getYaw(), to.getPitch(), teleportTransition.missingRespawnBlock(), teleportTransition.asPassenger(), Set.of(), teleportTransition.postTeleportTransition(), teleportTransition.cause()); ++ teleportTransition = teleportTransition.withChangedLocation(to).withVelocity(Vec3.ZERO).withRelatives(Set.of()); + // Paper start - Call EntityPortalExitEvent + velocity = Vec3.ZERO; + } @@ -1518,7 +1518,7 @@ + to = event.getTo().clone(); + velocity = org.bukkit.craftbukkit.util.CraftVector.toVec3(event.getAfter()); + } -+ teleportTransition = new TeleportTransition(((org.bukkit.craftbukkit.CraftWorld) to.getWorld()).getHandle(), org.bukkit.craftbukkit.util.CraftLocation.toVec3(to), velocity, to.getYaw(), to.getPitch(), teleportTransition.missingRespawnBlock(), teleportTransition.asPassenger(), Set.of(), teleportTransition.postTeleportTransition(), teleportTransition.cause()); ++ teleportTransition = teleportTransition.withChangedLocation(to).withRelatives(Set.of()).withVelocity(velocity); + } + } + if (this.isRemoved()) { @@ -1546,6 +1546,19 @@ for (Entity entity2 : list) { entity2.startRiding(entityx, true, false); +@@ -3014,6 +_,12 @@ + private TeleportTransition calculatePassengerTransition(TeleportTransition teleportTransition, Entity entity) { + float f = teleportTransition.yRot() + (teleportTransition.relatives().contains(Relative.Y_ROT) ? 0.0F : entity.getYRot() - this.getYRot()); + float f1 = teleportTransition.xRot() + (teleportTransition.relatives().contains(Relative.X_ROT) ? 0.0F : entity.getXRot() - this.getXRot()); ++ // Paper start - reposition entity as rider when teleporting via API call ++ // This change is mostly required for plugins teleporting entities *every* tick with passengers, specifically player passengers. ++ // The relative teleport of players, which base their location on the server -> client -> server teleport packet cycle, means player ++ // positions can quickly be desynced from their rider position, leading to infinitely growing offsets from their vehicle. ++ if (teleportTransition.passengerTeleportationMode() == TeleportTransition.PassengerTeleportationMode.POSITION_RIDER) this.positionRider(entity); ++ // Paper end - reposition entity as rider when teleporting via API call + Vec3 vec3 = entity.position().subtract(this.position()); + Vec3 vec31 = teleportTransition.position() + .add( @@ -3078,9 +_,17 @@ } @@ -1588,7 +1601,7 @@ + + public boolean teleportTo(ServerLevel level, double x, double y, double z, Set relativeMovements, float yaw, float pitch, boolean setCamera, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause) { + // CraftBukkit end -+ Entity entity = this.teleport(new TeleportTransition(level, new Vec3(x, y, z), Vec3.ZERO, yaw, pitch, relativeMovements, TeleportTransition.DO_NOTHING, cause)); // CraftBukkit ++ Entity entity = this.teleport(new TeleportTransition(level, new Vec3(x, y, z), Vec3.ZERO, yaw, pitch, relativeMovements, TeleportTransition.DO_NOTHING).withCause(cause)); // CraftBukkit return entity != null; } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownEnderpearl.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownEnderpearl.java.patch index be8ad6a68872..50edbeea3bfd 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownEnderpearl.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/ThrownEnderpearl.java.patch @@ -8,7 +8,7 @@ + // Store pre teleportation position as the teleport has been moved up. + final double preTeleportX = serverPlayer.getX(), preTeleportY = serverPlayer.getY(), preTeleportZ = serverPlayer.getZ(); + final float preTeleportYRot = serverPlayer.getYRot(), preTeleportXRot = serverPlayer.getXRot(); -+ ServerPlayer serverPlayer1 = serverPlayer.teleport(new TeleportTransition(serverLevel, vec3, Vec3.ZERO, 0.0F, 0.0F, Relative.union(Relative.ROTATION, Relative.DELTA), TeleportTransition.DO_NOTHING, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.ENDER_PEARL)); ++ ServerPlayer serverPlayer1 = serverPlayer.teleport(new TeleportTransition(serverLevel, vec3, Vec3.ZERO, 0.0F, 0.0F, Relative.union(Relative.ROTATION, Relative.DELTA), TeleportTransition.DO_NOTHING).withCause(org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.ENDER_PEARL)); + if (serverPlayer1 == null) { + this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); + return; diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/EndGatewayBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/EndGatewayBlock.java.patch index b520d37a11d0..0f210f81c6eb 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/EndGatewayBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/EndGatewayBlock.java.patch @@ -16,15 +16,16 @@ entity.setAsInsidePortal(this, pos); TheEndGatewayBlockEntity.triggerCooldown(level, pos, state, theEndGatewayBlockEntity); } -@@ -108,9 +_,9 @@ +@@ -108,10 +_,10 @@ return null; } else { return entity instanceof ThrownEnderpearl - ? new TeleportTransition(level, portalPosition, Vec3.ZERO, 0.0F, 0.0F, Set.of(), TeleportTransition.PLACE_PORTAL_TICKET) -+ ? new TeleportTransition(level, portalPosition, Vec3.ZERO, 0.0F, 0.0F, Set.of(), TeleportTransition.PLACE_PORTAL_TICKET, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_GATEWAY) // CraftBukkit ++ ? new TeleportTransition(level, portalPosition, Vec3.ZERO, 0.0F, 0.0F, Set.of(), TeleportTransition.PLACE_PORTAL_TICKET).withCause(org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_GATEWAY) // CraftBukkit - teleport cause : new TeleportTransition( -- level, portalPosition, Vec3.ZERO, 0.0F, 0.0F, Relative.union(Relative.DELTA, Relative.ROTATION), TeleportTransition.PLACE_PORTAL_TICKET -+ level, portalPosition, Vec3.ZERO, 0.0F, 0.0F, Relative.union(Relative.DELTA, Relative.ROTATION), TeleportTransition.PLACE_PORTAL_TICKET, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_GATEWAY // CraftBukkit - ); + level, portalPosition, Vec3.ZERO, 0.0F, 0.0F, Relative.union(Relative.DELTA, Relative.ROTATION), TeleportTransition.PLACE_PORTAL_TICKET +- ); ++ ).withCause(org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_GATEWAY); // CraftBukkit - teleport cause } } else { + return null; diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/EndPortalBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/EndPortalBlock.java.patch index 95ae4bc01432..d6884a6f36c8 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/EndPortalBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/EndPortalBlock.java.patch @@ -34,7 +34,7 @@ f = Direction.WEST.toYRot(); f1 = 0.0F; set = Relative.union(Relative.DELTA, Set.of(Relative.X_ROT)); -@@ -97,15 +_,24 @@ +@@ -97,15 +_,25 @@ f1 = respawnData.pitch(); set = Relative.union(Relative.DELTA, Relative.ROTATION); if (entity instanceof ServerPlayer serverPlayer) { @@ -45,9 +45,6 @@ bottomCenter = entity.adjustSpawnLocation(level1, blockPos).getBottomCenter(); } -- return new TeleportTransition( -- level1, bottomCenter, Vec3.ZERO, f, f1, set, TeleportTransition.PLAY_PORTAL_SOUND.then(TeleportTransition.PLACE_PORTAL_TICKET) -- ); + // CraftBukkit start + set.removeAll(Relative.ROTATION); // remove relative rotation flags to simplify event mutation + float absoluteYaw = !flag ? f : entity.getYRot() + f; @@ -57,9 +54,11 @@ + return null; + } + org.bukkit.Location to = result.to(); -+ -+ return new TeleportTransition(((org.bukkit.craftbukkit.CraftWorld) to.getWorld()).getHandle(), org.bukkit.craftbukkit.util.CraftLocation.toVec3(to), Vec3.ZERO, to.getYaw(), to.getPitch(), set, TeleportTransition.PLAY_PORTAL_SOUND.then(TeleportTransition.PLACE_PORTAL_TICKET), org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_PORTAL); + // CraftBukkit end + return new TeleportTransition( + level1, bottomCenter, Vec3.ZERO, f, f1, set, TeleportTransition.PLAY_PORTAL_SOUND.then(TeleportTransition.PLACE_PORTAL_TICKET) +- ); ++ ).withChangedLocation(to).withCause(org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_PORTAL); // CraftBukkit - portal event & cause } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/NetherPortalBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/NetherPortalBlock.java.patch index 9a769130ce04..775e6e35d2d5 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/NetherPortalBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/NetherPortalBlock.java.patch @@ -121,7 +121,7 @@ Vec3 vec3 = new Vec3(blockPos.getX() + (flag ? d2 : d4), blockPos.getY() + d3, blockPos.getZ() + (flag ? d4 : d2)); Vec3 vec31 = PortalShape.findCollisionFreePosition(vec3, level, entity, dimensions); - return new TeleportTransition(level, vec31, Vec3.ZERO, i, 0.0F, Relative.union(Relative.DELTA, Relative.ROTATION), postTeleportTransition); -+ return new TeleportTransition(level, vec31, Vec3.ZERO, i, 0.0F, Relative.union(Relative.DELTA, Relative.ROTATION), postTeleportTransition, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.NETHER_PORTAL); // CraftBukkit ++ return new TeleportTransition(level, vec31, Vec3.ZERO, i, 0.0F, Relative.union(Relative.DELTA, Relative.ROTATION), postTeleportTransition).withCause(org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.NETHER_PORTAL); // CraftBukkit } @Override diff --git a/paper-server/patches/sources/net/minecraft/world/level/portal/TeleportTransition.java.patch b/paper-server/patches/sources/net/minecraft/world/level/portal/TeleportTransition.java.patch index e497a2065335..58282a41137e 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/portal/TeleportTransition.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/portal/TeleportTransition.java.patch @@ -1,74 +1,144 @@ --- a/net/minecraft/world/level/portal/TeleportTransition.java +++ b/net/minecraft/world/level/portal/TeleportTransition.java -@@ -21,11 +_,18 @@ +@@ -21,7 +_,108 @@ boolean asPassenger, Set relatives, TeleportTransition.PostTeleportTransition postTeleportTransition -+ , org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause // CraftBukkit ++ // Paper start - additional transition data ++ , org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause, ++ PassengerTeleportationMode passengerTeleportationMode ) { - public static final TeleportTransition.PostTeleportTransition DO_NOTHING = entity -> {}; - public static final TeleportTransition.PostTeleportTransition PLAY_PORTAL_SOUND = TeleportTransition::playPortalSound; - public static final TeleportTransition.PostTeleportTransition PLACE_PORTAL_TICKET = TeleportTransition::placePortalTicket; - -+ // CraftBukkit start -+ public TeleportTransition(ServerLevel newLevel, Vec3 position, Vec3 deltaMovement, float yRot, float xRot, boolean missingRespawnBlock, boolean asPassenger, Set relatives, TeleportTransition.PostTeleportTransition postTeleportTransition) { -+ this(newLevel, position, deltaMovement, yRot, xRot, missingRespawnBlock, asPassenger, relatives, postTeleportTransition, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.UNKNOWN); -+ } -+ // CraftBukkit end + - public TeleportTransition( - ServerLevel newLevel, Vec3 position, Vec3 deltaMovement, float yRot, float xRot, TeleportTransition.PostTeleportTransition postTeleportTransition - ) { -@@ -41,7 +_,21 @@ - Set relatives, - TeleportTransition.PostTeleportTransition postTeleportTransition - ) { -- this(newLevel, position, deltaMovement, yRot, xRot, false, false, relatives, postTeleportTransition); -+ // CraftBukkit start -+ this(newLevel, position, deltaMovement, yRot, xRot, relatives, postTeleportTransition, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.UNKNOWN); ++ public enum PassengerTeleportationMode { ++ RELATIVE, ++ POSITION_RIDER + } ++ ++ // Vanilla compat constructor + public TeleportTransition( -+ ServerLevel newLevel, -+ Vec3 position, -+ Vec3 deltaMovement, -+ float yRot, -+ float xRot, -+ Set relatives, -+ TeleportTransition.PostTeleportTransition postTeleportTransition, -+ org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause ++ final ServerLevel newLevel, ++ final Vec3 position, ++ final Vec3 deltaMovement, ++ final float yRot, ++ final float xRot, ++ final boolean missingRespawnBlock, ++ final boolean asPassenger, ++ final Set relatives, ++ final TeleportTransition.PostTeleportTransition postTeleportTransition + ) { -+ this(newLevel, position, deltaMovement, yRot, xRot, false, false, relatives, postTeleportTransition, cause); -+ // CraftBukkit end - } - - private static void playPortalSound(Entity entity) { -@@ -100,7 +_,8 @@ - this.missingRespawnBlock(), ++ this( ++ newLevel, ++ position, ++ deltaMovement, ++ yRot, ++ xRot, ++ missingRespawnBlock, ++ asPassenger, ++ relatives, ++ postTeleportTransition, ++ org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.UNKNOWN, ++ PassengerTeleportationMode.RELATIVE ++ ); ++ } ++ ++ public TeleportTransition withChangedLocation(final org.bukkit.Location location) { ++ return new TeleportTransition( ++ ((org.bukkit.craftbukkit.CraftWorld) location.getWorld()).getHandle(), ++ org.bukkit.craftbukkit.util.CraftLocation.toVec3(location), ++ this.deltaMovement(), ++ location.getYaw(), ++ location.getPitch(), ++ this.missingRespawnBlock(), ++ this.asPassenger(), ++ this.relatives(), ++ this.postTeleportTransition(), ++ this.cause(), ++ this.passengerTeleportationMode() ++ ); ++ } ++ ++ public TeleportTransition withVelocity(final Vec3 velocity) { ++ return new TeleportTransition( ++ this.newLevel(), ++ this.position(), ++ velocity, ++ this.yRot(), ++ this.xRot(), ++ this.missingRespawnBlock(), ++ this.asPassenger(), ++ this.relatives(), ++ this.postTeleportTransition(), ++ this.cause(), ++ this.passengerTeleportationMode() ++ ); ++ } ++ ++ public TeleportTransition withRelatives(final Set relatives) { ++ return new TeleportTransition( ++ this.newLevel(), ++ this.position(), ++ this.deltaMovement(), ++ this.yRot(), ++ this.xRot(), ++ this.missingRespawnBlock(), ++ this.asPassenger(), ++ relatives, ++ this.postTeleportTransition(), ++ this.cause(), ++ this.passengerTeleportationMode() ++ ); ++ } ++ ++ public TeleportTransition withCause(final org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause) { ++ return new TeleportTransition( ++ this.newLevel(), ++ this.position(), ++ this.deltaMovement(), ++ this.yRot(), ++ this.xRot(), ++ this.missingRespawnBlock(), ++ this.asPassenger(), ++ this.relatives(), ++ this.postTeleportTransition(), ++ cause, ++ this.passengerTeleportationMode() ++ ); ++ } ++ // Paper end - additional transition data ++ + public static final TeleportTransition.PostTeleportTransition DO_NOTHING = entity -> {}; + public static final TeleportTransition.PostTeleportTransition PLAY_PORTAL_SOUND = TeleportTransition::playPortalSound; + public static final TeleportTransition.PostTeleportTransition PLACE_PORTAL_TICKET = TeleportTransition::placePortalTicket; +@@ -101,6 +_,10 @@ this.asPassenger(), this.relatives(), -- this.postTeleportTransition() -+ this.postTeleportTransition(), -+ this.cause() // Paper - keep cause + this.postTeleportTransition() ++ // Paper start - keep additional data ++ , this.cause(), ++ this.passengerTeleportationMode() ++ // Paper end - keep additional data ); } -@@ -114,7 +_,8 @@ - this.missingRespawnBlock(), +@@ -115,6 +_,10 @@ this.asPassenger(), this.relatives(), -- this.postTeleportTransition() -+ this.postTeleportTransition(), -+ this.cause() // Paper - keep cause + this.postTeleportTransition() ++ // Paper start - keep additional data ++ , this.cause(), ++ this.passengerTeleportationMode() ++ // Paper end - keep additional data ); } -@@ -128,7 +_,8 @@ - this.missingRespawnBlock(), +@@ -129,6 +_,10 @@ true, this.relatives(), -- this.postTeleportTransition() -+ this.postTeleportTransition(), -+ this.cause() // Paper - keep cause + this.postTeleportTransition() ++ // Paper start - keep additional data ++ , this.cause(), ++ this.passengerTeleportationMode() ++ // Paper end - keep additional data ); } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java index b177e23db960..10e9131b9f15 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -315,9 +315,12 @@ protected boolean teleport0(Location location, TeleportCause cause, TeleportFlag Vec3.ZERO, location.getYaw(), location.getPitch(), + false, + false, relativeFlags, TeleportTransition.DO_NOTHING, - cause + cause, + TeleportTransition.PassengerTeleportationMode.POSITION_RIDER )) != null; } From d77c4e8d1d40e03ab70f5a1c0d8e5c8480b18f0b Mon Sep 17 00:00:00 2001 From: Bjarne Koll Date: Sat, 6 Dec 2025 14:40:50 +0000 Subject: [PATCH 2/2] Another comment --- .../0001-Moonrise-optimisation-patches.patch | 14 +++++++------- .../0024-Optimise-EntityScheduler-ticking.patch | 4 ++-- .../net/minecraft/world/entity/Entity.java.patch | 3 ++- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/paper-server/patches/features/0001-Moonrise-optimisation-patches.patch b/paper-server/patches/features/0001-Moonrise-optimisation-patches.patch index f5c19cbda072..51d6e8560f75 100644 --- a/paper-server/patches/features/0001-Moonrise-optimisation-patches.patch +++ b/paper-server/patches/features/0001-Moonrise-optimisation-patches.patch @@ -28126,7 +28126,7 @@ index 8cc5c0716392ba06501542ff5cbe71ee43979e5d..09fd99c9cbd23b5f3c899bfb00c9b896 + // Paper end - block counting } diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 97384da7b1978f7662e0fb62709c2c9a3366a1d2..fcc7de0333333fd44cd6c5df7ff8f8967ab61fba 100644 +index 88fbc7030ae9190658b0e6b5fc0f7392c82e61ab..2c27c35ced4588fec828e05b75871d4980712d99 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -152,7 +152,7 @@ import org.jetbrains.annotations.Contract; @@ -28601,7 +28601,7 @@ index 97384da7b1978f7662e0fb62709c2c9a3366a1d2..fcc7de0333333fd44cd6c5df7ff8f896 } public InteractionResult interact(Player player, InteractionHand hand) { -@@ -4322,15 +4559,17 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -4323,15 +4560,17 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name } public Iterable getIndirectPassengers() { @@ -28627,7 +28627,7 @@ index 97384da7b1978f7662e0fb62709c2c9a3366a1d2..fcc7de0333333fd44cd6c5df7ff8f896 } public int countPlayerPassengers() { -@@ -4479,77 +4718,126 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -4480,77 +4719,126 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name return Mth.lerp(partialTick, this.yRotO, this.yRot); } @@ -28812,7 +28812,7 @@ index 97384da7b1978f7662e0fb62709c2c9a3366a1d2..fcc7de0333333fd44cd6c5df7ff8f896 public boolean touchingUnloadedChunk() { AABB aabb = this.getBoundingBox().inflate(1.0); -@@ -4709,6 +4997,15 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -4710,6 +4998,15 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name } public final void setPosRaw(double x, double y, double z, boolean forceBoundingBoxUpdate) { @@ -28828,7 +28828,7 @@ index 97384da7b1978f7662e0fb62709c2c9a3366a1d2..fcc7de0333333fd44cd6c5df7ff8f896 if (!checkPosition(this, x, y, z)) { return; } -@@ -4858,6 +5155,12 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -4859,6 +5156,12 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name @Override public final void setRemoved(Entity.RemovalReason removalReason, org.bukkit.event.entity.EntityRemoveEvent.@Nullable Cause cause) { // CraftBukkit - add Bukkit remove cause @@ -28841,7 +28841,7 @@ index 97384da7b1978f7662e0fb62709c2c9a3366a1d2..fcc7de0333333fd44cd6c5df7ff8f896 org.bukkit.craftbukkit.event.CraftEventFactory.callEntityRemoveEvent(this, cause); // CraftBukkit final boolean alreadyRemoved = this.removalReason != null; // Paper - Folia schedulers if (this.removalReason == null) { -@@ -4868,7 +5171,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -4869,7 +5172,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name this.stopRiding(); } @@ -28850,7 +28850,7 @@ index 97384da7b1978f7662e0fb62709c2c9a3366a1d2..fcc7de0333333fd44cd6c5df7ff8f896 this.levelCallback.onRemove(removalReason); this.onRemoval(removalReason); // Paper start - Folia schedulers -@@ -4902,7 +5205,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -4903,7 +5206,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name public boolean shouldBeSaved() { return (this.removalReason == null || this.removalReason.shouldSave()) && !this.isPassenger() diff --git a/paper-server/patches/features/0024-Optimise-EntityScheduler-ticking.patch b/paper-server/patches/features/0024-Optimise-EntityScheduler-ticking.patch index f7fc81961c17..75f8ee1425d1 100644 --- a/paper-server/patches/features/0024-Optimise-EntityScheduler-ticking.patch +++ b/paper-server/patches/features/0024-Optimise-EntityScheduler-ticking.patch @@ -67,10 +67,10 @@ index e7df5f105c721f2e1be1a13694275c0f03b7932b..0f56d83701ac770799970fceeb73eab5 io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.DIALOG_CLICK_MANAGER.handleQueue(this.tickCount); // Paper profilerFiller.push("commandFunctions"); diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 5d66f6c529f35f17e568833a394dbb24f57f9943..ca87e1aedbefb2bd10377463816ef05234d1ed02 100644 +index 65d15bc8eaa20ee3fb78150971b9d10aa75f180e..6e0e4f375155262afcb9e7f2fd22aa9b1bd3c2f2 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -5222,6 +5222,11 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -5223,6 +5223,11 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name this.getBukkitEntity().taskScheduler.retire(); } // Paper end - Folia schedulers diff --git a/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch index 335fbbf3020c..ea18a02be191 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch @@ -1540,7 +1540,7 @@ for (Entity entity2 : list) { entity2.startRiding(entityx, true, false); -@@ -3035,6 +_,12 @@ +@@ -3035,6 +_,13 @@ private TeleportTransition calculatePassengerTransition(TeleportTransition teleportTransition, Entity entity) { float f = teleportTransition.yRot() + (teleportTransition.relatives().contains(Relative.Y_ROT) ? 0.0F : entity.getYRot() - this.getYRot()); float f1 = teleportTransition.xRot() + (teleportTransition.relatives().contains(Relative.X_ROT) ? 0.0F : entity.getXRot() - this.getXRot()); @@ -1548,6 +1548,7 @@ + // This change is mostly required for plugins teleporting entities *every* tick with passengers, specifically player passengers. + // The relative teleport of players, which base their location on the server -> client -> server teleport packet cycle, means player + // positions can quickly be desynced from their rider position, leading to infinitely growing offsets from their vehicle. ++ // The addition to the teleport transition allows existing callers to this method to not accidentally mutate the entity state. + if (teleportTransition.passengerTeleportationMode() == TeleportTransition.PassengerTeleportationMode.POSITION_RIDER) this.positionRider(entity); + // Paper end - reposition entity as rider when teleporting via API call Vec3 vec3 = entity.position().subtract(this.position());