Files
MinecraftConsoles/Minecraft.Client/PS3/Leaderboards/PS3LeaderboardManager.cpp
2026-03-01 12:16:08 +08:00

1048 lines
27 KiB
C++

#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;
}