• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 // host.c -- coordinates spawning and killing of local servers
21 
22 #include "quakedef.h"
23 #include "r_local.h"
24 
25 /*
26 
27 A server can allways be started, even if the system started out as a client
28 to a remote system.
29 
30 A client can NOT be started if the system started as a dedicated server.
31 
32 Memory is cleared / released when a server or client begins, not when they end.
33 
34 */
35 
36 quakeparms_t host_parms;
37 
38 qboolean	host_initialized;		// true if into command execution
39 
40 double		host_frametime;
41 double		host_time;
42 double		realtime;				// without any filtering or bounding
43 double		oldrealtime;			// last frame run
44 int			host_framecount;
45 
46 int			host_hunklevel;
47 
48 int			minimum_memory;
49 
50 client_t	*host_client;			// current client
51 
52 jmp_buf 	host_abortserver;
53 
54 byte		*host_basepal;
55 byte		*host_colormap;
56 
57 cvar_t	host_framerate = CVAR2("host_framerate","0");	// set for slow motion
58 cvar_t	host_speeds = CVAR2("host_speeds","0");			// set for running times
59 
60 cvar_t	sys_ticrate = CVAR2("sys_ticrate","0.05");
61 cvar_t	serverprofile = CVAR2("serverprofile","0");
62 
63 cvar_t	fraglimit = CVAR4("fraglimit","0",false,true);
64 cvar_t	timelimit = CVAR4("timelimit","0",false,true);
65 cvar_t	teamplay = CVAR4("teamplay","0",false,true);
66 
67 cvar_t	samelevel = CVAR2("samelevel","0");
68 cvar_t	noexit = CVAR4("noexit","0",false,true);
69 
70 #ifdef QUAKE2
71 cvar_t	developer = CVAR2("developer","1");	// should be 0 for release!
72 #else
73 cvar_t	developer = CVAR2("developer","0");
74 #endif
75 
76 cvar_t	skill = CVAR2("skill","1");						// 0 - 3
77 cvar_t	deathmatch = CVAR2("deathmatch","0");			// 0, 1, or 2
78 cvar_t	coop = CVAR2("coop","0");			// 0 or 1
79 
80 cvar_t	pausable = CVAR2("pausable","1");
81 
82 cvar_t	temp1 = CVAR2("temp1","0");
83 
84 
85 /*
86 ================
87 Host_EndGame
88 ================
89 */
Host_EndGame(const char * message,...)90 void Host_EndGame (const char *message, ...)
91 {
92 	va_list		argptr;
93 	char		string[1024];
94 
95 	va_start (argptr,message);
96 	vsprintf (string,message,argptr);
97 	va_end (argptr);
98 	Con_DPrintf ("Host_EndGame: %s\n",string);
99 
100 	if (sv.active)
101 		Host_ShutdownServer (false);
102 
103 	if (cls.state == ca_dedicated)
104 		Sys_Error ("Host_EndGame: %s\n",string);	// dedicated servers exit
105 
106 	if (cls.demonum != -1)
107 		CL_NextDemo ();
108 	else
109 		CL_Disconnect ();
110 
111 	longjmp (host_abortserver, 1);
112 }
113 
114 /*
115 ================
116 Host_Error
117 
118 This shuts down both the client and server
119 ================
120 */
Host_Error(const char * error,...)121 void Host_Error (const char *error, ...)
122 {
123 	va_list		argptr;
124 	char		string[1024];
125 	static	qboolean inerror = false;
126 
127 	if (inerror)
128 		Sys_Error ("Host_Error: recursively entered");
129 	inerror = true;
130 
131 	SCR_EndLoadingPlaque ();		// reenable screen updates
132 
133 	va_start (argptr,error);
134 	vsprintf (string,error,argptr);
135 	va_end (argptr);
136 	Con_Printf ("Host_Error: %s\n",string);
137 
138 	if (sv.active)
139 		Host_ShutdownServer (false);
140 
141 	if (cls.state == ca_dedicated)
142 		Sys_Error ("Host_Error: %s\n",string);	// dedicated servers exit
143 
144 	CL_Disconnect ();
145 	cls.demonum = -1;
146 
147 	inerror = false;
148 
149 	longjmp (host_abortserver, 1);
150 }
151 
152 /*
153 ================
154 Host_FindMaxClients
155 ================
156 */
Host_FindMaxClients(void)157 void	Host_FindMaxClients (void)
158 {
159 	int		i;
160 
161 	svs.maxclients = 1;
162 
163 	i = COM_CheckParm ("-dedicated");
164 	if (i)
165 	{
166 		cls.state = ca_dedicated;
167 		if (i != (com_argc - 1))
168 		{
169 			svs.maxclients = Q_atoi (com_argv[i+1]);
170 		}
171 		else
172 			svs.maxclients = 8;
173 	}
174 	else
175 		cls.state = ca_disconnected;
176 
177 	i = COM_CheckParm ("-listen");
178 	if (i)
179 	{
180 		if (cls.state == ca_dedicated)
181 			Sys_Error ("Only one of -dedicated or -listen can be specified");
182 		if (i != (com_argc - 1))
183 			svs.maxclients = Q_atoi (com_argv[i+1]);
184 		else
185 			svs.maxclients = 8;
186 	}
187 	if (svs.maxclients < 1)
188 		svs.maxclients = 8;
189 	else if (svs.maxclients > MAX_SCOREBOARD)
190 		svs.maxclients = MAX_SCOREBOARD;
191 
192 	svs.maxclientslimit = svs.maxclients;
193 	if (svs.maxclientslimit < 4)
194 		svs.maxclientslimit = 4;
195 	svs.clients = (client_s*) Hunk_AllocName (svs.maxclientslimit*sizeof(client_t), "clients");
196 
197 	if (svs.maxclients > 1)
198 		Cvar_SetValue ("deathmatch", 1.0);
199 	else
200 		Cvar_SetValue ("deathmatch", 0.0);
201 }
202 
203 
204 /*
205 =======================
206 Host_InitLocal
207 ======================
208 */
Host_InitLocal(void)209 void Host_InitLocal (void)
210 {
211 	Host_InitCommands ();
212 
213 	Cvar_RegisterVariable (&host_framerate);
214 	Cvar_RegisterVariable (&host_speeds);
215 
216 	Cvar_RegisterVariable (&sys_ticrate);
217 	Cvar_RegisterVariable (&serverprofile);
218 
219 	Cvar_RegisterVariable (&fraglimit);
220 	Cvar_RegisterVariable (&timelimit);
221 	Cvar_RegisterVariable (&teamplay);
222 	Cvar_RegisterVariable (&samelevel);
223 	Cvar_RegisterVariable (&noexit);
224 	Cvar_RegisterVariable (&skill);
225 	Cvar_RegisterVariable (&developer);
226 	Cvar_RegisterVariable (&deathmatch);
227 	Cvar_RegisterVariable (&coop);
228 
229 	Cvar_RegisterVariable (&pausable);
230 
231 	Cvar_RegisterVariable (&temp1);
232 
233 	Host_FindMaxClients ();
234 
235 	host_time = 1.0;		// so a think at time 0 won't get called
236 }
237 
238 
239 /*
240 ===============
241 Host_WriteConfiguration
242 
243 Writes key bindings and archived cvars to config.cfg
244 ===============
245 */
Host_WriteConfiguration(void)246 void Host_WriteConfiguration (void)
247 {
248 	FILE	*f;
249 
250 // dedicated servers initialize the host but don't parse and set the
251 // config.cfg cvars
252 	if (host_initialized & !isDedicated)
253 	{
254 		f = fopen (va("%s/config.cfg",com_gamedir), "w");
255 		if (!f)
256 		{
257 			Con_Printf ("Couldn't write config.cfg.\n");
258 			return;
259 		}
260 
261 		Key_WriteBindings (f);
262 		Cvar_WriteVariables (f);
263 
264 		fclose (f);
265 	}
266 }
267 
268 
269 /*
270 =================
271 SV_ClientPrintf
272 
273 Sends text across to be displayed
274 FIXME: make this just a stuffed echo?
275 =================
276 */
SV_ClientPrintf(const char * fmt,...)277 void SV_ClientPrintf (const char *fmt, ...)
278 {
279 	va_list		argptr;
280 	char		string[1024];
281 
282 	va_start (argptr,fmt);
283 	vsprintf (string, fmt,argptr);
284 	va_end (argptr);
285 
286 	MSG_WriteByte (&host_client->message, svc_print);
287 	MSG_WriteString (&host_client->message, string);
288 }
289 
290 /*
291 =================
292 SV_BroadcastPrintf
293 
294 Sends text to all active clients
295 =================
296 */
SV_BroadcastPrintf(const char * fmt,...)297 void SV_BroadcastPrintf (const char *fmt, ...)
298 {
299 	va_list		argptr;
300 	char		string[1024];
301 	int			i;
302 
303 	va_start (argptr,fmt);
304 	vsprintf (string, fmt,argptr);
305 	va_end (argptr);
306 
307 	for (i=0 ; i<svs.maxclients ; i++)
308 		if (svs.clients[i].active && svs.clients[i].spawned)
309 		{
310 			MSG_WriteByte (&svs.clients[i].message, svc_print);
311 			MSG_WriteString (&svs.clients[i].message, string);
312 		}
313 }
314 
315 /*
316 =================
317 Host_ClientCommands
318 
319 Send text over to the client to be executed
320 =================
321 */
Host_ClientCommands(const char * fmt,...)322 void Host_ClientCommands (const char *fmt, ...)
323 {
324 	va_list		argptr;
325 	char		string[1024];
326 
327 	va_start (argptr,fmt);
328 	vsprintf (string, fmt,argptr);
329 	va_end (argptr);
330 
331 	MSG_WriteByte (&host_client->message, svc_stufftext);
332 	MSG_WriteString (&host_client->message, string);
333 }
334 
335 /*
336 =====================
337 SV_DropClient
338 
339 Called when the player is getting totally kicked off the host
340 if (crash = true), don't bother sending signofs
341 =====================
342 */
SV_DropClient(qboolean crash)343 void SV_DropClient (qboolean crash)
344 {
345 	int		saveSelf;
346 	int		i;
347 	client_t *client;
348 
349 	if (!crash)
350 	{
351 		// send any final messages (don't check for errors)
352 		if (NET_CanSendMessage (host_client->netconnection))
353 		{
354 			MSG_WriteByte (&host_client->message, svc_disconnect);
355 			NET_SendMessage (host_client->netconnection, &host_client->message);
356 		}
357 
358 		if (host_client->edict && host_client->spawned)
359 		{
360 		// call the prog function for removing a client
361 		// this will set the body to a dead frame, among other things
362 			saveSelf = pr_global_struct->self;
363 			pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
364 			PR_ExecuteProgram (pr_global_struct->ClientDisconnect);
365 			pr_global_struct->self = saveSelf;
366 		}
367 
368 		Sys_Printf ("Client %s removed\n",host_client->name);
369 	}
370 
371 // break the net connection
372 	NET_Close (host_client->netconnection);
373 	host_client->netconnection = NULL;
374 
375 // free the client (the body stays around)
376 	host_client->active = false;
377 	host_client->name[0] = 0;
378 	host_client->old_frags = -999999;
379 	net_activeconnections--;
380 
381 // send notification to all clients
382 	for (i=0, client = svs.clients ; i<svs.maxclients ; i++, client++)
383 	{
384 		if (!client->active)
385 			continue;
386 		MSG_WriteByte (&client->message, svc_updatename);
387 		MSG_WriteByte (&client->message, host_client - svs.clients);
388 		MSG_WriteString (&client->message, "");
389 		MSG_WriteByte (&client->message, svc_updatefrags);
390 		MSG_WriteByte (&client->message, host_client - svs.clients);
391 		MSG_WriteShort (&client->message, 0);
392 		MSG_WriteByte (&client->message, svc_updatecolors);
393 		MSG_WriteByte (&client->message, host_client - svs.clients);
394 		MSG_WriteByte (&client->message, 0);
395 	}
396 }
397 
398 /*
399 ==================
400 Host_ShutdownServer
401 
402 This only happens at the end of a game, not between levels
403 ==================
404 */
Host_ShutdownServer(qboolean crash)405 void Host_ShutdownServer(qboolean crash)
406 {
407 	int		i;
408 	int		count;
409 	sizebuf_t	buf;
410 	char		message[4];
411 	double	start;
412 
413 	if (!sv.active)
414 		return;
415 
416 	sv.active = false;
417 
418 // stop all client sounds immediately
419 	if (cls.state == ca_connected)
420 		CL_Disconnect ();
421 
422 // flush any pending messages - like the score!!!
423 	start = Sys_FloatTime();
424 	do
425 	{
426 		count = 0;
427 		for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
428 		{
429 			if (host_client->active && host_client->message.cursize)
430 			{
431 				if (NET_CanSendMessage (host_client->netconnection))
432 				{
433 					NET_SendMessage(host_client->netconnection, &host_client->message);
434 					SZ_Clear (&host_client->message);
435 				}
436 				else
437 				{
438 					NET_GetMessage(host_client->netconnection);
439 					count++;
440 				}
441 			}
442 		}
443 		if ((Sys_FloatTime() - start) > 3.0)
444 			break;
445 	}
446 	while (count);
447 
448 // make sure all the clients know we're disconnecting
449 	buf.data = (byte*) message;
450 	buf.maxsize = 4;
451 	buf.cursize = 0;
452 	MSG_WriteByte(&buf, svc_disconnect);
453 	count = NET_SendToAll(&buf, 5);
454 	if (count)
455 		Con_Printf("Host_ShutdownServer: NET_SendToAll failed for %u clients\n", count);
456 
457 	for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
458 		if (host_client->active)
459 			SV_DropClient(crash);
460 
461 //
462 // clear structures
463 //
464 	memset (&sv, 0, sizeof(sv));
465 	memset (svs.clients, 0, svs.maxclientslimit*sizeof(client_t));
466 }
467 
468 
469 /*
470 ================
471 Host_ClearMemory
472 
473 This clears all the memory used by both the client and server, but does
474 not reinitialize anything.
475 ================
476 */
Host_ClearMemory(void)477 void Host_ClearMemory (void)
478 {
479 	Con_DPrintf ("Clearing memory\n");
480 	D_FlushCaches ();
481 	Mod_ClearAll ();
482 	if (host_hunklevel)
483 		Hunk_FreeToLowMark (host_hunklevel);
484 
485 	cls.signon = 0;
486 	memset (&sv, 0, sizeof(sv));
487 	memset (&cl, 0, sizeof(cl));
488 }
489 
490 
491 //============================================================================
492 
493 
494 /*
495 ===================
496 Host_FilterTime
497 
498 Returns false if the time is too short to run a frame
499 ===================
500 */
Host_FilterTime(float time)501 qboolean Host_FilterTime (float time)
502 {
503 	realtime += time;
504 
505 	if (!cls.timedemo && realtime - oldrealtime < 1.0/72.0)
506 		return false;		// framerate is too high
507 
508 	host_frametime = realtime - oldrealtime;
509 	oldrealtime = realtime;
510 
511 	if (host_framerate.value > 0)
512 		host_frametime = host_framerate.value;
513 	else
514 	{	// don't allow really long or short frames
515 		if (host_frametime > 0.1)
516 			host_frametime = 0.1;
517 		if (host_frametime < 0.001)
518 			host_frametime = 0.001;
519 	}
520 
521 	return true;
522 }
523 
524 
525 /*
526 ===================
527 Host_GetConsoleCommands
528 
529 Add them exactly as if they had been typed at the console
530 ===================
531 */
Host_GetConsoleCommands(void)532 void Host_GetConsoleCommands (void)
533 {
534 	char	*cmd;
535 
536 	while (1)
537 	{
538 		cmd = Sys_ConsoleInput ();
539 		if (!cmd)
540 			break;
541 		Cbuf_AddText (cmd);
542 	}
543 }
544 
545 
546 /*
547 ==================
548 Host_ServerFrame
549 
550 ==================
551 */
552 #ifdef FPS_20
553 
_Host_ServerFrame(void)554 void _Host_ServerFrame (void)
555 {
556 // run the world state
557 	pr_global_struct->frametime = host_frametime;
558 
559 // read client messages
560 	SV_RunClients ();
561 
562 // move things around and think
563 // always pause in single player if in console or menus
564 	if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) )
565 		SV_Physics ();
566 }
567 
Host_ServerFrame(void)568 void Host_ServerFrame (void)
569 {
570 	float	save_host_frametime;
571 	float	temp_host_frametime;
572 
573 // run the world state
574 	pr_global_struct->frametime = host_frametime;
575 
576 // set the time and clear the general datagram
577 	SV_ClearDatagram ();
578 
579 // check for new clients
580 	SV_CheckForNewClients ();
581 
582 	temp_host_frametime = save_host_frametime = host_frametime;
583 	while(temp_host_frametime > (1.0/72.0))
584 	{
585 		if (temp_host_frametime > 0.05)
586 			host_frametime = 0.05;
587 		else
588 			host_frametime = temp_host_frametime;
589 		temp_host_frametime -= host_frametime;
590 		_Host_ServerFrame ();
591 	}
592 	host_frametime = save_host_frametime;
593 
594 // send all messages to the clients
595 	SV_SendClientMessages ();
596 }
597 
598 #else
599 
Host_ServerFrame(void)600 void Host_ServerFrame (void)
601 {
602 // run the world state
603 	pr_global_struct->frametime = host_frametime;
604 
605 // set the time and clear the general datagram
606 	SV_ClearDatagram ();
607 
608 // check for new clients
609 	SV_CheckForNewClients ();
610 
611 // read client messages
612 	SV_RunClients ();
613 
614 // move things around and think
615 // always pause in single player if in console or menus
616 	if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) )
617 		SV_Physics ();
618 
619 // send all messages to the clients
620 	SV_SendClientMessages ();
621 }
622 
623 #endif
624 
625 
626 /*
627 ==================
628 Host_Frame
629 
630 Runs all active servers
631 ==================
632 */
_Host_Frame(float time)633 void _Host_Frame (float time)
634 {
635 	static double		time1 = 0;
636 	static double		time2 = 0;
637 	static double		time3 = 0;
638 	int			pass1, pass2, pass3;
639 
640 	if (setjmp (host_abortserver) )
641 		return;			// something bad happened, or the server disconnected
642 
643 // keep the random time dependent
644 	rand ();
645 
646 // decide the simulation time
647 	if (!Host_FilterTime (time))
648 		return;			// don't run too fast, or packets will flood out
649 
650 // get new key events
651 	Sys_SendKeyEvents ();
652 
653 // allow mice or other external controllers to add commands
654 	IN_Commands ();
655 
656 // process console commands
657 	Cbuf_Execute ();
658 
659 	NET_Poll();
660 
661 // if running the server locally, make intentions now
662 	if (sv.active)
663 		CL_SendCmd ();
664 
665 //-------------------
666 //
667 // server operations
668 //
669 //-------------------
670 
671 // check for commands typed to the host
672 	Host_GetConsoleCommands ();
673 
674 	if (sv.active)
675 		Host_ServerFrame ();
676 
677 //-------------------
678 //
679 // client operations
680 //
681 //-------------------
682 
683 // if running the server remotely, send intentions now after
684 // the incoming messages have been read
685 	if (!sv.active)
686 		CL_SendCmd ();
687 
688 	host_time += host_frametime;
689 
690 // fetch results from server
691 	if (cls.state == ca_connected)
692 	{
693 		CL_ReadFromServer ();
694 	}
695 
696 // update video
697 	if (host_speeds.value)
698 		time1 = Sys_FloatTime ();
699 
700 	SCR_UpdateScreen ();
701 
702 	if (host_speeds.value)
703 		time2 = Sys_FloatTime ();
704 
705 // update audio
706 	if (cls.signon == SIGNONS)
707 	{
708 		S_Update (r_origin, vpn, vright, vup);
709 		CL_DecayLights ();
710 	}
711 	else
712 		S_Update (vec3_origin, vec3_origin, vec3_origin, vec3_origin);
713 
714 	CDAudio_Update();
715 
716 	if (host_speeds.value)
717 	{
718 		pass1 = (int) ((time1 - time3)*1000);
719 		time3 = Sys_FloatTime ();
720 		pass2 = (int) ((time2 - time1)*1000);
721 		pass3 = (int) ((time3 - time2)*1000);
722 		Con_Printf ("%3i tot %3i server %3i gfx %3i snd\n",
723 					pass1+pass2+pass3, pass1, pass2, pass3);
724 	}
725 
726 	host_framecount++;
727 }
728 
Host_Frame(float time)729 void Host_Frame (float time)
730 {
731 	double	time1, time2;
732 	static double	timetotal;
733 	static int		timecount;
734 	int		i, c, m;
735 
736 	if (!serverprofile.value)
737 	{
738 		_Host_Frame (time);
739 		return;
740 	}
741 
742 	time1 = Sys_FloatTime ();
743 	_Host_Frame (time);
744 	time2 = Sys_FloatTime ();
745 
746 	timetotal += time2 - time1;
747 	timecount++;
748 
749 	if (timecount < 1000)
750 		return;
751 
752 	m = (int) (timetotal*1000/timecount);
753 	timecount = 0;
754 	timetotal = 0;
755 	c = 0;
756 	for (i=0 ; i<svs.maxclients ; i++)
757 	{
758 		if (svs.clients[i].active)
759 			c++;
760 	}
761 
762 	Con_Printf ("serverprofile: %2i clients %2i msec\n",  c,  m);
763 }
764 
765 //============================================================================
766 
767 
768 extern int vcrFile;
769 #define	VCR_SIGNATURE	0x56435231
770 // "VCR1"
771 
Host_InitVCR(quakeparms_t * parms)772 void Host_InitVCR (quakeparms_t *parms)
773 {
774 	int		i, len, n;
775 	char	*p;
776 
777 	if (COM_CheckParm("-playback"))
778 	{
779 		if (com_argc != 2)
780 			Sys_Error("No other parameters allowed with -playback\n");
781 
782 		Sys_FileOpenRead("quake.vcr", &vcrFile);
783 		if (vcrFile == -1)
784 			Sys_Error("playback file not found\n");
785 
786 		Sys_FileRead (vcrFile, &i, sizeof(int));
787 		if (i != VCR_SIGNATURE)
788 			Sys_Error("Invalid signature in vcr file\n");
789 
790 		Sys_FileRead (vcrFile, &com_argc, sizeof(int));
791 		com_argv = (const char**) malloc(com_argc * sizeof(char *));
792 		com_argv[0] = parms->argv[0];
793 		for (i = 0; i < com_argc; i++)
794 		{
795 			Sys_FileRead (vcrFile, &len, sizeof(int));
796 			p = (char*) malloc(len);
797 			Sys_FileRead (vcrFile, p, len);
798 			com_argv[i+1] = p;
799 		}
800 		com_argc++; /* add one for arg[0] */
801 		parms->argc = com_argc;
802 		parms->argv = com_argv;
803 	}
804 
805 	if ( (n = COM_CheckParm("-record")) != 0)
806 	{
807 		vcrFile = Sys_FileOpenWrite("quake.vcr");
808 
809 		i = VCR_SIGNATURE;
810 		Sys_FileWrite(vcrFile, &i, sizeof(int));
811 		i = com_argc - 1;
812 		Sys_FileWrite(vcrFile, &i, sizeof(int));
813 		for (i = 1; i < com_argc; i++)
814 		{
815 			if (i == n)
816 			{
817 				len = 10;
818 				Sys_FileWrite(vcrFile, &len, sizeof(int));
819 				Sys_FileWrite(vcrFile, "-playback", len);
820 				continue;
821 			}
822 			len = Q_strlen(com_argv[i]) + 1;
823 			Sys_FileWrite(vcrFile, &len, sizeof(int));
824 			Sys_FileWrite(vcrFile, com_argv[i], len);
825 		}
826 	}
827 
828 }
829 
830 /*
831 ====================
832 Host_Init
833 ====================
834 */
Host_Init(quakeparms_t * parms)835 void Host_Init (quakeparms_t *parms)
836 {
837 
838 	if (standard_quake)
839 		minimum_memory = MINIMUM_MEMORY;
840 	else
841 		minimum_memory = MINIMUM_MEMORY_LEVELPAK;
842 
843 	if (COM_CheckParm ("-minmemory"))
844 		parms->memsize = minimum_memory;
845 
846 	host_parms = *parms;
847 
848 	if (parms->memsize < minimum_memory)
849 		Sys_Error ("Only %4.1f megs of memory available, can't execute game", parms->memsize / (float)0x100000);
850 
851 	com_argc = parms->argc;
852 	com_argv = parms->argv;
853 
854 	Memory_Init (parms->membase, parms->memsize);
855 	Cbuf_Init ();
856 	Cmd_Init ();
857 	V_Init ();
858 	Chase_Init ();
859 	Host_InitVCR (parms);
860 	COM_Init (parms->basedir);
861 	Host_InitLocal ();
862 	W_LoadWadFile ("gfx.wad");
863 	Key_Init ();
864 	Con_Init ();
865 	M_Init ();
866 	PR_Init ();
867 	Mod_Init ();
868 	NET_Init ();
869 	SV_Init ();
870 
871 	Con_Printf ("Exe: "__TIME__" "__DATE__"\n");
872 	Con_Printf ("%4.1f megabyte heap\n",parms->memsize/ (1024*1024.0));
873 
874 	R_InitTextures ();		// needed even for dedicated servers
875 
876 	if (cls.state != ca_dedicated)
877 	{
878 		host_basepal = (byte *)COM_LoadHunkFile ("gfx/palette.lmp");
879 		if (!host_basepal)
880 			Sys_Error ("Couldn't load gfx/palette.lmp");
881 		host_colormap = (byte *)COM_LoadHunkFile ("gfx/colormap.lmp");
882 		if (!host_colormap)
883 			Sys_Error ("Couldn't load gfx/colormap.lmp");
884 
885 #ifndef _WIN32 // on non win32, mouse comes before video for security reasons
886 		IN_Init ();
887 #endif
888 		VID_Init (host_basepal);
889 
890 		Draw_Init ();
891 		SCR_Init ();
892 		R_Init ();
893 
894 #ifndef _WIN32
895 	// on Win32, sound initialization has to come before video initialization, so we
896 	// can put up a popup if the sound hardware is in use
897 
898 	// Actually S_Init is called from inside VID_Init. So don't call here.
899 	// 	S_Init ();
900 #else
901 
902 #ifdef	GLQUAKE
903 	// FIXME: doesn't use the new one-window approach yet
904 		S_Init ();
905 #endif
906 
907 #endif	// _WIN32
908 		CDAudio_Init ();
909 		Sbar_Init ();
910 		CL_Init ();
911 #ifdef _WIN32 // on non win32, mouse comes before video for security reasons
912 		IN_Init ();
913 #endif
914 	}
915 
916 	Cbuf_InsertText ("exec quake.rc\n");
917 
918 	Hunk_AllocName (0, "-HOST_HUNKLEVEL-");
919 	host_hunklevel = Hunk_LowMark ();
920 
921 	host_initialized = true;
922 
923 	Sys_Printf ("========Quake Initialized=========\n");
924 }
925 
926 
927 /*
928 ===============
929 Host_Shutdown
930 
931 FIXME: this is a callback from Sys_Quit and Sys_Error.  It would be better
932 to run quit through here before the final handoff to the sys code.
933 ===============
934 */
Host_Shutdown(void)935 void Host_Shutdown(void)
936 {
937 	static qboolean isdown = false;
938 
939 	if (isdown)
940 	{
941 		printf ("recursive shutdown\n");
942 		return;
943 	}
944 	isdown = true;
945 
946 // keep Con_Printf from trying to update the screen
947 	scr_disabled_for_loading = true;
948 
949 	Host_WriteConfiguration ();
950 
951 	CDAudio_Shutdown ();
952 	NET_Shutdown ();
953 	S_Shutdown();
954 	IN_Shutdown ();
955 
956 	if (cls.state != ca_dedicated)
957 	{
958 		VID_Shutdown();
959 	}
960 }
961 
962