Skip to content

Commit

Permalink
Add support for Paper's chat events (EssentialsX#6033)
Browse files Browse the repository at this point in the history
  • Loading branch information
JRoy authored Feb 14, 2025
1 parent 4e64782 commit cb00783
Show file tree
Hide file tree
Showing 11 changed files with 362 additions and 47 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.earth2me.essentials.utils;

import net.ess3.api.IEssentials;
import net.ess3.provider.AbstractChatEvent;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.flattener.ComponentFlattener;
import net.kyori.adventure.text.format.NamedTextColor;
Expand All @@ -20,6 +21,7 @@ public final class AdventureUtil {
static {
final LegacyComponentSerializer.Builder builder = LegacyComponentSerializer.builder()
.flattener(ComponentFlattener.basic())
.extractUrls(AbstractChatEvent.URL_PATTERN)
.useUnusualXRepeatedCharacterHexFormat();
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_16_1_R01)) {
builder.hexColors();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.earth2me.essentials.utils;

import net.ess3.api.IUser;
import net.ess3.provider.AbstractChatEvent;
import org.bukkit.ChatColor;
import org.bukkit.Color;

Expand All @@ -24,7 +25,6 @@ public final class FormatUtil {
private static final Pattern REPLACE_ALL_RGB_PATTERN = Pattern.compile("(&)?&#([0-9a-fA-F]{6})");
//Used to prepare xmpp output
private static final Pattern LOGCOLOR_PATTERN = Pattern.compile("\\x1B\\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]");
private static final Pattern URL_PATTERN = Pattern.compile("((?:(?:https?)://)?[\\w-_\\.]{2,})\\.([a-zA-Z]{2,3}(?:/\\S+)?)");
//Used to strip ANSI control codes from console
private static final Pattern ANSI_CONTROL_PATTERN = Pattern.compile("[\\x1B\\x9B][\\[\\]()#;?]*(?:(?:(?:;[-a-zA-Z\\d/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d/#&.:=?%@~_]*)*)?\\x07|(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~])");
private static final Pattern PAPER_CONTROL_PATTERN = Pattern.compile("(?i)" + (char) 0x7f + "[0-9A-FK-ORX]");
Expand Down Expand Up @@ -297,9 +297,9 @@ static String blockURL(final String input) {
if (input == null) {
return null;
}
String text = URL_PATTERN.matcher(input).replaceAll("$1 $2");
while (URL_PATTERN.matcher(text).find()) {
text = URL_PATTERN.matcher(text).replaceAll("$1 $2");
String text = AbstractChatEvent.URL_PATTERN.matcher(input).replaceAll("$1 $2");
while (AbstractChatEvent.URL_PATTERN.matcher(text).find()) {
text = AbstractChatEvent.URL_PATTERN.matcher(text).replaceAll("$1 $2");
}
return text;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import com.earth2me.essentials.Essentials;
import com.earth2me.essentials.EssentialsLogger;
import com.earth2me.essentials.chat.processing.ChatHandler;
import com.earth2me.essentials.chat.processing.PaperChatHandler;
import com.earth2me.essentials.metrics.MetricsWrapper;
import com.earth2me.essentials.utils.AdventureUtil;
import com.earth2me.essentials.utils.VersionUtil;
import net.ess3.api.IEssentials;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
Expand Down Expand Up @@ -32,8 +34,13 @@ public void onEnable() {
return;
}

final ChatHandler legacyHandler = new ChatHandler((Essentials) ess, this);
legacyHandler.registerListeners();
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_16_5_R01) && VersionUtil.isPaper()) {
final PaperChatHandler paperHandler = new PaperChatHandler((Essentials) ess, this);
paperHandler.registerListeners();
} else {
final ChatHandler legacyHandler = new ChatHandler((Essentials) ess, this);
legacyHandler.registerListeners();
}

if (metrics == null) {
metrics = new MetricsWrapper(this, 3814, false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.earth2me.essentials.utils.AdventureUtil;
import com.earth2me.essentials.utils.FormatUtil;
import net.ess3.api.events.LocalChatSpyEvent;
import net.ess3.provider.AbstractChatEvent;
import net.essentialsx.api.v2.ChatType;
import net.essentialsx.api.v2.events.chat.ChatEvent;
import net.essentialsx.api.v2.events.chat.GlobalChatEvent;
Expand All @@ -22,10 +23,8 @@
import org.bukkit.scoreboard.Team;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Set;
import java.util.logging.Level;

import static com.earth2me.essentials.I18n.tlLiteral;

Expand All @@ -48,7 +47,7 @@ protected AbstractChatHandler(Essentials ess, EssentialsChat essChat) {
* <p>
* Handled at {@link org.bukkit.event.EventPriority#LOWEST} on both preview and chat events.
*/
protected void handleChatFormat(AsyncPlayerChatEvent event) {
protected void handleChatFormat(AbstractChatEvent event) {
if (isAborted(event)) {
return;
}
Expand All @@ -73,8 +72,9 @@ protected void handleChatFormat(AsyncPlayerChatEvent event) {
final long configRadius = ess.getSettings().getChatRadius();
chat.setRadius(Math.max(configRadius, 0));

final String formatted = FormatUtil.formatMessage(user, "essentials.chat", event.getMessage());
// This listener should apply the general chat formatting only...then return control back the event handler
event.setMessage(FormatUtil.formatMessage(user, "essentials.chat", event.getMessage()));
event.setMessage(formatted);

if (ChatColor.stripColor(event.getMessage()).isEmpty()) {
event.setCancelled(true);
Expand Down Expand Up @@ -110,6 +110,12 @@ protected void handleChatFormat(AsyncPlayerChatEvent event) {
event.setMessage(event.getMessage().substring(1));
}

// Prevent messages like "!&c" or "?&c" from being sent which would cause an empty message
if (ChatColor.stripColor(event.getMessage()).isEmpty()) {
event.setCancelled(true);
return;
}

if (chat.getType() == ChatType.UNKNOWN) {
format = AdventureUtil.miniToLegacy(tlLiteral("chatTypeLocal")).concat(format);
} else {
Expand All @@ -128,7 +134,7 @@ protected void handleChatFormat(AsyncPlayerChatEvent event) {
* <p>
* Runs at {@link org.bukkit.event.EventPriority#NORMAL} priority on submitted chat events only.
*/
protected void handleChatRecipients(AsyncPlayerChatEvent event) {
protected void handleChatRecipients(AbstractChatEvent event) {
if (isAborted(event)) {
return;
}
Expand All @@ -151,12 +157,12 @@ protected void handleChatRecipients(AsyncPlayerChatEvent event) {
return;
}

event.getRecipients().removeIf(player -> !ess.getUser(player).isAuthorized("essentials.chat.receive.local"));
event.removeRecipients(player -> !ess.getUser(player).isAuthorized("essentials.chat.receive.local"));
} else {
final String permission = "essentials.chat." + chat.getType().key();

if (user.isAuthorized(permission)) {
event.getRecipients().removeIf(player -> !ess.getUser(player).isAuthorized("essentials.chat.receive." + chat.getType().key()));
event.removeRecipients(player -> !ess.getUser(player).isAuthorized("essentials.chat.receive." + chat.getType().key()));

callChatEvent(event, chat.getType(), null);
} else {
Expand All @@ -171,22 +177,10 @@ protected void handleChatRecipients(AsyncPlayerChatEvent event) {
final Location loc = user.getLocation();
final World world = loc.getWorld();

final Set<Player> outList = event.getRecipients();
final Set<Player> spyList = new HashSet<>();

try {
outList.add(event.getPlayer());
} catch (final UnsupportedOperationException ex) {
if (ess.getSettings().isDebug()) {
essChat.getLogger().log(Level.INFO, "Plugin triggered custom chat event, local chat handling aborted.", ex);
}
return;
}

final Iterator<Player> it = outList.iterator();
while (it.hasNext()) {
final Player onlinePlayer = it.next();
final User onlineUser = ess.getUser(onlinePlayer);
event.removeRecipients(player -> {
final User onlineUser = ess.getUser(player);
if (!onlineUser.equals(user)) {
boolean abort = false;
final Location playerLoc = onlineUser.getLocation();
Expand All @@ -200,20 +194,21 @@ protected void handleChatRecipients(AsyncPlayerChatEvent event) {
}
if (abort) {
if (onlineUser.isAuthorized("essentials.chat.spy")) {
spyList.add(onlinePlayer);
spyList.add(player);
}
it.remove();
return true;
}
}
}
return false;
});

callChatEvent(event, ChatType.LOCAL, chat.getRadius());

if (event.isCancelled()) {
return;
}

if (outList.size() < 2) {
if (event.recipients().size() < 2) {
user.sendTl("localNoOne");
}

Expand Down Expand Up @@ -242,17 +237,22 @@ protected void handleChatRecipients(AsyncPlayerChatEvent event) {
* @param chatType Chat type which determines which event will be created and called.
* @param radius If chat is a local chat, this is a non-squared radius used to calculate recipients, otherwise {@code null}.
*/
protected void callChatEvent(final AsyncPlayerChatEvent event, final ChatType chatType, final Long radius) {
protected void callChatEvent(final AbstractChatEvent event, final ChatType chatType, final Long radius) {
final ChatEvent chatEvent;

if (chatType == ChatType.LOCAL) {
chatEvent = new LocalChatEvent(event.isAsynchronous(), event.getPlayer(), event.getFormat(), event.getMessage(), event.getRecipients(), radius);
chatEvent = new LocalChatEvent(event.isAsynchronous(), event.getPlayer(), event.getFormat(), event.getMessage(), event.recipients(), radius);
} else {
chatEvent = new GlobalChatEvent(event.isAsynchronous(), chatType, event.getPlayer(), event.getFormat(), event.getMessage(), event.getRecipients());
chatEvent = new GlobalChatEvent(event.isAsynchronous(), chatType, event.getPlayer(), event.getFormat(), event.getMessage(), event.recipients());
}

server.getPluginManager().callEvent(chatEvent);

event.removeRecipients(player -> !chatEvent.getRecipients().contains(player));
for (final Player recipient : chatEvent.getRecipients()) {
event.addRecipient(recipient);
}

event.setFormat(chatEvent.getFormat());
event.setMessage(chatEvent.getMessage());
event.setCancelled(chatEvent.isCancelled());
Expand All @@ -262,9 +262,9 @@ protected void callChatEvent(final AsyncPlayerChatEvent event, final ChatType ch
* Finalise the formatting stage of chat processing.
* <p>
* Handled at {@link org.bukkit.event.EventPriority#HIGHEST} during previews, and immediately after
* {@link #handleChatFormat(AsyncPlayerChatEvent)} when previews are not available.
* {@link #handleChatFormat(AbstractChatEvent)} when previews are not available.
*/
protected void handleChatPostFormat(AsyncPlayerChatEvent event) {
protected void handleChatPostFormat(AbstractChatEvent event) {
if (isAborted(event)) {
cache.clearProcessedChat(event.getPlayer());
}
Expand All @@ -273,7 +273,7 @@ protected void handleChatPostFormat(AsyncPlayerChatEvent event) {
/**
* Run costs for chat and clean up the cached {@link com.earth2me.essentials.chat.processing.ChatProcessingCache.ProcessedChat}
*/
protected void handleChatSubmit(AsyncPlayerChatEvent event) {
protected void handleChatSubmit(AbstractChatEvent event) {
if (isAborted(event)) {
return;
}
Expand All @@ -284,7 +284,7 @@ protected void handleChatSubmit(AsyncPlayerChatEvent event) {
cache.clearProcessedChat(event.getPlayer());
}

boolean isAborted(final AsyncPlayerChatEvent event) {
boolean isAborted(final AbstractChatEvent event) {
return event.isCancelled();
}

Expand Down Expand Up @@ -320,7 +320,7 @@ private void charge(final User user, final Trade charge) throws ChargeException
charge.charge(user);
}

boolean charge(final AsyncPlayerChatEvent event, final ChatProcessingCache.ProcessedChat chat) {
boolean charge(final AbstractChatEvent event, final ChatProcessingCache.ProcessedChat chat) {
try {
charge(chat.getUser(), chat.getCharge());
} catch (final ChargeException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.earth2me.essentials.Essentials;
import com.earth2me.essentials.chat.EssentialsChat;
import net.ess3.provider.AbstractChatEvent;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.AsyncPlayerChatEvent;
Expand All @@ -19,28 +20,33 @@ public void registerListeners() {
pm.registerEvents(new ChatHighest(), essChat);
}

private class ChatLowest implements ChatListener {
private AbstractChatEvent wrap(final AsyncPlayerChatEvent event) {
return new SpigotChatEvent(event);
}

private final class ChatLowest implements ChatListener {
@Override
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerChat(AsyncPlayerChatEvent event) {
handleChatFormat(event);
handleChatFormat(wrap(event));
}
}

private class ChatNormal implements ChatListener {
private final class ChatNormal implements ChatListener {
@Override
@EventHandler(priority = EventPriority.NORMAL)
public void onPlayerChat(AsyncPlayerChatEvent event) {
handleChatRecipients(event);
handleChatRecipients(wrap(event));
}
}

private class ChatHighest implements ChatListener {
private final class ChatHighest implements ChatListener {
@Override
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerChat(AsyncPlayerChatEvent event) {
handleChatPostFormat(event);
handleChatSubmit(event);
final AbstractChatEvent absEvent = wrap(event);
handleChatPostFormat(absEvent);
handleChatSubmit(absEvent);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.earth2me.essentials.chat.processing;

import com.earth2me.essentials.Essentials;
import com.earth2me.essentials.chat.EssentialsChat;
import net.ess3.provider.AbstractChatEvent;
import net.ess3.provider.providers.PaperChatListenerProvider;
import org.bukkit.plugin.PluginManager;

public class PaperChatHandler extends AbstractChatHandler {
public PaperChatHandler(Essentials ess, EssentialsChat essChat) {
super(ess, essChat);
}

public void registerListeners() {
final PluginManager pm = essChat.getServer().getPluginManager();
pm.registerEvents(new ChatListener(), essChat);
}

public final class ChatListener extends PaperChatListenerProvider {
@Override
public void onChatLowest(AbstractChatEvent event) {
handleChatFormat(event);
}

@Override
public void onChatNormal(AbstractChatEvent event) {
handleChatRecipients(event);
}

@Override
public void onChatHighest(AbstractChatEvent event) {
handleChatPostFormat(event);
handleChatSubmit(event);
}
}
}
Loading

0 comments on commit cb00783

Please sign in to comment.