Noob question about csqc

Discuss programming in the QuakeC language.
Post Reply
Nahuel
Posts: 495
Joined: Wed Jan 12, 2011 8:42 pm
Location: mar del plata

Noob question about csqc

Post by Nahuel »

Well, i am using darkplaces. In csqc i added som custom stats (just floats) But i want to add a vector (instead of three separated floats)
in dpextensions i use:

Code: Select all

void(float index, float type, .void field) SV_AddStat = #232;

can i just to use this in ssqc??

Code: Select all

SV_AddStat (STAT_CAMERA, 8, my_vector);
how many stat uses a vector?? I do not understand why csqc uses 4 stats for a string (4 stats carrying a total of 16 charactures) and just one stat for a float!!! how many stats uses a vector in csqc ?? just one stat like a float?? Thanks in advance.
hi, I am nahuel, I love quake and qc.
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: Noob question about csqc

Post by Spike »

Various defs:

Code: Select all

#define ev_string 1  //limited to 15 chars using 4 consecutive stats in dp (the additional stats should not be assigned), limited to 1024 chars in fte using a single stat within a different stat space.
#define ev_float 2  //truncated in dp, full precision in fte.
#define ev_vector 3 //server might support 3 consecutive floats, but the client has no builtin to return 3 consecutive ones.
#define ev_integer 8  //alternatively thought of as 'identity'
#define STAT_CAMERA 32  //private stats should start at 32.
float(float idx) getstat_i = #330; //builtins renamed to avoid fucked up renaming in various 'example' qc mods.
float(float idx) getstat_f = #331; //the fucked up renaming might help if you're evil by default (and renumber ev_float too), but I'm aiming for clarity here.
float(float stnum, float firstbit, float bitcount) getstat_bits = #331; //distinguished from getstat_f by the extra argument
string(float firststnum) getstat_s = #332;
Works fine in FTE, rounded to integers in DP.

Code: Select all

SV_AddStat(STAT_CAMERA, ev_vector, myssqcvectorfield);

mycsqcvectorvariable_x = getstat_f(STAT_CAMERA+0);
mycsqcvectorvariable_y = getstat_f(STAT_CAMERA+1);
mycsqcvectorvariable_z = getstat_f(STAT_CAMERA+2);
Evil hack that avoids DP's truncation.

Code: Select all

SV_AddStat(STAT_CAMERA, ev_integer, myssqcvectorfield_x);
SV_AddStat(STAT_CAMERA, ev_integer, myssqcvectorfield_y);
SV_AddStat(STAT_CAMERA, ev_integer, myssqcvectorfield_z);

mycsqcvectorvariable_x = getstat_i(STAT_CAMERA+0);
mycsqcvectorvariable_y = getstat_i(STAT_CAMERA+1);
mycsqcvectorvariable_z = getstat_i(STAT_CAMERA+2);
regarding floats in DP:
DP uses the older specification, and like vanilla technically does not support float stats. floats are sent in the same way that the STAT_CURRENTAMMO etc stats are sent, ie: rounded to an integer and sent as an integer. Builtin 331(getstat_f) can be used to read ev_float stats by taking that integer and converting to a float (this is also useful for reading entity numbers, which are also technically ints on the wire).
Alternatively, you can tell the engine that your stat was an integer all along, and use some implicit casts. After all, a 32bit value is a 32bit value, whether its a 32bit single precision float or a 32bit integer. Builtin 330(getstat_i) will read the 32bit integer stat directly without conversion (which matches how the server is told to read an integer from the float field without conversion).

regarding floats in FTE:
Internally, FTE has separate integer and float stat types, but for compatibilty setting the float stat will also set the int stat and vice versa. Builtin 330(getstat_i) will directly read the integer copy of the stat, while 331(getstat_f) will directly read the float stat (note that if the server sent an int, the float stat will be a copy of that int, just converted to a float, which still works with entity numbers). ammo stats etc are sent using the same mechanism, and are also able to hold fractional values.
This ensures that the two engines are generally compatible, just that fte has full precision on float stats instead of truncating them.

regarding vectors:
vectors are sent in terms of what they are - 3 consecutive floats. For this reason, the X component ends up in the idx+0 slot, the Y component ends up in idx+1, and Z ends up in idx+2. If you directly specify the float fields, you have the option to completely omit the z or whatever (eg if that field is not otherwise useful like top-down displays). Calling addstat with ev_vector will register 3 consecutive ev_float stats.

regarding strings in DP:
if you have some string stat, which is given the value "ABCDEFGHIJKLMNOP", the first 32bit stat will contain the first 4 8bit chars, thus "ABCD", second will contain the second set of 4 chars "EFGH", third "IJKL", fourth will contain "MNO\0". Yes, DP will truncate it to 15 chars and put a null terminator in that final slot for no apparent reason. when you then call getstat_s it'll combine all four consecutive stats into a single tempstring, for a max of 15 chars. This is why strings use 4 stats and are limited in length - because each stat is only 32bits wide.
The 4-stats/16 chars limit is derived from hexen2's puzzle pieces, but I don't know why dp restricts to 15 instead of 16.

regarding strings in FTE:
string stats are completely separate from numeric stats. This allows them to be variable length, and thus are limited to the generic maximum string length of 1024 instead of only 15 chars. getstat_s still returns a temporary string

regarding STAT_ITEMS:
stat_items is technically an integer stat comprising both self.items AND ((self.items2<<23) or (serverflags<<28)).
It requires special handling to unpack it without using integer operators in QC (which DP does not support). The getstatbits builtin can be used for that. it reads an ev_integer stat and extracts the bits specified, before converting to a float which csqc is able to then read. It is probably best to use a shift of 23 instead of 28, as a float can only hold integer values up to 23 bits before precision is lost.

hopefully that clears something up.
Post Reply