|
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