Discord Bot

Discord Bot

The Voxy Discord bot is a standalone Java application — not a Minecraft plugin. It runs separately and communicates with your network via the same MongoDB and Redis connections as Voxy.

Features

  • Account linking — Players link their Minecraft account to Discord in-game; the bot DMs them an approve/deny prompt
  • Rank ↔ role sync — Minecraft ranks are mapped to Discord roles; roles are assigned and removed automatically as grants change
  • Linked role — Optionally grant a special Discord role to all linked accounts
  • Slash commands/profile, /unlink, /associate, /disassociate
  • Status rotation — Cycles through configurable bot presence messages

Setup

1. Create a Discord Application

  1. Go to the Discord Developer Portal and create a new application
  2. Under Bot, create a bot user and copy the token
  3. Enable the Server Members Intent under Privileged Gateway Intents
  4. Invite the bot to your server with Manage Roles and Send Messages permissions

The bot's role must be positioned above any rank-associated roles in your server's role list, otherwise it cannot assign them.

2. Configure settings.yml

discord:
  token: "YOUR_BOT_TOKEN"
  guild: "YOUR_GUILD_ID"

  # Role ID to grant all linked accounts. Set to 0 to disable.
  linked-role: 0

  presence:
    interval: 30        # Seconds between status rotations (minimum 5)
    status: "online"    # online | idle | dnd | invisible
    activities:
      - type: "Playing"
        text: "On Your Network"
      - type: "Custom"
        text: "At your service!"

server:
  identifier: "discord-bot"
  display-name: "Discord Bot"
  group: "bots"

database:
  mongo:
    host: "localhost"
    port: 27017
    database: "voxy"
    srv: false
    auth:
      enabled: false
      username: ""
      password: ""
  redis:
    host: "localhost"
    port: 6379
    auth:
      enabled: false
      username: ""
      password: ""

3. Start the bot

java -jar voxy-discord.jar

The bot exits with an error if MongoDB or Redis is unreachable.

Slash Commands

Command Who Description
/profile [user] Anyone View a linked player's Minecraft profile (name, UUID, rank, level, XP, playtime, join date)
/unlink Anyone Unlinks your Discord account from Minecraft
/associate <rank> <discord-role> Admin Binds a Minecraft rank to a Discord role
/disassociate <rank> Admin Removes a rank-role binding

All responses are ephemeral (visible only to the invoking user).

UI Scripting (YAML)

The Discord bot can render rich interactive messages using YAML definitions in messages.yml.

Each message is keyed by a dotted route (for example link.request or profile.summary) and is defined as a list of top-level container components. Supported top-level component types are:

  • TEXT - a text display block (Markdown supported). Requires a text key.
  • SEPARATOR - a spacer/divider. Optional spacing (SMALL or LARGE) and divider (boolean).
  • SECTION - a block of TEXT children with a required accessory (thumbnail or button).
  • ACTION_ROW - a horizontal row of interactive components, listed under children.
  • BUTTON - a clickable action (inside an ACTION_ROW or as a section accessory).
  • STRING_SELECT - dropdown menu of textual options.
  • ENTITY_SELECT - dropdown for selecting users, roles, or channels.
  • MEDIA_GALLERY - a grid of images.
  • FILE_DISPLAY - a downloadable file.

Component notes

  • A BUTTON uses the key id for its custom identifier (not custom_id). Link-style buttons (style: LINK) use url and label instead of id.
  • A SECTION requires a children list containing only TEXT items, plus an accessory supplied as a map under accessory (or thumbnail). A thumbnail accessory must be a map with type: THUMBNAIL and a url - a bare URL string is rejected. A section cannot contain an ACTION_ROW.
  • For the link prompt, the approve/deny button IDs are generated at runtime (they encode the request UUID, e.g. discord-link:approve:<uuid>). Reference them in YAML with the {approve-id} and {deny-id} placeholders, which the bot substitutes before sending.

Example: link.request

link:
  request:
    - type: SECTION
      accessory:
        type: THUMBNAIL
        source: URL
        url: "https://cravatar.eu/helmavatar/{player-id}/800.png"
        description: "Avatar for {player}"
      children:
        - type: TEXT
          text: "## Account Link Request"
        - type: TEXT
          text: "Link request from **{player}**"
    - type: SEPARATOR
      spacing: SMALL
    - type: TEXT
      text: "This request expires in {minutes} minutes."
    - type: ACTION_ROW
      children:
        - type: BUTTON
          style: SUCCESS
          id: "{approve-id}"
          label: "Approve"
        - type: BUTTON
          style: DANGER
          id: "{deny-id}"
          label: "Deny"

When the bot renders this definition it builds the message from the listed components. Pressing Approve links the accounts, while Deny rejects the request. Placeholders such as {player}, {minutes}, {approve-id}, and {deny-id} are substituted at send time.

Account Linking

  1. Player runs /linkdiscord in-game
  2. Bot sends them a DM with Approve / Deny buttons
  3. Player clicks Approve — accounts are linked and role sync runs immediately
  4. Link requests expire after 5 minutes

To unlink, players run /unlinkdiscord in-game or /unlink on Discord.

Rank-Role Synchronization

Map a Minecraft rank to a Discord role with /associate:

/associate <rank> <discord-role>

Once associated, the bot automatically:

  • Assigns the role when a player receives that rank grant
  • Removes the role when the grant expires or is revoked
  • Reconciles all existing members on startup

Multiple ranks can map to the same role. A rank can only have one associated role.