Modding Guide

This page is an introduction to modding Quetoo — customizing gameplay through the game module system.

Architecture Overview

Quetoo uses a dynamically loaded game module architecture, separating gameplay logic from the engine. This means you can replace or extend game behavior without recompiling the engine itself.

ModuleFileLoaded by
Server-side game logicgame.so / game.dllServer at map load
Client-side game logiccgame.so / cgame.dllClient at map load

Both modules communicate with the engine through fixed API structs (g_import_t / g_export_t for the game module, cgi_t / cg_export_t for cgame).


Game Module (Server-Side)

Entry Point

The game module exports a single entry function:

g_export_t *G_LoadGame(g_import_t *import);

The engine calls this at startup, passing a g_import_t struct filled with engine functions (console output, collision, networking, etc.). The game returns a g_export_t struct with its function table.

API Version

The game module must match the engine’s GAME_API_VERSION. If it doesn’t, the server will refuse to load the module. Check src/game/g_types.h for the current version.

Key Source Files

FilePurpose
src/game/default/g_main.cModule init/shutdown, cvar registration, game loop
src/game/default/g_entity.cEntity lifecycle (spawn, free, think)
src/game/default/g_combat.cDamage, death, gibbing
src/game/default/g_weapon.cWeapon fire, projectile spawning
src/game/default/g_physics.cEntity physics simulation
src/game/default/g_player.cPlayer movement and state
src/game/default/g_teams.cTeam and CTF logic
src/game/default/g_map_list.cMap rotation logic
src/game/default/g_items.cItem pickups and inventory
src/game/default/g_ai.cBot AI

Entity System

Entities are stored in a fixed-size array (MAX_ENTITIES). Each entity has:

Entity slots are reused. A spawn_id field increments each time a slot is recycled, so code can detect stale references:

if (ent->current.spawn_id != expected_spawn_id) {
    // entity was freed and reallocated — handle accordingly
}

Adding a Console Variable

Register cvars in G_Init():

cvar_t *g_my_feature = gi.AddCvar("g_my_feature", "1", CVAR_SERVER_INFO,
                                   "Enables my custom feature.");

CVAR_SERVER_INFO causes the cvar value to be sent to clients as part of server info. CVAR_ARCHIVE persists the value across server restarts.

Adding a Server Command

gi.AddCmd("my_cmd", G_MyCmd_f, CMD_GAME, "Does something useful.");

Game Loop

G_Frame() is called by the server every game tick (60 Hz by default). Entity think functions (ent->think) are called from here.


Client Game Module (cgame, Client-Side)

The cgame module handles client-side presentation: the HUD, scoreboard, local effects, weapon models, and client-side movement prediction.

Key Source Files

FilePurpose
src/cgame/default/cg_main.cModule init, imports, frame loop
src/cgame/default/cg_hud.cHUD rendering
src/cgame/default/cg_predict.cClient-side movement prediction
src/cgame/default/cg_entity.cEntity interpolation and effects
src/cgame/default/cg_weapon.cView weapon model animation
src/cgame/default/ui/In-game menus (ObjectivelyMVC UI framework)

Entity Prediction

The cgame module predicts player movement locally to hide network latency. Predicted state is reconciled with authoritative server state each frame.


Building a Mod

A mod is a replacement game.so / cgame.so pair placed in a subdirectory of the game data:

~/.quetoo/mygame/game.so
~/.quetoo/mygame/cgame.so

Load it with +set game mygame on the command line, or from the console:

game mygame

Build Setup

The game module builds as a shared library. Use the existing Makefile.am in src/game/default/ as a reference. The key flags are:

AM_CFLAGS = -fPIC -DGAME_MODULE
LDFLAGS = -shared -Wl,-soname,game.so

Getting Help