Compare commits

...

2 Commits

Author SHA1 Message Date
Teriuihi 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
Teriuihi 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
6 changed files with 62 additions and 23 deletions

View File

@ -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";

View File

@ -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());
} }

View File

@ -5,8 +5,8 @@ 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;

View File

@ -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);
} }
} }

View File

@ -22,7 +22,9 @@ 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;
@ -188,9 +190,9 @@ public class ChatHandler {
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);
} }
} }
@ -243,7 +245,7 @@ public class ChatHandler {
// } // }
} }
private void sendChatChannelMessage(CustomChannel chatChannel, UUID uuid, Component component) { private void sendChatChannelMessage(CustomChannel chatChannel, UUID uuid, Component component, String message) {
Player player = Bukkit.getPlayer(uuid); Player player = Bukkit.getPlayer(uuid);
if (player == null) { if (player == null) {
ALogger.warn("Failed to send chat message from non existent player"); ALogger.warn("Failed to send chat message from non existent player");
@ -261,9 +263,31 @@ public class ChatHandler {
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) {
@ -283,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);

View File

@ -116,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());
@ -140,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()) {
@ -152,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()
@ -169,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);
}
} }
} }
} }