1 /*
2 ===========================================================================
3 
4 Return to Castle Wolfenstein multiplayer GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
8 
9 RTCW MP Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 RTCW MP Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with RTCW MP Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 /*
30  * name:		sv_init.c
31  *
32  * desc:
33  *
34 */
35 
36 #include "server.h"
37 
38 /*
39 ===============
40 SV_SendConfigstring
41 
42 Creates and sends the server command necessary to update the CS index for the
43 given client
44 ===============
45 */
SV_SendConfigstring(client_t * client,int index)46 static void SV_SendConfigstring(client_t *client, int index)
47 {
48 	int maxChunkSize = MAX_STRING_CHARS - 24;
49 	int len;
50 
51 	len = strlen(sv.configstrings[index]);
52 
53 	if( len >= maxChunkSize ) {
54 		int		sent = 0;
55 		int		remaining = len;
56 		char	*cmd;
57 		char	buf[MAX_STRING_CHARS];
58 
59 		while (remaining > 0 ) {
60 			if ( sent == 0 ) {
61 				cmd = "bcs0";
62 			}
63 			else if( remaining < maxChunkSize ) {
64 				cmd = "bcs2";
65 			}
66 			else {
67 				cmd = "bcs1";
68 			}
69 			Q_strncpyz( buf, &sv.configstrings[index][sent],
70 				maxChunkSize );
71 
72 			SV_SendServerCommand( client, "%s %i \"%s\"\n", cmd,
73 				index, buf );
74 
75 			sent += (maxChunkSize - 1);
76 			remaining -= (maxChunkSize - 1);
77 		}
78 	} else {
79 		// standard cs, just send it
80 		SV_SendServerCommand( client, "cs %i \"%s\"\n", index,
81 			sv.configstrings[index] );
82 	}
83 }
84 
85 /*
86 ===============
87 SV_UpdateConfigstrings
88 
89 Called when a client goes from CS_PRIMED to CS_ACTIVE.  Updates all
90 Configstring indexes that have changed while the client was in CS_PRIMED
91 ===============
92 */
SV_UpdateConfigstrings(client_t * client)93 void SV_UpdateConfigstrings(client_t *client)
94 {
95 	int index;
96 
97 	for( index = 0; index < MAX_CONFIGSTRINGS; index++ ) {
98 		// if the CS hasn't changed since we went to CS_PRIMED, ignore
99 		if(!client->csUpdated[index])
100 			continue;
101 
102 		// do not always send server info to all clients
103 		if ( index == CS_SERVERINFO && client->gentity &&
104 			(client->gentity->r.svFlags & SVF_NOSERVERINFO) ) {
105 			continue;
106 		}
107 		SV_SendConfigstring(client, index);
108 		client->csUpdated[index] = qfalse;
109 	}
110 }
111 
112 /*
113 ===============
114 SV_SetConfigstring
115 
116 ===============
117 */
SV_SetConfigstring(int index,const char * val)118 void SV_SetConfigstring( int index, const char *val ) {
119 	int		i;
120 	client_t    *client;
121 
122 	if ( index < 0 || index >= MAX_CONFIGSTRINGS ) {
123 		Com_Error (ERR_DROP, "SV_SetConfigstring: bad index %i", index);
124 	}
125 
126 	if ( !val ) {
127 		val = "";
128 	}
129 
130 	// don't bother broadcasting an update if no change
131 	if ( !strcmp( val, sv.configstrings[ index ] ) ) {
132 		return;
133 	}
134 
135 	// change the string in sv
136 	Z_Free( sv.configstrings[index] );
137 	sv.configstrings[index] = CopyString( val );
138 
139 	// send it to all the clients if we aren't
140 	// spawning a new server
141 	if ( sv.state == SS_GAME || sv.restarting ) {
142 //		SV_SendServerCommand( NULL, "cs %i \"%s\"\n", index, val );
143 
144 		// send the data to all relevent clients
145 		for ( i = 0, client = svs.clients; i < sv_maxclients->integer ; i++, client++ ) {
146 			if ( client->state < CS_ACTIVE ) {
147 				if ( client->state == CS_PRIMED )
148 					client->csUpdated[ index ] = qtrue;
149 				continue;
150 			}
151 			// do not always send server info to all clients
152 			if ( index == CS_SERVERINFO && client->gentity && ( client->gentity->r.svFlags & SVF_NOSERVERINFO ) ) {
153 				continue;
154 			}
155 
156 			// RF, don't send to bot/AI
157 			if ( sv_gametype->integer == GT_SINGLE_PLAYER && client->gentity && ( client->gentity->r.svFlags & SVF_CASTAI ) ) {
158 				continue;
159 			}
160 
161 //			SV_SendServerCommand( client, "cs %i \"%s\"\n", index, val );
162 
163 			SV_SendConfigstring(client, index);
164 		}
165 	}
166 }
167 
168 
169 
170 /*
171 ===============
172 SV_GetConfigstring
173 
174 ===============
175 */
SV_GetConfigstring(int index,char * buffer,int bufferSize)176 void SV_GetConfigstring( int index, char *buffer, int bufferSize ) {
177 	if ( bufferSize < 1 ) {
178 		Com_Error( ERR_DROP, "SV_GetConfigstring: bufferSize == %i", bufferSize );
179 	}
180 	if ( index < 0 || index >= MAX_CONFIGSTRINGS ) {
181 		Com_Error( ERR_DROP, "SV_GetConfigstring: bad index %i", index );
182 	}
183 	if ( !sv.configstrings[index] ) {
184 		buffer[0] = 0;
185 		return;
186 	}
187 
188 	Q_strncpyz( buffer, sv.configstrings[index], bufferSize );
189 }
190 
191 
192 /*
193 ===============
194 SV_SetUserinfo
195 
196 ===============
197 */
SV_SetUserinfo(int index,const char * val)198 void SV_SetUserinfo( int index, const char *val ) {
199 	if ( index < 0 || index >= sv_maxclients->integer ) {
200 		Com_Error( ERR_DROP, "SV_SetUserinfo: bad index %i", index );
201 	}
202 
203 	if ( !val ) {
204 		val = "";
205 	}
206 
207 	Q_strncpyz( svs.clients[index].userinfo, val, sizeof( svs.clients[ index ].userinfo ) );
208 	Q_strncpyz( svs.clients[index].name, Info_ValueForKey( val, "name" ), sizeof( svs.clients[index].name ) );
209 }
210 
211 
212 
213 /*
214 ===============
215 SV_GetUserinfo
216 
217 ===============
218 */
SV_GetUserinfo(int index,char * buffer,int bufferSize)219 void SV_GetUserinfo( int index, char *buffer, int bufferSize ) {
220 	if ( bufferSize < 1 ) {
221 		Com_Error( ERR_DROP, "SV_GetUserinfo: bufferSize == %i", bufferSize );
222 	}
223 	if ( index < 0 || index >= sv_maxclients->integer ) {
224 		Com_Error( ERR_DROP, "SV_GetUserinfo: bad index %i", index );
225 	}
226 	Q_strncpyz( buffer, svs.clients[ index ].userinfo, bufferSize );
227 }
228 
229 
230 /*
231 ================
232 SV_CreateBaseline
233 
234 Entity baselines are used to compress non-delta messages
235 to the clients -- only the fields that differ from the
236 baseline will be transmitted
237 ================
238 */
SV_CreateBaseline(void)239 static void SV_CreateBaseline( void ) {
240 	sharedEntity_t *svent;
241 	int entnum;
242 
243 	for ( entnum = 1; entnum < sv.num_entities ; entnum++ ) {
244 		svent = SV_GentityNum( entnum );
245 		if ( !svent->r.linked ) {
246 			continue;
247 		}
248 		svent->s.number = entnum;
249 
250 		//
251 		// take current state as baseline
252 		//
253 		sv.svEntities[entnum].baseline = svent->s;
254 	}
255 }
256 
257 
258 /*
259 ===============
260 SV_BoundMaxClients
261 
262 ===============
263 */
SV_BoundMaxClients(int minimum)264 static void SV_BoundMaxClients( int minimum ) {
265 	// get the current maxclients value
266 	Cvar_Get( "sv_maxclients", "20", 0 );         // NERVE - SMF - changed to 20 from 8
267 
268 	sv_maxclients->modified = qfalse;
269 
270 	if ( sv_maxclients->integer < minimum ) {
271 		Cvar_Set( "sv_maxclients", va( "%i", minimum ) );
272 	} else if ( sv_maxclients->integer > MAX_CLIENTS ) {
273 		Cvar_Set( "sv_maxclients", va( "%i", MAX_CLIENTS ) );
274 	}
275 }
276 
277 
278 /*
279 ===============
280 SV_Startup
281 
282 Called when a host starts a map when it wasn't running
283 one before.  Successive map or map_restart commands will
284 NOT cause this to be called, unless the game is exited to
285 the menu system first.
286 ===============
287 */
SV_Startup(void)288 static void SV_Startup( void ) {
289 	if ( svs.initialized ) {
290 		Com_Error( ERR_FATAL, "SV_Startup: svs.initialized" );
291 	}
292 	SV_BoundMaxClients( 1 );
293 
294 	// RF, avoid trying to allocate large chunk on a fragmented zone
295 	svs.clients = calloc( sizeof( client_t ) * sv_maxclients->integer, 1 );
296 	if ( !svs.clients ) {
297 		Com_Error( ERR_FATAL, "SV_Startup: unable to allocate svs.clients" );
298 	}
299 	//svs.clients = Z_Malloc (sizeof(client_t) * sv_maxclients->integer );
300 
301 	if ( com_dedicated->integer ) {
302 		svs.numSnapshotEntities = sv_maxclients->integer * PACKET_BACKUP * MAX_SNAPSHOT_ENTITIES;
303 	} else {
304 		// we don't need nearly as many when playing locally
305 		svs.numSnapshotEntities = sv_maxclients->integer * 4 * MAX_SNAPSHOT_ENTITIES;
306 	}
307 	svs.initialized = qtrue;
308 
309 	// Don't respect sv_killserver unless a server is actually running
310 	if ( sv_killserver->integer ) {
311 		Cvar_Set( "sv_killserver", "0" );
312 	}
313 
314 	Cvar_Set( "sv_running", "1" );
315 
316 	// Join the ipv6 multicast group now that a map is running so clients can scan for us on the local network.
317 	NET_JoinMulticast6();
318 }
319 
320 
321 /*
322 ==================
323 SV_ChangeMaxClients
324 ==================
325 */
SV_ChangeMaxClients(void)326 void SV_ChangeMaxClients( void ) {
327 	int oldMaxClients;
328 	int i;
329 	client_t    *oldClients;
330 	int count;
331 
332 	// get the highest client number in use
333 	count = 0;
334 	for ( i = 0 ; i < sv_maxclients->integer ; i++ ) {
335 		if ( svs.clients[i].state >= CS_CONNECTED ) {
336 			if ( i > count ) {
337 				count = i;
338 			}
339 		}
340 	}
341 	count++;
342 
343 	oldMaxClients = sv_maxclients->integer;
344 	// never go below the highest client number in use
345 	SV_BoundMaxClients( count );
346 	// if still the same
347 	if ( sv_maxclients->integer == oldMaxClients ) {
348 		return;
349 	}
350 
351 	oldClients = Hunk_AllocateTempMemory( count * sizeof( client_t ) );
352 	// copy the clients to hunk memory
353 	for ( i = 0 ; i < count ; i++ ) {
354 		if ( svs.clients[i].state >= CS_CONNECTED ) {
355 			oldClients[i] = svs.clients[i];
356 		} else {
357 			Com_Memset( &oldClients[i], 0, sizeof( client_t ) );
358 		}
359 	}
360 
361 	// free old clients arrays
362 	//Z_Free( svs.clients );
363 	free( svs.clients );    // RF, avoid trying to allocate large chunk on a fragmented zone
364 
365 	// allocate new clients
366 	// RF, avoid trying to allocate large chunk on a fragmented zone
367 	svs.clients = calloc( sizeof( client_t ) * sv_maxclients->integer, 1 );
368 	if ( !svs.clients ) {
369 		Com_Error( ERR_FATAL, "SV_Startup: unable to allocate svs.clients" );
370 	}
371 	//svs.clients = Z_Malloc ( sv_maxclients->integer * sizeof(client_t) );
372 
373 	Com_Memset( svs.clients, 0, sv_maxclients->integer * sizeof( client_t ) );
374 
375 	// copy the clients over
376 	for ( i = 0 ; i < count ; i++ ) {
377 		if ( oldClients[i].state >= CS_CONNECTED ) {
378 			svs.clients[i] = oldClients[i];
379 		}
380 	}
381 
382 	// free the old clients on the hunk
383 	Hunk_FreeTempMemory( oldClients );
384 
385 	// allocate new snapshot entities
386 	if ( com_dedicated->integer ) {
387 		svs.numSnapshotEntities = sv_maxclients->integer * PACKET_BACKUP * MAX_SNAPSHOT_ENTITIES;
388 	} else {
389 		// we don't need nearly as many when playing locally
390 		svs.numSnapshotEntities = sv_maxclients->integer * 4 * MAX_SNAPSHOT_ENTITIES;
391 	}
392 }
393 
394 
395 /*
396 ====================
397 SV_SetExpectedHunkUsage
398 
399   Sets com_expectedhunkusage, so the client knows how to draw the percentage bar
400 ====================
401 */
SV_SetExpectedHunkUsage(char * mapname)402 void SV_SetExpectedHunkUsage( char *mapname ) {
403 	int handle;
404 	char *memlistfile = "hunkusage.dat";
405 	char *buf;
406 	char *buftrav;
407 	char *token;
408 	int len;
409 
410 	len = FS_FOpenFileByMode( memlistfile, &handle, FS_READ );
411 	if ( len >= 0 ) { // the file exists, so read it in, strip out the current entry for this map, and save it out, so we can append the new value
412 
413 		buf = (char *)Z_Malloc( len + 1 );
414 		memset( buf, 0, len + 1 );
415 
416 		FS_Read( (void *)buf, len, handle );
417 		FS_FCloseFile( handle );
418 
419 		// now parse the file, filtering out the current map
420 		buftrav = buf;
421 		while ( ( token = COM_Parse( &buftrav ) ) && token[0] ) {
422 			if ( !Q_strcasecmp( token, mapname ) ) {
423 				// found a match
424 				token = COM_Parse( &buftrav );  // read the size
425 				if ( token && token[0] ) {
426 					// this is the usage
427 					Cvar_Set( "com_expectedhunkusage", token );
428 					Z_Free( buf );
429 					return;
430 				}
431 			}
432 		}
433 
434 		Z_Free( buf );
435 	}
436 	// just set it to a negative number,so the cgame knows not to draw the percent bar
437 	Cvar_Set( "com_expectedhunkusage", "-1" );
438 }
439 
440 /*
441 ================
442 SV_ClearServer
443 ================
444 */
SV_ClearServer(void)445 static void SV_ClearServer(void) {
446 	int i;
447 
448 	for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {
449 		if ( sv.configstrings[i] ) {
450 			Z_Free( sv.configstrings[i] );
451 		}
452 	}
453 	Com_Memset (&sv, 0, sizeof(sv));
454 }
455 
456 /*
457 ================
458 SV_TouchFile
459 ================
460 */
SV_TouchFile(const char * filename)461 static void SV_TouchFile( const char *filename ) {
462 	fileHandle_t f;
463 
464 	FS_FOpenFileRead_Filtered( filename, &f, qfalse, FS_EXCLUDE_DIR );
465 	if ( f ) {
466 		FS_FCloseFile( f );
467 	}
468 }
469 
470 
471 /*
472 ================
473 SV_TouchCGameDLL
474   touch the cgame DLL so that a pure client (with DLL sv_pure support) can load do the correct checks
475 ================
476 
477 void SV_TouchCGameDLL( void ) {
478 	fileHandle_t f;
479 	char *filename;
480 
481 	// Only touch the legacy dll since we have qvm support
482 	filename = "cgame_mp_x86.dll";
483 	FS_FOpenFileRead_Filtered( filename, &f, qfalse, FS_EXCLUDE_DIR );
484 	if ( f ) {
485 		FS_FCloseFile( f );
486 	}
487 }
488 */
489 
490 /*
491 ================
492 SV_SpawnServer
493 
494 Change the server to a new map, taking all connected
495 clients along with it.
496 This is NOT called for map_restart
497 ================
498 */
SV_SpawnServer(char * server,qboolean killBots)499 void SV_SpawnServer( char *server, qboolean killBots ) {
500 	int i;
501 	int checksum;
502 	qboolean isBot;
503 	char systemInfo[16384];
504 	const char  *p;
505 
506 	// shut down the existing game if it is running
507 	SV_ShutdownGameProgs();
508 
509 	Com_Printf( "------ Server Initialization ------\n" );
510 	Com_Printf( "Server: %s\n",server );
511 
512 	// if not running a dedicated server CL_MapLoading will connect the client to the server
513 	// also print some status stuff
514 	CL_MapLoading();
515 
516 	// make sure all the client stuff is unloaded
517 	CL_ShutdownAll(qfalse);
518 
519 	// clear the whole hunk because we're (re)loading the server
520 	Hunk_Clear();
521 
522 	// clear collision map data
523 	CM_ClearMap();
524 
525 	// init client structures and svs.numSnapshotEntities
526 	if ( !Cvar_VariableValue( "sv_running" ) ) {
527 		SV_Startup();
528 	} else {
529 		// check for maxclients change
530 		if ( sv_maxclients->modified ) {
531 			SV_ChangeMaxClients();
532 		}
533 	}
534 
535 	// clear pak references
536 	FS_ClearPakReferences( 0 );
537 
538 	// allocate the snapshot entities on the hunk
539 	svs.snapshotEntities = Hunk_Alloc( sizeof( entityState_t ) * svs.numSnapshotEntities, h_high );
540 	svs.nextSnapshotEntities = 0;
541 
542 	// toggle the server bit so clients can detect that a
543 	// server has changed
544 	svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;
545 
546 	// set nextmap to the same map, but it may be overriden
547 	// by the game startup or another console command
548 	Cvar_Set( "nextmap", "map_restart 0" );
549 //	Cvar_Set( "nextmap", va("map %s", server) );
550 
551 	for (i=0 ; i<sv_maxclients->integer ; i++) {
552 		// save when the server started for each client already connected
553 		if (svs.clients[i].state >= CS_CONNECTED) {
554 			svs.clients[i].oldServerTime = sv.time;
555 		}
556 	}
557 
558 	// wipe the entire per-level structure
559 	SV_ClearServer();
560 
561 	// MrE: main zone should be pretty much emtpy at this point
562 	// except for file system data and cached renderer data
563 	Z_LogHeap();
564 
565 	// allocate empty config strings
566 	for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {
567 		sv.configstrings[i] = CopyString( "" );
568 	}
569 
570 	// Ridah
571 	// DHM - Nerve :: We want to use the completion bar in multiplayer as well
572 	if ( sv_gametype->integer == GT_SINGLE_PLAYER || sv_gametype->integer >= GT_WOLF ) {
573 		SV_SetExpectedHunkUsage( va( "maps/%s.bsp", server ) );
574 	} else {
575 		// just set it to a negative number,so the cgame knows not to draw the percent bar
576 		Cvar_Set( "com_expectedhunkusage", "-1" );
577 	}
578 
579 	// make sure we are not paused
580 	Cvar_Set( "cl_paused", "0" );
581 
582 	// get a new checksum feed and restart the file system
583 	sv.checksumFeed = ( ( (unsigned int)rand() << 16 ) ^ (unsigned int)rand() ) ^ Com_Milliseconds();
584 
585 	FS_Restart( sv.checksumFeed );
586 
587 	// Load map config if present
588 	Cbuf_ExecuteText(EXEC_NOW, va( "exec mapcfgs/%s.cfg\n", server ) );
589 
590 	CM_LoadMap( va( "maps/%s.bsp", server ), qfalse, &checksum );
591 
592 	// set serverinfo visible name
593 	Cvar_Set( "mapname", server );
594 
595 	Cvar_Set( "sv_mapChecksum", va( "%i",checksum ) );
596 
597 	// serverid should be different each time
598 	sv.serverId = com_frameTime;
599 	sv.restartedServerId = sv.serverId;
600 	sv.checksumFeedServerId = sv.serverId;
601 	Cvar_Set( "sv_serverid", va( "%i", sv.serverId ) );
602 
603 	// clear physics interaction links
604 	SV_ClearWorld();
605 
606 	// media configstring setting should be done during
607 	// the loading stage, so connected clients don't have
608 	// to load during actual gameplay
609 	sv.state = SS_LOADING;
610 
611 	Cvar_Set( "sv_serverRestarting", "1" );
612 
613 	// load and spawn all other entities
614 	SV_InitGameProgs();
615 
616 	// don't allow a map_restart if game is modified
617 	sv_gametype->modified = qfalse;
618 
619 	// run a few frames to allow everything to settle
620 	for (i = 0;i < 3; i++)
621 	{
622 		VM_Call (gvm, GAME_RUN_FRAME, sv.time);
623 		SV_BotFrame (sv.time);
624 		sv.time += 100;
625 		svs.time += 100;
626 	}
627 
628 	// create a baseline for more efficient communications
629 	SV_CreateBaseline();
630 
631 	for ( i = 0 ; i < sv_maxclients->integer ; i++ ) {
632 		// send the new gamestate to all connected clients
633 		if ( svs.clients[i].state >= CS_CONNECTED ) {
634 			char    *denied;
635 
636 			if ( svs.clients[i].netchan.remoteAddress.type == NA_BOT ) {
637 				if ( killBots || Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER ) {
638 					SV_DropClient( &svs.clients[i], "" );
639 					continue;
640 				}
641 				isBot = qtrue;
642 			} else {
643 				isBot = qfalse;
644 			}
645 
646 			// connect the client again
647 			denied = VM_ExplicitArgPtr( gvm, VM_Call( gvm, GAME_CLIENT_CONNECT, i, qfalse, isBot ) );   // firstTime = qfalse
648 			if ( denied ) {
649 				// this generally shouldn't happen, because the client
650 				// was connected before the level change
651 				SV_DropClient( &svs.clients[i], denied );
652 			} else {
653 				if ( !isBot ) {
654 					// when we get the next packet from a connected client,
655 					// the new gamestate will be sent
656 					svs.clients[i].state = CS_CONNECTED;
657 				} else {
658 					client_t        *client;
659 					sharedEntity_t  *ent;
660 
661 					client = &svs.clients[i];
662 					client->state = CS_ACTIVE;
663 					ent = SV_GentityNum( i );
664 					ent->s.number = i;
665 					client->gentity = ent;
666 
667 					client->deltaMessage = -1;
668 					client->lastSnapshotTime = 0;	// generate a snapshot immediately
669 
670 					VM_Call( gvm, GAME_CLIENT_BEGIN, i );
671 				}
672 			}
673 		}
674 	}
675 
676 	// run another frame to allow things to look at all the players
677 	VM_Call (gvm, GAME_RUN_FRAME, sv.time);
678 	SV_BotFrame (sv.time);
679 	sv.time += 100;
680 	svs.time += 100;
681 
682 	if ( sv_pure->integer ) {
683 		// the server sends these to the clients so they will only
684 		// load pk3s also loaded at the server
685 		p = FS_LoadedPakChecksums();
686 		Cvar_Set( "sv_paks", p );
687 		if ( strlen( p ) == 0 ) {
688 			Com_Printf( "WARNING: sv_pure set but no PK3 files loaded\n" );
689 		}
690 		p = FS_LoadedPakNames();
691 		Cvar_Set( "sv_pakNames", p );
692 
693 		// we want the server to reference the mp_bin pk3 that the client is expected to load from
694 		// we need to touch the cgame and ui because they could be in
695 		// seperate pk3 files and the client will need to download the pk3
696 		// files with the latest cgame and ui to pass the pure check
697 
698 		// Only touch the legacy dlls since we have qvm support
699 		SV_TouchFile( "cgame_mp_x86.dll" );
700 		SV_TouchFile( "ui_mp_x86.dll" );
701 	} else {
702 		Cvar_Set( "sv_paks", "" );
703 		Cvar_Set( "sv_pakNames", "" );
704 	}
705 	// the server sends these to the clients so they can figure
706 	// out which pk3s should be auto-downloaded
707 	// NOTE: we consider the referencedPaks as 'required for operation'
708 	p = FS_ReferencedPakChecksums();
709 	Cvar_Set( "sv_referencedPaks", p );
710 	p = FS_ReferencedPakNames();
711 	Cvar_Set( "sv_referencedPakNames", p );
712 
713 	// save systeminfo and serverinfo strings
714 	Q_strncpyz( systemInfo, Cvar_InfoString_Big( CVAR_SYSTEMINFO ), sizeof( systemInfo ) );
715 	cvar_modifiedFlags &= ~CVAR_SYSTEMINFO;
716 	SV_SetConfigstring( CS_SYSTEMINFO, systemInfo );
717 
718 	SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) );
719 	cvar_modifiedFlags &= ~CVAR_SERVERINFO;
720 
721 	// NERVE - SMF
722 	SV_SetConfigstring( CS_WOLFINFO, Cvar_InfoString( CVAR_WOLFINFO ) );
723 	cvar_modifiedFlags &= ~CVAR_WOLFINFO;
724 
725 	// any media configstring setting now should issue a warning
726 	// and any configstring changes should be reliably transmitted
727 	// to all clients
728 	sv.state = SS_GAME;
729 
730 	// send a heartbeat now so the master will get up to date info
731 	SV_Heartbeat_f();
732 
733 	Hunk_SetMark();
734 
735 #ifndef DEDICATED
736 	if ( com_dedicated->integer ) {
737 		// restart renderer in order to show console for dedicated servers
738 		// launched through the regular binary
739 		CL_StartHunkUsers( qtrue );
740 	}
741 #endif
742 
743 	Cvar_Set( "sv_serverRestarting", "0" );
744 
745 	Com_Printf( "-----------------------------------\n" );
746 }
747 
748 // DHM - Nerve :: Update Server
749 #ifdef UPDATE_SERVER
750 /*
751 ====================
752 SV_ParseVersionMapping
753 
754   Reads versionmap.cfg which sets up a mapping of client version to installer to download
755 ====================
756 */
SV_ParseVersionMapping(void)757 void SV_ParseVersionMapping( void ) {
758 	int handle;
759 	char *filename = "versionmap.cfg";
760 	char *buf;
761 	char *buftrav;
762 	char *token;
763 	int len;
764 
765 	len = FS_SV_FOpenFileRead( filename, &handle );
766 	if ( len >= 0 ) { // the file exists
767 
768 		buf = (char *)Z_Malloc( len + 1 );
769 		memset( buf, 0, len + 1 );
770 
771 		FS_Read( (void *)buf, len, handle );
772 		FS_FCloseFile( handle );
773 
774 		// now parse the file, setting the version table info
775 		buftrav = buf;
776 
777 		token = COM_Parse( &buftrav );
778 		if ( strcmp( token, "RTCW-VersionMap" ) ) {
779 			Z_Free( buf );
780 			Com_Error( ERR_FATAL, "invalid versionmap.cfg" );
781 			return;
782 		}
783 
784 		Com_Printf( "\n------------Update Server-------------\n\nParsing version map..." );
785 
786 		while ( ( token = COM_Parse( &buftrav ) ) && token[0] ) {
787 			// read the version number
788 			strcpy( versionMap[ numVersions ].version, token );
789 
790 			// read the platform
791 			token = COM_Parse( &buftrav );
792 			if ( token && token[0] ) {
793 				strcpy( versionMap[ numVersions ].platform, token );
794 			} else {
795 				Z_Free( buf );
796 				Com_Error( ERR_FATAL, "error parsing versionmap.cfg, after %s", versionMap[ numVersions ].version );
797 				return;
798 			}
799 
800 			// read the installer name
801 			token = COM_Parse( &buftrav );
802 			if ( token && token[0] ) {
803 				strcpy( versionMap[ numVersions ].installer, token );
804 			} else {
805 				Z_Free( buf );
806 				Com_Error( ERR_FATAL, "error parsing versionmap.cfg, after %s", versionMap[ numVersions ].platform );
807 				return;
808 			}
809 
810 			numVersions++;
811 			if ( numVersions >= MAX_UPDATE_VERSIONS ) {
812 				Z_Free( buf );
813 				Com_Error( ERR_FATAL, "Exceeded maximum number of mappings(%d)", MAX_UPDATE_VERSIONS );
814 				return;
815 			}
816 
817 		}
818 
819 		Com_Printf( " found %d mapping%c\n--------------------------------------\n\n", numVersions, numVersions > 1 ? 's' : ' ' );
820 
821 		Z_Free( buf );
822 	} else {
823 		Com_Error( ERR_FATAL, "Couldn't open versionmap.cfg" );
824 	}
825 }
826 #endif
827 
828 /*
829 ===============
830 SV_Init
831 
832 Only called at main exe startup, not for each game
833 ===============
834 */
SV_Init(void)835 void SV_Init( void ) {
836 	int index;
837 
838 	SV_AddOperatorCommands();
839 
840 	// serverinfo vars
841 	Cvar_Get( "dmflags", "0", /*CVAR_SERVERINFO*/ 0 );
842 	Cvar_Get( "fraglimit", "0", /*CVAR_SERVERINFO*/ 0 );
843 	Cvar_Get( "timelimit", "0", CVAR_SERVERINFO );
844 	// DHM - Nerve :: default to GT_WOLF
845 	sv_gametype = Cvar_Get( "g_gametype", "5", CVAR_SERVERINFO | CVAR_LATCH );
846 
847 	// Rafael gameskill
848 	sv_gameskill = Cvar_Get( "g_gameskill", "3", CVAR_SERVERINFO | CVAR_LATCH );
849 	// done
850 
851 	Cvar_Get( "sv_keywords", "", CVAR_SERVERINFO );
852 	sv_mapname = Cvar_Get( "mapname", "nomap", CVAR_SERVERINFO | CVAR_ROM );
853 	sv_privateClients = Cvar_Get( "sv_privateClients", "0", CVAR_SERVERINFO );
854 	sv_hostname = Cvar_Get( "sv_hostname", "WolfHost", CVAR_SERVERINFO | CVAR_ARCHIVE );
855 	sv_maxclients = Cvar_Get( "sv_maxclients", "20", CVAR_SERVERINFO | CVAR_LATCH );               // NERVE - SMF - changed to 20 from 8
856 
857 	sv_minRate = Cvar_Get ("sv_minRate", "0", CVAR_ARCHIVE | CVAR_SERVERINFO );
858 	sv_maxRate = Cvar_Get( "sv_maxRate", "0", CVAR_ARCHIVE | CVAR_SERVERINFO );
859 	sv_dlRate = Cvar_Get("sv_dlRate", "100", CVAR_ARCHIVE | CVAR_SERVERINFO);
860 	sv_minPing = Cvar_Get( "sv_minPing", "0", CVAR_ARCHIVE | CVAR_SERVERINFO );
861 	sv_maxPing = Cvar_Get( "sv_maxPing", "0", CVAR_ARCHIVE | CVAR_SERVERINFO );
862 	sv_floodProtect = Cvar_Get( "sv_floodProtect", "1", CVAR_ARCHIVE | CVAR_SERVERINFO );
863 	sv_allowAnonymous = Cvar_Get( "sv_allowAnonymous", "0", CVAR_SERVERINFO );
864 	sv_friendlyFire = Cvar_Get( "g_friendlyFire", "1", CVAR_SERVERINFO | CVAR_ARCHIVE );           // NERVE - SMF
865 	sv_maxlives = Cvar_Get( "g_maxlives", "0", CVAR_ARCHIVE | CVAR_LATCH | CVAR_SERVERINFO );      // NERVE - SMF
866 	sv_tourney = Cvar_Get( "g_noTeamSwitching", "0", CVAR_ARCHIVE );                               // NERVE - SMF
867 
868 	// systeminfo
869 	Cvar_Get( "sv_cheats", "1", CVAR_SYSTEMINFO | CVAR_ROM );
870 	sv_serverid = Cvar_Get( "sv_serverid", "0", CVAR_SYSTEMINFO | CVAR_ROM );
871 	sv_pure = Cvar_Get( "sv_pure", "1", CVAR_SYSTEMINFO );
872 #ifdef USE_VOIP
873 	sv_voip = Cvar_Get("sv_voip", "1", CVAR_LATCH);
874 	Cvar_CheckRange(sv_voip, 0, 1, qtrue);
875 	sv_voipProtocol = Cvar_Get("sv_voipProtocol", sv_voip->integer ? "opus" : "", CVAR_SYSTEMINFO | CVAR_ROM );
876 #endif
877 	Cvar_Get( "sv_paks", "", CVAR_SYSTEMINFO | CVAR_ROM );
878 	Cvar_Get( "sv_pakNames", "", CVAR_SYSTEMINFO | CVAR_ROM );
879 	Cvar_Get( "sv_referencedPaks", "", CVAR_SYSTEMINFO | CVAR_ROM );
880 	Cvar_Get( "sv_referencedPakNames", "", CVAR_SYSTEMINFO | CVAR_ROM );
881 
882 #if defined ANTIWALLHACK
883 	awh_active = Cvar_Get("awh_active", "0", CVAR_SYSTEMINFO);
884 	awh_bbox_horz = Cvar_Get("awh_bbox_horz", "30", CVAR_SYSTEMINFO);
885 	awh_bbox_vert = Cvar_Get("awh_bbox_vert", "60", CVAR_SYSTEMINFO);
886 
887 	AWH_Init();
888 #endif
889 
890 	// server vars
891 	sv_rconPassword = Cvar_Get( "rconPassword", "", CVAR_TEMP );
892 	sv_privatePassword = Cvar_Get( "sv_privatePassword", "", CVAR_TEMP );
893 #ifndef UPDATE_SERVER
894 	sv_fps = Cvar_Get( "sv_fps", "20", CVAR_TEMP );
895 #else
896 	sv_fps = Cvar_Get( "sv_fps", "60", CVAR_TEMP ); // this allows faster downloads
897 #endif
898 	sv_timeout = Cvar_Get( "sv_timeout", "240", CVAR_TEMP );
899 	sv_zombietime = Cvar_Get( "sv_zombietime", "2", CVAR_TEMP );
900 	Cvar_Get( "nextmap", "", CVAR_TEMP );
901 
902 	sv_allowDownload = Cvar_Get( "sv_allowDownload", "1", CVAR_ARCHIVE );
903 	Cvar_Get ("sv_dlURL", "", CVAR_SERVERINFO | CVAR_ARCHIVE);
904 
905 	sv_master[0] = Cvar_Get("sv_master1", MASTER_SERVER_NAME, 0);
906 	sv_master[1] = Cvar_Get("sv_master2", "master.iortcw.org", 0);
907 	for(index = 2; index < MAX_MASTER_SERVERS; index++)
908 		sv_master[index] = Cvar_Get(va("sv_master%d", index + 1), "", CVAR_ARCHIVE);
909 
910 	sv_reconnectlimit = Cvar_Get( "sv_reconnectlimit", "3", 0 );
911 	sv_showloss = Cvar_Get( "sv_showloss", "0", 0 );
912 	sv_padPackets = Cvar_Get( "sv_padPackets", "0", 0 );
913 	sv_killserver = Cvar_Get( "sv_killserver", "0", 0 );
914 	sv_mapChecksum = Cvar_Get( "sv_mapChecksum", "", CVAR_ROM );
915 	sv_lanForceRate = Cvar_Get( "sv_lanForceRate", "1", CVAR_ARCHIVE );
916 
917 	sv_banFile = Cvar_Get("sv_banFile", "serverbans.dat", CVAR_ARCHIVE);
918 
919 	sv_onlyVisibleClients = Cvar_Get( "sv_onlyVisibleClients", "0", 0 );       // DHM - Nerve
920 
921 	sv_forceNameUniq = Cvar_Get( "sv_forceNameUniq", "0", CVAR_ARCHIVE );
922 
923 	sv_showAverageBPS = Cvar_Get( "sv_showAverageBPS", "0", 0 );           // NERVE - SMF - net debugging
924 
925 	// NERVE - SMF - create user set cvars
926 	Cvar_Get( "g_userTimeLimit", "0", 0 );
927 	Cvar_Get( "g_userAlliedRespawnTime", "0", 0 );
928 	Cvar_Get( "g_userAxisRespawnTime", "0", 0 );
929 	Cvar_Get( "g_maxlives", "0", 0 );
930 	Cvar_Get( "g_noTeamSwitching", "0", CVAR_ARCHIVE );
931 	Cvar_Get( "g_altStopwatchMode", "0", CVAR_ARCHIVE );
932 	Cvar_Get( "g_minGameClients", "8", CVAR_SERVERINFO );
933 	Cvar_Get( "g_complaintlimit", "3", CVAR_ARCHIVE );
934 	Cvar_Get( "gamestate", "-1", CVAR_WOLFINFO | CVAR_ROM );
935 	Cvar_Get( "g_currentRound", "0", CVAR_WOLFINFO );
936 	Cvar_Get( "g_nextTimeLimit", "0", CVAR_WOLFINFO );
937 	// -NERVE - SMF
938 
939 	// TTimo - some UI additions
940 	// NOTE: sucks to have this hardcoded really, I suppose this should be in UI
941 	Cvar_Get( "g_axismaxlives", "0", 0 );
942 	Cvar_Get( "g_alliedmaxlives", "0", 0 );
943 	Cvar_Get( "g_fastres", "0", CVAR_ARCHIVE );
944 	Cvar_Get( "g_fastResMsec", "1000", CVAR_ARCHIVE );
945 
946 	// ATVI Tracker Wolfenstein Misc #273
947 	Cvar_Get( "g_voteFlags", "255", CVAR_ARCHIVE | CVAR_SERVERINFO );
948 
949 	// ATVI Tracker Wolfenstein Misc #263
950 	Cvar_Get( "g_antilag", "0", CVAR_ARCHIVE | CVAR_SERVERINFO );
951 
952 	// TTimo - autodownload speed tweaks
953 #ifndef UPDATE_SERVER
954 	// the download netcode tops at 18/20 kb/s, no need to make you think you can go above
955 	sv_dl_maxRate = Cvar_Get( "sv_dl_maxRate", "42000", CVAR_ARCHIVE );
956 #else
957 	// the update server is on steroids, sv_fps 60 and no snapshotMsec limitation, it can go up to 30 kb/s
958 	sv_dl_maxRate = Cvar_Get( "sv_dl_maxRate", "60000", CVAR_ARCHIVE );
959 #endif
960 
961 	// initialize bot cvars so they are listed and can be set before loading the botlib
962 	SV_BotInitCvars();
963 
964 	// init the botlib here because we need the pre-compiler in the UI
965 	SV_BotInitBotLib();
966 
967 	// DHM - Nerve
968 #ifdef UPDATE_SERVER
969 	SV_Startup();
970 	SV_ParseVersionMapping();
971 
972 	// serverid should be different each time
973 	sv.serverId = com_frameTime + 100;
974 	sv.restartedServerId = sv.serverId; // I suppose the init here is just to be safe
975 	sv.checksumFeedServerId = sv.serverId;
976 	Cvar_Set( "sv_serverid", va( "%i", sv.serverId ) );
977 	Cvar_Set( "mapname", "Update" );
978 
979 	// allocate empty config strings
980 	{
981 		int i;
982 
983 		for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {
984 			sv.configstrings[i] = CopyString( "" );
985 		}
986 	}
987 #endif
988 
989 	// Load saved bans
990 	Cbuf_AddText("rehashbans\n");
991 }
992 
993 
994 /*
995 ==================
996 SV_FinalMessage
997 
998 Used by SV_Shutdown to send a final message to all
999 connected clients before the server goes down.  The messages are sent immediately,
1000 not just stuck on the outgoing message list, because the server is going
1001 to totally exit after returning from this function.
1002 ==================
1003 */
SV_FinalMessage(char * message)1004 void SV_FinalMessage( char *message ) {
1005 	int i, j;
1006 	client_t    *cl;
1007 
1008 	// send it twice, ignoring rate
1009 	for ( j = 0 ; j < 2 ; j++ ) {
1010 		for ( i = 0, cl = svs.clients ; i < sv_maxclients->integer ; i++, cl++ ) {
1011 			if ( cl->state >= CS_CONNECTED ) {
1012 				// don't send a disconnect to a local client
1013 				if ( cl->netchan.remoteAddress.type != NA_LOOPBACK ) {
1014 					SV_SendServerCommand( cl, "print \"%s\n\"\n", message );
1015 					SV_SendServerCommand( cl, "disconnect \"%s\"", message );
1016 				}
1017 				// force a snapshot to be sent
1018 				cl->lastSnapshotTime = 0;
1019 				SV_SendClientSnapshot( cl );
1020 			}
1021 		}
1022 	}
1023 }
1024 
1025 
1026 /*
1027 ================
1028 SV_Shutdown
1029 
1030 Called when each game quits,
1031 before Sys_Quit or Sys_Error
1032 ================
1033 */
SV_Shutdown(char * finalmsg)1034 void SV_Shutdown( char *finalmsg ) {
1035 	if ( !com_sv_running || !com_sv_running->integer ) {
1036 		return;
1037 	}
1038 
1039 	Com_Printf( "----- Server Shutdown (%s) -----\n", finalmsg );
1040 
1041 	NET_LeaveMulticast6();
1042 
1043 	if ( svs.clients && !com_errorEntered ) {
1044 		SV_FinalMessage( finalmsg );
1045 	}
1046 
1047 	SV_RemoveOperatorCommands();
1048 	SV_MasterShutdown();
1049 	SV_ShutdownGameProgs();
1050 
1051 	// free current level
1052 	SV_ClearServer();
1053 
1054 	// free server static data
1055 	if(svs.clients)
1056 	{
1057 		int index;
1058 
1059 		for(index = 0; index < sv_maxclients->integer; index++)
1060 			SV_FreeClient(&svs.clients[index]);
1061 
1062 		free(svs.clients);
1063 	}
1064 	memset( &svs, 0, sizeof( svs ) );
1065 
1066 	Cvar_Set( "sv_running", "0" );
1067 
1068 	Com_Printf( "---------------------------\n" );
1069 
1070 	// disconnect any local clients
1071 	if( sv_killserver->integer != 2 )
1072 		CL_Disconnect( qfalse );
1073 }
1074 
1075