Day21 - Discord 基礎

Discord 基礎

前言

在前一篇我們準備好了 Discord 基本的一些東西與設定,接下來當然要繼續聊 Discord 的部分囉~

Discord

前一篇我們分別認識了官方所提供的註冊指令到 Bot 的程式碼,以及登入 Discord Bot 的程式碼,但實際上來講就這樣嗎?不,其實還有很多東西可以講,就讓我們專注於 Discord Bot 的方便吧!

首先我們先看一下前一篇寫的程式碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// index.js
const { Client, Intents } = require('discord.js'); // 引入 discord.js 套件
// 實例化 Client
const client = new Client({
intents: [
Intents.FLAGS.GUILDS
]
});

// 當機器人準備好時
client.once('ready', () => {
console.log('Ready!');
});

// 登入機器人
client.login(TOKEN);

我們先專注於 const client = new Client({ ... }) 這裡面的物件

1
2
3
4
5
6
7
// ... 略過其他程式碼
const client = new Client({
intents: [
Intents.FLAGS.GUILDS
]
});
// ... 略過其他程式碼

Intents(意圖)

首先 const client = new Client({ ... }) 這行是在建立一個新的 Discord.js 物件,你可以想像它就像是一個接入 Discord API 的橋樑,讓我們可以透過程式碼去操作 Discord。

而裡面是傳入一些地方,先講講 intents 這個參數,這個參數非常的重要,會影響你的機器人可以做哪些事情。

問題來了,intents 主要是幹嘛的呢?簡單來說就是告知 Discord 我們會有哪些「意圖」,例如:我們的機器人會需要接收伺服器的訊息,那麼我們就需要告知 Discord 我們會需要接收伺服器的訊息,這樣 Discord 才會將伺服器的訊息傳送給我們的機器人。

這邊我先舉例一下我先前寫的程式碼:

1
2
3
4
5
6
7
8
9
const { Client, GatewayIntentBits } = require('discord.js');

const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
],
});

我們可以看到 intents 接收了一個陣列,裡面放了三個參數,這三個參數分別是:

  • GatewayIntentBits.Guilds:可以接收伺服器相關的事件,例如:使用者加入伺服器、使用者離開伺服器等等。
  • GatewayIntentBits.GuildMembers:可以接收伺服器內的聊天訊息事件,例如:使用者傳送訊息、使用者編輯訊息等等。
  • GatewayIntentBits.MessageContent:這個比較特別一點,這是在告知機器人我們需要接收訊息的內容,例如:使用者傳送的訊息內容、使用者編輯的訊息內容等等,這個跟前面的 GatewayIntentBits.GuildMembers 不同的地方在於,GatewayIntentBits.GuildMembers 只會告知我們使用者傳送了訊息,但不會告知我們訊息的內容,所以我們需要另外告知 Discord 我們需要接收訊息的內容。

當然不只有這些,還有…

  • GatewayIntentBits.GuildMessageReactions:可以接收伺服器內的反應事件,例如:使用者給予訊息反應、使用者移除訊息反應等等。
  • GatewayIntentBits.DirectMessages:可以接收私人訊息事件,例如:使用者傳送私人訊息、使用者編輯私人訊息等等。
  • GatewayIntentBits.DirectMessageReactions:可以接收私人訊息的反應事件,例如:使用者給予私人訊息反應、使用者移除私人訊息反應等等。
  • GatewayIntentBits.DirectMessageTyping:可以接收私人訊息的打字事件,例如:使用者正在打字、使用者停止打字等等。

當然這邊只列出一些而已,其他部分可以參考 Discord.js 官方文件

partials(部分)

partials 有一點特別,它也是 new Client 時會傳入的參數之一:

1
2
3
4
5
6
7
8
9
10
11
const { Client, GatewayIntentBits, Partials } = require('discord.js');
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
],
partials: [
Partials.Channel
],
});

partials 這個參數是用來告知 Discord 我們需要接收哪些「部分」的資料,例如:我們需要接收哪些訊息的內容、哪些訊息的反應等等。

