AOS REVIVALMenuJoin Discord
Server guide 05

config.toml reference

Every key BattleSpades reads, generated from the server's own configuration loader so nothing is missing or invented. Each entry shows what happens if you leave it out, what the shipped sample sets, and the range the server clamps it to.

Checked BattleSpades 0.1.0-beta.1Reference

How the config is loaded

  • The server reads config.toml from its own folder (not the shell's current directory) once at startup. Restart after editing.
  • --config other.toml loads another file; --port N overrides only the port for that run; --check validates everything without opening the port.
  • A missing file, or a file with a TOML syntax error, falls back to built-in defaults — a syntax error only prints a warning. Always run --check after editing.
  • Semantic mistakes stop the server with a clear error instead: unknown RULE_* names or values, an unknown default_mode, unsafe map names in map_rotation, invalid match_length_minutes, a Steam app_id other than 224540, duplicate Steam ports, a non-HTTPS base_url…
  • Numbers outside a key's range are silently clamped to the range shown below.
  • Relative paths (maps, bans.json, state/…, log file) resolve against the server folder.
  • Never save the file with a UTF-8 byte-order mark (BOM); it breaks parsing and the server falls back to defaults.

Which value wins

For match rules the narrowest setting wins: 1) a [modes.<code>] override for the running mode, 2) the [game_rules] Match Lobby rule, 3) [lobby] match_length_minutes (clocks only), 4) the recovered retail default. Old [game] keys such as respawn_time and fall_damage still work when their RULE_* equivalent is not set.

Reading an entry

  • Default if omitted — the value the code uses when the key (or its whole table) is missing. It can differ from the sample file; the reference shows both values where they differ.
  • Sample config.toml — shown only when the shipped sample file sets a different value.
  • Clamped to — the range the loader enforces. Accepted — the only allowed values.
  • Not in sample config — a valid key the sample file does not list (advanced or legacy).

Jump to a table:

TableWhat it controls
servername, port, slots, welcome message
admin · loggingadmin password, bans file, logs
revival · steamAoSPlay and Steam listing
game · lobby · teamsmode, map, rotation, votes, balance
objectives · world · audio · weaponsobjective guards, content paths, music, deprecated damage keys
botsserver bots
anticheat · conductcheat checks, griefing, AFK
network · plugins · debugadvanced budgets, plugins, diagnostics
map_creatorMap Creator launcher only
modes.<code>per-mode overrides
game_rulesthe 102 Match Lobby rules (separate page)

Server, admin and logging

[server]7 keys

Identity, listen port, capacity and the private welcome message. Every other table is optional; a key you leave out uses the default shown here.

namestring

Name shown in server browsers and the scoreboard. Clients see at most 31 characters (the retail limit); a longer name is cut and a warning is logged.

Default if omitted
"BattleSpades Server"
portinteger

UDP port for game traffic. The same socket answers A2S server-info queries. Defaults to 27015 (also used when the key is missing). Set 32887 only if players must join from the unmodified retail Steam browser, which always connects to that port. --port overrides it for one run.

Default if omitted
27015
max_playersinteger

Player slots, 1–255. The stock Match Lobby offered 2–24 and 24 is the retail-tested ceiling. Bots occupy slots too.

Default if omitted
24
Clamped to
1 – 255
tick_rateinteger

Simulation rate (clamped to 10–240). Keep 60: client physics and reconciliation are calibrated to it and other values break movement such as jumping.

Default if omitted
60
Clamped to
10 – 240
steam_idinteger

Stable 64-bit server identity sent to clients and in A2S replies when the server is not registered with Steam. Leave the sample value unless you know you need another one.

Default if omitted
90087911866072060
Clamped to
≥ 0
join_greetingstringnot in sample config

Private chat line sent once per connection after the player finishes loading. Tokens: {player}, {release}, {build_date}. An empty string disables it.

Default if omitted
"Welcome, {player}! {release} | Build (UTC): {build_date}"
motdarraynot in sample config

Message of the day: a string or an array of lines sent after the greeting. Setting it replaces the default Revival lines; [] disables it.

Default if omitted
["Dig in. Build big. Server + client: an open AoS Revival project | https://aosplay.net", "Server: https://github.com/KikoTs/BattleSpades", "Client: https://github.com/KikoTs/BattleSpadesClient"]

[admin]3 keys

The in-game /admin password, command logging and the ban list file.

passwordstring

Password for /admin <password>. Login is disabled while it is changeme, empty, or shorter than 12 characters. Containers take it from BATTLESPADES_ADMIN_PASSWORD.

Default if omitted
"changeme"
log_commandsboolean

Log every command use (the /admin password is always redacted).

Default if omitted
true
bans_pathstring

Ban list file (JSON, keyed by IP address). Survives restarts.

Default if omitted
"bans.json"

[logging]8 keys

Log level, file, rotation and packet-trace diagnostics. Files live in the logs/ folder next to the server.

levelstring

Python log level: DEBUG, INFO, WARNING, ERROR.

Default if omitted
"INFO"
filestring

Log file name, relative to the logs/ folder (absolute paths are used as given).

Default if omitted
"server.log"
consoleboolean

Also print logs to the console.

Default if omitted
true
packet_traceboolean

Full packet parsing and hex dumps. Reverse-engineering only; very large logs.

Default if omitted
false
queue_capacityinteger

Log records buffered for the background writer; when full, records are dropped instead of stalling the game.

Default if omitted
8192
Clamped to
≥ 256
max_bytesinteger

Rotate the log at this size (1 MB–1 GB).

Default if omitted
16777216
Clamped to
1048576 – 1073741824
backup_countinteger

Rotated log files kept (1–10).

Default if omitted
3
Clamped to
1 – 10
suppress_packetsarray

Packet IDs hidden from debug packet logs (2 = WorldUpdate, 4 = ClientData, 11 = SetColor).

Default if omitted
[2, 4, 11]
Sample config.toml
[2, 4, 11, 56, 57]

AoSPlay and Steam listing

Step-by-step setup is in Ports and public listing.

[revival]10 keys

The AoSPlay (Revival) server list, player identity tickets, and round results for account progression. The write credential is never read from this file: set AOS_MASTER_WRITE_TOKEN in the server's environment.

enabledboolean

Publish to the AoSPlay server list, accept Revival join tickets and upload round results. It stays off (with a warning) until AOS_MASTER_WRITE_TOKEN is set in the environment.

Default if omitted
true
base_urlstring

AoSPlay API origin. Must be HTTPS (plain HTTP only for localhost). AOS_MASTER_URL overrides it.

Default if omitted
"https://www.aosplay.net"
public_hoststring

