home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / sviluppo / quake_src / host.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-17  |  23.8 KB  |  1,074 lines

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