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