Public IPv4 address or DNS name players use to reach you; used in the listing and the server ID. Replace 127.0.0.1 before going public. AOS_PUBLIC_HOST overrides it.

Default if omitted
"127.0.0.1"
server_idstring

Listing identifier. Blank derives public_host:port; if you set it, it must equal exactly that. AOS_SERVER_ID overrides it.

Default if omitted
""
regionstring

Region shown in the AoSPlay list (ASCII token, up to 31 characters).

Default if omitted
"europe"
results_pathstring

SQLite outbox of round results waiting to be uploaded. Keep it across upgrades; unsent results retry with their original IDs.

Default if omitted
"state/round-results.sqlite3"
officialboolean

Official-listing flag in heartbeats. Community-registered servers are always shown as community regardless of this value.

Default if omitted
false
require_identityboolean

Reject players who connect without a valid Revival or Steam identity ticket (legacy/unranked clients).

Default if omitted
false
heartbeat_interval_secondsnumber

Heartbeat period (15–60 s). Population changes are also published within seconds.

Default if omitted
30
Clamped to
15 – 60
request_timeout_secondsnumber

HTTP timeout for AoSPlay requests (1–15 s).

Default if omitted
5
Clamped to
1 – 15

[steam]18 keys

Optional registration in the original retail Steam server browser through an isolated 32-bit helper. Off by default; direct connections and the AoSPlay list work without it. Valve DLLs are never bundled.

enabledboolean

Start the isolated Steam browser registrar. Needs the original 32-bit steam_api.dll in steam-runtime/ (Windows). The Linux container always forces this off.

Default if omitted
false
app_idinteger

Must stay 224540 (Ace of Spades). Startup rejects any other value, including Spacewar's 480.

Default if omitted
224540
runtime_dirstring

Folder containing the original x86 steam_api.dll. Blank uses ./steam-runtime or the BATTLESPADES_STEAM_RUNTIME environment variable.

Default if omitted
""
steamclient_dirstring

Folder with a compatible x86 steamclient.dll, tier0_s.dll and vstdlib_s.dll. Blank auto-discovers an installed desktop Steam.

Default if omitted
""
helper_pathstring

Override for the bundled x86 bridge helper. Blank uses the bundled one.

Default if omitted
""
use_supplied_steamclientboolean

Copy a supplied steamclient.dll into the runtime. Keep false: the small legacy DLL from old client folders was measured hanging during Steam initialisation.

Default if omitted
false
steam_portinteger

Steam updater/master UDP port (retail used 8766). Forward it when Steam listing is on.

Default if omitted
8766
query_portinteger

Steam A2S query UDP port; 0 means game port + 1. The game, Steam and query ports must all be different. Forward it when Steam listing is on.

Default if omitted
0
publicboolean

true lists publicly; false selects LAN / no-master mode.

Default if omitted
true
secureboolean

Requests VAC mode from the registrar. Leave false: the legacy ticket handshake is not VAC validation. Requires public = true.

Default if omitted
false
regionstring

Optional retail region tag (ASCII letters, digits, _ . -, up to 31 characters).

Default if omitted
""
game_versionstring

Advertised game version; the original value is 1.0.0.0.

Default if omitted
"1.0.0.0"
protocol_versioninteger

Advertised protocol tag; retail clients speak 168.

Default if omitted
168
Clamped to
≥ 0
playlist_idinteger

Playlist tag in the retail browser filter string.

Default if omitted
8
Clamped to
≥ 0
texture_skinstring

Skin tag; blank auto-selects the mafia skin for VIP and Territory Control.

Default if omitted
""
require_registrationboolean

When true, startup fails unless Steam logon completes within startup_timeout_seconds. False (recommended) keeps the game running during a Steam outage.

Default if omitted
false
startup_timeout_secondsnumber

How long startup waits for Steam logon (1–60 s).

Default if omitted
8
Clamped to
1 – 60
publish_interval_secondsnumber

How often name/map/population changes are pushed to Steam (0.25–10 s). Runs outside the simulation.

Default if omitted
1
Clamped to
0.25 – 10

Game, lobby and teams

Modes, rotation and votes are explained in Game modes and maps.

[game]12 keys

Startup mode and map plus core simulation switches. Several older keys here are compatibility aliases for [game_rules] entries.

default_modestring

Mode at startup. Accepts the short codes listed here or their aliases (zombie, occupation, classic_ctf, …). An unknown value stops the server with the list of valid names.

Default if omitted
"tdm"
Accepted
arenacctfctfdemdiamhoctctdmvipzom
default_mapstring

Startup map: a .vxl file name from the maps folder, without the extension. If omitted the server starts on MayanJungle.

Default if omitted
"MayanJungle"
respawn_timenumbernot in sample config

Legacy alias for RULE_RESPAWN_TIMES. Used only when that rule is not set in [game_rules].

Default if omitted
5
friendly_fireboolean

Allow damage to teammates.

Default if omitted
false
fall_damageboolean

Land fall damage. Water landings are controlled separately by RULE_ENABLE_FALL_ON_WATER_DAMAGE.

Default if omitted
true
build_damageboolean

Allow weapons and explosions to damage and destroy blocks.

Default if omitted
true
score_limitintegernot in sample config

Legacy generic score limit. Each mode uses its own rule (RULE_*_SCORE_TARGET); this value is only an A2S fallback.

Default if omitted
10
Clamped to
≥ 0
radar_station_lifetime_secondsnumber

How long a deployed radar station lasts (retail 45 s; 1–250).

Default if omitted
45
Clamped to
1 – 250
same_team_collisionboolean

Whether teammates physically block each other. Sent to clients so prediction matches.

Default if omitted
false
bot_countinteger

Legacy fixed bot count, used only when the config has no [bots] table.

Default if omitted
0
movement_authoritystring

server (production): the server simulates every player. client echoes client positions and exists only for diagnostics.

Default if omitted
"server"
Accepted
serverclient
map_sync_modestring

Keep full. auto (delta sync) is experimental and leaves the client world incomplete.

Default if omitted
"full"
Accepted
autofull

[lobby]16 keys

Match length, map rotation and voting, end-of-round presentation, and kick-vote limits.

match_length_minutesunknownnot in sample config

Optional clock for every mode, in minutes. Only the stock lobby choices are accepted: 5, 10, 15 … 60 (steps of 5) or 90. A [modes.<code>].time_limit still wins. Leave it commented out to use each mode's retail clock.

Default if omitted
unset
map_rotationarray

Maps offered in the end-of-round vote. Empty uses the mode's retail playlist; if none of those maps is installed, every .vxl in the maps folder. Missing files are skipped with a log line and maps retail marks invalid for the mode are dropped.

Default if omitted
[]
map_rotation_shuffleboolean

