|
|
1.1 root 1:
2: #include "server.h"
3:
4: /*
5: ===============================================================================
6:
7: OPERATOR CONSOLE ONLY COMMANDS
8:
9: These commands can only be entered from stdin or by a remote operator datagram
10: ===============================================================================
11: */
12:
13: /*
14: ====================
15: SV_SetMaster_f
16:
17: Specify a list of master servers
18: ====================
19: */
20: void SV_SetMaster_f (void)
21: {
22: int i, slot;
23:
24: // only dedicated servers send heartbeats
25: if (!dedicated->value)
26: {
27: Com_Printf ("Only dedicated servers use masters.\n");
28: return;
29: }
30:
31: // make sure the server is listed public
32: Cvar_Set ("public", "1");
33:
34: for (i=1 ; i<MAX_MASTERS ; i++)
35: memset (&master_adr[i], 0, sizeof(master_adr[i]));
36:
37: slot = 1; // slot 0 will always contain the id master
38: for (i=1 ; i<Cmd_Argc() ; i++)
39: {
40: if (slot == MAX_MASTERS)
41: break;
42:
43: if (!NET_StringToAdr (Cmd_Argv(i), &master_adr[i]))
44: {
45: Com_Printf ("Bad address: %s\n", Cmd_Argv(i));
46: continue;
47: }
48: if (master_adr[slot].port == 0)
49: master_adr[slot].port = BigShort (PORT_MASTER);
50:
51: Com_Printf ("Master server at %s\n", NET_AdrToString (master_adr[slot]));
52:
53: Com_Printf ("Sending a ping.\n");
54:
55: Netchan_OutOfBandPrint (NS_SERVER, master_adr[slot], "ping");
56:
57: slot++;
58: }
59:
60: svs.last_heartbeat = -9999999;
61: }
62:
63:
64:
65: /*
66: ==================
67: SV_SetPlayer
68:
69: Sets sv_client and sv_player to the player with idnum Cmd_Argv(1)
70: ==================
71: */
72: qboolean SV_SetPlayer (void)
73: {
74: client_t *cl;
75: int i;
76: int idnum;
77: char *s;
78:
79: if (Cmd_Argc() < 2)
80: return false;
81:
82: s = Cmd_Argv(1);
83:
84: // numeric values are just slot numbers
85: if (s[0] >= '0' && s[0] <= '9')
86: {
87: idnum = atoi(Cmd_Argv(1));
88: if (idnum < 0 || idnum >= maxclients->value)
89: {
90: Com_Printf ("Bad client slot: %i\n", idnum);
91: return false;
92: }
93:
94: sv_client = &svs.clients[idnum];
95: sv_player = sv_client->edict;
96: if (!sv_client->state)
97: {
98: Com_Printf ("Clinet %i is not active\n", idnum);
99: return false;
100: }
101: return true;
102: }
103:
104: // check for a name match
105: for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
106: {
107: if (!cl->state)
108: continue;
109: if (!strcmp(cl->name, s))
110: {
111: sv_client = cl;
112: sv_player = sv_client->edict;
113: return true;
114: }
115: }
116:
117: Com_Printf ("Userid %s is not on the server\n", s);
118: return false;
119: }
120:
121:
122: /*
123: ===============================================================================
124:
125: SAVEGAME FILES
126:
127: ===============================================================================
128: */
129:
130: /*
131: =====================
132: SV_WipeSavegame
133:
134: Delete save/<XXX>/
135: =====================
136: */
137: void SV_WipeSavegame (char *savename)
138: {
139: char name[MAX_OSPATH];
140: char *s;
141:
142: Com_sprintf (name, sizeof(name), "%s/save/%s/server.ssv", FS_Gamedir (), savename);
143: remove (name);
144: Com_sprintf (name, sizeof(name), "%s/save/%s/game.ssv", FS_Gamedir (), savename);
145: remove (name);
146:
147: Com_sprintf (name, sizeof(name), "%s/save/%s/*.sav", FS_Gamedir (), savename);
148: s = Sys_FindFirst( name, 0, 0 );
149: while (s)
150: {
151: remove (s);
152: s = Sys_FindNext( 0, 0 );
153: }
154: Sys_FindClose ();
155: Com_sprintf (name, sizeof(name), "%s/save/%s/*.sv2", FS_Gamedir (), savename);
156: s = Sys_FindFirst(name, 0, 0 );
157: while (s)
158: {
159: remove (s);
160: s = Sys_FindNext( 0, 0 );
161: }
162: Sys_FindClose ();
163: }
164:
165:
166: /*
167: ================
168: CopyFile
169: ================
170: */
171: void CopyFile (char *src, char *dst)
172: {
173: FILE *f1, *f2;
174: int l;
175: byte buffer[65536];
176:
177: Com_DPrintf ("CopyFile (%s, %s)\n", src, dst);
178:
179: f1 = fopen (src, "rb");
180: if (!f1)
181: return;
182: f2 = fopen (dst, "wb");
183: if (!f2)
184: {
185: fclose (f1);
186: return;
187: }
188:
189: while (1)
190: {
191: l = fread (buffer, 1, sizeof(buffer), f1);
192: if (!l)
193: break;
194: fwrite (buffer, 1, l, f2);
195: }
196:
197: fclose (f1);
198: fclose (f2);
199: }
200:
201:
202: /*
203: ================
204: SV_CopySaveGame
205: ================
206: */
207: void SV_CopySaveGame (char *src, char *dst)
208: {
209: char name[MAX_OSPATH], name2[MAX_OSPATH];
210: int l, len;
211: char *found;
212:
213: SV_WipeSavegame (dst);
214:
215: // copy the savegame over
216: Com_sprintf (name, sizeof(name), "%s/save/%s/server.ssv", FS_Gamedir(), src);
217: Com_sprintf (name2, sizeof(name2), "%s/save/%s/server.ssv", FS_Gamedir(), dst);
218: FS_CreatePath (name2);
219: CopyFile (name, name2);
220:
221: Com_sprintf (name, sizeof(name), "%s/save/%s/game.ssv", FS_Gamedir(), src);
222: Com_sprintf (name2, sizeof(name2), "%s/save/%s/game.ssv", FS_Gamedir(), dst);
223: CopyFile (name, name2);
224:
225: Com_sprintf (name, sizeof(name), "%s/save/%s/", FS_Gamedir(), src);
226: len = strlen(name);
227: Com_sprintf (name, sizeof(name), "%s/save/%s/*.sav", FS_Gamedir(), src);
228: found = Sys_FindFirst(name, 0, 0 );
229: while (found)
230: {
231: strcpy (name+len, found+len);
232:
233: Com_sprintf (name2, sizeof(name2), "%s/save/%s/%s", FS_Gamedir(), dst, found+len);
234: CopyFile (name, name2);
235:
236: // change sav to sv2
237: l = strlen(name);
238: strcpy (name+l-3, "sv2");
239: l = strlen(name2);
240: strcpy (name2+l-3, "sv2");
241: CopyFile (name, name2);
242:
243: found = Sys_FindNext( 0, 0 );
244: }
245: Sys_FindClose ();
246: }
247:
248:
249: /*
250: ==============
251: SV_WriteLevelFile
252:
253: ==============
254: */
255: void SV_WriteLevelFile (void)
256: {
257: char name[MAX_OSPATH];
258: FILE *f;
259:
260: Com_sprintf (name, sizeof(name), "%s/save/current/%s.sv2", FS_Gamedir(), sv.name);
261: f = fopen(name, "wb");
262: if (!f)
263: {
264: Com_Printf ("Failed to open %s\n", name);
265: return;
266: }
267: fwrite (sv.configstrings, sizeof(sv.configstrings), 1, f);
268: CM_WritePortalState (f);
269: fclose (f);
270:
271: Com_sprintf (name, sizeof(name), "%s/save/current/%s.sav", FS_Gamedir(), sv.name);
272: ge->WriteLevel (name);
273: }
274:
275: /*
276: ==============
277: SV_ReadLevelFile
278:
279: ==============
280: */
281: void SV_ReadLevelFile (void)
282: {
283: char name[MAX_OSPATH];
284: FILE *f;
285:
286: Com_sprintf (name, sizeof(name), "%s/save/current/%s.sv2", FS_Gamedir(), sv.name);
287: f = fopen(name, "rb");
288: if (!f)
289: {
290: Com_Printf ("Failed to open %s\n", name);
291: return;
292: }
293: FS_Read (sv.configstrings, sizeof(sv.configstrings), f);
294: CM_ReadPortalState (f);
295: fclose (f);
296:
297: Com_sprintf (name, sizeof(name), "%s/save/current/%s.sav", FS_Gamedir(), sv.name);
298: ge->ReadLevel (name);
299: }
300:
301: /*
302: ==============
303: SV_WriteServerFile
304:
305: ==============
306: */
307: void SV_WriteServerFile (qboolean autosave)
308: {
309: FILE *f;
310: cvar_t *var;
311: char name[MAX_OSPATH], string[128];
312: char comment[32];
313: time_t aclock;
314: struct tm *newtime;
315:
316: Com_sprintf (name, sizeof(name), "%s/save/current/server.ssv", FS_Gamedir());
317: f = fopen (name, "wb");
318: if (!f)
319: {
320: Com_Printf ("Couldn't write %s\n", name);
321: return;
322: }
323: // write the comment field
324: memset (comment, 0, sizeof(comment));
325:
326: if (!autosave)
327: {
328: time (&aclock);
329: newtime = localtime (&aclock);
330: Com_sprintf (comment,sizeof(comment), "%2i:%i%i %2i/%2i ", newtime->tm_hour
331: , newtime->tm_min/10, newtime->tm_min%10,
332: newtime->tm_mon+1, newtime->tm_mday);
333: strncat (comment, sv.configstrings[CS_NAME], sizeof(comment)-1-strlen(comment) );
334: }
335: else
336: { // autosaved
337: Com_sprintf (comment, sizeof(comment), "ENTERING %s", sv.configstrings[CS_NAME]);
338: }
339:
340: fwrite (comment, 1, sizeof(comment), f);
341:
342: // write the mapcmd
343: fwrite (svs.mapcmd, 1, sizeof(svs.mapcmd), f);
344:
345: // write all CVAR_LATCH cvars
346: // these will be things like coop, skill, deathmatch, etc
347: for (var = cvar_vars ; var ; var=var->next)
348: {
349: if (!(var->flags & CVAR_LATCH))
350: continue;
351: if (strlen(var->name) >= sizeof(name)-1
352: || strlen(var->string) >= sizeof(string)-1)
353: {
354: Com_Printf ("Cvar too long: %s = %s\n", var->name, var->string);
355: continue;
356: }
357: memset (name, 0, sizeof(name));
358: memset (string, 0, sizeof(string));
359: strcpy (name, var->name);
360: strcpy (string, var->string);
361: fwrite (name, 1, sizeof(name), f);
362: fwrite (string, 1, sizeof(string), f);
363: }
364:
365: fclose (f);
366:
367: // write game state
368: Com_sprintf (name, sizeof(name), "%s/save/current/game.ssv", FS_Gamedir());
369: ge->WriteGame (name, autosave);
370: }
371:
372: /*
373: ==============
374: SV_ReadServerFile
375:
376: ==============
377: */
378: void SV_ReadServerFile (void)
379: {
380: FILE *f;
381: char name[MAX_OSPATH], string[128];
382: char comment[32];
383: char mapcmd[MAX_TOKEN_CHARS];
384:
385: Com_sprintf (name, sizeof(name), "%s/save/current/server.ssv", FS_Gamedir());
386: f = fopen (name, "rb");
387: if (!f)
388: {
389: Com_Printf ("Couldn't read %s\n", name);
390: return;
391: }
392: // read the comment field
393: FS_Read (comment, sizeof(comment), f);
394:
395: // read the mapcmd
396: FS_Read (mapcmd, sizeof(mapcmd), f);
397:
398: // read all CVAR_LATCH cvars
399: // these will be things like coop, skill, deathmatch, etc
400: while (1)
401: {
402: if (!fread (name, 1, sizeof(name), f))
403: break;
404: FS_Read (string, sizeof(string), f);
405: Com_DPrintf ("Set %s = %s\n", name, string);
406: Cvar_ForceSet (name, string);
407: }
408:
409: fclose (f);
410:
411: // start a new game fresh with new cvars
412: SV_InitGame ();
413:
414: strcpy (svs.mapcmd, mapcmd);
415:
416: // read game state
417: Com_sprintf (name, sizeof(name), "%s/save/current/game.ssv", FS_Gamedir());
418: ge->ReadGame (name);
419: }
420:
421:
422: //=========================================================
423:
424:
425:
426:
427: /*
428: ==================
429: SV_DemoMap_f
430:
431: Puts the server in demo mode on a specific map/cinematic
432: ==================
433: */
434: void SV_DemoMap_f (void)
435: {
436: SV_Map (true, Cmd_Argv(1), false );
437: }
438:
439: /*
440: ==================
441: SV_GameMap_f
442:
443: Saves the state of the map just being exited and goes to a new map.
444:
445: If the initial character of the map string is '*', the next map is
446: in a new unit, so the current savegame directory is cleared of
447: map files.
448:
449: Example:
450:
451: *inter.cin+jail
452:
453: Clears the archived maps, plays the inter.cin cinematic, then
454: goes to map jail.bsp.
455: ==================
456: */
457: void SV_GameMap_f (void)
458: {
459: char *map;
460: int i;
461: client_t *cl;
462: qboolean *savedInuse;
463:
464: if (Cmd_Argc() != 2)
465: {
466: Com_Printf ("USAGE: gamemap <map>\n");
467: return;
468: }
469:
470: FS_CreatePath (va("%s/save/current/", FS_Gamedir()));
471:
472: // check for clearing the current savegame
473: map = Cmd_Argv(1);
474: if (map[0] == '*')
475: {
476: // wipe all the *.sav files
477: SV_WipeSavegame ("current");
478: }
479: else
480: { // save the map just exited
481: if (sv.state == ss_game)
482: {
483: // clear all the client inuse flags before saving so that
484: // when the level is re-entered, the clients will spawn
485: // at spawn points instead of occupying body shells
486: savedInuse = malloc(maxclients->value * sizeof(qboolean));
487: for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
488: {
489: savedInuse[i] = cl->edict->inuse;
490: cl->edict->inuse = false;
491: }
492:
493: SV_WriteLevelFile ();
494:
495: // we must restore these for clients to transfer over correctly
496: for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
497: cl->edict->inuse = savedInuse[i];
498: free (savedInuse);
499: }
500: }
501:
502: // start up the next map
503: SV_Map (false, Cmd_Argv(1), false );
504:
505: // archive server state
506: strncpy (svs.mapcmd, Cmd_Argv(1), sizeof(svs.mapcmd)-1);
507:
508: // copy off the level to the autosave slot
509: if (!dedicated->value)
510: {
511: SV_WriteServerFile (true);
512: SV_CopySaveGame ("current", "save0");
513: }
514: }
515:
516: /*
517: ==================
518: SV_Map_f
519:
520: Goes directly to a given map without any savegame archiving.
521: For development work
522: ==================
523: */
524: void SV_Map_f (void)
525: {
526: char *map;
527: char expanded[MAX_QPATH];
528:
529: // if not a pcx, demo, or cinematic, check to make sure the level exists
530: map = Cmd_Argv(1);
531: if (!strstr (map, "."))
532: {
533: Com_sprintf (expanded, sizeof(expanded), "maps/%s.bsp", map);
534: if (FS_LoadFile (expanded, NULL) == -1)
535: {
536: Com_Printf ("Can't find %s\n", expanded);
537: return;
538: }
539: }
540:
541: sv.state = ss_dead; // don't save current level when changing
542: SV_WipeSavegame("current");
543: SV_GameMap_f ();
544: }
545:
546: /*
547: =====================================================================
548:
549: SAVEGAMES
550:
551: =====================================================================
552: */
553:
554:
555: /*
556: ==============
557: SV_Loadgame_f
558:
559: ==============
560: */
561: void SV_Loadgame_f (void)
562: {
563: char name[MAX_OSPATH];
564: FILE *f;
565: char *dir;
566:
567: if (Cmd_Argc() != 2)
568: {
569: Com_Printf ("USAGE: loadgame <directory>\n");
570: return;
571: }
572:
573: Com_Printf ("Loading game...\n");
574:
575: dir = Cmd_Argv(1);
576: if (strstr (dir, "..") || strstr (dir, "/") || strstr (dir, "\\") )
577: {
578: Com_Printf ("Bad savedir.\n");
579: }
580:
581: // make sure the server.ssv file exists
582: Com_sprintf (name, sizeof(name), "%s/save/%s/server.ssv", FS_Gamedir(), Cmd_Argv(1));
583: f = fopen (name, "rb");
584: if (!f)
585: {
586: Com_Printf ("No such savegame: %s\n", name);
587: return;
588: }
589: fclose (f);
590:
591: SV_CopySaveGame (Cmd_Argv(1), "current");
592:
593: SV_ReadServerFile ();
594:
595: // go to the map
596: sv.state = ss_dead; // don't save current level when changing
597: SV_Map (false, svs.mapcmd, true);
598: }
599:
600:
601:
602: /*
603: ==============
604: SV_Savegame_f
605:
606: ==============
607: */
608: void SV_Savegame_f (void)
609: {
610: char *dir;
611:
612: if (sv.state != ss_game)
613: {
614: Com_Printf ("You must be in a game to save.\n");
615: return;
616: }
617:
618: if (Cmd_Argc() != 2)
619: {
620: Com_Printf ("USAGE: savegame <directory>\n");
621: return;
622: }
623:
624: if (Cvar_VariableValue("deathmatch"))
625: {
626: Com_Printf ("Can't savegame in a deathmatch\n");
627: return;
628: }
629:
630: if (!strcmp (Cmd_Argv(1), "current"))
631: {
632: Com_Printf ("Can't save to 'current'\n");
633: return;
634: }
635:
636: if (maxclients->value == 1 && svs.clients[0].edict->client->ps.stats[STAT_HEALTH] <= 0)
637: {
638: Com_Printf ("\nCan't savegame while dead!\n");
639: return;
640: }
641:
642: dir = Cmd_Argv(1);
643: if (strstr (dir, "..") || strstr (dir, "/") || strstr (dir, "\\") )
644: {
645: Com_Printf ("Bad savedir.\n");
646: }
647:
648: Com_Printf ("Saving game...\n");
649:
650: // archive current level, including all client edicts.
651: // when the level is reloaded, they will be shells awaiting
652: // a connecting client
653: SV_WriteLevelFile ();
654:
655: // save server state
656: SV_WriteServerFile (false);
657:
658: // copy it off
659: SV_CopySaveGame ("current", dir);
660:
661: Com_Printf ("Done.\n");
662: }
663:
664: //===============================================================
665:
666: /*
667: ==================
668: SV_Kick_f
669:
670: Kick a user off of the server
671: ==================
672: */
673: void SV_Kick_f (void)
674: {
675: if (!svs.initialized)
676: {
677: Com_Printf ("No server running.\n");
678: return;
679: }
680:
681: if (Cmd_Argc() != 2)
682: {
683: Com_Printf ("Usage: kick <userid>\n");
684: return;
685: }
686:
687: if (!SV_SetPlayer ())
688: return;
689:
690: SV_BroadcastPrintf (PRINT_HIGH, "%s was kicked\n", sv_client->name);
691: // print directly, because the dropped client won't get the
692: // SV_BroadcastPrintf message
693: SV_ClientPrintf (sv_client, PRINT_HIGH, "You were kicked from the game\n");
694: SV_DropClient (sv_client);
695: sv_client->lastmessage = svs.realtime; // min case there is a funny zombie
696: }
697:
698:
699: /*
700: ================
701: SV_Status_f
702: ================
703: */
704: void SV_Status_f (void)
705: {
706: int i, j, l;
707: client_t *cl;
708: char *s;
709: int ping;
710: if (!svs.clients)
711: {
712: Com_Printf ("No server running.\n");
713: return;
714: }
715: Com_Printf ("map : %s\n", sv.name);
716:
717: Com_Printf ("num score ping name lastmsg address qport \n");
718: Com_Printf ("--- ----- ---- --------------- ------- --------------------- ------\n");
719: for (i=0,cl=svs.clients ; i<maxclients->value; i++,cl++)
720: {
721: if (!cl->state)
722: continue;
723: Com_Printf ("%3i ", i);
724: Com_Printf ("%5i ", cl->edict->client->ps.stats[STAT_FRAGS]);
725:
726: if (cl->state == cs_connected)
727: Com_Printf ("CNCT ");
728: else if (cl->state == cs_zombie)
729: Com_Printf ("ZMBI ");
730: else
731: {
732: ping = cl->ping < 9999 ? cl->ping : 9999;
733: Com_Printf ("%4i ", ping);
734: }
735:
736: Com_Printf ("%s", cl->name);
737: l = 16 - strlen(cl->name);
738: for (j=0 ; j<l ; j++)
739: Com_Printf (" ");
740:
741: Com_Printf ("%7i ", svs.realtime - cl->lastmessage );
742:
743: s = NET_AdrToString ( cl->netchan.remote_address);
744: Com_Printf ("%s", s);
745: l = 22 - strlen(s);
746: for (j=0 ; j<l ; j++)
747: Com_Printf (" ");
748:
749: Com_Printf ("%5i", cl->netchan.qport);
750:
751: Com_Printf ("\n");
752: }
753: Com_Printf ("\n");
754: }
755:
756: /*
757: ==================
758: SV_ConSay_f
759: ==================
760: */
761: void SV_ConSay_f(void)
762: {
763: client_t *client;
764: int j;
765: char *p;
766: char text[1024];
767:
768: if (Cmd_Argc () < 2)
769: return;
770:
771: strcpy (text, "console: ");
772: p = Cmd_Args();
773:
774: if (*p == '"')
775: {
776: p++;
777: p[strlen(p)-1] = 0;
778: }
779:
780: strcat(text, p);
781:
782: for (j = 0, client = svs.clients; j < maxclients->value; j++, client++)
783: {
784: if (client->state != cs_spawned)
785: continue;
786: SV_ClientPrintf(client, PRINT_CHAT, "%s\n", text);
787: }
788: }
789:
790:
791: /*
792: ==================
793: SV_Heartbeat_f
794: ==================
795: */
796: void SV_Heartbeat_f (void)
797: {
798: svs.last_heartbeat = -9999999;
799: }
800:
801:
802: /*
803: ===========
804: SV_Serverinfo_f
805:
806: Examine or change the serverinfo string
807: ===========
808: */
809: void SV_Serverinfo_f (void)
810: {
811: Com_Printf ("Server info settings:\n");
812: Info_Print (Cvar_Serverinfo());
813: }
814:
815:
816: /*
817: ===========
818: SV_DumpUser_f
819:
820: Examine all a users info strings
821: ===========
822: */
823: void SV_DumpUser_f (void)
824: {
825: if (Cmd_Argc() != 2)
826: {
827: Com_Printf ("Usage: info <userid>\n");
828: return;
829: }
830:
831: if (!SV_SetPlayer ())
832: return;
833:
834: Com_Printf ("userinfo\n");
835: Com_Printf ("--------\n");
836: Info_Print (sv_client->userinfo);
837:
838: }
839:
840:
841: /*
842: ==============
843: SV_ServerRecord_f
844:
845: Begins server demo recording. Every entity and every message will be
846: recorded, but no playerinfo will be stored. Primarily for demo merging.
847: ==============
848: */
849: void SV_ServerRecord_f (void)
850: {
851: char name[MAX_OSPATH];
852: char buf_data[MAX_MSGLEN];
853: sizebuf_t buf;
854: int len;
855: int i;
856:
857: if (Cmd_Argc() != 2)
858: {
859: Com_Printf ("serverrecord <demoname>\n");
860: return;
861: }
862:
863: if (svs.demofile)
864: {
865: Com_Printf ("Already recording.\n");
866: return;
867: }
868:
869: if (sv.state != ss_game)
870: {
871: Com_Printf ("You must be in a level to record.\n");
872: return;
873: }
874:
875: //
876: // open the demo file
877: //
878: Com_sprintf (name, sizeof(name), "%s/demos/%s.dm2", FS_Gamedir(), Cmd_Argv(1));
879:
880: Com_Printf ("recording to %s.\n", name);
881: FS_CreatePath (name);
882: svs.demofile = fopen (name, "wb");
883: if (!svs.demofile)
884: {
885: Com_Printf ("ERROR: couldn't open.\n");
886: return;
887: }
888:
889: // setup a buffer to catch all multicasts
890: SZ_Init (&svs.demo_multicast, svs.demo_multicast_buf, sizeof(svs.demo_multicast_buf));
891:
892: //
893: // write a single giant fake message with all the startup info
894: //
895: SZ_Init (&buf, buf_data, sizeof(buf_data));
896:
897: for (i=0 ; i<MAX_CONFIGSTRINGS ; i++)
898: if (sv.configstrings[i][0])
899: {
900: MSG_WriteByte (&buf, svc_configstring);
901: MSG_WriteShort (&buf, i);
902: MSG_WriteString (&buf, sv.configstrings[i]);
903: }
904:
905: // write it to the demo file
906: Com_DPrintf ("signon message length: %i\n", buf.cursize);
907: len = LittleLong (buf.cursize);
908: fwrite (&len, 4, 1, svs.demofile);
909: fwrite (buf.data, buf.cursize, 1, svs.demofile);
910:
911: // the rest of the demo file will be individual frames
912: }
913:
914:
915: /*
916: ==============
917: SV_ServerStop_f
918:
919: Ends server demo recording
920: ==============
921: */
922: void SV_ServerStop_f (void)
923: {
924: if (!svs.demofile)
925: {
926: Com_Printf ("Not doing a serverrecord.\n");
927: return;
928: }
929: fclose (svs.demofile);
930: svs.demofile = NULL;
931: Com_Printf ("Recording completed.\n");
932: }
933:
934:
935: /*
936: ===============
937: SV_KillServer_f
938:
939: Kick everyone off, possibly in preparation for a new game
940:
941: ===============
942: */
943: void SV_KillServer_f (void)
944: {
945: if (!svs.initialized)
946: return;
947: SV_Shutdown ("Server was killed.\n", false);
948: NET_Config ( false ); // close network sockets
949: }
950:
951: /*
952: ===============
953: SV_ServerCommand_f
954:
955: Let the game dll handle a command
956: ===============
957: */
958: void SV_ServerCommand_f (void)
959: {
960: if (!ge)
961: {
962: Com_Printf ("No game loaded.\n");
963: return;
964: }
965:
966: ge->ServerCommand();
967: }
968:
969: //===========================================================
970:
971: /*
972: ==================
973: SV_InitOperatorCommands
974: ==================
975: */
976: void SV_InitOperatorCommands (void)
977: {
978: Cmd_AddCommand ("heartbeat", SV_Heartbeat_f);
979: Cmd_AddCommand ("kick", SV_Kick_f);
980: Cmd_AddCommand ("status", SV_Status_f);
981: Cmd_AddCommand ("serverinfo", SV_Serverinfo_f);
982: Cmd_AddCommand ("dumpuser", SV_DumpUser_f);
983:
984: Cmd_AddCommand ("map", SV_Map_f);
985: Cmd_AddCommand ("demomap", SV_DemoMap_f);
986: Cmd_AddCommand ("gamemap", SV_GameMap_f);
987: Cmd_AddCommand ("setmaster", SV_SetMaster_f);
988:
989: if ( dedicated->value )
990: Cmd_AddCommand ("say", SV_ConSay_f);
991:
992: Cmd_AddCommand ("serverrecord", SV_ServerRecord_f);
993: Cmd_AddCommand ("serverstop", SV_ServerStop_f);
994:
995: Cmd_AddCommand ("save", SV_Savegame_f);
996: Cmd_AddCommand ("load", SV_Loadgame_f);
997:
998: Cmd_AddCommand ("killserver", SV_KillServer_f);
999:
1000: Cmd_AddCommand ("sv", SV_ServerCommand_f);
1001: }
1002:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.