123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959 |
- /*
- Copyright (C) 1996-1997 Id Software, Inc.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- // host.c -- coordinates spawning and killing of local servers
- #include "quakedef.h"
- #include "r_local.h"
- /*
- A server can allways be started, even if the system started out as a client
- to a remote system.
- A client can NOT be started if the system started as a dedicated server.
- Memory is cleared / released when a server or client begins, not when they end.
- */
- quakeparms_t host_parms;
- qboolean host_initialized; // true if into command execution
- double host_frametime;
- double host_time;
- double realtime; // without any filtering or bounding
- double oldrealtime; // last frame run
- int host_framecount;
- int host_hunklevel;
- int minimum_memory;
- client_t *host_client; // current client
- jmp_buf host_abortserver;
- byte *host_basepal;
- byte *host_colormap;
- cvar_t host_framerate = {"host_framerate","0"}; // set for slow motion
- cvar_t host_speeds = {"host_speeds","0"}; // set for running times
- cvar_t sys_ticrate = {"sys_ticrate","0.05"};
- cvar_t serverprofile = {"serverprofile","0"};
- cvar_t fraglimit = {"fraglimit","0",false,true};
- cvar_t timelimit = {"timelimit","0",false,true};
- cvar_t teamplay = {"teamplay","0",false,true};
- cvar_t samelevel = {"samelevel","0"};
- cvar_t noexit = {"noexit","0",false,true};
- #ifdef QUAKE2
- cvar_t developer = {"developer","1"}; // should be 0 for release!
- #else
- cvar_t developer = {"developer","0"};
- #endif
- cvar_t skill = {"skill","1"}; // 0 - 3
- cvar_t deathmatch = {"deathmatch","0"}; // 0, 1, or 2
- cvar_t coop = {"coop","0"}; // 0 or 1
- cvar_t pausable = {"pausable","1"};
- cvar_t temp1 = {"temp1","0"};
- /*
- ================
- Host_EndGame
- ================
- */
- void Host_EndGame (char *message, ...)
- {
- va_list argptr;
- char string[1024];
-
- va_start (argptr,message);
- vsprintf (string,message,argptr);
- va_end (argptr);
- Con_DPrintf ("Host_EndGame: %s\n",string);
-
- if (sv.active)
- Host_ShutdownServer (false);
- if (cls.state == ca_dedicated)
- Sys_Error ("Host_EndGame: %s\n",string); // dedicated servers exit
-
- if (cls.demonum != -1)
- CL_NextDemo ();
- else
- CL_Disconnect ();
- longjmp (host_abortserver, 1);
- }
- /*
- ================
- Host_Error
- This shuts down both the client and server
- ================
- */
- void Host_Error (char *error, ...)
- {
- va_list argptr;
- char string[1024];
- static qboolean inerror = false;
-
- if (inerror)
- Sys_Error ("Host_Error: recursively entered");
- inerror = true;
-
- SCR_EndLoadingPlaque (); // reenable screen updates
- va_start (argptr,error);
- vsprintf (string,error,argptr);
- va_end (argptr);
- Con_Printf ("Host_Error: %s\n",string);
-
- if (sv.active)
- Host_ShutdownServer (false);
- if (cls.state == ca_dedicated)
- Sys_Error ("Host_Error: %s\n",string); // dedicated servers exit
- CL_Disconnect ();
- cls.demonum = -1;
- inerror = false;
- longjmp (host_abortserver, 1);
- }
- /*
- ================
- Host_FindMaxClients
- ================
- */
- void Host_FindMaxClients (void)
- {
- int i;
- svs.maxclients = 1;
-
- i = COM_CheckParm ("-dedicated");
- if (i)
- {
- cls.state = ca_dedicated;
- if (i != (com_argc - 1))
- {
- svs.maxclients = Q_atoi (com_argv[i+1]);
- }
- else
- svs.maxclients = 8;
- }
- else
- cls.state = ca_disconnected;
- i = COM_CheckParm ("-listen");
- if (i)
- {
- if (cls.state == ca_dedicated)
- Sys_Error ("Only one of -dedicated or -listen can be specified");
- if (i != (com_argc - 1))
- svs.maxclients = Q_atoi (com_argv[i+1]);
- else
- svs.maxclients = 8;
- }
- if (svs.maxclients < 1)
- svs.maxclients = 8;
- else if (svs.maxclients > MAX_SCOREBOARD)
- svs.maxclients = MAX_SCOREBOARD;
- svs.maxclientslimit = svs.maxclients;
- if (svs.maxclientslimit < 4)
- svs.maxclientslimit = 4;
- svs.clients = Hunk_AllocName (svs.maxclientslimit*sizeof(client_t), "clients");
- if (svs.maxclients > 1)
- Cvar_SetValue ("deathmatch", 1.0);
- else
- Cvar_SetValue ("deathmatch", 0.0);
- }
- /*
- =======================
- Host_InitLocal
- ======================
- */
- void Host_InitLocal (void)
- {
- Host_InitCommands ();
-
- Cvar_RegisterVariable (&host_framerate);
- Cvar_RegisterVariable (&host_speeds);
- Cvar_RegisterVariable (&sys_ticrate);
- Cvar_RegisterVariable (&serverprofile);
- Cvar_RegisterVariable (&fraglimit);
- Cvar_RegisterVariable (&timelimit);
- Cvar_RegisterVariable (&teamplay);
- Cvar_RegisterVariable (&samelevel);
- Cvar_RegisterVariable (&noexit);
- Cvar_RegisterVariable (&skill);
- Cvar_RegisterVariable (&developer);
- Cvar_RegisterVariable (&deathmatch);
- Cvar_RegisterVariable (&coop);
- Cvar_RegisterVariable (&pausable);
- Cvar_RegisterVariable (&temp1);
- Host_FindMaxClients ();
-
- host_time = 1.0; // so a think at time 0 won't get called
- }
- /*
- ===============
- Host_WriteConfiguration
- Writes key bindings and archived cvars to config.cfg
- ===============
- */
- void Host_WriteConfiguration (void)
- {
- FILE *f;
- // dedicated servers initialize the host but don't parse and set the
- // config.cfg cvars
- if (host_initialized & !isDedicated)
- {
- f = fopen (va("%s/config.cfg",com_gamedir), "w");
- if (!f)
- {
- Con_Printf ("Couldn't write config.cfg.\n");
- return;
- }
-
- Key_WriteBindings (f);
- Cvar_WriteVariables (f);
- fclose (f);
- }
- }
- /*
- =================
- SV_ClientPrintf
- Sends text across to be displayed
- FIXME: make this just a stuffed echo?
- =================
- */
- void SV_ClientPrintf (char *fmt, ...)
- {
- va_list argptr;
- char string[1024];
-
- va_start (argptr,fmt);
- vsprintf (string, fmt,argptr);
- va_end (argptr);
-
- MSG_WriteByte (&host_client->message, svc_print);
- MSG_WriteString (&host_client->message, string);
- }
- /*
- =================
- SV_BroadcastPrintf
- Sends text to all active clients
- =================
- */
- void SV_BroadcastPrintf (char *fmt, ...)
- {
- va_list argptr;
- char string[1024];
- int i;
-
- va_start (argptr,fmt);
- vsprintf (string, fmt,argptr);
- va_end (argptr);
-
- for (i=0 ; i<svs.maxclients ; i++)
- if (svs.clients[i].active && svs.clients[i].spawned)
- {
- MSG_WriteByte (&svs.clients[i].message, svc_print);
- MSG_WriteString (&svs.clients[i].message, string);
- }
- }
- /*
- =================
- Host_ClientCommands
- Send text over to the client to be executed
- =================
- */
- void Host_ClientCommands (char *fmt, ...)
- {
- va_list argptr;
- char string[1024];
-
- va_start (argptr,fmt);
- vsprintf (string, fmt,argptr);
- va_end (argptr);
-
- MSG_WriteByte (&host_client->message, svc_stufftext);
- MSG_WriteString (&host_client->message, string);
- }
- /*
- =====================
- SV_DropClient
- Called when the player is getting totally kicked off the host
- if (crash = true), don't bother sending signofs
- =====================
- */
- void SV_DropClient (qboolean crash)
- {
- int saveSelf;
- int i;
- client_t *client;
- if (!crash)
- {
- // send any final messages (don't check for errors)
- if (NET_CanSendMessage (host_client->netconnection))
- {
- MSG_WriteByte (&host_client->message, svc_disconnect);
- NET_SendMessage (host_client->netconnection, &host_client->message);
- }
-
- if (host_client->edict && host_client->spawned)
- {
- // call the prog function for removing a client
- // this will set the body to a dead frame, among other things
- saveSelf = pr_global_struct->self;
- pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
- PR_ExecuteProgram (pr_global_struct->ClientDisconnect);
- pr_global_struct->self = saveSelf;
- }
- Sys_Printf ("Client %s removed\n",host_client->name);
- }
- // break the net connection
- NET_Close (host_client->netconnection);
- host_client->netconnection = NULL;
- // free the client (the body stays around)
- host_client->active = false;
- host_client->name[0] = 0;
- host_client->old_frags = -999999;
- net_activeconnections--;
- // send notification to all clients
- for (i=0, client = svs.clients ; i<svs.maxclients ; i++, client++)
- {
- if (!client->active)
- continue;
- MSG_WriteByte (&client->message, svc_updatename);
- MSG_WriteByte (&client->message, host_client - svs.clients);
- MSG_WriteString (&client->message, "");
- MSG_WriteByte (&client->message, svc_updatefrags);
- MSG_WriteByte (&client->message, host_client - svs.clients);
- MSG_WriteShort (&client->message, 0);
- MSG_WriteByte (&client->message, svc_updatecolors);
- MSG_WriteByte (&client->message, host_client - svs.clients);
- MSG_WriteByte (&client->message, 0);
- }
- }
- /*
- ==================
- Host_ShutdownServer
- This only happens at the end of a game, not between levels
- ==================
- */
- void Host_ShutdownServer(qboolean crash)
- {
- int i;
- int count;
- sizebuf_t buf;
- char message[4];
- double start;
- if (!sv.active)
- return;
- sv.active = false;
- // stop all client sounds immediately
- if (cls.state == ca_connected)
- CL_Disconnect ();
- // flush any pending messages - like the score!!!
- start = Sys_FloatTime();
- do
- {
- count = 0;
- for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
- {
- if (host_client->active && host_client->message.cursize)
- {
- if (NET_CanSendMessage (host_client->netconnection))
- {
- NET_SendMessage(host_client->netconnection, &host_client->message);
- SZ_Clear (&host_client->message);
- }
- else
- {
- NET_GetMessage(host_client->netconnection);
- count++;
- }
- }
- }
- if ((Sys_FloatTime() - start) > 3.0)
- break;
- }
- while (count);
- // make sure all the clients know we're disconnecting
- buf.data = message;
- buf.maxsize = 4;
- buf.cursize = 0;
- MSG_WriteByte(&buf, svc_disconnect);
- count = NET_SendToAll(&buf, 5);
- if (count)
- Con_Printf("Host_ShutdownServer: NET_SendToAll failed for %u clients\n", count);
- for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
- if (host_client->active)
- SV_DropClient(crash);
- //
- // clear structures
- //
- memset (&sv, 0, sizeof(sv));
- memset (svs.clients, 0, svs.maxclientslimit*sizeof(client_t));
- }
- /*
- ================
- Host_ClearMemory
- This clears all the memory used by both the client and server, but does
- not reinitialize anything.
- ================
- */
- void Host_ClearMemory (void)
- {
- Con_DPrintf ("Clearing memory\n");
- D_FlushCaches ();
- Mod_ClearAll ();
- if (host_hunklevel)
- Hunk_FreeToLowMark (host_hunklevel);
- cls.signon = 0;
- memset (&sv, 0, sizeof(sv));
- memset (&cl, 0, sizeof(cl));
- }
- //============================================================================
- /*
- ===================
- Host_FilterTime
- Returns false if the time is too short to run a frame
- ===================
- */
- qboolean Host_FilterTime (float time)
- {
- realtime += time;
- if (!cls.timedemo && realtime - oldrealtime < 1.0/72.0)
- return false; // framerate is too high
- host_frametime = realtime - oldrealtime;
- oldrealtime = realtime;
- if (host_framerate.value > 0)
- host_frametime = host_framerate.value;
- else
- { // don't allow really long or short frames
- if (host_frametime > 0.1)
- host_frametime = 0.1;
- if (host_frametime < 0.001)
- host_frametime = 0.001;
- }
-
- return true;
- }
- /*
- ===================
- Host_GetConsoleCommands
- Add them exactly as if they had been typed at the console
- ===================
- */
- void Host_GetConsoleCommands (void)
- {
- char *cmd;
- while (1)
- {
- cmd = Sys_ConsoleInput ();
- if (!cmd)
- break;
- Cbuf_AddText (cmd);
- }
- }
- /*
- ==================
- Host_ServerFrame
- ==================
- */
- #ifdef FPS_20
- void _Host_ServerFrame (void)
- {
- // run the world state
- pr_global_struct->frametime = host_frametime;
- // read client messages
- SV_RunClients ();
-
- // move things around and think
- // always pause in single player if in console or menus
- if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) )
- SV_Physics ();
- }
- void Host_ServerFrame (void)
- {
- float save_host_frametime;
- float temp_host_frametime;
- // run the world state
- pr_global_struct->frametime = host_frametime;
- // set the time and clear the general datagram
- SV_ClearDatagram ();
-
- // check for new clients
- SV_CheckForNewClients ();
- temp_host_frametime = save_host_frametime = host_frametime;
- while(temp_host_frametime > (1.0/72.0))
- {
- if (temp_host_frametime > 0.05)
- host_frametime = 0.05;
- else
- host_frametime = temp_host_frametime;
- temp_host_frametime -= host_frametime;
- _Host_ServerFrame ();
- }
- host_frametime = save_host_frametime;
- // send all messages to the clients
- SV_SendClientMessages ();
- }
- #else
- void Host_ServerFrame (void)
- {
- // run the world state
- pr_global_struct->frametime = host_frametime;
- // set the time and clear the general datagram
- SV_ClearDatagram ();
-
- // check for new clients
- SV_CheckForNewClients ();
- // read client messages
- SV_RunClients ();
-
- // move things around and think
- // always pause in single player if in console or menus
- if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) )
- SV_Physics ();
- // send all messages to the clients
- SV_SendClientMessages ();
- }
- #endif
- /*
- ==================
- Host_Frame
- Runs all active servers
- ==================
- */
- void _Host_Frame (float time)
- {
- static double time1 = 0;
- static double time2 = 0;
- static double time3 = 0;
- int pass1, pass2, pass3;
- if (setjmp (host_abortserver) )
- return; // something bad happened, or the server disconnected
- // keep the random time dependent
- rand ();
-
- // decide the simulation time
- if (!Host_FilterTime (time))
- return; // don't run too fast, or packets will flood out
-
- // get new key events
- Sys_SendKeyEvents ();
- // allow mice or other external controllers to add commands
- IN_Commands ();
- // process console commands
- Cbuf_Execute ();
- NET_Poll();
- // if running the server locally, make intentions now
- if (sv.active)
- CL_SendCmd ();
-
- //-------------------
- //
- // server operations
- //
- //-------------------
- // check for commands typed to the host
- Host_GetConsoleCommands ();
-
- if (sv.active)
- Host_ServerFrame ();
- //-------------------
- //
- // client operations
- //
- //-------------------
- // if running the server remotely, send intentions now after
- // the incoming messages have been read
- if (!sv.active)
- CL_SendCmd ();
- host_time += host_frametime;
- // fetch results from server
- if (cls.state == ca_connected)
- {
- CL_ReadFromServer ();
- }
- // update video
- if (host_speeds.value)
- time1 = Sys_FloatTime ();
-
- SCR_UpdateScreen ();
- if (host_speeds.value)
- time2 = Sys_FloatTime ();
-
- // update audio
- if (cls.signon == SIGNONS)
- {
- S_Update (r_origin, vpn, vright, vup);
- CL_DecayLights ();
- }
- else
- S_Update (vec3_origin, vec3_origin, vec3_origin, vec3_origin);
-
- CDAudio_Update();
- if (host_speeds.value)
- {
- pass1 = (time1 - time3)*1000;
- time3 = Sys_FloatTime ();
- pass2 = (time2 - time1)*1000;
- pass3 = (time3 - time2)*1000;
- Con_Printf ("%3i tot %3i server %3i gfx %3i snd\n",
- pass1+pass2+pass3, pass1, pass2, pass3);
- }
-
- host_framecount++;
- }
- void Host_Frame (float time)
- {
- double time1, time2;
- static double timetotal;
- static int timecount;
- int i, c, m;
- if (!serverprofile.value)
- {
- _Host_Frame (time);
- return;
- }
-
- time1 = Sys_FloatTime ();
- _Host_Frame (time);
- time2 = Sys_FloatTime ();
-
- timetotal += time2 - time1;
- timecount++;
-
- if (timecount < 1000)
- return;
- m = timetotal*1000/timecount;
- timecount = 0;
- timetotal = 0;
- c = 0;
- for (i=0 ; i<svs.maxclients ; i++)
- {
- if (svs.clients[i].active)
- c++;
- }
- Con_Printf ("serverprofile: %2i clients %2i msec\n", c, m);
- }
- //============================================================================
- extern int vcrFile;
- #define VCR_SIGNATURE 0x56435231
- // "VCR1"
- void Host_InitVCR (quakeparms_t *parms)
- {
- int i, len, n;
- char *p;
-
- if (COM_CheckParm("-playback"))
- {
- if (com_argc != 2)
- Sys_Error("No other parameters allowed with -playback\n");
- Sys_FileOpenRead("quake.vcr", &vcrFile);
- if (vcrFile == -1)
- Sys_Error("playback file not found\n");
- Sys_FileRead (vcrFile, &i, sizeof(int));
- if (i != VCR_SIGNATURE)
- Sys_Error("Invalid signature in vcr file\n");
- Sys_FileRead (vcrFile, &com_argc, sizeof(int));
- com_argv = malloc(com_argc * sizeof(char *));
- com_argv[0] = parms->argv[0];
- for (i = 0; i < com_argc; i++)
- {
- Sys_FileRead (vcrFile, &len, sizeof(int));
- p = malloc(len);
- Sys_FileRead (vcrFile, p, len);
- com_argv[i+1] = p;
- }
- com_argc++; /* add one for arg[0] */
- parms->argc = com_argc;
- parms->argv = com_argv;
- }
- if ( (n = COM_CheckParm("-record")) != 0)
- {
- vcrFile = Sys_FileOpenWrite("quake.vcr");
- i = VCR_SIGNATURE;
- Sys_FileWrite(vcrFile, &i, sizeof(int));
- i = com_argc - 1;
- Sys_FileWrite(vcrFile, &i, sizeof(int));
- for (i = 1; i < com_argc; i++)
- {
- if (i == n)
- {
- len = 10;
- Sys_FileWrite(vcrFile, &len, sizeof(int));
- Sys_FileWrite(vcrFile, "-playback", len);
- continue;
- }
- len = Q_strlen(com_argv[i]) + 1;
- Sys_FileWrite(vcrFile, &len, sizeof(int));
- Sys_FileWrite(vcrFile, com_argv[i], len);
- }
- }
-
- }
- /*
- ====================
- Host_Init
- ====================
- */
- void Host_Init (quakeparms_t *parms)
- {
- if (standard_quake)
- minimum_memory = MINIMUM_MEMORY;
- else
- minimum_memory = MINIMUM_MEMORY_LEVELPAK;
- if (COM_CheckParm ("-minmemory"))
- parms->memsize = minimum_memory;
- host_parms = *parms;
- if (parms->memsize < minimum_memory)
- Sys_Error ("Only %4.1f megs of memory available, can't execute game", parms->memsize / (float)0x100000);
- com_argc = parms->argc;
- com_argv = parms->argv;
- Memory_Init (parms->membase, parms->memsize);
- Cbuf_Init ();
- Cmd_Init ();
- V_Init ();
- Chase_Init ();
- Host_InitVCR (parms);
- COM_Init (parms->basedir);
- Host_InitLocal ();
- W_LoadWadFile ("gfx.wad");
- Key_Init ();
- Con_Init ();
- M_Init ();
- PR_Init ();
- Mod_Init ();
- NET_Init ();
- SV_Init ();
- Con_Printf ("Exe: "__TIME__" "__DATE__"\n");
- Con_Printf ("%4.1f megabyte heap\n",parms->memsize/ (1024*1024.0));
-
- R_InitTextures (); // needed even for dedicated servers
-
- if (cls.state != ca_dedicated)
- {
- host_basepal = (byte *)COM_LoadHunkFile ("gfx/palette.lmp");
- if (!host_basepal)
- Sys_Error ("Couldn't load gfx/palette.lmp");
- host_colormap = (byte *)COM_LoadHunkFile ("gfx/colormap.lmp");
- if (!host_colormap)
- Sys_Error ("Couldn't load gfx/colormap.lmp");
- #ifndef _WIN32 // on non win32, mouse comes before video for security reasons
- IN_Init ();
- #endif
- VID_Init (host_basepal);
- Draw_Init ();
- SCR_Init ();
- R_Init ();
- #ifndef _WIN32
- // on Win32, sound initialization has to come before video initialization, so we
- // can put up a popup if the sound hardware is in use
- S_Init ();
- #else
- #ifdef GLQUAKE
- // FIXME: doesn't use the new one-window approach yet
- S_Init ();
- #endif
- #endif // _WIN32
- CDAudio_Init ();
- Sbar_Init ();
- CL_Init ();
- #ifdef _WIN32 // on non win32, mouse comes before video for security reasons
- IN_Init ();
- #endif
- }
- Cbuf_InsertText ("exec quake.rc\n");
- Hunk_AllocName (0, "-HOST_HUNKLEVEL-");
- host_hunklevel = Hunk_LowMark ();
- host_initialized = true;
-
- Sys_Printf ("========Quake Initialized=========\n");
- }
- /*
- ===============
- Host_Shutdown
- FIXME: this is a callback from Sys_Quit and Sys_Error. It would be better
- to run quit through here before the final handoff to the sys code.
- ===============
- */
- void Host_Shutdown(void)
- {
- static qboolean isdown = false;
-
- if (isdown)
- {
- printf ("recursive shutdown\n");
- return;
- }
- isdown = true;
- // keep Con_Printf from trying to update the screen
- scr_disabled_for_loading = true;
- Host_WriteConfiguration ();
- CDAudio_Shutdown ();
- NET_Shutdown ();
- S_Shutdown();
- IN_Shutdown ();
- if (cls.state != ca_dedicated)
- {
- VID_Shutdown();
- }
- }
|