first commit
This commit is contained in:
520
Minecraft.Client/Xbox/Leaderboards/XboxLeaderboardManager.cpp
Normal file
520
Minecraft.Client/Xbox/Leaderboards/XboxLeaderboardManager.cpp
Normal file
@@ -0,0 +1,520 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "XboxLeaderboardManager.h"
|
||||
|
||||
#include "..\Network\NetworkPlayerXbox.h"
|
||||
|
||||
#ifdef _XBOX
|
||||
LeaderboardManager *LeaderboardManager::m_instance = new XboxLeaderboardManager(); //Singleton instance of the LeaderboardManager
|
||||
#endif
|
||||
|
||||
const XboxLeaderboardManager::LeaderboardDescriptor XboxLeaderboardManager::LEADERBOARD_DESCRIPTORS[XboxLeaderboardManager::NUM_LEADERBOARDS][4] = {
|
||||
{
|
||||
XboxLeaderboardManager::LeaderboardDescriptor( STATS_VIEW_TRAVELLING_PEACEFUL, 4, STATS_COLUMN_TRAVELLING_PEACEFUL_WALKED, STATS_COLUMN_TRAVELLING_PEACEFUL_FALLEN, STATS_COLUMN_TRAVELLING_PEACEFUL_MINECART, STATS_COLUMN_TRAVELLING_PEACEFUL_BOAT, NULL, NULL, NULL,NULL),
|
||||
XboxLeaderboardManager::LeaderboardDescriptor( STATS_VIEW_TRAVELLING_EASY, 4, STATS_COLUMN_TRAVELLING_EASY_WALKED, STATS_COLUMN_TRAVELLING_EASY_FALLEN, STATS_COLUMN_TRAVELLING_EASY_MINECART, STATS_COLUMN_TRAVELLING_EASY_BOAT, NULL, NULL, NULL,NULL),
|
||||
XboxLeaderboardManager::LeaderboardDescriptor( STATS_VIEW_TRAVELLING_NORMAL, 4, STATS_COLUMN_TRAVELLING_NORMAL_WALKED, STATS_COLUMN_TRAVELLING_NORMAL_FALLEN, STATS_COLUMN_TRAVELLING_NORMAL_MINECART, STATS_COLUMN_TRAVELLING_NORMAL_BOAT, NULL, NULL, NULL,NULL),
|
||||
XboxLeaderboardManager::LeaderboardDescriptor( STATS_VIEW_TRAVELLING_HARD, 4, STATS_COLUMN_TRAVELLING_HARD_WALKED, STATS_COLUMN_TRAVELLING_HARD_FALLEN, STATS_COLUMN_TRAVELLING_HARD_MINECART, STATS_COLUMN_TRAVELLING_HARD_BOAT, NULL, NULL, NULL,NULL),
|
||||
}, {
|
||||
XboxLeaderboardManager::LeaderboardDescriptor( STATS_VIEW_MINING_BLOCKS_PEACEFUL, 7, STATS_COLUMN_MINING_BLOCKS_PEACEFUL_DIRT, STATS_COLUMN_MINING_BLOCKS_PEACEFUL_STONE, STATS_COLUMN_MINING_BLOCKS_PEACEFUL_SAND, STATS_COLUMN_MINING_BLOCKS_PEACEFUL_COBBLESTONE, STATS_COLUMN_MINING_BLOCKS_PEACEFUL_GRAVEL, STATS_COLUMN_MINING_BLOCKS_PEACEFUL_CLAY, STATS_COLUMN_MINING_BLOCKS_PEACEFUL_OBSIDIAN, NULL ),
|
||||
XboxLeaderboardManager::LeaderboardDescriptor( STATS_VIEW_MINING_BLOCKS_EASY, 7, STATS_COLUMN_MINING_BLOCKS_EASY_DIRT, STATS_COLUMN_MINING_BLOCKS_EASY_STONE, STATS_COLUMN_MINING_BLOCKS_EASY_SAND, STATS_COLUMN_MINING_BLOCKS_EASY_COBBLESTONE, STATS_COLUMN_MINING_BLOCKS_EASY_GRAVEL, STATS_COLUMN_MINING_BLOCKS_EASY_CLAY, STATS_COLUMN_MINING_BLOCKS_EASY_OBSIDIAN, NULL ),
|
||||
XboxLeaderboardManager::LeaderboardDescriptor( STATS_VIEW_MINING_BLOCKS_NORMAL, 7, STATS_COLUMN_MINING_BLOCKS_NORMAL_DIRT, STATS_COLUMN_MINING_BLOCKS_NORMAL_STONE, STATS_COLUMN_MINING_BLOCKS_NORMAL_SAND, STATS_COLUMN_MINING_BLOCKS_NORMAL_COBBLESTONE, STATS_COLUMN_MINING_BLOCKS_NORMAL_GRAVEL, STATS_COLUMN_MINING_BLOCKS_NORMAL_CLAY, STATS_COLUMN_MINING_BLOCKS_NORMAL_OBSIDIAN, NULL ),
|
||||
XboxLeaderboardManager::LeaderboardDescriptor( STATS_VIEW_MINING_BLOCKS_HARD, 7, STATS_COLUMN_MINING_BLOCKS_HARD_DIRT, STATS_COLUMN_MINING_BLOCKS_HARD_STONE, STATS_COLUMN_MINING_BLOCKS_HARD_SAND, STATS_COLUMN_MINING_BLOCKS_HARD_COBBLESTONE, STATS_COLUMN_MINING_BLOCKS_HARD_GRAVEL, STATS_COLUMN_MINING_BLOCKS_HARD_CLAY, STATS_COLUMN_MINING_BLOCKS_HARD_OBSIDIAN, NULL ),
|
||||
}, {
|
||||
XboxLeaderboardManager::LeaderboardDescriptor( STATS_VIEW_FARMING_PEACEFUL, 6, STATS_COLUMN_FARMING_PEACEFUL_EGGS, STATS_COLUMN_FARMING_PEACEFUL_WHEAT, STATS_COLUMN_FARMING_PEACEFUL_MUSHROOMS,STATS_COLUMN_FARMING_PEACEFUL_SUGARCANE,STATS_COLUMN_FARMING_PEACEFUL_MILK, STATS_COLUMN_FARMING_PEACEFUL_PUMPKINS, NULL, NULL ),
|
||||
XboxLeaderboardManager::LeaderboardDescriptor( STATS_VIEW_FARMING_EASY, 6, STATS_COLUMN_FARMING_EASY_EGGS, STATS_COLUMN_FARMING_PEACEFUL_WHEAT, STATS_COLUMN_FARMING_EASY_MUSHROOMS, STATS_COLUMN_FARMING_EASY_SUGARCANE, STATS_COLUMN_FARMING_EASY_MILK, STATS_COLUMN_FARMING_EASY_PUMPKINS, NULL, NULL ),
|
||||
XboxLeaderboardManager::LeaderboardDescriptor( STATS_VIEW_FARMING_NORMAL, 6, STATS_COLUMN_FARMING_NORMAL_EGGS, STATS_COLUMN_FARMING_NORMAL_WHEAT, STATS_COLUMN_FARMING_NORMAL_MUSHROOMS, STATS_COLUMN_FARMING_NORMAL_SUGARCANE, STATS_COLUMN_FARMING_NORMAL_MILK, STATS_COLUMN_FARMING_NORMAL_PUMPKINS, NULL, NULL ),
|
||||
XboxLeaderboardManager::LeaderboardDescriptor( STATS_VIEW_FARMING_HARD, 6, STATS_COLUMN_FARMING_HARD_EGGS, STATS_COLUMN_FARMING_HARD_WHEAT, STATS_COLUMN_FARMING_HARD_MUSHROOMS, STATS_COLUMN_FARMING_HARD_SUGARCANE, STATS_COLUMN_FARMING_HARD_MILK, STATS_COLUMN_FARMING_HARD_PUMPKINS, NULL, NULL ),
|
||||
}, {
|
||||
XboxLeaderboardManager::LeaderboardDescriptor( NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ),
|
||||
XboxLeaderboardManager::LeaderboardDescriptor( STATS_VIEW_KILLS_EASY, 7, STATS_COLUMN_KILLS_EASY_ZOMBIES, STATS_COLUMN_KILLS_EASY_SKELETONS, STATS_COLUMN_KILLS_EASY_CREEPERS, STATS_COLUMN_KILLS_EASY_SPIDERS, STATS_COLUMN_KILLS_EASY_SPIDERJOCKEYS, STATS_COLUMN_KILLS_EASY_ZOMBIEPIGMEN, STATS_COLUMN_KILLS_EASY_SLIME, NULL ),
|
||||
XboxLeaderboardManager::LeaderboardDescriptor( STATS_VIEW_KILLS_NORMAL, 7, STATS_COLUMN_KILLS_NORMAL_ZOMBIES, STATS_COLUMN_KILLS_NORMAL_SKELETONS, STATS_COLUMN_KILLS_NORMAL_CREEPERS, STATS_COLUMN_KILLS_NORMAL_SPIDERS, STATS_COLUMN_KILLS_NORMAL_SPIDERJOCKEYS, STATS_COLUMN_KILLS_NORMAL_ZOMBIEPIGMEN, STATS_COLUMN_KILLS_NORMAL_SLIME, NULL ),
|
||||
XboxLeaderboardManager::LeaderboardDescriptor( STATS_VIEW_KILLS_HARD, 7, STATS_COLUMN_KILLS_HARD_ZOMBIES, STATS_COLUMN_KILLS_HARD_SKELETONS, STATS_COLUMN_KILLS_HARD_CREEPERS, STATS_COLUMN_KILLS_HARD_SPIDERS, STATS_COLUMN_KILLS_HARD_SPIDERJOCKEYS, STATS_COLUMN_KILLS_HARD_ZOMBIEPIGMEN, STATS_COLUMN_KILLS_HARD_SLIME, NULL ),
|
||||
},
|
||||
};
|
||||
|
||||
XboxLeaderboardManager::XboxLeaderboardManager()
|
||||
{
|
||||
m_eStatsState = eStatsState_Idle;
|
||||
m_statsRead = false;
|
||||
|
||||
m_hSession = NULL;
|
||||
m_spec = NULL;
|
||||
m_stats = NULL;
|
||||
|
||||
m_isQNetSession = false;
|
||||
m_endingSession = false;
|
||||
}
|
||||
|
||||
XboxLeaderboardManager::~XboxLeaderboardManager() {}
|
||||
|
||||
void XboxLeaderboardManager::Tick()
|
||||
{
|
||||
if( m_eStatsState == eStatsState_Getting )
|
||||
{
|
||||
|
||||
/*if( IsStatsReadComplete() )
|
||||
if( m_readCompleteCallback != NULL )
|
||||
m_readCompleteCallback(m_readCompleteUserdata);*/
|
||||
|
||||
if ( IsStatsReadComplete() )
|
||||
if (m_readListener != NULL)
|
||||
{
|
||||
// 4J Stu - If the state is other than ready, then we don't have any stats to sort
|
||||
if(m_eFilterMode == LeaderboardManager::eFM_Friends && m_eStatsState == eStatsState_Ready) SortFriendStats();
|
||||
|
||||
bool ret = m_readListener->OnStatsReadComplete(m_eStatsState==eStatsState_Ready, 0, m_stats); // TODO
|
||||
if (ret) m_eStatsState = eStatsState_Idle;
|
||||
}
|
||||
}
|
||||
|
||||
if( m_endingSession )
|
||||
{
|
||||
if( XHasOverlappedIoCompleted( &m_endSessionOverlapped ))
|
||||
{
|
||||
DeleteSession();
|
||||
m_endingSession = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool XboxLeaderboardManager::OpenSession()
|
||||
{
|
||||
//Can't create a new session when deleting a previous one
|
||||
if (m_endingSession) return false;
|
||||
|
||||
//We've already got an open session
|
||||
if (m_hSession != NULL) return true;
|
||||
|
||||
int lockedProfile = ProfileManager.GetLockedProfile();
|
||||
if( lockedProfile == -1 )
|
||||
{
|
||||
m_hSession = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
XUserGetXUID(lockedProfile, &m_myXUID);
|
||||
XUserSetContext(lockedProfile, X_CONTEXT_GAME_TYPE, X_CONTEXT_GAME_TYPE_STANDARD);
|
||||
|
||||
//We already have a QNet session (ie we are joining/in/leaving a multiplayer game)
|
||||
if(g_NetworkManager.IsInSession())
|
||||
{
|
||||
if(g_NetworkManager.IsInStatsEnabledSession())
|
||||
{
|
||||
m_isQNetSession = true;
|
||||
return true;
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// return false;
|
||||
//}
|
||||
}
|
||||
|
||||
XSESSION_INFO sessionInfo;
|
||||
ULONGLONG sessionNonce;
|
||||
|
||||
DWORD ret = XSessionCreate(XSESSION_CREATE_USES_STATS | XSESSION_CREATE_HOST, lockedProfile, 8, 8, &sessionNonce, &sessionInfo, NULL, &m_hSession);
|
||||
if( ret != ERROR_SUCCESS )
|
||||
{
|
||||
m_hSession = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD userIndices[1] = { lockedProfile };
|
||||
BOOL privateSlots[1] = { FALSE };
|
||||
ret = XSessionJoinLocal(m_hSession, 1, userIndices, privateSlots, NULL);
|
||||
if( ret != ERROR_SUCCESS )
|
||||
{
|
||||
m_hSession = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = XSessionStart(m_hSession, 0, NULL);
|
||||
if( ret != ERROR_SUCCESS )
|
||||
{
|
||||
m_hSession = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void XboxLeaderboardManager::CloseSession()
|
||||
{
|
||||
if( !m_endingSession )
|
||||
{
|
||||
if (!XHasOverlappedIoCompleted(&m_overlapped))
|
||||
XCancelOverlapped(&m_overlapped);
|
||||
|
||||
if (m_isQNetSession == true)
|
||||
{
|
||||
m_isQNetSession = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_hSession == NULL) return;
|
||||
|
||||
memset(&m_endSessionOverlapped, 0, sizeof(m_endSessionOverlapped));
|
||||
|
||||
DWORD ret = XSessionEnd( m_hSession, &m_endSessionOverlapped );
|
||||
if (ret == ERROR_SUCCESS || ret == ERROR_IO_PENDING)
|
||||
{
|
||||
m_endingSession = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Failed so just delete the session
|
||||
if (ret != ERROR_SUCCESS) DeleteSession();
|
||||
}
|
||||
|
||||
m_readListener = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void XboxLeaderboardManager::DeleteSession()
|
||||
{
|
||||
XSessionDelete(m_hSession, NULL);
|
||||
CloseHandle(m_hSession);
|
||||
m_hSession = NULL;
|
||||
}
|
||||
|
||||
bool XboxLeaderboardManager::WriteStats(unsigned int viewCount, ViewIn views)
|
||||
{
|
||||
DWORD ret = S_OK;
|
||||
|
||||
// some debug code to catch the leaderboard write with 7 views
|
||||
#ifndef _CONTENT_PACKAGE
|
||||
if(viewCount>5) __debugbreak();
|
||||
#endif
|
||||
|
||||
// 4J Stu - If we are online we already have a session, so use that
|
||||
if(m_isQNetSession == true)
|
||||
{
|
||||
INetworkPlayer *player = g_NetworkManager.GetPlayerByXuid(m_myXUID);
|
||||
if(player != NULL)
|
||||
{
|
||||
ret = ((NetworkPlayerXbox *)player)->GetQNetPlayer()->WriteStats(viewCount,views);
|
||||
//printf("Wrote stats to QNet player\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = ERROR_NO_SUCH_USER;
|
||||
assert(false && "Failed to write stats to a QNET session as no player exists with that XUID");
|
||||
app.DebugPrintf("Failed to write stats to a QNET session as no player exists with that XUID\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = XSessionWriteStats(m_hSession, m_myXUID, viewCount, views, NULL);
|
||||
}
|
||||
if (ret != ERROR_SUCCESS) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void XboxLeaderboardManager::CancelOperation()
|
||||
{
|
||||
//Need to have a session open
|
||||
if( m_hSession == NULL )
|
||||
if( !OpenSession() )
|
||||
return;
|
||||
|
||||
//Abort any current read operation
|
||||
if( m_eStatsState == eStatsState_Getting )
|
||||
if( !XHasOverlappedIoCompleted( &m_overlapped ))
|
||||
XCancelOverlapped( &m_overlapped );
|
||||
|
||||
m_eStatsState = eStatsState_Idle;
|
||||
}
|
||||
|
||||
bool XboxLeaderboardManager::ReadStats_MyScore(LeaderboardReadListener *callback, int difficulty, EStatsType type, PlayerUID myUID, unsigned int readCount)
|
||||
{
|
||||
if (!readStats(difficulty,type)) return false;
|
||||
if (!LeaderboardManager::ReadStats_MyScore(callback, difficulty, type, myUID, readCount)) return false;
|
||||
|
||||
HANDLE hEnumerator;
|
||||
DWORD ret;
|
||||
|
||||
//DWORD readCount = 0;
|
||||
|
||||
m_numStats = 0;
|
||||
ret = XUserCreateStatsEnumeratorByXuid(
|
||||
0,
|
||||
m_myXUID,
|
||||
readCount,
|
||||
1, //specCount,
|
||||
m_spec,
|
||||
&m_numStats,
|
||||
&hEnumerator);
|
||||
|
||||
if( ret != ERROR_SUCCESS ) return false;
|
||||
|
||||
//Allocate a buffer for the stats
|
||||
m_stats = (PXUSER_STATS_READ_RESULTS) new BYTE[m_numStats];
|
||||
if (m_stats == NULL) return false;
|
||||
|
||||
memset(m_stats, 0, m_numStats);
|
||||
memset(&m_overlapped, 0, sizeof(m_overlapped));
|
||||
|
||||
ret = XEnumerate(
|
||||
hEnumerator, // Enumeration handle
|
||||
m_stats, // Buffer
|
||||
m_numStats, // Size of buffer
|
||||
NULL, // Number of rows returned; not used for async
|
||||
&m_overlapped ); // Overlapped structure; not used for sync
|
||||
|
||||
if ( (ret!=ERROR_SUCCESS) && (ret!=ERROR_IO_PENDING) ) return false;
|
||||
|
||||
m_eStatsState = eStatsState_Getting;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XboxLeaderboardManager::ReadStats_Friends(LeaderboardReadListener *callback, int difficulty, EStatsType type, PlayerUID myUID, unsigned int startIndex, unsigned int readCount)
|
||||
{
|
||||
if (!readStats(difficulty,type)) return false;
|
||||
if (!LeaderboardManager::ReadStats_Friends(callback, difficulty, type, myUID, startIndex, readCount)) return false;
|
||||
|
||||
HANDLE hEnumerator;
|
||||
DWORD ret;
|
||||
|
||||
unsigned int friendCount;
|
||||
XUID *friends;
|
||||
|
||||
getFriends(friendCount, &friends);
|
||||
|
||||
if(friendCount == 0 || friends == NULL)
|
||||
{
|
||||
app.DebugPrintf("XboxLeaderboardManager::ReadStats_Friends - No friends found. Possibly you are offline?\n");
|
||||
return false;
|
||||
}
|
||||
assert(friendCount > 0 && friends != NULL);
|
||||
|
||||
m_numStats = 0;
|
||||
ret = XUserReadStats(
|
||||
0,
|
||||
friendCount,
|
||||
friends,
|
||||
1, //specCount,
|
||||
m_spec,
|
||||
&m_numStats,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
|
||||
//Annoyingly, this returns ERROR_INSUFFICIENT_BUFFER when it is being asked to calculate the size of the buffer by passing zero resultsSize
|
||||
if ( (ret!=ERROR_SUCCESS) && (ret!=ERROR_INSUFFICIENT_BUFFER) ) return false;
|
||||
|
||||
//Allocate a buffer for the stats
|
||||
m_stats = (PXUSER_STATS_READ_RESULTS) new BYTE[m_numStats];
|
||||
if (m_stats == NULL) return false;
|
||||
|
||||
memset(m_stats, 0, m_numStats);
|
||||
memset(&m_overlapped, 0, sizeof(m_overlapped));
|
||||
|
||||
ret = XUserReadStats(
|
||||
0,
|
||||
friendCount,
|
||||
friends,
|
||||
1,
|
||||
m_spec,
|
||||
&m_numStats,
|
||||
m_stats,
|
||||
&m_overlapped);
|
||||
|
||||
if( (ret!=ERROR_SUCCESS) && (ret!=ERROR_IO_PENDING) ) return false;
|
||||
|
||||
m_eStatsState = eStatsState_Getting;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XboxLeaderboardManager::ReadStats_TopRank(LeaderboardReadListener *callback, int difficulty, EStatsType type , unsigned int startIndex, unsigned int readCount)
|
||||
{
|
||||
if (!readStats(difficulty,type)) return false;
|
||||
if (!LeaderboardManager::ReadStats_TopRank(callback, difficulty, type, startIndex, readCount)) return false;
|
||||
|
||||
HANDLE hEnumerator;
|
||||
|
||||
m_numStats = 0;
|
||||
DWORD ret = XUserCreateStatsEnumeratorByRank(
|
||||
0, // Current title ID
|
||||
startIndex, // Index to start enumerating from
|
||||
readCount, // Number of rows to retrieve
|
||||
1, // Number of stats specs
|
||||
m_spec, // Stats spec,
|
||||
&m_numStats, // Size of buffer
|
||||
&hEnumerator ); // Enumeration handle
|
||||
|
||||
if( ret != ERROR_SUCCESS ) return false;
|
||||
|
||||
//Allocate a buffer for the stats
|
||||
m_stats = (PXUSER_STATS_READ_RESULTS) new BYTE[m_numStats];
|
||||
if (m_stats == NULL) return false;
|
||||
|
||||
memset(m_stats, 0, m_numStats);
|
||||
memset(&m_overlapped, 0, sizeof(m_overlapped));
|
||||
|
||||
ret = XEnumerate(
|
||||
hEnumerator, // Enumeration handle
|
||||
m_stats, // Buffer
|
||||
m_numStats, // Size of buffer
|
||||
NULL, // Number of rows returned; not used for async
|
||||
&m_overlapped ); // Overlapped structure; not used for sync
|
||||
|
||||
if( (ret!=ERROR_SUCCESS) && (ret!=ERROR_IO_PENDING) ) return false;
|
||||
|
||||
m_eStatsState = eStatsState_Getting;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XboxLeaderboardManager::readStats(int difficulty, EStatsType type)
|
||||
{
|
||||
//Need to have a session open
|
||||
if (m_hSession==NULL) if(!OpenSession()) return false;
|
||||
|
||||
m_eStatsState = eStatsState_Failed;
|
||||
m_statsRead = false;
|
||||
|
||||
if (m_stats) delete [] m_stats;
|
||||
|
||||
//Setup the spec structure for the read request
|
||||
m_spec = new XUSER_STATS_SPEC[1];
|
||||
m_spec[0].dwViewId = LEADERBOARD_DESCRIPTORS[(int)type][difficulty].m_viewId;
|
||||
m_spec[0].dwNumColumnIds = LEADERBOARD_DESCRIPTORS[(int)type][difficulty].m_columnCount;
|
||||
for (unsigned int i=0; i<m_spec[0].dwNumColumnIds; ++i)
|
||||
m_spec[0].rgwColumnIds[i] = LEADERBOARD_DESCRIPTORS[(int)type][difficulty].m_columnIds[i];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void XboxLeaderboardManager::FlushStats()
|
||||
{
|
||||
if( m_hSession == NULL || m_isQNetSession ) return;
|
||||
memset(&m_flushStatsOverlapped, 0, sizeof(m_flushStatsOverlapped));
|
||||
XSessionFlushStats(m_hSession, &m_flushStatsOverlapped);
|
||||
}
|
||||
|
||||
bool XboxLeaderboardManager::IsStatsReadComplete()
|
||||
{
|
||||
//If the read has completed
|
||||
if( XHasOverlappedIoCompleted( &m_overlapped ) )
|
||||
{
|
||||
//If we've had an error
|
||||
if( XGetOverlappedExtendedError( &m_overlapped ) != ERROR_SUCCESS )
|
||||
{
|
||||
m_eStatsState = eStatsState_Failed;
|
||||
if( m_stats )
|
||||
{
|
||||
delete [] m_stats;
|
||||
m_stats = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//If we've not got any results
|
||||
if( !m_stats || m_stats->dwNumViews == 0 || m_stats->pViews[0].dwNumRows == 0 )
|
||||
{
|
||||
m_eStatsState = eStatsState_NoResults;
|
||||
if( m_stats )
|
||||
{
|
||||
delete [] m_stats;
|
||||
m_stats = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_eStatsState = eStatsState_Ready;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int XboxLeaderboardManager::FriendSortFunction(const void* a, const void* b)
|
||||
{
|
||||
return ((int)((XUSER_STATS_ROW*)a)->dwRank) - ((int)((XUSER_STATS_ROW*)b)->dwRank);
|
||||
}
|
||||
|
||||
void XboxLeaderboardManager::SortFriendStats()
|
||||
{
|
||||
for( unsigned int leaderboardIndex=0 ; leaderboardIndex<m_stats->dwNumViews ; ++leaderboardIndex )
|
||||
{
|
||||
//First filter out any friends who aren't in the leaderboard
|
||||
XUSER_STATS_ROW* pRow = m_stats->pViews[leaderboardIndex].pRows;
|
||||
//View rows is returned not including XUIDs that aren't in this leaderboard, but we want to recalculate that sort of thing
|
||||
m_stats->pViews[leaderboardIndex].dwTotalViewRows = m_stats->pViews[leaderboardIndex].dwNumRows;
|
||||
for( unsigned int rowIndex=0 ; rowIndex<m_stats->pViews[leaderboardIndex].dwTotalViewRows ; )
|
||||
{
|
||||
if( pRow->dwRank == 0 )
|
||||
{
|
||||
memmove( pRow, pRow + 1, ( ( m_stats->pViews[leaderboardIndex].dwTotalViewRows - rowIndex ) - 1 ) * sizeof(XUSER_STATS_ROW) );
|
||||
m_stats->pViews[leaderboardIndex].dwTotalViewRows--;
|
||||
}
|
||||
else
|
||||
{
|
||||
rowIndex++;
|
||||
pRow++;
|
||||
}
|
||||
}
|
||||
|
||||
//Then sort by rank
|
||||
qsort( m_stats->pViews[leaderboardIndex].pRows, m_stats->pViews[leaderboardIndex].dwTotalViewRows, sizeof(XUSER_STATS_ROW), FriendSortFunction );
|
||||
m_stats->pViews[leaderboardIndex].dwNumRows = m_stats->pViews[leaderboardIndex].dwTotalViewRows;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
void XboxLeaderboardManager::SetStatsRetrieved(bool success)
|
||||
{
|
||||
if( m_stats != NULL )
|
||||
{
|
||||
delete [] m_stats;
|
||||
m_stats = NULL;
|
||||
}
|
||||
|
||||
m_statsRead = success;
|
||||
m_eStatsState = eStatsState_Idle;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// 4J-JEV: Adapted/stolen from 'XUI_Leaderboards'.
|
||||
bool XboxLeaderboardManager::getFriends(unsigned int &friendsCount, PlayerUID** friends)
|
||||
{
|
||||
DWORD resultsSize;
|
||||
HANDLE hEnumerator;
|
||||
DWORD ret;
|
||||
DWORD numFriends;
|
||||
|
||||
//First, get a list of (up to 100) friends (this is the maximum that the enumerator currently supports)
|
||||
ret = XFriendsCreateEnumerator( ProfileManager.GetLockedProfile(), 0, 100, &resultsSize, &hEnumerator);
|
||||
if(ret!=ERROR_SUCCESS) return false;
|
||||
|
||||
XONLINE_FRIEND *xonlineFriends = (XONLINE_FRIEND*) new BYTE[resultsSize];
|
||||
|
||||
ret = XEnumerate(
|
||||
hEnumerator,
|
||||
xonlineFriends,
|
||||
resultsSize,
|
||||
&numFriends,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (ret!=ERROR_SUCCESS) friendsCount = 0;
|
||||
|
||||
PlayerUID *filteredFriends = new PlayerUID[numFriends+1];
|
||||
|
||||
friendsCount = 0;
|
||||
for (unsigned int friendIndex=0; friendIndex<numFriends; ++friendIndex)
|
||||
{
|
||||
if( ( xonlineFriends[friendIndex].dwFriendState & (XONLINE_FRIENDSTATE_FLAG_SENTREQUEST | XONLINE_FRIENDSTATE_FLAG_RECEIVEDREQUEST) ) == 0 )
|
||||
{
|
||||
filteredFriends[friendsCount++] = xonlineFriends[friendIndex].xuid;
|
||||
}
|
||||
}
|
||||
|
||||
filteredFriends[friendsCount++] = m_myXUID; //m_filteredFriends[m_numFilteredFriends++] = LeaderboardManager::Instance()->GetMyXUID();
|
||||
|
||||
// Return.
|
||||
*friends = filteredFriends;
|
||||
return true;
|
||||
}
|
||||
136
Minecraft.Client/Xbox/Leaderboards/XboxLeaderboardManager.h
Normal file
136
Minecraft.Client/Xbox/Leaderboards/XboxLeaderboardManager.h
Normal file
@@ -0,0 +1,136 @@
|
||||
#pragma once
|
||||
|
||||
#include <xuiresource.h>
|
||||
#include <xuiapp.h>
|
||||
|
||||
#include "..\..\Common\Leaderboards\LeaderboardManager.h"
|
||||
|
||||
class XboxLeaderboardManager : public LeaderboardManager
|
||||
{
|
||||
public:
|
||||
enum EStatsState
|
||||
{
|
||||
eStatsState_Idle=0, //No current stats read operation
|
||||
eStatsState_Getting, //Stats read in progress
|
||||
eStatsState_Failed, //Stats read failed
|
||||
eStatsState_Ready, //Stats read completed, ready for use
|
||||
eStatsState_NoResults, //Stats read completed, no results found
|
||||
eNumStatStates,
|
||||
};
|
||||
|
||||
protected: // LEADERBOARD DESCRIPTIONS //
|
||||
// From 'XUI_Leaderboards.cpp'.
|
||||
|
||||
// 4J Stu - Because the kills leaderboard doesn't a peaceful entry there are some special
|
||||
// handling to make it skip that. We have re-arranged the order of the leaderboards so
|
||||
// I am making this in case we do it again.
|
||||
// 4J Stu - Made it a member of the class, rather than a #define
|
||||
static const int LEADERBOARD_KILLS_POSITION = 3;
|
||||
|
||||
static const int NUM_LEADERBOARDS = 4;//6; //Number of leaderboards
|
||||
static const int NUM_ENTRIES = 101; //Cache up to this many entries
|
||||
static const int READ_SIZE = 15; //Read this many entries at a time
|
||||
|
||||
struct LeaderboardDescriptor {
|
||||
DWORD m_viewId;
|
||||
DWORD m_columnCount;
|
||||
WORD m_columnIds[8];
|
||||
|
||||
LeaderboardDescriptor( DWORD viewId, DWORD columnCount,
|
||||
WORD columnId_0, WORD columnId_1, WORD columnId_2, WORD columnId_3,
|
||||
WORD columnId_4, WORD columnId_5, WORD columnId_6, WORD columnId_7)
|
||||
{
|
||||
m_viewId = viewId;
|
||||
m_columnCount = columnCount;
|
||||
m_columnIds[0] = columnId_0;
|
||||
m_columnIds[1] = columnId_1;
|
||||
m_columnIds[2] = columnId_2;
|
||||
m_columnIds[3] = columnId_3;
|
||||
m_columnIds[4] = columnId_4;
|
||||
m_columnIds[5] = columnId_5;
|
||||
m_columnIds[6] = columnId_6;
|
||||
m_columnIds[7] = columnId_7;
|
||||
}
|
||||
};
|
||||
|
||||
static const LeaderboardDescriptor LEADERBOARD_DESCRIPTORS[NUM_LEADERBOARDS][4];
|
||||
|
||||
|
||||
private:
|
||||
|
||||
EStatsState m_eStatsState; //State of the stats read
|
||||
bool m_statsRead; //Whether or not the stats read operation has completed
|
||||
|
||||
HANDLE m_hSession; //Current session
|
||||
XOVERLAPPED m_overlapped; //Overlapped structure used for async actions
|
||||
XUSER_STATS_SPEC* m_spec; //Spec structure used in reads
|
||||
|
||||
DWORD m_numStats;
|
||||
PXUSER_STATS_READ_RESULTS m_stats; //Structure that stats are read into
|
||||
|
||||
bool m_isQNetSession; //Session is being managed via QNet
|
||||
bool m_endingSession; //Session is currently being ended
|
||||
XOVERLAPPED m_endSessionOverlapped; //Overlapped stucture for end session async action
|
||||
|
||||
XOVERLAPPED m_flushStatsOverlapped;
|
||||
|
||||
public:
|
||||
XboxLeaderboardManager();
|
||||
~XboxLeaderboardManager();
|
||||
|
||||
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 *callback, int difficulty, EStatsType type, PlayerUID myUID, unsigned int startIndex, unsigned int readCount);
|
||||
virtual bool ReadStats_MyScore(LeaderboardReadListener *callback, int difficulty, EStatsType type, PlayerUID myUID, unsigned int readCount);
|
||||
virtual bool ReadStats_TopRank(LeaderboardReadListener *callback, 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();
|
||||
|
||||
virtual bool isIdle() { return m_eStatsState != eStatsState_Getting; }
|
||||
|
||||
private:
|
||||
bool readStats(int difficulty, EStatsType type);
|
||||
|
||||
//Check if the stats read operation has completed
|
||||
bool IsStatsReadComplete();
|
||||
|
||||
//Function used by qsort to sort friends
|
||||
static int FriendSortFunction(const void* a, const void* b);
|
||||
|
||||
//Sort the list of friend stats
|
||||
void SortFriendStats();
|
||||
|
||||
bool getFriends(unsigned int &friendsCount, XUID** friends);
|
||||
|
||||
#if 0
|
||||
public:
|
||||
|
||||
//Should be called once the stats have been retrieved and used by the application
|
||||
void SetStatsRetrieved(bool success);
|
||||
|
||||
EStatsState GetStatsState() { return m_eStatsState; }
|
||||
bool GetStatsRead() { return m_statsRead; }
|
||||
|
||||
PXUSER_STATS_READ_RESULTS GetStats() { return m_stats; }
|
||||
#endif
|
||||
public:
|
||||
PlayerUID GetMyXUID() { return m_myXUID; }
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user