|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.