Your first game mode
A mode is a script that defines the callbacks it cares about and calls the server back. This one
greets players, answers /hello, keeps a clock in the corner of every screen and puts a subtitle
up when someone walks into the spawn. Save it, point [gamemode] script at it, start the server.
SetGameModeText("hello")
local spawnX, spawnY, spawnZ, spawnYaw = GetDefaultSpawn()local clock -- a HUD text every player seeslocal spawnZone -- a circle around the spawn
function OnGameModeInit() Log("hello on " .. GetLevel() .. ", " .. GetMaxPlayers() .. " slots")
clock = CreateHudText(0.99, 0.02, FormatWorldTime(), COLOUR_YELLOW, 1.0, HUD_ALIGN_RIGHT) SetTimer(function() SetHudText(clock, FormatWorldTime()) end, 2000, true)
spawnZone = CreateCircleZone(spawnX, spawnY, 12)end
function OnPlayerConnect(pid) SendClientMessage(pid, COLOUR_SERVER, "Welcome to " .. GetLevel() .. ", " .. GetPlayerName(pid) .. ". /hello says hello.") SendClientMessageToAll(COLOUR_SERVER, GetPlayerName(pid) .. " joined")end
function OnPlayerRequestSpawn(pid) -- a step of 1.5 m per player id, so nobody spawns inside anyone SetSpawnInfo(pid, spawnX + 1.5 * (pid % 16), spawnY + 1.5 * (pid // 16), spawnZ, spawnYaw) return trueend
function OnPlayerSpawn(pid) GameText(pid, GetLevel(), 3000, GAMETEXT_CENTRE) ShowHudText(clock, pid)end
function OnPlayerEnterZone(pid, zone) if zone == spawnZone then GameText(pid, "The spawn", 1500, GAMETEXT_LOWER) endend
function OnPlayerCommandText(pid, cmd, args) if cmd == "hello" then SendClientMessage(pid, COLOUR_GREEN, "Hello, " .. GetPlayerName(pid) .. "!") return true -- handled; the server's built-ins stay out of it end return false -- not ours: /pos, /players, /tp ... answer as usualend
function OnPlayerDisconnect(pid, reason) SendClientMessageToAll(COLOUR_SERVER, GetPlayerName(pid) .. " left (" .. reason .. ")")endWhat happens, in order
Section titled “What happens, in order”-
Load. The script runs top to bottom:
SetGameModeTextnames the mode in the log,GetDefaultSpawnreads[spawn]fromserver.toml. ThenOnGameModeInitruns — the place for anything that exists for the whole session: the HUD text, its timer, the zone. -
A player connects. The handshake is done and their client is loading the level;
OnPlayerConnectmay talk to them already. They are not in the world yet — no position, no health. -
The level is ready.
OnPlayerRequestSpawndecides where:SetSpawnInfosets the point,return truelets the spawn happen now (falsewould hold the player until the mode callsSpawnPlayeritself — a lobby, a team pick). -
In the world.
OnPlayerSpawn: the player is replicated to everyone. NowGetPlayerPos,GameText,ShowHudTextmean something. -
Every tick the server tests every player against every zone and calls
OnPlayerEnterZone/OnPlayerLeaveZoneon the edges; timers fire from the same slot. -
Chat. A
/helloline arrives asOnPlayerCommandText(pid, "hello", ""). Returningtrueends it there;falsehands the line on to the server’s built-in commands, then toUnknown command. -
Leaving.
OnPlayerDisconnectstill knows the name; the id is free for the next player after it returns.
Where next
Section titled “Where next”- Every callback the world can call, with its arguments and what a return value does: Callbacks.
- Moving, healing, teleporting and reading players: Players.
- Something on the client’s screen the HUD cannot do? Ship a client script and talk to it with script events; share values with every client through state bags.
[gamemode] watch = truereloads the script on every save — see hot reload.
