From fb5b173c6a742c584413c8fc8b7c871d79234756 Mon Sep 17 00:00:00 2001 From: EnZaXD Date: Sat, 25 Jan 2025 21:47:08 +0100 Subject: [PATCH] Add PlayerClientLoadedWorldEvent (#11940) --- .../player/PlayerClientLoadedWorldEvent.java | 46 +++++++++++++++++++ ...on-checking-in-player-move-packet-ha.patch | 10 ++-- .../ServerGamePacketListenerImpl.java.patch | 15 +++++- .../world/entity/player/Player.java.patch | 22 +++++++++ 4 files changed, 87 insertions(+), 6 deletions(-) create mode 100644 paper-api/src/main/java/io/papermc/paper/event/player/PlayerClientLoadedWorldEvent.java diff --git a/paper-api/src/main/java/io/papermc/paper/event/player/PlayerClientLoadedWorldEvent.java b/paper-api/src/main/java/io/papermc/paper/event/player/PlayerClientLoadedWorldEvent.java new file mode 100644 index 000000000..1b97997ee --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/event/player/PlayerClientLoadedWorldEvent.java @@ -0,0 +1,46 @@ +package io.papermc.paper.event.player; + +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * Called when a player is marked as loaded. + *

+ * This either happens when the player notifies the server after loading the world (closing the downloading terrain screen) + * or when the player has not done so for 60 ticks after joining the server or respawning. + */ +@NullMarked +public class PlayerClientLoadedWorldEvent extends PlayerEvent { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private final boolean timeout; + + @ApiStatus.Internal + public PlayerClientLoadedWorldEvent(final Player who, final boolean timeout) { + super(who); + this.timeout = timeout; + } + + /** + * True if the event was triggered because the server has not been notified by the player + * for 60 ticks after the player joined the server or respawned. + * + * @return true if the event was triggered because of a timeout + */ + public boolean isTimeout() { + return timeout; + } + + @Override + public HandlerList getHandlers() { + return HANDLER_LIST; + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } +} 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 77a7a836d..00cdbd326 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 @@ -88,7 +88,7 @@ index 3aad9ee86d6af392f4a98022cbc88bb53000e7be..27ef385a85b13ceb58e8d14984998310 } @Override -@@ -1361,7 +1393,7 @@ public class ServerGamePacketListenerImpl +@@ -1368,7 +1400,7 @@ public class ServerGamePacketListenerImpl } } @@ -97,7 +97,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 -@@ -1400,6 +1432,7 @@ public class ServerGamePacketListenerImpl +@@ -1407,6 +1439,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 +105,7 @@ index 3aad9ee86d6af392f4a98022cbc88bb53000e7be..27ef385a85b13ceb58e8d14984998310 // Paper start - prevent position desync if (this.awaitingPositionFromClient != null) { return; // ... thanks Mojang for letting move calls teleport across dimensions. -@@ -1432,7 +1465,17 @@ public class ServerGamePacketListenerImpl +@@ -1439,7 +1472,17 @@ public class ServerGamePacketListenerImpl } // Paper start - Add fail move event @@ -124,7 +124,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); -@@ -1568,7 +1611,7 @@ public class ServerGamePacketListenerImpl +@@ -1575,7 +1618,7 @@ public class ServerGamePacketListenerImpl private boolean updateAwaitingTeleport() { if (this.awaitingPositionFromClient != null) { @@ -133,7 +133,7 @@ index 3aad9ee86d6af392f4a98022cbc88bb53000e7be..27ef385a85b13ceb58e8d14984998310 this.awaitingTeleportTime = this.tickCount; this.teleport( this.awaitingPositionFromClient.x, -@@ -1587,6 +1630,33 @@ public class ServerGamePacketListenerImpl +@@ -1594,6 +1637,33 @@ public class ServerGamePacketListenerImpl } } 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 7b1d2a2d2..e485e7c21 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 @@ -373,7 +373,7 @@ this.awaitingPositionFromClient.x, this.awaitingPositionFromClient.y, this.awaitingPositionFromClient.z, -@@ -495,6 +_,7 @@ +@@ -495,12 +_,20 @@ this.lastGoodZ = this.awaitingPositionFromClient.z; this.player.hasChangedDimension(); this.awaitingPositionFromClient = null; @@ -381,6 +381,19 @@ } } + @Override + public void handleAcceptPlayerLoad(ServerboundPlayerLoadedPacket packet) { + PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); ++ // Paper start - PlayerLoadedWorldEvent ++ if (this.player.hasClientLoaded()) { ++ return; ++ } ++ final io.papermc.paper.event.player.PlayerClientLoadedWorldEvent event = new io.papermc.paper.event.player.PlayerClientLoadedWorldEvent(this.player.getBukkitEntity(), false); ++ event.callEvent(); ++ // Paper end - PlayerLoadedWorldEvent + this.player.setClientLoaded(true); + } + @@ -521,6 +_,7 @@ @Override public void handleRecipeBookChangeSettingsPacket(ServerboundRecipeBookChangeSettingsPacket packet) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch index 83e1b14b2..5e8dba7c7 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch @@ -674,3 +674,25 @@ for (int i = 0; i < this.inventory.getContainerSize(); i++) { ItemStack item = this.inventory.getItem(i); +@@ -2089,12 +_,20 @@ + } + + public boolean hasClientLoaded() { +- return this.clientLoaded || this.clientLoadedTimeoutTimer <= 0; ++ return this.clientLoaded; // Paper - Add PlayerLoadedWorldEvent + } + + public void tickClientLoadTimeout() { + if (!this.clientLoaded) { + this.clientLoadedTimeoutTimer--; ++ // Paper start - Add PlayerLoadedWorldEvent ++ if (this.clientLoadedTimeoutTimer <= 0) { ++ this.clientLoaded = true; ++ ++ final io.papermc.paper.event.player.PlayerClientLoadedWorldEvent event = new io.papermc.paper.event.player.PlayerClientLoadedWorldEvent((org.bukkit.craftbukkit.entity.CraftPlayer) getBukkitEntity(), true); ++ event.callEvent(); ++ } ++ // Paper end - Add PlayerLoadedWorldEvent + } + } +