如何使用 JDA 添加多个反应以嵌入消息
Posted
技术标签:
【中文标题】如何使用 JDA 添加多个反应以嵌入消息【英文标题】:How to add multiple reactions to embed message with JDA 【发布时间】:2020-04-12 10:13:26 【问题描述】:我正在尝试使机器人响应带有嵌入消息的命令,该消息下有多个反应。 我已经让它添加了 1 个反应,但我还需要添加不同的反应,就像这样:(http://prntscr.com/qd8da4) 网上有很多教程添加了 1 个反应,但没有一个添加多个反应。
我正在使用最新版本的 Discord JDA。
我目前拥有的代码是:
public void onGuildMessageReceived(GuildMessageReceivedEvent event)
String[] args = event.getMessage().getContentRaw().split("\\s+");
if (args[0].equalsIgnoreCase(DiscordBot.prefix + "info"))
SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss z");
Date date = new Date(System.currentTimeMillis());
MessageChannel channel = event.getChannel(); // Channel the command was sent in.
EmbedBuilder info = new EmbedBuilder();
info.setTitle("Server Info");
info.setDescription("Info About the bot.");
info.addField("Creator", "Name", false);
info.setColor(0xf45642);
info.setTimestamp(Instant.now());
channel.sendMessage(info.build()).queue(message -> message.addReaction("✔️").queue());
【问题讨论】:
这能回答你的问题吗? How to add reaction to an embed message JDA 【参考方案1】:我自己也遇到了同样的问题,因为没有真正的本地方式来做我想做的事情,即在点击反应时执行某些机器人操作。
我最终创建了几个帮助程序类,允许程序在点击反应时进行回调:
以下是会监听响应点击的响应:
public class ReactionListener<T>
private final Map<String, Consumer<Message>> reactions;
private final long userId;
private volatile T data;
private Long expiresIn, lastAction;
private boolean active;
public ReactionListener(long userId, T data)
this.data = data;
this.userId = userId;
reactions = new LinkedHashMap<>();
active = true;
lastAction = System.currentTimeMillis();
expiresIn = TimeUnit.MINUTES.toMillis(5);
public boolean isActive()
return active;
public void disable()
this.active = false;
/**
* The time after which this listener expires which is now + specified time
* Defaults to now+5min
*
* @param timeUnit time units
* @param time amount of time units
*/
public void setExpiresIn(TimeUnit timeUnit, long time)
expiresIn = timeUnit.toMillis(time);
/**
* Check if this listener has specified emote
*
* @param emote the emote to check for
* @return does this listener do anything with this emote?
*/
public boolean hasReaction(String emote)
return reactions.containsKey(emote);
/**
* React to the reaction :')
*
* @param emote the emote used
* @param message the message bound to the reaction
*/
public void react(String emote, Message message)
if (hasReaction(emote)) reactions.get(emote).accept(message);
public T getData()
return data;
public void setData(T data)
this.data = data;
/**
* Register a consumer for a specified emote
* Multiple emote's will result in overriding the old one
*
* @param emote the emote to respond to
* @param consumer the behaviour when emote is used
*/
public void registerReaction(String emote, Consumer<Message> consumer)
reactions.put(emote, consumer);
/**
* @return list of all emotes used in this reaction listener
*/
public Set<String> getEmotes()
return reactions.keySet();
/**
* updates the timestamp when the reaction was last accessed
*/
public void updateLastAction()
lastAction = System.currentTimeMillis();
/**
* When does this reaction listener expire?
*
* @return timestamp in millis
*/
public Long getExpiresInTimestamp()
return lastAction + expiresIn;
public long getUserId()
return userId;
接下来我们要处理点击时的反应。此方法需要当前登录的 userId 以确保仅记录用户的操作而不会记录其他人。如果其他人也可以反应,它可以修改为全局。:
public class ReactionHandler
private final ConcurrentHashMap<Long, ConcurrentHashMap<Long, ReactionListener<?>>> reactions;
private ReactionHandler()
reactions = new ConcurrentHashMap<>();
public synchronized void addReactionListener(long guildId, Message message, ReactionListener<?> handler)
addReactionListener(guildId, message, handler, true);
public synchronized void addReactionListener(long guildId, Message message, ReactionListener<?> handler, boolean queue)
if (handler == null)
return;
if (message.getChannelType().equals(ChannelType.TEXT))
if (!PermissionUtil.checkPermission(message.getTextChannel(), message.getGuild().getSelfMember(), Permission.MESSAGE_ADD_REACTION))
return;
if (!reactions.containsKey(guildId))
reactions.put(guildId, new ConcurrentHashMap<>());
if (!reactions.get(guildId).containsKey(message.getIdLong()))
for (String emote : handler.getEmotes())
RestAction<Void> action = message.addReaction(emote);
if (queue) action.queue(); else action.complete();
reactions.get(guildId).put(message.getIdLong(), handler);
public synchronized void removeReactionListener(long guildId, long messageId)
if (!reactions.containsKey(guildId)) return;
reactions.get(guildId).remove(messageId);
/**
* Handles the reaction
*
* @param channel TextChannel of the message
* @param messageId id of the message
* @param userId id of the user reacting
* @param reaction the reaction
*/
public void handle(TextChannel channel, long messageId, long userId, MessageReaction reaction)
ReactionListener<?> listener = reactions.get(channel.getGuild().getIdLong()).get(messageId);
if (!listener.isActive() || listener.getExpiresInTimestamp() < System.currentTimeMillis())
reactions.get(channel.getGuild().getIdLong()).remove(messageId);
else if ((listener.hasReaction(reaction.getReactionEmote().getName())) && listener.getUserId() == userId)
reactions.get(channel.getGuild().getIdLong()).get(messageId).updateLastAction();
Message message = channel.retrieveMessageById(messageId).complete();
listener.react(reaction.getReactionEmote().getName(), message);
/**
* Do we have an event for a message?
*
* @param guildId discord guild-id of the message
* @param messageId id of the message
* @return do we have an handler?
*/
public boolean canHandle(long guildId, long messageId)
return reactions.containsKey(guildId) && reactions.get(guildId).containsKey(messageId);
public synchronized void removeGuild(long guildId)
reactions.remove(guildId);
/**
* Delete expired handlers
*/
public synchronized void cleanCache()
long now = System.currentTimeMillis();
for (Iterator<Map.Entry<Long, ConcurrentHashMap<Long, ReactionListener<?>>>> iterator = reactions.entrySet().iterator(); iterator.hasNext(); )
Map.Entry<Long, ConcurrentHashMap<Long, ReactionListener<?>>> mapEntry = iterator.next();
mapEntry.getValue().values().removeIf(listener -> !listener.isActive() || listener.getExpiresInTimestamp() < now);
if (mapEntry.getValue().values().isEmpty())
reactions.remove(mapEntry.getKey());
然后,有了这两个库,我们就可以在我们的消息中实现它们。
channel.sendMessage(info.build()).queue((msg) ->
ReactionListener<String> handler = new ReactionListener<>(userId, msg.getId());
handler.setExpiresIn(TimeUnit.MINUTES, 1);
handler.registerReaction("✔️", (ret) -> foo());
handler.registerReaction("X", (ret) -> bar());
reactionHandler.addReactionListener(guild.getIdLong(), msg, handler);
);
【讨论】:
以上是关于如何使用 JDA 添加多个反应以嵌入消息的主要内容,如果未能解决你的问题,请参考以下文章
如何根据反应发送消息,然后根据用户消息发送另一个消息?使用 JDA