From db061ef00efae186ddf83bec045dad0a6012175f Mon Sep 17 00:00:00 2001 From: Ben Robson Date: Tue, 9 Dec 2025 22:07:40 +1100 Subject: [PATCH 01/13] Add Velocity chat rank formatting --- zander-velocity/README.md | 16 ++++ zander-velocity/pom.xml | 11 +++ .../java/net/cfc/zander/ZanderPlugin.java | 80 +++++++++++++++++++ .../src/main/resources/velocity-plugin.json | 13 +++ 4 files changed, 120 insertions(+) create mode 100644 zander-velocity/README.md create mode 100644 zander-velocity/src/main/java/net/cfc/zander/ZanderPlugin.java create mode 100644 zander-velocity/src/main/resources/velocity-plugin.json diff --git a/zander-velocity/README.md b/zander-velocity/README.md new file mode 100644 index 0000000..bb1e735 --- /dev/null +++ b/zander-velocity/README.md @@ -0,0 +1,16 @@ +# Zander Velocity + +Zander Velocity formats chat network-wide. Ensure each LuckPerms group defines readable metadata: + +``` +lp group admin meta set displayname "Admin" +lp group admin meta set rank_description "Has full access to staff & server tools." +``` + +`displayname` is used for the hover title (falling back to the prefix text or `Member`), and `rank_description` shows in the hover description (falling back to `No description set for this rank.`). The proxy resolves the highest-priority prefix for each player and renders chat as: + +``` +[Rank] Username: message +``` + +The bracketed rank prefix is hoverable and shows the rank name and description. diff --git a/zander-velocity/pom.xml b/zander-velocity/pom.xml index 8b37212..57e086e 100644 --- a/zander-velocity/pom.xml +++ b/zander-velocity/pom.xml @@ -87,6 +87,17 @@ 3.4.0-SNAPSHOT provided + + net.luckperms + api + 5.4 + provided + + + net.kyori + adventure-text-minimessage + 4.17.0 + com.googlecode.json-simple json-simple diff --git a/zander-velocity/src/main/java/net/cfc/zander/ZanderPlugin.java b/zander-velocity/src/main/java/net/cfc/zander/ZanderPlugin.java new file mode 100644 index 0000000..acb368e --- /dev/null +++ b/zander-velocity/src/main/java/net/cfc/zander/ZanderPlugin.java @@ -0,0 +1,80 @@ +package net.cfc.zander; + +import com.velocitypowered.api.event.Subscribe; +import com.velocitypowered.api.event.player.PlayerChatEvent; +import com.velocitypowered.api.plugin.Plugin; +import com.velocitypowered.api.proxy.Player; +import com.velocitypowered.api.proxy.ProxyServer; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.luckperms.api.LuckPerms; +import net.luckperms.api.LuckPermsProvider; +import net.luckperms.api.cacheddata.CachedMetaData; +import org.slf4j.Logger; + +import javax.inject.Inject; + +@Plugin(id = "zander", name = "Zander", version = "1.0.0", authors = {"CFC"}) +public class ZanderPlugin { + + private final ProxyServer proxyServer; + private final Logger logger; + private final LuckPerms luckPerms; + private final MiniMessage miniMessage; + + @Inject + public ZanderPlugin(final ProxyServer proxyServer, final Logger logger) { + this.proxyServer = proxyServer; + this.logger = logger; + this.luckPerms = LuckPermsProvider.get(); + this.miniMessage = MiniMessage.miniMessage(); + + this.proxyServer.getEventManager().register(this, this); + this.logger.info("Loaded Zander chat formatter for Velocity."); + } + + @Subscribe + public void onPlayerChat(final PlayerChatEvent event) { + final Player player = event.getPlayer(); + final CachedMetaData metaData = this.luckPerms.getPlayerAdapter(Player.class).getMetaData(player); + + final Component rankPrefix = buildRankPrefix(metaData); + final Component finalMessage = Component.text() + .append(rankPrefix) + .append(Component.space()) + .append(Component.text(player.getUsername())) + .append(Component.text(": ")) + .append(event.getMessage()) + .build(); + + event.setResult(PlayerChatEvent.ChatResult.message(finalMessage)); + } + + private Component buildRankPrefix(final CachedMetaData metaData) { + final String prefix = metaData.getPrefix(); + final String rankNameMeta = metaData.getMetaValue("displayname"); + final String rankDescriptionMeta = metaData.getMetaValue("rank_description"); + + final String rankName = (rankNameMeta != null && !rankNameMeta.isBlank()) + ? rankNameMeta + : (prefix != null && !prefix.isBlank() ? prefix : "Member"); + final String rankDescription = (rankDescriptionMeta != null && !rankDescriptionMeta.isBlank()) + ? rankDescriptionMeta + : "No description set for this rank."; + + final String safeRankName = MiniMessage.escapeTags(rankName); + final String safeRankDescription = MiniMessage.escapeTags(rankDescription); + final String hoverText = "" + escapeMiniMessageAttribute(safeRankName) + "\n" + + escapeMiniMessageAttribute(safeRankDescription) + ""; + + final String miniMessagePrefix = "" + + "[" + safeRankName + "]" + + ""; + + return this.miniMessage.deserialize(miniMessagePrefix); + } + + private String escapeMiniMessageAttribute(final String input) { + return input.replace("'", "\\'"); + } +} diff --git a/zander-velocity/src/main/resources/velocity-plugin.json b/zander-velocity/src/main/resources/velocity-plugin.json new file mode 100644 index 0000000..6347199 --- /dev/null +++ b/zander-velocity/src/main/resources/velocity-plugin.json @@ -0,0 +1,13 @@ +{ + "id": "zander", + "name": "Zander", + "version": "1.0.0", + "main": "net.cfc.zander.ZanderPlugin", + "authors": ["CFC"], + "dependencies": [ + { + "id": "luckperms", + "optional": false + } + ] +} From b889deb7785cdd58ef2ed1b13c0a24af0247f797 Mon Sep 17 00:00:00 2001 From: Ben Robson Date: Tue, 9 Dec 2025 23:24:12 +1100 Subject: [PATCH 02/13] Integrate LuckPerms chat formatting into Velocity --- zander-velocity/README.md | 4 +- .../java/net/cfc/zander/ZanderPlugin.java | 80 ------------------- .../zander/velocity/ZanderVelocityMain.java | 3 +- .../zander/velocity/events/UserChatEvent.java | 60 +++++++++++++- .../src/main/resources/velocity-plugin.json | 16 ++-- 5 files changed, 72 insertions(+), 91 deletions(-) delete mode 100644 zander-velocity/src/main/java/net/cfc/zander/ZanderPlugin.java diff --git a/zander-velocity/README.md b/zander-velocity/README.md index bb1e735..5e28b60 100644 --- a/zander-velocity/README.md +++ b/zander-velocity/README.md @@ -1,13 +1,13 @@ # Zander Velocity -Zander Velocity formats chat network-wide. Ensure each LuckPerms group defines readable metadata: +Zander Velocity formats network-wide chat directly on the proxy. To surface readable rank data, ensure each LuckPerms group defines the following metadata: ``` lp group admin meta set displayname "Admin" lp group admin meta set rank_description "Has full access to staff & server tools." ``` -`displayname` is used for the hover title (falling back to the prefix text or `Member`), and `rank_description` shows in the hover description (falling back to `No description set for this rank.`). The proxy resolves the highest-priority prefix for each player and renders chat as: +`displayname` appears in the hover title (falling back to the prefix text or `Member`), and `rank_description` appears in the hover description (falling back to `No description set for this rank.`). The proxy resolves the highest-priority prefix for each player and renders chat as: ``` [Rank] Username: message diff --git a/zander-velocity/src/main/java/net/cfc/zander/ZanderPlugin.java b/zander-velocity/src/main/java/net/cfc/zander/ZanderPlugin.java deleted file mode 100644 index acb368e..0000000 --- a/zander-velocity/src/main/java/net/cfc/zander/ZanderPlugin.java +++ /dev/null @@ -1,80 +0,0 @@ -package net.cfc.zander; - -import com.velocitypowered.api.event.Subscribe; -import com.velocitypowered.api.event.player.PlayerChatEvent; -import com.velocitypowered.api.plugin.Plugin; -import com.velocitypowered.api.proxy.Player; -import com.velocitypowered.api.proxy.ProxyServer; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.minimessage.MiniMessage; -import net.luckperms.api.LuckPerms; -import net.luckperms.api.LuckPermsProvider; -import net.luckperms.api.cacheddata.CachedMetaData; -import org.slf4j.Logger; - -import javax.inject.Inject; - -@Plugin(id = "zander", name = "Zander", version = "1.0.0", authors = {"CFC"}) -public class ZanderPlugin { - - private final ProxyServer proxyServer; - private final Logger logger; - private final LuckPerms luckPerms; - private final MiniMessage miniMessage; - - @Inject - public ZanderPlugin(final ProxyServer proxyServer, final Logger logger) { - this.proxyServer = proxyServer; - this.logger = logger; - this.luckPerms = LuckPermsProvider.get(); - this.miniMessage = MiniMessage.miniMessage(); - - this.proxyServer.getEventManager().register(this, this); - this.logger.info("Loaded Zander chat formatter for Velocity."); - } - - @Subscribe - public void onPlayerChat(final PlayerChatEvent event) { - final Player player = event.getPlayer(); - final CachedMetaData metaData = this.luckPerms.getPlayerAdapter(Player.class).getMetaData(player); - - final Component rankPrefix = buildRankPrefix(metaData); - final Component finalMessage = Component.text() - .append(rankPrefix) - .append(Component.space()) - .append(Component.text(player.getUsername())) - .append(Component.text(": ")) - .append(event.getMessage()) - .build(); - - event.setResult(PlayerChatEvent.ChatResult.message(finalMessage)); - } - - private Component buildRankPrefix(final CachedMetaData metaData) { - final String prefix = metaData.getPrefix(); - final String rankNameMeta = metaData.getMetaValue("displayname"); - final String rankDescriptionMeta = metaData.getMetaValue("rank_description"); - - final String rankName = (rankNameMeta != null && !rankNameMeta.isBlank()) - ? rankNameMeta - : (prefix != null && !prefix.isBlank() ? prefix : "Member"); - final String rankDescription = (rankDescriptionMeta != null && !rankDescriptionMeta.isBlank()) - ? rankDescriptionMeta - : "No description set for this rank."; - - final String safeRankName = MiniMessage.escapeTags(rankName); - final String safeRankDescription = MiniMessage.escapeTags(rankDescription); - final String hoverText = "" + escapeMiniMessageAttribute(safeRankName) + "\n" - + escapeMiniMessageAttribute(safeRankDescription) + ""; - - final String miniMessagePrefix = "" - + "[" + safeRankName + "]" - + ""; - - return this.miniMessage.deserialize(miniMessagePrefix); - } - - private String escapeMiniMessageAttribute(final String input) { - return input.replace("'", "\\'"); - } -} diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/ZanderVelocityMain.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/ZanderVelocityMain.java index 15a42c3..87a40bb 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/ZanderVelocityMain.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/ZanderVelocityMain.java @@ -41,7 +41,8 @@ name = "zander-velocity", version = "1.2.0", dependencies = { - @Dependency(id = "signedvelocity") + @Dependency(id = "signedvelocity"), + @Dependency(id = "luckperms") } ) public class ZanderVelocityMain { diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java index 2140a07..d071fbb 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java @@ -9,25 +9,34 @@ import io.github.ModularEnigma.Response; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.luckperms.api.LuckPerms; +import net.luckperms.api.LuckPermsProvider; +import net.luckperms.api.cacheddata.CachedMetaData; import org.modularsoft.zander.velocity.ZanderVelocityMain; import org.modularsoft.zander.velocity.model.Filter; import org.modularsoft.zander.velocity.model.discord.DiscordChat; public class UserChatEvent { + private final LuckPerms luckPerms = LuckPermsProvider.get(); + private final MiniMessage miniMessage = MiniMessage.miniMessage(); + @Subscribe public void UserChatEvent(PlayerChatEvent event) { Player player = event.getPlayer(); + Component originalMessage = event.getMessage(); + String rawMessage = originalMessage.toString(); String BaseAPIURL = ZanderVelocityMain.getConfig().getString(Route.from("BaseAPIURL")); String APIKey = ZanderVelocityMain.getConfig().getString(Route.from("APIKey")); // Filter out commands. - if (event.getMessage().startsWith("/")) return; + if (rawMessage.startsWith("/")) return; // Check chat for blocked content try { Filter phrase = Filter.builder() - .content(event.getMessage().toString()) + .content(rawMessage) .build(); Request phraseReq = Request.builder() @@ -49,11 +58,12 @@ public void UserChatEvent(PlayerChatEvent event) { Component builder = Component.text(phraseCaughtMessage).color(NamedTextColor.RED); player.sendMessage(builder); event.setResult(PlayerChatEvent.ChatResult.denied()); + return; } else { DiscordChat chat = DiscordChat.builder() .username(player.getUsername()) .server(player.getCurrentServer().get().getServer().getServerInfo().getName()) - .content(event.getMessage().toString()) + .content(rawMessage) .build(); Request discordChatReq = Request.builder() @@ -66,10 +76,54 @@ public void UserChatEvent(PlayerChatEvent event) { Response discordChatReqRes = discordChatReq.execute(); ZanderVelocityMain.getLogger().info("Response (" + discordChatReqRes.getStatusCode() + "): " + discordChatReqRes.getBody()); } + + Component formattedMessage = formatChatMessage(player, originalMessage); + event.setResult(PlayerChatEvent.ChatResult.message(formattedMessage)); } catch (Exception e) { Component builder = Component.text("The chat filter could not be reached at this time, there maybe an issue with the API.").color(NamedTextColor.YELLOW); player.sendMessage(builder); System.out.println(e); } } + + private Component formatChatMessage(Player player, Component originalMessage) { + CachedMetaData metaData = luckPerms.getPlayerAdapter(Player.class).getMetaData(player); + Component rankPrefix = buildRankPrefix(metaData); + + return Component.text() + .append(rankPrefix) + .append(Component.space()) + .append(Component.text(player.getUsername())) + .append(Component.text(": ")) + .append(originalMessage) + .build(); + } + + private Component buildRankPrefix(CachedMetaData metaData) { + String prefix = metaData.getPrefix(); + String rankNameMeta = metaData.getMetaValue("displayname"); + String rankDescriptionMeta = metaData.getMetaValue("rank_description"); + + String rankName = (rankNameMeta != null && !rankNameMeta.isBlank()) + ? rankNameMeta + : (prefix != null && !prefix.isBlank() ? prefix : "Member"); + String rankDescription = (rankDescriptionMeta != null && !rankDescriptionMeta.isBlank()) + ? rankDescriptionMeta + : "No description set for this rank."; + + String safeRankName = MiniMessage.escapeTags(rankName); + String safeRankDescription = MiniMessage.escapeTags(rankDescription); + String hoverText = "" + escapeMiniMessageAttribute(safeRankName) + "\\n" + + escapeMiniMessageAttribute(safeRankDescription) + ""; + + String miniMessagePrefix = "" + + "[" + safeRankName + "]" + + ""; + + return miniMessage.deserialize(miniMessagePrefix); + } + + private String escapeMiniMessageAttribute(String input) { + return input.replace("'", "\\'"); + } } diff --git a/zander-velocity/src/main/resources/velocity-plugin.json b/zander-velocity/src/main/resources/velocity-plugin.json index 6347199..dd7fe25 100644 --- a/zander-velocity/src/main/resources/velocity-plugin.json +++ b/zander-velocity/src/main/resources/velocity-plugin.json @@ -1,13 +1,19 @@ { - "id": "zander", - "name": "Zander", - "version": "1.0.0", - "main": "net.cfc.zander.ZanderPlugin", - "authors": ["CFC"], + "id": "zander-velocity", + "name": "zander-velocity", + "version": "1.2.0", + "main": "org.modularsoft.zander.velocity.ZanderVelocityMain", + "authors": [ + "ModularSoft" + ], "dependencies": [ { "id": "luckperms", "optional": false + }, + { + "id": "signedvelocity", + "optional": true } ] } From f645a2d432cef17038f70e4817e6d45dcaafefbd Mon Sep 17 00:00:00 2001 From: Ben Robson Date: Tue, 9 Dec 2025 23:30:17 +1100 Subject: [PATCH 03/13] Fix chat event message handling --- .../modularsoft/zander/velocity/events/UserChatEvent.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java index d071fbb..8caca5b 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java @@ -25,8 +25,8 @@ public class UserChatEvent { @Subscribe public void UserChatEvent(PlayerChatEvent event) { Player player = event.getPlayer(); - Component originalMessage = event.getMessage(); - String rawMessage = originalMessage.toString(); + String rawMessage = event.getMessage(); + Component originalMessage = Component.text(rawMessage); String BaseAPIURL = ZanderVelocityMain.getConfig().getString(Route.from("BaseAPIURL")); String APIKey = ZanderVelocityMain.getConfig().getString(Route.from("APIKey")); @@ -111,8 +111,8 @@ private Component buildRankPrefix(CachedMetaData metaData) { ? rankDescriptionMeta : "No description set for this rank."; - String safeRankName = MiniMessage.escapeTags(rankName); - String safeRankDescription = MiniMessage.escapeTags(rankDescription); + String safeRankName = miniMessage.escapeTags(rankName); + String safeRankDescription = miniMessage.escapeTags(rankDescription); String hoverText = "" + escapeMiniMessageAttribute(safeRankName) + "\\n" + escapeMiniMessageAttribute(safeRankDescription) + ""; From f1362007c6d66f6c931d031de4df28c0d8d7096c Mon Sep 17 00:00:00 2001 From: Ben Robson Date: Tue, 9 Dec 2025 23:33:51 +1100 Subject: [PATCH 04/13] Serialize chat result for PlayerChatEvent --- .../org/modularsoft/zander/velocity/events/UserChatEvent.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java index 8caca5b..b227a2b 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java @@ -78,7 +78,8 @@ public void UserChatEvent(PlayerChatEvent event) { } Component formattedMessage = formatChatMessage(player, originalMessage); - event.setResult(PlayerChatEvent.ChatResult.message(formattedMessage)); + String serializedMessage = miniMessage.serialize(formattedMessage); + event.setResult(PlayerChatEvent.ChatResult.message(serializedMessage)); } catch (Exception e) { Component builder = Component.text("The chat filter could not be reached at this time, there maybe an issue with the API.").color(NamedTextColor.YELLOW); player.sendMessage(builder); From 7afed95d5e0ca5a9e78ea0595f2e1c517bba819e Mon Sep 17 00:00:00 2001 From: Ben Robson Date: Wed, 10 Dec 2025 07:42:35 +1100 Subject: [PATCH 05/13] Fix chat prefix MiniMessage formatting --- .../zander/velocity/events/UserChatEvent.java | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java index b227a2b..6ad203e 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java @@ -10,6 +10,7 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import net.luckperms.api.LuckPerms; import net.luckperms.api.LuckPermsProvider; import net.luckperms.api.cacheddata.CachedMetaData; @@ -25,8 +26,8 @@ public class UserChatEvent { @Subscribe public void UserChatEvent(PlayerChatEvent event) { Player player = event.getPlayer(); - String rawMessage = event.getMessage(); - Component originalMessage = Component.text(rawMessage); + Component originalMessage = event.getMessage(); + String rawMessage = PlainTextComponentSerializer.plainText().serialize(originalMessage); String BaseAPIURL = ZanderVelocityMain.getConfig().getString(Route.from("BaseAPIURL")); String APIKey = ZanderVelocityMain.getConfig().getString(Route.from("APIKey")); @@ -78,8 +79,7 @@ public void UserChatEvent(PlayerChatEvent event) { } Component formattedMessage = formatChatMessage(player, originalMessage); - String serializedMessage = miniMessage.serialize(formattedMessage); - event.setResult(PlayerChatEvent.ChatResult.message(serializedMessage)); + event.setResult(PlayerChatEvent.ChatResult.message(formattedMessage)); } catch (Exception e) { Component builder = Component.text("The chat filter could not be reached at this time, there maybe an issue with the API.").color(NamedTextColor.YELLOW); player.sendMessage(builder); @@ -112,13 +112,14 @@ private Component buildRankPrefix(CachedMetaData metaData) { ? rankDescriptionMeta : "No description set for this rank."; - String safeRankName = miniMessage.escapeTags(rankName); - String safeRankDescription = miniMessage.escapeTags(rankDescription); - String hoverText = "" + escapeMiniMessageAttribute(safeRankName) + "\\n" - + escapeMiniMessageAttribute(safeRankDescription) + ""; + rankName = stripLegacy(rankName); + rankDescription = stripLegacy(rankDescription); - String miniMessagePrefix = "" - + "[" + safeRankName + "]" + String hoverText = "" + escapeMiniMessageContent(rankName) + "\n" + + "" + escapeMiniMessageContent(rankDescription) + ""; + + String miniMessagePrefix = "" + + "[" + escapeMiniMessageContent(rankName) + "]" + ""; return miniMessage.deserialize(miniMessagePrefix); @@ -127,4 +128,12 @@ private Component buildRankPrefix(CachedMetaData metaData) { private String escapeMiniMessageAttribute(String input) { return input.replace("'", "\\'"); } + + private String escapeMiniMessageContent(String input) { + return input.replace("<", "\\<").replace(">", "\\>"); + } + + private String stripLegacy(String input) { + return input.replaceAll("ยง.", "").replaceAll("&.", ""); + } } From 8c6ab3402ca94ddd49891ca5b24577626f21fc6f Mon Sep 17 00:00:00 2001 From: Ben Robson Date: Thu, 8 Jan 2026 18:26:13 +1100 Subject: [PATCH 06/13] Fix chat formatting for Velocity message API --- .../zander/velocity/events/UserChatEvent.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java index 6ad203e..f04aff6 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java @@ -10,7 +10,6 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.minimessage.MiniMessage; -import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import net.luckperms.api.LuckPerms; import net.luckperms.api.LuckPermsProvider; import net.luckperms.api.cacheddata.CachedMetaData; @@ -26,8 +25,8 @@ public class UserChatEvent { @Subscribe public void UserChatEvent(PlayerChatEvent event) { Player player = event.getPlayer(); - Component originalMessage = event.getMessage(); - String rawMessage = PlainTextComponentSerializer.plainText().serialize(originalMessage); + String rawMessage = event.getMessage(); + Component originalMessage = Component.text(rawMessage); String BaseAPIURL = ZanderVelocityMain.getConfig().getString(Route.from("BaseAPIURL")); String APIKey = ZanderVelocityMain.getConfig().getString(Route.from("APIKey")); @@ -79,7 +78,13 @@ public void UserChatEvent(PlayerChatEvent event) { } Component formattedMessage = formatChatMessage(player, originalMessage); - event.setResult(PlayerChatEvent.ChatResult.message(formattedMessage)); + player.getCurrentServer() + .map(serverConnection -> serverConnection.getServer()) + .ifPresentOrElse( + server -> server.getPlayersConnected().forEach(target -> target.sendMessage(formattedMessage)), + () -> player.sendMessage(formattedMessage) + ); + event.setResult(PlayerChatEvent.ChatResult.denied()); } catch (Exception e) { Component builder = Component.text("The chat filter could not be reached at this time, there maybe an issue with the API.").color(NamedTextColor.YELLOW); player.sendMessage(builder); From 65a0f5c1482c828b7c35ab230df6ebe738852b21 Mon Sep 17 00:00:00 2001 From: Ben Robson Date: Thu, 8 Jan 2026 18:36:08 +1100 Subject: [PATCH 07/13] Run chat handler at last post order --- .../org/modularsoft/zander/velocity/events/UserChatEvent.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java index f04aff6..b34495f 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java @@ -1,6 +1,7 @@ package org.modularsoft.zander.velocity.events; import com.jayway.jsonpath.JsonPath; +import com.velocitypowered.api.event.PostOrder; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.player.PlayerChatEvent; import com.velocitypowered.api.proxy.Player; @@ -22,7 +23,7 @@ public class UserChatEvent { private final LuckPerms luckPerms = LuckPermsProvider.get(); private final MiniMessage miniMessage = MiniMessage.miniMessage(); - @Subscribe + @Subscribe(order = PostOrder.LAST) public void UserChatEvent(PlayerChatEvent event) { Player player = event.getPlayer(); String rawMessage = event.getMessage(); From 5f5ec596ca81e793b548895bdbd20914906d1260 Mon Sep 17 00:00:00 2001 From: Ben Robson Date: Thu, 8 Jan 2026 18:54:50 +1100 Subject: [PATCH 08/13] Use legacy prefix and richer hover text --- .../zander/velocity/events/UserChatEvent.java | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java index b34495f..04f119f 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java @@ -9,8 +9,10 @@ import io.github.ModularEnigma.Request; import io.github.ModularEnigma.Response; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.luckperms.api.LuckPerms; import net.luckperms.api.LuckPermsProvider; import net.luckperms.api.cacheddata.CachedMetaData; @@ -121,18 +123,27 @@ private Component buildRankPrefix(CachedMetaData metaData) { rankName = stripLegacy(rankName); rankDescription = stripLegacy(rankDescription); - String hoverText = "" + escapeMiniMessageContent(rankName) + "\n" - + "" + escapeMiniMessageContent(rankDescription) + ""; - - String miniMessagePrefix = "" - + "[" + escapeMiniMessageContent(rankName) + "]" - + ""; + Component prefixComponent = buildPrefixComponent(prefix, rankName); + Component hoverText = Component.text() + .append(prefixComponent) + .append(Component.space()) + .append(Component.text(rankName).color(NamedTextColor.GOLD)) + .append(Component.newline()) + .append(Component.text(rankDescription).color(NamedTextColor.GRAY)) + .build(); - return miniMessage.deserialize(miniMessagePrefix); + return prefixComponent.hoverEvent(HoverEvent.showText(hoverText)); } - private String escapeMiniMessageAttribute(String input) { - return input.replace("'", "\\'"); + private Component buildPrefixComponent(String prefix, String rankName) { + if (prefix != null && !prefix.isBlank()) { + return LegacyComponentSerializer.legacyAmpersand().deserialize(prefix); + } + + String miniMessagePrefix = "[" + + escapeMiniMessageContent(rankName) + + "]"; + return miniMessage.deserialize(miniMessagePrefix); } private String escapeMiniMessageContent(String input) { From fe0bdd8372bcc0704160ae40f18bc7d23e69f9c0 Mon Sep 17 00:00:00 2001 From: Ben Robson Date: Thu, 8 Jan 2026 19:09:16 +1100 Subject: [PATCH 09/13] Support group-scoped rank meta keys --- .../zander/velocity/events/UserChatEvent.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java index 04f119f..3af271e 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java @@ -97,7 +97,8 @@ public void UserChatEvent(PlayerChatEvent event) { private Component formatChatMessage(Player player, Component originalMessage) { CachedMetaData metaData = luckPerms.getPlayerAdapter(Player.class).getMetaData(player); - Component rankPrefix = buildRankPrefix(metaData); + String primaryGroup = luckPerms.getPlayerAdapter(Player.class).getUser(player).getPrimaryGroup(); + Component rankPrefix = buildRankPrefix(metaData, primaryGroup); return Component.text() .append(rankPrefix) @@ -108,10 +109,10 @@ private Component formatChatMessage(Player player, Component originalMessage) { .build(); } - private Component buildRankPrefix(CachedMetaData metaData) { + private Component buildRankPrefix(CachedMetaData metaData, String primaryGroup) { String prefix = metaData.getPrefix(); - String rankNameMeta = metaData.getMetaValue("displayname"); - String rankDescriptionMeta = metaData.getMetaValue("rank_description"); + String rankNameMeta = getMetaValue(metaData, "displayname", primaryGroup); + String rankDescriptionMeta = getMetaValue(metaData, "rank_description", primaryGroup); String rankName = (rankNameMeta != null && !rankNameMeta.isBlank()) ? rankNameMeta @@ -135,6 +136,16 @@ private Component buildRankPrefix(CachedMetaData metaData) { return prefixComponent.hoverEvent(HoverEvent.showText(hoverText)); } + private String getMetaValue(CachedMetaData metaData, String baseKey, String primaryGroup) { + if (primaryGroup != null && !primaryGroup.isBlank()) { + String scopedValue = metaData.getMetaValue(baseKey + "." + primaryGroup); + if (scopedValue != null && !scopedValue.isBlank()) { + return scopedValue; + } + } + return metaData.getMetaValue(baseKey); + } + private Component buildPrefixComponent(String prefix, String rankName) { if (prefix != null && !prefix.isBlank()) { return LegacyComponentSerializer.legacyAmpersand().deserialize(prefix); From 30bae4750cc5b000b6f41f19b6cb0d49e962c640 Mon Sep 17 00:00:00 2001 From: Ben Robson Date: Fri, 9 Jan 2026 10:47:43 +1100 Subject: [PATCH 10/13] Match group-scoped meta keys case-insensitively --- .../zander/velocity/events/UserChatEvent.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java index 3af271e..064c8b5 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java @@ -20,6 +20,8 @@ import org.modularsoft.zander.velocity.model.Filter; import org.modularsoft.zander.velocity.model.discord.DiscordChat; +import java.util.Map; + public class UserChatEvent { private final LuckPerms luckPerms = LuckPermsProvider.get(); @@ -138,10 +140,20 @@ private Component buildRankPrefix(CachedMetaData metaData, String primaryGroup) private String getMetaValue(CachedMetaData metaData, String baseKey, String primaryGroup) { if (primaryGroup != null && !primaryGroup.isBlank()) { - String scopedValue = metaData.getMetaValue(baseKey + "." + primaryGroup); + String scopedKey = baseKey + "." + primaryGroup; + String scopedValue = metaData.getMetaValue(scopedKey); if (scopedValue != null && !scopedValue.isBlank()) { return scopedValue; } + + for (Map.Entry entry : metaData.getMeta().entrySet()) { + if (entry.getKey().equalsIgnoreCase(scopedKey)) { + String value = entry.getValue(); + if (value != null && !value.isBlank()) { + return value; + } + } + } } return metaData.getMetaValue(baseKey); } From 918da0321b04fcffb0b74665e907840db4f9fd2c Mon Sep 17 00:00:00 2001 From: Ben Robson Date: Fri, 9 Jan 2026 21:05:29 +1100 Subject: [PATCH 11/13] Fix scoped meta map type --- .../zander/velocity/events/UserChatEvent.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java index 064c8b5..f710efc 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java @@ -20,6 +20,7 @@ import org.modularsoft.zander.velocity.model.Filter; import org.modularsoft.zander.velocity.model.discord.DiscordChat; +import java.util.List; import java.util.Map; public class UserChatEvent { @@ -146,11 +147,14 @@ private String getMetaValue(CachedMetaData metaData, String baseKey, String prim return scopedValue; } - for (Map.Entry entry : metaData.getMeta().entrySet()) { + for (Map.Entry> entry : metaData.getMeta().entrySet()) { if (entry.getKey().equalsIgnoreCase(scopedKey)) { - String value = entry.getValue(); - if (value != null && !value.isBlank()) { - return value; + List values = entry.getValue(); + if (values != null && !values.isEmpty()) { + String value = values.get(0); + if (value != null && !value.isBlank()) { + return value; + } } } } From e96b65933ea74b8bb51ea7cb644860556e9bd635 Mon Sep 17 00:00:00 2001 From: Ben Robson Date: Fri, 9 Jan 2026 21:22:16 +1100 Subject: [PATCH 12/13] Fallback to any scoped displayname meta --- .../zander/velocity/events/UserChatEvent.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java index f710efc..f6aefb2 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java @@ -159,6 +159,18 @@ private String getMetaValue(CachedMetaData metaData, String baseKey, String prim } } } + + for (Map.Entry> entry : metaData.getMeta().entrySet()) { + if (entry.getKey().regionMatches(true, 0, baseKey + ".", 0, baseKey.length() + 1)) { + List values = entry.getValue(); + if (values != null && !values.isEmpty()) { + String value = values.get(0); + if (value != null && !value.isBlank()) { + return value; + } + } + } + } return metaData.getMetaValue(baseKey); } From ab087cb726a80bccad499b3feb57fd2fe5850b6b Mon Sep 17 00:00:00 2001 From: Ben Robson Date: Fri, 9 Jan 2026 21:42:38 +1100 Subject: [PATCH 13/13] Resolve rank meta priority and trim logs --- .../zander/velocity/ZanderVelocityMain.java | 1 - .../zander/velocity/commands/discord.java | 2 - .../zander/velocity/commands/report.java | 3 +- .../zander/velocity/commands/rules.java | 2 - .../zander/velocity/commands/website.java | 2 - .../zander/velocity/events/UserChatEvent.java | 70 ++++++++----------- .../velocity/events/UserCommandSpyEvent.java | 9 +-- .../velocity/events/UserOnProxyPing.java | 4 +- .../velocity/events/UserSocialSpyEvent.java | 8 +-- .../events/session/UserOnDisconnect.java | 7 +- .../velocity/events/session/UserOnLogin.java | 10 +-- .../velocity/events/session/UserOnSwitch.java | 11 +-- .../util/announcement/TipChatter.java | 6 -- .../zander/velocity/util/api/Heartbeat.java | 3 - 14 files changed, 45 insertions(+), 93 deletions(-) diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/ZanderVelocityMain.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/ZanderVelocityMain.java index 87a40bb..18ac5b0 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/ZanderVelocityMain.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/ZanderVelocityMain.java @@ -114,6 +114,5 @@ public ZanderVelocityMain( container.ifPresent(pluginContainer -> pluginContainer.getExecutorService().shutdown()); } - logger.info("Zander Proxy has started."); } } diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/commands/discord.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/commands/discord.java index cfc9159..84d65b7 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/commands/discord.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/commands/discord.java @@ -5,7 +5,6 @@ import com.velocitypowered.api.command.SimpleCommand; import dev.dejvokep.boostedyaml.route.Route; import io.github.ModularEnigma.Request; -import io.github.ModularEnigma.Response; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.format.NamedTextColor; @@ -38,7 +37,6 @@ public void execute(final Invocation invocation) { } catch (Exception e) { Component builder = Component.text("An error has occurred. Is the API down?").color(NamedTextColor.RED); source.sendMessage(builder); - System.out.println(e); } } } diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/commands/report.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/commands/report.java index 72825e5..5752ff6 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/commands/report.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/commands/report.java @@ -87,7 +87,6 @@ public void execute(Invocation invocation) { } catch (Exception e) { player.sendMessage(Component.text("An error has occurred. Is the API down?").color(NamedTextColor.RED)); - System.out.println(e); } } else { source.sendMessage(Component.text("Only players can use this command.").color(NamedTextColor.RED)); @@ -112,4 +111,4 @@ public List suggest(Invocation invocation) { return completions; } -} \ No newline at end of file +} diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/commands/rules.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/commands/rules.java index 438d97c..640db2d 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/commands/rules.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/commands/rules.java @@ -5,7 +5,6 @@ import com.velocitypowered.api.command.SimpleCommand; import dev.dejvokep.boostedyaml.route.Route; import io.github.ModularEnigma.Request; -import io.github.ModularEnigma.Response; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.format.NamedTextColor; @@ -37,7 +36,6 @@ public void execute(final Invocation invocation) { } catch (Exception e) { Component builder = Component.text("An error has occurred. Is the API down?").color(NamedTextColor.RED); source.sendMessage(builder); - System.out.println(e); } } } diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/commands/website.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/commands/website.java index 39af9b6..564034e 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/commands/website.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/commands/website.java @@ -5,7 +5,6 @@ import com.velocitypowered.api.command.SimpleCommand; import dev.dejvokep.boostedyaml.route.Route; import io.github.ModularEnigma.Request; -import io.github.ModularEnigma.Response; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.format.NamedTextColor; @@ -37,7 +36,6 @@ public void execute(final Invocation invocation) { } catch (Exception e) { Component builder = Component.text("An error has occurred. Is the API down?").color(NamedTextColor.RED); source.sendMessage(builder); - System.out.println(e); } } } diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java index f6aefb2..1a16bc0 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserChatEvent.java @@ -16,13 +16,13 @@ import net.luckperms.api.LuckPerms; import net.luckperms.api.LuckPermsProvider; import net.luckperms.api.cacheddata.CachedMetaData; +import net.luckperms.api.model.user.User; +import net.luckperms.api.node.NodeType; +import net.luckperms.api.node.types.MetaNode; import org.modularsoft.zander.velocity.ZanderVelocityMain; import org.modularsoft.zander.velocity.model.Filter; import org.modularsoft.zander.velocity.model.discord.DiscordChat; -import java.util.List; -import java.util.Map; - public class UserChatEvent { private final LuckPerms luckPerms = LuckPermsProvider.get(); @@ -58,8 +58,6 @@ public void UserChatEvent(PlayerChatEvent event) { Boolean success = JsonPath.parse(phraseJson).read("$.success"); String phraseCaughtMessage = JsonPath.read(phraseJson, "$.message"); - ZanderVelocityMain.getLogger().info("[FILTER] Response (" + phraseRes.getStatusCode() + "): " + phraseRes.getBody()); - if (!success) { Component builder = Component.text(phraseCaughtMessage).color(NamedTextColor.RED); player.sendMessage(builder); @@ -80,7 +78,6 @@ public void UserChatEvent(PlayerChatEvent event) { .build(); Response discordChatReqRes = discordChatReq.execute(); - ZanderVelocityMain.getLogger().info("Response (" + discordChatReqRes.getStatusCode() + "): " + discordChatReqRes.getBody()); } Component formattedMessage = formatChatMessage(player, originalMessage); @@ -94,14 +91,13 @@ public void UserChatEvent(PlayerChatEvent event) { } catch (Exception e) { Component builder = Component.text("The chat filter could not be reached at this time, there maybe an issue with the API.").color(NamedTextColor.YELLOW); player.sendMessage(builder); - System.out.println(e); } } private Component formatChatMessage(Player player, Component originalMessage) { - CachedMetaData metaData = luckPerms.getPlayerAdapter(Player.class).getMetaData(player); - String primaryGroup = luckPerms.getPlayerAdapter(Player.class).getUser(player).getPrimaryGroup(); - Component rankPrefix = buildRankPrefix(metaData, primaryGroup); + User user = luckPerms.getPlayerAdapter(Player.class).getUser(player); + CachedMetaData metaData = user.getCachedData().getMetaData(); + Component rankPrefix = buildRankPrefix(user, metaData); return Component.text() .append(rankPrefix) @@ -112,10 +108,10 @@ private Component formatChatMessage(Player player, Component originalMessage) { .build(); } - private Component buildRankPrefix(CachedMetaData metaData, String primaryGroup) { + private Component buildRankPrefix(User user, CachedMetaData metaData) { String prefix = metaData.getPrefix(); - String rankNameMeta = getMetaValue(metaData, "displayname", primaryGroup); - String rankDescriptionMeta = getMetaValue(metaData, "rank_description", primaryGroup); + String rankNameMeta = getMetaValue(user, metaData, "displayname"); + String rankDescriptionMeta = getMetaValue(user, metaData, "rank_description"); String rankName = (rankNameMeta != null && !rankNameMeta.isBlank()) ? rankNameMeta @@ -139,41 +135,37 @@ private Component buildRankPrefix(CachedMetaData metaData, String primaryGroup) return prefixComponent.hoverEvent(HoverEvent.showText(hoverText)); } - private String getMetaValue(CachedMetaData metaData, String baseKey, String primaryGroup) { - if (primaryGroup != null && !primaryGroup.isBlank()) { - String scopedKey = baseKey + "." + primaryGroup; - String scopedValue = metaData.getMetaValue(scopedKey); - if (scopedValue != null && !scopedValue.isBlank()) { - return scopedValue; - } - - for (Map.Entry> entry : metaData.getMeta().entrySet()) { - if (entry.getKey().equalsIgnoreCase(scopedKey)) { - List values = entry.getValue(); - if (values != null && !values.isEmpty()) { - String value = values.get(0); - if (value != null && !value.isBlank()) { - return value; - } - } + private String getMetaValue(User user, CachedMetaData metaData, String baseKey) { + MetaNode bestNode = null; + for (MetaNode node : user.getNodes(NodeType.META)) { + String key = node.getMetaKey(); + if (matchesMetaKey(key, baseKey)) { + if (bestNode == null || node.getPriority() > bestNode.getPriority()) { + bestNode = node; } } } - for (Map.Entry> entry : metaData.getMeta().entrySet()) { - if (entry.getKey().regionMatches(true, 0, baseKey + ".", 0, baseKey.length() + 1)) { - List values = entry.getValue(); - if (values != null && !values.isEmpty()) { - String value = values.get(0); - if (value != null && !value.isBlank()) { - return value; - } - } + if (bestNode != null) { + String value = bestNode.getMetaValue(); + if (value != null && !value.isBlank()) { + return value; } } + return metaData.getMetaValue(baseKey); } + private boolean matchesMetaKey(String key, String baseKey) { + if (key == null) { + return false; + } + if (key.equalsIgnoreCase(baseKey)) { + return true; + } + return key.regionMatches(true, 0, baseKey + ".", 0, baseKey.length() + 1); + } + private Component buildPrefixComponent(String prefix, String rankName) { if (prefix != null && !prefix.isBlank()) { return LegacyComponentSerializer.legacyAmpersand().deserialize(prefix); diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserCommandSpyEvent.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserCommandSpyEvent.java index 79311f5..135a54b 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserCommandSpyEvent.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserCommandSpyEvent.java @@ -5,7 +5,6 @@ import com.velocitypowered.api.proxy.Player; import dev.dejvokep.boostedyaml.route.Route; import io.github.ModularEnigma.Request; -import io.github.ModularEnigma.Response; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.modularsoft.zander.velocity.ZanderVelocityMain; @@ -25,8 +24,6 @@ public void onPlayerCommand(CommandExecuteEvent event) { String APIKey = ZanderVelocityMain.getConfig().getString(Route.from("APIKey")); String command = event.getCommand(); // Get the full command - ZanderVelocityMain.getLogger().info("Command: {}", command); - // Check if the command is one we need to log (ignore direct message commands) if (command.startsWith("msg") || command.startsWith("tell") || command.startsWith("w") || command.startsWith("message") || command.startsWith("r")) { @@ -50,12 +47,10 @@ public void onPlayerCommand(CommandExecuteEvent event) { .setRequestBody(commandSpy.toString()) .build(); - Response commandSpyRes = commandSpyReq.execute(); - ZanderVelocityMain.getLogger().info("Response (" + commandSpyRes.getStatusCode() + "): " + commandSpyRes.getBody()); + commandSpyReq.execute(); } catch (Exception e) { Component builder = Component.text("An error has occurred. Is the API down?").color(NamedTextColor.RED); player.disconnect(builder); - System.out.println(e); } } -} \ No newline at end of file +} diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserOnProxyPing.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserOnProxyPing.java index 2c0038a..ff1ba99 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserOnProxyPing.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserOnProxyPing.java @@ -53,8 +53,6 @@ public void onProxyPingEvent(ProxyPingEvent event) { pingBuilder.description(serverPingDescription); } catch (Exception e) { - System.out.print(e); - // Fallback MOTD in case of an exception String motdTopLine = ZanderVelocityMain.getConfig().getString(Route.from("announcementMOTDTopLine")); Component fallbackDescription = LegacyComponentSerializer.builder() @@ -68,4 +66,4 @@ public void onProxyPingEvent(ProxyPingEvent event) { // Set the modified ServerPing back to the event event.setPing(pingBuilder.build()); } -} \ No newline at end of file +} diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserSocialSpyEvent.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserSocialSpyEvent.java index 2320caa..4f02074 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserSocialSpyEvent.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/UserSocialSpyEvent.java @@ -6,7 +6,6 @@ import com.velocitypowered.api.proxy.ServerConnection; import dev.dejvokep.boostedyaml.route.Route; import io.github.ModularEnigma.Request; -import io.github.ModularEnigma.Response; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.modularsoft.zander.velocity.ZanderVelocityMain; @@ -30,8 +29,6 @@ public void onUserChatDMEvent(CommandExecuteEvent event) { Player player = (Player) event.getCommandSource(); String command = event.getCommand(); - logger.info("Command: {}", command); - // Check if the command is a direct message command if (command.contains("msg") || command.contains("tell") || command.contains("w") || command.contains("message") || command.contains("r")) { @@ -76,8 +73,7 @@ public void onUserChatDMEvent(CommandExecuteEvent event) { .setRequestBody(socialSpy.toString()) // Ensure proper serialization to JSON .build(); - Response socialSpyRes = socialSpyReq.execute(); - logger.info("Social Spy Response ({}): {}", socialSpyRes.getStatusCode(), socialSpyRes.getBody()); + socialSpyReq.execute(); } catch (Exception e) { logger.error("Error occurred while handling social spy request", e); @@ -85,4 +81,4 @@ public void onUserChatDMEvent(CommandExecuteEvent event) { } } } -} \ No newline at end of file +} diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/session/UserOnDisconnect.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/session/UserOnDisconnect.java index b560fbe..484367a 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/session/UserOnDisconnect.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/session/UserOnDisconnect.java @@ -6,7 +6,6 @@ import com.velocitypowered.api.proxy.ProxyServer; import dev.dejvokep.boostedyaml.route.Route; import io.github.ModularEnigma.Request; -import io.github.ModularEnigma.Response; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.modularsoft.zander.velocity.ZanderVelocityMain; @@ -38,8 +37,7 @@ public void UserDisconnectEvent (DisconnectEvent event) { .setRequestBody(destroySession.toString()) .build(); - Response destroySessionRes = destroySessionReq.execute(); - ZanderVelocityMain.getLogger().info("Response (" + destroySessionRes.getStatusCode() + "): " + destroySessionRes.getBody()); + destroySessionReq.execute(); } catch (Exception e) { Component builder = Component.text("An error has occurred. Is the API down?").color(NamedTextColor.RED); player.disconnect(builder); @@ -60,8 +58,7 @@ public void UserDisconnectEvent (DisconnectEvent event) { .setRequestBody(leave.toString()) .build(); - Response discordLeaveRes = discordLeaveReq.execute(); - ZanderVelocityMain.getLogger().info("Response (" + discordLeaveRes.getStatusCode() + "): " + discordLeaveRes.getBody()); + discordLeaveReq.execute(); } catch (Exception e) { Component builder = Component.text("An error has occurred. Is the API down?").color(NamedTextColor.RED); player.disconnect(builder); diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/session/UserOnLogin.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/session/UserOnLogin.java index 6eea4a9..20588fd 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/session/UserOnLogin.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/session/UserOnLogin.java @@ -5,7 +5,6 @@ import com.velocitypowered.api.proxy.Player; import dev.dejvokep.boostedyaml.route.Route; import io.github.ModularEnigma.Request; -import io.github.ModularEnigma.Response; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.modularsoft.zander.velocity.ZanderVelocityMain; @@ -36,8 +35,7 @@ public void UserLoginEvent (PostLoginEvent event) { .setRequestBody(createUser.toString()) .build(); - Response createUserRes = createUserReq.execute(); - ZanderVelocityMain.getLogger().info("Response (" + createUserRes.getStatusCode() + "): " + createUserRes.getBody()); + createUserReq.execute(); try { // @@ -55,8 +53,7 @@ public void UserLoginEvent (PostLoginEvent event) { .setRequestBody(createSession.toString()) .build(); - Response createSessionRes = createSessionReq.execute(); - ZanderVelocityMain.getLogger().info("Response (" + createSessionRes.getStatusCode() + "): " + createSessionRes.getBody()); + createSessionReq.execute(); // Send Discord API POST for join message DiscordJoin join = DiscordJoin.builder() @@ -70,8 +67,7 @@ public void UserLoginEvent (PostLoginEvent event) { .setRequestBody(join.toString()) .build(); - Response discordJoinRes = discordJoinReq.execute(); - ZanderVelocityMain.getLogger().info("Response (" + discordJoinRes.getStatusCode() + "): " + discordJoinRes.getBody()); + discordJoinReq.execute(); } catch (Exception e) { Component builder = Component.text("An error has occurred. Is the API down?").color(NamedTextColor.RED); player.disconnect(builder); diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/session/UserOnSwitch.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/session/UserOnSwitch.java index b39aeb7..be69596 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/session/UserOnSwitch.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/session/UserOnSwitch.java @@ -5,7 +5,6 @@ import com.velocitypowered.api.proxy.Player; import dev.dejvokep.boostedyaml.route.Route; import io.github.ModularEnigma.Request; -import io.github.ModularEnigma.Response; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.modularsoft.zander.velocity.ZanderVelocityMain; @@ -27,8 +26,6 @@ public void onServerConnect(ServerConnectedEvent event) { String BaseAPIURL = ZanderVelocityMain.getConfig().getString(Route.from("BaseAPIURL")); String APIKey = ZanderVelocityMain.getConfig().getString(Route.from("APIKey")); - logger.info("Player {} is switching to server {}", username, server); - // Handle Session Switch API try { SessionSwitch switchSession = SessionSwitch.builder() @@ -43,8 +40,7 @@ public void onServerConnect(ServerConnectedEvent event) { .setRequestBody(switchSession.toString()) // Ensure this method works properly .build(); - Response switchSessionRes = switchSessionReq.execute(); - logger.info("Session Switch Response ({}): {}", switchSessionRes.getStatusCode(), switchSessionRes.getBody()); + switchSessionReq.execute(); } catch (Exception e) { logger.error("Error during Session Switch API request", e); player.disconnect(Component.text("An error has occurred. Please try again later.").color(NamedTextColor.RED)); @@ -65,11 +61,10 @@ public void onServerConnect(ServerConnectedEvent event) { .setRequestBody(discordSwitch.toString()) // Ensure this method works properly .build(); - Response discordSwitchRes = discordSwitchReq.execute(); - logger.info("Discord Switch Response ({}): {}", discordSwitchRes.getStatusCode(), discordSwitchRes.getBody()); + discordSwitchReq.execute(); } catch (Exception e) { logger.error("Error during Discord Switch API request", e); player.sendMessage(Component.text("An error occurred, but you can still continue playing.").color(NamedTextColor.RED)); } } -} \ No newline at end of file +} diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/util/announcement/TipChatter.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/util/announcement/TipChatter.java index 129fff7..9fd525d 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/util/announcement/TipChatter.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/util/announcement/TipChatter.java @@ -44,11 +44,6 @@ public static void startAnnouncementTipTask() { String colourMessageFormat = JsonPath.read(json, "$.data[0].colourMessageFormat"); String link = JsonPath.read(json, "$.data[0].link"); - // Log the color message format and link - logger.info("Announcement Tip: {}", colourMessageFormat); - logger.info("Link: {}", link); - logger.info("JSON: {}", json); - // Broadcast the message to all online players ZanderVelocityMain.getProxy().getAllPlayers().forEach(player -> { // Send the message to each player @@ -64,7 +59,6 @@ public static void startAnnouncementTipTask() { } catch (Exception e) { // Handle exceptions here logger.error("Announcement Tip Failed, will try again later.", e); - System.out.println("Announcement Tip Failed, will try again in " + ZanderVelocityMain.getConfig().getString(Route.from("announcementTipInterval")) + " minutes."); } }, 0, ZanderVelocityMain.getConfig().getInt(Route.from("announcementTipInterval")), TimeUnit.MINUTES); } diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/util/api/Heartbeat.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/util/api/Heartbeat.java index ccc1bf8..c067d3d 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/util/api/Heartbeat.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/util/api/Heartbeat.java @@ -34,8 +34,6 @@ public static void startHeartbeatTask() { Response res = req.execute(); String json = res.getBody(); Boolean heartbeat = JsonPath.read(json, "$.success"); - System.out.println("API Heartbeat Success"); - // Check if the heartbeat is not successful if (!heartbeat) { // Kick all players @@ -47,7 +45,6 @@ public static void startHeartbeatTask() { } } catch (Exception e) { // Handle exceptions here - e.printStackTrace(); ZanderVelocityMain.getLogger().error("API Heartbeat Failed, kicking all players until back online."); // Kick all players