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

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
                    125:                for (i=0 ; i<100 ; i++)
                    126:                        ge->RunFrame ();
                    127:        }
                    128: }
                    129: 
                    130: 
                    131: /*
                    132: ================
                    133: SV_SpawnServer
                    134: 
                    135: Change the server to a new map, taking all connected
                    136: clients along with it.
                    137: 
                    138: ================
                    139: */
                    140: void SV_SpawnServer (char *server, char *spawnpoint, server_state_t serverstate, qboolean attractloop, qboolean loadgame)
                    141: {
                    142:        int                     i;
                    143:        unsigned        checksum;
                    144: 
                    145:        if (attractloop)
                    146:                Cvar_Set ("paused", "0");
                    147: 
                    148:        Com_Printf ("------- Server Initialization -------\n");
                    149: 
                    150:        Com_DPrintf ("SpawnServer: %s\n",server);
                    151:        if (sv.demofile)
                    152:                fclose (sv.demofile);
                    153: 
                    154:        svs.spawncount++;               // any partially connected client will be
                    155:                                                        // restarted
                    156:        sv.state = ss_dead;
                    157:        Com_SetServerState (sv.state);
                    158: 
                    159:        // wipe the entire per-level structure
                    160:        memset (&sv, 0, sizeof(sv));
                    161:        svs.realtime = 0;
                    162:        sv.loadgame = loadgame;
                    163:        sv.attractloop = attractloop;
                    164: 
                    165:        // save name for levels that don't set message
                    166:        strcpy (sv.configstrings[CS_NAME], server);
                    167: 
                    168:        SZ_Init (&sv.multicast, sv.multicast_buf, sizeof(sv.multicast_buf));
                    169: 
                    170:        strcpy (sv.name, server);
                    171: 
                    172:        // leave slots at start for clients only
                    173:        for (i=0 ; i<maxclients->value ; i++)
                    174:        {
                    175:                // needs to reconnect
                    176:                if (svs.clients[i].state > cs_connected)
                    177:                        svs.clients[i].state = cs_connected;
                    178:                svs.clients[i].lastframe = -1;
                    179:        }
                    180: 
                    181:        sv.time = 1000;
                    182:        
                    183:        strcpy (sv.name, server);
                    184:        strcpy (sv.configstrings[CS_NAME], server);
                    185: 
                    186:        if (serverstate != ss_game)
                    187:        {
                    188:                sv.models[1] = CM_LoadMap ("", false, &checksum);       // no real map
                    189:        }
                    190:        else
                    191:        {
                    192:                Com_sprintf (sv.configstrings[CS_MODELS+1],sizeof(sv.configstrings[CS_MODELS+1]),
                    193:                        "maps/%s.bsp", server);
                    194:                sv.models[1] = CM_LoadMap (sv.configstrings[CS_MODELS+1], false, &checksum);
                    195:        }
                    196:        Com_sprintf (sv.configstrings[CS_MAPCHECKSUM],sizeof(sv.configstrings[CS_MAPCHECKSUM]),
                    197:                "%i", checksum);
                    198: 
                    199:        //
                    200:        // clear physics interaction links
                    201:        //
                    202:        SV_ClearWorld ();
                    203:        
                    204:        for (i=1 ; i< CM_NumInlineModels() ; i++)
                    205:        {
                    206:                Com_sprintf (sv.configstrings[CS_MODELS+1+i], sizeof(sv.configstrings[CS_MODELS+1+i]),
                    207:                        "*%i", i);
                    208:                sv.models[i+1] = CM_InlineModel (sv.configstrings[CS_MODELS+1+i]);
                    209:        }
                    210: 
                    211:        //
                    212:        // spawn the rest of the entities on the map
                    213:        //      
                    214: 
                    215:        // precache and static commands can be issued during
                    216:        // map initialization
                    217:        sv.state = ss_loading;
                    218:        Com_SetServerState (sv.state);
                    219: 
                    220:        // load and spawn all other entities
                    221:        ge->SpawnEntities ( sv.name, CM_EntityString(), spawnpoint );
                    222: 
                    223:        // run two frames to allow everything to settle
                    224:        ge->RunFrame ();
                    225:        ge->RunFrame ();
                    226: 
                    227:        // all precaches are complete
                    228:        sv.state = serverstate;
                    229:        Com_SetServerState (sv.state);
                    230:        
                    231:        // create a baseline for more efficient communications
                    232:        SV_CreateBaseline ();
                    233: 
                    234:        // check for a savegame
                    235:        SV_CheckForSavegame ();
                    236: 
                    237:        // set serverinfo variable
                    238:        Cvar_FullSet ("mapname", sv.name, CVAR_SERVERINFO | CVAR_NOSET);
                    239: 
                    240:        Com_Printf ("-------------------------------------\n");
                    241: }
                    242: 
                    243: /*
                    244: ==============
                    245: SV_InitGame
                    246: 
                    247: A brand new game has been started
                    248: ==============
                    249: */
                    250: void SV_InitGame (void)
                    251: {
                    252:        int             i;
                    253:        edict_t *ent;
                    254:        char    idmaster[32];
                    255: 
                    256:        if (svs.initialized)
                    257:        {
                    258:                // cause any connected clients to reconnect
                    259:                SV_Shutdown ("Server restarted\n", true);
                    260:        }
                    261:        else
                    262:        {
                    263:                // make sure the client is down
                    264:                CL_Drop ();
                    265:                SCR_BeginLoadingPlaque ();
                    266:        }
                    267: 
                    268:        // get any latched variable changes (maxclients, etc)
                    269:        Cvar_GetLatchedVars ();
                    270: 
                    271:        svs.initialized = true;
                    272: 
                    273:        if (Cvar_VariableValue ("coop") && Cvar_VariableValue ("deathmatch"))
                    274:        {
                    275:                Com_Printf("Deathmatch and Coop both set, disabling Coop\n");
                    276:                Cvar_FullSet ("coop", "0",  CVAR_SERVERINFO | CVAR_LATCH);
                    277:        }
                    278: 
                    279:        // dedicated servers are can't be single player and are usually DM
                    280:        // so unless they explicity set coop, force it to deathmatch
                    281:        if (dedicated->value)
                    282:        {
                    283:                if (!Cvar_VariableValue ("coop"))
                    284:                        Cvar_FullSet ("deathmatch", "1",  CVAR_SERVERINFO | CVAR_LATCH);
                    285:        }
                    286: 
                    287:        // init clients
                    288:        if (Cvar_VariableValue ("deathmatch"))
                    289:        {
                    290:                if (maxclients->value <= 1)
                    291:                        Cvar_FullSet ("maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH);
                    292:                else if (maxclients->value > MAX_CLIENTS)
                    293:                        Cvar_FullSet ("maxclients", va("%i", MAX_CLIENTS), CVAR_SERVERINFO | CVAR_LATCH);
                    294:        }
                    295:        else if (Cvar_VariableValue ("coop"))
                    296:        {
                    297:                if (maxclients->value <= 1 || maxclients->value > 4)
                    298:                        Cvar_FullSet ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
1.1.1.2 ! root      299: #ifdef COPYPROTECT
1.1       root      300:                if (!sv.attractloop && !dedicated->value)
                    301:                        Sys_CopyProtect ();
1.1.1.2 ! root      302: #endif
1.1       root      303:        }
                    304:        else    // non-deathmatch, non-coop is one player
                    305:        {
                    306:                Cvar_FullSet ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH);
1.1.1.2 ! root      307: #ifdef COPYPROTECT
1.1       root      308:                if (!sv.attractloop)
                    309:                        Sys_CopyProtect ();
1.1.1.2 ! root      310: #endif
1.1       root      311:        }
                    312: 
                    313:        svs.spawncount = rand();
                    314:        svs.clients = Z_Malloc (sizeof(client_t)*maxclients->value);
                    315:        svs.num_client_entities = maxclients->value*UPDATE_BACKUP*64;
                    316:        svs.client_entities = Z_Malloc (sizeof(entity_state_t)*svs.num_client_entities);
                    317: 
                    318:        // init network stuff
                    319:        NET_Config ( (maxclients->value > 1) );
                    320: 
                    321:        // heartbeats will always be sent to the id master
                    322:        svs.last_heartbeat = -99999;            // send immediately
                    323:        Com_sprintf(idmaster, sizeof(idmaster), "192.246.40.37:%i", PORT_MASTER);
                    324:        NET_StringToAdr (idmaster, &master_adr[0]);
                    325: 
                    326:        // init game
                    327:        SV_InitGameProgs ();
                    328:        for (i=0 ; i<maxclients->value ; i++)
                    329:        {
                    330:                ent = EDICT_NUM(i+1);
                    331:                ent->s.number = i+1;
                    332:                svs.clients[i].edict = ent;
                    333:                memset (&svs.clients[i].lastcmd, 0, sizeof(svs.clients[i].lastcmd));
                    334:        }
                    335: }
                    336: 
                    337: 
                    338: /*
                    339: ======================
                    340: SV_Map
                    341: 
                    342:   the full syntax is:
                    343: 
                    344:   map [*]<map>$<startspot>+<nextserver>
                    345: 
                    346: command from the console or progs.
                    347: Map can also be a.cin, .pcx, or .dm2 file
                    348: Nextserver is used to allow a cinematic to play, then proceed to
                    349: another level:
                    350: 
                    351:        map tram.cin+jail_e3
                    352: ======================
                    353: */
                    354: void SV_Map (qboolean attractloop, char *levelstring, qboolean loadgame)
                    355: {
                    356:        char    level[MAX_QPATH];
                    357:        char    *ch;
                    358:        int             l;
                    359:        char    spawnpoint[MAX_QPATH];
                    360: 
                    361:        sv.loadgame = loadgame;
                    362:        sv.attractloop = attractloop;
                    363: 
                    364:        if (sv.state == ss_dead && !sv.loadgame)
                    365:                SV_InitGame (); // the game is just starting
                    366: 
                    367:        strcpy (level, levelstring);
                    368: 
                    369:        // if there is a + in the map, set nextserver to the remainder
                    370:        ch = strstr(level, "+");
                    371:        if (ch)
                    372:        {
                    373:                *ch = 0;
1.1.1.2 ! root      374:                        Cvar_Set ("nextserver", va("gamemap \"%s\"", ch+1));
1.1       root      375:        }
                    376:        else
                    377:                Cvar_Set ("nextserver", "");
                    378: 
1.1.1.2 ! root      379:        //ZOID special hack for end game screen in coop mode
        !           380:        if (Cvar_VariableValue ("coop") && !Q_stricmp(level, "victory.pcx"))
        !           381:                Cvar_Set ("nextserver", "gamemap \"*base1\"");
1.1       root      382: 
                    383:        // if there is a $, use the remainder as a spawnpoint
                    384:        ch = strstr(level, "$");
                    385:        if (ch)
                    386:        {
                    387:                *ch = 0;
                    388:                strcpy (spawnpoint, ch+1);
                    389:        }
                    390:        else
                    391:                spawnpoint[0] = 0;
                    392: 
                    393:        // skip the end-of-unit flag if necessary
                    394:        if (level[0] == '*')
                    395:                strcpy (level, level+1);
                    396: 
                    397:        l = strlen(level);
                    398:        if (l > 4 && !strcmp (level+l-4, ".cin") )
                    399:        {
                    400:                SCR_BeginLoadingPlaque ();                      // for local system
1.1.1.2 ! root      401:                SV_BroadcastCommand ("changing\n");
1.1       root      402:                SV_SpawnServer (level, spawnpoint, ss_cinematic, attractloop, loadgame);
                    403:        }
                    404:        else if (l > 4 && !strcmp (level+l-4, ".dm2") )
                    405:        {
                    406:                SCR_BeginLoadingPlaque ();                      // for local system
1.1.1.2 ! root      407:                SV_BroadcastCommand ("changing\n");
1.1       root      408:                SV_SpawnServer (level, spawnpoint, ss_demo, attractloop, loadgame);
                    409:        }
                    410:        else if (l > 4 && !strcmp (level+l-4, ".pcx") )
                    411:        {
                    412:                SCR_BeginLoadingPlaque ();                      // for local system
1.1.1.2 ! root      413:                SV_BroadcastCommand ("changing\n");
1.1       root      414:                SV_SpawnServer (level, spawnpoint, ss_pic, attractloop, loadgame);
                    415:        }
                    416:        else
                    417:        {
                    418:                SCR_BeginLoadingPlaque ();                      // for local system
                    419:                SV_BroadcastCommand ("changing\n");
                    420:                SV_SendClientMessages ();
                    421:                SV_SpawnServer (level, spawnpoint, ss_game, attractloop, loadgame);
                    422:                Cbuf_CopyToDefer ();
                    423:        }
                    424: 
                    425:        SV_BroadcastCommand ("reconnect\n");
                    426: }

unix.superglobalmegacorp.com

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