the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 1131 lines 29 kB view raw
1#include "stdafx.h" 2 3#include <cstdlib> 4#include <np.h> 5//#include <sys/ppu_thread.h> 6 7#include "SonyLeaderboardManager.h" 8 9#include "base64.h" 10 11#include "Common\Consoles_App.h" 12#include "Common\Network\Sony\SQRNetworkManager.h" 13 14#include "..\..\..\Minecraft.World\StringHelpers.h" 15 16 17#ifdef __ORBIS__ 18#include "Orbis\OrbisExtras\ShutdownManager.h" 19#include "Orbis\Orbis_App.h" 20#elif defined __PSVITA__ 21#include "PSVita\PSVitaExtras\ShutdownManager.h" 22#include "PSVita\PSVita_App.h" 23#elif defined __PS3__ 24#include "PS3\PS3Extras\ShutdownManager.h" 25#include "PS3\PS3_App.h" 26#else 27#error "SonyLeaderboardManager is included for a non-sony platform." 28#endif 29 30SonyLeaderboardManager::SonyLeaderboardManager() 31{ 32 m_eStatsState = eStatsState_Idle; 33 34 m_titleContext = -1; 35 36 m_myXUID = INVALID_XUID; 37 38 m_scores = NULL; 39 40 m_statsType = eStatsType_Kills; 41 m_difficulty = 0; 42 43 m_requestId = 0; 44 45 m_openSessions = 0; 46 47 InitializeCriticalSection(&m_csViewsLock); 48 49 m_running = false; 50 m_threadScoreboard = NULL; 51} 52 53SonyLeaderboardManager::~SonyLeaderboardManager() 54{ 55 m_running = false; 56 57 // 4J-JEV: Wait for thread to stop and hope it doesn't take too long. 58 long long startShutdown = System::currentTimeMillis(); 59 while (m_threadScoreboard->isRunning()) 60 { 61 Sleep(1); 62 assert( (System::currentTimeMillis() - startShutdown) < 16 ); 63 } 64 65 delete m_threadScoreboard; 66 67 DeleteCriticalSection(&m_csViewsLock); 68} 69 70int SonyLeaderboardManager::scoreboardThreadEntry(LPVOID lpParam) 71{ 72 ShutdownManager::HasStarted(ShutdownManager::eLeaderboardThread); 73 SonyLeaderboardManager *self = reinterpret_cast<SonyLeaderboardManager *>(lpParam); 74 75 self->m_running = true; 76 app.DebugPrintf("[SonyLeaderboardManager] Thread started.\n"); 77 78 bool needsWriting = false; 79 do 80 { 81 if (self->m_openSessions > 0 || needsWriting) 82 { 83 self->scoreboardThreadInternal(); 84 } 85 86 EnterCriticalSection(&self->m_csViewsLock); 87 needsWriting = self->m_views.size() > 0; 88 LeaveCriticalSection(&self->m_csViewsLock); 89 90 // 4J Stu - We can't write while we aren't signed in to live 91 if (!ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad())) 92 { 93 needsWriting = false; 94 } 95 96 if ( (!needsWriting) && (self->m_eStatsState != eStatsState_Getting) ) 97 { 98 Sleep(50); // 4J-JEV: When we're not reading or writing. 99 } 100 101 } while ( (self->m_running || self->m_eStatsState == eStatsState_Getting || needsWriting) 102 && ShutdownManager::ShouldRun(ShutdownManager::eLeaderboardThread) 103 ); 104 105 // 4J-JEV, moved this here so setScore can finish up. 106 self->destroyTitleContext(self->m_titleContext); 107 108 // TODO sceNpScoreTerm(); 109 app.DebugPrintf("[SonyLeaderboardManager] Thread closed.\n"); 110 ShutdownManager::HasFinished(ShutdownManager::eLeaderboardThread); 111 return 0; 112} 113 114void SonyLeaderboardManager::scoreboardThreadInternal() 115{ 116 // 4J-JEV: Just initialise the context the once now. 117 if (m_titleContext == -1) 118 { 119 int primaryPad = ProfileManager.GetPrimaryPad(); 120 121 if (!ProfileManager.IsSignedInLive(primaryPad)) return; 122 123 int ret = initialiseScoreUtility(); 124 if (ret < 0) 125 { 126 if ( !scoreUtilityAlreadyInitialised(ret) ) 127 { 128 app.DebugPrintf("[SonyLeaderboardManager] initialiseScoreUtility() failed. ret = 0x%x\n", ret); 129 return; 130 } 131 else 132 { 133 app.DebugPrintf("[SonyLeaderboardManager] initialiseScoreUtility() already initialised, (0x%x)\n", ret); 134 } 135 } 136 137 SceNpId npId; 138 ProfileManager.GetSceNpId(primaryPad,&npId); 139 140 ret = createTitleContext(npId); 141 142 if (ret < 0) return; 143 else m_titleContext = ret; 144 } 145 else assert( m_titleContext > 0 ); //Paranoia 146 147 148 switch (m_eStatsState) 149 { 150 case eStatsState_Getting: 151 // Player starts using async multiplayer feature 152 // 4J-PB - Fix for SCEA FQA #4 - TRC R4064 - Incorrect usage of AsyncMultiplay 153 // Note 1: 154 // The following NP call should be reserved for asynchronous multiplayer modes that require PS Plus to be accessed. 155 // 156 // Note 2: 157 // The message is not displayed with a user without PlayStation�Plus subscription and they are able to access the Leaderboards. 158 159 // NotifyAsyncPlusFeature(); 160 161 switch(m_eFilterMode) 162 { 163 case eFM_MyScore: 164 case eFM_Friends: 165 getScoreByIds(); 166 break; 167 case eFM_TopRank: 168 getScoreByRange(); 169 break; 170 } 171 break; 172 173 case eStatsState_Canceled: 174 case eStatsState_Failed: 175 case eStatsState_Ready: 176 case eStatsState_Idle: 177 178 // 4J-JEV: Moved this here, I don't want reading and 179 // writing going on at the same time. 180 // -- 181 // 4J-JEV: Writing no longer changes the manager state, 182 // we'll manage the write queue seperately. 183 184 EnterCriticalSection(&m_csViewsLock); 185 bool hasWork = !m_views.empty(); 186 LeaveCriticalSection(&m_csViewsLock); 187 188 if (hasWork) 189 { 190 setScore(); 191 } 192 193 break; 194 } 195} 196 197HRESULT SonyLeaderboardManager::fillByIdsQuery(const SceNpId &myNpId, SceNpId* &npIds, uint32_t &len) 198{ 199 HRESULT ret; 200 201 // Get queried users. 202 switch(m_eFilterMode) 203 { 204 case eFM_Friends: 205 { 206 // 4J-JEV: Implementation for Orbis & Vita as they a very similar. 207#if (defined __ORBIS__) || (defined __PSVITA__) 208 209 sce::Toolkit::NP::Utilities::Future<sce::Toolkit::NP::FriendsList> s_friendList; 210 ret = getFriendsList(s_friendList); 211 212 if(ret != SCE_TOOLKIT_NP_SUCCESS) 213 { 214 // Error handling 215 if (m_eStatsState != eStatsState_Canceled) m_eStatsState = eStatsState_Failed; 216 app.DebugPrintf("[SonyLeaderboardManager] 'getFriendslist' fail, 0x%x.\n", ret); 217 return false; 218 } 219 else if (s_friendList.hasResult()) 220 { 221 // 4J-JEV: Friends list doesn't include player, leave space for them. 222 len = s_friendList.get()->size() + 1; 223 224 npIds = new SceNpId[len]; 225 226 int i = 0; 227 228 sce::Toolkit::NP::FriendsList::const_iterator itr; 229 for (itr = s_friendList.get()->begin(); itr != s_friendList.get()->end(); itr++) 230 { 231 npIds[i] = itr->npid; 232 i++; 233 } 234 235 npIds[len-1] = myNpId; // 4J-JEV: Append player to end of query. 236 } 237 else 238 { 239 // 4J-JEV: Something terrible must have happend, 240 // 'getFriendslist' was supposed to be a synchronous operation. 241 __debugbreak(); 242 243 // 4J-JEV: We can at least fall-back to just the players score. 244 len = 1; 245 npIds = new SceNpId[1]; 246 247 npIds[0] = myNpId; 248 } 249 250#elif (defined __PS3__) 251 // PS3 252 253 // 4J-JEV: Doesn't include the player (its just their friends). 254 ret = sceNpBasicGetFriendListEntryCount(&len); 255 len += 1; 256 257 npIds = new SceNpId[len]; 258 259 260 for (uint32_t i = 0; i < len-1; i++) 261 { 262 ret = sceNpBasicGetFriendListEntry(i, npIds+i); 263 if (ret<0) return ret; 264 265 } 266 npIds[len-1] = myNpId; // 4J-JEV: Append player to end of query. 267 268#endif 269 } 270 break; 271 case eFM_MyScore: 272 { 273 len = 1; 274 npIds = new SceNpId[1]; 275 npIds[0] = myNpId; 276 } 277 break; 278 } 279 280 return S_OK; 281} 282 283bool SonyLeaderboardManager::getScoreByIds() 284{ 285 if (m_eStatsState == eStatsState_Canceled) return false; 286 287 // ---------------------------- 288 SonyRtcTick last_sort_date; 289 SceNpScoreRankNumber mTotalRecord; 290 291 SceNpId *npIds = NULL; 292 293 int ret; 294 uint32_t num = 0; 295 296 SceNpScorePlayerRankData *ptr; 297 SceNpScoreComment *comments; 298 // ---------------------------- 299 300 // Check for invalid LManager state. 301 assert( m_eFilterMode == eFM_Friends 302 || m_eFilterMode == eFM_MyScore); 303 304 SceNpId myNpId; 305 // 4J-PB - should it be user 0? 306 if(!ProfileManager.IsSignedInLive(0)) 307 { 308 app.DebugPrintf("[SonyLeaderboardManager] OpenSession() fail: User isn't signed in to PSN\n"); 309 return false; 310 } 311 ProfileManager.GetSceNpId(0,&myNpId); 312 313 ret = fillByIdsQuery(myNpId, npIds, num); 314#ifdef __PS3__ 315 if (ret < 0) goto error2; 316#endif 317 318 ptr = new SceNpScorePlayerRankData[num]; 319 comments = new SceNpScoreComment[num]; 320 321 ZeroMemory(ptr, sizeof(SceNpScorePlayerRankData) * num); 322 ZeroMemory(comments, sizeof(SceNpScoreComment) * num); 323 324 /* app.DebugPrintf("sceNpScoreGetRankingByNpId(\n\t transaction=%i,\n\t boardID=0,\n\t npId=%i,\n\t friendCount*sizeof(SceNpId)=%i*%i=%i,\ 325 rankData=%i,\n\t friendCount*sizeof(SceNpScorePlayerRankData)=%i,\n\t NULL, 0, NULL, 0,\n\t friendCount=%i,\n...\n", 326 transaction, npId, friendCount, sizeof(SceNpId), friendCount*sizeof(SceNpId), 327 rankData, friendCount*sizeof(SceNpScorePlayerRankData), friendCount 328 ); */ 329 330 int boardId = getBoardId(m_difficulty, m_statsType); 331 332 // 4J-JEV: Orbis can only do with 100 ids max, so we use batches. 333#ifdef __ORBIS__ 334 for (int batch=0; batch<num; batch+=100) 335 { 336#endif 337 ret = createTransactionContext(m_titleContext); 338 if (m_eStatsState == eStatsState_Canceled) 339 { 340 // Cancel operation has been called, abort. 341 app.DebugPrintf("[SonyLeaderboardManager]\tgetScoreByIds() - m_eStatsState == eStatsState_Canceled.\n"); 342 343 destroyTransactionContext(ret); 344 345 if (npIds != NULL) delete [] npIds; 346 if (ptr != NULL) delete [] ptr; 347 if (comments != NULL) delete [] comments; 348 349 return false; 350 } 351 else if (ret < 0) 352 { 353 // Error occurred creating a transacion, abort. 354 app.DebugPrintf("[SonyLeaderboardManager]\tgetScoreByIds() - createTransaction failed, ret=0x%X\n", ret); 355 356 m_eStatsState = eStatsState_Failed; 357 358 if (npIds != NULL) delete [] npIds; 359 if (ptr != NULL) delete [] ptr; 360 if (comments != NULL) delete [] comments; 361 362 return false; 363 } 364 else 365 { 366 // Transaction created successfully, continue. 367 m_requestId = ret; 368 } 369 370#ifdef __ORBIS__ 371 int tmpNum = min( num - batch, (unsigned int) 100 ); 372 app.DebugPrintf("[SonyLeaderboardManager]\t Requesting ids %i-%i of %i.\n", batch, batch+tmpNum, num); 373#else 374 int tmpNum = num; 375#endif 376 ret = sceNpScoreGetRankingByNpId( 377 m_requestId, 378 boardId, // BoardId 379 380#ifdef __ORBIS__ 381 batch + npIds, sizeof(SceNpId) * tmpNum, //IN: Player IDs 382 batch + ptr, sizeof(SceNpScorePlayerRankData) * tmpNum, //OUT: Rank Data 383 batch + comments, sizeof(SceNpScoreComment) * tmpNum, //OUT: Comments 384#else 385 npIds, sizeof(SceNpId) * tmpNum, //IN: Player IDs 386 ptr, sizeof(SceNpScorePlayerRankData) * tmpNum, //OUT: Rank Data 387 comments, sizeof(SceNpScoreComment) * tmpNum, //OUT: Comments 388#endif 389 390 NULL, 0, // GameData. (unused) 391 392 tmpNum, 393 394 &last_sort_date, 395 &mTotalRecord, 396 397 NULL // Reserved, specify null. 398 ); 399 400 if (ret == SCE_NP_COMMUNITY_ERROR_ABORTED) 401 { 402 ret = destroyTransactionContext(m_requestId); 403 app.DebugPrintf("[SonyLeaderboardManager] getScoreByIds(): 'sceNpScoreGetRankingByRange' aborted (0x%X).\n", ret); 404 405 delete [] ptr; 406 delete [] comments; 407 delete [] npIds; 408 409 return false; 410 } 411 else if (ret == SCE_NP_COMMUNITY_SERVER_ERROR_GAME_RANKING_NOT_FOUND) 412 { 413 // 4J-JEV: Keep going, other batches might have scores. 414 } 415 else if (ret<0) goto error3; 416 417 // Return. 418 destroyTransactionContext(m_requestId); 419 m_requestId = 0; 420 421#ifdef __ORBIS__ 422 } 423#endif 424 425 m_readCount = num; 426 427 // Filter scorers and construct output structure. 428 if (m_scores != NULL) delete [] m_scores; 429 m_scores = new ReadScore[m_readCount]; 430 convertToOutput(m_readCount, m_scores, ptr, comments); 431 m_maxRank = m_readCount; 432 433 app.DebugPrintf( 434 "[SonyLeaderboardManager] getScoreByIds(), Success!\n" 435 "\t Board %i\n" 436 "\t %i of %i results have an entry\n" 437 "1stScore=%i\n", 438 boardId, 439 m_readCount, num, 440 ptr->rankData.scoreValue 441 ); 442 443 // Sort scores 444 std::sort(m_scores, m_scores + m_readCount, SortByRank); 445 446 delete [] ptr; 447 delete [] comments; 448 delete [] npIds; 449 450 m_eStatsState = eStatsState_Ready; 451 return true; 452 453 // Error. 454error3: 455 if (ret!=SCE_NP_COMMUNITY_ERROR_ABORTED) //0x8002a109 456 destroyTransactionContext(m_requestId); 457 m_requestId = 0; 458 delete [] ptr; 459 delete [] comments; 460error2: 461 if (npIds != NULL) delete [] npIds; 462error1: 463 if (m_eStatsState != eStatsState_Canceled) m_eStatsState = eStatsState_Failed; 464 app.DebugPrintf("[SonyLeaderboardManager] getScoreByIds() FAILED, ret=0x%X\n", ret); 465 return false; 466} 467 468bool SonyLeaderboardManager::getScoreByRange() 469{ 470 SonyRtcTick last_sort_date; 471 SceNpScoreRankNumber mTotalRecord; 472 473 unsigned int num = m_readCount; 474 SceNpScoreRankData *ptr; 475 SceNpScoreComment *comments; 476 477 assert(m_eFilterMode == eFM_TopRank); 478 479 int ret = createTransactionContext(m_titleContext); 480 if (m_eStatsState == eStatsState_Canceled) 481 { 482 // Cancel operation has been called, abort. 483 app.DebugPrintf("[SonyLeaderboardManager]\tgetScoreByRange() - m_eStatsState == eStatsState_Canceled.\n"); 484 destroyTransactionContext(ret); 485 return false; 486 } 487 else if (ret < 0) 488 { 489 // Error occurred creating a transaction, abort. 490 m_eStatsState = eStatsState_Failed; 491 app.DebugPrintf("[SonyLeaderboardManager]\tgetScoreByRange() - createTransaction failed, ret=0x%X\n", ret); 492 return false; 493 } 494 else 495 { 496 // Transaction created successfully, continue. 497 m_requestId = ret; 498 } 499 500 ptr = new SceNpScoreRankData[num]; 501 comments = new SceNpScoreComment[num]; 502 503 int boardId = getBoardId(m_difficulty, m_statsType); 504 ret = sceNpScoreGetRankingByRange( 505 m_requestId, 506 boardId, // BoardId 507 508 m_startIndex, 509 510 ptr, sizeof(SceNpScoreRankData) * num, //OUT: Rank Data 511 512 comments, sizeof(SceNpScoreComment) * num, //OUT: Comment Data 513 514 NULL, 0, // GameData. 515 516 num, 517 518 &last_sort_date, 519 &m_maxRank, // 'Total number of players registered in the target scoreboard.' 520 521 NULL // Reserved, specify null. 522 ); 523 524 if (ret == SCE_NP_COMMUNITY_ERROR_ABORTED) 525 { 526 ret = destroyTransactionContext(m_requestId); 527 app.DebugPrintf("[SonyLeaderboardManager] getScoreByRange(): 'sceNpScoreGetRankingByRange' aborted (0x%X).\n", ret); 528 529 delete [] ptr; 530 delete [] comments; 531 532 return false; 533 } 534 else if (ret == SCE_NP_COMMUNITY_SERVER_ERROR_GAME_RANKING_NOT_FOUND) 535 { 536 ret = destroyTransactionContext(m_requestId); 537 app.DebugPrintf("[SonyLeaderboardManager] getScoreByRange(): Game ranking not found."); 538 539 delete [] ptr; 540 delete [] comments; 541 542 m_scores = NULL; 543 m_readCount = 0; 544 545 m_eStatsState = eStatsState_Ready; 546 return false; 547 } 548 else if (ret<0) goto error2; 549 else 550 { 551 app.DebugPrintf("[SonyLeaderboardManager] getScoreByRange(), success, 1stScore=%i.\n", ptr->scoreValue); 552 } 553 554 // Return. 555 destroyTransactionContext(m_requestId); 556 m_requestId = 0; 557 558 //m_stats = ptr; //Maybe: addPadding(num,ptr); 559 560 if (m_scores != NULL) delete [] m_scores; 561 m_readCount = ret; 562 m_scores = new ReadScore[m_readCount]; 563 for (int i=0; i<m_readCount; i++) 564 { 565 //memcpy(m_scores+i, ptr+i, sizeof(SceNpScoreRankData)); 566 initReadScoreStruct(m_scores[i], ptr[i]); 567 //fromBase32(m_scores+i, comments+i); 568 fillReadScoreStruct(m_scores[i], comments[i]); 569 } 570 571 m_eStatsState = eStatsState_Ready; 572 return true; 573 574 // Error. 575error2: 576 if (ret!=SCE_NP_COMMUNITY_ERROR_ABORTED) //0x8002a109 577 destroyTransactionContext(m_requestId); 578 m_requestId = 0; 579 580 delete [] ptr; 581 delete [] comments; 582error1: 583 if (m_eStatsState != eStatsState_Canceled) m_eStatsState = eStatsState_Failed; 584 app.DebugPrintf("[SonyLeaderboardManager]\tgetScoreByRange() failed, ret=0x%X\n", ret); 585 return false; 586} 587 588bool SonyLeaderboardManager::setScore() 589{ 590 int ret; 591 SceNpId npId; 592 int32_t writeTitleContext = 0; 593 SceNpScoreRankNumber tmp = 0; 594 SceNpScoreComment comment; 595 596 // Get next job. 597 598 EnterCriticalSection(&m_csViewsLock); 599 RegisterScore rscore = m_views.front(); 600 m_views.pop(); 601 LeaveCriticalSection(&m_csViewsLock); 602 603 if ( ProfileManager.IsGuest(rscore.m_iPad) ) 604 { 605 app.DebugPrintf("[SonyLeaderboardManager] setScore(): m_iPad[%i] is guest.\n", rscore.m_iPad); 606 return true; 607 } 608 609 ProfileManager.GetSceNpId(rscore.m_iPad, &npId); 610 writeTitleContext = createTitleContext(npId); 611 if (writeTitleContext < 0) 612 { 613 app.DebugPrintf("[SonyLeaderboardManager] setScore(): sceNpScoreCreateTitleCtx FAILED, ret == %X.\n", ret); 614 return false; 615 } 616 617 ret = createTransactionContext(writeTitleContext); 618 619 // Start emptying queue if leaderboards has been closed. 620 if (ret == SCE_NP_COMMUNITY_ERROR_NOT_INITIALIZED) 621 { 622 EnterCriticalSection(&m_csViewsLock); 623 m_views.pop(); 624 LeaveCriticalSection(&m_csViewsLock); 625 } 626 627 // Error handling. 628 if (ret<0) 629 { 630 app.DebugPrintf("[SonyLeaderboardManager] setScore() FAILED, ret=0x%X\n", ret); 631 destroyTitleContext(writeTitleContext); 632 return false; 633 } 634 m_requestId = ret; 635 636 toBase32(&comment, (void *) &rscore.m_commentData); 637 638 int boardId = getBoardId(rscore.m_difficulty, rscore.m_commentData.m_statsType); 639 ret = sceNpScoreRecordScore( 640 m_requestId, // transId, 641 boardId, // boardId, 642 rscore.m_score, //IN: new score, 643 644 &comment, // Comments 645 NULL, // GameInfo 646 647 &tmp, //OUT: current rank, 648 649#ifndef __PS3__ 650 NULL, //compareDate 651#endif 652 653 NULL // Reserved, specify null. 654 ); 655 656 if (ret==SCE_NP_COMMUNITY_SERVER_ERROR_NOT_BEST_SCORE) //0x8002A415 657 { 658 app.DebugPrintf("[SonyLeaderboardManager] setScore(), doesn't beat current score, %i.\n", tmp); 659 } 660 else if (ret==SCE_NP_COMMUNITY_ERROR_ABORTED) 661 { 662 goto error1;//0x8002a109 663 } 664 else if (ret<0) 665 { 666 goto error2; 667 } 668 else 669 { 670 app.DebugPrintf("[SonyLeaderboardManager] setScore(), success. boardId=%i, score=%i\n", boardId, rscore.m_score); 671 } 672 673 // Return. 674 destroyTransactionContext(m_requestId); 675 m_requestId = 0; 676 //m_eStatsState = eStatsState_Idle; 677 return true; 678 679 // Error. 680error2: 681 destroyTransactionContext(m_requestId); 682 m_requestId = 0; 683 684error1: 685 app.DebugPrintf("[SonyLeaderboardManager] setScore() FAILED, ret=0x%X\n", ret); 686 destroyTitleContext(writeTitleContext); 687 return false; 688} 689 690void SonyLeaderboardManager::Tick() 691{ 692 ReadView view; 693 694 switch( m_eStatsState ) 695 { 696 case eStatsState_Ready: 697 { 698 assert(m_scores != NULL || m_readCount == 0); 699 700 view.m_numQueries = m_readCount; 701 view.m_queries = m_scores; 702 703 // 4J-JEV: Debugging. 704 //LeaderboardManager::printStats(view); 705 706 eStatsReturn ret = eStatsReturn_NoResults; 707 if (view.m_numQueries > 0) 708 ret = eStatsReturn_Success; 709 710 if (m_readListener != NULL) 711 { 712 app.DebugPrintf("[SonyLeaderboardManager] OnStatsReadComplete(%i, %i, _), m_readCount=%i.\n", ret, m_maxRank, m_readCount); 713 m_readListener->OnStatsReadComplete(ret, m_maxRank, view); 714 } 715 716 m_eStatsState = eStatsState_Idle; 717 718 delete [] m_scores; 719 m_scores = NULL; 720 } 721 break; 722 723 case eStatsState_Failed: 724 { 725 view.m_numQueries = 0; 726 view.m_queries = NULL; 727 728 if ( m_readListener != NULL ) 729 m_readListener->OnStatsReadComplete(eStatsReturn_NetworkError, 0, view); 730 731 m_eStatsState = eStatsState_Idle; 732 } 733 break; 734 735 case eStatsState_Canceled: 736 { 737 m_eStatsState = eStatsState_Idle; 738 } 739 break; 740 741 default: // Getting or Idle. 742 break; 743 } 744} 745 746bool SonyLeaderboardManager::OpenSession() 747{ 748 if (m_openSessions == 0) 749 { 750 if (m_threadScoreboard == NULL) 751 { 752 m_threadScoreboard = new C4JThread(&scoreboardThreadEntry, this, "4JScoreboard"); 753 m_threadScoreboard->SetProcessor(CPU_CORE_LEADERBOARDS); 754 m_threadScoreboard->SetPriority(THREAD_PRIORITY_BELOW_NORMAL); 755 m_threadScoreboard->Run(); 756 } 757 758 app.DebugPrintf("[SonyLeaderboardManager] OpenSession(): Starting sceNpScore utility.\n"); 759 } 760 else 761 { 762 app.DebugPrintf("[SonyLeaderboardManager] OpenSession(): Another session opened, total=%i\n", m_openSessions+1); 763 } 764 765 m_openSessions++; 766 return true; 767} 768 769void SonyLeaderboardManager::CloseSession() 770{ 771 m_openSessions--; 772 773 if (m_openSessions == 0) app.DebugPrintf("[SonyLeaderboardManager] CloseSession(): Quitting sceNpScore utility.\n"); 774 else app.DebugPrintf("[SonyLeaderboardManager] CloseSession(): %i sessions still open.\n", m_openSessions); 775} 776 777void SonyLeaderboardManager::DeleteSession() {} 778 779bool SonyLeaderboardManager::WriteStats(unsigned int viewCount, ViewIn views) 780{ 781 // Need to cancel read/write operation first. 782 //if (m_eStatsState != eStatsState_Idle) return false; 783 784 // Write relevant parameters. 785 //RegisterScore *regScore = reinterpret_cast<RegisterScore *>(views); 786 787 EnterCriticalSection(&m_csViewsLock); 788 for (int i=0; i<viewCount; i++) 789 { 790 app.DebugPrintf("[SonyLeaderboardManager] WriteStats(), starting. difficulty=%i, statsType=%i, score=%i\n", 791 views[i].m_difficulty, views[i].m_commentData.m_statsType, views[i].m_score); 792 793 m_views.push(views[i]); 794 } 795 LeaveCriticalSection(&m_csViewsLock); 796 797 delete [] views; //*regScore; 798 799 //m_eStatsState = eStatsState_Writing; 800 return true; 801} 802 803// myUID ignored on PS3. 804bool SonyLeaderboardManager::ReadStats_Friends(LeaderboardReadListener *listener, int difficulty, EStatsType type, PlayerUID myUID, unsigned int startIndex, unsigned int readCount) 805{ 806 // Need to cancel read/write operation first. 807 if (m_eStatsState != eStatsState_Idle) return false; 808 if (!LeaderboardManager::ReadStats_Friends(listener, difficulty, type, myUID, startIndex, readCount)) return false; 809 810 m_eStatsState = eStatsState_Getting; 811 return true; 812} 813 814// myUID ignored on PS3. 815bool SonyLeaderboardManager::ReadStats_MyScore(LeaderboardReadListener *listener, int difficulty, EStatsType type, PlayerUID myUID, unsigned int readCount) 816{ 817 // Need to cancel read/write operation first. 818 if (m_eStatsState != eStatsState_Idle) return false; 819 if (!LeaderboardManager::ReadStats_MyScore(listener, difficulty, type, myUID, readCount)) return false; 820 821 m_eStatsState = eStatsState_Getting; 822 return true; 823} 824 825// myUID ignored on PS3. 826bool SonyLeaderboardManager::ReadStats_TopRank(LeaderboardReadListener *listener, int difficulty, EStatsType type, unsigned int startIndex, unsigned int readCount) 827{ 828 // Need to cancel read/write operation first. 829 if (m_eStatsState != eStatsState_Idle) return false; 830 if (!LeaderboardManager::ReadStats_TopRank(listener, difficulty, type, startIndex, readCount)) return false; 831 832 m_eStatsState = eStatsState_Getting; 833 return true; 834} 835 836void SonyLeaderboardManager::FlushStats() {} 837 838void SonyLeaderboardManager::CancelOperation() 839{ 840 m_readListener = NULL; 841 m_eStatsState = eStatsState_Canceled; 842 843 if (m_requestId != 0) 844 { 845 int ret = abortTransactionContext(m_requestId); 846 if (ret < 0) app.DebugPrintf("[SonyLeaderboardManager] CancelOperation(): Problem encountered aborting current operation, 0x%X.\n", ret); 847 else app.DebugPrintf("[SonyLeaderboardManager] CancelOperation(): Operation aborted successfully.\n"); 848 } 849 else 850 { 851 app.DebugPrintf("[SonyLeaderboardManager] CancelOperation(): No current operation.\n"); 852 } 853} 854 855bool SonyLeaderboardManager::isIdle() 856{ 857 return m_eStatsState == eStatsState_Idle; 858} 859 860int SonyLeaderboardManager::getBoardId(int difficulty, EStatsType statsType) 861{ 862 switch (statsType) 863 { 864 case eStatsType_Travelling: 865 if (0 <= difficulty && difficulty < 4) return 1 + difficulty; // [1,2,3,4] 866 else return -1; 867 868 case eStatsType_Mining: 869 if (0 <= difficulty && difficulty < 4) return 5 + difficulty; // [5,6,7,8] 870 else return -1; 871 872 case eStatsType_Farming: 873 if (0 <= difficulty && difficulty < 4) return 9 + difficulty; // [9,10,11,12] 874 else return -1; 875 876 case eStatsType_Kills: 877 if (1 <= difficulty && difficulty < 4) return 13 + difficulty - 1; // [13,14,15,16] 878 else return -1; 879 880 default: return -1; 881 } 882} 883 884// 4J-JEV: Filter out all friends who don't have scores. 885/* 886SceNpScoreRankData *SonyLeaderboardManager::filterJustScorers(unsigned int &num, SceNpScorePlayerRankData *friendsData) 887{ 888int num2 = 0; 889for (int i=0; i<num; i++) if (friendsData[i].hasData) num2++; 890num = num2; num2 = 0; 891SceNpScoreRankData *out = new SceNpScoreRankData[num]; 892for (int i=0; i<num; i++) if (friendsData[i].hasData) out[num2++] = friendsData[i].rankData; 893return out; 894} */ 895 896// 4J-JEV: Unused, here if we want to switch LeaderboardManager::ViewOut to 'SceNpScorePlayerRankData'. 897SceNpScorePlayerRankData *SonyLeaderboardManager::addPadding(unsigned int num, SceNpScoreRankData *rankData) 898{ 899 SceNpScorePlayerRankData *out = new SceNpScorePlayerRankData[num]; 900 for (int i=0; i<num; i++) 901 { 902 out[i].hasData = true; 903 out[i].rankData = rankData[i]; 904 } 905 delete [] rankData; 906 return out; 907} 908 909// 4J-JEV: Filter and create output object. 910void SonyLeaderboardManager::convertToOutput(unsigned int &num, ReadScore *out, SceNpScorePlayerRankData *rankData, SceNpScoreComment *comm) 911{ 912 int j=0; 913 for (int i=0; i<num; i++) 914 { 915 if (rankData[i].hasData) 916 { 917 initReadScoreStruct( out[j], rankData[i].rankData ); 918 fillReadScoreStruct( out[j], comm[i] ); 919 920 j++; 921 } 922 } 923 924 num = j; 925} 926 927void SonyLeaderboardManager::toBinary(void *out, SceNpScoreComment *in) 928{ 929 string decoded = base64_decode( string((char*)in) ); 930 memcpy(out, decoded.c_str(), RECORD_SIZE); 931} 932 933void SonyLeaderboardManager::fromBinary(SceNpScoreComment **out, void *in) 934{ 935 *out = (SceNpScoreComment *) new unsigned char[SCE_NP_SCORE_COMMENT_MAXLEN + 1]; 936 string encoded = base64_encode((unsigned char const *) in, RECORD_SIZE); 937 memcpy(out, encoded.c_str(), SCE_NP_SCORE_COMMENT_MAXLEN); 938} 939 940void SonyLeaderboardManager::toBase32(SceNpScoreComment *out, void *in) 941{ 942 ZeroMemory(out,sizeof(SceNpScoreComment)); 943 PBYTE bytes = (PBYTE) in; 944 char *chars = getComment(out); 945 946 for (int i = 0; i < SCE_NP_SCORE_COMMENT_MAXLEN; i++) 947 { 948 int sByte = (i*5) / 8; 949 int eByte = (5+(i*5)) / 8; 950 int dIndex = (i*5) % 8; 951 952 unsigned char fivebits = 0; 953 954 fivebits = *(bytes+sByte) << dIndex; 955 956 if (eByte != sByte) 957 fivebits = fivebits | *(bytes+eByte) >> (8-dIndex); 958 959 fivebits = (fivebits>>3) & 0x1F; 960 961 if (fivebits < 10) // 0 - 9 962 chars[i] = '0' + fivebits; 963 else if (fivebits < 32) // A - V 964 chars[i] = 'A' + (fivebits-10); 965 else 966 assert(false); 967 } 968 969 toSymbols( getComment(out) ); 970} 971 972void SonyLeaderboardManager::fromBase32(void *out, SceNpScoreComment *in) 973{ 974 PBYTE bytes = (PBYTE) out; 975 ZeroMemory(bytes, RECORD_SIZE); 976 977 fromSymbols( getComment(in) ); 978 979 char ch[2] = { 0, 0 }; 980 for (int i = 0; i < SCE_NP_SCORE_COMMENT_MAXLEN; i++) 981 { 982 ch[0] = getComment(in)[i]; 983 unsigned char fivebits = strtol(ch, NULL, 32) << 3; 984 985 int sByte = (i*5) / 8; 986 int eByte = (5+(i*5)) / 8; 987 int dIndex = (i*5) % 8; 988 989 *(bytes + sByte) = *(bytes+sByte) | (fivebits >> dIndex); 990 991 if (eByte != sByte) 992 *(bytes + eByte) = fivebits << (8-dIndex); 993 } 994} 995 996char symbBase32[32] = { 997 ' ', '!','\"', '#', '$', '%', '&','\'', '(', ')', 998 '*', '+', '`', '-', '.', '/', ':', ';', '<', '=', 999 '>', '?', '[','\\', ']', '^', '_', '{', '|', '}', 1000 '~', '@' 1001}; 1002 1003char charBase32[32] = { 1004 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 1005 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 1006 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 1007 'U', 'V' 1008}; 1009 1010void SonyLeaderboardManager::toSymbols(char *str) 1011{ 1012 for (int i = 0; i < 63; i++) 1013 { 1014 for (int j=0; j < 32; j++) 1015 { 1016 if (str[i]==charBase32[j]) 1017 str[i] =symbBase32[j]; 1018 } 1019 } 1020} 1021 1022void SonyLeaderboardManager::fromSymbols(char *str) 1023{ 1024 for (int i = 0; i < 63; i++) 1025 { 1026 for (int j=0; j < 32; j++) 1027 { 1028 if (str[i]==symbBase32[j]) 1029 str[i] =charBase32[j]; 1030 } 1031 } 1032} 1033 1034bool SonyLeaderboardManager::test_string(string testing) 1035{ 1036#ifndef _CONTENT_PACKAGE 1037 static SceNpScoreComment comment; 1038 ZeroMemory(&comment, sizeof(SceNpScoreComment)); 1039 memcpy(&comment, testing.c_str(), SCE_NP_SCORE_COMMENT_MAXLEN); 1040 1041 int ctx = createTransactionContext(m_titleContext); 1042 if (ctx<0) return false; 1043 1044 int ret = sceNpScoreCensorComment(ctx, (const char *) &comment, NULL); 1045 1046 if (ret == SCE_NP_COMMUNITY_SERVER_ERROR_CENSORED) 1047 { 1048 app.DebugPrintf("\n[TEST_STRING]: REJECTED "); 1049 } 1050 else if (ret < 0) 1051 { 1052 destroyTransactionContext(ctx); 1053 return false; 1054 } 1055 else 1056 { 1057 app.DebugPrintf("\n[TEST_STRING]: permitted "); 1058 } 1059 1060 app.DebugPrintf("'%s'\n", getComment(&comment)); 1061 destroyTransactionContext(ctx); 1062 return true; 1063#else 1064 return true; 1065#endif 1066} 1067 1068void SonyLeaderboardManager::initReadScoreStruct(ReadScore &out, SceNpScoreRankData &rankData) 1069{ 1070 ZeroMemory(&out, sizeof(ReadScore)); 1071 1072 // Init rank and onlineID 1073 out.m_uid.setOnlineID( rankData.npId.handle, true ); 1074 out.m_rank = rankData.rank; 1075 1076 // Convert to wstring and copy name. 1077 wstring wstrName = convStringToWstring( string(rankData.npId.handle.data) ).c_str(); 1078 //memcpy(&out.m_name, wstrName.c_str(), XUSER_NAME_SIZE); 1079 out.m_name=wstrName; 1080} 1081 1082void SonyLeaderboardManager::fillReadScoreStruct(ReadScore &out, SceNpScoreComment &comment) 1083{ 1084 StatsData statsData; 1085 fromBase32( (void *) &statsData, &comment ); 1086 1087 switch (statsData.m_statsType) 1088 { 1089 case eStatsType_Farming: 1090 out.m_statsSize = 6; 1091 out.m_statsData[0] = statsData.m_farming.m_eggs; 1092 out.m_statsData[1] = statsData.m_farming.m_wheat; 1093 out.m_statsData[2] = statsData.m_farming.m_mushroom; 1094 out.m_statsData[3] = statsData.m_farming.m_sugarcane; 1095 out.m_statsData[4] = statsData.m_farming.m_milk; 1096 out.m_statsData[5] = statsData.m_farming.m_pumpkin; 1097 break; 1098 case eStatsType_Mining: 1099 out.m_statsSize = 7; 1100 out.m_statsData[0] = statsData.m_mining.m_dirt; 1101 out.m_statsData[1] = statsData.m_mining.m_cobblestone; 1102 out.m_statsData[2] = statsData.m_mining.m_sand; 1103 out.m_statsData[3] = statsData.m_mining.m_stone; 1104 out.m_statsData[4] = statsData.m_mining.m_gravel; 1105 out.m_statsData[5] = statsData.m_mining.m_clay; 1106 out.m_statsData[6] = statsData.m_mining.m_obsidian; 1107 break; 1108 case eStatsType_Kills: 1109 out.m_statsSize = 7; 1110 out.m_statsData[0] = statsData.m_kills.m_zombie; 1111 out.m_statsData[1] = statsData.m_kills.m_skeleton; 1112 out.m_statsData[2] = statsData.m_kills.m_creeper; 1113 out.m_statsData[3] = statsData.m_kills.m_spider; 1114 out.m_statsData[4] = statsData.m_kills.m_spiderJockey; 1115 out.m_statsData[5] = statsData.m_kills.m_zombiePigman; 1116 out.m_statsData[6] = statsData.m_kills.m_slime; 1117 break; 1118 case eStatsType_Travelling: 1119 out.m_statsSize = 4; 1120 out.m_statsData[0] = statsData.m_travelling.m_walked; 1121 out.m_statsData[1] = statsData.m_travelling.m_fallen; 1122 out.m_statsData[2] = statsData.m_travelling.m_minecart; 1123 out.m_statsData[3] = statsData.m_travelling.m_boat; 1124 break; 1125 } 1126} 1127 1128bool SonyLeaderboardManager::SortByRank(const ReadScore &lhs, const ReadScore &rhs) 1129{ 1130 return lhs.m_rank < rhs.m_rank; 1131}