DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

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 }