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