Try   HackMD

這是一篇 Discord Bot 的進階教學文章,會教學如何將 Discord Bot 指令分門別類,以及如何在 Discord Bot 上線期間直接新增、移除、更新指令,讓 Discord Bot 未來能夠方便維護和擁有更好的可讀性。
如果還不了解 Discord Bot 的用途以及該如何創建一臺 Discord Bot 的讀者,建議可以參考這篇之前本作者撰寫的 Python Discord Bot 基礎教學

:book: 更多 Python Discord Bot 教學系列和程式範例
https://github.com/smallshawn95/Python-Discord-Bot-Teach.git



一、Cog 架構簡介:

為了要讓未來 Discord Bot 方便維護以及增加可讀性,將各個指令分門別類會是一個不錯的方法,而 Cog 就是能夠實現這功能的架構,Cog 可以將程式碼分門別類,讓主程式只要負責執行加載檔案和卸載檔案的動作。
基礎教學的內容中,最後有提到使用關鍵字的 on_message 和前綴指令 command 如果放在同一個檔案會無法運作的問題,而使用 Cog 架構就可以來解決這個問題。
更多資訊可參考 Discord.py Cog 官方文檔

Picture_1

二、Discord Bot Cog 架構介紹:

Picture_2

  • bot 主程式

    負責執行載入(load)、卸載(unload)、重新載入(reload)程式檔案,可以讓 Discord Bot 上線期間就能更改指令。
  • cogs 資料夾

    放置分類過後的程式檔案,利用檔名就能知道此檔案的用途,增加撰寫程式碼的效率。

三、Discord Bot Cog 主程式實作:

:bulb:小幫助
使用「前綴指令help(例:$help)」可以了解目前有哪些指令可以執行。
Picture_3

  • Load 載入

    通常使用於撰寫好新的程式檔案要上線,或者要將之前載出的程式檔案再次上線。
    執行語法:前綴符號load 檔案名稱(例:$load main)

    ​​@bot.command() ​​async def load(ctx, extension): ​​ await bot.load_extension(f"cogs.{extension}") ​​ await ctx.send(f"Loaded {extension} done.")
    • 載入成功會回傳訊息讓使用者知道
      Picture_4

    • main檔案載入成功
      Picture_5

  • UnLoad 卸載

    通常使用於程式檔案出 Bug 時,卸載來阻止其他使用者執行到錯誤指令。
    執行語法:前綴符號unload 檔案名稱(例:$unload main)

    ​​@bot.command() ​​async def unload(ctx, extension): ​​ await bot.unload_extension(f"cogs.{extension}") ​​ await ctx.send(f"UnLoaded {extension} done.")
    • 卸載成功會回傳訊息讓使用者知道
      Picture_6

    • main檔案卸載成功
      Picture_7

  • ReLoad 重新載入

    通常使用於更改過程式檔案要直接更新,或者 Debug 時的測試。
    執行語法:前綴符號reload 檔案名稱(例:$reload main)

    ​​@bot.command() ​​async def reload(ctx, extension): ​​ await bot.reload_extension(f"cogs.{extension}") ​​ await ctx.send(f"ReLoaded {extension} done.")
    • 重新載入成功會回傳訊息讓使用者知道
      Picture_8

    • main檔案重新載入成功
      Picture_9
      Picture_10

  • 完整程式碼

import os import asyncio import discord from discord.ext import commands intents = discord.Intents.all() bot = commands.Bot(command_prefix = "$", intents = intents) # 當機器人完成啟動時 @bot.event async def on_ready(): print(f"目前登入身份 --> {bot.user}") # 載入指令程式檔案 @bot.command() async def load(ctx, extension): await bot.load_extension(f"cogs.{extension}") await ctx.send(f"Loaded {extension} done.") # 卸載指令檔案 @bot.command() async def unload(ctx, extension): await bot.unload_extension(f"cogs.{extension}") await ctx.send(f"UnLoaded {extension} done.") # 重新載入程式檔案 @bot.command() async def reload(ctx, extension): await bot.reload_extension(f"cogs.{extension}") await ctx.send(f"ReLoaded {extension} done.") # 一開始bot開機需載入全部程式檔案 async def load_extensions(): for filename in os.listdir("./cogs"): if filename.endswith(".py"): await bot.load_extension(f"cogs.{filename[:-3]}") async def main(): async with bot: await load_extensions() await bot.start("機器人的TOKEN") # 確定執行此py檔才會執行 if __name__ == "__main__": asyncio.run(main())

四、Discord Bot Cog cogs 資料夾實作:

只需要注意幾個地方,就能將基礎教學中的程式碼搬過來使用,而且可以將關鍵字觸發和前綴指令共同放在同一個檔案中。

  1. @bot.event 要改成 @commands.Cog.listener()
  2. @bot.command() 要改成 @commands.command()
  3. class 的名稱跟檔名相同比較好管理,習慣會首字母大寫
  4. class 中使用到 bot 物件時,要改成 self.bot 才能使用
  5. 每個指令的第一個參數要是 self,否則程式碼會出錯
  • 主要程式碼結構

    ​​​​import discord ​​​​from discord.ext import commands ​​​​class Main(commands.Cog): ​​​​ def __init__(self, bot: commands.Bot): ​​​​ self.bot = bot ​​​​ ​​​​ ... ​​​​async def setup(bot): ​​​​ await bot.add_cog(Main(bot))
  • 範例程式碼

    ​​​​import discord ​​​​from discord.ext import commands ​​​​# 定義名為 Main 的 Cog ​​​​class Main(commands.Cog): ​​​​ def __init__(self, bot: commands.Bot): ​​​​ self.bot = bot ​​​​ # 前綴指令 ​​​​ @commands.command() ​​​​ async def Hello(self, ctx: commands.Context): ​​​​ await ctx.send("Hello, world!") ​​​​ # 關鍵字觸發 ​​​​ @commands.Cog.listener() ​​​​ async def on_message(self, message: discord.Message): ​​​​ if message.author == self.bot.user: ​​​​ return ​​​​ if message.content == "Hello": ​​​​ await message.channel.send("Hello, world!") ​​​​# Cog 載入 Bot 中 ​​​​async def setup(bot: commands.Bot): ​​​​ await bot.add_cog(Main(bot))

本次 Discord Bot 進階教學 — Cog 篇到此介紹完了,希望大家有成功將指令分門別類,並且可以線上載入、卸載、重新加載指令。
本次教學中較難懂的點可能是 class 那部分,需要已經具備 class 的知識才能了解實際的運作,而筆者也沒有特別詳細描述,那是因為程式的資料過於龐大,如果每行程式碼都要釐清實際運作過程將會寸步難行,所以我們只要看得懂這行大概要做什麼以及如何應用,這樣就足以完成我們的 Discord Bot。
感謝各位觀看完整篇的教學,下篇教學將會介紹目前 Discord 推薦 Bot 應該都要使用的斜線指令該如何撰寫,敬請期待下一篇教學。


📢 歡迎加入我的 Discord 伺服器
https://discord.gg/Jtd3eVrFJs

Copyright © 2023 SmallShawn95. All rights reserved.