|
|
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.