Shuffle the map list once at startup, like the retail lobby did.

Default if omitted
true
map_vote_retail_max_playersboolean

Offer maps whose retail player cap is below the current human count only after maps that fit.

Default if omitted
true
end_screen_secondsnumber

How long the scores screen stays up after the vote before the next map loads (0–120 s).

Default if omitted
12
Clamped to
0 – 120
end_round_scoreboardboolean

Hold the scoreboard open at round end.

Default if omitted
true
end_round_headlineboolean

Show the retail round-result headline (“{team} wins!”, “Draw!”) on the scoreboard.

Default if omitted
true
map_vote_size_fitboolean

Offer maps sized for the current player count first.

Default if omitted
true
map_vote_area_per_playernumber

Playable columns wanted per player when ranking maps by size.

Default if omitted
8000
Clamped to
1 – 262144
map_vote_min_areanumber

Minimum ideal map area regardless of player count.

Default if omitted
24000
Clamped to
0 – 262144
map_vote_recent_excludeinteger

The last N played maps are offered last.

Default if omitted
2
Clamped to
0 – 32
map_vote_bot_weightnumber

How much a bot counts as a player for map sizing (0–1).

Default if omitted
1
Clamped to
0 – 1
votekick_cooldown_secondsnumber

How long a player (by address) must wait before starting another kick vote. Retail: 300 s.

Default if omitted
300
Clamped to
0 – 3600
votekick_cancelled_cooldown_secondsnumber

Shorter wait after the starter cancels their own vote. Retail: 45 s.

Default if omitted
45
Clamped to
0 – 3600
votekick_min_team_playersinteger

Players (bots included) the starter's team needs before a kick vote can start. Retail: 3; 0 disables the check.

Default if omitted
3
Clamped to
0 – 32
map_size_overridestable

Pin a map's size used by the vote ranking: an area (columns) or small / medium / large, e.g. { WW1 = "large", DragonIsland = 27000 }.

Default if omitted
{}

[teams]11 keys

Team names, colours, and automatic team balancing at join time and during a match.

team1_namestring

Team name as a client string-table ID. Keep TEAM1_COLOR (shown as “Blue”); literal text shows as “Missing string …” in game.

Default if omitted
"TEAM1_COLOR"
team2_namestring

Keep TEAM2_COLOR (shown as “Green”).

Default if omitted
"TEAM2_COLOR"
team1_colorarray

RGB colour of team 1 (retail blue). Pure RGB values make HUD and blocks glow.

Default if omitted
[44, 117, 179]
team2_colorarray

RGB colour of team 2 (retail green).

Default if omitted
[137, 179, 44]
auto_balanceboolean

A joiner who picks a team already balance_threshold players larger is placed on the smaller team, and team switches that would unbalance are refused.

Default if omitted
true
balance_thresholdinteger

Player difference that counts as unbalanced.

Default if omitted
2
balance_mid_matchboolean

Also repair imbalance during a match (for example after players leave).

Default if omitted
true
balance_grace_secondsnumber

How long an imbalance must last before anyone is moved.

Default if omitted
5
Clamped to
0 – 600
balance_player_cooldownnumber

A human is never moved twice within this many seconds.

Default if omitted
600
Clamped to
0 – 86400
balance_bot_wait_secondsnumber

After a dead bot fails to fix the imbalance, wait this long before retiring and replacing a bot.

Default if omitted
10
Clamped to
0 – 600
balance_check_intervalnumber

How often the balancer checks, in seconds.

Default if omitted
1
Clamped to
0.1 – 60

[objectives]10 keys

Escape watch (marking players who leave the playable map) and guards that keep intel, diamonds and bombs obtainable.

escape_watch_enabledboolean

Mark players who leave the playable map on the enemy minimap so they can be hunted.

Default if omitted
true
objective_pickup_ends_spawn_protectionboolean

Picking up an objective ends spawn protection.

Default if omitted
true
objective_pickup_requires_losboolean

Objectives cannot be picked up through walls or floors.

Default if omitted
true
escape_watch_intervalnumber

Check period in seconds.

Default if omitted
1
Clamped to
0.1 – 60
escape_watch_embedded_secondsnumber

Time inside solid terrain before a player is marked.

Default if omitted
3
Clamped to
0 – 600
escape_watch_entomb_secondsnumber

Time an objective carrier, VIP, survivor or zone holder may stay sealed in a tiny pocket before being marked.

Default if omitted
5
Clamped to
0 – 600
escape_watch_sky_secondsnumber

Time above the map top before a player is marked.

Default if omitted
5
Clamped to
0 – 600
objective_entomb_secondsnumber

An intel, diamond or bomb that is buried, sealed or floating this long is returned or resettled.

Default if omitted
5
Clamped to
0 – 600
objective_afk_secondsnumber

Players without input this long stop counting towards holding a Territory Control or Multi-Hill zone. 0 disables.

Default if omitted
60
Clamped to
0 – 3600
ctf_base_pit_depthnumber

A CTF carrier in an open pit dug up to this many blocks below its base still scores.

Default if omitted
24
Clamped to
0 – 240

[world]10 keys

Content folders and fallback atmosphere. Map sidecar metadata (fog, skybox) overrides the fallbacks for maps that have it.

map_size_xinteger

Informational only. Maps are always 512 × 512 × 240; a different value is ignored with a warning.

Default if omitted
512
map_size_yinteger

Informational only. Maps are always 512 × 512 × 240; a different value is ignored with a warning.

Default if omitted
512
map_size_zinteger

Informational only. Maps are always 512 × 512 × 240; a different value is ignored with a warning.

Default if omitted
240
water_levelintegernot in sample config

Ignored (with a warning). The water plane is fixed by the map format.

Default if omitted
238
water_damagebooleannot in sample config

Ignored (with a warning). Retail has no water damage.

Default if omitted
true
default_skyboxstring

Skybox for maps without their own sidecar. Must name a stock client environment file.

Default if omitted
"User_Grassland.txt"
maps_pathstring

Folder containing .vxl maps (relative to the server folder).

Default if omitted
"maps"
prefabs_pathstring

Folder containing .kv6 prefabs.

Default if omitted
"prefabs"
entities_wire_readyboolean

Send map entities (crates, intel) to clients. Keep true.

Default if omitted
true
fog_color_rgbarray

Fallback fog colour; a map's own metadata wins.

Default if omitted
[12, 13, 11]

[audio]1 keys

Server-driven music.

mode_start_musicboolean

Play a looping in-round music bed at round start and for joiners. A deliberate deviation: retail rounds were silent (map ambience only) until the final minute. Set false for retail behaviour.

Default if omitted
true

[weapons]5 keys

