如何让 Discord.js 回复不和谐的 DM 消息

How to make Discord.js reply to discord DM messages

我正在尝试让 discord.js 阅读 Discord 上的 DM 消息,以获得一个 server/faction 从头开始​​制作的应用程序机器人,但我有它可以发送第一部分,当你键入 %apply 到 bot 尝试通过问题 2 时出现问题它不断得到问题 2 而不是去问题 3

我试图过滤掉与传递的消息不同的 DM 消息,所以我有几个 if 命令

bot.on("message", function(message) {
if (message.author.equals(bot.user)) return;
    if (message.content === "%apply") {
        apply = "TRUE";
        a0 = message.author.lastMessageID
        message.author.sendMessage("```We need to ask some questions so  we can know a litte bit about yourself```");
        message.author.sendMessage("```Application Started - Type '#Cancel' to cancel the application```");
        message.author.sendMessage("```Question 1: In-Game Name?```");
    }
    if ((message.guild === null) && (message.author.lastMessageID != a0) && (message.content != "%apply") && (apply === "TRUE")) {
        a1 = message.author.lastMessageID;
        message.author.sendMessage("```Question 2: Age?```");
    }
    if ((message.guild === null) && (message.author.lastMessageID != a1) && (message.author.lastMessageID != a0) && (apply === "TRUE")) {
        a2 = message.author.lastMessageID;
        message.author.sendMessage("```Question 3: Timezone? NA, AU, EU, NZ, or Other? (If other, describe your timezone)```");
    }
    if ((message.guild === null) && (message.author.lastMessageID != a2) && (message.author.lastMessageID != a1) && (message.author.lastMessageID != a0) && (apply === "TRUE")) {
        a3 = message.author.lastMessageID;
        message.author.sendMessage("```Question 4: Do you have schematica?```");
    }

我预计它会从问题 1 到问题 2 再到问题 3

您的变量 a0, ... , a3"onMessage" 范围内,并且每次在您的回调中都未定义。因此,如果您的消息不是 %apply,您将陷入 "Question 2" 步骤

您应该在全局变量中跟踪您的用户注册步骤,并阅读它以了解您正在进行的步骤。 以下是如何执行此操作的简短示例。 请注意,这是一个非常基本的方法,如果您需要向应用程序添加更复杂的功能,使用一些 in-memory 数据库可能会更好。 它还需要更多的控制,我想还有一些其他的数据存储来跟踪用户的答案。

let userApplications = {}

bot.on("message", function(message) {
  if (message.author.equals(bot.user)) return;

  let authorId = message.author.id;

  if (message.content === "%apply") {
      console.log(`Apply begin for authorId ${authorId}`);
      // User is not already in a registration process    
      if (!(authorId in userApplications)) {
          userApplications[authorId] = { "step" : 1}

          message.author.send("```We need to ask some questions so  we can know a litte bit about yourself```");
          message.author.send("```Application Started - Type '#Cancel' to cancel the application```");
          message.author.send("```Question 1: In-Game Name?```");
      }

  } else {

      if (message.channel.type === "dm" && authorId in userApplications) {
          let authorApplication = userApplications[authorId];

          if (authorApplication.step == 1 ) {
              message.author.send("```Question 2: Age?```");
              authorApplication.step ++;
          }
          else if (authorApplication.step == 2) {
              message.author.send("```Question 3: Timezone? NA, AU, EU, NZ, or Other? (If other, describe your timezone)```");
              authorApplication.step ++;
          }
          else if (authorApplication.step == 3) {
              message.author.send("```Question 4: Do you have schematica?```");
              authorApplication.step ++;
          }

          else if (authorApplication.step == 4) {
              message.author.send("```Thanks for your registration. Type %apply to register again```");
              delete userApplications[authorId];
          }

      }
  }


});

其他一些快速笔记:

  • sendMessage(msg) 在 discord.js 中已弃用 api,现在应使用 send(msg)
  • 测试收到的消息是否是 dm,我认为最好检查 message.channel.type 而不是寻找空的 message.guildId

前言

虽然@Gruntzy's answer is not wrong, there's another solution that's built into Discord.js and meant for these situations - TextChannel.awaitMessages()。您可以在如下所示的系统中使用它。

示例代码

const questions = [                    // ------------------------------------
  "What's your IGN?",                  //
  "How old are you?",                  // Define the questions you'd like the
  "What time zone do you reside in?",  // application to have in this array.
  "Do you have Schematica?"            //
];                                     // ------------------------------------

const applying = [];

bot.on("message", async message => {
  if (message.author.bot) return;

  if (message.content.toLowerCase() === "%apply") {
    if (applying.includes(message.author.id)) return;

    try {
      console.log(`${message.author.tag} began applying.`);

      applying.push(message.author.id);
      await message.channel.send(":pencil: **Application started!** Type `#cancel` to exit.");

      for (let i = 0, cancel = false; i < questions.length && cancel === false; i++) {
        await message.channel.send(questions[i]);
        await message.channel.awaitMessages(m => m.author.id === message.author.id, { max: 1, time: 300000, errors: ["time"] })
          .then(collected => {
            if (collected.first().content.toLowerCase() === "#cancel") {
              await message.channel.send(":x: **Application cancelled.**");
              applying.splice(applying.indexOf(message.author.id), 1);
              cancel = true;

              console.log(`${message.author.tag} cancelled their application.`);
            }
          }).catch(() => {
            await message.channel.send(":hourglass: **Application timed out.**");
            applying.splice(applying.indexOf(message.author.id), 1);
            cancel = true;

            console.log(`${message.author.tag} let their application time out.`);
          });
      }

      await message.channel.send(":thumbsup: **You're all done!**");

      console.log(`${message.author.tag} finished applying.`);
    } catch(err) {
      console.error(err);
    }
  }
});

说明

为了让代码更容易理解,我们一步一步来...

1.前几行。

  • questions 数组包含您希望在应用程序中提出的所有问题。为了效率,我实现了一个数组;只需更改一行即可添加或删除问题,并且不会一遍又一遍地复制和粘贴相同的代码。
  • applying数组将帮助我们跟踪应用程序过程中的用户。

2。消息事件。

  • 我已经实现了一个箭头函数 (ES6) 作为回调并将其声明为异步,因此我们可以在其中使用 await
  • 我们防止机器人触发任何命令。
  • 我们检查 case iNsEnSiTiVeLy 是否应该 运行 命令。
  • 您会注意到前面的代码包含在 try...catch statement. This allows us to catch any unhandled promise rejections (i.e. if TextChannel.send() 中,很容易引发错误。

3。 %apply命令。

  • 我们将用户添加到 applying 数组。
  • 我们发送开始消息。
    • 注意关键字await:它在继续之前等待承诺实现。
  • 我们使用 for 循环遍历 questions 数组。
    • let i = 0, cancel = false 声明了 i("counter" 变量)和一个 cancel 变量,这样我们就可以在用户想要取消应用程序时停止循环。超时。我们不能使用 break within our then() 回调,所以我已经恢复到这种方法。
    • i < questions.length && cancel === false 是我们在继续下一次迭代之前要匹配的条件 - 计数器必须在数组的范围内,并且 cancel 必须仍然是 false.
    • i++ 将计数器加 1。
  • 在循环中,我们发送问题然后调用 TextChannel.awaitMessages()。我们的第一个参数是消息必须通过的过滤器,第二个是选项。
    • 在我们的 then() 回调中,我们检查消息是否为 #cancel。如果是,我们发送取消消息,从数组中删除用户,并将 cancel 的值设置为 true.
    • 如果 5 分钟内没有提供消息,我们的 catch() 方法将被调用。所以在我们的回调中,我们发送超时消息,从数组中删除用户,并将 cancel 的值设置为 true.
  • 循环完成后,我们发送完成消息。此时,您可以随心所欲地处理申请。