Viscord Vonix Mods v5.2.1 Search GitHub
Viscord/Reference/Configuration

Configuration#

Viscord reads one TOML file:

config/viscord/viscord.toml

The file is generated on first boot with every key present and commented. Values below are taken from config/toml/ViscordConfigToml.java (the typed accessors that read the values) and config/toml/TomlConfigManager.java (the spec that writes and repairs the file). Where the two disagree, the accessor is what the running server uses.

There are 46 keys declared across thirteen tables. Two of them (discord.webhook_id and discord.events.webhook_url) are written by the generator but read by no code path — they are marked spec-only below. The other 44 drive behaviour. Every key is optional in the sense that a missing value falls back to the compiled default, but the three placeholder secrets must be replaced before anything connects.

Reload

/viscord reload closes the platform connection, re-reads the file, and reconnects. No server restart is needed for any key on this page. See Upgrades and reload.

[general]#

Key Type Default Meaning
enabled bool false Master switch. False means Viscord initialises nothing at startup and logs Disabled in config.
platform string "discord" Which platform to connect: discord, fluxer, or both.
debug bool false Verbose logging. Also enables the rate-limiter's info line naming the bucket that limited a call.

platform = "both" connects Discord and Fluxer independently: chat and events are duplicated to both, but a message on one platform is not relayed to the other. Cross-platform relay is what [general.tridirectional] adds.

[general.tridirectional]#

Three-way relay between Discord, Fluxer, and Minecraft. Requires Discord and Fluxer to both be configured; enabling this switches the connection path even if platform is still discord.

Key Type Default Meaning
enabled bool false Master switch for tridirectional relay.
discord_to_fluxer bool true Relay Discord messages into Fluxer.
fluxer_to_discord bool true Relay Fluxer messages into Discord.
show_source bool true Prefix bridged messages with [Discord] or [Fluxer].

With show_source = false a bridged line is author: message with no platform tag. Turn it off only when the two channels are visually distinct anyway; the tag is also what the echo guard uses to spot Discord-originated text arriving back from Fluxer.

[discord]#

Key Type Default Meaning
bot_token string "YOUR_BOT_TOKEN_HERE" Bot token from the Discord developer portal.
channel_id string "YOUR_CHANNEL_ID_HERE" Channel Viscord watches and posts chat to. Comma-separated values watch several channels.
webhook_url string "" Webhook for Minecraft → Discord chat. Empty means outbound chat is dropped.
webhook_id string "" Spec-only. Written to the file; no accessor reads it.
invite_url string "" Invite link shown by /discord and used as the click target on the [Discord] tag in chat.

channel_id is also the source of the guild for native command registration: Viscord resolves each configured channel, finds its guild, and synchronises /link, /list, /home, /help, and /status there. If no configured channel resolves, no native commands are registered at all.

The webhook ID used by the echo guard is extracted from webhook_url at runtime by splitting on / and taking the numeric segment after webhooks. There is no separate key to set it.

Correction to older docs

Earlier Viscord documentation listed discord.webhook_id as a settable key that you only need to change for an explicit override. No accessor for it exists in ViscordConfigToml.java: the webhook ID used by the echo guard is always parsed out of discord.webhook_url at runtime. The generator still writes a webhook_id = "" line because the config spec defines it, so the key is present in your file — but editing it changes nothing. Do not rely on it.

[discord.events]#

Key Type Default Meaning
channel_id string "" Separate channel for join/leave/death/advancement embeds. Empty means events go to discord.channel_id.
webhook_url string "" Spec-only. Written to the file; event embeds always go through the bot API.

Event embeds are sent by the bot, not the webhook, so this channel must be one the bot can see and post in. When set, Viscord also reads this channel, which is how one server's event embeds become another server's in-game notifications. Because delivery is bot-API only, a separate event webhook cannot be configured — the webhook_url line here is written by the generator but has no effect.

[fluxer]#

Key Type Default Meaning
bot_token string "YOUR_FLUXER_BOT_TOKEN" Bot token from the Fluxer developer portal.
channel_id string "YOUR_FLUXER_CHANNEL_ID" Fluxer channel for chat. Comma-separated values are all watched.
event_channel_id string "" Separate event channel. Empty means fluxer.channel_id.
webhook_url string "" Optional webhook for per-player names and avatars on Fluxer. Without it, messages post through the bot API as **name**: text.

