the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 717 lines 25 kB view raw
1#include "stdafx.h" 2#include "DurangoLeaderboardManager.h" 3#include "..\..\..\Minecraft.World\StringHelpers.h" 4 5namespace WFC = Windows::Foundation::Collections; 6namespace CC = concurrency; 7 8LeaderboardManager *LeaderboardManager::m_instance = new DurangoLeaderboardManager(); //Singleton instance of the LeaderboardManager 9 10DurangoLeaderboardManager::DurangoLeaderboardManager() 11{ 12 m_eStatsState = eStatsState_Idle; 13 InitializeCriticalSection(&m_csStatsState); 14 15 m_openSessions = 0; 16 m_xboxLiveContext = nullptr; 17 m_scores = NULL; 18 m_readCount = 0; 19 m_maxRank = 0; 20 m_waitingForProfiles = false; 21 22 m_difficulty = 0; 23 m_type = eStatsType_UNDEFINED; 24 m_statNames = ref new PC::Vector<P::String^>(); 25 m_xboxUserIds = ref new PC::Vector<P::String^>(); 26 m_leaderboardAsyncOp = nullptr; 27 m_statsAsyncOp = nullptr; 28 29 for(unsigned int difficulty = 0; difficulty < 4; ++difficulty) 30 { 31 m_leaderboardNames[difficulty][eStatsType_Travelling] = L"LeaderboardTravelling" + _toString(difficulty); 32 m_leaderboardNames[difficulty][eStatsType_Mining] = L"LeaderboardMining" + _toString(difficulty); 33 m_leaderboardNames[difficulty][eStatsType_Farming] = L"LeaderboardFarming" + _toString(difficulty); 34 m_leaderboardNames[difficulty][eStatsType_Kills] = L"LeaderboardKills" + _toString(difficulty); 35 36 m_socialLeaderboardNames[difficulty][eStatsType_Travelling] = L"Leaderboard.LeaderboardId.0.DifficultyLevelId." + _toString(difficulty); 37 m_socialLeaderboardNames[difficulty][eStatsType_Mining] = L"Leaderboard.LeaderboardId.1.DifficultyLevelId." + _toString(difficulty); 38 m_socialLeaderboardNames[difficulty][eStatsType_Farming] = L"Leaderboard.LeaderboardId.2.DifficultyLevelId." + _toString(difficulty); 39 m_socialLeaderboardNames[difficulty][eStatsType_Kills] = L"Leaderboard.LeaderboardId.3.DifficultyLevelId." + _toString(difficulty); 40 41 m_leaderboardStatNames[difficulty][eStatsType_Travelling].push_back( L"DistanceTravelled.DifficultyLevelId." + _toString(difficulty) + L".TravelMethodId.0"); // Walked 42 m_leaderboardStatNames[difficulty][eStatsType_Travelling].push_back( L"DistanceTravelled.DifficultyLevelId." + _toString(difficulty) + L".TravelMethodId.2"); // Fallen 43 m_leaderboardStatNames[difficulty][eStatsType_Travelling].push_back( L"DistanceTravelled.DifficultyLevelId." + _toString(difficulty) + L".TravelMethodId.4"); // Minecart 44 m_leaderboardStatNames[difficulty][eStatsType_Travelling].push_back( L"DistanceTravelled.DifficultyLevelId." + _toString(difficulty) + L".TravelMethodId.5"); // Boat 45 46 m_leaderboardStatNames[difficulty][eStatsType_Mining].push_back( L"BlockBroken.DifficultyLevelId." + _toString(difficulty) + L".BlockId.3"); // Dirt 47 m_leaderboardStatNames[difficulty][eStatsType_Mining].push_back( L"BlockBroken.DifficultyLevelId." + _toString(difficulty) + L".BlockId.4"); // Cobblestone 48 m_leaderboardStatNames[difficulty][eStatsType_Mining].push_back( L"BlockBroken.DifficultyLevelId." + _toString(difficulty) + L".BlockId.12"); // Sand 49 m_leaderboardStatNames[difficulty][eStatsType_Mining].push_back( L"BlockBroken.DifficultyLevelId." + _toString(difficulty) + L".BlockId.1"); // Stone 50 m_leaderboardStatNames[difficulty][eStatsType_Mining].push_back( L"BlockBroken.DifficultyLevelId." + _toString(difficulty) + L".BlockId.13"); // Gravel 51 m_leaderboardStatNames[difficulty][eStatsType_Mining].push_back( L"BlockBroken.DifficultyLevelId." + _toString(difficulty) + L".BlockId.82"); // Clay 52 m_leaderboardStatNames[difficulty][eStatsType_Mining].push_back( L"BlockBroken.DifficultyLevelId." + _toString(difficulty) + L".BlockId.49"); // Obsidian 53 54 m_leaderboardStatNames[difficulty][eStatsType_Farming].push_back( L"McItemAcquired.DifficultyLevelId." + _toString(difficulty) + L".AcquisitionMethodId.1.ItemId.344"); // Eggs 55 m_leaderboardStatNames[difficulty][eStatsType_Farming].push_back( L"BlockBroken.DifficultyLevelId." + _toString(difficulty) + L".BlockId.59"); // Wheat 56 m_leaderboardStatNames[difficulty][eStatsType_Farming].push_back( L"BlockBroken.DifficultyLevelId." + _toString(difficulty) + L".BlockId.39"); // Mushroom 57 m_leaderboardStatNames[difficulty][eStatsType_Farming].push_back( L"BlockBroken.DifficultyLevelId." + _toString(difficulty) + L".BlockId.83"); // Sugarcane 58 m_leaderboardStatNames[difficulty][eStatsType_Farming].push_back( L"McItemAcquired.DifficultyLevelId." + _toString(difficulty) + L".AcquisitionMethodId.2.ItemId.335"); // Milk 59 m_leaderboardStatNames[difficulty][eStatsType_Farming].push_back( L"McItemAcquired.DifficultyLevelId." + _toString(difficulty) + L".AcquisitionMethodId.1.ItemId.86"); // Pumpkin 60 61 m_leaderboardStatNames[difficulty][eStatsType_Kills].push_back( L"MobKilledTotal.DifficultyLevelId." + _toString(difficulty) + L".EnemyRoleId.54"); // Zombie 62 m_leaderboardStatNames[difficulty][eStatsType_Kills].push_back( L"MobKilledTotal.DifficultyLevelId." + _toString(difficulty) + L".EnemyRoleId.51"); // Skeleton 63 m_leaderboardStatNames[difficulty][eStatsType_Kills].push_back( L"MobKilledTotal.DifficultyLevelId." + _toString(difficulty) + L".EnemyRoleId.50"); // Creeper 64 m_leaderboardStatNames[difficulty][eStatsType_Kills].push_back( L"MobKilledTotal.DifficultyLevelId." + _toString(difficulty) + L".EnemyRoleId.52"); // Spider 65 m_leaderboardStatNames[difficulty][eStatsType_Kills].push_back( L"MobKilledTotal.DifficultyLevelId." + _toString(difficulty) + L".EnemyRoleId.49"); // Spider Jockey 66 m_leaderboardStatNames[difficulty][eStatsType_Kills].push_back( L"MobKilledTotal.DifficultyLevelId." + _toString(difficulty) + L".EnemyRoleId.57"); // Zombie Pigman 67 m_leaderboardStatNames[difficulty][eStatsType_Kills].push_back( L"MobKilledTotal.DifficultyLevelId." + _toString(difficulty) + L".EnemyRoleId.55"); // Slime 68 } 69} 70 71void DurangoLeaderboardManager::Tick() 72{ 73 ReadView view; 74 75 switch( getState() ) 76 { 77 case eStatsState_GettingLeaderboardInfo: 78 break; 79 case eStatsState_ReceivedLeaderboardInfo: 80 { 81 setState(eStatsState_GettingStatsInfo); 82 83 // Get the actual display info for the stats 84 m_statsAsyncOp = m_xboxLiveContext->UserStatisticsService->GetMultipleUserStatisticsAsync( 85 m_xboxUserIds->GetView(), // the collection of Xbox user IDs whose stats we want to retrieve 86 SERVICE_CONFIG_ID, // the service config that contains the stats we want 87 m_statNames->GetView() // a list of stat names we want 88 ); 89 90 auto task = concurrency::create_task(m_statsAsyncOp).then( [this] (CC::task<WFC::IVectorView<MXS::UserStatistics::UserStatisticsResult^>^> resultListTask) 91 { 92 try 93 { 94 app.DebugPrintf("[LeaderboardManager] Second continuation\n"); 95 m_statsAsyncOp = nullptr; 96 97 WFC::IVectorView<MXS::UserStatistics::UserStatisticsResult^>^ resultList = resultListTask.get(); 98 99 if (m_xboxLiveContext == nullptr) throw(ref new P::Exception(-1)); 100 101 int userIndex = 0; 102 for( MXS::UserStatistics::UserStatisticsResult^ result : resultList ) 103 { 104 app.DebugPrintf("XboxUserId: %ls\n", result->XboxUserId->Data()); 105 106 for( UINT index = 0; index<result->ServiceConfigurationStatistics->Size; index++ ) 107 { 108 MXS::UserStatistics::ServiceConfigurationStatistic^ configStat = result->ServiceConfigurationStatistics->GetAt(index); 109 //app.DebugPrintf("ServiceConfigurationId: %ls\n", configStat->ServiceConfigurationId->Data()); 110 111 updateStatsInfo(userIndex, m_difficulty, m_type, configStat->Statistics); 112 } 113 ++userIndex; 114 } 115 116 app.DebugPrintf("[LeaderboardManager] Setting to ready\n"); 117 setState(eStatsState_Ready); 118 119 } 120 catch (Platform::Exception^ ex) 121 { 122 m_leaderboardAsyncOp = nullptr; 123 setState(eStatsState_Failed); 124 125 if (ex->HResult == HTTP_E_STATUS_NOT_FOUND) app.DebugPrintf("[LeaderboardManager] ERROR calling GetLeaderboardAsync: 404 Not Found - 0x%0.8x\n", ex->HResult); 126 else app.DebugPrintf("[LeaderboardManager] ERROR calling GetLeaderboardAsync: 0x%0.8x\n", ex->HResult); 127 } 128 catch (...) 129 { 130 app.DebugPrintf("[LeaderboardManager] SecondContinuation: Unknown exception.\n"); 131 } 132 }); 133 } 134 break; 135 case eStatsState_GettingStatsInfo: 136 break; 137 case eStatsState_Ready: 138 { 139 // If we're waiting on profiles, don't return scores just yet 140 if (m_waitingForProfiles) 141 { 142 return; 143 } 144 else 145 { 146 if (m_displayNames.size() == m_readCount) 147 { 148 // Add display names to scores 149 for (int i = 0; i < m_displayNames.size(); i++) 150 { 151 m_scores[i].m_name = m_displayNames[i]; 152 } 153 } 154 else 155 { 156 // This seem to happen if something went wrong with Xbox Live 157 app.DebugPrintf("DurangoLeaderboardManager::Tick: Display names count (%i) didn't match read count (%i)", m_displayNames.size(), m_readCount); 158 } 159 160 m_displayNames.clear(); 161 } 162 163 //assert(m_scores != NULL || m_readCount == 0); 164 165 view.m_numQueries = m_readCount; 166 view.m_queries = m_scores; 167 168 // 4J-JEV: Debugging. 169 //LeaderboardManager::printStats(view); 170 171 eStatsReturn ret = view.m_numQueries > 0 ? eStatsReturn_Success : eStatsReturn_NoResults; 172 173 if (m_readListener != NULL) 174 { 175 app.DebugPrintf("[LeaderboardManager] OnStatsReadComplete(%i, %i, _)\n", ret, m_readCount); 176 m_readListener->OnStatsReadComplete(ret, m_maxRank, view); 177 } 178 179 app.DebugPrintf("[LeaderboardManager] Deleting scores\n"); 180 delete [] m_scores; 181 m_scores = NULL; 182 183 setState(eStatsState_Idle); 184 } 185 break; 186 187 case eStatsState_Failed: 188 view.m_numQueries = 0; 189 view.m_queries = NULL; 190 191 if ( m_readListener != NULL ) 192 { 193 m_readListener->OnStatsReadComplete(eStatsReturn_NetworkError, 0, view); 194 } 195 196 setState(eStatsState_Idle); 197 198 break; 199 200 case eStatsState_Canceled: 201 app.DebugPrintf("[LeaderboardManager] Setting canceled\n"); 202 setState(eStatsState_Idle); 203 break; 204 205 default: // Getting or Idle. 206 if (m_openSessions == 0 && m_xboxLiveContext != nullptr) 207 { 208 m_xboxLiveContext = nullptr; 209 210 app.DebugPrintf("[LeaderboardManager] Tick(): Nulled XboxLiveContext\n"); 211 } 212 break; 213 } 214} 215 216//Open a session 217bool DurangoLeaderboardManager::OpenSession() 218{ 219 if (m_openSessions == 0) 220 { 221 app.DebugPrintf("[LeaderboardManager] OpenSession()\n"); 222 223 try 224 { 225 WXS::User^ user = ProfileManager.GetUser(ProfileManager.GetPrimaryPad()); 226 if(user != nullptr && user->IsSignedIn && !user->IsGuest) 227 { 228 m_xboxLiveContext = ref new MXS::XboxLiveContext(user); 229 } 230 else 231 { 232 app.DebugPrintf("[LeaderboardManager] OpenSession(): Failed to created new XboxLiveContext, No valid user\n"); 233 return false; 234 } 235 } 236 catch (Platform::Exception^ ex) 237 { 238 m_xboxLiveContext = nullptr; 239 app.DebugPrintf("[LeaderboardManager] OpenSession(): Failed to created new XboxLiveContext, ret == 0x%08X.\n", ex->HResult); 240 return false; 241 } 242 catch (...) 243 { 244 app.DebugPrintf("[LeaderboardManager] OpenSession(): Unknown exception.\n"); 245 return false; 246 } 247 } 248 else app.DebugPrintf("[LeaderboardManager] OpenSession(): Another session opened, total=%i\n", m_openSessions+1); 249 250 m_openSessions++; 251 return true; 252} 253 254//Close a session 255void DurangoLeaderboardManager::CloseSession() 256{ 257 m_openSessions--; 258 259 if (m_openSessions == 0) 260 { 261 if(isIdle()) 262 { 263 m_xboxLiveContext = nullptr; 264 265 app.DebugPrintf("[LeaderboardManager] CloseSession(): Nulled XboxLiveContext\n"); 266 } 267 } 268 else app.DebugPrintf("[LeaderboardManager] CloseSession(): %i sessions still open.\n", m_openSessions); 269} 270 271//Delete a session 272void DurangoLeaderboardManager::DeleteSession() 273{ 274} 275 276//Write the given stats 277//This is called synchronously and will not free any memory allocated for views when it is done 278 279bool DurangoLeaderboardManager::WriteStats(unsigned int viewCount, ViewIn views) 280{ 281 return false; 282} 283 284bool DurangoLeaderboardManager::ReadStats_Friends(LeaderboardReadListener *listener, int difficulty, EStatsType type, PlayerUID myUID, unsigned int startIndex, unsigned int readCount) 285{ 286 // Need to cancel read/write operation first. 287 if (!isIdle()) return false; 288 if (!LeaderboardManager::ReadStats_Friends(listener, difficulty, type, myUID, startIndex, readCount)) return false; 289 setState(eStatsState_GettingLeaderboardInfo); 290 291 if( m_xboxLiveContext == nullptr ) 292 { 293 throw ref new Platform::InvalidArgumentException(L"A valid User is required"); 294 } 295 296 // Request the leaderboard to get ranking information 297 auto asyncOp = m_xboxLiveContext->LeaderboardService->GetLeaderboardForSocialGroupWithSkipToRankAsync( 298 ref new P::String(myUID.toString().c_str()), 299 SERVICE_CONFIG_ID, 300 ref new P::String(m_socialLeaderboardNames[difficulty][type].c_str()), 301 MXS::Social::SocialGroupConstants::People, 302 startIndex, 303 ref new P::String(L"descending"), 304 readCount 305 ); 306 307 runLeaderboardRequest(asyncOp, difficulty, type, readCount, EFilterMode::eFM_Friends); 308 309 return true; 310} 311 312bool DurangoLeaderboardManager::ReadStats_MyScore(LeaderboardReadListener *listener, int difficulty, EStatsType type, PlayerUID myUID, unsigned int readCount) 313{ 314 // Need to cancel read/write operation first. 315 if (!isIdle()) return false; 316 if (!LeaderboardManager::ReadStats_MyScore(listener, difficulty, type, myUID, readCount)) return false; 317 setState(eStatsState_GettingLeaderboardInfo); 318 319 if( m_xboxLiveContext == nullptr ) 320 { 321 throw ref new Platform::InvalidArgumentException(L"A valid User is required"); 322 } 323 324 P::String^ leaderboardName = ref new P::String(m_leaderboardNames[difficulty][type].c_str()); 325 326 // Request the leaderboard to get ranking information 327 auto asyncOp = m_xboxLiveContext->LeaderboardService->GetLeaderboardWithSkipToUserAsync( 328 SERVICE_CONFIG_ID, 329 leaderboardName, 330 ref new P::String(myUID.toString().c_str()), // skip to this user 331 readCount 332 ); 333 334 runLeaderboardRequest(asyncOp, difficulty, type, readCount, EFilterMode::eFM_MyScore); 335 336 return true; 337} 338 339bool DurangoLeaderboardManager::ReadStats_TopRank(LeaderboardReadListener *listener, int difficulty, EStatsType type, unsigned int startIndex, unsigned int readCount) 340{ 341 // Need to cancel read/write operation first. 342 if (!isIdle()) return false; 343 if (!LeaderboardManager::ReadStats_TopRank(listener, difficulty, type, startIndex, readCount)) return false; 344 setState(eStatsState_GettingLeaderboardInfo); 345 346 if( m_xboxLiveContext == nullptr ) 347 { 348 throw ref new Platform::InvalidArgumentException(L"A valid User is required"); 349 } 350 351 P::String^ leaderboardName = ref new P::String(m_leaderboardNames[difficulty][type].c_str()); 352 353 // Request the leaderboard to get ranking information 354 auto asyncOp = m_xboxLiveContext->LeaderboardService->GetLeaderboardAsync( 355 SERVICE_CONFIG_ID, 356 leaderboardName, 357 startIndex, // skip this many ranks 358 readCount 359 ); 360 361 runLeaderboardRequest(asyncOp, difficulty, type, readCount, EFilterMode::eFM_TopRank); 362 363 return true; 364} 365 366//Perform a flush of the stats 367void DurangoLeaderboardManager::FlushStats() 368{ 369} 370 371//Cancel the current operation 372void DurangoLeaderboardManager::CancelOperation() 373{ 374 m_readListener = NULL; 375 setState(eStatsState_Canceled); 376 377 if(m_leaderboardAsyncOp) m_leaderboardAsyncOp->Cancel(); 378 if(m_statsAsyncOp) m_statsAsyncOp->Cancel(); 379 380 //if (m_transactionCtx != 0) 381 //{ 382 // int ret = sceNpScoreAbortTransaction(m_transactionCtx); 383 // 384 // if (ret < 0) 385 // { 386 // app.DebugPrintf("[LeaderboardManager] CancelOperation(): Problem encountered aborting current operation, 0x%X.\n", ret); 387 // } 388 // else 389 // { 390 // app.DebugPrintf("[LeaderboardManager] CancelOperation(): Operation aborted successfully.\n"); 391 // } 392 //} 393 //else app.DebugPrintf("[LeaderboardManager] CancelOperation(): No current operation.\n"); 394} 395 396//Is the leaderboard manager idle. 397bool DurangoLeaderboardManager::isIdle() 398{ 399 return getState() == eStatsState_Idle; 400} 401 402void DurangoLeaderboardManager::runLeaderboardRequest(WF::IAsyncOperation<MXSL::LeaderboardResult^>^ asyncOp, int difficulty, EStatsType type, unsigned int readCount, EFilterMode filter) 403{ 404 m_leaderboardAsyncOp = asyncOp; 405 m_difficulty = difficulty; 406 m_type = type; 407 408 // Build stat names 409 m_statNames = ref new PC::Vector<P::String^>(); 410 m_statNames->Clear(); 411 for(wstring name : m_leaderboardStatNames[difficulty][type]) 412 { 413 m_statNames->Append(ref new P::String(name.c_str())); 414 } 415 416 app.DebugPrintf("[LeaderboardManager] Running request\n"); 417 CC::create_task(asyncOp) 418 .then( [this, readCount, difficulty, type, filter] (CC::task<MXSL::LeaderboardResult^> resultTask) 419 { 420 try 421 { 422 app.DebugPrintf("[LeaderboardManager] First continuation.\n"); 423 424 m_leaderboardAsyncOp = nullptr; 425 426 MXSL::LeaderboardResult^ lastResult = resultTask.get(); 427 428 app.DebugPrintf( 429 "Name: %ls - Filter: %ls - Rows: Retrieved=%d Total=%d Requested=%d.\n", 430 lastResult->DisplayName->Data(), 431 LeaderboardManager::filterNames[ (int) filter ].c_str(), 432 lastResult->Rows->Size, lastResult->TotalRowCount, readCount 433 ); 434 435 //app.DebugPrintf("Column count: %d, Column: %ls, %ls, %d\n", lastResult->Columns->Size, lastResult->Columns->GetAt(0)->DisplayName->Data(), lastResult->Columns->GetAt(0)->StatisticName->Data(), lastResult->Columns->GetAt(0)->StatisticType); 436 437 // 4J-JEV: Fix for Xbox One #162541 - [CRASH] Code: Leaderboards: Title crashes after pressing [B] Back button while changing Leaderboards' filter to 'My Score' 438 // 4J-JEV: Fix for X1: #165487 - [CRASH] XR-074: Compliance: The title does not properly handle switching to offline session while browsing the Leaderboards. 439 if (m_xboxLiveContext == nullptr) throw(ref new P::Exception(-1)); 440 441 // If this is My_Score, check that the user appears 442 if (filter == eFM_MyScore) 443 { 444 bool userIncluded = false; 445 for(int i = 0; i < lastResult->Rows->Size; i++) 446 { 447 if (lastResult->Rows->GetAt(i)->XboxUserId == m_xboxLiveContext->User->XboxUserId) userIncluded = true; 448 } 449 450 // If the user isn't included, don't show the results 451 if (!userIncluded) 452 { 453 m_readCount = 0; 454 throw(ref new P::Exception(INET_E_DATA_NOT_AVAILABLE)); 455 } 456 } 457 458 m_maxRank = lastResult->TotalRowCount; 459 m_readCount = lastResult->Rows->Size; 460 461 if (m_scores != NULL) delete [] m_scores; 462 m_scores = new ReadScore[m_readCount]; 463 ZeroMemory(m_scores, sizeof(ReadScore) * m_readCount); 464 465 m_xboxUserIds->Clear(); 466 467 app.DebugPrintf("[LeaderboardManager] Retrieved Scores:\n"); 468 for( UINT index = 0; index < lastResult->Rows->Size; index++ ) 469 { 470 MXSL::LeaderboardRow^ row = lastResult->Rows->GetAt(index); 471 472 app.DebugPrintf( 473 "\tIndex: %d\tRank: %d\tPercentile: %.1f%%\tXboxUserId: %ls\tValue: %ls.\n", 474 index, 475 row->Rank, 476 row->Percentile * 100, 477 row->XboxUserId->Data(), 478 row->Values->GetAt(0)->Data() 479 ); 480 481 m_scores[index].m_name = row->Gamertag->Data(); 482 m_scores[index].m_rank = row->Rank; 483 m_scores[index].m_uid = PlayerUID(row->XboxUserId->Data()); 484 485 // 4J-JEV: Added to help determine if this player's score is hidden due to their privacy settings. 486 m_scores[index].m_totalScore = (unsigned long) _fromString<long long>(row->Values->GetAt(0)->Data()); 487 488 m_xboxUserIds->Append(row->XboxUserId); 489 } 490 491 if(m_readCount > 0) 492 { 493 vector<PlayerUID> xuids = vector<PlayerUID>(); 494 for(int i = 0; i < lastResult->Rows->Size; i++) 495 { 496 xuids.push_back(PlayerUID(lastResult->Rows->GetAt(i)->XboxUserId->Data())); 497 } 498 m_waitingForProfiles = true; 499 ProfileManager.GetProfiles(xuids, &GetProfilesCallback, this); 500 setState(eStatsState_ReceivedLeaderboardInfo); 501 } 502 else 503 { 504 // we hit the end of the list 505 app.DebugPrintf("Reach the end\n"); 506 setState(eStatsState_Ready); 507 } 508 } 509 catch (Platform::Exception^ ex) 510 { 511 m_leaderboardAsyncOp = nullptr; 512 if (ex->HResult == INET_E_DATA_NOT_AVAILABLE) 513 { 514 // we hit the end of the list 515 app.DebugPrintf("ERROR: Reach the end\n"); 516 setState(eStatsState_Ready); 517 } 518 else if(ex->HResult == HTTP_E_STATUS_NOT_FOUND) 519 { 520 app.DebugPrintf("Error calling GetLeaderboardAsync function: 404 Not Found - 0x%0.8x\n", ex->HResult); 521 setState(eStatsState_Failed); 522 } 523 else 524 { 525 app.DebugPrintf("Error calling GetLeaderboardAsync function: 0x%0.8x\n", ex->HResult); 526 setState(eStatsState_Failed); 527 } 528 } 529 catch (...) 530 { 531 app.DebugPrintf("[LeaderboardManager] Unknown exception.\n"); 532 } 533 }); 534} 535 536void DurangoLeaderboardManager::updateStatsInfo(int userIndex, int difficulty, EStatsType type, WFC::IVectorView<MXS::UserStatistics::Statistic^>^ statsResult) 537{ 538 if (m_scores) 539 { 540 LeaderboardManager::ReadScore *userScore = &m_scores[userIndex]; 541 542 switch (type) 543 { 544 case eStatsType_Farming: userScore->m_statsSize = 6; break; 545 case eStatsType_Mining: userScore->m_statsSize = 7; break; 546 case eStatsType_Kills: userScore->m_statsSize = 7; break; 547 case eStatsType_Travelling: userScore->m_statsSize = 4; break; 548 } 549 550 int statIndex = 0, sumScores = 0; 551 for(wstring statName : m_leaderboardStatNames[difficulty][type]) 552 { 553 bool found = false; 554 for(auto result : statsResult) 555 { 556 if(statName.compare(result->StatisticName->Data()) == 0) 557 { 558 userScore->m_statsData[statIndex] = _fromString<unsigned long>(result->Value->Data()); 559 found = true; 560 break; 561 } 562 } 563 if(!found) 564 { 565 userScore->m_statsData[statIndex] = 0; 566 } 567 568 sumScores += userScore->m_statsData[statIndex]; 569 ++statIndex; 570 } 571 572 if ( (sumScores == 0) && (userScore->m_totalScore > 0) ) 573 { 574 app.DebugPrintf("[LeaderboardManager] Player '%s' (rank %d) likely has privacy settings enabled.\n", userScore->m_name.c_str(), userScore->m_rank); 575 userScore->m_idsErrorMessage = IDS_LEADERBOARD_SCORE_HIDDEN; 576 } 577 } 578} 579 580void DurangoLeaderboardManager::GetProfilesCallback(LPVOID param, std::vector<Microsoft::Xbox::Services::Social::XboxUserProfile^> profiles) 581{ 582 DurangoLeaderboardManager *dlm = (DurangoLeaderboardManager *)param; 583 584 app.DebugPrintf("[LeaderboardManager] GetProfilesCallback, profiles.size() == %d.\n", profiles.size()); 585 586 if (profiles.size() > 0) 587 { 588 dlm->m_displayNames = vector<wstring>(); 589 for (int i = 0; i < profiles.size(); i++) 590 { 591 dlm->m_displayNames.push_back(profiles[i]->GameDisplayName->Data()); 592 } 593 } 594 else 595 { 596 dlm->setState(eStatsState_Failed); 597 } 598 599 dlm->m_waitingForProfiles = false; 600} 601 602DurangoLeaderboardManager::EStatsState DurangoLeaderboardManager::getState() 603{ 604 return m_eStatsState; 605} 606 607void DurangoLeaderboardManager::setState(EStatsState newState) 608{ 609 EnterCriticalSection(&m_csStatsState); 610 611 bool validTransition = false; 612 613 switch(m_eStatsState) 614 { 615 case eStatsState_Idle: 616 switch(newState) 617 { 618 case eStatsState_GettingLeaderboardInfo: 619 validTransition = true; 620 break; 621 }; 622 break; 623 case eStatsState_GettingLeaderboardInfo: 624 switch(newState) 625 { 626 case eStatsState_Ready: 627 case eStatsState_ReceivedLeaderboardInfo: 628 case eStatsState_Canceled: 629 case eStatsState_Failed: 630 validTransition = true; 631 break; 632 }; 633 break; 634 break; 635 case eStatsState_ReceivedLeaderboardInfo: 636 switch(newState) 637 { 638 case eStatsState_GettingStatsInfo: 639 case eStatsState_Canceled: 640 case eStatsState_Failed: 641 validTransition = true; 642 break; 643 }; 644 break; 645 case eStatsState_GettingStatsInfo: 646 switch(newState) 647 { 648 case eStatsState_Ready: 649 case eStatsState_Canceled: 650 case eStatsState_Failed: 651 validTransition = true; 652 break; 653 }; 654 break; 655 case eStatsState_Failed: 656 switch(newState) 657 { 658 case eStatsState_Idle: 659 validTransition = true; 660 break; 661 }; 662 break; 663 case eStatsState_Ready: 664 switch(newState) 665 { 666 case eStatsState_Canceled: 667 case eStatsState_Idle: 668 case eStatsState_Failed: 669 validTransition = true; 670 break; 671 }; 672 break; 673 case eStatsState_Canceled: 674 switch(newState) 675 { 676 case eStatsState_Ready: 677 newState = eStatsState_Idle; 678 case eStatsState_Idle: 679 validTransition = true; 680 break; 681 }; 682 break; 683 }; 684 685#ifndef _CONTENT_PACKAGE 686 app.DebugPrintf( 687 "[LeaderboardManager] %s state transition:\t%ls(%d) -> %ls(%d).\n", 688 (validTransition ? "Valid" : "INVALID"), 689 stateToString(m_eStatsState).c_str(), m_eStatsState, 690 stateToString(newState).c_str(), newState 691 ); 692#endif 693 694 if (validTransition) 695 { 696 m_eStatsState = newState; 697 } 698 699 LeaveCriticalSection(&m_csStatsState); 700} 701 702wstring DurangoLeaderboardManager::stateToString(EStatsState eState) 703{ 704 switch (eState) 705 { 706 case eStatsState_Idle: return L"eStatsState_Idle"; 707 case eStatsState_GettingLeaderboardInfo: return L"eStatsState_GettingLeaderboardInfo"; 708 case eStatsState_ReceivedLeaderboardInfo: return L"eStatsState_ReceivedLeaderboardInfo"; 709 case eStatsState_GettingStatsInfo: return L"eStatsState_GettingStatsInfo"; 710 case eStatsState_ReceivedStatsInfo: return L"eStatsState_ReceivedStatsInfo"; 711 case eStatsState_Failed: return L"eStatsState_Failed"; 712 case eStatsState_Ready: return L"eStatsState_Ready"; 713 case eStatsState_Canceled: return L"eStatsState_Canceled"; 714 case eStatsState_Max: return L"eStatsState_MAX"; 715 default: return L"UNKNOWN"; 716 } 717}