Analizar argumentos de mención
En un capítulo anterior, aprendimos a crear comandos con la entrada del usuario; También a usar menciones como entrada de usuario Sin embargo, el uso de message.mentions puede ocasionar algunos problemas.
Por ejemplo, no sabe qué mención pertenece a qué argumento. O si está dividiendo el contenido del mensaje por espacios para obtener los argumentos, Las menciones seguirán ocupando espacio en su matriz de argumentos, estropeando el resto del análisis de argumentos si no tienes cuidado.
Digamos que estás haciendo un bot para moderar su servidor. Querrás que el bot banee o warnee a la persona mencionada. Pero, ¿qué pasa si intentas usar el comando de esta manera?
Obvio que has baneado a Villano por que es al que le has mencionado primero. Sin embargo, la API de Discord no envía las menciones en el orden en que aparecen; En su lugar, están ordenados por su ID.
Si la @Victima se ha unido a Discord antes que @Villano y tiene una ID más pequeña, es posible que se le prohíba la prohibición. O tal vez alguien hace un mal uso de un comando, el bot aún puede aceptarlo, pero creará un resultado inesperado. Digamos que alguien usó accidentalmente el comando de prohibición de esta manera:
El bot todavía baneara a alguien, pero volverá a ser @Victima. message.mentions.users todavía contiene una mención, que el bot usará. Pero en realidad, querrás que tu bot pueda decirle al usuario que hizo un mal uso del comando.
Cómo funcionan las menciones de Discord
Discord usa una sintaxis especial para incrustar menciones en un mensaje. Para las menciones del usuario, es la identificación del usuario con <@ al principio y > al final, así: <@86890631690977280>. Si tienen un apodo, también habrá un ! Después de la @. Las menciones de roles y las menciones de canales funcionan de manera similar. Las menciones de roles se ven como <@&134362454976102401> y las menciones de canales como <#222197033908436994>.
Eso significa que cuando recibe un mensaje de la API de Discord y contiene menciones, el contenido del mensaje contendrá esa sintaxis especial. Si tu envías:
Entonces el message.content para ese mensaje se verá así:
'Creo que deberíamos agregar el rol <@&134362454976102401> a <@86890631690977280>.'
Implementación
Entonces, ¿cómo usas esta nueva información para tu bot? La mayor parte de su código no cambiará; sin embargo, en lugar de usar message.mentions para encontrar los usuarios mencionados, tendrás que hacerlo manualmente. Esto puede sonar aterrador al principio, pero verás que es bastante simple una vez que veas el código.
Digamos que ya tienes un controlador de comandos simple como este:
client.on('messageCreate', message => {
if (!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).trim().split(/ +/);
const command = args.shift().toLowerCase();
});
2
3
4
5
6
Ahora puedes probar rápidamente las aguas actualizando el comando avatar. Esto es lo que tenemos hasta ahora. Es bastante simple; mostrará el avatar de quién usó el comando.
client.on('messageCreate', message => {
// ...
if (command === 'avatar') {
const user = message.author;
return message.channel.send(`Avatar de ${user.username}: ${user.displayAvatarURL({ dynamic: true })}`);
}
});
2
3
4
5
6
7
8
Pero, ¿cómo se obtiene el usuario correcto ahora? Bueno, esto require unos sencillos pasos. Ponerlo en una función lo hará fácilmente reutilizable. Usaremos el nombre getUserFromMention aquí:
function getUserFromMention(mention) {
if (!mention) return;
if (mention.startsWith('<@') && mention.endsWith('>')) {
mention = mention.slice(2, -1);
if (mention.startsWith('!')) {
mention = mention.slice(1);
}
return client.users.cache.get(mention);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
Como puedes ver, es una función relativamente sencilla. Básicamente, solo funciona a través de la estructura de la mención poco a poco:
- Comprueba si la mención comienza con
<@y termina con>y luego los elimina. - Si el usuario tiene un apodo y su mención contiene un
!, lo elimina también. - Ahora solo debe dejar el ID, así que utilícelo para buscar el usuario de la colección
client.users.cache. Siempre que encuentra un error con la mención (es decir, estructura no válida), simplemente devuelveundefinedpara indicar que la mención no es válida.
TIP
El método .slice() se usa aquí de una manera más avanzada. Puedes leer el Documentación MDNopen in new window para más información.
Ahora tiene una función ingeniosa que puede usar para convertir una mención sin formato en un objeto de usuario adecuado. Conectarlo al comando te dará esto:
client.on('messageCreate', message => {
// ...
if (command === 'avatar') {
if (args[0]) {
const user = getUserFromMention(args[0]);
if (!user) {
return message.reply('Utilice una mención adecuada si desea ver el avatar de otra persona.');
}
return message.channel.send(`Avatar de ${user.username}: ${user.displayAvatarURL({ dynamic: true })}`);
}
return message.channel.send(`${message.author.username}, tu avatar: ${message.author.displayAvatarURL({ dynamic: true })}`);
}
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Y aquí, conectamos la nueva función al comando. Si el usuario proporcionó un argumento, debería ser la mención del usuario, por lo que simplemente se pasa directamente a la función.
¡Y eso es todo! Simple, ¿no es así? Inicia tu bot y ve si funciona.
Así que ahora, en lugar de usar message.mentions, puedes usar tu nueva y fantástica función. Esto te permitirá agregar comprobaciones adecuadas para todos sus argumentos para que pueda saber cuándo un comando se usa y no se usa correctamente.
Pero esto no marca el final de la página. Si te sientes aventurero, puede seguir leyendo y aprender a usar las expresiones regulares para convertir fácilmente una mención en un objeto de usuario en solo dos líneas.
Comando ban
Ahora sabes cómo analizar las menciones de los usuarios para un comando simple como el comando avatar. Sin embargo, el comando avatar no se beneficia tanto como el ejemplo de la introducción.
Al escribir un comando de ban en el que puede aparecer una mención en el motivo, las menciones de análisis manual son mucho más importantes. Puede ver un ejemplo de cómo hacerlo de la siguiente manera:
client.on('messageCreate', async message => {
// ...
if (command === 'ban') {
if (args.length < 2) {
return message.reply('Menciona al usuario que quieres banear y especifica un motivo.');
}
const user = getUserFromMention(args[0]);
if (!user) {
return message.reply('Utiliza una mención adecuada si desea banear a un usuario.');
}
const reason = args.slice(1).join(' ');
try {
await message.guild.members.ban(user, { reason });
} catch (error) {
return message.channel.send(`No pude banear a: **${user.tag}**: ${error}`);
}
return message.channel.send(`He baneado a **${user.tag}** correctamente de este servidor!`);
}
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Ahora, si envías un comando como el siguiente, siempre puedes estar seguro de que usarás la mención al principio para averiguar a quién banear, y validarás adecuadamente la mención:
Uso de expresiones regulares
Anteriormente, aprendiste a usar funciones rudimentarias relacionadas con cadenas para convertir la sintaxis de mención especial que usa Discord en un objeto de usuario de discord.js adecuado. Pero usando expresiones regulares (también conocidas como "RegEx" o "RegExp"), ¡puedes condensar toda esa lógica en una sola línea! Loco, ¿verdad?
Si nunca antes has trabajado con expresiones regulares, esto puede parecer abrumador. Pero, de hecho, ya has utilizado expresiones regulares. ¿Recuerda withoutPrefix.split(/ + /);? Este pequeño / + / es una expresión regular. El / a cada lado le dice a JavaScript dónde comienza y dónde termina la expresión regular; el material intermedio es su contenido.
TIP
Para obtener una explicación más detallada, consulte la documentación de MDNopen in new window.
La expresión regular que utilizarás para las menciones de los usuarios tendrá este aspecto: /^<@!?(\d+)>$/. Así es como funciona la expresión regular:
- El
^al principio y el$al final significa que la mención debe ocupar toda la cadena. - Tiene los típicos
<@y>al principio y al final. - El
?Después del!Indica que el!Es opcional. \ d +significa que la expresión regular buscará varios dígitos, que serán el ID.- Los paréntesis alrededor de
\ d +crean un grupo de captura, que le permite sacar el ID de la mención.
Usando el método .match() en cadenas, puedes obtener los valores del grupo de captura, es decir, el ID de la mención.
ADVERTENCIA
Discord.js tiene patrones integrados open in new window para las menciones coincidentes, sin embargo, a partir de la versión 11.4 no contienen ningún grupo, por lo tanto, no son útiles para eliminar la identificación de la mención.
Actualizar su función getUserFromMention para usar RegExp le da esto:
function getUserFromMention(mention) {
// La identificación es la primera y única coincidencia encontrada por la expresión regular.
const matches = mention.match(/^<@!?(\d+)>$/);
// Si la variable proporcionada no fue una mención, las coincidencias serán nulas en lugar de una matriz (array)
if (!matches) return;
// Sin embargo, el primer elemento de la matriz (array) de coincidencias será la mención completa, no solo el ID,
// Entonces usa el index 1.
const id = matches[1];
return client.users.cache.get(id);
}
2
3
4
5
6
7
8
9
10
11
12
13
¿Ves? Eso es mucho más corto y no tan complicado. Si vuelves a ejecutar tu bot ahora, todo debería de funcionar igual.
Resultado del código
Si quieres comparar tu código con el código que hemos hecho durante el camino, puedes revisarlo en nuestro repositorio de GitHub aquí open in new window.




