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

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

unix.superglobalmegacorp.com

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