Discord Bot#3 Cog

Cog簡介

  • 將我們所有的指令整理成一個一個的物件
  • 將這些指令做成物件後,我們的機器人本體(bot.py)就只需要負責載入或移除這些物件
  • 完成之後,我們就可以更方便地去DEBUG囉!

Cog實作

幫你的指令及事件搬家

  1. 在bot.py的所在的資料夾中,開一個資料夾Cog

  2. 在Cog資料夾底下新增 event.py image.py main.py 三個檔案

  3. 打開main檔案,開始把指令搬家囉

  4. 先打出這個基本的Cog結構

  • class Main(command.Cog): 一個叫做 Main 的物件,它擁有 command.Cog 的特性,裡面會存放各種你想放的指令以及事件
  • __ init __(self, bot):生成 Main 這個物件的時候會呼叫的 function, 這裡的用意是想讓Main這個物件也可以讀取到bot.py裡的 Bot物件
  • def setup(bot): 這個函式會在每次載入Main這個Cog的時候執行,讓bot.py裡的機器人載入Cog
import discord from discord.ext import commands class Main(commands.Cog): def __init__(self, bot): self.bot = bot def setup(bot): bot.add_cog(Main(bot))
  1. 將 ping 和 purge 兩個指令剪下貼上到class Main裡面

  2. 修改 ping 和 purge 指令

Note: 直接寫在 bot.py和寫成Cog主要有兩個不同,第一是修飾器,第二個則是 function的參數一定要有self,Cog因為是一個class,所以每個function的第一個參數都必須是self

  • 修飾器比較
command event
bot.py @bot.command() @bot.event
Cog @commands.command() @commands.Cog.listener()
  • Main.py (記得bot也要改成self.bot喔)
import discord from discord.ext import commands class Main(commands.Cog): def __init__(self, bot): self.bot = bot @commands.command() async def ping(self, ctx): await ctx.send(self.bot.latency) @commands.command() async def purge(self, ctx, num=1): deleted = await ctx.channel.purge(limit=num+1) await ctx.send(f'{len(deleted)} messages deleted!') def load(bot): bot.add_cog(Main(bot))
  1. 接著把傳送圖片相關的指令搬到 image.py,注意這裡也會需要另外import random和json兩個module,且在程式一開始也需要讀取json檔案
import discord from discord.ext import commands import random import json with open('setting.json', 'r', encoding='utf8') as jsonFile: setting = json.load(jsonFile) class Image(commands.Cog): def __init__(self, bot): self.bot = bot @commands.command() async def image(self, ctx): dcFile = discord.File(random.choice(setting['image'])) await ctx.send(file=dcFile) @commands.command() async def webimage(self, ctx): await ctx.send(random.choice(setting['webimage'])) def setup(bot): bot.add_cog(Image(bot))
  1. 最後是 event.py,我們需要把on_member_join,on_member_remove,on_message三個指令搬至 event.py

Note: 由於這個Cog全部都是event,修飾器是用@commands.Cog.listener(),而不是之前的@commands.command()

import discord from discord.ext import commands import json with open('setting.json', 'r', encoding='utf8') as jsonFile: setting = json.load(jsonFile) class Event(commands.Cog): def __init__(self, bot): self.bot = bot @commands.Cog.listener() async def on_member_join(self, member): ch = self.bot.get_channel(int(setting['channel_id'])) await ch.send(f'{member} Ya hello') @commands.Cog.listener() async def on_member_remove(self, member): ch = self.bot.get_channel(int(setting['channel_id'])) await ch.send(f'{member} Bye bye') @commands.Cog.listener() async def on_message(self, msg): if 'Yo' in msg.content and msg.author != self.bot.user: await msg.channel.send('Yo') await self.bot.process_commands(msg) def setup(bot): bot.add_cog(Event(bot))

在bot.py中使用Cog

  • 在bot.py的run前面加入下列程式碼,它會找到Cog資料夾中所有的py檔案,並用load_extension載入這些cog,記得在檔案開頭加入 from pathlib import Path

Note: 這裡的load功能其實就有點像是程式開頭的from import

for cog in [p.stem for p in Path(".").glob("./Cog/*.py")]: bot.load_extension(f'Cog.{cog}') print(f'Loaded {cog}.') print('Done.')

實用的Debug函式

  • load
@bot.command() async def load(ctx, ext): bot.load_extension(f'Cog.{ext}') await ctx.send(f'{ext} loaded successfully.')
  • unload
@bot.command() async def unload(ctx, ext): bot.unload_extension(f'Cog.{ext}') await ctx.send(f'{ext} unloaded successfully.')
  • reload (DEBUG神器)
@bot.command() async def reload(ctx, ext): bot.reload_extension(f'Cog.{ext}') await ctx.send(f'{ext} reloaded successfully.')

小小指令報錯功能

  • 我們可以直接使用內建的 on_command_error 事件,幫助我們把這些錯誤訊息傳送至頻道

  • 示意圖

@commands.Cog.listener() async def on_command_error(self, ctx, err): await ctx.send(err)

一些自學資源

Proladon - Code a Discord bot
彭彭 - Python 入門課程