Fluxer's webhook URL format is https://api.fluxer.app/v1/webhooks/{id}/{token}. Viscord parses the ID from that shape and registers it as the bot's own webhook so only its echoes are suppressed; other webhooks in the channel are treated as cross-server traffic.

fluxer.bot_token is validated against the literal placeholder string as well as against empty, so leaving the default in place produces a clear Bot token not configured! error rather than an authentication loop.

[server]#

Key Type Default Meaning
prefix string "[MC]" Server tag in bridged messages, and the anchor for the echo-loop guard. Must be unique per server in a shared channel.
name string "Minecraft Server" Display name used in embed authors, /list output, and bot status context.
avatar_url string https://minotar.net/armor/bust/{uuid}/100.png Template for player avatars on webhook messages. Placeholders: {uuid} (no dashes) and {username}.

avatar_url is a template, not a fixed URL. Viscord substitutes the dashless UUID when one is known and falls back to the username otherwise. If the value is blank it uses the same Minotar URL as a built-in fallback, so blank does not mean "no avatar". When SkinRestorer is installed and the player has a saved custom skin, Viscord resolves https://mc-heads.net/avatar/<texture-hash>/100.png first and ignores this template.

Correction to older docs

Earlier documentation gave server.avatar_url a default of "". The compiled default in ViscordConfigToml.Server.AVATAR_URL is https://minotar.net/armor/bust/{uuid}/100.png, and that is the value written into a fresh viscord.toml.

[messages]#

Key Type Default Meaning
discord_to_minecraft string "[Discord] {username}: {message}" Format for platform → Minecraft chat. Placeholders: {username}, {message}.
minecraft_to_discord string "{message}" Minecraft → platform format. Accepted and persisted, but not applied by the 5.2.1 send path.
webhook_username string "{prefix} {username}" Webhook author name on Minecraft → Discord chat. Placeholders: {prefix}, {username}.
use_display_name bool true Resolve Discord authors as server nickname / global display name; false uses the plain account name.

Two behaviours worth knowing before you customise these:

  • discord_to_minecraft is also used for Fluxer chat. Viscord replaces the literal [Discord] in the rendered result with [Fluxer], so a custom prefix like [Chat] stays as written and is not rewritten.
  • If the rendered discord_to_minecraft string contains [Discord] and discord.invite_url is set, that tag becomes a clickable component that opens the invite. Everything around it stays plain text.

webhook_username matters beyond appearance: the echo guard prefixes a heuristic on it. Viscord splits the format at {prefix} and checks whether an incoming webhook author name starts with the text before the placeholder followed by server.prefix. Moving {prefix} to the end of the format is legal but weakens that particular check.

Correction to older docs

minecraft_to_discord is documented upstream as the Minecraft → Discord chat format with a {message} placeholder. No code path reads this key in 5.2.1 — the outbound text is webhook_username plus the in-game message after DiscordFormatter.convertToDiscordFormatting. The key is written by the spec and survives migration, but editing it changes nothing. Use webhook_username for the author line and [filters.chat] to control what reaches Discord at all.

[messages.events]#

Key Type Default Meaning
join bool true Post an embed when a player joins.
leave bool true Post an embed when a player leaves.
death bool true Post the localised death message.
advancement bool true Post advancement notifications.

Each flag is checked before the platform call, so disabling one removes the network work entirely rather than filtering it later. Advancements are additionally deduplicated: the same player and title within five seconds is dropped, because a single unlock can fire several events.

[filters]#

Key Type Default Meaning
ignore_bots bool true Drop messages whose author is a bot.
ignore_webhooks bool true Drop messages from other webhooks.
trusted_bot_ids string "" Comma-separated bot or webhook IDs that bypass both ignore filters.
filter_by_prefix bool true Drop bot and webhook authors whose display name starts with this server's prefix.
show_other_server_events bool true Accept event embeds posted by other Viscord servers.

These five interact, and the interaction is the usual cause of "cross-server chat is silent". The exact rules are in Multi-server. The short version: prefix and self-origin checks apply only to bot and webhook authors, never to ordinary Discord users, and a message from this server's own bot or webhook is dropped unconditionally before any filter is consulted.