Legacy damage keys. They are still parsed but no gameplay code reads them: weapon damage comes from the recovered retail weapon tables, scaled by RULE_WEAPON_DAMAGE.

rifle_damageintegernot in sample config

Deprecated and ignored: damage comes from the retail per-weapon tables. Setting it logs a warning; remove the [weapons] table.

Default if omitted
49
smg_damageintegernot in sample config

Deprecated and ignored: damage comes from the retail per-weapon tables. Setting it logs a warning; remove the [weapons] table.

Default if omitted
29
shotgun_damageintegernot in sample config

Deprecated and ignored: damage comes from the retail per-weapon tables. Setting it logs a warning; remove the [weapons] table.

Default if omitted
27
spade_damageintegernot in sample config

Deprecated and ignored: damage comes from the retail per-weapon tables. Setting it logs a warning; remove the [weapons] table.

Default if omitted
50
grenade_damageintegernot in sample config

Deprecated and ignored: damage comes from the retail per-weapon tables. Setting it logs a warning; remove the [weapons] table.

Default if omitted
100

Bots

Practical recipes are in the bots guide.

[bots]22 keys

Server-owned bots. Their decisions and pathfinding run in a worker thread or process outside the 60 Hz simulation.

enabledboolean

Turn server bots on. Note that a [bots] table without this key means disabled.

Default if omitted
false
Sample config.toml
true
population_modestring

backfill: keep humans + bots near fill_target. fixed: always run max_bots. admin: only what admins add with /bots.

Default if omitted
"backfill"
Accepted
backfillfixedadmin
fill_targetinteger

Backfill target: bots are added until playing humans (spectators do not count) plus bots reach this number.

Default if omitted
12
Clamped to
≥ 0
max_botsinteger

Hard cap on bots (and the count used by fixed mode).

Default if omitted
12
Clamped to
≥ 0
reserve_human_slotsinteger

Slots always kept free for joining humans; at least 1 is always reserved in every mode. When a human joins a full server a bot leaves.

Default if omitted
2
Clamped to
≥ 0
difficultystring

Skill of newly created bot profiles: casual, normal, hard, or mixed.

Default if omitted
"mixed"
Accepted
casualnormalhardmixed
workerstring

thread uses less memory for one casual instance. process isolates a worker crash and is what every official fleet profile uses.

Default if omitted
"thread"
Accepted
threadprocess
perception_hznumber

How often bots perceive the world (1–30 Hz).

Default if omitted
10
Clamped to
1 – 30
decision_hznumber

How often bots decide (1 Hz up to perception_hz).

Default if omitted
8
Clamped to
1 – bots.perception_hz
path_requests_per_secondinteger

Pathfinding request budget.

Default if omitted
24
Clamped to
≥ 1
main_thread_budget_msnumber

Main-thread time allowed per tick for applying bot intentions.

Default if omitted
0.75
Clamped to
≥ 0.1
seedinteger

Random seed for bot behaviour; 0 is the default.

Default if omitted
0
behavior_versionstring

cooperative tactical squads (default) or classic for the older behaviour layer.

Default if omitted
"cooperative"
Accepted
classiccooperative
friendly_mischiefboolean

Allow harmless playful behaviour towards teammates.

Default if omitted
true
chatterboolean

Occasional, rate-limited bot chat after kills, deaths and round events.

Default if omitted
true
debug_visualizationboolean

Enable /bots debug snapshots. Off in production.

Default if omitted
false
clean_slate_gamesinteger

Recycle the bot planner after this many games/map changes to keep memory flat. 0 disables recycling; per-round state is always reset.

Default if omitted
3
Clamped to
≥ 0
skill_balanceboolean

When one team's humans clearly out-kill the other side, ease that team's bots and sharpen the other team's.

Default if omitted
true
skill_balance_max_shiftnumber

Largest change to any bot profile field (0–0.9).

Default if omitted
0.35
Clamped to
0 – 0.9
skill_balance_ratenumber

Change per second while balancing.

Default if omitted
0.03
Clamped to
0 – 1
skill_balance_deadbandnumber

Kill-ratio edge ignored as noise (0–0.95).

Default if omitted
0.15
Clamped to
0 – 0.95
skill_balance_min_eventsinteger

Kills + deaths a team needs before balancing starts.

Default if omitted
6
Clamped to
1 – 1000

Anti-cheat and conduct

How to use these in practice: Admin and moderation.

[anticheat]44 keys

Server-side validation switches and the statistical suspicion report. Checks that could punish honest players on bad connections ship log-only (enforce_* = false).

accuracy_min_marginnumber

…and must also beat the median by at least this much.

Default if omitted
0.15
Clamped to
0 – 1
accuracy_min_populationinteger

Other players with data needed for the comparison.

Default if omitted
20
Clamped to
≥ 0
accuracy_min_shotsinteger

Shots with a weapon before its accuracy is compared.

Default if omitted
100
Clamped to
≥ 0
accuracy_percentilenumber

Accuracy above this percentile of the population is suspicious…

Default if omitted
99
Clamped to
0 – 100
admin_login_attemptsinteger

Wrong /admin passwords from one address before the player is kicked and the address banned for 10 minutes.

Default if omitted
3
Clamped to
≥ 0
aim_direction_tolerance_degnumber

Allowed aim difference in degrees.

Default if omitted
10
Clamped to
≥ 0
backlog_max_framesinteger

Queued input frames tolerated.

Default if omitted
6
Clamped to
≥ 0
enforce_aim_directionboolean

Reject shots whose direction disagrees with that frame's aim. Log-only when false.

Default if omitted
false
enforce_block_intervalbooleannot in sample config

Enforce the retail minimum of 0.1 s between one player's block builds. Log-only when false. Not in the sample config.

Default if omitted
false
enforce_input_backlogboolean

Catch up players whose input queue stays too long (fake lag). Log-only when false.

Default if omitted
false
enforce_input_starvationboolean

Make airborne players fall and time out completely silent clients when input stops arriving. Log-only when false.

Default if omitted
false
enforce_shot_originboolean

Reject shots, throws and builds whose origin is too far from the server's eye position for that frame. Log-only when false.

Default if omitted
false
engage_cone_degnumber

Engagement cone used by the aim signals.

Default if omitted
4
Clamped to
≥ 0
flag_min_scorenumber

Suspicion score at which a player is flagged.

Default if omitted
1
Clamped to
≥ 0
headshot_hit_min_hitsinteger

…after at least this many hits.

Default if omitted
60
Clamped to
≥ 0
headshot_hit_rationumber

Flag when headshots exceed this share of single-ray hits…

Default if omitted
0.55
Clamped to
0 – 1
headshot_kill_min_killsinteger

