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