• Register

The Quake Database for anything quake 1 related! (YES IT LIVES!)

Post tutorial Report RSS Quake c - pointers, struct and the entity

Comparison of C pointers, structs and Quake-C's entity type.

Posted by on - Advanced Server Side Coding

We will now relate two important C programming concepts to Quake-C.
These are the pointer and the struct.

Pointer: a variable that stores a memory address.

Struct: "objects" that contain variables inside of them.

This might seem confusing. Dont worry - you are in league with C programming disciples the world over. This is a complicated set of ideas that takes time and effort to understand. For C coders, sometimes it takes years to get them straight. Quake-C is a little bit easier because the engine hides some of the difficulty of usage and understanding.

C code examples;

pointer:

char *h_name;

struct:

typedef struct
{
vec3_t normal;
float dist;
} plane_t;

These are from the glquake source code.

In essence in C, every variable is really a pointer. The compiler hides this from you. "h_name" contains a memory address. This memory location contains the data. Things are more difficult in C! "h_name" can not, as defined, be used - you have to allocate memory first. Any C coder knows what I mean. (And thus one of the greatest evils of C coding ever was born - the dreaded "memory leak"...)

Quake-C hides these two concepts from you in the entity construct. Entity is a special case - a pointer to a struct. This is how the glquake engine C code defines an entity:

typedef struct entity_s
{
qboolean forcelink; // model changed

int update_type;

entity_state_t baseline; // to fill in defaults in updates

double msgtime; // time of last update
vec3_t msg_origins[2]; // last two updates (0 is newest)
vec3_t origin;
vec3_t msg_angles[2]; // last two updates (0 is newest)
vec3_t angles;
struct model_s *model; // NULL = no model
struct efrag_s *efrag; // linked list of efrags
int frame;
float syncbase; // for client-side animations
byte *colormap;
int effects; // light, particals, etc
int skinnum; // for Alias models
int visframe; // last frame this entity was
// found in an active leaf

int dlightframe; // dynamic lighting
int dlightbits;

// FIXME: could turn these into a union
int trivial_accept;
struct mnode_s *topnode; // for bmodels, first world node
// that splits bmodel, or NULL if
// not split
} entity_t;

As a Quake-C coder, you wont even see half of that.

This is the information from the player entity in vanilla quake:

server EDICT 1:
modelindex 59.0000
absmin ' 463.0000 -369.0000 63.0312'
absmax ' 497.0000 -335.0000 121.0312'
movetype 3.0000
solid 3.0000
origin ' 480.0000 -352.0000 88.0312'
oldorigin ' 480.0000 -352.0000 88.0312'
angles ' -0.0000 90.0000 0.0000'
classname player
model progs/player.mdl
frame 12.0000
mins ' -16.0000 -16.0000 -24.0000'
maxs ' 16.0000 16.0000 32.0000'
size ' 32.0000 32.0000 56.0000'
think player_stand1()
nextthink 1.7140
health 100.0000
weapon 1.0000
weaponmodel progs/v_shot.mdl
currentammo 25.0000
ammo_shells 25.0000
items 4353.0000
takedamage 2.0000
view_ofs ' 0.0000 0.0000 22.0000'
v_angle ' 0.0000 90.0000 0.0000'
netname player
flags 4616.0000
team 1.0000
max_health 100.0000
watertype -1.0000
th_pain player_pain()
th_die PlayerDie()
walkframe 1.0000
attack_finished 1.2140
jump_flag -33.3334
air_finished 13.6307
dmg 2.0000

In essence this data is from a "pointer" to an entity "struct" stored in memory.
What you dont see is any element that is: float with "0" value, blank string, '0 0 0' vector, world value entity pointer, or 0 void type. These elements are all there, the print function is coded not to display them.

The entity struct is hidden by Quake-C and is dynamic in the engine. By dynamic I mean that Quake-C code can add elements while running that are not pre-programmed in the engines C code.

Entities store data for control of almost *everything* that happens in the game! Player avatar - entity, monsters - entities, doors, plats, deathmatch walls - entities.

This includes non-visible (trigger fields, blank model string or "progs/null.mdl") "think" and trigger entities. Think entities are used to control game action and flow. Trigger entities can be touched or damaged and ideally cause some other action to occur via the {entity_pointer}.target and {entity_pointer}.targetname elements.

Thus the entity is a very important concept to understand for Quake-C coders.

The struct of entity is defined in progs/defs.qc and other source files by special types. Some of this data specified by the engine MUST be there. There is a special part of defs.qc that MUST occur in a certain order and MUST match what is in the game engine.

