|
|
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); ! 299: if (!sv.attractloop && !dedicated->value) ! 300: Sys_CopyProtect (); ! 301: } ! 302: else // non-deathmatch, non-coop is one player ! 303: { ! 304: Cvar_FullSet ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH); ! 305: if (!sv.attractloop) ! 306: Sys_CopyProtect (); ! 307: } ! 308: ! 309: svs.spawncount = rand(); ! 310: svs.clients = Z_Malloc (sizeof(client_t)*maxclients->value); ! 311: svs.num_client_entities = maxclients->value*UPDATE_BACKUP*64; ! 312: svs.client_entities = Z_Malloc (sizeof(entity_state_t)*svs.num_client_entities); ! 313: ! 314: // init network stuff ! 315: NET_Config ( (maxclients->value > 1) ); ! 316: ! 317: // heartbeats will always be sent to the id master ! 318: svs.last_heartbeat = -99999; // send immediately ! 319: Com_sprintf(idmaster, sizeof(idmaster), "192.246.40.37:%i", PORT_MASTER); ! 320: NET_StringToAdr (idmaster, &master_adr[0]); ! 321: ! 322: // init game ! 323: SV_InitGameProgs (); ! 324: for (i=0 ; i<maxclients->value ; i++) ! 325: { ! 326: ent = EDICT_NUM(i+1); ! 327: ent->s.number = i+1; ! 328: svs.clients[i].edict = ent; ! 329: memset (&svs.clients[i].lastcmd, 0, sizeof(svs.clients[i].lastcmd)); ! 330: } ! 331: } ! 332: ! 333: ! 334: /* ! 335: ====================== ! 336: SV_Map ! 337: ! 338: the full syntax is: ! 339: ! 340: map [*]<map>$<startspot>+<nextserver> ! 341: ! 342: command from the console or progs. ! 343: Map can also be a.cin, .pcx, or .dm2 file ! 344: Nextserver is used to allow a cinematic to play, then proceed to ! 345: another level: ! 346: ! 347: map tram.cin+jail_e3 ! 348: ====================== ! 349: */ ! 350: void SV_Map (qboolean attractloop, char *levelstring, qboolean loadgame) ! 351: { ! 352: char level[MAX_QPATH]; ! 353: char *ch; ! 354: int l; ! 355: char spawnpoint[MAX_QPATH]; ! 356: ! 357: sv.loadgame = loadgame; ! 358: sv.attractloop = attractloop; ! 359: ! 360: if (sv.state == ss_dead && !sv.loadgame) ! 361: SV_InitGame (); // the game is just starting ! 362: ! 363: strcpy (level, levelstring); ! 364: ! 365: // if there is a + in the map, set nextserver to the remainder ! 366: ch = strstr(level, "+"); ! 367: if (ch) ! 368: { ! 369: *ch = 0; ! 370: Cvar_Set ("nextserver", va("gamemap \"%s\"", ch+1)); ! 371: } ! 372: else ! 373: Cvar_Set ("nextserver", ""); ! 374: ! 375: ! 376: // if there is a $, use the remainder as a spawnpoint ! 377: ch = strstr(level, "$"); ! 378: if (ch) ! 379: { ! 380: *ch = 0; ! 381: strcpy (spawnpoint, ch+1); ! 382: } ! 383: else ! 384: spawnpoint[0] = 0; ! 385: ! 386: // skip the end-of-unit flag if necessary ! 387: if (level[0] == '*') ! 388: strcpy (level, level+1); ! 389: ! 390: l = strlen(level); ! 391: if (l > 4 && !strcmp (level+l-4, ".cin") ) ! 392: { ! 393: SCR_BeginLoadingPlaque (); // for local system ! 394: SV_SpawnServer (level, spawnpoint, ss_cinematic, attractloop, loadgame); ! 395: } ! 396: else if (l > 4 && !strcmp (level+l-4, ".dm2") ) ! 397: { ! 398: SCR_BeginLoadingPlaque (); // for local system ! 399: SV_SpawnServer (level, spawnpoint, ss_demo, attractloop, loadgame); ! 400: } ! 401: else if (l > 4 && !strcmp (level+l-4, ".pcx") ) ! 402: { ! 403: SCR_BeginLoadingPlaque (); // for local system ! 404: SV_SpawnServer (level, spawnpoint, ss_pic, attractloop, loadgame); ! 405: } ! 406: else ! 407: { ! 408: SCR_BeginLoadingPlaque (); // for local system ! 409: SV_BroadcastCommand ("changing\n"); ! 410: SV_SendClientMessages (); ! 411: SV_SpawnServer (level, spawnpoint, ss_game, attractloop, loadgame); ! 412: Cbuf_CopyToDefer (); ! 413: } ! 414: ! 415: SV_BroadcastCommand ("reconnect\n"); ! 416: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.