• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 
21 #include "qwsvdef.h"
22 
23 qboolean	sv_allow_cheats;
24 
25 int fp_messages=4, fp_persecond=4, fp_secondsdead=10;
26 char fp_msg[255] = { 0 };
27 extern cvar_t cl_warncmd;
28 	extern		redirect_t	sv_redirected;
29 
30 
31 /*
32 ===============================================================================
33 
34 OPERATOR CONSOLE ONLY COMMANDS
35 
36 These commands can only be entered from stdin or by a remote operator datagram
37 ===============================================================================
38 */
39 
40 /*
41 ====================
42 SV_SetMaster_f
43 
44 Make a master server current
45 ====================
46 */
SV_SetMaster_f(void)47 void SV_SetMaster_f (void)
48 {
49 	char	data[2];
50 	int		i;
51 
52 	memset (&master_adr, 0, sizeof(master_adr));
53 
54 	for (i=1 ; i<Cmd_Argc() ; i++)
55 	{
56 		if (!strcmp(Cmd_Argv(i), "none") || !NET_StringToAdr (Cmd_Argv(i), &master_adr[i-1]))
57 		{
58 			Con_Printf ("Setting nomaster mode.\n");
59 			return;
60 		}
61 		if (master_adr[i-1].port == 0)
62 			master_adr[i-1].port = BigShort (27000);
63 
64 		Con_Printf ("Master server at %s\n", NET_AdrToString (master_adr[i-1]));
65 
66 		Con_Printf ("Sending a ping.\n");
67 
68 		data[0] = A2A_PING;
69 		data[1] = 0;
70 		NET_SendPacket (2, data, master_adr[i-1]);
71 	}
72 
73 	svs.last_heartbeat = -99999;
74 }
75 
76 
77 /*
78 ==================
79 SV_Quit_f
80 ==================
81 */
SV_Quit_f(void)82 void SV_Quit_f (void)
83 {
84 	SV_FinalMessage ("server shutdown\n");
85 	Con_Printf ("Shutting down.\n");
86 	SV_Shutdown ();
87 	Sys_Quit ();
88 }
89 
90 /*
91 ============
92 SV_Logfile_f
93 ============
94 */
SV_Logfile_f(void)95 void SV_Logfile_f (void)
96 {
97 	char	name[MAX_OSPATH];
98 
99 	if (sv_logfile)
100 	{
101 		Con_Printf ("File logging off.\n");
102 		fclose (sv_logfile);
103 		sv_logfile = NULL;
104 		return;
105 	}
106 
107 	sprintf (name, "%s/qconsole.log", com_gamedir);
108 	Con_Printf ("Logging text to %s.\n", name);
109 	sv_logfile = fopen (name, "w");
110 	if (!sv_logfile)
111 		Con_Printf ("failed.\n");
112 }
113 
114 
115 /*
116 ============
117 SV_Fraglogfile_f
118 ============
119 */
SV_Fraglogfile_f(void)120 void SV_Fraglogfile_f (void)
121 {
122 	char	name[MAX_OSPATH];
123 	int		i;
124 
125 	if (sv_fraglogfile)
126 	{
127 		Con_Printf ("Frag file logging off.\n");
128 		fclose (sv_fraglogfile);
129 		sv_fraglogfile = NULL;
130 		return;
131 	}
132 
133 	// find an unused name
134 	for (i=0 ; i<1000 ; i++)
135 	{
136 		sprintf (name, "%s/frag_%i.log", com_gamedir, i);
137 		sv_fraglogfile = fopen (name, "r");
138 		if (!sv_fraglogfile)
139 		{	// can't read it, so create this one
140 			sv_fraglogfile = fopen (name, "w");
141 			if (!sv_fraglogfile)
142 				i=1000;	// give error
143 			break;
144 		}
145 		fclose (sv_fraglogfile);
146 	}
147 	if (i==1000)
148 	{
149 		Con_Printf ("Can't open any logfiles.\n");
150 		sv_fraglogfile = NULL;
151 		return;
152 	}
153 
154 	Con_Printf ("Logging frags to %s.\n", name);
155 }
156 
157 
158 /*
159 ==================
160 SV_SetPlayer
161 
162 Sets host_client and sv_player to the player with idnum Cmd_Argv(1)
163 ==================
164 */
SV_SetPlayer(void)165 qboolean SV_SetPlayer (void)
166 {
167 	client_t	*cl;
168 	int			i;
169 	int			idnum;
170 
171 	idnum = atoi(Cmd_Argv(1));
172 
173 	for (i=0,cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++)
174 	{
175 		if (!cl->state)
176 			continue;
177 		if (cl->userid == idnum)
178 		{
179 			host_client = cl;
180 			sv_player = host_client->edict;
181 			return true;
182 		}
183 	}
184 	Con_Printf ("Userid %i is not on the server\n", idnum);
185 	return false;
186 }
187 
188 
189 /*
190 ==================
191 SV_God_f
192 
193 Sets client to godmode
194 ==================
195 */
SV_God_f(void)196 void SV_God_f (void)
197 {
198 	if (!sv_allow_cheats)
199 	{
200 		Con_Printf ("You must run the server with -cheats to enable this command.\n");
201 		return;
202 	}
203 
204 	if (!SV_SetPlayer ())
205 		return;
206 
207 	sv_player->v.flags = (int)sv_player->v.flags ^ FL_GODMODE;
208 	if (!((int)sv_player->v.flags & FL_GODMODE) )
209 		SV_ClientPrintf (host_client, PRINT_HIGH, "godmode OFF\n");
210 	else
211 		SV_ClientPrintf (host_client, PRINT_HIGH, "godmode ON\n");
212 }
213 
214 
SV_Noclip_f(void)215 void SV_Noclip_f (void)
216 {
217 	if (!sv_allow_cheats)
218 	{
219 		Con_Printf ("You must run the server with -cheats to enable this command.\n");
220 		return;
221 	}
222 
223 	if (!SV_SetPlayer ())
224 		return;
225 
226 	if (sv_player->v.movetype != MOVETYPE_NOCLIP)
227 	{
228 		sv_player->v.movetype = MOVETYPE_NOCLIP;
229 		SV_ClientPrintf (host_client, PRINT_HIGH, "noclip ON\n");
230 	}
231 	else
232 	{
233 		sv_player->v.movetype = MOVETYPE_WALK;
234 		SV_ClientPrintf (host_client, PRINT_HIGH, "noclip OFF\n");
235 	}
236 }
237 
238 
239 /*
240 ==================
241 SV_Give_f
242 ==================
243 */
SV_Give_f(void)244 void SV_Give_f (void)
245 {
246 	char	*t;
247 	int		v;
248 
249 	if (!sv_allow_cheats)
250 	{
251 		Con_Printf ("You must run the server with -cheats to enable this command.\n");
252 		return;
253 	}
254 
255 	if (!SV_SetPlayer ())
256 		return;
257 
258 	t = Cmd_Argv(2);
259 	v = atoi (Cmd_Argv(3));
260 
261 	switch (t[0])
262 	{
263 	case '2':
264 	case '3':
265 	case '4':
266 	case '5':
267 	case '6':
268 	case '7':
269 	case '8':
270 	case '9':
271 		sv_player->v.items = (int)sv_player->v.items | IT_SHOTGUN<< (t[0] - '2');
272 		break;
273 
274 	case 's':
275 		sv_player->v.ammo_shells = v;
276 		break;
277 	case 'n':
278 		sv_player->v.ammo_nails = v;
279 		break;
280 	case 'r':
281 		sv_player->v.ammo_rockets = v;
282 		break;
283 	case 'h':
284 		sv_player->v.health = v;
285 		break;
286 	case 'c':
287 		sv_player->v.ammo_cells = v;
288 		break;
289 	}
290 }
291 
292 
293 /*
294 ======================
295 SV_Map_f
296 
297 handle a
298 map <mapname>
299 command from the console or progs.
300 ======================
301 */
SV_Map_f(void)302 void SV_Map_f (void)
303 {
304 	char	level[MAX_QPATH];
305 	char	expanded[MAX_QPATH];
306 	FILE	*f;
307 
308 	if (Cmd_Argc() != 2)
309 	{
310 		Con_Printf ("map <levelname> : continue game on a new level\n");
311 		return;
312 	}
313 	strcpy (level, Cmd_Argv(1));
314 
315 #if 0
316 	if (!strcmp (level, "e1m8"))
317 	{	// QuakeWorld can't go to e1m8
318 		SV_BroadcastPrintf (PRINT_HIGH, "can't go to low grav level in QuakeWorld...\n");
319 		strcpy (level, "e1m5");
320 	}
321 #endif
322 
323 	// check to make sure the level exists
324 	sprintf (expanded, "maps/%s.bsp", level);
325 	COM_FOpenFile (expanded, &f);
326 	if (!f)
327 	{
328 		Con_Printf ("Can't find %s\n", expanded);
329 		return;
330 	}
331 	fclose (f);
332 
333 	SV_BroadcastCommand ("changing\n");
334 	SV_SendMessagesToAll ();
335 
336 	SV_SpawnServer (level);
337 
338 	SV_BroadcastCommand ("reconnect\n");
339 }
340 
341 
342 /*
343 ==================
344 SV_Kick_f
345 
346 Kick a user off of the server
347 ==================
348 */
SV_Kick_f(void)349 void SV_Kick_f (void)
350 {
351 	int			i;
352 	client_t	*cl;
353 	int			uid;
354 
355 	uid = atoi(Cmd_Argv(1));
356 
357 	for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
358 	{
359 		if (!cl->state)
360 			continue;
361 		if (cl->userid == uid)
362 		{
363 			SV_BroadcastPrintf (PRINT_HIGH, "%s was kicked\n", cl->name);
364 			// print directly, because the dropped client won't get the
365 			// SV_BroadcastPrintf message
366 			SV_ClientPrintf (cl, PRINT_HIGH, "You were kicked from the game\n");
367 			SV_DropClient (cl);
368 			return;
369 		}
370 	}
371 
372 	Con_Printf ("Couldn't find user number %i\n", uid);
373 }
374 
375 
376 /*
377 ================
378 SV_Status_f
379 ================
380 */
SV_Status_f(void)381 void SV_Status_f (void)
382 {
383 	int			i, j, l;
384 	client_t	*cl;
385 	float		cpu, avg, pak;
386 	char		*s;
387 
388 
389 	cpu = (svs.stats.latched_active+svs.stats.latched_idle);
390 	if (cpu)
391 		cpu = 100*svs.stats.latched_active/cpu;
392 	avg = 1000*svs.stats.latched_active / STATFRAMES;
393 	pak = (float)svs.stats.latched_packets/ STATFRAMES;
394 
395 	Con_Printf ("net address      : %s\n",NET_AdrToString (net_local_adr));
396 	Con_Printf ("cpu utilization  : %3i%%\n",(int)cpu);
397 	Con_Printf ("avg response time: %i ms\n",(int)avg);
398 	Con_Printf ("packets/frame    : %5.2f (%d)\n", pak, num_prstr);
399 
400 // min fps lat drp
401 	if (sv_redirected != RD_NONE) {
402 		// most remote clients are 40 columns
403 		//           0123456789012345678901234567890123456789
404 		Con_Printf ("name               userid frags\n");
405         Con_Printf ("  address          rate ping drop\n");
406 		Con_Printf ("  ---------------- ---- ---- -----\n");
407 		for (i=0,cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++)
408 		{
409 			if (!cl->state)
410 				continue;
411 
412 			Con_Printf ("%-16.16s  ", cl->name);
413 
414 			Con_Printf ("%6i %5i", cl->userid, (int)cl->edict->v.frags);
415 			if (cl->spectator)
416 				Con_Printf(" (s)\n");
417 			else
418 				Con_Printf("\n");
419 
420 			s = NET_BaseAdrToString ( cl->netchan.remote_address);
421 			Con_Printf ("  %-16.16s", s);
422 			if (cl->state == cs_connected)
423 			{
424 				Con_Printf ("CONNECTING\n");
425 				continue;
426 			}
427 			if (cl->state == cs_zombie)
428 			{
429 				Con_Printf ("ZOMBIE\n");
430 				continue;
431 			}
432 			Con_Printf ("%4i %4i %5.2f\n"
433 				, (int)(1000*cl->netchan.frame_rate)
434 				, (int)SV_CalcPing (cl)
435 				, 100.0*cl->netchan.drop_count / cl->netchan.incoming_sequence);
436 		}
437 	} else {
438 		Con_Printf ("frags userid address         name            rate ping drop  qport\n");
439 		Con_Printf ("----- ------ --------------- --------------- ---- ---- ----- -----\n");
440 		for (i=0,cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++)
441 		{
442 			if (!cl->state)
443 				continue;
444 			Con_Printf ("%5i %6i ", (int)cl->edict->v.frags,  cl->userid);
445 
446 			s = NET_BaseAdrToString ( cl->netchan.remote_address);
447 			Con_Printf ("%s", s);
448 			l = 16 - strlen(s);
449 			for (j=0 ; j<l ; j++)
450 				Con_Printf (" ");
451 
452 			Con_Printf ("%s", cl->name);
453 			l = 16 - strlen(cl->name);
454 			for (j=0 ; j<l ; j++)
455 				Con_Printf (" ");
456 			if (cl->state == cs_connected)
457 			{
458 				Con_Printf ("CONNECTING\n");
459 				continue;
460 			}
461 			if (cl->state == cs_zombie)
462 			{
463 				Con_Printf ("ZOMBIE\n");
464 				continue;
465 			}
466 			Con_Printf ("%4i %4i %3.1f %4i"
467 				, (int)(1000*cl->netchan.frame_rate)
468 				, (int)SV_CalcPing (cl)
469 				, 100.0*cl->netchan.drop_count / cl->netchan.incoming_sequence
470 				, cl->netchan.qport);
471 			if (cl->spectator)
472 				Con_Printf(" (s)\n");
473 			else
474 				Con_Printf("\n");
475 
476 
477 		}
478 	}
479 	Con_Printf ("\n");
480 }
481 
482 /*
483 ==================
484 SV_ConSay_f
485 ==================
486 */
SV_ConSay_f(void)487 void SV_ConSay_f(void)
488 {
489 	client_t *client;
490 	int		j;
491 	char	*p;
492 	char	text[1024];
493 
494 	if (Cmd_Argc () < 2)
495 		return;
496 
497 	Q_strcpy (text, "console: ");
498 	p = Cmd_Args();
499 
500 	if (*p == '"')
501 	{
502 		p++;
503 		p[Q_strlen(p)-1] = 0;
504 	}
505 
506 	Q_strcat(text, p);
507 
508 	for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++)
509 	{
510 		if (client->state != cs_spawned)
511 			continue;
512 		SV_ClientPrintf(client, PRINT_CHAT, "%s\n", text);
513 	}
514 }
515 
516 
517 /*
518 ==================
519 SV_Heartbeat_f
520 ==================
521 */
SV_Heartbeat_f(void)522 void SV_Heartbeat_f (void)
523 {
524 	svs.last_heartbeat = -9999;
525 }
526 
SV_SendServerInfoChange(char * key,char * value)527 void SV_SendServerInfoChange(char *key, char *value)
528 {
529 	if (!sv.state)
530 		return;
531 
532 	MSG_WriteByte (&sv.reliable_datagram, svc_serverinfo);
533 	MSG_WriteString (&sv.reliable_datagram, key);
534 	MSG_WriteString (&sv.reliable_datagram, value);
535 }
536 
537 /*
538 ===========
539 SV_Serverinfo_f
540 
541   Examine or change the serverinfo string
542 ===========
543 */
544 char *CopyString(char *s);
SV_Serverinfo_f(void)545 void SV_Serverinfo_f (void)
546 {
547 	cvar_t	*var;
548 
549 	if (Cmd_Argc() == 1)
550 	{
551 		Con_Printf ("Server info settings:\n");
552 		Info_Print (svs.info);
553 		return;
554 	}
555 
556 	if (Cmd_Argc() != 3)
557 	{
558 		Con_Printf ("usage: serverinfo [ <key> <value> ]\n");
559 		return;
560 	}
561 
562 	if (Cmd_Argv(1)[0] == '*')
563 	{
564 		Con_Printf ("Star variables cannot be changed.\n");
565 		return;
566 	}
567 	Info_SetValueForKey (svs.info, Cmd_Argv(1), Cmd_Argv(2), MAX_SERVERINFO_STRING);
568 
569 	// if this is a cvar, change it too
570 	var = Cvar_FindVar (Cmd_Argv(1));
571 	if (var)
572 	{
573 		Z_Free (var->string);	// free the old value string
574 		var->string = CopyString (Cmd_Argv(2));
575 		var->value = Q_atof (var->string);
576 	}
577 
578 	SV_SendServerInfoChange(Cmd_Argv(1), Cmd_Argv(2));
579 }
580 
581 
582 /*
583 ===========
584 SV_Serverinfo_f
585 
586   Examine or change the serverinfo string
587 ===========
588 */
589 char *CopyString(char *s);
SV_Localinfo_f(void)590 void SV_Localinfo_f (void)
591 {
592 	if (Cmd_Argc() == 1)
593 	{
594 		Con_Printf ("Local info settings:\n");
595 		Info_Print (localinfo);
596 		return;
597 	}
598 
599 	if (Cmd_Argc() != 3)
600 	{
601 		Con_Printf ("usage: localinfo [ <key> <value> ]\n");
602 		return;
603 	}
604 
605 	if (Cmd_Argv(1)[0] == '*')
606 	{
607 		Con_Printf ("Star variables cannot be changed.\n");
608 		return;
609 	}
610 	Info_SetValueForKey (localinfo, Cmd_Argv(1), Cmd_Argv(2), MAX_LOCALINFO_STRING);
611 }
612 
613 
614 /*
615 ===========
616 SV_User_f
617 
618 Examine a users info strings
619 ===========
620 */
SV_User_f(void)621 void SV_User_f (void)
622 {
623 	if (Cmd_Argc() != 2)
624 	{
625 		Con_Printf ("Usage: info <userid>\n");
626 		return;
627 	}
628 
629 	if (!SV_SetPlayer ())
630 		return;
631 
632 	Info_Print (host_client->userinfo);
633 }
634 
635 /*
636 ================
637 SV_Gamedir
638 
639 Sets the fake *gamedir to a different directory.
640 ================
641 */
SV_Gamedir(void)642 void SV_Gamedir (void)
643 {
644 	char			*dir;
645 
646 	if (Cmd_Argc() == 1)
647 	{
648 		Con_Printf ("Current *gamedir: %s\n", Info_ValueForKey (svs.info, "*gamedir"));
649 		return;
650 	}
651 
652 	if (Cmd_Argc() != 2)
653 	{
654 		Con_Printf ("Usage: sv_gamedir <newgamedir>\n");
655 		return;
656 	}
657 
658 	dir = Cmd_Argv(1);
659 
660 	if (strstr(dir, "..") || strstr(dir, "/")
661 		|| strstr(dir, "\\") || strstr(dir, ":") )
662 	{
663 		Con_Printf ("*Gamedir should be a single filename, not a path\n");
664 		return;
665 	}
666 
667 	Info_SetValueForStarKey (svs.info, "*gamedir", dir, MAX_SERVERINFO_STRING);
668 }
669 
670 /*
671 ================
672 SV_Floodport_f
673 
674 Sets the gamedir and path to a different directory.
675 ================
676 */
677 
SV_Floodprot_f(void)678 void SV_Floodprot_f (void)
679 {
680 	int arg1, arg2, arg3;
681 
682 	if (Cmd_Argc() == 1)
683 	{
684 		if (fp_messages) {
685 			Con_Printf ("Current floodprot settings: \nAfter %d msgs per %d seconds, silence for %d seconds\n",
686 				fp_messages, fp_persecond, fp_secondsdead);
687 			return;
688 		} else
689 			Con_Printf ("No floodprots enabled.\n");
690 	}
691 
692 	if (Cmd_Argc() != 4)
693 	{
694 		Con_Printf ("Usage: floodprot <# of messages> <per # of seconds> <seconds to silence>\n");
695 		Con_Printf ("Use floodprotmsg to set a custom message to say to the flooder.\n");
696 		return;
697 	}
698 
699 	arg1 = atoi(Cmd_Argv(1));
700 	arg2 = atoi(Cmd_Argv(2));
701 	arg3 = atoi(Cmd_Argv(3));
702 
703 	if (arg1<=0 || arg2 <= 0 || arg3<=0) {
704 		Con_Printf ("All values must be positive numbers\n");
705 		return;
706 	}
707 
708 	if (arg1 > 10) {
709 		Con_Printf ("Can only track up to 10 messages.\n");
710 		return;
711 	}
712 
713 	fp_messages	= arg1;
714 	fp_persecond = arg2;
715 	fp_secondsdead = arg3;
716 }
717 
SV_Floodprotmsg_f(void)718 void SV_Floodprotmsg_f (void)
719 {
720 	if (Cmd_Argc() == 1) {
721 		Con_Printf("Current msg: %s\n", fp_msg);
722 		return;
723 	} else if (Cmd_Argc() != 2) {
724 		Con_Printf("Usage: floodprotmsg \"<message>\"\n");
725 		return;
726 	}
727 	sprintf(fp_msg, "%s", Cmd_Argv(1));
728 }
729 
730 /*
731 ================
732 SV_Gamedir_f
733 
734 Sets the gamedir and path to a different directory.
735 ================
736 */
737 char	gamedirfile[MAX_OSPATH];
SV_Gamedir_f(void)738 void SV_Gamedir_f (void)
739 {
740 	char			*dir;
741 
742 	if (Cmd_Argc() == 1)
743 	{
744 		Con_Printf ("Current gamedir: %s\n", com_gamedir);
745 		return;
746 	}
747 
748 	if (Cmd_Argc() != 2)
749 	{
750 		Con_Printf ("Usage: gamedir <newdir>\n");
751 		return;
752 	}
753 
754 	dir = Cmd_Argv(1);
755 
756 	if (strstr(dir, "..") || strstr(dir, "/")
757 		|| strstr(dir, "\\") || strstr(dir, ":") )
758 	{
759 		Con_Printf ("Gamedir should be a single filename, not a path\n");
760 		return;
761 	}
762 
763 	COM_Gamedir (dir);
764 	Info_SetValueForStarKey (svs.info, "*gamedir", dir, MAX_SERVERINFO_STRING);
765 }
766 
767 /*
768 ================
769 SV_Snap
770 ================
771 */
SV_Snap(int uid)772 void SV_Snap (int uid)
773 {
774 	client_t *cl;
775 	char		pcxname[80];
776 	char		checkname[MAX_OSPATH];
777 	int			i;
778 
779 	for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
780 	{
781 		if (!cl->state)
782 			continue;
783 		if (cl->userid == uid)
784 			break;
785 	}
786 	if (i >= MAX_CLIENTS) {
787 		Con_Printf ("userid not found\n");
788 		return;
789 	}
790 
791 	sprintf(pcxname, "%d-00.pcx", uid);
792 
793 	sprintf(checkname, "%s/snap", gamedirfile);
794 	Sys_mkdir(gamedirfile);
795 	Sys_mkdir(checkname);
796 
797 	for (i=0 ; i<=99 ; i++)
798 	{
799 		pcxname[strlen(pcxname) - 6] = i/10 + '0';
800 		pcxname[strlen(pcxname) - 5] = i%10 + '0';
801 		sprintf (checkname, "%s/snap/%s", gamedirfile, pcxname);
802 		if (Sys_FileTime(checkname) == -1)
803 			break;	// file doesn't exist
804 	}
805 	if (i==100)
806 	{
807 		Con_Printf ("Snap: Couldn't create a file, clean some out.\n");
808 		return;
809 	}
810 	strcpy(cl->uploadfn, checkname);
811 
812 	memcpy(&cl->snap_from, &net_from, sizeof(net_from));
813 	if (sv_redirected != RD_NONE)
814 		cl->remote_snap = true;
815 	else
816 		cl->remote_snap = false;
817 
818 	ClientReliableWrite_Begin (cl, svc_stufftext, 24);
819 	ClientReliableWrite_String (cl, "cmd snap");
820 	Con_Printf ("Requesting snap from user %d...\n", uid);
821 }
822 
823 /*
824 ================
825 SV_Snap_f
826 ================
827 */
SV_Snap_f(void)828 void SV_Snap_f (void)
829 {
830 	int			uid;
831 
832 	if (Cmd_Argc() != 2)
833 	{
834 		Con_Printf ("Usage:  snap <userid>\n");
835 		return;
836 	}
837 
838 	uid = atoi(Cmd_Argv(1));
839 
840 	SV_Snap(uid);
841 }
842 
843 /*
844 ================
845 SV_Snap
846 ================
847 */
SV_SnapAll_f(void)848 void SV_SnapAll_f (void)
849 {
850 	client_t *cl;
851 	int			i;
852 
853 	for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++)
854 	{
855 		if (cl->state < cs_connected || cl->spectator)
856 			continue;
857 		SV_Snap(cl->userid);
858 	}
859 }
860 
861 /*
862 ==================
863 SV_InitOperatorCommands
864 ==================
865 */
SV_InitOperatorCommands(void)866 void SV_InitOperatorCommands (void)
867 {
868 	if (COM_CheckParm ("-cheats"))
869 	{
870 		sv_allow_cheats = true;
871 		Info_SetValueForStarKey (svs.info, "*cheats", "ON", MAX_SERVERINFO_STRING);
872 	}
873 
874 	Cmd_AddCommand ("logfile", SV_Logfile_f);
875 	Cmd_AddCommand ("fraglogfile", SV_Fraglogfile_f);
876 
877 	Cmd_AddCommand ("snap", SV_Snap_f);
878 	Cmd_AddCommand ("snapall", SV_SnapAll_f);
879 	Cmd_AddCommand ("kick", SV_Kick_f);
880 	Cmd_AddCommand ("status", SV_Status_f);
881 
882 	Cmd_AddCommand ("map", SV_Map_f);
883 	Cmd_AddCommand ("setmaster", SV_SetMaster_f);
884 
885 	Cmd_AddCommand ("say", SV_ConSay_f);
886 	Cmd_AddCommand ("heartbeat", SV_Heartbeat_f);
887 	Cmd_AddCommand ("quit", SV_Quit_f);
888 	Cmd_AddCommand ("god", SV_God_f);
889 	Cmd_AddCommand ("give", SV_Give_f);
890 	Cmd_AddCommand ("noclip", SV_Noclip_f);
891 	Cmd_AddCommand ("serverinfo", SV_Serverinfo_f);
892 	Cmd_AddCommand ("localinfo", SV_Localinfo_f);
893 	Cmd_AddCommand ("user", SV_User_f);
894 	Cmd_AddCommand ("gamedir", SV_Gamedir_f);
895 	Cmd_AddCommand ("sv_gamedir", SV_Gamedir);
896 	Cmd_AddCommand ("floodprot", SV_Floodprot_f);
897 	Cmd_AddCommand ("floodprotmsg", SV_Floodprotmsg_f);
898 
899 	cl_warncmd.value = 1;
900 }
901