diff --git a/pom.xml b/pom.xml index 9db32ab..137ddae 100644 --- a/pom.xml +++ b/pom.xml @@ -38,6 +38,17 @@ fastjson2 2.0.21 + + net.dv8tion + JDA + 5.0.0-beta.18 + + + club.minnced + opus-java + + + diff --git a/src/main/java/com/zhanganzhi/chathub/adaptors/discord/DiscordAdaptor.java b/src/main/java/com/zhanganzhi/chathub/adaptors/discord/DiscordAdaptor.java new file mode 100644 index 0000000..7abe5bc --- /dev/null +++ b/src/main/java/com/zhanganzhi/chathub/adaptors/discord/DiscordAdaptor.java @@ -0,0 +1,118 @@ +package com.zhanganzhi.chathub.adaptors.discord; + +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.JDABuilder; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.interactions.commands.build.Commands; +import net.dv8tion.jda.api.requests.GatewayIntent; + +import com.zhanganzhi.chathub.ChatHub; +import com.zhanganzhi.chathub.adaptors.IAdaptor; +import com.zhanganzhi.chathub.core.Config; +import com.zhanganzhi.chathub.entity.Platform; +import com.zhanganzhi.chathub.event.MessageEvent; +import com.zhanganzhi.chathub.event.ServerChangeEvent; + +public class DiscordAdaptor implements IAdaptor { + private static final Platform platform = Platform.DISCORD; + private final Config config = Config.getInstance(); + private final ChatHub chatHub; + private JDA jda; + private TextChannel channel; + + public DiscordAdaptor(ChatHub chatHub) { + this.chatHub = chatHub; + } + + @Override + public Platform getPlatform() { + return platform; + } + + @Override + public void onUserChat(MessageEvent event) { + sendMessage(config.getDiscordChatMessage( + event.getServerName(), + event.user(), + event.content() + )); + } + + @Override + public void onJoinServer(ServerChangeEvent event) { + sendMessage(config.getDiscordJoinMessage( + event.server, + event.player.getUsername() + )); + } + + @Override + public void onLeaveServer(ServerChangeEvent event) { + sendMessage(config.getDiscordLeaveMessage( + event.player.getUsername() + )); + } + + @Override + public void onSwitchServer(ServerChangeEvent event) { + sendMessage(config.getDiscordSwitchMessage( + event.player.getUsername(), + event.serverPrev, + event.server + )); + } + + @Override + public void sendListMessage(String source) { + } + + void sendMessage(String message) { + if (config.isDiscordEnabled()) { + new Thread(() -> channel.sendMessage(message).queue()).start(); + } + } + + @Override + public void start() { + if (config.isDiscordEnabled()) { + // logger + chatHub.getLogger().info("Discord enabled"); + + // build jda + jda = JDABuilder.createLight(config.getDiscordToken()) + .enableIntents( + GatewayIntent.MESSAGE_CONTENT + ) + .addEventListeners(new DiscordReceiver(chatHub)) + .build(); + + // commands + jda.updateCommands().addCommands( + Commands + .slash("list", "List online players") + .setGuildOnly(true) + ).queue(); + + // await jda ready + try { + jda.awaitReady(); + } catch (InterruptedException e) { + chatHub.getLogger().error("Discord jda failed to start: " + e.getMessage()); + } + + // get channel + channel = jda.getTextChannelById(config.getDiscordChannelId()); + } + } + + @Override + public void stop() { + if (config.isDiscordEnabled() && jda != null) { + jda.shutdownNow(); + } + } + + @Override + public void restart() { + } +} diff --git a/src/main/java/com/zhanganzhi/chathub/adaptors/discord/DiscordReceiver.java b/src/main/java/com/zhanganzhi/chathub/adaptors/discord/DiscordReceiver.java new file mode 100644 index 0000000..4ab1a62 --- /dev/null +++ b/src/main/java/com/zhanganzhi/chathub/adaptors/discord/DiscordReceiver.java @@ -0,0 +1,65 @@ +package com.zhanganzhi.chathub.adaptors.discord; + +import com.velocitypowered.api.proxy.Player; +import com.velocitypowered.api.proxy.server.RegisteredServer; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; + +import com.zhanganzhi.chathub.ChatHub; +import com.zhanganzhi.chathub.core.Config; +import com.zhanganzhi.chathub.core.EventHub; +import com.zhanganzhi.chathub.entity.Platform; +import com.zhanganzhi.chathub.event.MessageEvent; + +public class DiscordReceiver extends ListenerAdapter { + private static final Platform PLATFORM = Platform.DISCORD; + private final Config config = Config.getInstance(); + private final ChatHub chatHub; + private final EventHub eventHub; + + public DiscordReceiver(ChatHub chatHub) { + this.chatHub = chatHub; + this.eventHub = chatHub.getEventHub(); + } + + @Override + public void onMessageReceived(MessageReceivedEvent messageReceivedEvent) { + // ignore bot message + if (messageReceivedEvent.getAuthor().isBot()) { + return; + } + + // check channel id + if (!messageReceivedEvent.getChannel().getId().equals(config.getDiscordChannelId())) { + return; + } + + // handle message + String content = messageReceivedEvent.getMessage().getContentStripped(); + eventHub.onUserChat(new MessageEvent( + PLATFORM, + null, + messageReceivedEvent.getAuthor().getEffectiveName(), + content + )); + } + + @Override + public void onSlashCommandInteraction(SlashCommandInteractionEvent slashCommandInteractionEvent) { + if (slashCommandInteractionEvent.getName().equals("list")) { + StringBuilder stringBuilder = new StringBuilder(); + for (RegisteredServer registeredServer : chatHub.getProxyServer().getAllServers()) { + if (!registeredServer.getPlayersConnected().isEmpty()) { + stringBuilder.append(config.getDiscordListMessage( + registeredServer.getServerInfo().getName(), + registeredServer.getPlayersConnected().size(), + registeredServer.getPlayersConnected().stream().map(Player::getUsername).toArray(String[]::new) + )); + stringBuilder.append("\n"); + } + } + slashCommandInteractionEvent.reply(stringBuilder.isEmpty() ? config.getDiscordListEmptyMessage() : stringBuilder.toString()).queue(); + } + } +} diff --git a/src/main/java/com/zhanganzhi/chathub/core/Config.java b/src/main/java/com/zhanganzhi/chathub/core/Config.java index e127d3a..b4bdd98 100644 --- a/src/main/java/com/zhanganzhi/chathub/core/Config.java +++ b/src/main/java/com/zhanganzhi/chathub/core/Config.java @@ -95,6 +95,59 @@ public String getMinecraftListEmptyMessage() { return configToml.getString("minecraft.message.listEmpty"); } + public boolean isDiscordEnabled() { + return configToml.getBoolean("discord.enable"); + } + + public String getDiscordToken() { + return configToml.getString("discord.token"); + } + + public String getDiscordChannelId() { + return configToml.getString("discord.channelId"); + } + + public String getDiscordChatMessage(String server, String name, String message) { + return configToml + .getString("discord.message.chat") + .replace("{server}", getPlainServername(server)) + .replace("{name}", name) + .replace("{message}", message); + } + + public String getDiscordJoinMessage(String server, String name) { + return configToml + .getString("discord.message.join") + .replace("{server}", getPlainServername(server)) + .replace("{name}", name); + } + + public String getDiscordLeaveMessage(String name) { + return configToml + .getString("discord.message.leave") + .replace("{name}", name); + } + + public String getDiscordSwitchMessage(String name, String serverFrom, String serverTo) { + return configToml + .getString("discord.message.switch") + .replace("{name}", name) + .replace("{serverFrom}", getPlainServername(serverFrom)) + .replace("{serverTo}", getPlainServername(serverTo)); + } + + public String getDiscordListMessage(String server, int count, String[] playerList) { + return configToml + .getString("discord.message.list") + .replace("{server}", getPlainServername(server)) + .replace("{count}", String.valueOf(count)) + .replace("{playerList}", String.join(", ", playerList)); + } + + public String getDiscordListEmptyMessage() { + return configToml.getString("discord.message.listEmpty"); + } + public boolean isKookEnabled() { return tempIsKookEnabled; } diff --git a/src/main/java/com/zhanganzhi/chathub/core/EventHub.java b/src/main/java/com/zhanganzhi/chathub/core/EventHub.java index fc64ebb..0237b5c 100644 --- a/src/main/java/com/zhanganzhi/chathub/core/EventHub.java +++ b/src/main/java/com/zhanganzhi/chathub/core/EventHub.java @@ -4,6 +4,7 @@ import com.zhanganzhi.chathub.ChatHub; import com.zhanganzhi.chathub.adaptors.IAdaptor; +import com.zhanganzhi.chathub.adaptors.discord.DiscordAdaptor; import com.zhanganzhi.chathub.adaptors.kook.KookAdaptor; import com.zhanganzhi.chathub.adaptors.velocity.VelocityAdaptor; import com.zhanganzhi.chathub.entity.Platform; @@ -15,6 +16,7 @@ public class EventHub { public EventHub(ChatHub chatHub) { adaptors = List.of( + new DiscordAdaptor(chatHub), new KookAdaptor(chatHub, this), new VelocityAdaptor(chatHub, this) ); diff --git a/src/main/java/com/zhanganzhi/chathub/entity/Platform.java b/src/main/java/com/zhanganzhi/chathub/entity/Platform.java index b01ed1c..02756dc 100644 --- a/src/main/java/com/zhanganzhi/chathub/entity/Platform.java +++ b/src/main/java/com/zhanganzhi/chathub/entity/Platform.java @@ -1,6 +1,7 @@ package com.zhanganzhi.chathub.entity; public enum Platform { + DISCORD("discord"), KOOK("kook"), VELOCITY("velocity"); diff --git a/src/main/resources/config.toml b/src/main/resources/config.toml index c5a029b..ca96321 100644 --- a/src/main/resources/config.toml +++ b/src/main/resources/config.toml @@ -2,8 +2,9 @@ lobby = '§f§l大厅服' survival = '§2§l生存服' creative = '§6§l创造服' -kook = '§a§lKOOK' -qq = '§5§l群聊天' +discord = '§a§lDiscord' +kook = '§a§lKook' +qq = '§a§l群聊天' [minecraft] completeTakeoverMode = false @@ -18,6 +19,19 @@ msgTarget = '§7§o{sender}悄悄地对你说: {message}' list = '§8§l» §7[{server}§7] 当前共有§6{count}§7名玩家在线: §e{playerList}' listEmpty = '当前没有玩家在线' +[discord] +enable = false +token = '' +channelId = '' + +[discord.message] +chat = '[{server}] <{name}>: {message}' +join = '[+] [{server}] {name}' +leave = '[-] {name}' +switch = '<{name}>: [{serverFrom}] ➟ [{serverTo}]' +list = '- [{server}] 当前共有{count}名玩家在线: {playerList}' +listEmpty = '当前没有玩家在线' + [kook] enable = false token = ''