Skip to content
Search

Quake:SourceReview

lastmod 2018-08-17created 2018-07-061 edits

Describes the source code structure of the Quake game.

Intro

  • botlib: Library for the AI of Bots, the AI-controlled players. It reads aas, a data file made specifically for bots, and contains code for shortest paths that avoid obstacles and for chat.
  • cgame: Client-side mod source for the Quake 3 game. Contains how the information in packets is presented, such as how effects are shown when firing a gun or a rocket.
  • game: Server-side mod source for the Quake 3 game. Contains how the server handles things, such as how much health is lost when an opponent is hit by a gun or a rocket, and what happens to the score when someone dies.
  • q3_ui: UI mod source for the Quake 3 game. Handles the main menu and the in-game menu.
  • renderer: The renderer part of the Quake 3 engine. The renderer can be built separately as a static library, so that it can also be used in other in-house tools (a shader tool, a texture tool, and so on). Once you have the renderer's interface, the renderer is easy to use from outside as well.
  • quake3: The Quake 3 engine core. Contains the sound manager, memory manager, client- and server-side engine processing, vm, file manager, cvar manager, collision handling, code for Windows and Linux, and so on.
  • splines: Seems to be a library used for making splines in other tools.
  • ui: UI mod source for Quake 3 Team Arena.

Engine and virtual machine

The Quake 3 engine needs a virtual machine to run the game. A virtual machine, abbreviated VM, is simply the mod source part needed to run the game. In other words, to play Quake 3 you need three VMs, cgame.dll, game.dll and ui.dll (or .qvm), and when the mod source was released, it was the source of these three VMs that was released.

A VM can be compiled as either a dll version or a qvm version. A qvm is a kind of binary file compiled with Quake C, which dates back to the Quake 1 days, and the engine can read and execute this file. (Actually I don't know the details of qvm yet either, since it was first released with Q3.)

When a VM calls an engine function, it does so through syscalls starting with trap_, and when the engine calls into a VM, it calls vmMain. Notably, neither the syscalls called from a VM nor vmMain called from the engine pass pointers as parameters; everything must be passed as integers only. This secures stability at the engine level and prevents mistakes by mod developers, but it also helps keep the structural consistency of the whole engine exchanging handles rather than pointers.

So mod developers can use engine functions only through syscalls, and the kinds and number of syscalls decide whether this engine is good or not.

Memory management

The engine uses two memory managers called zone and hunk. The zone memory manager first mallocs a large block of memory (as much as set in com_zoneMegs) and then uses a double linked list to split it up for each memory request. Because searching the list takes a little time, it is used only for general purposes. The hunk memory manager likewise first mallocs a large block of memory (as much as set in com_hunkMegs), but it is mainly used when things that are reset together all at once make requests in sequence, such as when loading a map or initializing the renderer. Since hunk manages memory by a memory position rather than a list, it is very fast, and clearing is fast too (just move the position back to the initial position). The memory managers not only check for memory overflow, but also report the memory status in detail when you type meminfo in the console.

Meanwhile, the VMs basically do not use the engine's memory managers (because a malicious VM could break the engine through the memory addresses returned by requesting memory from the engine). Interestingly, they solve everything with static memory. All entity lists and information are static, and clearing is easily handled with memset. g_mem.c in game imitates dynamic memory allocation, but it too creates a static memory pool and hands out pieces for each request. In any case, since the VMs use no dynamic memory at all, there is no need to worry about memory leaks.

Console

The engine has two consoles: the in-game console and the system console.

The in-game console appears when you press the console key while the game client is active. The system console is created when the engine starts up, but is usually hidden once the client becomes active. The in-game console and the system console are synchronized with each other, but the game console is mostly used by users, while the system console is mainly useful for developers. The system console may look different by platform: on the Windows version it is made as a window, while on the Linux version it is shown only in the terminal console. The in-game console looks the same on every platform. The system console is useful from the early stages of engine development: you can see all kinds of logs at a glance, copy the logs to the clipboard, and setting the developer variable to 1 also prints developer logs so you can understand the situation in more detail. In particular, when Quake 3 runs as a dedicated server, the client disappears and this system console window becomes active, so it is also used to watch how the server is running. When a fatal error occurs in the engine, all functions shut down and the system console window becomes active and blinks, which helps a lot in finding errors.

Console logging is not slow, so printing logs every frame during rendering debugging does not slow things down, and if you set logfile to 1, all log content is also saved to a file, so there is no worry about losing logs.

Cinematic

Cinematic is a film technique, but in id games it refers to the feature that plays videos. You can watch one right away by typing something like cinematic intro.roq in the console. In Quake 3, files with the roq extension are cinematic files.

Other games (games using d3d) usually use dshow or buy the blink library, but since the Quake 3 engine is based on OpenGL, id seems to have developed its own. (In fact, even when a library with such features exists, id likes to develop things themselves from scratch, clean and fast.)

This Quake 3 cinematic is known to have been written by game designer graeme devine, a veteran with 18 years in the game industry who had coded the video playback part of The 11th Hour, released in 1995.

roq compresses the screen with a technique used in jpeg called vector quantisation, and compresses audio with dpcm. A few years ago, Professor Tim Ferguson analyzed this codec and published an unofficial format. This codec is known to decode faster than dshow or blink, but files tend to be larger instead.

Because roq is fast, it is also used as an overlay layer in UIs; a good example is the great UI of 'Return to castle wolfenstein'. In Quake 3 Team Arena, roq is also used on the TVs inside maps, and in Doom 3 all the TV effects use roq.

Sound

The engine's sound system sticks quite closely to the basics.

Since things like dsound could not be used (it had to be multi-platform), the mixer was implemented by hand. It can mix up to 96 channels at once, and it adjusts the left and right volume according to the 3D position when rendering, so sound in 3D space is implemented properly. It also has a Doppler effect, and setting s_show to 1 shows the sound system at work at a glance.

After analyzing the source of the sound system, you will easily understand how sound works in a game.

See also

Favorite site