Built in functions

Discuss programming in the QuakeC language.
Post Reply
goblinoid
Posts: 22
Joined: Fri Mar 21, 2008 9:28 pm

Built in functions

Post by goblinoid »

Greetings,

At the end of defs.qc there is a bunch of built in functions, can someone explain me how they work? I mean in a generic way, not what each of them does, like where they come from, how the engine handle them, things like that.

Thanks
KrimZon
Posts: 11
Joined: Fri Nov 05, 2004 6:18 pm

Re: Built in functions

Post by KrimZon »

All the actual compiled QuakeC code is compiled into one array of instructions. There's also a bunch of indexes for things like global variables, fields and functions.

Each entry in the function list contains, among other things, the index into the instruction list of the first instruction of that function.

Builtins however have a negative index, and instead point to an index in an engine-side list of C function pointers. The engine checks the sign and if it's negative it looks in the builtin list and calls the C function rather than interpreting any instructions from the progs. The # number in the declaration/definition of a builtin is its actual position in the builtins list.

So the engine has to define every single builtin function that gets made available to the QC. They're generally for something that QC can't do on its own, or which would be much slower to do in QC. To QC they behave exactly like QC functions - they take parameters, they return a value and they can affect other globals or entities while running.

I don't know if that fully explains it. I have further notes on QuakeC here but they're incomplete and aimed for developing a QC interpreter. There's also a somewhat human-readable dump of the stock progs.dat, which I used when making those notes.

(While posting this I noticed slight errors in my notes, but they still demonstrate the general structure of a compiled progs.dat)
goblinoid
Posts: 22
Joined: Fri Mar 21, 2008 9:28 pm

Post by goblinoid »

Thank you KrimZon, it's more clear now. I'll take a look in those links later.

I have another question, how they should be delcared on defs.qc? Does their names mater or if they're in the right order they'll work anyway?
KrimZon
Posts: 11
Joined: Fri Nov 05, 2004 6:18 pm

Post by KrimZon »

That's actually a pretty useful point - the only thing that matters when declaring a particular builtin is the number. (Also the parameters have to match so that they make sense to the function and don't cause an error, but they don't have to be exact).

You can change the name of a builtin and write your own wrapper for it - Frikbot does this to make it so easy to add to any mod - it does stuff like:

Code: Select all

void(entity e, string s) sprint_real = #24;
void(entity e, string s) sprint =
{
  if (!e.is_bot)
    sprint_real(e, s);
};
This means that the rest of any mod can keep calling sprintf but the builtin only gets called for real players.

You can also have multiple names for the same builtin, a common example being:

Code: Select all

void(entity e, string s) centerprint = #73;
void(entity e, string s1, string s2) centerprint2 = #73;
void(entity e, string s1, string s2, string s3) centerprint3 = #73;
// etc.
You'll then get multiple functions in the function list that point to the same builtin.

All the # part does is say that instead of having a body, this function is performed by the built in function pointer #73 or whichever number it is.

They're actually defined the same as a normal function (at least in the original QuakeC syntax) except where the body goes, you put # followed by a number:

Code: Select all

*return_value* ( *parameter_list* ) *name* = { *code* }; // qc
*return_value* ( *parameter_list* ) *name* = #*number* ; // builtin
It's replacing the body "{ .. }" with builtin number "#...".


So:

They can be in any order. (Just have to be defined before use.)

They can have any name.

There can be duplicates with different names.

They can have any parameters so long as the builtin code knows what to do with them. (But for most of the stock quake builtins the parameters in defs.qc are pretty much the only right ones.)

Also you don't even have to define builtins you don't use - they can just be left out entirely. (This is how extensions work - the engine has the builtins but there's no problem for mods to not define them or call them. You can also define a builtin that isn't present in a particular engine, and everything will be fine so long as you don't actually call that function.)
goblinoid
Posts: 22
Joined: Fri Mar 21, 2008 9:28 pm

Post by goblinoid »

Thanks again KrimZon.

I have a problem with a mod and mvdsv, it's not recognising some built in function. Perhaps they're out of order or something, I'll check that.

Anything else I should know about builtins?
Lardarse
Posts: 266
Joined: Sat Nov 05, 2005 1:58 pm
Location: Bristol, UK

Post by Lardarse »

There is a hard limit of 8 function paramaters that can be passed to a function. Modern QuakeC compilers allow you to extend that, but it's not possible to send more than 8 parameters to a builtin function.
Roaming status: Testing and documentation
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Post by Spike »

if your mvdsv problem is with mvdsv-specific builtins then you probably need to set a cvar so they actually exist and the 'standard' ones do not.
you could instead add some string that makes it think its ktpro.
sadly I don't remember the string or cvar name
Post Reply