host.c 20 KB

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