Click for more information!

Code3Arena

ARTICLE 1 - ENTITIES
by SumFuka

This is the first in a series of 'articles' explaining various things about the quake3 game world. Every wondered how you interact with the game world ? This is the first question we're going to tackle... by working from the ground up. Quake's design hasn't changed much from quake1 thru to quake3... the most basic thing in the world is - yes, an entity !

AN ENTITY ?

Virtually anything you can name in the game world is an entity. A rocket ? That's a simple example of an entity. An ammo pack ? An entity. A player ? Again, that's an entity (albeit a special one). Let's take an example... urm... ummm... let's fire a rocket ! Here's how it works.
  1. You press the fire button
  2. An empty entity slot is chosen (i.e. a slot that is not inuse)
  3. A rocket entity is created in that slot
  4. The rocket settings are defined (positioned just in front of you, aimed in a certain direction, moving at 900 units/second, etc)
  5. The rocket moves through the world until an event is triggered :
    • If the rocket hits something damageable (e.g. a player or a wall) then it explodes and the entity is removed
    • If the rocket doesn't hit anything within 10 seconds, it explodes and the entity is removed
    • If the rocket hits the sky then the entity is removed (no explosion).
  6. Once the entity is removed, the slot is marked not inuse and may be re-used
As you can see, a rocket's life is relatively short ! You might be thinking, is there a limit to the number of rockets that can simultaneously be flying around the map ? Well, yes.

HOW MANY ENTITIES EXIST IN THE QUAKE WORLD ?

Time to do some sleuth work. By the way, when we refer to the quake 'world', we mean the game world and everything in it (not 'quakeworld'). What's in the quake world ? Lots of things... like a map, like the players, and like... ENTITIES ! Jump into MSVC and do a "Find in Files" on 'g_entities'. In g_main.c at line 17 we can find :
 gentity_t		g_entities[MAX_GENTITIES];
This line says that there exists a finite array of entities in the game world. This array is called 'g_entities' and is MAX_ENTITIES long. So what is the constant MAX_ENTITIES ?? Do a "Find in Files" on MAX_ENTITIES and we find q_shared.h line 718 (and 717) to be quite interesting :
 #define	GENTITYNUM_BITS		10		// don't need to send any more
 #define	MAX_GENTITIES		(1 << GENTITYNUM_BITS)
Ok, Carmack is exhibiting some guru-level C syntax here. Take my word that (x << y) means to double x y times. Given that ENTITYNUM_BITS is 10, MAX_GENTITIES is therefore 2 to the power of 10, or 1024. In other words, there is room in the world for approximately 1024 rockets, players, weapons, armors etc at any one time.

CAN THE ENTITIES RUN OUT ?

What would happen if you sat at one end of a very long space map with the RL and held down the fire button ? Assuming that your rockets fly for the full ten seconds, you can have about 10 rockets in the air at once. (Remember that when a rocket explodes the entity can be re-used by the next rocket virtually right away). If you start a 32 player game with your mates and you all sit and fire into space, there would be about 320 rockets flying through the air at any one time. We still haven't run out of entities...

There is a certain number of entities that are permanently used during the whole game (for example, players, weapons and items). All other non-permanent entities follow the cycle create - live a short life - reuse. This is something to think about when you're coding mods - If you make a cluster grenade that splits into 100 mini grenades, then one idiot could quickly run your world out of entities by firing a bunch of cluster grenades in quick succession.

What happens if your world runs out of entities ? Assume the worst-case scenario, that your server will crash. If an entity is going to exist for a relatively long time, make sure that it isn't possible for huge numbers of them to exist at the same time.

WHAT'S IN AN ENTITY ?

Let's look at g_local.h, starting at line 49 :
struct gentity_s {
	entityState_t	s;	// communicated by server to clients
	entityShared_t	r;	// shared by both the server system and game

	// DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER
	// EXPECTS THE FIELDS IN THAT ORDER!
	//================================

	struct gclient_s	*client;			// NULL if not a client

	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

	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;
	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;
	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 w/o 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

	int		watertype;
	int		waterlevel;

	int		noise_index;

	// timing variables
	float		wait;
	float		random;

	gitem_t		*item;	// for bonus items

	qboolean	botDelayBegin;
};
Right up the top there is some important stuff - an entityState_t and entityShared_t... these bits include general stuff like the location of the entity, the type of entity it is, the size of the bounding box, etc.

Next comes struct gclient_s *client; - this is a pointer to additional information, if the entity is a 'client' (i.e. player or bot). If the entity is not a client, then this bit is NULL (unused).

Further down we can see heaps of interesting fields - classname, speed, movedir, target, team etc. Not all of these fields are used with all entities... a red armor would not use the 'damage' fields, for example (wheras a rocket would). Most of these are pretty self-explanatory.

"THINKING" ETC

Lines 110-116 in g_local.h define function pointers. The names of these are think, reached, blocked, touch, use, pain, die. Although the syntax here is very hardcore (remember, Carmack is a codecutting God), it's quite easy to explain with an example.

We want our rockets to explode after 10 seconds. Remember, from g_missile.c :

	bolt->nextthink = level.time + 10000;
	bolt->think = G_ExplodeMissile;
This means that after 10 seconds, the rocket 'thinks' and the function G_ExplodeMissile is called on the rocket entity. Similarly, a grenade explodes after 2.5 seconds. Can you find the code for this ? (Answer : g_missile.c line 294). 'Thinking' is a nice "fire and forget" mechanism - we create an entity, define what it does at some future time, and then forget about it - the game engine takes care of the entity from then on.

10 times a second, the server checks if each entity is due to 'think'. If yes, the 'think' function is run for that entity. Similarly, other entity functions are called in response to certain events. If a player is killed, then the player_die function is called (see g_client.c line 921). The same goes for touch, blocked, pain, etc.

PERMANENT ENTITIES & CLIENTS

In q_shared.h we see that the maximum number of clients (players or bots) - MAX_CLIENTS - is 128. By definition, the first MAX_CLIENTS entities in g_entities are reserved for clients. Arrays in C are numbered from 0, so g_entities[0] is reserved for client 0, g_entities[1] for client 1... up to g_entities[127] for player 127.

Just as there exists an array of entities in the world, there also exists an array of 'client information' structures - see line 18 in g_main.c :

 gclient_t		g_clients[MAX_CLIENTS];
Here we have an array of 128 gclient_t's (client information structures). And each of the first 128 g_entities point to a corresponding g_client[x]. For example, g_entities[0]->client points to g_clients[0], etc. We'll have a look at what's in the client information structure another time.

Well, entities really do make the world go round (well, they actually go around the world, kinda... anyway...). Another time we'll talk about temporary entities (rail trails, blood spurts and similar effects). Till then, remember... "West Side."

[ Home ] [ Next >> ]