|
|
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.