[filters.chat]#

Key Type Default Meaning
enabled bool false Drop in-game messages that begin with prefix instead of bridging them.
prefix string "!" The prefix that marks a message as game-only.

This filter runs on the raw packet text before anything is sent, so a suppressed message costs no network call. An empty or null prefix with enabled = true forwards everything — an empty prefix never matches.

[bot_status]#

Key Type Default Meaning
enabled bool true Keep the bot's activity line in sync with the player count.
format string "Online: {online}/{max}" Status template. Placeholders: {online}, {max}.

Updates are coalesced. A mass reconnect produces one status push, not one per player — see Performance.

[account_linking]#

Key Type Default Range Meaning
enabled bool true — Allow /viscord discord link and Discord-side /link code.
code_expiry int (seconds) 300 60–600 How long a generated code stays valid.

Values outside 60–600 are corrected to the nearest bound when the file is loaded. The in-game message reports expiry in whole minutes, so a 90-second setting displays as 1 minute. The full handshake is in Account linking.

[discord_rate_limit]#

Sliding 60-second windows on the platform-side commands. A value of 0 disables that bucket. Limits are read on every call, so a reload takes effect immediately.

Key Type Default Range Meaning
link_per_user_per_min int 3 0–1000 Per-user /link attempts per minute.
link_global_per_min int 30 0–10000 Channel-wide /link attempts per minute.
list_per_user_per_min int 2 0–1000 Per-user !list and /list calls per minute.
list_global_per_min int 20 0–10000 Channel-wide !list and /list calls per minute.
home_per_user_per_min int 4 0–1000 Per-user /home executions per minute.
home_global_per_min int 20 0–10000 Channel-wide /home executions per minute.

The six keys cover three buckets, not six independent limits. /link and /list each have a per-user and a global cap; /home uses the home_* pair. Fluxer !list calls share the list bucket under a single fluxer key because the Fluxer message handler does not surface a stable per-user ID — the global cap still applies, the per-user cap effectively does not.

A rate-limited /link is silent by design: no reply, one log line at info level when general.debug is true. See Commands for why.

[advanced]#

Two keys are declared by the config spec and written into every generated file. Neither is read by any Viscord code path in 5.2.1.

Key Type Default Range Status
queue_size int 100 10–1000 Generated and range-checked; no consumer.
rate_limit int (ms) 1000 100–5000 Generated and range-checked; no consumer.

Executor sizing, queueing, and back-pressure are fixed in code rather than configurable — see Performance. If you are upgrading from an older build and these keys are already in your file, leave them; they are harmless and will be preserved.

Types and coercion#

TOML integers arrive from NightConfig as Long. ConfigValue.get() inspects the declared default type and coerces numbers to Integer, Long, or Double before returning, and falls back to the default on a ClassCastException. That means a hand-edited code_expiry = "300" (a string) yields the default rather than a crash. It also means a wrong-typed value fails silently — if a number you set appears to be ignored, check it is unquoted.

Upgrades and reload#

Two mechanisms keep an existing file valid:

  1. ConfigSpec.correct() runs on every load. Missing keys are added with their defaults and out-of-range integers are clamped. This is what makes upgrading in place safe: a new key appears in your file rather than being invisible until you recreate it.
  2. applyDefaults() runs only when the file does not exist, writing the full commented file from scratch.

/viscord reload does the whole cycle off-thread: it shuts the current platform connection down, resets the manager singleton so fresh platform objects are created, re-reads the config directory, and re-initialises if general.enabled is still true. Feedback is bounced back to the server thread. If general.enabled is false at reload time you get Viscord is disabled in config. and no connection.

A reload is a reconnect

Because the platform objects are rebuilt, reload also re-registers native Discord commands and re-sends the startup embed. A reload during a busy period is visible in the channel. Prefer it over a restart, but do not loop it.

Legacy JSON migration#

If config/viscord/viscord.json exists and viscord.toml does not, Viscord migrates the old file: it writes a TOML file, copies across every key it knows how to map (including renamed paths such as formats.discord_to_minecraft → messages.discord_to_minecraft and linking.code_expiry_seconds → account_linking.code_expiry), then renames the original to viscord.json.backup. If migration throws, it logs the error and writes a default TOML file instead, leaving the JSON in place.