@kokapuk

Почему бот после запуска игнорирует первое событие?

Как только я запустил бота, ему нужно прогнать одно событие, что бы он начал их ловить. В чем проблема?

const { Client, GatewayIntentBits } = require('discord.js');
const db = require('./db');
const keep_alive = require('./keep_alive.js')
const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers] });

db.connect()
  .then(() => console.log('Connected to db!'))
  .catch((e) => console.log(`Failed to connect to db: ${e}`));

client.on('ready', () => {
  console.log(`Logged in as ${client.user.tag}!`);
});

client.on('interactionCreate', async (interaction) => {
  if (!interaction.isChatInputCommand()) return;

  if (interaction.commandName === 'cleardb') {
    db.clearAllMembers()
      .then(async () => {
        const msg = 'All members has been deleted from db!';
        console.log(msg);
        await interaction.reply(msg);
      })
      .catch(async (e) => {
        const msg = `Failed to clear cluster: ${e}`;
        console.log(msg);
        await interaction.reply(msg);
      });
  }
});

client.on('guildMemberRemove', async (member) => {
  if (member.guild.id != process.env.guild_id) {
    return;
  }

  let rolesId = [];

  member.roles.cache.map((role) => {
    if (role.id == process.env.guild_id) {
      return;
    }

    rolesId.push(role.id);
  });

  if (rolesId.length > 0) {
    db.writeMember(member.id, rolesId)
      .then(() => console.log(`Member ${member.id} has been written to db with these roles: ${JSON.stringify(rolesId)}!`))
      .catch((e) => console.log(`Failed to write member to dbd: ${e}`));

    return;
  }
});

client.on('guildMemberAdd', async (member) => {
  if (member.guild.id != process.env.guild_id) {
    return;
  }

  if (!(await db.memberExists(member.id))) {
    return;
  }

  var memberFromDb = await db.getMember(member.id);

  member.roles
    .add(memberFromDb.roles)
    .then(() => console.log(`Member ${member.id} returned to the guild and got their roles back!`))
    .catch((e) => console.log(`Member ${member.id} returned to the guild but have not got their roles back because of error: ${e}!`));

  db.deleteMember(member.id)
    .then(() => console.log(`Member ${member.id} has been deleted!`))
    .catch((e) => console.log(`Failed to delete member: ${e}`));
});

client.login(process.env.token);
  • Вопрос задан
  • 129 просмотров
Решения вопроса 2
Syjalo
@Syjalo
Представьте себе бота
Не все участники есть в кэше клиента. Они появляются там тогда, когда бот каким-либо образом повзаимодействовал с участником. Добавление интента GuildPresences добавляет участников в кэш, так как вы даете знать Discord Gateway, что хотите получать информацию о презенсах участников. Gateway отправляет клиенту эту информацию при старте и добавляет участников в кэш, НО только тех, кто не офлайн и не указал невидимый статус. Следовательно если у участника невидимый статус и он ни разу не взаимодействовал с ботом и он выйдет из сервера, то событие guildMemberRemove будет проигнорировано, так как этого участника нет в кэше.

Почему так происходит?
Это сделано для таго, чтобы вы всегда могли быть уверены, что в событии придут все данные; то есть и новые данные участника, и старый. Так как Discord не отправляет старые данные, то они берутся из кэша, а раз их в кэше нет, значит данные неполные и событие не срабатывает.

Решением этой проблемы являются партиалы, которые дают знать клиенту, что вы готовы к получению неполных данных. Неполные данные означают, что в данных может содержаться только id и ничего другого.
Подробнее о партиалах
Ответ написан
Комментировать
@kokapuk Автор вопроса
И так, проблема была не в самих событиях, а в том, что я пытался достать кэш ролей из мембера, хотя он на старте пуст. Нужно добавить GatewayIntentBits.GuildPresences в intents, чтобы избежать этой проблемы. Если кто то может объяснить, почему так, я был бы очень благодарен.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы