Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
179 changes: 128 additions & 51 deletions src/main/java/ru/overwrite/chat/ChatManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@

import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectList;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.chat.hover.content.Text;
import net.md_5.bungee.chat.ComponentSerializer;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.plugin.messaging.Messenger;
import ru.overwrite.chat.configuration.Config;
import ru.overwrite.chat.configuration.data.ChatChannel;
Expand All @@ -21,6 +22,8 @@

public class ChatManager {

private static final LegacyComponentSerializer LEGACY_SERIALIZER = LegacyComponentSerializer.legacySection();

private final PromisedChat plugin;
private final Config pluginConfig;
private final String[] searchList = {"%player%", "%prefix%", "%suffix%", "%dph%"};
Expand All @@ -41,24 +44,21 @@ private void setupProxy() {
}
}

public void processChat(Player p, String rawMessage, AsyncPlayerChatEvent e) {
public PreparedChatMessage prepareChat(Player p, String rawMessage) {
ChatChannel channel = pluginConfig.findChannel(rawMessage);

if (!channel.equals(pluginConfig.getDefaultChannel()) && !p.hasPermission(channel.permission())) {
channel = pluginConfig.getDefaultChannel();
}

String message = (channel.prefix() != '\0' && rawMessage.charAt(0) == channel.prefix())
? rawMessage.substring(1).trim() : rawMessage;
String message = stripPrefix(channel, rawMessage);

if (message.isEmpty()) {
e.setCancelled(true);
return;
return null;
}

if (channel.cooldownSettings().process(p)) {
e.setCancelled(true);
return;
return null;
}

String donatePlaceholder = plugin.getPerms() != null ? getDonatePlaceholder(p, channel) : "";
Expand All @@ -71,21 +71,62 @@ public void processChat(Player p, String rawMessage, AsyncPlayerChatEvent e) {

String chatFormat = Utils.colorize(Utils.replacePlaceholders(p, Utils.replaceEach(channel.format(), searchList, replacementList)));

e.getRecipients().clear();
String renderedMessage = chatFormat.replace("%message%", colorizedMessage);

String hoverText = null;
String clickAction = null;
String clickActionValue = null;

ChatChannel.HoverSettings hoverSettings = channel.hover();
if (hoverSettings != null && hoverSettings.hoverEnabled()) {
hoverText = Utils.colorize(Utils.replacePlaceholders(p, Utils.replaceEach(hoverSettings.hoverMessage(), searchList, replacementList)));
if (hoverSettings.clickEventEnabled()) {
clickAction = hoverSettings.clickAction();
clickActionValue = Utils.replacePlaceholders(p, Utils.replaceEach(hoverSettings.clickActionValue(), searchList, replacementList));
}
}

return new PreparedChatMessage(
p,
channel,
renderedMessage,
getRadius(p, channel),
hoverText,
clickAction,
clickActionValue
);
}

public Component createPaperComponent(PreparedChatMessage prepared) {
Component component = LEGACY_SERIALIZER.deserialize(prepared.renderedMessage());

if (!prepared.hoverEnabled()) {
return component;
}

ObjectList<Player> playersInRadius = getRadius(p, channel);
Component hoverComponent = LEGACY_SERIALIZER.deserialize(prepared.hoverText());
Component wrapped = Component.empty().append(component).hoverEvent(HoverEvent.showText(hoverComponent));

String formatWithMessage = getFormatWithMessage(chatFormat, colorizedMessage);
ClickEvent clickEvent = createPaperClickEvent(prepared);
return clickEvent != null ? wrapped.clickEvent(clickEvent) : wrapped;
}

if (sendHover(p, replacementList, playersInRadius, formatWithMessage, channel)) {
e.setCancelled(true);
public void forwardProxy(PreparedChatMessage prepared) {
if (pluginMessage == null || prepared.channel().radius() >= 0) {
return;
}
e.getRecipients().addAll(playersInRadius);
e.setFormat(formatWithMessage);
if (pluginMessage != null && channel.radius() < 0) {
pluginMessage.sendCrossProxy(p, formatWithMessage, channel.permission(), false);

if (prepared.hoverEnabled()) {
pluginMessage.sendCrossProxy(
prepared.player(),
ComponentSerializer.toString(createProxyComponents(prepared)),
prepared.channel().permission(),
true
);
return;
}

pluginMessage.sendCrossProxy(prepared.player(), prepared.renderedMessage(), prepared.channel().permission(), false);
}

public boolean checkNewbie(Player p, Cancellable e) {
Expand All @@ -105,34 +146,6 @@ public boolean checkNewbie(Player p, Cancellable e) {
return false;
}

public boolean sendHover(Player p, String[] replacementList, ObjectList<Player> recipients, String formatWithMessage, ChatChannel channel) {
ChatChannel.HoverSettings hoverSettings = channel.hover();
if (!hoverSettings.hoverEnabled()) {
return false;
}
String hoverText = Utils.colorize(Utils.replacePlaceholders(p, Utils.replaceEach(hoverSettings.hoverMessage(), searchList, replacementList)));
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(TextComponent.fromLegacyText(hoverText)));
BaseComponent[] comp = TextComponent.fromLegacyText(formatWithMessage);
for (BaseComponent component : comp) {
component.setHoverEvent(hoverEvent);
}
if (hoverSettings.clickEventEnabled()) {
ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.valueOf(hoverSettings.clickAction()), Utils.replacePlaceholders(p, Utils.replaceEach(hoverSettings.clickActionValue(), searchList, replacementList)));
for (BaseComponent component : comp) {
component.setClickEvent(clickEvent);
}
}
for (Player recipient : recipients) {
recipient.spigot().sendMessage(comp);
}
if (pluginMessage != null && channel.radius() < 0) {
pluginMessage.sendCrossProxy(p, ComponentSerializer.toString(comp), channel.permission(), true);
}
// Костыли... костыли вечны.
Bukkit.getConsoleSender().sendMessage(formatWithMessage);
return true;
}

private ObjectList<Player> getRadius(Player p, ChatChannel chatChannel) {
ObjectList<Player> plist = new ObjectArrayList<>();
double radius = chatChannel.radius();
Expand All @@ -155,14 +168,78 @@ private ObjectList<Player> getRadius(Player p, ChatChannel chatChannel) {
return plist;
}

private String getFormatWithMessage(String format, String chatMessage) {
return format
.replace("%message%", chatMessage)
.replace("%", "%%"); // Это надо чтобы PAPI не выёбывался
private String stripPrefix(ChatChannel channel, String rawMessage) {
return channel.prefix() != '\0' && !rawMessage.isEmpty() && rawMessage.charAt(0) == channel.prefix()
? rawMessage.substring(1).trim()
: rawMessage;
}

private BaseComponent[] createProxyComponents(PreparedChatMessage prepared) {
BaseComponent[] components = TextComponent.fromLegacyText(prepared.renderedMessage());
net.md_5.bungee.api.chat.HoverEvent hoverEvent = new net.md_5.bungee.api.chat.HoverEvent(
net.md_5.bungee.api.chat.HoverEvent.Action.SHOW_TEXT,
new Text(TextComponent.fromLegacyText(prepared.hoverText()))
);

for (BaseComponent component : components) {
component.setHoverEvent(hoverEvent);
}

net.md_5.bungee.api.chat.ClickEvent clickEvent = createProxyClickEvent(prepared);
if (clickEvent != null) {
for (BaseComponent component : components) {
component.setClickEvent(clickEvent);
}
}

return components;
}

private ClickEvent createPaperClickEvent(PreparedChatMessage prepared) {
if (prepared.clickAction() == null || prepared.clickActionValue() == null) {
return null;
}

try {
return ClickEvent.clickEvent(ClickEvent.Action.valueOf(prepared.clickAction()), prepared.clickActionValue());
} catch (IllegalArgumentException e) {
plugin.getLogger().warning("Unknown click action for Paper chat: " + prepared.clickAction());
return null;
}
}

private net.md_5.bungee.api.chat.ClickEvent createProxyClickEvent(PreparedChatMessage prepared) {
if (prepared.clickAction() == null || prepared.clickActionValue() == null) {
return null;
}

try {
return new net.md_5.bungee.api.chat.ClickEvent(
net.md_5.bungee.api.chat.ClickEvent.Action.valueOf(prepared.clickAction()),
prepared.clickActionValue()
);
} catch (IllegalArgumentException e) {
plugin.getLogger().warning("Unknown click action for proxy chat: " + prepared.clickAction());
return null;
}
}

private String getDonatePlaceholder(Player p, ChatChannel chatChannel) {
String primaryGroup = plugin.getPerms().getPrimaryGroup(p);
return chatChannel.donatePlaceholders().getOrDefault(primaryGroup, "");
}

public record PreparedChatMessage(
Player player,
ChatChannel channel,
String renderedMessage,
ObjectList<Player> recipients,
String hoverText,
String clickAction,
String clickActionValue
) {
public boolean hoverEnabled() {
return hoverText != null && !hoverText.isEmpty();
}
}
}
41 changes: 29 additions & 12 deletions src/main/java/ru/overwrite/chat/listener/ChatListener.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
package ru.overwrite.chat.listener;

import io.papermc.paper.chat.ChatRenderer;
import io.papermc.paper.event.player.AsyncChatEvent;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import ru.overwrite.chat.ChatManager;
import ru.overwrite.chat.ChatManager.PreparedChatMessage;
import ru.overwrite.chat.PromisedChat;
import ru.overwrite.chat.configuration.Config;

Expand All @@ -23,63 +28,75 @@ public ChatListener(PromisedChat plugin) {
// Не ну а хуле делать

@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onChatLowest(AsyncPlayerChatEvent e) {
public void onChatLowest(AsyncChatEvent e) {
if (pluginConfig.getChatPriority() != EventPriority.LOWEST) {
return;
}
process(e);
}

@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onChatLow(AsyncPlayerChatEvent e) {
public void onChatLow(AsyncChatEvent e) {
if (pluginConfig.getChatPriority() != EventPriority.LOW) {
return;
}
process(e);
}

@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onChatNormal(AsyncPlayerChatEvent e) {
public void onChatNormal(AsyncChatEvent e) {
if (pluginConfig.getChatPriority() != EventPriority.NORMAL) {
return;
}
process(e);
}

@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onChatHigh(AsyncPlayerChatEvent e) {
public void onChatHigh(AsyncChatEvent e) {
if (pluginConfig.getChatPriority() != EventPriority.HIGH) {
return;
}
process(e);
}

@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onChatHighest(AsyncPlayerChatEvent e) {
public void onChatHighest(AsyncChatEvent e) {
if (pluginConfig.getChatPriority() != EventPriority.HIGHEST) {
return;
}
process(e);
}

@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onChatMonitor(AsyncPlayerChatEvent e) {
public void onChatMonitor(AsyncChatEvent e) {
if (pluginConfig.getChatPriority() != EventPriority.MONITOR) {
return;
}
process(e);
}

private void process(AsyncPlayerChatEvent e) {
Player p = e.getPlayer();
private void process(AsyncChatEvent e) {
Player player = e.getPlayer();

if (chatManager.checkNewbie(p, e)) {
if (chatManager.checkNewbie(player, e)) {
return;
}

String rawMessage = e.getMessage();
PreparedChatMessage prepared = chatManager.prepareChat(player, PlainTextComponentSerializer.plainText().serialize(e.message()));
if (prepared == null) {
e.setCancelled(true);
return;
}

e.viewers().removeIf(viewer -> shouldRemoveViewer(viewer, prepared));

chatManager.processChat(p, rawMessage, e);
Component renderedMessage = chatManager.createPaperComponent(prepared);
e.renderer(ChatRenderer.viewerUnaware((source, sourceDisplayName, message) -> renderedMessage));

chatManager.forwardProxy(prepared);
}

private boolean shouldRemoveViewer(Audience viewer, PreparedChatMessage prepared) {
return viewer instanceof Player player && !prepared.recipients().contains(player);
}
}
Loading