|
|
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.