…after at least this many hitscan kills.

Default if omitted
30
Clamped to
≥ 0
headshot_kill_rationumber

Flag when headshots exceed this share of hitscan kills…

Default if omitted
0.6
Clamped to
0 – 1
kick_on_protocol_violationboolean

Kick immediately for packets the stock client never sends (NaN values, forged tools, impossible packets).

Default if omitted
true
pellet_seed_min_shotsinteger

Shotgun shots needed for the pellet-seed signal.

Default if omitted
64
Clamped to
≥ 0
pellet_seed_top_sharenumber

Pellet-seed skew threshold.

Default if omitted
0.2
Clamped to
0 – 1
reaction_acquire_degnumber

Angle that counts as having acquired a target.

Default if omitted
10
Clamped to
≥ 0
reaction_history_framesinteger

Frames of aim history used to measure reaction time.

Default if omitted
60
Clamped to
1 – 600
reaction_median_msnumber

Median reaction time below this is suspicious.

Default if omitted
90
Clamped to
≥ 0
reaction_min_samplesinteger

Reaction samples needed.

Default if omitted
15
Clamped to
≥ 0
reaction_reengage_secondsnumber

A target counts as new again after this long.

Default if omitted
3
Clamped to
≥ 0
report_backupsinteger

Rotated report files kept.

Default if omitted
3
Clamped to
0 – 20
report_enabledboolean

Write the statistical suspicion report. It only flags players, never kicks.

Default if omitted
true
report_max_bytesinteger

Rotate the report at this size.

Default if omitted
5000000
Clamped to
4096 – 1073741824
report_pathstring

Report file (JSON lines). Review it in game with /acreport and /acstats.

Default if omitted
"logs/anticheat.jsonl"
shot_origin_tolerancenumber

Allowed origin error in blocks.

Default if omitted
1.5
Clamped to
≥ 0
snap_framesinteger

…within this many frames…

Default if omitted
2
Clamped to
1 – 30
snap_head_radiusnumber

…ending within this radius of a head…

Default if omitted
0.35
Clamped to
≥ 0
snap_margin_degnumber

…with this angular margin.

Default if omitted
0.75
Clamped to
≥ 0
snap_min_degnumber

An aim snap is a turn of at least this many degrees…

Default if omitted
20
Clamped to
≥ 0
snap_min_engagedinteger

Engagements needed before the snap ratio counts.

Default if omitted
20
Clamped to
≥ 0
snap_min_eventsinteger

Snaps needed before the signal counts.

Default if omitted
4
Clamped to
≥ 0
snap_rationumber

Share of engagements that are snaps before flagging.

Default if omitted
0.1
Clamped to
0 – 1
starvation_airborne_ticksinteger

Starved ticks before an airborne player falls.

Default if omitted
24
Clamped to
≥ 0
starvation_timeout_secondsnumber

Silence before a client times out.

Default if omitted
8
Clamped to
≥ 0
summary_interval_secondsnumber

Per-player summary log period, and the suspicion report's evaluation period.

Default if omitted
60
Clamped to
≥ 0
sustained_min_countinteger

…minimum violations in that window…

Default if omitted
20
Clamped to
≥ 0
sustained_min_minutesnumber

Window for sustained log-only violations…

Default if omitted
5
Clamped to
≥ 0
sustained_per_minutenumber

…and minimum rate per minute.

Default if omitted
3
Clamped to
≥ 0

[conduct]15 keys

Team-griefing and AFK kicks, and reserved player names.

afk_exempt_adminsboolean

Logged-in admins are never AFK-kicked.

Default if omitted
true
afk_kick_secondsnumber

Kick after this long without real input (movement keys, fire, aim). The clock pauses while loading, dead, or between rounds. 0 disables.

Default if omitted
600
Clamped to
≥ 0
afk_spectator_kick_secondsnumber

AFK limit for spectators; 0 exempts them.

Default if omitted
1800
Clamped to
≥ 0
afk_warn_secondsnumber

Private warning before the AFK kick.

Default if omitted
540
Clamped to
≥ 0
announce_kicksboolean

Announce grief/AFK kicks in system chat.

Default if omitted
true
grief_decay_secondsnumber

One grief point decays every this many seconds.

Default if omitted
60
Clamped to
≥ 0
grief_exempt_adminsboolean

Logged-in admins never earn grief points (bots never do).

Default if omitted
true
grief_incident_max_pointsnumber

…capped at this many points, so one accident cannot kick alone.

Default if omitted
6
Clamped to
≥ 0
grief_incident_secondsnumber

Everything within this window counts as one incident…

Default if omitted
3
Clamped to
≥ 0
grief_kick_enabledboolean

Kick team griefers. When false, points and warnings still happen but nobody is kicked.

Default if omitted
true
grief_kick_pointsnumber

Grief points that trigger the kick (retail reason “kicked for griefing”).

Default if omitted
10
Clamped to
≥ 0
grief_team_damage_pointsnumber

Points per 100 HP of damage to teammates.

Default if omitted
1
Clamped to
≥ 0
grief_team_kill_pointsnumber

Points per team kill, including deaths caused by setting off a teammate's landmine.

Default if omitted
3
Clamped to
≥ 0
grief_warn_pointsnumber

Grief points that trigger a private warning.

Default if omitted
5
Clamped to
≥ 0
reserved_namesarray

Extra names nobody may use, on top of the built-in Server, Admin, Console, System, Moderator, BattleSpades and similar. Look-alike names are caught too.

Default if omitted
[]

Network, plugins and debug

[network]36 keys

ENet admission and per-tick work budgets, lag compensation, and terrain repair. The shipped values are measured production defaults; most operators never change this table.

timeout_msintegernot in sample config

Ignored. Accepted for old configs; a non-default value logs a warning. Retail and this server keep ENet's default peer timeout.

Default if omitted
10000
max_connectionsinteger

ENet peer limit for the listen socket.

Default if omitted
64
bandwidth_limitintegernot in sample config

Ignored, like timeout_ms. ENet keeps unlimited (0/0) bandwidth.

Default if omitted
0
require_protocol_versionboolean

Refuse clients that do not connect with protocol 168, with the retail client-out-of-date or server-out-of-date message.

Default if omitted
true
event_budgetinteger

Maximum ENet events handled per network pump.

Default if omitted
512
Clamped to
≥ 32
max_pending_packetsinteger

Receive queue bound before packets are dropped.

Default if omitted
4096
Clamped to
≥ 256
packet_drain_budgetinteger

Gameplay packets processed per tick.

Default if omitted
4096
Clamped to
≥ 64
plugin_event_budget_msnumber

Total time plugin callbacks may take per event; remaining callbacks are skipped so plugins cannot stall a tick.

