discord.js 的冷却系统问题

Posted

技术标签:

【中文标题】discord.js 的冷却系统问题【英文标题】:Cooldown system issue at discord.js 【发布时间】:2021-08-13 09:05:40 【问题描述】:

我是编码新手,我正在制作一个不和谐的机器人,我想发出一个命令,让所有成员都需要等待一段时间才能再次使用它,但其中一些不需要同时等待。

例如:角色 X 的成员等待 20 秒,角色 Y 的成员等待 10 秒。

问题是我无法使用名为 humanize-duration 的 npm 包来使其工作以腾出时间。嵌入说明未显示正确的时间戳。可能是我自己搞错了。

我试图解决我的问题?

我尝试阅读 discord.js 文档、humanize-duration 文档和 this post,但无法修复。另外,我没有收到任何错误。顺便说一句,我使用了一个命令处理程序。

这是我用作示例的代码(ping 命令):

const Discord = require("discord.js");
const humanizeDuration = require("humanize-duration");

let cooldown = new Set();

module.exports = 
  name: "ping",
  description: "It shows the bot latency.",
  
  execute(client, message, args) 
      
    let guild = client.guilds.cache.get("828376495969402901");

    let member = guild.members.cache.get(message.author.id);
      
    if(cooldown.has(message.author.id) && !member.roles.cache.has("830503345251680298")) 
        const remaining = humanizeDuration(cooldown.has(message.author.id) && !member.roles.cache.has("830503345251680298") - Date.now(),  units: ["s"], round: true, language: "en" );
        const cooldownEmbed = new Discord.MessageEmbed()
        .setTitle(`Slow down, bud`)
        .setDescription(`You can run \`ping\` again in **$remaining**.\nThe default cooldown is \`20s\`, but boosters can only wait \`10s\`!`)
        .setColor(`RANDOM`);
        
       return message.channel.send(cooldownEmbed)
    else if (cooldown.has(message.author.id) && member.roles.cache.has("830503345251680298")) 
        const remaining = humanizeDuration(cooldown.has(message.author.id) && member.roles.cache.has("830503345251680298") - Date.now(),  units: ["s"], round: true, language: "en" );
        const cooldownEmbed = new Discord.MessageEmbed()
        .setTitle(`Too fast`)
        .setDescription(`You can run this command again in **$remaining**. (booster perk)`)
        .setColor(`RANDOM`);
        
        return message.channel.send(cooldownEmbed)
    
    
    if(cooldown.add(message.author.id) && !member.roles.cache.has("830503345251680298")) 
    setTimeout(() => 
        cooldown.delete(message.author.id) && !member.roles.cache.has("830503345251680298")
    , 10000)
else if(cooldown.add(message.author.id) && member.roles.cache.has("830503345251680298")) 
    setTimeout(() => 
        cooldown.delete(message.author.id) && member.roles.cache.has("830503345251680298")
    , 2000)


    message.channel.send('Pinging...').then(message => 

      const embed = new Discord.MessageEmbed()
        .setDescription(`Pong! :ping_pong: \`$Date.now() - message.createdTimestamp ms\``)
        .setColor(`RANDOM`);

      message.edit(" ", embed);
    )
  

非常感谢您提前提供的帮助。

亲切的问候。

【问题讨论】:

【参考方案1】:

有几个错误。首先,cooldown.has(message.author.id)member.roles.cache.has("830503345251680298") 都返回一个布尔值。你不能用它来测量剩余时间。

图像上显示的错误是由于您试图从布尔值 (!member.roles.cache.has("830503345251680298")) 中减去日期 (Date.now()),因此它返回自纪元时间以来的毫秒数。检查下面的sn-p:

console.log(true - Date.now())
console.log(false - Date.now())

要解决此问题,您需要将到期日期存储在某处。我建议您将这些冷却到期时间与成员 ID 的密钥一起存储在不和谐 collection 中。然后,检查两件事;如果成员具有助推器角色 (memberHasBooster) 并且成员必须等待冷却时间到期 (memberHasCooldown)。

如果是memberHasCooldown,您可以通过从到期日期 (cooldowns.get(message.author.id)) 中减去当前日期 (new Date()) 来计算剩余时间。它以毫秒为单位返回剩余时间。请注意,我使用了cooldowns.get,而不是cooldowns.hasCollection#get 返回存储的实际值,Collection#has 仅返回布尔值。

然后,您可以格式化剩余时间,并将其发送到嵌入中。

如果成员没有冷却时间,您可以使用Collection#set 添加一个新的。键是成员 ID,值是到期日期。您可以通过将 10000/20000 毫秒 (timeout) 添加到当前时间来计算到期日期。您还需要添加具有相同timeoutsetTimeout 并从集合中删除冷却时间。

添加冷却时间后,您可以发送实际消息。我在这里使用了异步/等待。不要忘记为实际发送的消息使用不同的名称(sentMessage 而不是 message)。

