|
|
1.1 root 1: // cl_parse.c -- parse a message received from the server
2:
3: #include "client.h"
4:
5: char *svc_strings[256] =
6: {
7: "svc_bad",
8:
9: "svc_muzzleflash",
10: "svc_muzzlflash2",
11: "svc_temp_entity",
12: "svc_layout",
13: "svc_inventory",
14:
15: "svc_nop",
16: "svc_disconnect",
17: "svc_reconnect",
18: "svc_sound",
19: "svc_print",
20: "svc_stufftext",
21: "svc_serverdata",
22: "svc_configstring",
23: "svc_spawnbaseline",
24: "svc_centerprint",
25: "svc_download",
26: "svc_playerinfo",
27: "svc_packetentities",
28: "svc_deltapacketentities",
29: "svc_frame"
30: };
31:
32: //=============================================================================
33:
1.1.1.2 ! root 34: void CL_DownloadFileName(char *dest, int destlen, char *fn)
! 35: {
! 36: if (strncmp(fn, "players", 7) == 0)
! 37: Com_sprintf (dest, destlen, "%s/%s", BASEDIRNAME, fn);
! 38: else
! 39: Com_sprintf (dest, destlen, "%s/%s", FS_Gamedir(), fn);
! 40: }
! 41:
1.1 root 42: /*
43: ===============
44: CL_CheckOrDownloadFile
45:
46: Returns true if the file exists, otherwise it attempts
47: to start a download from the server.
48: ===============
49: */
50: qboolean CL_CheckOrDownloadFile (char *filename)
51: {
1.1.1.2 ! root 52: FILE *fp;
! 53: char name[MAX_OSPATH];
! 54:
1.1 root 55: if (strstr (filename, ".."))
56: {
57: Com_Printf ("Refusing to download a path with ..\n");
58: return true;
59: }
60:
61: if (FS_LoadFile (filename, NULL) != -1)
62: { // it exists, no need to download
63: return true;
64: }
65:
66: strcpy (cls.downloadname, filename);
1.1.1.2 ! root 67:
! 68: // download to a temp name, and only rename
! 69: // to the real name when done, so if interrupted
! 70: // a runt file wont be left
! 71: COM_StripExtension (cls.downloadname, cls.downloadtempname);
! 72: strcat (cls.downloadtempname, ".tmp");
! 73:
! 74: //ZOID
! 75: // check to see if we already have a tmp for this file, if so, try to resume
! 76: // open the file if not opened yet
! 77: CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
! 78:
! 79: // FS_CreatePath (name);
! 80:
! 81: fp = fopen (name, "r+b");
! 82: if (fp) { // it exists
! 83: int len;
! 84: fseek(fp, 0, SEEK_END);
! 85: len = ftell(fp);
! 86:
! 87: cls.download = fp;
! 88:
! 89: // give the server an offset to start the download
! 90: Com_Printf ("Resuming %s\n", cls.downloadname);
! 91: MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
! 92: MSG_WriteString (&cls.netchan.message,
! 93: va("download %s %i", cls.downloadname, len));
! 94: } else {
! 95: Com_Printf ("Downloading %s\n", cls.downloadname);
! 96: MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
! 97: MSG_WriteString (&cls.netchan.message,
! 98: va("download %s", cls.downloadname));
! 99: }
! 100:
! 101: cls.downloadnumber++;
! 102:
! 103: return false;
! 104: }
! 105:
! 106: /*
! 107: ===============
! 108: CL_Download_f
! 109:
! 110: Request a download from the server
! 111: ===============
! 112: */
! 113: void CL_Download_f (void)
! 114: {
! 115: char filename[MAX_OSPATH];
! 116:
! 117: if (Cmd_Argc() != 2) {
! 118: Com_Printf("Usage: download <filename>\n");
! 119: return;
! 120: }
! 121:
! 122: Com_sprintf(filename, sizeof(filename), "%s", Cmd_Argv(1));
! 123:
! 124: if (strstr (filename, ".."))
! 125: {
! 126: Com_Printf ("Refusing to download a path with ..\n");
! 127: return;
! 128: }
! 129:
! 130: if (FS_LoadFile (filename, NULL) != -1)
! 131: { // it exists, no need to download
! 132: Com_Printf("File already exists.\n");
! 133: return;
! 134: }
! 135:
! 136: strcpy (cls.downloadname, filename);
1.1 root 137: Com_Printf ("Downloading %s\n", cls.downloadname);
138:
139: // download to a temp name, and only rename
140: // to the real name when done, so if interrupted
141: // a runt file wont be left
142: COM_StripExtension (cls.downloadname, cls.downloadtempname);
143: strcat (cls.downloadtempname, ".tmp");
144:
145: MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
146: MSG_WriteString (&cls.netchan.message,
147: va("download %s", cls.downloadname));
148:
149: cls.downloadnumber++;
150: }
151:
152: /*
153: ======================
154: CL_RegisterSounds
155: ======================
156: */
157: void CL_RegisterSounds (void)
158: {
159: int i;
160:
161: S_BeginRegistration ();
162: CL_RegisterTEntSounds ();
163: for (i=1 ; i<MAX_SOUNDS ; i++)
164: {
165: if (!cl.configstrings[CS_SOUNDS+i][0])
166: break;
167: cl.sound_precache[i] = S_RegisterSound (cl.configstrings[CS_SOUNDS+i]);
168: Sys_SendKeyEvents (); // pump message loop
169: }
170: S_EndRegistration ();
171: }
172:
173:
174: /*
175: =====================
176: CL_ParseDownload
177:
178: A download message has been received from the server
179: =====================
180: */
181: void CL_ParseDownload (void)
182: {
183: int size, percent;
184: char name[MAX_OSPATH];
185: int r;
186:
187: // read the data
188: size = MSG_ReadShort (&net_message);
189: percent = MSG_ReadByte (&net_message);
190: if (size == -1)
191: {
1.1.1.2 ! root 192: Com_Printf ("Server does not have this file.\n");
1.1 root 193: if (cls.download)
194: {
1.1.1.2 ! root 195: // if here, we tried to resume a file but the server said no
1.1 root 196: fclose (cls.download);
197: cls.download = NULL;
198: }
199: CL_RequestNextDownload ();
200: return;
201: }
202:
203: // open the file if not opened yet
204: if (!cls.download)
205: {
1.1.1.2 ! root 206: CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
1.1 root 207:
208: FS_CreatePath (name);
209:
210: cls.download = fopen (name, "wb");
211: if (!cls.download)
212: {
213: net_message.readcount += size;
214: Com_Printf ("Failed to open %s\n", cls.downloadtempname);
215: CL_RequestNextDownload ();
216: return;
217: }
218: }
219:
220: fwrite (net_message.data + net_message.readcount, 1, size, cls.download);
221: net_message.readcount += size;
222:
223: if (percent != 100)
224: {
225: // request next block
1.1.1.2 ! root 226: // change display routines by zoid
! 227: #if 0
1.1 root 228: Com_Printf (".");
229: if (10*(percent/10) != cls.downloadpercent)
230: {
231: cls.downloadpercent = 10*(percent/10);
232: Com_Printf ("%i%%", cls.downloadpercent);
233: }
1.1.1.2 ! root 234: #endif
! 235: cls.downloadpercent = percent;
! 236:
1.1 root 237: MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
238: SZ_Print (&cls.netchan.message, "nextdl");
239: }
240: else
241: {
242: char oldn[MAX_OSPATH];
243: char newn[MAX_OSPATH];
244:
1.1.1.2 ! root 245: // Com_Printf ("100%%\n");
1.1 root 246:
247: fclose (cls.download);
248:
249: // rename the temp file to it's final name
1.1.1.2 ! root 250: CL_DownloadFileName(oldn, sizeof(oldn), cls.downloadtempname);
! 251: CL_DownloadFileName(newn, sizeof(newn), cls.downloadname);
1.1 root 252: r = rename (oldn, newn);
253: if (r)
254: Com_Printf ("failed to rename.\n");
255:
256: cls.download = NULL;
257: cls.downloadpercent = 0;
258:
259: // get another file if needed
260:
261: CL_RequestNextDownload ();
262: }
263: }
264:
265:
266: /*
267: =====================================================================
268:
269: SERVER CONNECTING MESSAGES
270:
271: =====================================================================
272: */
273:
274: /*
275: ==================
276: CL_ParseServerData
277: ==================
278: */
279: void CL_ParseServerData (void)
280: {
281: extern cvar_t *fs_gamedirvar;
282: char *str;
283: int i;
284:
285: Com_DPrintf ("Serverdata packet received.\n");
286: //
287: // wipe the client_state_t struct
288: //
289: CL_ClearState ();
290: cls.state = ca_connected;
291:
292: // parse protocol version number
293: i = MSG_ReadLong (&net_message);
294: cls.serverProtocol = i;
295:
296: // BIG HACK to let demos from release work with the 3.0x patch!!!
1.1.1.2 ! root 297: if (Com_ServerState() && PROTOCOL_VERSION == 33)
1.1 root 298: {
299: }
300: else if (i != PROTOCOL_VERSION)
301: Com_Error (ERR_DROP,"Server returned version %i, not %i", i, PROTOCOL_VERSION);
302:
303: cl.servercount = MSG_ReadLong (&net_message);
304: cl.attractloop = MSG_ReadByte (&net_message);
305:
306: // game directory
307: str = MSG_ReadString (&net_message);
308: strncpy (cl.gamedir, str, sizeof(cl.gamedir)-1);
309:
310: // set gamedir
311: if ((*str && (!fs_gamedirvar->string || !*fs_gamedirvar->string || strcmp(fs_gamedirvar->string, str))) || (!*str && (fs_gamedirvar->string || *fs_gamedirvar->string)))
312: Cvar_Set("game", str);
313:
314: // parse player entity number
315: cl.playernum = MSG_ReadShort (&net_message);
316:
317: // get the full level name
318: str = MSG_ReadString (&net_message);
319:
320: if (cl.playernum == -1)
321: { // playing a cinematic or showing a pic, not a level
322: SCR_PlayCinematic (str);
323: }
324: else
325: {
326: // seperate the printfs so the server message can have a color
327: Com_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
328: Com_Printf ("%c%s\n", 2, str);
329:
330: // need to prep refresh at next oportunity
331: cl.refresh_prepped = false;
332: }
333: }
334:
335: /*
336: ==================
337: CL_ParseBaseline
338: ==================
339: */
340: void CL_ParseBaseline (void)
341: {
342: entity_state_t *es;
343: int bits;
344: int newnum;
345: entity_state_t nullstate;
346:
347: memset (&nullstate, 0, sizeof(nullstate));
348:
349: newnum = CL_ParseEntityBits (&bits);
350: es = &cl_entities[newnum].baseline;
351: CL_ParseDelta (&nullstate, es, newnum, bits);
352: }
353:
354:
355: /*
356: ================
357: CL_LoadClientinfo
358:
359: ================
360: */
361: void CL_LoadClientinfo (clientinfo_t *ci, char *s)
362: {
1.1.1.2 ! root 363: int i;
1.1 root 364: char *t;
365: char model_name[MAX_QPATH];
366: char skin_name[MAX_QPATH];
367: char model_filename[MAX_QPATH];
368: char skin_filename[MAX_QPATH];
369: char weapon_filename[MAX_QPATH];
370:
1.1.1.2 ! root 371: if (strcmp(ci->cinfo, s) == 0)
! 372: return; // hasn't changed
! 373:
! 374: strncpy(ci->cinfo, s, sizeof(ci->cinfo));
! 375: ci->cinfo[sizeof(ci->cinfo)-1] = 0;
! 376:
1.1 root 377: // isolate the player's name
1.1.1.2 ! root 378: strncpy(ci->name, s, sizeof(ci->name));
! 379: ci->name[sizeof(ci->name)-1] = 0;
1.1 root 380: t = strstr (s, "\\");
381: if (t)
382: {
383: ci->name[t-s] = 0;
384: s = t+1;
385: }
386:
387: if (cl_noskins->value || *s == 0)
388: {
389: Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
390: Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/weapon.md2");
391: Com_sprintf (skin_filename, sizeof(skin_filename), "players/male/grunt.pcx");
392: Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/male/grunt_i.pcx");
393: ci->model = re.RegisterModel (model_filename);
1.1.1.2 ! root 394: memset(ci->weaponmodel, 0, sizeof(ci->weaponmodel));
! 395: ci->weaponmodel[0] = re.RegisterModel (weapon_filename);
1.1 root 396: ci->skin = re.RegisterSkin (skin_filename);
397: ci->icon = re.RegisterPic (ci->iconname);
398: }
399: else
400: {
401: // isolate the model name
402: strcpy (model_name, s);
403: t = strstr(model_name, "/");
404: if (!t)
405: t = strstr(model_name, "\\");
406: if (!t)
407: t = model_name;
408: *t = 0;
409:
410: // isolate the skin name
411: strcpy (skin_name, s + strlen(model_name) + 1);
412:
413: // model file
414: Com_sprintf (model_filename, sizeof(model_filename), "players/%s/tris.md2", model_name);
415: ci->model = re.RegisterModel (model_filename);
416: if (!ci->model)
417: {
418: strcpy(model_name, "male");
419: Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
420: ci->model = re.RegisterModel (model_filename);
421: }
422:
423: // skin file
424: Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
425: ci->skin = re.RegisterSkin (skin_filename);
426:
427: // if we don't have the skin and the model wasn't male,
428: // see if the male has it (this is for CTF's skins)
1.1.1.2 ! root 429: if (!ci->skin && Q_stricmp(model_name, "male"))
1.1 root 430: {
431: // change model to male
432: strcpy(model_name, "male");
433: Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
434: ci->model = re.RegisterModel (model_filename);
435:
436: // see if the skin exists for the male model
437: Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
438: ci->skin = re.RegisterSkin (skin_filename);
439: }
440:
441: // weapon file
1.1.1.2 ! root 442: for (i = 0; i < num_cl_weaponmodels; i++) {
! 443: Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/%s/%s", model_name, cl_weaponmodels[i]);
! 444: ci->weaponmodel[i] = re.RegisterModel(weapon_filename);
! 445: if (!ci->weaponmodel[i] && strcmp(model_name, "cyborg") == 0) {
! 446: // try male
! 447: Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/%s", cl_weaponmodels[i]);
! 448: ci->weaponmodel[i] = re.RegisterModel(weapon_filename);
! 449: }
! 450: if (!cl_vwep->value)
! 451: break; // only one when vwep is off
! 452: }
1.1 root 453:
454: // icon file
455: Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/%s/%s_i.pcx", model_name, skin_name);
456: ci->icon = re.RegisterPic (ci->iconname);
457: }
458:
459: // must have loaded all data types to be valud
1.1.1.2 ! root 460: if (!ci->skin || !ci->icon || !ci->model || !ci->weaponmodel[0])
1.1 root 461: {
462: ci->skin = NULL;
463: ci->icon = NULL;
464: ci->model = NULL;
1.1.1.2 ! root 465: ci->weaponmodel[0] = NULL;
1.1 root 466: return;
467: }
468: }
469:
470: /*
471: ================
472: CL_ParseClientinfo
473:
474: Load the skin, icon, and model for a client
475: ================
476: */
477: void CL_ParseClientinfo (int player)
478: {
479: char *s;
480: clientinfo_t *ci;
481:
482: s = cl.configstrings[player+CS_PLAYERSKINS];
483:
484: ci = &cl.clientinfo[player];
485:
486: CL_LoadClientinfo (ci, s);
487: }
488:
489:
490: /*
491: ================
492: CL_ParseConfigString
493: ================
494: */
495: void CL_ParseConfigString (void)
496: {
497: int i;
498: char *s;
499:
500: i = MSG_ReadShort (&net_message);
501: if (i < 0 || i >= MAX_CONFIGSTRINGS)
502: Com_Error (ERR_DROP, "configstring > MAX_CONFIGSTRINGS");
503: s = MSG_ReadString(&net_message);
504: strcpy (cl.configstrings[i], s);
505:
506: // do something apropriate
507:
508: if (i >= CS_LIGHTS && i < CS_LIGHTS+MAX_LIGHTSTYLES)
509: CL_SetLightstyle (i - CS_LIGHTS);
510: else if (i == CS_CDTRACK)
511: {
512: if (cl.refresh_prepped)
513: CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
514: }
515: else if (i >= CS_MODELS && i < CS_MODELS+MAX_MODELS)
516: {
517: if (cl.refresh_prepped)
518: {
519: cl.model_draw[i-CS_MODELS] = re.RegisterModel (cl.configstrings[i]);
520: if (cl.configstrings[i][0] == '*')
521: cl.model_clip[i-CS_MODELS] = CM_InlineModel (cl.configstrings[i]);
522: else
523: cl.model_clip[i-CS_MODELS] = NULL;
524: }
525: }
526: else if (i >= CS_SOUNDS && i < CS_SOUNDS+MAX_MODELS)
527: {
528: if (cl.refresh_prepped)
529: cl.sound_precache[i-CS_SOUNDS] = S_RegisterSound (cl.configstrings[i]);
530: }
531: else if (i >= CS_IMAGES && i < CS_IMAGES+MAX_MODELS)
532: {
533: if (cl.refresh_prepped)
534: cl.image_precache[i-CS_IMAGES] = re.RegisterPic (cl.configstrings[i]);
535: }
536: else if (i >= CS_PLAYERSKINS && i < CS_PLAYERSKINS+MAX_CLIENTS)
537: {
538: if (cl.refresh_prepped)
539: CL_ParseClientinfo (i-CS_PLAYERSKINS);
540: }
541: }
542:
543:
544: /*
545: =====================================================================
546:
547: ACTION MESSAGES
548:
549: =====================================================================
550: */
551:
552: /*
553: ==================
554: CL_ParseStartSoundPacket
555: ==================
556: */
557: void CL_ParseStartSoundPacket(void)
558: {
559: vec3_t pos_v;
560: float *pos;
561: int channel, ent;
562: int sound_num;
563: float volume;
564: float attenuation;
565: int flags;
566: float ofs;
567:
568: flags = MSG_ReadByte (&net_message);
569: sound_num = MSG_ReadByte (&net_message);
570:
571: if (flags & SND_VOLUME)
572: volume = MSG_ReadByte (&net_message) / 255.0;
573: else
574: volume = DEFAULT_SOUND_PACKET_VOLUME;
575:
576: if (flags & SND_ATTENUATION)
577: attenuation = MSG_ReadByte (&net_message) / 64.0;
578: else
579: attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
580:
581: if (flags & SND_OFFSET)
582: ofs = MSG_ReadByte (&net_message) / 1000.0;
583: else
584: ofs = 0;
585:
586: if (flags & SND_ENT)
587: { // entity reletive
588: channel = MSG_ReadShort(&net_message);
589: ent = channel>>3;
590: if (ent > MAX_EDICTS)
591: Com_Error (ERR_DROP,"CL_ParseStartSoundPacket: ent = %i", ent);
592:
593: channel &= 7;
594: }
595: else
596: {
597: ent = 0;
598: channel = 0;
599: }
600:
601: if (flags & SND_POS)
602: { // positioned in space
603: MSG_ReadPos (&net_message, pos_v);
604:
605: pos = pos_v;
606: }
607: else // use entity number
608: pos = NULL;
609:
610: if (!cl.sound_precache[sound_num])
611: return;
612:
613: S_StartSound (pos, ent, channel, cl.sound_precache[sound_num], volume, attenuation, ofs);
614: }
615:
616:
617: void SHOWNET(char *s)
618: {
619: if (cl_shownet->value>=2)
620: Com_Printf ("%3i:%s\n", net_message.readcount-1, s);
621: }
622:
623: /*
624: =====================
625: CL_ParseServerMessage
626: =====================
627: */
628: void CL_ParseServerMessage (void)
629: {
630: int cmd;
631: char *s;
632: int i;
633:
634: //
635: // if recording demos, copy the message out
636: //
637: if (cl_shownet->value == 1)
638: Com_Printf ("%i ",net_message.cursize);
639: else if (cl_shownet->value >= 2)
640: Com_Printf ("------------------\n");
641:
642:
643: //
644: // parse the message
645: //
646: while (1)
647: {
648: if (net_message.readcount > net_message.cursize)
649: {
650: Com_Error (ERR_DROP,"CL_ParseServerMessage: Bad server message");
651: break;
652: }
653:
654: cmd = MSG_ReadByte (&net_message);
655:
656: if (cmd == -1)
657: {
658: SHOWNET("END OF MESSAGE");
659: break;
660: }
661:
662: if (cl_shownet->value>=2)
663: {
664: if (!svc_strings[cmd])
665: Com_Printf ("%3i:BAD CMD %i\n", net_message.readcount-1,cmd);
666: else
667: SHOWNET(svc_strings[cmd]);
668: }
669:
670: // other commands
671: switch (cmd)
672: {
673: default:
674: Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n");
675: break;
676:
677: case svc_nop:
678: // Com_Printf ("svc_nop\n");
679: break;
680:
681: case svc_disconnect:
682: Com_Error (ERR_DISCONNECT,"Server disconnected\n");
683: break;
684:
685: case svc_reconnect:
686: Com_Printf ("Server disconnected, reconnecting\n");
1.1.1.2 ! root 687: if (cls.download) {
! 688: //ZOID, close download
! 689: fclose (cls.download);
! 690: cls.download = NULL;
! 691: }
1.1 root 692: cls.state = ca_connecting;
693: cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
694: break;
695:
696: case svc_print:
697: i = MSG_ReadByte (&net_message);
698: if (i == PRINT_CHAT)
699: {
700: S_StartLocalSound ("misc/talk.wav");
701: con.ormask = 128;
702: }
703: Com_Printf ("%s", MSG_ReadString (&net_message));
704: con.ormask = 0;
705: break;
706:
707: case svc_centerprint:
708: SCR_CenterPrint (MSG_ReadString (&net_message));
709: break;
710:
711: case svc_stufftext:
712: s = MSG_ReadString (&net_message);
713: Com_DPrintf ("stufftext: %s\n", s);
714: Cbuf_AddText (s);
715: break;
716:
717: case svc_serverdata:
718: Cbuf_Execute (); // make sure any stuffed commands are done
719: CL_ParseServerData ();
720: break;
721:
722: case svc_configstring:
723: CL_ParseConfigString ();
724: break;
725:
726: case svc_sound:
727: CL_ParseStartSoundPacket();
728: break;
729:
730: case svc_spawnbaseline:
731: CL_ParseBaseline ();
732: break;
733:
734: case svc_temp_entity:
735: CL_ParseTEnt ();
736: break;
737:
738: case svc_muzzleflash:
739: CL_ParseMuzzleFlash ();
740: break;
741:
742: case svc_muzzleflash2:
743: CL_ParseMuzzleFlash2 ();
744: break;
745:
746: case svc_download:
747: CL_ParseDownload ();
748: break;
749:
750: case svc_frame:
751: CL_ParseFrame ();
752: break;
753:
754: case svc_inventory:
755: CL_ParseInventory ();
756: break;
757:
758: case svc_layout:
759: s = MSG_ReadString (&net_message);
760: strncpy (cl.layout, s, sizeof(cl.layout)-1);
761: break;
762:
763: case svc_playerinfo:
764: case svc_packetentities:
765: case svc_deltapacketentities:
766: Com_Error (ERR_DROP, "Out of place frame data");
767: break;
768: }
769: }
770:
771: CL_AddNetgraph ();
772:
773: //
774: // we don't know if it is ok to save a demo message until
775: // after we have parsed the frame
776: //
777: if (cls.demorecording && !cls.demowaiting)
778: CL_WriteDemoMessage ();
779:
780: }
781:
782:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.