이전 글에서 만든 discord.js
파일에 아래와 같이 추가해준다
// discord.js
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('Server info.');
} else if (commandName === 'user') {
await interaction.reply('User info.');
}
});
isChatInputCommand()
= 채팅 입력된게 상호작용을 뜻하는것인지 확인하는 함수
commandName
= 명령을 입력하면 해당 변수로 값이 들어오게된다
reply
= 명령에 응답하는 함수
다시 재실행을 한 후 디스코드에서 /ping
/server
/user
명령어를 입력하면 아래와 같이 나오게 된다
위와같이 if문으로 수많은 명령에 대한 분기처리를 하게되면 점점 봇의 역할이 늘어갈수록 소스를 읽기 힘든 스파게티코드가 될 것이다. 때문에 명령어를 파일로 분리할 것이다. (디스코드에서도 적극 권장)
아래는 기본적으로 사용할 파일들
// deploy-commands.js
const { REST, Routes } = require('discord.js');
const { clientId, guildId, token } = require('./config.json');
const commands = [];
const rest = new REST({ version: '10' }).setToken(token);
rest.put(Routes.applicationGuildCommands(clientId, guildId), { body: commands })
.then(data => console.log(`Successfully registered ${data.length} application commands.`))
.catch(console.error);
// discord.js
// Require the necessary discord.js classes
const { Client, GatewayIntentBits } = require('discord.js');
const token = process.env.DISCORD_BOT_TOKEN;
// Create a new client instance
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
// When the client is ready, run this code (only once)
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('Server info.');
} else if (commandName === 'user') {
await interaction.reply('User info.');
}
});
client.login(token);
그럼 현재 필자의 디렉토리 구조는 다음과 같다
discord-bot
├──`commands`
│ └── `ping.js`
├── node_modules
├── .env (config.json 대신)
├── deploy-commands.js
├── serverSides
│ └──routes
│ └──api
│ ├──discord.js
│ └──index.js
├── index.js
├── package-lock.json
└── package.json
그후 위에서 언급한 if 문으로 명령어를 분기처리하는 것이 아닌 명령어를 파일별로 분기처리를 할 것이기때문에 /commands/ping.js 파일을 테스트용으로 만들어준다.
// ping.js
const { SlashCommandBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('ping')
.setDescription('Replies with Pong!'),
async execute(interaction) {
await interaction.reply('Pong!');
},
};
그후 discord.js 파일에서 명령파일을 동적으로 검색 할 수 있게 다음과 같이 추가해준다
// discord.js
const { Client, GatewayIntentBits, Collection } = require('discord.js');
const fs = require('node:fs');
const path = require('node:path');
client.commands = new Collection();
const commandsPath = path.join(__dirname, '../../../commands');
const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js')); //
commandFiles.map(file => {
const filePath = path.join(commandsPath, file);
const command = require(filePath);
console.log("command list : ", command?.data?.name);
client.commands.set(command.data.name, command);
});
deploy-commands.js 파일도 위와같이 수정이 필요하다
// deploy-commands.js
const token = process.env.DISCORD_BOT_TOKEN;
const clientId = process.env.CLIENT_ID;
const guildId = process.env.GUILD_ID;
const commands = [];
const commandsPath = path.join(__dirname, './commands');
const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js'));
commandFiles.map(file => {
const filePath = path.join(commandsPath, file);
const command = require(filePath);
console.log("deploy-commands file command name : ", command?.data?.name);
commands.push(command.data.toJSON());
});
const rest = new REST({ version: '10' }).setToken(token);
rest.put(Routes.applicationGuildCommands(clientId, guildId), { body: commands })
.then(data => console.log(`Successfully registered ${data.length} application commands.`))
.catch(console.error);
맨처음 if 문으로 분기처리해줬던 discord.js 파일에 interactionCreate 를 다음과같이 바꿔준다
// discord.js
client.on('interactionCreate', async interaction => {
if (!interaction.isChatInputCommand()) return;
const command = interaction.client.commands.get(interaction.commandName);
if (!command) return;
try {
await command.execute(interaction);
} catch (error) {
console.error(error);
await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true });
}
});
이제 분기처리 구조를 바꿨는데 실행을 해보자!
$ node deploy-commands.js
$ node server.js
command list : ping
위와같이 command list 가 찍히면 정상적으로 해당 명령어를 불러오게 된것이다. (/server 명령어는 분기처리 해주면서 제거했기 때문에 현재는 ping 명령어만 먹힌다)
!!! 명령어 파일을 추가하게되면 node deploy-commands.js
를 꼭 실행시켜주자