diff --git a/build-data/paper.at b/build-data/paper.at index d1158d474df4..f924d3ebabed 100644 --- a/build-data/paper.at +++ b/build-data/paper.at @@ -227,6 +227,7 @@ public net.minecraft.world.entity.LivingEntity detectEquipmentUpdates()V public net.minecraft.world.entity.LivingEntity effectsDirty public net.minecraft.world.entity.LivingEntity entityEventForEquipmentBreak(Lnet/minecraft/world/entity/EquipmentSlot;)B public net.minecraft.world.entity.LivingEntity getDeathSound()Lnet/minecraft/sounds/SoundEvent; +public net.minecraft.world.entity.LivingEntity getRiddenSpeed(Lnet/minecraft/world/entity/player/Player;)F public net.minecraft.world.entity.LivingEntity getSoundVolume()F public net.minecraft.world.entity.LivingEntity jumping public net.minecraft.world.entity.LivingEntity lastHurt diff --git a/paper-api/src/main/java/io/papermc/paper/event/player/PlayerMoveVehicleEvent.java b/paper-api/src/main/java/io/papermc/paper/event/player/PlayerMoveVehicleEvent.java new file mode 100644 index 000000000000..51f869515d2d --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/event/player/PlayerMoveVehicleEvent.java @@ -0,0 +1,81 @@ +package io.papermc.paper.event.player; + +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * Runs when a player attempts to move a vehicle to a new position. + */ +@NullMarked +public class PlayerMoveVehicleEvent extends PlayerEvent implements Cancellable { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private final Location from; + private final Location to; + private final Entity vehicle; + private boolean cancelled; + + @ApiStatus.Internal + public PlayerMoveVehicleEvent(final Player player, final Entity vehicle, final Location from, final Location to) { + super(player); + this.vehicle = vehicle; + this.from = from; + this.to = to; + } + /** + * Gets the location the vehicle moved from + * + * @return Location the vehicle moved from + */ + public Location getFrom() { + return this.from.clone(); + } + + /** + * Gets the location the vehicle is moving to + * + * @return Location the vehicle is moving to + */ + public Location getTo() { + return this.to.clone(); + } + + /** + * Gets the vehicle this player is currently moving. + * Note: You should use {@link PlayerMoveVehicleEvent#getTo()} for getting the previous and + * new location of the vehicle. + *

+ * The behavior of getting the location of the vehicle in this event is undefined. + * + * @return vehicle + */ + public Entity getVehicle() { + return vehicle; + } + + @Override + public HandlerList getHandlers() { + return HANDLER_LIST; + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } + + @Override + public boolean isCancelled() { + return this.cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } +} diff --git a/paper-server/patches/features/0029-Optimise-collision-checking-in-player-move-packet-ha.patch b/paper-server/patches/features/0029-Optimise-collision-checking-in-player-move-packet-ha.patch index 00cdbd32645d..145144bb4178 100644 --- a/paper-server/patches/features/0029-Optimise-collision-checking-in-player-move-packet-ha.patch +++ b/paper-server/patches/features/0029-Optimise-collision-checking-in-player-move-packet-ha.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Optimise collision checking in player move packet handling Move collision logic to just the hasNewCollision call instead of getCubes + hasNewCollision diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 3aad9ee86d6af392f4a98022cbc88bb53000e7be..27ef385a85b13ceb58e8d149849983107c539b31 100644 +index 2e838877ce1da44c0dbe2c3275a76fc97e640fa3..2389fbf02ca593829f91185ffa6c790c0d6ebb12 100644 --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -561,7 +561,7 @@ public class ServerGamePacketListenerImpl +@@ -554,7 +554,7 @@ public class ServerGamePacketListenerImpl return; } @@ -18,7 +18,7 @@ index 3aad9ee86d6af392f4a98022cbc88bb53000e7be..27ef385a85b13ceb58e8d14984998310 d3 = d - this.vehicleLastGoodX; // Paper - diff on change, used for checking large move vectors above d4 = d1 - this.vehicleLastGoodY; // Paper - diff on change, used for checking large move vectors above d5 = d2 - this.vehicleLastGoodZ; // Paper - diff on change, used for checking large move vectors above -@@ -571,6 +571,7 @@ public class ServerGamePacketListenerImpl +@@ -564,6 +564,7 @@ public class ServerGamePacketListenerImpl } rootVehicle.move(MoverType.PLAYER, new Vec3(d3, d4, d5)); @@ -26,7 +26,7 @@ index 3aad9ee86d6af392f4a98022cbc88bb53000e7be..27ef385a85b13ceb58e8d14984998310 double verticalDelta = d4; // Paper - Decompile fix, was named d11 previously, is now gone in the source d3 = d - rootVehicle.getX(); d4 = d1 - rootVehicle.getY(); -@@ -582,14 +583,22 @@ public class ServerGamePacketListenerImpl +@@ -575,15 +576,20 @@ public class ServerGamePacketListenerImpl d7 = d3 * d3 + d4 * d4 + d5 * d5; boolean flag2 = false; if (d7 > org.spigotmc.SpigotConfig.movedWronglyThreshold) { // Spigot @@ -36,23 +36,21 @@ index 3aad9ee86d6af392f4a98022cbc88bb53000e7be..27ef385a85b13ceb58e8d14984998310 } rootVehicle.absMoveTo(d, d1, d2, f, f1); - this.player.absMoveTo(d, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit - boolean flag3 = serverLevel.noCollision(rootVehicle, rootVehicle.getBoundingBox().deflate(0.0625)); -- if (flag && (flag2 || !flag3)) { -+ // Paper start - optimise out extra getCubes + // Paper start +- boolean teleportBack = flag && (flag2 || !flag3); + boolean teleportBack = flag2; // violating this is always a fail -+ if (!teleportBack) { + if (!teleportBack) { + // note: only call after setLocation, or else getBoundingBox is wrong + AABB newBox = rootVehicle.getBoundingBox(); + if (didCollide || !oldBox.equals(newBox)) { + teleportBack = this.hasNewCollision(serverLevel, rootVehicle, oldBox, newBox); + } // else: no collision at all detected, why do we care? -+ } -+ if (teleportBack) { // Paper end - optimise out extra getCubes - rootVehicle.absMoveTo(x, y, z, f, f1); - this.player.absMoveTo(x, y, z, this.player.getYRot(), this.player.getXRot()); // CraftBukkit - this.send(ClientboundMoveVehiclePacket.fromEntity(rootVehicle)); -@@ -667,9 +676,32 @@ public class ServerGamePacketListenerImpl ++ + // Move event - emulating from the vehicle + org.bukkit.entity.Entity rootVehicleBukkit = rootVehicle.getBukkitEntity(); + Location from = new Location(rootVehicleBukkit.getWorld(), x, y, z, f, f1); // Copy from #absMoveTo on teleportBack +@@ -637,9 +643,32 @@ public class ServerGamePacketListenerImpl } private boolean noBlocksAround(Entity entity) { @@ -88,7 +86,7 @@ index 3aad9ee86d6af392f4a98022cbc88bb53000e7be..27ef385a85b13ceb58e8d14984998310 } @Override -@@ -1368,7 +1400,7 @@ public class ServerGamePacketListenerImpl +@@ -1338,7 +1367,7 @@ public class ServerGamePacketListenerImpl } } @@ -97,7 +95,7 @@ index 3aad9ee86d6af392f4a98022cbc88bb53000e7be..27ef385a85b13ceb58e8d14984998310 d3 = d - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above d4 = d1 - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above d5 = d2 - this.lastGoodZ; // Paper - diff on change, used for checking large move vectors above -@@ -1407,6 +1439,7 @@ public class ServerGamePacketListenerImpl +@@ -1377,6 +1406,7 @@ public class ServerGamePacketListenerImpl boolean flag1 = this.player.verticalCollisionBelow; this.player.move(MoverType.PLAYER, new Vec3(d3, d4, d5)); this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move @@ -105,7 +103,7 @@ index 3aad9ee86d6af392f4a98022cbc88bb53000e7be..27ef385a85b13ceb58e8d14984998310 // Paper start - prevent position desync if (this.awaitingPositionFromClient != null) { return; // ... thanks Mojang for letting move calls teleport across dimensions. -@@ -1439,7 +1472,17 @@ public class ServerGamePacketListenerImpl +@@ -1409,7 +1439,17 @@ public class ServerGamePacketListenerImpl } // Paper start - Add fail move event @@ -124,7 +122,7 @@ index 3aad9ee86d6af392f4a98022cbc88bb53000e7be..27ef385a85b13ceb58e8d14984998310 if (teleportBack) { io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.CLIPPED_INTO_BLOCK, toX, toY, toZ, toYaw, toPitch, false); -@@ -1575,7 +1618,7 @@ public class ServerGamePacketListenerImpl +@@ -1545,7 +1585,7 @@ public class ServerGamePacketListenerImpl private boolean updateAwaitingTeleport() { if (this.awaitingPositionFromClient != null) { @@ -133,7 +131,7 @@ index 3aad9ee86d6af392f4a98022cbc88bb53000e7be..27ef385a85b13ceb58e8d14984998310 this.awaitingTeleportTime = this.tickCount; this.teleport( this.awaitingPositionFromClient.x, -@@ -1594,6 +1637,33 @@ public class ServerGamePacketListenerImpl +@@ -1564,6 +1604,33 @@ public class ServerGamePacketListenerImpl } } diff --git a/paper-server/patches/features/0031-Do-not-record-movement-for-vehicles-players-unaffect.patch b/paper-server/patches/features/0031-Do-not-record-movement-for-vehicles-players-unaffect.patch index ad20395cfe38..5f6ae1a34bae 100644 --- a/paper-server/patches/features/0031-Do-not-record-movement-for-vehicles-players-unaffect.patch +++ b/paper-server/patches/features/0031-Do-not-record-movement-for-vehicles-players-unaffect.patch @@ -11,11 +11,11 @@ a portal in spectator mode and then later switching to creative mode would portal the player. diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 366c26b2ca539be189b67d75ae73a587c4102c14..4068132a33f87dd07d6df1033ed11ba16a57313b 100644 +index 2389fbf02ca593829f91185ffa6c790c0d6ebb12..ae2ca486db1e689862fc446dc1d051fb058a1187 100644 --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -657,7 +657,7 @@ public class ServerGamePacketListenerImpl - // CraftBukkit end +@@ -624,7 +624,7 @@ public class ServerGamePacketListenerImpl + } this.player.serverLevel().getChunkSource().move(this.player); - rootVehicle.recordMovementThroughBlocks(new Vec3(x, y, z), rootVehicle.position()); @@ -23,7 +23,7 @@ index 366c26b2ca539be189b67d75ae73a587c4102c14..4068132a33f87dd07d6df1033ed11ba1 Vec3 vec3 = new Vec3(rootVehicle.getX() - x, rootVehicle.getY() - y, rootVehicle.getZ() - z); this.handlePlayerKnownMovement(vec3); rootVehicle.setOnGroundWithMovement(packet.onGround(), vec3); -@@ -1574,7 +1574,7 @@ public class ServerGamePacketListenerImpl +@@ -1541,7 +1541,7 @@ public class ServerGamePacketListenerImpl Vec3 vec3 = new Vec3(this.player.getX() - x, this.player.getY() - y, this.player.getZ() - z); this.player.setOnGroundWithMovement(packet.isOnGround(), packet.horizontalCollision(), vec3); this.player.doCheckFallDamage(vec3.x, vec3.y, vec3.z, packet.isOnGround()); diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch index 8589a3b4e7d4..cc8251021497 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch @@ -167,7 +167,7 @@ this.player.setLastClientInput(packet.input()); } -@@ -390,17 +_,29 @@ +@@ -390,17 +_,22 @@ public void handleMoveVehicle(ServerboundMoveVehiclePacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); if (containsInvalidValues(packet.position().x(), packet.position().y(), packet.position().z(), packet.yRot(), packet.xRot())) { @@ -182,13 +182,6 @@ + // Paper end - Don't allow vehicle movement from players while teleporting if (rootVehicle != this.player && rootVehicle.getControllingPassenger() == this.player && rootVehicle == this.lastVehicle) { ServerLevel serverLevel = this.player.serverLevel(); -+ // CraftBukkit - store current player position -+ double prevX = this.player.getX(); -+ double prevY = this.player.getY(); -+ double prevZ = this.player.getZ(); -+ float prevYaw = this.player.getYRot(); -+ float prevPitch = this.player.getXRot(); -+ // CraftBukkit end double x = rootVehicle.getX(); double y = rootVehicle.getY(); double z = rootVehicle.getZ(); @@ -276,7 +269,7 @@ d3 = d - rootVehicle.getX(); d4 = d1 - rootVehicle.getY(); if (d4 > -0.5 || d4 < 0.5) { -@@ -435,18 +_,71 @@ +@@ -435,14 +_,44 @@ d5 = d2 - rootVehicle.getZ(); d7 = d3 * d3 + d4 * d4 + d5 * d5; boolean flag2 = false; @@ -287,68 +280,42 @@ } rootVehicle.absMoveTo(d, d1, d2, f, f1); -+ this.player.absMoveTo(d, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit boolean flag3 = serverLevel.noCollision(rootVehicle, rootVehicle.getBoundingBox().deflate(0.0625)); - if (flag && (flag2 || !flag3)) { +- if (flag && (flag2 || !flag3)) { ++ // Paper start ++ boolean teleportBack = flag && (flag2 || !flag3); ++ if (!teleportBack) { ++ // Move event - emulating from the vehicle ++ org.bukkit.entity.Entity rootVehicleBukkit = rootVehicle.getBukkitEntity(); ++ Location from = new Location(rootVehicleBukkit.getWorld(), x, y, z, f, f1); // Copy from #absMoveTo on teleportBack ++ Location to = rootVehicleBukkit.getLocation(); ++ ++ // Prevent 40 event-calls for less than a single pixel of movement >.> ++ double delta = Math.pow(from.getX() - to.getX(), 2) + Math.pow(from.getY() - to.getY(), 2) + Math.pow(from.getZ() - to.getZ(), 2); ++ float deltaAngle = Math.abs(from.getYaw() - to.getYaw()) + Math.abs(from.getPitch() - to.getPitch()); ++ ++ if ((delta > 1f / 256 || deltaAngle > 10f) && !this.player.isImmobile()) { ++ Location oldLoc = to.clone(); ++ io.papermc.paper.event.player.PlayerMoveVehicleEvent event = new io.papermc.paper.event.player.PlayerMoveVehicleEvent(this.player.getBukkitEntity(), rootVehicleBukkit, from, to); ++ if (event.callEvent()) { ++ if (event.getTo() != to || !oldLoc.equals(event.getTo())) { // If instance changed or value change, resync ++ Location newTo = event.getTo(); ++ rootVehicle.absMoveTo(newTo.x(), newTo.y(), newTo.z(), newTo.getYaw(), newTo.getPitch()); // move the vehicle to the new location ++ this.send(ClientboundMoveVehiclePacket.fromEntity(rootVehicle)); // resync the vehicle ++ } ++ } else { ++ teleportBack = true; ++ // Reset the above tick -- as ignore checks that they are flying ++ // Most notable if they are in air. ++ this.aboveGroundTickCount = 0; ++ } ++ } ++ } ++ if (teleportBack) { ++ // Paper end rootVehicle.absMoveTo(x, y, z, f, f1); -+ this.player.absMoveTo(x, y, z, this.player.getYRot(), this.player.getXRot()); // CraftBukkit this.send(ClientboundMoveVehiclePacket.fromEntity(rootVehicle)); return; - } -+ -+ // CraftBukkit start - fire PlayerMoveEvent -+ org.bukkit.entity.Player player = this.getCraftPlayer(); -+ if (!this.hasMoved) { -+ this.lastPosX = prevX; -+ this.lastPosY = prevY; -+ this.lastPosZ = prevZ; -+ this.lastYaw = prevYaw; -+ this.lastPitch = prevPitch; -+ this.hasMoved = true; -+ } -+ Location from = new Location(player.getWorld(), this.lastPosX, this.lastPosY, this.lastPosZ, this.lastYaw, this.lastPitch); // Get the Players previous Event location. -+ Location to = CraftLocation.toBukkit(packet.position(), player.getWorld(), packet.yRot(), packet.xRot()); -+ -+ // Prevent 40 event-calls for less than a single pixel of movement >.> -+ double delta = Math.pow(this.lastPosX - to.getX(), 2) + Math.pow(this.lastPosY - to.getY(), 2) + Math.pow(this.lastPosZ - to.getZ(), 2); -+ float deltaAngle = Math.abs(this.lastYaw - to.getYaw()) + Math.abs(this.lastPitch - to.getPitch()); -+ -+ if ((delta > 1f / 256 || deltaAngle > 10f) && !this.player.isImmobile()) { -+ this.lastPosX = to.getX(); -+ this.lastPosY = to.getY(); -+ this.lastPosZ = to.getZ(); -+ this.lastYaw = to.getYaw(); -+ this.lastPitch = to.getPitch(); -+ -+ Location oldTo = to.clone(); -+ PlayerMoveEvent event = new PlayerMoveEvent(player, from, to); -+ this.cserver.getPluginManager().callEvent(event); -+ -+ // If the event is cancelled we move the player back to their old location. -+ if (event.isCancelled()) { -+ this.teleport(from); -+ return; -+ } -+ -+ // If a Plugin has changed the To destination then we teleport the Player -+ // there to avoid any 'Moved wrongly' or 'Moved too quickly' errors. -+ // We only do this if the Event was not cancelled. -+ if (!oldTo.equals(event.getTo()) && !event.isCancelled()) { -+ this.player.getBukkitEntity().teleport(event.getTo(), PlayerTeleportEvent.TeleportCause.PLUGIN); -+ return; -+ } -+ -+ // Check to see if the Players Location has some how changed during the call of the event. -+ // This can happen due to a plugin teleporting the player instead of using .setTo() -+ if (!from.equals(this.getCraftPlayer().getLocation()) && this.justTeleported) { -+ this.justTeleported = false; -+ return; -+ } -+ } -+ // CraftBukkit end - - this.player.serverLevel().getChunkSource().move(this.player); - rootVehicle.recordMovementThroughBlocks(new Vec3(x, y, z), rootVehicle.position()); @@ -455,7 +_,7 @@ rootVehicle.setOnGroundWithMovement(packet.onGround(), vec3); rootVehicle.doCheckFallDamage(vec3.x, vec3.y, vec3.z, packet.onGround());