29 Commits
Author SHA1 Message Date
auto e74361a7b7 Add "local" chat channels with proximity-based messaging
Introduced a "local" channel type to restrict chat visibility based on player proximity, configurable via `LOCAL_DISTANCE`. Added channel spy functionality to monitor "local" messages. Updated constructors and configuration to support this new feature.
2025-03-22 18:19:25 +01:00
auto 769859a617 Fix bypass permission logic for ignored players in chat
Updated the filtering logic to correctly handle the "chat.ignorebypass" permission, ensuring players with bypass permission are not excluded due to ignore settings. Adjusted related conditionals in ChatHandler and ChatListener, and refactored patterns without altering functionality.
2025-03-22 02:44:42 +01:00
auto cb0bda8d5b Prevent sending mail to ignored players.
Added a check to block users from sending mail to players who have ignored them. A message is displayed to inform the sender, ensuring clearer communication and respecting player preferences.
2025-03-21 22:56:10 +01:00
auto 5212954946 Refactor config reload and server name handling.
Replaced inconsistent `ReloadConfig` usage with `reloadConfig` across the codebase for better naming consistency. Introduced `ServerName` utility to standardize server name retrieval and improve maintainability. Added logging enhancements for better debugging of muted users and blocked messages.
2025-03-21 22:55:57 +01:00
auto f1b8af6136 Merge branch 'ignore_fix' 2025-03-21 20:35:06 +01:00
Len bfc9af69d0 Fix URL clicking in chat. 2025-02-09 18:04:55 +01:00
Len ea705c879f Allow nick request from nick preview message 2025-02-07 20:45:21 +01:00
Len f5c0a0676c Delay unread mail message and also send it as a title message 2025-02-07 20:44:59 +01:00
stijn 9bd9e21321 Merge pull request 'vote_mute' (#2) from vote_mute into main
Reviewed-on: #2
2025-01-22 20:45:21 +00:00
stijn 1c570fd524 Merge branch 'main' into vote_mute 2025-01-22 20:43:24 +00:00
stijn 131ea6da9d Merge pull request 'ignore_fix' (#1) from ignore_fix into main
Reviewed-on: #1
2025-01-22 20:43:13 +00:00
auto 3275db13d0 Merge branch 'main' into vote_mute 2025-01-02 00:36:36 +01:00
auto a908e32d0b Fix message validation and chat log order
Corrected conditional logic in VoteToMuteHelper to validate messages properly and adjusted sorting of chat logs in VoteToMuteStarter to display in reverse chronological order. The update now accurately verifies the existence of selected messages and presents recent logs first for more user-friendly navigation.
2024-06-04 21:18:57 +02:00
auto 8393d12c6d Update vote-to-mute feature
The vote-to-mute feature is updated to include information about the vote initiating player. Also, the duration to retrieve chat logs increased from 5 minutes to 10 minutes. Lastly, eligible players are now notified live about the voting progress.
2024-05-05 16:14:48 +02:00
auto 782c7df4ef Update vote to mute functionality in chat system
Several changes were made to update the vote to mute functionality in the chat system. The threshold for eligible players online for vote has been changed from 10 to 6. In addition, improvements have been made to prevent the vote from ending prematurely. Lastly, feedback messages to users when they cast their vote and an update to the vote start message format have been implemented.
2024-05-05 15:42:59 +02:00
auto a876a9f77b Update vote validation and argument naming
Updated the method "votePassed" in "ActiveVoteToMute" to consider a scenario where no votes have been made for muting. Also, corrected the argument name from "yesno" to "yesNo" in "VoteToMuteHelper" to match with its name in the command constructor
2024-05-05 00:11:56 +02:00
auto f3147b3256 Refine ChatPlugin and improve "vote to mute" logic
Modified ChatPlugin to include "thisPlugin" within the ShutdownListener initialization. Additionally, adjusted the mute vote failure message color from green to red in ActiveVoteToMute file and added a condition to return false if there are no votes. Also, made improvements to the pagination logic in the VoteToMuteStarter file. Lastly, improved the chat logging mechanics in ChatLogHandler by adding and refining various log information for capturing action details.
2024-05-04 23:41:27 +02:00
auto 65503a02f3 Refactor death message display in PlayerListener
The commit refactors the method for displaying player death messages in the PlayerListener class. Specifically, it adds functionality to replace usernames with display names in death notifications. More descriptive death messages with themed colors and icons are now shown.
2024-04-30 22:15:46 +02:00
auto 7140a0cd78 Merge branch 'main' into vote_mute 2024-04-28 21:38:26 +02:00
auto 187f71d6c3 Implement logging for ChatLogHandler
The ChatLogHandler now includes logging for better troubleshooting and understanding of the server state. Logging triggers when chat logging is disabled, when it starts, and also if there's a failure in saving chat messages to the database.
2024-04-28 21:36:45 +02:00
auto 3b2aa84164 Add player muted logging and abstract embed building
The update introduces a log entry indicating when a player has been muted due to voting. The embed creation for this process has been isolated and extracted into a separate function. This contributes to better code modularity and organization.
2024-04-13 16:52:56 +02:00
auto 0fb497c2f1 Merge branch 'main' into vote_mute 2024-04-13 16:15:56 +02:00
auto 192fca3a89 Fix chat log message deletion query
Corrected the SQL query in the `deleteOldMessages` method within `ChatLogQueries.java`. Originally, it was incorrectly deleting newer messages rather than older ones due to an incorrect comparison symbol. It has now been adjusted to properly delete older messages based on the provided duration.
2024-04-07 19:16:32 +02:00
auto d6135f2456 Add mute vote results sent to Discord and staff presence check
Enhanced the vote-to-mute feature by adding a function that sends the mute vote results to a general channel on Discord. A 'staff presence' check has also been added which prevents the mute vote from being initiated if a staff member is online, instead, it prompts users to directly contact a staff member for help.
2024-04-07 18:29:46 +02:00
auto c057c69653 Enable optional logging in ChatLogHandler
Modified the ChatLogHandler to support optional logging by introducing a new argument in the getInstance() method. This argument sets the logging state during instantiation. This facilitates better flexibility when using the ChatLogHandler across different sections of the code base as logging requirements may differ.
2024-04-07 18:11:19 +02:00
auto c25767e473 Add VoteToMuteHelper and enhance ActiveVoteToMute
Implemented a new module titled VoteToMuteHelper to enhance the voting system and augment the user experience. This module enhances the system by providing relevant player suggestions and setting up the mute player. Made updates to the ActiveVoteToMute module to handle potential voters and mute the player if the vote is passed. VoteToMute module is also updated to include the total eligible players. The code is made robust by adding appropriate error checks.
2024-04-07 18:07:20 +02:00
auto 37aa9fdf4c Replace Object2ObjectOpenHashMap with HashMap
The usage of Object2ObjectOpenHashMap in storing chat logs and the chat log handler was switched to HashMap. This was done to ensure the plugin can be run on proxy as velocity does not include this library
2024-04-07 16:32:33 +02:00
auto ed2ba74772 Add start of VoteToMute functionality in chat system
Implemented VoteToMute system enabling initiated voting for muting a player in chat. This includes creating new classes "ActiveVoteToMute", "VoteToMute", and "VoteToMuteStarter". The "VoteToMute" class handles the voting command logic, it allows players to vote on whether to mute other players. The code also adds a call to register this new command in the main VelocityChat class.
2024-04-06 19:39:36 +02:00
auto 44d6e994cc Implement chat log handler with database support
The code changes introduce the ability to log chat messages. A new ChatLogHandler class has been added that manages the queue of chat log messages, both storing them in memory and writing them to a database. New columns have been added to the database and the interactivity with the database is handled using prepared statements to improve security and performance. The chat messages are deleted from the database after a certain period, which can be configured.
2024-04-06 17:25:15 +02:00
17 changed files with 177 additions and 63 deletions
@@ -15,9 +15,9 @@ public abstract interface ChatAPI {
DatabaseConnection getDataBase(); DatabaseConnection getDataBase();
void ReloadConfig(); void reloadConfig();
void ReloadChatFilters(); void reloadChatFilters();
HashMap<String, String> getPrefixes(); HashMap<String, String> getPrefixes();
@@ -5,15 +5,12 @@ import com.alttd.chat.config.PrefixConfig;
import com.alttd.chat.database.DatabaseConnection; import com.alttd.chat.database.DatabaseConnection;
import com.alttd.chat.database.Queries; import com.alttd.chat.database.Queries;
import com.alttd.chat.managers.ChatUserManager; import com.alttd.chat.managers.ChatUserManager;
import com.alttd.chat.managers.PartyManager;
import com.alttd.chat.managers.RegexManager; import com.alttd.chat.managers.RegexManager;
import com.alttd.chat.util.ALogger;
import net.luckperms.api.LuckPerms; import net.luckperms.api.LuckPerms;
import net.luckperms.api.LuckPermsProvider; import net.luckperms.api.LuckPermsProvider;
import net.luckperms.api.model.group.Group; import net.luckperms.api.model.group.Group;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
public class ChatImplementation implements ChatAPI{ public class ChatImplementation implements ChatAPI{
@@ -26,7 +23,7 @@ public class ChatImplementation implements ChatAPI{
public ChatImplementation() { public ChatImplementation() {
instance = this; instance = this;
ReloadConfig(); reloadConfig();
luckPerms = getLuckPerms(); luckPerms = getLuckPerms();
databaseConnection = getDataBase(); databaseConnection = getDataBase();
@@ -57,13 +54,13 @@ public class ChatImplementation implements ChatAPI{
} }
@Override @Override
public void ReloadConfig() { public void reloadConfig() {
Config.init(); Config.init();
loadPrefixes(); loadPrefixes();
} }
@Override @Override
public void ReloadChatFilters() { public void reloadChatFilters() {
RegexManager.initialize(); RegexManager.initialize();
} }
@@ -368,6 +368,8 @@ public final class Config {
public static String CUSTOM_CHANNEL_TOGGLED = "<yellow>Toggled <channel> <status>.</yellow>"; public static String CUSTOM_CHANNEL_TOGGLED = "<yellow>Toggled <channel> <status>.</yellow>";
public static Component TOGGLED_ON = null; public static Component TOGGLED_ON = null;
public static Component TOGGLED_OFF = null; public static Component TOGGLED_OFF = null;
public static double LOCAL_DISTANCE;
public static String CHANNEL_SPY = "<i><gray>SPY:</gray> <dark_gray>(<dark_gray><sender> → <channel>) <message></dark_gray>";
private static void chatChannels() { private static void chatChannels() {
ConfigurationNode node = getNode("chat-channels"); ConfigurationNode node = getNode("chat-channels");
if (node.empty()) { if (node.empty()) {
@@ -383,12 +385,16 @@ public final class Config {
new CustomChannel(channelName, new CustomChannel(channelName,
getString(key + "format", ""), getString(key + "format", ""),
getList(key + "servers", Collections.EMPTY_LIST), getList(key + "servers", Collections.EMPTY_LIST),
getBoolean(key + "proxy", false)); getBoolean(key + "proxy", false),
getBoolean(key + "local", false)
);
} }
CUSTOM_CHANNEL_TOGGLED = getString("chat-channels-messages.channel-toggled", CUSTOM_CHANNEL_TOGGLED); CUSTOM_CHANNEL_TOGGLED = getString("chat-channels-messages.channel-toggled", CUSTOM_CHANNEL_TOGGLED);
TOGGLED_ON = Utility.parseMiniMessage(getString("chat-channels-messages.channel-on", "<green>on</green><gray>")); TOGGLED_ON = Utility.parseMiniMessage(getString("chat-channels-messages.channel-on", "<green>on</green><gray>"));
TOGGLED_OFF = Utility.parseMiniMessage(getString("chat-channels-messages.channel-off", "<red>off</red><gray>")); TOGGLED_OFF = Utility.parseMiniMessage(getString("chat-channels-messages.channel-off", "<red>off</red><gray>"));
LOCAL_DISTANCE = getDouble("chat-channels-messages.local-distance", 200.0);
CHANNEL_SPY = getString("chat-channels-messages.spy", CHANNEL_SPY);
} }
public static String SERVERMUTEPERMISSION = "chat.command.mute-server"; public static String SERVERMUTEPERMISSION = "chat.command.mute-server";
@@ -424,6 +430,7 @@ public final class Config {
public static String mailUnread = "<green><click:run_command:/mail list unread>You have <amount> unread mail, click to view it.</click></green>"; public static String mailUnread = "<green><click:run_command:/mail list unread>You have <amount> unread mail, click to view it.</click></green>";
public static String mailSent = "<green>Successfully send mail to <player_name></green>: <#2e8b57><message></#2e8b57>"; public static String mailSent = "<green>Successfully send mail to <player_name></green>: <#2e8b57><message></#2e8b57>";
public static List<String> mailCommandAlias = new ArrayList<>(); public static List<String> mailCommandAlias = new ArrayList<>();
public static int mailDisplayDelay = 5;
private static void mailSettings() { private static void mailSettings() {
mailHeader = getString("settings.mail.header", mailHeader); mailHeader = getString("settings.mail.header", mailHeader);
mailBody = getString("settings.mail.message", mailBody); mailBody = getString("settings.mail.message", mailBody);
@@ -432,6 +439,7 @@ public final class Config {
mailReceived = getString("settings.mail.mail-received", mailReceived); mailReceived = getString("settings.mail.mail-received", mailReceived);
mailUnread = getString("settings.mail.mail-unread", mailUnread); mailUnread = getString("settings.mail.mail-unread", mailUnread);
mailSent = getString("settings.mail.mail-sent", mailSent); mailSent = getString("settings.mail.mail-sent", mailSent);
mailDisplayDelay = getInt("settings.mail.delay", mailDisplayDelay);
} }
public static HashMap<String, Long> serverChannelId = new HashMap<>(); public static HashMap<String, Long> serverChannelId = new HashMap<>();
@@ -503,7 +511,7 @@ public final class Config {
public static String NICK_TOO_SOON = "<red>Please wait <time><red> until requesting a new nickname"; public static String NICK_TOO_SOON = "<red>Please wait <time><red> until requesting a new nickname";
public static String NICK_REQUEST_PLACED = "<green>Replaced your previous request <oldrequestednick><green> with <newrequestednick><green>."; public static String NICK_REQUEST_PLACED = "<green>Replaced your previous request <oldrequestednick><green> with <newrequestednick><green>.";
public static String NICK_REQUEST_NEW = "<green>New nickname request by <player><green>!"; public static String NICK_REQUEST_NEW = "<green>New nickname request by <player><green>!";
public static String NICK_TRYOUT = "<white><prefix><white> <nick><gray>: <white>Hi, this is what my new nickname could look like!"; public static String NICK_TRYOUT = "<white><prefix><white> <nick><gray>: <white><click:suggest_command:/nick request <nickrequest>>Hi, this is what my new nickname could look like! Click this message to request.";
public static String NICK_REQUESTED = "<green>Your requested to be nicknamed <nick><green> has been received. Staff will accept or deny this request asap!"; public static String NICK_REQUESTED = "<green>Your requested to be nicknamed <nick><green> has been received. Staff will accept or deny this request asap!";
public static String NICK_REVIEW_WAITING = "<green>There are <amount> nicknames waiting for review!"; public static String NICK_REVIEW_WAITING = "<green>There are <amount> nicknames waiting for review!";
public static String NICK_TAKEN = "<red>Someone else already has this nickname, or has this name as their username."; public static String NICK_TAKEN = "<red>Someone else already has this nickname, or has this name as their username.";
@@ -10,12 +10,14 @@ public class Channel {
protected String channelName; protected String channelName;
protected String format; protected String format;
protected boolean proxy; protected boolean proxy;
protected boolean local;
public Channel(String channelName, String format, boolean proxy) { public Channel(String channelName, String format, boolean proxy, boolean local) {
this.permission = "chat.channel." + channelName.toLowerCase(); this.permission = "chat.channel." + channelName.toLowerCase();
this.channelName = channelName; this.channelName = channelName;
this.format = format; this.format = format;
this.proxy = proxy; this.proxy = proxy;
this.local = local;
channels.put(channelName.toLowerCase(), this); channels.put(channelName.toLowerCase(), this);
} }
@@ -39,6 +41,10 @@ public class Channel {
return proxy; return proxy;
} }
public boolean isLocal() {
return local;
}
public static Channel getChatChannel(String channelName) { public static Channel getChatChannel(String channelName) {
return channels.get(channelName.toLowerCase()); return channels.get(channelName.toLowerCase());
} }
@@ -5,14 +5,13 @@ import java.util.*;
public class CustomChannel extends Channel { public class CustomChannel extends Channel {
private final List<String> servers; private final List<String> servers;
public CustomChannel(String channelName, String format, List<String> servers, boolean proxy) { public CustomChannel(String channelName, String format, List<String> servers, boolean proxy, boolean local) {
super(channelName, format, proxy); super(channelName, format, proxy, local);
this.permission = "chat.channel." + channelName.toLowerCase(); this.permission = "chat.channel." + channelName.toLowerCase();
this.channelName = channelName; this.channelName = channelName;
this.format = format; this.format = format;
this.servers = servers; this.servers = servers;
this.proxy = proxy; this.proxy = proxy;
channels.put(channelName.toLowerCase(), this);
} }
public List<String> getServers() { public List<String> getServers() {
return servers; return servers;
@@ -2,6 +2,6 @@ package com.alttd.chat.objects.channels;
public abstract class DefaultChannel extends Channel{ public abstract class DefaultChannel extends Channel{
public DefaultChannel(String channelName, String format, boolean proxy) { public DefaultChannel(String channelName, String format, boolean proxy) {
super(channelName, format, proxy); super(channelName, format, proxy, false);
} }
} }
@@ -23,6 +23,7 @@ public class Utility {
private static final List<String> EMPTY_LIST = new ArrayList<>(); private static final List<String> EMPTY_LIST = new ArrayList<>();
static final Pattern DEFAULT_URL_PATTERN = Pattern.compile("(?:(https?)://)?([-\\w_.]+\\.\\w{2,})(/\\S*)?"); static final Pattern DEFAULT_URL_PATTERN = Pattern.compile("(?:(https?)://)?([-\\w_.]+\\.\\w{2,})(/\\S*)?");
static final Pattern URL_SCHEME_PATTERN = Pattern.compile("^[a-z][a-z0-9+\\-.]*:");
private static MiniMessage miniMessage = null; private static MiniMessage miniMessage = null;
@@ -307,6 +308,9 @@ public class Utility {
String url = matcher.group(); String url = matcher.group();
String clickUrl = url; String clickUrl = url;
String urlFormat = Config.URLFORMAT; String urlFormat = Config.URLFORMAT;
// if (!URL_SCHEME_PATTERN.matcher(clickUrl).find()) {
// clickUrl = "http://" + clickUrl;
// }
message = message.replace(url, urlFormat.replaceAll("<url>", url).replaceAll("<clickurl>", clickUrl)); message = message.replace(url, urlFormat.replaceAll("<url>", url).replaceAll("<clickurl>", clickUrl));
} }
return message; return message;
@@ -12,13 +12,16 @@ import com.alttd.chat.objects.channels.Channel;
import com.alttd.chat.objects.channels.CustomChannel; import com.alttd.chat.objects.channels.CustomChannel;
import com.alttd.chat.objects.chat_log.ChatLogHandler; import com.alttd.chat.objects.chat_log.ChatLogHandler;
import com.alttd.chat.util.ALogger; import com.alttd.chat.util.ALogger;
import com.alttd.chat.util.ServerName;
import com.alttd.chat.util.Utility; import com.alttd.chat.util.Utility;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
import org.bukkit.command.PluginCommand; import org.bukkit.command.PluginCommand;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.util.List; import java.util.List;
public class ChatPlugin extends JavaPlugin { public class ChatPlugin extends JavaPlugin {
@@ -38,7 +41,7 @@ public class ChatPlugin extends JavaPlugin {
chatAPI = new ChatImplementation(); chatAPI = new ChatImplementation();
chatHandler = new ChatHandler(); chatHandler = new ChatHandler();
DatabaseConnection.initialize(); DatabaseConnection.initialize();
serverConfig = new ServerConfig(Bukkit.getServer().getName()); serverConfig = new ServerConfig(ServerName.getServerName());
ChatLogHandler chatLogHandler = ChatLogHandler.getInstance(true); ChatLogHandler chatLogHandler = ChatLogHandler.getInstance(true);
registerListener(new PlayerListener(serverConfig), new ChatListener(chatLogHandler), new BookListener(), new ShutdownListener(chatLogHandler, this)); registerListener(new PlayerListener(serverConfig), new ChatListener(chatLogHandler), new BookListener(), new ShutdownListener(chatLogHandler, this));
if(serverConfig.GLOBALCHAT) { if(serverConfig.GLOBALCHAT) {
@@ -57,8 +60,10 @@ public class ChatPlugin extends JavaPlugin {
registerCommand("p", new PartyChat()); registerCommand("p", new PartyChat());
registerCommand("emotes", new Emotes()); registerCommand("emotes", new Emotes());
for (Channel channel : Channel.getChannels()) { for (Channel channel : Channel.getChannels()) {
if (!(channel instanceof CustomChannel customChannel)) continue; if (!(channel instanceof CustomChannel customChannel)) {
this.getServer().getCommandMap().register(channel.getChannelName().toLowerCase(), new ChatChannel(customChannel)); continue;
}
this.getServer().getCommandMap().register(channel.getChannelName().toLowerCase(), new ChatChannel(customChannel));
} }
messageChannel = Config.MESSAGECHANNEL; messageChannel = Config.MESSAGECHANNEL;
@@ -116,10 +121,10 @@ public class ChatPlugin extends JavaPlugin {
serverConfig.MUTED = !serverConfig.MUTED; serverConfig.MUTED = !serverConfig.MUTED;
} }
public void ReloadConfig() { public void reloadConfig() {
chatAPI.ReloadConfig(); chatAPI.reloadConfig();
chatAPI.ReloadChatFilters(); chatAPI.reloadChatFilters();
serverConfig = new ServerConfig(Bukkit.getServer().getName()); serverConfig = new ServerConfig(ServerName.getServerName());
Bukkit.broadcast(Utility.parseMiniMessage("Reloaded ChatPlugin Config."), "command.chat.reloadchat"); Bukkit.broadcast(Utility.parseMiniMessage("Reloaded ChatPlugin Config."), "command.chat.reloadchat");
ALogger.info("Reloaded ChatPlugin config."); ALogger.info("Reloaded ChatPlugin config.");
} }
@@ -8,7 +8,9 @@ import com.alttd.chat.objects.ChatFilter;
import com.alttd.chat.objects.ChatUser; import com.alttd.chat.objects.ChatUser;
import com.alttd.chat.objects.ModifiableString; import com.alttd.chat.objects.ModifiableString;
import com.alttd.chat.objects.channels.CustomChannel; import com.alttd.chat.objects.channels.CustomChannel;
import com.alttd.chat.util.ALogger;
import com.alttd.chat.util.GalaxyUtility; import com.alttd.chat.util.GalaxyUtility;
import com.alttd.chat.util.ServerName;
import com.alttd.chat.util.Utility; import com.alttd.chat.util.Utility;
import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
@@ -20,12 +22,15 @@ import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import java.util.*; import java.util.*;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
public class ChatHandler { public class ChatHandler {
@@ -126,12 +131,11 @@ public class ChatHandler {
Component senderName = user.getDisplayName(); Component senderName = user.getDisplayName();
Component prefix = user.getPrefix(); Component prefix = user.getPrefix();
TagResolver placeholders = TagResolver.resolver( TagResolver placeholders = TagResolver.resolver(
Placeholder.component("sender", senderName), Placeholder.component("sender", senderName),
Placeholder.component("prefix", prefix), Placeholder.component("prefix", prefix),
Placeholder.component("message", parseMessageContent(player, message)), Placeholder.component("message", parseMessageContent(player, message)),
Placeholder.parsed("server", Bukkit.getServer().getName()) Placeholder.parsed("server", ServerName.getServerName())
); );
Component component = Utility.parseMiniMessage(Config.GCFORMAT, placeholders); Component component = Utility.parseMiniMessage(Config.GCFORMAT, placeholders);
@@ -157,7 +161,10 @@ public class ChatHandler {
return; return;
} }
if (isMuted(player, message, "[" + channel.getChannelName() + " Muted] ")) return; if (isMuted(player, message, "[" + channel.getChannelName() + " Muted] ")) {
ALogger.info("Refusing to send message by muted user");
return;
}
ChatUser user = ChatUserManager.getChatUser(player.getUniqueId()); ChatUser user = ChatUserManager.getChatUser(player.getUniqueId());
Component senderName = user.getDisplayName(); Component senderName = user.getDisplayName();
@@ -165,7 +172,7 @@ public class ChatHandler {
TagResolver placeholders = TagResolver.resolver( TagResolver placeholders = TagResolver.resolver(
Placeholder.component("sender", senderName), Placeholder.component("sender", senderName),
Placeholder.component("message", parseMessageContent(player, message)), Placeholder.component("message", parseMessageContent(player, message)),
Placeholder.parsed("server", Bukkit.getServer().getName()), Placeholder.parsed("server", ServerName.getServerName()),
Placeholder.parsed("channel", channel.getChannelName()) Placeholder.parsed("channel", channel.getChannelName())
); );
Component component = Utility.parseMiniMessage(channel.getFormat(), placeholders); Component component = Utility.parseMiniMessage(channel.getFormat(), placeholders);
@@ -176,15 +183,16 @@ public class ChatHandler {
player, player,
Utility.parseMiniMessage(Utility.parseColors(modifiableString.string())), Utility.parseMiniMessage(Utility.parseColors(modifiableString.string())),
""); "");
return; // the message was blocked ALogger.info("Refusing to send blocked chat message");
return;
} }
component = modifiableString.component(); component = modifiableString.component();
if (channel.isProxy()) { if (channel.isProxy()) {
sendChatChannelMessage(player, channel.getChannelName(), "chatchannel", component); sendChatChannelMessage(player, channel.getChannelName(), "chatchannel", component, message);
} else { } else {
sendChatChannelMessage(channel, player.getUniqueId(), component); sendChatChannelMessage(channel, player.getUniqueId(), component, message);
} }
} }
@@ -237,22 +245,49 @@ public class ChatHandler {
// } // }
} }
private void sendChatChannelMessage(CustomChannel chatChannel, UUID uuid, Component component) { private void sendChatChannelMessage(CustomChannel chatChannel, UUID uuid, Component component, String message) {
if (!chatChannel.getServers().contains(Bukkit.getServer().getName())) { Player player = Bukkit.getPlayer(uuid);
if (player == null) {
ALogger.warn("Failed to send chat message from non existent player");
return; return;
} }
Player player = Bukkit.getPlayer(uuid); if (!chatChannel.getServers().contains(ServerName.getServerName())) {
if (player == null) { player.sendRichMessage("<red>Unable to send messages to <channel> in this server.</red>",
Placeholder.parsed("channel", chatChannel.getChannelName()));
ALogger.info(String.format("Not sending chat message due to [%s] not being in this channels config",
ServerName.getServerName()));
return; return;
} }
Stream<? extends Player> stream = Bukkit.getServer().getOnlinePlayers().stream() Stream<? extends Player> stream = Bukkit.getServer().getOnlinePlayers().stream()
.filter(p -> p.hasPermission(chatChannel.getPermission())); .filter(p -> p.hasPermission(chatChannel.getPermission()));
if (!player.hasPermission("chat.ignorebypass")) { if (!player.hasPermission("chat.ignorebypass")) {
stream = stream.filter(p -> !ChatUserManager.getChatUser(p.getUniqueId()).getIgnoredPlayers().contains(uuid) && !p.hasPermission("chat.ignorebypass")); stream = stream.filter(receiver -> !ChatUserManager.getChatUser(receiver.getUniqueId()).getIgnoredPlayers().contains(uuid)
|| receiver.hasPermission("chat.ignorebypass"));
} }
stream.forEach(p -> p.sendMessage(component)); if (chatChannel.isLocal()) {
Location location = player.getLocation();
stream = stream.filter(receiver -> {
Player receiverPlayer = Bukkit.getPlayer(receiver.getUniqueId());
if (receiverPlayer == null)
return false;
if (!location.getWorld().getUID().equals(receiverPlayer.getLocation().getWorld().getUID()))
return false;
return !(receiverPlayer.getLocation().distance(location) > Config.LOCAL_DISTANCE);
});
}
List<? extends Player> recipientPlayers = stream.toList();
recipientPlayers.forEach(p -> p.sendMessage(component));
List<UUID> recipientUUIDs = recipientPlayers.stream().map(Entity::getUniqueId).toList();
Bukkit.getServer().getOnlinePlayers().stream()
.filter(onlinePlayer -> onlinePlayer.hasPermission(Config.SPYPERMISSION))
.filter(onlinePlayer -> !recipientUUIDs.contains(onlinePlayer.getUniqueId()))
.forEach(onlinePlayer -> onlinePlayer.sendRichMessage(Config.CHANNEL_SPY,
Placeholder.component("sender", player.name()),
Placeholder.parsed("channel", chatChannel.getChannelName()),
Placeholder.parsed("message", message)));
} }
private void sendPluginMessage(Player player, String channel, Component component) { private void sendPluginMessage(Player player, String channel, Component component) {
@@ -272,7 +307,7 @@ public class ChatHandler {
player.sendPluginMessage(plugin, Config.MESSAGECHANNEL, out.toByteArray()); player.sendPluginMessage(plugin, Config.MESSAGECHANNEL, out.toByteArray());
} }
public void sendChatChannelMessage(Player player, String chatChannelName, String channel, Component component) { public void sendChatChannelMessage(Player player, String chatChannelName, String channel, Component component, String ignored) {
ByteArrayDataOutput out = ByteStreams.newDataOutput(); ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF(channel); out.writeUTF(channel);
out.writeUTF(chatChannelName); out.writeUTF(chatChannelName);
@@ -9,6 +9,7 @@ import com.alttd.chat.objects.*;
import com.alttd.chat.objects.chat_log.ChatLogHandler; import com.alttd.chat.objects.chat_log.ChatLogHandler;
import com.alttd.chat.util.ALogger; import com.alttd.chat.util.ALogger;
import com.alttd.chat.util.GalaxyUtility; import com.alttd.chat.util.GalaxyUtility;
import com.alttd.chat.util.ServerName;
import com.alttd.chat.util.Utility; import com.alttd.chat.util.Utility;
import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
@@ -106,7 +107,7 @@ public class ChatListener implements Listener {
GalaxyUtility.sendBlockedNotification("Language", player, GalaxyUtility.sendBlockedNotification("Language", player,
modifiableString.component(), modifiableString.component(),
""); "");
chatLogHandler.addChatLog(uuid, player.getServer().getName(), PlainTextComponentSerializer.plainText().serialize(input), true); chatLogHandler.addChatLog(uuid, ServerName.getServerName(), PlainTextComponentSerializer.plainText().serialize(input), true);
return; // the message was blocked return; // the message was blocked
} }
@@ -115,7 +116,7 @@ public class ChatListener implements Listener {
if (!player.hasPermission("chat.ignorebypass")) { if (!player.hasPermission("chat.ignorebypass")) {
stream = stream.filter(receiver -> !ChatUserManager.getChatUser(receiver.getUniqueId()).getIgnoredPlayers().contains(uuid) stream = stream.filter(receiver -> !ChatUserManager.getChatUser(receiver.getUniqueId()).getIgnoredPlayers().contains(uuid)
&& !receiver.hasPermission("chat.ignorebypass")); || receiver.hasPermission("chat.ignorebypass"));
} }
Set<Player> receivers = stream.collect(Collectors.toSet()); Set<Player> receivers = stream.collect(Collectors.toSet());
@@ -129,7 +130,7 @@ public class ChatListener implements Listener {
for (Player pingPlayer : playersToPing) { for (Player pingPlayer : playersToPing) {
pingPlayer.playSound(pingPlayer.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS, 1, 1); pingPlayer.playSound(pingPlayer.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS, 1, 1);
} }
chatLogHandler.addChatLog(uuid, player.getServer().getName(), modifiableString.string(), false); chatLogHandler.addChatLog(uuid, ServerName.getServerName(), modifiableString.string(), false);
ALogger.info(PlainTextComponentSerializer.plainText().serialize(input)); ALogger.info(PlainTextComponentSerializer.plainText().serialize(input));
} }
@@ -139,9 +140,9 @@ public class ChatListener implements Listener {
String nickName = PlainTextComponentSerializer.plainText().serialize(onlinePlayer.displayName()); String nickName = PlainTextComponentSerializer.plainText().serialize(onlinePlayer.displayName());
Pattern namePattern = Pattern.compile("\\b(?<!\\\\)" + name + "\\b", Pattern.CASE_INSENSITIVE); Pattern namePattern = Pattern.compile("\\b(?<!\\\\)" + name + "\\b", Pattern.CASE_INSENSITIVE);
// Pattern escapedNamePattern = Pattern.compile("\\b\\\\" + name + "\\b", Pattern.CASE_INSENSITIVE); // Pattern escapedNamePattern = Pattern.compile("\\b\\\\" + name + "\\b", Pattern.CASE_INSENSITIVE);
Pattern nickPattern = Pattern.compile("\\b(?<!\\\\)" + nickName + "\\b", Pattern.CASE_INSENSITIVE); Pattern nickPattern = Pattern.compile("\\b(?<!\\\\)" + nickName + "\\b", Pattern.CASE_INSENSITIVE);
// Pattern escapedNickPattern = Pattern.compile("\\b\\\\" + nickName + "\\b", Pattern.CASE_INSENSITIVE); // Pattern escapedNickPattern = Pattern.compile("\\b\\\\" + nickName + "\\b", Pattern.CASE_INSENSITIVE);
ChatUser onlinePlayerUser = ChatUserManager.getChatUser(onlinePlayer.getUniqueId()); ChatUser onlinePlayerUser = ChatUserManager.getChatUser(onlinePlayer.getUniqueId());
if (namePattern.matcher(modifiableString.string()).find()) { if (namePattern.matcher(modifiableString.string()).find()) {
@@ -151,16 +152,18 @@ public class ChatListener implements Listener {
.replacement(mention.append(onlinePlayerUser.getDisplayName())) .replacement(mention.append(onlinePlayerUser.getDisplayName()))
.build()); .build());
//TODO replace all instances of \name with just name but using the match result so the capitalization doesn't change //TODO replace all instances of \name with just name but using the match result so the capitalization doesn't change
// modifiableString.replace(TextReplacementConfig.builder() // modifiableString.replace(TextReplacementConfig.builder()
// .once() // .once()
// .match(escapedNamePattern) // .match(escapedNamePattern)
// .replacement((a, b) -> { // .replacement((a, b) -> {
// String substring = a.group().substring(1); // String substring = a.group().substring(1);
// return ; // return ;
// }); // });
if (!ChatUserManager.getChatUser(onlinePlayer.getUniqueId()).getIgnoredPlayers().contains(player.getUniqueId()) if (!ChatUserManager.getChatUser(onlinePlayer.getUniqueId()).getIgnoredPlayers().contains(player.getUniqueId())
&& !player.hasPermission("chat.ignorebypass")) || player.hasPermission("chat.ignorebypass")) {
playersToPing.add(onlinePlayer); playersToPing.add(onlinePlayer);
}
} else if (nickPattern.matcher(modifiableString.string()).find()) { } else if (nickPattern.matcher(modifiableString.string()).find()) {
modifiableString.replace(TextReplacementConfig.builder() modifiableString.replace(TextReplacementConfig.builder()
.once() .once()
@@ -168,8 +171,9 @@ public class ChatListener implements Listener {
.replacement(mention.append(onlinePlayerUser.getDisplayName())) .replacement(mention.append(onlinePlayerUser.getDisplayName()))
.build()); .build());
if (!ChatUserManager.getChatUser(onlinePlayer.getUniqueId()).getIgnoredPlayers().contains(player.getUniqueId()) if (!ChatUserManager.getChatUser(onlinePlayer.getUniqueId()).getIgnoredPlayers().contains(player.getUniqueId())
&& !player.hasPermission("chat.ignorebypass")) || player.hasPermission("chat.ignorebypass")) {
playersToPing.add(onlinePlayer); playersToPing.add(onlinePlayer);
}
} }
} }
} }
@@ -198,7 +202,7 @@ public class ChatListener implements Listener {
}); });
MiniMessage miniMessage = MiniMessage.builder().tags(tagResolver.build()).build(); MiniMessage miniMessage = MiniMessage.builder().tags(tagResolver.build()).build();
Component component = miniMessage.deserialize(rawMessage); Component component = miniMessage.deserialize(Utility.formatText(rawMessage));
for(ChatFilter chatFilter : RegexManager.getEmoteFilters()) { for(ChatFilter chatFilter : RegexManager.getEmoteFilters()) {
component = component.replaceText( component = component.replaceText(
TextReplacementConfig.builder() TextReplacementConfig.builder()
@@ -11,6 +11,7 @@ import com.alttd.chat.objects.channels.Channel;
import com.alttd.chat.objects.channels.CustomChannel; import com.alttd.chat.objects.channels.CustomChannel;
import com.alttd.chat.objects.ChatUser; import com.alttd.chat.objects.ChatUser;
import com.alttd.chat.util.ALogger; import com.alttd.chat.util.ALogger;
import com.alttd.chat.util.ServerName;
import com.alttd.chat.util.Utility; import com.alttd.chat.util.Utility;
import com.google.common.io.ByteArrayDataInput; import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
@@ -164,7 +165,7 @@ public class PluginMessage implements PluginMessageListener {
break; break;
} }
case "reloadconfig": case "reloadconfig":
ChatPlugin.getInstance().ReloadConfig(); ChatPlugin.getInstance().reloadConfig();
break; break;
case "chatpunishments": case "chatpunishments":
UUID uuid = UUID.fromString(in.readUTF()); UUID uuid = UUID.fromString(in.readUTF());
@@ -194,7 +195,7 @@ public class PluginMessage implements PluginMessageListener {
ALogger.warn("Received ChatChannel message for non existent channel."); ALogger.warn("Received ChatChannel message for non existent channel.");
return; return;
} }
if (!chatChannel.getServers().contains(Bukkit.getServer().getName())) { if (!chatChannel.getServers().contains(ServerName.getServerName())) {
ALogger.warn("Received ChatChannel message for the wrong server."); ALogger.warn("Received ChatChannel message for the wrong server.");
return; return;
} }
@@ -95,7 +95,8 @@ public class Nicknames implements CommandExecutor, TabCompleter {
sender.sendMessage(Utility.parseMiniMessage(Config.NICK_TRYOUT, sender.sendMessage(Utility.parseMiniMessage(Config.NICK_TRYOUT,
Placeholder.component("prefix", Utility.applyColor(api.getUserManager().getUser(player.getUniqueId()) Placeholder.component("prefix", Utility.applyColor(api.getUserManager().getUser(player.getUniqueId())
.getCachedData().getMetaData().getPrefix())), // TODO pull this from chatuser? .getCachedData().getMetaData().getPrefix())), // TODO pull this from chatuser?
Placeholder.component("nick", Utility.applyColor(args[1])))); Placeholder.component("nick", Utility.applyColor(args[1])),
Placeholder.unparsed("nickrequest", args[1])));
} }
} else { } else {
sender.sendMessage(Utility.parseMiniMessage(Config.NICK_NO_LUCKPERMS)); sender.sendMessage(Utility.parseMiniMessage(Config.NICK_NO_LUCKPERMS));
@@ -0,0 +1,41 @@
package com.alttd.chat.util;
import org.bukkit.Bukkit;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class ServerName {
private static final String serverName = loadServerName();
private static String loadServerName() {
String serverName = "unknown";
try {
File serverPropertiesFile = new File(Bukkit.getWorldContainer().getParentFile(), "server.properties");
if (!serverPropertiesFile.exists()) {
ALogger.warn(String.format("server.properties file not found in %s!", serverPropertiesFile.getAbsolutePath()));
return serverName;
}
Properties properties = new Properties();
FileInputStream fis = new FileInputStream(serverPropertiesFile);
properties.load(fis);
fis.close();
serverName = properties.getProperty("server-name", serverName);
ALogger.info(String.format("Found server name [%s]", serverName));
} catch (IOException e) {
ALogger.error("Failed to read server.properties", e);
}
return serverName;
}
public static String getServerName() {
return serverName;
}
}
@@ -24,7 +24,6 @@ import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.plugin.Dependency; import com.velocitypowered.api.plugin.Dependency;
import com.velocitypowered.api.plugin.Plugin; import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.plugin.annotation.DataDirectory; import com.velocitypowered.api.plugin.annotation.DataDirectory;
import com.velocitypowered.api.proxy.ConsoleCommandSource;
import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.messages.ChannelIdentifier; import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier; import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
@@ -83,9 +82,9 @@ public class VelocityChat {
ChatUserManager.addUser(console); ChatUserManager.addUser(console);
} }
public void ReloadConfig() { public void reloadConfig() {
chatAPI.ReloadConfig(); chatAPI.reloadConfig();
chatAPI.ReloadChatFilters(); chatAPI.reloadChatFilters();
serverHandler.cleanup(); serverHandler.cleanup();
ByteArrayDataOutput buf = ByteStreams.newDataOutput(); ByteArrayDataOutput buf = ByteStreams.newDataOutput();
buf.writeUTF("reloadconfig"); buf.writeUTF("reloadconfig");
@@ -15,7 +15,7 @@ public class Reload {
.<CommandSource>literal("reloadchat") .<CommandSource>literal("reloadchat")
.requires(ctx -> ctx.hasPermission("command.chat.reloadchat")) .requires(ctx -> ctx.hasPermission("command.chat.reloadchat"))
.executes(context -> { .executes(context -> {
VelocityChat.getPlugin().ReloadConfig(); VelocityChat.getPlugin().reloadConfig();
return 1; return 1;
}) })
.build(); .build();
@@ -205,6 +205,10 @@ public class ChatHandler {
} }
Mail mail = new Mail(targetUUID, uuid, message); Mail mail = new Mail(targetUUID, uuid, message);
ChatUser chatUser = ChatUserManager.getChatUser(targetUUID); ChatUser chatUser = ChatUserManager.getChatUser(targetUUID);
if (chatUser.getIgnoredPlayers().contains(uuid)) {
commandSource.sendMessage(Utility.parseMiniMessage("<red>You cannot mail this player</red>"));
return;
}
chatUser.addMail(mail); chatUser.addMail(mail);
// TODO load from config // TODO load from config
String finalSenderName = senderName; String finalSenderName = senderName;
@@ -23,8 +23,10 @@ import com.velocitypowered.api.proxy.server.RegisteredServer;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import net.kyori.adventure.title.Title;
import java.util.*; import java.util.*;
import java.util.concurrent.TimeUnit;
public class ProxyPlayerListener { public class ProxyPlayerListener {
@@ -68,9 +70,17 @@ public class ProxyPlayerListener {
List<Mail> unReadMail = chatUser.getUnReadMail(); List<Mail> unReadMail = chatUser.getUnReadMail();
if (unReadMail.isEmpty()) if (unReadMail.isEmpty())
return; return;
player.sendMessage(Utility.parseMiniMessage(Config.mailUnread, VelocityChat plugin = VelocityChat.getPlugin();
Placeholder.unparsed("amount", String.valueOf(unReadMail.size())) plugin.getProxy().getScheduler().buildTask(plugin, () -> {
)); if (!player.isActive())
return;
Component message = Utility.parseMiniMessage(Config.mailUnread,
Placeholder.unparsed("amount", String.valueOf(unReadMail.size())));
player.sendMessage(message);
player.showTitle(Title.title(message, Component.empty()));
}).delay(Config.mailDisplayDelay * 50L, TimeUnit.MILLISECONDS).schedule();
} }
@Subscribe @Subscribe