Tweak a few extension checks, to try to avoid nasty surprises.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5961 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2021-07-17 15:09:34 +00:00
parent 44e6ec8dd1
commit 626a053b36
4 changed files with 219 additions and 92 deletions

View File

@ -2681,7 +2681,7 @@ void QCBUILTIN PF_R_SetViewFlag(pubprogfuncs_t *prinst, struct globalvars_s *pr_
PR_BIError(prinst, "PF_R_SetViewFlag: invalid pointer\n");
return;
}
ptr = (struct reverbproperties_s*)(prinst->stringtable + qcptr);
ptr = (prinst->stringtable + qcptr);
memcpy(r_refdef.userdata, ptr, size);
}
break;
@ -4531,7 +4531,7 @@ static void QCBUILTIN PF_cs_serverkeyblob (pubprogfuncs_t *prinst, struct global
PR_BIError(prinst, "PF_cs_serverkeyblob: invalid pointer\n");
return;
}
ptr = (struct reverbproperties_s*)(prinst->stringtable + qcptr);
ptr = (prinst->stringtable + qcptr);
blob = InfoBuf_BlobForKey(&cl.serverinfo, keyname, &blobsize, NULL);
@ -4619,7 +4619,7 @@ static void QCBUILTIN PF_cs_getplayerkeyblob (pubprogfuncs_t *prinst, struct glo
PR_BIError(prinst, "PF_cs_getplayerkeyblob: invalid pointer\n");
return;
}
ptr = (struct reverbproperties_s*)(prinst->stringtable + qcptr);
ptr = (prinst->stringtable + qcptr);
if ((unsigned int)pnum >= (unsigned int)cl.allocated_client_slots)
G_INT(OFS_RETURN) = 0;
@ -4668,10 +4668,11 @@ static void QCBUILTIN PF_cs_infokey (pubprogfuncs_t *prinst, struct globalvars_s
G_INT(OFS_RETURN) = 0;
}
static int PR_CSQC_NamedBuiltinUnsupported(const char *name);
static void QCBUILTIN PF_checkextension (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *extname = PR_GetStringOfs(prinst, OFS_PARM0);
int i;
int i, ebi;
for (i = 0; i < QSG_Extensions_count; i++)
{
if (!QSG_Extensions[i].name)
@ -4685,7 +4686,18 @@ static void QCBUILTIN PF_checkextension (pubprogfuncs_t *prinst, struct globalva
G_FLOAT(OFS_RETURN) = QSG_Extensions[i].extensioncheck(&ctx);
}
else
{
//make sure all of its builtins are actually supported.
//if any is marked as 'fixme' then we've not implemented it in csqc yet.
for (ebi = 0; ebi < countof(QSG_Extensions[i].builtinnames) && QSG_Extensions[i].builtinnames[ebi]; ebi++)
if (PR_CSQC_NamedBuiltinUnsupported(QSG_Extensions[i].builtinnames[ebi]))
{
G_FLOAT(OFS_RETURN) = false;
return;
}
G_FLOAT(OFS_RETURN) = true;
}
return;
}
}
@ -6928,9 +6940,9 @@ static struct {
{"registertempent", PF_NoCSQC, 208},//{"RegisterTempEnt", PF_RegisterTEnt, 0, 0, 0, 208},
{"customtempent", PF_NoCSQC, 209},//{"CustomTempEnt", PF_CustomTEnt, 0, 0, 0, 209},
//210
// {"fork", PF_Fixme, 210},//{"fork", PF_Fork, 0, 0, 0, 210},
{"fork", PF_Fixme, 210},//{"fork", PF_Fork, 0, 0, 0, 210},
{"abort", PF_Abort, 211}, //#211 void() abort (FTE_MULTITHREADED)
// {"sleep", PF_Fixme, 212},//{"sleep", PF_Sleep, 0, 0, 0, 212},
{"sleep", PF_Fixme, 212},//{"sleep", PF_Sleep, 0, 0, 0, 212},
{"forceinfokey", PF_NoCSQC, 213},//{"forceinfokey", PF_ForceInfoKey, 0, 0, 0, 213},
{"forceinfokeyblob", PF_NoCSQC, 0},//{"forceinfokey", PF_ForceInfoKey, 0, 0, 0, 213},
{"chat", PF_NoCSQC, 214},//{"chat", PF_chat, 0, 0, 0, 214},// #214 void(string filename, float starttag, entity edict) SV_Chat (FTE_NPCCHAT)
@ -7515,6 +7527,16 @@ static struct {
{NULL}
};
static int PR_CSQC_NamedBuiltinUnsupported(const char *name)
{
int i;
for (i = 0; BuiltinList[i].name; i++)
{
if (!strcmp(BuiltinList[i].name, name))
return (BuiltinList[i].bifunc == PF_Fixme);
}
return false;
}
int PR_CSQC_BuiltinValid(char *name, int num)
{
int i;
@ -8476,6 +8498,17 @@ void PR_CSExtensionList_f(void)
int ebi;
int bi;
qc_extension_t *extlist;
qboolean inactive;
char biissues[8192];
const builtin_t *pr_builtin = csqc_builtin;
int num;
qboolean wrongmodule;
int j;
const char *extname;
extcheck_t extcheck = {cls.fteprotocolextensions, cls.fteprotocolextensions2};
#define SHOW_ACTIVEEXT 1
#define SHOW_ACTIVEBI 2
@ -8525,56 +8558,83 @@ void PR_CSExtensionList_f(void)
for (i = 0; i < QSG_Extensions_count; i++)
{
*biissues = 0;
inactive = false;
if (!extlist[i].name)
continue;
if (i < 32)
for (ebi = 0; ebi < countof(extlist[i].builtinnames) && extlist[i].builtinnames[ebi]; ebi++)
{
if (!(cls.fteprotocolextensions & (1<<i)))
{
if (showflags & SHOW_NOTSUPPORTEDEXT)
Con_Printf("^4protocol %s is not supported\n", extlist[i].name);
continue;
}
}
wrongmodule = false;
for (ebi = 0; ebi < extlist[i].numbuiltins; ebi++)
{
for (bi = 0; BuiltinList[bi].name; bi++)
{
if (!strcmp(BuiltinList[bi].name, extlist[i].builtinnames[ebi]))
break;
{
if (BuiltinList[bi].bifunc == PF_Fixme)
wrongmodule=true;
else
break;
}
}
if (!BuiltinList[bi].name)
{
if (showflags & SHOW_NOTSUPPORTEDEXT)
Con_Printf("^4%s is not supported\n", extlist[i].name);
break;
if (wrongmodule)
continue;
Q_strncatz2(biissues, va(CON_ERROR"\t^4#:%s is not known\n", extlist[i].builtinnames[ebi]));
inactive = true;
continue;
}
if (csqc_builtin[BuiltinList[bi].ebfsnum] != BuiltinList[bi].bifunc)
num = BuiltinList[bi].ebfsnum;
if (!num)
;//builtins with no number are handled at load time. there are no number conflicts so no way for the builtin to be inactive. if there is an error then its not because of the extension itself.
else if (pr_builtin[num] != BuiltinList[bi].bifunc)
{
if (csqc_builtin[BuiltinList[bi].ebfsnum] == PF_Fixme)
{
if (showflags & SHOW_NOTACTIVEEXT)
Con_Printf("^4%s is not currently active (builtin: %s#%i)\n", extlist[i].name, BuiltinList[bi].name, BuiltinList[bi].ebfsnum);
}
if (pr_builtin[num] == PF_Fixme)
Q_strncatz2(biissues, va("\t^4#%i:%s is not implemented\n", num, BuiltinList[bi].name));
else
{
if (showflags & SHOW_NOTACTIVEEXT)
Con_Printf("^4%s was overridden (builtin: %s#%i)\n", extlist[i].name, BuiltinList[bi].name, BuiltinList[bi].ebfsnum);
for (j = 0; BuiltinList[j].name; j++)
{
if (BuiltinList[j].bifunc == pr_builtin[num])
{
Q_strncatz2(biissues, va("\t#%i:%s is currently %s\n", num,BuiltinList[bi].name, BuiltinList[j].name));
break;
}
}
if (!BuiltinList[j].name)
Q_strncatz2(biissues, va("\t^4#%i:%s is currently unknown\n", num, BuiltinList[bi].name));
}
break;
inactive = true;
}
}
if (ebi == extlist[i].numbuiltins)
if (extlist[i].description)
extname = va("^[%s\\tip\\%s^]", extlist[i].name, extlist[i].description);
else
extname = extlist[i].name;
if (extlist[i].extensioncheck && !extlist[i].extensioncheck(&extcheck))
{
if (showflags & SHOW_NOTSUPPORTEDEXT)
Con_Printf(CON_WARNING"protocol %s is blocked\n%s", extname, biissues);
}
else if (inactive)
{
if (showflags & SHOW_NOTSUPPORTEDEXT)
Con_Printf(CON_ERROR"%s is inactive\n%s", extname, biissues);
}
else
{
if (showflags & SHOW_ACTIVEEXT)
{
if (!extlist[i].numbuiltins)
Con_Printf("%s is supported\n", extlist[i].name);
if (!extlist[i].builtinnames[0])
Con_Printf("%s is supported\n%s", extname, biissues);
else
Con_Printf("%s is currently active\n", extlist[i].name);
Con_Printf("%s is currently active\n%s", extname, biissues);
}
}
}

View File

@ -7533,9 +7533,9 @@ static qboolean check_pext_csqc (extcheck_t *extcheck) {return !!(extcheck->p
//static qboolean check_pext2_maxplayers (extcheck_t *extcheck) {return !!(extcheck->pext2 & PEXT2_MAXPLAYERS);}
//static qboolean check_pext2_predinfo (extcheck_t *extcheck) {return !!(extcheck->pext2 & PEXT2_PREDINFO);}
//static qboolean check_pext2_newsizeencoding (extcheck_t *extcheck) {return !!(extcheck->pext2 & PEXT2_NEWSIZEENCODING);}
//static qboolean check_pext2_infoblobs (extcheck_t *extcheck) {return !!(extcheck->pext2 & PEXT2_INFOBLOBS);}
static qboolean check_pext2_infoblobs (extcheck_t *extcheck) {return !!(extcheck->pext2 & PEXT2_INFOBLOBS);}
//static qboolean check_pext2_stunaware (extcheck_t *extcheck) {return !!(extcheck->pext2 & PEXT2_STUNAWARE);}
//static qboolean check_pext2_vrinputs (extcheck_t *extcheck) {return !!(extcheck->pext2 & PEXT2_VRINPUTS);}
static qboolean check_pext2_vrinputs (extcheck_t *extcheck) {return !!(extcheck->pext2 & PEXT2_VRINPUTS);}
#define NOBI NULL, 0,{NULL},
qc_extension_t QSG_Extensions[] = {
@ -7545,7 +7545,7 @@ qc_extension_t QSG_Extensions[] = {
{"??MVDSV_BUILTINS", NULL, 21,{"executecommand", "mvdtokenize", "mvdargc", "mvdargv",
"teamfield", "substr", "mvdstrcat", "mvdstrlen", "str2byte",
"str2short", "mvdnewstr", "mvdfreestr", "conprint", "readcmd",
"mvdstrcpy", "strstr", "mvdstrncpy", "log", "redirectcmd",
"mvdstrcpy", "strstr", "mvdstrncpy", "logtext", "redirectcmd",
"mvdcalltimeofday", "forcedemoframe"}},
{"BX_COLOREDTEXT"},
{"DP_CON_SET", NULL, 0,{NULL}, "The 'set' console command exists, and can be used to create/set cvars."},
@ -7784,7 +7784,7 @@ qc_extension_t QSG_Extensions[] = {
{"FTE_QC_PERSISTENTTEMPSTRINGS", NOBI "Supersedes DP_QC_MULTIPLETEMPSTRINGS. Temp strings are garbage collected automatically, and do not expire while they're still in use. This makes strzone redundant."},
#endif
#ifdef RAGDOLL
{"FTE_QC_RAGDOLL_WIP", NULL, 1,{"ragupdate", "skel_set_bone_world", "skel_mmap"}},
{"FTE_QC_RAGDOLL_WIP", NULL, 1,{"skel_ragupdate", "skel_set_bone_world", "skel_mmap"}},
#endif
{"FTE_QC_SENDPACKET", NULL, 1,{"sendpacket"}, "Allows the use of out-of-band udp packets to/from other hosts. Includes the SV_ParseConnectionlessPacket event."},
{"FTE_QC_STUFFCMDFLAGS", NULL, 1,{"stuffcmdflags"}, "Variation on regular stuffcmd that gives control over how spectators/mvds should be treated."},
@ -7828,7 +7828,8 @@ qc_extension_t QSG_Extensions[] = {
{"FTE_TERRAIN_MAP", NULL, 1,{"terrain_edit"}, "This engine supports .hmp files, as well as terrain embedded within bsp files."},
{"FTE_RAW_MAP", NULL, 7,{"brush_get","brush_create","brush_delete","brush_selected","brush_getfacepoints","brush_calcfacepoints","brush_findinvolume"}, "This engine supports directly loading .map files, as well as realtime editing of the various brushes."},
#endif
{"FTE_INFOBLOBS", check_pext2_infoblobs, 0,{"forceinfokeyblob", "getplayerkeyblob", "setlocaluserinfoblob", "getlocaluserinfoblob", "serverkeyblob"}, "Removes the length limits on user/server/local info strings, and allows embedded nulls and other otherwise-reserved characters. This can be used to network avatar images and the like, or other binary data."},
{"FTE_VRINPUTS", check_pext2_vrinputs, 0,{NULL}, "input_weapon, input_left_*, input_right_*, input_head_* work, both in csqc (as inputs with suitable plugin/hardware support) and ssqc (available in PlayerPreThink)."},
{"KRIMZON_SV_PARSECLIENTCOMMAND", NULL, 3,{"clientcommand", "tokenize", "argv"}, "SSQC's SV_ParseClientCommand function is able to handle client 'cmd' commands. The tokenizing parts also work in csqc."}, //very very similar to the mvdsv system.
{"NEH_CMD_PLAY2"},

View File

@ -6378,7 +6378,7 @@ char *PF_infokey_Internal (int entnum, const char *key)
else //FIXME: should we report the spoofable/proxy address if the real ip is not known?
NET_BaseAdrToString (ov, sizeof(ov), &controller->netchan.remote_address);
}
else if (!strcmp(key, "csqcactive"))
else if (!strcmp(key, "csqcactive") || !strcmp(key, "*csqcactive"))
sprintf(ov, "%d", controller->csqcactive);
else if (!strcmp(key, "ping"))
sprintf(ov, "%d", SV_CalcPing (&svs.clients[entnum-1], false));
@ -6491,6 +6491,45 @@ static void QCBUILTIN PF_infokey_f (pubprogfuncs_t *prinst, struct globalvars_s
G_FLOAT(OFS_RETURN) = atof(value);
}
static void QCBUILTIN PF_infokey_blob (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
edict_t *e = G_EDICT(prinst, OFS_PARM0);
const char *key = PR_GetStringOfs(prinst, OFS_PARM1);
int qcptr = (prinst->callargc>2)?G_INT(OFS_PARM2):0;
int qcsize = (prinst->callargc>3)?G_INT(OFS_PARM3):0;
unsigned e1 = NUM_FOR_EDICT(prinst, e);
size_t blobsize = 0;
const char *value;
//raw blob info, so no query hacks
if (e1 == 0)
{
if ((value = InfoBuf_BlobForKey(&svs.info, key, &blobsize, NULL)) == NULL)
value = InfoBuf_BlobForKey(&svs.localinfo, key, &blobsize, NULL);
}
else if (e1 <= (unsigned)sv.allocated_client_slots)
value = InfoBuf_BlobForKey (&svs.clients[e1-1].userinfo, key, &blobsize, NULL);
else
value = NULL;
if (qcptr)
{ //we were told somewhere to store it
void *ptr = PR_GetWriteQCPtr(prinst, qcptr, qcsize);
if (!ptr) //but the place was invalid?
PR_BIError(prinst, "PF_infokey_blob: invalid pointer/size\n");
else
{
blobsize = min(blobsize, qcsize);
memcpy(ptr, value, blobsize);
G_INT(OFS_RETURN) = blobsize;
}
}
else //no output, so just return the size
G_INT(OFS_RETURN) = blobsize;
}
static void QCBUILTIN PF_sv_serverkeystring (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *key = PR_GetStringOfs(prinst, OFS_PARM0);
@ -7238,7 +7277,7 @@ static void QCBUILTIN PF_checkextension (pubprogfuncs_t *prinst, struct globalva
break;
}
for (i = 0; i < ext->numbuiltins; i++)
for (i = 0; i < countof(ext->builtinnames) && ext->builtinnames[i]; i++)
{
if (*ext->builtinnames[i] == '.' || *ext->builtinnames[i] == '#')
{
@ -7292,7 +7331,7 @@ static void QCBUILTIN PF_builtinsupported (pubprogfuncs_t *prinst, struct global
const char *s = PR_GetStringOfs(prinst, OFS_PARM0);
int binum = (prinst->callargc < 2)?0:G_FLOAT(OFS_PARM1);
G_FLOAT(OFS_RETURN) = PR_EnableEBFSBuiltin(s, binum);
G_FLOAT(OFS_RETURN) = !!PR_EnableEBFSBuiltin(s, binum);
}
@ -7768,9 +7807,9 @@ const char *SV_CheckRejectConnection(netadr_t *adr, const char *uinfo, unsigned
NET_AdrToString(addrstr, sizeof(addrstr), adr);
*clfeatures = 0;
switch(protocol)
safeswitch(protocol)
{
default: bp = "unknown"; break;
safedefault: bp = "unknown"; break;
case SCP_QUAKEWORLD: bp = "qw"; break;
case SCP_QUAKE2: bp = "q2"; break;
case SCP_QUAKE3: bp = "q3"; break;
@ -7854,6 +7893,8 @@ const char *SV_CheckRejectConnection(netadr_t *adr, const char *uinfo, unsigned
Info_SetValueForKey(clfeatures, "PEXT2_NEWSIZEENCODING", "1", sizeof(clfeatures));
if (pext2 & PEXT2_INFOBLOBS)
Info_SetValueForKey(clfeatures, "PEXT2_INFOBLOBS", "1", sizeof(clfeatures));
if (pext2 & PEXT2_VRINPUTS)
Info_SetValueForKey(clfeatures, "PEXT2_VRINPUTS", "1", sizeof(clfeatures));
if (ezpext1 & EZPEXT1_FLOATENTCOORDS)
Info_SetValueForKey(clfeatures, "EZPEXT1_FLOATENTCOORDS", "1", sizeof(clfeatures));
@ -10958,6 +10999,7 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"infokey", PF_infokey_s, 0, 80, 0, 80, D("string(entity e, string key)", "If e is world, returns the field 'key' from either the serverinfo or the localinfo. If e is a player, returns the value of 'key' from the player's userinfo string. There are a few special exceptions, like 'ip' which is not technically part of the userinfo.")}, //80
{"infokeyf", PF_infokey_f, 0, 0, 0, 0, D("float(entity e, string key)", "Identical to regular infokey, except returns a float.")}, //80
{"infokey_blob", PF_infokey_blob, 0, 0, 0, 0, D("int(entity e, string key, optional void *outbuf, int outbufsize)", "Retrieves a user's blob size, and optionally writes it to the specified buffer.")},
{"stof", PF_stof, 0, 81, 0, 81, "float(string)"}, //81
{"multicast", PF_multicast, 0, 82, 0, 82, D("#define unicast(pl,reli) do{msg_entity = pl; multicast('0 0 0', reli?MULITCAST_ONE_R:MULTICAST_ONE);}while(0)\n"
"void(vector where, float set)", "Once the MSG_MULTICAST network message buffer has been filled with data, this builtin is used to dispatch it to the given target, filtering by pvs for reduced network bandwidth.")}, //82
@ -11844,6 +11886,8 @@ int PR_EnableEBFSBuiltin(const char *name, int binum)
{
if (!binum)
binum = BuiltinList[i].ebfsnum;
if (!binum)
return -1;
if (!pr_overridebuiltins.value)
{
if (pr_builtin[binum] != NULL && pr_builtin[binum] != PF_Fixme)
@ -12055,6 +12099,12 @@ void PR_SVExtensionList_f(void)
int ebi;
int bi;
qc_extension_t *extlist;
qboolean inactive, wrongmodule;
char *extname;
int num;
char biissues[8192];
extcheck_t extcheck = {Net_PextMask(PROTOCOL_VERSION_FTE1, false), Net_PextMask(PROTOCOL_VERSION_FTE2, false)};
#define SHOW_ACTIVEEXT 1
#define SHOW_ACTIVEBI 2
@ -12072,7 +12122,10 @@ void PR_SVExtensionList_f(void)
if (!BuiltinList[i].ebfsnum)
continue; //a reserved builtin.
if (BuiltinList[i].bifunc == PF_Fixme)
Con_Printf("^1%s:%i needs to be added\n", BuiltinList[i].name, BuiltinList[i].ebfsnum);
{ //can give a lot of false positives due to builtins that exist only in menuqc.
if (showflags & SHOW_NOTACTIVEBI)
Con_Printf("^1#%i:%s is not ssqc\n", BuiltinList[i].ebfsnum, BuiltinList[i].name);
}
else if (pr_builtin[BuiltinList[i].ebfsnum] == BuiltinList[i].bifunc)
{
if (showflags & SHOW_ACTIVEBI)
@ -12091,78 +12144,91 @@ void PR_SVExtensionList_f(void)
for (i = 0; i < QSG_Extensions_count; i++)
{
*biissues = 0;
inactive = false;
if (!extlist[i].name)
continue;
if (i < 32)
for (ebi = 0; ebi < countof(extlist[i].builtinnames) && extlist[i].builtinnames[ebi]; ebi++)
{
if (!(Net_PextMask(PROTOCOL_VERSION_FTE1, false) & (1<<i)))
{
if (showflags & SHOW_NOTSUPPORTEDEXT)
Con_Printf("^4protocol %s is not supported\n", extlist[i].name);
continue;
}
}
wrongmodule = false;
for (ebi = 0; ebi < extlist[i].numbuiltins; ebi++)
{
for (bi = 0; BuiltinList[bi].name; bi++)
{
if (BuiltinList[bi].bifunc == PF_Fixme)
continue; //this builtin is unusable in ssqc. some of them are listed because of menuqc
if (!strcmp(BuiltinList[bi].name, extlist[i].builtinnames[ebi]))
break;
{
if (BuiltinList[bi].bifunc == PF_Fixme)
wrongmodule=true;
else
break;
}
}
if (!BuiltinList[bi].name)
{
if (showflags & SHOW_NOTSUPPORTEDEXT)
Con_Printf("^4%s is not supported\n", extlist[i].name);
break;
if (wrongmodule)
continue;
Q_strncatz2(biissues, va(CON_ERROR"\t^4#:%s is not known\n", extlist[i].builtinnames[ebi]));
inactive = true;
continue;
}
if (pr_builtin[BuiltinList[bi].ebfsnum] != BuiltinList[bi].bifunc)
if (progstype == PROG_QW)
num = BuiltinList[bi].qwnum;
else if (progstype == PROG_H2)
num = BuiltinList[bi].h2num;
else
num = BuiltinList[bi].nqnum;
if (!num)
num = BuiltinList[bi].ebfsnum;
if (!num)
;//builtins with no number are handled at load time. there are no number conflicts so no way for the builtin to be inactive. if there is an error then its not because of the extension itself.
else if (pr_builtin[num] != BuiltinList[bi].bifunc)
{
if (pr_builtin[BuiltinList[bi].ebfsnum] == PF_Fixme)
{
if (showflags & SHOW_NOTACTIVEEXT)
Con_Printf("^4%s is not currently active (builtin: %s#%i)\n", extlist[i].name, BuiltinList[bi].name, BuiltinList[bi].ebfsnum);
}
if (pr_builtin[num] == PF_Fixme)
Q_strncatz2(biissues, va("\t^4#%i:%s is not implemented\n", num, BuiltinList[bi].name));
else
{
if (showflags & SHOW_NOTACTIVEEXT)
for (j = 0; BuiltinList[j].name; j++)
{
Con_Printf("^4%s was overridden (builtin: %s#%i)\n", extlist[i].name, BuiltinList[bi].name, BuiltinList[bi].ebfsnum);
for (j = 0; BuiltinList[j].name; j++)
if (BuiltinList[j].bifunc == pr_builtin[num])
{
if (BuiltinList[j].bifunc == pr_builtin[BuiltinList[bi].ebfsnum])
{
Con_Printf("^4%s is currently %s (#%i)\n", extlist[i].name, BuiltinList[j].name, BuiltinList[j].ebfsnum);
break;
}
Q_strncatz2(biissues, va("\t#%i:%s is currently %s\n", num,BuiltinList[bi].name, BuiltinList[j].name));
break;
}
}
if (!BuiltinList[j].name)
Q_strncatz2(biissues, va("\t^4#%i:%s is currently unknown\n", num, BuiltinList[bi].name));
}
break;
inactive = true;
}
}
if (ebi == extlist[i].numbuiltins)
if (extlist[i].description)
extname = va("^[%s\\tip\\%s^]", extlist[i].name, extlist[i].description);
else
extname = extlist[i].name;
if (extlist[i].extensioncheck && !extlist[i].extensioncheck(&extcheck))
{
if (showflags & SHOW_NOTSUPPORTEDEXT)
Con_Printf(CON_WARNING"protocol %s is blocked\n%s", extname, biissues);
}
else if (inactive)
{
if (showflags & SHOW_NOTSUPPORTEDEXT)
Con_Printf(CON_ERROR"%s is inactive\n%s", extname, biissues);
}
else
{
if (showflags & SHOW_ACTIVEEXT)
{
if (extlist[i].description)
{
if (!extlist[i].numbuiltins)
Con_Printf("^[%s\\tip\\%s^] is supported\n", extlist[i].name, extlist[i].description);
else
Con_Printf("^[%s\\tip\\%s^] is currently active\n", extlist[i].name, extlist[i].description);
}
else
{
if (!extlist[i].numbuiltins)
Con_Printf("%s is supported\n", extlist[i].name);
else
Con_Printf("%s is currently active\n", extlist[i].name);
}
if (!extlist[i].builtinnames[0])
Con_Printf("%s is supported\n%s", extname, biissues);
else
Con_Printf("%s is currently active\n%s", extname, biissues);
}
}
}
@ -13963,7 +14029,7 @@ void PR_DumpPlatform_f(void)
nd = 0;
for (j = 0; j < QSG_Extensions_count; j++)
{
for (k = 0; k < QSG_Extensions[j].numbuiltins; k++)
for (k = 0; k < countof(QSG_Extensions[j].builtinnames) && QSG_Extensions[j].builtinnames[k]; k++)
{
if (!strcmp(QSG_Extensions[j].builtinnames[k], BuiltinList[i].name))
{

View File

@ -2563,7 +2563,7 @@ void SV_User_f (void)
"OLD vweap", "q2bsp", "q3bsp", "colormod", "splitscreen", "hexen2", "spawnstatic2", "customtempeffects",
"packents", "UNKNOWN", "showpic", "setattachment","UNKNOWN", "chunkeddls", "csqc", "dpflags"};
static const char *pext2names[32] = { "prydoncursor", "voip", "setangledelta", "rplcdeltas", "maxplayers", "predinfo", "sizeenc", "infoblobs",
"stunaware", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN",
"stunaware", "vrinputs", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN",
"UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN",
"UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"};