From 205b890bb1c11d6c74a23fef269907406af1b5a3 Mon Sep 17 00:00:00 2001 From: EarthCow <56940983+EarthCow@users.noreply.github.com> Date: Fri, 31 Oct 2025 17:00:57 -0400 Subject: [PATCH 01/17] Config leave msg cache option --- src/main/resources/config.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index a59a76f..79910f9 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -111,6 +111,13 @@ Messages: ConsoleSilentJoin: "Join message was silenced. %player% joined the network" ConsoleSilentLeave: "Leave message was silenced. %player% left the network" Settings: + # As PAPIProxyBridge is unable to parse placeholders for offline players, a cache for the leave network message must + # be implemented. By default, this cache will only be updated when a player joins, swaps, leaves, or the plugin is + # reloaded but for placeholders that frequently change such as experience level, armor rating, etc. you may wish for + # this cache to occur more often. + # Designate how long in seconds the leave network message will be cached or use 0 for default behavior. + LeaveNetworkMessageCacheDuration: 0 + # Should players with the networkjoinmessages.silent permission be silenced by default? # It will be set to this for all players after a reboot. They can toggle it for themselves with the /njoinspoof toggle command SilentJoinDefaultState: true @@ -206,4 +213,4 @@ OtherPlugins: debug: false # Do not touch this -config-version: 8 \ No newline at end of file +config-version: 9 \ No newline at end of file From c02330fa84b0fd67c278495ae72cbc4002151760 Mon Sep 17 00:00:00 2001 From: EarthCow <56940983+EarthCow@users.noreply.github.com> Date: Fri, 31 Oct 2025 17:33:55 -0400 Subject: [PATCH 02/17] Implements default leave msg cache behavior --- .../bungee/abstraction/BungeePlayer.java | 10 ++++++++++ .../networkjoinmessages/common/MessageHandler.java | 4 ++++ .../common/abstraction/CorePlayer.java | 3 +++ .../common/listeners/CorePlayerListener.java | 10 +++++++--- .../velocity/abstraction/VelocityPlayer.java | 10 ++++++++++ 5 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/bungee/abstraction/BungeePlayer.java b/src/main/java/xyz/earthcow/networkjoinmessages/bungee/abstraction/BungeePlayer.java index 64b1cb8..d915e5c 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/bungee/abstraction/BungeePlayer.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/bungee/abstraction/BungeePlayer.java @@ -16,6 +16,7 @@ public class BungeePlayer implements CorePlayer { private final ProxiedPlayer bungeePlayer; private CoreBackendServer lastKnownConnectedServer; private final Audience audience; + private String cachedLeaveMessage; public BungeePlayer(ProxiedPlayer bungeePlayer) { this.bungeePlayer = bungeePlayer; @@ -77,4 +78,13 @@ public void setLastKnownConnectedServer(CoreBackendServer server) { public boolean isInLimbo() { return false; } + + @Override + public String getCachedLeaveMessage() { + return cachedLeaveMessage; + } + @Override + public void setCachedLeaveMessage(String cachedLeaveMessage) { + this.cachedLeaveMessage = cachedLeaveMessage; + } } diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/common/MessageHandler.java b/src/main/java/xyz/earthcow/networkjoinmessages/common/MessageHandler.java index eb42ddf..4102b1d 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/common/MessageHandler.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/common/MessageHandler.java @@ -28,6 +28,10 @@ public MessageHandler(CorePlugin plugin, Storage storage, Formatter formatter, @ this.sayanVanishHook = sayanVanishHook; } + public void updateCachedLeaveMessage(CorePlayer player) { + formatter.parsePlaceholdersAndThen(formatLeaveMessage(player), player, player::setCachedLeaveMessage); + } + /** * Sends a message to the specified command sender. * If the command sender is a CorePlayer object diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/common/abstraction/CorePlayer.java b/src/main/java/xyz/earthcow/networkjoinmessages/common/abstraction/CorePlayer.java index c52c062..0256b9c 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/common/abstraction/CorePlayer.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/common/abstraction/CorePlayer.java @@ -24,4 +24,7 @@ public interface CorePlayer extends CoreCommandSender { Audience getAudience(); boolean isInLimbo(); + + String getCachedLeaveMessage(); + void setCachedLeaveMessage(String cachedLeaveMessage); } diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java b/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java index 4fd37e3..d0a0e06 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java @@ -161,6 +161,8 @@ private void handlePlayerJoin(@NotNull CorePlayer player, @NotNull CoreBackendSe storage.setConnected(player, true); player.setLastKnownConnectedServer(server); + messageHandler.updateCachedLeaveMessage(player); + boolean firstJoin = !firstJoinTracker.hasJoined(player.getUniqueId()); MessageType msgType = firstJoin ? MessageType.FIRST_JOIN : MessageType.JOIN; @@ -204,6 +206,8 @@ private void handlePlayerJoin(@NotNull CorePlayer player, @NotNull CoreBackendSe private void handlePlayerSwap(@NotNull CorePlayer player, @NotNull CoreBackendServer server, boolean fromLimbo) { player.setLastKnownConnectedServer(server); + messageHandler.updateCachedLeaveMessage(player); + String to = server.getName(); String from = storage.getFrom(player); @@ -282,13 +286,13 @@ public void onDisconnect(@NotNull CorePlayer player) { return; } - String message = messageHandler.formatLeaveMessage(player); + String message = player.getCachedLeaveMessage(); // Silent boolean isSilent = isSilentEvent(player); - // Broadcast message - messageHandler.broadcastMessage(message, MessageType.LEAVE, player, isSilent); + // Broadcast message - NULL parseTarget skips parsing placeholders + messageHandler.broadcastMessage(message, MessageType.LEAVE, null, isSilent); Component formattedMessage = Formatter.deserialize(message); // Call the custom NetworkLeaveEvent diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/velocity/abstraction/VelocityPlayer.java b/src/main/java/xyz/earthcow/networkjoinmessages/velocity/abstraction/VelocityPlayer.java index ea13ac2..96e80b1 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/velocity/abstraction/VelocityPlayer.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/velocity/abstraction/VelocityPlayer.java @@ -17,6 +17,7 @@ public class VelocityPlayer implements CorePlayer { private final Player velocityPlayer; private CoreBackendServer lastKnownConnectedServer; private final Audience audience; + private String cachedLeaveMessage; public VelocityPlayer(Player velocityPlayer) { this.velocityPlayer = velocityPlayer; @@ -84,4 +85,13 @@ public boolean isInLimbo() { //noinspection ConstantValue return ((ConnectedPlayer) velocityPlayer).getConnection().getState().name() == null; } + + @Override + public String getCachedLeaveMessage() { + return cachedLeaveMessage; + } + @Override + public void setCachedLeaveMessage(String cachedLeaveMessage) { + this.cachedLeaveMessage = cachedLeaveMessage; + } } From 5ff8f277a7ea6c2d3a8cf7355d4e09e21c3d7a89 Mon Sep 17 00:00:00 2001 From: EarthCow <56940983+EarthCow@users.noreply.github.com> Date: Sat, 1 Nov 2025 14:48:10 -0400 Subject: [PATCH 03/17] Prevents broadcastMessage exception --- .../common/listeners/CorePlayerListener.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java b/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java index d0a0e06..798e6a1 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java @@ -291,8 +291,8 @@ public void onDisconnect(@NotNull CorePlayer player) { // Silent boolean isSilent = isSilentEvent(player); - // Broadcast message - NULL parseTarget skips parsing placeholders - messageHandler.broadcastMessage(message, MessageType.LEAVE, null, isSilent); + // Broadcast message - NULL parseTarget skips parsing placeholders in sendMessage + messageHandler.broadcastMessage(message, MessageType.LEAVE, player.getCurrentServer().getName(), "", null, isSilent); Component formattedMessage = Formatter.deserialize(message); // Call the custom NetworkLeaveEvent From e34bceab1bd797543366e6bd37a8e28d35420cc9 Mon Sep 17 00:00:00 2001 From: EarthCow <56940983+EarthCow@users.noreply.github.com> Date: Sat, 1 Nov 2025 14:59:54 -0400 Subject: [PATCH 04/17] Update cached msg on reload --- .../xyz/earthcow/networkjoinmessages/common/Core.java | 2 +- .../common/commands/CoreReloadCommand.java | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/common/Core.java b/src/main/java/xyz/earthcow/networkjoinmessages/common/Core.java index b62b71d..f8df566 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/common/Core.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/common/Core.java @@ -50,7 +50,7 @@ public Core(CorePlugin plugin) { this.coreImportCommand = new CoreImportCommand(corePlayerListener.getPlayerJoinTracker()); this.coreSpoofCommand = new CoreSpoofCommand(plugin, storage, messageHandler); - this.coreReloadCommand = new CoreReloadCommand(configManager, storage, discordIntegration, messageHandler); + this.coreReloadCommand = new CoreReloadCommand(plugin, configManager, storage, discordIntegration, messageHandler); this.coreToggleJoinCommand = new CoreToggleJoinCommand(storage, messageHandler); } diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/common/commands/CoreReloadCommand.java b/src/main/java/xyz/earthcow/networkjoinmessages/common/commands/CoreReloadCommand.java index b5b63c5..c7a9030 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/common/commands/CoreReloadCommand.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/common/commands/CoreReloadCommand.java @@ -4,18 +4,21 @@ import xyz.earthcow.networkjoinmessages.common.MessageHandler; import xyz.earthcow.networkjoinmessages.common.Storage; import xyz.earthcow.networkjoinmessages.common.abstraction.CoreCommandSender; +import xyz.earthcow.networkjoinmessages.common.abstraction.CorePlugin; import xyz.earthcow.networkjoinmessages.common.modules.DiscordIntegration; import java.util.List; public class CoreReloadCommand implements Command { + private final CorePlugin plugin; private final ConfigManager configManager; private final Storage storage; private final DiscordIntegration discordIntegration; private final MessageHandler messageHandler; - public CoreReloadCommand(ConfigManager configManager, Storage storage, DiscordIntegration discordIntegration, MessageHandler messageHandler) { + public CoreReloadCommand(CorePlugin plugin, ConfigManager configManager, Storage storage, DiscordIntegration discordIntegration, MessageHandler messageHandler) { + this.plugin = plugin; this.configManager = configManager; this.storage = storage; this.discordIntegration = discordIntegration; @@ -29,6 +32,11 @@ public void execute(CoreCommandSender coreCommandSender, String[] args) { storage.setUpDefaultValuesFromConfig(); discordIntegration.loadVariables(); + // Update all player's cached leave message + plugin.runTaskAsync(() -> + plugin.getAllPlayers().forEach(messageHandler::updateCachedLeaveMessage) + ); + messageHandler.sendMessage(coreCommandSender, storage.getReloadConfirmation() ); From b9884a082a4948876899818cb8441b7b380f34b9 Mon Sep 17 00:00:00 2001 From: EarthCow <56940983+EarthCow@users.noreply.github.com> Date: Sat, 1 Nov 2025 15:01:40 -0400 Subject: [PATCH 05/17] Send reload confirmation after msg update --- .../common/commands/CoreReloadCommand.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/common/commands/CoreReloadCommand.java b/src/main/java/xyz/earthcow/networkjoinmessages/common/commands/CoreReloadCommand.java index c7a9030..800fc4b 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/common/commands/CoreReloadCommand.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/common/commands/CoreReloadCommand.java @@ -33,13 +33,12 @@ public void execute(CoreCommandSender coreCommandSender, String[] args) { discordIntegration.loadVariables(); // Update all player's cached leave message - plugin.runTaskAsync(() -> - plugin.getAllPlayers().forEach(messageHandler::updateCachedLeaveMessage) - ); - - messageHandler.sendMessage(coreCommandSender, - storage.getReloadConfirmation() - ); + plugin.runTaskAsync(() -> { + plugin.getAllPlayers().forEach(messageHandler::updateCachedLeaveMessage); + messageHandler.sendMessage(coreCommandSender, + storage.getReloadConfirmation() + ); + }); } } From 09f5cc158691442bda2f58b227140a1f20b19858 Mon Sep 17 00:00:00 2001 From: EarthCow <56940983+EarthCow@users.noreply.github.com> Date: Sat, 1 Nov 2025 15:09:16 -0400 Subject: [PATCH 06/17] Adds leave cache duration to storage --- .../xyz/earthcow/networkjoinmessages/common/Storage.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/common/Storage.java b/src/main/java/xyz/earthcow/networkjoinmessages/common/Storage.java index 157ba41..812131f 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/common/Storage.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/common/Storage.java @@ -85,6 +85,9 @@ public final class Storage { @Getter private String consoleSilentLeave; + @Getter + private int leaveCacheDuration; + /** * The default silent state of a player joining with the networkjoinmessages.silent permission * Default: true - Someone joining with the permission will be silent (not send a join message) @@ -206,6 +209,8 @@ public void setUpDefaultValuesFromConfig() { /// Settings + this.leaveCacheDuration = config.getInt("Settings.LeaveNetworkMessageCacheDuration"); + this.silentJoinDefaultState = config.getBoolean("Settings.SilentJoinDefaultState"); this.swapServerMessageEnabled = config.getBoolean("Settings.SwapServerMessageEnabled"); @@ -594,6 +599,8 @@ public String getLeaveNetworkMessage() { public Collection getCustomCharts() { List customCharts = new ArrayList<>(); + customCharts.add(new SimplePie("leave_cache_duration", () -> String.valueOf(swapServerMessageEnabled))); + customCharts.add(new SimplePie("swap_enabled", () -> String.valueOf(swapServerMessageEnabled))); customCharts.add(new SimplePie("first_join_enabled", () -> String.valueOf(firstJoinNetworkMessageEnabled))); customCharts.add(new SimplePie("join_enabled", () -> String.valueOf(joinNetworkMessageEnabled))); From d77f330180f31c2aefbae0d2b5c8cfce6b34bcb7 Mon Sep 17 00:00:00 2001 From: EarthCow <56940983+EarthCow@users.noreply.github.com> Date: Sat, 1 Nov 2025 16:05:44 -0400 Subject: [PATCH 07/17] Implements cache tasks --- .../bungee/BungeeMain.java | 9 +++++-- .../common/MessageHandler.java | 27 +++++++++++++++++++ .../networkjoinmessages/common/Storage.java | 12 ++++++++- .../common/abstraction/CorePlugin.java | 3 ++- .../common/commands/CoreReloadCommand.java | 1 + .../common/listeners/CorePlayerListener.java | 3 +++ .../velocity/VelocityMain.java | 23 ++++++++++++++-- 7 files changed, 72 insertions(+), 6 deletions(-) diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/bungee/BungeeMain.java b/src/main/java/xyz/earthcow/networkjoinmessages/bungee/BungeeMain.java index e9975ea..af4d9db 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/bungee/BungeeMain.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/bungee/BungeeMain.java @@ -180,8 +180,13 @@ public PremiumVanish getVanishAPI() { } @Override - public void runTaskLater(Runnable task, int timeInSecondsLater) { - getProxy().getScheduler().schedule(this, task, timeInSecondsLater, TimeUnit.SECONDS); + public void cancelTask(int taskId) { + getProxy().getScheduler().cancel(taskId); + } + + @Override + public int runTaskRepeatedly(Runnable task, int timeInSecondsLater) { + return getProxy().getScheduler().schedule(this, task, timeInSecondsLater, timeInSecondsLater, TimeUnit.SECONDS).getId(); } @Override diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/common/MessageHandler.java b/src/main/java/xyz/earthcow/networkjoinmessages/common/MessageHandler.java index 4102b1d..03f2d4c 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/common/MessageHandler.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/common/MessageHandler.java @@ -18,6 +18,8 @@ public final class MessageHandler { private final Storage storage; private final Formatter formatter; + private final Map taskIds = new HashMap<>(); + @Nullable private final SayanVanishHook sayanVanishHook; @@ -26,6 +28,31 @@ public MessageHandler(CorePlugin plugin, Storage storage, Formatter formatter, @ this.storage = storage; this.formatter = formatter; this.sayanVanishHook = sayanVanishHook; + initCacheTasks(); + } + + public void initCacheTasks() { + taskIds.values().forEach(plugin::cancelTask); + taskIds.clear(); + if (storage.getLeaveCacheDuration() == 0) return; + for (CorePlayer player : plugin.getAllPlayers()) { + startLeaveCacheTaskForPlayer(player); + } + } + + public void startLeaveCacheTaskForPlayer(CorePlayer player) { + if (storage.getLeaveCacheDuration() == 0) return; + taskIds.put( + player.getUniqueId(), + plugin.runTaskRepeatedly(() -> updateCachedLeaveMessage(player), storage.getLeaveCacheDuration()) + ); + } + + public void stopLeaveCacheTaskForPlayer(CorePlayer player) { + if (taskIds.isEmpty()) return; + Integer taskId = taskIds.remove(player.getUniqueId()); + if (taskId == null) return; + plugin.cancelTask(taskId); } public void updateCachedLeaveMessage(CorePlayer player) { diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/common/Storage.java b/src/main/java/xyz/earthcow/networkjoinmessages/common/Storage.java index 812131f..74b89c3 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/common/Storage.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/common/Storage.java @@ -14,7 +14,7 @@ import java.util.*; /** - * Singleton class for holding config values and user data that should persist after the user leaves the proxy + * Class for holding config values and user data that should persist after the user leaves the proxy */ public final class Storage { @@ -271,6 +271,16 @@ public void setUpDefaultValuesFromConfig() { ); this.swapServerMessageRequires = "ANY"; } + + // Verify leave cache duration + if (leaveCacheDuration < 0) { + plugin.getCoreLogger() + .info( + "Setting error: Settings.LeaveNetworkMessageCacheDuration " + + "requires a non-negative value. Defaulting to 0 behavior." + ); + this.leaveCacheDuration = 0; + } } public boolean getSilentMessageState(CorePlayer player) { diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/common/abstraction/CorePlugin.java b/src/main/java/xyz/earthcow/networkjoinmessages/common/abstraction/CorePlugin.java index 7cdbc78..4808070 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/common/abstraction/CorePlugin.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/common/abstraction/CorePlugin.java @@ -26,7 +26,8 @@ public interface CorePlugin { PremiumVanish getVanishAPI(); - void runTaskLater(Runnable task, int timeInSecondsLater); + void cancelTask(int taskId); + int runTaskRepeatedly(Runnable task, int timeInSecondsLater); void runTaskAsync(Runnable task); boolean isPluginLoaded(String pluginName); diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/common/commands/CoreReloadCommand.java b/src/main/java/xyz/earthcow/networkjoinmessages/common/commands/CoreReloadCommand.java index 800fc4b..7651ed8 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/common/commands/CoreReloadCommand.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/common/commands/CoreReloadCommand.java @@ -31,6 +31,7 @@ public void execute(CoreCommandSender coreCommandSender, String[] args) { configManager.reload(); storage.setUpDefaultValuesFromConfig(); discordIntegration.loadVariables(); + messageHandler.initCacheTasks(); // Update all player's cached leave message plugin.runTaskAsync(() -> { diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java b/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java index 798e6a1..0cf1a9b 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java @@ -162,6 +162,7 @@ private void handlePlayerJoin(@NotNull CorePlayer player, @NotNull CoreBackendSe player.setLastKnownConnectedServer(server); messageHandler.updateCachedLeaveMessage(player); + messageHandler.startLeaveCacheTaskForPlayer(player); boolean firstJoin = !firstJoinTracker.hasJoined(player.getUniqueId()); MessageType msgType = firstJoin ? MessageType.FIRST_JOIN : MessageType.JOIN; @@ -283,6 +284,7 @@ public void onDisconnect(@NotNull CorePlayer player) { if (shouldNotBroadcast(player, MessageType.LEAVE)) { plugin.getPlayerManager().removePlayer(player.getUniqueId()); storage.setConnected(player, false); + messageHandler.stopLeaveCacheTaskForPlayer(player); return; } @@ -308,6 +310,7 @@ public void onDisconnect(@NotNull CorePlayer player) { plugin.getPlayerManager().removePlayer(player.getUniqueId()); storage.setConnected(player, false); + messageHandler.stopLeaveCacheTaskForPlayer(player); } public H2PlayerJoinTracker getPlayerJoinTracker() { diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/velocity/VelocityMain.java b/src/main/java/xyz/earthcow/networkjoinmessages/velocity/VelocityMain.java index 37022dc..dfc6ec6 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/velocity/VelocityMain.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/velocity/VelocityMain.java @@ -10,6 +10,7 @@ import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.server.RegisteredServer; +import com.velocitypowered.api.scheduler.ScheduledTask; import lombok.Getter; import org.bstats.charts.CustomChart; import org.bstats.velocity.Metrics; @@ -28,10 +29,12 @@ import java.io.File; import java.nio.file.Path; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.UUID; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import java.util.stream.Collectors; @Plugin( @@ -69,6 +72,8 @@ public class VelocityMain implements CorePlugin { private VelocityDiscordListener velocityDiscordListener = null; + private final List tasks = new ArrayList<>(); + @Inject public VelocityMain(ProxyServer proxy, Logger logger, @DataDirectory Path dataDirectory, Metrics.Factory metricsFactory) { this.proxy = proxy; @@ -169,8 +174,22 @@ public void unregisterDiscordListener() { } @Override - public void runTaskLater(Runnable task, int timeInSecondsLater) { - proxy.getScheduler().buildTask(this, task).delay(timeInSecondsLater, TimeUnit.SECONDS).schedule(); + public void cancelTask(int taskId) { + try { + tasks.get(taskId).cancel(); + } catch (IndexOutOfBoundsException ignored) { + } + } + + @Override + public int runTaskRepeatedly(Runnable task, int timeInSecondsLater) { + tasks.add( + proxy.getScheduler().buildTask(this, scheduledTask -> { + task.run(); + tasks.remove(scheduledTask); + }).delay(timeInSecondsLater, TimeUnit.SECONDS).repeat(timeInSecondsLater, TimeUnit.SECONDS).schedule() + ); + return tasks.size() - 1; } @Override From f029e316199d480e40adadcb2d3b810b2ace4602 Mon Sep 17 00:00:00 2001 From: EarthCow <56940983+EarthCow@users.noreply.github.com> Date: Sat, 1 Nov 2025 16:07:19 -0400 Subject: [PATCH 08/17] Fix player object in debug msg --- .../common/listeners/CorePlayerListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java b/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java index 0cf1a9b..01cc79e 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java @@ -52,7 +52,7 @@ public CorePlayerListener(CorePlugin plugin, Storage storage, MessageHandler mes private boolean isSilentEvent(@NotNull CorePlayer player) { // Event is silent if, the player has a silent message state OR // premiumVanish is present, the treat vanished players as silent option is true, and the player is vanished - plugin.getCoreLogger().debug("Checking if the event for player " + player + " should been silent:"); + plugin.getCoreLogger().debug("Checking if the event for player " + player.getName() + " should been silent:"); plugin.getCoreLogger().debug(String.format( "silent message state: %s, SayanVanish hook is NOT null: %s, SVTreatVanishedPlayersAsSilent: %s, " + "SayanVanish player is vanished: %s, PremiumVanish hook is NOT null: %s, " + From 05aca5851da7ab1d36e3adb842f44d0955356d28 Mon Sep 17 00:00:00 2001 From: EarthCow <56940983+EarthCow@users.noreply.github.com> Date: Sat, 1 Nov 2025 16:17:47 -0400 Subject: [PATCH 09/17] Adds processingLeave list; possibly fixes #29 --- .../common/listeners/CorePlayerListener.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java b/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java index 4fd37e3..55c5ad5 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java @@ -14,6 +14,10 @@ import xyz.earthcow.networkjoinmessages.common.util.H2PlayerJoinTracker; import xyz.earthcow.networkjoinmessages.common.util.MessageType; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + public class CorePlayerListener { private final CorePlugin plugin; @@ -21,6 +25,7 @@ public class CorePlayerListener { private final MessageHandler messageHandler; private H2PlayerJoinTracker firstJoinTracker; + private final List processingLeave = new ArrayList<>(); @Nullable private final SayanVanishHook sayanVanishHook; @@ -52,7 +57,7 @@ public CorePlayerListener(CorePlugin plugin, Storage storage, MessageHandler mes private boolean isSilentEvent(@NotNull CorePlayer player) { // Event is silent if, the player has a silent message state OR // premiumVanish is present, the treat vanished players as silent option is true, and the player is vanished - plugin.getCoreLogger().debug("Checking if the event for player " + player + " should been silent:"); + plugin.getCoreLogger().debug("Checking if the event for player " + player.getName() + " should been silent:"); plugin.getCoreLogger().debug(String.format( "silent message state: %s, SayanVanish hook is NOT null: %s, SVTreatVanishedPlayersAsSilent: %s, " + "SayanVanish player is vanished: %s, PremiumVanish hook is NOT null: %s, " + @@ -275,10 +280,17 @@ public void onServerConnected(@NotNull CorePlayer player, @NotNull CoreBackendSe * @param player Trigger player */ public void onDisconnect(@NotNull CorePlayer player) { + if (processingLeave.contains(player.getUniqueId())) { + plugin.getCoreLogger().debug("Disconnect event ignored for player " + player.getName() + + ", due to another disconnect event already processing them"); + return; + } + processingLeave.add(player.getUniqueId()); if (shouldNotBroadcast(player, MessageType.LEAVE)) { plugin.getPlayerManager().removePlayer(player.getUniqueId()); storage.setConnected(player, false); + processingLeave.remove(player.getUniqueId()); return; } @@ -304,6 +316,7 @@ public void onDisconnect(@NotNull CorePlayer player) { plugin.getPlayerManager().removePlayer(player.getUniqueId()); storage.setConnected(player, false); + processingLeave.remove(player.getUniqueId()); } public H2PlayerJoinTracker getPlayerJoinTracker() { From 123b3084e160401a466407dd4481d41fd8d8b2d8 Mon Sep 17 00:00:00 2001 From: EarthCow <56940983+EarthCow@users.noreply.github.com> Date: Sun, 2 Nov 2025 22:54:15 -0500 Subject: [PATCH 10/17] Revert "Adds processingLeave list; possibly fixes #29" This reverts commit 05aca5851da7ab1d36e3adb842f44d0955356d28. --- .../common/listeners/CorePlayerListener.java | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java b/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java index 55c5ad5..4fd37e3 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java @@ -14,10 +14,6 @@ import xyz.earthcow.networkjoinmessages.common.util.H2PlayerJoinTracker; import xyz.earthcow.networkjoinmessages.common.util.MessageType; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - public class CorePlayerListener { private final CorePlugin plugin; @@ -25,7 +21,6 @@ public class CorePlayerListener { private final MessageHandler messageHandler; private H2PlayerJoinTracker firstJoinTracker; - private final List processingLeave = new ArrayList<>(); @Nullable private final SayanVanishHook sayanVanishHook; @@ -57,7 +52,7 @@ public CorePlayerListener(CorePlugin plugin, Storage storage, MessageHandler mes private boolean isSilentEvent(@NotNull CorePlayer player) { // Event is silent if, the player has a silent message state OR // premiumVanish is present, the treat vanished players as silent option is true, and the player is vanished - plugin.getCoreLogger().debug("Checking if the event for player " + player.getName() + " should been silent:"); + plugin.getCoreLogger().debug("Checking if the event for player " + player + " should been silent:"); plugin.getCoreLogger().debug(String.format( "silent message state: %s, SayanVanish hook is NOT null: %s, SVTreatVanishedPlayersAsSilent: %s, " + "SayanVanish player is vanished: %s, PremiumVanish hook is NOT null: %s, " + @@ -280,17 +275,10 @@ public void onServerConnected(@NotNull CorePlayer player, @NotNull CoreBackendSe * @param player Trigger player */ public void onDisconnect(@NotNull CorePlayer player) { - if (processingLeave.contains(player.getUniqueId())) { - plugin.getCoreLogger().debug("Disconnect event ignored for player " + player.getName() + - ", due to another disconnect event already processing them"); - return; - } - processingLeave.add(player.getUniqueId()); if (shouldNotBroadcast(player, MessageType.LEAVE)) { plugin.getPlayerManager().removePlayer(player.getUniqueId()); storage.setConnected(player, false); - processingLeave.remove(player.getUniqueId()); return; } @@ -316,7 +304,6 @@ public void onDisconnect(@NotNull CorePlayer player) { plugin.getPlayerManager().removePlayer(player.getUniqueId()); storage.setConnected(player, false); - processingLeave.remove(player.getUniqueId()); } public H2PlayerJoinTracker getPlayerJoinTracker() { From 867d8aff1836aacee1c7c15efaa145a289942170 Mon Sep 17 00:00:00 2001 From: EarthCow <56940983+EarthCow@users.noreply.github.com> Date: Sun, 2 Nov 2025 22:57:42 -0500 Subject: [PATCH 11/17] Adds CorePlayer#isDisconnecting --- .../common/abstraction/CorePlayer.java | 3 +++ .../common/listeners/CorePlayerListener.java | 2 ++ .../velocity/abstraction/VelocityPlayer.java | 11 +++++++++++ 3 files changed, 16 insertions(+) diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/common/abstraction/CorePlayer.java b/src/main/java/xyz/earthcow/networkjoinmessages/common/abstraction/CorePlayer.java index c52c062..535f335 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/common/abstraction/CorePlayer.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/common/abstraction/CorePlayer.java @@ -24,4 +24,7 @@ public interface CorePlayer extends CoreCommandSender { Audience getAudience(); boolean isInLimbo(); + + boolean isDisconnecting(); + void setDisconnecting(); } diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java b/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java index 4fd37e3..53e37cd 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java @@ -275,6 +275,8 @@ public void onServerConnected(@NotNull CorePlayer player, @NotNull CoreBackendSe * @param player Trigger player */ public void onDisconnect(@NotNull CorePlayer player) { + if (player.isDisconnecting()) return; + player.setDisconnecting(); if (shouldNotBroadcast(player, MessageType.LEAVE)) { plugin.getPlayerManager().removePlayer(player.getUniqueId()); diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/velocity/abstraction/VelocityPlayer.java b/src/main/java/xyz/earthcow/networkjoinmessages/velocity/abstraction/VelocityPlayer.java index ea13ac2..f09d384 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/velocity/abstraction/VelocityPlayer.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/velocity/abstraction/VelocityPlayer.java @@ -17,6 +17,7 @@ public class VelocityPlayer implements CorePlayer { private final Player velocityPlayer; private CoreBackendServer lastKnownConnectedServer; private final Audience audience; + private boolean disconnecting = false; public VelocityPlayer(Player velocityPlayer) { this.velocityPlayer = velocityPlayer; @@ -84,4 +85,14 @@ public boolean isInLimbo() { //noinspection ConstantValue return ((ConnectedPlayer) velocityPlayer).getConnection().getState().name() == null; } + + @Override + public boolean isDisconnecting() { + return disconnecting; + } + + @Override + public void setDisconnecting() { + this.disconnecting = true; + } } From bb3e7ef5ee1232eda2ee81850130633d0fd2bf14 Mon Sep 17 00:00:00 2001 From: EarthCow <56940983+EarthCow@users.noreply.github.com> Date: Sun, 2 Nov 2025 23:01:03 -0500 Subject: [PATCH 12/17] Better cache duration default --- src/main/resources/config.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 79910f9..0a5dd87 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -112,11 +112,11 @@ Messages: ConsoleSilentLeave: "Leave message was silenced. %player% left the network" Settings: # As PAPIProxyBridge is unable to parse placeholders for offline players, a cache for the leave network message must - # be implemented. By default, this cache will only be updated when a player joins, swaps, leaves, or the plugin is - # reloaded but for placeholders that frequently change such as experience level, armor rating, etc. you may wish for - # this cache to occur more often. - # Designate how long in seconds the leave network message will be cached or use 0 for default behavior. - LeaveNetworkMessageCacheDuration: 0 + # be implemented. For placeholders that frequently change such as experience level, armor rating, etc. you may wish + # for this cache to update more often. + # Designate how long in seconds the leave network message will be cached or use 0 to only update cache on join and + # server swap. + LeaveNetworkMessageCacheDuration: 45 # Should players with the networkjoinmessages.silent permission be silenced by default? # It will be set to this for all players after a reboot. They can toggle it for themselves with the /njoinspoof toggle command From 74787d71333bc02a88c351768fe06ad23372e096 Mon Sep 17 00:00:00 2001 From: EarthCow <56940983+EarthCow@users.noreply.github.com> Date: Sun, 2 Nov 2025 23:05:19 -0500 Subject: [PATCH 13/17] Bump version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 2fe978a..b2649ee 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ # Project metadata group=xyz.earthcow.networkjoinmessages -version=3.1.0 +version=3.2.0 description=A plugin handling join, leave and swap messages for proxy servers. # Plugin.yml metadata From 6ac2171f4cbffc4100dd07cd89cffc826713fe0e Mon Sep 17 00:00:00 2001 From: EarthCow <56940983+EarthCow@users.noreply.github.com> Date: Sun, 2 Nov 2025 23:08:37 -0500 Subject: [PATCH 14/17] Debug message for updating cache --- .../xyz/earthcow/networkjoinmessages/common/MessageHandler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/common/MessageHandler.java b/src/main/java/xyz/earthcow/networkjoinmessages/common/MessageHandler.java index 03f2d4c..ebf71a2 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/common/MessageHandler.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/common/MessageHandler.java @@ -56,6 +56,7 @@ public void stopLeaveCacheTaskForPlayer(CorePlayer player) { } public void updateCachedLeaveMessage(CorePlayer player) { + plugin.getCoreLogger().debug("Updating cached leave message for player " + player.getName()); formatter.parsePlaceholdersAndThen(formatLeaveMessage(player), player, player::setCachedLeaveMessage); } From 107a3d6d29aa453fd02994311fac6c6a71e5d11f Mon Sep 17 00:00:00 2001 From: EarthCow <56940983+EarthCow@users.noreply.github.com> Date: Sun, 2 Nov 2025 23:21:12 -0500 Subject: [PATCH 15/17] Stop removing ScheduledTask id from list --- .../earthcow/networkjoinmessages/velocity/VelocityMain.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/velocity/VelocityMain.java b/src/main/java/xyz/earthcow/networkjoinmessages/velocity/VelocityMain.java index dfc6ec6..afb3030 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/velocity/VelocityMain.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/velocity/VelocityMain.java @@ -184,10 +184,8 @@ public void cancelTask(int taskId) { @Override public int runTaskRepeatedly(Runnable task, int timeInSecondsLater) { tasks.add( - proxy.getScheduler().buildTask(this, scheduledTask -> { - task.run(); - tasks.remove(scheduledTask); - }).delay(timeInSecondsLater, TimeUnit.SECONDS).repeat(timeInSecondsLater, TimeUnit.SECONDS).schedule() + proxy.getScheduler().buildTask(this, task) + .delay(timeInSecondsLater, TimeUnit.SECONDS).repeat(timeInSecondsLater, TimeUnit.SECONDS).schedule() ); return tasks.size() - 1; } From 76a41619d2e32818107c314812435fa6b652fceb Mon Sep 17 00:00:00 2001 From: EarthCow <56940983+EarthCow@users.noreply.github.com> Date: Sun, 2 Nov 2025 23:40:44 -0500 Subject: [PATCH 16/17] BungeePlayer disconnecting field --- .../bungee/abstraction/BungeePlayer.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/bungee/abstraction/BungeePlayer.java b/src/main/java/xyz/earthcow/networkjoinmessages/bungee/abstraction/BungeePlayer.java index d915e5c..59a0687 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/bungee/abstraction/BungeePlayer.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/bungee/abstraction/BungeePlayer.java @@ -17,6 +17,7 @@ public class BungeePlayer implements CorePlayer { private CoreBackendServer lastKnownConnectedServer; private final Audience audience; private String cachedLeaveMessage; + private boolean disconnecting = false; public BungeePlayer(ProxiedPlayer bungeePlayer) { this.bungeePlayer = bungeePlayer; @@ -87,4 +88,13 @@ public String getCachedLeaveMessage() { public void setCachedLeaveMessage(String cachedLeaveMessage) { this.cachedLeaveMessage = cachedLeaveMessage; } + + @Override + public boolean isDisconnecting() { + return disconnecting; + } + @Override + public void setDisconnecting() { + this.disconnecting = true; + } } From 79277af794b5d997499f170309cc1c8e5f8f7ac3 Mon Sep 17 00:00:00 2001 From: EarthCow <56940983+EarthCow@users.noreply.github.com> Date: Sun, 2 Nov 2025 23:54:17 -0500 Subject: [PATCH 17/17] Duplicate disconnect debug msg --- .../common/listeners/CorePlayerListener.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java b/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java index d09a9a7..cf46597 100644 --- a/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java +++ b/src/main/java/xyz/earthcow/networkjoinmessages/common/listeners/CorePlayerListener.java @@ -280,7 +280,11 @@ public void onServerConnected(@NotNull CorePlayer player, @NotNull CoreBackendSe * @param player Trigger player */ public void onDisconnect(@NotNull CorePlayer player) { - if (player.isDisconnecting()) return; + if (player.isDisconnecting()) { + plugin.getCoreLogger().debug("Disconnect event ignored for player " + player.getName() + + ", due to another disconnect event already processing them"); + return; + } player.setDisconnecting(); if (shouldNotBroadcast(player, MessageType.LEAVE)) {