那為什麼要特別設定這個呢?主要原因是因為 Discord 會將一些資料分成兩個部分,一個是完整的資料,另一個是部分的資料,例如:我們需要接收訊息的內容,但 Discord 會將訊息的內容分成兩個部分,一個是完整的訊息內容,另一個是部分的訊息內容,這樣就會造成我們無法取得完整的訊息內容,所以我們需要告知 Discord 我們需要接收完整的訊息內容。

那麼我們大致上了解了 Partials 的用途後,就先這樣繼續往下吧~有需要我們再來聊這個。

Discord 方法與事件

接下來我們就來聊聊 Discord 的方法與事件,這邊我們就先來看看 Discord 的方法吧!

我們在範例程式碼中,其實有看到 Client 實例化後,做了一些事情…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// index.js
const { Client, Intents } = require('discord.js'); // 引入 discord.js 套件
// 實例化 Client
const client = new Client({
// ... 略過其他程式碼
});

// 當機器人準備好時
client.once('ready', () => {
// ... 略過其他程式碼
});

// 登入機器人
client.login(TOKEN);

分別是…

  • once 註冊了一個事件,但這個事件只會觸發一次。
  • login 登入機器人,就是登入機器人的意思。

但實際上來講,方法不只有這些,詳細可以看 Discord.js 官方文件

但最常見的莫過於 ononce,這兩個方法都是用來註冊事件的,但 on 會持續監聽事件,而 once 則只會監聽一次事件。

講完這些方法後,接下來當然是要聊聊事件了,我們先來看看前面的程式碼:

1
2
3
client.once('ready', () => {
// ... 略過其他程式碼
});

這邊我們可以看到 once 監聽了一個事件,也就是 ready 事件,這個事件是在機器人準備好時觸發的,所以當機器人準備好時,就會觸發這個事件。

那麼 client.onclient.once 哪裡來的呢?如果你有去翻 Discord.js 官方文件,你會發現你只找得到 client.login 這個方法,但沒有 client.onclient.once 這兩個方法,那這兩個方法是哪裡來的呢?

其實主要是來自 EventEmitter 這個類別,EventEmitter 這個類別是 Node.js 內建的類別,而 Client 這個類別繼承了 EventEmitter 這個類別,所以我們才可以使用 client.onclient.once 這兩個方法,你可以在這邊 EventEmitter 看到。

那麼 onceon 裡面的事件除了 ready 之外,還有哪些呢?其實非常的多,而且上面寫法也不是唯一的寫法,你可以這樣寫:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const {
Client,
GatewayIntentBits,
Partials,
Events,
} = require('discord.js');

const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
],
partials: [
Partials.Channel,
],
});

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

client.login(TOKEN);

這邊我們可以看到 once 裡面的事件變成了 Events.ClientReady,這是因為 Events 這個物件是 Discord.js 提供的,裡面包含了所有的事件,你可以在這邊 Events 看到。

那寫字串跟使用 Events 有什麼差嗎?其實我認為沒差很多,只是差別在於你可以直接透過 Events 下拉選單,就可以看到所有的事件,而不用去翻文件,這樣比較方便而已

下拉選單

實際上 Events 也是傳入相對應的字串而已,底下是我翻出來的原始碼:

1
2
3
4
5
6
7
export enum Events {
ClientReady = 'ready',
MessageCreate = 'messageCreate',
MessageDelete = 'messageDelete',
MessageUpdate = 'messageUpdate',
// ... 略過其他程式碼
}

所以不論你寫…

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

或是…

1
2
3
client.once(Events.ClientReady, () => {
console.log('Ready!');
});

兩者都是相同的結果,只是一個不用特別去查文件,直接下拉就可以選。

接下來我們先來寫一點小東西好了,我們來試著寫監聽訊息的事件,然後輸出到終端機上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// index.js
const {
Client,
GatewayIntentBits,
Partials,
Events,
} = require('discord.js');

const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
],
partials: [
Partials.Channel,
],
});

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

// 監聽訊息事件,請使用 on 作為持續監聽事件
client.on(Events.MessageCreate, (message) => {
console.log('[有人說:」',message.content);
});

client.login(TOKEN);

接著透過 node index.js 啟動後,你在頻道上發送一個訊息就可以看到終端機上輸出了,如下圖:

MessageCreate

很簡單吧?那我們這一篇也先到這邊結束好了,我們下一篇繼續聊 Discord 的部分。