SaveGame.cpp (35167B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. 25 26 =========================================================================== 27 */ 28 29 #pragma hdrstop 30 #include "../../idlib/precompiled.h" 31 32 33 #include "../Game_local.h" 34 35 #include "TypeInfo.h" 36 37 /* 38 Save game related helper classes. 39 40 Save games are implemented in two classes, idSaveGame and idRestoreGame, that implement write/read functions for 41 common types. They're passed in to each entity and object for them to archive themselves. Each class 42 implements save/restore functions for it's own data. When restoring, all the objects are instantiated, 43 then the restore function is called on each, superclass first, then subclasses. 44 45 Pointers are restored by saving out an object index for each unique object pointer and adding them to a list of 46 objects that are to be saved. Restore instantiates all the objects in the list before calling the Restore function 47 on each object so that the pointers returned are valid. No object's restore function should rely on any other objects 48 being fully instantiated until after the restore process is complete. Post restore fixup should be done by posting 49 events with 0 delay. 50 51 The savegame header will have the Game Name, Version, Map Name, and Player Persistent Info. 52 53 Changes in version make savegames incompatible, and the game will start from the beginning of the level with 54 the player's persistent info. 55 56 Changes to classes that don't need to break compatibilty can use the build number as the savegame version. 57 Later versions are responsible for restoring from previous versions by ignoring any unused data and initializing 58 variables that weren't in previous versions with safe information. 59 60 At the head of the save game is enough information to restore the player to the beginning of the level should the 61 file be unloadable in some way (for example, due to script changes). 62 */ 63 64 /* 65 ================ 66 idSaveGame::idSaveGame() 67 ================ 68 */ 69 idSaveGame::idSaveGame( idFile *savefile, idFile *stringTableFile, int saveVersion ) { 70 //compressor = idCompressor::AllocLZW(); 71 //compressor->Init( savefile, true, 8 ); 72 //file = compressor; 73 file = savefile; 74 stringFile = stringTableFile; 75 version = saveVersion; 76 77 // Put NULL at the start of the list so we can skip over it. 78 objects.Clear(); 79 objects.Append( NULL ); 80 81 curStringTableOffset = 0; 82 } 83 84 /* 85 ================ 86 idSaveGame::~idSaveGame() 87 ================ 88 */ 89 idSaveGame::~idSaveGame() { 90 //compressor->FinishCompress(); 91 //delete compressor; 92 93 if ( objects.Num() ) { 94 Close(); 95 } 96 } 97 98 /* 99 ================ 100 idSaveGame::Close 101 ================ 102 */ 103 void idSaveGame::Close() { 104 WriteSoundCommands(); 105 106 // read trace models 107 idClipModel::SaveTraceModels( this ); 108 109 for( int i = 1; i < objects.Num(); i++ ) { 110 CallSave_r( objects[ i ]->GetType(), objects[ i ] ); 111 } 112 113 objects.Clear(); 114 115 // Save out the string table at the end of the file 116 for ( int i = 0; i < stringTable.Num(); ++i ) { 117 stringFile->WriteString( stringTable[i].string ); 118 } 119 120 stringHash.Free(); 121 stringTable.Clear(); 122 123 if ( file->Length() > MIN_SAVEGAME_SIZE_BYTES || stringFile->Length() > MAX_SAVEGAME_STRING_TABLE_SIZE ) { 124 idLib::FatalError( "OVERFLOWED SAVE GAME FILE BUFFER" ); 125 } 126 127 #ifdef ID_DEBUG_MEMORY 128 idStr gameState = file->GetName(); 129 gameState.StripFileExtension(); 130 WriteGameState_f( idCmdArgs( va( "test %s_save", gameState.c_str() ), false ) ); 131 #endif 132 } 133 134 /* 135 ================ 136 idSaveGame::WriteDecls 137 ================ 138 */ 139 void idSaveGame::WriteDecls() { 140 // Write out all loaded decls 141 for ( int t = 0; t < declManager->GetNumDeclTypes(); t++ ) { 142 for ( int d = 0; d < declManager->GetNumDecls( (declType_t)t ); d++ ) { 143 const idDecl * decl = declManager->DeclByIndex( (declType_t)t, d, false ); 144 if ( decl == NULL || decl->GetState() == DS_UNPARSED ) { 145 continue; 146 } 147 const char * declName = decl->GetName(); 148 if ( declName[0] == 0 ) { 149 continue; 150 } 151 WriteString( declName ); 152 } 153 WriteString( 0 ); 154 } 155 } 156 157 /* 158 ================ 159 idSaveGame::WriteObjectList 160 ================ 161 */ 162 void idSaveGame::WriteObjectList() { 163 WriteInt( objects.Num() - 1 ); 164 for ( int i = 1; i < objects.Num(); i++ ) { 165 WriteString( objects[ i ]->GetClassname() ); 166 } 167 } 168 169 /* 170 ================ 171 idSaveGame::CallSave_r 172 ================ 173 */ 174 void idSaveGame::CallSave_r( const idTypeInfo *cls, const idClass *obj ) { 175 if ( cls->super ) { 176 CallSave_r( cls->super, obj ); 177 if ( cls->super->Save == cls->Save ) { 178 // don't call save on this inheritance level since the function was called in the super class 179 return; 180 } 181 } 182 183 ( obj->*cls->Save )( this ); 184 } 185 186 /* 187 ================ 188 idSaveGame::AddObject 189 ================ 190 */ 191 void idSaveGame::AddObject( const idClass *obj ) { 192 objects.AddUnique( obj ); 193 } 194 195 /* 196 ================ 197 idSaveGame::Write 198 ================ 199 */ 200 void idSaveGame::Write( const void *buffer, int len ) { 201 file->Write( buffer, len ); 202 } 203 204 /* 205 ================ 206 idSaveGame::WriteInt 207 ================ 208 */ 209 void idSaveGame::WriteInt( const int value ) { 210 file->WriteBig( value ); 211 } 212 213 /* 214 ================ 215 idSaveGame::WriteJoint 216 ================ 217 */ 218 void idSaveGame::WriteJoint( const jointHandle_t value ) { 219 file->WriteBig( (int&)value ); 220 } 221 222 /* 223 ================ 224 idSaveGame::WriteShort 225 ================ 226 */ 227 void idSaveGame::WriteShort( const short value ) { 228 file->WriteBig( value ); 229 } 230 231 /* 232 ================ 233 idSaveGame::WriteByte 234 ================ 235 */ 236 void idSaveGame::WriteByte( const byte value ) { 237 file->Write( &value, sizeof( value ) ); 238 } 239 240 /* 241 ================ 242 idSaveGame::WriteSignedChar 243 ================ 244 */ 245 void idSaveGame::WriteSignedChar( const signed char value ) { 246 file->Write( &value, sizeof( value ) ); 247 } 248 249 /* 250 ================ 251 idSaveGame::WriteFloat 252 ================ 253 */ 254 void idSaveGame::WriteFloat( const float value ) { 255 file->WriteBig( value ); 256 } 257 258 /* 259 ================ 260 idSaveGame::WriteBool 261 ================ 262 */ 263 void idSaveGame::WriteBool( const bool value ) { 264 file->WriteBool( value ); 265 } 266 267 /* 268 ================ 269 idSaveGame::WriteString 270 ================ 271 */ 272 void idSaveGame::WriteString( const char *string ) { 273 if ( string == NULL || *string == 0 ) { 274 WriteInt( -1 ); 275 return; 276 } 277 278 // If we already have this string in our hash, write out of the offset in the table and return 279 int hash = stringHash.GenerateKey( string ); 280 for ( int i = stringHash.First( hash); i != -1; i = stringHash.Next( i ) ) { 281 if ( stringTable[i].string.Cmp( string ) == 0 ) { 282 WriteInt( stringTable[i].offset ); 283 return; 284 } 285 } 286 287 // Add the string to our hash, generate the index, and update our current table offset 288 stringTableIndex_s & tableIndex = stringTable.Alloc(); 289 tableIndex.offset = curStringTableOffset; 290 tableIndex.string = string; 291 stringHash.Add( hash, stringTable.Num() - 1 ); 292 293 WriteInt( curStringTableOffset ); 294 curStringTableOffset += ( strlen( string ) + 4 ); 295 } 296 297 /* 298 ================ 299 idSaveGame::WriteVec2 300 ================ 301 */ 302 void idSaveGame::WriteVec2( const idVec2 &vec ) { 303 file->WriteBig( vec ); 304 } 305 306 /* 307 ================ 308 idSaveGame::WriteVec3 309 ================ 310 */ 311 void idSaveGame::WriteVec3( const idVec3 &vec ) { 312 file->WriteBig( vec ); 313 } 314 315 /* 316 ================ 317 idSaveGame::WriteVec4 318 ================ 319 */ 320 void idSaveGame::WriteVec4( const idVec4 &vec ) { 321 file->WriteBig( vec ); 322 } 323 324 /* 325 ================ 326 idSaveGame::WriteVec6 327 ================ 328 */ 329 void idSaveGame::WriteVec6( const idVec6 &vec ) { 330 file->WriteBig( vec ); 331 } 332 333 /* 334 ================ 335 idSaveGame::WriteBounds 336 ================ 337 */ 338 void idSaveGame::WriteBounds( const idBounds &bounds ) { 339 file->WriteBig( bounds ); 340 } 341 342 /* 343 ================ 344 idSaveGame::WriteBounds 345 ================ 346 */ 347 void idSaveGame::WriteWinding( const idWinding &w ) 348 { 349 int i, num; 350 num = w.GetNumPoints(); 351 file->WriteBig( num ); 352 for ( i = 0; i < num; i++ ) { 353 idVec5 v = w[i]; 354 file->WriteBig( v ); 355 } 356 } 357 358 359 /* 360 ================ 361 idSaveGame::WriteMat3 362 ================ 363 */ 364 void idSaveGame::WriteMat3( const idMat3 &mat ) { 365 file->WriteBig( mat ); 366 } 367 368 /* 369 ================ 370 idSaveGame::WriteAngles 371 ================ 372 */ 373 void idSaveGame::WriteAngles( const idAngles &angles ) { 374 file->WriteBig( angles ); 375 } 376 377 /* 378 ================ 379 idSaveGame::WriteObject 380 ================ 381 */ 382 void idSaveGame::WriteObject( const idClass *obj ) { 383 int index; 384 385 index = objects.FindIndex( obj ); 386 if ( index < 0 ) { 387 gameLocal.DPrintf( "idSaveGame::WriteObject - WriteObject FindIndex failed\n" ); 388 389 // Use the NULL index 390 index = 0; 391 } 392 393 WriteInt( index ); 394 } 395 396 /* 397 ================ 398 idSaveGame::WriteStaticObject 399 ================ 400 */ 401 void idSaveGame::WriteStaticObject( const idClass &obj ) { 402 CallSave_r( obj.GetType(), &obj ); 403 } 404 405 /* 406 ================ 407 idSaveGame::WriteDict 408 ================ 409 */ 410 void idSaveGame::WriteDict( const idDict *dict ) { 411 int num; 412 int i; 413 const idKeyValue *kv; 414 415 if ( !dict ) { 416 WriteInt( -1 ); 417 } else { 418 num = dict->GetNumKeyVals(); 419 WriteInt( num ); 420 for( i = 0; i < num; i++ ) { 421 kv = dict->GetKeyVal( i ); 422 WriteString( kv->GetKey() ); 423 WriteString( kv->GetValue() ); 424 } 425 } 426 } 427 428 /* 429 ================ 430 idSaveGame::WriteMaterial 431 ================ 432 */ 433 void idSaveGame::WriteMaterial( const idMaterial *material ) { 434 if ( !material ) { 435 WriteString( "" ); 436 } else { 437 WriteString( material->GetName() ); 438 } 439 } 440 441 /* 442 ================ 443 idSaveGame::WriteSkin 444 ================ 445 */ 446 void idSaveGame::WriteSkin( const idDeclSkin *skin ) { 447 if ( !skin ) { 448 WriteString( "" ); 449 } else { 450 WriteString( skin->GetName() ); 451 } 452 } 453 454 /* 455 ================ 456 idSaveGame::WriteParticle 457 ================ 458 */ 459 void idSaveGame::WriteParticle( const idDeclParticle *particle ) { 460 if ( !particle ) { 461 WriteString( "" ); 462 } else { 463 WriteString( particle->GetName() ); 464 } 465 } 466 467 /* 468 ================ 469 idSaveGame::WriteFX 470 ================ 471 */ 472 void idSaveGame::WriteFX( const idDeclFX *fx ) { 473 if ( !fx ) { 474 WriteString( "" ); 475 } else { 476 WriteString( fx->GetName() ); 477 } 478 } 479 480 /* 481 ================ 482 idSaveGame::WriteModelDef 483 ================ 484 */ 485 void idSaveGame::WriteModelDef( const idDeclModelDef *modelDef ) { 486 if ( !modelDef ) { 487 WriteString( "" ); 488 } else { 489 WriteString( modelDef->GetName() ); 490 } 491 } 492 493 /* 494 ================ 495 idSaveGame::WriteSoundShader 496 ================ 497 */ 498 void idSaveGame::WriteSoundShader( const idSoundShader *shader ) { 499 const char *name; 500 501 if ( !shader ) { 502 WriteString( "" ); 503 } else { 504 name = shader->GetName(); 505 WriteString( name ); 506 } 507 } 508 509 /* 510 ================ 511 idSaveGame::WriteModel 512 ================ 513 */ 514 void idSaveGame::WriteModel( const idRenderModel *model ) { 515 const char *name; 516 517 if ( !model ) { 518 WriteString( "" ); 519 } else { 520 name = model->Name(); 521 WriteString( name ); 522 } 523 } 524 525 /* 526 ================ 527 idSaveGame::WriteUserInterface 528 ================ 529 */ 530 void idSaveGame::WriteUserInterface( const idUserInterface *ui, bool unique ) { 531 const char *name; 532 533 if ( !ui ) { 534 WriteString( "" ); 535 } else { 536 name = ui->Name(); 537 WriteString( name ); 538 WriteBool( unique ); 539 if ( ui->WriteToSaveGame( file ) == false ) { 540 gameLocal.Error( "idSaveGame::WriteUserInterface: ui failed to write properly\n" ); 541 } 542 } 543 } 544 545 /* 546 ================ 547 idSaveGame::WriteRenderEntity 548 ================ 549 */ 550 void idSaveGame::WriteRenderEntity( const renderEntity_t &renderEntity ) { 551 int i; 552 553 WriteModel( renderEntity.hModel ); 554 555 WriteInt( renderEntity.entityNum ); 556 WriteInt( renderEntity.bodyId ); 557 558 WriteBounds( renderEntity.bounds ); 559 560 // callback is set by class's Restore function 561 562 WriteInt( renderEntity.suppressSurfaceInViewID ); 563 WriteInt( renderEntity.suppressShadowInViewID ); 564 WriteInt( renderEntity.suppressShadowInLightID ); 565 WriteInt( renderEntity.allowSurfaceInViewID ); 566 567 WriteVec3( renderEntity.origin ); 568 WriteMat3( renderEntity.axis ); 569 570 WriteMaterial( renderEntity.customShader ); 571 WriteMaterial( renderEntity.referenceShader ); 572 WriteSkin( renderEntity.customSkin ); 573 574 if ( renderEntity.referenceSound != NULL ) { 575 WriteInt( renderEntity.referenceSound->Index() ); 576 } else { 577 WriteInt( 0 ); 578 } 579 580 for( i = 0; i < MAX_ENTITY_SHADER_PARMS; i++ ) { 581 WriteFloat( renderEntity.shaderParms[ i ] ); 582 } 583 584 for( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) { 585 WriteUserInterface( renderEntity.gui[ i ], renderEntity.gui[ i ] ? renderEntity.gui[ i ]->IsUniqued() : false ); 586 } 587 588 WriteFloat( renderEntity.modelDepthHack ); 589 590 WriteBool( renderEntity.noSelfShadow ); 591 WriteBool( renderEntity.noShadow ); 592 WriteBool( renderEntity.noDynamicInteractions ); 593 WriteBool( renderEntity.weaponDepthHack ); 594 595 WriteInt( renderEntity.forceUpdate ); 596 597 WriteInt( renderEntity.timeGroup ); 598 WriteInt( renderEntity.xrayIndex ); 599 } 600 601 /* 602 ================ 603 idSaveGame::WriteRenderLight 604 ================ 605 */ 606 void idSaveGame::WriteRenderLight( const renderLight_t &renderLight ) { 607 int i; 608 609 WriteMat3( renderLight.axis ); 610 WriteVec3( renderLight.origin ); 611 612 WriteInt( renderLight.suppressLightInViewID ); 613 WriteInt( renderLight.allowLightInViewID ); 614 WriteBool( renderLight.noShadows ); 615 WriteBool( renderLight.noSpecular ); 616 WriteBool( renderLight.pointLight ); 617 WriteBool( renderLight.parallel ); 618 619 WriteVec3( renderLight.lightRadius ); 620 WriteVec3( renderLight.lightCenter ); 621 622 WriteVec3( renderLight.target ); 623 WriteVec3( renderLight.right ); 624 WriteVec3( renderLight.up ); 625 WriteVec3( renderLight.start ); 626 WriteVec3( renderLight.end ); 627 628 // only idLight has a prelightModel and it's always based on the entityname, so we'll restore it there 629 // WriteModel( renderLight.prelightModel ); 630 631 WriteInt( renderLight.lightId ); 632 633 WriteMaterial( renderLight.shader ); 634 635 for( i = 0; i < MAX_ENTITY_SHADER_PARMS; i++ ) { 636 WriteFloat( renderLight.shaderParms[ i ] ); 637 } 638 639 if ( renderLight.referenceSound != NULL ) { 640 WriteInt( renderLight.referenceSound->Index() ); 641 } else { 642 WriteInt( 0 ); 643 } 644 } 645 646 /* 647 ================ 648 idSaveGame::WriteRefSound 649 ================ 650 */ 651 void idSaveGame::WriteRefSound( const refSound_t &refSound ) { 652 if ( refSound.referenceSound ) { 653 WriteInt( refSound.referenceSound->Index() ); 654 } else { 655 WriteInt( 0 ); 656 } 657 WriteVec3( refSound.origin ); 658 WriteInt( refSound.listenerId ); 659 WriteSoundShader( refSound.shader ); 660 WriteFloat( refSound.diversity ); 661 WriteBool( refSound.waitfortrigger ); 662 663 WriteFloat( refSound.parms.minDistance ); 664 WriteFloat( refSound.parms.maxDistance ); 665 WriteFloat( refSound.parms.volume ); 666 WriteFloat( refSound.parms.shakes ); 667 WriteInt( refSound.parms.soundShaderFlags ); 668 WriteInt( refSound.parms.soundClass ); 669 } 670 671 /* 672 ================ 673 idSaveGame::WriteRenderView 674 ================ 675 */ 676 void idSaveGame::WriteRenderView( const renderView_t &view ) { 677 int i; 678 679 WriteInt( view.viewID ); 680 WriteInt( 0 /* view.x */ ); 681 WriteInt( 0 /* view.y */ ); 682 WriteInt( 0 /* view.width */ ); 683 WriteInt( 0 /* view.height */ ); 684 685 WriteFloat( view.fov_x ); 686 WriteFloat( view.fov_y ); 687 WriteVec3( view.vieworg ); 688 WriteMat3( view.viewaxis ); 689 690 WriteBool( view.cramZNear ); 691 692 WriteInt( view.time[0] ); 693 694 for( i = 0; i < MAX_GLOBAL_SHADER_PARMS; i++ ) { 695 WriteFloat( view.shaderParms[ i ] ); 696 } 697 } 698 699 /* 700 =================== 701 idSaveGame::WriteUsercmd 702 =================== 703 */ 704 void idSaveGame::WriteUsercmd( const usercmd_t &usercmd ) { 705 WriteByte( usercmd.buttons ); 706 WriteSignedChar( usercmd.forwardmove ); 707 WriteSignedChar( usercmd.rightmove ); 708 WriteShort( usercmd.angles[0] ); 709 WriteShort( usercmd.angles[1] ); 710 WriteShort( usercmd.angles[2] ); 711 WriteShort( usercmd.mx ); 712 WriteShort( usercmd.my ); 713 WriteByte( usercmd.impulse ); 714 WriteByte( usercmd.impulseSequence ); 715 } 716 717 /* 718 =================== 719 idSaveGame::WriteContactInfo 720 =================== 721 */ 722 void idSaveGame::WriteContactInfo( const contactInfo_t &contactInfo ) { 723 WriteInt( (int)contactInfo.type ); 724 WriteVec3( contactInfo.point ); 725 WriteVec3( contactInfo.normal ); 726 WriteFloat( contactInfo.dist ); 727 WriteInt( contactInfo.contents ); 728 WriteMaterial( contactInfo.material ); 729 WriteInt( contactInfo.modelFeature ); 730 WriteInt( contactInfo.trmFeature ); 731 WriteInt( contactInfo.entityNum ); 732 WriteInt( contactInfo.id ); 733 } 734 735 /* 736 =================== 737 idSaveGame::WriteTrace 738 =================== 739 */ 740 void idSaveGame::WriteTrace( const trace_t &trace ) { 741 WriteFloat( trace.fraction ); 742 WriteVec3( trace.endpos ); 743 WriteMat3( trace.endAxis ); 744 WriteContactInfo( trace.c ); 745 } 746 747 /* 748 =================== 749 idRestoreGame::WriteTraceModel 750 =================== 751 */ 752 void idSaveGame::WriteTraceModel( const idTraceModel &trace ) { 753 int j, k; 754 755 WriteInt( (int&)trace.type ); 756 WriteInt( trace.numVerts ); 757 for ( j = 0; j < MAX_TRACEMODEL_VERTS; j++ ) { 758 WriteVec3( trace.verts[j] ); 759 } 760 WriteInt( trace.numEdges ); 761 for ( j = 0; j < (MAX_TRACEMODEL_EDGES+1); j++ ) { 762 WriteInt( trace.edges[j].v[0] ); 763 WriteInt( trace.edges[j].v[1] ); 764 WriteVec3( trace.edges[j].normal ); 765 } 766 WriteInt( trace.numPolys ); 767 for ( j = 0; j < MAX_TRACEMODEL_POLYS; j++ ) { 768 WriteVec3( trace.polys[j].normal ); 769 WriteFloat( trace.polys[j].dist ); 770 WriteBounds( trace.polys[j].bounds ); 771 WriteInt( trace.polys[j].numEdges ); 772 for ( k = 0; k < MAX_TRACEMODEL_POLYEDGES; k++ ) { 773 WriteInt( trace.polys[j].edges[k] ); 774 } 775 } 776 WriteVec3( trace.offset ); 777 WriteBounds( trace.bounds ); 778 WriteBool( trace.isConvex ); 779 // padding win32 native structs 780 char tmp[3]; 781 memset( tmp, 0, sizeof( tmp ) ); 782 file->Write( tmp, 3 ); 783 } 784 785 /* 786 =================== 787 idSaveGame::WriteClipModel 788 =================== 789 */ 790 void idSaveGame::WriteClipModel( const idClipModel *clipModel ) { 791 if ( clipModel != NULL ) { 792 WriteBool( true ); 793 clipModel->Save( this ); 794 } else { 795 WriteBool( false ); 796 } 797 } 798 799 /* 800 =================== 801 idSaveGame::WriteSoundCommands 802 =================== 803 */ 804 void idSaveGame::WriteSoundCommands() { 805 gameSoundWorld->WriteToSaveGame( file ); 806 } 807 808 /* 809 ====================== 810 idSaveGame::WriteBuildNumber 811 ====================== 812 */ 813 void idSaveGame::WriteBuildNumber( const int value ) { 814 WriteInt( BUILD_NUMBER ); 815 } 816 817 /*********************************************************************** 818 819 idRestoreGame 820 821 ***********************************************************************/ 822 823 /* 824 ================ 825 idRestoreGame::RestoreGame 826 ================ 827 */ 828 idRestoreGame::idRestoreGame( idFile * savefile, idFile * stringTableFile, int saveVersion ) { 829 file = savefile; 830 stringFile = stringTableFile; 831 version = saveVersion; 832 } 833 834 /* 835 ================ 836 idRestoreGame::~idRestoreGame() 837 ================ 838 */ 839 idRestoreGame::~idRestoreGame() { 840 } 841 842 /* 843 ================ 844 idRestoreGame::ReadDecls 845 ================ 846 */ 847 void idRestoreGame::ReadDecls() { 848 idStr declName; 849 for ( int t = 0; t < declManager->GetNumDeclTypes(); t++ ) { 850 while ( true ) { 851 ReadString( declName ); 852 if ( declName.IsEmpty() ) { 853 break; 854 } 855 declManager->FindType( (declType_t)t, declName ); 856 } 857 } 858 } 859 860 /* 861 ================ 862 void idRestoreGame::CreateObjects 863 ================ 864 */ 865 void idRestoreGame::CreateObjects() { 866 int i, num; 867 idStr classname; 868 idTypeInfo *type; 869 870 ReadInt( num ); 871 872 // create all the objects 873 objects.SetNum( num + 1 ); 874 memset( objects.Ptr(), 0, sizeof( objects[ 0 ] ) * objects.Num() ); 875 876 for( i = 1; i < objects.Num(); i++ ) { 877 ReadString( classname ); 878 type = idClass::GetClass( classname ); 879 if ( type == NULL ) { 880 Error( "idRestoreGame::CreateObjects: Unknown class '%s'", classname.c_str() ); 881 return; 882 } 883 objects[ i ] = type->CreateInstance(); 884 885 #ifdef ID_DEBUG_MEMORY 886 InitTypeVariables( objects[i], type->classname, 0xce ); 887 #endif 888 } 889 } 890 891 /* 892 ================ 893 void idRestoreGame::RestoreObjects 894 ================ 895 */ 896 void idRestoreGame::RestoreObjects() { 897 int i; 898 899 ReadSoundCommands(); 900 901 // read trace models 902 idClipModel::RestoreTraceModels( this ); 903 904 // restore all the objects 905 for( i = 1; i < objects.Num(); i++ ) { 906 CallRestore_r( objects[ i ]->GetType(), objects[ i ] ); 907 } 908 909 // regenerate render entities and render lights because are not saved 910 for( i = 1; i < objects.Num(); i++ ) { 911 if ( objects[ i ]->IsType( idEntity::Type ) ) { 912 idEntity *ent = static_cast<idEntity *>( objects[ i ] ); 913 ent->UpdateVisuals(); 914 ent->Present(); 915 } 916 } 917 918 #ifdef ID_DEBUG_MEMORY 919 idStr gameState = file->GetName(); 920 gameState.StripFileExtension(); 921 WriteGameState_f( idCmdArgs( va( "test %s_restore", gameState.c_str() ), false ) ); 922 //CompareGameState_f( idCmdArgs( va( "test %s_save", gameState.c_str() ) ) ); 923 gameLocal.Error( "dumped game states" ); 924 #endif 925 } 926 927 /* 928 ==================== 929 void idRestoreGame::DeleteObjects 930 ==================== 931 */ 932 void idRestoreGame::DeleteObjects() { 933 934 // Remove the NULL object before deleting 935 objects.RemoveIndex( 0 ); 936 937 objects.DeleteContents( true ); 938 } 939 940 /* 941 ================ 942 idRestoreGame::Error 943 ================ 944 */ 945 void idRestoreGame::Error( const char *fmt, ... ) { 946 va_list argptr; 947 char text[ 1024 ]; 948 949 va_start( argptr, fmt ); 950 vsprintf( text, fmt, argptr ); 951 va_end( argptr ); 952 953 objects.DeleteContents( true ); 954 955 gameLocal.Error( "%s", text ); 956 } 957 958 /* 959 ================ 960 idRestoreGame::CallRestore_r 961 ================ 962 */ 963 void idRestoreGame::CallRestore_r( const idTypeInfo *cls, idClass *obj ) { 964 if ( cls->super ) { 965 CallRestore_r( cls->super, obj ); 966 if ( cls->super->Restore == cls->Restore ) { 967 // don't call save on this inheritance level since the function was called in the super class 968 return; 969 } 970 } 971 972 ( obj->*cls->Restore )( this ); 973 } 974 975 /* 976 ================ 977 idRestoreGame::Read 978 ================ 979 */ 980 void idRestoreGame::Read( void *buffer, int len ) { 981 file->Read( buffer, len ); 982 } 983 984 /* 985 ================ 986 idRestoreGame::ReadInt 987 ================ 988 */ 989 void idRestoreGame::ReadInt( int &value ) { 990 file->ReadBig( value ); 991 } 992 993 /* 994 ================ 995 idRestoreGame::ReadJoint 996 ================ 997 */ 998 void idRestoreGame::ReadJoint( jointHandle_t &value ) { 999 file->ReadBig( (int&)value ); 1000 } 1001 1002 /* 1003 ================ 1004 idRestoreGame::ReadShort 1005 ================ 1006 */ 1007 void idRestoreGame::ReadShort( short &value ) { 1008 file->ReadBig( value ); 1009 } 1010 1011 /* 1012 ================ 1013 idRestoreGame::ReadByte 1014 ================ 1015 */ 1016 void idRestoreGame::ReadByte( byte &value ) { 1017 file->Read( &value, sizeof( value ) ); 1018 } 1019 1020 /* 1021 ================ 1022 idRestoreGame::ReadSignedChar 1023 ================ 1024 */ 1025 void idRestoreGame::ReadSignedChar( signed char &value ) { 1026 file->Read( &value, sizeof( value ) ); 1027 } 1028 1029 /* 1030 ================ 1031 idRestoreGame::ReadFloat 1032 ================ 1033 */ 1034 void idRestoreGame::ReadFloat( float &value ) { 1035 file->ReadBig( value ); 1036 } 1037 1038 /* 1039 ================ 1040 idRestoreGame::ReadBool 1041 ================ 1042 */ 1043 void idRestoreGame::ReadBool( bool &value ) { 1044 file->ReadBig( value ); 1045 } 1046 1047 /* 1048 ================ 1049 idRestoreGame::ReadString 1050 ================ 1051 */ 1052 void idRestoreGame::ReadString( idStr &string ) { 1053 string.Empty(); 1054 1055 int offset = -1; 1056 ReadInt( offset ); 1057 1058 if ( offset < 0 ) { 1059 return; 1060 } 1061 1062 stringFile->Seek( offset, FS_SEEK_SET ); 1063 stringFile->ReadString( string ); 1064 1065 return; 1066 } 1067 1068 /* 1069 ================ 1070 idRestoreGame::ReadVec2 1071 ================ 1072 */ 1073 void idRestoreGame::ReadVec2( idVec2 &vec ) { 1074 file->ReadBig( vec ); 1075 } 1076 1077 /* 1078 ================ 1079 idRestoreGame::ReadVec3 1080 ================ 1081 */ 1082 void idRestoreGame::ReadVec3( idVec3 &vec ) { 1083 file->ReadBig( vec ); 1084 } 1085 1086 /* 1087 ================ 1088 idRestoreGame::ReadVec4 1089 ================ 1090 */ 1091 void idRestoreGame::ReadVec4( idVec4 &vec ) { 1092 file->ReadBig( vec ); 1093 } 1094 1095 /* 1096 ================ 1097 idRestoreGame::ReadVec6 1098 ================ 1099 */ 1100 void idRestoreGame::ReadVec6( idVec6 &vec ) { 1101 file->ReadBig( vec ); 1102 } 1103 1104 /* 1105 ================ 1106 idRestoreGame::ReadBounds 1107 ================ 1108 */ 1109 void idRestoreGame::ReadBounds( idBounds &bounds ) { 1110 file->ReadBig( bounds ); 1111 } 1112 1113 /* 1114 ================ 1115 idRestoreGame::ReadWinding 1116 ================ 1117 */ 1118 void idRestoreGame::ReadWinding( idWinding &w ) 1119 { 1120 int i, num; 1121 ReadInt( num ); 1122 w.SetNumPoints( num ); 1123 for ( i = 0; i < num; i++ ) { 1124 idVec5 & v = w[i]; 1125 file->ReadBig( v ); 1126 } 1127 } 1128 1129 /* 1130 ================ 1131 idRestoreGame::ReadMat3 1132 ================ 1133 */ 1134 void idRestoreGame::ReadMat3( idMat3 &mat ) { 1135 file->ReadBig( mat ); 1136 } 1137 1138 /* 1139 ================ 1140 idRestoreGame::ReadAngles 1141 ================ 1142 */ 1143 void idRestoreGame::ReadAngles( idAngles &angles ) { 1144 file->ReadBig( angles ); 1145 } 1146 1147 /* 1148 ================ 1149 idRestoreGame::ReadObject 1150 ================ 1151 */ 1152 void idRestoreGame::ReadObject( idClass *&obj ) { 1153 int index; 1154 1155 ReadInt( index ); 1156 if ( ( index < 0 ) || ( index >= objects.Num() ) ) { 1157 Error( "idRestoreGame::ReadObject: invalid object index" ); 1158 } 1159 obj = objects[ index ]; 1160 } 1161 1162 /* 1163 ================ 1164 idRestoreGame::ReadStaticObject 1165 ================ 1166 */ 1167 void idRestoreGame::ReadStaticObject( idClass &obj ) { 1168 CallRestore_r( obj.GetType(), &obj ); 1169 } 1170 1171 /* 1172 ================ 1173 idRestoreGame::ReadDict 1174 ================ 1175 */ 1176 void idRestoreGame::ReadDict( idDict *dict ) { 1177 int num; 1178 int i; 1179 idStr key; 1180 idStr value; 1181 1182 ReadInt( num ); 1183 1184 if ( num < 0 ) { 1185 dict = NULL; 1186 } else { 1187 dict->Clear(); 1188 for( i = 0; i < num; i++ ) { 1189 ReadString( key ); 1190 ReadString( value ); 1191 dict->Set( key, value ); 1192 } 1193 } 1194 } 1195 1196 /* 1197 ================ 1198 idRestoreGame::ReadMaterial 1199 ================ 1200 */ 1201 void idRestoreGame::ReadMaterial( const idMaterial *&material ) { 1202 idStr name; 1203 1204 ReadString( name ); 1205 if ( !name.Length() ) { 1206 material = NULL; 1207 } else { 1208 material = declManager->FindMaterial( name ); 1209 } 1210 } 1211 1212 /* 1213 ================ 1214 idRestoreGame::ReadSkin 1215 ================ 1216 */ 1217 void idRestoreGame::ReadSkin( const idDeclSkin *&skin ) { 1218 idStr name; 1219 1220 ReadString( name ); 1221 if ( !name.Length() ) { 1222 skin = NULL; 1223 } else { 1224 skin = declManager->FindSkin( name ); 1225 } 1226 } 1227 1228 /* 1229 ================ 1230 idRestoreGame::ReadParticle 1231 ================ 1232 */ 1233 void idRestoreGame::ReadParticle( const idDeclParticle *&particle ) { 1234 idStr name; 1235 1236 ReadString( name ); 1237 if ( !name.Length() ) { 1238 particle = NULL; 1239 } else { 1240 particle = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, name ) ); 1241 } 1242 } 1243 1244 /* 1245 ================ 1246 idRestoreGame::ReadFX 1247 ================ 1248 */ 1249 void idRestoreGame::ReadFX( const idDeclFX *&fx ) { 1250 idStr name; 1251 1252 ReadString( name ); 1253 if ( !name.Length() ) { 1254 fx = NULL; 1255 } else { 1256 fx = static_cast<const idDeclFX *>( declManager->FindType( DECL_FX, name ) ); 1257 } 1258 } 1259 1260 /* 1261 ================ 1262 idRestoreGame::ReadSoundShader 1263 ================ 1264 */ 1265 void idRestoreGame::ReadSoundShader( const idSoundShader *&shader ) { 1266 idStr name; 1267 1268 ReadString( name ); 1269 if ( !name.Length() ) { 1270 shader = NULL; 1271 } else { 1272 shader = declManager->FindSound( name ); 1273 } 1274 } 1275 1276 /* 1277 ================ 1278 idRestoreGame::ReadModelDef 1279 ================ 1280 */ 1281 void idRestoreGame::ReadModelDef( const idDeclModelDef *&modelDef ) { 1282 idStr name; 1283 1284 ReadString( name ); 1285 if ( !name.Length() ) { 1286 modelDef = NULL; 1287 } else { 1288 modelDef = static_cast<const idDeclModelDef *>( declManager->FindType( DECL_MODELDEF, name, false ) ); 1289 } 1290 } 1291 1292 /* 1293 ================ 1294 idRestoreGame::ReadModel 1295 ================ 1296 */ 1297 void idRestoreGame::ReadModel( idRenderModel *&model ) { 1298 idStr name; 1299 1300 ReadString( name ); 1301 if ( !name.Length() ) { 1302 model = NULL; 1303 } else { 1304 model = renderModelManager->FindModel( name ); 1305 } 1306 } 1307 1308 /* 1309 ================ 1310 idRestoreGame::ReadUserInterface 1311 ================ 1312 */ 1313 void idRestoreGame::ReadUserInterface( idUserInterface *&ui ) { 1314 idStr name; 1315 1316 ReadString( name ); 1317 if ( !name.Length() ) { 1318 ui = NULL; 1319 } else { 1320 bool unique; 1321 ReadBool( unique ); 1322 ui = uiManager->FindGui( name, true, unique ); 1323 if ( ui ) { 1324 if ( ui->ReadFromSaveGame( file ) == false ) { 1325 Error( "idSaveGame::ReadUserInterface: ui failed to read properly\n" ); 1326 } else { 1327 ui->StateChanged( gameLocal.time ); 1328 } 1329 } 1330 } 1331 } 1332 1333 /* 1334 ================ 1335 idRestoreGame::ReadRenderEntity 1336 ================ 1337 */ 1338 void idRestoreGame::ReadRenderEntity( renderEntity_t &renderEntity ) { 1339 int i; 1340 int index; 1341 1342 ReadModel( renderEntity.hModel ); 1343 1344 ReadInt( renderEntity.entityNum ); 1345 ReadInt( renderEntity.bodyId ); 1346 1347 ReadBounds( renderEntity.bounds ); 1348 1349 // callback is set by class's Restore function 1350 renderEntity.callback = NULL; 1351 renderEntity.callbackData = NULL; 1352 1353 ReadInt( renderEntity.suppressSurfaceInViewID ); 1354 ReadInt( renderEntity.suppressShadowInViewID ); 1355 ReadInt( renderEntity.suppressShadowInLightID ); 1356 ReadInt( renderEntity.allowSurfaceInViewID ); 1357 1358 ReadVec3( renderEntity.origin ); 1359 ReadMat3( renderEntity.axis ); 1360 1361 ReadMaterial( renderEntity.customShader ); 1362 ReadMaterial( renderEntity.referenceShader ); 1363 ReadSkin( renderEntity.customSkin ); 1364 1365 ReadInt( index ); 1366 renderEntity.referenceSound = gameSoundWorld->EmitterForIndex( index ); 1367 1368 for( i = 0; i < MAX_ENTITY_SHADER_PARMS; i++ ) { 1369 ReadFloat( renderEntity.shaderParms[ i ] ); 1370 } 1371 1372 for( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) { 1373 ReadUserInterface( renderEntity.gui[ i ] ); 1374 } 1375 1376 // idEntity will restore "cameraTarget", which will be used in idEntity::Present to restore the remoteRenderView 1377 renderEntity.remoteRenderView = NULL; 1378 1379 renderEntity.joints = NULL; 1380 renderEntity.numJoints = 0; 1381 1382 ReadFloat( renderEntity.modelDepthHack ); 1383 1384 ReadBool( renderEntity.noSelfShadow ); 1385 ReadBool( renderEntity.noShadow ); 1386 ReadBool( renderEntity.noDynamicInteractions ); 1387 ReadBool( renderEntity.weaponDepthHack ); 1388 1389 ReadInt( renderEntity.forceUpdate ); 1390 1391 ReadInt( renderEntity.timeGroup ); 1392 ReadInt( renderEntity.xrayIndex ); 1393 } 1394 1395 /* 1396 ================ 1397 idRestoreGame::ReadRenderLight 1398 ================ 1399 */ 1400 void idRestoreGame::ReadRenderLight( renderLight_t &renderLight ) { 1401 int index; 1402 int i; 1403 1404 ReadMat3( renderLight.axis ); 1405 ReadVec3( renderLight.origin ); 1406 1407 ReadInt( renderLight.suppressLightInViewID ); 1408 ReadInt( renderLight.allowLightInViewID ); 1409 ReadBool( renderLight.noShadows ); 1410 ReadBool( renderLight.noSpecular ); 1411 ReadBool( renderLight.pointLight ); 1412 ReadBool( renderLight.parallel ); 1413 1414 ReadVec3( renderLight.lightRadius ); 1415 ReadVec3( renderLight.lightCenter ); 1416 1417 ReadVec3( renderLight.target ); 1418 ReadVec3( renderLight.right ); 1419 ReadVec3( renderLight.up ); 1420 ReadVec3( renderLight.start ); 1421 ReadVec3( renderLight.end ); 1422 1423 // only idLight has a prelightModel and it's always based on the entityname, so we'll restore it there 1424 // ReadModel( renderLight.prelightModel ); 1425 renderLight.prelightModel = NULL; 1426 1427 ReadInt( renderLight.lightId ); 1428 1429 ReadMaterial( renderLight.shader ); 1430 1431 for( i = 0; i < MAX_ENTITY_SHADER_PARMS; i++ ) { 1432 ReadFloat( renderLight.shaderParms[ i ] ); 1433 } 1434 1435 ReadInt( index ); 1436 renderLight.referenceSound = gameSoundWorld->EmitterForIndex( index ); 1437 } 1438 1439 /* 1440 ================ 1441 idRestoreGame::ReadRefSound 1442 ================ 1443 */ 1444 void idRestoreGame::ReadRefSound( refSound_t &refSound ) { 1445 int index; 1446 ReadInt( index ); 1447 1448 refSound.referenceSound = gameSoundWorld->EmitterForIndex( index ); 1449 ReadVec3( refSound.origin ); 1450 ReadInt( refSound.listenerId ); 1451 ReadSoundShader( refSound.shader ); 1452 ReadFloat( refSound.diversity ); 1453 ReadBool( refSound.waitfortrigger ); 1454 1455 ReadFloat( refSound.parms.minDistance ); 1456 ReadFloat( refSound.parms.maxDistance ); 1457 ReadFloat( refSound.parms.volume ); 1458 ReadFloat( refSound.parms.shakes ); 1459 ReadInt( refSound.parms.soundShaderFlags ); 1460 ReadInt( refSound.parms.soundClass ); 1461 } 1462 1463 /* 1464 ================ 1465 idRestoreGame::ReadRenderView 1466 ================ 1467 */ 1468 void idRestoreGame::ReadRenderView( renderView_t &view ) { 1469 int i; 1470 1471 ReadInt( view.viewID ); 1472 ReadInt( i /* view.x */ ); 1473 ReadInt( i /* view.y */ ); 1474 ReadInt( i /* view.width */ ); 1475 ReadInt( i /* view.height */ ); 1476 1477 ReadFloat( view.fov_x ); 1478 ReadFloat( view.fov_y ); 1479 ReadVec3( view.vieworg ); 1480 ReadMat3( view.viewaxis ); 1481 1482 ReadBool( view.cramZNear ); 1483 1484 ReadInt( view.time[0] ); 1485 1486 for( i = 0; i < MAX_GLOBAL_SHADER_PARMS; i++ ) { 1487 ReadFloat( view.shaderParms[ i ] ); 1488 } 1489 } 1490 1491 /* 1492 ================= 1493 idRestoreGame::ReadUsercmd 1494 ================= 1495 */ 1496 void idRestoreGame::ReadUsercmd( usercmd_t &usercmd ) { 1497 ReadByte( usercmd.buttons ); 1498 ReadSignedChar( usercmd.forwardmove ); 1499 ReadSignedChar( usercmd.rightmove ); 1500 ReadShort( usercmd.angles[0] ); 1501 ReadShort( usercmd.angles[1] ); 1502 ReadShort( usercmd.angles[2] ); 1503 ReadShort( usercmd.mx ); 1504 ReadShort( usercmd.my ); 1505 ReadByte( usercmd.impulse ); 1506 ReadByte( usercmd.impulseSequence ); 1507 } 1508 1509 /* 1510 =================== 1511 idRestoreGame::ReadContactInfo 1512 =================== 1513 */ 1514 void idRestoreGame::ReadContactInfo( contactInfo_t &contactInfo ) { 1515 ReadInt( (int &)contactInfo.type ); 1516 ReadVec3( contactInfo.point ); 1517 ReadVec3( contactInfo.normal ); 1518 ReadFloat( contactInfo.dist ); 1519 ReadInt( contactInfo.contents ); 1520 ReadMaterial( contactInfo.material ); 1521 ReadInt( contactInfo.modelFeature ); 1522 ReadInt( contactInfo.trmFeature ); 1523 ReadInt( contactInfo.entityNum ); 1524 ReadInt( contactInfo.id ); 1525 } 1526 1527 /* 1528 =================== 1529 idRestoreGame::ReadTrace 1530 =================== 1531 */ 1532 void idRestoreGame::ReadTrace( trace_t &trace ) { 1533 ReadFloat( trace.fraction ); 1534 ReadVec3( trace.endpos ); 1535 ReadMat3( trace.endAxis ); 1536 ReadContactInfo( trace.c ); 1537 } 1538 1539 /* 1540 =================== 1541 idRestoreGame::ReadTraceModel 1542 =================== 1543 */ 1544 void idRestoreGame::ReadTraceModel( idTraceModel &trace ) { 1545 int j, k; 1546 1547 ReadInt( (int&)trace.type ); 1548 ReadInt( trace.numVerts ); 1549 for ( j = 0; j < MAX_TRACEMODEL_VERTS; j++ ) { 1550 ReadVec3( trace.verts[j] ); 1551 } 1552 ReadInt( trace.numEdges ); 1553 for ( j = 0; j < (MAX_TRACEMODEL_EDGES+1); j++ ) { 1554 ReadInt( trace.edges[j].v[0] ); 1555 ReadInt( trace.edges[j].v[1] ); 1556 ReadVec3( trace.edges[j].normal ); 1557 } 1558 ReadInt( trace.numPolys ); 1559 for ( j = 0; j < MAX_TRACEMODEL_POLYS; j++ ) { 1560 ReadVec3( trace.polys[j].normal ); 1561 ReadFloat( trace.polys[j].dist ); 1562 ReadBounds( trace.polys[j].bounds ); 1563 ReadInt( trace.polys[j].numEdges ); 1564 for ( k = 0; k < MAX_TRACEMODEL_POLYEDGES; k++ ) { 1565 ReadInt( trace.polys[j].edges[k] ); 1566 } 1567 } 1568 ReadVec3( trace.offset ); 1569 ReadBounds( trace.bounds ); 1570 ReadBool( trace.isConvex ); 1571 // padding win32 native structs 1572 char tmp[3]; 1573 file->Read( tmp, 3 ); 1574 } 1575 1576 /* 1577 ===================== 1578 idRestoreGame::ReadClipModel 1579 ===================== 1580 */ 1581 void idRestoreGame::ReadClipModel( idClipModel *&clipModel ) { 1582 bool restoreClipModel; 1583 1584 ReadBool( restoreClipModel ); 1585 if ( restoreClipModel ) { 1586 clipModel = new (TAG_SAVEGAMES) idClipModel(); 1587 clipModel->Restore( this ); 1588 } else { 1589 clipModel = NULL; 1590 } 1591 } 1592 1593 /* 1594 ===================== 1595 idRestoreGame::ReadSoundCommands 1596 ===================== 1597 */ 1598 void idRestoreGame::ReadSoundCommands() { 1599 gameSoundWorld->StopAllSounds(); 1600 gameSoundWorld->ReadFromSaveGame( file ); 1601 }