Objects in the Q2 World

Quake2 renders a 3D world. To keep this effective and updateable over a network, the Quake2 world is divided into static objects and entities. The static objects are the walls, floor, water, sky etc. Each client has its own map of these things, called a PAK-file. The server has an identical copy of the PAK-file. The entities, on the other hand, are movable, changeable and removable. Some of them are also positioned by the PAK-file, while others appear only temporarily. Monsters, windows and barrels are positioned by the PAK-file, while explosions and gun sparks can be created and removed dynamically during game play.

Each entity in the Quake2 world is represented by an edict_t structure. This structure contains data about that entity, which can be a player, a piece of equipment, a monster, a door or a window; anything that is not static to the world. The edict can also be extended by a couple of structures, if it is an item or a player. Noticeable is the fact that the edict_t structure is divided into two parts: the engine part and the DLL part. This means that the engine and the DLL have agreed on a contract, as to which the structure's first 19 attributes should be. The rest of the structure is up to the DLL to design. Hence, the DLL can add a lot of attributes and functionality to each entity, without having to take the engine's behaviour into account. In the original Quake2 3.14 code, the DLL adds about 70 attributes to the edict_t structure.

The edict_t structure and its substructures also contain function pointers. Most prominent is the think function, which is the means by which each entity gets some processor time for thinking and acting. The entity can set a nextthink variable, which tells when it needs processor time again. This is an efficient way of simulating multithreading without the overhead of context switching and problems of synchronization. It does require the collaboration of all entities for the scheduling to be fair.

A global variable, g_edicts, contains an array of all the entities in the world, which is used for looping through the entities to animate them, finding them, and disabling them. The g_edicts variable is allocated by a TagMalloc function in the import API and exported through the export API. This means that the server can also iterate through, and modify all the entities in the world.

Note about the allocation: It is accomplished using the TagMalloc function imported through the game import API. This means that the memory is allocated by the engine using runtime functions linked with the engine. This means that the access violations, which often arise when allocating and releasing memory in DLLs linking with different runtime allocator functions, are remedied.