Как заставить Discord Bot ждать, пока конкретный пользователь отправит сообщение с JDA?

В настоящее время я знакомлюсь с классом программирования на Java и недавно начал экспериментировать с инструментами JDA, чтобы создать базовый бот Discord для моего сервера. В идеале, я хочу, чтобы мой бот отвечал, когда кто-то говорит "Привет, яблоки!" спрашивая их имя, а затем отвечая "Привет!" если это сообщение было отправлено тем же человеком, который сказал "Привет, яблоки!" В данный момент мой бот не может дождаться ввода пользователя после начального "Hello 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;
        }
      }   
    }        
  }
}

Мои ожидаемые результаты:
ПОЛЬЗОВАТЕЛЬ: Привет, Яблоки!
БОТ: Привет! Скажи мне свое имя или скажи стоп!
ПОЛЬЗОВАТЕЛЬ2: Привет!
БОТ: Ждите своей очереди USER2!
ПОЛЬЗОВАТЕЛЬ: Джимми
БОТ: Привет, Джимми!

Фактические результаты: (отправлено все сразу)
Привет! Скажи мне свое имя или скажи "Стоп"!
Привет привет яблоки!!
Ждите своей очереди (мой никнейм диссонанса)!

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

Тогда вам нужно всего лишь зарегистрировать экземпляр этого в вашем исходном обработчике событий

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

Другой альтернативой этому является использование класса JDA-Utilities. EventWaiter,

Другие вопросы по тегам