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