Running a mode
The server reads server.toml from its working directory (/app/server.toml in the container).
Every key is documented in the file itself — [server], [gamemode], [rates], [aoi],
[world], [persistence], [validation], [master], [accounts], [commands], [spawn],
[combat], [audit] — and the command line overrides it flag by flag.
Naming the mode
Section titled “Naming the mode”[gamemode]script = "gamemodes/freeroam.lua" # relative to the server's working directorywatch = false # true: reload the script whenever its file changes (a development server)--gamemode gamemodes/freeroam.lua on the command line does the same; --gamemode "" runs the
built-in C# freeroam with no script at all.
Shipping your own script
Section titled “Shipping your own script”Mount the script and a server.toml naming it into the container:
docker run ... \ -v ./my-server.toml:/app/server.toml \ -v ./my-modes:/app/my-modes \ <the server image>with script = "my-modes/arena.lua" in that server.toml. Inside a script, require resolves
relative to the script’s own directory, so a mode can be split across files (require "arena.rounds").
Scripts are plain Lua 5.4 with the standard libraries. They run in the server’s process and are
trusted: through the luanet table they reach the CLR (luanet.import_type("System.IO.File")),
which is how a mode that wants a database or the file system gets one.
Hot reload
Section titled “Hot reload”/reload (admins), ReloadGameMode([reason]) from the script itself, or [gamemode] watch = true
reload the game mode without a restart. At the start of the next tick, outside every callback:
- the running mode is shut down (
OnGameModeExit; the Lua VM is disposed, its timers with it); - everything a script makes is torn down — the zones, the HUD texts, the props, the state bags,
the nameplates, colours and teams,
SetPlayerData, the admin flags the old mode promoted (the[accounts]admins keep theirs); - the mode is loaded again from
[gamemode] script(the file is read from disk again), initialised (OnGameModeInit) and told about every player again:OnPlayerConnect,OnPlayerLoginfor the logged-in,OnPlayerSpawnfor those in the world.
The players, their vitals, inventories, buffs, horses, drops, doors and containers stay as they
are; everyone reads the game mode was reloaded: <name>.
A script that fails to load (a syntax error) leaves the built-in freeroam in charge until the next reload — the server never goes down for a typo:
game mode: arena.lua failed to load (...); the built-in freeroam runs until the next reloadA missing file refuses the reload and keeps the running mode.
Reading the log
Section titled “Reading the log”The mode logs with Log(...) (or print), prefixed [lua]. A runtime error inside a callback is
logged as [lua] error in OnPlayerText: ... and that callback’s effect is skipped. The tick budget
report (the slowest tick took 41 ms against a 33 ms budget) appears every 10 s while a tick
overruns — usually a mode’s OnTick or a timer doing too much.
