discordjs / discord.js

A powerful JavaScript library for interacting with the Discord API
https://discord.js.org
Apache License 2.0
25.36k stars 3.97k forks source link

Not subscribing to specific Intents may break discord.js functionality #3924

Closed monbrey closed 3 years ago

monbrey commented 4 years ago

Documenting this here so people can reference this is future PRs.

With Discord providing supports for bots to subscribe to the type of events they want to receive via Intents, this can have some unintended impacts on how discord.js works.

Most noticeably, since Discord.js assumes all Guilds and GuildChannels will be cached (as per current functionality) omitting the GUILDS intent breaks things.

Example code, with issue present:

const client = new Discord.Client({
    partials: ["REACTION", "MESSAGE"],
    ws: { intents: ["GUILD_MESSAGES"] }
});

client.on("message", message => {
    console.log(message.content);
});
client.on("raw", console.log);

In this example, the raw event emits a MESSAGE_CREATE with full message, author and member data.

{
    type: 0,
    tts: false,
    timestamp: '2020-03-10T03:47:47.743000+00:00',
    pinned: false,
    nonce: '686782331209383936',
    mentions: [],
    mention_roles: [],
    mention_everyone: false,
    member: {
      roles: [Array],
      premium_since: null,
      nick: null,
      mute: false,
      joined_at: '2018-02-11T06:18:41.269000+00:00',
      hoisted_role: null,
      deaf: false
    },
    id: '686782331981529107',
    flags: 0,
    embeds: [],
    edited_timestamp: null,
    content: 'test',
    channel_id: '620798312160821280',
    author: {
      username: 'Monbrey',
      id: '122157285790187530',
      discriminator: '4502',
      avatar: '42fd1742230b86f138d323bf20e369d5'
    },
    attachments: [],
    guild_id: '412130302958239745'
}

The data includes guild_id and channel_id, which could be used to fetch a Guild and GuildChannel via the respective Managers. However client.on("message") doesn't emit at all, not even a Partial. It relies on a channel existing in cache for anything to be emitted: see https://github.com/discordjs/discord.js/blob/36050d07f5ded196f5f6601619da2d3dc3604126/src/client/actions/MessageCreate.js#L7-L36

Fixed:

const client = new Discord.Client({
    partials: ["REACTION", "MESSAGE"],
    ws: { intents: ["GUILDS", "GUILD_MESSAGES"] }
});

client.on("message", message => {
    console.log(message.content);
});

Adding the GUILDS intent allows the bot to receive the full Guilds and Channels expected in the identify payload, and cache everything. Events will then emit as expected.

To properly support a partial implementation of this where Guild and Channel could be uncached, the Message class would need to switch to the guildID/channelID property approach, with getters for the object, in the same way member properties like <Guild>.ownerID are handled.

Fyko commented 4 years ago

Do you think a set of default intents would be a good idea? They could apply when a ClientOptions#ws#intents is not supplied and perhaps throw some sort of warning?

monbrey commented 4 years ago

Do you think a set of default intents would be a good idea?

I can go either way on that. I think there's some value in forcing people to define the ones they need, as that's in line with why Discord is introducing them.

If we set a default, it should probably be all non-privileged intents, but we could also just advise that as an easy way to do it in the guide.

advaith1 commented 4 years ago

imo: