Как заставить Discord Bot ждать, пока конкретный пользователь отправит сообщение с JDA? - PullRequest
0 голосов
/ 02 февраля 2019

В настоящее время я знакомлюсь с классом программирования на 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: Привет!
БОТ: Подожди свою очередь ПОЛЬЗОВАТЕЛЬ2!
ПОЛЬЗОВАТЕЛЬ: Джимми
БОТ: Привет, Джимми!

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

1 Ответ

0 голосов
/ 02 февраля 2019

Поскольку вы используете основанную на событиях среду, вы можете реализовать это поведение с помощью конечного автомата.Всякий раз, когда вы получаете свой первоначальный триггер, в этом случае "Hi Apple!" вы инициируете новый конечный автомат для этого текстового канала.

В этом конечном автомате вы обрабатываете сообщения, пока не поступит ваш сигнал завершения, в этом случае"Stop!".

Конечный автомат будет реализован с использованием регистра-переключателя в методе события вместе с приватным полем 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.

...