|
4 | 4 | import net.kyori.adventure.audience.Audience;
|
5 | 5 | import net.kyori.adventure.text.Component;
|
6 | 6 | import net.kyori.adventure.text.TextComponent;
|
| 7 | +import net.kyori.adventure.text.TextReplacementConfig; |
7 | 8 | import net.kyori.adventure.text.event.ClickEvent;
|
8 | 9 | import net.kyori.adventure.text.event.HoverEvent;
|
| 10 | +import net.kyori.adventure.text.format.NamedTextColor; |
| 11 | +import net.kyori.adventure.text.format.TextDecoration; |
9 | 12 | import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
10 |
| -import org.bukkit.ChatColor; |
| 13 | +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; |
11 | 14 | import org.bukkit.configuration.file.FileConfiguration;
|
12 | 15 | import org.bukkit.configuration.file.YamlConfiguration;
|
13 | 16 | import org.bukkit.entity.Player;
|
|
18 | 21 | import org.bukkit.event.player.PlayerQuitEvent;
|
19 | 22 |
|
20 | 23 | import java.io.File;
|
21 |
| -import java.util.Objects; |
| 24 | +import java.util.regex.Pattern; |
22 | 25 |
|
23 | 26 | public class PublicChat implements Listener {
|
24 | 27 | public final Main plugin;
|
25 | 28 | private final FileConfiguration permissionConfig;
|
26 | 29 |
|
| 30 | + public static final Pattern DEFAULT_URL_PATTERN = Pattern.compile("https?://(?:www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b[-a-zA-Z0-9()@:%_\\\\+.~#?&/=]*"); |
| 31 | + |
27 | 32 | public PublicChat(final Main plugin) {
|
28 | 33 | this.plugin = plugin;
|
29 | 34 | File customConfig = Main.PermissionConfig;
|
30 | 35 | permissionConfig = YamlConfiguration.loadConfiguration(customConfig);
|
31 | 36 | }
|
32 | 37 |
|
33 |
| - public String replacePrefixColors(String message, final Player player) { |
34 |
| - for (ChatColor color : ChatColor.values()) { |
35 |
| - if (plugin.getConfig().getString("ChatCo.chatPrefixes." + color.name()) != null && message.startsWith(Objects.requireNonNull(plugin.getConfig().getString("ChatCo.chatPrefixes." + color.name())))) { |
| 38 | + public Component replacePrefixColors(Component message, final Player player) { |
| 39 | + String messagePlain = PlainTextComponentSerializer.plainText().serialize(message); |
36 | 40 |
|
37 |
| - // check for global or player permission |
38 |
| - if (permissionConfig.getBoolean("ChatCo.chatPrefixes." + color.name(), false) || player.hasPermission("ChatCo.chatPrefixes." + color.name())) { |
39 |
| - message = color + message; |
40 |
| - } |
| 41 | + for (String color : NamedTextColor.NAMES.keys()) { |
| 42 | + String configKey = "ChatCo.chatPrefixes." + color; |
| 43 | + String configValue = plugin.getConfig().getString(configKey); |
41 | 44 |
|
42 |
| - // break here since we found a prefix color code |
43 |
| - break; |
| 45 | + if (configValue != null && messagePlain.startsWith(configValue)) { |
| 46 | + if (permissionConfig.getBoolean(configKey, false) || player.hasPermission(configKey)) { |
| 47 | + return message.color(NamedTextColor.NAMES.value(color)); |
| 48 | + } |
44 | 49 | }
|
45 | 50 | }
|
46 | 51 |
|
47 | 52 | return message;
|
48 | 53 | }
|
49 | 54 |
|
50 |
| - public String replaceInlineColors(String message, final Player player) { |
51 |
| - for (ChatColor color : ChatColor.values()) { |
52 |
| - if ((permissionConfig.getBoolean("ChatCo.chatColors." + color.name(), false) || player.hasPermission("ChatCo.chatColors." + color.name())) && plugin.getConfig().getString("ChatCo.chatColors." + color.name()) != null) { |
53 |
| - message = message.replace(Objects.requireNonNull(plugin.getConfig().getString("ChatCo.chatColors." + color.name())), color.toString()); |
| 55 | + public Component replaceInlineColors(Component message, final Player player) { |
| 56 | + for (String color : NamedTextColor.NAMES.keys()) { |
| 57 | + String configKey = "ChatCo.chatColors." + color; |
| 58 | + String configValue = plugin.getConfig().getString(configKey); |
| 59 | + |
| 60 | + if (configValue != null) { |
| 61 | + if (permissionConfig.getBoolean(configKey, false) || player.hasPermission(configKey)) { |
| 62 | + return message.replaceText(TextReplacementConfig.builder() |
| 63 | + .match(Pattern.quote(configValue) + ".*$") |
| 64 | + .replacement(s -> s.content(s.content().substring(configValue.length())).color(NamedTextColor.NAMES.value(color))) |
| 65 | + .build()); |
| 66 | + } |
54 | 67 | }
|
55 | 68 | }
|
56 | 69 |
|
57 | 70 | return message;
|
58 | 71 | }
|
59 | 72 |
|
| 73 | + private Component replaceUrls(Component component) { |
| 74 | + return component.replaceText( |
| 75 | + TextReplacementConfig.builder() |
| 76 | + .match(DEFAULT_URL_PATTERN) |
| 77 | + .replacement(url -> url |
| 78 | + .decorate(TextDecoration.UNDERLINED) |
| 79 | + .clickEvent(ClickEvent.openUrl(url.content())) |
| 80 | + .hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT, Component.text(url.content()))) |
| 81 | + ) |
| 82 | + .build() |
| 83 | + ); |
| 84 | + } |
| 85 | + |
60 | 86 | /**
|
61 | 87 | * See <a href="https://docs.advntr.dev/text.html">Text (Chat Components)</a>
|
62 | 88 | */
|
63 | 89 | @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
64 | 90 | public void onAsyncChat(AsyncChatEvent event) {
|
65 |
| - // Plain message |
66 |
| - final Player player = event.getPlayer(); |
67 |
| - |
68 | 91 | String legacyMessage = LegacyComponentSerializer.legacyAmpersand().serialize(event.message());
|
69 |
| - legacyMessage = replacePrefixColors(legacyMessage, player); |
70 |
| - legacyMessage = replaceInlineColors(legacyMessage, player); |
71 | 92 |
|
72 | 93 | // Do not send empty messages
|
73 | 94 | if (legacyMessage.trim().isEmpty()) {
|
74 |
| - event.setCancelled(true); |
| 95 | + event.viewers().clear(); |
75 | 96 | return;
|
76 | 97 | }
|
77 | 98 |
|
78 | 99 | // Message text
|
79 | 100 | Component messageText = Component.text(legacyMessage);
|
80 | 101 |
|
| 102 | + // Player |
| 103 | + final Player player = event.getPlayer(); |
| 104 | + |
| 105 | + // Replace color codes |
| 106 | + messageText = replacePrefixColors(messageText, player); |
| 107 | + messageText = replaceInlineColors(messageText, player); |
| 108 | + |
| 109 | + // Clickable links |
| 110 | + messageText = replaceUrls(messageText); |
| 111 | + |
81 | 112 | // Sender name
|
82 | 113 | Component sender = player.displayName();
|
83 | 114 |
|
|
0 commit comments