简体   繁体   English

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

[英]How to make a Discord Bot wait for a specific user to send a message with JDA?

I'm currently taking an intro to programming class in Java, and have recently started experimenting with the JDA tools to make a basic Discord bot for my server.我目前正在介绍 Java 编程课程,最近开始尝试使用 JDA 工具为我的服务器制作一个基本的 Discord 机器人。 Ideally, I want my bot to respond when someone says "Hello Apples!"理想情况下,我希望我的机器人在有人说“你好苹果!”时做出回应。 by asking them for their name, then responding with "Hi !"通过询问他们的名字,然后回答“嗨!” if this message was sent by the same person who said "Hello Apples!"如果此消息是由说“Hello Apples!”的同一个人发送的Right now my bot fails to await any user input past the initial "Hello Apples!"现在我的机器人无法等待任何用户输入超过最初的“Hello Apples!” message, and spills out all of its text at once.消息,并立即溢出所有文本。 I believe my current code is set up properly to ensure that the bot will only respond with "Hi !"我相信我当前的代码设置正确,以确保机器人只会响应“嗨!” if it receives a message from the same person who originally sent "Hi Apples!", but I can't be completely sure because it doesn't wait for an additional message, and as a result reads from the same message twice and prints out:如果它收到来自最初发送“Hi Apples!”的同一个人的消息,但我不能完全确定,因为它不等待其他消息,因此从同一消息读取两次并打印出来:
Hi!你好! Tell me your name, or say "Stop"!告诉我你的名字,或者说“停止”!
Hi Hi Apples!!嗨嗨苹果!!
Wait your turn等待轮到你

I would really like to know how to create a "stop" of some sort, or a method that would cause the bot to wait for addition user input from the user who originally greeted the bot, and if possible, a way to set a time limit so the bot doesn't remain inoperable if they don't reply.我真的很想知道如何创建某种“停止”,或者一种方法,它会导致机器人等待最初问候机器人的用户的额外用户输入,如果可能的话,一种设置时间的方法限制,以便机器人在他们不回复时不会保持无法操作。

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;
        }
      }   
    }        
  }
}

My expected results are:我的预期结果是:
USER: Hi Apples!用户:嗨,苹果!
BOT: Hi!博:嗨! Tell me your name, or say stop!告诉我你的名字,或者说停止!
USER2: Hi!用户 2:嗨!
BOT: Wait your turn USER2! BOT:轮到你了 USER2!
USER: Jimmy用户:吉米
BOT: Hi Jimmy!机器人:嗨,吉米!

Actual results: (Sent all at once)实际结果:(一次性发送)
Hi!你好! Tell me your name, or say "Stop"!告诉我你的名字,或者说“停止”!
Hi Hi Apples!!嗨嗨苹果!!
Wait your turn (my discord nickname)!轮到你了(我的不和谐昵称)!

Since you are using an event-based framework you could implement this behavior with the use of a state-machine.由于您使用的是基于事件的框架,因此您可以使用状态机来实现此行为。 Whenever you get your initial trigger, in this case "Hi Apple!"每当您获得初始触发器时,在这种情况下, "Hi Apple!" you would initiate a new state-machine for that text channel.您将为该文本通道启动一个新的状态机。

In this state-machine you handle message events until your termination signal arrives, in this case "Stop!"在这个状态机中,您处理消息事件,直到您的终止信号到达,在本例中为"Stop!" . .

The state-machine would be implemented using a switch-case in the event method together with a private state field.状态机将使用事件方法中的 switch-case 和私有state字段来实现。 In this case you only have one interaction in the entire conversation so there is only one state which makes this pointless.在这种情况下,您在整个对话中只有一个交互,因此只有一种状态使这毫无意义。

But for example in the case of having a conversation which is what I assume this will be later on you would need to go with the state-machine concept.但是,例如在进行对话的情况下,我认为这将在稍后进行,您将需要采用状态机概念。

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();
        }
    }
}

Then you only need to register an instance of this in your initial event handler然后你只需要在你的初始事件处理程序中注册一个 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());
}

Make sure that you don't mix GuildMessageReceivedEvent and MessageReceivedEvent here, since they are fired in sequence and you might receive your initial message twice.确保您不要在此处混合GuildMessageReceivedEventMessageReceivedEvent ,因为它们是按顺序触发的,您可能会收到两次初始消息。 Both your state machine and the message listener should listen to the same kind of event.您的状态机和消息侦听器都应该侦听相同类型的事件。

Another alternative to this is using the JDA-Utilities class EventWaiter .另一种替代方法是使用JDA-UtilitiesEventWaiter

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM