A Discord slash-command bot for Black Desert Online guilds that want quick access to Node War statistics and profile data. The bot talks to the companion service NodewarBotApi to gather data, keeps track of which guild members are allowed to run the privileged commands, and responds with Discord embeds for an at-a-glance view of recent performance.
DiscordBotApp/– primary bot application targeting .NET 9; hosts slash commands, permission checks, and state persistence.ApiDebugger/– optional console utility for manually probing the Node War API while developing or troubleshooting.state.json– created at runtime alongside the executable and used to persist guild admins/officers; a.bakcopy is also written after each change.
- Slash commands for Node War data: top/bottom performers, individual player breakdowns, and scoreboard image uploads.
- Player profile workflow so members can register gear scores and view their own profile plus Node War stats in one embed.
- Guild-scoped admin/officer management (
/add-officer,/remove-officer,/list-officers,/who-is-admin). - Automatically designates the user who invited the bot (or, as a fallback, the guild owner) as the initial bot admin when joining a server.
- Persists command permissions per guild and logs every interaction for easier auditing.
- Optional
ApiDebuggertool to quickly sanity-check API endpoints from the command line.
- .NET SDK 9.0 (preview) – the projects target
net9.0and rely on the associated preview packages. - A Discord bot application with the
botandapplications.commandsscopes enabled, plus the privileged intents your use case requires (the sample config enablesGuilds,GuildMessages,DirectMessages, andMessageContent). - The companion API service Sebastians-codes/NodewarBotApi running and reachable at
http://localhost:8000.- Provides the Node War and profile endpoints the bot consumes.
- Configure matching API keys/URLs if you deploy it elsewhere.
- Ensure the host can reach the API and persist
state.json.
API contract
GET /nodewar/top/{guildId}→ array of{ name, kills, deaths, kda }.GET /nodewar/{playerName}/{guildId}→ detailed player payload.POST /nodewar/(multipart form) → processes scoreboard screenshots (image,api_key,guild_id).GET /profile/name/{profileName}/{guildId}→ stored player profile.GET /profile/id/{discordId}→ profile for the calling user.POST /profile→ creates/updates a player profile (payload matches thePlayerProfilerecord).
Note: The bot currently hard-codes the API base URL (
http://localhost:8000). Update the URLs inNodeWarCommandModule.csandPlayerProfileCommandModule.csif you host the API elsewhere or need HTTPS.
Update DiscordBotApp/appsettings.json before running:
{
"Discord": {
"Token": "<your bot token>",
"LogLevel": "Info",
"ActivityType": "Watching",
"ActivityName": "Node War reports",
"MessageCacheSize": 100,
"TestGuildId": ""
}
}Tokenmust contain your bot token (never commit it).ActivityType/ActivityNamecontrol the rich presence text shown under the bot name.TestGuildId(optional) lets you register slash commands to a single guild for rapid iteration; leave blank or0to register globally (may take up to an hour to propagate).- Adjust
Discord:LogLevelorMessageCacheSizeas needed for your hosting environment.
The bot writes state.json to the working directory. Ensure the process has write access; back the file up if you redeploy to another host to preserve admin/officer assignments.
# Restore packages
dotnet restore
# Launch the Discord bot
dotnet run --project DiscordBotAppWhen the bot joins a guild it reads the audit log to discover who invited it (requires the View Audit Log permission). That user becomes the bot admin and can delegate officer permissions. Commands respond ephemerally by default so they only appear to the caller.
If you modify slash commands, restart the bot after dotnet build/dotnet run. With global registration, allow Discord time to propagate the updates.
| Command | Access | Description |
|---|---|---|
/about |
Anyone | Short description of the bot. |
/help-nodewar |
Admin & officers* | Lists Node War-focused commands. |
/register |
Admin & officers* | Register your profile (AP/AAP/DP, class, spec). |
/profile |
Admin & officers* | View your stored profile plus Node War summary. |
/help-admin |
Admin & officers | Overview of administrative commands. |
/who-is-admin |
Admin & officers* | Shows who currently controls the bot for this guild. |
/list-officers |
Admin & officers | Lists approved officers for this guild. |
/add-officer |
Bot admin | Add a member to the officer list. |
/remove-officer |
Bot admin | Remove a member from the officer list. |
/performance |
Admin & officers | Shows top/bottom performers for recent wars. |
/player-stats |
Admin & officers | Detailed Node War stats for a chosen player. |
/upload-warscores |
Admin & officers | Upload a scoreboard image for OCR + ingestion. |
/profile-by-name |
Admin & officers | View a specific profile (by profile name) with war stats. |
*Commands marked with an asterisk are decorated with [AllowAnyone], but the default InteractionHandler.CheckPermissionsAsync currently only exempts /help and /about. Update that method if you want these commands to be publicly accessible.
State.cskeeps guild-specific admin/officer mappings instate.jsonand backs it up tostate.json.bakafter each save.- Permission checks run for every interaction; commands flagged as admin/officer-only will reject other users with an ephemeral message.
- Use
/who-is-adminand/list-officersto confirm who currently has elevated access.
For quick API smoke tests without Discord, run the helper app:
dotnet run --project ApiDebuggerFollow the prompts to hit the same endpoints the bot uses. This is useful when developing the OCR/Node War backend or verifying authorization issues.
- Slash commands missing: make sure the bot was invited with the
applications.commandsscope and, during development, populateDiscord:TestGuildIdso commands deploy immediately to that guild. - Permission denied responses: the bot could not identify you as the guild admin/officer. Confirm
state.jsoncontains your Discord ID or have the admin run/add-officer. - API failures: the bot logs HTTP status codes and response bodies to stdout. Check the console and ensure the Node War API is reachable from the bot host.
- Image uploads failing: confirm the API expects the
api_keyvalueapi_key_1or updateNodeWarCommandModule.SendImageToApiAsyncto match your backend.
No license file is included. Add one if you plan to distribute or open-source the project.