Engine and vm changes required for tempbuffers (along with a few related builtins like findlist).

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5712 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2020-06-27 19:32:08 +00:00
parent 7a22fb2527
commit 18b2ee695f
9 changed files with 232 additions and 45 deletions

View file

@ -6648,6 +6648,10 @@ static struct {
{"precache_model", PF_cs_PrecacheModel, 20}, // #20 void(string str) precache_model (QUAKE)
{"stuffcmd", PF_NoCSQC, 21}, // #21 void(entity client, string s) stuffcmd (QUAKE) (don't support)
{"findradius", PF_findradius, 22}, // #22 entity(vector org, float rad) findradius (QUAKE)
#ifdef QCGC
{"findradius_list", PF_findradius_list, 0},
{"find_list", PF_FindList, 0},
#endif
{"bprint", PF_NoCSQC, 23}, // #23 void(string s, ...) bprint (QUAKE) (don't support)
{"sprint", PF_NoCSQC, 24}, // #24 void(entity e, string s, ...) sprint (QUAKE) (don't support)
{"dprint", PF_dprint, 25}, // #25 void(string s, ...) dprint (QUAKE)
@ -6756,6 +6760,9 @@ static struct {
{"stov", PF_stov, 117}, // #117 vector(string str) stov (FRIK_FILE)
{"strzone", PF_strzone, 118}, // #118 string(string str) dupstring (FRIK_FILE)
{"strunzone", PF_strunzone, 119}, // #119 void(string str) freestring (FRIK_FILE)
#ifdef QCGC
{"createbuffer", PF_createbuffer, 0},
#endif
{"localsound", PF_cl_localsound, 177},

View file

@ -2283,6 +2283,9 @@ static struct {
{"findentity", PF_FindFloat, 25},
{"findchain", PF_menu_findchain, 26},
{"findchainfloat", PF_menu_findchainfloat, 27},
#ifdef QCGC
{"find_list", PF_FindList, 0},
#endif
{"precache_file", PF_CL_precache_file, 28},
{"precache_sound", PF_CL_precache_sound, 29},
{"coredump", PF_coredump, 30},
@ -2319,6 +2322,9 @@ static struct {
{"stov", PF_stov, 55},
{"strzone", PF_strzone, 56},
{"strunzone", PF_strunzone, 57},
#ifdef QCGC
{"createbuffer", PF_createbuffer, 0},
#endif
{"tokenize", PF_Tokenize, 58},
{"argv", PF_ArgV, 59},
{"isserver", PF_isserver, 60},

View file

@ -1359,11 +1359,13 @@ void QCBUILTIN PF_FindFloat (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
int s;
wedict_t *ed;
#ifdef HAVE_LEGACY
if (prinst->callargc != 3) //I can hate mvdsv if I want to.
{
PR_BIError(prinst, "PF_FindFloat (#98): callargc != 3\nDid you mean to set pr_imitatemvdsv to 1?");
return;
}
#endif
e = G_EDICTNUM(prinst, OFS_PARM0);
f = G_INT(OFS_PARM1)+prinst->fieldadjust;
@ -1402,6 +1404,8 @@ void QCBUILTIN PF_FindString (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
return;
}
//FIXME: bound f
for (e++ ; e < *prinst->parms->num_edicts ; e++)
{
ed = WEDICT_NUM_PB(prinst, e);
@ -1420,6 +1424,85 @@ void QCBUILTIN PF_FindString (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
RETURN_EDICT(prinst, *prinst->parms->edicts);
}
#ifdef QCGC
void QCBUILTIN PF_FindList (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
world_t *w = prinst->parms->user;
int e;
int f = G_INT(OFS_PARM0)+prinst->fieldadjust;
string_t t;
wedict_t *ed;
etype_t type = G_INT(OFS_PARM2);
int *list = alloca(sizeof(*list)*w->num_edicts); //guess at a max
int *retlist;
unsigned found = 0;
//FIXME: bound f
if (type == ev_string)
{
const char *s = PR_GetStringOfs(prinst, OFS_PARM1);
if (!s)
s = ""; /* o.O */
for (e=1 ; e < *prinst->parms->num_edicts ; e++)
{
ed = WEDICT_NUM_PB(prinst, e);
if (ED_ISFREE(ed) || ed->readonly)
continue;
t = ((string_t *)ed->v)[f];
if (!t)
continue;
if (!strcmp(PR_GetString(prinst, t),s))
list[found++] = EDICT_TO_PROG(prinst, ed);
}
}
else if (type == ev_float)
{ //handling -0 properly requires care
float s = G_FLOAT(OFS_PARM1);
for (e=1 ; e < *prinst->parms->num_edicts ; e++)
{
ed = WEDICT_NUM_PB(prinst, e);
if (ED_ISFREE(ed))
continue;
if (((float*)ed->v)[f] == s)
list[found++] = EDICT_TO_PROG(prinst, ed);
}
}
else if (type == ev_vector)
{ //big types...
float *s = G_VECTOR(OFS_PARM1);
for (e=1 ; e < *prinst->parms->num_edicts ; e++)
{
ed = WEDICT_NUM_PB(prinst, e);
if (ED_ISFREE(ed))
continue;
if (((float*)ed->v)[f+0] == s[0]&&
((float*)ed->v)[f+1] == s[1]&&
((float*)ed->v)[f+2] == s[2])
list[found++] = EDICT_TO_PROG(prinst, ed);
}
}
else
{ //generic references and other stuff that can just be treated as ints
int s = G_INT(OFS_PARM1);
for (e=1 ; e < *prinst->parms->num_edicts ; e++)
{
ed = WEDICT_NUM_PB(prinst, e);
if (ED_ISFREE(ed))
continue;
if (((int*)ed->v)[f] == s)
list[found++] = EDICT_TO_PROG(prinst, ed);
}
}
G_INT(OFS_PARM3) = found;
G_INT(OFS_RETURN) = prinst->AllocTempString(prinst, (char**)&retlist, (found+1)*sizeof(*retlist));
memcpy(retlist, list, found*sizeof(*retlist));
retlist[found] = 0;
}
#endif
//Finding
////////////////////////////////////////////////////
//Cvars
@ -3240,9 +3323,6 @@ Returns a chain of entities that have origins within a spherical area
findradius (origin, radius)
=================
*/
#define AREA_ALL 0
#define AREA_SOLID 1
#define AREA_TRIGGER 2
void QCBUILTIN PF_findradius (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
world_t *w = prinst->parms->user;
@ -3340,6 +3420,59 @@ void QCBUILTIN PF_findradius (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl
RETURN_EDICT(prinst, chain);
}
#ifdef QCGC
void QCBUILTIN PF_findradius_list (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
world_t *w = prinst->parms->user;
wedict_t *ent;
float rad;
float *org;
vec3_t eorg;
int i, j;
wedict_t **nearent;
vec3_t mins, maxs;
int numents, count = 0;
int *temp;
org = G_VECTOR(OFS_PARM0);
rad = G_FLOAT(OFS_PARM1);
//find out how many ents there are within the box specified.
mins[0] = org[0] - rad;
mins[1] = org[1] - rad;
mins[2] = org[2] - rad;
maxs[0] = org[0] + rad;
maxs[1] = org[1] + rad;
maxs[2] = org[2] + rad;
nearent = alloca(sizeof(wedict_t)*w->num_edicts); //guess at a max
numents = World_AreaEdicts(w, mins, maxs, nearent, w->num_edicts, AREA_ALL);
//allocate space for a result (overestimating slightly still)
G_INT(OFS_RETURN) = prinst->AllocTempString(prinst, (char**)&temp, (1+numents)*sizeof(*temp));
rad = rad*rad;
for (i=0 ; i<numents ; i++)
{
ent = nearent[i];
if (ent->v->solid == SOLID_NOT && !((pint_t)ent->v->flags & FL_FINDABLE_NONSOLID))
continue;
for (j=0 ; j<3 ; j++)
{
eorg[j] = org[j] - ent->v->origin[j];
eorg[j] -= bound(ent->v->mins[j], org[j], ent->v->maxs[j]);
}
if (DotProduct(eorg,eorg) > rad)
continue;
temp[count++] = EDICT_TO_PROG(prinst, ent);
}
temp[count] = 0;
G_INT(OFS_PARM2) = count;
}
#endif
//entity nextent(entity)
void QCBUILTIN PF_nextent (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
@ -3977,6 +4110,22 @@ void QCBUILTIN PF_strzone(pubprogfuncs_t *prinst, struct globalvars_s *pr_global
#endif
}
#ifdef QCGC
void QCBUILTIN PF_createbuffer (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int len = G_INT(OFS_PARM0);
char *buf;
if (len <= 0)
G_INT(OFS_RETURN) = 0;
else
{
len++;
G_INT(OFS_RETURN) = prinst->AllocTempString(prinst, &buf, len);
memset(buf, 0, len);
}
}
#endif
//string(string str1, string str2, str3, etc) strcat
void QCBUILTIN PF_strcat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
@ -4927,8 +5076,9 @@ void QCBUILTIN PF_uri_escape (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
*result = 0;
while (*s && o < result+sizeof(result)-4)
{
//unreserved chars according to RFC3986
if ((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') || (*s >= '0' && *s <= '9')
|| *s == '.' || *s == '-' || *s == '_')
|| *s == '.' || *s == '-' || *s == '_' || *s == '~')
*o++ = *s++;
else
{

View file

@ -120,6 +120,7 @@ void QCBUILTIN PF_ArgV (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
void QCBUILTIN PF_argv_start_index (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_argv_end_index (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_FindString (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_FindList (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_nextent (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_Sin (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_Cos (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
@ -128,6 +129,7 @@ void QCBUILTIN PF_bound (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals
void QCBUILTIN PF_mod (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_strlen(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_strcat (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_createbuffer (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_ftos (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_fabs (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_vtos (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
@ -380,6 +382,7 @@ void QCBUILTIN PF_strtrim (pubprogfuncs_t *prinst, struct globalvars_s *pr_globa
void QCBUILTIN PF_digest_hex (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_digest_ptr (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_findradius_list (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_findradius (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_edict_for_num (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_num_for_edict (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);

View file

@ -326,6 +326,11 @@ void QDECL World_LinkEdict (world_t *w, wedict_t *ent, qboolean touch_triggers);
// sets ent->v.absmin and ent->v.absmax
// if touchtriggers, calls prog functions for the intersected triggers
#define AREA_ALL 0
#define AREA_SOLID 1
#define AREA_TRIGGER 2
extern int World_AreaEdicts (world_t *w, vec3_t mins, vec3_t maxs, wedict_t **list, int maxcount, int areatype);
#ifdef USEAREAGRID
void World_TouchAllLinks (world_t *w, wedict_t *ent);
extern size_t areagridsequence;

View file

@ -383,42 +383,54 @@ reeval:
case OP_STOREP_FLD: // integers
case OP_STOREP_S:
case OP_STOREP_FNC: // pointers
i = OPB->_int;
errorif (QCPOINTERWRITEFAIL(i, sizeof(int)))
i = OPB->_int + OPC->_int*sizeof(ptr->_int);
errorif (QCPOINTERWRITEFAIL(i, sizeof(ptr->_int)))
{
if (i == -1)
break;
if (i == 0)
QCFAULT(&progfuncs->funcs, "bad pointer write in %s (null pointer)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name));
else
QCFAULT(&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), i, prinst.addressableused);
if (!(ptr=PR_GetWriteTempStringPtr(progfuncs, OPB->_int, OPC->_int*sizeof(ptr->_int), sizeof(ptr->_int))))
{
if (i == -1)
break;
if (i == 0)
QCFAULT(&progfuncs->funcs, "bad pointer write in %s (null pointer)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name));
else
QCFAULT(&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), i, prinst.addressableused);
}
}
ptr = QCPOINTERM(i);
else
ptr = QCPOINTERM(i);
ptr->_int = OPA->_int;
break;
case OP_STOREP_V:
i = OPB->_int;
i = OPB->_int + (OPC->_int*sizeof(ptr->_int));
errorif (QCPOINTERWRITEFAIL(i, sizeof(vec3_t)))
{
if (i == -1)
break;
QCFAULT(&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), i, prinst.addressableused);
if (!(ptr=PR_GetWriteTempStringPtr(progfuncs, OPB->_int, OPC->_int*sizeof(ptr->_int), sizeof(vec3_t))))
{
if (i == -1)
break;
QCFAULT(&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), i, prinst.addressableused);
}
}
ptr = QCPOINTERM(i);
else
ptr = QCPOINTERM(i);
ptr->_vector[0] = OPA->_vector[0];
ptr->_vector[1] = OPA->_vector[1];
ptr->_vector[2] = OPA->_vector[2];
break;
case OP_STOREP_C: //store character in a string
i = OPB->_int;
i = OPB->_int + (OPC->_int)*sizeof(char);
errorif (QCPOINTERWRITEFAIL(i, sizeof(char)))
{
if (i == -1)
break;
QCFAULT(&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), i, prinst.addressableused);
if (!(ptr=PR_GetWriteTempStringPtr(progfuncs, OPB->_int, OPC->_int*sizeof(char), sizeof(char))))
{
if (i == -1)
break;
QCFAULT(&progfuncs->funcs, "bad pointer write in %s (%x >= %x)", PR_StringToNative(&progfuncs->funcs, prinst.pr_xfunction->s_name), i, prinst.addressableused);
}
}
ptr = QCPOINTERM(i);
else
ptr = QCPOINTERM(i);
*(unsigned char *)ptr = (char)OPA->_float;
break;
@ -955,10 +967,10 @@ reeval:
OPC->_int = OPA->_int - OPB->_int;
break;
case OP_LOADP_C: //load character from a string/pointer
i = (unsigned int)OPA->_int + (unsigned int)OPB->_float;
i = (unsigned int)OPA->_int + (int)OPB->_float;
errorif (QCPOINTERREADFAIL(i, sizeof(char)))
{
if (!(ptr=PR_GetReadTempStringPtr(progfuncs, OPA->_int, OPB->_int*4, sizeof(int))))
if (!(ptr=PR_GetReadTempStringPtr(progfuncs, OPA->_int, OPB->_float, sizeof(char))))
{
if (i == -1)
{

View file

@ -1032,13 +1032,13 @@ const char *ASMCALL PR_StringToNative (pubprogfuncs_t *ppf, string_t str)
eval_t *PR_GetReadTempStringPtr(progfuncs_t *progfuncs, string_t str, size_t offset, size_t datasize)
{
static vec3_t dummy; //don't resize anything when reading.
if (((unsigned int)str & STRING_SPECMASK) != STRING_TEMP)
if (((unsigned int)str & STRING_SPECMASK) == STRING_TEMP)
{
unsigned int i = str & ~STRING_SPECMASK;
tempstr_t *temp;
if (i < prinst.maxtempstrings && (temp=prinst.tempstrings[i]))
{
if (offset + datasize < temp->size)
if (offset + datasize <= temp->size)
return (eval_t*)(temp->value + offset);
else
return (eval_t*)dummy;
@ -1048,7 +1048,7 @@ eval_t *PR_GetReadTempStringPtr(progfuncs_t *progfuncs, string_t str, size_t off
}
eval_t *PR_GetWriteTempStringPtr(progfuncs_t *progfuncs, string_t str, size_t offset, size_t datasize)
{
if (((unsigned int)str & STRING_SPECMASK) != STRING_TEMP)
if (((unsigned int)str & STRING_SPECMASK) == STRING_TEMP)
{
unsigned int i = str & ~STRING_SPECMASK;
tempstr_t *temp;
@ -1061,12 +1061,13 @@ eval_t *PR_GetWriteTempStringPtr(progfuncs_t *progfuncs, string_t str, size_t of
newsize = offset + datasize;
if (newsize > (1u<<20u))
return NULL; //gotta have a cut-off point somewhere.
newsize = (newsize+sizeof(float)-1)&~(sizeof(float)-1);
newtemp = progfuncs->funcs.parms->memalloc(sizeof(tempstr_t) - sizeof(((tempstr_t*)NULL)->value) + newsize);
newtemp->size = newsize;
memcpy(newtemp->value, temp->value, temp->size);
memset(newtemp->value+temp->size, 0, newsize-temp->size);
progfuncs->funcs.parms->memfree(temp);
prinst.tempstrings[i] = temp = newtemp;
}
return (eval_t*)(temp->value + offset);
}
@ -1167,7 +1168,7 @@ static size_t PR_QCGC_Sweep(progfuncs_t *progfuncs, smallbool *marked, tempstr_t
#ifdef _DEBUG
if (tempstrings[p] != prinst.tempstrings[p])
{ //something weird happened. tempstrings are supposed to be immutable (at least in length).
externs->Sys_Error("tempstring was reallocated while qc was running");
externs->Sys_Error("tempstring was reallocated while gc was running");
continue;
}
#endif

View file

@ -10572,11 +10572,17 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"traceline", PF_svtraceline, 16, 16, 16, 0, D("void(vector v1, vector v2, float flags, entity ent)", "Traces a thin line through the world from v1 towards v2.\nWill not collide with ent, ent.owner, or any entity who's owner field refers to ent.\nThe passed entity will also be used to determine whether to use a capsule trace, the contents that the trace should impact, and a couple of other extra fields that define the trace.\nThere are no side effects beyond the trace_* globals being written.\nflags&MOVE_NOMONSTERS will not impact on non-bsp entities.\nflags&MOVE_MISSILE will impact with increased size.\nflags&MOVE_HITMODEL will impact upon model meshes, instead of their bounding boxes.\nflags&MOVE_TRIGGERS will also stop on triggers\nflags&MOVE_EVERYTHING will stop if it hits anything, even non-solid entities.\nflags&MOVE_LAGGED will backdate entity positions for the purposes of this builtin according to the indicated player ent's latency, to provide lag compensation.")},
{"checkclient", PF_checkclient, 17, 17, 17, 0, D("entity()", "Returns one of the player entities. The returned player will change periodically.")},
{"find", PF_FindString, 18, 18, 18, 0, D("entity(entity start, .string fld, string match)", "Scan for the next entity with a given field set to the given 'match' value. start should be either world, or the previous entity that was found. Returns world on failure/if there are no more.\nIf you have many many entities then you may find that hashtables will give more performance (but requires extra upkeep).")},
#ifdef QCGC
{"find_list", PF_FindList, 0, 0, 0, 0, D("entity*(.__variant fld, __variant match, int type=EV_STRING, __out int count)", "Scan for the next entity with a given field set to the given 'match' value. start should be either world, or the previous entity that was found. Returns world on failure/if there are no more.\nIf you have many many entities then you may find that hashtables will give more performance (but requires extra upkeep).")},
#endif
{"precache_sound", PF_precache_sound, 19, 19, 19, 0, D("string(string s)", "Precaches a sound, making it known to clients and loading it from disk. This builtin (strongly) should be called during spawn functions. This builtin must be called for the sound before the sound builtin is called, or it might not even be heard.")},
{"precache_model", PF_precache_model, 20, 20, 20, 0, D("string(string s)", "Precaches a model, making it known to clients and loading it from disk if it has a .bsp extension. This builtin (strongly) should be called during spawn functions. This must be called for each model name before setmodel may use that model name.\nModelindicies precached in SSQC will always be positive. CSQC precaches will be negative if they are not also on the server.")},
{"stuffcmd", PF_stuffcmd, 21, 21, 21, 0, D("void(entity client, string s)", "Sends a console command (or cvar) to the client, where it will be executed. Different clients support different commands. Do NOT forget the final \\n.\nThis builtin is generally considered evil.")},
{"stuffcmdflags", PF_stuffcmdflags, 0, 0, 0, 0, D("void(entity client, float flags, string s)", "Sends a console command (or cvar) to the client, where it will be executed. Different clients support different commands. Do NOT forget the final \\n.\nThis (just as evil) variant allows specifying some flags too. See the STUFFCMD_* constants.")},
{"findradius", PF_findradius, 22, 22, 22, 0, D("entity(vector org, float rad, optional .entity chainfield)", "Finds all entities within a distance of the 'org' specified. One entity is returned directly, while other entities are returned via that entity's .chain field.")},
{"findradius", PF_findradius, 22, 22, 22, 0, D(/*"FTEDEP(\"Has recursion issues. Use findradius_list.\") "*/"entity(vector org, float rad, optional .entity chainfield)", "Finds all entities within a distance of the 'org' specified. One entity is returned directly, while other entities are returned via that entity's .chain field. Use findradius_list for an updated alternative without reenterancy issues.")},
#ifdef QCGC
{"findradius_list", PF_findradius_list, 0, 0, 0, 0, D("entity*(vector org, float rad, __out int foundcount, int sort=0)", "Finds all entities linked with a bbox within a distance of the 'org' specified, returning the list as a temp-array (world signifies the end). Unlike findradius, sv_gameplayfix_blowupfallenzombies is ignored (use FL_FINDABLE_NONSOLID instead), while sv_gameplayfix_findradiusdistancetobox and dpcompat_findradiusarealinks are force-enabled. The resulting buffer will automatically be cleaned up by the engine and does not need to be freed.")},
#endif
//both bprint and sprint accept different arguments in QW vs NQ/H2
{"bprint", PF_bprint, 23, 0, 23, 0, D("void(string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8)", "NQ: Concatenates all arguments, and prints the messsage on the console of all connected clients.")},
{"bprint", PF_bprint, 0, 23, 0, 0, D("void(float msglvl, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7)", "QW: Concatenates all string arguments, and prints the messsage on the console of only all clients who's 'msg' infokey is set lower or equal to the supplied 'msglvl' argument.")},
@ -10823,11 +10829,12 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"substring", PF_substring, 0, 0, 0, 116, "string(string s, float start, float length)"}, // (FRIK_FILE)
{"stov", PF_stov, 0, 0, 0, 117, "vector(string s)"}, // (FRIK_FILE)
#ifdef QCGC
{"strzone", PF_strzone, 0, 0, 0, 118, D("FTEDEP(\"Redundant\") string(string s, ...)", "Create a semi-permanent copy of a string that only becomes invalid once strunzone is called on the string (instead of when the engine assumes your string has left scope). This builtin has become redundant in FTEQW due to the FTE_QC_PERSISTENTTEMPSTRINGS extension and is now functionally identical to strcat for compatibility with old engines+mods.")}, // (FRIK_FILE)
{"strunzone", PF_strunzone, 0, 0, 0, 119, D("FTEDEP(\"Redundant\") void(string s)", "Destroys a string that was allocated by strunzone. Further references to the string MAY crash the game. In FTE, this function became redundant and now does nothing.")}, // (FRIK_FILE)
{"strzone", PF_strzone, 0, 0, 0, 118, D("FTEDEP(\"Redundant\") string(string s, ...)", "Create a semi-permanent copy of a string that only becomes invalid once strunzone is called on the string (instead of when the engine assumes your string has left scope). This builtin has become redundant in FTEQW due to the FTE_QC_PERSISTENTTEMPSTRINGS extension and is now functionally identical to strcat for compatibility with old engines+mods.")}, // (FRIK_FILE)
{"strunzone", PF_strunzone, 0, 0, 0, 119, D("FTEDEP(\"Redundant\") void(string s)", "Destroys a string that was allocated by strunzone. Further references to the string MAY crash the game. In FTE, this function became redundant and now does nothing.")}, // (FRIK_FILE)
{"createbuffer", PF_createbuffer, 0, 0, 0, 0, D("void*(int bytes)", "Returns a temporary buffer that can be written to / read from. The buffer will be garbage collected and thus cannot be explicitly freed. Tempstrings and buffer references must not be stored into the buffer as the garbage collector will not scan these.")},
#else
{"strzone", PF_strzone, 0, 0, 0, 118, D("string(string s, ...)", "Create a semi-permanent copy of a string that only becomes invalid once strunzone is called on the string (instead of when the engine assumes your string has left scope).")}, // (FRIK_FILE)
{"strunzone", PF_strunzone, 0, 0, 0, 119, D("void(string s)", "Destroys a string that was allocated by strunzone. Further references to the string MAY crash the game.")}, // (FRIK_FILE)
{"strzone", PF_strzone, 0, 0, 0, 118, D("string(string s, ...)", "Create a semi-permanent copy of a string that only becomes invalid once strunzone is called on the string (instead of when the engine assumes your string has left scope).")}, // (FRIK_FILE)
{"strunzone", PF_strunzone, 0, 0, 0, 119, D("void(string s)", "Destroys a string that was allocated by strunzone. Further references to the string MAY crash the game.")}, // (FRIK_FILE)
#endif
//end frikfile
@ -11124,8 +11131,8 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"getplayerkeyvalue", PF_Fixme,0, 0, 0, 348, D("string(float playernum, string keyname)", "Look up a player's userinfo, to discover things like their name, topcolor, bottomcolor, skin, team, *ver.\nAlso includes scoreboard info like frags, ping, pl, userid, entertime, as well as voipspeaking and voiploudness.")},// (EXT_CSQC)
{"getplayerkeyfloat", PF_Fixme,0, 0, 0, 0, D("float(float playernum, string keyname, optional float assumevalue)", "Cheaper version of getplayerkeyvalue that avoids the need for so many tempstrings.")},
{"getplayerkeyblob", PF_Fixme,0, 0, 0, 0, D("int(float playernum, string keyname, optional void *outptr, int size)", "Obtains a copy of the full data blob. Will write up to size bytes but return the full size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there.")},
{"setlocaluserinfo", PF_Fixme,0, 0, 0, 0, D("void(float seat, string keyname, string newvalue)", "Change a userinfo key for the local player, equivelent to the setinfo console command. The server will normally forward the setting to other clients.")},
{"getlocaluserinfo", PF_Fixme,0, 0, 0, 0, D("string(float seat, string keyname)", "Reads a local userinfo key for the active seat. This is not quite the same as getplayerkeyvalue, due to latency and possible serverside filtering.")},
{"setlocaluserinfo", PF_Fixme,0, 0, 0, 0, D("void(float seat, string keyname, string newvalue)", "Change a userinfo key for the specified local player seat, equivelent to the setinfo console command. The server will normally forward the setting to other clients.")},
{"getlocaluserinfo", PF_Fixme,0, 0, 0, 0, D("string(float seat, string keyname)", "Reads a local userinfo key for the specified local player seat. This is not quite the same as getplayerkeyvalue, due to latency and possible serverside filtering.")},
{"setlocaluserinfoblob",PF_Fixme,0, 0, 0, 0, D("void(float seat, string keyname, void *outptr, int size)", "Sets the userinfo key to a blob that may contain nulls etc. Keys with a leading underscore will be visible to only the server (for user-specific binary settings).")},
{"getlocaluserinfoblob",PF_Fixme,0, 0, 0, 0, D("int(float seat, string keyname, void *outptr, int maxsize)", "Obtains a copy of the full data blob. Will write up to size bytes but return the full size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there.")},
{"getlocalinfo", PF_getlocalinfo,0, 0, 0, 0, D("int(string keyname, optional void *outptr, int size)", "Obtains a copy of a data blob (with spaces) from the server's private localinfo. Will write up to size bytes and return the actual size. Does not null terminate (but memalloc(ret+1) will, if you want to cast the buffer to a string), and the blob may contain embedded nulls. Ignores all special keys, returning only what is actually there.")},
@ -11376,8 +11383,8 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
// {"undefined", PF_Fixme, 0, 0, 0, 507, ""},
// {"undefined", PF_Fixme, 0, 0, 0, 508, ""},
// {"undefined", PF_Fixme, 0, 0, 0, 509, ""},
{"uri_escape", PF_uri_escape, 0, 0, 0, 510, "string(string in)"},//DP_QC_URI_ESCAPE
{"uri_unescape", PF_uri_unescape, 0, 0, 0, 511, "string(string in)"},//DP_QC_URI_ESCAPE
{"uri_escape", PF_uri_escape, 0, 0, 0, 510, D("string(string in)", "Uses percent-encoding to encode any bytes in the input string which are not ascii alphanumeric, period, hyphen, or underscore. All other bytes will expand to eg '%20' for a single space char. This encoding scheme is compatible with http and other uris.")},//DP_QC_URI_ESCAPE
{"uri_unescape", PF_uri_unescape, 0, 0, 0, 511, D("string(string in)", "Undo any percent-encoding in the input string, hopefully resulting in the same original sequence of bytes (and thus chars too).")},//DP_QC_URI_ESCAPE
{"num_for_edict", PF_num_for_edict, 0, 0, 0, 512, "float(entity ent)"},//DP_QC_NUM_FOR_EDICT
{"uri_get", PF_uri_get, 0, 0, 0, 513, D("#define uri_post uri_get\nfloat(string uril, float id, optional string postmimetype, optional string postdata)", "uri_get() gets content from an URL and calls a callback \"uri_get_callback\" with it set as string; an unique ID of the transfer is returned\nreturns 1 on success, and then calls the callback with the ID, 0 or the HTTP status code, and the received data in a string\nFor a POST request, you will typically want the postmimetype set to application/x-www-form-urlencoded.\nFor a GET request, omit the mime+data entirely.\nConsult your webserver/php/etc documentation for best-practise.")},//DP_QC_URI_GET
{"uri_post", PF_uri_get, 0, 0, 0, 513, D("float(string uril, float id, optional string postmimetype, optional string postdata, optional float strbuf)", "uri_get() gets content from an URL and calls a callback \"uri_get_callback\" with it set as string; an unique ID of the transfer is returned\nreturns 1 on success, and then calls the callback with the ID, 0 or the HTTP status code, and the received data in a string"), true},//DP_QC_URI_POST
@ -12047,7 +12054,7 @@ void PR_DumpPlatform_f(void)
{"PlayerPreThink", "void()", QW|NQ, D("With Prediction(QW compat/FTE default): Called before the player's input commands are processed.\nNo Prediction(NQ compat): Called AFTER the player's movement intents have already been processed (ie: velocity will have already changed according to input_*, but before the actual position change.")},
{"PlayerPostThink", "void()", QW|NQ, D("Called after the player's input commands are processed.")},
{"ClientKill", "void()", QW|NQ, D("Called in response to 'cmd kill' (or just 'kill').")},
{"ClientConnect", "void(optional float csqcactive)", QW|NQ|ID1, D("Called after the connecting client has finished loading and is ready to receive active entities. Note that this is NOT the first place that a client might be referred to.")},
{"ClientConnect", "void()", QW|NQ|ID1, D("Called after the connecting client has finished loading and is ready to receive active entities. Note that this is NOT the first place that a client might be referred to. To determine if the client has csqc active (and kick anyone that doesn't), you can use if(infokeyf(self,INFOKEY_P_CSQCACTIVE)) {sprint(self, \"CSQC is required for this server\\n\");dropclient(self);}")},
{"PutClientInServer", "void()", QW|NQ, D("Enginewise, this is only ever called immediately after ClientConnect and is thus a little redundant. Modwise, this is also called for respawning a player etc.")},
{"ClientDisconnect", "void()", QW|NQ, D("Called once a client disconnects or times out. Not guarenteed to be called on map changes.")},
{"SetNewParms", "void()", QW|NQ, D("Called without context when a new client initially connects (before ClientConnect is even called). This function is expected to only set the parm* globals so that they can be decoded properly later. You should not rely on 'self' being set.")},
@ -13064,7 +13071,7 @@ void PR_DumpPlatform_f(void)
" #define DEP __deprecated //predefine this if you want to avoid our deprecation warnings.\n"
"#endif\n"
"#ifndef FTEDEP\n"
" #define FTEDEP //for symbols deprecated in FTE that may still be useful/required for other engines\n"
" #define FTEDEP(reason) //for symbols deprecated in FTE that may still be useful/required for other engines\n"
"#endif\n");

View file

@ -1376,10 +1376,6 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v
return trace;
}
#define AREA_ALL 0
#define AREA_SOLID 1
#define AREA_TRIGGER 2
#ifdef USEAREAGRID
/*