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 // cl_parse.c -- parse a message received from the server 21 22 #include "quakedef.h" 23 24 char *svc_strings[] = 25 { 26 "svc_bad", 27 "svc_nop", 28 "svc_disconnect", 29 "svc_updatestat", 30 "svc_version", // [long] server version 31 "svc_setview", // [short] entity number 32 "svc_sound", // <see code> 33 "svc_time", // [float] server time 34 "svc_print", // [string] null terminated string 35 "svc_stufftext", // [string] stuffed into client's console buffer 36 // the string should be \n terminated 37 "svc_setangle", // [vec3] set the view angle to this absolute value 38 39 "svc_serverdata", // [long] version ... 40 "svc_lightstyle", // [byte] [string] 41 "svc_updatename", // [byte] [string] 42 "svc_updatefrags", // [byte] [short] 43 "svc_clientdata", // <shortbits + data> 44 "svc_stopsound", // <see code> 45 "svc_updatecolors", // [byte] [byte] 46 "svc_particle", // [vec3] <variable> 47 "svc_damage", // [byte] impact [byte] blood [vec3] from 48 49 "svc_spawnstatic", 50 "OBSOLETE svc_spawnbinary", 51 "svc_spawnbaseline", 52 53 "svc_temp_entity", // <variable> 54 "svc_setpause", 55 "svc_signonnum", 56 "svc_centerprint", 57 "svc_killedmonster", 58 "svc_foundsecret", 59 "svc_spawnstaticsound", 60 "svc_intermission", 61 "svc_finale", 62 63 "svc_cdtrack", 64 "svc_sellscreen", 65 66 "svc_smallkick", 67 "svc_bigkick", 68 69 "svc_updateping", 70 "svc_updateentertime", 71 72 "svc_updatestatlong", 73 "svc_muzzleflash", 74 "svc_updateuserinfo", 75 "svc_download", 76 "svc_playerinfo", 77 "svc_nails", 78 "svc_choke", 79 "svc_modellist", 80 "svc_soundlist", 81 "svc_packetentities", 82 "svc_deltapacketentities", 83 "svc_maxspeed", 84 "svc_entgravity", 85 86 "svc_setinfo", 87 "svc_serverinfo", 88 "svc_updatepl", 89 "NEW PROTOCOL", 90 "NEW PROTOCOL", 91 "NEW PROTOCOL", 92 "NEW PROTOCOL", 93 "NEW PROTOCOL", 94 "NEW PROTOCOL", 95 "NEW PROTOCOL", 96 "NEW PROTOCOL", 97 "NEW PROTOCOL", 98 "NEW PROTOCOL", 99 "NEW PROTOCOL", 100 "NEW PROTOCOL", 101 "NEW PROTOCOL" 102 }; 103 104 int oldparsecountmod; 105 int parsecountmod; 106 double parsecounttime; 107 108 int cl_spikeindex, cl_playerindex, cl_flagindex; 109 110 //============================================================================= 111 112 int packet_latency[NET_TIMINGS]; 113 114 int CL_CalcNet (void) 115 { 116 int a, i; 117 frame_t *frame; 118 int lost; 119 char st[80]; 120 121 for (i=cls.netchan.outgoing_sequence-UPDATE_BACKUP+1 122 ; i <= cls.netchan.outgoing_sequence 123 ; i++) 124 { 125 frame = &cl.frames[i&UPDATE_MASK]; 126 if (frame->receivedtime == -1) 127 packet_latency[i&NET_TIMINGSMASK] = 9999; // dropped 128 else if (frame->receivedtime == -2) 129 packet_latency[i&NET_TIMINGSMASK] = 10000; // choked 130 else if (frame->invalid) 131 packet_latency[i&NET_TIMINGSMASK] = 9998; // invalid delta 132 else 133 packet_latency[i&NET_TIMINGSMASK] = (frame->receivedtime - frame->senttime)*20; 134 } 135 136 lost = 0; 137 for (a=0 ; a<NET_TIMINGS ; a++) 138 { 139 i = (cls.netchan.outgoing_sequence-a) & NET_TIMINGSMASK; 140 if (packet_latency[i] == 9999) 141 lost++; 142 } 143 return lost * 100 / NET_TIMINGS; 144 } 145 146 //============================================================================= 147 148 /* 149 =============== 150 CL_CheckOrDownloadFile 151 152 Returns true if the file exists, otherwise it attempts 153 to start a download from the server. 154 =============== 155 */ 156 qboolean CL_CheckOrDownloadFile (char *filename) 157 { 158 FILE *f; 159 160 if (strstr (filename, "..")) 161 { 162 Con_Printf ("Refusing to download a path with ..\n"); 163 return true; 164 } 165 166 COM_FOpenFile (filename, &f); 167 if (f) 168 { // it exists, no need to download 169 fclose (f); 170 return true; 171 } 172 173 //ZOID - can't download when recording 174 if (cls.demorecording) { 175 Con_Printf("Unable to download %s in record mode.\n", cls.downloadname); 176 return true; 177 } 178 //ZOID - can't download when playback 179 if (cls.demoplayback) 180 return true; 181 182 strcpy (cls.downloadname, filename); 183 Con_Printf ("Downloading %s...\n", cls.downloadname); 184 185 // download to a temp name, and only rename 186 // to the real name when done, so if interrupted 187 // a runt file wont be left 188 COM_StripExtension (cls.downloadname, cls.downloadtempname); 189 strcat (cls.downloadtempname, ".tmp"); 190 191 MSG_WriteByte (&cls.netchan.message, clc_stringcmd); 192 MSG_WriteString (&cls.netchan.message, va("download %s", cls.downloadname)); 193 194 cls.downloadnumber++; 195 196 return false; 197 } 198 199 /* 200 ================= 201 Model_NextDownload 202 ================= 203 */ 204 void Model_NextDownload (void) 205 { 206 char *s; 207 int i; 208 extern char gamedirfile[]; 209 210 if (cls.downloadnumber == 0) 211 { 212 Con_Printf ("Checking models...\n"); 213 cls.downloadnumber = 1; 214 } 215 216 cls.downloadtype = dl_model; 217 for ( 218 ; cl.model_name[cls.downloadnumber][0] 219 ; cls.downloadnumber++) 220 { 221 s = cl.model_name[cls.downloadnumber]; 222 if (s[0] == '*') 223 continue; // inline brush model 224 if (!CL_CheckOrDownloadFile(s)) 225 return; // started a download 226 } 227 228 for (i=1 ; i<MAX_MODELS ; i++) 229 { 230 if (!cl.model_name[i][0]) 231 break; 232 233 cl.model_precache[i] = Mod_ForName (cl.model_name[i], false); 234 235 if (!cl.model_precache[i]) 236 { 237 Con_Printf ("\nThe required model file '%s' could not be found or downloaded.\n\n" 238 , cl.model_name[i]); 239 Con_Printf ("You may need to download or purchase a %s client " 240 "pack in order to play on this server.\n\n", gamedirfile); 241 CL_Disconnect (); 242 return; 243 } 244 } 245 246 // all done 247 cl.worldmodel = cl.model_precache[1]; 248 R_NewMap (); 249 Hunk_Check (); // make sure nothing is hurt 250 251 // done with modellist, request first of static signon messages 252 MSG_WriteByte (&cls.netchan.message, clc_stringcmd); 253 // MSG_WriteString (&cls.netchan.message, va("prespawn %i 0 %i", cl.servercount, cl.worldmodel->checksum2)); 254 MSG_WriteString (&cls.netchan.message, va(prespawn_name, cl.servercount, cl.worldmodel->checksum2)); 255 } 256 257 /* 258 ================= 259 Sound_NextDownload 260 ================= 261 */ 262 void Sound_NextDownload (void) 263 { 264 char *s; 265 int i; 266 267 if (cls.downloadnumber == 0) 268 { 269 Con_Printf ("Checking sounds...\n"); 270 cls.downloadnumber = 1; 271 } 272 273 cls.downloadtype = dl_sound; 274 for ( 275 ; cl.sound_name[cls.downloadnumber][0] 276 ; cls.downloadnumber++) 277 { 278 s = cl.sound_name[cls.downloadnumber]; 279 if (!CL_CheckOrDownloadFile(va("sound/%s",s))) 280 return; // started a download 281 } 282 283 for (i=1 ; i<MAX_SOUNDS ; i++) 284 { 285 if (!cl.sound_name[i][0]) 286 break; 287 cl.sound_precache[i] = S_PrecacheSound (cl.sound_name[i]); 288 } 289 290 // done with sounds, request models now 291 memset (cl.model_precache, 0, sizeof(cl.model_precache)); 292 cl_playerindex = -1; 293 cl_spikeindex = -1; 294 cl_flagindex = -1; 295 MSG_WriteByte (&cls.netchan.message, clc_stringcmd); 296 // MSG_WriteString (&cls.netchan.message, va("modellist %i 0", cl.servercount)); 297 MSG_WriteString (&cls.netchan.message, va(modellist_name, cl.servercount, 0)); 298 } 299 300 301 /* 302 ====================== 303 CL_RequestNextDownload 304 ====================== 305 */ 306 void CL_RequestNextDownload (void) 307 { 308 switch (cls.downloadtype) 309 { 310 case dl_single: 311 break; 312 case dl_skin: 313 Skin_NextDownload (); 314 break; 315 case dl_model: 316 Model_NextDownload (); 317 break; 318 case dl_sound: 319 Sound_NextDownload (); 320 break; 321 case dl_none: 322 default: 323 Con_DPrintf("Unknown download type.\n"); 324 } 325 } 326 327 /* 328 ===================== 329 CL_ParseDownload 330 331 A download message has been received from the server 332 ===================== 333 */ 334 void CL_ParseDownload (void) 335 { 336 int size, percent; 337 char name[1024]; 338 int r; 339 340 341 // read the data 342 size = MSG_ReadShort (); 343 percent = MSG_ReadByte (); 344 345 if (cls.demoplayback) { 346 if (size > 0) 347 msg_readcount += size; 348 return; // not in demo playback 349 } 350 351 if (size == -1) 352 { 353 Con_Printf ("File not found.\n"); 354 if (cls.download) 355 { 356 Con_Printf ("cls.download shouldn't have been set\n"); 357 fclose (cls.download); 358 cls.download = NULL; 359 } 360 CL_RequestNextDownload (); 361 return; 362 } 363 364 // open the file if not opened yet 365 if (!cls.download) 366 { 367 if (strncmp(cls.downloadtempname,"skins/",6)) 368 sprintf (name, "%s/%s", com_gamedir, cls.downloadtempname); 369 else 370 sprintf (name, "qw/%s", cls.downloadtempname); 371 372 COM_CreatePath (name); 373 374 cls.download = fopen (name, "wb"); 375 if (!cls.download) 376 { 377 msg_readcount += size; 378 Con_Printf ("Failed to open %s\n", cls.downloadtempname); 379 CL_RequestNextDownload (); 380 return; 381 } 382 } 383 384 fwrite (net_message.data + msg_readcount, 1, size, cls.download); 385 msg_readcount += size; 386 387 if (percent != 100) 388 { 389 // change display routines by zoid 390 // request next block 391 #if 0 392 Con_Printf ("."); 393 if (10*(percent/10) != cls.downloadpercent) 394 { 395 cls.downloadpercent = 10*(percent/10); 396 Con_Printf ("%i%%", cls.downloadpercent); 397 } 398 #endif 399 cls.downloadpercent = percent; 400 401 MSG_WriteByte (&cls.netchan.message, clc_stringcmd); 402 SZ_Print (&cls.netchan.message, "nextdl"); 403 } 404 else 405 { 406 char oldn[MAX_OSPATH]; 407 char newn[MAX_OSPATH]; 408 409 #if 0 410 Con_Printf ("100%%\n"); 411 #endif 412 413 fclose (cls.download); 414 415 // rename the temp file to it's final name 416 if (strcmp(cls.downloadtempname, cls.downloadname)) { 417 if (strncmp(cls.downloadtempname,"skins/",6)) { 418 sprintf (oldn, "%s/%s", com_gamedir, cls.downloadtempname); 419 sprintf (newn, "%s/%s", com_gamedir, cls.downloadname); 420 } else { 421 sprintf (oldn, "qw/%s", cls.downloadtempname); 422 sprintf (newn, "qw/%s", cls.downloadname); 423 } 424 r = rename (oldn, newn); 425 if (r) 426 Con_Printf ("failed to rename.\n"); 427 } 428 429 cls.download = NULL; 430 cls.downloadpercent = 0; 431 432 // get another file if needed 433 434 CL_RequestNextDownload (); 435 } 436 } 437 438 static byte *upload_data; 439 static int upload_pos; 440 static int upload_size; 441 442 void CL_NextUpload(void) 443 { 444 byte buffer[1024]; 445 int r; 446 int percent; 447 int size; 448 449 if (!upload_data) 450 return; 451 452 r = upload_size - upload_pos; 453 if (r > 768) 454 r = 768; 455 memcpy(buffer, upload_data + upload_pos, r); 456 MSG_WriteByte (&cls.netchan.message, clc_upload); 457 MSG_WriteShort (&cls.netchan.message, r); 458 459 upload_pos += r; 460 size = upload_size; 461 if (!size) 462 size = 1; 463 percent = upload_pos*100/size; 464 MSG_WriteByte (&cls.netchan.message, percent); 465 SZ_Write (&cls.netchan.message, buffer, r); 466 467 Con_DPrintf ("UPLOAD: %6d: %d written\n", upload_pos - r, r); 468 469 if (upload_pos != upload_size) 470 return; 471 472 Con_Printf ("Upload completed\n"); 473 474 free(upload_data); 475 upload_data = 0; 476 upload_pos = upload_size = 0; 477 } 478 479 void CL_StartUpload (byte *data, int size) 480 { 481 if (cls.state < ca_onserver) 482 return; // gotta be connected 483 484 // override 485 if (upload_data) 486 free(upload_data); 487 488 Con_DPrintf("Upload starting of %d...\n", size); 489 490 upload_data = malloc(size); 491 memcpy(upload_data, data, size); 492 upload_size = size; 493 upload_pos = 0; 494 495 CL_NextUpload(); 496 } 497 498 qboolean CL_IsUploading(void) 499 { 500 if (upload_data) 501 return true; 502 return false; 503 } 504 505 void CL_StopUpload(void) 506 { 507 if (upload_data) 508 free(upload_data); 509 upload_data = NULL; 510 } 511 512 /* 513 ===================================================================== 514 515 SERVER CONNECTING MESSAGES 516 517 ===================================================================== 518 */ 519 520 /* 521 ================== 522 CL_ParseServerData 523 ================== 524 */ 525 void CL_ParseServerData (void) 526 { 527 char *str; 528 FILE *f; 529 char fn[MAX_OSPATH]; 530 qboolean cflag = false; 531 extern char gamedirfile[MAX_OSPATH]; 532 int protover; 533 534 Con_DPrintf ("Serverdata packet received.\n"); 535 // 536 // wipe the client_state_t struct 537 // 538 CL_ClearState (); 539 540 // parse protocol version number 541 // allow 2.2 and 2.29 demos to play 542 protover = MSG_ReadLong (); 543 if (protover != PROTOCOL_VERSION && 544 !(cls.demoplayback && (protover == 26 || protover == 27 || protover == 28))) 545 Host_EndGame ("Server returned version %i, not %i\nYou probably need to upgrade.\nCheck http://www.quakeworld.net/", protover, PROTOCOL_VERSION); 546 547 cl.servercount = MSG_ReadLong (); 548 549 // game directory 550 str = MSG_ReadString (); 551 552 if (strcasecmp(gamedirfile, str)) { 553 // save current config 554 Host_WriteConfiguration (); 555 cflag = true; 556 } 557 558 COM_Gamedir(str); 559 560 //ZOID--run the autoexec.cfg in the gamedir 561 //if it exists 562 if (cflag) { 563 sprintf(fn, "%s/%s", com_gamedir, "config.cfg"); 564 if ((f = fopen(fn, "r")) != NULL) { 565 fclose(f); 566 Cbuf_AddText ("cl_warncmd 0\n"); 567 Cbuf_AddText("exec config.cfg\n"); 568 Cbuf_AddText("exec frontend.cfg\n"); 569 Cbuf_AddText ("cl_warncmd 1\n"); 570 } 571 } 572 573 // parse player slot, high bit means spectator 574 cl.playernum = MSG_ReadByte (); 575 if (cl.playernum & 128) 576 { 577 cl.spectator = true; 578 cl.playernum &= ~128; 579 } 580 581 // get the full level name 582 str = MSG_ReadString (); 583 strncpy (cl.levelname, str, sizeof(cl.levelname)-1); 584 585 // get the movevars 586 movevars.gravity = MSG_ReadFloat(); 587 movevars.stopspeed = MSG_ReadFloat(); 588 movevars.maxspeed = MSG_ReadFloat(); 589 movevars.spectatormaxspeed = MSG_ReadFloat(); 590 movevars.accelerate = MSG_ReadFloat(); 591 movevars.airaccelerate = MSG_ReadFloat(); 592 movevars.wateraccelerate = MSG_ReadFloat(); 593 movevars.friction = MSG_ReadFloat(); 594 movevars.waterfriction = MSG_ReadFloat(); 595 movevars.entgravity = MSG_ReadFloat(); 596 597 // seperate the printfs so the server message can have a color 598 Con_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"); 599 Con_Printf ("%c%s\n", 2, str); 600 601 // ask for the sound list next 602 memset(cl.sound_name, 0, sizeof(cl.sound_name)); 603 MSG_WriteByte (&cls.netchan.message, clc_stringcmd); 604 // MSG_WriteString (&cls.netchan.message, va("soundlist %i 0", cl.servercount)); 605 MSG_WriteString (&cls.netchan.message, va(soundlist_name, cl.servercount, 0)); 606 607 // now waiting for downloads, etc 608 cls.state = ca_onserver; 609 } 610 611 /* 612 ================== 613 CL_ParseSoundlist 614 ================== 615 */ 616 void CL_ParseSoundlist (void) 617 { 618 int numsounds; 619 char *str; 620 int n; 621 622 // precache sounds 623 // memset (cl.sound_precache, 0, sizeof(cl.sound_precache)); 624 625 numsounds = MSG_ReadByte(); 626 627 for (;;) { 628 str = MSG_ReadString (); 629 if (!str[0]) 630 break; 631 numsounds++; 632 if (numsounds == MAX_SOUNDS) 633 Host_EndGame ("Server sent too many sound_precache"); 634 strcpy (cl.sound_name[numsounds], str); 635 } 636 637 n = MSG_ReadByte(); 638 639 if (n) { 640 MSG_WriteByte (&cls.netchan.message, clc_stringcmd); 641 // MSG_WriteString (&cls.netchan.message, va("soundlist %i %i", cl.servercount, n)); 642 MSG_WriteString (&cls.netchan.message, va(soundlist_name, cl.servercount, n)); 643 return; 644 } 645 646 cls.downloadnumber = 0; 647 cls.downloadtype = dl_sound; 648 Sound_NextDownload (); 649 } 650 651 /* 652 ================== 653 CL_ParseModellist 654 ================== 655 */ 656 void CL_ParseModellist (void) 657 { 658 int nummodels; 659 char *str; 660 int n; 661 662 // precache models and note certain default indexes 663 nummodels = MSG_ReadByte(); 664 665 for (;;) 666 { 667 str = MSG_ReadString (); 668 if (!str[0]) 669 break; 670 nummodels++; 671 if (nummodels==MAX_MODELS) 672 Host_EndGame ("Server sent too many model_precache"); 673 strcpy (cl.model_name[nummodels], str); 674 675 if (!strcmp(cl.model_name[nummodels],"progs/spike.mdl")) 676 cl_spikeindex = nummodels; 677 if (!strcmp(cl.model_name[nummodels],"progs/player.mdl")) 678 cl_playerindex = nummodels; 679 if (!strcmp(cl.model_name[nummodels],"progs/flag.mdl")) 680 cl_flagindex = nummodels; 681 } 682 683 n = MSG_ReadByte(); 684 685 if (n) { 686 MSG_WriteByte (&cls.netchan.message, clc_stringcmd); 687 // MSG_WriteString (&cls.netchan.message, va("modellist %i %i", cl.servercount, n)); 688 MSG_WriteString (&cls.netchan.message, va(modellist_name, cl.servercount, n)); 689 return; 690 } 691 692 cls.downloadnumber = 0; 693 cls.downloadtype = dl_model; 694 Model_NextDownload (); 695 } 696 697 /* 698 ================== 699 CL_ParseBaseline 700 ================== 701 */ 702 void CL_ParseBaseline (entity_state_t *es) 703 { 704 int i; 705 706 es->modelindex = MSG_ReadByte (); 707 es->frame = MSG_ReadByte (); 708 es->colormap = MSG_ReadByte(); 709 es->skinnum = MSG_ReadByte(); 710 for (i=0 ; i<3 ; i++) 711 { 712 es->origin[i] = MSG_ReadCoord (); 713 es->angles[i] = MSG_ReadAngle (); 714 } 715 } 716 717 718 719 /* 720 ===================== 721 CL_ParseStatic 722 723 Static entities are non-interactive world objects 724 like torches 725 ===================== 726 */ 727 void CL_ParseStatic (void) 728 { 729 entity_t *ent; 730 int i; 731 entity_state_t es; 732 733 CL_ParseBaseline (&es); 734 735 i = cl.num_statics; 736 if (i >= MAX_STATIC_ENTITIES) 737 Host_EndGame ("Too many static entities"); 738 ent = &cl_static_entities[i]; 739 cl.num_statics++; 740 741 // copy it to the current state 742 ent->model = cl.model_precache[es.modelindex]; 743 ent->frame = es.frame; 744 ent->colormap = vid.colormap; 745 ent->skinnum = es.skinnum; 746 747 VectorCopy (es.origin, ent->origin); 748 VectorCopy (es.angles, ent->angles); 749 750 R_AddEfrags (ent); 751 } 752 753 /* 754 =================== 755 CL_ParseStaticSound 756 =================== 757 */ 758 void CL_ParseStaticSound (void) 759 { 760 vec3_t org; 761 int sound_num, vol, atten; 762 int i; 763 764 for (i=0 ; i<3 ; i++) 765 org[i] = MSG_ReadCoord (); 766 sound_num = MSG_ReadByte (); 767 vol = MSG_ReadByte (); 768 atten = MSG_ReadByte (); 769 770 S_StaticSound (cl.sound_precache[sound_num], org, vol, atten); 771 } 772 773 774 775 /* 776 ===================================================================== 777 778 ACTION MESSAGES 779 780 ===================================================================== 781 */ 782 783 /* 784 ================== 785 CL_ParseStartSoundPacket 786 ================== 787 */ 788 void CL_ParseStartSoundPacket(void) 789 { 790 vec3_t pos; 791 int channel, ent; 792 int sound_num; 793 int volume; 794 float attenuation; 795 int i; 796 797 channel = MSG_ReadShort(); 798 799 if (channel & SND_VOLUME) 800 volume = MSG_ReadByte (); 801 else 802 volume = DEFAULT_SOUND_PACKET_VOLUME; 803 804 if (channel & SND_ATTENUATION) 805 attenuation = MSG_ReadByte () / 64.0; 806 else 807 attenuation = DEFAULT_SOUND_PACKET_ATTENUATION; 808 809 sound_num = MSG_ReadByte (); 810 811 for (i=0 ; i<3 ; i++) 812 pos[i] = MSG_ReadCoord (); 813 814 ent = (channel>>3)&1023; 815 channel &= 7; 816 817 if (ent > MAX_EDICTS) 818 Host_EndGame ("CL_ParseStartSoundPacket: ent = %i", ent); 819 820 S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation); 821 } 822 823 824 /* 825 ================== 826 CL_ParseClientdata 827 828 Server information pertaining to this client only, sent every frame 829 ================== 830 */ 831 void CL_ParseClientdata (void) 832 { 833 int i; 834 float latency; 835 frame_t *frame; 836 837 // calculate simulated time of message 838 oldparsecountmod = parsecountmod; 839 840 i = cls.netchan.incoming_acknowledged; 841 cl.parsecount = i; 842 i &= UPDATE_MASK; 843 parsecountmod = i; 844 frame = &cl.frames[i]; 845 parsecounttime = cl.frames[i].senttime; 846 847 frame->receivedtime = realtime; 848 849 // calculate latency 850 latency = frame->receivedtime - frame->senttime; 851 852 if (latency < 0 || latency > 1.0) 853 { 854 // Con_Printf ("Odd latency: %5.2f\n", latency); 855 } 856 else 857 { 858 // drift the average latency towards the observed latency 859 if (latency < cls.latency) 860 cls.latency = latency; 861 else 862 cls.latency += 0.001; // drift up, so correction are needed 863 } 864 } 865 866 /* 867 ===================== 868 CL_NewTranslation 869 ===================== 870 */ 871 void CL_NewTranslation (int slot) 872 { 873 #ifdef GLQUAKE 874 if (slot > MAX_CLIENTS) 875 Sys_Error ("CL_NewTranslation: slot > MAX_CLIENTS"); 876 877 R_TranslatePlayerSkin(slot); 878 #else 879 880 int i, j; 881 int top, bottom; 882 byte *dest, *source; 883 player_info_t *player; 884 char s[512]; 885 886 if (slot > MAX_CLIENTS) 887 Sys_Error ("CL_NewTranslation: slot > MAX_CLIENTS"); 888 889 player = &cl.players[slot]; 890 891 strcpy(s, Info_ValueForKey(player->userinfo, "skin")); 892 COM_StripExtension(s, s); 893 if (player->skin && !stricmp(s, player->skin->name)) 894 player->skin = NULL; 895 896 if (player->_topcolor != player->topcolor || 897 player->_bottomcolor != player->bottomcolor || !player->skin) { 898 player->_topcolor = player->topcolor; 899 player->_bottomcolor = player->bottomcolor; 900 901 dest = player->translations; 902 source = vid.colormap; 903 memcpy (dest, vid.colormap, sizeof(player->translations)); 904 top = player->topcolor; 905 if (top > 13 || top < 0) 906 top = 13; 907 top *= 16; 908 bottom = player->bottomcolor; 909 if (bottom > 13 || bottom < 0) 910 bottom = 13; 911 bottom *= 16; 912 913 for (i=0 ; i<VID_GRADES ; i++, dest += 256, source+=256) 914 { 915 if (top < 128) // the artists made some backwards ranges. sigh. 916 memcpy (dest + TOP_RANGE, source + top, 16); 917 else 918 for (j=0 ; j<16 ; j++) 919 dest[TOP_RANGE+j] = source[top+15-j]; 920 921 if (bottom < 128) 922 memcpy (dest + BOTTOM_RANGE, source + bottom, 16); 923 else 924 for (j=0 ; j<16 ; j++) 925 dest[BOTTOM_RANGE+j] = source[bottom+15-j]; 926 } 927 } 928 #endif 929 } 930 931 /* 932 ============== 933 CL_UpdateUserinfo 934 ============== 935 */ 936 void CL_ProcessUserInfo (int slot, player_info_t *player) 937 { 938 strncpy (player->name, Info_ValueForKey (player->userinfo, "name"), sizeof(player->name)-1); 939 player->topcolor = atoi(Info_ValueForKey (player->userinfo, "topcolor")); 940 player->bottomcolor = atoi(Info_ValueForKey (player->userinfo, "bottomcolor")); 941 if (Info_ValueForKey (player->userinfo, "*spectator")[0]) 942 player->spectator = true; 943 else 944 player->spectator = false; 945 946 if (cls.state == ca_active) 947 Skin_Find (player); 948 949 Sbar_Changed (); 950 CL_NewTranslation (slot); 951 } 952 953 /* 954 ============== 955 CL_UpdateUserinfo 956 ============== 957 */ 958 void CL_UpdateUserinfo (void) 959 { 960 int slot; 961 player_info_t *player; 962 963 slot = MSG_ReadByte (); 964 if (slot >= MAX_CLIENTS) 965 Host_EndGame ("CL_ParseServerMessage: svc_updateuserinfo > MAX_SCOREBOARD"); 966 967 player = &cl.players[slot]; 968 player->userid = MSG_ReadLong (); 969 strncpy (player->userinfo, MSG_ReadString(), sizeof(player->userinfo)-1); 970 971 CL_ProcessUserInfo (slot, player); 972 } 973 974 /* 975 ============== 976 CL_SetInfo 977 ============== 978 */ 979 void CL_SetInfo (void) 980 { 981 int slot; 982 player_info_t *player; 983 char key[MAX_MSGLEN]; 984 char value[MAX_MSGLEN]; 985 986 slot = MSG_ReadByte (); 987 if (slot >= MAX_CLIENTS) 988 Host_EndGame ("CL_ParseServerMessage: svc_setinfo > MAX_SCOREBOARD"); 989 990 player = &cl.players[slot]; 991 992 strncpy (key, MSG_ReadString(), sizeof(key) - 1); 993 key[sizeof(key) - 1] = 0; 994 strncpy (value, MSG_ReadString(), sizeof(value) - 1); 995 key[sizeof(value) - 1] = 0; 996 997 Con_DPrintf("SETINFO %s: %s=%s\n", player->name, key, value); 998 999 Info_SetValueForKey (player->userinfo, key, value, MAX_INFO_STRING); 1000 1001 CL_ProcessUserInfo (slot, player); 1002 } 1003 1004 /* 1005 ============== 1006 CL_ServerInfo 1007 ============== 1008 */ 1009 void CL_ServerInfo (void) 1010 { 1011 int slot; 1012 player_info_t *player; 1013 char key[MAX_MSGLEN]; 1014 char value[MAX_MSGLEN]; 1015 1016 strncpy (key, MSG_ReadString(), sizeof(key) - 1); 1017 key[sizeof(key) - 1] = 0; 1018 strncpy (value, MSG_ReadString(), sizeof(value) - 1); 1019 key[sizeof(value) - 1] = 0; 1020 1021 Con_DPrintf("SERVERINFO: %s=%s\n", key, value); 1022 1023 Info_SetValueForKey (cl.serverinfo, key, value, MAX_SERVERINFO_STRING); 1024 } 1025 1026 /* 1027 ===================== 1028 CL_SetStat 1029 ===================== 1030 */ 1031 void CL_SetStat (int stat, int value) 1032 { 1033 int j; 1034 if (stat < 0 || stat >= MAX_CL_STATS) 1035 Sys_Error ("CL_SetStat: %i is invalid", stat); 1036 1037 Sbar_Changed (); 1038 1039 if (stat == STAT_ITEMS) 1040 { // set flash times 1041 Sbar_Changed (); 1042 for (j=0 ; j<32 ; j++) 1043 if ( (value & (1<<j)) && !(cl.stats[stat] & (1<<j))) 1044 cl.item_gettime[j] = cl.time; 1045 } 1046 1047 cl.stats[stat] = value; 1048 } 1049 1050 /* 1051 ============== 1052 CL_MuzzleFlash 1053 ============== 1054 */ 1055 void CL_MuzzleFlash (void) 1056 { 1057 vec3_t fv, rv, uv; 1058 dlight_t *dl; 1059 int i; 1060 player_state_t *pl; 1061 1062 i = MSG_ReadShort (); 1063 1064 if ((unsigned)(i-1) >= MAX_CLIENTS) 1065 return; 1066 1067 #ifdef GLQUAKE 1068 // don't draw our own muzzle flash in gl if flashblending 1069 if (i-1 == cl.playernum && gl_flashblend.value) 1070 return; 1071 #endif 1072 1073 pl = &cl.frames[parsecountmod].playerstate[i-1]; 1074 1075 dl = CL_AllocDlight (i); 1076 VectorCopy (pl->origin, dl->origin); 1077 AngleVectors (pl->viewangles, fv, rv, uv); 1078 1079 VectorMA (dl->origin, 18, fv, dl->origin); 1080 dl->radius = 200 + (rand()&31); 1081 dl->minlight = 32; 1082 dl->die = cl.time + 0.1; 1083 dl->color[0] = 0.2; 1084 dl->color[1] = 0.1; 1085 dl->color[2] = 0.05; 1086 dl->color[3] = 0.7; 1087 } 1088 1089 1090 #define SHOWNET(x) if(cl_shownet.value==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x); 1091 /* 1092 ===================== 1093 CL_ParseServerMessage 1094 ===================== 1095 */ 1096 int received_framecount; 1097 void CL_ParseServerMessage (void) 1098 { 1099 int cmd; 1100 char *s; 1101 int i, j; 1102 1103 received_framecount = host_framecount; 1104 cl.last_servermessage = realtime; 1105 CL_ClearProjectiles (); 1106 1107 // 1108 // if recording demos, copy the message out 1109 // 1110 if (cl_shownet.value == 1) 1111 Con_Printf ("%i ",net_message.cursize); 1112 else if (cl_shownet.value == 2) 1113 Con_Printf ("------------------\n"); 1114 1115 1116 CL_ParseClientdata (); 1117 1118 // 1119 // parse the message 1120 // 1121 while (1) 1122 { 1123 if (msg_badread) 1124 { 1125 Host_EndGame ("CL_ParseServerMessage: Bad server message"); 1126 break; 1127 } 1128 1129 cmd = MSG_ReadByte (); 1130 1131 if (cmd == -1) 1132 { 1133 msg_readcount++; // so the EOM showner has the right value 1134 SHOWNET("END OF MESSAGE"); 1135 break; 1136 } 1137 1138 SHOWNET(svc_strings[cmd]); 1139 1140 // other commands 1141 switch (cmd) 1142 { 1143 default: 1144 Host_EndGame ("CL_ParseServerMessage: Illegible server message"); 1145 break; 1146 1147 case svc_nop: 1148 // Con_Printf ("svc_nop\n"); 1149 break; 1150 1151 case svc_disconnect: 1152 if (cls.state == ca_connected) 1153 Host_EndGame ("Server disconnected\n" 1154 "Server version may not be compatible"); 1155 else 1156 Host_EndGame ("Server disconnected"); 1157 break; 1158 1159 case svc_print: 1160 i = MSG_ReadByte (); 1161 if (i == PRINT_CHAT) 1162 { 1163 S_LocalSound ("misc/talk.wav"); 1164 con_ormask = 128; 1165 } 1166 Con_Printf ("%s", MSG_ReadString ()); 1167 con_ormask = 0; 1168 break; 1169 1170 case svc_centerprint: 1171 SCR_CenterPrint (MSG_ReadString ()); 1172 break; 1173 1174 case svc_stufftext: 1175 s = MSG_ReadString (); 1176 Con_DPrintf ("stufftext: %s\n", s); 1177 Cbuf_AddText (s); 1178 break; 1179 1180 case svc_damage: 1181 V_ParseDamage (); 1182 break; 1183 1184 case svc_serverdata: 1185 Cbuf_Execute (); // make sure any stuffed commands are done 1186 CL_ParseServerData (); 1187 vid.recalc_refdef = true; // leave full screen intermission 1188 break; 1189 1190 case svc_setangle: 1191 for (i=0 ; i<3 ; i++) 1192 cl.viewangles[i] = MSG_ReadAngle (); 1193 // cl.viewangles[PITCH] = cl.viewangles[ROLL] = 0; 1194 break; 1195 1196 case svc_lightstyle: 1197 i = MSG_ReadByte (); 1198 if (i >= MAX_LIGHTSTYLES) 1199 Sys_Error ("svc_lightstyle > MAX_LIGHTSTYLES"); 1200 Q_strcpy (cl_lightstyle[i].map, MSG_ReadString()); 1201 cl_lightstyle[i].length = Q_strlen(cl_lightstyle[i].map); 1202 break; 1203 1204 case svc_sound: 1205 CL_ParseStartSoundPacket(); 1206 break; 1207 1208 case svc_stopsound: 1209 i = MSG_ReadShort(); 1210 S_StopSound(i>>3, i&7); 1211 break; 1212 1213 case svc_updatefrags: 1214 Sbar_Changed (); 1215 i = MSG_ReadByte (); 1216 if (i >= MAX_CLIENTS) 1217 Host_EndGame ("CL_ParseServerMessage: svc_updatefrags > MAX_SCOREBOARD"); 1218 cl.players[i].frags = MSG_ReadShort (); 1219 break; 1220 1221 case svc_updateping: 1222 i = MSG_ReadByte (); 1223 if (i >= MAX_CLIENTS) 1224 Host_EndGame ("CL_ParseServerMessage: svc_updateping > MAX_SCOREBOARD"); 1225 cl.players[i].ping = MSG_ReadShort (); 1226 break; 1227 1228 case svc_updatepl: 1229 i = MSG_ReadByte (); 1230 if (i >= MAX_CLIENTS) 1231 Host_EndGame ("CL_ParseServerMessage: svc_updatepl > MAX_SCOREBOARD"); 1232 cl.players[i].pl = MSG_ReadByte (); 1233 break; 1234 1235 case svc_updateentertime: 1236 // time is sent over as seconds ago 1237 i = MSG_ReadByte (); 1238 if (i >= MAX_CLIENTS) 1239 Host_EndGame ("CL_ParseServerMessage: svc_updateentertime > MAX_SCOREBOARD"); 1240 cl.players[i].entertime = realtime - MSG_ReadFloat (); 1241 break; 1242 1243 case svc_spawnbaseline: 1244 i = MSG_ReadShort (); 1245 CL_ParseBaseline (&cl_baselines[i]); 1246 break; 1247 case svc_spawnstatic: 1248 CL_ParseStatic (); 1249 break; 1250 case svc_temp_entity: 1251 CL_ParseTEnt (); 1252 break; 1253 1254 case svc_killedmonster: 1255 cl.stats[STAT_MONSTERS]++; 1256 break; 1257 1258 case svc_foundsecret: 1259 cl.stats[STAT_SECRETS]++; 1260 break; 1261 1262 case svc_updatestat: 1263 i = MSG_ReadByte (); 1264 j = MSG_ReadByte (); 1265 CL_SetStat (i, j); 1266 break; 1267 case svc_updatestatlong: 1268 i = MSG_ReadByte (); 1269 j = MSG_ReadLong (); 1270 CL_SetStat (i, j); 1271 break; 1272 1273 case svc_spawnstaticsound: 1274 CL_ParseStaticSound (); 1275 break; 1276 1277 case svc_cdtrack: 1278 cl.cdtrack = MSG_ReadByte (); 1279 CDAudio_Play ((byte)cl.cdtrack, true); 1280 break; 1281 1282 case svc_intermission: 1283 cl.intermission = 1; 1284 cl.completed_time = realtime; 1285 vid.recalc_refdef = true; // go to full screen 1286 for (i=0 ; i<3 ; i++) 1287 cl.simorg[i] = MSG_ReadCoord (); 1288 for (i=0 ; i<3 ; i++) 1289 cl.simangles[i] = MSG_ReadAngle (); 1290 VectorCopy (vec3_origin, cl.simvel); 1291 break; 1292 1293 case svc_finale: 1294 cl.intermission = 2; 1295 cl.completed_time = realtime; 1296 vid.recalc_refdef = true; // go to full screen 1297 SCR_CenterPrint (MSG_ReadString ()); 1298 break; 1299 1300 case svc_sellscreen: 1301 Cmd_ExecuteString ("help"); 1302 break; 1303 1304 case svc_smallkick: 1305 cl.punchangle = -2; 1306 break; 1307 case svc_bigkick: 1308 cl.punchangle = -4; 1309 break; 1310 1311 case svc_muzzleflash: 1312 CL_MuzzleFlash (); 1313 break; 1314 1315 case svc_updateuserinfo: 1316 CL_UpdateUserinfo (); 1317 break; 1318 1319 case svc_setinfo: 1320 CL_SetInfo (); 1321 break; 1322 1323 case svc_serverinfo: 1324 CL_ServerInfo (); 1325 break; 1326 1327 case svc_download: 1328 CL_ParseDownload (); 1329 break; 1330 1331 case svc_playerinfo: 1332 CL_ParsePlayerinfo (); 1333 break; 1334 1335 case svc_nails: 1336 CL_ParseProjectiles (); 1337 break; 1338 1339 case svc_chokecount: // some preceding packets were choked 1340 i = MSG_ReadByte (); 1341 for (j=0 ; j<i ; j++) 1342 cl.frames[ (cls.netchan.incoming_acknowledged-1-j)&UPDATE_MASK ].receivedtime = -2; 1343 break; 1344 1345 case svc_modellist: 1346 CL_ParseModellist (); 1347 break; 1348 1349 case svc_soundlist: 1350 CL_ParseSoundlist (); 1351 break; 1352 1353 case svc_packetentities: 1354 CL_ParsePacketEntities (false); 1355 break; 1356 1357 case svc_deltapacketentities: 1358 CL_ParsePacketEntities (true); 1359 break; 1360 1361 case svc_maxspeed : 1362 movevars.maxspeed = MSG_ReadFloat(); 1363 break; 1364 1365 case svc_entgravity : 1366 movevars.entgravity = MSG_ReadFloat(); 1367 break; 1368 1369 case svc_setpause: 1370 cl.paused = MSG_ReadByte (); 1371 if (cl.paused) 1372 CDAudio_Pause (); 1373 else 1374 CDAudio_Resume (); 1375 break; 1376 1377 } 1378 } 1379 1380 CL_SetSolidEntities (); 1381 } 1382 1383 1384