Configuration: Discord
Full setting-by-setting reference for the wn-discord bridge's TOML config: connection and presence, channel routing, text commands, chat relay, content filtering, diagnostics limits, announcements, every embed/message template group, account linking, role sync, the Warring Nations feed integration and per-nation Discord servers, and scheduled alerts.
SERVER ADMINSMODPACK DEVS
config/warring-nations/wn-discord-server.toml
All Discord ids (guild/role/channel/category) are strings in the file, to dodge long precision foot-guns; paste the numeric snowflake as a quoted string, e.g. guildId = "123456789012345678".
i
Secrets. The bot token and OAuth client secret can be set in the file, but the environment variables WN_DISCORD_BOT_TOKEN and WN_DISCORD_CLIENT_SECRET take priority when present; use them if you don't want secrets checked into a backed-up or shared config file.
connection
The bot's login, presence, and which guild it operates in.
enabled
false
Master switch. If false the whole bridge stays a no-op (the extensibility API still installs, so addons load fine either way) and never connects to Discord.
botToken
""
Bot token. Prefer WN_DISCORD_BOT_TOKEN.
guildId
""
The Discord server (guild) id the bot operates in.
serverId
""
This Minecraft server's own short name ("survival", "creative"), only needed for a multi-server deployment where several MC servers' wn-discord instances share one guild. Blank is correct for a normal single-server setup.
staffRoleId
""
Role id allowed to run admin slash commands / console commands. Administrator permission also always qualifies.
presenceFormat
"%online% / %max% players"
The bot's Discord presence/activity text, refreshed every presenceIntervalSeconds. Placeholders: %online% %max% %activewars% %nationcount% %currentwar% (one currently active war's belligerents, e.g. "Rome vs Carthage", rotating to a different active war automatically as real time passes; "no active wars" when there are none). Prefix with WATCHING:/LISTENING:/COMPETING: (stripped before display) to use that activity type instead of the default Playing. Blank means no activity text is shown. Only used when presenceRotation is empty.
presenceRotation
[]
Optional list of presence texts to cycle through round-robin, one per presenceIntervalSeconds tick, instead of always showing presenceFormat. Same placeholders and activity-type prefix support.
presenceIntervalSeconds
60
How often (seconds) the presence text is re-rendered and pushed to Discord.
channels
Which Discord channel each feed posts to.
chat
""
Channel id for two-way player chat.
console
""
Channel id for the console mirror plus command execution.
events
""
Channel id for join/leave/death/advancement/server-start-stop.
extra
[]
Extra "key=channelId" entries for addon-registered feeds, e.g. "nation=123456789012345678". WN's own feeds use the keys nation, war, diplomacy, village, government, op-audit-log, nation-audit-log (see the example config below for wiring up all seven at once).
textCommands
Running slash commands as plain chat messages instead.
enabled
true
Let every
slash command also be run as a
!-prefixed chat message. On by default.
prefix
"!"
The prefix a chat message must start with to be tried as a command.
relay
The two-way chat bridge and console mirror.
mcToDiscord
true
Relay in-game chat to Discord.
discordToMc
true
Relay Discord chat into the game.
useWebhooks
true
Post relayed chat through a channel webhook so it shows the player's name and head avatar (DiscordSRV-style), instead of a plain bot message. Requires Manage Webhooks.
consoleEnabled
false
Mirror the server log into the console channel.
consoleAllowCommands
false
Allow running server commands by typing in the console channel (staff/admin only, checked Discord-side).
consoleCommandPrefix
""
Optional prefix a console-channel line must start with to be treated as a command; empty means every line is a command attempt.
duplicateCollapseEnabled
true
Discord-to-MC only: collapse consecutive identical messages into a (+N) counter line instead of relaying the full text again each time.
duplicateCollapseWindowSeconds
45
How long a repeat must follow the previous identical message within to be collapsed; older repeats relay in full again.
consoleFlushIntervalSeconds
2
How often (seconds) queued console/log lines are grouped into a fenced code-block message and sent to the console channel. Only takes effect on the next server start.
filter
Content filtering and flood control on the relay.
slurFilterEnabled
true
Block relayed messages containing a word from slurBlocklist.
slurBlocklist
["nigger", "nigga", "faggot"]
The slur blocklist itself. This is the one place to edit it, directly in the generated TOML file, no rebuild required.
inviteLinkFilterEnabled
true
Block relayed messages containing a discord.gg/... or discord.com/invite/... link.
massMentionFilterEnabled
true
Neutralize @everyone/@here in relayed content.
rateLimitEnabled
true
Per-user flood control on the relay, both directions.
rateLimitMaxMessages
5
Messages allowed per user within the window before extras are silently dropped.
rateLimitWindowSeconds
10
Sliding window size, in seconds, for the flood check.
debug
Limits for the /debug crashlogs diagnostic command.
crashLogMaxCount
10
Hard cap on how many recent crash logs one /debug crashlogs invocation may request at once (the count option is clamped to this).
crashLogMaxAttachmentBytes
8388608
Max size (bytes) of a single crash-log file Discord will accept as a DM attachment; an oversized log is gzipped first, then split into numbered parts if still too big even compressed.
announcements
Independent on/off switches for each in-game event announcement.
join / leave / death / advancement / serverStartStop
true (all)
Toggle each announcement independently.
templates
The high-traffic single-line relay and announcement templates, and the option to send an event as an embed instead of plain text.
mcChatToDiscord
"%player% » %message%"
Also: discordChatToMc, join, leave, death, advancement, serverStart, serverStop. Placeholders: %player% %message% %user% %advancement%, plus anything an addon registers via registerPlaceholder. discordChatToMc additionally supports &#RRGGBB ... &r color tokens (matching the core mod's TAB integration), applied when rendered into an in-game chat message.
{join|leave|death|advancement|serverStart|serverStop}AsEmbed
false
Send that event as a configurable embed instead of plain text. Off by default; when on, see the matching {event}EmbedTitle / EmbedDescription / EmbedColor / EmbedFooter / EmbedFields keys (fields as "Name|Value|inline" rows, e.g. ["Server|%player% joined|false"]).
wnTemplates
Wording, colors, and naming for the Warring Nations feed embeds (nation, village, war, capture, diplomacy, government) and the structured notification API a third-party addon like wn-bluemap or wn-siege calls into.
roleNameTemplate
"%nation%"
Discord role name for a nation. Placeholders: %nation% %tag% %level% %members% %color% %server% (blank unless serverId is set, see multi-server below).
nationChannelNameTemplate
"%nation%"
The channel's actual name (rendered then slugged). Also takes %server%.
nationChannelWelcomeMessage / nationChannelTopicTemplate / archivedChannelPrefix
see example config
Text for a newly-provisioned nation channel's welcome message and topic (also takes %server%), and the plain (non-template) prefix applied to an archived channel's name on disband.
(one title/description/color/footer/fields set per nation, village, war, capture, and diplomacy event)
see below
Every embed WnFeeds posts: nation founded/disbanded/renamed, member joined/left, pending-approval and approve/deny confirmations, village founded/disbanded/renamed/affiliation-changed, war declared/status/rollcall/resolved, capture alerts, diplomacy changes. WnGovFeeds separately posts to the government channel (entity/membership/proposal/vote/procedure events), lighter-weight and not templated the same way. Every default reproduces the mod's original hardcoded wording, emoji, and color exactly; color is a hex string (with or without #) or a %placeholder% that renders to one. Buttons, file/thumbnail/image attachments, and computed values (score lines, rollcall response lists) stay fixed Java behavior, not template content. Deliberately not surfaced as a feed: raw treasury-balance changes (would spam) and individual bet placements (would violate the "never post per-bettor amounts publicly" principle the aggregate bet-settled feed follows).
warStartedTitle / Description / Color, warEndedTitle / Description / Color
"⚔ War declared" / "**%attacker%** vs **%defender%**%map_link%" / "FF7043", "White flag War ended" / "**%attacker%** vs **%defender%** %outcome%%map_link%" / "747F8D"
Wording for DiscordBridge#notifyWarStarted/#notifyWarEnded, part of the structured notification API a third-party addon (e.g. wn-bluemap) calls instead of composing its own message text. Placeholders: %attacker% %defender% %map_link% (blank when the caller passed none), plus on the ended variant %winner% (blank on a truce) and %outcome% (Java-computed: "won by **<winner>**" or "ended in a truce").
siegeRingFallenTitle / Description / Color, siegeRingRelievedTitle / Description / Color, siegeKeepHoldTitle / Description / Color
"Ring breached" / "Ring relieved" / "Keep under siege"
Wording for a composable
siege's ring-fallen/ring-relieved/keep-hold-entered moments, fired both by
WnFeeds' own event subscriptions (into the
war feed) and by
DiscordBridge#notifySiegeRingFallen/
#notifySiegeRingRelieved/
#notifySiegeKeepHoldEntered for an addon (e.g. wn-siege) reporting the same moment from its own engine. Placeholders:
%attacker% %defender% %ring% (1-indexed)
%map_link%.
villageSiegeStartedTitle / Description / Color, villageSiegeLiftedTitle / Description / Color
"Village under siege" / "Village siege lifted"
Wording for WnFeeds' own village-siege-started/lifted subscriptions, posted to the village feed. Placeholders: %village% %attacker%.
villageSiegeStartedApiTitle / Description / Color, villageSiegeLiftedApiTitle / Description / Color
same defaults as above, plus %map_link%
The structured notification API equivalents (DiscordBridge#notifyVillageSiegeStarted/#notifyVillageSiegeLifted) for an addon reporting a village siege it observed itself. Kept as separate keys from the plain ones above so an admin can word wn-discord's own feed differently from an addon-sourced report, even though both ship identical default text.
presetAppliedTitle / Description / Color
"Preset applied" / "**%nation%** applied the **%preset%** preset (%collection%, %era%). Changed: %changed_fields%." / "FAA61A"
WnFeeds' own preset-applied subscription, posted to the
nation feed whenever a nation applies one of Warring Nations'
built-in presets and it actually changed something (never fires on a no-op apply). Placeholders:
%nation% %preset% %collection% %era% %changed_fields% (comma-joined).
presetAppliedApiTitle / Description / Color
same title/color, description also takes %treasury_line%%roles_line%%map_link%
The structured notification API equivalent (DiscordBridge#notifyPresetApplied) for an addon composing the same announcement from its own preset-application logic. Extra placeholders: %treasury_line% (blank unless the preset credited treasury), %roles_line% (blank unless the preset created roles), %map_link%.
betSettledEnabled
true
Post an aggregate war-bet settlement embed to the war feed channel whenever a war with active bets resolves. Never names individual bettors or amounts, only totals (bettor count, total pot, total paid out). Placeholders: %bettor_count% %total_pot% %total_paid_out% %winner% (won only).
betSettledWonTitle / betSettledWonColor / betSettledRefundTitle / betSettledRefundColor / betSettledDescription / betSettledPotFieldName / betSettledPotFieldValue
see example config
Title/color for the two settlement variants (a decisive winner vs. an all-refund settlement), shared description, and the "paid out" field.
commandTemplates
Titles, colors, and static copy for the roughly 20 embeds the built-in slash and equivalent ! text commands reply with.
COVERS
One title/color/empty-state set per reply embed: /server online, /nations list, /nation info, /war list, /account whois, /nations roster, /nations chunk, /nations compare, /nations leaderboard, /staff claims, /nations history, /server status, /whitelist (6 shapes), /war rally, /help <command> (bare /help is a Components V2 view, not templated at all), /debug, plus the shared "bridged command" done/output shape and the shared error-embed wrapper. Live list/table bodies (rosters, leaderboard rows, help text) stay computed, not templated. See Commands: Discord for what each command does.
linkTemplates
In-game chat text and OAuth callback page text for the account-linking flow.
(13 in-game link-flow chat messages)
see example config note
/discord link|unlink|status|reload's in-game chat text; supports &#RRGGBB ... &r color tokens layered on each message's default semantic color.
requireLinkKickMessage / requireLinkUnavailableMessage
see below
The kick message shown when linking.requireLinkedToPlay is on and a joining player has no linked account. Placeholders: %url%.
(14 OAuth callback page title/body pairs)
see below
The HTML pages served by the /discord link browser redirect flow. HTML/CSS shell is fixed; only title/body text is templated. Placeholders: %error% (cancelled page), %name% (linked page), both pre-escaped for HTML.
commandGates
Generic fallback replies shared by every slash command and its text-command equivalent.
unknownCommandMessage / unknownSubcommandMessage / unknownSubcommandTextMessage / requireLinkMessage / adminOnlyMessage / commandFailedMessage
see below
Unknown command/subcommand, permission/link gates, unhandled exceptions. Placeholders vary per key: unknownSubcommandTextMessage takes %subcommand% %options% %prefix% %command%; commandFailedMessage takes %error%.
linking
OAuth2 account linking (/discord link) and its embedded callback server.
enabled
false
Enable /discord link (OAuth2 account linking).
clientId
""
OAuth2 application client id.
clientSecret
""
OAuth2 client secret. Prefer WN_DISCORD_CLIENT_SECRET.
redirectUri
"http://localhost:9955/callback"
Must exactly match a redirect URI registered on the Discord application.
callbackBindHost
"0.0.0.0"
Interface the embedded OAuth callback HTTP server binds to.
callbackPort
9955
Port for the embedded callback server.
requireLinkedToPlay
false
Kick unlinked players on join with the link URL.
codeExpiryMinutes
10
Minutes a /discord link browser link stays valid before it expires. Only takes effect on the next server start.
callbackRateLimitMaxRequests
10
Max requests per source address within callbackRateLimitWindowSeconds on the internet-facing OAuth callback server before extras get a "too many requests" page.
callbackRateLimitWindowSeconds
10
Sliding window size, in seconds, for callbackRateLimitMaxRequests.
roleSync
Discord role to in-game group sync for op / linked / nation status.
enabled
false
Enable Discord role ↔ in-game group sync (op / linked / nation). Requires linked accounts and the GUILD_MEMBERS intent.
opRoleId
""
Role granted to linked server operators (added/removed live as op status changes).
linkedRoleId
""
Role granted to any linked player.
nationRolesAuto
false
Auto-create/assign a Discord role named after each player's
Warring Nations nation (nations are FTB Teams, so this is effectively FTB-team role sync too). Name rendered via
wnTemplates.roleNameTemplate. A stale nation role from a former nation is stripped on the next reconcile pass once the switch is detected.
intervalSeconds
60
How often (seconds) the periodic role-sync pass re-scans online players. /staff resync always runs immediately regardless of this.
warringNations
Feed publishing, chat bridging, and per-nation channel automation.
feedsEnabled
true
Publish the nation/war/diplomacy feeds.
nationChatBridge
false
Relay /nation msg to a nation's Discord destination. One-way, in-game to Discord only.
perNationChannelsEnabled
false
Auto-create a private per-nation Discord channel and role on nation creation; archive (lock and rename) on disband. Requires Manage Channels + Manage Roles. Discord hard-caps a guild at 500 channels total, so with many hundreds of nations this mode can hit it; nationServers mode below has no such shared ceiling. /debug bridge reports remaining channel headroom.
nationChannelCategoryId
""
Optional category new nation channels are created under.
archiveNationChannelsOnDisband
true
If false, a disbanded nation's channel is left completely untouched instead of being locked/renamed.
channelCapWarnThreshold
20
Channel slots remaining before an admin gets a one-time log warning about Discord's 500-channel cap approaching. Only matters if perNationChannelsEnabled is on.
warScoreboardEditIntervalSeconds
30
Minimum seconds between edits to a war's live score embed as chunks are captured.
warThreadsEnabled
true
Spin up a public Discord thread off each
war's live scoreboard message when it's declared, for that war's own ongoing discussion instead of it blending into the shared war feed channel.
warringNations.nationServers
An alternative to a shared per-nation hub channel: letting each nation link its own, separate Discord server it fully controls. Takes precedence over perNationChannelsEnabled if both are somehow on. Server-owner-wide, not per-nation; once enabled, every nation uses this mode.
enabled
false
Let nations link their own dedicated Discord server instead of a hub channel. File-only, restart required.
linkedRoleName / opRoleName / citizenRoleName
"Linked" / "Operator" / "Citizen"
Names of the roles auto-created and synced in each linked nation server.
botNicknameTemplate
"WN | %nation%"
The bot's own nickname in each linked nation server, so it visibly reads as that nation's own bot instead of a generic guest. Set on link, kept in sync on in-game rename. Placeholder: %nation%. Blank leaves the bot's nickname alone.
syncMemberRankNicknames
false
Append " [<rank>]" (their real in-game nation rank, or their assigned custom role's name) to a linked member's own nickname in their nation's linked server, kept in sync every reconcile pass. Off by default: unlike the bot's own nickname, this edits a real person's display name and needs Manage Nicknames.
verifyCodeExpiryMinutes
10
Minutes a !verify <code> code stays valid before a nation leader must mint a fresh one.
verifyCodeLength
8
Character length of a minted !verify code.
syncIntervalSeconds
60
How often (seconds) each linked nation server's own role sync and channel-default reconcile pass runs, independent of roleSync.intervalSeconds.
warringNations.nationServers.feeds
Independent per-nation-server feed toggles, live-settable with /config set.
chatBridge / lifecycle / war / claims / diplomacy / roleSync
true (all)
Each toggle is independent and live-settable. roleSync off saves the per-nation REST traffic entirely if you only want the feeds/chat bridge.
alerts
DiscordSRV-style scheduled announcements, independent of any game event.
enabled
false
Turn scheduled announcements on.
intervalSeconds
3600
Seconds between posts (clamped to a minimum of 60).
channel
"events"
Logical channel key to post to: any of chat/console/events/an extra key.
messages
[]
Messages to rotate through round-robin. Empty list means the feature is a no-op even if enabled is true.
Example config
A minimal, working config for chat relay plus all seven WN feeds (nation, war, diplomacy, village, government, op-audit-log, nation-audit-log).
[connection]
enabled = true
guildId = "123456789012345678"
staffRoleId = "234567890123456789"
# botToken left blank on purpose: set via the WN_DISCORD_BOT_TOKEN env var instead.
[channels]
chat = "345678901234567890"
console = "456789012345678901"
events = "567890123456789012"
extra = [
"nation=678901234567890123",
"war=789012345678901234",
"diplomacy=890123456789012345",
"village=123456789012345670",
"government=123456789012345671",
"op-audit-log=901234567890123456",
"nation-audit-log=012345678901234567"
]