DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

PlayerProfile.cpp (17782B)


      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 #include "PlayerProfile.h"
     29 #include "PS3_Includes.h"
     30 #include "PSN/PS3_Session.h"
     31 
     32 const int32		FRAMEWORK_PROFILE_VER		= 1;
     33 
     34 
     35 // Store master volume settings in archived cvars, becausue we want them to apply
     36 // even if a user isn't signed in.
     37 // The range is from 0 to 15, which matches the setting in vanilla DOOM.
     38 idCVar s_volume_sound( "s_volume_sound", "8", CVAR_ARCHIVE | CVAR_INTEGER, "sound volume", 0, 15 );
     39 idCVar s_volume_midi( "s_volume_midi", "8", CVAR_ARCHIVE | CVAR_INTEGER, "music volume", 0, 15 );
     40 
     41 
     42 
     43 /*
     44 ================================================
     45 idProfileMgr
     46 ================================================
     47 */
     48 
     49 /*
     50 ========================
     51 idProfileMgr
     52 ========================
     53 */
     54 idProfileMgr::idProfileMgr() : 
     55 	profileSaveProcessor( new (TAG_SAVEGAMES) idSaveGameProcessorSaveProfile ),
     56 	profileLoadProcessor( new (TAG_SAVEGAMES) idSaveGameProcessorLoadProfile ),
     57 	profile( NULL ),
     58 	handle( 0 ) {
     59 }
     60 
     61 
     62 /*
     63 ================================================
     64 ~idProfileMgr
     65 ================================================
     66 */
     67 idProfileMgr::~idProfileMgr() {
     68 	delete profileSaveProcessor;
     69 	profileSaveProcessor = NULL;
     70 
     71 	delete profileLoadProcessor;
     72 	profileLoadProcessor = NULL;
     73 }
     74 
     75 /*
     76 ========================
     77 idProfileMgr::Init
     78 ========================
     79 */
     80 void idProfileMgr::Init( idPlayerProfile * profile_ ) {
     81 	profile = profile_;
     82 	handle = 0;
     83 }
     84 
     85 /*
     86 ========================
     87 idProfileMgr::Pump
     88 ========================
     89 */
     90 void idProfileMgr::Pump() {
     91 	// profile can be NULL if we forced the user to register as in the case of map-ing into a level from the press start screen
     92 	if ( profile == NULL ) {
     93 		return;
     94 	}
     95 
     96 	// See if we are done with saving/loading the profile
     97 	bool saving = profile->GetState() == idPlayerProfile::SAVING;
     98 	bool loading = profile->GetState() == idPlayerProfile::LOADING;
     99 	if ( ( saving || loading ) && psn_session->GetSaveGameManager()->IsSaveGameCompletedFromHandle( handle ) ) {
    100 		profile->SetState( idPlayerProfile::IDLE );
    101 
    102 		if ( saving ) {
    103 			// Done saving
    104 		} else if ( loading ) {
    105 			// Done loading
    106 			const idSaveLoadParms & parms = profileLoadProcessor->GetParms();
    107 			if ( parms.GetError() == SAVEGAME_E_FOLDER_NOT_FOUND || parms.GetError() == SAVEGAME_E_FILE_NOT_FOUND ) {
    108 				profile->SaveSettings();
    109 			} else if ( parms.GetError() != SAVEGAME_E_NONE ) {
    110 				profile->SetState( idPlayerProfile::ERR );
    111 			}
    112 		}
    113 	}
    114 
    115 	// See if we need to save/load the profile
    116 	if ( profile->GetRequestedState() == idPlayerProfile::SAVE_REQUESTED ) {
    117 		SaveSettings();
    118 		profile->SetRequestedState( idPlayerProfile::IDLE );
    119 	} else if ( profile->GetRequestedState() == idPlayerProfile::LOAD_REQUESTED ) {
    120 		LoadSettings();
    121 		profile->SetRequestedState( idPlayerProfile::IDLE );
    122 	}
    123 }
    124 
    125 /*
    126 ========================
    127 idProfileMgr::GetProfile
    128 ========================
    129 */
    130 idPlayerProfile * idProfileMgr::GetProfile() { 
    131 	if ( profile == NULL ) {
    132 		return NULL;
    133 	}
    134 
    135 	bool loading = ( profile->GetState() == idPlayerProfile::LOADING ) || ( profile->GetRequestedState() == idPlayerProfile::LOAD_REQUESTED );
    136 	if ( loading ) {
    137 		return NULL;
    138 	}
    139 
    140 	return profile;
    141 }
    142 
    143 /*
    144 ========================
    145 idProfileMgr::SaveSettings
    146 ========================
    147 */
    148 void idProfileMgr::SaveSettings() {
    149 	if ( profile != NULL && saveGame_enable.GetBool() ) {
    150 		// Issue the async save...
    151 		if ( profileSaveProcessor->InitSaveProfile( profile, "" ) ) {
    152 			handle = psn_session->GetSaveGameManager()->ExecuteProcessor( profileSaveProcessor );
    153 			profile->SetState( idPlayerProfile::SAVING );
    154 		}
    155 	} else {
    156 		// If not able to save the profile, just change the state and leave
    157 		if ( profile == NULL ) {
    158 			idLib::Warning( "Not saving profile, profile is NULL." );
    159 		}
    160 		if ( !saveGame_enable.GetBool() ) {
    161 			idLib::Warning( "Skipping profile save because saveGame_enable = 0" );
    162 		}
    163 	}
    164 }
    165 
    166 /*
    167 ========================
    168 idProfileMgr::LoadSettings
    169 ========================
    170 */
    171 void idProfileMgr::LoadSettings() {
    172 	if ( profile != NULL && saveGame_enable.GetBool() ) {
    173 		if ( profileLoadProcessor->InitLoadProfile( profile, "" ) ) {
    174 			// Skip the not found error because this might be the first time to play the game!
    175 			profileLoadProcessor->SetSkipSystemErrorDialogMask( SAVEGAME_E_FOLDER_NOT_FOUND | SAVEGAME_E_FILE_NOT_FOUND );
    176 
    177 			handle = psn_session->GetSaveGameManager()->ExecuteProcessor( profileLoadProcessor );
    178 			profile->SetState( idPlayerProfile::LOADING );
    179 		}
    180 	} else {
    181 		// If not able to save the profile, just change the state and leave
    182 		if ( profile == NULL ) {
    183 			idLib::Warning( "Not loading profile, profile is NULL." );
    184 		}
    185 		if ( !saveGame_enable.GetBool() ) {
    186 			idLib::Warning( "Skipping profile load because saveGame_enable = 0" );
    187 		}
    188 	}
    189 }
    190 
    191 /*
    192 ================================================
    193 idSaveGameProcessorSaveProfile
    194 ================================================
    195 */
    196 
    197 /*
    198 ========================
    199 idSaveGameProcessorSaveProfile::idSaveGameProcessorSaveProfile
    200 ========================
    201 */
    202 idSaveGameProcessorSaveProfile::idSaveGameProcessorSaveProfile() {
    203 	profileFile = NULL;
    204 	profile = NULL;
    205 }
    206 
    207 /*
    208 ========================
    209 idSaveGameProcessorSaveProfile::InitSaveProfile
    210 ========================
    211 */
    212 bool idSaveGameProcessorSaveProfile::InitSaveProfile( idPlayerProfile * profile_, const char * folder ) {
    213 
    214 	// Serialize the profile and pass a file to the processor
    215 	profileFile = new (TAG_SAVEGAMES) idFile_Memory( SAVEGAME_PROFILE_FILENAME );
    216 	profileFile->MakeWritable();
    217 	profileFile->SetMaxLength( MAX_PROFILE_SIZE );
    218 
    219 	idTempArray< byte > buffer( MAX_PROFILE_SIZE );
    220 	idBitMsg msg;
    221 	msg.InitWrite( buffer.Ptr(), MAX_PROFILE_SIZE );
    222 	idSerializer ser( msg, true );
    223 	profile_->SerializeSettings( ser );
    224 
    225 	profileFile->Write( msg.GetReadData(), msg.GetSize() );
    226 	profileFile->MakeReadOnly();
    227 
    228 	idList< idSaveFileEntry > files;
    229 	files.Append( idSaveFileEntry( profileFile, SAVEGAMEFILE_BINARY | SAVEGAMEFILE_AUTO_DELETE, SAVEGAME_PROFILE_FILENAME ) );
    230 
    231 	idSaveGameDetails description;
    232 	if ( !idSaveGameProcessor::Init() ) {
    233 		return false;
    234 	}
    235 
    236 	if ( files.Num() == 0 ) {
    237 		idLib::Warning( "No files to save." );
    238 		return false;
    239 	}
    240 
    241 	// Setup save system
    242 	parms.directory = AddSaveFolderPrefix( folder, idSaveGameManager::PACKAGE_PROFILE  );
    243 	parms.mode = SAVEGAME_MBF_SAVE | SAVEGAME_MBF_HIDDEN;	// do NOT delete the existing files
    244 	parms.saveFileType = SAVEFILE_TYPE_AUTO;
    245 	for ( int i = 0; i < files.Num(); ++i ) {
    246 		parms.files.Append( files[i] );
    247 	}
    248 
    249 
    250 	description.title = idLocalization::GetString( "#str_savegame_title" );
    251 	description.subTitle = idLocalization::GetString( "#str_savegame_profile_heading" );
    252 	description.summary = idLocalization::GetString( "#str_savegame_profile_desc" );
    253 
    254 
    255 	// Add static image as the thumbnail
    256 	staticScreenshotFile = new (TAG_SAVEGAMES) idFile_Memory( "image" );
    257 
    258 	// Open up the Image file and Make it a memory file.
    259 	void* thumbImage = NULL;
    260 	int imagesize = fileSystem->ReadFile( "base/textures/PROFILE.PNG", &thumbImage );		// This file lives at USRData.. i think.
    261 	staticScreenshotFile->MakeWritable();
    262 	staticScreenshotFile->Write( thumbImage, imagesize );
    263 	staticScreenshotFile->MakeReadOnly();
    264 
    265 	parms.files.Append( idSaveFileEntry( staticScreenshotFile, SAVEGAMEFILE_THUMB, "image" ) );
    266 	fileSystem->FreeFile( thumbImage );
    267 
    268 
    269 	this->parms.description = description;
    270 	parms.description.slotName = folder;
    271 
    272 
    273 
    274 	// TODO:KC - what was the purpose of this?
    275 	// JAF idKeyInput::SetUserDeviceNumForBind( profile_->GetDeviceNumForProfile() );
    276 
    277 	profile = profile_;
    278 
    279 	return true;
    280 }
    281 
    282 /*
    283 ========================
    284 idSaveGameProcessorSaveProfile::Process
    285 ========================
    286 */
    287 bool idSaveGameProcessorSaveProfile::Process() {
    288 	// Files already setup for save, just execute as normal files
    289 
    290 	// Platform-specific implementation
    291 	// This will start a worker thread for async operation.
    292 	// It will always signal when it's completed.
    293 	Sys_ExecuteSavegameCommandAsync( &parms );
    294 
    295 	return false;
    296 }
    297 
    298 /*
    299 ================================================
    300 idSaveGameProcessorLoadProfile
    301 ================================================
    302 */
    303 
    304 /*
    305 ========================
    306 idSaveGameProcessorLoadProfile::idSaveGameProcessorLoadProfile
    307 ========================
    308 */
    309 idSaveGameProcessorLoadProfile::idSaveGameProcessorLoadProfile() {
    310 	profileFile = NULL;
    311 	profile = NULL;
    312 }
    313 
    314 /*
    315 ========================
    316 idSaveGameProcessorLoadProfile::~idSaveGameProcessorLoadProfile
    317 ========================
    318 */
    319 idSaveGameProcessorLoadProfile::~idSaveGameProcessorLoadProfile() {
    320 }
    321 
    322 /*
    323 ========================
    324 idSaveGameProcessorLoadProfile::InitLoadFiles
    325 ========================
    326 */
    327 bool idSaveGameProcessorLoadProfile::InitLoadProfile( idPlayerProfile * profile_, const char * folder_ ) {
    328 	if ( !idSaveGameProcessor::Init() ) {
    329 		return false;
    330 	}
    331 
    332 	parms.directory = AddSaveFolderPrefix( folder_, idSaveGameManager::PACKAGE_PROFILE );
    333 	parms.description.slotName = folder_;
    334 	parms.mode = SAVEGAME_MBF_LOAD | SAVEGAME_MBF_HIDDEN;
    335 	parms.saveFileType = SAVEFILE_TYPE_AUTO;
    336 
    337 	profileFile = new (TAG_SAVEGAMES) idFile_Memory( SAVEGAME_PROFILE_FILENAME );
    338 	parms.files.Append( idSaveFileEntry( profileFile, SAVEGAMEFILE_BINARY, SAVEGAME_PROFILE_FILENAME ) );
    339 
    340 	profile = profile_;
    341 
    342 	return true;
    343 }
    344 
    345 /*
    346 ========================
    347 idSaveGameProcessorLoadProfile::Process
    348 ========================
    349 */
    350 bool idSaveGameProcessorLoadProfile::Process() {
    351 	Sys_ExecuteSavegameCommandAsync( &parms );
    352 
    353 	return false;
    354 }
    355 
    356 /*
    357 ========================
    358 idSaveGameProcessorLoadProfile::PostProcess
    359 ========================
    360 */
    361 void idSaveGameProcessorLoadProfile::PostProcess() {
    362 	// Serialize the loaded profile
    363 	bool foundProfile = profileFile->Length() > 0;
    364 
    365 	if ( foundProfile ) {
    366 		idTempArray< byte> buffer( MAX_PROFILE_SIZE );
    367 
    368 		// Serialize settings from this buffer
    369 		profileFile->MakeReadOnly();
    370 		profileFile->ReadBigArray( buffer.Ptr(), profileFile->Length() );
    371 
    372 		idBitMsg msg;
    373 		msg.InitRead( buffer.Ptr(), (int)buffer.Size() );
    374 		idSerializer ser( msg, false );
    375 		profile->SerializeSettings( ser );
    376 
    377 		// JAF idKeyInput::SetUserDeviceNumForBind( profile->GetDeviceNumForProfile() );
    378 
    379 	} else {
    380 		parms.errorCode = SAVEGAME_E_FILE_NOT_FOUND;
    381 	}
    382 
    383 	delete profileFile;
    384 }
    385 
    386 /*
    387 ========================
    388 Contains data that needs to be saved out on a per player profile basis, global for the lifetime of the player so
    389 the data can be shared across computers.
    390 - HUD tint colors 
    391 - key bindings
    392 - etc...
    393 ========================
    394 */
    395 
    396 /*
    397 ========================
    398 idPlayerProfile::idPlayerProfile
    399 ========================
    400 */
    401 idPlayerProfile::idPlayerProfile() {
    402 	SetDefaults();
    403 
    404 	// Don't have these in SetDefaults because they're used for state management and SetDefaults is called when
    405 	// loading the profile
    406 	state				= IDLE;
    407 	requestedState		= IDLE;
    408 }
    409 
    410 /*
    411 ========================
    412 idPlayerProfile::SetDefaults
    413 ========================
    414 */
    415 void idPlayerProfile::SetDefaults() {
    416 	
    417 	achievementBits		= 0;
    418 	seenInstallMessage  = false;
    419 	stats.SetNum( MAX_PLAYER_PROFILE_STATS );
    420 	for ( int i = 0; i < MAX_PLAYER_PROFILE_STATS; ++i ) {
    421 		stats[i].i = 0;
    422 	}
    423 
    424 	deviceNum			= 0;
    425 	state				= IDLE;
    426 	requestedState		= IDLE;
    427 	frameScaleX			= 0.85f;
    428 	frameScaleY			= 0.85f;
    429 }
    430 
    431 /*
    432 ========================
    433 idPlayerProfile::Init
    434 ========================
    435 */
    436 void idPlayerProfile::Init() {
    437 	SetDefaults();
    438 }
    439 
    440 /*
    441 ========================
    442 idPlayerProfile::~idPlayerProfile
    443 ========================
    444 */
    445 idPlayerProfile::~idPlayerProfile() {
    446 }
    447 
    448 /*
    449 ========================
    450 idPlayerProfile::SerializeSettings
    451 ========================
    452 */
    453 bool idPlayerProfile::SerializeSettings( idSerializer & ser ) {
    454 	int flags = cvarSystem->GetModifiedFlags();
    455 
    456 	// Default to current tag/version
    457 	int32	tag		= GetProfileTag();
    458 	int32	version	= FRAMEWORK_PROFILE_VER;
    459 
    460 	// Serialize tag/version
    461 	ser.SerializePacked( tag );
    462 	if ( tag != GetProfileTag() ) {
    463 		idLib::Warning( "Profile tag did not match, profile will be re-initialized" );
    464 		SetDefaults();
    465 		SaveSettings();	// Flag the profile to save so we have the latest version stored
    466 
    467 		return false;		
    468 	}
    469 	ser.SerializePacked( version );
    470 	if ( version != FRAMEWORK_PROFILE_VER ) {
    471 		// For now, don't allow profiles with invalid versions load
    472 		// We could easily support old version by doing a few version checks below to pick and choose what we load as well.
    473 		idLib::Warning( "Profile version did not match.  Profile will be replaced" );
    474 		SetDefaults();
    475 		SaveSettings();	// Flag the profile to save so we have the latest version stored
    476 
    477 		return false;		
    478 	}
    479 
    480 	// Serialize audio settings
    481 	SERIALIZE_BOOL( ser, seenInstallMessage );
    482 
    483 	// New setting to save to make sure that we have or haven't seen this achievement before used to pass TRC R149d
    484 	ser.Serialize( achievementBits );
    485 
    486 	ser.Serialize( frameScaleX );
    487 	ser.Serialize( frameScaleY );
    488 	SERIALIZE_BOOL( ser, alwaysRun );
    489 
    490 
    491 	// we save all the cvar-based settings in the profile even though some cvars are archived
    492 	// so that we are consistent and don't miss any or get affected when the archive flag is changed
    493 	SERIALIZE_CVAR_INT( ser, s_volume_sound );
    494 	SERIALIZE_CVAR_INT( ser, s_volume_midi );
    495 	
    496 	// Don't trigger profile save due to modified archived cvars during profile load
    497 	cvarSystem->ClearModifiedFlags( CVAR_ARCHIVE );	// must clear because set() is an OR operation, not assignment...
    498 	cvarSystem->SetModifiedFlags( flags );
    499 
    500 	return true;
    501 }
    502 /*
    503 ========================
    504 idPlayerProfile::GetLevel
    505 ========================
    506 */
    507 int idPlayerProfile::GetLevel() const {
    508 	return 1;
    509 }
    510 
    511 /*
    512 ========================
    513 idPlayerProfile::StatSetInt
    514 ========================
    515 */
    516 void idPlayerProfile::StatSetInt( int s, int v ) {
    517 	stats[s].i = v;
    518 }
    519 
    520 /*
    521 ========================
    522 idPlayerProfile::StatSetFloat
    523 ========================
    524 */
    525 void idPlayerProfile::StatSetFloat( int s, float v ) {
    526 	stats[s].f = v;
    527 }
    528 
    529 /*
    530 ========================
    531 idPlayerProfile::StatGetInt
    532 ========================
    533 */
    534 int	idPlayerProfile::StatGetInt( int s ) const { 
    535 	return stats[s].i;
    536 }
    537 
    538 /*
    539 ========================
    540 idPlayerProfile::StatGetFloat
    541 ========================
    542 */
    543 float idPlayerProfile::StatGetFloat( int s ) const {
    544 	return stats[s].f;
    545 }
    546 
    547 /*
    548 ========================
    549 idPlayerProfile::SaveSettings
    550 ========================
    551 */
    552 void idPlayerProfile::SaveSettings() {
    553 	if ( state != SAVING ) {
    554 		if ( GetRequestedState() == IDLE ) {
    555 			SetRequestedState( SAVE_REQUESTED );
    556 		}
    557 	}
    558 }
    559 
    560 /*
    561 ========================
    562 idPlayerProfile::SaveSettings
    563 ========================
    564 */
    565 void idPlayerProfile::LoadSettings() {
    566 	if ( state != LOADING ) {
    567 		if ( verify( GetRequestedState() == IDLE ) ) {
    568 			SetRequestedState( LOAD_REQUESTED );
    569 		}
    570 	}
    571 }
    572 
    573 /*
    574 ========================
    575 idPlayerProfile::SetAchievementBit
    576 ========================
    577 */
    578 void idPlayerProfile::SetAchievementBit( const int id ) {
    579 	if ( id > 63 ) {
    580 		assert( false );		// FIXME: add another set of achievement bit flags
    581 		return;
    582 	}
    583 
    584 	achievementBits |= (int64)1 << id;
    585 }
    586 
    587 /*
    588 ========================
    589 idPlayerProfile::ClearAchievementBit
    590 ========================
    591 */
    592 void idPlayerProfile::ClearAchievementBit( const int id ) {
    593 	if ( id > 63 ) {
    594 		assert( false );		// FIXME: add another set of achievement bit flags
    595 		return;
    596 	}
    597 
    598 	achievementBits &= ~( (int64)1 << id );
    599 }
    600 
    601 /*
    602 ========================
    603 idPlayerProfile::GetAchievementBit
    604 ========================
    605 */
    606 bool idPlayerProfile::GetAchievementBit( const int id ) const {
    607 	if ( id > 63 ) {
    608 		assert( false );		// FIXME: add another set of achievement bit flags
    609 		return false;
    610 	}
    611 
    612 	return ( achievementBits & (int64)1 << id ) != 0;
    613 }
    614 
    615 /*
    616 ========================
    617 Returns the value stored in the music volume cvar.
    618 ========================
    619 */
    620 int	idPlayerProfile::GetMusicVolume() const {
    621 	return s_volume_midi.GetInteger();
    622 }
    623 
    624 /*
    625 ========================
    626 Returns the value stored in the sound volume cvar.
    627 ========================
    628 */
    629 int	idPlayerProfile::GetSoundVolume() const {
    630 	return s_volume_sound.GetInteger();
    631 }
    632 
    633 /*
    634 ========================
    635 Sets the music volume cvar.
    636 ========================
    637 */
    638 void idPlayerProfile::SetMusicVolume( int volume ) {
    639 	s_volume_midi.SetInteger( volume );
    640 }
    641 
    642 /*
    643 ========================
    644 Sets the sound volume cvar.
    645 ========================
    646 */
    647 void idPlayerProfile::SetSoundVolume( int volume ) {
    648 	s_volume_sound.SetInteger( volume );
    649 }