This is an (incomplete) collection of the data structures used in the Quake III Arena source code. These structures are rather complicated and depend on each other in many ways. I have made this document so that hackers of the Q3A code (including me :) have a quick reference and don't have to search for the definition of a particular structure in the headers hidden inside the source tree. The structures are also cross-referenced (using 'ref' links) so it is easy to find out what exactly a particular structure contains.
I have copied the source code from the ioquake3 source tree. This code is widely used as a base for further development of mods and total conversions. There may be some differences (mostly additions) as compared to the original 1.32b source released by id Software.
You can help to improve this document. If during hacking you look up a structure or enum not present in this document, please, make an effort and add it. The HTML code is very simple and easy to modify (no fancy stylesheets or scripts are used). Adding a new entry is mainly copy-paste and adjusting a few 'href' tags. If you add new entries please, send a copy of the updated document to this address.
// playerState_t is the information needed by both the client and server // to predict player motion and actions. // Nothing outside of Pmove() should modify these, or some degree of prediction error // will occur. // You can't add anything to this without modifying the code in 'msg.c'. // playerState_t is a full superset of entityState_t (ref) as it is used by players, // so if a playerState_t is transmitted, the entityState_t can be fully derived // from it. typedef struct playerState_s { int commandTime; // cmd->serverTime of last executed command int pm_type; int bobCycle; // for view bobbing and footstep generation int pm_flags; // ducked, jump_held, etc int pm_time; vec3_t origin; vec3_t velocity; int weaponTime; int gravity; int speed; int delta_angles[3]; // add to command angles to get view direction // changed by spawns, rotating objects, and teleporters int groundEntityNum; // ENTITYNUM_NONE = in air int legsTimer; // don't change low priority animations until this runs out int legsAnim; // mask off ANIM_TOGGLEBIT int torsoTimer; // don't change low priority animations until this runs out int torsoAnim; // mask off ANIM_TOGGLEBIT int movementDir; // a number 0 to 7 that represents the reletive angle // of movement to the view angle (axial and diagonals) // when at rest, the value will remain unchanged // used to twist the legs during strafing vec3_t grapplePoint; // location of grapple to pull towards if PMF_GRAPPLE_PULL int eFlags; // copied to entityState_t->eFlags (ref) int eventSequence; // pmove generated events int events[MAX_PS_EVENTS]; int eventParms[MAX_PS_EVENTS]; int externalEvent; // events set on player from another source int externalEventParm; int externalEventTime; int clientNum; // ranges from 0 to MAX_CLIENTS-1 int weapon; // copied to entityState_t->weapon int weaponstate; vec3_t viewangles; // for fixed views int viewheight; // damage feedback int damageEvent; // when it changes, latch the other parms int damageYaw; int damagePitch; int damageCount; int stats[MAX_STATS]; int persistant[MAX_PERSISTANT]; // stats that aren't cleared on death int powerups[MAX_POWERUPS]; // level.time that the powerup runs out int ammo[MAX_WEAPONS]; int generic1; int loopSound; int jumppad_ent; // jumppad entity hit this frame /* not communicated over the net at all */ int ping; // server to game info for scoreboard int pmove_framecount; // FIXME: don't transmit over the network int jumppad_frame; int entityEventSequence; } playerState_t;
#define CVAR_ARCHIVE 1 // set to cause it to be saved to vars.rc // used for system variables, not for player // specific configurations #define CVAR_USERINFO 2 // sent to server on connect or change #define CVAR_SERVERINFO 4 // sent in response to front end requests #define CVAR_SYSTEMINFO 8 // these cvars will be duplicated on all clients #define CVAR_INIT 16 // don't allow change from console at all, // but can be set from the command line #define CVAR_LATCH 32 // will only change when C code next does // a Cvar_Get(), so it can't be changed // without proper initialization. modified // will be set, even though the value hasn't // changed yet #define CVAR_ROM 64 // display only, cannot be set by user at all #define CVAR_USER_CREATED 128 // created by a set command #define CVAR_TEMP 256 // can be set even when cheats are disabled, but is not archived #define CVAR_CHEAT 512 // can not be changed if cheats are disabled #define CVAR_NORESTART 1024 // do not clear when a cvar_restart is issued #define CVAR_SERVER_CREATED 2048 // cvar was created by a server the client connected to. #define CVAR_NONEXISTENT 0xFFFFFFFF // Cvar doesn't exist.
typedef struct cvar_s { char *name; char *string; char *resetString; // cvar_restart will reset to this value char *latchedString; // for CVAR_LATCH vars int flags; // (ref) qboolean modified; // set each time the cvar is changed int modificationCount; // incremented each time the cvar is changed float value; // atof( string ) int integer; // atoi( string ) qboolean validate; qboolean integral; float min; float max; struct cvar_s *next; struct cvar_s *hashNext; } cvar_t;
typedef int cvarHandle_t; typedef struct { cvarHandle_t handle; int modificationCount; float value; int integer; char string[MAX_CVAR_VALUE_STRING]; } vmCvar_t;
typedef struct cplane_s { vec3_t normal; float dist; byte type; // for fast side tests: 0,1,2 = axial, 3 = nonaxial byte signbits; // signx + (signy<<1) + (signz<<2), used as lookup during collision byte pad[2]; } cplane_t;
typedef struct { qboolean allsolid; // if true, plane is not valid qboolean startsolid; // if true, the initial point was in a solid area float fraction; // time completed, 1.0 = didn't hit anything vec3_t endpos; // final position cplane_t plane; // surface normal at impact, transformed to world space (ref) int surfaceFlags; // surface hit int contents; // contents on other side of surface hit int entityNum; // entity the contacted sirface is a part of } trace_t;
typedef struct usercmd_s { int serverTime; int angles[3]; int buttons; byte weapon; // weapon signed char forwardmove, rightmove, upmove; } usercmd_t;
typedef struct { trType_t trType; // (ref) int trTime; int trDuration; // if non 0, trTime + trDuration = stop time vec3_t trBase; vec3_t trDelta; // velocity, etc } trajectory_t;
// entityState_t is the information conveyed from the server // in an update message about entities that the client will // need to render in some way // Different eTypes may use the information in different ways // The messages are delta compressed, so it doesn't really matter if // the structure size is fairly large typedef struct entityState_s { int number; // entity index int eType; // (ref) int eFlags; // (ref) trajectory_t pos; // for calculating position trajectory_t apos; // for calculating angles int time; int time2; vec3_t origin; vec3_t origin2; vec3_t angles; vec3_t angles2; int otherEntityNum; // shotgun sources, etc int otherEntityNum2; int groundEntityNum; // -1 = in air int constantLight; // r + (g<<8) + (b<<16) + (intensity<<24) int loopSound; // constantly loop this sound int modelindex; int modelindex2; int clientNum; // 0 to (MAX_CLIENTS - 1), for players and corpses int frame; int solid; // for client side prediction, trap_linkentity sets this properly int event; // impulse events -- muzzle flashes, footsteps, etc int eventParm; // for players int powerups; // bit flags int weapon; // determines weapon and flash model, etc int legsAnim; // mask off ANIM_TOGGLEBIT int torsoAnim; // mask off ANIM_TOGGLEBIT int generic1; } entityState_t;
// entityState_t->eFlags #define EF_DEAD 0x00000001 // don't draw a foe marker over players with EF_DEAD #ifdef MISSIONPACK #define EF_TICKING 0x00000002 // used to make players play the prox mine ticking sound #endif #define EF_TELEPORT_BIT 0x00000004 // toggled every time the origin abruptly changes #define EF_AWARD_EXCELLENT 0x00000008 // draw an excellent sprite #define EF_PLAYER_EVENT 0x00000010 #define EF_BOUNCE 0x00000010 // for missiles #define EF_BOUNCE_HALF 0x00000020 // for missiles #define EF_AWARD_GAUNTLET 0x00000040 // draw a gauntlet sprite #define EF_NODRAW 0x00000080 // may have an event, but no model (unspawned items) #define EF_FIRING 0x00000100 // for lightning gun #define EF_KAMIKAZE 0x00000200 #define EF_MOVER_STOP 0x00000400 // will push otherwise #define EF_AWARD_CAP 0x00000800 // draw the capture sprite #define EF_TALK 0x00001000 // draw a talk balloon #define EF_CONNECTION 0x00002000 // draw a connection trouble sprite #define EF_VOTED 0x00004000 // already cast a vote #define EF_AWARD_IMPRESSIVE 0x00008000 // draw an impressive sprite #define EF_AWARD_DEFEND 0x00010000 // draw a defend sprite #define EF_AWARD_ASSIST 0x00020000 // draw a assist sprite #define EF_AWARD_DENIED 0x00040000 // denied #define EF_TEAMVOTED 0x00080000 // already cast a team vote
// entityState_t->eType typedef enum { ET_GENERAL, ET_PLAYER, ET_ITEM, ET_MISSILE, ET_MOVER, ET_BEAM, ET_PORTAL, ET_SPEAKER, ET_PUSH_TRIGGER, ET_TELEPORT_TRIGGER, ET_INVISIBLE, ET_GRAPPLE, // grapple hooked on wall ET_TEAM, ET_EVENTS // any of the EV_* events can be added freestanding // by setting eType to ET_EVENTS + eventNum // this avoids having to set eFlags and eventNum } entityType_t;
// gitem_t->type typedef enum { IT_BAD, IT_WEAPON, // EFX: rotate + upscale + minlight IT_AMMO, // EFX: rotate IT_ARMOR, // EFX: rotate + minlight IT_HEALTH, // EFX: static external sphere + rotating internal IT_POWERUP, // instant on, timer based // EFX: rotate + external ring that rotates IT_HOLDABLE, // single use, holdable item // EFX: rotate + bob IT_PERSISTANT_POWERUP, IT_TEAM } itemType_t;
typedef struct gitem_s { char *classname; // spawning name char *pickup_sound; char *world_model[MAX_ITEM_MODELS]; // [4] char *icon; char *pickup_name; // for printing on pickup int quantity; // for ammo how much, or duration of powerup itemType_t giType; // (ref) int giTag; char *precaches; // string of all models and images this item will use char *sounds; // string of all sounds this item will use } gitem_t;
typedef enum { PM_NORMAL, // can accelerate and turn PM_NOCLIP, // noclip movement PM_SPECTATOR, // still run into walls PM_DEAD, // no acceleration or turning, but free falling PM_FREEZE, // stuck in place with no control PM_INTERMISSION, // no movement or status bar PM_SPINTERMISSION // no movement or status bar } pmtype_t;
// player state pm_flags #define PMF_DUCKED 1 #define PMF_JUMP_HELD 2 #define PMF_BACKWARDS_JUMP 8 // go into backwards land #define PMF_BACKWARDS_RUN 16 // coast down to backwards run #define PMF_TIME_LAND 32 // pm_time is time before rejump #define PMF_TIME_KNOCKBACK 64 // pm_time is an air-accelerate only time #define PMF_TIME_WATERJUMP 256 // pm_time is waterjump #define PMF_RESPAWNED 512 // clear after attack and jump buttons come up #define PMF_USE_ITEM_HELD 1024 #define PMF_GRAPPLE_PULL 2048 // pull towards grapple location #define PMF_FOLLOW 4096 // spectate following another player #define PMF_SCOREBOARD 8192 // spectate as a scoreboard #define PMF_INVULEXPAND 16384 // invulnerability sphere set to full size
typedef struct { playerState_t *ps; // state (in/out) usercmd_t cmd; // command (in) int tracemask; // collide against these types of surfaces int debugLevel; // if set, diagnostic output will be printed qboolean noFootsteps; // if the game is setup for no footsteps by the server qboolean gauntletHit; // true if a gauntlet attack would actually hit something int framecount; /* results (out) */ int numtouch; int touchents[MAXTOUCH]; vec3_t mins, maxs; // bounding box size int watertype; int waterlevel; float xyspeed; /* for fixed msec Pmove */ int pmove_fixed; int pmove_msec; /* callbacks to test the world these will be different functions during game and cgame */ void (* trace) ( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentMask ); int (* pointcontents) (const vec3_t point, int passEntityNum); } pmove_t;
// entityState_t->event // entity events are for effects that take place reletive // to an existing entities origin. Very network efficient. // two bits at the top of the entityState->event field // will be incremented with each change in the event so // that an identical event started twice in a row can // be distinguished. And off the value with ~EV_EVENT_BITS // to retrieve the actual event number #define EV_EVENT_BIT1 0x00000100 #define EV_EVENT_BIT2 0x00000200 #define EV_EVENT_BITS (EV_EVENT_BIT1 | EV_EVENT_BIT2) #define EVENT_VALID_MSEC 300 typedef enum { EV_NONE, EV_FOOTSTEP, EV_FOOTSTEP_METAL, EV_FOOTSPLASH, EV_FOOTWADE, EV_SWIM, EV_STEP_4, EV_STEP_8, EV_STEP_12, EV_STEP_16, EV_FALL_SHORT, EV_FALL_MEDIUM, EV_FALL_FAR, EV_JUMP_PAD, // boing sound at origin, jump sound on player EV_JUMP, EV_WATER_TOUCH, // foot touches EV_WATER_LEAVE, // foot leaves EV_WATER_UNDER, // head touches EV_WATER_CLEAR, // head leaves EV_ITEM_PICKUP, // normal item pickups are predictable EV_GLOBAL_ITEM_PICKUP, // powerup / team sounds are broadcast to everyone EV_NOAMMO, EV_CHANGE_WEAPON, EV_FIRE_WEAPON, EV_USE_ITEM0, EV_USE_ITEM1, EV_USE_ITEM2, EV_USE_ITEM3, EV_USE_ITEM4, EV_USE_ITEM5, EV_USE_ITEM6, EV_USE_ITEM7, EV_USE_ITEM8, EV_USE_ITEM9, EV_USE_ITEM10, EV_USE_ITEM11, EV_USE_ITEM12, EV_USE_ITEM13, EV_USE_ITEM14, EV_USE_ITEM15, EV_ITEM_RESPAWN, EV_ITEM_POP, EV_PLAYER_TELEPORT_IN, EV_PLAYER_TELEPORT_OUT, EV_GRENADE_BOUNCE, // eventParm will be the soundindex EV_GENERAL_SOUND, EV_GLOBAL_SOUND, // no attenuation EV_GLOBAL_TEAM_SOUND, EV_BULLET_HIT_FLESH, EV_BULLET_HIT_WALL, EV_MISSILE_HIT, EV_MISSILE_MISS, EV_MISSILE_MISS_METAL, EV_RAILTRAIL, EV_SHOTGUN, EV_BULLET, // otherEntity is the shooter EV_PAIN, EV_DEATH1, EV_DEATH2, EV_DEATH3, EV_OBITUARY, EV_POWERUP_QUAD, EV_POWERUP_BATTLESUIT, EV_POWERUP_REGEN, EV_GIB_PLAYER, // gib a previously living player EV_SCOREPLUM, // score plum //#ifdef MISSIONPACK EV_PROXIMITY_MINE_STICK, EV_PROXIMITY_MINE_TRIGGER, EV_KAMIKAZE, // kamikaze explodes EV_OBELISKEXPLODE, // obelisk explodes EV_OBELISKPAIN, // obelisk is in pain EV_INVUL_IMPACT, // invulnerability sphere impact EV_JUICED, // invulnerability juiced effect EV_LIGHTNINGBOLT, // lightning bolt bounced of invulnerability sphere //#endif EV_DEBUG_LINE, EV_STOPLOOPINGSOUND, EV_TAUNT, EV_TAUNT_YES, EV_TAUNT_NO, EV_TAUNT_FOLLOWME, EV_TAUNT_GETFLAG, EV_TAUNT_GUARDBASE, EV_TAUNT_PATROL } entity_event_t;
// entity->svFlags // the server does not know how to interpret most of the values // in entityStates (level eType), so the game must explicitly flag // special server behaviors #define SVF_NOCLIENT 0x00000001 // don't send entity to clients, even if it has effects #define SVF_CLIENTMASK 0x00000002 #define SVF_BOT 0x00000008 // set if the entity is a bot #define SVF_BROADCAST 0x00000020 // send to all connected clients #define SVF_PORTAL 0x00000040 // merge a second pvs at origin2 into snapshots #define SVF_USE_CURRENT_ORIGIN 0x00000080 // entity->r.currentOrigin instead of entity->s.origin // for link position (missiles and movers) #define SVF_SINGLECLIENT 0x00000100 // only send to a single client (entityShared_t->singleClient) #define SVF_NOSERVERINFO 0x00000200 // don't send CS_SERVERINFO updates to this client // so that it can be updated for ping tools without // lagging clients #define SVF_CAPSULE 0x00000400 // use capsule for collision detection instead of bbox #define SVF_NOTSINGLECLIENT 0x00000800 // send entity to everyone but one client // (entityShared_t->singleClient)
typedef struct { entityState_t s; // communicated by server to clients (ref) qboolean linked; // qfalse if not in any good cluster int linkcount; int svFlags; // SVF_NOCLIENT, SVF_BROADCAST, etc (ref) /* only send to this client when SVF_SINGLECLIENT is set if SVF_CLIENTMASK is set, use bitmask for clients to send to (maxclients must be <= 32, up to the mod to enforce this) */ int singleClient; qboolean bmodel; // if false, assume an explicit mins / maxs bounding box // only set by trap_SetBrushModel vec3_t mins, maxs; int contents; // CONTENTS_TRIGGER, CONTENTS_SOLID, CONTENTS_BODY, etc // a non-solid entity should set to 0 vec3_t absmin, absmax; // derived from mins/maxs and origin + rotation /* currentOrigin will be used for all collision detection and world linking. it will not necessarily be the same as the trajectory evaluation for the current time, because each entity must be moved one at a time after time is advanced to avoid simultanious collision issues */ vec3_t currentOrigin; vec3_t currentAngles; /* when a trace call is made and passEntityNum != ENTITYNUM_NONE, an ent will be excluded from testing if: ent->s.number == passEntityNum (don't interact with self) ent->s.ownerNum = passEntityNum (don't interact with your own missiles) entity[ent->s.ownerNum].ownerNum = passEntityNum (don't interact with other missiles from owner) */ int ownerNum; } entityShared_t;
// the server looks at a sharedEntity, which is the start of the game's gentity_t structure typedef struct { entityState_t s; // communicated by server to clients (ref) entityShared_t r; // shared by both the server system and game (ref) } sharedEntity_t;
typedef struct gentity_s gentity_t; typedef struct gclient_s gclient_t; struct gentity_s { entityState_t s; // communicated by server to clients (ref) entityShared_t r; // shared by both the server system and game (ref) // DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER EXPECTS THE FIELDS IN THAT ORDER! struct gclient_s *client; // NULL if not a client (ref) qboolean inuse; char *classname; // set in QuakeEd int spawnflags; // set in QuakeEd qboolean neverFree; // if true, FreeEntity will only unlink // bodyque uses this int flags; // FL_* variables (ref) char *model; char *model2; int freetime; // level.time when the object was freed int eventTime; // events will be cleared EVENT_VALID_MSEC after set qboolean freeAfterEvent; qboolean unlinkAfterEvent; qboolean physicsObject; // if true, it can be pushed by movers and fall off edges // all game items are physicsObjects float physicsBounce; // 1.0 = continuous bounce, 0.0 = no bounce int clipmask; // brushes with this content value will be collided against // when moving. items and corpses do not collide against // players, for instance /* movers */ moverState_t moverState; // (ref) int soundPos1; int sound1to2; int sound2to1; int soundPos2; int soundLoop; gentity_t *parent; gentity_t *nextTrain; gentity_t *prevTrain; vec3_t pos1, pos2; char *message; int timestamp; // body queue sinking, etc float angle; // set in editor, -1 = up, -2 = down char *target; char *targetname; char *team; char *targetShaderName; char *targetShaderNewName; gentity_t *target_ent; float speed; vec3_t movedir; int nextthink; void (*think) (gentity_t * self); void (*reached) (gentity_t * self); // movers call this when hitting endpoint void (*blocked) (gentity_t * self, gentity_t * other); void (*touch) (gentity_t * self, gentity_t * other, trace_t * trace); void (*use) (gentity_t * self, gentity_t * other, gentity_t * activator); void (*pain) (gentity_t * self, gentity_t * attacker, int damage); void (*die) (gentity_t * self, gentity_t * inflictor, gentity_t * attacker, int damage, int mod); int pain_debounce_time; int fly_sound_debounce_time; // wind tunnel int last_move_time; int health; qboolean takedamage; int damage; int splashDamage; // quad will increase this without increasing radius int splashRadius; int methodOfDeath; int splashMethodOfDeath; int count; gentity_t *chain; gentity_t *enemy; gentity_t *activator; gentity_t *teamchain; // next entity in team gentity_t *teammaster; // master of the team #ifdef MISSIONPACK int kamikazeTime; int kamikazeShockTime; #endif int watertype; int waterlevel; int noise_index; /* timing variables */ float wait; float random; gitem_t *item; // for bonus items (ref) };
// gentity->flags #define FL_GODMODE 0x00000010 #define FL_NOTARGET 0x00000020 #define FL_TEAMSLAVE 0x00000400 // not the first on the team #define FL_NO_KNOCKBACK 0x00000800 #define FL_DROPPED_ITEM 0x00001000 #define FL_NO_BOTS 0x00002000 // spawn point not for bot use #define FL_NO_HUMANS 0x00004000 // spawn point just for bots #define FL_FORCE_GESTURE 0x00008000 // force gesture on client
// client data that stays across multiple respawns, but is cleared // on each level change or team change at ClientBegin() typedef struct { clientConnected_t connected; usercmd_t cmd; // we would lose angles if not persistant (ref) qboolean localClient; // true if "ip" info key is "localhost" qboolean initialSpawn; // the first spawn should be at a cool location qboolean predictItemPickup; // based on cg_predictItems userinfo qboolean pmoveFixed; char netname[MAX_NETNAME]; int maxHealth; // for handicapping int enterTime; // level.time the client entered the game playerTeamState_t teamState; // status in teamplay games (ref) int voteCount; // to prevent people from constantly calling votes int teamVoteCount; // to prevent people from constantly calling votes qboolean teamInfo; // send team overlay updates? } clientPersistant_t;
// this structure is cleared on each ClientSpawn(), // except for 'client->pers' and 'client->sess' struct gclient_s { // ps MUST be the first element, because the server expects it playerState_t ps; // communicated by server to clients (ref) /* the rest of the structure is private to game */ clientPersistant_t pers; // (ref) clientSession_t sess; // (ref) qboolean readyToExit; // wishes to leave the intermission qboolean noclip; int lastCmdTime; // level.time of last usercmd_t, for EF_CONNECTION /* we can't just use pers.lastCommand.time, because of the g_sycronousclients case */ int buttons; int oldbuttons; int latched_buttons; vec3_t oldOrigin; /* sum up damage over an entire frame, so shotgun blasts give a single big kick */ int damage_armor; // damage absorbed by armor int damage_blood; // damage taken out of health int damage_knockback; // impact damage vec3_t damage_from; // origin for vector calculation qboolean damage_fromWorld; // if true, don't use the damage_from vector int accurateCount; // for "impressive" reward sound int accuracy_shots; // total number of shots int accuracy_hits; // total number of hits // int lastkilled_client; // last client that this client killed int lasthurt_client; // last client that damaged this client int lasthurt_mod; // type of damage the client did // timers int respawnTime; // can respawn when time > this, force after g_forcerespwan int inactivityTime; // kick players when time > this qboolean inactivityWarning; // qtrue if the five seoond warning has been given int rewardTime; // clear the EF_AWARD_IMPRESSIVE, etc when time > this int airOutTime; int lastKillTime; // for multiple kill rewards qboolean fireHeld; // used for hook gentity_t *hook; // grapple hook if out (ref) int switchTeamTime; // time the player switched teams /* timeResidual is used to handle events that happen every second like health / armor countdowns and regeneration */ int timeResidual; #ifdef MISSIONPACK gentity_t *persistantPowerup; // (ref) int portalID; int ammoTimes[WP_NUM_WEAPONS]; int invulnerabilityTime; #endif char *areabits; };
// this structure is cleared as each map is entered typedef struct { struct gclient_s *clients; // [maxclients] (ref) struct gentity_s *gentities; // (ref) int gentitySize; int num_entities; // current number, <= MAX_GENTITIES int warmupTime; // restart match at this time fileHandle_t logFile; // store latched cvars here that we want to get at often int maxclients; int framenum; int time; // in msec int previousTime; // so movers can back up when blocked int startTime; // level.time the map was started int teamScores[TEAM_NUM_TEAMS]; int lastTeamLocationTime; // last time of client team location update qboolean newSession; // don't use any old session data, because // we changed gametype qboolean restarted; // waiting for a map_restart to fire int numConnectedClients; int numNonSpectatorClients; // includes connecting clients int numPlayingClients; // connected, non-spectators int sortedClients[MAX_CLIENTS]; // sorted by score int follow1, follow2; // clientNums for auto-follow spectators int snd_fry; // sound index for standing in lava int warmupModificationCount; // for detecting if g_warmup is changed /* voting state */ char voteString[MAX_STRING_CHARS]; char voteDisplayString[MAX_STRING_CHARS]; int voteTime; // level.time vote was called int voteExecuteTime; // time the vote is executed int voteYes; int voteNo; int numVotingClients; // set by CalculateRanks /* team voting state */ char teamVoteString[2][MAX_STRING_CHARS]; int teamVoteTime[2]; // level.time vote was called int teamVoteYes[2]; int teamVoteNo[2]; int numteamVotingClients[2]; // set by CalculateRanks /* spawn variables */ qboolean spawning; // the G_Spawn*() functions are valid int numSpawnVars; char *spawnVars[MAX_SPAWN_VARS][2]; // key/value pairs int numSpawnVarChars; char spawnVarChars[MAX_SPAWN_VARS_CHARS]; /* intermission state */ int intermissionQueued; // intermission was qualified, but /* wait INTERMISSION_DELAY_TIME before actually going there so the last frag can be watched. Disable future kills during this delay */ int intermissiontime; // time the intermission was started char *changemap; qboolean readyToExit; // at least one client wants to exit int exitTime; vec3_t intermission_origin; // also used for spectator spawns vec3_t intermission_angle; qboolean locationLinked; // target_locations get linked gentity_t *locationHead; // head of the location list (ref) int bodyQueIndex; // dead bodies gentity_t *bodyQue[BODY_QUEUE_SIZE]; // (ref) #ifdef MISSIONPACK int portalSequence; #endif } level_locals_t;
// client data that stays across multiple levels or tournament restarts // this is achieved by writing all the data to cvar strings at game shutdown // time and reading them back at connection time. Anything added here // MUST be dealt with in G_InitSessionData() / G_ReadSessionData() / G_WriteSessionData() typedef struct { team_t sessionTeam; // (ref) int spectatorTime; // for determining next-in-line to play spectatorState_t spectatorState; // (ref) int spectatorClient; // for chasecam and follow mode int wins, losses; // tournament stats qboolean teamLeader; // true when this client is a team leader } clientSession_t;
typedef enum { SPECTATOR_NOT, SPECTATOR_FREE, SPECTATOR_FOLLOW, SPECTATOR_SCOREBOARD } spectatorState_t;
typedef enum { TEAM_FREE, TEAM_RED, TEAM_BLUE, TEAM_SPECTATOR, TEAM_NUM_TEAMS } team_t;
typedef enum { TEAM_BEGIN, // Beginning a team game, spawn at base TEAM_ACTIVE // Now actively playing } playerTeamStateState_t; typedef struct { playerTeamStateState_t state; int location; int captures; int basedefense; int carrierdefense; int flagrecovery; int fragcarrier; int assists; float lasthurtcarrier; float lastreturnedflag; float flagsince; float lastfraggedcarrier; } playerTeamState_t;
// movers are things like doors, plats, buttons, etc typedef enum { MOVER_POS1, MOVER_POS2, MOVER_1TO2, MOVER_2TO1 } moverState_t;
typedef struct svEntity_s { struct worldSector_s *worldSector; struct svEntity_s *nextEntityInWorldSector; entityState_t baseline; // for delta compression of initial sighting (ref) int numClusters; // if -1, use headnode instead int clusternums[MAX_ENT_CLUSTERS]; int lastCluster; // if all the clusters don't fit in clusternums int areanum, areanum2; int snapshotCounter; // used to prevent double adding from portal views } svEntity_t;
typedef enum { SS_DEAD, // no map loaded SS_LOADING, // spawning level entities SS_GAME // actively running } serverState_t; typedef struct { serverState_t state; qboolean restarting; // if true, send configstring changes during SS_LOADING int serverId; // changes each server start int restartedServerId; // serverId before a map_restart int checksumFeed; // the feed key that we use to compute the pure checksum strings int checksumFeedServerId; // the serverId associated with the current checksumFeed // (always <= serverId) int snapshotCounter; // incremented for each snapshot built int timeResidual; // <= 1000 / sv_frame->value int nextFrameTime; // when time > nextFrameTime, process world /* Note by LM: This is not used anywhere in the server code. Actually, it is defined in 'cm_local.h' and its definition is not included in any of the headers included in 'server.h' (directly or indirectly). I don't understand why the compiler does not report an error here. */ struct cmodel_s *models[MAX_MODELS]; char *configstrings[MAX_CONFIGSTRINGS]; svEntity_t svEntities[MAX_GENTITIES]; // (ref) char *entityParsePoint; // used during game VM init /* the game virtual machine will update these on init and changes */ sharedEntity_t *gentities; // (ref) int gentitySize; int num_entities; // current number, <= MAX_GENTITIES playerState_t *gameClients; // (ref) int gameClientSize; // will be > sizeof(playerState_t) due to game private data int restartTime; int time; } server_t;
typedef struct { int areabytes; byte areabits[MAX_MAP_AREA_BYTES]; // portalarea visibility bits playerState_t ps; // (ref) int num_entities; int first_entity; // into the circular sv_packet_entities[] // the entities MUST be in increasing state number // order, otherwise the delta compression will fail int messageSent; // time the message was transmitted int messageAcked; // time the message was acked int messageSize; // used to rate drop packets } clientSnapshot_t;
typedef struct client_s { clientState_t state; // (ref) char userinfo[MAX_INFO_STRING]; // name, etc char reliableCommands[MAX_RELIABLE_COMMANDS][MAX_STRING_CHARS]; int reliableSequence; // last added reliable message, not necesarily sent or acknowledged yet int reliableAcknowledge; // last acknowledged reliable message int reliableSent; // last sent reliable message, not necesarily acknowledged yet int messageAcknowledge; int gamestateMessageNum; // netchan->outgoingSequence of gamestate int challenge; usercmd_t lastUsercmd; // (ref) int lastMessageNum; // for delta compression int lastClientCommand; // reliable client message sequence char lastClientCommandString[MAX_STRING_CHARS]; sharedEntity_t *gentity; // SV_GentityNum(clientnum) (ref) char name[MAX_NAME_LENGTH]; // extracted from userinfo, high bits masked /* downloading */ char downloadName[MAX_QPATH]; // if not empty string, we are downloading fileHandle_t download; // file being downloaded int downloadSize; // total bytes (can't use EOF because of paks) int downloadCount; // bytes sent int downloadClientBlock; // last block we sent to the client, awaiting ack int downloadCurrentBlock; // current block number int downloadXmitBlock; // last block we xmited unsigned char *downloadBlocks[MAX_DOWNLOAD_WINDOW]; // the buffers for the download blocks int downloadBlockSize[MAX_DOWNLOAD_WINDOW]; qboolean downloadEOF; // We have sent the EOF block int downloadSendTime; // time we last got an ack from the client int deltaMessage; // frame last client usercmd message int nextReliableTime; // svs.time when another reliable command will be allowed int lastPacketTime; // svs.time when packet was last received int lastConnectTime; // svs.time when connection started int nextSnapshotTime; // send another snapshot when svs.time >= nextSnapshotTime qboolean rateDelayed; // true if nextSnapshotTime was set based on rate instead of snapshotMsec int timeoutCount; // must timeout a few frames in a row so debugging doesn't break clientSnapshot_t frames[PACKET_BACKUP]; // updates can be delta'd from here (ref) int ping; int rate; // bytes / second int snapshotMsec; // requests a snapshot every snapshotMsec unless rate choked int pureAuthentic; qboolean gotCP; // TTimo - additional flag to distinguish between a bad pure checksum, // and no cp command at all netchan_t netchan; // (ref) /* TTimo queuing outgoing fragmented messages to send them properly, without udp packet bursts in case large fragmented messages are stacking up buffer them into this queue, and hand them out to netchan as needed */ netchan_buffer_t *netchan_start_queue; // (ref) netchan_buffer_t **netchan_end_queue; // (ref) #ifdef USE_VOIP qboolean hasVoip; qboolean muteAllVoip; qboolean ignoreVoipFromClient[MAX_CLIENTS]; voipServerPacket_t voipPacket[64]; // !!! FIXME: WAY too much memory! int queuedVoipPackets; #endif int oldServerTime; qboolean csUpdated[MAX_CONFIGSTRINGS + 1]; } client_t;
typedef enum { CS_FREE, // can be reused for a new connection CS_ZOMBIE, // client has been disconnected, but don't reuse // connection for a couple seconds CS_CONNECTED, // has been assigned to a client_t, but no gamestate yet CS_PRIMED, // gamestate has been sent, but client hasn't sent a usercmd CS_ACTIVE // client is fully in game } clientState_t;
// Netchan handles packet fragmentation and out of order / duplicate suppression typedef struct { netsrc_t sock; // (ref) int dropped; // between last packet and previous netadr_t remoteAddress; // (ref) int qport; // qport value to write when transmitting /* sequencing variables */ int incomingSequence; int outgoingSequence; /* incoming fragment assembly buffer */ int fragmentSequence; int fragmentLength; byte fragmentBuffer[MAX_MSGLEN]; /* outgoing fragment buffer we need to space out the sending of large fragmented messages */ qboolean unsentFragments; int unsentFragmentStart; int unsentLength; byte unsentBuffer[MAX_MSGLEN]; } netchan_t;
// this structure will be cleared only when the game dll changes typedef struct { qboolean initialized; // sv_init has completed int time; // will be strictly increasing across level changes int snapFlagServerBit; // ^= SNAPFLAG_SERVERCOUNT every SV_SpawnServer() client_t *clients; // [sv_maxclients->integer] (ref) int numSnapshotEntities; // sv_maxclients->integer*PACKET_BACKUP*MAX_PACKET_ENTITIES int nextSnapshotEntities; // next snapshotEntities to use entityState_t *snapshotEntities; // [numSnapshotEntities] (ref) int nextHeartbeatTime; challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting (ref) netadr_t redirectAddress; // for rcon return messages (ref) netadr_t authorizeAddress; // for rcon return messages (ref) } serverStatic_t;
typedef struct { netadr_t adr; // (ref) int challenge; int clientChallenge; // challenge number coming from the client int time; // time the last packet was sent to the autherize server int pingTime; // time the challenge response was sent to client int firstTime; // time the adr was first used, for authorize timeout checks qboolean connected; } challenge_t;
typedef struct { netadrtype_t type; // (ref) byte ip[4]; byte ip6[16]; unsigned short port; unsigned long scope_id; // Needed for IPv6 link-local addresses } netadr_t;
typedef enum { NA_BAD = 0, // an address lookup failed NA_BOT, NA_LOOPBACK, NA_BROADCAST, NA_IP, NA_IP6, NA_MULTICAST6, NA_UNSPEC } netadrtype_t;
typedef enum { NS_CLIENT, NS_SERVER } netsrc_t;
typedef struct netchan_buffer_s { msg_t msg; // (ref) byte msgBuffer[MAX_MSGLEN]; struct netchan_buffer_s *next; } netchan_buffer_t;
// server to client commands // the svc_strings[] array in cl_parse.c should mirror this enum svc_ops_e { svc_bad, svc_nop, svc_gamestate, svc_configstring, // [short] [string] only in gamestate messages svc_baseline, // only in gamestate messages svc_serverCommand, // [string] to be executed by client game module svc_download, // [short] size [size bytes] svc_snapshot, svc_EOF, /* svc_extension follows a svc_EOF, followed by another svc_* ... this keeps legacy clients compatible. */ svc_extension, svc_voip, // not wrapped in USE_VOIP, so this value is reserved. };
// client to server commands enum clc_ops_e { clc_bad, clc_nop, clc_move, // [[usercmd_t] clc_moveNoDelta, // [[usercmd_t] clc_clientCommand, // [string] message clc_EOF, /* clc_extension follows a clc_EOF, followed by another clc_* ... this keeps legacy servers compatible. */ clc_extension, clc_voip, // not wrapped in USE_VOIP, so this value is reserved. };
typedef struct { qboolean allowoverflow; // if false, do a Com_Error qboolean overflowed; // set to true if the buffer size failed (with allowoverflow set) qboolean oob; // set to true if the buffer size failed (with allowoverflow set) byte *data; int maxsize; int cursize; int readcount; int bit; // for bitwise reads and writes } msg_t;
typedef enum { TR_STATIONARY, TR_INTERPOLATE, // non-parametric, but interpolate between snapshots TR_LINEAR, TR_LINEAR_STOP, TR_SINE, // value = base + sin( time / duration ) * delta TR_GRAVITY } trType_t;
// snapshots are a view of the server at a given time // Snapshots are generated at regular time intervals by the server, // but they may not be sent if a client's rate level is exceeded, or // they may be dropped by the network. typedef struct { int snapFlags; // SNAPFLAG_RATE_DELAYED, etc int ping; int serverTime; // server time the message is valid for (in msec) byte areamask[MAX_MAP_AREA_BYTES]; // portalarea visibility bits playerState_t ps; // complete information about the current player at this time (ref) int numEntities; // all of the entities that need to be presented entityState_t entities[MAX_ENTITIES_IN_SNAPSHOT]; // at the time of this snapshot (ref) int numServerCommands; // text based server commands to execute when this int serverCommandSequence; // snapshot becomes current } snapshot_t;
// centity_t have a direct corespondence with gentity_t in the game, but // only the entityState_t is directly communicated to the cgame typedef struct centity_s { entityState_t currentState; // from cg.frame (ref) entityState_t nextState; // from cg.nextFrame, if available (ref) qboolean interpolate; // true if next is valid to interpolate to qboolean currentValid; // true if cg.frame holds this entity int muzzleFlashTime; // move to playerEntity? int previousEvent; int teleportFlag; int trailTime; // so missile trails can handle dropped initial packets int dustTrailTime; int miscTime; int snapShotTime; // last time this entity was found in a snapshot playerEntity_t pe; // (ref) int errorTime; // decay the error from this time vec3_t errorOrigin; vec3_t errorAngles; qboolean extrapolated; // false if origin / angles is an interpolation vec3_t rawOrigin; vec3_t rawAngles; vec3_t beamEnd; // exact interpolated position of entity on this frame vec3_t lerpOrigin; vec3_t lerpAngles; } centity_t;
// player entities need to track more information // than any other type of entity. // note that not every player entity is a client entity, // because corpses after respawn are outside the normal // client numbering range typedef struct { lerpFrame_t legs, torso, flag; // (ref) int painTime; int painDirection; // flip from 0 to 1 int lightningFiring; /* railgun trail spawning */ vec3_t railgunImpact; qboolean railgunFlash; /* machinegun spinning */ float barrelAngle; int barrelTime; qboolean barrelSpinning; } playerEntity_t;
typedef struct { int oldFrame; int oldFrameTime; // time when ->oldFrame was exactly on int frame; int frameTime; // time when ->frame will be exactly on float backlerp; float yawAngle; qboolean yawing; float pitchAngle; qboolean pitching; int animationNumber; // may include ANIM_TOGGLEBIT animation_t *animation; int animationTime; // time when the first frame of the animation will be exact } lerpFrame_t;
// local entities are created as a result of events or predicted actions, // and live independently from all server transmitted entities typedef struct localEntity_s { struct localEntity_s *prev, *next; leType_t leType; int leFlags; int startTime; int endTime; int fadeInTime; float lifeRate; // 1.0 / (endTime - startTime) trajectory_t pos; trajectory_t angles; float bounceFactor; // 0.0 = no bounce, 1.0 = perfect float color[4]; float radius; float light; vec3_t lightColor; leMarkType_t leMarkType; // mark to leave on fragment impact leBounceSoundType_t leBounceSoundType; refEntity_t refEntity; // (ref) } localEntity_t;
// each client has an associated clientInfo_t // that contains media references necessary to present the // client model and other color coded effects // this is regenerated each time a client's configstring changes, // usually as a result of a userinfo (name, model, etc) change typedef struct { qboolean infoValid; char name[MAX_QPATH]; team_t team; int botSkill; // 0 = not bot, 1-5 = bot vec3_t color1; vec3_t color2; int score; // updated by score servercmds int location; // location index for team mode int health; // you only get this info about your teammates int armor; int curWeapon; int handicap; int wins, losses; // in tourney mode int teamTask; // task in teamplay (offence/defence) qboolean teamLeader; // true when this is a team leader int powerups; // so can display quad/flag status int medkitUsageTime; int invulnerabilityStartTime; int invulnerabilityStopTime; int breathPuffTime; /* when clientinfo is changed, the loading of models/skins/sounds can be deferred until you are dead, to prevent hitches in gameplay */ char modelName[MAX_QPATH]; char skinName[MAX_QPATH]; char headModelName[MAX_QPATH]; char headSkinName[MAX_QPATH]; char redTeam[MAX_TEAMNAME]; char blueTeam[MAX_TEAMNAME]; qboolean deferred; qboolean newAnims; // true if using the new mission pack animations qboolean fixedlegs; // true if legs yaw is always the same as torso yaw qboolean fixedtorso; // true if torso never changes yaw vec3_t headOffset; // move head in icon views footstep_t footsteps; gender_t gender; // from model qhandle_t legsModel; qhandle_t legsSkin; qhandle_t torsoModel; qhandle_t torsoSkin; qhandle_t headModel; qhandle_t headSkin; qhandle_t modelIcon; animation_t animations[MAX_TOTALANIMATIONS]; sfxHandle_t sounds[MAX_CUSTOM_SOUNDS]; // (int) } clientInfo_t;
// each WP_* weapon enum has an associated weaponInfo_t // that contains media references necessary to present the // weapon and its effects typedef struct weaponInfo_s { qboolean registered; gitem_t *item; // (ref) qhandle_t handsModel; // the hands don't actually draw, they just position the weapon qhandle_t weaponModel; qhandle_t barrelModel; qhandle_t flashModel; vec3_t weaponMidpoint; // so it will rotate centered instead of by tag float flashDlight; vec3_t flashDlightColor; sfxHandle_t flashSound[4]; // fast firing weapons randomly choose (int) qhandle_t weaponIcon; qhandle_t ammoIcon; qhandle_t ammoModel; qhandle_t missileModel; sfxHandle_t missileSound; // (int) void (* missileTrailFunc) (centity_t *ce, const struct weaponInfo_s *wi); float missileDlight; vec3_t missileDlightColor; int missileRenderfx; void (* ejectBrassFunc) (centity_t *); float trailRadius; float wiTrailTime; sfxHandle_t readySound; // (int) sfxHandle_t firingSound; // (int) qboolean loopFireSound; // (int) } weaponInfo_t;
// each IT_* item has an associated itemInfo_t // that constains media references necessary to present the // item and its effects typedef struct { qboolean registered; qhandle_t models[MAX_ITEM_MODELS]; qhandle_t icon; } itemInfo_t;
typedef struct { int clientFrame; // incremented each frame int clientNum; qboolean demoPlayback; qboolean levelShot; // taking a level menu screenshot int deferredPlayerLoading; qboolean loading; // don't defer players at initial startup qboolean intermissionStarted; // don't play voice rewards, because game will end shortly /* there are only one or two snapshot_t that are relevent at a time */ int latestSnapshotNum; // the number of snapshots the client system has received int latestSnapshotTime; // the time from latestSnapshotNum, so we don't need to read the snapshot yet snapshot_t *snap; // cg.snap->serverTime <= cg.time (ref) snapshot_t *nextSnap; // cg.nextSnap->serverTime > cg.time, or NULL (ref) snapshot_t activeSnapshots[2]; // (ref) float frameInterpolation; // (float)( cg.time - cg.frame->serverTime ) / (cg.nextFrame->serverTime - cg.frame->serverTime) qboolean thisFrameTeleport; qboolean nextFrameTeleport; int frametime; // cg.time - cg.oldTime int time; // this is the time value that the client // is rendering at. int oldTime; // time at last frame, used for missile trails and prediction checking int physicsTime; // either cg.snap->time or cg.nextSnap->time int timelimitWarnings; // 5 min, 1 min, overtime int fraglimitWarnings; qboolean mapRestart; // set on a map restart to set back the weapon qboolean renderingThirdPerson; // during deaths, chasecams, etc // prediction state qboolean hyperspace; // true if prediction has hit a trigger_teleport playerState_t predictedPlayerState; // (ref) centity_t predictedPlayerEntity; // (ref) qboolean validPPS; // clear until the first call to CG_PredictPlayerState int predictedErrorTime; vec3_t predictedError; int eventSequence; int predictableEvents[MAX_PREDICTED_EVENTS]; float stepChange; // for stair up smoothing int stepTime; float duckChange; // for duck viewheight smoothing int duckTime; float landChange; // for landing hard int landTime; // input state sent to server int weaponSelect; /* auto rotating items */ vec3_t autoAngles; vec3_t autoAxis[3]; vec3_t autoAnglesFast; vec3_t autoAxisFast[3]; /* view rendering */ refdef_t refdef; // (ref) vec3_t refdefViewAngles; // will be converted to refdef.viewaxis /* zoom key */ qboolean zoomed; int zoomTime; float zoomSensitivity; /* information screen text during loading */ char infoScreenText[MAX_STRING_CHARS]; /* scoreboard */ int scoresRequestTime; int numScores; int selectedScore; int teamScores[2]; score_t scores[MAX_CLIENTS]; qboolean showScores; qboolean scoreBoardShowing; int scoreFadeTime; char killerName[MAX_NAME_LENGTH]; char spectatorList[MAX_STRING_CHARS]; // list of names int spectatorLen; // length of list float spectatorWidth; // width in device units int spectatorTime; // next time to offset int spectatorPaintX; // current paint x int spectatorPaintX2; // current paint x int spectatorOffset; // current offset from start int spectatorPaintLen; // current offset from start /* skull trails */ skulltrail_t skulltrails[MAX_CLIENTS]; /* centerprinting */ int centerPrintTime; int centerPrintCharWidth; int centerPrintY; char centerPrint[1024]; int centerPrintLines; /* low ammo warning state */ int lowAmmoWarning; // 1 = low, 2 = empty /* kill timers for carnage reward */ int lastKillTime; /* crosshair client ID */ int crosshairClientNum; int crosshairClientTime; /* powerup active flashing */ int powerupActive; int powerupTime; /* attacking player */ int attackerTime; int voiceTime; /* reward medals */ int rewardStack; int rewardTime; int rewardCount[MAX_REWARDSTACK]; qhandle_t rewardShader[MAX_REWARDSTACK]; qhandle_t rewardSound[MAX_REWARDSTACK]; /* sound buffer mainly for announcer sounds */ int soundBufferIn; int soundBufferOut; int soundTime; qhandle_t soundBuffer[MAX_SOUNDBUFFER]; /* for voice chat buffer */ int voiceChatTime; int voiceChatBufferIn; int voiceChatBufferOut; /* warmup countdown */ int warmup; int warmupCount; int itemPickup; int itemPickupTime; int itemPickupBlendTime; // the pulse around the crosshair is timed seperately int weaponSelectTime; int weaponAnimation; int weaponAnimationTime; /* blend blobs */ float damageTime; float damageX, damageY, damageValue; /* status bar head */ float headYaw; float headEndPitch; float headEndYaw; int headEndTime; float headStartPitch; float headStartYaw; int headStartTime; /* view movement */ float v_dmg_time; float v_dmg_pitch; float v_dmg_roll; vec3_t kick_angles; // weapon kicks vec3_t kick_origin; /* temp working variables for player view */ float bobfracsin; int bobcycle; float xyspeed; int nextOrbitTime; /* development tool */ refEntity_t testModelEntity; // (ref) char testModelName[MAX_QPATH]; qboolean testGun; } cg_t;
// all of the model, shader, and sound references that are // loaded at gamestate time are stored in cgMedia_t // Other media that can be tied to clients, weapons, or items are // stored in the clientInfo_t, itemInfo_t, weaponInfo_t, and powerupInfo_t typedef struct { qhandle_t charsetShader; qhandle_t charsetProp; qhandle_t charsetPropGlow; qhandle_t charsetPropB; qhandle_t whiteShader; qhandle_t redCubeModel; qhandle_t blueCubeModel; qhandle_t redCubeIcon; qhandle_t blueCubeIcon; qhandle_t redFlagModel; qhandle_t blueFlagModel; qhandle_t neutralFlagModel; qhandle_t redFlagShader[3]; qhandle_t blueFlagShader[3]; qhandle_t flagShader[4]; qhandle_t flagPoleModel; qhandle_t flagFlapModel; qhandle_t redFlagFlapSkin; qhandle_t blueFlagFlapSkin; qhandle_t neutralFlagFlapSkin; qhandle_t redFlagBaseModel; qhandle_t blueFlagBaseModel; qhandle_t neutralFlagBaseModel; #ifdef MISSIONPACK qhandle_t overloadBaseModel; qhandle_t overloadTargetModel; qhandle_t overloadLightsModel; qhandle_t overloadEnergyModel; qhandle_t harvesterModel; qhandle_t harvesterRedSkin; qhandle_t harvesterBlueSkin; qhandle_t harvesterNeutralModel; #endif qhandle_t armorModel; qhandle_t armorIcon; qhandle_t teamStatusBar; qhandle_t deferShader; // gib explosions qhandle_t gibAbdomen; qhandle_t gibArm; qhandle_t gibChest; qhandle_t gibFist; qhandle_t gibFoot; qhandle_t gibForearm; qhandle_t gibIntestine; qhandle_t gibLeg; qhandle_t gibSkull; qhandle_t gibBrain; qhandle_t smoke2; qhandle_t machinegunBrassModel; qhandle_t shotgunBrassModel; qhandle_t railRingsShader; qhandle_t railCoreShader; qhandle_t lightningShader; qhandle_t friendShader; qhandle_t balloonShader; qhandle_t connectionShader; qhandle_t selectShader; qhandle_t viewBloodShader; qhandle_t tracerShader; qhandle_t crosshairShader[NUM_CROSSHAIRS]; qhandle_t lagometerShader; qhandle_t backTileShader; qhandle_t noammoShader; qhandle_t smokePuffShader; qhandle_t smokePuffRageProShader; qhandle_t shotgunSmokePuffShader; qhandle_t plasmaBallShader; qhandle_t waterBubbleShader; qhandle_t bloodTrailShader; #ifdef MISSIONPACK qhandle_t nailPuffShader; qhandle_t blueProxMine; #endif qhandle_t numberShaders[11]; qhandle_t shadowMarkShader; qhandle_t botSkillShaders[5]; // wall mark shaders qhandle_t wakeMarkShader; qhandle_t bloodMarkShader; qhandle_t bulletMarkShader; qhandle_t burnMarkShader; qhandle_t holeMarkShader; qhandle_t energyMarkShader; // powerup shaders qhandle_t quadShader; qhandle_t redQuadShader; qhandle_t quadWeaponShader; qhandle_t invisShader; qhandle_t regenShader; qhandle_t battleSuitShader; qhandle_t battleWeaponShader; qhandle_t hastePuffShader; qhandle_t redKamikazeShader; qhandle_t blueKamikazeShader; // weapon effect models qhandle_t bulletFlashModel; qhandle_t ringFlashModel; qhandle_t dishFlashModel; qhandle_t lightningExplosionModel; // weapon effect shaders qhandle_t railExplosionShader; qhandle_t plasmaExplosionShader; qhandle_t bulletExplosionShader; qhandle_t rocketExplosionShader; qhandle_t grenadeExplosionShader; qhandle_t bfgExplosionShader; qhandle_t bloodExplosionShader; // special effects models qhandle_t teleportEffectModel; qhandle_t teleportEffectShader; #ifdef MISSIONPACK qhandle_t kamikazeEffectModel; qhandle_t kamikazeShockWave; qhandle_t kamikazeHeadModel; qhandle_t kamikazeHeadTrail; qhandle_t guardPowerupModel; qhandle_t scoutPowerupModel; qhandle_t doublerPowerupModel; qhandle_t ammoRegenPowerupModel; qhandle_t invulnerabilityImpactModel; qhandle_t invulnerabilityJuicedModel; qhandle_t medkitUsageModel; qhandle_t dustPuffShader; qhandle_t heartShader; #endif qhandle_t invulnerabilityPowerupModel; // scoreboard headers qhandle_t scoreboardName; qhandle_t scoreboardPing; qhandle_t scoreboardScore; qhandle_t scoreboardTime; // medals shown during gameplay qhandle_t medalImpressive; qhandle_t medalExcellent; qhandle_t medalGauntlet; qhandle_t medalDefend; qhandle_t medalAssist; qhandle_t medalCapture; // sounds sfxHandle_t quadSound; sfxHandle_t tracerSound; sfxHandle_t selectSound; sfxHandle_t useNothingSound; sfxHandle_t wearOffSound; sfxHandle_t footsteps[FOOTSTEP_TOTAL][4]; sfxHandle_t sfx_lghit1; sfxHandle_t sfx_lghit2; sfxHandle_t sfx_lghit3; sfxHandle_t sfx_ric1; sfxHandle_t sfx_ric2; sfxHandle_t sfx_ric3; sfxHandle_t sfx_railg; sfxHandle_t sfx_rockexp; sfxHandle_t sfx_plasmaexp; #ifdef MISSIONPACK sfxHandle_t sfx_proxexp; sfxHandle_t sfx_nghit; sfxHandle_t sfx_nghitflesh; sfxHandle_t sfx_nghitmetal; sfxHandle_t sfx_chghit; sfxHandle_t sfx_chghitflesh; sfxHandle_t sfx_chghitmetal; sfxHandle_t kamikazeExplodeSound; sfxHandle_t kamikazeImplodeSound; sfxHandle_t kamikazeFarSound; sfxHandle_t useInvulnerabilitySound; sfxHandle_t invulnerabilityImpactSound1; sfxHandle_t invulnerabilityImpactSound2; sfxHandle_t invulnerabilityImpactSound3; sfxHandle_t invulnerabilityJuicedSound; sfxHandle_t obeliskHitSound1; sfxHandle_t obeliskHitSound2; sfxHandle_t obeliskHitSound3; sfxHandle_t obeliskRespawnSound; sfxHandle_t winnerSound; sfxHandle_t loserSound; sfxHandle_t youSuckSound; #endif sfxHandle_t gibSound; sfxHandle_t gibBounce1Sound; sfxHandle_t gibBounce2Sound; sfxHandle_t gibBounce3Sound; sfxHandle_t teleInSound; sfxHandle_t teleOutSound; sfxHandle_t noAmmoSound; sfxHandle_t respawnSound; sfxHandle_t talkSound; sfxHandle_t landSound; sfxHandle_t fallSound; sfxHandle_t jumpPadSound; sfxHandle_t oneMinuteSound; sfxHandle_t fiveMinuteSound; sfxHandle_t suddenDeathSound; sfxHandle_t threeFragSound; sfxHandle_t twoFragSound; sfxHandle_t oneFragSound; sfxHandle_t hitSound; sfxHandle_t hitSoundHighArmor; sfxHandle_t hitSoundLowArmor; sfxHandle_t hitTeamSound; sfxHandle_t impressiveSound; sfxHandle_t excellentSound; sfxHandle_t deniedSound; sfxHandle_t humiliationSound; sfxHandle_t assistSound; sfxHandle_t defendSound; sfxHandle_t firstImpressiveSound; sfxHandle_t firstExcellentSound; sfxHandle_t firstHumiliationSound; sfxHandle_t takenLeadSound; sfxHandle_t tiedLeadSound; sfxHandle_t lostLeadSound; sfxHandle_t voteNow; sfxHandle_t votePassed; sfxHandle_t voteFailed; sfxHandle_t watrInSound; sfxHandle_t watrOutSound; sfxHandle_t watrUnSound; sfxHandle_t flightSound; sfxHandle_t medkitSound; sfxHandle_t weaponHoverSound; // teamplay sounds sfxHandle_t captureAwardSound; sfxHandle_t redScoredSound; sfxHandle_t blueScoredSound; sfxHandle_t redLeadsSound; sfxHandle_t blueLeadsSound; sfxHandle_t teamsTiedSound; sfxHandle_t captureYourTeamSound; sfxHandle_t captureOpponentSound; sfxHandle_t returnYourTeamSound; sfxHandle_t returnOpponentSound; sfxHandle_t takenYourTeamSound; sfxHandle_t takenOpponentSound; sfxHandle_t redFlagReturnedSound; sfxHandle_t blueFlagReturnedSound; sfxHandle_t neutralFlagReturnedSound; sfxHandle_t enemyTookYourFlagSound; sfxHandle_t enemyTookTheFlagSound; sfxHandle_t yourTeamTookEnemyFlagSound; sfxHandle_t yourTeamTookTheFlagSound; sfxHandle_t youHaveFlagSound; sfxHandle_t yourBaseIsUnderAttackSound; sfxHandle_t holyShitSound; // tournament sounds sfxHandle_t count3Sound; sfxHandle_t count2Sound; sfxHandle_t count1Sound; sfxHandle_t countFightSound; sfxHandle_t countPrepareSound; #ifdef MISSIONPACK // new stuff qhandle_t patrolShader; qhandle_t assaultShader; qhandle_t campShader; qhandle_t followShader; qhandle_t defendShader; qhandle_t teamLeaderShader; qhandle_t retrieveShader; qhandle_t escortShader; qhandle_t flagShaders[3]; sfxHandle_t countPrepareTeamSound; sfxHandle_t ammoregenSound; sfxHandle_t doublerSound; sfxHandle_t guardSound; sfxHandle_t scoutSound; #endif qhandle_t cursor; qhandle_t selectCursor; qhandle_t sizeCursor; sfxHandle_t regenSound; sfxHandle_t protectSound; sfxHandle_t n_healthSound; sfxHandle_t hgrenb1aSound; sfxHandle_t hgrenb2aSound; sfxHandle_t wstbimplSound; sfxHandle_t wstbimpmSound; sfxHandle_t wstbimpdSound; sfxHandle_t wstbactvSound; } cgMedia_t;
// The client game static (cgs) structure hold everything // loaded or calculated from the gamestate. It will NOT // be cleared when a tournement restart is done, allowing // all clients to begin playing instantly typedef struct { gameState_t gameState; // gamestate from server (ref) glconfig_t glconfig; // rendering configuration (ref) float screenXScale; // derived from glconfig float screenYScale; float screenXBias; int serverCommandSequence; // reliable command stream counter int processedSnapshotNum; // the number of snapshots cgame has requested qboolean localServer; // detected on startup by checking sv_running /* parsed from serverinfo */ gametype_t gametype; // (ref) int dmflags; int teamflags; int fraglimit; int capturelimit; int timelimit; int maxclients; char mapname[MAX_QPATH]; char redTeam[MAX_QPATH]; char blueTeam[MAX_QPATH]; int voteTime; int voteYes; int voteNo; qboolean voteModified; // beep whenever changed char voteString[MAX_STRING_TOKENS]; int teamVoteTime[2]; int teamVoteYes[2]; int teamVoteNo[2]; qboolean teamVoteModified[2]; // beep whenever changed char teamVoteString[2][MAX_STRING_TOKENS]; int levelStartTime; int scores1, scores2; // from configstrings int redflag, blueflag; // flag status from configstrings int flagStatus; qboolean newHud; /* locally derived information from gamestate */ qhandle_t gameModels[MAX_MODELS]; sfxHandle_t gameSounds[MAX_SOUNDS]; // (int) int numInlineModels; qhandle_t inlineDrawModel[MAX_MODELS]; vec3_t inlineModelMidpoints[MAX_MODELS]; clientInfo_t clientinfo[MAX_CLIENTS]; /* teamchat width is *3 because of embedded color codes */ char teamChatMsgs[TEAMCHAT_HEIGHT][TEAMCHAT_WIDTH * 3 + 1]; int teamChatMsgTimes[TEAMCHAT_HEIGHT]; int teamChatPos; int teamLastChatPos; int cursorX; int cursorY; qboolean eventHandling; qboolean mouseCaptured; qboolean sizingHud; void *capturedItem; qhandle_t activeCursor; /* orders */ int currentOrder; qboolean orderPending; int orderTime; int currentVoiceClient; int acceptOrderTime; int acceptTask; int acceptLeader; char acceptVoice[MAX_NAME_LENGTH]; /* media */ cgMedia_t media; // (ref) } cgs_t;
// snapshots are a view of the server at a given time typedef struct { qboolean valid; // cleared if delta parsing was invalid int snapFlags; // rate delayed and dropped commands int serverTime; // server time the message is valid for (in msec) int messageNum; // copied from netchan->incoming_sequence int deltaNum; // messageNum the delta is from int ping; // time from when cmdNum-1 was sent to time packet was reeceived byte areamask[MAX_MAP_AREA_BYTES]; // portalarea visibility bits int cmdNum; // the next cmdNum the server is expecting playerState_t ps; // complete information about the current player at this time (ref) int numEntities; // all of the entities that need to be presented int parseEntitiesNum; // at the time of this snapshot int serverCommandNum; // execute all commands up to this before // making the snapshot current } clSnapshot_t;
typedef struct { int timeoutcount; // it requres several frames in a timeout condition // to disconnect, preventing debugging breaks from // causing immediate disconnects on continue clSnapshot_t snap; // latest received from server (ref) int serverTime; // may be paused during play int oldServerTime; // to prevent time from flowing bakcwards int oldFrameServerTime; // to check tournament restarts int serverTimeDelta; // cl.serverTime = cls.realtime + cl.serverTimeDelta /* this value changes as net lag varies */ qboolean extrapolatedSnapshot; // set if any cgame frame has been forced to extrapolate /* cleared when CL_AdjustTimeDelta looks at it */ qboolean newSnapshots; // set on parse of any valid packet gameState_t gameState; // configstrings !!!! char mapname[MAX_QPATH]; // extracted from CS_SERVERINFO int parseEntitiesNum; // index (not anded off) into cl_parse_entities[] int mouseDx[2], mouseDy[2]; // added to by mouse events int mouseIndex; int joystickAxis[MAX_JOYSTICK_AXIS]; // set by joystick events /* cgame communicates a few values to the client system */ int cgameUserCmdValue; // current weapon to add to usercmd_t float cgameSensitivity; /* cmds[cmdNumber] is the predicted command, [cmdNumber-1] is the last properly generated command */ usercmd_t cmds[CMD_BACKUP]; // each mesage will send several old cmds (ref) int cmdNumber; // incremented each frame, because multiple /* frames may need to be packed into a single packet */ outPacket_t outPackets[PACKET_BACKUP]; // information about each packet we have sent out /* the client maintains its own idea of view angles, which are sent to the server each frame. It is cleared to 0 upon entering each level. the server sends a delta each frame which is added to the locally tracked view angles to account for standing on rotating objects, and teleport direction changes */ vec3_t viewangles; int serverId; // included in each client message so the server // can tell if it is for a prior map_restart // big stuff at end of structure so most offsets are 15 bits or less clSnapshot_t snapshots[PACKET_BACKUP]; // (ref) entityState_t entityBaselines[MAX_GENTITIES]; // for delta compression when not in previous frame (ref) entityState_t parseEntities[MAX_PARSE_ENTITIES]; // (ref) } clientActive_t;
The clientConnection_t structure is wiped when disconnecting from a server, either to go to a full screen console, play a demo, or connect to a different server A connection can be to either a server through the network layer or a demo through a file. typedef struct { int clientNum; int lastPacketSentTime; // for retransmits during connection int lastPacketTime; // for timeouts netadr_t serverAddress; // (ref) int connectTime; // for connection retransmits int connectPacketCount; // for display on connection dialog char serverMessage[MAX_STRING_TOKENS]; // for display on connection dialog int challenge; // from the server to use for connecting int checksumFeed; // from the server for checksum calculations /* these are our reliable messages that go to the server */ int reliableSequence; int reliableAcknowledge; // the last one the server has executed char reliableCommands[MAX_RELIABLE_COMMANDS][MAX_STRING_CHARS]; /* server message (unreliable) and command (reliable) sequence numbers are NOT cleared at level changes, but continue to increase as long as the connection is valid message sequence is used by both the network layer and the delta compression layer */ int serverMessageSequence; /* reliable messages received from server */ int serverCommandSequence; int lastExecutedServerCommand; // last server command grabbed or executed with CL_GetServerCommand char serverCommands[MAX_RELIABLE_COMMANDS][MAX_STRING_CHARS]; /* file transfer from server */ fileHandle_t download; char downloadTempName[MAX_OSPATH]; char downloadName[MAX_OSPATH]; #ifdef USE_CURL qboolean cURLEnabled; qboolean cURLUsed; qboolean cURLDisconnected; char downloadURL[MAX_OSPATH]; CURL *downloadCURL; CURLM *downloadCURLM; #endif int sv_allowDownload; char sv_dlURL[MAX_CVAR_VALUE_STRING]; int downloadNumber; int downloadBlock; // block we are waiting for int downloadCount; // how many bytes we got int downloadSize; // how many bytes we got char downloadList[MAX_INFO_STRING]; // list of paks we need to download qboolean downloadRestart; // if true, we need to do another FS_Restart because we downloaded a pak /* demo information */ char demoName[MAX_QPATH]; qboolean spDemoRecording; qboolean demorecording; qboolean demoplaying; qboolean demowaiting; // don't record until a non-delta message is received qboolean firstDemoFrameSkipped; fileHandle_t demofile; int timeDemoFrames; // counter of rendered frames int timeDemoStart; // cls.realtime before first frame int timeDemoBaseTime; // each frame will be at this time + frameNum * 50 int timeDemoLastFrame; // time the last frame was rendered int timeDemoMinDuration; // minimum frame duration int timeDemoMaxDuration; // maximum frame duration unsigned char timeDemoDurations[MAX_TIMEDEMO_DURATIONS]; // log of frame durations #ifdef USE_VOIP qboolean speexInitialized; int speexFrameSize; int speexSampleRate; /* incoming data... */ SpeexBits speexDecoderBits[MAX_CLIENTS]; void *speexDecoder[MAX_CLIENTS]; byte voipIncomingGeneration[MAX_CLIENTS]; int voipIncomingSequence[MAX_CLIENTS]; float voipGain[MAX_CLIENTS]; qboolean voipIgnore[MAX_CLIENTS]; qboolean voipMuteAll; /* outgoing data... */ int voipTarget1; // these three ints make up a bit mask of 92 bits. int voipTarget2; // the bits say who a VoIP pack is addressed to: int voipTarget3; // (1 << clientnum). See cl_voipSendTarget cvar. SpeexPreprocessState *speexPreprocessor; SpeexBits speexEncoderBits; void *speexEncoder; int voipOutgoingDataSize; int voipOutgoingDataFrames; int voipOutgoingSequence; byte voipOutgoingGeneration; byte voipOutgoingData[1024]; float voipPower; #endif /* big stuff at end of structure so most offsets are 15 bits or less */ netchan_t netchan; // (ref) } clientConnection_t;
typedef struct { connstate_t state; // connection status qboolean cddialog; // bring up the cd needed dialog next frame char servername[MAX_OSPATH]; // name of server from original connect (used by reconnect) /* when the server clears the hunk, all of these must be restarted */ qboolean rendererStarted; qboolean soundStarted; qboolean soundRegistered; qboolean uiStarted; qboolean cgameStarted; int framecount; int frametime; // msec since last frame int realtime; // ignores pause int realFrametime; // ignoring pause, so console always works int numlocalservers; serverInfo_t localServers[MAX_OTHER_SERVERS]; // (ref) int numglobalservers; serverInfo_t globalServers[MAX_GLOBAL_SERVERS]; // (ref) /* additional global servers */ int numGlobalServerAddresses; netadr_t globalServerAddresses[MAX_GLOBAL_SERVERS]; // (ref) int numfavoriteservers; serverInfo_t favoriteServers[MAX_OTHER_SERVERS]; // (ref) int pingUpdateSource; // source currently pinging or updating /* update server info */ netadr_t updateServer; // (ref) char updateChallenge[MAX_TOKEN_CHARS]; char updateInfoString[MAX_INFO_STRING]; netadr_t authorizeServer; // (ref) /* rendering info */ glconfig_t glconfig; qhandle_t charSetShader; qhandle_t whiteShader; qhandle_t consoleShader; } clientStatic_t;
typedef struct { netadr_t adr; int start; int time; char info[MAX_INFO_STRING]; } ping_t;
typedef struct { netadr_t adr; // (ref) char hostName[MAX_NAME_LENGTH]; char mapName[MAX_NAME_LENGTH]; char game[MAX_NAME_LENGTH]; int netType; int gameType; int clients; int maxClients; int minPing; int maxPing; int ping; qboolean visible; int punkbuster; } serverInfo_t;
typedef enum { RT_MODEL, RT_POLY, RT_SPRITE, RT_BEAM, RT_RAIL_CORE, RT_RAIL_RINGS, RT_LIGHTNING, RT_PORTALSURFACE, // doesn't draw anything, just info for portals RT_MAX_REF_ENTITY_TYPE } refEntityType_t;
typedef struct { refEntityType_t reType; int renderfx; qhandle_t hModel; // opaque type outside refresh /* most recent data */ vec3_t lightingOrigin; // so multi-part models can be lit identically (RF_LIGHTING_ORIGIN) float shadowPlane; // projection shadows go here, stencils go slightly lower vec3_t axis[3]; // rotation vectors qboolean nonNormalizedAxes; // axis are not normalized, i.e. they have scale float origin[3]; // also used as MODEL_BEAM's "from" int frame; // also used as MODEL_BEAM's diameter /* previous data for frame interpolation */ float oldorigin[3]; // also used as MODEL_BEAM's "to" int oldframe; float backlerp; // 0.0 = current, 1.0 = old /* texturing */ int skinNum; // inline skin index qhandle_t customSkin; // NULL for default skin qhandle_t customShader; // use one image for the entire thing /* misc */ byte shaderRGBA[4]; // colors used by rgbgen entity shaders float shaderTexCoord[2]; // texture coordinates used by tcMod entity modifiers float shaderTime; // subtracted from refdef time to control effect start times /* extra sprite information */ float radius; float rotation; } refEntity_t;
typedef struct { int x, y, width, height; float fov_x, fov_y; vec3_t vieworg; vec3_t viewaxis[3]; // transformation matrix /* time in milliseconds for shader effects and other time dependent rendering issues */ int time; int rdflags; // RDF_NOWORLDMODEL, etc /* 1 bits will prevent the associated area from rendering at all */ byte areamask[MAX_MAP_AREA_BYTES]; /* text messages for deform text shaders */ char text[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH]; } refdef_t;
typedef struct { int client; int score; int ping; int time; int scoreFlags; int powerUps; int accuracy; int impressiveCount; int excellentCount; int guantletCount; int defendCount; int assistCount; int captures; qboolean perfect; int team; } score_t;
typedef struct { int stringOffsets[MAX_CONFIGSTRINGS]; char stringData[MAX_GAMESTATE_CHARS]; int dataCount; } gameState_t;
typedef struct { char renderer_string[MAX_STRING_CHARS]; char vendor_string[MAX_STRING_CHARS]; char version_string[MAX_STRING_CHARS]; char extensions_string[BIG_INFO_STRING]; int maxTextureSize; // queried from GL int numTextureUnits; // multitexture ability int colorBits, depthBits, stencilBits; glDriverType_t driverType; glHardwareType_t hardwareType; qboolean deviceSupportsGamma; textureCompression_t textureCompression; qboolean textureEnvAddAvailable; int vidWidth, vidHeight; // aspect is the screen's physical width / height, which may be different // than scrWidth / scrHeight if the pixels are non-square // normal screens should be 4/3, but wide aspect monitors may be 16/9 float windowAspect; int displayFrequency; // synonymous with "does rendering consume the entire screen?", therefore // a Voodoo or Voodoo2 will have this set to TRUE, as will a Win32 ICD that // used CDS. qboolean isFullscreen; qboolean stereoEnabled; qboolean smpActive; // dual processor } glconfig_t;
typedef enum { GT_FFA, // free for all GT_TOURNAMENT, // one on one tournament GT_SINGLE_PLAYER, // single player ffa //-- team games go after this -- GT_TEAM, // team deathmatch GT_CTF, // capture the flag GT_1FCTF, GT_OBELISK, GT_HARVESTER, GT_MAX_GAME_TYPE } gametype_t;