Ресурсов для создания ботов Discord очень мало. Кроме того, функциональные возможности Discord постоянно изменяются или добавляются, что удерживает пользователей от создания забавных или полезных ботов для себя и своих сообществ. Как текущий разработчик бота Discord, управляющий ботом, базой данных и сотнями пользователей, я составил руководство, содержащее основы, а также несколько советов из моего собственного опыта. Это руководство поможет вам создать бота Discord с нуля с помощью discord.py.

Начало работы:

ПРИМЕЧАНИЕ. для этого потребуется наличие подтвержденной учетной записи Discord, а также двухфакторная аутентификация с помощью Google Authenticator.

  • Нажмите «Новое приложение» в правом верхнем углу, дайте своему боту имя и согласитесь с Условиями использования для разработчиков.

Поздравляю! Вы создали своего первого бота! Теперь давайте пригласим его в гильдию и дадим ему функциональность!

Приглашение вашего бота:

  • Нажмите «OAuth2» в левом столбце и выберите «Генератор URL» из дополнительных параметров.

  • Хотя это меню может показаться громоздким, настройка довольно проста! В разделе «scopes» просто отметьте «bot». В этом руководстве используется новый API взаимодействий и встроенные команды косой черты. Чтобы включить их, также проверьте «applications.commands».

  • «Разрешения для ботов» зависят от вас! Я лично даю своему боту административный контроль, потому что ему нужны почти все опции для правильной работы. Однако, если вы не планируете использовать все функции Discord, проверьте только то, что, по вашему мнению, потребуется для вашей функциональности.
  • Скопируйте/вставьте сгенерированный URL внизу страницы и откройте его в своем браузере! Выберите гильдию, в которую вы хотите ее пригласить, а затем разрешите ей присоединиться!
    ПРИМЕЧАНИЕ. Вы также можете сохранить это для будущих приглашений.

Стратегия программирования:

Хотя в этом руководстве используется discord.py, существует множество способов кодирования ботов Discord. Вы можете кодировать все вручную с помощью вызовов API или использовать существующие простые в использовании библиотеки. Две основные библиотеки:

Предварительные условия [discord.py]:

  • Установить Питон
  • Установите IDE и настройте ее для Python. Я лично использую Visual Studio Code
  • Установите discord.py с помощью PIP:
#Linux/macOS:
python3 -m pip install -U discord.py
#Windows:
py -3 -m pip install -U discord.py

АЛЬТЕРНАТИВНЫЙ ВАРИАНТ [Включает голосовую поддержку]:

#Linux/macOS:
python3 -m pip install -U "discord.py[voice]"
#Windows:
py -3 -m pip install -U discord.py[voice]
  • Создайте новый файл: yourBotName.py (или предпочитаемое вами соглашение об именах).

Теперь пришло время заняться программированием!

Прохождение кода:

Для начала вам сначала нужно импортировать необходимые библиотеки и классы:

import discord, discord.utils
from discord import app_commands

Намерения:
Discord использует «намерения», которые в основном представляют собой разрешения для ботов, которые, возможно, потребуется включить в зависимости от того, что вы делаете. Вот несколько примеров наиболее распространенных:

#INTENTS 
intents = discord.Intents.all() #Grabs default intents 
intents.members = True #Changes member visibility intent (allows the bot to “see” members)
intents.presences = True #Changes presence intent (allows you to set a custom bot presence)

Бот как класс
Хотя это и не обязательно, может быть полезно сделать вашего бота Discord объектом. Вы даже можете использовать иерархию объектов, но базовая реализация класса бота может выглядеть так:

#BOT CLASS
class bot(discord.Client):
  def __init__(self): 
    super().__init__(intents = intents) #Set the bot’s intents
    self.synced = False #Default synced value

  async def on_ready(self): #Bot on_ready function 
    await self.wait_until_ready() #Wait until the bot is ready.
    if not self.synced:
      await tree.sync(guild = discord.Object(id = your_guild_id)) #EXPLANATION BELOW
      self.synced = True #Update synced variable
    self.change_presence(status = discord.Status.online, activity = discord.Game(your_status_message_here)) #Sets custom activity status 
    print("your_bot_name_here is Ready.") #Prints ready message

Типы синхронизации:
Вы заметите, что я указываю одну гильдию в вызове функции tree.sync. Это очень важно для целей тестирования. Discord позволяет запускать либо глобальную синхронизацию, либо отдельную синхронизацию (синхронизируется с одной гильдией). Запуск глобальной синхронизации может занять час или два, прежде чем ее можно будет использовать. При кодировании/тестировании используйте одну гильдию, а при развертывании просто используйте:

await tree.sync()

CommandTree:
Далее вам нужно создать объект бота, а также CommandTree для него:

bot = bot() #Initialize a bot object
tree = app_commands.CommandTree(bot) #Initialize a CommandTree

Токен и выполнение.
Наконец, получите свой токен и используйте его для запуска бота.
ПРИМЕЧАНИЕ. Вам нужно перейти в раздел «Бот » в левой колонке веб-портала и нажмите «Сбросить токен». Это токен, который свяжет ваш код с ботом Discord. Не делитесь этим ни с кем!

#RUN YOUR BOT
bot.run(your_token_here)

Поздравляем! У вас есть работающий бот! Теперь я объясню, как реализовать некоторые базовые функции!

Важная информация:

Прежде чем я перейду к особенностям «забавного» кода, важно понять, как работают боты Discord. Вот некоторые вещи, которые вы должны знать и/или учитывать, прежде чем добавлять функции в своего бота.

События:
серверы Discord (которые будут перенаправлять на ваш код) прослушивают «события». События — это триггеры, которые заставляют бота каким-то образом реагировать. Хотя их много, наиболее распространенными триггерами, на которые реагируют боты, являются следующие:

  • Участник, отправляющий сообщение
  • Член, вызывающий команду косой черты
  • Ваш бот вступает в новую гильдию

Каждый из этих триггеров запрограммирован по-разному. Для каждого из вышеперечисленных случаев используются следующие декораторы функций и сигнатуры:

#ON MESSAGE EVENTS
@bot.event
async def on_message(message: discord.Message):
    ...your functionality here

#SLASH COMMAND EVENTS
@tree.command(description = "This is a command description!")
async def command_name(interaction: discord.Interaction):
    ...your functionality here

#BOT JOINING NEW GUILD EVENTS
@bot.event
async def on_guild_join(guild: discord.Guild):
    ...your functionality here

Структура кода:
Имейте в виду, есть только по одной функции on_message и on_guild_join. Команды косой черты будут иметь одну функцию для каждой команды или подкоманды. Это будет зависеть от вас, чтобы реализовать так, как вы хотите.

Хранение данных.
Важно учитывать необходимость хранения данных пользователя или бота и то, как вы можете это сделать. Чтение и запись в текстовые файлы являются опцией, словари облегчат эту задачу. Но проблемы возникнут с требованиями к параллелизму и скорости, если вы масштабируете бота для обработки большего количества пользователей и гильдий.

Самое простое решение — использовать постоянно работающую базу данных. Это может быть размещено с помощью стороннего сервиса или вы можете разместить его самостоятельно на энергоэффективном устройстве, таком как Raspberry Pi или ноутбуке. Существует множество типов баз данных и разновидностей SQL, которые используются в каждой из них. Для собственного производства я использовал Raspberry Pi с MariaDB (облегченный форк MySQL). Это, опять же, зависит от вас, если вам нужно хранить большие объемы данных для вашего бота.

Слеш-команды:

Теперь, когда вы обдумали, как вы хотите вызывать свою функциональность и где хранить потенциальные результаты, позвольте мне объяснить, как работают слеш-команды.

Команды косой черты используют декоратор your_tree_name.command() над декораторами необязательных разрешений, а затем имеют подпись в формате:

#BASIC SIGNATURE
async def command_name(interaction: discord.Interaction, parameters...):

Параметры:
при необходимости вы можете включить дополнительные параметры, которые необходимо указать, когда пользователь вызывает команду. Примитивные типы данных говорят сами за себя, но одной из основных функций, по которой я изо всех сил пытался найти документацию, были списки параметров, из которых можно выбирать. Вот несколько примеров распространенных реализаций, которые могут вам понадобиться:

#SIGNATURE WITH SPECIFIC EXAMPLES
async def command_name(interaction: discord.Interaction, role: Optional[discord.Role], member: Optional[discord.Member], mode: Literal["Hello", "World"]):

В приведенном выше примере я включил синтаксис для использования опций, выбора ролей и участников и литеральных списков. Существуют и другие классы разногласий, которые вы можете использовать в панелях выбора. Я надеюсь, что этот фрагмент кода будет полезен!

Разрешения [Необязательно]:
Дополнительные декораторы разрешений позволяют вам ограничить, кто может запускать команду. Аргумент должен принимать значение True, чтобы проверка app_command продолжила выполнение. Пример, который я взял с официального сайта discord.py, приведен ниже:

#LAMBDA EVALUATION FUNCTION
def check_if_it_is_me(interaction: discord.Interaction) -> bool:
    return interaction.user.id == 85309593344815104 #Checks user id of invoker against a constant user id