These control the entity construct:

.float
.vector
.string
.entity
.void()

They are used just like normal variables.

.float one;

This will add an floating point element to *every* single entity accessed as {entity_pointer}.one

These are all pointers to some data for the entity construct.
Float is a single floating point value.

There is no integer type. You have to use a float. If you want bit flags, there are 24 valid bit flags in a float. NOTE: that last time I tested it, floating point round off error is a concern for significantly large value floats. Just for all you hardcore coders and mathematicians out there.

Vector is a set of 3 floating point values with {vector_descriptor} for the entire vector and sub elements accessed via: {vector_descriptor}_x, {vector_descriptor}_y and {vector_descriptor}_z.

Within an entity this becomes {entity_pointer}.{vector_descriptor} for the entire vector and sub elements: {entity_pointer}.{vector_descriptor}_x, {entity_pointer}.{vector_descriptor}_y and {entity_pointer}.{vector_descriptor}_z.

String points to variable length string data.

Entity is a pointer to the entire entity structure. That is right - the exact structure we are talking about. This is refrenced {entity_pointer}.{entity_pointer} - and you can have many sub levels of this.

Void is a pointer to storage for a function call address.

This leads to a significant server crash - the null function call error. If an {entity_pointer}.{void_type} is called and the pointer is 0, the server crashes!

Everything that is a visible model in the game - is an entity. Including the map itself - the worldspawn, entity 0.

So, how do the pointers work?

There are several special pointers:

self, other, world.

"world" is always entity 0. "world.model" will be something like "maps/start.bsp"

"self" and "other" are entity pointers that the engine sets prior to calling various Quake-C functions.

For instance when calling player code, self is set to the memory address of the entity struct of the player that is to be manipulated.

The one instance of the engine calling Quake-C with self, that often confuses Quake-C coders, is the touch function. When a touch function is called self is the object touched and other is the touching object. Other is usually a player, or maybe a monster.

To make a new entity pointer:

entity e;

You can not set the value directly but only by reference:

e = self;

For a completely new entity you must call the builtin spawn()

e = spawn();

This is how the engine creates a new memory allocation for an entity struct.
If successful a blank struct will be returned in the pointer. If not world is returned. It is not absolutely necessary to check this - the server becomes useless long before all the entity space is used.

To use members of the entity struct:

setorigin(e, ' 0 0 0');
setmodel(e, "progs/player.mdl");
e.skin = 1;
e.frame = 10;

Any of the .{type} variables can be referenced for every entity but 0, the world. Some elements of world can NOT be set and trying to do so will crash the server.

Note: you could do (and in some cases you can):

e.origin = ' 0 0 0';
e.model = "progs/player.mdl";

However, setmodel and setorigin have special significance for the engine.

These two elements are very important to an entity! To be visible in the game, an entity MUST: have a valid model string (in most engines [excluding darkplaces and derivatives] the model must have a precache_model() done at map load) and have an origin that occurs withing the empty space of the map.

To recap:

Any "entity" variable is a pointer to an entity structure. The structure is defined by all usage of the five ".{type}" variables in the .qc files listed in "progs.src".

It is certain that some of the greatest confusion in coding Quake-C comes from understanding how entity pointers work. And some of the worst bugs come from having entity pointers set wrong.

Post comment Comments
numbersix Author
numbersix - - 2,244 comments

Quake-c Manual ver 3.4 entry for variables and types:

1. The Quake-C Language

Names of variable, fields, or functions have a maximum of 64 characters, must begin with A-Z,a-z, or _, and can continue with those characters or 0-9.

Definition of new types

Let's start with the bad news: it is impossible, in Quake-C, to define new types. That means for instance that you cannot create a type named ammo, derived from float, that will only be used to store ammo count. So much for the clean programming habits.

Definition of structures and objects

It is often convenient, in C (or C++), to create new structures (or Objects, or record) to store a few related informations at the same place. For instance, you may wish to use a single structure to store all the ammo count of the player, and also the current selected weapon, since those informations are obviously related to each other.

Though both entity and vector are obviously structured types, it is impossible to create new structured types of that kind, in Quake-C. However, the entity type can be modified to suit some of your needs.

Reply Good karma+1 vote
numbersix Author
numbersix - - 2,244 comments

1.2 Constants and variables

Definition of variables

The general form of variable definitions is:

type variable1, variable2;
where type is one of the pre-defined simple types.
Scoping of variables: There are two levels of scoping. By default all variables are global: they can be accessed by any functions, and they are shared by all the functions (and all the clients of a given network server, of course).

But inside the functions, using the keyword local just before the declaration of a variable, you can make this variable visible only the the function itself (i.e. it will be allocated on the stack).

Note that parameters of a functions are treated like local variables, they are only visible to the function, but they can be modified.

Definitions of constants

Any global variable that is initialized by setting a value to it is actually assumed to be a constant.

The general form of definition of constants is then:

type variable1 = value;
Note that though it looks like a definition of variable, with a default initial value, is is totally different. There is no memory reserved for constants, and they are not saved to game files (only regular variables are).

To make matters worse, if you use a constant like a variable, and try to affect a new value to it... well, it's very likely that you will cause troubles to the program (malfunctions, or crashes). So never modify the value of a constant.

Reply Good karma+1 vote
numbersix Author
numbersix - - 2,244 comments

2. The Quake-C Basic Types

2.1 The simple Types

2.1.1 Void type

An empty result, mostly used for definition of procedures (i.e. functions that return no result at all).

2.1.2 Float type

A floating point value.

Floats are also used to store booleans (TRUE, FALSE) or integer values like counters, or bit flags.

Valid syntax: 12 1.6 0.5 -100
Invalid syntax: .5
A parsing ambiguity is present with negative constants. "a-5" will be parsed as "a", then "-5", causing an error. Separate the - from the digits with a space "a - 5" to get the proper behavior.

2.1.3 Vector type

A vector, made of 3 float coordinates.
Used to represent positions or directions in 3D space.
Valid syntax: '0 0 0' or '20.5 -10 0.00001'
Note the simple quotes around the vector. Do not use double quotes, they are reserved for strings.

If you declare a vector foobar, then you can access it's x, y and z fields with: foobar_x, foobar_y,foobar_z.

2.1.4 String type

This is used to store character string.
Used to indicate file names, or messages to be broadcast to players.
Valid syntax: "maps/jrwiz1.bsp" or "ouch!\n"
Use \n for newline.

Note: that character strings cannot be modified, or concatenated. Because they are stored at fixed locations in memory, and if would be potentially troublesome to allow modification.

2.1.5 entity type

The reference of an entity in the game, like things, players, monsters.
For instance, this is the type of the entities self and other.

The entity type is a structured type, made of fields.
A description of each field is available.

Reply Good karma+1 vote
numbersix Author
numbersix - - 2,244 comments

2.2 The field types

2.2.1 What's a field?

Contrary to the other types, the entity type is a reference to an instance of a structured object, that contains many informations of totally different kinds.

To access all these informations conveniently, they are stored as fields of the entity object, and each field is given a name and a type, that makes it distinct of the others.

Some of the fields do not store value, but instead they store the function to be executed in certain conditions. They are called the methods that can be applied to the object.

If Quake-C was an object oriented programming language, those method functions and would be distinguished from the other fields. And, above all, you would be able to create new object types, with their own fields.

As Quake-C stands currently, all the field definitions are definitions of entity fields. So anywhere in your code you could add definition of new fields, and the compiler would interpret them as an extension of the entity definition.

2.2.2 Creating new fields

The only way to extend the entity type is to add some fields at the end of the structures.

This is done via a field definitions, whose general structure is:

.type field_name;
For instance, if you wanted to add a sling to the game, and needed to store the count of pellets for every player, you would add the following line in the source code:

.float ammo_sling;
That will add a fields ammo_sling to every entity in the game, and in particular to the player entities.
Here are all the possible definitions of entity fields, with their types:

.float field_name;
.string field_name;
.vector field_name;
.entity field_name;
The strange bit is that you can add those type definitions almost anywhere in the source code. They are not supposed to be grouped in a single place, where the entity type would be defined.

Reply Good karma+1 vote
numbersix Author
numbersix - - 2,244 comments

2.2.3 Allowed modifications of types

In the first file read by the Quake-C compiler, defs.qc, there must be a definition for the entity fields, and world fields. This definition is hard coded. You had better not touch it, or you will have to recompile Quake itself.

The globals are defined before the special definition void end_sys_globals;
The entity fields are defined before the special definition void end_sys_fields;

It's not important if you don't understand the nonsense above. It's an ugly hack. Just don't modify defs.qc before those two tags, and you won't be in trouble.

Reply Good karma+1 vote
Post a comment

Your comment will be anonymous unless you join the community. Or sign in with your social account: