Architecture
How the engine is layered and why gameplay stays in the gamemode.
Design principles
- Transport-free core — the engine core exposes deterministic
HandlePacket/TickAPIs, so it can be tested without sockets. - Single UDP socket — one
net.ListenPacketdemultiplexes peers by address. - Isolated reliability layer — each peer owns its RakNet connection: sequence numbers, ordering channels, dedup, resend queues and fragmentation.
- No gameplay policy in the core — the core reports facts; the gamemode decides.
Layers
text
Client (SA-MP 0.3.7 / 0.3.DL)
│ UDP
▼
raknet transport, cookies, ACK/ordering, fragmentation
│
▼
samp/protocol RPC encode/decode, sync structs, InitGame
│
▼
server peers, world pools, streaming, event dispatch
│
▼
runtime Knight AST evaluator + native table
│
▼
gamemode (.sa) callbacks + natives = gameplay
Event flow for a chat line
text
client → RPC_Chat (101)
→ protocol.ParseChat
→ runtime.OnPlayerText(playerid, text)
if a handler exists and returns false → stop
→ otherwise broadcast to all clients
Streaming
Players, vehicles, objects, labels and pickups are streamed by distance. The stream radius comes from streamdistance in server.cfg and can be changed at runtime.
Concurrency
Packet handling is single-threaded per tick, so world state needs no locks. Database work runs on worker goroutines and posts results back to the tick loop, where gamemode callbacks are invoked.
Note
This is why database callbacks and timers run on the main loop: gamemode code is never executed concurrently.