diff options
Diffstat (limited to 'apps/plugins/sdl/progs/quake/host.c')
-rw-r--r-- | apps/plugins/sdl/progs/quake/host.c | 977 |
1 files changed, 977 insertions, 0 deletions
diff --git a/apps/plugins/sdl/progs/quake/host.c b/apps/plugins/sdl/progs/quake/host.c new file mode 100644 index 0000000000..9a5f7c29d6 --- /dev/null +++ b/apps/plugins/sdl/progs/quake/host.c | |||
@@ -0,0 +1,977 @@ | |||
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 | /* | ||
86 | ================ | ||
87 | Host_EndGame | ||
88 | ================ | ||
89 | */ | ||
90 | void Host_EndGame (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 | */ | ||
121 | void Host_Error (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 | */ | ||
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 = 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 | */ | ||
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 | */ | ||
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 | */ | ||
277 | void SV_ClientPrintf (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 | */ | ||
297 | void SV_BroadcastPrintf (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 | */ | ||
322 | void Host_ClientCommands (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 | */ | ||
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 | */ | ||
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 = 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 | */ | ||
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 | */ | ||
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 | */ | ||
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 | |||
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 | |||
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 | |||
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 | */ | ||
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 = (time1 - time3)*1000; | ||
719 | time3 = Sys_FloatTime (); | ||
720 | pass2 = (time2 - time1)*1000; | ||
721 | pass3 = (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 | |||
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 = 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 | |||
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 = 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 = 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 | */ | ||
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 | //printf("init 1"); | ||
855 | |||
856 | Memory_Init (parms->membase, parms->memsize); | ||
857 | //printf("init 2"); | ||
858 | Cbuf_Init (); | ||
859 | //printf("init 3"); | ||
860 | Cmd_Init (); | ||
861 | //printf("init 4"); | ||
862 | V_Init (); | ||
863 | //printf("init 5"); | ||
864 | Chase_Init (); | ||
865 | //printf("init 6"); | ||
866 | Host_InitVCR (parms); | ||
867 | //printf("init 7"); | ||
868 | COM_Init (parms->basedir); | ||
869 | //printf("init 8"); | ||
870 | Host_InitLocal (); | ||
871 | //printf("init 9"); | ||
872 | W_LoadWadFile ("gfx.wad"); | ||
873 | //printf("init 10"); | ||
874 | Key_Init (); | ||
875 | Con_Init (); | ||
876 | M_Init (); | ||
877 | PR_Init (); | ||
878 | Mod_Init (); | ||
879 | NET_Init (); | ||
880 | //printf("init 11"); | ||
881 | SV_Init (); | ||
882 | //printf("init 12"); | ||
883 | |||
884 | Con_Printf ("Exe: "__TIME__" "__DATE__"\n"); | ||
885 | Con_Printf ("%4.1f megabyte heap\n",parms->memsize/ (1024*1024.0)); | ||
886 | |||
887 | R_InitTextures (); // needed even for dedicated servers | ||
888 | |||
889 | //printf("init 13"); | ||
890 | if (cls.state != ca_dedicated) | ||
891 | { | ||
892 | host_basepal = (byte *)COM_LoadHunkFile ("gfx/palette.lmp"); | ||
893 | if (!host_basepal) | ||
894 | Sys_Error ("Couldn't load gfx/palette.lmp"); | ||
895 | host_colormap = (byte *)COM_LoadHunkFile ("gfx/colormap.lmp"); | ||
896 | if (!host_colormap) | ||
897 | Sys_Error ("Couldn't load gfx/colormap.lmp"); | ||
898 | |||
899 | #ifndef _WIN32 // on non win32, mouse comes before video for security reasons | ||
900 | IN_Init (); | ||
901 | #endif | ||
902 | VID_Init (host_basepal); | ||
903 | |||
904 | Draw_Init (); | ||
905 | SCR_Init (); | ||
906 | R_Init (); | ||
907 | #ifndef _WIN32 | ||
908 | // on Win32, sound initialization has to come before video initialization, so we | ||
909 | // can put up a popup if the sound hardware is in use | ||
910 | S_Init (); | ||
911 | #else | ||
912 | |||
913 | #ifdef GLQUAKE | ||
914 | // FIXME: doesn't use the new one-window approach yet | ||
915 | S_Init (); | ||
916 | #endif | ||
917 | |||
918 | #endif // _WIN32 | ||
919 | CDAudio_Init (); | ||
920 | Sbar_Init (); | ||
921 | CL_Init (); | ||
922 | #ifdef _WIN32 // on non win32, mouse comes before video for security reasons | ||
923 | IN_Init (); | ||
924 | #endif | ||
925 | } | ||
926 | |||
927 | Cbuf_InsertText ("exec quake.rc\n"); | ||
928 | |||
929 | Hunk_AllocName (0, "-HOST_HUNKLEVEL-"); | ||
930 | host_hunklevel = Hunk_LowMark (); | ||
931 | |||
932 | host_initialized = true; | ||
933 | |||
934 | Sys_Printf ("========Quake Initialized=========\n"); | ||
935 | |||
936 | extern int enable_printf; | ||
937 | enable_printf = 0; | ||
938 | } | ||
939 | |||
940 | |||
941 | /* | ||
942 | =============== | ||
943 | Host_Shutdown | ||
944 | |||
945 | FIXME: this is a callback from Sys_Quit and Sys_Error. It would be better | ||
946 | to run quit through here before the final handoff to the sys code. | ||
947 | =============== | ||
948 | */ | ||
949 | void Host_Shutdown(void) | ||
950 | { | ||
951 | static qboolean isdown = false; | ||
952 | |||
953 | if (isdown) | ||
954 | { | ||
955 | printf ("recursive shutdown\n"); | ||
956 | return; | ||
957 | } | ||
958 | isdown = true; | ||
959 | |||
960 | // keep Con_Printf from trying to update the screen | ||
961 | scr_disabled_for_loading = true; | ||
962 | |||
963 | Host_WriteConfiguration (); | ||
964 | |||
965 | CDAudio_Shutdown (); | ||
966 | NET_Shutdown (); | ||
967 | S_Shutdown(); | ||
968 | IN_Shutdown (); | ||
969 | |||
970 | Sys_Shutdown(); | ||
971 | |||
972 | if (cls.state != ca_dedicated) | ||
973 | { | ||
974 | VID_Shutdown(); | ||
975 | } | ||
976 | } | ||
977 | |||