Default if omitted
2
Clamped to
≥ 0.1
max_map_mutation_journalinteger

Terrain changes remembered for a player who is still downloading the map. Overflow makes that join unsafe and it is refused instead of desynced.

Default if omitted
8192
Clamped to
≥ 64
map_air_catchup_batch_limitinteger

Blocks re-sent per input frame when catch-up is enabled.

Default if omitted
256
Clamped to
≥ 1
map_air_catchup_enabledboolean

Re-send every destroyed block to joiners after they spawn. Off: the map download already contains all edits, and this made joiners watch terrain change after spawning.

Default if omitted
false
unreliable_throttle_decelerationintegernot in sample config

ENet's unreliable-packet throttle step. 0 keeps every 30 Hz world update flowing to players on jittery links.

Default if omitted
0
Clamped to
0 – 32
entity_tick_batch_limitinteger

Upper bound of entity behaviour updates per tick.

Default if omitted
8192
Clamped to
≥ 64
mode_event_queue_limitinteger

Queued game-mode events before new ones are dropped (and counted).

Default if omitted
8192
Clamped to
≥ 64
mode_event_drain_budgetinteger

Game-mode events processed per tick.

Default if omitted
512
Clamped to
≥ 1
world_mutation_queue_limitinteger

Pending block edits kept per server.

Default if omitted
2048
Clamped to
≥ 64
world_mutation_batch_limitinteger

Block-edit requests committed per tick.

Default if omitted
256
Clamped to
≥ 1
world_mutation_cell_budgetinteger

Voxel cells changed per tick by block edits.

Default if omitted
4096
Clamped to
≥ 64
world_mutation_timeout_ticksinteger

Ticks a block edit may wait for its movement frame before it is discarded.

Default if omitted
180
Clamped to
≥ 30
prefab_queue_limitinteger

Prefab placements waiting to commit.

Default if omitted
32
Clamped to
1 – 128
prefab_cell_batch_limitinteger

Map Creator (UGC) model cells committed per tick.

Default if omitted
16
Clamped to
1 – 128
prefab_competitive_cell_budgetinteger

Cells of competitive prefabs committed per tick across all players. A prefab always commits whole; extra prefabs wait a tick.

Default if omitted
2048
Clamped to
64 – 8192
prefab_validation_batch_limitinteger

Prepared Map Creator prefab cells checked against the world per tick.

Default if omitted
1024
Clamped to
64 – 4096
prefab_health_state_batchinteger

Damaged block/prefab health rows per packet sent to a joining player.

Default if omitted
128
Clamped to
1 – 4096
lag_compensation_enabledboolean

Check hitscan and melee hits against where the shooter saw the target (one round trip ago). Only hitboxes are rewound.

Default if omitted
true
lag_compensation_max_msnumber

Hard cap on rewind time.

Default if omitted
250
Clamped to
0 – 1000
lag_compensation_extra_msnumber

Rewind never exceeds the shooter's round trip plus this margin.

Default if omitted
50
Clamped to
0 – 250
lag_compensation_view_delay_msnumber

Extra view delay added to the rewind. Keep 0: the retail client extrapolates remote players.

Default if omitted
0
Clamped to
0 – 250
terrain_repair_enabledboolean

Later re-send the true state of blocks whose client-side prediction was rejected, so clients converge.

Default if omitted
true
terrain_repair_queue_limitinteger

Pending terrain repairs.

Default if omitted
8192
Clamped to
≥ 64
terrain_repair_batch_limitinteger

Cells repaired per repair pass.

Default if omitted
8
Clamped to
≥ 1
terrain_repair_interval_ticksinteger

Ticks between repair passes.

Default if omitted
3
Clamped to
≥ 1
terrain_repair_delay_ticksinteger

Quiet period before a repair is sent.

Default if omitted
120
Clamped to
≥ 1
terrain_collapse_repair_batch_limitinteger

Cells confirmed per pass after a structure collapse.

Default if omitted
8
Clamped to
≥ 1
terrain_collapse_repair_delay_ticksinteger

Delay before collapse confirmations start (18 ticks = 0.3 s).

Default if omitted
18
Clamped to
≥ 1
transition_grace_secondsnumber

Time between the map-ended packet and closing old sessions on a map change, so retail clients reach the reconnect screen.

Default if omitted
1.25
Clamped to
0 – 5

[plugins]4 keys

Trusted local Python plugins loaded at startup. Plugins are not sandboxed.

enabledboolean

Load plugins from the plugin folder at startup.

Default if omitted
true
pathstring

Plugin folder. Public top-level .py files containing a BasePlugin subclass are loaded; files starting with _ are skipped.

Default if omitted
"plugins"
allowlistarray

If not empty, only these plugins load (file stem or plugin name).

Default if omitted
[]
denylistarray

Plugins that never load. Always wins over the allowlist.

Default if omitted
[]

[debug]22 keys

Reverse-engineering and netcode calibration controls. Keep every shipped value in production.

debug_parityboolean

Physics parity capture over a local UDP socket. Reverse-engineering only.

Default if omitted
false
debug_parity_hoststring

Parity capture address.

Default if omitted
"127.0.0.1"
debug_parity_portinteger

Parity capture port.

Default if omitted
32895
debug_parity_queue_capacityinteger

Parity capture queue bound.

Default if omitted
256
Clamped to
≥ 64
debug_parity_sample_hznumber

Parity sample rate.

Default if omitted
10
Clamped to
0.1 – 10
debug_parity_flush_intervalnumber

Parity capture flush period.

Default if omitted
1
Clamped to
≥ 0.1
debug_parity_flush_batchinteger

Parity records per flush.

Default if omitted
128
Clamped to
≥ 1
broadcast_world_updatesboolean

A/B switch; false stops all position updates. Keep true.

Default if omitted
true
worldupdate_broadcast_intervalinteger

Ticks between world updates (2 = retail 30 Hz).

Default if omitted
2
Clamped to
≥ 1
worldupdate_include_selfboolean

Send each player their own correction row. Required by the stock client.

Default if omitted
true
worldupdate_loop_offsetinteger

Self-row stamp offset. Keep 0.

Default if omitted
0
worldupdate_self_row_intervalinteger

Ticks between grounded self rows.

Default if omitted
2
Clamped to
≥ 1
worldupdate_airborne_self_row_intervalinteger

Ticks between airborne self rows.

Default if omitted
6
Clamped to
≥ 1
jetpack_owner_handoff_input_framesinteger

Jetpack correction hand-off window.

Default if omitted
30
Clamped to
0 – 120
jetpack_owner_release_handoff_input_framesinteger

Jetpack release hand-off cap.

