1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19*/
20// sv_user.c -- server code for moving users
21
22#include "qwsvdef.h"
23
24edict_t	*sv_player;
25
26usercmd_t	cmd;
27
28cvar_t	cl_rollspeed = {"cl_rollspeed", "200"};
29cvar_t	cl_rollangle = {"cl_rollangle", "2.0"};
30cvar_t	sv_spectalk = {"sv_spectalk", "1"};
31
32cvar_t	sv_mapcheck	= {"sv_mapcheck", "1"};
33
34extern	vec3_t	player_mins;
35
36extern int fp_messages, fp_persecond, fp_secondsdead;
37extern char fp_msg[];
38extern cvar_t pausable;
39
40/*
41============================================================
42
43USER STRINGCMD EXECUTION
44
45host_client and sv_player will be valid.
46============================================================
47*/
48
49/*
50================
51SV_New_f
52
53Sends the first message from the server to a connected client.
54This will be sent on the initial connection and upon each server load.
55================
56*/
57void SV_New_f (void)
58{
59	char		*gamedir;
60	int			playernum;
61
62	if (host_client->state == cs_spawned)
63		return;
64
65	host_client->state = cs_connected;
66	host_client->connection_started = realtime;
67
68	// send the info about the new client to all connected clients
69//	SV_FullClientUpdate (host_client, &sv.reliable_datagram);
70//	host_client->sendinfo = true;
71
72	gamedir = Info_ValueForKey (svs.info, "*gamedir");
73	if (!gamedir[0])
74		gamedir = "qw";
75
76//NOTE:  This doesn't go through ClientReliableWrite since it's before the user
77//spawns.  These functions are written to not overflow
78	if (host_client->num_backbuf) {
79		Con_Printf("WARNING %s: [SV_New] Back buffered (%d0, clearing", host_client->name, host_client->netchan.message.cursize);
80		host_client->num_backbuf = 0;
81		SZ_Clear(&host_client->netchan.message);
82	}
83
84	// send the serverdata
85	MSG_WriteByte (&host_client->netchan.message, svc_serverdata);
86	MSG_WriteLong (&host_client->netchan.message, PROTOCOL_VERSION);
87	MSG_WriteLong (&host_client->netchan.message, svs.spawncount);
88	MSG_WriteString (&host_client->netchan.message, gamedir);
89
90	playernum = NUM_FOR_EDICT(host_client->edict)-1;
91	if (host_client->spectator)
92		playernum |= 128;
93	MSG_WriteByte (&host_client->netchan.message, playernum);
94
95	// send full levelname
96	MSG_WriteString (&host_client->netchan.message, PR_GetString(sv.edicts->v.message));
97
98	// send the movevars
99	MSG_WriteFloat(&host_client->netchan.message, movevars.gravity);
100	MSG_WriteFloat(&host_client->netchan.message, movevars.stopspeed);
101	MSG_WriteFloat(&host_client->netchan.message, movevars.maxspeed);
102	MSG_WriteFloat(&host_client->netchan.message, movevars.spectatormaxspeed);
103	MSG_WriteFloat(&host_client->netchan.message, movevars.accelerate);
104	MSG_WriteFloat(&host_client->netchan.message, movevars.airaccelerate);
105	MSG_WriteFloat(&host_client->netchan.message, movevars.wateraccelerate);
106	MSG_WriteFloat(&host_client->netchan.message, movevars.friction);
107	MSG_WriteFloat(&host_client->netchan.message, movevars.waterfriction);
108	MSG_WriteFloat(&host_client->netchan.message, movevars.entgravity);
109
110	// send music
111	MSG_WriteByte (&host_client->netchan.message, svc_cdtrack);
112	MSG_WriteByte (&host_client->netchan.message, sv.edicts->v.sounds);
113
114	// send server info string
115	MSG_WriteByte (&host_client->netchan.message, svc_stufftext);
116	MSG_WriteString (&host_client->netchan.message, va("fullserverinfo \"%s\"\n", svs.info) );
117}
118
119/*
120==================
121SV_Soundlist_f
122==================
123*/
124void SV_Soundlist_f (void)
125{
126	char		**s;
127	int			n;
128
129	if (host_client->state != cs_connected)
130	{
131		Con_Printf ("soundlist not valid -- allready spawned\n");
132		return;
133	}
134
135	// handle the case of a level changing while a client was connecting
136	if ( atoi(Cmd_Argv(1)) != svs.spawncount )
137	{
138		Con_Printf ("SV_Soundlist_f from different level\n");
139		SV_New_f ();
140		return;
141	}
142
143	n = atoi(Cmd_Argv(2));
144
145//NOTE:  This doesn't go through ClientReliableWrite since it's before the user
146//spawns.  These functions are written to not overflow
147	if (host_client->num_backbuf) {
148		Con_Printf("WARNING %s: [SV_Soundlist] Back buffered (%d0, clearing", host_client->name, host_client->netchan.message.cursize);
149		host_client->num_backbuf = 0;
150		SZ_Clear(&host_client->netchan.message);
151	}
152
153	MSG_WriteByte (&host_client->netchan.message, svc_soundlist);
154	MSG_WriteByte (&host_client->netchan.message, n);
155	for (s = sv.sound_precache+1 + n ;
156		*s && host_client->netchan.message.cursize < (MAX_MSGLEN/2);
157		s++, n++)
158		MSG_WriteString (&host_client->netchan.message, *s);
159
160	MSG_WriteByte (&host_client->netchan.message, 0);
161
162	// next msg
163	if (*s)
164		MSG_WriteByte (&host_client->netchan.message, n);
165	else
166		MSG_WriteByte (&host_client->netchan.message, 0);
167}
168
169/*
170==================
171SV_Modellist_f
172==================
173*/
174void SV_Modellist_f (void)
175{
176	char		**s;
177	int			n;
178
179	if (host_client->state != cs_connected)
180	{
181		Con_Printf ("modellist not valid -- allready spawned\n");
182		return;
183	}
184
185	// handle the case of a level changing while a client was connecting
186	if ( atoi(Cmd_Argv(1)) != svs.spawncount )
187	{
188		Con_Printf ("SV_Modellist_f from different level\n");
189		SV_New_f ();
190		return;
191	}
192
193	n = atoi(Cmd_Argv(2));
194
195//NOTE:  This doesn't go through ClientReliableWrite since it's before the user
196//spawns.  These functions are written to not overflow
197	if (host_client->num_backbuf) {
198		Con_Printf("WARNING %s: [SV_Modellist] Back buffered (%d0, clearing", host_client->name, host_client->netchan.message.cursize);
199		host_client->num_backbuf = 0;
200		SZ_Clear(&host_client->netchan.message);
201	}
202
203	MSG_WriteByte (&host_client->netchan.message, svc_modellist);
204	MSG_WriteByte (&host_client->netchan.message, n);
205	for (s = sv.model_precache+1+n ;
206		*s && host_client->netchan.message.cursize < (MAX_MSGLEN/2);
207		s++, n++)
208		MSG_WriteString (&host_client->netchan.message, *s);
209	MSG_WriteByte (&host_client->netchan.message, 0);
210
211	// next msg
212	if (*s)
213		MSG_WriteByte (&host_client->netchan.message, n);
214	else
215		MSG_WriteByte (&host_client->netchan.message, 0);
216}
217
218/*
219==================
220SV_PreSpawn_f
221==================
222*/
223void SV_PreSpawn_f (void)
224{
225	unsigned	buf;
226	unsigned	check;
227
228	if (host_client->state != cs_connected)
229	{
230		Con_Printf ("prespawn not valid -- allready spawned\n");
231		return;
232	}
233
234	// handle the case of a level changing while a client was connecting
235	if ( atoi(Cmd_Argv(1)) != svs.spawncount )
236	{
237		Con_Printf ("SV_PreSpawn_f from different level\n");
238		SV_New_f ();
239		return;
240	}
241
242	buf = atoi(Cmd_Argv(2));
243	if (buf >= sv.num_signon_buffers)
244		buf = 0;
245
246	if (!buf) {
247		// should be three numbers following containing checksums
248		check = atoi(Cmd_Argv(3));
249
250//		Con_DPrintf("Client check = %d\n", check);
251
252		if (sv_mapcheck.value && check != sv.worldmodel->checksum &&
253			check != sv.worldmodel->checksum2) {
254			SV_ClientPrintf (host_client, PRINT_HIGH,
255				"Map model file does not match (%s), %i != %i/%i.\n"
256				"You may need a new version of the map, or the proper install files.\n",
257				sv.modelname, check, sv.worldmodel->checksum, sv.worldmodel->checksum2);
258			SV_DropClient (host_client);
259			return;
260		}
261		host_client->checksum = check;
262	}
263
264//NOTE:  This doesn't go through ClientReliableWrite since it's before the user
265//spawns.  These functions are written to not overflow
266	if (host_client->num_backbuf) {
267		Con_Printf("WARNING %s: [SV_PreSpawn] Back buffered (%d0, clearing", host_client->name, host_client->netchan.message.cursize);
268		host_client->num_backbuf = 0;
269		SZ_Clear(&host_client->netchan.message);
270	}
271
272	SZ_Write (&host_client->netchan.message,
273		sv.signon_buffers[buf],
274		sv.signon_buffer_size[buf]);
275
276	buf++;
277	if (buf == sv.num_signon_buffers)
278	{	// all done prespawning
279		MSG_WriteByte (&host_client->netchan.message, svc_stufftext);
280		MSG_WriteString (&host_client->netchan.message, va("cmd spawn %i 0\n",svs.spawncount) );
281	}
282	else
283	{	// need to prespawn more
284		MSG_WriteByte (&host_client->netchan.message, svc_stufftext);
285		MSG_WriteString (&host_client->netchan.message,
286			va("cmd prespawn %i %i\n", svs.spawncount, buf) );
287	}
288}
289
290/*
291==================
292SV_Spawn_f
293==================
294*/
295void SV_Spawn_f (void)
296{
297	int		i;
298	client_t	*client;
299	edict_t	*ent;
300	eval_t *val;
301	int n;
302
303	if (host_client->state != cs_connected)
304	{
305		Con_Printf ("Spawn not valid -- allready spawned\n");
306		return;
307	}
308
309// handle the case of a level changing while a client was connecting
310	if ( atoi(Cmd_Argv(1)) != svs.spawncount )
311	{
312		Con_Printf ("SV_Spawn_f from different level\n");
313		SV_New_f ();
314		return;
315	}
316
317	n = atoi(Cmd_Argv(2));
318
319	// make sure n is valid
320	if ( n < 0 || n > MAX_CLIENTS )
321	{
322		Con_Printf ("SV_Spawn_f invalid client start\n");
323		SV_New_f ();
324		return;
325	}
326
327
328
329// send all current names, colors, and frag counts
330	// FIXME: is this a good thing?
331	SZ_Clear (&host_client->netchan.message);
332
333// send current status of all other players
334
335	// normally this could overflow, but no need to check due to backbuf
336	for (i=n, client = svs.clients + n ; i<MAX_CLIENTS ; i++, client++)
337		SV_FullClientUpdateToClient (client, host_client);
338
339// send all current light styles
340	for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
341	{
342		ClientReliableWrite_Begin (host_client, svc_lightstyle,
343			3 + (sv.lightstyles[i] ? strlen(sv.lightstyles[i]) : 1));
344		ClientReliableWrite_Byte (host_client, (char)i);
345		ClientReliableWrite_String (host_client, sv.lightstyles[i]);
346	}
347
348	// set up the edict
349	ent = host_client->edict;
350
351	memset (&ent->v, 0, progs->entityfields * 4);
352	ent->v.colormap = NUM_FOR_EDICT(ent);
353	ent->v.team = 0;	// FIXME
354	ent->v.netname = PR_SetString(host_client->name);
355
356	host_client->entgravity = 1.0;
357	val = GetEdictFieldValue(ent, "gravity");
358	if (val)
359		val->_float = 1.0;
360	host_client->maxspeed = sv_maxspeed.value;
361	val = GetEdictFieldValue(ent, "maxspeed");
362	if (val)
363		val->_float = sv_maxspeed.value;
364
365//
366// force stats to be updated
367//
368	memset (host_client->stats, 0, sizeof(host_client->stats));
369
370	ClientReliableWrite_Begin (host_client, svc_updatestatlong, 6);
371	ClientReliableWrite_Byte (host_client, STAT_TOTALSECRETS);
372	ClientReliableWrite_Long (host_client, pr_global_struct->total_secrets);
373
374	ClientReliableWrite_Begin (host_client, svc_updatestatlong, 6);
375	ClientReliableWrite_Byte (host_client, STAT_TOTALMONSTERS);
376	ClientReliableWrite_Long (host_client, pr_global_struct->total_monsters);
377
378	ClientReliableWrite_Begin (host_client, svc_updatestatlong, 6);
379	ClientReliableWrite_Byte (host_client, STAT_SECRETS);
380	ClientReliableWrite_Long (host_client, pr_global_struct->found_secrets);
381
382	ClientReliableWrite_Begin (host_client, svc_updatestatlong, 6);
383	ClientReliableWrite_Byte (host_client, STAT_MONSTERS);
384	ClientReliableWrite_Long (host_client, pr_global_struct->killed_monsters);
385
386	// get the client to check and download skins
387	// when that is completed, a begin command will be issued
388	ClientReliableWrite_Begin (host_client, svc_stufftext, 8);
389	ClientReliableWrite_String (host_client, "skins\n" );
390
391}
392
393/*
394==================
395SV_SpawnSpectator
396==================
397*/
398void SV_SpawnSpectator (void)
399{
400	int		i;
401	edict_t	*e;
402
403	VectorCopy (vec3_origin, sv_player->v.origin);
404	VectorCopy (vec3_origin, sv_player->v.view_ofs);
405	sv_player->v.view_ofs[2] = 22;
406
407	// search for an info_playerstart to spawn the spectator at
408	for (i=MAX_CLIENTS-1 ; i<sv.num_edicts ; i++)
409	{
410		e = EDICT_NUM(i);
411		if (!strcmp(PR_GetString(e->v.classname), "info_player_start"))
412		{
413			VectorCopy (e->v.origin, sv_player->v.origin);
414			return;
415		}
416	}
417
418}
419
420/*
421==================
422SV_Begin_f
423==================
424*/
425void SV_Begin_f (void)
426{
427	unsigned pmodel = 0, emodel = 0;
428	int		i;
429
430	if (host_client->state == cs_spawned)
431		return; // don't begin again
432
433	host_client->state = cs_spawned;
434
435	// handle the case of a level changing while a client was connecting
436	if ( atoi(Cmd_Argv(1)) != svs.spawncount )
437	{
438		Con_Printf ("SV_Begin_f from different level\n");
439		SV_New_f ();
440		return;
441	}
442
443	if (host_client->spectator)
444	{
445		SV_SpawnSpectator ();
446
447		if (SpectatorConnect) {
448			// copy spawn parms out of the client_t
449			for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
450				(&pr_global_struct->parm1)[i] = host_client->spawn_parms[i];
451
452			// call the spawn function
453			pr_global_struct->time = sv.time;
454			pr_global_struct->self = EDICT_TO_PROG(sv_player);
455			PR_ExecuteProgram (SpectatorConnect);
456		}
457	}
458	else
459	{
460		// copy spawn parms out of the client_t
461		for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
462			(&pr_global_struct->parm1)[i] = host_client->spawn_parms[i];
463
464		// call the spawn function
465		pr_global_struct->time = sv.time;
466		pr_global_struct->self = EDICT_TO_PROG(sv_player);
467		PR_ExecuteProgram (pr_global_struct->ClientConnect);
468
469		// actually spawn the player
470		pr_global_struct->time = sv.time;
471		pr_global_struct->self = EDICT_TO_PROG(sv_player);
472		PR_ExecuteProgram (pr_global_struct->PutClientInServer);
473	}
474
475	// clear the net statistics, because connecting gives a bogus picture
476	host_client->netchan.frame_latency = 0;
477	host_client->netchan.frame_rate = 0;
478	host_client->netchan.drop_count = 0;
479	host_client->netchan.good_count = 0;
480
481	//check he's not cheating
482
483	pmodel = atoi(Info_ValueForKey (host_client->userinfo, "pmodel"));
484	emodel = atoi(Info_ValueForKey (host_client->userinfo, "emodel"));
485
486	if (pmodel != sv.model_player_checksum ||
487		emodel != sv.eyes_player_checksum)
488		SV_BroadcastPrintf (PRINT_HIGH, "%s WARNING: non standard player/eyes model detected\n", host_client->name);
489
490	// if we are paused, tell the client
491	if (sv.paused) {
492		ClientReliableWrite_Begin (host_client, svc_setpause, 2);
493		ClientReliableWrite_Byte (host_client, sv.paused);
494		SV_ClientPrintf(host_client, PRINT_HIGH, "Server is paused.\n");
495	}
496
497#if 0
498//
499// send a fixangle over the reliable channel to make sure it gets there
500// Never send a roll angle, because savegames can catch the server
501// in a state where it is expecting the client to correct the angle
502// and it won't happen if the game was just loaded, so you wind up
503// with a permanent head tilt
504	ent = EDICT_NUM( 1 + (host_client - svs.clients) );
505	MSG_WriteByte (&host_client->netchan.message, svc_setangle);
506	for (i=0 ; i < 2 ; i++)
507		MSG_WriteAngle (&host_client->netchan.message, ent->v.angles[i] );
508	MSG_WriteAngle (&host_client->netchan.message, 0 );
509#endif
510}
511
512//=============================================================================
513
514/*
515==================
516SV_NextDownload_f
517==================
518*/
519void SV_NextDownload_f (void)
520{
521	byte	buffer[1024];
522	int		r;
523	int		percent;
524	int		size;
525
526	if (!host_client->download)
527		return;
528
529	r = host_client->downloadsize - host_client->downloadcount;
530	if (r > 768)
531		r = 768;
532	r = fread (buffer, 1, r, host_client->download);
533	ClientReliableWrite_Begin (host_client, svc_download, 6+r);
534	ClientReliableWrite_Short (host_client, r);
535
536	host_client->downloadcount += r;
537	size = host_client->downloadsize;
538	if (!size)
539		size = 1;
540	percent = host_client->downloadcount*100/size;
541	ClientReliableWrite_Byte (host_client, percent);
542	ClientReliableWrite_SZ (host_client, buffer, r);
543
544	if (host_client->downloadcount != host_client->downloadsize)
545		return;
546
547	fclose (host_client->download);
548	host_client->download = NULL;
549
550}
551
552void OutofBandPrintf(netadr_t where, char *fmt, ...)
553{
554	va_list		argptr;
555	char	send[1024];
556
557	send[0] = 0xff;
558	send[1] = 0xff;
559	send[2] = 0xff;
560	send[3] = 0xff;
561	send[4] = A2C_PRINT;
562	va_start (argptr, fmt);
563	vsprintf (send+5, fmt, argptr);
564	va_end (argptr);
565
566	NET_SendPacket (strlen(send)+1, send, where);
567}
568
569/*
570==================
571SV_NextUpload
572==================
573*/
574void SV_NextUpload (void)
575{
576	byte	buffer[1024];
577	int		r;
578	int		percent;
579	int		size;
580	client_t *client;
581
582	if (!*host_client->uploadfn) {
583		SV_ClientPrintf(host_client, PRINT_HIGH, "Upload denied\n");
584		ClientReliableWrite_Begin (host_client, svc_stufftext, 8);
585		ClientReliableWrite_String (host_client, "stopul");
586
587		// suck out rest of packet
588		size = MSG_ReadShort ();	MSG_ReadByte ();
589		msg_readcount += size;
590		return;
591	}
592
593	size = MSG_ReadShort ();
594	percent = MSG_ReadByte ();
595
596	if (!host_client->upload)
597	{
598		host_client->upload = fopen(host_client->uploadfn, "wb");
599		if (!host_client->upload) {
600			Sys_Printf("Can't create %s\n", host_client->uploadfn);
601			ClientReliableWrite_Begin (host_client, svc_stufftext, 8);
602			ClientReliableWrite_String (host_client, "stopul");
603			*host_client->uploadfn = 0;
604			return;
605		}
606		Sys_Printf("Receiving %s from %d...\n", host_client->uploadfn, host_client->userid);
607		if (host_client->remote_snap)
608			OutofBandPrintf(host_client->snap_from, "Server receiving %s from %d...\n", host_client->uploadfn, host_client->userid);
609	}
610
611	fwrite (net_message.data + msg_readcount, 1, size, host_client->upload);
612	msg_readcount += size;
613
614Con_DPrintf ("UPLOAD: %d received\n", size);
615
616	if (percent != 100) {
617		ClientReliableWrite_Begin (host_client, svc_stufftext, 8);
618		ClientReliableWrite_String (host_client, "nextul\n");
619	} else {
620		fclose (host_client->upload);
621		host_client->upload = NULL;
622
623		Sys_Printf("%s upload completed.\n", host_client->uploadfn);
624
625		if (host_client->remote_snap) {
626			char *p;
627
628			if ((p = strchr(host_client->uploadfn, '/')) != NULL)
629				p++;
630			else
631				p = host_client->uploadfn;
632			OutofBandPrintf(host_client->snap_from, "%s upload completed.\nTo download, enter:\ndownload %s\n",
633				host_client->uploadfn, p);
634		}
635	}
636
637}
638
639/*
640==================
641SV_BeginDownload_f
642==================
643*/
644void SV_BeginDownload_f(void)
645{
646	char	*name;
647	extern	cvar_t	allow_download;
648	extern	cvar_t	allow_download_skins;
649	extern	cvar_t	allow_download_models;
650	extern	cvar_t	allow_download_sounds;
651	extern	cvar_t	allow_download_maps;
652	extern	int		file_from_pak; // ZOID did file come from pak?
653
654	name = Cmd_Argv(1);
655// hacked by zoid to allow more conrol over download
656		// first off, no .. or global allow check
657	if (strstr (name, "..") || !allow_download.value
658		// leading dot is no good
659		|| *name == '.'
660		// leading slash bad as well, must be in subdir
661		|| *name == '/'
662		// next up, skin check
663		|| (strncmp(name, "skins/", 6) == 0 && !allow_download_skins.value)
664		// now models
665		|| (strncmp(name, "progs/", 6) == 0 && !allow_download_models.value)
666		// now sounds
667		|| (strncmp(name, "sound/", 6) == 0 && !allow_download_sounds.value)
668		// now maps (note special case for maps, must not be in pak)
669		|| (strncmp(name, "maps/", 6) == 0 && !allow_download_maps.value)
670		// MUST be in a subdirectory
671		|| !strstr (name, "/") )
672	{	// don't allow anything with .. path
673		ClientReliableWrite_Begin (host_client, svc_download, 4);
674		ClientReliableWrite_Short (host_client, -1);
675		ClientReliableWrite_Byte (host_client, 0);
676		return;
677	}
678
679	if (host_client->download) {
680		fclose (host_client->download);
681		host_client->download = NULL;
682	}
683
684	// lowercase name (needed for casesen file systems)
685	{
686		char *p;
687
688		for (p = name; *p; p++)
689			*p = (char)tolower(*p);
690	}
691
692
693	host_client->downloadsize = COM_FOpenFile (name, &host_client->download);
694	host_client->downloadcount = 0;
695
696	if (!host_client->download
697		// special check for maps, if it came from a pak file, don't allow
698		// download  ZOID
699		|| (strncmp(name, "maps/", 5) == 0 && file_from_pak))
700	{
701		if (host_client->download) {
702			fclose(host_client->download);
703			host_client->download = NULL;
704		}
705
706		Sys_Printf ("Couldn't download %s to %s\n", name, host_client->name);
707		ClientReliableWrite_Begin (host_client, svc_download, 4);
708		ClientReliableWrite_Short (host_client, -1);
709		ClientReliableWrite_Byte (host_client, 0);
710		return;
711	}
712
713	SV_NextDownload_f ();
714	Sys_Printf ("Downloading %s to %s\n", name, host_client->name);
715}
716
717//=============================================================================
718
719/*
720==================
721SV_Say
722==================
723*/
724void SV_Say (qboolean team)
725{
726	client_t *client;
727	int		j, tmp;
728	char	*p;
729	char	text[2048];
730	char	t1[32], *t2;
731
732	if (Cmd_Argc () < 2)
733		return;
734
735	if (team)
736	{
737		strncpy (t1, Info_ValueForKey (host_client->userinfo, "team"), 31);
738		t1[31] = 0;
739	}
740
741	if (host_client->spectator && (!sv_spectalk.value || team))
742		sprintf (text, "[SPEC] %s: ", host_client->name);
743	else if (team)
744		sprintf (text, "(%s): ", host_client->name);
745	else {
746		sprintf (text, "%s: ", host_client->name);
747	}
748
749	if (fp_messages) {
750		if (!sv.paused && realtime<host_client->lockedtill) {
751			SV_ClientPrintf(host_client, PRINT_CHAT,
752				"You can't talk for %d more seconds\n",
753					(int) (host_client->lockedtill - realtime));
754			return;
755		}
756		tmp = host_client->whensaidhead - fp_messages + 1;
757		if (tmp < 0)
758			tmp = 10+tmp;
759		if (!sv.paused &&
760			host_client->whensaid[tmp] && (realtime-host_client->whensaid[tmp] < fp_persecond)) {
761			host_client->lockedtill = realtime + fp_secondsdead;
762			if (fp_msg[0])
763				SV_ClientPrintf(host_client, PRINT_CHAT,
764					"FloodProt: %s\n", fp_msg);
765			else
766				SV_ClientPrintf(host_client, PRINT_CHAT,
767					"FloodProt: You can't talk for %d seconds.\n", fp_secondsdead);
768			return;
769		}
770		host_client->whensaidhead++;
771		if (host_client->whensaidhead > 9)
772			host_client->whensaidhead = 0;
773		host_client->whensaid[host_client->whensaidhead] = realtime;
774	}
775
776	p = Cmd_Args();
777
778	if (*p == '"')
779	{
780		p++;
781		p[Q_strlen(p)-1] = 0;
782	}
783
784	Q_strcat(text, p);
785	Q_strcat(text, "\n");
786
787	Sys_Printf ("%s", text);
788
789	for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++)
790	{
791		if (client->state != cs_spawned)
792			continue;
793		if (host_client->spectator && !sv_spectalk.value)
794			if (!client->spectator)
795				continue;
796
797		if (team)
798		{
799			// the spectator team
800			if (host_client->spectator) {
801				if (!client->spectator)
802					continue;
803			} else {
804				t2 = Info_ValueForKey (client->userinfo, "team");
805				if (strcmp(t1, t2) || client->spectator)
806					continue;	// on different teams
807			}
808		}
809		SV_ClientPrintf(client, PRINT_CHAT, "%s", text);
810	}
811}
812
813
814/*
815==================
816SV_Say_f
817==================
818*/
819void SV_Say_f(void)
820{
821	SV_Say (false);
822}
823/*
824==================
825SV_Say_Team_f
826==================
827*/
828void SV_Say_Team_f(void)
829{
830	SV_Say (true);
831}
832
833
834
835//============================================================================
836
837/*
838=================
839SV_Pings_f
840
841The client is showing the scoreboard, so send new ping times for all
842clients
843=================
844*/
845void SV_Pings_f (void)
846{
847	client_t *client;
848	int		j;
849
850	for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++)
851	{
852		if (client->state != cs_spawned)
853			continue;
854
855		ClientReliableWrite_Begin (host_client, svc_updateping, 4);
856		ClientReliableWrite_Byte (host_client, j);
857		ClientReliableWrite_Short (host_client, SV_CalcPing(client));
858		ClientReliableWrite_Begin (host_client, svc_updatepl, 4);
859		ClientReliableWrite_Byte (host_client, j);
860		ClientReliableWrite_Byte (host_client, client->lossage);
861	}
862}
863
864
865
866/*
867==================
868SV_Kill_f
869==================
870*/
871void SV_Kill_f (void)
872{
873	if (sv_player->v.health <= 0)
874	{
875		SV_ClientPrintf (host_client, PRINT_HIGH, "Can't suicide -- allready dead!\n");
876		return;
877	}
878
879	pr_global_struct->time = sv.time;
880	pr_global_struct->self = EDICT_TO_PROG(sv_player);
881	PR_ExecuteProgram (pr_global_struct->ClientKill);
882}
883
884/*
885==================
886SV_TogglePause
887==================
888*/
889void SV_TogglePause (const char *msg)
890{
891	int i;
892	client_t *cl;
893
894	sv.paused ^= 1;
895
896	if (msg)
897		SV_BroadcastPrintf (PRINT_HIGH, "%s", msg);
898
899	// send notification to all clients
900	for (i=0, cl = svs.clients ; i<MAX_CLIENTS ; i++, cl++)
901	{
902		if (!cl->state)
903			continue;
904		ClientReliableWrite_Begin (cl, svc_setpause, 2);
905		ClientReliableWrite_Byte (cl, sv.paused);
906	}
907}
908
909
910/*
911==================
912SV_Pause_f
913==================
914*/
915void SV_Pause_f (void)
916{
917	int i;
918	client_t *cl;
919	char st[sizeof(host_client->name) + 32];
920
921	if (!pausable.value) {
922		SV_ClientPrintf (host_client, PRINT_HIGH, "Pause not allowed.\n");
923		return;
924	}
925
926	if (host_client->spectator) {
927		SV_ClientPrintf (host_client, PRINT_HIGH, "Spectators can not pause.\n");
928		return;
929	}
930
931	if (sv.paused)
932		sprintf (st, "%s paused the game\n", host_client->name);
933	else
934		sprintf (st, "%s unpaused the game\n", host_client->name);
935
936	SV_TogglePause(st);
937}
938
939
940/*
941=================
942SV_Drop_f
943
944The client is going to disconnect, so remove the connection immediately
945=================
946*/
947void SV_Drop_f (void)
948{
949	SV_EndRedirect ();
950	if (!host_client->spectator)
951		SV_BroadcastPrintf (PRINT_HIGH, "%s dropped\n", host_client->name);
952	SV_DropClient (host_client);
953}
954
955/*
956=================
957SV_PTrack_f
958
959Change the bandwidth estimate for a client
960=================
961*/
962void SV_PTrack_f (void)
963{
964	int		i;
965	edict_t *ent, *tent;
966
967	if (!host_client->spectator)
968		return;
969
970	if (Cmd_Argc() != 2)
971	{
972		// turn off tracking
973		host_client->spec_track = 0;
974		ent = EDICT_NUM(host_client - svs.clients + 1);
975		tent = EDICT_NUM(0);
976		ent->v.goalentity = EDICT_TO_PROG(tent);
977		return;
978	}
979
980	i = atoi(Cmd_Argv(1));
981	if (i < 0 || i >= MAX_CLIENTS || svs.clients[i].state != cs_spawned ||
982		svs.clients[i].spectator) {
983		SV_ClientPrintf (host_client, PRINT_HIGH, "Invalid client to track\n");
984		host_client->spec_track = 0;
985		ent = EDICT_NUM(host_client - svs.clients + 1);
986		tent = EDICT_NUM(0);
987		ent->v.goalentity = EDICT_TO_PROG(tent);
988		return;
989	}
990	host_client->spec_track = i + 1; // now tracking
991
992	ent = EDICT_NUM(host_client - svs.clients + 1);
993	tent = EDICT_NUM(i + 1);
994	ent->v.goalentity = EDICT_TO_PROG(tent);
995}
996
997
998/*
999=================
1000SV_Rate_f
1001
1002Change the bandwidth estimate for a client
1003=================
1004*/
1005void SV_Rate_f (void)
1006{
1007	int		rate;
1008
1009	if (Cmd_Argc() != 2)
1010	{
1011		SV_ClientPrintf (host_client, PRINT_HIGH, "Current rate is %i\n",
1012			(int)(1.0/host_client->netchan.rate + 0.5));
1013		return;
1014	}
1015
1016	rate = atoi(Cmd_Argv(1));
1017	if (rate < 500)
1018		rate = 500;
1019	if (rate > 10000)
1020		rate = 10000;
1021
1022	SV_ClientPrintf (host_client, PRINT_HIGH, "Net rate set to %i\n", rate);
1023	host_client->netchan.rate = 1.0/rate;
1024}
1025
1026
1027/*
1028=================
1029SV_Msg_f
1030
1031Change the message level for a client
1032=================
1033*/
1034void SV_Msg_f (void)
1035{
1036	if (Cmd_Argc() != 2)
1037	{
1038		SV_ClientPrintf (host_client, PRINT_HIGH, "Current msg level is %i\n",
1039			host_client->messagelevel);
1040		return;
1041	}
1042
1043	host_client->messagelevel = atoi(Cmd_Argv(1));
1044
1045	SV_ClientPrintf (host_client, PRINT_HIGH, "Msg level set to %i\n", host_client->messagelevel);
1046}
1047
1048/*
1049==================
1050SV_SetInfo_f
1051
1052Allow clients to change userinfo
1053==================
1054*/
1055void SV_SetInfo_f (void)
1056{
1057	int i;
1058	char oldval[MAX_INFO_STRING];
1059
1060
1061	if (Cmd_Argc() == 1)
1062	{
1063		Con_Printf ("User info settings:\n");
1064		Info_Print (host_client->userinfo);
1065		return;
1066	}
1067
1068	if (Cmd_Argc() != 3)
1069	{
1070		Con_Printf ("usage: setinfo [ <key> <value> ]\n");
1071		return;
1072	}
1073
1074	if (Cmd_Argv(1)[0] == '*')
1075		return;		// don't set priveledged values
1076
1077	strcpy(oldval, Info_ValueForKey(host_client->userinfo, Cmd_Argv(1)));
1078
1079	Info_SetValueForKey (host_client->userinfo, Cmd_Argv(1), Cmd_Argv(2), MAX_INFO_STRING);
1080// name is extracted below in ExtractFromUserInfo
1081//	strncpy (host_client->name, Info_ValueForKey (host_client->userinfo, "name")
1082//		, sizeof(host_client->name)-1);
1083//	SV_FullClientUpdate (host_client, &sv.reliable_datagram);
1084//	host_client->sendinfo = true;
1085
1086	if (!strcmp(Info_ValueForKey(host_client->userinfo, Cmd_Argv(1)), oldval))
1087		return; // key hasn't changed
1088
1089	// process any changed values
1090	SV_ExtractFromUserinfo (host_client);
1091
1092	i = host_client - svs.clients;
1093	MSG_WriteByte (&sv.reliable_datagram, svc_setinfo);
1094	MSG_WriteByte (&sv.reliable_datagram, i);
1095	MSG_WriteString (&sv.reliable_datagram, Cmd_Argv(1));
1096	MSG_WriteString (&sv.reliable_datagram, Info_ValueForKey(host_client->userinfo, Cmd_Argv(1)));
1097}
1098
1099/*
1100==================
1101SV_ShowServerinfo_f
1102
1103Dumps the serverinfo info string
1104==================
1105*/
1106void SV_ShowServerinfo_f (void)
1107{
1108	Info_Print (svs.info);
1109}
1110
1111void SV_NoSnap_f(void)
1112{
1113	if (*host_client->uploadfn) {
1114		*host_client->uploadfn = 0;
1115		SV_BroadcastPrintf (PRINT_HIGH, "%s refused remote screenshot\n", host_client->name);
1116	}
1117}
1118
1119typedef struct
1120{
1121	char	*name;
1122	void	(*func) (void);
1123} ucmd_t;
1124
1125ucmd_t ucmds[] =
1126{
1127	{"new", SV_New_f},
1128	{"modellist", SV_Modellist_f},
1129	{"soundlist", SV_Soundlist_f},
1130	{"prespawn", SV_PreSpawn_f},
1131	{"spawn", SV_Spawn_f},
1132	{"begin", SV_Begin_f},
1133
1134	{"drop", SV_Drop_f},
1135	{"pings", SV_Pings_f},
1136
1137// issued by hand at client consoles
1138	{"rate", SV_Rate_f},
1139	{"kill", SV_Kill_f},
1140	{"pause", SV_Pause_f},
1141	{"msg", SV_Msg_f},
1142
1143	{"say", SV_Say_f},
1144	{"say_team", SV_Say_Team_f},
1145
1146	{"setinfo", SV_SetInfo_f},
1147
1148	{"serverinfo", SV_ShowServerinfo_f},
1149
1150	{"download", SV_BeginDownload_f},
1151	{"nextdl", SV_NextDownload_f},
1152
1153	{"ptrack", SV_PTrack_f}, //ZOID - used with autocam
1154
1155	{"snap", SV_NoSnap_f},
1156
1157	{NULL, NULL}
1158};
1159
1160/*
1161==================
1162SV_ExecuteUserCommand
1163==================
1164*/
1165void SV_ExecuteUserCommand (char *s)
1166{
1167	ucmd_t	*u;
1168
1169	Cmd_TokenizeString (s);
1170	sv_player = host_client->edict;
1171
1172	SV_BeginRedirect (RD_CLIENT);
1173
1174	for (u=ucmds ; u->name ; u++)
1175		if (!strcmp (Cmd_Argv(0), u->name) )
1176		{
1177			u->func ();
1178			break;
1179		}
1180
1181	if (!u->name)
1182		Con_Printf ("Bad user command: %s\n", Cmd_Argv(0));
1183
1184	SV_EndRedirect ();
1185}
1186
1187/*
1188===========================================================================
1189
1190USER CMD EXECUTION
1191
1192===========================================================================
1193*/
1194
1195/*
1196===============
1197V_CalcRoll
1198
1199Used by view and sv_user
1200===============
1201*/
1202float V_CalcRoll (vec3_t angles, vec3_t velocity)
1203{
1204	vec3_t	forward, right, up;
1205	float	sign;
1206	float	side;
1207	float	value;
1208
1209	AngleVectors (angles, forward, right, up);
1210	side = DotProduct (velocity, right);
1211	sign = side < 0 ? -1 : 1;
1212	side = fabs(side);
1213
1214	value = cl_rollangle.value;
1215
1216	if (side < cl_rollspeed.value)
1217		side = side * value / cl_rollspeed.value;
1218	else
1219		side = value;
1220
1221	return side*sign;
1222
1223}
1224
1225
1226
1227
1228//============================================================================
1229
1230vec3_t	pmove_mins, pmove_maxs;
1231
1232/*
1233====================
1234AddLinksToPmove
1235
1236====================
1237*/
1238void AddLinksToPmove ( areanode_t *node )
1239{
1240	link_t		*l, *next;
1241	edict_t		*check;
1242	int			pl;
1243	int			i;
1244	physent_t	*pe;
1245
1246	pl = EDICT_TO_PROG(sv_player);
1247
1248	// touch linked edicts
1249	for (l = node->solid_edicts.next ; l != &node->solid_edicts ; l = next)
1250	{
1251		next = l->next;
1252		check = EDICT_FROM_AREA(l);
1253
1254		if (check->v.owner == pl)
1255			continue;		// player's own missile
1256		if (check->v.solid == SOLID_BSP
1257			|| check->v.solid == SOLID_BBOX
1258			|| check->v.solid == SOLID_SLIDEBOX)
1259		{
1260			if (check == sv_player)
1261				continue;
1262
1263			for (i=0 ; i<3 ; i++)
1264				if (check->v.absmin[i] > pmove_maxs[i]
1265				|| check->v.absmax[i] < pmove_mins[i])
1266					break;
1267			if (i != 3)
1268				continue;
1269			if (pmove.numphysent == MAX_PHYSENTS)
1270				return;
1271			pe = &pmove.physents[pmove.numphysent];
1272			pmove.numphysent++;
1273
1274			VectorCopy (check->v.origin, pe->origin);
1275			pe->info = NUM_FOR_EDICT(check);
1276			if (check->v.solid == SOLID_BSP)
1277				pe->model = sv.models[(int)(check->v.modelindex)];
1278			else
1279			{
1280				pe->model = NULL;
1281				VectorCopy (check->v.mins, pe->mins);
1282				VectorCopy (check->v.maxs, pe->maxs);
1283			}
1284		}
1285	}
1286
1287// recurse down both sides
1288	if (node->axis == -1)
1289		return;
1290
1291	if ( pmove_maxs[node->axis] > node->dist )
1292		AddLinksToPmove ( node->children[0] );
1293	if ( pmove_mins[node->axis] < node->dist )
1294		AddLinksToPmove ( node->children[1] );
1295}
1296
1297
1298/*
1299================
1300AddAllEntsToPmove
1301
1302For debugging
1303================
1304*/
1305void AddAllEntsToPmove (void)
1306{
1307	int			e;
1308	edict_t		*check;
1309	int			i;
1310	physent_t	*pe;
1311	int			pl;
1312
1313	pl = EDICT_TO_PROG(sv_player);
1314	check = NEXT_EDICT(sv.edicts);
1315	for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
1316	{
1317		if (check->free)
1318			continue;
1319		if (check->v.owner == pl)
1320			continue;
1321		if (check->v.solid == SOLID_BSP
1322			|| check->v.solid == SOLID_BBOX
1323			|| check->v.solid == SOLID_SLIDEBOX)
1324		{
1325			if (check == sv_player)
1326				continue;
1327
1328			for (i=0 ; i<3 ; i++)
1329				if (check->v.absmin[i] > pmove_maxs[i]
1330				|| check->v.absmax[i] < pmove_mins[i])
1331					break;
1332			if (i != 3)
1333				continue;
1334			pe = &pmove.physents[pmove.numphysent];
1335
1336			VectorCopy (check->v.origin, pe->origin);
1337			pmove.physents[pmove.numphysent].info = e;
1338			if (check->v.solid == SOLID_BSP)
1339				pe->model = sv.models[(int)(check->v.modelindex)];
1340			else
1341			{
1342				pe->model = NULL;
1343				VectorCopy (check->v.mins, pe->mins);
1344				VectorCopy (check->v.maxs, pe->maxs);
1345			}
1346
1347			if (++pmove.numphysent == MAX_PHYSENTS)
1348				break;
1349		}
1350	}
1351}
1352
1353/*
1354===========
1355SV_PreRunCmd
1356===========
1357Done before running a player command.  Clears the touch array
1358*/
1359byte playertouch[(MAX_EDICTS+7)/8];
1360
1361void SV_PreRunCmd(void)
1362{
1363	memset(playertouch, 0, sizeof(playertouch));
1364}
1365
1366/*
1367===========
1368SV_RunCmd
1369===========
1370*/
1371void SV_RunCmd (usercmd_t *ucmd)
1372{
1373	edict_t		*ent;
1374	int			i, n;
1375	int			oldmsec;
1376
1377	cmd = *ucmd;
1378
1379	// chop up very long commands
1380	if (cmd.msec > 50)
1381	{
1382		oldmsec = ucmd->msec;
1383		cmd.msec = oldmsec/2;
1384		SV_RunCmd (&cmd);
1385		cmd.msec = oldmsec/2;
1386		cmd.impulse = 0;
1387		SV_RunCmd (&cmd);
1388		return;
1389	}
1390
1391	if (!sv_player->v.fixangle)
1392		VectorCopy (ucmd->angles, sv_player->v.v_angle);
1393
1394	sv_player->v.button0 = ucmd->buttons & 1;
1395	sv_player->v.button2 = (ucmd->buttons & 2)>>1;
1396	if (ucmd->impulse)
1397		sv_player->v.impulse = ucmd->impulse;
1398
1399//
1400// angles
1401// show 1/3 the pitch angle and all the roll angle
1402	if (sv_player->v.health > 0)
1403	{
1404		if (!sv_player->v.fixangle)
1405		{
1406			sv_player->v.angles[PITCH] = -sv_player->v.v_angle[PITCH]/3;
1407			sv_player->v.angles[YAW] = sv_player->v.v_angle[YAW];
1408		}
1409		sv_player->v.angles[ROLL] =
1410			V_CalcRoll (sv_player->v.angles, sv_player->v.velocity)*4;
1411	}
1412
1413	host_frametime = ucmd->msec * 0.001;
1414	if (host_frametime > 0.1)
1415		host_frametime = 0.1;
1416
1417	if (!host_client->spectator)
1418	{
1419		pr_global_struct->frametime = host_frametime;
1420
1421		pr_global_struct->time = sv.time;
1422		pr_global_struct->self = EDICT_TO_PROG(sv_player);
1423		PR_ExecuteProgram (pr_global_struct->PlayerPreThink);
1424
1425		SV_RunThink (sv_player);
1426	}
1427
1428	for (i=0 ; i<3 ; i++)
1429		pmove.origin[i] = sv_player->v.origin[i] + (sv_player->v.mins[i] - player_mins[i]);
1430	VectorCopy (sv_player->v.velocity, pmove.velocity);
1431	VectorCopy (sv_player->v.v_angle, pmove.angles);
1432
1433	pmove.spectator = host_client->spectator;
1434	pmove.waterjumptime = sv_player->v.teleport_time;
1435	pmove.numphysent = 1;
1436	pmove.physents[0].model = sv.worldmodel;
1437	pmove.cmd = *ucmd;
1438	pmove.dead = sv_player->v.health <= 0;
1439	pmove.oldbuttons = host_client->oldbuttons;
1440
1441	movevars.entgravity = host_client->entgravity;
1442	movevars.maxspeed = host_client->maxspeed;
1443
1444	for (i=0 ; i<3 ; i++)
1445	{
1446		pmove_mins[i] = pmove.origin[i] - 256;
1447		pmove_maxs[i] = pmove.origin[i] + 256;
1448	}
1449#if 1
1450	AddLinksToPmove ( sv_areanodes );
1451#else
1452	AddAllEntsToPmove ();
1453#endif
1454
1455#if 0
1456{
1457	int before, after;
1458
1459before = PM_TestPlayerPosition (pmove.origin);
1460	PlayerMove ();
1461after = PM_TestPlayerPosition (pmove.origin);
1462
1463if (sv_player->v.health > 0 && before && !after )
1464	Con_Printf ("player %s got stuck in playermove!!!!\n", host_client->name);
1465}
1466#else
1467	PlayerMove ();
1468#endif
1469
1470	host_client->oldbuttons = pmove.oldbuttons;
1471	sv_player->v.teleport_time = pmove.waterjumptime;
1472	sv_player->v.waterlevel = waterlevel;
1473	sv_player->v.watertype = watertype;
1474	if (onground != -1)
1475	{
1476		sv_player->v.flags = (int)sv_player->v.flags | FL_ONGROUND;
1477		sv_player->v.groundentity = EDICT_TO_PROG(EDICT_NUM(pmove.physents[onground].info));
1478	}
1479	else
1480		sv_player->v.flags = (int)sv_player->v.flags & ~FL_ONGROUND;
1481	for (i=0 ; i<3 ; i++)
1482		sv_player->v.origin[i] = pmove.origin[i] - (sv_player->v.mins[i] - player_mins[i]);
1483
1484#if 0
1485	// truncate velocity the same way the net protocol will
1486	for (i=0 ; i<3 ; i++)
1487		sv_player->v.velocity[i] = (int)pmove.velocity[i];
1488#else
1489	VectorCopy (pmove.velocity, sv_player->v.velocity);
1490#endif
1491
1492	VectorCopy (pmove.angles, sv_player->v.v_angle);
1493
1494	if (!host_client->spectator)
1495	{
1496		// link into place and touch triggers
1497		SV_LinkEdict (sv_player, true);
1498
1499		// touch other objects
1500		for (i=0 ; i<pmove.numtouch ; i++)
1501		{
1502			n = pmove.physents[pmove.touchindex[i]].info;
1503			ent = EDICT_NUM(n);
1504			if (!ent->v.touch || (playertouch[n/8]&(1<<(n%8))))
1505				continue;
1506			pr_global_struct->self = EDICT_TO_PROG(ent);
1507			pr_global_struct->other = EDICT_TO_PROG(sv_player);
1508			PR_ExecuteProgram (ent->v.touch);
1509			playertouch[n/8] |= 1 << (n%8);
1510		}
1511	}
1512}
1513
1514/*
1515===========
1516SV_PostRunCmd
1517===========
1518Done after running a player command.
1519*/
1520void SV_PostRunCmd(void)
1521{
1522	// run post-think
1523
1524	if (!host_client->spectator) {
1525		pr_global_struct->time = sv.time;
1526		pr_global_struct->self = EDICT_TO_PROG(sv_player);
1527		PR_ExecuteProgram (pr_global_struct->PlayerPostThink);
1528		SV_RunNewmis ();
1529	} else if (SpectatorThink) {
1530		pr_global_struct->time = sv.time;
1531		pr_global_struct->self = EDICT_TO_PROG(sv_player);
1532		PR_ExecuteProgram (SpectatorThink);
1533	}
1534}
1535
1536
1537/*
1538===================
1539SV_ExecuteClientMessage
1540
1541The current net_message is parsed for the given client
1542===================
1543*/
1544void SV_ExecuteClientMessage (client_t *cl)
1545{
1546	int		c;
1547	char	*s;
1548	usercmd_t	oldest, oldcmd, newcmd;
1549	client_frame_t	*frame;
1550	vec3_t o;
1551	qboolean	move_issued = false; //only allow one move command
1552	int		checksumIndex;
1553	byte	checksum, calculatedChecksum;
1554	int		seq_hash;
1555
1556	// calc ping time
1557	frame = &cl->frames[cl->netchan.incoming_acknowledged & UPDATE_MASK];
1558	frame->ping_time = realtime - frame->senttime;
1559
1560	// make sure the reply sequence number matches the incoming
1561	// sequence number
1562	if (cl->netchan.incoming_sequence >= cl->netchan.outgoing_sequence)
1563		cl->netchan.outgoing_sequence = cl->netchan.incoming_sequence;
1564	else
1565		cl->send_message = false;	// don't reply, sequences have slipped
1566
1567	// save time for ping calculations
1568	cl->frames[cl->netchan.outgoing_sequence & UPDATE_MASK].senttime = realtime;
1569	cl->frames[cl->netchan.outgoing_sequence & UPDATE_MASK].ping_time = -1;
1570
1571	host_client = cl;
1572	sv_player = host_client->edict;
1573
1574//	seq_hash = (cl->netchan.incoming_sequence & 0xffff) ; // ^ QW_CHECK_HASH;
1575	seq_hash = cl->netchan.incoming_sequence;
1576
1577	// mark time so clients will know how much to predict
1578	// other players
1579 	cl->localtime = sv.time;
1580	cl->delta_sequence = -1;	// no delta unless requested
1581	while (1)
1582	{
1583		if (msg_badread)
1584		{
1585			Con_Printf ("SV_ReadClientMessage: badread\n");
1586			SV_DropClient (cl);
1587			return;
1588		}
1589
1590		c = MSG_ReadByte ();
1591		if (c == -1)
1592			break;
1593
1594		switch (c)
1595		{
1596		default:
1597			Con_Printf ("SV_ReadClientMessage: unknown command char\n");
1598			SV_DropClient (cl);
1599			return;
1600
1601		case clc_nop:
1602			break;
1603
1604		case clc_delta:
1605			cl->delta_sequence = MSG_ReadByte ();
1606			break;
1607
1608		case clc_move:
1609			if (move_issued)
1610				return;		// someone is trying to cheat...
1611
1612			move_issued = true;
1613
1614			checksumIndex = MSG_GetReadCount();
1615			checksum = (byte)MSG_ReadByte ();
1616
1617			// read loss percentage
1618			cl->lossage = MSG_ReadByte();
1619
1620			MSG_ReadDeltaUsercmd (&nullcmd, &oldest);
1621			MSG_ReadDeltaUsercmd (&oldest, &oldcmd);
1622			MSG_ReadDeltaUsercmd (&oldcmd, &newcmd);
1623
1624			if ( cl->state != cs_spawned )
1625				break;
1626
1627			// if the checksum fails, ignore the rest of the packet
1628			calculatedChecksum = COM_BlockSequenceCRCByte(
1629				net_message.data + checksumIndex + 1,
1630				MSG_GetReadCount() - checksumIndex - 1,
1631				seq_hash);
1632
1633			if (calculatedChecksum != checksum)
1634			{
1635				Con_DPrintf ("Failed command checksum for %s(%d) (%d != %d)\n",
1636					cl->name, cl->netchan.incoming_sequence, checksum, calculatedChecksum);
1637				return;
1638			}
1639
1640			if (!sv.paused) {
1641				SV_PreRunCmd();
1642
1643				if (net_drop < 20)
1644				{
1645					while (net_drop > 2)
1646					{
1647						SV_RunCmd (&cl->lastcmd);
1648						net_drop--;
1649					}
1650					if (net_drop > 1)
1651						SV_RunCmd (&oldest);
1652					if (net_drop > 0)
1653						SV_RunCmd (&oldcmd);
1654				}
1655				SV_RunCmd (&newcmd);
1656
1657				SV_PostRunCmd();
1658			}
1659
1660			cl->lastcmd = newcmd;
1661			cl->lastcmd.buttons = 0; // avoid multiple fires on lag
1662			break;
1663
1664
1665		case clc_stringcmd:
1666			s = MSG_ReadString ();
1667			SV_ExecuteUserCommand (s);
1668			break;
1669
1670		case clc_tmove:
1671			o[0] = MSG_ReadCoord();
1672			o[1] = MSG_ReadCoord();
1673			o[2] = MSG_ReadCoord();
1674			// only allowed by spectators
1675			if (host_client->spectator) {
1676				VectorCopy(o, sv_player->v.origin);
1677				SV_LinkEdict(sv_player, false);
1678			}
1679			break;
1680
1681		case clc_upload:
1682			SV_NextUpload();
1683			break;
1684
1685		}
1686	}
1687}
1688
1689/*
1690==============
1691SV_UserInit
1692==============
1693*/
1694void SV_UserInit (void)
1695{
1696	Cvar_RegisterVariable (&cl_rollspeed);
1697	Cvar_RegisterVariable (&cl_rollangle);
1698	Cvar_RegisterVariable (&sv_spectalk);
1699	Cvar_RegisterVariable (&sv_mapcheck);
1700}
1701
1702
1703