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 Component TOGGLED_ON = 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() {
ConfigurationNode node = getNode("chat-channels");
if (node.empty()) {
@ -383,12 +385,16 @@ public final class Config {
new CustomChannel(channelName,
getString(key + "format", ""),
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);
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>"));
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";

View File

@ -10,12 +10,14 @@ public class Channel {
protected String channelName;
protected String format;
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.channelName = channelName;
this.format = format;
this.proxy = proxy;
this.local = local;
channels.put(channelName.toLowerCase(), this);
}
@ -39,6 +41,10 @@ public class Channel {
return proxy;
}
public boolean isLocal() {
return local;
}
public static Channel getChatChannel(String channelName) {
return channels.get(channelName.toLowerCase());
}

View File

@ -5,8 +5,8 @@ import java.util.*;
public class CustomChannel extends Channel {
private final List<String> servers;
public CustomChannel(String channelName, String format, List<String> servers, boolean proxy) {
super(channelName, format, proxy);
public CustomChannel(String channelName, String format, List<String> servers, boolean proxy, boolean local) {
super(channelName, format, proxy, local);
this.permission = "chat.channel." + channelName.toLowerCase();
this.channelName = channelName;
this.format = format;

View File

@ -2,6 +2,6 @@ package com.alttd.chat.objects.channels;
public abstract class DefaultChannel extends Channel{
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.serializer.gson.GsonComponentSerializer;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@ -188,9 +190,9 @@ public class ChatHandler {
component = modifiableString.component();
if (channel.isProxy()) {
sendChatChannelMessage(player, channel.getChannelName(), "chatchannel", component);
sendChatChannelMessage(player, channel.getChannelName(), "chatchannel", component, message);
} 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);
if (player == null) {
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()
.filter(p -> p.hasPermission(chatChannel.getPermission()));
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) {
@ -283,7 +307,7 @@ public class ChatHandler {
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();
out.writeUTF(channel);
out.writeUTF(chatChannelName);

View File

@ -116,7 +116,7 @@ public class ChatListener implements Listener {
if (!player.hasPermission("chat.ignorebypass")) {
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());
@ -140,9 +140,9 @@ public class ChatListener implements Listener {
String nickName = PlainTextComponentSerializer.plainText().serialize(onlinePlayer.displayName());
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 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());
if (namePattern.matcher(modifiableString.string()).find()) {
@ -152,16 +152,18 @@ public class ChatListener implements Listener {
.replacement(mention.append(onlinePlayerUser.getDisplayName()))
.build());
//TODO replace all instances of \name with just name but using the match result so the capitalization doesn't change
// modifiableString.replace(TextReplacementConfig.builder()
// .once()
// .match(escapedNamePattern)
// .replacement((a, b) -> {
// String substring = a.group().substring(1);
// return ;
// });
// modifiableString.replace(TextReplacementConfig.builder()
// .once()
// .match(escapedNamePattern)
// .replacement((a, b) -> {
// String substring = a.group().substring(1);
// return ;
// });
if (!ChatUserManager.getChatUser(onlinePlayer.getUniqueId()).getIgnoredPlayers().contains(player.getUniqueId())
&& !player.hasPermission("chat.ignorebypass"))
|| player.hasPermission("chat.ignorebypass")) {
playersToPing.add(onlinePlayer);
}
} else if (nickPattern.matcher(modifiableString.string()).find()) {
modifiableString.replace(TextReplacementConfig.builder()
.once()
@ -169,8 +171,9 @@ public class ChatListener implements Listener {
.replacement(mention.append(onlinePlayerUser.getDisplayName()))
.build());
if (!ChatUserManager.getChatUser(onlinePlayer.getUniqueId()).getIgnoredPlayers().contains(player.getUniqueId())
&& !player.hasPermission("chat.ignorebypass"))
|| player.hasPermission("chat.ignorebypass")) {
playersToPing.add(onlinePlayer);
}
}
}
}