Default if omitted
600
Clamped to
0 – 1200
jetpack_activation_defer_framesinteger

Frames thrust starts after activation is announced.

Default if omitted
2
Clamped to
0 – 30
jetpack_exhaustion_tail_framesinteger

Frames thrust continues after exhaustion is announced.

Default if omitted
3
Clamped to
0 – 30
debug_selfrowboolean

Write self-row samples for offline calibration. Debug only.

Default if omitted
false
movement_debug_captureboolean

Movement capture. Debug only.

Default if omitted
false
movement_input_latch_framesinteger

Retail input latch (0 or 1). Keep 1.

Default if omitted
1
Clamped to
0 – 1
input_gap_fill_limitinteger

Refill up to this many lost client input frames so a dropped packet does not leave the server a frame behind (0–9).

Default if omitted
8
Clamped to
0 – 9
clock_sync_loop_biasinteger

Clock-sync bias. Keep 0.

Default if omitted
0

Map Creator launcher

[map_creator]10 keys

Read only by the separate Map Creator launcher (run_map_creator.py / BattleSpadesMapCreator). The normal game server ignores this table. Command-line flags override these values.

authornot in sample config

Author credit for a new project.

Default if omitted
—
descriptionnot in sample config

Description for a new project.

Default if omitted
—
output_dirstring

Folder where standalone projects are saved (relative paths resolve beside the executable). Mutually exclusive with publish_root.

Default if omitted
—
Sample config.toml
"ugc-projects"
prefab_setnot in sample config

Prefab set index for a new project, 0–5.

Default if omitted
—
projectstring

Project name to open or create. An existing .ugc/.vxl/.txt triplet with this name is reopened.

Default if omitted
"MyUGCMap"
publish_rootstring

Instead of output_dir: the client's hosted_ugc folder, so saved maps appear in the stock Publish Map screen.

Default if omitted
—
Sample config.toml
""
retail_rootstring

Your legally installed Ace of Spades folder containing ugc/maps and ugc/kv6. Blank auto-discovers it. BattleSpades does not ship these retail assets.

Default if omitted
—
Sample config.toml
""
target_modestring

