如何使用JDA让Discord机器人等待特定用户发送消息?

5
我正在学习Java编程入门课程,并最近开始尝试使用JDA工具为我的服务器创建一个基本的Discord机器人。理想情况下,当有人说“你好,Apples!”时,我希望我的机器人会询问他们的名字,然后如果这条消息是由原先发送“Hello Apples!”的人发送的话,就回复“Hi!”。现在我的机器人在初始的“Hello Apples!”消息过后无法等待任何用户输入,而是一次性输出所有文本。我相信我的当前代码已经正确设置,以确保机器人只会在收到来自最初发送“Hi Apples!”的人的消息时才回复“Hi!”,但是我不能完全确定,因为它不会等待另一条消息,结果会读取相同的消息两次并打印出:
Hi! 告诉我你的名字,或者说“Stop”!
Hi 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;
        }
      }   
    }        
  }
}

我期望的结果是:
用户:你好 Apples!
机器人:你好!请告诉我你的名字,或者说停止!
用户2:你好!
机器人:请等待你的轮到 USER2!
用户:Jimmy
机器人:你好 Jimmy!

实际结果:(一次性发送)
你好!请告诉我你的名字,或者说“停止”!
嗨嗨 Apples!
请等待你的轮到 (我的 Discord 昵称)!

1个回答

5
由于您使用的是基于事件的框架,因此您可以通过使用状态机来实现此行为。每当您获取初始触发器时,在本例中为“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();
        }
    }
}

那么你只需要在初始事件处理程序中注册一个该实例。
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-Utilities类中的EventWaiter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接