PlayerProfile.cpp (10794B)
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 #pragma hdrstop 29 #include "../idlib/precompiled.h" 30 #pragma hdrstop 31 #include "PlayerProfile.h" 32 33 // After releasing a version to the market, here are limitations for compatibility: 34 // - the major version should not ever change 35 // - always add new items to the bottom of the save/load routine 36 // - never remove or change the size of items, just stop using them or add new items to the end 37 // 38 // The biggest reason these limitations exist is because if a newer profile is created and then loaded with a GMC 39 // version, we have to support it. 40 const int16 PROFILE_TAG = ( 'D' << 8 ) | '3'; 41 const int8 PROFILE_VER_MAJOR = 10; // If this is changed, you should reset the minor version and remove all backward compatible code 42 const int8 PROFILE_VER_MINOR = 0; // Within each major version, minor versions can be supported for backward compatibility 43 44 class idPlayerProfileLocal : public idPlayerProfile { 45 }; 46 idPlayerProfileLocal playerProfiles[MAX_INPUT_DEVICES]; 47 48 /* 49 ======================== 50 Contains data that needs to be saved out on a per player profile basis, global for the lifetime of the player so 51 the data can be shared across computers. 52 - HUD tint colors 53 - key bindings 54 - etc... 55 ======================== 56 */ 57 58 /* 59 ======================== 60 idPlayerProfile * CreatePlayerProfile 61 ======================== 62 */ 63 idPlayerProfile * idPlayerProfile::CreatePlayerProfile( int deviceIndex ) { 64 playerProfiles[deviceIndex].SetDefaults(); 65 playerProfiles[deviceIndex].deviceNum = deviceIndex; 66 return &playerProfiles[deviceIndex]; 67 } 68 69 /* 70 ======================== 71 idPlayerProfile::idPlayerProfile 72 ======================== 73 */ 74 idPlayerProfile::idPlayerProfile() { 75 SetDefaults(); 76 77 // Don't have these in SetDefaults because they're used for state management and SetDefaults is called when 78 // loading the profile 79 state = IDLE; 80 requestedState = IDLE; 81 deviceNum = -1; 82 dirty = false; 83 } 84 85 /* 86 ======================== 87 idPlayerProfile::SetDefaults 88 ======================== 89 */ 90 void idPlayerProfile::SetDefaults() { 91 achievementBits = 0; 92 achievementBits2 = 0; 93 dlcReleaseVersion = 0; 94 95 stats.SetNum( MAX_PLAYER_PROFILE_STATS ); 96 for ( int i = 0; i < MAX_PLAYER_PROFILE_STATS; ++i ) { 97 stats[i].i = 0; 98 } 99 100 leftyFlip = false; 101 customConfig = false; 102 configSet = 0; 103 } 104 105 /* 106 ======================== 107 idPlayerProfile::~idPlayerProfile 108 ======================== 109 */ 110 idPlayerProfile::~idPlayerProfile() { 111 } 112 113 /* 114 ======================== 115 idPlayerProfile::Serialize 116 ======================== 117 */ 118 bool idPlayerProfile::Serialize( idSerializer & ser ) { 119 // NOTE: 120 // See comments at top of file on versioning rules 121 122 // Default to current tag/version 123 int32 magicNumber = 0; 124 magicNumber += PROFILE_TAG << 16; 125 magicNumber += PROFILE_VER_MAJOR << 8; 126 magicNumber += PROFILE_VER_MINOR; 127 128 // Serialize version 129 ser.SerializePacked( magicNumber ); 130 int16 tag = ( magicNumber >> 16 ) & 0xffff; 131 int8 majorVersion = ( magicNumber >> 8 ) & 0xff; 132 int8 minorVersion = magicNumber & 0xff; minorVersion; 133 134 if ( tag != PROFILE_TAG ) { 135 return false; 136 } 137 138 if ( majorVersion != PROFILE_VER_MAJOR ) { 139 return false; 140 } 141 142 // Archived cvars (all the menu settings for Doom3 are archived cvars) 143 idDict cvarDict; 144 cvarSystem->MoveCVarsToDict( CVAR_ARCHIVE, cvarDict ); 145 cvarDict.Serialize( ser ); 146 if ( ser.IsReading() ) { 147 // Never sync these cvars with Steam because they require an engine or video restart 148 cvarDict.Delete( "r_fullscreen" ); 149 cvarDict.Delete( "r_vidMode" ); 150 cvarDict.Delete( "r_multisamples" ); 151 cvarDict.Delete( "com_engineHz" ); 152 cvarSystem->SetCVarsFromDict( cvarDict ); 153 common->StartupVariable( NULL ); 154 } 155 156 // The dlcReleaseVersion is used to determine that new content is available 157 ser.SerializePacked( dlcReleaseVersion ); 158 159 // New setting to save to make sure that we have or haven't seen this achievement before used to pass TRC R149d 160 ser.Serialize( achievementBits ); 161 ser.Serialize( achievementBits2 ); 162 163 // Check to map sure we are on a valid map before we save, this helps prevent someone from creating a test map and 164 // gaining a bunch of achievements from it 165 int numStats = stats.Num(); 166 ser.SerializePacked( numStats ); 167 stats.SetNum( numStats ); 168 for ( int i = 0; i < numStats; ++i ) { 169 ser.SerializePacked( stats[i].i ); 170 } 171 172 ser.Serialize( leftyFlip ); 173 ser.Serialize( configSet ); 174 175 if ( ser.IsReading() ) { 176 // Which binding is used on the console? 177 ser.Serialize( customConfig ); 178 179 ExecConfig( false ); 180 181 if ( customConfig ) { 182 for ( int i = 0; i < K_LAST_KEY; ++i ) { 183 idStr bind; 184 ser.SerializeString( bind ); 185 idKeyInput::SetBinding( i, bind.c_str() ); 186 } 187 } 188 } else { 189 190 if ( !customConfig ) { 191 ExecConfig( false ); 192 } 193 194 customConfig = true; 195 ser.Serialize( customConfig ); 196 197 for ( int i = 0; i < K_LAST_KEY; ++i ) { 198 idStr bind = idKeyInput::GetBinding( i ); 199 ser.SerializeString( bind ); 200 } 201 } 202 203 return true; 204 } 205 206 /* 207 ======================== 208 idPlayerProfile::StatSetInt 209 ======================== 210 */ 211 void idPlayerProfile::StatSetInt( int s, int v ) { 212 stats[s].i = v; 213 MarkDirty( true ); 214 } 215 216 /* 217 ======================== 218 idPlayerProfile::StatSetFloat 219 ======================== 220 */ 221 void idPlayerProfile::StatSetFloat( int s, float v ) { 222 stats[s].f = v; 223 MarkDirty( true ); 224 } 225 226 /* 227 ======================== 228 idPlayerProfile::StatGetInt 229 ======================== 230 */ 231 int idPlayerProfile::StatGetInt( int s ) const { 232 return stats[s].i; 233 } 234 235 /* 236 ======================== 237 idPlayerProfile::StatGetFloat 238 ======================== 239 */ 240 float idPlayerProfile::StatGetFloat( int s ) const { 241 return stats[s].f; 242 } 243 244 /* 245 ======================== 246 idPlayerProfile::SaveSettings 247 ======================== 248 */ 249 void idPlayerProfile::SaveSettings( bool forceDirty ) { 250 if ( state != SAVING ) { 251 if ( forceDirty ) { 252 MarkDirty( true ); 253 } 254 if ( GetRequestedState() == IDLE && IsDirty() ) { 255 SetRequestedState( SAVE_REQUESTED ); 256 } 257 } 258 } 259 260 /* 261 ======================== 262 idPlayerProfile::SaveSettings 263 ======================== 264 */ 265 void idPlayerProfile::LoadSettings() { 266 if ( state != LOADING ) { 267 if ( verify( GetRequestedState() == IDLE ) ) { 268 SetRequestedState( LOAD_REQUESTED ); 269 } 270 } 271 } 272 273 /* 274 ======================== 275 idPlayerProfile::SetAchievement 276 ======================== 277 */ 278 void idPlayerProfile::SetAchievement( const int id ) { 279 if ( id >= idAchievementSystem::MAX_ACHIEVEMENTS ) { 280 assert( false ); // FIXME: add another set of achievement bit flags 281 return; 282 } 283 284 uint64 mask = 0; 285 if ( id < 64 ) { 286 mask = achievementBits; 287 achievementBits |= (int64)1 << id; 288 mask = ~mask & achievementBits; 289 } else { 290 mask = achievementBits2; 291 achievementBits2 |= (int64)1 << ( id - 64 ); 292 mask = ~mask & achievementBits2; 293 } 294 295 // Mark the profile dirty if achievement bits changed 296 if ( mask != 0 ) { 297 MarkDirty( true ); 298 } 299 } 300 301 /* 302 ======================== 303 idPlayerProfile::ClearAchievement 304 ======================== 305 */ 306 void idPlayerProfile::ClearAchievement( const int id ) { 307 if ( id >= idAchievementSystem::MAX_ACHIEVEMENTS ) { 308 assert( false ); // FIXME: add another set of achievement bit flags 309 return; 310 } 311 312 if ( id < 64 ) { 313 achievementBits &= ~( (int64)1 << id ); 314 } else { 315 achievementBits2 &= ~( (int64)1 << ( id - 64 ) ); 316 } 317 318 MarkDirty( true ); 319 } 320 321 /* 322 ======================== 323 idPlayerProfile::GetAchievement 324 ======================== 325 */ 326 bool idPlayerProfile::GetAchievement( const int id ) const { 327 if ( id >= idAchievementSystem::MAX_ACHIEVEMENTS ) { 328 assert( false ); // FIXME: add another set of achievement bit flags 329 return false; 330 } 331 332 if ( id < 64 ) { 333 return ( achievementBits & (int64)1 << id ) != 0; 334 } else { 335 return ( achievementBits2 & (int64)1 << ( id - 64 ) ) != 0; 336 } 337 } 338 339 /* 340 ======================== 341 idPlayerProfile::SetConfig 342 ======================== 343 */ 344 void idPlayerProfile::SetConfig( int config, bool save ) { 345 configSet = config; 346 ExecConfig( save ); 347 } 348 349 /* 350 ======================== 351 idPlayerProfile::SetConfig 352 ======================== 353 */ 354 void idPlayerProfile::RestoreDefault() { 355 ExecConfig( true, true ); 356 } 357 358 /* 359 ======================== 360 idPlayerProfile::SetLeftyFlip 361 ======================== 362 */ 363 void idPlayerProfile::SetLeftyFlip( bool lf ) { 364 leftyFlip = lf; 365 ExecConfig( true ); 366 } 367 368 /* 369 ======================== 370 idPlayerProfile::ExecConfig 371 ======================== 372 */ 373 void idPlayerProfile::ExecConfig( bool save, bool forceDefault ) { 374 375 int flags = 0; 376 if ( !save ) { 377 flags = cvarSystem->GetModifiedFlags(); 378 } 379 380 if ( !customConfig || forceDefault ) { 381 cmdSystem->AppendCommandText( "exec default.cfg\n" ); 382 cmdSystem->AppendCommandText( "exec joy_360_0.cfg\n" ); 383 } 384 385 if ( leftyFlip ) { 386 cmdSystem->AppendCommandText( "exec joy_lefty.cfg" ); 387 } else { 388 cmdSystem->AppendCommandText( "exec joy_righty.cfg" ); 389 } 390 391 cmdSystem->ExecuteCommandBuffer(); 392 393 if ( !save ) { 394 cvarSystem->ClearModifiedFlags( CVAR_ARCHIVE ); 395 cvarSystem->SetModifiedFlags( flags ); 396 } 397 } 398 399 CONSOLE_COMMAND( setProfileDefaults, "sets profile settings to default and saves", 0 ) { 400 if ( session->GetSignInManager().GetMasterLocalUser() == NULL ) { 401 return; 402 } 403 idPlayerProfile * profile = session->GetSignInManager().GetMasterLocalUser()->GetProfile(); 404 if ( verify( profile != NULL ) ) { 405 profile->SetDefaults(); 406 profile->SaveSettings( true ); 407 } 408 }