shithub: qk1

Download patch

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;