Mode the map is validated for: tdm, ctf, dem, mh, oc, tc, vip, zom or dia (blank keeps the project's mode, or tdm for a new one).

Default if omitted
—
Sample config.toml
""
terrainstring

Baseplate for a new project: desert, lunar, mountain, grassland, temple, urban, marsh, snowy or water (blank = grassland). Never replaces an existing map.

Default if omitted
—
Sample config.toml
""
titlenot in sample config

Display title for a new project.

Default if omitted
—

Per-mode overrides

Add a [modes.<code>] table to change one mode without touching the others. Alias table names work too ([modes.zombie] applies to zom; if both exist the short-code table wins). Keys a mode does not read are ignored.

ExampleTXT
[modes.tdm]
time_limit = 1200      # 20 minutes
score_limit = 100

[modes.zom]
infection_delay = 30.0
minimum_players = 4

[modes.tdm]Team Deathmatch

KeyWhen not setMeaning
time_limit[lobby] match_length_minutes, else 900 sRound/match clock in seconds (0 = no clock). Wins over [lobby].match_length_minutes.
score_limituses RULE_TDM_SCORE_TARGETWin threshold for the mode (kills, captures, rounds, points…).
kill_points1Team points per enemy kill.
headshot_bonus0Extra team points for a headshot kill (a custom-server option; retail gives none).

[modes.ctf]Capture the Flag

KeyWhen not setMeaning
time_limit[lobby] match_length_minutes, else 1800 sRound/match clock in seconds (0 = no clock). Wins over [lobby].match_length_minutes.
score_limituses RULE_CTF_SCORE_TARGETWin threshold for the mode (kills, captures, rounds, points…).
intel_auto_returnuses RULE_CTF_ENABLE_INTEL_AUTO_RETURN (mode default true)Dropped intel returns home by itself after a while.
intel_return_on_touchuses RULE_CTF_ENABLE_INTEL_RETURN_ON_TOUCHA defender touching dropped intel returns it immediately.
intel_in_own_base_to_scoreuses RULE_CTF_ENABLE_INTEL_IN_OWN_BASE_TO_SCOREYour own intel must be at home for a capture to count.
shoot_with_inteluses RULE_CTF_ENABLE_SHOOT_WITH_INTEL (mode default false)Carriers may shoot while holding the intel.

[modes.cctf]Classic CTF

KeyWhen not setMeaning
time_limit[lobby] match_length_minutes, else 5400 sRound/match clock in seconds (0 = no clock). Wins over [lobby].match_length_minutes.
score_limituses RULE_CTF_SCORE_TARGET (mode default 5)Win threshold for the mode (kills, captures, rounds, points…).
intel_auto_returnuses RULE_CTF_ENABLE_INTEL_AUTO_RETURN (mode default false)Dropped intel returns home by itself after a while.
intel_return_on_touchuses RULE_CTF_ENABLE_INTEL_RETURN_ON_TOUCHA defender touching dropped intel returns it immediately.
intel_in_own_base_to_scoreuses RULE_CTF_ENABLE_INTEL_IN_OWN_BASE_TO_SCOREYour own intel must be at home for a capture to count.
shoot_with_inteluses RULE_CTF_ENABLE_SHOOT_WITH_INTEL (mode default true)Carriers may shoot while holding the intel.

[modes.zom]Zombie

KeyWhen not setMeaning
time_limit[lobby] match_length_minutes, else 600 sRound/match clock in seconds (0 = no clock). Wins over [lobby].match_length_minutes.
score_limituses RULE_ZOMBIE_NOOF_ROUNDSWin threshold for the mode (kills, captures, rounds, points…).
first_infecteduses RULE_NOOF_FIRST_INFECTED_ZOMBIESPlayers infected when the Zombie round starts.
infection_delay60Seconds before the first infection.
minimum_players2Players needed before a Zombie round starts (never below 2).
zombie_respawn_time0Respawn delay for zombies.
round_intermission5Pause between rounds, in seconds.
round_respawns_per_tick4Players respawned per tick at a round restart (spreads the load).

[modes.vip]VIP

KeyWhen not setMeaning
time_limit[lobby] match_length_minutes, else 900 sRound/match clock in seconds (0 = no clock). Wins over [lobby].match_length_minutes.
score_limituses RULE_VIP_NOOF_ROUNDSWin threshold for the mode (kills, captures, rounds, points…).
selection_delay10Seconds before one VIP per team is chosen.
round_intermission7Pause between rounds, in seconds.
round_respawns_per_tick4Players respawned per tick at a round restart (spreads the load).
minimum_team_size1Players per team needed before a VIP round starts.
sudden_deathuses RULE_ENABLE_SUDDEN_DEATHVIP sudden death at the end of the clock.
vip_health_multiplieruses RULE_VIP_HEALTHVIP health multiplier.

[modes.mh]Multi-Hill

KeyWhen not setMeaning
time_limit[lobby] match_length_minutes, else 1500 sRound/match clock in seconds (0 = no clock). Wins over [lobby].match_length_minutes.
score_limit100Win threshold for the mode (kills, captures, rounds, points…).
max_active_basesuses RULE_MULTIHILL_MAX_ACTIVE_BASESZones/bases active at the same time.
base_active_timeuses RULE_BASE_ACTIVE_TIMESeconds a Multi-Hill zone stays active before moving.
capture_point_resupplytrueStanding in a held capture point refills ammo and blocks.
capture_point_refill_time10Seconds between capture-point refills.

[modes.tc]Territory Control

KeyWhen not setMeaning
time_limit[lobby] match_length_minutes, else 1500 sRound/match clock in seconds (0 = no clock). Wins over [lobby].match_length_minutes.
max_active_basesuses RULE_TC_MAX_ACTIVE_BASESZones/bases active at the same time.
capture_rateuses RULE_CAPTURE_RATECapture speed multiplier.
capture_point_resupplytrueStanding in a held capture point refills ammo and blocks.
capture_point_refill_time10Seconds between capture-point refills.

[modes.dia]Diamond Mine

KeyWhen not setMeaning
time_limit[lobby] match_length_minutes, else 900 sRound/match clock in seconds (0 = no clock). Wins over [lobby].match_length_minutes.
score_limituses RULE_DIA_SCORE_TARGETWin threshold for the mode (kills, captures, rounds, points…).
max_active_basesuses RULE_DIAMOND_MAX_ACTIVE_BASESZones/bases active at the same time.
max_active_diamondsuses RULE_MAX_ACTIVE_DIAMONDSDiamonds on the map at once.
diamond_lifetimeuses RULE_DIAMOND_LIFETIMESeconds a dropped diamond lasts.

[modes.dem]Demolition

KeyWhen not setMeaning
time_limit[lobby] match_length_minutes, else 900 sRound/match clock in seconds (0 = no clock). Wins over [lobby].match_length_minutes.
build_state_lengthuses RULE_BUILD_STATE_LENGTHDemolition build phase in seconds (0 = no build phase).

[modes.oc]Occupation

KeyWhen not setMeaning
time_limit[lobby] match_length_minutes, else 900 sRound/match clock in seconds (0 = no clock). Wins over [lobby].match_length_minutes.
score_limituses RULE_OCC_SCORE_TARGETWin threshold for the mode (kills, captures, rounds, points…).
max_active_bombsuses RULE_MAX_ACTIVE_BOMBSBombs active at once (1–3).
bomb_fuse_timeuses RULE_BOMB_FUSE_TIMEBomb fuse in seconds.

[modes.arena]Arena (BattleSpades extension)

KeyWhen not setMeaning
rounds_to_win5Arena rounds needed to win (alias: score_limit).
round_time_limit180Seconds per Arena round.
time_limit0Round/match clock in seconds (0 = no clock). Wins over [lobby].match_length_minutes.

Environment variables

Secrets and deployment-specific values can come from the environment. Variables marked “Docker image” are applied by the container entrypoint only.

VariableApplies toEffect
BATTLESPADES_SERVER_NAMEDocker imageSets [server] name (up to 64 characters accepted; clients show 31).
BATTLESPADES_PORTDocker imageSets [server] port, the UDP game and A2S port (1–65535).
BATTLESPADES_MAX_PLAYERSDocker imageSets [server] max_players (1–255).
BATTLESPADES_MODEDocker imageSets [game] default_mode (a mode code or alias).
BATTLESPADES_MAPDocker imageSets [game] default_map. A map name, never a path.
BATTLESPADES_BOT_COUNTDocker imageFixed bot population (0–254): sets [bots] to fixed with this many bots, or disables bots at 0.
BATTLESPADES_REGIONDocker imageSets [revival] region.
BATTLESPADES_OFFICIALDocker imageSets [revival] official (true/false, yes/no, on/off, 1/0).
BATTLESPADES_REQUIRE_IDENTITYDocker imageSets [revival] require_identity.
BATTLESPADES_REVIVAL_ENABLEDDocker imageSets [revival] enabled. Use false for a private test container.
BATTLESPADES_ADMIN_PASSWORDDocker imageSets [admin] password; must be at least 12 characters. The container refuses to start while the password is still changeme.
BATTLESPADES_ALLOW_INSECURE_DEFAULTSDocker imageSet to true only to start a throwaway container with the sample changeme password.
BATTLESPADES_DATA_DIRDocker imageWritable data directory, /data or below (default /data). Holds the generated config, logs and bans.json.
BATTLESPADES_CONFIG_TEMPLATEDocker imageTOML file used as the template (default: the image's config.toml). Mount your own complete config here to change keys the other variables do not cover.
BATTLESPADES_RUNTIME_CONFIGDocker imageWhere the effective config is written (default /data/runtime/config.toml).
AOS_MASTER_WRITE_TOKENany launchThe server-scoped aos_srv_… token AoSPlay returns when you register. Required for listing, identity tickets and results; never put it in config.toml.
AOS_MASTER_URLany launchOverrides [revival] base_url.
AOS_PUBLIC_HOSTany launchOverrides [revival] public_host: the public IPv4 players connect to.
AOS_PUBLIC_PORTany launchPublic UDP game port when it differs from the listen port (router mapping or a relay such as Playit).
AOS_PUBLIC_QUERY_PORTany launchPublic A2S port. Defaults to the public game port when AOS_PUBLIC_PORT is set.
AOS_SERVER_IDany launchOverrides [revival] server_id; must equal public_host:public_port.
BATTLESPADES_STEAM_RUNTIMEany launchFallback for [steam] runtime_dir.
BATTLESPADES_STEAMCLIENT_RUNTIMEany launchFallback for [steam] steamclient_dir.
BATTLESPADES_STEAM_HELPERany launchFallback for [steam] helper_path.

Common questions

I changed config.toml but nothing happened.

Restart the server; the file is read once at startup. If it still uses defaults, run --check and look for a TOML parse warning (often a BOM or a missing quote).

Is this list complete?

Yes for the version shown at the top: it is generated from BattleSpades' server/config.py, server/game_rules.py and the mode sources by scripts/generate-server-reference.py in the website repository.

Can I change settings while the server runs?

Only a few, through admin commands (/map, /mode, /time, /fog, /bots …, /lockscore, /infiniteblocks). Those changes last until the next restart.