Allow csqc to read csqc entity updates, prints, and centerprints.

This commit is contained in:
Shpoike 2020-09-04 11:53:42 +01:00
parent 3c848f993e
commit ec82ca0448
3 changed files with 171 additions and 40 deletions

View file

@ -97,6 +97,7 @@ void CL_FreeState(void)
CL_ClearTrailStates();
PR_ClearProgs(&cl.qcvm);
free(cl.static_entities);
free(cl.ssqc_to_csqc);
memset (&cl, 0, sizeof(cl));
}

View file

@ -724,16 +724,75 @@ static void CLFTE_ParseEntitiesUpdate(void)
}
}
static void CSQC_ClearCsEdictForSSQC(size_t entnum)
{
edict_t *ed;
if (entnum >= cl.ssqc_to_csqc_max)
return; //invalid...
ed = cl.ssqc_to_csqc[entnum];
if (ed)
{
cl.ssqc_to_csqc[entnum] = NULL;
//let the csqc know.
pr_global_struct->self = EDICT_TO_PROG(ed);
if (qcvm->extfuncs.CSQC_Ent_Remove)
PR_ExecuteProgram(qcvm->extfuncs.CSQC_Ent_Remove);
else
ED_Free(ed);
}
}
static void CSQC_UpdateCsEdictForSSQC(size_t entnum)
{
edict_t *ed;
eval_t *ev;
qboolean isnew;
if (entnum >= cl.ssqc_to_csqc_max)
{
size_t nc = q_min(MAX_EDICTS, entnum+64);
void *nptr;
if (entnum >= nc)
Host_EndGame("entnum > MAX_EDICTS");
nptr = realloc(cl.ssqc_to_csqc, nc * sizeof(*cl.ssqc_to_csqc));
if (!nptr)
Sys_Error("realloc failure");
cl.ssqc_to_csqc = nptr;
memset(cl.ssqc_to_csqc+cl.ssqc_to_csqc_max, 0, (nc-cl.ssqc_to_csqc_max)*sizeof(*cl.ssqc_to_csqc));
cl.ssqc_to_csqc_max = nc;
}
ed = cl.ssqc_to_csqc[entnum];
if (!ed)
{
//allocate our new ent.
ed = cl.ssqc_to_csqc[entnum] = ED_Alloc();
//fill its entnum field too.
ev = GetEdictFieldValue(ed, qcvm->extfields.entnum);
if (ev)
ev->_float = entnum;
isnew = true;
}
else
isnew = false;
G_FLOAT(OFS_PARM0) = isnew;
pr_global_struct->self = EDICT_TO_PROG(ed);
PR_ExecuteProgram(cl.qcvm.extfuncs.CSQC_Ent_Update);
}
//csqc entities protocol, payload is identical in both fte+dp. just the svcs differ.
void CLFTE_ParseCSQCEntitiesUpdate(void)
{
/*if (cl.qcvm.extfuncs.CSQC_Ent_Update)
if (qcvm->extfuncs.CSQC_Ent_Update)
{
edict_t *ed;
unsigned int entnum;
qboolean removeflag;
for(;;)
{
//replacement deltas now also includes 22bit entity num indicies.
if (cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)
if (cl.protocol_pext2 & PEXT2_REPLACEMENTDELTAS)
{
entnum = (unsigned short)MSG_ReadShort();
removeflag = !!(entnum & 0x8000);
@ -753,36 +812,31 @@ void CLFTE_ParseCSQCEntitiesUpdate(void)
if (removeflag)
{
ed = cl.ssqc_to_csqc[entnum];
if (ed)
{
pr_global_struct->self = EDICT_TO_PROG(ed);
if (cl.qcvm.extfuncs.CSQC_Ent_Remove)
PR_ExecuteProgram(cl.qcvm.extfuncs.CSQC_Ent_Remove);
else
ED_Free(ed);
}
if (cl_shownet.value >= 3)
Con_SafePrintf("%3i: Remove %i\n", msg_readcount, entnum);
CSQC_ClearCsEdictForSSQC(entnum);
}
else
{
// if (cl.csqcdebug)
// packetsize = MSG_ReadShort();
/* if (sized)
{
packetsize = MSG_ReadShort();
if (cl_shownet.value >= 3)
Con_SafePrintf("%3i - %3i: Update %i\n", msg_readcount, msg_readcount+packetsize-1, entnum);
}
else
*/ {
if (cl_shownet.value >= 3)
Con_SafePrintf("%3i: Update %i\n", msg_readcount, entnum);
}
ed = cl.ssqc_to_csqc[entnum];
if (!ed)
{
cl.ssqc_to_csqc[entnum] = ed = ED_Alloc();
ed->v.entnum = entnum;
G_FLOAT(OFS_PARM0) = true;
CSQC_UpdateCsEdictForSSQC(entnum);
// if (sized)
// ;//TODO make sure we read the right size...
}
}
}
else
G_FLOAT(OFS_PARM0) = false;
pr_global_struct->self = EDICT_TO_PROG(ed);
PR_ExecuteProgram(cl.qcvm.extfuncs.CSQC_Ent_Update);
}
}
}
else*/
Host_Error ("Received svc_csqcentities but unable to parse");
}
@ -2128,30 +2182,46 @@ static void CL_ParseStuffText(const char *msg)
{
const char *str;
q_strlcat(cl.stuffcmdbuf, msg, sizeof(cl.stuffcmdbuf));
while ((str = strchr(cl.stuffcmdbuf, '\n')))
for (; (str = strchr(cl.stuffcmdbuf, '\n')); memmove(cl.stuffcmdbuf, str, Q_strlen(str)+1))
{
qboolean handled;
qboolean handled = false;
str++;//skip past the \n
if (*cl.stuffcmdbuf == 0x01 && cl.protocol == PROTOCOL_NETQUAKE) //proquake message, just strip this and try again (doesn't necessarily have a trailing \n straight away)
{
for (str = cl.stuffcmdbuf+1; *str >= 0x01 && *str <= 0x1f; str++)
;//FIXME: parse properly
memmove(cl.stuffcmdbuf, str, Q_strlen(str)+1);
continue;
}
str++;//skip past the \n
//handle //prefixed commands
//handle special commands
if (cl.stuffcmdbuf[0] == '/' && cl.stuffcmdbuf[1] == '/')
{
handled = Cmd_ExecuteString(cl.stuffcmdbuf+2, src_server);
if (!handled)
Con_DPrintf("Server sent unknown command %s\n", Cmd_Argv(1));
Con_DPrintf("Server sent unknown command %s\n", Cmd_Argv(0));
}
else
handled = Cmd_ExecuteString(cl.stuffcmdbuf, src_server);
//give the csqc a chance to handle them
if (!handled && cl.qcvm.extfuncs.CSQC_Parse_StuffCmd && str-cl.stuffcmdbuf<STRINGTEMP_LENGTH)
{
char *tmp;
PR_SwitchQCVM(&cl.qcvm);
tmp = PR_GetTempString();
memcpy(tmp, cl.stuffcmdbuf, str-cl.stuffcmdbuf);
tmp[str-cl.stuffcmdbuf] = 0; //null terminate it.
G_INT(OFS_PARM0) = PR_SetEngineString(tmp);
PR_ExecuteProgram(cl.qcvm.extfuncs.CSQC_Parse_StuffCmd);
handled = true; //unfortunately the mod is expected to localcmd unknown things.
PR_SwitchQCVM(NULL);
}
//let the server exec general user commands (massive security hole)
if (!handled)
Cbuf_AddTextLen(cl.stuffcmdbuf, str-cl.stuffcmdbuf);
memmove(cl.stuffcmdbuf, str, Q_strlen(str)+1);
}
}
@ -2229,6 +2299,66 @@ static qboolean CL_ParseSpecialPrints(const char *printtext)
return false;
}
static void CL_ParsePrint(const char *msg)
{
const char *str;
char *tmp;
if (CL_ParseSpecialPrints(msg))
return;
if (cl.qcvm.extfuncs.CSQC_Parse_Print)
{
q_strlcat(cl.printbuffer, msg, sizeof(cl.printbuffer));
for (; *cl.printbuffer; memmove(cl.printbuffer, str, Q_strlen(str)+1))
{
for (str = cl.printbuffer; str < cl.printbuffer+STRINGTEMP_LENGTH-1; str++)
{
if (*str == '\r' || *str == '\n')
{
str++;
break;
}
if (!*str)
return;
}
PR_SwitchQCVM(&cl.qcvm);
tmp = PR_GetTempString();
memcpy(tmp, cl.printbuffer, str-cl.printbuffer);
tmp[str-cl.printbuffer] = 0;
G_INT(OFS_PARM0) = PR_SetEngineString(tmp);
G_FLOAT(OFS_PARM1) = ((*tmp=='\1')?3:2); //guess at the print level. we don't really have them in NQ.
PR_ExecuteProgram(qcvm->extfuncs.CSQC_Parse_Print);
PR_SwitchQCVM(NULL);
}
}
else
{
if (*cl.printbuffer)
{
Con_Printf ("%s", cl.printbuffer);
*cl.printbuffer = 0;
}
Con_Printf ("%s", msg);
}
}
static void CL_ParseCenterPrint(const char *msg)
{
char *tmp;
if (cl.qcvm.extfuncs.CSQC_Parse_CenterPrint)
{ //let the csqc do it.
PR_SwitchQCVM(&cl.qcvm);
tmp = PR_GetTempString();
q_strlcpy(tmp, msg, STRINGTEMP_LENGTH);
G_INT(OFS_PARM0) = PR_SetEngineString(tmp);
PR_ExecuteProgram(qcvm->extfuncs.CSQC_Parse_CenterPrint);
//qc calls cprint if it wants the legacy behaviour...
PR_SwitchQCVM(NULL);
}
else
SCR_CenterPrint(msg);
}
/*
=====================
CL_ParseServerMessage
@ -2328,15 +2458,12 @@ void CL_ParseServerMessage (void)
Host_EndGame ("Server disconnected\n");
case svc_print:
str = MSG_ReadString();
if (!CL_ParseSpecialPrints(str))
Con_Printf ("%s", str);
CL_ParsePrint(MSG_ReadString());
break;
case svc_centerprint:
//johnfitz -- log centerprints to console
str = MSG_ReadString ();
SCR_CenterPrint (str);
CL_ParseCenterPrint (MSG_ReadString());
//johnfitz
break;
@ -2493,8 +2620,7 @@ void CL_ParseServerMessage (void)
cl.completed_time = cl.time;
vid.recalc_refdef = true; // go to full screen
//johnfitz -- log centerprints to console
str = MSG_ReadString ();
SCR_CenterPrint (str);
CL_ParseCenterPrint (MSG_ReadString());
//johnfitz
break;
@ -2503,8 +2629,7 @@ void CL_ParseServerMessage (void)
cl.completed_time = cl.time;
vid.recalc_refdef = true; // go to full screen
//johnfitz -- log centerprints to console
str = MSG_ReadString ();
SCR_CenterPrint (str);
CL_ParseCenterPrint (MSG_ReadString ());
//johnfitz
break;
@ -2574,7 +2699,9 @@ void CL_ParseServerMessage (void)
case svcdp_csqcentities: //FTE uses DP's svc number for nq, because compat (despite fte's svc being first). same payload either way.
if (!(cl.protocol_pext2 & PEXT2_REPLACEMENTDELTAS) && cl.protocol != PROTOCOL_VERSION_DP7)
Host_Error ("Received svcdp_csqcentities but extension not active");
PR_SwitchQCVM(&cl.qcvm);
CLFTE_ParseCSQCEntitiesUpdate();
PR_SwitchQCVM(NULL);
break;
case svcdp_spawnbaseline2: //limited to a handful of extra properties.
if (cl.protocol != PROTOCOL_VERSION_DP7)

View file

@ -275,6 +275,7 @@ typedef struct
qboolean requestresend;
char stuffcmdbuf[1024]; //comment-extensions are a thing with certain servers, make sure we can handle them properly without further hacks/breakages. there's also some server->client only console commands that we might as well try to handle a bit better, like reconnect
char printbuffer[1024];
enum
{
PRINT_NONE,
@ -300,6 +301,8 @@ typedef struct
qcvm_t qcvm; //for csqc.
float csqc_sensitivity; //scaler for sensitivity
size_t ssqc_to_csqc_max;
edict_t **ssqc_to_csqc; //to find the csqc ent for an ssqc index.
char serverinfo[8192]; // \key\value infostring data.
} client_state_t;