Discord.gd

repository·main·Indexed 41 days ago

https://github.com/3ddelano/discord.gd

A 100% GDScript Godot plugin for creating Discord bots directly within the Godot engine. It provides a node-based interface to the Discord Bot API, featuring the DiscordBot node for event handling via signals and the ApplicationCommand class for managing slash commands, buttons, and select menus.

Tokens
19K
Snippets
58
Records
86
Agent score
49%

What's inside Discord.gd

  1. Advanced Bot features in Discord.gd

    main

    The advanced bot implementation in Discord.gd supports several high-level features for building complex Discord bots in Godot:

    • Separate command files: Organize your bot logic by splitting commands into individual files rather than a single monolithic script.
    • Application commands: Support for Discord's modern slash commands and interaction-based commands.
    • Message Buttons commands: Ability to handle interactions triggered by buttons attached to messages.
    • Select menu commands: Ability to handle interactions triggered by select menus (dropdowns).
  2. Use the BitField class to manage Discord flags

    main

    The BitField class is a base data structure designed to simplify interacting with Discord's bitfield-based flags and permissions. It allows you to manipulate packed bits using human-readable strings, bit numbers, or other BitField instances.

    Key properties:

    • bitfield (int): The raw integer value of the packed bits.
    • FLAGS (Dictionary): A dictionary of numeric bitfield flags (this is defined in the specific extension class you are using, such as GuildFlags or PermissionFlags).
  3. Use the DiscordInteraction class to respond to interactions

    main

    The DiscordInteraction class is used to handle and respond to various types of Discord interactions (commands, buttons, select menus, etc.). It provides methods to reply, update, or follow up on an interaction.

    Core Properties

    • application_id: The application's ID.
    • channel_id: The ID of the channel where the interaction occurred.
    • guild_id: The ID of the guild (server) where the interaction occurred.
    • id: The unique ID of the interaction.
    • member: A Dictionary containing member information if the interaction occurred in a guild.
    • message: The Message object the interaction was attached to (for component interactions).
    • token: The interaction's unique token.
    • type: The interaction's type.
    • data: A Dictionary containing additional interaction data.
  4. Use the Embed class to create Discord embeds

    main

    The Embed class is a wrapper for Discord Embed objects. It contains all the data required for an embed and provides chainable setter methods to simplify construction. Most setter methods return the Embed instance itself, allowing you to chain multiple configuration calls in a single statement.

    var embed = Embed.new()
    embed.set_title("My Title") \
        .set_description("My Description") \
        .set_color(0xff0000)
  5. Configure and use the DiscordBot class

    main

    The DiscordBot class is the primary Node for interacting with the Discord API. It manages communication via Discord's websockets and REST API, using HTTPRequest internally. To use it, you must provide a bot token and configure appropriate Gateway Intents.

    Key Properties

    • TOKEN (String): The Discord Bot token from the Discord Developer Portal.
    • INTENTS (int): The Gateway Intents required for the bot to receive specific events. Default is 513.
    • VERBOSE (bool): Set to true to enable additional debug logging.
    • user (User): The bot's own user account information.
    • guilds (Dictionary): A map of guilds the bot is in, keyed by their IDs.
    • channels (Dictionary): A map of text and DM channels the bot can access, keyed by their IDs.
    var bot = DiscordBot.new()
    bot.TOKEN = "YOUR_BOT_TOKEN"
    bot.INTENTS = 513 # Example intent value
    bot.login()
  6. Use DiscordBot signals for event handling

    main

    The DiscordBot node communicates with your game via signals. After the bot_ready signal is emitted, you can connect other event-driven signals to your nodes to react to Discord activity.

    Common signals include:

    • bot_ready: Emitted when the connection to the Discord gateway is successfully established.
    • message_create: Emitted when a new message is created.
    • guild_create: Emitted when a new guild (server) is available to the bot.
  7. Use the MessageFlags class to interact with message bitfields

    main

    The MessageFlags class is an extended data structure used to interact with the flags bitfield of a Discord Message. Because it extends BitField, you can use all standard bitfield methods to check, set, or manipulate specific flags.

    This class provides a type-safe way to handle the specific flags supported by Discord messages.

  8. Handle MessageButton interactions

    main

    When a user clicks a button, the interaction is emitted via the DiscordBot.interaction_create signal. To handle button clicks:

    1. Listen for the interaction_create signal.
    2. Use interaction.is_button() to verify the interaction type.
    3. Access the custom_id via interaction.data.custom_id to determine which button was pressed.
    4. Use interaction.reply() to respond to the user.
    func _on_interaction_create(bot, interaction: DiscordInteraction):
        # Make sure the interaction is only from a MessageButton
        if not interaction.is_button():
            return
        
        # Get the custom_id of the button
        var custom_id = interaction.data.custom_id
    
        match custom_id:
            "my_button1":
                # Handle my_button1 logic here
                interaction.reply({
                   "content": "You pressed my_button1"
                })
    
            "other_button2":
                # Handle other_button2 logic here
                ...
  9. Set an emoji on a MessageButton

    main

    To add an emoji to a button, use set_emoji(new_emoji: Dictionary).

    Important Limitations:

    • This only works for Custom Emojis.
    • Standard ASCII emojis are not supported directly due to Godot limitations.

    Workaround for ASCII emojis:

    1. Upload the emoji you want to use as a custom emoji to a Discord server.
    2. Retrieve the emoji id for that custom emoji.
    3. Pass a dictionary containing that ID to set_emoji().

    Emoji Dictionary Format:

    {
        "id": "ID_OF_THE_CUSTOM_EMOJI",
        "name": "optional_name"
    }
    var checkmark_button = MessageButton.new()
    checkmark_button.set_style(MessageButton.STYLES.SECONDARY)
    checkmark_button.set_custom_id("abcde")
    
    # Using a custom emoji ID
    checkmark_button.set_emoji({"id": "556051807504433152"})
    
    var row = MessageActionRow.new().add_component(checkmark_button)
    bot.send(message.channel_id, {
        "content": "This is a emoji button",
        "components": [row]
    })
  10. Respond to Application Commands

    main

    Application commands trigger the DiscordBot.interaction_create signal. To handle a command, check if the interaction is a command using interaction.is_command(), then inspect interaction.data to determine which command was called.

    Interaction Lifecycle

    1. Immediate Reply: Use interaction.reply(data) to send an immediate response. The data is a dictionary (e.g., containing content or embeds).
    2. Deferred Reply: If your command logic takes longer than 3 seconds, call interaction.defer_reply() first. This prevents the interaction from timing out.
    3. Editing a Deferred Reply: After performing long-running tasks, use interaction.edit_reply(data) to update the deferred response with the final result.
    # In the DiscordBot.interaction_create, 
    func _on_bot_interaction_create(bot: DiscordBot, interaction: DiscordInteraction):
        if not interaction.is_command():
            return
        
        var command_data = interaction.data
    
        match command_data.name:
            "ping":
                interaction.reply({
                    "embeds": [
                        MessageEmbed.new().set_title("Pong!")
                    ]
                })
    
            "long-command":
                # Use defer_reply() if processing takes > 3s
                interaction.defer_reply()
    
                # Simulate long processing
                yield(get_tree().create_timer(5), "timeout")
                
                # Edit the deferred reply
                interaction.edit_reply({
                    "content": "After processing for 5s the reply is edited!" 
                })
    
            _: 
                interaction.reply({"content": "Command not implemented."})
  11. Set up a Discord.gd bot in Godot

    main

    To start using Discord.gd, follow these steps:

    1. Install the plugin following the installation guide.
    2. Add the DiscordBot node: In your Godot scene, add a DiscordBot node as a child to any existing node in your scene tree.
    3. Configure the Token: In the Inspector for the DiscordBot node, set the TOKEN property. You can obtain this token from the Discord Developer Portal.
    4. Login: Call the .login() method on the DiscordBot node instance to establish a connection to the Discord gateway.
    5. Handle Readiness: Once the connection is established, the DiscordBot node will emit the bot_ready signal. You should connect this signal to your logic nodes (e.g., a Test node) to know when the bot is online and ready to receive events.
    # Example of calling login from a script attached to a different node
    # Assuming 'bot' is a reference to your DiscordBot node
    func _ready():
        bot.login()
    
    # Connecting to the bot_ready signal
    func _on_bot_ready():
        print("Bot is online!")
  12. Handle SelectMenu interactions

    main

    SelectMenu interactions are received via the DiscordBot.interaction_create signal. To handle them:

    1. Check if the interaction is a select menu using interaction.is_select_menu().
    2. Access the menu's unique identifier via interaction.data.custom_id.
    3. Access the user's selections via interaction.data.values (an array of strings).

    Example pattern:

    func _on_interaction_create(bot, interaction: DiscordInteraction):
        if not interaction.is_select_menu():
            return
        
        var custom_id = interaction.data.custom_id
        var values = interaction.data.values
    
        match custom_id:
            "menu1":
                # Handle logic
                interaction.reply({"content": "You selected " + str(values)})
    func _on_interaction_create(bot, interaction: DiscordInteraction):
        if not interaction.is_select_menu():
            return
        
        var custom_id = interaction.data.custom_id
        var values = interaction.data.values
    
        match custom_id:
            "menu1":
                var msg = "You selected `" + PoolStringArray(values).join(", ") + "`"
                interaction.reply({
                   "content": msg
                })