查看下面的完整代码:

let Discord = require('discord.js');
let humanizeDuration = require('humanize-duration');

let cooldowns = new Discord.Collection();

module.exports = 
  name: 'ping',
  description: 'It shows the bot latency.',
  async execute(client, message, args) 
      let guild = client.guilds.cache.get('828376495969402901');
      let member = guild.members.cache.get(message.author.id);
      let memberHasBooster = member.roles.cache.has('830503345251680298');
      let memberHasCooldown = cooldowns.has(message.author.id);

      if (memberHasCooldown) 
        let remaining = cooldowns.get(message.author.id) - new Date.now();
        let remainingFormatted = humanizeDuration(remaining, 
          language: 'en',
          round: true,
          units: ['s'],
        );
        let embed = new Discord.MessageEmbed()
          .setColor(`RANDOM`)
          .setTitle(`Slow down, bud`)
          .setDescription(
            `You can run \`ping\` again in **$remainingFormatted**. $
              memberHasBooster
                ? '(booster perk)'
                : '\nThe default cooldown is `20s`, but boosters can only wait `10s`!'
            `,
          );

        return message.channel.send(embed);
      

      // add cooldown
      const timeout = memberHasBooster ? 10 * 1000 : 20 * 1000;
      cooldowns.set(message.author.id, new Date() + timeout);

      setTimeout(() => cooldowns.delete(message.author.id), timeout);

      const sentMessage = await message.channel.send('Pinging...');

      const embed = new Discord.MessageEmbed()
        .setDescription(
          `Pong! :ping_pong: \`$
            Date.now() - sentMessage.createdTimestamp
           ms\``,
        )
        .setColor(`RANDOM`);

      sentMessage.edit(' ', embed);
  ,
;

【讨论】:

你好,Zsolt Meszaros。非常感谢你的帮助。关于代码,它给了我错误“Date.now 不是构造函数”,然后我从中删除了“new”,即使它有效,它仍然给我“0 秒”。也许我不应该使用这个 npm 包?亲切的问候。 您好,问题已解决。非常感谢您到目前为止 Zsolt Meszaros 和 felony123 的帮助。亲切的问候。【参考方案2】:

问题 #1:cooldown.has(message.author.id) && member.roles.cache.has("830503345251680298") 不返回 数字

问题 2:结果似乎返回了一个以 毫秒 为单位的数字,因此您需要使用正确的计算以 毫秒 为单位计算剩余时间。你可以使用performance.now(),而不是Date.now()

它是如何工作的:

const performance = require('perf_hooks');
 
var start = performance.now();
// something happens
var end = performance.now();
var total = Math.floor(end - start) // returns time between each event

可能的解决方案:

const Discord = require("discord.js");
const humanizeDuration = require("humanize-duration");
const  performance  = require('perf_hooks');

let cooldown = new Set();

module.exports = 
    name: "ping",
    description: "It shows the bot latency.",

    execute(client, message, args) 

        let guild = client.guilds.cache.get("828376495969402901");
        var start = performance.now();
        let member = guild.members.cache.get(message.author.id);

        if (cooldown.has(message.author.id) && !member.roles.cache.has("830503345251680298")) 
            var end = performance.now();
            var total = Math.floor(end - start)
            const remaining = humanizeDuration(total,  units: ["s"], round: true, language: "en" );
            const cooldownEmbed = new Discord.MessageEmbed()
                .setTitle(`Slow down, bud`)
                .setDescription(`You can run \`ping\` again in **$remaining**.\nThe default cooldown is \`20s\`, but boosters can only wait \`10s\`!`)
                .setColor(`RANDOM`);

            return message.channel.send(cooldownEmbed)
        
    


message.channel.send('Pinging...').then(message => 

    const embed = new Discord.MessageEmbed()
        .setDescription(`Pong! :ping_pong: \`$Date.now() - message.createdTimestamp ms\``)
        .setColor(`RANDOM`);

    message.edit(" ", embed);
)

【讨论】:

您好,感谢您迄今为止的帮助。不幸的是,它没有用。您的代码帮助我以秒为单位制作时间戳,但它只显示 0 秒,正如此屏幕截图所示。 i.imgur.com/vI9weP5.png 亲切的问候。 是的,它将为零,因为endstart 之间存在微小的差异。 @felony123 似乎误解了这个问题。您需要检查距离冷却到期时间的剩余时间,而不是您开始运行命令的时间与您的代码检查冷却时间是否具有作者 ID 的时间之间的差异。

以上是关于discord.js 的冷却系统问题的主要内容,如果未能解决你的问题,请参考以下文章

命令冷却 discord.js

Discord.js 命令冷却时间

Discord.js 命令冷却时间 + 剩余时间

TypeError: command.execute 在捕获错误时不是函数。此外,冷却不起作用。在 Discord.js 上

Discord.js 规则系统

Discord.js-commando 节流不起作用