Collecteurs
Collecteurs de messages
Les Collector sont utiles pour permettre à votre bot d'obtenir une entrée supplémentaire après l'envoi de la première commande. Un exemple serait de lancer un quiz, où le bot va "attendre" une réponse correcte de quelqu'un.
Collecteur de message basique
Pour l'instant, prenons l'exemple qu'ils nous ont fourni :
// `m` est un objet message qui sera passé à travers la fonction de filtre
const collectorFilter = (m) => m.content.includes('discord');
const collector = interaction.channel.createMessageCollector({ filter: collectorFilter, time: 15_000 });
collector.on('collect', (m) => {
console.log(`Collecté ${m.content}`);
});
collector.on('end', (collected) => {
console.log(`${collected.size} éléments collectés`);
});Vous pouvez fournir une clé filter au paramètre objet de createMessageCollector(). La valeur de cette clé doit être une fonction qui retourne une valeur booléenne pour indiquer si ce message doit être collecté ou non. Pour vérifier plusieurs conditions dans votre filtre, vous pouvez les connecter en utilisant des opérateurs logiques. Si vous ne fournissez pas de filtre, tous les messages du canal sur lequel le collecteur a été démarré seront collectés.
Notez que l'exemple ci-dessus utilise retour implicite pour la fonction de filtre et le transmet à l'objet options en utilisant la notation d'abréviation de propriété d'objet.
Si un message passe par le filtre, il déclenchera l'événement collect pour le collector que vous avez créé. Ce message est ensuite transmis au écouteur d'événement sous le nom de collected et la fonction fournie est exécutée. Dans l'exemple ci-dessus, vous enregistrez simplement le message. Une fois que le collecteur a terminé la collecte en fonction des conditions de fin fournies, l'événement end émet.
Vous pouvez contrôler quand un collecteur se termine en fournissant des clés d'options supplémentaires lors de la création d'un collecteur :
time: Durée en millisecondes pendant laquelle le collecteur doit s'exécutermax: Nombre de messages pour passer avec succès le filtremaxProcessed: Nombre de messages rencontrés (indépendamment du résultat du filtre)
L'avantage d'utiliser un collecteur basé sur événements plutôt que .awaitMessages() (son homologue basé sur Promise) est que vous pouvez faire quelque chose directement après la collecte de chaque message, plutôt que seulement après la fin du collecteur. Vous pouvez également arrêter manuellement le collecteur en appelant collector.stop().
Attendre les messages
L'utilisation de TextChannel#awaitMessages peut être plus facile si vous comprenez les Promises, et cela vous permet d'avoir un code plus propre dans l'ensemble. C'est essentiellement identique à TextChannel#createMessageCollector, sauf promisé. Cependant, l'inconvénient d'utiliser cette méthode est que vous ne pouvez rien faire avant que la Promise ne soit résolue ou rejetée, soit par une erreur ou une complétion. Cependant, cela devrait suffire pour la plupart des objectifs, comme attendre la bonne réponse dans un quiz. Au lieu de prendre leur exemple, mettons en place une commande de quiz de base en utilisant la fonctionnalité .awaitMessages().
D'abord, vous aurez besoin de quelques questions et réponses au choix, voici un ensemble de base :
[
{
"question": "What color is the sky?",
"answers": ["blue"]
},
{
"question": "How many letters are there in the alphabet?",
"answers": ["26", "twenty-six", "twenty six", "twentysix"]
}
]L'ensemble fourni permet une erreur du répondeur avec un tableau de réponses autorisées. Idéalement, il serait préférable de placer ceci dans un fichier JSON, que vous pouvez appeler quiz.json pour simplifier.
const quiz = require('./quiz.json');
// ...
const item = quiz[Math.floor(Math.random() * quiz.length)];
const collectorFilter = (response) => {
return item.answers.some((answer) => answer.toLowerCase() === response.content.toLowerCase());
};
interaction.reply({ content: item.question, withResponse: true }).then((response) => {
response.resource.message.channel
.awaitMessages({ filter: collectorFilter, max: 1, time: 30_000, errors: ['time'] })
.then((collected) => {
interaction.followUp(`${collected.first().author} got the correct answer!`);
})
.catch((collected) => {
interaction.followUp('Looks like nobody got the answer this time.');
});
});Si vous ne comprenez pas comment .some() fonctionne, vous pouvez en lire plus de détails
ici.
Dans ce filtre, vous itérez dans les réponses pour trouver ce que vous voulez. Vous aimeriez ignorer la casse car de simples fautes de frappe peuvent se produire, vous convertissez donc chaque réponse en minuscules et vérifiez également si elle est égale à la réponse en minuscules. Dans la section options, vous ne voulez permettre qu'une seule réponse de passer, d'où le paramètre max: 1.
Le filtre recherche des messages qui correspondent à l'une des réponses du tableau des réponses possibles pour les transmettre au collecteur. Les options (le deuxième paramètre) spécient qu'un maximum d'un message peut passer le filtre avec succès avant que la Promise ne se résolve avec succès. La section d'erreurs spécifie que l'heure causera une erreur, ce qui causera le rejet de la Promise si une bonne réponse n'est pas reçue dans le délai d'une minute. Comme vous pouvez le voir, il n'y a pas d'événement collect, donc vous être limité à cet égard.
Collecteurs de réactions
Collecteur de réaction de base
Ceux-ci fonctionnent assez similairement aux collecteurs de messages, sauf que vous les appliquez sur un message plutôt que sur un canal. Cet exemple utilise la méthode Message#createReactionCollector. Le filtre vérifiera l'émoji 👍 dans la teinte de peau par défaut spécifiquement, alors méfiez-vous. Il vérifiera également que la personne qui a réagi partage le même id que l'auteur du message d'origine auquel le collecteur a été assigné.
const collectorFilter = (reaction, user) => {
return reaction.emoji.name === '👍' && user.id === message.author.id;
};
const collector = message.createReactionCollector({ filter: collectorFilter, time: 15_000 });
collector.on('collect', (reaction, user) => {
console.log(`Collected ${reaction.emoji.name} from ${user.tag}`);
});
collector.on('end', (collected) => {
console.log(`Collected ${collected.size} items`);
});Attendre les réactions
Message#awaitReactions fonctionne presque de la même manière qu'un collecteur de réaction, sauf qu'il est basé sur Promise. Les mêmes différences s'appliquent qu'avec les collecteurs de canal.
const collectorFilter = (reaction, user) => {
return reaction.emoji.name === '👍' && user.id === message.author.id;
};
message
.awaitReactions({ filter: collectorFilter, max: 4, time: 60_000, errors: ['time'] })
.then((collected) => console.log(collected.size))
.catch((collected) => {
console.log(`After a minute, only ${collected.size} out of 4 reacted.`);
});Collecteurs d'interactions
Le troisième type de collecteur vous permet de collecter des interactions ; par exemple, lorsque les utilisateurs activent une commande slash ou cliquent sur un bouton dans un message.
Collecteur de composants de message de base
La collecte des interactions à partir des composants de message fonctionne similairement aux collecteurs de réaction. Dans l'exemple suivant, vous vérifierez que l'interaction provient d'un bouton et que l'utilisateur qui clique sur le bouton est le même utilisateur qui a lancé la commande.
Une différence importante à noter avec les collecteurs d'interactions est que Discord s'attend à une réponse à toutes les interactions dans les 3 secondes - même celles que vous ne voulez pas collecter. Pour cette raison, vous pouvez souhaiter .deferUpdate() toutes les interactions dans votre filtre, ou ne pas utiliser de filtre du tout et gérer ce comportement dans l'événement collect.
const { ComponentType } = require('discord.js');
const collector = message.createMessageComponentCollector({ componentType: ComponentType.Button, time: 15_000 });
collector.on('collect', (i) => {
if (i.user.id === interaction.user.id) {
i.reply(`${i.user.id} clicked on the ${i.customId} button.`);
} else {
i.reply({ content: `These buttons aren't for you!`, flags: MessageFlags.Ephemeral });
}
});
collector.on('end', (collected) => {
console.log(`Collected ${collected.size} interactions.`);
});Attendre un composant de message
Comme avant, cela fonctionne similairement au collecteur de composants de message, sauf qu'il est basé sur Promise.
Contrairementaux autres collecteurs basés sur Promise, cette méthode ne collectera qu'une seule interaction qui passe le filtre. Si aucune interaction n'est collectée avant l'expiration du délai, la Promise sera rejetée. Ce comportement s'aligne avec l'exigence de Discord que les actions reçoivent immédiatement une réponse. Dans cet exemple, vous utiliserez .deferUpdate() sur toutes les interactions du filtre.
const { ComponentType } = require('discord.js');
const collectorFilter = (i) => {
i.deferUpdate();
return i.user.id === interaction.user.id;
};
message
.awaitMessageComponent({ filter: collectorFilter, componentType: ComponentType.StringSelect, time: 60_000 })
.then((interaction) => interaction.editReply(`You selected ${interaction.values.join(', ')}!`))
.catch((err) => console.log('No interactions were collected.'));Attendre la soumission de modal
Si vous voulez attendre la soumission d'un modal dans le contexte d'une autre exécution de commande ou de bouton, vous pouvez trouver le collecteur promisé CommandInteraction#awaitModalSubmit utile.
Comme Discord ne vous informe pas si l'utilisateur ferme le modal, fournir une time maximale à attendre est crucial :
initialInteraction
.awaitModalSubmit({ time: 60_000, filter })
.then((interaction) => interaction.editReply('Merci pour votre soumission !'))
.catch((err) => console.log('Aucune interaction de soumission de modal n\'a été collectée'));Pour plus d'informations sur le travail avec les modaux, consultez la section modaux de ce guide.