Annotation of quake2/server/sv_ccmds.c, revision 1.1.1.3

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.