Annotation of quake2/server/sv_init.c, revision 1.1.1.4

1.1.1.4 ! 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: server_static_t        svs;                            // persistant server info
                     24: server_t               sv;                                     // local server
                     25: 
                     26: /*
                     27: ================
                     28: SV_FindIndex
                     29: 
                     30: ================
                     31: */
                     32: int SV_FindIndex (char *name, int start, int max, qboolean create)
                     33: {
                     34:        int             i;
                     35:        
                     36:        if (!name || !name[0])
                     37:                return 0;
                     38: 
                     39:        for (i=1 ; i<max && sv.configstrings[start+i][0] ; i++)
                     40:                if (!strcmp(sv.configstrings[start+i], name))
                     41:                        return i;
                     42: 
                     43:        if (!create)
                     44:                return 0;
                     45: 
                     46:        if (i == max)
                     47:                Com_Error (ERR_DROP, "*Index: overflow");
                     48: 
                     49:        strncpy (sv.configstrings[start+i], name, sizeof(sv.configstrings[i]));
                     50: 
                     51:        if (sv.state != ss_loading)
                     52:        {       // send the update to everyone
                     53:                SZ_Clear (&sv.multicast);
                     54:                MSG_WriteChar (&sv.multicast, svc_configstring);
                     55:                MSG_WriteShort (&sv.multicast, start+i);
                     56:                MSG_WriteString (&sv.multicast, name);
                     57:                SV_Multicast (vec3_origin, MULTICAST_ALL_R);
                     58:        }
                     59: 
                     60:        return i;
                     61: }
                     62: 
                     63: 
                     64: int SV_ModelIndex (char *name)
                     65: {
                     66:        return SV_FindIndex (name, CS_MODELS, MAX_MODELS, true);
                     67: }
                     68: 
                     69: int SV_SoundIndex (char *name)
                     70: {
                     71:        return SV_FindIndex (name, CS_SOUNDS, MAX_SOUNDS, true);
                     72: }
                     73: 
                     74: int SV_ImageIndex (char *name)
                     75: {
                     76:        return SV_FindIndex (name, CS_IMAGES, MAX_IMAGES, true);
                     77: }
                     78: 
                     79: 
                     80: /*
                     81: ================
                     82: SV_CreateBaseline
                     83: 
                     84: Entity baselines are used to compress the update messages
                     85: to the clients -- only the fields that differ from the
                     86: baseline will be transmitted
                     87: ================
                     88: */
                     89: void SV_CreateBaseline (void)
                     90: {
                     91:        edict_t                 *svent;
                     92:        int                             entnum; 
                     93: 
                     94:        for (entnum = 1; entnum < ge->num_edicts ; entnum++)
                     95:        {
                     96:                svent = EDICT_NUM(entnum);
                     97:                if (!svent->inuse)
                     98:                        continue;
                     99:                if (!svent->s.modelindex && !svent->s.sound && !svent->s.effects)
                    100:                        continue;
                    101:                svent->s.number = entnum;
                    102: 
                    103:                //
                    104:                // take current state as baseline
                    105:                //
                    106:                VectorCopy (svent->s.origin, svent->s.old_origin);
                    107:                sv.baselines[entnum] = svent->s;
                    108:        }
                    109: }
                    110: 
                    111: 
                    112: /*
                    113: =================
                    114: SV_CheckForSavegame
                    115: =================
                    116: */
                    117: void SV_CheckForSavegame (void)
                    118: {
                    119:        char            name[MAX_OSPATH];
                    120:        FILE            *f;
                    121:        int                     i;
                    122: 
                    123:        if (sv_noreload->value)
                    124:                return;
                    125: 
                    126:        if (Cvar_VariableValue ("deathmatch"))
                    127:                return;
                    128: 
                    129:        Com_sprintf (name, sizeof(name), "%s/save/current/%s.sav", FS_Gamedir(), sv.name);
                    130:        f = fopen (name, "rb");
                    131:        if (!f)
                    132:                return;         // no savegame
                    133: 
                    134:        fclose (f);
                    135: 
                    136:        SV_ClearWorld ();
                    137: 
                    138:        // get configstrings and areaportals
                    139:        SV_ReadLevelFile ();
                    140: 
                    141:        if (!sv.loadgame)
                    142:        {       // coming back to a level after being in a different
                    143:                // level, so run it for ten seconds
1.1.1.3   root      144: 
                    145:                // rlava2 was sending too many lightstyles, and overflowing the
                    146:                // reliable data. temporarily changing the server state to loading
                    147:                // prevents these from being passed down.
                    148:                server_state_t          previousState;          // PGM
                    149: 
                    150:                previousState = sv.state;                               // PGM
                    151:                sv.state = ss_loading;                                  // PGM
1.1       root      152:                for (i=0 ; i<100 ; i++)
                    153:                        ge->RunFrame ();
1.1.1.3   root      154: 
                    155:                sv.state = previousState;                               // PGM
1.1       root      156:        }
                    157: }
                    158: 
                    159: 
                    160: /*
                    161: ================
                    162: SV_SpawnServer
                    163: 
                    164: Change the server to a new map, taking all connected
                    165: clients along with it.
                    166: 
                    167: ================
                    168: */
                    169: void SV_SpawnServer (char *server, char *spawnpoint, server_state_t serverstate, qboolean attractloop, qboolean loadgame)
                    170: {
                    171:        int                     i;
                    172:        unsigned        checksum;
                    173: 
                    174:        if (attractloop)
                    175:                Cvar_Set ("paused", "0");
                    176: 
                    177:        Com_Printf ("------- Server Initialization -------\n");
                    178: 
                    179:        Com_DPrintf ("SpawnServer: %s\n",server);
                    180:        if (sv.demofile)
                    181:                fclose (sv.demofile);
                    182: 
                    183:        svs.spawncount++;               // any partially connected client will be
                    184:                                                        // restarted
                    185:        sv.state = ss_dead;
                    186:        Com_SetServerState (sv.state);
                    187: 
                    188:        // wipe the entire per-level structure
                    189:        memset (&sv, 0, sizeof(sv));
                    190:        svs.realtime = 0;
                    191:        sv.loadgame = loadgame;
                    192:        sv.attractloop = attractloop;
                    193: 
                    194:        // save name for levels that don't set message
                    195:        strcpy (sv.configstrings[CS_NAME], server);
1.1.1.3   root      196:        if (Cvar_VariableValue ("deathmatch"))
                    197:        {
                    198:                sprintf(sv.configstrings[CS_AIRACCEL], "%g", sv_airaccelerate->value);
                    199:                pm_airaccelerate = sv_airaccelerate->value;
                    200:        }
                    201:        else
                    202:        {
                    203:                strcpy(sv.configstrings[CS_AIRACCEL], "0");
                    204:                pm_airaccelerate = 0;
                    205:        }
1.1       root      206: 
                    207:        SZ_Init (&sv.multicast, sv.multicast_buf, sizeof(sv.multicast_buf));
                    208: 
                    209:        strcpy (sv.name, server);
                    210: 
                    211:        // leave slots at start for clients only
                    212:        for (i=0 ; i<maxclients->value ; i++)
                    213:        {
                    214:                // needs to reconnect
                    215:                if (svs.clients[i].state > cs_connected)
                    216:                        svs.clients[i].state = cs_connected;
                    217:                svs.clients[i].lastframe = -1;
                    218:        }
                    219: 
                    220:        sv.time = 1000;
                    221:        
                    222:        strcpy (sv.name, server);
                    223:        strcpy (sv.configstrings[CS_NAME], server);
                    224: 
                    225:        if (serverstate != ss_game)
                    226:        {
                    227:                sv.models[1] = CM_LoadMap ("", false, &checksum);       // no real map
                    228:        }
                    229:        else
                    230:        {
                    231:                Com_sprintf (sv.configstrings[CS_MODELS+1],sizeof(sv.configstrings[CS_MODELS+1]),
                    232:                        "maps/%s.bsp", server);
                    233:                sv.models[1] = CM_LoadMap (sv.configstrings[CS_MODELS+1], false, &checksum);
                    234:        }
                    235:        Com_sprintf (sv.configstrings[CS_MAPCHECKSUM],sizeof(sv.configstrings[CS_MAPCHECKSUM]),
                    236:                "%i", checksum);
                    237: 
                    238:        //
                    239:        // clear physics interaction links
                    240:        //
                    241:        SV_ClearWorld ();
                    242:        
                    243:        for (i=1 ; i< CM_NumInlineModels() ; i++)
                    244:        {
                    245:                Com_sprintf (sv.configstrings[CS_MODELS+1+i], sizeof(sv.configstrings[CS_MODELS+1+i]),
                    246:                        "*%i", i);
                    247:                sv.models[i+1] = CM_InlineModel (sv.configstrings[CS_MODELS+1+i]);
                    248:        }
                    249: 
                    250:        //
                    251:        // spawn the rest of the entities on the map
                    252:        //      
                    253: 
                    254:        // precache and static commands can be issued during
                    255:        // map initialization
                    256:        sv.state = ss_loading;
                    257:        Com_SetServerState (sv.state);
                    258: 
                    259:        // load and spawn all other entities
                    260:        ge->SpawnEntities ( sv.name, CM_EntityString(), spawnpoint );
                    261: 
                    262:        // run two frames to allow everything to settle
                    263:        ge->RunFrame ();
                    264:        ge->RunFrame ();
                    265: 
                    266:        // all precaches are complete
                    267:        sv.state = serverstate;
                    268:        Com_SetServerState (sv.state);
                    269:        
                    270:        // create a baseline for more efficient communications
                    271:        SV_CreateBaseline ();
                    272: 
                    273:        // check for a savegame
                    274:        SV_CheckForSavegame ();
                    275: 
                    276:        // set serverinfo variable
                    277:        Cvar_FullSet ("mapname", sv.name, CVAR_SERVERINFO | CVAR_NOSET);
                    278: 
                    279:        Com_Printf ("-------------------------------------\n");
                    280: }
                    281: 
                    282: /*
                    283: ==============
                    284: SV_InitGame
                    285: 
                    286: A brand new game has been started
                    287: ==============
                    288: */
                    289: void SV_InitGame (void)
                    290: {
                    291:        int             i;
                    292:        edict_t *ent;
                    293:        char    idmaster[32];
                    294: 
                    295:        if (svs.initialized)
                    296:        {
                    297:                // cause any connected clients to reconnect
                    298:                SV_Shutdown ("Server restarted\n", true);
                    299:        }
                    300:        else
                    301:        {
                    302:                // make sure the client is down
                    303:                CL_Drop ();
                    304:                SCR_BeginLoadingPlaque ();
                    305:        }
                    306: 
                    307:        // get any latched variable changes (maxclients, etc)
                    308:        Cvar_GetLatchedVars ();
                    309: 
                    310:        svs.initialized = true;
                    311: 
                    312:        if (Cvar_VariableValue ("coop") && Cvar_VariableValue ("deathmatch"))
                    313:        {
                    314:                Com_Printf("Deathmatch and Coop both set, disabling Coop\n");
                    315:                Cvar_FullSet ("coop", "0",  CVAR_SERVERINFO | CVAR_LATCH);
                    316:        }
                    317: 
                    318:        // dedicated servers are can't be single player and are usually DM
                    319:        // so unless they explicity set coop, force it to deathmatch
                    320:        if (dedicated->value)
                    321:        {
                    322:                if (!Cvar_VariableValue ("coop"))
                    323:                        Cvar_FullSet ("deathmatch", "1",  CVAR_SERVERINFO | CVAR_LATCH);
                    324:        }
                    325: 
                    326:        // init clients
                    327:        if (Cvar_VariableValue ("deathmatch"))
                    328:        {
                    329:                if (maxclients->value <= 1)
                    330:                        Cvar_FullSet ("maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH);
                    331:                else if (maxclients->value > MAX_CLIENTS)
                    332:                        Cvar_FullSet ("maxclients", va("%i", MAX_CLIENTS), CVAR_SERVERINFO | CVAR_LATCH);
                    333:        }
                    334:        else if (Cvar_VariableValue ("coop"))
                    335:        {
                    336:                if (maxclients->value <= 1 || maxclients->value > 4)
                    337:                        Cvar_FullSet ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
1.1.1.2   root      338: #ifdef COPYPROTECT
1.1       root      339:                if (!sv.attractloop && !dedicated->value)
                    340:                        Sys_CopyProtect ();
1.1.1.2   root      341: #endif
1.1       root      342:        }
                    343:        else    // non-deathmatch, non-coop is one player
                    344:        {
                    345:                Cvar_FullSet ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH);
1.1.1.2   root      346: #ifdef COPYPROTECT
1.1       root      347:                if (!sv.attractloop)
                    348:                        Sys_CopyProtect ();
1.1.1.2   root      349: #endif
1.1       root      350:        }
                    351: 
                    352:        svs.spawncount = rand();
                    353:        svs.clients = Z_Malloc (sizeof(client_t)*maxclients->value);
                    354:        svs.num_client_entities = maxclients->value*UPDATE_BACKUP*64;
                    355:        svs.client_entities = Z_Malloc (sizeof(entity_state_t)*svs.num_client_entities);
                    356: 
                    357:        // init network stuff
                    358:        NET_Config ( (maxclients->value > 1) );
                    359: 
                    360:        // heartbeats will always be sent to the id master
                    361:        svs.last_heartbeat = -99999;            // send immediately
                    362:        Com_sprintf(idmaster, sizeof(idmaster), "192.246.40.37:%i", PORT_MASTER);
                    363:        NET_StringToAdr (idmaster, &master_adr[0]);
                    364: 
                    365:        // init game
                    366:        SV_InitGameProgs ();
                    367:        for (i=0 ; i<maxclients->value ; i++)
                    368:        {
                    369:                ent = EDICT_NUM(i+1);
                    370:                ent->s.number = i+1;
                    371:                svs.clients[i].edict = ent;
                    372:                memset (&svs.clients[i].lastcmd, 0, sizeof(svs.clients[i].lastcmd));
                    373:        }
                    374: }
                    375: 
                    376: 
                    377: /*
                    378: ======================
                    379: SV_Map
                    380: 
                    381:   the full syntax is:
                    382: 
                    383:   map [*]<map>$<startspot>+<nextserver>
                    384: 
                    385: command from the console or progs.
                    386: Map can also be a.cin, .pcx, or .dm2 file
                    387: Nextserver is used to allow a cinematic to play, then proceed to
                    388: another level:
                    389: 
                    390:        map tram.cin+jail_e3
                    391: ======================
                    392: */
                    393: void SV_Map (qboolean attractloop, char *levelstring, qboolean loadgame)
                    394: {
                    395:        char    level[MAX_QPATH];
                    396:        char    *ch;
                    397:        int             l;
                    398:        char    spawnpoint[MAX_QPATH];
                    399: 
                    400:        sv.loadgame = loadgame;
                    401:        sv.attractloop = attractloop;
                    402: 
                    403:        if (sv.state == ss_dead && !sv.loadgame)
                    404:                SV_InitGame (); // the game is just starting
                    405: 
                    406:        strcpy (level, levelstring);
                    407: 
                    408:        // if there is a + in the map, set nextserver to the remainder
                    409:        ch = strstr(level, "+");
                    410:        if (ch)
                    411:        {
                    412:                *ch = 0;
1.1.1.2   root      413:                        Cvar_Set ("nextserver", va("gamemap \"%s\"", ch+1));
1.1       root      414:        }
                    415:        else
                    416:                Cvar_Set ("nextserver", "");
                    417: 
1.1.1.2   root      418:        //ZOID special hack for end game screen in coop mode
                    419:        if (Cvar_VariableValue ("coop") && !Q_stricmp(level, "victory.pcx"))
                    420:                Cvar_Set ("nextserver", "gamemap \"*base1\"");
1.1       root      421: 
                    422:        // if there is a $, use the remainder as a spawnpoint
                    423:        ch = strstr(level, "$");
                    424:        if (ch)
                    425:        {
                    426:                *ch = 0;
                    427:                strcpy (spawnpoint, ch+1);
                    428:        }
                    429:        else
                    430:                spawnpoint[0] = 0;
                    431: 
                    432:        // skip the end-of-unit flag if necessary
                    433:        if (level[0] == '*')
                    434:                strcpy (level, level+1);
                    435: 
                    436:        l = strlen(level);
                    437:        if (l > 4 && !strcmp (level+l-4, ".cin") )
                    438:        {
                    439:                SCR_BeginLoadingPlaque ();                      // for local system
1.1.1.2   root      440:                SV_BroadcastCommand ("changing\n");
1.1       root      441:                SV_SpawnServer (level, spawnpoint, ss_cinematic, attractloop, loadgame);
                    442:        }
                    443:        else if (l > 4 && !strcmp (level+l-4, ".dm2") )
                    444:        {
                    445:                SCR_BeginLoadingPlaque ();                      // for local system
1.1.1.2   root      446:                SV_BroadcastCommand ("changing\n");
1.1       root      447:                SV_SpawnServer (level, spawnpoint, ss_demo, attractloop, loadgame);
                    448:        }
                    449:        else if (l > 4 && !strcmp (level+l-4, ".pcx") )
                    450:        {
                    451:                SCR_BeginLoadingPlaque ();                      // for local system
1.1.1.2   root      452:                SV_BroadcastCommand ("changing\n");
1.1       root      453:                SV_SpawnServer (level, spawnpoint, ss_pic, attractloop, loadgame);
                    454:        }
                    455:        else
                    456:        {
                    457:                SCR_BeginLoadingPlaque ();                      // for local system
                    458:                SV_BroadcastCommand ("changing\n");
                    459:                SV_SendClientMessages ();
                    460:                SV_SpawnServer (level, spawnpoint, ss_game, attractloop, loadgame);
                    461:                Cbuf_CopyToDefer ();
                    462:        }
                    463: 
                    464:        SV_BroadcastCommand ("reconnect\n");
                    465: }

unix.superglobalmegacorp.com

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