【问题标题】:How to make a Discord Bot wait for a specific user to send a message with JDA?如何让 Discord Bot 等待特定用户使用 JDA 发送消息?
【发布时间】:2019-06-26 17:57:54
【问题描述】:

我目前正在学习 Java 编程课程,最近开始尝试使用 JDA 工具为我的服务器制作一个基本的 Discord 机器人。理想情况下,我希望我的机器人在有人说“Hello Apples!”时做出回应。询问他们的姓名,然后回复“嗨!”如果这条消息是由说“Hello Apples!”的同一个人发送的现在我的机器人无法等待任何用户输入超过最初的“Hello Apples!”消息,并立即溢出其所有文本。我相信我当前的代码设置正确,以确保机器人只会回应“嗨!”如果它收到来自最初发送“Hi Apples!”的同一个人的消息,但我不能完全确定,因为它不等待额外的消息,结果从同一条消息中读取两次并打印出来:
你好!告诉我你的名字,或者说“停”!
嗨嗨苹果!
等你来

我真的很想知道如何创建某种“停止”,或者一种方法可以导致机器人等待最初问候机器人的用户的附加用户输入,如果可能的话,一种方法设置时间限制,这样如果机器人不回复,机器人就不会保持无法操作。

import net.dv8tion.jda.core.AccountType;
import net.dv8tion.jda.core.JDA;
import net.dv8tion.jda.core.JDABuilder;

public class Main {
  public static void main(String[] args) throws Exception {
    try {
      JDA api = new     JDABuilder(AccountType.BOT).setToken("NTQxMTMxMDc4MTY1ODU2MjYw.DzbGoQ.oFIM_py    pLMOc60qU1PgeeUXU8Qo").build();
      api.addEventListener(new MyEventListener());
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

import net.dv8tion.jda.core.entities.Member;
import net.dv8tion.jda.core.entities.Message;
import net.dv8tion.jda.core.entities.MessageChannel;
import net.dv8tion.jda.core.entities.Role;
import net.dv8tion.jda.core.entities.User;
import net.dv8tion.jda.core.entities.*;
import net.dv8tion.jda.core.events.message.MessageReceivedEvent;
import net.dv8tion.jda.core.hooks.ListenerAdapter;

public class MyEventListener extends ListenerAdapter {
  public void onMessageReceived(MessageReceivedEvent event) {
    if (event.getAuthor().isBot()) return;

    Message message = event.getMessage();
    String content = message.getContentRaw();
    MessageChannel channel = event.getChannel();

    if (content.startsWith("Hi Apples!")) {
      Member member = message.getMember();
      channel.sendMessage("Hi! Tell me your name, or say \"Stop\"!").queue();
      int n = 0;    
      while (n == 0) {
        Message message2 = event.getMessage(); 
        String content2 = message.getContentRaw();
        Member member2 = message2.getMember();
        String nick = member2.getNickname();
        if (member == member2) {
          channel.sendMessage("Hi " + content2 + "!").queue();
          n = 1;
        }
        else {
        }
          channel.sendMessage("Wait your turn " + nick + "!").queue();
        if (content2 == "Stop") {
          channel.sendMessage("Understood!").queue();
          n = 1;
        }
      }   
    }        
  }
}

我的预期结果是:
用户:嗨苹果!
博特:嗨!告诉我你的名字,或者说停止!
USER2:嗨!
BOT:等待轮到你 USER2!
用户:吉米
机器人:嗨,吉米!

实际结果:(一次全部发送)
你好!告诉我你的名字,或者说“停”!
嗨嗨苹果!
轮到你了(我的不和谐昵称)!

【问题讨论】:

    标签: java discord discord-jda


    【解决方案1】:

    由于您使用的是基于事件的框架,因此您可以使用状态机来实现此行为。每当您获得初始触发器时,在这种情况下 "Hi Apple!" 您将为该文本通道启动一个新的状态机。

    在此状态机中,您处理消息事件,直到您的终止信号到达,在本例中为 "Stop!"

    状态机将使用事件方法中的 switch-case 和私有 state 字段来实现。在这种情况下,您在整个对话中只有一次交互,因此只有一种状态使这毫无意义。

    但例如,在我假设稍后会进行的对话的情况下,您将需要使用状态机概念。

    public class AppleStateMachine extends ListenerAdapter {
        private final long channelId, authorId; // id because keeping the entity would risk cache to become outdated
    
        public AppleStateMachine(MessageChannel channel, User author) {
            this.channelId = channel.getIdLong();
            this.authorId = author.getIdLong();
        }
    
        @Override
        public void onMessageReceived(MessageReceivedEvent event) {
            if (event.getAuthor().isBot()) return; // don't respond to other bots
            if (event.getChannel().getIdLong() != channelId) return; // ignore other channels
            MessageChannel channel = event.getChannel();
            String content = event.getMessage().getContentRaw();
            // since only one state is present you don't need a switch but that would be the concept if you had more than 1 interaction point in this protocol
            if (content.equals("Stop")) {
                channel.sendMessage("Understood!").queue();
                event.getJDA().removeEventListener(this); // stop listening
            }
            else if (event.getAuthor().getIdLong() == authorId) {
                channel.sendMessage("Hi " + content + "!").queue();
                event.getJDA().removeEventListener(this); // stop listening
            }
            else {
                channel.sendMessage("Wait your turn " + event.getMember().getEffectiveName() + "!").queue();
            }
        }
    }
    

    那么你只需要在你的初始事件处理程序中注册一个 this 的实例

    if (content.startsWith("Hi Apples!")) {
        channel.sendMessage("Hi! Tell me your name, or say \"Stop\"!").queue();
        event.getJDA().addEventListener(new AppleStateMachine(channel, member.getUser());
    }
    

    请确保您不要在此处混用 GuildMessageReceivedEventMessageReceivedEvent,因为它们是按顺序触发的,您可能会收到两次初始消息。您的状态机和消息侦听器都应该侦听相同类型的事件。

    另一种替代方法是使用JDA-UtilitiesEventWaiter

    【讨论】:

      猜你喜欢
      • 2021-07-06
      • 2021-06-17
      • 2020-09-10
      • 1970-01-01
      • 2020-05-11
      • 2019-03-01
      • 2020-05-13
      • 2021-05-05
      • 2021-09-10
      相关资源
      最近更新 更多