seven:
a 'client command' is basically a reverse stuffcmd, but a bit more restricted (ie: you can't send 'quit'...). If you use any of the cheats like noclip, god, give, notarget, fly, kill, etc, the client sends a clc_clientcmd message with the command its trying to issue directly embedded as a string.
The "cmd" console command takes its arguments and uses that as the complete clientcmd string.
This means that "cmd god" is directly equivelent to "god" (just without the client being able to intercept it).
"cmd name foo" for instance, will change your name on the server without affecting your name on the next server/map/config.
When the server receives a clc_clientcmd, it walks through some list of 'known' strings and invokes the first match it finds, and issues some console print back to the issuer if its not recognised.
KRIMZON_SV_PARSECLIENTCOMMAND basically allows you to intercept that clc_clientcmd before the server tries to execute it. This allows you to a) add alternative commands. b) block cheats. c) hack with the 'say' command's string etc.
Anyway, its fairly simple:
Code: Select all
void(string str) SV_ParseClientCommand =
{
float numargs = tokenize(str);
if (argv(0) == "mynewcommand")
dosomething();
else
clientcommand(self, str);
};
The vital thing to remember is that the clientcommand call MUST BE CALLED FOR ALL UNRECOGNISED COMMANDS. Failing to call it in such cases _will_ result in problems, like downloads failing or even being unable to connect to the server.
The exact requirements of each command vary a little, most commands can be safely ignored, like god, say etc, its only the weird ones like prespaw/spawn/begin/signon.
Note that you can also call clientcommand from random bits of your own code. This allows you to get the server to run its regular handling, so gives you a practical way to eg change a player's name/colour without having to depend upon potentially cheatable/savable stuffcmds.
tokenize/argv are part of this extension rather than another one. argv requires tokenize to have previously been called. argv(0) will then return the intial token, argv(1) will return the first argument, etc. enclose the argument in quotes if you want argv to ever return a string with a space in it.
note that qc string equality is case sensitive, and the tokenize command was greatly butchered in dp to serve as a random parser and thus will not exactly match how the server tokenizes the string, but this is not relevent for your use-case.
So, for your use-case, you want to issue that 'cmd' stuffcmd. This causes the client to issue a clc_clientcmd, which the ssqc can parse with that function I pasted above. If you stuffcmd(self, "cmd clientcvar ct $scr_centertime\n"); then you have:
if (argv(0) == "clientcvar" && argv(1) == "ct") self.scr_centertime = atof(argv(2)); else <some code to call clientcommand>.
Beware that stuffcmd is not instant, nor are any clcs. So the time between the stuffcmd and the server getting the response can vary, even up to a second or beyond. Note that stuffcmd+cmd both send reliably, so you can override the client's current value as a stuffcmd on the very next line (or even as part of the very same stuffcmd!), you just won't be able to restore it until you know what to restore it to. Avoid sending multiple queries in order to avoid overwriting the user's choice with a value you sent.
This cannot be used for cheat prevention as a modified client can easily handle your stuffcmd specifically and send an allowed response while still using a cheaty value in the cvar (the same is true of querying it through csqc too).
CSQC does have the upper hand in that it has a 'shutdown' function within which cvars can be reliably restored.
and yes, you can use editable aliases to restore things, but that's bad as it requires lots of effort from the user instead of just using the client's menus to their heart's content (and they might not have your default cfg (using automatic mod downloads) and thus will not get anything restored at all).