안녕하세요! RyuWoong 입니다.
이번에는 간단한 명령어를 생성하고 실행하도록 해보겠습니다.
Discord.js Tutorial의 내용입니다. 그럼 시작해볼까요?
Quick Start.
앞서 disocrdBot 폴더 내에 프로젝트를 생성하셨다면,
discordBot 폴더 내에 index.js라는 파일을 생성하고 아래와 같이 입력합니다.
//index.js
const { Client, Events, GatewayIntentBits } = require('discord.js');
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
client.once(Events.ClientReady, (c) => {
console.log(`Ready! Logged in as ${c.user.tag}`);
});
client.login(TOKEN);
// TOKEN은 아까 Application에서 Refresh Token하여 얻은 값을 넣어줍시다.
// 예 ) '12dfjkldj201213'
그리고 Package.json 파일을 열어서 license 아래에 아래와 같이 추가해 줍니다.
//package.json
...
"scripts": {
"start": "node index.js"
}
...
그리고 터미널을 열어 봇을 온라인해봅시다!
npm start
// 또는
yarn start
터미널에 Logged in as ${client.user.tag}! 가 올바로 출력되고, Discord에서 봇 상태가 온라인으로 변경되었다면, 성공적으로 봇을 실행한 것입니다. 그럼 이제 명령어를 추가해봅시다
Slash Command.
Discord는 Slash Command라는 새로운 개념을 도입했습니다.
과거에 prefix를 설정하고 메세지를 읽어 명령어가 실행되는 것은 old Command로 좋은 예제가 아니라고 합니다.
Slash Command를 사용했을 때 장점은 아래와 같습니다.
- ephemeral messages
- search
- localization
- autocomplete
- modals
- no ping required for mention
- masked links in responses
- option types
- option validation
- no triggering multiple bots
- easily accessible descriptions
- slash command mentions
- good UI
- built-in permissions system
- officially supported and updated by Discord
- no gateway intents required
- performance
- slash commands list
- help command is not needed (because commands are shown in slash commands list)
- option resolving (gives member, user, role, channel objects if mentioned, even when using id)
- no gateway events required (http interactions)
- disable/enable in dms easily
Discord.js Discord Sever에서 발췌한 내용입니다.
더이상 우리는 !help와 같은 명령어를 사용하지 않아도 됩니다. 왜냐하면 Slash Command에서는 명령어와 명령어 설명을 함께 입력하여 명령어를 생성하고, 그 명령어를 배포 하여 Discord에서 명령어 리스트를 보여줄 수 있는 과정이 있기 때문입니다.
명령어 추가하기.
자! 그럼 명령어를 추가해봅시다.
프로젝트 내에 commands라는 폴더를 만들어주세요.
왜 만드는지는 차차 설명 드리겠습니다. 그리고 commands 폴더 안에, ping.js라는 파일을 만들겠습니다.
// commands/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!');
},
};
이렇게 우리는 SlashCommand를 만들었습니다. 명령어 이름은 ping이고 명령어를 동작하면 Pong을 답변해주는 명령어입니다.
그리고 다시 index.js 파일을 열어 아래 코드를 삽입해주겠습니다.
// index.js
const fs = require('node:fs'); // <--add
const path = require('node:path'); // <--add
const { Client, Events, GatewayIntentBits } = require('discord.js');
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
client.commands = new Collection(); // <--add
const commandsPath = path.join(__dirname, 'commands'); // <--add
const commandFiles = fs.readdirSync(commandsPath).filter((file) => file.endsWith('.js')); // <--add
// add under block
for (const file of commandFiles) {
const filePath = path.join(commandsPath, file);
const command = require(filePath);
// Set a new item in the Collection with the key as the command name and the value as the exported module
if ('data' in command && 'execute' in command) {
client.commands.set(command.data.name, command);
} else {
console.log(`[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`);
}
}
...
방금 작성한 코드는 명령어 배열을 봇에게 등록하는 코드입니다.
명령어를 index.js에 쭉 나열해서 추가할 수도 있겠지만, 그럼 구분하기도 어렵고 수정도 어렵겠죠?
그래서 명령어는 commands 폴더에서만 새로 만들어서 작성하고, 그 파일들을 읽어들여서 명령어로 만듭니다.
이벤트 추가하기.
자! 그러면 명령어가 들어 왔을 때 봇이 인식할 수 있도록 이벤트를 추가해 주겠습니다.
for문 아래 이어서 작성해주시면 됩니다.
// index.js
...
client.on(Events.InteractionCreate, async (interaction) => {
if (!interaction.isChatInputCommand()) return;
const command = interaction.client.commands.get(interaction.commandName);
if (!command) {
console.error(`No command matching ${interaction.commandName} was found.`);
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 });
}
});
...
Slash Commands는 모두 Interaction입니다. 따라서 우리는 Interaction Event를 달아줍니다.
만약 Interaction이 들어오면, 우리는 이전에 작성한 Command 배열 내에 일치하는 Command Name을 찾아 명령을 실행해줍니다.
명령어가 없다면 무시되고, 오류가 생겼다면 오류가 생겼다고 답글을 달아주게 작성 되어있습니다.
명령어 배포하기.
Slash Commands를 소개할 때 말씀드렸었죠? 배포 하는 과정이 있다고, 배포를 하지 않으면 discord는 이 Bot이 어떤 명령어를 가지고 있는지 알 수 없기 때문에 Slash Command가 동작하지 않습니다. 따라서 우리는 Command가 뭐가 있는지 discord에 알려줘야 합니다.
// index.js
...
const commands = []; // <-- add
for (const file of commandFiles) {
const filePath = path.join(commandsPath, file);
const command = require(filePath);
commands.push(command.data.toJSON()); // <-- add
// Set a new item in the Collection with the key as the command name and the value as the exported module
if ('data' in command && 'execute' in command) {
client.commands.set(command.data.name, command);
} else {
console.log(`[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`);
}
}
const rest = new REST({ version: '10' }).setToken('token'); // <-- add
// and deploy your commands!
// add under block
(async () => {
try {
console.log(`Started refreshing ${commands.length} application (/) commands.`);
// The put method is used to fully refresh all commands in the guild with the current set
const data = await rest.put(Routes.applicationGuildCommands('ApplicationID', 'GuildID'), {
body: commands,
});
console.log(`Successfully reloaded ${data.length} application (/) commands.`);
} catch (error) {
// And of course, make sure you catch and log any errors!
console.error(error);
}
})();
...
코드에서 add 부분들을 추가해주세요.
이 코드는 서버가 실행 됐을 때 읽어들인 Commands들을 특정 서버에 배포해주는 역할을 합니다.
따라서 rest 코드의 token , await rest.put(Routes.applicationGuildCommands('ApplicationID', 'GuildID'), { body: commands }); 코드 내 ApplicationID(봇 ApplicationID)와 GuildID(서버 ID)를 알맞게 넣어주세요.
다 넣으셨으면 다시 npm start를 입력하여 Bot을 실행시켜줍시다.
본인이 GuildID로 넣은 서버에 봇이 있는지 확인 하신후 /ping 명령어를 입력해봅시다.
아마 disocrd에서 자동으로 해당 봇이 이 명령어가 있다고 알려줄겁니다! 신기하죠?
명령어를 입력하면 봇은 Pong!하고 답글을 달아줍니다.
마무리.
어때요? 그리 어렵지 않죠?
그 외에도 다양한 이벤트와 방법이 무궁무진합니다. 특히 SlashCommand는 이전에 help 명령어 입력할 일 없이 조금 더 직관적일 수도 있다는 생각이 드네요. 그럼 다음에는 또 다른 재밌는 기술로 찾아 뵙겠습니다.
'Project > Make a Discord Bot with JS' 카테고리의 다른 글
[discord.js] 자바스크립트로 디스코드 봇 만들기 - 시작하기 앞서 .00 (0) | 2023.02.09 |
---|
삽질의 기록과 일상을 남기는 블로그입니다. 주로 React Native를 다룹니다.
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!