From 9b64e3d79899e51111b15ef5ede07736401af765 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Thu, 12 Mar 2026 15:49:17 +0100 Subject: [PATCH 1/3] Fix AFK bypass via fishing rod and incorrect teleportOfflineUnknown player name --- .../essentials/EssentialsPlayerListener.java | 87 +++++++------------ .../essentials/commands/Commandtpoffline.java | 2 +- 2 files changed, 30 insertions(+), 59 deletions(-) diff --git a/Essentials/src/main/java/com/earth2me/essentials/EssentialsPlayerListener.java b/Essentials/src/main/java/com/earth2me/essentials/EssentialsPlayerListener.java index c1fb775d7b4..b6435b6a9d3 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/EssentialsPlayerListener.java +++ b/Essentials/src/main/java/com/earth2me/essentials/EssentialsPlayerListener.java @@ -9,33 +9,19 @@ import com.earth2me.essentials.textreader.TextInput; import com.earth2me.essentials.textreader.TextPager; import com.earth2me.essentials.userstorage.ModernUserMap; -import com.earth2me.essentials.utils.CommonPlaceholders; -import com.earth2me.essentials.utils.DateUtil; -import com.earth2me.essentials.utils.FormatUtil; -import com.earth2me.essentials.utils.LocationUtil; -import com.earth2me.essentials.utils.MaterialUtil; -import com.earth2me.essentials.utils.VersionUtil; +import com.earth2me.essentials.utils.*; import io.papermc.lib.PaperLib; import io.papermc.paper.ban.BanListType; import io.papermc.paper.event.connection.configuration.AsyncPlayerConnectionConfigureEvent; import io.papermc.paper.event.player.PlayerServerFullCheckEvent; import net.ess3.api.IEssentials; import net.ess3.api.events.AfkStatusChangeEvent; -import net.ess3.provider.CommandSendListenerProvider; -import net.ess3.provider.FormattedCommandAliasProvider; -import net.ess3.provider.InventoryViewProvider; -import net.ess3.provider.KnownCommandsProvider; -import net.ess3.provider.TickCountProvider; +import net.ess3.provider.*; import net.ess3.provider.providers.BukkitCommandSendListenerProvider; import net.ess3.provider.providers.PaperCommandSendListenerProvider; import net.essentialsx.PaperAdventureSmuggler; import net.essentialsx.api.v2.events.AsyncUserDataLoadEvent; -import org.bukkit.BanEntry; -import org.bukkit.BanList; -import org.bukkit.GameMode; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; +import org.bukkit.*; import org.bukkit.command.Command; import org.bukkit.command.FormattedCommandAlias; import org.bukkit.command.PluginCommand; @@ -45,26 +31,8 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import org.bukkit.event.inventory.ClickType; -import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.event.inventory.InventoryCloseEvent; -import org.bukkit.event.inventory.InventoryDragEvent; -import org.bukkit.event.inventory.InventoryType; -import org.bukkit.event.player.AsyncPlayerChatEvent; -import org.bukkit.event.player.AsyncPlayerPreLoginEvent; -import org.bukkit.event.player.PlayerBucketEmptyEvent; -import org.bukkit.event.player.PlayerChangedWorldEvent; -import org.bukkit.event.player.PlayerCommandPreprocessEvent; -import org.bukkit.event.player.PlayerEggThrowEvent; -import org.bukkit.event.player.PlayerFishEvent; -import org.bukkit.event.player.PlayerGameModeChangeEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerLoginEvent; -import org.bukkit.event.player.PlayerMoveEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.event.player.PlayerRespawnEvent; -import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.event.inventory.*; +import org.bukkit.event.player.*; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; @@ -74,16 +42,8 @@ import java.io.IOException; import java.lang.management.ManagementFactory; import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.Set; -import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; import java.util.function.Predicate; @@ -454,13 +414,13 @@ private void joinFlow(final User user, final long currentTime, final String mess effectiveMessage = null; } else if (ess.getSettings().isCustomJoinMessage()) { final String msg = (newUsername ? ess.getSettings().getCustomNewUsernameMessage() : ess.getSettings().getCustomJoinMessage()) - .replace("{PLAYER}", user.getDisplayName()).replace("{USERNAME}", user.getName()) - .replace("{UNIQUE}", NumberFormat.getInstance().format(ess.getUsers().getUserCount())) - .replace("{ONLINE}", NumberFormat.getInstance().format(ess.getOnlinePlayers().size())) - .replace("{UPTIME}", DateUtil.formatDateDiff(ManagementFactory.getRuntimeMXBean().getStartTime())) - .replace("{PREFIX}", FormatUtil.replaceFormat(ess.getPermissionsHandler().getPrefix(user.getBase()))) - .replace("{SUFFIX}", FormatUtil.replaceFormat(ess.getPermissionsHandler().getSuffix(user.getBase()))) - .replace("{OLDUSERNAME}", lastAccountName == null ? "" : lastAccountName); + .replace("{PLAYER}", user.getDisplayName()).replace("{USERNAME}", user.getName()) + .replace("{UNIQUE}", NumberFormat.getInstance().format(ess.getUsers().getUserCount())) + .replace("{ONLINE}", NumberFormat.getInstance().format(ess.getOnlinePlayers().size())) + .replace("{UPTIME}", DateUtil.formatDateDiff(ManagementFactory.getRuntimeMXBean().getStartTime())) + .replace("{PREFIX}", FormatUtil.replaceFormat(ess.getPermissionsHandler().getPrefix(user.getBase()))) + .replace("{SUFFIX}", FormatUtil.replaceFormat(ess.getPermissionsHandler().getSuffix(user.getBase()))) + .replace("{OLDUSERNAME}", lastAccountName == null ? "" : lastAccountName); effectiveMessage = msg.isEmpty() ? null : msg; } else if (ess.getSettings().allowSilentJoinQuit()) { effectiveMessage = message; @@ -760,7 +720,7 @@ public void onPlayerCommandPreprocess(final PlayerCommandPreprocessEvent event) final String cmd = event.getMessage().split(" ")[0].replace("/", "").toLowerCase(Locale.ENGLISH); final int argStartIndex = event.getMessage().indexOf(" "); final String args = argStartIndex == -1 ? "" // No arguments present - : event.getMessage().substring(argStartIndex); // arguments start at argStartIndex; substring from there. + : event.getMessage().substring(argStartIndex); // arguments start at argStartIndex; substring from there. // If the plugin command does not exist, check if it is an alias from commands.yml if (ess.getServer().getPluginCommand(cmd) == null) { @@ -792,8 +752,8 @@ public void handlePlayerCommandPreprocess(final PlayerCommandPreprocessEvent eve for (final User spyer : ess.getOnlineUsers()) { if (spyer.isSocialSpyEnabled() && !player.equals(spyer.getBase())) { final ComponentHolder base = (user.isMuted() && ess.getSettings().getSocialSpyListenMutedPlayers()) - ? spyer.tlComponent("socialSpyMutedPrefix") - : spyer.tlComponent("socialSpyPrefix"); + ? spyer.tlComponent("socialSpyMutedPrefix") + : spyer.tlComponent("socialSpyPrefix"); final ComponentHolder nameComponent = ess.getAdventureFacet().legacyToAdventure(playerName); final ComponentHolder messageComponent = ess.getAdventureFacet().text(": " + event.getMessage()); @@ -1174,6 +1134,17 @@ public void onInventoryCloseEvent(final InventoryCloseEvent event) { @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onPlayerFishEvent(final PlayerFishEvent event) { + + final PlayerFishEvent.State state = event.getState(); + + // Only count real player interaction + if (state != PlayerFishEvent.State.FISHING + && state != PlayerFishEvent.State.REEL_IN + && state != PlayerFishEvent.State.CAUGHT_FISH + && state != PlayerFishEvent.State.CAUGHT_ENTITY) { + return; + } + final User user = ess.getUser(event.getPlayer()); user.updateActivityOnInteract(true); } @@ -1273,8 +1244,8 @@ private boolean isEssentialsCommand(final String label) { final PluginCommand command = ess.getServer().getPluginCommand(label); return command != null - && (command.getPlugin() == ess || command.getPlugin().getClass().getName().startsWith("com.earth2me.essentials") || command.getPlugin().getClass().getName().startsWith("net.essentialsx")) - && (ess.getSettings().isCommandOverridden(label) || ess.getAlternativeCommandsHandler().getAlternative(label) == null); + && (command.getPlugin() == ess || command.getPlugin().getClass().getName().startsWith("com.earth2me.essentials") || command.getPlugin().getClass().getName().startsWith("net.essentialsx")) + && (ess.getSettings().isCommandOverridden(label) || ess.getAlternativeCommandsHandler().getAlternative(label) == null); } } } diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandtpoffline.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandtpoffline.java index 5448aa7cfeb..cc4f31c0e32 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandtpoffline.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandtpoffline.java @@ -21,7 +21,7 @@ public void run(final Server server, final User user, final String label, final final Location logout = target.getLogoutLocation(); if (logout == null) { - user.sendTl("teleportOfflineUnknown", user.getDisplayName()); + user.sendTl("teleportOfflineUnknown", target.getDisplayName()); throw new NoChargeException(); } From 79a961014f425ea0137e8d12c3d0d748b15c1117 Mon Sep 17 00:00:00 2001 From: JRoy <10731363+JRoy@users.noreply.github.com> Date: Sat, 4 Apr 2026 13:07:19 -0700 Subject: [PATCH 2/3] formatting --- .../essentials/EssentialsPlayerListener.java | 76 ++++++++++++++----- 1 file changed, 58 insertions(+), 18 deletions(-) diff --git a/Essentials/src/main/java/com/earth2me/essentials/EssentialsPlayerListener.java b/Essentials/src/main/java/com/earth2me/essentials/EssentialsPlayerListener.java index b6435b6a9d3..0fedea23fe3 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/EssentialsPlayerListener.java +++ b/Essentials/src/main/java/com/earth2me/essentials/EssentialsPlayerListener.java @@ -9,19 +9,33 @@ import com.earth2me.essentials.textreader.TextInput; import com.earth2me.essentials.textreader.TextPager; import com.earth2me.essentials.userstorage.ModernUserMap; -import com.earth2me.essentials.utils.*; +import com.earth2me.essentials.utils.CommonPlaceholders; +import com.earth2me.essentials.utils.DateUtil; +import com.earth2me.essentials.utils.FormatUtil; +import com.earth2me.essentials.utils.LocationUtil; +import com.earth2me.essentials.utils.MaterialUtil; +import com.earth2me.essentials.utils.VersionUtil; import io.papermc.lib.PaperLib; import io.papermc.paper.ban.BanListType; import io.papermc.paper.event.connection.configuration.AsyncPlayerConnectionConfigureEvent; import io.papermc.paper.event.player.PlayerServerFullCheckEvent; import net.ess3.api.IEssentials; import net.ess3.api.events.AfkStatusChangeEvent; -import net.ess3.provider.*; +import net.ess3.provider.CommandSendListenerProvider; +import net.ess3.provider.FormattedCommandAliasProvider; +import net.ess3.provider.InventoryViewProvider; +import net.ess3.provider.KnownCommandsProvider; +import net.ess3.provider.TickCountProvider; import net.ess3.provider.providers.BukkitCommandSendListenerProvider; import net.ess3.provider.providers.PaperCommandSendListenerProvider; import net.essentialsx.PaperAdventureSmuggler; import net.essentialsx.api.v2.events.AsyncUserDataLoadEvent; -import org.bukkit.*; +import org.bukkit.BanEntry; +import org.bukkit.BanList; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.command.Command; import org.bukkit.command.FormattedCommandAlias; import org.bukkit.command.PluginCommand; @@ -31,8 +45,26 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import org.bukkit.event.inventory.*; -import org.bukkit.event.player.*; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.inventory.InventoryDragEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.AsyncPlayerPreLoginEvent; +import org.bukkit.event.player.PlayerBucketEmptyEvent; +import org.bukkit.event.player.PlayerChangedWorldEvent; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.player.PlayerEggThrowEvent; +import org.bukkit.event.player.PlayerFishEvent; +import org.bukkit.event.player.PlayerGameModeChangeEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerLoginEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerRespawnEvent; +import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; @@ -42,8 +74,16 @@ import java.io.IOException; import java.lang.management.ManagementFactory; import java.text.NumberFormat; -import java.util.*; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; import java.util.Map.Entry; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; import java.util.function.Predicate; @@ -414,13 +454,13 @@ private void joinFlow(final User user, final long currentTime, final String mess effectiveMessage = null; } else if (ess.getSettings().isCustomJoinMessage()) { final String msg = (newUsername ? ess.getSettings().getCustomNewUsernameMessage() : ess.getSettings().getCustomJoinMessage()) - .replace("{PLAYER}", user.getDisplayName()).replace("{USERNAME}", user.getName()) - .replace("{UNIQUE}", NumberFormat.getInstance().format(ess.getUsers().getUserCount())) - .replace("{ONLINE}", NumberFormat.getInstance().format(ess.getOnlinePlayers().size())) - .replace("{UPTIME}", DateUtil.formatDateDiff(ManagementFactory.getRuntimeMXBean().getStartTime())) - .replace("{PREFIX}", FormatUtil.replaceFormat(ess.getPermissionsHandler().getPrefix(user.getBase()))) - .replace("{SUFFIX}", FormatUtil.replaceFormat(ess.getPermissionsHandler().getSuffix(user.getBase()))) - .replace("{OLDUSERNAME}", lastAccountName == null ? "" : lastAccountName); + .replace("{PLAYER}", user.getDisplayName()).replace("{USERNAME}", user.getName()) + .replace("{UNIQUE}", NumberFormat.getInstance().format(ess.getUsers().getUserCount())) + .replace("{ONLINE}", NumberFormat.getInstance().format(ess.getOnlinePlayers().size())) + .replace("{UPTIME}", DateUtil.formatDateDiff(ManagementFactory.getRuntimeMXBean().getStartTime())) + .replace("{PREFIX}", FormatUtil.replaceFormat(ess.getPermissionsHandler().getPrefix(user.getBase()))) + .replace("{SUFFIX}", FormatUtil.replaceFormat(ess.getPermissionsHandler().getSuffix(user.getBase()))) + .replace("{OLDUSERNAME}", lastAccountName == null ? "" : lastAccountName); effectiveMessage = msg.isEmpty() ? null : msg; } else if (ess.getSettings().allowSilentJoinQuit()) { effectiveMessage = message; @@ -720,7 +760,7 @@ public void onPlayerCommandPreprocess(final PlayerCommandPreprocessEvent event) final String cmd = event.getMessage().split(" ")[0].replace("/", "").toLowerCase(Locale.ENGLISH); final int argStartIndex = event.getMessage().indexOf(" "); final String args = argStartIndex == -1 ? "" // No arguments present - : event.getMessage().substring(argStartIndex); // arguments start at argStartIndex; substring from there. + : event.getMessage().substring(argStartIndex); // arguments start at argStartIndex; substring from there. // If the plugin command does not exist, check if it is an alias from commands.yml if (ess.getServer().getPluginCommand(cmd) == null) { @@ -752,8 +792,8 @@ public void handlePlayerCommandPreprocess(final PlayerCommandPreprocessEvent eve for (final User spyer : ess.getOnlineUsers()) { if (spyer.isSocialSpyEnabled() && !player.equals(spyer.getBase())) { final ComponentHolder base = (user.isMuted() && ess.getSettings().getSocialSpyListenMutedPlayers()) - ? spyer.tlComponent("socialSpyMutedPrefix") - : spyer.tlComponent("socialSpyPrefix"); + ? spyer.tlComponent("socialSpyMutedPrefix") + : spyer.tlComponent("socialSpyPrefix"); final ComponentHolder nameComponent = ess.getAdventureFacet().legacyToAdventure(playerName); final ComponentHolder messageComponent = ess.getAdventureFacet().text(": " + event.getMessage()); @@ -1244,8 +1284,8 @@ private boolean isEssentialsCommand(final String label) { final PluginCommand command = ess.getServer().getPluginCommand(label); return command != null - && (command.getPlugin() == ess || command.getPlugin().getClass().getName().startsWith("com.earth2me.essentials") || command.getPlugin().getClass().getName().startsWith("net.essentialsx")) - && (ess.getSettings().isCommandOverridden(label) || ess.getAlternativeCommandsHandler().getAlternative(label) == null); + && (command.getPlugin() == ess || command.getPlugin().getClass().getName().startsWith("com.earth2me.essentials") || command.getPlugin().getClass().getName().startsWith("net.essentialsx")) + && (ess.getSettings().isCommandOverridden(label) || ess.getAlternativeCommandsHandler().getAlternative(label) == null); } } } From 8900bbf1890c53c2a46dc5788c43ce1a9a872d8e Mon Sep 17 00:00:00 2001 From: JRoy <10731363+JRoy@users.noreply.github.com> Date: Sat, 4 Apr 2026 19:00:37 -0700 Subject: [PATCH 3/3] setting --- .../earth2me/essentials/EssentialsPlayerListener.java | 9 +-------- .../src/main/java/com/earth2me/essentials/ISettings.java | 2 ++ .../src/main/java/com/earth2me/essentials/Settings.java | 5 +++++ Essentials/src/main/resources/config.yml | 9 ++++++--- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Essentials/src/main/java/com/earth2me/essentials/EssentialsPlayerListener.java b/Essentials/src/main/java/com/earth2me/essentials/EssentialsPlayerListener.java index 0fedea23fe3..efd64c56b02 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/EssentialsPlayerListener.java +++ b/Essentials/src/main/java/com/earth2me/essentials/EssentialsPlayerListener.java @@ -1174,14 +1174,7 @@ public void onInventoryCloseEvent(final InventoryCloseEvent event) { @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onPlayerFishEvent(final PlayerFishEvent event) { - - final PlayerFishEvent.State state = event.getState(); - - // Only count real player interaction - if (state != PlayerFishEvent.State.FISHING - && state != PlayerFishEvent.State.REEL_IN - && state != PlayerFishEvent.State.CAUGHT_FISH - && state != PlayerFishEvent.State.CAUGHT_ENTITY) { + if (!ess.getSettings().cancelAfkOnFish()) { return; } diff --git a/Essentials/src/main/java/com/earth2me/essentials/ISettings.java b/Essentials/src/main/java/com/earth2me/essentials/ISettings.java index 0ba2d7d9c14..857dd0ce226 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/ISettings.java +++ b/Essentials/src/main/java/com/earth2me/essentials/ISettings.java @@ -221,6 +221,8 @@ public interface ISettings extends IConf { boolean cancelAfkOnChat(); + boolean cancelAfkOnFish(); + boolean sleepIgnoresAfkPlayers(); boolean sleepIgnoresVanishedPlayers(); diff --git a/Essentials/src/main/java/com/earth2me/essentials/Settings.java b/Essentials/src/main/java/com/earth2me/essentials/Settings.java index 8d41da405e7..136a448ba5d 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Settings.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Settings.java @@ -1320,6 +1320,11 @@ public boolean cancelAfkOnChat() { return config.getBoolean("cancel-afk-on-chat", true); } + @Override + public boolean cancelAfkOnFish() { + return config.getBoolean("cancel-afk-on-fish", true); + } + @Override public boolean sleepIgnoresAfkPlayers() { return sleepIgnoresAfkPlayers; diff --git a/Essentials/src/main/resources/config.yml b/Essentials/src/main/resources/config.yml index 5c87444d9fb..25bbf68d716 100644 --- a/Essentials/src/main/resources/config.yml +++ b/Essentials/src/main/resources/config.yml @@ -491,7 +491,7 @@ auto-afk: 300 auto-afk-timeout: -1 # A list of commands to be executed instead of kicking the player once the -# threshold defined above in 'afk-auto-timeout' is reached. If this list is empty +# threshold defined above in 'afk-auto-timeout' is reached. If this list is empty # and 'afk-auto-timeout' is not set to -1, Essentials will default to # kicking the player once they reach the timeout threshold. # @@ -527,6 +527,9 @@ cancel-afk-on-move: true # Should Essentials automatically remove AFK status when a player sends a chat message? cancel-afk-on-chat: true +# Should Essentials automatically remove AFK status when a player uses a fishing rod? +cancel-afk-on-fish: true + # Should AFK players be ignored when other players are trying to sleep? # When this setting is false, players won't be able to skip the night if some players are AFK. # Players with the permission 'essentials.sleepingignored' will always be ignored. @@ -897,8 +900,8 @@ baltop-requirements: minimum-balance: 0 minimum-playtime: 0 -# Limit the number of cached balance top entries. -# Recommended for servers with a large number of players, as it reduces memory usage. +# Limit the number of cached balance top entries. +# Recommended for servers with a large number of players, as it reduces memory usage. # Set to -1 to disable the limit. baltop-entry-limit: -1