简体   繁体   中英

Discord.js Cooldowns with Time Remaining using Command Handler

I am looking to make a cool down system for discord bot commands using discord.js. I am looking for it to show the time remaining left on the cool down when the user tries to do the command. Currently I have it so it does a cool down using the command handler so that I just have to add "timeout: '10000'," although I cant seem to find a way to get it show the time remaining by using this system.

This is the code that I currently have in my message.js file so that is can be used with the command handler so that I do not have to write the timeout code on every command file. Code below is the whole message.js file.

const Timeout = new Set();
const { MessageEmbed } = require('discord.js')
const {prefix} = require('../../config.json')
const ms = require('ms')
module.exports=async(bot, message)=>{

    if(message.author.bot) return;
    if(!message.content.toLowerCase().startsWith(prefix)) return;
    if(!message.member) message.member = await message.guild.fetchMember(messsage);
    if(!message.guild) return;
    const args = message.content.slice(prefix.length).trim().split(/ +/g);
    const cmd = args.shift().toLowerCase();

    if(cmd.length === 0) return;

    let command = bot.commands.get(cmd);
    if(!command) command = bot.commands.get(bot.aliases.get(cmd));

    if(command){
        if(command.timeout){
            if(Timeout.has(`${message.author.id}${command.name}`)){
                return message.reply(`**Slow down, you can only use this command every ${ms(command.timeout)}!**`)
            } else {

                command.run(bot, message, args);
                Timeout.add(`${message.author.id}${command.name}`)
                setTimeout(() => {
                    Timeout.delete(`${message.author.id}${command.name}`)
                }, command.timeout);
            }
        } else {
            command.run(bot, message, args)
        }
    }
}

Current response is above in bold text.

For reference, the message.js file is referenced in the following code in my index.js file.

bot.on('message', async message =>{
    require('./events/guild/message')(bot, message)
})

The following is what I have to put at the beginning of each command file, with a simple command example shown for reference.

const Discord = require('discord.js');
module.exports={
    name: 'test',
    category: 'info',
    timeout: '15000', //This would result in a 15 second cooldown as time is in ms.
    run: async(bot, message, args) =>{
        message.channel.send(`test`)
    }
}

To conclude, I am looking to keep my system, but instead of it saying "Slow down, you can only use this command every 15000, (For example above) I would like it to say something in the lines of "Slow it down. you can use this command again in 10s. The default cooldown is 15s.

If I'm not mistaken you want to convert every 15000 into every 15s ?

You already have the ms module so looks like you are just confused how to use it:

If it receives a string it converts it into ms, if it receives a number it converts it into a readable format like 1d 2h 3m ,

In your module.exports you have it a string, so make it a number and everything is fixed.

That string might also intercept with setTimeout(func, time)

If for some reason you don't want to change the module.exports.timeout into a string, before you call ms , you will have to do parseInt(command.timeout)

code:

let command = bot.commands.get(cmd) || bot.commands.get(bot.aliases.get(cmd));

if (!command) return;
if (!command.timeout) return command.run(bot, message, args);

//if you changed it to a number in module.exports you don't have to parseInt it
const timeout = parseInt(command.timeout);
if (Timeout.has(`${message.author.id}${command.name}`)) {
    return message.reply(`**Slow down, you can only use this command every ${ms(timeout)}!**`)
} else {
    command.run(bot, message, args);
    Timeout.add(`${message.author.id}${command.name}`)
    setTimeout(() => {
        Timeout.delete(`${message.author.id}${command.name}`)
    }, timeout);
}

Second part:

You will need to track when you set the timeout, the issue with using the Set class is that it's not a key value based, so there's two options:

Set.add({ key: key, time: Date.now()}) or use Discord.Collection / Map

First: still using Set , setting objects instead:

const timeout = command.timeout;
const key = message.author.id + command.name;
let found;

for(const e of Timeout) {
  if(e.key === key) {
    found = e;
    //possibly bad practice, arguable
    break;
  }
}

if(found) {
  const timePassed = Date.now() - found.time;
  const timeLeft = timeout - timePassed;
  //the part at this command has a default cooldown of, did you want to hard code 15s? or have it be the commands.config.timeout?
  return message.reply(`**Slow down, you can use this command again in ${ms(timeLeft)} This command has a default cooldown of ${timeout}!**`)
} else {
  command.run(bot, message, args);
  Timeout.add({ key, time: Date.now() });

  setTimeout(() => {
     Timeout.delete(key);
  }, timeout);
}

Second: Discord.Collection or Map works too since its just an extended class from that

I'm going with Map , if you use Collection just do:

const { MessageEmbed, Collection } = require("discord.js");
const Timeout = new Collection();

Map code:

const Timeout = new Map();

After code:

const timeout = command.timeout;
const key = message.author.id + command.name;
const found = Timeout.get(key);
if(found) {
  const timePassed = Date.now() - found;
  const timeLeft = timeout - timePassed;
  //the part at this command has a default cooldown of, did you want to hard code 15s? or have it be the commands.config.timeout?
  return message.reply(`**Slow down, you can use this command again in ${ms(timeLeft)} This command has a default cooldown of ${timeout}!**`);
} else {
  command.run(bot, message, args);
  Timeout.set(key, Date.now());

  setTimeout(() => {
     Timeout.delete(key);
  }, timeout);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM