diff --git a/EssentialsDiscord/src/main/java/net/essentialsx/discord/JDADiscordService.java b/EssentialsDiscord/src/main/java/net/essentialsx/discord/JDADiscordService.java index 2843e55af2b..a5e6fccec22 100644 --- a/EssentialsDiscord/src/main/java/net/essentialsx/discord/JDADiscordService.java +++ b/EssentialsDiscord/src/main/java/net/essentialsx/discord/JDADiscordService.java @@ -22,6 +22,7 @@ import net.ess3.nms.refl.providers.AchievementListenerProvider; import net.ess3.nms.refl.providers.AdvancementListenerProvider; import net.ess3.provider.providers.PaperAdvancementListenerProvider; +import net.ess3.provider.providers.PaperAsyncChatListenerProvider; import net.essentialsx.api.v2.ChatType; import net.essentialsx.api.v2.events.discord.DiscordMessageEvent; import net.essentialsx.api.v2.services.discord.DiscordService; @@ -37,11 +38,12 @@ import net.essentialsx.discord.interactions.commands.ExecuteCommand; import net.essentialsx.discord.interactions.commands.ListCommand; import net.essentialsx.discord.interactions.commands.MessageCommand; +import net.essentialsx.discord.listeners.BukkitChatListener; import net.essentialsx.discord.listeners.BukkitListener; import net.essentialsx.discord.listeners.DiscordCommandDispatcher; import net.essentialsx.discord.listeners.DiscordListener; import net.essentialsx.discord.listeners.EssentialsChatListener; -import net.essentialsx.discord.listeners.BukkitChatListener; +import net.essentialsx.discord.listeners.PaperChatListener; import net.essentialsx.discord.util.ConsoleInjector; import net.essentialsx.discord.util.DiscordUtil; import net.essentialsx.discord.util.MessageUtil; @@ -88,6 +90,7 @@ public class JDADiscordService implements DiscordService, IEssentialsModule { private DiscordCommandDispatcher commandDispatcher; private InteractionControllerImpl interactionController; private Listener chatListener; + private Listener paperChatListener; private boolean invalidStartup = false; public JDADiscordService(EssentialsDiscord plugin) { @@ -349,12 +352,27 @@ public void updateListener() { HandlerList.unregisterAll(chatListener); chatListener = null; } + if (paperChatListener != null) { + HandlerList.unregisterAll(paperChatListener); + paperChatListener = null; + } - chatListener = getSettings().isUseEssentialsEvents() && plugin.isEssentialsChat() - ? new EssentialsChatListener(this) - : new BukkitChatListener(this); + if (getSettings().isUseEssentialsEvents() && plugin.isEssentialsChat()) { + chatListener = new EssentialsChatListener(this); + } else { + try { + Class.forName("io.papermc.paper.event.player.AsyncChatEvent"); + chatListener = new PaperChatListener(this); + paperChatListener = new PaperAsyncChatListenerProvider(plugin); + } catch (ClassNotFoundException ignored) { + chatListener = new BukkitChatListener(this); + } + } Bukkit.getPluginManager().registerEvents(chatListener, plugin); + if (paperChatListener != null) { + Bukkit.getPluginManager().registerEvents(paperChatListener, plugin); + } } public void updatePresence() { diff --git a/EssentialsDiscord/src/main/java/net/essentialsx/discord/listeners/PaperChatListener.java b/EssentialsDiscord/src/main/java/net/essentialsx/discord/listeners/PaperChatListener.java new file mode 100644 index 00000000000..5acb2dee0f3 --- /dev/null +++ b/EssentialsDiscord/src/main/java/net/essentialsx/discord/listeners/PaperChatListener.java @@ -0,0 +1,35 @@ +package net.essentialsx.discord.listeners; + +import net.ess3.provider.AbstractAsyncChatEvent; +import net.essentialsx.api.v2.ChatType; +import net.essentialsx.api.v2.events.discord.DiscordChatMessageEvent; +import net.essentialsx.discord.JDADiscordService; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; + +public class PaperChatListener implements Listener { + private final JDADiscordService jda; + + public PaperChatListener(JDADiscordService jda) { + this.jda = jda; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onChat(AbstractAsyncChatEvent event) { + final Player player = event.getPlayer(); + + Bukkit.getScheduler().runTask(jda.getPlugin(), () -> { + final DiscordChatMessageEvent chatEvent = new DiscordChatMessageEvent(event.getPlayer(), event.getMessage(), ChatType.UNKNOWN); + chatEvent.setCancelled(!jda.getSettings().isShowAllChat() && !event.getRecipients().containsAll(Bukkit.getOnlinePlayers())); + Bukkit.getPluginManager().callEvent(chatEvent); + if (chatEvent.isCancelled()) { + return; + } + + jda.sendChatMessage(player, chatEvent.getMessage()); + }); + } +} diff --git a/providers/PaperProvider/src/main/java/net/ess3/provider/AbstractAsyncChatEvent.java b/providers/PaperProvider/src/main/java/net/ess3/provider/AbstractAsyncChatEvent.java new file mode 100644 index 00000000000..7c6d9343309 --- /dev/null +++ b/providers/PaperProvider/src/main/java/net/ess3/provider/AbstractAsyncChatEvent.java @@ -0,0 +1,38 @@ +package net.ess3.provider; + +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; +import org.jetbrains.annotations.NotNull; + +import java.util.Set; + +public class AbstractAsyncChatEvent extends PlayerEvent { + private static final HandlerList handlers = new HandlerList(); + + private final String legacyMessage; + private final Set playerRecipients; + + public AbstractAsyncChatEvent(boolean async, Player sender, String message, Set recipients) { + super(sender, async); + this.legacyMessage = message; + this.playerRecipients = recipients; + } + + public String getMessage() { + return legacyMessage; + } + + public Set getRecipients() { + return playerRecipients; + } + + @Override + public @NotNull HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/providers/PaperProvider/src/main/java/net/ess3/provider/providers/PaperAsyncChatListenerProvider.java b/providers/PaperProvider/src/main/java/net/ess3/provider/providers/PaperAsyncChatListenerProvider.java new file mode 100644 index 00000000000..502bf5f33f3 --- /dev/null +++ b/providers/PaperProvider/src/main/java/net/ess3/provider/providers/PaperAsyncChatListenerProvider.java @@ -0,0 +1,49 @@ +package net.ess3.provider.providers; + +import io.papermc.paper.event.player.AsyncChatEvent; +import io.papermc.paper.text.PaperComponents; +import net.ess3.provider.AbstractAsyncChatEvent; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.serializer.ComponentSerializer; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.stream.Collectors; + +public class PaperAsyncChatListenerProvider implements Listener { + private final ComponentSerializer serializer; + private final JavaPlugin plugin; + + public PaperAsyncChatListenerProvider(JavaPlugin plugin) { + this.plugin = plugin; + ComponentSerializer yeOldSerializer; + try { + // This method is only available in Paper 1.18.1+ and replaces the old deprecated method below. + yeOldSerializer = PaperComponents.plainTextSerializer(); + } catch (NoSuchMethodError e) { + //noinspection deprecation + yeOldSerializer = PaperComponents.plainSerializer(); + } + this.serializer = yeOldSerializer; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onAsyncChatEvent(final AsyncChatEvent event) { + Bukkit.getPluginManager().callEvent( + new AbstractAsyncChatEvent( + event.isAsynchronous(), + event.getPlayer(), + serializer.serialize(event.message()), + event.viewers().stream() + .filter(v -> v instanceof Player) + .map(v -> (Player) v) + .collect(Collectors.toSet()) + ) + ); + } +}