Creare Slash Commands in Discord.js

Discord consente agli sviluppatori di registrare degli slash commands, che consentono agli utenti un modo molto semplice per interagire direttamente con l’applicazione. Tuttavia, prima di poter rispondere ad uno slash […]

Avatar di gbfactory
gbfactory 3 Agosto 2022

Discord consente agli sviluppatori di registrare degli slash commands, che consentono agli utenti un modo molto semplice per interagire direttamente con l'applicazione. Tuttavia, prima di poter rispondere ad uno slash command, è necessario registrarlo.

Registrare uno Slash Command

In questa lezione della guida vedremo solamente le cose indispensabili per poter iniziare a lavorare con gli slash commands, ma puoi fare riferimento in ogni momento alla lezione più approfondita sugli slash commands per ulteriori dettagli.

Script per la Registrazione dei Comandi

Come prima cosa creiamo un file chiamato registra-comandi.js all'interno della directory del progetto. Questo file verrà utilizzato per registrare ed aggiornare gli slash commands utilizzati dalla nostra applicazione.

Dobbiamo installare il pacchetto @discordjs/rest eseguendo il seguente comando:

npm install @discordjs/rest 

Di seguito è riportato lo script che possiamo utilizzare per registrare o aggiornare gli slash commands. Vediamo prima il significato di alcune variabili:

  • clientId: l'id del client della tua applicazione;
  • guildId: l'id del server in cui desideriamo registrare i comandi;
  • commands: l'array dei comandi da registrare con i dati costruiti utilizzando lo slash commands builder contenuto all'interno di discord.js.

Per ottenere l'id del client della nostra applicazione, andiamo sulla Discord Developer Platform e selezioniamo la nostra applicazione. Sulla pagina "General Information" troveremo l'id alla voce "Application ID".

Invece, per ottenere l'id del server all'interno di cui desideriamo registrare i nostri slash commands dobbiamo aprire le Impostazioni di Discord e dalla pagina "Avanzate" attivare la "Modalità per sviluppatori". Questo ti consentirà di accedere all'opzione "Copia ID" del menu contestuale quando premiamo con il tasto destro sull'icona di un server, sul profilo di un utente, ecc.

const { SlashCommandBuilder, Routes } = require('discord.js');
const { REST } = require('@discordjs/rest');
const { clientId, guildId, token } = require('./config.json');

const commands = [
	new SlashCommandBuilder().setName('ping').setDescription('Risponde con pong!'),
	new SlashCommandBuilder().setName('server').setDescription('Risponde con le informazioni sul server!'),
	new SlashCommandBuilder().setName('user').setDescription('Risponde con le informazioni sull\'utente!'),
]
	.map(command => command.toJSON());

const rest = new REST({ version: '10' }).setToken(token);

rest.put(Routes.applicationGuildCommands(clientId, guildId), { body: commands })
	.then(() => console.log('I comandi sono stati registrati con successo.'))
	.catch(console.error);

Una volta aver modificato il file secondo le proprie esigenze, possiamo eseguirlo con il comando node registra-comandi.js all'interno della directory del nostro progetto. I comandi verranno così registrati all'interno del server che abbiamo specificato, tieni presente che puoi anche registrare i comandi globalmente.

Questo file deve essere eseguito solamente una volta, puoi eseguirlo nuovamente solo se hai aggiunto dei comandi o modificato quelli esistenti.

Rispondere agli Slash Commands

Una volta aver registrato gli slash commands, possiamo intercettare le interazioni con l'evento interactionCreate all'interno del file index.js.

Come prima cosa controlliamo se l'interazione è un comando utilizzando isChatInputCommand() e poi controlliamo la proprietà commandName per sapere che comando è stato eseguito. Infine, possiamo rispondere ad un'interazione con il metodo reply().

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

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

	const { commandName } = interaction;

	if (commandName === 'ping') {
		await interaction.reply('Pong!');
	} else if (commandName === 'server') {
		await interaction.reply('Informazioni sul server.');
	} else if (commandName === 'user') {
		await interaction.reply('Informazioni sull\'utente.');
	}
});

client.login(token);

Comando Informazioni Server

Tieni presente che all'interno dell'API di Discord i server sono chiamati "guilds", letteralmente gilda. Nel codice interaction.guild fa riferimento al server in cui è stata inviata l'interazione (un'istanza di Guild), che ci mette a disposizione varie proprietà, come .name per ottenere il nome del server, oppure .memberCount per sapere quanti membri sono all'interno del server.

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

	const { commandName } = interaction;

	if (commandName === 'ping') {
		await interaction.reply('Pong!');
	} else if (commandName === 'server') {
		await interaction.reply(`Nome del server: ${interaction.guild.name}\nUtenti totali: ${interaction.guild.memberCount}`);
	} else if (commandName === 'user') {
		await interaction.reply('Informazioni sull\'utente.');
	}
});

Potremmo anche stampare la data in cui è stato creato il server utilizzando .createdAt, oppure il livello di verifica del server con .verificationLevel. Molte altre informazioni sono ottenibili con i metodi e le proprietà illustrate all'interno della documentazione della classe Guild.

Comando Informazioni Utente

Nell'API user fa riferimento a un'utente di Discord. Utilizzando interaction.user facciamo riferimento all'utente che ha eseguito l'interazione (un'istanza di User), che ci mette a disposizione varie proprietà, tra cui .tag oppure .id.

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

	const { commandName } = interaction;

	if (commandName === 'ping') {
		await interaction.reply('Pong!');
	} else if (commandName === 'server') {
		await interaction.reply(`Nome del server: ${interaction.guild.name}\nUtenti totali: ${interaction.guild.memberCount}`);
	} else if (commandName === 'user') {
		await interaction.reply(`Il tuo tag: ${interaction.user.tag}\nIl tuo id: ${interaction.user.id}`);
	}
});

Puoi fare riferimento alla classe User sulla documentazione di discord.js per esplorare tutti i metodi e tutte le proprietà disponibili per l'utente.

Il problema con gli if ed else

Se non abbiamo in programma di aggiungere molti comandi al nostro bot, utilizzare una catena di if ed else/if va più che bene. Tuttavia, aggiungendo sempre più comandi di complessità crescente, lavorare tra tutti gli if ed else diventa molto complesso.

Ecco alcuni motivi per cui non si dovrebbe usare questo sistema per gestire i comandi:

  • Impiego di molto tempo per trovare una sezione specifica del codice;
  • Diventa molto semplice scrivere spaghetti code;
  • È difficile mantenere il codice mentre cresce;
  • Difficile fare debugging;
  • Difficile organizzare il codice;
  • Non è una buona pratica da seguire.

Nella prossima lezione della guida vedremo come realizzare quello che viene chiamato "command handler", ovvero "gestore dei comandi". Questo ci consentirà di gestire i comandi in modo molto più semplice e soprattutto efficiente, avendo anche ogni comando in un file isolato.