#SLASH COMMAND
@tree.command()
@app_commands.check(check_if_it_is_me) #Variable or called function must be true for command to execute
async def only_for_me(interaction: discord.Interaction):
    await interaction.response.send_message('I know you!', ephemeral = True) #Sends ephemeral response

Ответы:
Важно, чтобы вы всегда включали discord.Interaction в качестве первого параметра, а также понимали, как работают Discord Interactions. Взаимодействия требуют «ответа». Поэтому в какой-то момент в команде вам нужно будет включить ответ на сообщение. Ответ может быть отправлен либо сразу, если ваша команда быстрая, либо, если требуется время на обработку, вам может потребоваться отложить ответ и отреагировать на него позже:

#STANDARD RESPONSE
await interaction.response.send_message("I'm a response")

#DELAYED RESPONSE
await interaction.response.defer() #Defers response
await interaction.followup.send("I'm a response") #Follows up with a deferred response

В любом случае бот ответит сообщением после выполнения команды. Ответы обычно должны быть эфемерными (отправляться в виде синего сообщения, которое может видеть только исполнитель). Вы можете просто добавить эфемерный аргумент после вашей строки в функциях send или send_message.

Заканчивать:

Теперь вы добавили команду и готовы запустить/протестировать своего бота! Поздравляю! Если у вас есть дополнительные вопросы, лучше всего начать с Справочника Interactions API; затем онлайн-форумы. Если у вас есть какие-либо дополнительные предложения для будущих статей или правок, дайте мне знать!

Вот несколько общих советов по разработке ботов, основанных на моем опыте разработки:

  • Создание второго приложения на портале разработчиков Discord может позволить вам запускать производственный код в одном приложении и одновременно запускать частную сборку в другом. Это необходимо, если вы не хотите, чтобы приложение простояло при разработке.
  • Может быть полезно использовать инструмент разработки для переключения между рабочими и тестовыми экземплярами вашего бота.
  • Базы данных MySQL проще использовать с помощью MySQL Python Connector, хотя вам все равно может понадобиться собственный контроллер SQL или множество служебных функций.
  • Рефакторинг и переработка кода, а также создание дополнительных файлов чрезвычайно важны, поскольку проекты могут быстро расти! Бот, который я все еще разрабатываю, приближается к 2000 строк кода!

Завершенный код:

import discord, discord.utils
from discord import app_commands

#INTENTS
intents = discord.Intents.all() #Grabs default intents 
intents.members = True #Changes member visibility intent (allows the bot to "see" members)
intents.presences = True #Changes presence intent (allows you to set a custom bot presence)

#BOT CLASS
class bot(discord.Client): #Bot class
  def __init__(self): 
    super().__init__(intents = intents) #Set the bot's intents
    self.synced = False #Default synced value

  async def on_ready(self): #Bot on_ready function 
    await self.wait_until_ready() #Wait until the bot is ready.
    if not self.synced:
      await tree.sync(guild = discord.Object(id = your_guild_id)) #EXPLANATION BELOW
      self.synced = True #Update synced variable
    self.change_presence(status = discord.Status.online, activity = discord.Game(your_status_message_here)) #Sets custom activity status 
    print("your_bot_name_here is Ready.") #Prints ready message

#ON MESSAGE EVENTS
@bot.event
async def on_message(message: discord.Message):
    ...your functionality here

#SLASH COMMAND EVENTS
@tree.command(description = "This is a command description!")
async def command_name(interaction: discord.Interaction):
    await interaction.response.send_message("I'm a response")

#SLASH COMMAND EVENTS
@tree.command(description = "This is second command's description!")
@app_commands.check(check_if_it_is_me) #Variable or called function must be true for command to execute
async def second_command_name(interaction: discord.Interaction):
    await interaction.response.send_message('I know you!', ephemeral = True) #Sends ephemeral response

#BOT JOINING NEW GUILD EVENTS
@bot.event
async def on_guild_join(guild: discord.Guild):
    ...your functionality here

#LAMBDA EVALUATION FUNCTION
def check_if_it_is_me(interaction: discord.Interaction) -> bool:
    return interaction.user.id == 85309593344815104 #Checks user id of invoker against a constant user id

#INITIALIZATION
bot = bot() #Initialize a bot object
tree = app_commands.CommandTree(bot) #Initialize a CommandTree

#RUN YOUR BOT
bot.run(your_token_here)

Я надеюсь, что вы нашли эту статью краткой и информативной! Спасибо за чтение и удачи в развитии!