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

В настоящее время я изучаю класс программирования на Java и недавно начал экспериментировать с инструментами JDA, чтобы создать базового бота Discord для моего сервера. В идеале я хочу, чтобы мой бот отвечал, когда кто-то говорит "Привет, яблоки!" спросив их имя, а затем ответив «Привет!» если это сообщение было отправлено тем же человеком, который сказал "Hello Apples!" Прямо сейчас мой бот не ожидает ввода пользователем после начального "Hello Apples!" сообщение и сразу выводит весь его текст. Я считаю, что мой текущий код настроен правильно, чтобы бот отвечал только "Привет!" если он получает сообщение от того же человека, который изначально послал «Привет, яблоки!», но я не могу быть полностью уверен, потому что он не ждет дополнительного сообщения и в результате дважды читает одно и то же сообщение и распечатывает :
Привет! Назовите свое имя или скажите «Стоп»!
Привет, привет, яблоки !!
Подождите своей очереди

Я действительно хотел бы знать, как создать какую-то «остановку» или метод, который заставил бы бот ждать добавления пользовательского ввода от пользователя, который первоначально приветствовал бота, и, если возможно, способ установить время limit, чтобы бот не оставался неработоспособным, если он не отвечает.

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: Привет!
БОТ: Подождите своей очереди. ПОЛЬЗОВАТЕЛЬ2!
ПОЛЬЗОВАТЕЛЬ: Джимми
БОТ: Привет, Джимми!

Фактические результаты: (Отправлено сразу)
Привет! Назовите мне свое имя или скажите «Стоп»!
Привет, привет, яблоки!
Подожди своей очереди (мой псевдоним Discord)!


person DanM5    schedule 02.02.2019    source источник


Ответы (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());
}

Убедитесь, что вы не смешиваете здесь GuildMessageReceivedEvent и MessageReceivedEvent, поскольку они запускаются последовательно, и вы можете получить свое первоначальное сообщение дважды. И ваш конечный автомат, и прослушиватель сообщений должны прослушивать события одного и того же типа.

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

person Minn    schedule 02.02.2019