Rev 8644 | Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5131 | clevermous | 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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 | Memory_Init (parms->membase, parms->memsize); |
||
855 | Cbuf_Init (); |
||
856 | Cmd_Init (); |
||
857 | V_Init (); |
||
858 | Chase_Init (); |
||
859 | Host_InitVCR (parms); |
||
860 | COM_Init (parms->basedir); |
||
861 | Host_InitLocal (); |
||
862 | W_LoadWadFile ("gfx.wad"); |
||
863 | Key_Init (); |
||
864 | Con_Init (); |
||
865 | M_Init (); |
||
866 | PR_Init (); |
||
867 | Mod_Init (); |
||
868 | NET_Init (); |
||
869 | SV_Init (); |
||
870 | |||
871 | Con_Printf ("Exe: "__TIME__" "__DATE__"\n"); |
||
872 | Con_Printf ("%4.1f megabyte heap\n",parms->memsize/ (1024*1024.0)); |
||
873 | |||
874 | R_InitTextures (); // needed even for dedicated servers |
||
875 | |||
876 | if (cls.state != ca_dedicated) |
||
877 | { |
||
878 | host_basepal = (byte *)COM_LoadHunkFile ("gfx/palette.lmp"); |
||
879 | if (!host_basepal) |
||
880 | Sys_Error ("Couldn't load gfx/palette.lmp"); |
||
881 | host_colormap = (byte *)COM_LoadHunkFile ("gfx/colormap.lmp"); |
||
882 | if (!host_colormap) |
||
883 | Sys_Error ("Couldn't load gfx/colormap.lmp"); |
||
884 | |||
885 | #ifndef _WIN32 // on non win32, mouse comes before video for security reasons |
||
886 | IN_Init (); |
||
887 | #endif |
||
888 | VID_Init (host_basepal); |
||
889 | |||
890 | Draw_Init (); |
||
891 | SCR_Init (); |
||
892 | R_Init (); |
||
893 | #ifndef _WIN32 |
||
894 | // on Win32, sound initialization has to come before video initialization, so we |
||
895 | // can put up a popup if the sound hardware is in use |
||
896 | S_Init (); |
||
897 | #else |
||
898 | |||
899 | #ifdef GLQUAKE |
||
900 | // FIXME: doesn't use the new one-window approach yet |
||
901 | S_Init (); |
||
902 | #endif |
||
903 | |||
904 | #endif // _WIN32 |
||
905 | CDAudio_Init (); |
||
906 | Sbar_Init (); |
||
907 | CL_Init (); |
||
908 | #ifdef _WIN32 // on non win32, mouse comes before video for security reasons |
||
909 | IN_Init (); |
||
910 | #endif |
||
911 | } |
||
912 | |||
913 | Cbuf_InsertText ("exec quake.rc\n"); |
||
914 | |||
915 | Hunk_AllocName (0, "-HOST_HUNKLEVEL-"); |
||
916 | host_hunklevel = Hunk_LowMark (); |
||
917 | |||
918 | host_initialized = true; |
||
919 | |||
920 | Sys_Printf ("========Quake Initialized=========\n"); |
||
921 | } |
||
922 | |||
923 | |||
924 | /* |
||
925 | =============== |
||
926 | Host_Shutdown |
||
927 | |||
928 | FIXME: this is a callback from Sys_Quit and Sys_Error. It would be better |
||
929 | to run quit through here before the final handoff to the sys code. |
||
930 | =============== |
||
931 | */ |
||
932 | void Host_Shutdown(void) |
||
933 | { |
||
934 | static qboolean isdown = false; |
||
935 | |||
936 | if (isdown) |
||
937 | { |
||
938 | printf ("recursive shutdown\n"); |
||
939 | return; |
||
940 | } |
||
941 | isdown = true; |
||
942 | |||
943 | // keep Con_Printf from trying to update the screen |
||
944 | scr_disabled_for_loading = true; |
||
945 | |||
946 | Host_WriteConfiguration (); |
||
947 | |||
948 | CDAudio_Shutdown (); |
||
949 | NET_Shutdown (); |
||
950 | S_Shutdown(); |
||
951 | IN_Shutdown (); |
||
952 | |||
953 | if (cls.state != ca_dedicated) |
||
954 | { |
||
955 | VID_Shutdown(); |
||
956 | } |
||
957 | }>>>>>>>> |
||
958 |