ref: 28eafdc8ebdc8f0c05196cc45cc9bb38ae4550a6
parent: 042cdd0a45e01b52d76f5e6045b23815b948a4fc
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Sat Nov 25 21:10:30 EST 2023
DP_QC_TOKENIZE_CONSOLE + KRIMZON_SV_PARSECLIENTCOMMAND
--- a/pr_cmds.c
+++ b/pr_cmds.c
@@ -1553,9 +1553,12 @@
static const char *exts[] = {
"DP_EF_NODRAW",
+ "DP_QC_TOKENIZE_CONSOLE", /* FIXME(sigrid): not really; see somewhere below */
+ "KRIMZON_SV_PARSECLIENTCOMMAND",
};
-static void PF_checkextension (pr_t *pr)
+static void
+PF_checkextension(pr_t *pr)
{
const char *ext = G_STRING(pr, OFS_PARM0);
int i;
@@ -1570,7 +1573,8 @@
}
}
-static void PF_clientstat (pr_t *pr)
+static void
+PF_clientstat(pr_t *pr)
{
// FIXME
// Arcane Dimensions will fall off if this one isn't defined
@@ -1578,6 +1582,60 @@
USED(pr);
}
+static void
+PF_clientcommand(pr_t *pr)
+{
+ client_t *tmp;
+ edict_t *e;
+ char *cmd;
+ int n;
+
+ if(!pr->parse_cl_command.in_callback){
+ Con_DPrintf("clientcommand(...) outside of SV_ParseClientCommand\n");
+ return;
+ }
+ e = G_EDICT(pr, OFS_PARM0);
+ cmd = G_STRING(pr, OFS_PARM1);
+ if((n = NUM_FOR_EDICT(pr, e)-1) >= svs.maxclients || !svs.clients[n].active){
+ Con_DPrintf("clientcommand(...) on a non-client entity\n");
+ return;
+ }
+ if(!*cmd)
+ return;
+ tmp = host_client;
+ host_client = &svs.clients[n];
+ Cmd_ExecuteString(cmd, src_client);
+ host_client = tmp;
+}
+
+static void
+PF_tokenize(pr_t *pr)
+{
+ char *s;
+ int n;
+
+ s = G_STRING(pr, OFS_PARM0);
+ for(n = 0; s != nil && n < nelem(pr->parse_cl_command.argv); n++){
+ while(*s && isspace(*s))
+ s++;
+ if(*s == 0 || (s = COM_Parse(s)) == nil)
+ break;
+ pr->parse_cl_command.argv[n] = PR_CopyStrTmp(pr, com_token);
+ }
+ pr->parse_cl_command.argc = n;
+ G_FLOAT(pr, OFS_RETURN) = n;
+}
+
+static void
+PF_argv(pr_t *pr)
+{
+ int i;
+
+ if((i = G_FLOAT(pr, OFS_PARM0)) < 0)
+ i += pr->parse_cl_command.argc;
+ G_INT(pr, OFS_RETURN) = i >= pr->parse_cl_command.argc ? 0 : pr->parse_cl_command.argv[i];
+}
+
static const builtin_t pr_sv_builtins[] =
{
PF_Fixme,
@@ -1670,11 +1728,17 @@
[99] = PF_checkextension,
[232] = PF_clientstat,
+[440] = PF_clientcommand,
+[441] = PF_tokenize,
+[442] = PF_argv,
+[514] = PF_tokenize, /* FIXME(sigrid): strictly speaking, this is supposed to be "tokenize_console" */
};
void
-PR_SetBuiltinsSV(pr_t *pr)
+PR_InitSV(pr_t *pr)
{
pr->builtins = pr_sv_builtins;
pr->numbuiltins = nelem(pr_sv_builtins);
+
+ pr->parse_cl_command.func = ED_FindFunction(pr, "SV_ParseClientCommand");
}
--- a/pr_edict.c
+++ b/pr_edict.c
@@ -14,7 +14,7 @@
ddef_t *ED_FieldAtOfs (pr_t *pr, int ofs);
bool ED_ParseEpair (pr_t *pr, void *base, ddef_t *key, char *s);
-void PR_SetBuiltinsSV(pr_t *pr);
+void PR_InitSV(pr_t *pr);
cvar_t nomonsters = {"nomonsters", "0"};
@@ -1108,7 +1108,7 @@
pr->max_edicts = MAX_EDICTS;
pr->edicts = Hunk_Alloc(pr->max_edicts*pr->edict_size);
- PR_SetBuiltinsSV(pr);
+ PR_InitSV(pr);
return pr;
}
--- a/progs.h
+++ b/progs.h
@@ -68,6 +68,13 @@
edict_t *edicts;
int num_edicts;
int max_edicts;
+
+ // krimzon parse client command
+ struct {
+ dfunction_t *func;
+ int argc, argv[64];
+ bool in_callback;
+ }parse_cl_command;
};
typedef union eval_s
@@ -103,6 +110,8 @@
void ED_Print (pr_t *pr, edict_t *ed);
char *ED_ParseEdict (pr_t *pr, char *data, edict_t *ent);
+
+dfunction_t *ED_FindFunction (pr_t *pr, char *name);
void ED_ParseGlobals (pr_t *pr, char *data);
void ED_LoadFromFile (pr_t *pr, char *data);
--- a/quakedef.h
+++ b/quakedef.h
@@ -3,6 +3,7 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
+#include <ctype.h>
#ifdef __plan9__
typedef enum {false, true} bool;
--- a/sv_user.c
+++ b/sv_user.c
@@ -425,9 +425,35 @@
*/
bool SV_ReadClientMessage (void)
{
- int ret;
- int cmd;
- char *s;
+ int ret, i, cmd;
+ client_t *tmp;
+ char *s;
+ static const char *ret1[] = {
+ "\03ban",
+ "\03fly",
+ "\03god",
+ "\03say",
+ "\04give",
+ "\04kick",
+ "\04kill",
+ "\04name",
+ "\04ping",
+ "\04tell",
+ "\05begin",
+ "\05color",
+ "\05pause",
+ "\05spawn",
+ "\06noclip",
+ "\06status",
+ "\010notarget",
+ "\010prespawn",
+ "\010say_team",
+ };
+ static const char *nooverride[] = {
+ "\05begin",
+ "\05spawn",
+ "\010prespawn",
+ };
do
{
@@ -469,50 +495,34 @@
break;
case clc_stringcmd:
- s = MSG_ReadString ();
+ s = MSG_ReadString();
+ if(sv.pr->parse_cl_command.func != nil){
+ for(i = 0; i < nelem(nooverride); i++){
+ if(cistrncmp(nooverride[i]+1, s, nooverride[i][0]) == 0)
+ break;
+ }
+ if(i >= nelem(nooverride)){
+ tmp = host_client;
+ G_INT(sv.pr, OFS_PARM0) = PR_SetStr(sv.pr, s);
+ sv.pr->global_struct->self = EDICT_TO_PROG(sv.pr, tmp->edict);
+ sv.pr->global_struct->time = sv.time;
+ sv.pr->parse_cl_command.in_callback = true;
+ PR_ExecuteProgram(sv.pr, sv.pr->parse_cl_command.func - sv.pr->functions);
+ sv.pr->parse_cl_command.in_callback = false;
+ break;
+ }
+ }
ret = 0;
- if (cistrncmp(s, "status", 6) == 0)
- ret = 1;
- else if (cistrncmp(s, "god", 3) == 0)
- ret = 1;
- else if (cistrncmp(s, "notarget", 8) == 0)
- ret = 1;
- else if (cistrncmp(s, "fly", 3) == 0)
- ret = 1;
- else if (cistrncmp(s, "name", 4) == 0)
- ret = 1;
- else if (cistrncmp(s, "noclip", 6) == 0)
- ret = 1;
- else if (cistrncmp(s, "say", 3) == 0)
- ret = 1;
- else if (cistrncmp(s, "say_team", 8) == 0)
- ret = 1;
- else if (cistrncmp(s, "tell", 4) == 0)
- ret = 1;
- else if (cistrncmp(s, "color", 5) == 0)
- ret = 1;
- else if (cistrncmp(s, "kill", 4) == 0)
- ret = 1;
- else if (cistrncmp(s, "pause", 5) == 0)
- ret = 1;
- else if (cistrncmp(s, "spawn", 5) == 0)
- ret = 1;
- else if (cistrncmp(s, "begin", 5) == 0)
- ret = 1;
- else if (cistrncmp(s, "prespawn", 8) == 0)
- ret = 1;
- else if (cistrncmp(s, "kick", 4) == 0)
- ret = 1;
- else if (cistrncmp(s, "ping", 4) == 0)
- ret = 1;
- else if (cistrncmp(s, "give", 4) == 0)
- ret = 1;
- else if (cistrncmp(s, "ban", 3) == 0)
- ret = 1;
- if (ret == 2)
- Cbuf_InsertText (s);
- else if (ret == 1)
- Cmd_ExecuteString (s, src_client);
+ for(i = 0; i < nelem(ret1); i++){
+ if(cistrncmp(ret1[i]+1, s, ret1[i][0]) == 0){
+ ret = 1;
+ break;
+ }
+ }
+ if(ret == 2)
+ Cbuf_InsertText(s);
+ else if(ret == 1)
+ Cmd_ExecuteString(s, src_client);
else
Con_DPrintf("%s tried to %s\n", host_client->name, s);
break;