The Game Subsystem as a library is essentially a passive component. It needs to be called and executed by a program/application. This could be any application linked against the DLL, including your test programs. It is usually the Q2 game server process that interfaces the Game Subsystem and executes it at predefined intervals.
Here is the definition of
function that provides the main loadtime interface between
server process and Game DLL :
game_export_t *GetGameApi(game_import_t *import);
GetGameApi is used at startup to exchange info between the server and the game dll. It is called by the server passing in a tables of functions to the dll (the game imports). It returns a struct o' pointers back to the server, the game exports. Yes, the prototype is basically useless to you until you know what's in the structs.
The dll is linked at a fixed base address. You really, positively must leave it that way. If you don't the save/load game won't work for you.
The main engine, as part of the server, provides
a set of functions and global variables to
the Game Subsystem. The Game Subsystem can
refer to these and call them, but they can not
be changed or replaced. The imported
functions are listed
game.h::game_import_t. As the
server cannot be changed, and as there is no
override mechanism, this part of the game
is fixed. This includes, among other things,
the client side prediction mechanism.
The majority of the import functions relate to former QuakeC builtin "standard functions", like traceline(), etc.
The following is a list of the Quake2 engine
internal commands which can be, or have to be
referenced by the Game DLL. The functions are
effectively referenced as
gi.bprintf (print_level, text, variables)
function sends message to all players.
print_level gives the message priority, and
gi.dprintf (text, variables) function
emits debug messages. Debug cvar allows you to view these.
gi.cprintf (entity, print_level, text, variables)
function sends message to only one entity. Again,
print_level sets message priority (see
above for values).
gi.centerprintf (entity, text, variables)
function sends message to one entity and displays message
in centre of screen.
gi.soundindex (sound_name) function
will cache a sound during spawning, after that it simply
returns the index which refers to that sound. The
is both string identifier of the sound, and the filename in
the PACK file, minus the
"sounds/" prefix. You say
gi.soundindex("misc/w_pkup.wav") to refer to the
gi.sound (entity, channel, sound_index, volume, attenuation, time_ofs) function generates sound
centered on a given entity. The
specifies the sort of sound - a second sound of the same
sort will overwrite the first. The
sound to play is given by
sound_index, which is
retrieved using gi.soundindex. The
is between 0 and 1. The
how far away sound can be heard, effectively.
time_ofs might be a delay time before
playing the sound ???not yet found anything other than 0.
channel parameter can be:
attenuationcontrol parameter, which hints on how to decrease the sound volume by distance, can be:
gi.positioned_sound (origin, entity, sound_index, volume, attenuation, time_ofs) function is similar
gi.sound. See there (above) for most of settings.
origin sets position for sound to
come from relative to level origin (NOT entity origin),
e.g. to avoid sending entities to the client that are
usually invisible. You do not link (and send) the entitiy,
you just tell the client to place a sound at its position,
without the client ever to hear about the entitiy as such.
gi.modelindex (model_filename) function is
during spawning it caches the model, after that it simply
returns the index which refers to that model.
gi.setmodel (entity, model_filename)
sets the entities' model to
Another cache/retrieval function,
Is used to precache the icon during initialisation, and reference it
gi.trace (point1, vector1, vector2, point2, ignore, mask)
function traces a box (given by min/max coordinates in the
two vectors) from
point2, ignoring entity
ignore, stoping if it hits an object of
specified in mask.
vector1, vector2 set the box which will do the tracing - if
NULL, then a line is used instead (clipping a ray, e.g. a laser beam
or instant hit bullet shot).
The function returns a pointer to a struct of type
which contains these components
The mask can be one (or more) of contents values (again
gi.pointcontents) or can be one of:
gi.AreasConnected (int areanum1, int areanum2)
checks if two areas are connected - used to check whether
a monster can hear a sound or not. Connected thus
relateds to the PHS processing, which is essentially
a runtime floodfill of an adjacency graph each time an
areaportal opens or closes.
It presumably returns 1 if the two areas are connected, 0 else.
gi.pointcontents (point) returns the content of
the given point, will be one of:
gi.BoxEdicts(mins, maxs, entity_list, maxcount, areatype)
generates a list of all the entities contained in a certain
axial box. The
mins, maxs vectors define the box
(relative to level origin).
gi.SetAreaPortalState (poral_num, open)
is used to (re)set portal when a door opens or closes
(e.g. to prevent sound detection through closed doors).
gi.inPHS (point1, point2) function
checks to see if
point2 is in the
Potentially Hearable Set of
The potentially hearable set (PHS) is a PVS-like
data structure used by Quake II to determine
whether there is any unoccluded path connecting
two points. In contrast to PVS, which determines
visibility and lines of sight, no direct
ray tracing is done.
Note that if
point2 is in the PHS of
point1 will also
be in the PHS of
the first law of Q2 sound propagation: if I can hear
you, then you can hear me.
gi.inPVS (point1, point2)
checks to see if
point2 is in the Potentially Visible
point1. The PVS is the same concept
as a PHS, except it tracks sight instead of sound. Internally
(in the engine) ther a vast differences. PVS is computed
at MAP compile time, is static and could be checked by
clipping the LOS against the BSP. It can thus also be
improved (made smaller) by runtime checks. Sound does not
require direct paths, and has to be handled at runtime
(by a floodfill on each areaportal change).
entity into the world's list of active
entities, so that it is sent to the client and e.g.
used for client ???and server side collision detection etc.
It must be re-linked if its size, position or solidity
changes, ???to force client side updates.
from interacting with the world, and
must be done before deleting it.
returns the number of arguments on the console.
gi.args() returns the next entry on the
console as a string.
returns the argument number index from the console (command is arg 0).
gi.AddCommandString(text) adds a command to the
server console, as if it had been typed.
gi.cvar(variable_name, value, flags)
declares and sets the variable to the value, and sets flags :
sets the variable to value,
returns the ???variable just set.
sets the variable to
It returns the variable just set, and
???forces the value setting.
Send the prepared data to a single client by UDP,
reliable flag enables the internal
acknowledging mechanism based on sequence numbers.
gi.multicast(origin, to) sends prepared data
(including origin) to :
The various parameters and bits of data have to be send in an endianess-insensitive manner, and in some cases (e.g. angles) conversion to lower bit resolution and/or integer representation is done, too.
This is one of he most important functions,
gi.Pmove(pmove). It moves the player,
according to information given in varaible
gi.configstring (index, string) serves as
a general means of communication from server to all
index parameter has the values:
Intended for detecting 'cheater' maps (e.g. by CRC check), that is, maps with modified lightmaps and textures. This could also be used for identifying the registered PACK (POP - Proof Of Purchase), or to recognize out of date map revisions.
q_shared.h::MAX_CONFIGSTRINGSdefines the compile time configstring table as
CS_STATUSBARis longer than 64. Several adjacent configstring slots are used, and only the last one is \0 terminated. So over the network, you might see configstring 5 with length 150, configstring 6 with length 86, and configstring 7 with length 22, but it all works out in the end.
gi.DebugGraph (value, colour) draws a graph???
Doesn't seem to do anything try turning debug mode on, a cvar.
gi.error (text, variables),
shuts down the game and displays the error message.
size bytes of memory, ???and sets
a tag to determine how/when to release/purge/clean up.
See DOOM Zone Memory allocation source.
Clean up the pool/zone memory, release all allocated
chunks that are labelled as/below the given tag/priority.
gi.TagFree(block) function does
memory (de)allocation, is not used anywhere in code?
The Game Subsystem provides what is listed
the data structures provided in the original
One of the functions is called at the start of a game, does initialization. One of the functions is also called at the beginning of each level to do similar stuff on a per-level basis. Another one of the gameapi functions is called every frame, and that is the function that does all of the game subsystem processing.
Note that the server was compiled with the original game DLL source partly visible at compile time. These visible parts, if not ignored by the server, can not be changed. Unfortunately, this is only partly documented.
flag masks the server visible
There is also
to handle local copies of functions needed in
that does not belong to the game system.
The Game Subsystem is fully described by the Game DLL sources. However, as the server has been compiled already, many parts of the Game Subsystem will simply be ignored. The only way to interact with the server is to:
Possibly the most important function, explained separately. See ???there.
As FRAMETIME is not exported to the server except at compiletime, changing it is not possible.
Has been 1 for Quake2 test/demo. 2 for Q2 3.05??? 3 for Q2 3.10???
Only a part of the world structure/game system was visible to the server at compile time, and these can neither be changed nor can anything outside be visible to the server. The server does not use all of the header's contents even if they were visible at compile time. Comments indicate:
q_shared.h::entity_state_t q_shared.h::player_state_t game.h::gclient_t, as is game.h::edict_s, as is q_shared.h::pmove_state_t, as is.
The following observations have to be made:
There are several restriction which should be noted in particular: