aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.Client/PS3/Leaderboards
diff options
context:
space:
mode:
authordaoge_cmd <3523206925@qq.com>2026-03-01 12:16:08 +0800
committerdaoge_cmd <3523206925@qq.com>2026-03-01 12:16:08 +0800
commitb691c43c44ff180d10e7d4a9afc83b98551ff586 (patch)
tree3e9849222cbc6ba49f2f1fc6e5fe7179632c7390 /Minecraft.Client/PS3/Leaderboards
parentdef8cb415354ac390b7e89052a50605285f1aca9 (diff)
Initial commit
Diffstat (limited to 'Minecraft.Client/PS3/Leaderboards')
-rw-r--r--Minecraft.Client/PS3/Leaderboards/PS3LeaderboardManager.cpp1048
-rw-r--r--Minecraft.Client/PS3/Leaderboards/PS3LeaderboardManager.h110
-rw-r--r--Minecraft.Client/PS3/Leaderboards/base64.cpp131
-rw-r--r--Minecraft.Client/PS3/Leaderboards/base64.h7
4 files changed, 1296 insertions, 0 deletions
diff --git a/Minecraft.Client/PS3/Leaderboards/PS3LeaderboardManager.cpp b/Minecraft.Client/PS3/Leaderboards/PS3LeaderboardManager.cpp
new file mode 100644
index 00000000..38380bfb
--- /dev/null
+++ b/Minecraft.Client/PS3/Leaderboards/PS3LeaderboardManager.cpp
@@ -0,0 +1,1048 @@
+#include "stdafx.h"
+
+#include "PS3LeaderboardManager.h"
+
+#include "base64.h"
+
+#include "..\PS3_App.h"
+#include "..\..\Common\Consoles_App.h"
+
+#include "Common\Network\Sony\SQRNetworkManager.h"
+
+#include "..\..\..\Minecraft.World\StringHelpers.h"
+
+#include <cstdlib>
+
+#include <np.h>
+#include <sys/ppu_thread.h>
+
+#include "PS3\PS3Extras\ShutdownManager.h"
+
+#ifdef __PS3__
+LeaderboardManager *LeaderboardManager::m_instance = new PS3LeaderboardManager(); //Singleton instance of the LeaderboardManager
+#endif
+
+PS3LeaderboardManager::PS3LeaderboardManager()
+{
+ m_eStatsState = eStatsState_Idle;
+
+ m_titleContext = -1;
+
+ m_myXUID = INVALID_XUID;
+
+ m_scores = NULL; //m_stats = NULL;
+
+ m_statsType = eStatsType_Kills;
+ m_difficulty = 0;
+
+ m_transactionCtx = 0;
+
+ m_openSessions = 0;
+
+ InitializeCriticalSection(&m_csViewsLock);
+
+ m_running = false;
+ m_threadScoreboard = NULL;
+}
+
+PS3LeaderboardManager::~PS3LeaderboardManager()
+{
+ m_running = false;
+
+ // 4J-JEV: Wait for thread to stop and hope it doesn't take too long.
+ long long startShutdown = System::currentTimeMillis();
+ while (m_threadScoreboard->isRunning())
+ {
+ Sleep(1);
+ assert( (System::currentTimeMillis() - startShutdown) < 16 );
+ }
+
+ delete m_threadScoreboard;
+
+ DeleteCriticalSection(&m_csViewsLock);
+}
+
+int PS3LeaderboardManager::scoreboardThreadEntry(LPVOID lpParam)
+{
+ ShutdownManager::HasStarted(ShutdownManager::eLeaderboardThread);
+ PS3LeaderboardManager *self = reinterpret_cast<PS3LeaderboardManager *>(lpParam);
+
+ self->m_running = true;
+ app.DebugPrintf("[LeaderboardManager] Thread started.\n");
+
+ bool needsWriting = false;
+ do
+ {
+ if (self->m_openSessions > 0 || needsWriting)
+ {
+ self->scoreboardThreadInternal();
+ }
+
+ EnterCriticalSection(&self->m_csViewsLock);
+ needsWriting = self->m_views.size() > 0;
+ LeaveCriticalSection(&self->m_csViewsLock);
+
+ // 4J Stu - We can't write while we aren't signed in to live
+ if (!ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()))
+ {
+ needsWriting = false;
+ }
+
+ if ( (!needsWriting) && (self->m_eStatsState != eStatsState_Getting) )
+ {
+ Sleep(50); // 4J-JEV: When we're not reading or writing.
+ }
+
+ } while ( (self->m_running || self->m_eStatsState == eStatsState_Getting || needsWriting)
+ && ShutdownManager::ShouldRun(ShutdownManager::eLeaderboardThread)
+ );
+
+ // 4J-JEV, moved this here so setScore can finish up.
+ sceNpScoreDestroyTitleCtx(self->m_titleContext);
+ sceNpScoreTerm();
+ app.DebugPrintf("[LeaderboardManager] Thread closed.\n");
+ ShutdownManager::HasFinished(ShutdownManager::eLeaderboardThread);
+ return 0;
+}
+
+void PS3LeaderboardManager::scoreboardThreadInternal()
+{
+ // 4J-JEV: Just initialise the context the once now.
+ if (m_titleContext == -1)
+ {
+ //CD - Init NP Score
+ int ret = sceNpScoreInit();
+ if ( ret < 0 )
+ {
+ if ( ret != SCE_NP_COMMUNITY_ERROR_ALREADY_INITIALIZED )
+ {
+ app.DebugPrintf("[LeaderboardManager] sceNpScoreInit() failed. ret = 0x%x\n", ret);
+ return;
+ }
+ else
+ {
+ app.DebugPrintf("[LeaderboardManager] sceNpScoreInit() already initialised, (0x%x)\n", ret);
+ }
+ }
+
+
+ SceNpId npId;
+ ret = sceNpManagerGetNpId(&npId);
+ if (ret < 0)
+ {
+ app.DebugPrintf("[LeaderboardManager] OpenSession(): sceNpManagerGetNpId FAILED, ret == %X.\n", ret);
+ return;
+ }
+
+ ret = sceNpScoreCreateTitleCtx( &s_npCommunicationId, &s_npCommunicationPassphrase, &npId );
+
+ if (ret < 0)
+ {
+ app.DebugPrintf("[LeaderboardManager] OpenSession(): sceNpScoreCreateTitleCtx FAILED, ret == %X.\n", ret);
+ return;
+ }
+ else
+ {
+ m_titleContext = ret;
+ }
+ }
+ else assert( m_titleContext > 0 ); //Paranoia
+
+
+ switch (m_eStatsState)
+ {
+ case eStatsState_Getting:
+ switch(m_eFilterMode)
+ {
+ case eFM_MyScore:
+ case eFM_Friends:
+ getScoreByIds();
+ break;
+ case eFM_TopRank:
+ getScoreByRange();
+ break;
+ }
+ break;
+
+ case eStatsState_Canceled:
+ case eStatsState_Failed:
+ case eStatsState_Ready:
+ case eStatsState_Idle:
+
+ // 4J-JEV: Moved this here, I don't want reading and
+ // writing going on at the same time.
+ // --
+ // 4J-JEV: Writing no longer changes the manager state,
+ // we'll manage the write queue seperately.
+
+ EnterCriticalSection(&m_csViewsLock);
+ bool hasWork = !m_views.empty();
+ LeaveCriticalSection(&m_csViewsLock);
+
+ if (hasWork)
+ {
+ setScore();
+ }
+
+ break;
+ }
+}
+
+bool PS3LeaderboardManager::getScoreByIds()
+{
+ if (m_eStatsState == eStatsState_Canceled) return false;
+
+ // ----------------------------
+ CellRtcTick last_sort_date;
+ SceNpScoreRankNumber mTotalRecord;
+
+ SceNpId *npIds = NULL;
+
+
+ int ret;
+ uint32_t num = 0;
+
+ SceNpScorePlayerRankData *ptr;
+ SceNpScoreComment *comments;
+ // ----------------------------
+
+ // Check for invalid LManager state.
+ assert( m_eFilterMode == eFM_Friends
+ || m_eFilterMode == eFM_MyScore);
+
+ SceNpId myNpId;
+ ret = sceNpManagerGetNpId(&myNpId);
+ if (ret<0) goto error1;
+
+ // Get queried users.
+ if (m_eFilterMode == eFM_Friends)
+ {
+ // 4J-JEV: Doesn't include the player (its just their friends).
+ ret = sceNpBasicGetFriendListEntryCount(&num);
+ num += 1;
+
+ npIds = new SceNpId[num];
+
+ for (uint32_t i = 0; i < num-1; i++)
+ {
+ ret = sceNpBasicGetFriendListEntry(i, npIds+i);
+ if (ret<0) goto error2;
+
+ }
+ npIds[num-1] = myNpId; // 4J-JEV: Append player to end of query.
+ }
+ else if (m_eFilterMode == eFM_MyScore)
+ {
+ num = 1;
+ npIds = new SceNpId[1];
+ npIds[0] = myNpId;
+ }
+
+ ret = sceNpScoreCreateTransactionCtx(m_titleContext);
+ if (m_eStatsState == eStatsState_Canceled)
+ {
+ // Cancel operation has been called, abort.
+ app.DebugPrintf("[LeaderboardManager]\tgetScoreByIds() - m_eStatsState == eStatsState_Canceled.\n");
+
+ sceNpScoreDestroyTransactionCtx(ret);
+
+ if (npIds != NULL) delete [] npIds;
+ return false;
+ }
+ else if (ret < 0)
+ {
+ // Error occurred creating a transacion, abort.
+ app.DebugPrintf("[LeaderboardManager]\tgetScoreByIds() - createTransaction failed, ret=0x%X\n", ret);
+
+ m_eStatsState = eStatsState_Failed;
+
+ if (npIds != NULL) delete [] npIds;
+ return false;
+ }
+ else
+ {
+ // Transaction created successfully, continue.
+ m_transactionCtx = ret;
+ app.DebugPrintf("[LeaderboardManager] REQUEST ID A = 0x%X\n", m_transactionCtx);
+ }
+
+ ptr = new SceNpScorePlayerRankData[num];
+ comments = new SceNpScoreComment[num];
+
+ /* app.DebugPrintf("sceNpScoreGetRankingByNpId(\n\t transaction=%i,\n\t boardID=0,\n\t npId=%i,\n\t friendCount*sizeof(SceNpId)=%i*%i=%i,\
+ rankData=%i,\n\t friendCount*sizeof(SceNpScorePlayerRankData)=%i,\n\t NULL, 0, NULL, 0,\n\t friendCount=%i,\n...\n",
+ transaction, npId, friendCount, sizeof(SceNpId), friendCount*sizeof(SceNpId),
+ rankData, friendCount*sizeof(SceNpScorePlayerRankData), friendCount
+ ); */
+
+ int boardId = getBoardId(m_difficulty, m_statsType);
+ ret = sceNpScoreGetRankingByNpId(
+ m_transactionCtx,
+ boardId, // BoardId
+
+ npIds, sizeof(SceNpId) * num, //IN: Player IDs
+ ptr, sizeof(SceNpScorePlayerRankData) * num, //OUT: Rank Data
+
+ comments, sizeof(SceNpScoreComment) * num, //OUT: Comments
+
+ NULL, 0, // GameData. (unused)
+
+ num,
+
+ &last_sort_date,
+ &mTotalRecord,
+
+ NULL // Reserved, specify null.
+ );
+
+ if (ret == SCE_NP_COMMUNITY_ERROR_ABORTED)
+ {
+ app.DebugPrintf("[LeaderboardManager] getScoreByIds(): 'sceNpScoreGetRankingByRange' aborted (0x%X).\n", ret);
+
+ ret = sceNpScoreDestroyTransactionCtx(m_transactionCtx);
+ m_transactionCtx = 0;
+
+ delete [] ptr;
+ delete [] comments;
+ delete [] npIds;
+
+ return false;
+ }
+ else if (ret == SCE_NP_COMMUNITY_SERVER_ERROR_GAME_RANKING_NOT_FOUND)
+ {
+ app.DebugPrintf("[LeaderboardManager] getScoreByIds(): Game ranking not found.\n");
+
+ ret = sceNpScoreDestroyTransactionCtx(m_transactionCtx);
+ m_transactionCtx = 0;
+
+ delete [] ptr;
+ delete [] comments;
+ delete [] npIds;
+
+ m_scores = NULL;
+ m_readCount = 0;
+ m_maxRank = num;
+
+ m_eStatsState = eStatsState_Ready;
+ return false;
+ }
+ else if (ret<0) goto error3;
+
+ // Return.
+ sceNpScoreDestroyTransactionCtx(m_transactionCtx);
+ m_transactionCtx = 0;
+
+ m_readCount = num;
+
+ // Filter scorers and construct output structure.
+ if (m_scores != NULL) delete [] m_scores;
+ m_scores = new ReadScore[m_readCount];
+ convertToOutput(m_readCount, m_scores, ptr, comments);
+ m_maxRank = m_readCount;
+
+ app.DebugPrintf(
+ "[LeaderboardManager] getScoreByIds(), Success!\n"
+ "\t Board %i\n"
+ "\t %i of %i results have an entry\n"
+ "1stScore=%i\n",
+ boardId,
+ m_readCount, num,
+ ptr->rankData.scoreValue
+ );
+
+ // Sort scores
+ std::sort(m_scores, m_scores + m_readCount, SortByRank);
+
+ delete [] ptr;
+ delete [] comments;
+ delete [] npIds;
+
+ m_eStatsState = eStatsState_Ready;
+ return true;
+
+ // Error.
+error3:
+ if (ret!=SCE_NP_COMMUNITY_ERROR_ABORTED) //0x8002a109
+ sceNpScoreDestroyTransactionCtx(m_transactionCtx);
+ m_transactionCtx = 0;
+ delete [] ptr;
+ delete [] comments;
+error2:
+ if (npIds != NULL) delete [] npIds;
+error1:
+ if (m_eStatsState != eStatsState_Canceled) m_eStatsState = eStatsState_Failed;
+ app.DebugPrintf("[LeaderboardManger] getScoreByIds() FAILED, ret=0x%X\n", ret);
+ return false;
+}
+
+bool PS3LeaderboardManager::getScoreByRange()
+{
+ CellRtcTick last_sort_date;
+ SceNpScoreRankNumber mTotalRecord;
+
+ unsigned int num = m_readCount;
+ SceNpScoreRankData *ptr;
+ SceNpScoreComment *comments;
+
+ assert(m_eFilterMode == eFM_TopRank);
+
+ int ret = sceNpScoreCreateTransactionCtx(m_titleContext);
+ if (m_eStatsState == eStatsState_Canceled)
+ {
+ // Cancel operation has been called, abort.
+ app.DebugPrintf("[LeaderboardManager]\tgetScoreByRange() - m_eStatsState == eStatsState_Canceled.\n");
+ sceNpScoreDestroyTransactionCtx(ret);
+ return false;
+ }
+ else if (ret < 0)
+ {
+ // Error occurred creating a transacion, abort.
+ m_eStatsState = eStatsState_Failed;
+ app.DebugPrintf("[LeaderboardManager]\tgetScoreByRange() - createTransaction failed, ret=0x%X\n", ret);
+ return false;
+ }
+ else
+ {
+ // Transaction created successfully, continue.
+ m_transactionCtx = ret;
+ app.DebugPrintf("[LeaderboardManager] REQUEST ID B = 0x%X\n", m_transactionCtx );
+ }
+
+ ptr = new SceNpScoreRankData[num];
+ comments = new SceNpScoreComment[num];
+
+ int boardId = getBoardId(m_difficulty, m_statsType);
+ ret = sceNpScoreGetRankingByRange(
+ m_transactionCtx,
+ boardId, // BoardId
+
+ m_startIndex,
+
+ ptr, sizeof(SceNpScoreRankData) * num, //OUT: Rank Data
+
+ comments, sizeof(SceNpScoreComment) * num, //OUT: Comment Data
+
+ NULL, 0, // GameData.
+
+ num,
+
+ &last_sort_date,
+ &m_maxRank, // 'Total number of players registered in the target scoreboard.'
+
+ NULL // Reserved, specify null.
+ );
+
+ if (ret == SCE_NP_COMMUNITY_ERROR_ABORTED)
+ {
+ app.DebugPrintf("[LeaderboardManager] getScoreByRange(): 'sceNpScoreGetRankingByRange' aborted (0x%X).\n", ret);
+
+ ret = sceNpScoreDestroyTransactionCtx(m_transactionCtx);
+ m_transactionCtx = 0;
+
+ delete [] ptr;
+ delete [] comments;
+
+ return false;
+ }
+ else if (ret == SCE_NP_COMMUNITY_SERVER_ERROR_GAME_RANKING_NOT_FOUND)
+ {
+ app.DebugPrintf("[LeaderboardManager] getScoreByRange(): Game ranking not found.");
+
+ ret = sceNpScoreDestroyTransactionCtx(m_transactionCtx);
+ m_transactionCtx = 0;
+
+ delete [] ptr;
+ delete [] comments;
+
+ m_scores = NULL;
+ m_readCount = 0;
+
+ m_eStatsState = eStatsState_Ready;
+ return false;
+ }
+ else if (ret<0) goto error2;
+ else
+ {
+ app.DebugPrintf("[LeaderboardManager] getScoreByRange(), success, 1stScore=%i.\n", ptr->scoreValue);
+ }
+
+ // Return.
+ sceNpScoreDestroyTransactionCtx(m_transactionCtx);
+ m_transactionCtx = 0;
+
+ //m_stats = ptr; //Maybe: addPadding(num,ptr);
+
+ if (m_scores != NULL) delete [] m_scores;
+ m_readCount = ret;
+ m_scores = new ReadScore[m_readCount];
+ for (int i=0; i<m_readCount; i++)
+ {
+ //memcpy(m_scores+i, ptr+i, sizeof(SceNpScoreRankData));
+ initReadScoreStruct(m_scores[i], ptr[i]);
+ //fromBase32(m_scores+i, comments+i);
+ fillReadScoreStruct(m_scores[i], comments[i]);
+ }
+
+ m_eStatsState = eStatsState_Ready;
+ return true;
+
+ // Error.
+error2:
+ if (ret!=SCE_NP_COMMUNITY_ERROR_ABORTED) //0x8002a109
+ sceNpScoreDestroyTransactionCtx(m_transactionCtx);
+ m_transactionCtx = 0;
+
+ delete [] ptr;
+ delete [] comments;
+error1:
+ if (m_eStatsState != eStatsState_Canceled) m_eStatsState = eStatsState_Failed;
+ app.DebugPrintf("[LeaderboardManager]\tgetScoreByRange() failed, ret=0x%X\n", ret);
+ return false;
+}
+
+bool PS3LeaderboardManager::setScore()
+{
+ int ret;
+ SceNpId npId;
+ int32_t writeTitleContext = 0;
+ SceNpScoreRankNumber tmp = 0;
+ SceNpScoreComment comment;
+
+ // Get next job.
+
+ EnterCriticalSection(&m_csViewsLock);
+ RegisterScore rscore = m_views.front();
+ m_views.pop();
+ LeaveCriticalSection(&m_csViewsLock);
+
+ if ( ProfileManager.IsGuest(rscore.m_iPad) )
+ {
+ app.DebugPrintf("[LeaderboardManager] setScore(): m_iPad[%i] is guest.\n", rscore.m_iPad);
+ return true;
+ }
+
+ ProfileManager.GetSceNpId(rscore.m_iPad, &npId);
+ writeTitleContext = sceNpScoreCreateTitleCtx( &s_npCommunicationId, &s_npCommunicationPassphrase, &npId);
+ if (writeTitleContext < 0)
+ {
+ app.DebugPrintf("[LeaderboardManager] setScore(): sceNpScoreCreateTitleCtx FAILED, ret == %X.\n", ret);
+ return false;
+ }
+
+ ret = sceNpScoreCreateTransactionCtx(writeTitleContext);
+
+ // Start emptying queue if leaderboards has been closed.
+ if (ret == SCE_NP_COMMUNITY_ERROR_NOT_INITIALIZED)
+ {
+ EnterCriticalSection(&m_csViewsLock);
+ m_views.pop();
+ LeaveCriticalSection(&m_csViewsLock);
+ }
+
+ // Error handling.
+ if (ret<0)
+ {
+ app.DebugPrintf("[LeaderboardManager] setScore() FAILED, ret=0x%X\n", ret);
+ sceNpScoreDestroyTransactionCtx(writeTitleContext);
+ return false;
+ }
+ m_transactionCtx = ret;
+ app.DebugPrintf("[LeaderboardManager] REQUEST ID C = 0x%X\n", m_transactionCtx );
+
+ toBase32(&comment, (void *) &rscore.m_commentData);
+
+ int boardId = getBoardId(rscore.m_difficulty, rscore.m_commentData.m_statsType);
+ ret = sceNpScoreRecordScore(
+ m_transactionCtx, // transId,
+ boardId, // boardId,
+ rscore.m_score, //IN: new score,
+
+ &comment, // Comments
+ NULL, // GameInfo
+
+ &tmp, //OUT: current rank,
+
+ NULL // Reserved, specify null.
+ );
+
+ if (ret==SCE_NP_COMMUNITY_SERVER_ERROR_NOT_BEST_SCORE) //0x8002A415
+ {
+ app.DebugPrintf("[LeaderboardManager] setScore(), doesn't beat current score, %i.\n", tmp);
+ }
+ else if (ret==SCE_NP_COMMUNITY_ERROR_ABORTED) goto error1;//0x8002a109
+ else if (ret<0) goto error2;
+ else
+ {
+ app.DebugPrintf("[LeaderboardManager] setScore(), success. boardId=%i, score=%i\n", boardId, rscore.m_score);
+ }
+
+ // Return.
+ sceNpScoreDestroyTransactionCtx(m_transactionCtx);
+ m_transactionCtx = 0;
+ //m_eStatsState = eStatsState_Idle;
+ return true;
+
+ // Error.
+error2:
+ sceNpScoreDestroyTransactionCtx(m_transactionCtx);
+ m_transactionCtx = 0;
+error1:
+ app.DebugPrintf("[LeaderboardManager] setScore() FAILED, ret=0x%X\n", ret);
+ sceNpScoreDestroyTitleCtx(writeTitleContext);
+ return false;
+}
+
+void PS3LeaderboardManager::Tick()
+{
+ ReadView view;
+
+ switch( m_eStatsState )
+ {
+ case eStatsState_Ready:
+ {
+ assert(m_scores != NULL || m_readCount == 0);
+
+ view.m_numQueries = m_readCount;
+ view.m_queries = m_scores;
+
+ // 4J-JEV: Debugging.
+ //LeaderboardManager::printStats(view);
+
+ eStatsReturn ret = eStatsReturn_NoResults;
+ if (view.m_numQueries > 0)
+ ret = eStatsReturn_Success;
+
+ if (m_readListener != NULL)
+ {
+ app.DebugPrintf("[LeaderboardManager] OnStatsReadComplete(%i, %i, _), m_readCount=%i.\n", ret, m_maxRank, m_readCount);
+ m_readListener->OnStatsReadComplete(ret, m_maxRank, view);
+ }
+
+ m_eStatsState = eStatsState_Idle;
+
+ delete [] m_scores;
+ m_scores = NULL;
+ }
+ break;
+
+ case eStatsState_Failed:
+ {
+ view.m_numQueries = 0;
+ view.m_queries = NULL;
+
+ if ( m_readListener != NULL )
+ m_readListener->OnStatsReadComplete(eStatsReturn_NetworkError, 0, view);
+
+ m_eStatsState = eStatsState_Idle;
+ }
+ break;
+
+ case eStatsState_Canceled:
+ {
+ m_eStatsState = eStatsState_Idle;
+ }
+ break;
+
+ default: // Getting or Idle.
+ break;
+ }
+}
+
+bool PS3LeaderboardManager::OpenSession()
+{
+ if (m_openSessions == 0)
+ {
+ if (m_threadScoreboard == NULL)
+ {
+ m_threadScoreboard = new C4JThread(&scoreboardThreadEntry, this, "4JScoreboard");
+ m_threadScoreboard->SetProcessor(CPU_CORE_LEADERBOARDS);
+ m_threadScoreboard->SetPriority(THREAD_PRIORITY_BELOW_NORMAL);
+ m_threadScoreboard->Run();
+ }
+
+ app.DebugPrintf("[LeaderboardManager] OpenSession(): Starting sceNpScore utility.\n");
+ }
+ else
+ {
+ app.DebugPrintf("[LeaderboardManager] OpenSession(): Another session opened, total=%i\n", m_openSessions+1);
+ }
+
+ m_openSessions++;
+ return true;
+}
+
+void PS3LeaderboardManager::CloseSession()
+{
+ m_openSessions--;
+
+ if (m_openSessions == 0) app.DebugPrintf("[LeaderboardManager] CloseSession(): Quitting sceNpScore utility.\n");
+ else app.DebugPrintf("[LeaderboardManager] CloseSession(): %i sessions still open.\n", m_openSessions);
+}
+
+void PS3LeaderboardManager::DeleteSession() {}
+
+bool PS3LeaderboardManager::WriteStats(unsigned int viewCount, ViewIn views)
+{
+ // Need to cancel read/write operation first.
+ //if (m_eStatsState != eStatsState_Idle) return false;
+
+ // Write relevant parameters.
+ //RegisterScore *regScore = reinterpret_cast<RegisterScore *>(views);
+
+ EnterCriticalSection(&m_csViewsLock);
+ for (int i=0; i<viewCount; i++)
+ {
+ app.DebugPrintf("[LeaderboardManager] WriteStats(), starting. difficulty=%i, statsType=%i, score=%i\n",
+ views[i].m_difficulty, views[i].m_commentData.m_statsType, views[i].m_score);
+
+ m_views.push(views[i]);
+ }
+ LeaveCriticalSection(&m_csViewsLock);
+
+ delete [] views; //*regScore;
+
+ //m_eStatsState = eStatsState_Writing;
+ return true;
+}
+
+// myUID ignored on PS3.
+bool PS3LeaderboardManager::ReadStats_Friends(LeaderboardReadListener *listener, int difficulty, EStatsType type, PlayerUID myUID, unsigned int startIndex, unsigned int readCount)
+{
+ // Need to cancel read/write operation first.
+ if (m_eStatsState != eStatsState_Idle) return false;
+ if (!LeaderboardManager::ReadStats_Friends(listener, difficulty, type, myUID, startIndex, readCount)) return false;
+
+ //int ret = sceNpManagerGetNpId(&m_myNpId);
+ //if (ret<0) return false;
+
+ m_eStatsState = eStatsState_Getting;
+ return true;
+}
+
+// myUID ignored on PS3.
+bool PS3LeaderboardManager::ReadStats_MyScore(LeaderboardReadListener *listener, int difficulty, EStatsType type, PlayerUID myUID, unsigned int readCount)
+{
+ // Need to cancel read/write operation first.
+ if (m_eStatsState != eStatsState_Idle) return false;
+ if (!LeaderboardManager::ReadStats_MyScore(listener, difficulty, type, myUID, readCount)) return false;
+
+ //int ret = sceNpManagerGetNpId(&m_myNpId);
+ //if (ret<0) return false;
+
+ m_eStatsState = eStatsState_Getting;
+ return true;
+}
+
+// myUID ignored on PS3.
+bool PS3LeaderboardManager::ReadStats_TopRank(LeaderboardReadListener *listener, int difficulty, EStatsType type, unsigned int startIndex, unsigned int readCount)
+{
+ // Need to cancel read/write operation first.
+ if (m_eStatsState != eStatsState_Idle) return false;
+ if (!LeaderboardManager::ReadStats_TopRank(listener, difficulty, type, startIndex, readCount)) return false;
+ m_eStatsState = eStatsState_Getting;
+ return true;
+}
+
+void PS3LeaderboardManager::FlushStats() {}
+
+void PS3LeaderboardManager::CancelOperation()
+{
+ m_readListener = NULL;
+ m_eStatsState = eStatsState_Canceled;
+
+ if (m_transactionCtx != 0)
+ {
+ int ret = sceNpScoreAbortTransaction(m_transactionCtx);
+
+ if (ret < 0)
+ {
+ app.DebugPrintf("[LeaderboardManager] CancelOperation(): Problem encountered aborting current operation, 0x%X.\n", ret);
+ }
+ else
+ {
+ app.DebugPrintf("[LeaderboardManager] CancelOperation(): Operation aborted successfully.\n");
+ }
+ }
+ else
+ {
+ app.DebugPrintf("[LeaderboardManager] CancelOperation(): No current operation.\n");
+ }
+}
+
+bool PS3LeaderboardManager::isIdle()
+{
+ return m_eStatsState == eStatsState_Idle;
+}
+
+int PS3LeaderboardManager::getBoardId(int difficulty, EStatsType statsType)
+{
+ switch (statsType)
+ {
+ case eStatsType_Travelling:
+ if (0 <= difficulty && difficulty < 4) return 1 + difficulty; // [1,2,3,4]
+ else return -1;
+
+ case eStatsType_Mining:
+ if (0 <= difficulty && difficulty < 4) return 5 + difficulty; // [5,6,7,8]
+ else return -1;
+
+ case eStatsType_Farming:
+ if (0 <= difficulty && difficulty < 4) return 9 + difficulty; // [9,10,11,12]
+ else return -1;
+
+ case eStatsType_Kills:
+ if (1 <= difficulty && difficulty < 4) return 13 + difficulty - 1; // [13,14,15,16]
+ else return -1;
+
+ default: return -1;
+ }
+}
+
+// 4J-JEV: Filter out all friends who don't have scores.
+/*
+SceNpScoreRankData *PS3LeaderboardManager::filterJustScorers(unsigned int &num, SceNpScorePlayerRankData *friendsData)
+{
+ int num2 = 0;
+ for (int i=0; i<num; i++) if (friendsData[i].hasData) num2++;
+ num = num2; num2 = 0;
+ SceNpScoreRankData *out = new SceNpScoreRankData[num];
+ for (int i=0; i<num; i++) if (friendsData[i].hasData) out[num2++] = friendsData[i].rankData;
+ return out;
+} */
+
+// 4J-JEV: Unused, here if we want to switch LeaderboardManager::ViewOut to 'SceNpScorePlayerRankData'.
+SceNpScorePlayerRankData *PS3LeaderboardManager::addPadding(unsigned int num, SceNpScoreRankData *rankData)
+{
+ SceNpScorePlayerRankData *out = new SceNpScorePlayerRankData[num];
+ for (int i=0; i<num; i++)
+ {
+ out[i].hasData = true;
+ out[i].rankData = rankData[i];
+ }
+ delete [] rankData;
+ return out;
+}
+
+// 4J-JEV: Filter and create output object.
+void PS3LeaderboardManager::convertToOutput(unsigned int &num, ReadScore *out, SceNpScorePlayerRankData *rankData, SceNpScoreComment *comm)
+{
+ int j=0;
+ for (int i=0; i<num; i++)
+ {
+ if (rankData[i].hasData)
+ {
+ initReadScoreStruct( out[j], rankData[i].rankData );
+ fillReadScoreStruct( out[j], comm[i] );
+
+ j++;
+ }
+ }
+
+ num = j;
+}
+
+void PS3LeaderboardManager::toBinary(void *out, SceNpScoreComment *in)
+{
+ string decoded = base64_decode( string((char*)in) );
+ memcpy(out, decoded.c_str(), RECORD_SIZE);
+}
+
+void PS3LeaderboardManager::fromBinary(SceNpScoreComment **out, void *in)
+{
+ *out = (SceNpScoreComment *) new unsigned char[SCE_NP_SCORE_COMMENT_MAXLEN + 1];
+ string encoded = base64_encode((unsigned char const *) in, RECORD_SIZE);
+ memcpy(out, encoded.c_str(), SCE_NP_SCORE_COMMENT_MAXLEN);
+}
+
+void PS3LeaderboardManager::toBase32(SceNpScoreComment *out, void *in)
+{
+ ZeroMemory(out,sizeof(SceNpScoreComment));
+ PBYTE bytes = (PBYTE) in;
+ char *chars = out->data;
+
+ for (int i = 0; i < SCE_NP_SCORE_COMMENT_MAXLEN; i++)
+ {
+ int sByte = (i*5) / 8;
+ int eByte = (5+(i*5)) / 8;
+ int dIndex = (i*5) % 8;
+
+ unsigned char fivebits = 0;
+
+ fivebits = *(bytes+sByte) << dIndex;
+
+ if (eByte != sByte)
+ fivebits = fivebits | *(bytes+eByte) >> (8-dIndex);
+
+ fivebits = (fivebits>>3) & 0x1F;
+
+ if (fivebits < 10) // 0 - 9
+ chars[i] = '0' + fivebits;
+ else if (fivebits < 32) // A - V
+ chars[i] = 'A' + (fivebits-10);
+ else
+ assert(false);
+ }
+
+ toSymbols(out->data);
+}
+
+void PS3LeaderboardManager::fromBase32(void *out, SceNpScoreComment *in)
+{
+ PBYTE bytes = (PBYTE) out;
+ ZeroMemory(bytes, RECORD_SIZE);
+
+ fromSymbols(in->data);
+
+ char ch[2] = { 0, 0 };
+ for (int i = 0; i < SCE_NP_SCORE_COMMENT_MAXLEN; i++)
+ {
+ ch[0] = in->data[i];
+ unsigned char fivebits = strtol(ch, NULL, 32) << 3;
+
+ int sByte = (i*5) / 8;
+ int eByte = (5+(i*5)) / 8;
+ int dIndex = (i*5) % 8;
+
+ *(bytes + sByte) = *(bytes+sByte) | (fivebits >> dIndex);
+
+ if (eByte != sByte)
+ *(bytes + eByte) = fivebits << (8-dIndex);
+ }
+}
+
+char symbBase32[32] = {
+ ' ', '!','\"', '#', '$', '%', '&','\'', '(', ')',
+ '*', '+', '`', '-', '.', '/', ':', ';', '<', '=',
+ '>', '?', '[','\\', ']', '^', '_', '{', '|', '}',
+ '~', '@'
+};
+
+char charBase32[32] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+ 'U', 'V'
+};
+
+void PS3LeaderboardManager::toSymbols(char *str)
+{
+ for (int i = 0; i < 63; i++)
+ {
+ for (int j=0; j < 32; j++)
+ {
+ if (str[i]==charBase32[j])
+ str[i] =symbBase32[j];
+ }
+ }
+}
+
+void PS3LeaderboardManager::fromSymbols(char *str)
+{
+ for (int i = 0; i < 63; i++)
+ {
+ for (int j=0; j < 32; j++)
+ {
+ if (str[i]==symbBase32[j])
+ str[i] =charBase32[j];
+ }
+ }
+}
+
+bool PS3LeaderboardManager::test_string(string testing)
+{
+#ifndef _CONTENT_PACKAGE
+ static SceNpScoreComment comment;
+ ZeroMemory(&comment, sizeof(SceNpScoreComment));
+ memcpy(&comment, testing.c_str(), SCE_NP_SCORE_COMMENT_MAXLEN);
+
+ int ctx = sceNpScoreCreateTransactionCtx(m_titleContext);
+ if (ctx<0) return false;
+
+ int ret = sceNpScoreCensorComment(ctx, (const void *) &comment, NULL);
+
+ if (ret == SCE_NP_COMMUNITY_SERVER_ERROR_CENSORED)
+ {
+ //app.DebugPrintf("\n[TEST_STRING]: REJECTED ");
+ }
+ else if (ret < 0)
+ {
+ sceNpScoreDestroyTransactionCtx(ctx);
+ return false;
+ }
+ else
+ {
+ //app.DebugPrintf("\n[TEST_STRING]: permitted ");
+ }
+
+ //app.DebugPrintf("'%s'\n", comment.data);
+ sceNpScoreDestroyTransactionCtx(ctx);
+ return true;
+#else
+ return true;
+#endif
+}
+
+void PS3LeaderboardManager::initReadScoreStruct(ReadScore &out, SceNpScoreRankData &rankData)
+{
+ ZeroMemory(&out, sizeof(ReadScore));
+
+ // Init rank and onlineID
+ out.m_uid.setOnlineID( rankData.npId.handle, true );
+ out.m_rank = rankData.rank;
+
+ // Convert to wstring and copy name.
+ wstring wstrName = convStringToWstring( string(rankData.onlineName.data) ).c_str();
+ //memcpy(&out.m_name, wstrName.c_str(), XUSER_NAME_SIZE);
+ out.m_name=wstrName;
+}
+
+void PS3LeaderboardManager::fillReadScoreStruct(ReadScore &out, SceNpScoreComment &comment)
+{
+ StatsData statsData;
+ fromBase32( (void *) &statsData, &comment );
+
+ switch (statsData.m_statsType)
+ {
+ case eStatsType_Farming:
+ out.m_statsSize = 6;
+ out.m_statsData[0] = statsData.m_farming.m_eggs;
+ out.m_statsData[1] = statsData.m_farming.m_wheat;
+ out.m_statsData[2] = statsData.m_farming.m_mushroom;
+ out.m_statsData[3] = statsData.m_farming.m_sugarcane;
+ out.m_statsData[4] = statsData.m_farming.m_milk;
+ out.m_statsData[5] = statsData.m_farming.m_pumpkin;
+ break;
+ case eStatsType_Mining:
+ out.m_statsSize = 7;
+ out.m_statsData[0] = statsData.m_mining.m_dirt;
+ out.m_statsData[1] = statsData.m_mining.m_cobblestone;
+ out.m_statsData[2] = statsData.m_mining.m_sand;
+ out.m_statsData[3] = statsData.m_mining.m_stone;
+ out.m_statsData[4] = statsData.m_mining.m_gravel;
+ out.m_statsData[5] = statsData.m_mining.m_clay;
+ out.m_statsData[6] = statsData.m_mining.m_obsidian;
+ break;
+ case eStatsType_Kills:
+ out.m_statsSize = 7;
+ out.m_statsData[0] = statsData.m_kills.m_zombie;
+ out.m_statsData[1] = statsData.m_kills.m_skeleton;
+ out.m_statsData[2] = statsData.m_kills.m_creeper;
+ out.m_statsData[3] = statsData.m_kills.m_spider;
+ out.m_statsData[4] = statsData.m_kills.m_spiderJockey;
+ out.m_statsData[5] = statsData.m_kills.m_zombiePigman;
+ out.m_statsData[6] = statsData.m_kills.m_slime;
+ break;
+ case eStatsType_Travelling:
+ out.m_statsSize = 4;
+ out.m_statsData[0] = statsData.m_travelling.m_walked;
+ out.m_statsData[1] = statsData.m_travelling.m_fallen;
+ out.m_statsData[2] = statsData.m_travelling.m_minecart;
+ out.m_statsData[3] = statsData.m_travelling.m_boat;
+ break;
+ }
+}
+
+bool PS3LeaderboardManager::SortByRank(const ReadScore &lhs, const ReadScore &rhs)
+{
+ return lhs.m_rank < rhs.m_rank;
+} \ No newline at end of file
diff --git a/Minecraft.Client/PS3/Leaderboards/PS3LeaderboardManager.h b/Minecraft.Client/PS3/Leaderboards/PS3LeaderboardManager.h
new file mode 100644
index 00000000..7a85896d
--- /dev/null
+++ b/Minecraft.Client/PS3/Leaderboards/PS3LeaderboardManager.h
@@ -0,0 +1,110 @@
+#pragma once
+
+#include "..\..\Common\Leaderboards\LeaderboardManager.h"
+#include "..\..\..\Minecraft.World\x64headers\extraX64.h"
+
+#include "PS3\Passphrase\ps3__np_conf.h"
+
+using namespace std;
+
+class PS3LeaderboardManager : public LeaderboardManager
+{
+protected:
+ enum EStatsState
+ {
+ eStatsState_Idle,
+ eStatsState_Getting,
+ eStatsState_Failed,
+ eStatsState_Ready,
+ eStatsState_Canceled,
+ //eStatsState_Writing,
+ eStatsState_Max
+ };
+
+public:
+ PS3LeaderboardManager();
+ virtual ~PS3LeaderboardManager();
+
+private:
+ unsigned short m_openSessions;
+
+ C4JThread *m_threadScoreboard;
+ bool m_running;
+
+ int32_t m_titleContext;
+ int m_transactionCtx;
+
+ //SceNpId m_myNpId;
+
+ static int scoreboardThreadEntry(LPVOID lpParam);
+ void scoreboardThreadInternal();
+
+ bool getScoreByIds();
+ bool getScoreByRange();
+
+ bool setScore();
+ queue<RegisterScore> m_views;
+
+ CRITICAL_SECTION m_csViewsLock;
+
+ EStatsState m_eStatsState; //State of the stats read
+// EFilterMode m_eFilterMode;
+
+ ReadScore *m_scores;
+ unsigned int m_maxRank;
+ //SceNpScoreRankData *m_stats;
+
+public:
+ virtual void Tick();
+
+ //Open a session
+ virtual bool OpenSession();
+
+ //Close a session
+ virtual void CloseSession();
+
+ //Delete a session
+ virtual void DeleteSession();
+
+ //Write the given stats
+ //This is called synchronously and will not free any memory allocated for views when it is done
+ virtual bool WriteStats(unsigned int viewCount, ViewIn views);
+
+ virtual bool ReadStats_Friends(LeaderboardReadListener *listener, int difficulty, EStatsType type, PlayerUID myUID, unsigned int startIndex, unsigned int readCount);
+ virtual bool ReadStats_MyScore(LeaderboardReadListener *listener, int difficulty, EStatsType type, PlayerUID myUID, unsigned int readCount);
+ virtual bool ReadStats_TopRank(LeaderboardReadListener *listener, int difficulty, EStatsType type, unsigned int startIndex, unsigned int readCount);
+
+ //Perform a flush of the stats
+ virtual void FlushStats();
+
+ //Cancel the current operation
+ virtual void CancelOperation();
+
+ //Is the leaderboard manager idle.
+ virtual bool isIdle();
+
+private:
+ int getBoardId(int difficulty, EStatsType);
+
+ //LeaderboardManager::ReadScore *filterJustScorers(unsigned int &num, LeaderboardManager::ReadScore *friendsData);
+
+ SceNpScorePlayerRankData *addPadding(unsigned int num, SceNpScoreRankData *rankData);
+
+ void convertToOutput(unsigned int &num, ReadScore *out, SceNpScorePlayerRankData *rankData, SceNpScoreComment *comm);
+
+ void toBinary(void *out, SceNpScoreComment *in);
+ void fromBinary(SceNpScoreComment **out, void *in);
+
+ void toBase32(SceNpScoreComment *out, void *in);
+ void fromBase32(void *out, SceNpScoreComment *in);
+
+ void toSymbols(char *);
+ void fromSymbols(char *);
+
+ bool test_string(string);
+
+ void initReadScoreStruct(ReadScore &out, SceNpScoreRankData &);
+ void fillReadScoreStruct(ReadScore &out, SceNpScoreComment &comment);
+
+ static bool SortByRank(const ReadScore &lhs, const ReadScore &rhs);
+};
diff --git a/Minecraft.Client/PS3/Leaderboards/base64.cpp b/Minecraft.Client/PS3/Leaderboards/base64.cpp
new file mode 100644
index 00000000..19106cc4
--- /dev/null
+++ b/Minecraft.Client/PS3/Leaderboards/base64.cpp
@@ -0,0 +1,131 @@
+/*
+ base64.cpp and base64.h
+
+ Copyright (C) 2004-2008 René Nyffenegger
+
+ This source code is provided 'as-is', without any express or implied
+ warranty. In no event will the author be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this source code must not be misrepresented; you must not
+ claim that you wrote the original source code. If you use this source code
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original source code.
+
+ 3. This notice may not be removed or altered from any source distribution.
+
+ René Nyffenegger rene.nyffenegger@adp-gmbh.ch
+
+*/
+
+#include "stdafx.h"
+
+#include "base64.h"
+#include <iostream>
+
+static const std::string base64_chars =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/";
+
+
+static inline bool is_base64(unsigned char c) {
+ return (isalnum(c) || (c == '+') || (c == '/'));
+}
+
+// 4J ADDED,
+std::string base64_encode(std::string str)
+{
+ return base64_encode( reinterpret_cast<const unsigned char*>(str.c_str()), str.length() );
+}
+
+std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
+ std::string ret;
+ int i = 0;
+ int j = 0;
+ unsigned char char_array_3[3];
+ unsigned char char_array_4[4];
+
+ while (in_len--) {
+ char_array_3[i++] = *(bytes_to_encode++);
+ if (i == 3) {
+ char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
+ char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
+ char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
+ char_array_4[3] = char_array_3[2] & 0x3f;
+
+ for(int ii = 0; (ii <4) ; ii++)
+ ret += base64_chars[char_array_4[ii]];
+ i = 0;
+ }
+ }
+
+ if (i)
+ {
+ for(j = i; j < 3; j++)
+ char_array_3[j] = '\0';
+
+ char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
+ char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
+ char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
+ char_array_4[3] = char_array_3[2] & 0x3f;
+
+ for (j = 0; (j < i + 1); j++)
+ ret += base64_chars[char_array_4[j]];
+
+ while((i++ < 3))
+ ret += '=';
+
+ }
+
+ return ret;
+
+}
+
+std::string base64_decode(std::string const& encoded_string) {
+ int in_len = encoded_string.size();
+ int i = 0;
+ int j = 0;
+ int in_ = 0;
+ unsigned char char_array_4[4], char_array_3[3];
+ std::string ret;
+
+ while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
+ char_array_4[i++] = encoded_string[in_]; in_++;
+ if (i ==4) {
+ for (i = 0; i <4; i++)
+ char_array_4[i] = base64_chars.find(char_array_4[i]);
+
+ char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
+ char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
+ char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
+
+ for (i = 0; (i < 3); i++)
+ ret += char_array_3[i];
+ i = 0;
+ }
+ }
+
+ if (i) {
+ for (j = i; j <4; j++)
+ char_array_4[j] = 0;
+
+ for (j = 0; j <4; j++)
+ char_array_4[j] = base64_chars.find(char_array_4[j]);
+
+ char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
+ char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
+ char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
+
+ for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
+ }
+
+ return ret;
+} \ No newline at end of file
diff --git a/Minecraft.Client/PS3/Leaderboards/base64.h b/Minecraft.Client/PS3/Leaderboards/base64.h
new file mode 100644
index 00000000..7f6a1e49
--- /dev/null
+++ b/Minecraft.Client/PS3/Leaderboards/base64.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <string>
+
+std::string base64_encode(std::string str);
+std::string base64_encode(unsigned char const* , unsigned int len);
+std::string base64_decode(std::string const& s); \ No newline at end of file