cl_parse.c (17021B)
1 /* 2 =========================================================================== 3 Copyright (C) 1999-2005 Id Software, Inc. 4 5 This file is part of Quake III Arena source code. 6 7 Quake III Arena source code is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the License, 10 or (at your option) any later version. 11 12 Quake III Arena source code is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 // cl_parse.c -- parse a message received from the server 23 24 #include "client.h" 25 26 char *svc_strings[256] = { 27 "svc_bad", 28 29 "svc_nop", 30 "svc_gamestate", 31 "svc_configstring", 32 "svc_baseline", 33 "svc_serverCommand", 34 "svc_download", 35 "svc_snapshot" 36 }; 37 38 void SHOWNET( msg_t *msg, char *s) { 39 if ( cl_shownet->integer >= 2) { 40 Com_Printf ("%3i:%s\n", msg->readcount-1, s); 41 } 42 } 43 44 45 /* 46 ========================================================================= 47 48 MESSAGE PARSING 49 50 ========================================================================= 51 */ 52 53 /* 54 ================== 55 CL_DeltaEntity 56 57 Parses deltas from the given base and adds the resulting entity 58 to the current frame 59 ================== 60 */ 61 void CL_DeltaEntity (msg_t *msg, clSnapshot_t *frame, int newnum, entityState_t *old, 62 qboolean unchanged) { 63 entityState_t *state; 64 65 // save the parsed entity state into the big circular buffer so 66 // it can be used as the source for a later delta 67 state = &cl.parseEntities[cl.parseEntitiesNum & (MAX_PARSE_ENTITIES-1)]; 68 69 if ( unchanged ) { 70 *state = *old; 71 } else { 72 MSG_ReadDeltaEntity( msg, old, state, newnum ); 73 } 74 75 if ( state->number == (MAX_GENTITIES-1) ) { 76 return; // entity was delta removed 77 } 78 cl.parseEntitiesNum++; 79 frame->numEntities++; 80 } 81 82 /* 83 ================== 84 CL_ParsePacketEntities 85 86 ================== 87 */ 88 void CL_ParsePacketEntities( msg_t *msg, clSnapshot_t *oldframe, clSnapshot_t *newframe) { 89 int newnum; 90 entityState_t *oldstate; 91 int oldindex, oldnum; 92 93 newframe->parseEntitiesNum = cl.parseEntitiesNum; 94 newframe->numEntities = 0; 95 96 // delta from the entities present in oldframe 97 oldindex = 0; 98 oldstate = NULL; 99 if (!oldframe) { 100 oldnum = 99999; 101 } else { 102 if ( oldindex >= oldframe->numEntities ) { 103 oldnum = 99999; 104 } else { 105 oldstate = &cl.parseEntities[ 106 (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)]; 107 oldnum = oldstate->number; 108 } 109 } 110 111 while ( 1 ) { 112 // read the entity index number 113 newnum = MSG_ReadBits( msg, GENTITYNUM_BITS ); 114 115 if ( newnum == (MAX_GENTITIES-1) ) { 116 break; 117 } 118 119 if ( msg->readcount > msg->cursize ) { 120 Com_Error (ERR_DROP,"CL_ParsePacketEntities: end of message"); 121 } 122 123 while ( oldnum < newnum ) { 124 // one or more entities from the old packet are unchanged 125 if ( cl_shownet->integer == 3 ) { 126 Com_Printf ("%3i: unchanged: %i\n", msg->readcount, oldnum); 127 } 128 CL_DeltaEntity( msg, newframe, oldnum, oldstate, qtrue ); 129 130 oldindex++; 131 132 if ( oldindex >= oldframe->numEntities ) { 133 oldnum = 99999; 134 } else { 135 oldstate = &cl.parseEntities[ 136 (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)]; 137 oldnum = oldstate->number; 138 } 139 } 140 if (oldnum == newnum) { 141 // delta from previous state 142 if ( cl_shownet->integer == 3 ) { 143 Com_Printf ("%3i: delta: %i\n", msg->readcount, newnum); 144 } 145 CL_DeltaEntity( msg, newframe, newnum, oldstate, qfalse ); 146 147 oldindex++; 148 149 if ( oldindex >= oldframe->numEntities ) { 150 oldnum = 99999; 151 } else { 152 oldstate = &cl.parseEntities[ 153 (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)]; 154 oldnum = oldstate->number; 155 } 156 continue; 157 } 158 159 if ( oldnum > newnum ) { 160 // delta from baseline 161 if ( cl_shownet->integer == 3 ) { 162 Com_Printf ("%3i: baseline: %i\n", msg->readcount, newnum); 163 } 164 CL_DeltaEntity( msg, newframe, newnum, &cl.entityBaselines[newnum], qfalse ); 165 continue; 166 } 167 168 } 169 170 // any remaining entities in the old frame are copied over 171 while ( oldnum != 99999 ) { 172 // one or more entities from the old packet are unchanged 173 if ( cl_shownet->integer == 3 ) { 174 Com_Printf ("%3i: unchanged: %i\n", msg->readcount, oldnum); 175 } 176 CL_DeltaEntity( msg, newframe, oldnum, oldstate, qtrue ); 177 178 oldindex++; 179 180 if ( oldindex >= oldframe->numEntities ) { 181 oldnum = 99999; 182 } else { 183 oldstate = &cl.parseEntities[ 184 (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)]; 185 oldnum = oldstate->number; 186 } 187 } 188 } 189 190 191 /* 192 ================ 193 CL_ParseSnapshot 194 195 If the snapshot is parsed properly, it will be copied to 196 cl.snap and saved in cl.snapshots[]. If the snapshot is invalid 197 for any reason, no changes to the state will be made at all. 198 ================ 199 */ 200 void CL_ParseSnapshot( msg_t *msg ) { 201 int len; 202 clSnapshot_t *old; 203 clSnapshot_t newSnap; 204 int deltaNum; 205 int oldMessageNum; 206 int i, packetNum; 207 208 // get the reliable sequence acknowledge number 209 // NOTE: now sent with all server to client messages 210 //clc.reliableAcknowledge = MSG_ReadLong( msg ); 211 212 // read in the new snapshot to a temporary buffer 213 // we will only copy to cl.snap if it is valid 214 Com_Memset (&newSnap, 0, sizeof(newSnap)); 215 216 // we will have read any new server commands in this 217 // message before we got to svc_snapshot 218 newSnap.serverCommandNum = clc.serverCommandSequence; 219 220 newSnap.serverTime = MSG_ReadLong( msg ); 221 222 newSnap.messageNum = clc.serverMessageSequence; 223 224 deltaNum = MSG_ReadByte( msg ); 225 if ( !deltaNum ) { 226 newSnap.deltaNum = -1; 227 } else { 228 newSnap.deltaNum = newSnap.messageNum - deltaNum; 229 } 230 newSnap.snapFlags = MSG_ReadByte( msg ); 231 232 // If the frame is delta compressed from data that we 233 // no longer have available, we must suck up the rest of 234 // the frame, but not use it, then ask for a non-compressed 235 // message 236 if ( newSnap.deltaNum <= 0 ) { 237 newSnap.valid = qtrue; // uncompressed frame 238 old = NULL; 239 clc.demowaiting = qfalse; // we can start recording now 240 } else { 241 old = &cl.snapshots[newSnap.deltaNum & PACKET_MASK]; 242 if ( !old->valid ) { 243 // should never happen 244 Com_Printf ("Delta from invalid frame (not supposed to happen!).\n"); 245 } else if ( old->messageNum != newSnap.deltaNum ) { 246 // The frame that the server did the delta from 247 // is too old, so we can't reconstruct it properly. 248 Com_Printf ("Delta frame too old.\n"); 249 } else if ( cl.parseEntitiesNum - old->parseEntitiesNum > MAX_PARSE_ENTITIES-128 ) { 250 Com_Printf ("Delta parseEntitiesNum too old.\n"); 251 } else { 252 newSnap.valid = qtrue; // valid delta parse 253 } 254 } 255 256 // read areamask 257 len = MSG_ReadByte( msg ); 258 MSG_ReadData( msg, &newSnap.areamask, len); 259 260 // read playerinfo 261 SHOWNET( msg, "playerstate" ); 262 if ( old ) { 263 MSG_ReadDeltaPlayerstate( msg, &old->ps, &newSnap.ps ); 264 } else { 265 MSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.ps ); 266 } 267 268 // read packet entities 269 SHOWNET( msg, "packet entities" ); 270 CL_ParsePacketEntities( msg, old, &newSnap ); 271 272 // if not valid, dump the entire thing now that it has 273 // been properly read 274 if ( !newSnap.valid ) { 275 return; 276 } 277 278 // clear the valid flags of any snapshots between the last 279 // received and this one, so if there was a dropped packet 280 // it won't look like something valid to delta from next 281 // time we wrap around in the buffer 282 oldMessageNum = cl.snap.messageNum + 1; 283 284 if ( newSnap.messageNum - oldMessageNum >= PACKET_BACKUP ) { 285 oldMessageNum = newSnap.messageNum - ( PACKET_BACKUP - 1 ); 286 } 287 for ( ; oldMessageNum < newSnap.messageNum ; oldMessageNum++ ) { 288 cl.snapshots[oldMessageNum & PACKET_MASK].valid = qfalse; 289 } 290 291 // copy to the current good spot 292 cl.snap = newSnap; 293 cl.snap.ping = 999; 294 // calculate ping time 295 for ( i = 0 ; i < PACKET_BACKUP ; i++ ) { 296 packetNum = ( clc.netchan.outgoingSequence - 1 - i ) & PACKET_MASK; 297 if ( cl.snap.ps.commandTime >= cl.outPackets[ packetNum ].p_serverTime ) { 298 cl.snap.ping = cls.realtime - cl.outPackets[ packetNum ].p_realtime; 299 break; 300 } 301 } 302 // save the frame off in the backup array for later delta comparisons 303 cl.snapshots[cl.snap.messageNum & PACKET_MASK] = cl.snap; 304 305 if (cl_shownet->integer == 3) { 306 Com_Printf( " snapshot:%i delta:%i ping:%i\n", cl.snap.messageNum, 307 cl.snap.deltaNum, cl.snap.ping ); 308 } 309 310 cl.newSnapshots = qtrue; 311 } 312 313 314 //===================================================================== 315 316 int cl_connectedToPureServer; 317 318 /* 319 ================== 320 CL_SystemInfoChanged 321 322 The systeminfo configstring has been changed, so parse 323 new information out of it. This will happen at every 324 gamestate, and possibly during gameplay. 325 ================== 326 */ 327 void CL_SystemInfoChanged( void ) { 328 char *systemInfo; 329 const char *s, *t; 330 char key[BIG_INFO_KEY]; 331 char value[BIG_INFO_VALUE]; 332 qboolean gameSet; 333 334 systemInfo = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SYSTEMINFO ]; 335 // NOTE TTimo: 336 // when the serverId changes, any further messages we send to the server will use this new serverId 337 // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=475 338 // in some cases, outdated cp commands might get sent with this news serverId 339 cl.serverId = atoi( Info_ValueForKey( systemInfo, "sv_serverid" ) ); 340 341 // don't set any vars when playing a demo 342 if ( clc.demoplaying ) { 343 return; 344 } 345 346 s = Info_ValueForKey( systemInfo, "sv_cheats" ); 347 if ( atoi(s) == 0 ) { 348 Cvar_SetCheatState(); 349 } 350 351 // check pure server string 352 s = Info_ValueForKey( systemInfo, "sv_paks" ); 353 t = Info_ValueForKey( systemInfo, "sv_pakNames" ); 354 FS_PureServerSetLoadedPaks( s, t ); 355 356 s = Info_ValueForKey( systemInfo, "sv_referencedPaks" ); 357 t = Info_ValueForKey( systemInfo, "sv_referencedPakNames" ); 358 FS_PureServerSetReferencedPaks( s, t ); 359 360 gameSet = qfalse; 361 // scan through all the variables in the systeminfo and locally set cvars to match 362 s = systemInfo; 363 while ( s ) { 364 Info_NextPair( &s, key, value ); 365 if ( !key[0] ) { 366 break; 367 } 368 // ehw! 369 if ( !Q_stricmp( key, "fs_game" ) ) { 370 gameSet = qtrue; 371 } 372 373 Cvar_Set( key, value ); 374 } 375 // if game folder should not be set and it is set at the client side 376 if ( !gameSet && *Cvar_VariableString("fs_game") ) { 377 Cvar_Set( "fs_game", "" ); 378 } 379 cl_connectedToPureServer = Cvar_VariableValue( "sv_pure" ); 380 } 381 382 /* 383 ================== 384 CL_ParseGamestate 385 ================== 386 */ 387 void CL_ParseGamestate( msg_t *msg ) { 388 int i; 389 entityState_t *es; 390 int newnum; 391 entityState_t nullstate; 392 int cmd; 393 char *s; 394 395 Con_Close(); 396 397 clc.connectPacketCount = 0; 398 399 // wipe local client state 400 CL_ClearState(); 401 402 // a gamestate always marks a server command sequence 403 clc.serverCommandSequence = MSG_ReadLong( msg ); 404 405 // parse all the configstrings and baselines 406 cl.gameState.dataCount = 1; // leave a 0 at the beginning for uninitialized configstrings 407 while ( 1 ) { 408 cmd = MSG_ReadByte( msg ); 409 410 if ( cmd == svc_EOF ) { 411 break; 412 } 413 414 if ( cmd == svc_configstring ) { 415 int len; 416 417 i = MSG_ReadShort( msg ); 418 if ( i < 0 || i >= MAX_CONFIGSTRINGS ) { 419 Com_Error( ERR_DROP, "configstring > MAX_CONFIGSTRINGS" ); 420 } 421 s = MSG_ReadBigString( msg ); 422 len = strlen( s ); 423 424 if ( len + 1 + cl.gameState.dataCount > MAX_GAMESTATE_CHARS ) { 425 Com_Error( ERR_DROP, "MAX_GAMESTATE_CHARS exceeded" ); 426 } 427 428 // append it to the gameState string buffer 429 cl.gameState.stringOffsets[ i ] = cl.gameState.dataCount; 430 Com_Memcpy( cl.gameState.stringData + cl.gameState.dataCount, s, len + 1 ); 431 cl.gameState.dataCount += len + 1; 432 } else if ( cmd == svc_baseline ) { 433 newnum = MSG_ReadBits( msg, GENTITYNUM_BITS ); 434 if ( newnum < 0 || newnum >= MAX_GENTITIES ) { 435 Com_Error( ERR_DROP, "Baseline number out of range: %i", newnum ); 436 } 437 Com_Memset (&nullstate, 0, sizeof(nullstate)); 438 es = &cl.entityBaselines[ newnum ]; 439 MSG_ReadDeltaEntity( msg, &nullstate, es, newnum ); 440 } else { 441 Com_Error( ERR_DROP, "CL_ParseGamestate: bad command byte" ); 442 } 443 } 444 445 clc.clientNum = MSG_ReadLong(msg); 446 // read the checksum feed 447 clc.checksumFeed = MSG_ReadLong( msg ); 448 449 // parse serverId and other cvars 450 CL_SystemInfoChanged(); 451 452 // reinitialize the filesystem if the game directory has changed 453 FS_ConditionalRestart( clc.checksumFeed ); 454 455 // This used to call CL_StartHunkUsers, but now we enter the download state before loading the 456 // cgame 457 CL_InitDownloads(); 458 459 // make sure the game starts 460 Cvar_Set( "cl_paused", "0" ); 461 } 462 463 464 //===================================================================== 465 466 /* 467 ===================== 468 CL_ParseDownload 469 470 A download message has been received from the server 471 ===================== 472 */ 473 void CL_ParseDownload ( msg_t *msg ) { 474 int size; 475 unsigned char data[MAX_MSGLEN]; 476 int block; 477 478 // read the data 479 block = MSG_ReadShort ( msg ); 480 481 if ( !block ) 482 { 483 // block zero is special, contains file size 484 clc.downloadSize = MSG_ReadLong ( msg ); 485 486 Cvar_SetValue( "cl_downloadSize", clc.downloadSize ); 487 488 if (clc.downloadSize < 0) 489 { 490 Com_Error(ERR_DROP, MSG_ReadString( msg ) ); 491 return; 492 } 493 } 494 495 size = MSG_ReadShort ( msg ); 496 if (size > 0) 497 MSG_ReadData( msg, data, size ); 498 499 if (clc.downloadBlock != block) { 500 Com_DPrintf( "CL_ParseDownload: Expected block %d, got %d\n", clc.downloadBlock, block); 501 return; 502 } 503 504 // open the file if not opened yet 505 if (!clc.download) 506 { 507 if (!*clc.downloadTempName) { 508 Com_Printf("Server sending download, but no download was requested\n"); 509 CL_AddReliableCommand( "stopdl" ); 510 return; 511 } 512 513 clc.download = FS_SV_FOpenFileWrite( clc.downloadTempName ); 514 515 if (!clc.download) { 516 Com_Printf( "Could not create %s\n", clc.downloadTempName ); 517 CL_AddReliableCommand( "stopdl" ); 518 CL_NextDownload(); 519 return; 520 } 521 } 522 523 if (size) 524 FS_Write( data, size, clc.download ); 525 526 CL_AddReliableCommand( va("nextdl %d", clc.downloadBlock) ); 527 clc.downloadBlock++; 528 529 clc.downloadCount += size; 530 531 // So UI gets access to it 532 Cvar_SetValue( "cl_downloadCount", clc.downloadCount ); 533 534 if (!size) { // A zero length block means EOF 535 if (clc.download) { 536 FS_FCloseFile( clc.download ); 537 clc.download = 0; 538 539 // rename the file 540 FS_SV_Rename ( clc.downloadTempName, clc.downloadName ); 541 } 542 *clc.downloadTempName = *clc.downloadName = 0; 543 Cvar_Set( "cl_downloadName", "" ); 544 545 // send intentions now 546 // We need this because without it, we would hold the last nextdl and then start 547 // loading right away. If we take a while to load, the server is happily trying 548 // to send us that last block over and over. 549 // Write it twice to help make sure we acknowledge the download 550 CL_WritePacket(); 551 CL_WritePacket(); 552 553 // get another file if needed 554 CL_NextDownload (); 555 } 556 } 557 558 /* 559 ===================== 560 CL_ParseCommandString 561 562 Command strings are just saved off until cgame asks for them 563 when it transitions a snapshot 564 ===================== 565 */ 566 void CL_ParseCommandString( msg_t *msg ) { 567 char *s; 568 int seq; 569 int index; 570 571 seq = MSG_ReadLong( msg ); 572 s = MSG_ReadString( msg ); 573 574 // see if we have already executed stored it off 575 if ( clc.serverCommandSequence >= seq ) { 576 return; 577 } 578 clc.serverCommandSequence = seq; 579 580 index = seq & (MAX_RELIABLE_COMMANDS-1); 581 Q_strncpyz( clc.serverCommands[ index ], s, sizeof( clc.serverCommands[ index ] ) ); 582 } 583 584 585 /* 586 ===================== 587 CL_ParseServerMessage 588 ===================== 589 */ 590 void CL_ParseServerMessage( msg_t *msg ) { 591 int cmd; 592 593 if ( cl_shownet->integer == 1 ) { 594 Com_Printf ("%i ",msg->cursize); 595 } else if ( cl_shownet->integer >= 2 ) { 596 Com_Printf ("------------------\n"); 597 } 598 599 MSG_Bitstream(msg); 600 601 // get the reliable sequence acknowledge number 602 clc.reliableAcknowledge = MSG_ReadLong( msg ); 603 // 604 if ( clc.reliableAcknowledge < clc.reliableSequence - MAX_RELIABLE_COMMANDS ) { 605 clc.reliableAcknowledge = clc.reliableSequence; 606 } 607 608 // 609 // parse the message 610 // 611 while ( 1 ) { 612 if ( msg->readcount > msg->cursize ) { 613 Com_Error (ERR_DROP,"CL_ParseServerMessage: read past end of server message"); 614 break; 615 } 616 617 cmd = MSG_ReadByte( msg ); 618 619 if ( cmd == svc_EOF) { 620 SHOWNET( msg, "END OF MESSAGE" ); 621 break; 622 } 623 624 if ( cl_shownet->integer >= 2 ) { 625 if ( !svc_strings[cmd] ) { 626 Com_Printf( "%3i:BAD CMD %i\n", msg->readcount-1, cmd ); 627 } else { 628 SHOWNET( msg, svc_strings[cmd] ); 629 } 630 } 631 632 // other commands 633 switch ( cmd ) { 634 default: 635 Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n"); 636 break; 637 case svc_nop: 638 break; 639 case svc_serverCommand: 640 CL_ParseCommandString( msg ); 641 break; 642 case svc_gamestate: 643 CL_ParseGamestate( msg ); 644 break; 645 case svc_snapshot: 646 CL_ParseSnapshot( msg ); 647 break; 648 case svc_download: 649 CL_ParseDownload( msg ); 650 break; 651 } 652 } 653 } 654 655