Search code examples
javascriptnode.jsdiscorddiscord.jsbots

Discord.js: Returning the current voice.channelId of a user is outdated


For a command of my discord bot I need to get the ID of the voicechannel the user is currently connected to. I've got something similar working currently:

module.exports = {
 name: 'hit',
 description: "Return your voiceChannel ID",
 execute(message) {
    console.log('User ' + message.author.username + ' // ' + message.author.id + ' used the hit command.');

    console.log(message.member.voice.channelId);
 }
};

The problem is that this only returns the voicechannel id of the channel that the user was in when the bot was started. If the user switches the channel or leaves every channel the voicechannel id that is returned here still stays the same. I also tried this, which had the exact same problem:

module.exports = {
    name: 'hit',
    description: "Return your voiceChannel ID",
    execute(message, config, commands) {
        console.log('User ' + message.author.username + ' // ' + message.author.id + ' used the hit command.');

        awaitFetch(message);
    }
};

async function awaitFetch(message) {
    let newInfo = await message.member.fetch(true);
    console.log(newInfo.voice.channelId);
}

I think it is because discord.js caches these information when starting up. But I have no idea how to update said cache...

Returning 'null' even though I am in a voice channel

Edit: not sure if this helps but here is the main.js which calls every command:

const Discord = require('discord.js');
let config = require('./config.json');

const client = new Discord.Client({
    intents: [
        Discord.Intents.FLAGS.GUILDS,
        Discord.Intents.FLAGS.GUILD_MESSAGES,
        Discord.Intents.FLAGS.GUILD_MEMBERS,
        Discord.Intents.FLAGS.GUILD_PRESENCES,
    ]
});

const fs = require('fs');

client.commands = new Discord.Collection();

const commandFiles = fs.readdirSync('./commands/').filter(file => file.endsWith('.js'));
for(const file of commandFiles) {
    const command = require(`./commands/${file}`);

    client.commands.set(command.name, command);
}

client.once('ready', () => {
    console.log('Online!');
});

client.on('messageCreate', message => {

    console.log (message.member.voice.channelId);

    if(message.author.bot || message.mentions.everyone === true) return;

    if(fs.existsSync(`guildConfigs/${message.guild.id}.json`)) {
        delete require.cache[require.resolve(`./guildConfigs/${message.guild.id}.json`)];
        config = Object.assign({}, require(`./guildConfigs/${message.guild.id}.json`));
    }
    else{
        config = require('./config.json');
    }

    let prefix = config.prefix;

    if(message.mentions.has(client.user) && !message.author.bot) {
        client.commands.get('pinged').execute(message, config);
    }
    else if(!message.content.startsWith(prefix)) return;

    const args = message.content.slice(prefix.length).split(' ');
    const command = args.shift().toLowerCase();

    if(command === 'help') {
        client.commands.get('help').execute(message, config, client.commands);
    } else if(command === 'ping') {
        client.commands.get('ping').execute(message);
    } else if(command === 'hit') {
        client.commands.get('hit').execute(message, args, config);
    } else if(command === 'topic') {
        client.commands.get('topic').execute(message);
    } else if(command === 'fact') {
        client.commands.get('fact').execute(message);
    } else if(command === 'settings') {
        if(message.member.permissions.has('ADMINISTRATOR')) {
            client.commands.get('settings').execute(message, args, config);
        }
        else{
            message.channel.send('Sorry bro, but this command is only available for server admins 😐');
        }
    }
});

client.login(config.token);

bump


Solution

  • Ok, I'm making some points:

    • I see you're not using a database and instead your creating several json files for each guild, that's not the beast approach (in case you plan to serve several guilds), to fix that you can think about using MongoDB, it works literally in the same way(BSON not JSON but you won't see the difference).
    • The events you're listening to won't be fired unless the ready event is fired, so a good practice would be to move all your listeners(message, join or whatever) inside the ready event callback
    • (just a tip): You're splitting the message with .split(' ') but what if the user enters !ping user(with two spaces)? That will results in ['ping', '', 'user'], instead you can call the split function with a regex: .split(/ +/) in this way you will split the message with at least one space
    • Once you have the command name with const commandName = args.shift().toLowerCase(), you can do:
    const command = client.commands.get(commandName);
    if(!command) return;
    // The permissions check you do for the settings command should be moved on the
    // command logic itself, what you should do in the main file is just take a message,
    // get a command and execute it
    command.execute(message, args) // from the message instance you can get the client and the config can be required(using a db would resolve this 'issue')
    

    Said that, the solution for your problem is simple, you just forgot to add the GUILD_VOICE_STATES intent on your client, that's it, that should fix this issue