Skip to content

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.

server.toml
[gamemode]
script = "gamemodes/freeroam.lua" # relative to the server's working directory
watch = 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.

Mount the script and a server.toml naming it into the container:

Terminal window
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.

/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:

  1. the running mode is shut down (OnGameModeExit; the Lua VM is disposed, its timers with it);
  2. 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);
  3. the mode is loaded again from [gamemode] script (the file is read from disk again), initialised (OnGameModeInit) and told about every player again: OnPlayerConnect, OnPlayerLogin for the logged-in, OnPlayerSpawn for 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 reload

A missing file refuses the reload and keeps the running mode.

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.