1 /*
2 ===========================================================================
3 Copyright (C) 1999 - 2005, Id Software, Inc.
4 Copyright (C) 2000 - 2013, Raven Software, Inc.
5 Copyright (C) 2001 - 2013, Activision, Inc.
6 Copyright (C) 2005 - 2015, ioquake3 contributors
7 Copyright (C) 2013 - 2015, OpenJK contributors
8 
9 This file is part of the OpenJK source code.
10 
11 OpenJK is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License version 2 as
13 published by the Free Software Foundation.
14 
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, see <http://www.gnu.org/licenses/>.
22 ===========================================================================
23 */
24 
25 #include "server.h"
26 #include "ghoul2/G2.h"
27 #include "qcommon/cm_public.h"
28 #include "qcommon/MiniHeap.h"
29 #include "qcommon/stringed_ingame.h"
30 #include "sv_gameapi.h"
31 
32 /*
33 ===============
34 SV_SendConfigstring
35 
36 Creates and sends the server command necessary to update the CS index for the
37 given client
38 ===============
39 */
SV_SendConfigstring(client_t * client,int index)40 static void SV_SendConfigstring(client_t *client, int index)
41 {
42 	int maxChunkSize = MAX_STRING_CHARS - 24;
43 	int len;
44 
45 	len = strlen(sv.configstrings[index]);
46 
47 	if( len >= maxChunkSize ) {
48 		int		sent = 0;
49 		int		remaining = len;
50 		char	*cmd;
51 		char	buf[MAX_STRING_CHARS];
52 
53 		while (remaining > 0 ) {
54 			if ( sent == 0 ) {
55 				cmd = "bcs0";
56 			}
57 			else if( remaining < maxChunkSize ) {
58 				cmd = "bcs2";
59 			}
60 			else {
61 				cmd = "bcs1";
62 			}
63 			Q_strncpyz( buf, &sv.configstrings[index][sent],
64 				maxChunkSize );
65 
66 			SV_SendServerCommand( client, "%s %i \"%s\"\n", cmd,
67 				index, buf );
68 
69 			sent += (maxChunkSize - 1);
70 			remaining -= (maxChunkSize - 1);
71 		}
72 	} else {
73 		// standard cs, just send it
74 		SV_SendServerCommand( client, "cs %i \"%s\"\n", index,
75 			sv.configstrings[index] );
76 	}
77 }
78 
79 /*
80 ===============
81 SV_UpdateConfigstrings
82 
83 Called when a client goes from CS_PRIMED to CS_ACTIVE.  Updates all
84 Configstring indexes that have changed while the client was in CS_PRIMED
85 ===============
86 */
SV_UpdateConfigstrings(client_t * client)87 void SV_UpdateConfigstrings(client_t *client)
88 {
89 	int index;
90 
91 	for( index = 0; index < MAX_CONFIGSTRINGS; index++ ) {
92 		// if the CS hasn't changed since we went to CS_PRIMED, ignore
93 		if(!client->csUpdated[index])
94 			continue;
95 
96 		// do not always send server info to all clients
97 		if ( index == CS_SERVERINFO && client->gentity &&
98 			(client->gentity->r.svFlags & SVF_NOSERVERINFO) ) {
99 			continue;
100 		}
101 		SV_SendConfigstring(client, index);
102 		client->csUpdated[index] = qfalse;
103 	}
104 }
105 
106 /*
107 ===============
108 SV_SetConfigstring
109 
110 ===============
111 */
SV_SetConfigstring(int index,const char * val)112 void SV_SetConfigstring (int index, const char *val) {
113 	int		i;
114 	client_t	*client;
115 
116 	if ( index < 0 || index >= MAX_CONFIGSTRINGS ) {
117 		Com_Error (ERR_DROP, "SV_SetConfigstring: bad index %i\n", index);
118 	}
119 
120 	if ( !val ) {
121 		val = "";
122 	}
123 
124 	// don't bother broadcasting an update if no change
125 	if ( !strcmp( val, sv.configstrings[ index ] ) ) {
126 		return;
127 	}
128 
129 	// change the string in sv
130 	Z_Free( sv.configstrings[index] );
131 	sv.configstrings[index] = CopyString( val );
132 
133 	// send it to all the clients if we aren't
134 	// spawning a new server
135 	if ( sv.state == SS_GAME || sv.restarting ) {
136 
137 		// send the data to all relevent clients
138 		for (i = 0, client = svs.clients; i < sv_maxclients->integer ; i++, client++) {
139 			if ( client->state < CS_ACTIVE ) {
140 				if ( client->state == CS_PRIMED )
141 					client->csUpdated[ index ] = qtrue;
142 				continue;
143 			}
144 			// do not always send server info to all clients
145 			if ( index == CS_SERVERINFO && client->gentity && (client->gentity->r.svFlags & SVF_NOSERVERINFO) ) {
146 				continue;
147 			}
148 
149 			SV_SendConfigstring(client, index);
150 		}
151 	}
152 }
153 
154 /*
155 ===============
156 SV_GetConfigstring
157 
158 ===============
159 */
SV_GetConfigstring(int index,char * buffer,int bufferSize)160 void SV_GetConfigstring( int index, char *buffer, int bufferSize ) {
161 	if ( bufferSize < 1 ) {
162 		Com_Error( ERR_DROP, "SV_GetConfigstring: bufferSize == %i", bufferSize );
163 	}
164 	if ( index < 0 || index >= MAX_CONFIGSTRINGS ) {
165 		Com_Error (ERR_DROP, "SV_GetConfigstring: bad index %i\n", index);
166 	}
167 	if ( !sv.configstrings[index] ) {
168 		buffer[0] = 0;
169 		return;
170 	}
171 
172 	Q_strncpyz( buffer, sv.configstrings[index], bufferSize );
173 }
174 
175 /*
176 ===============
177 SV_SetUserinfo
178 
179 ===============
180 */
SV_SetUserinfo(int index,const char * val)181 void SV_SetUserinfo( int index, const char *val ) {
182 	if ( index < 0 || index >= sv_maxclients->integer ) {
183 		Com_Error (ERR_DROP, "SV_SetUserinfo: bad index %i\n", index);
184 	}
185 
186 	if ( !val ) {
187 		val = "";
188 	}
189 
190 	Q_strncpyz( svs.clients[index].userinfo, val, sizeof( svs.clients[ index ].userinfo ) );
191 	Q_strncpyz( svs.clients[index].name, Info_ValueForKey( val, "name" ), sizeof(svs.clients[index].name) );
192 }
193 
194 /*
195 ===============
196 SV_GetUserinfo
197 
198 ===============
199 */
SV_GetUserinfo(int index,char * buffer,int bufferSize)200 void SV_GetUserinfo( int index, char *buffer, int bufferSize ) {
201 	if ( bufferSize < 1 ) {
202 		Com_Error( ERR_DROP, "SV_GetUserinfo: bufferSize == %i", bufferSize );
203 	}
204 	if ( index < 0 || index >= sv_maxclients->integer ) {
205 		Com_Error (ERR_DROP, "SV_GetUserinfo: bad index %i\n", index);
206 	}
207 	Q_strncpyz( buffer, svs.clients[ index ].userinfo, bufferSize );
208 }
209 
210 /*
211 ================
212 SV_CreateBaseline
213 
214 Entity baselines are used to compress non-delta messages
215 to the clients -- only the fields that differ from the
216 baseline will be transmitted
217 ================
218 */
SV_CreateBaseline(void)219 void SV_CreateBaseline( void ) {
220 	sharedEntity_t *svent;
221 	int				entnum;
222 
223 	for ( entnum = 1; entnum < sv.num_entities ; entnum++ ) {
224 		svent = SV_GentityNum(entnum);
225 		if (!svent->r.linked) {
226 			continue;
227 		}
228 		svent->s.number = entnum;
229 
230 		//
231 		// take current state as baseline
232 		//
233 		sv.svEntities[entnum].baseline = svent->s;
234 	}
235 }
236 
237 /*
238 ===============
239 SV_BoundMaxClients
240 
241 ===============
242 */
SV_BoundMaxClients(int minimum)243 void SV_BoundMaxClients( int minimum ) {
244 	// get the current maxclients value
245 	Cvar_Get( "sv_maxclients", "8", 0 );
246 
247 	sv_maxclients->modified = qfalse;
248 
249 	if ( sv_maxclients->integer < minimum ) {
250 		Cvar_Set( "sv_maxclients", va("%i", minimum) );
251 	} else if ( sv_maxclients->integer > MAX_CLIENTS ) {
252 		Cvar_Set( "sv_maxclients", va("%i", MAX_CLIENTS) );
253 	}
254 }
255 
256 /*
257 ===============
258 SV_Startup
259 
260 Called when a host starts a map when it wasn't running
261 one before.  Successive map or map_restart commands will
262 NOT cause this to be called, unless the game is exited to
263 the menu system first.
264 ===============
265 */
SV_Startup(void)266 void SV_Startup( void ) {
267 	if ( svs.initialized ) {
268 		Com_Error( ERR_FATAL, "SV_Startup: svs.initialized" );
269 	}
270 	SV_BoundMaxClients( 1 );
271 
272 	svs.clients = (struct client_s *)Z_Malloc (sizeof(client_t) * sv_maxclients->integer, TAG_CLIENTS, qtrue );
273 	if ( com_dedicated->integer ) {
274 		svs.numSnapshotEntities = sv_maxclients->integer * PACKET_BACKUP * MAX_SNAPSHOT_ENTITIES;
275 		Cvar_Set( "r_ghoul2animsmooth", "0");
276 		Cvar_Set( "r_ghoul2unsqashaftersmooth", "0");
277 
278 	} else {
279 		// we don't need nearly as many when playing locally
280 		svs.numSnapshotEntities = sv_maxclients->integer * 4 * MAX_SNAPSHOT_ENTITIES;
281 	}
282 	SV_ChallengeInit();
283 	svs.initialized = qtrue;
284 
285 	// Don't respect sv_killserver unless a server is actually running
286 	if ( sv_killserver->integer ) {
287 		Cvar_Set( "sv_killserver", "0" );
288 	}
289 
290 	Cvar_Set( "sv_running", "1" );
291 }
292 
293 /*
294 Ghoul2 Insert Start
295 */
296 
SV_InitSV(void)297  void SV_InitSV(void)
298 {
299 	// clear out most of the sv struct
300 	memset(&sv, 0, (sizeof(sv)));
301 	sv.mLocalSubBSPIndex = -1;
302 }
303 /*
304 Ghoul2 Insert End
305 */
306 
307 /*
308 ==================
309 SV_ChangeMaxClients
310 ==================
311 */
SV_ChangeMaxClients(void)312 void SV_ChangeMaxClients( void ) {
313 	int		oldMaxClients;
314 	int		i;
315 	client_t	*oldClients;
316 	int		count;
317 
318 	// get the highest client number in use
319 	count = 0;
320 	for ( i = 0 ; i < sv_maxclients->integer ; i++ ) {
321 		if ( svs.clients[i].state >= CS_CONNECTED ) {
322 			if (i > count)
323 				count = i;
324 		}
325 	}
326 	count++;
327 
328 	oldMaxClients = sv_maxclients->integer;
329 	// never go below the highest client number in use
330 	SV_BoundMaxClients( count );
331 	// if still the same
332 	if ( sv_maxclients->integer == oldMaxClients ) {
333 		return;
334 	}
335 
336 	oldClients = (struct client_s *)Hunk_AllocateTempMemory( count * sizeof(client_t) );
337 	// copy the clients to hunk memory
338 	for ( i = 0 ; i < count ; i++ ) {
339 		if ( svs.clients[i].state >= CS_CONNECTED ) {
340 			oldClients[i] = svs.clients[i];
341 		}
342 		else {
343 			Com_Memset(&oldClients[i], 0, sizeof(client_t));
344 		}
345 	}
346 
347 	// free old clients arrays
348 	Z_Free( svs.clients );
349 
350 	// allocate new clients
351 	svs.clients = (struct client_s *)Z_Malloc ( sv_maxclients->integer * sizeof(client_t), TAG_CLIENTS, qtrue );
352 	Com_Memset( svs.clients, 0, sv_maxclients->integer * sizeof(client_t) );
353 
354 	// copy the clients over
355 	for ( i = 0 ; i < count ; i++ ) {
356 		if ( oldClients[i].state >= CS_CONNECTED ) {
357 			svs.clients[i] = oldClients[i];
358 		}
359 	}
360 
361 	// free the old clients on the hunk
362 	Hunk_FreeTempMemory( oldClients );
363 
364 	// allocate new snapshot entities
365 	if ( com_dedicated->integer ) {
366 		svs.numSnapshotEntities = sv_maxclients->integer * PACKET_BACKUP * MAX_SNAPSHOT_ENTITIES;
367 	} else {
368 		// we don't need nearly as many when playing locally
369 		svs.numSnapshotEntities = sv_maxclients->integer * 4 * MAX_SNAPSHOT_ENTITIES;
370 	}
371 }
372 
373 /*
374 ================
375 SV_ClearServer
376 ================
377 */
SV_ClearServer(void)378 void SV_ClearServer(void) {
379 	int i;
380 
381 	for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {
382 		if ( sv.configstrings[i] ) {
383 			Z_Free( sv.configstrings[i] );
384 		}
385 	}
386 
387 //	CM_ClearMap();
388 
389 	/*
390 Ghoul2 Insert Start
391 */
392 
393 	// nope, can't do this anymore.. sv contains entitystates with STL in them.
394 //	memset (&sv, 0, sizeof(sv));
395  	SV_InitSV();
396 /*
397 Ghoul2 Insert End
398 */
399 //	Com_Memset (&sv, 0, sizeof(sv));
400 }
401 
402 /*
403 ================
404 SV_TouchCGame
405 
406   touch the cgame.vm so that a pure client can load it if it's in a seperate pk3
407 ================
408 */
SV_TouchCGame(void)409 void SV_TouchCGame(void) {
410 	fileHandle_t	f;
411 	char filename[MAX_QPATH];
412 
413 	Com_sprintf( filename, sizeof(filename), "cgamex86.dll" );
414 
415 	FS_FOpenFileRead( filename, &f, qfalse );
416 	if ( f ) {
417 		FS_FCloseFile( f );
418 	}
419 }
420 
SV_SendMapChange(void)421 void SV_SendMapChange(void)
422 {
423 	int		i;
424 
425 	if (svs.clients)
426 	{
427 		for (i=0 ; i<sv_maxclients->integer ; i++)
428 		{
429 			if (svs.clients[i].state >= CS_CONNECTED)
430 			{
431 				if ( svs.clients[i].netchan.remoteAddress.type != NA_BOT ||
432 					svs.clients[i].demo.demorecording )
433 				{
434 					SV_SendClientMapChange( &svs.clients[i] ) ;
435 				}
436 			}
437 		}
438 	}
439 }
440 
441 extern void SV_SendClientGameState( client_t *client );
442 /*
443 ================
444 SV_SpawnServer
445 
446 Change the server to a new map, taking all connected
447 clients along with it.
448 This is NOT called for map_restart
449 ================
450 */
SV_SpawnServer(char * server,qboolean killBots,ForceReload_e eForceReload)451 void SV_SpawnServer( char *server, qboolean killBots, ForceReload_e eForceReload ) {
452 	int			i;
453 	int			checksum;
454 	qboolean	isBot;
455 	char		systemInfo[16384];
456 	const char	*p;
457 
458 	SV_StopAutoRecordDemos();
459 
460 	SV_SendMapChange();
461 
462 	re->RegisterMedia_LevelLoadBegin(server, eForceReload);
463 
464 	// shut down the existing game if it is running
465 	SV_ShutdownGameProgs();
466 	svs.gameStarted = qfalse;
467 
468 	Com_Printf ("------ Server Initialization ------\n");
469 	Com_Printf ("Server: %s\n",server);
470 
471 /*
472 Ghoul2 Insert Start
473 */
474  	// de allocate the snapshot entities
475 	if (svs.snapshotEntities)
476 	{
477 		delete[] svs.snapshotEntities;
478 		svs.snapshotEntities = NULL;
479 	}
480 /*
481 Ghoul2 Insert End
482 */
483 
484 	SV_SendMapChange();
485 
486 	// if not running a dedicated server CL_MapLoading will connect the client to the server
487 	// also print some status stuff
488 	CL_MapLoading();
489 
490 #ifndef DEDICATED
491 	// make sure all the client stuff is unloaded
492 	CL_ShutdownAll( qfalse );
493 #endif
494 
495 	CM_ClearMap();
496 
497 	// clear the whole hunk because we're (re)loading the server
498 	Hunk_Clear();
499 
500 	re->InitSkins();
501 	re->InitShaders(qtrue);
502 
503 	// init client structures and svs.numSnapshotEntities
504 	if ( !Cvar_VariableValue("sv_running") ) {
505 		SV_Startup();
506 	} else {
507 		// check for maxclients change
508 		if ( sv_maxclients->modified ) {
509 			SV_ChangeMaxClients();
510 		}
511 	}
512 
513 	SV_SendMapChange();
514 
515 /*
516 Ghoul2 Insert Start
517 */
518  	// clear out those shaders, images and Models as long as this
519 	// isnt a dedicated server.
520 	/*
521 	if ( !com_dedicated->integer )
522 	{
523 #ifndef DEDICATED
524 		R_InitImages();
525 
526 		R_InitShaders();
527 
528 		R_ModelInit();
529 #endif
530 	}
531 	else
532 	*/
533 	if (com_dedicated->integer)
534 	{
535 		re->SVModelInit();
536 	}
537 
538 	SV_SendMapChange();
539 
540 	// clear pak references
541 	FS_ClearPakReferences(0);
542 
543 /*
544 Ghoul2 Insert Start
545 */
546 	// allocate the snapshot entities on the hunk
547 //	svs.snapshotEntities = (struct entityState_s *)Hunk_Alloc( sizeof(entityState_t)*svs.numSnapshotEntities, h_high );
548 	svs.nextSnapshotEntities = 0;
549 
550 	// allocate the snapshot entities
551 	svs.snapshotEntities = new entityState_s[svs.numSnapshotEntities];
552 	// we CAN afford to do this here, since we know the STL vectors in Ghoul2 are empty
553 	memset(svs.snapshotEntities, 0, sizeof(entityState_t)*svs.numSnapshotEntities);
554 
555 /*
556 Ghoul2 Insert End
557 */
558 
559 	// toggle the server bit so clients can detect that a
560 	// server has changed
561 	svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;
562 
563 	// set nextmap to the same map, but it may be overriden
564 	// by the game startup or another console command
565 	Cvar_Set( "nextmap", "map_restart 0");
566 //	Cvar_Set( "nextmap", va("map %s", server) );
567 
568 	for (i=0 ; i<sv_maxclients->integer ; i++) {
569 		// save when the server started for each client already connected
570 		if (svs.clients[i].state >= CS_CONNECTED) {
571 			svs.clients[i].oldServerTime = svs.time;
572 		}
573 	}
574 
575 	// wipe the entire per-level structure
576 	SV_ClearServer();
577 	for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {
578 		sv.configstrings[i] = CopyString("");
579 	}
580 
581 	//rww - RAGDOLL_BEGIN
582 	re->G2API_SetTime(sv.time,0);
583 	//rww - RAGDOLL_END
584 
585 	// make sure we are not paused
586 	Cvar_Set("cl_paused", "0");
587 
588 	// get a new checksum feed and restart the file system
589 	srand(Com_Milliseconds());
590 	sv.checksumFeed = ( ((int) rand() << 16) ^ rand() ) ^ Com_Milliseconds();
591 	FS_Restart( sv.checksumFeed );
592 
593 	CM_LoadMap( va("maps/%s.bsp", server), qfalse, &checksum );
594 
595 	SV_SendMapChange();
596 
597 	// set serverinfo visible name
598 	Cvar_Set( "mapname", server );
599 
600 	Cvar_Set( "sv_mapChecksum", va("%i",checksum) );
601 
602 	// serverid should be different each time
603 	sv.serverId = com_frameTime;
604 	sv.restartedServerId = sv.serverId; // I suppose the init here is just to be safe
605 	Cvar_Set( "sv_serverid", va("%i", sv.serverId ) );
606 
607 	time( &sv.realMapTimeStarted );
608 	sv.demosPruned = qfalse;
609 
610 	// clear physics interaction links
611 	SV_ClearWorld ();
612 
613 	// media configstring setting should be done during
614 	// the loading stage, so connected clients don't have
615 	// to load during actual gameplay
616 	sv.state = SS_LOADING;
617 
618 	// load and spawn all other entities
619 	SV_InitGameProgs();
620 
621 	// don't allow a map_restart if game is modified
622 	sv_gametype->modified = qfalse;
623 
624 	// run a few frames to allow everything to settle
625 	for ( i = 0 ;i < 3 ; i++ ) {
626 		//rww - RAGDOLL_BEGIN
627 		re->G2API_SetTime(sv.time,0);
628 		//rww - RAGDOLL_END
629 		GVM_RunFrame( sv.time );
630 		SV_BotFrame( sv.time );
631 		sv.time += 100;
632 		svs.time += 100;
633 	}
634 	//rww - RAGDOLL_BEGIN
635 	re->G2API_SetTime(sv.time,0);
636 	//rww - RAGDOLL_END
637 
638 	// create a baseline for more efficient communications
639 	SV_CreateBaseline ();
640 
641 	for (i=0 ; i<sv_maxclients->integer ; i++) {
642 		// send the new gamestate to all connected clients
643 		if (svs.clients[i].state >= CS_CONNECTED) {
644 			char	*denied;
645 
646 			if ( svs.clients[i].netchan.remoteAddress.type == NA_BOT ) {
647 				if ( killBots ) {
648 					SV_DropClient( &svs.clients[i], "" );
649 					continue;
650 				}
651 				isBot = qtrue;
652 			}
653 			else {
654 				isBot = qfalse;
655 			}
656 
657 			// connect the client again
658 			denied = GVM_ClientConnect( i, qfalse, isBot );	// firstTime = qfalse
659 			if ( denied ) {
660 				// this generally shouldn't happen, because the client
661 				// was connected before the level change
662 				SV_DropClient( &svs.clients[i], denied );
663 			} else {
664 				if( !isBot ) {
665 					// when we get the next packet from a connected client,
666 					// the new gamestate will be sent
667 					svs.clients[i].state = CS_CONNECTED;
668 				}
669 				else {
670 					client_t		*client;
671 					sharedEntity_t	*ent;
672 
673 					client = &svs.clients[i];
674 					client->state = CS_ACTIVE;
675 					ent = SV_GentityNum( i );
676 					ent->s.number = i;
677 					client->gentity = ent;
678 
679 					client->deltaMessage = -1;
680 					client->nextSnapshotTime = svs.time;	// generate a snapshot immediately
681 
682 					GVM_ClientBegin( i );
683 				}
684 			}
685 		}
686 	}
687 
688 	// run another frame to allow things to look at all the players
689 	GVM_RunFrame( sv.time );
690 	SV_BotFrame( sv.time );
691 	sv.time += 100;
692 	svs.time += 100;
693 	//rww - RAGDOLL_BEGIN
694 	re->G2API_SetTime(sv.time,0);
695 	//rww - RAGDOLL_END
696 
697 	if ( sv_pure->integer ) {
698 		// the server sends these to the clients so they will only
699 		// load pk3s also loaded at the server
700 		p = FS_LoadedPakChecksums();
701 		Cvar_Set( "sv_paks", p );
702 		if (strlen(p) == 0) {
703 			Com_Printf( "WARNING: sv_pure set but no PK3 files loaded\n" );
704 		}
705 		p = FS_LoadedPakNames();
706 		Cvar_Set( "sv_pakNames", p );
707 
708 		// if a dedicated pure server we need to touch the cgame because it could be in a
709 		// seperate pk3 file and the client will need to load the latest cgame.qvm
710 		if ( com_dedicated->integer ) {
711 			SV_TouchCGame();
712 		}
713 	}
714 	else {
715 		Cvar_Set( "sv_paks", "" );
716 		Cvar_Set( "sv_pakNames", "" );
717 	}
718 	// the server sends these to the clients so they can figure
719 	// out which pk3s should be auto-downloaded
720 	p = FS_ReferencedPakChecksums();
721 	Cvar_Set( "sv_referencedPaks", p );
722 	p = FS_ReferencedPakNames();
723 	Cvar_Set( "sv_referencedPakNames", p );
724 
725 	// save systeminfo and serverinfo strings
726 	Q_strncpyz( systemInfo, Cvar_InfoString_Big( CVAR_SYSTEMINFO ), sizeof( systemInfo ) );
727 	cvar_modifiedFlags &= ~CVAR_SYSTEMINFO;
728 	SV_SetConfigstring( CS_SYSTEMINFO, systemInfo );
729 
730 	SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) );
731 	cvar_modifiedFlags &= ~CVAR_SERVERINFO;
732 
733 	// any media configstring setting now should issue a warning
734 	// and any configstring changes should be reliably transmitted
735 	// to all clients
736 	sv.state = SS_GAME;
737 
738 	// send a heartbeat now so the master will get up to date info
739 	SV_Heartbeat_f();
740 
741 	Hunk_SetMark();
742 
743 	/* MrE: 2000-09-13: now called in CL_DownloadsComplete
744 	// don't call when running dedicated
745 	if ( !com_dedicated->integer ) {
746 		// note that this is called after setting the hunk mark with Hunk_SetMark
747 		CL_StartHunkUsers();
748 	}
749 	*/
750 
751 	for ( client_t *client = svs.clients; client - svs.clients < sv_maxclients->integer; client++) {
752 		// bots will not request gamestate, so it must be manually sent
753 		// cannot do this above where it says it will because mapname is not set at that time
754 		if ( client->netchan.remoteAddress.type == NA_BOT && client->demo.demorecording ) {
755 			SV_SendClientGameState( client );
756 		}
757 	}
758 
759 	SV_BeginAutoRecordDemos();
760 }
761 
762 
763 /*
764 ===============
765 SV_Init
766 
767 Only called at main exe startup, not for each game
768 ===============
769 */
770 void SV_BotInitBotLib(void);
771 
772 #ifdef DEDICATED
773 
774 #define G2_VERT_SPACE_SERVER_SIZE 256
775 IHeapAllocator *G2VertSpaceServer = NULL;
776 CMiniHeap IHeapAllocator_singleton(G2_VERT_SPACE_SERVER_SIZE * 1024);
777 
778 
779 /*
780 ================
781 CL_RefPrintf
782 
783 DLL glue
784 ================
785 */
SV_RefPrintf(int print_level,const char * fmt,...)786 void QDECL SV_RefPrintf( int print_level, const char *fmt, ...) {
787 	va_list		argptr;
788 	char		msg[MAXPRINTMSG];
789 
790 	va_start (argptr,fmt);
791 	Q_vsnprintf(msg, sizeof(msg), fmt, argptr);
792 	va_end (argptr);
793 
794 	if ( print_level == PRINT_ALL ) {
795 		Com_Printf ("%s", msg);
796 	} else if ( print_level == PRINT_WARNING ) {
797 		Com_Printf (S_COLOR_YELLOW "%s", msg);		// yellow
798 	} else if ( print_level == PRINT_DEVELOPER ) {
799 		Com_DPrintf (S_COLOR_RED "%s", msg);		// red
800 	}
801 }
802 
803 qboolean Com_TheHunkMarkHasBeenMade(void);
804 
805 //qcommon/vm.cpp
806 extern vm_t *currentVM;
807 
808 //qcommon/cm_load.cpp
809 extern void *gpvCachedMapDiskImage;
810 extern qboolean gbUsingCachedMapDataRightNow;
811 
GetSharedMemory(void)812 static char *GetSharedMemory( void ) { return sv.mSharedMemory; }
GetCurrentVM(void)813 static vm_t *GetCurrentVM( void ) { return currentVM; }
CM_GetCachedMapDiskImage(void)814 static void *CM_GetCachedMapDiskImage( void ) { return gpvCachedMapDiskImage; }
CM_SetCachedMapDiskImage(void * ptr)815 static void CM_SetCachedMapDiskImage( void *ptr ) { gpvCachedMapDiskImage = ptr; }
CM_SetUsingCache(qboolean usingCache)816 static void CM_SetUsingCache( qboolean usingCache ) { gbUsingCachedMapDataRightNow = usingCache; }
817 
818 //server stuff D:
819 extern void SV_GetConfigstring( int index, char *buffer, int bufferSize );
820 extern void SV_SetConfigstring( int index, const char *val );
821 
GetG2VertSpaceServer(void)822 static IHeapAllocator *GetG2VertSpaceServer( void ) {
823 	return G2VertSpaceServer;
824 }
825 
826 refexport_t	*re = NULL;
827 
SV_InitRef(void)828 static void SV_InitRef( void ) {
829 	static refimport_t ri;
830 	refexport_t *ret;
831 
832 	Com_Printf( "----- Initializing Renderer ----\n" );
833 
834 	memset( &ri, 0, sizeof( ri ) );
835 
836 	//set up the import table
837 	ri.Printf = SV_RefPrintf;
838 	ri.Error = Com_Error;
839 	ri.OPrintf = Com_OPrintf;
840 	ri.Milliseconds = Sys_Milliseconds2; //FIXME: unix+mac need this
841 	ri.Hunk_AllocateTempMemory = Hunk_AllocateTempMemory;
842 	ri.Hunk_FreeTempMemory = Hunk_FreeTempMemory;
843 	ri.Hunk_Alloc = Hunk_Alloc;
844 	ri.Hunk_MemoryRemaining = Hunk_MemoryRemaining;
845 	ri.Z_Malloc = Z_Malloc;
846 	ri.Z_Free = Z_Free;
847 	ri.Z_MemSize = Z_MemSize;
848 	ri.Z_MorphMallocTag = Z_MorphMallocTag;
849 	ri.Cmd_ExecuteString = Cmd_ExecuteString;
850 	ri.Cmd_Argc = Cmd_Argc;
851 	ri.Cmd_Argv = Cmd_Argv;
852 	ri.Cmd_ArgsBuffer = Cmd_ArgsBuffer;
853 	ri.Cmd_AddCommand = Cmd_AddCommand;
854 	ri.Cmd_RemoveCommand = Cmd_RemoveCommand;
855 	ri.Cvar_Set = Cvar_Set;
856 	ri.Cvar_Get = Cvar_Get;
857 	ri.Cvar_VariableStringBuffer = Cvar_VariableStringBuffer;
858 	ri.Cvar_VariableString = Cvar_VariableString;
859 	ri.Cvar_VariableValue = Cvar_VariableValue;
860 	ri.Cvar_VariableIntegerValue = Cvar_VariableIntegerValue;
861 	ri.Sys_LowPhysicalMemory = Sys_LowPhysicalMemory;
862 	ri.SE_GetString = SE_GetString;
863 	ri.FS_FreeFile = FS_FreeFile;
864 	ri.FS_FreeFileList = FS_FreeFileList;
865 	ri.FS_Read = FS_Read;
866 	ri.FS_ReadFile = FS_ReadFile;
867 	ri.FS_FCloseFile = FS_FCloseFile;
868 	ri.FS_FOpenFileRead = FS_FOpenFileRead;
869 	ri.FS_FOpenFileWrite = FS_FOpenFileWrite;
870 	ri.FS_FOpenFileByMode = FS_FOpenFileByMode;
871 	ri.FS_FileExists = FS_FileExists;
872 	ri.FS_FileIsInPAK = FS_FileIsInPAK;
873 	ri.FS_ListFiles = FS_ListFiles;
874 	ri.FS_Write = FS_Write;
875 	ri.FS_WriteFile = FS_WriteFile;
876 	ri.CM_BoxTrace = CM_BoxTrace;
877 	ri.CM_DrawDebugSurface = CM_DrawDebugSurface;
878 //	ri.CM_CullWorldBox = CM_CullWorldBox;
879 //	ri.CM_TerrainPatchIterate = CM_TerrainPatchIterate;
880 //	ri.CM_RegisterTerrain = CM_RegisterTerrain;
881 //	ri.CM_ShutdownTerrain = CM_ShutdownTerrain;
882 	ri.CM_ClusterPVS = CM_ClusterPVS;
883 	ri.CM_LeafArea = CM_LeafArea;
884 	ri.CM_LeafCluster = CM_LeafCluster;
885 	ri.CM_PointLeafnum = CM_PointLeafnum;
886 	ri.CM_PointContents = CM_PointContents;
887 	ri.Com_TheHunkMarkHasBeenMade = Com_TheHunkMarkHasBeenMade;
888 //	ri.S_RestartMusic = S_RestartMusic;
889 //	ri.SND_RegisterAudio_LevelLoadEnd = SND_RegisterAudio_LevelLoadEnd;
890 //	ri.CIN_RunCinematic = CIN_RunCinematic;
891 //	ri.CIN_PlayCinematic = CIN_PlayCinematic;
892 //	ri.CIN_UploadCinematic = CIN_UploadCinematic;
893 //	ri.CL_WriteAVIVideoFrame = CL_WriteAVIVideoFrame;
894 
895 	// g2 data access
896 	ri.GetSharedMemory = GetSharedMemory;
897 
898 	// (c)g vm callbacks
899 	ri.GetCurrentVM = GetCurrentVM;
900 //	ri.CGVMLoaded = CGVMLoaded;
901 //	ri.CGVM_RagCallback = CGVM_RagCallback;
902 
903 	// ugly win32 backend
904 	ri.CM_GetCachedMapDiskImage = CM_GetCachedMapDiskImage;
905 	ri.CM_SetCachedMapDiskImage = CM_SetCachedMapDiskImage;
906 	ri.CM_SetUsingCache = CM_SetUsingCache;
907 
908 	//FIXME: Might have to do something about this...
909 	ri.GetG2VertSpaceServer = GetG2VertSpaceServer;
910 	G2VertSpaceServer = &IHeapAllocator_singleton;
911 
912 	ret = GetRefAPI( REF_API_VERSION, &ri );
913 
914 //	Com_Printf( "-------------------------------\n");
915 
916 	if ( !ret ) {
917 		Com_Error (ERR_FATAL, "Couldn't initialize refresh" );
918 	}
919 
920 	re = ret;
921 }
922 #endif
923 
SV_Init(void)924 void SV_Init (void) {
925 
926 	time( &svs.startTime );
927 
928 	SV_AddOperatorCommands ();
929 
930 	// serverinfo vars
931 	Cvar_Get ("dmflags", "0", CVAR_SERVERINFO);
932 	Cvar_Get ("fraglimit", "20", CVAR_SERVERINFO);
933 	Cvar_Get ("timelimit", "0", CVAR_SERVERINFO);
934 	Cvar_Get ("capturelimit", "0", CVAR_SERVERINFO);
935 
936 	// Get these to establish them and to make sure they have a default before the menus decide to stomp them.
937 	Cvar_Get ("g_maxHolocronCarry", "3", CVAR_SERVERINFO);
938 	Cvar_Get ("g_privateDuel", "1", CVAR_SERVERINFO );
939 	Cvar_Get ("g_saberLocking", "1", CVAR_SERVERINFO );
940 	Cvar_Get ("g_maxForceRank", "7", CVAR_SERVERINFO );
941 	Cvar_Get ("duel_fraglimit", "10", CVAR_SERVERINFO);
942 	Cvar_Get ("g_forceBasedTeams", "0", CVAR_SERVERINFO);
943 	Cvar_Get ("g_duelWeaponDisable", "1", CVAR_SERVERINFO);
944 
945 	sv_gametype = Cvar_Get ("g_gametype", "0", CVAR_SERVERINFO | CVAR_LATCH, "Server gametype value" );
946 	sv_needpass = Cvar_Get ("g_needpass", "0", CVAR_SERVERINFO | CVAR_ROM, "Server needs password to join" );
947 	Cvar_Get ("sv_keywords", "", CVAR_SERVERINFO);
948 	Cvar_Get ("protocol", va("%i", PROTOCOL_VERSION), CVAR_SERVERINFO | CVAR_ROM);
949 	sv_mapname = Cvar_Get ("mapname", "nomap", CVAR_SERVERINFO | CVAR_ROM);
950 	sv_privateClients = Cvar_Get ("sv_privateClients", "0", CVAR_SERVERINFO, "Number of reserved client slots available with password" );
951 	Cvar_CheckRange( sv_privateClients, 0, MAX_CLIENTS, qtrue );
952 	sv_hostname = Cvar_Get ("sv_hostname", "*Jedi*", CVAR_SERVERINFO | CVAR_ARCHIVE, "The name of the server that is displayed in the serverlist" );
953 	sv_maxclients = Cvar_Get ("sv_maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH, "Max. connected clients" );
954 
955 
956 	//cvar_t	*sv_ratePolicy;		// 1-2
957 	//cvar_t	*sv_clientRate;
958 	sv_ratePolicy = Cvar_Get( "sv_ratePolicy", "1", CVAR_ARCHIVE_ND, "Determines which policy of enforcement is used for client's \"rate\" cvar" );
959 	Cvar_CheckRange(sv_ratePolicy, 1, 2, qtrue);
960 	sv_clientRate = Cvar_Get( "sv_clientRate", "50000", CVAR_ARCHIVE_ND);
961 	sv_minRate = Cvar_Get ("sv_minRate", "0", CVAR_ARCHIVE_ND | CVAR_SERVERINFO, "Min bandwidth rate allowed on server. Use 0 for unlimited." );
962 	sv_maxRate = Cvar_Get ("sv_maxRate", "0", CVAR_ARCHIVE_ND | CVAR_SERVERINFO, "Max bandwidth rate allowed on server. Use 0 for unlimited." );
963 	sv_minPing = Cvar_Get ("sv_minPing", "0", CVAR_ARCHIVE_ND | CVAR_SERVERINFO );
964 	sv_maxPing = Cvar_Get ("sv_maxPing", "0", CVAR_ARCHIVE_ND | CVAR_SERVERINFO );
965 	sv_floodProtect = Cvar_Get ("sv_floodProtect", "1", CVAR_ARCHIVE | CVAR_SERVERINFO, "Protect against flooding of server commands" );
966 	sv_floodProtectSlow = Cvar_Get ("sv_floodProtectSlow", "1", CVAR_ARCHIVE | CVAR_SERVERINFO, "Use original method of delaying commands with flood protection" );
967 	// systeminfo
968 	Cvar_Get ("sv_cheats", "1", CVAR_SYSTEMINFO | CVAR_ROM, "Allow cheats on server if set to 1" );
969 	sv_serverid = Cvar_Get ("sv_serverid", "0", CVAR_SYSTEMINFO | CVAR_ROM );
970 	sv_pure = Cvar_Get ("sv_pure", "0", CVAR_SYSTEMINFO, "Pure server" );
971 	Cvar_Get ("sv_paks", "", CVAR_SYSTEMINFO | CVAR_ROM );
972 	Cvar_Get ("sv_pakNames", "", CVAR_SYSTEMINFO | CVAR_ROM );
973 	Cvar_Get ("sv_referencedPaks", "", CVAR_SYSTEMINFO | CVAR_ROM );
974 	Cvar_Get ("sv_referencedPakNames", "", CVAR_SYSTEMINFO | CVAR_ROM );
975 
976 	// server vars
977 	sv_rconPassword = Cvar_Get ("rconPassword", "", CVAR_TEMP );
978 	sv_privatePassword = Cvar_Get ("sv_privatePassword", "", CVAR_TEMP );
979 	sv_snapsMin = Cvar_Get ("sv_snapsMin", "10", CVAR_ARCHIVE_ND ); // 1 <=> sv_snapsMax
980 	sv_snapsMax = Cvar_Get ("sv_snapsMax", "40", CVAR_ARCHIVE_ND ); // sv_snapsMin <=> sv_fps
981 	sv_snapsPolicy = Cvar_Get ("sv_snapsPolicy", "1", CVAR_ARCHIVE_ND, "Determines which policy of enforcement is used for client's \"snaps\" cvar");
982 	Cvar_CheckRange(sv_snapsPolicy, 0, 2, qtrue);
983 	sv_fps = Cvar_Get ("sv_fps", "40", CVAR_SERVERINFO, "Server frames per second" );
984 	sv_timeout = Cvar_Get ("sv_timeout", "200", CVAR_TEMP );
985 	sv_zombietime = Cvar_Get ("sv_zombietime", "2", CVAR_TEMP );
986 	Cvar_Get ("nextmap", "", CVAR_TEMP );
987 
988 	sv_allowDownload = Cvar_Get ("sv_allowDownload", "0", CVAR_SERVERINFO, "Allow clients to download mod files via UDP from the server");
989 	sv_master[0] = Cvar_Get ("sv_master1", MASTER_SERVER_NAME, CVAR_PROTECTED );
990 	sv_master[1] = Cvar_Get ("sv_master2", JKHUB_MASTER_SERVER_NAME, CVAR_PROTECTED);
991 	for(int index = 2; index < MAX_MASTER_SERVERS; index++)
992 		sv_master[index] = Cvar_Get(va("sv_master%d", index + 1), "", CVAR_ARCHIVE_ND|CVAR_PROTECTED);
993 	sv_reconnectlimit = Cvar_Get ("sv_reconnectlimit", "3", 0);
994 	sv_showghoultraces = Cvar_Get ("sv_showghoultraces", "0", 0);
995 	sv_showloss = Cvar_Get ("sv_showloss", "0", 0);
996 	sv_padPackets = Cvar_Get ("sv_padPackets", "0", 0);
997 	sv_killserver = Cvar_Get ("sv_killserver", "0", 0);
998 	sv_mapChecksum = Cvar_Get ("sv_mapChecksum", "", CVAR_ROM);
999 	sv_lanForceRate = Cvar_Get ("sv_lanForceRate", "1", CVAR_ARCHIVE_ND );
1000 
1001 	sv_filterCommands = Cvar_Get( "sv_filterCommands", "1", CVAR_ARCHIVE );
1002 
1003 //	sv_debugserver = Cvar_Get ("sv_debugserver", "0", 0);
1004 
1005 	sv_autoDemo = Cvar_Get( "sv_autoDemo", "0", CVAR_ARCHIVE_ND | CVAR_SERVERINFO, "Automatically take server-side demos" );
1006 	sv_autoDemoBots = Cvar_Get( "sv_autoDemoBots", "0", CVAR_ARCHIVE_ND, "Record server-side demos for bots" );
1007 	sv_autoDemoMaxMaps = Cvar_Get( "sv_autoDemoMaxMaps", "0", CVAR_ARCHIVE_ND );
1008 
1009 	sv_legacyFixes = Cvar_Get( "sv_legacyFixes", "1", CVAR_ARCHIVE );
1010 
1011 	sv_banFile = Cvar_Get( "sv_banFile", "serverbans.dat", CVAR_ARCHIVE, "File to use to store bans and exceptions" );
1012 
1013 	sv_maxOOBRate = Cvar_Get("sv_maxOOBRate", "1000", CVAR_ARCHIVE, "Maximum rate of handling incoming server commands" );
1014 	sv_maxOOBRateIP = Cvar_Get("sv_maxOOBRateIP", "1", CVAR_ARCHIVE, "Maximum rate of handling incoming server commands per IP address" );
1015 	sv_autoWhitelist = Cvar_Get("sv_autoWhitelist", "1", CVAR_ARCHIVE, "Save player IPs to allow them using server during DOS attack" );
1016 
1017 	// initialize bot cvars so they are listed and can be set before loading the botlib
1018 	SV_BotInitCvars();
1019 
1020 	// init the botlib here because we need the pre-compiler in the UI
1021 	SV_BotInitBotLib();
1022 
1023 	// Load saved bans
1024 	Cbuf_AddText("sv_rehashbans\n");
1025 
1026 	// Load IP whitelist
1027 	SVC_LoadWhitelist();
1028 
1029 	// Only allocated once, no point in moving it around and fragmenting
1030 	// create a heap for Ghoul2 to use for game side model vertex transforms used in collision detection
1031 #ifdef DEDICATED
1032 	SV_InitRef();
1033 #endif
1034 }
1035 
1036 
1037 /*
1038 ==================
1039 SV_FinalMessage
1040 
1041 Used by SV_Shutdown to send a final message to all
1042 connected clients before the server goes down.  The messages are sent immediately,
1043 not just stuck on the outgoing message list, because the server is going
1044 to totally exit after returning from this function.
1045 ==================
1046 */
SV_FinalMessage(char * message)1047 void SV_FinalMessage( char *message ) {
1048 	int			i, j;
1049 	client_t	*cl;
1050 
1051 	// send it twice, ignoring rate
1052 	for ( j = 0 ; j < 2 ; j++ ) {
1053 		for (i=0, cl = svs.clients ; i < sv_maxclients->integer ; i++, cl++) {
1054 			if (cl->state >= CS_CONNECTED) {
1055 				// don't send a disconnect to a local client
1056 				if ( cl->netchan.remoteAddress.type != NA_LOOPBACK ) {
1057 					SV_SendServerCommand( cl, "print \"%s\"", message );
1058 					SV_SendServerCommand( cl, "disconnect" );
1059 				}
1060 				// force a snapshot to be sent
1061 				cl->nextSnapshotTime = -1;
1062 				SV_SendClientSnapshot( cl );
1063 			}
1064 		}
1065 	}
1066 }
1067 
1068 
1069 /*
1070 ================
1071 SV_Shutdown
1072 
1073 Called when each game quits,
1074 before Sys_Quit or Sys_Error
1075 ================
1076 */
SV_Shutdown(char * finalmsg)1077 void SV_Shutdown( char *finalmsg )
1078 {
1079 	if ( !com_sv_running || !com_sv_running->integer )
1080 	{
1081 		return;
1082 	}
1083 
1084 //	Com_Printf( "----- Server Shutdown -----\n" );
1085 
1086 	if ( svs.clients && !com_errorEntered ) {
1087 		SV_FinalMessage( finalmsg );
1088 	}
1089 
1090 	SV_RemoveOperatorCommands();
1091 	SV_MasterShutdown();
1092 	SV_ChallengeShutdown();
1093 	SV_ShutdownGameProgs();
1094 	svs.gameStarted = qfalse;
1095 /*
1096 Ghoul2 Insert Start
1097 */
1098  	// de allocate the snapshot entities
1099 	if (svs.snapshotEntities)
1100 	{
1101 		delete[] svs.snapshotEntities;
1102 		svs.snapshotEntities = NULL;
1103 	}
1104 
1105 	// free current level
1106 	SV_ClearServer();
1107 	CM_ClearMap();//jfm: add a clear here since it's commented out in clearServer.  This prevents crashing cmShaderTable on exit.
1108 
1109 	// free server static data
1110 	if ( svs.clients ) {
1111 		Z_Free( svs.clients );
1112 	}
1113 	Com_Memset( &svs, 0, sizeof( svs ) );
1114 
1115 	Cvar_Set( "sv_running", "0" );
1116 	Cvar_Set("ui_singlePlayerActive", "0");
1117 
1118 //	Com_Printf( "---------------------------\n" );
1119 
1120 	// disconnect any local clients
1121 	if( sv_killserver->integer != 2 )
1122 		CL_Disconnect( qfalse );
1123 }
1124