PlayerProfile.cpp 17 KB

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