csgo-2018-source/game/client/cstrike15/Scaleform/leaderboardsdialog_scaleform.cpp
2021-07-24 21:11:47 -07:00

1428 lines
43 KiB
C++

//==== Copyright © 1996-2005, Valve Corporation, All rights reserved. =========//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "fmtstr.h"
#if defined( INCLUDE_SCALEFORM )
#include "basepanel.h"
#include "leaderboardsdialog_scaleform.h"
#include <vgui/ILocalize.h>
#ifdef _X360
#include "xbox/xbox_launch.h"
#include "ixboxsystem.h"
#include "../../common/xlast_csgo/csgo.spa.h"
#endif
#include "keyvalues.h"
#include "engineinterface.h"
#include "modinfo.h"
#include "gameui_interface.h"
#include "tier1/utlbuffer.h"
#include "filesystem.h"
using namespace vgui;
// for SRC
#include <vstdlib/random.h>
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
#define LEADERBOARD_SHOW_RANK_UNDER 1000
CCreateLeaderboardsDialogScaleform* CCreateLeaderboardsDialogScaleform::m_pInstance = NULL;
SFUI_BEGIN_GAME_API_DEF
SFUI_DECL_METHOD( OnOk ),
SFUI_DECL_METHOD( SetQuery ),
SFUI_DECL_METHOD( Query_NumResults ),
SFUI_DECL_METHOD( Query_GetCurrentPlayerRow ),
SFUI_DECL_METHOD( QueryRow_GamerTag ),
SFUI_DECL_METHOD( QueryRow_ColumnValue ),
SFUI_DECL_METHOD( QueryRow_ColumnRatio ),
SFUI_DECL_METHOD( DisplayUserInfo ),
SFUI_END_GAME_API_DEF( CCreateLeaderboardsDialogScaleform, LeaderBoards )
;
// For tracking the last panel the user viewed on this screen
ConVar player_last_leaderboards_panel( "player_last_leaderboards_panel", "0", FCVAR_ARCHIVE | FCVAR_ARCHIVE_GAMECONSOLE | FCVAR_SS, "Last opened panel in the Leaderboards screen" );
ConVar player_last_leaderboards_mode( "player_last_leaderboards_mode", "0", FCVAR_ARCHIVE | FCVAR_ARCHIVE_GAMECONSOLE | FCVAR_SS, "Last mode setting in the Leaderboards screen" );
ConVar player_last_leaderboards_filter( "player_last_leaderboards_filter", "0", FCVAR_ARCHIVE | FCVAR_ARCHIVE_GAMECONSOLE | FCVAR_SS, "Last mode setting in the Leaderboards screen" );
const float QUERY_DELAY_TIME = 0.5f;
const float QUERY_SHORT_DELAY_TIME = 0.35f;
// Enable this define for asynch debug output
// #define DIAGNOSE_ASYNCH_PROBLEMS 1
void CCreateLeaderboardsDialogScaleform::LoadDialog( void )
{
if ( !m_pInstance )
{
STEAMWORKS_TESTSECRETALWAYS();
m_pInstance = new CCreateLeaderboardsDialogScaleform( );
SFUI_REQUEST_ELEMENT( SF_FULL_SCREEN_SLOT, g_pScaleformUI, CCreateLeaderboardsDialogScaleform, m_pInstance, LeaderBoards );
}
}
void CCreateLeaderboardsDialogScaleform::UnloadDialog( void )
{
if ( m_pInstance )
{
m_pInstance->RemoveFlashElement();
}
}
void CCreateLeaderboardsDialogScaleform::UpdateDialog( void )
{
if ( m_pInstance )
{
m_pInstance->Tick();
}
}
CCreateLeaderboardsDialogScaleform::CCreateLeaderboardsDialogScaleform( void ) :
m_hAsyncQuery(0),
m_currentFilterType(eLBFilter_Overall),
m_startingRowIndex(-1),
m_rowsPerPage(0),
m_bCheckForQueryResults(false),
m_iNumFriends(0),
m_iNextFriend(-1),
m_bEnumeratingFriends(false),
m_bResultsValid(false),
m_iTotalViewRows(0)
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD( GET_ACTIVE_SPLITSCREEN_SLOT() );
m_iPlayerSlot = XBX_GetActiveUserId();
IPlayerLocal *pProfile = g_pMatchFramework->GetMatchSystem()->GetPlayerManager()->GetLocalPlayer( m_iPlayerSlot );
if ( pProfile )
m_PlayerXUID = pProfile->GetXUID();
#if defined (_X360)
m_pResultsBuffer = NULL;
m_pFriends = NULL;
ZeroMemory( m_pFriendsResult, sizeof(m_pFriendsResult[0]) * (MAX_FRIENDS+1) );
#endif // _X360
#if !defined( NO_STEAM )
m_currentLeaderboardHandle = (SteamLeaderboard_t)0;
m_currentLeaderboardName = NULL;
V_memset( &m_cachedLeaderboardScores, 0, sizeof(LeaderboardScoresDownloaded_t) );
m_pLeaderboardDescription = NULL;
V_memset( m_payloadSizes, 0, sizeof(int)*kMaxPayloadEntries );
SetDefLessFunc( m_LeaderboardHandles );
#endif // !NO_STEAM
}
void CCreateLeaderboardsDialogScaleform::OnOk( SCALEFORM_CALLBACK_ARGS_DECL )
{
CCreateLeaderboardsDialogScaleform::UnloadDialog();
}
void CCreateLeaderboardsDialogScaleform::FlashLoaded( void )
{
if ( FlashAPIIsValid() )
{
m_pScaleformUI->Value_InvokeWithoutReturn( m_FlashAPI, "InitDialogData", NULL, 0 );
}
}
void CCreateLeaderboardsDialogScaleform::FlashReady( void )
{
SFVALUE PanelHandle = m_pScaleformUI->Value_GetMember( m_FlashAPI, "ScoreBoard" );
if ( PanelHandle )
{
SFVALUE AnimatedPanelHandle = m_pScaleformUI->Value_GetMember( PanelHandle, "Panel" );
if ( AnimatedPanelHandle )
{
// Grab any references you need now...
m_pScaleformUI->ReleaseValue( AnimatedPanelHandle );
}
m_pScaleformUI->ReleaseValue( PanelHandle );
}
m_bCheckForQueryResults = false;
m_bResultsValid = false;
m_iNumFriends = 0;
m_iNextFriend = -1;
#if defined (_X360)
m_pResultsBuffer = NULL;
m_pFriends = NULL;
ZeroMemory( m_pFriendsResult, sizeof(m_pFriendsResult[0]) * (MAX_FRIENDS+1) );
#endif // _X360
Show();
}
bool CCreateLeaderboardsDialogScaleform::PreUnloadFlash( void )
{
return true;
}
void CCreateLeaderboardsDialogScaleform::PostUnloadFlash( void )
{
#ifdef _X360
// release the async handle
if ( m_hAsyncQuery != 0 )
{
xboxsystem->CancelOverlappedOperation( m_hAsyncQuery );
xboxsystem->ReleaseAsyncHandle( m_hAsyncQuery );
}
// Wipe out any previous results
if ( m_pResultsBuffer != NULL )
{
delete [] m_pResultsBuffer;
m_pResultsBuffer = NULL;
}
if ( m_pFriends )
{
delete [] m_pFriends;
m_pFriends = NULL;
// Free the structures that track our friends' statistics
for ( int idx = 0; idx < MAX_FRIENDS+1; ++idx )
{
if ( m_pFriendsResult[idx] != NULL )
{
delete [] m_pFriendsResult[idx];
m_pFriendsResult[idx] = NULL;
}
}
}
#endif // _X360
#if !defined( NO_STEAM )
if ( !m_pLeaderboardDescription )
m_pLeaderboardDescription->deleteThis();
#endif // !NO_STEAM
if ( GameUI().IsInLevel() )
{
BasePanel()->RestorePauseMenu();
}
else
{
BasePanel()->RestoreMainMenuScreen();
}
m_pInstance = NULL;
delete this;
}
void CCreateLeaderboardsDialogScaleform::Show( void )
{
if ( FlashAPIIsValid() )
{
WITH_SLOT_LOCKED
{
ScaleformUI()->Value_InvokeWithoutReturn( m_FlashAPI, "showPanel", 0, NULL );
}
}
}
void CCreateLeaderboardsDialogScaleform::Hide( void )
{
if ( FlashAPIIsValid() )
{
WITH_SLOT_LOCKED
{
ScaleformUI()->Value_InvokeWithoutReturn( m_FlashAPI, "hidePanel", 0, NULL );
}
}
}
void CCreateLeaderboardsDialogScaleform::Tick( void )
{
if ( FlashAPIIsValid() )
{
QueryUpdate();
CheckForQueryResults();
}
}
//-----------------------------------------------------------------------------
// Purpose: Called from scaleform whenever any of our search parameters change:
// game mode & type, filter (me/friends/overall), position in board
//-----------------------------------------------------------------------------
void CCreateLeaderboardsDialogScaleform::SetQuery( SCALEFORM_CALLBACK_ARGS_DECL )
{
#if defined (_X360)
// As soon as we change any parameters, cancel any previous queries
if ( m_hAsyncQuery != 0 )
{
#ifdef DIAGNOSE_ASYNCH_PROBLEMS
printf( "Leaderboard: SetQuery: Aborting a pending query.\n" );
#endif
xboxsystem->CancelOverlappedOperation( m_hAsyncQuery );
xboxsystem->ReleaseAsyncHandle( m_hAsyncQuery );
m_hAsyncQuery = 0;
}
m_bCheckForQueryResults = false;
int nIdx = 0;
int filterType = (int)( pui->Params_GetArgAsNumber( obj, nIdx++ ) );
m_currentFilterType = (eLeaderboardFiltersType) clamp( filterType, (int)eLBFilter_Overall, (int)eLBFilter_Friends );
// if this is a new friends query, free all of the tracking structures from previous friends stat queries
if ( m_currentFilterType == eLBFilter_Friends )
{
for ( int idx = 0; idx < MAX_FRIENDS+1; ++idx )
{
if ( m_pFriendsResult[idx] != NULL )
{
delete [] m_pFriendsResult[idx];
m_pFriendsResult[idx] = NULL;
}
}
// Do not reset m_pFriends list here! It's slow to read out, so once we've gotten it keep
// it around until the dialog goes away (not when we're flicking through filters)
m_bEnumeratingFriends = false;
m_iNextFriend = -1;
}
m_startingRowIndex = (int)( pui->Params_GetArgAsNumber( obj, nIdx++ ) );
m_rowsPerPage = (int)( pui->Params_GetArgAsNumber( obj, nIdx++ ) );
DWORD dwViewId = (DWORD)( pui->Params_GetArgAsNumber( obj, nIdx++ ) );
DWORD dwNumColumns = (DWORD)( pui->Params_GetArgAsNumber( obj, nIdx++ ) );
// Sanity check the column list passed in:
SFVALUE columnIdArray = pui->Params_GetArg( obj, nIdx++ );
if ( pui->Value_GetType( columnIdArray ) != IScaleformUI::VT_Array )
{
Warning( "CCreateLeaderboardsDialogScaleform::SetQuery: Invalid final argument - expected an array of columnIds!\n" );
dwNumColumns = 0;
}
else
{
int arrayLen = pui->Value_GetArraySize( columnIdArray );
if ( arrayLen != (int)dwNumColumns )
{
Warning( "CCreateLeaderboardsDialogScaleform::SetQuery: columnIds length differs from param count - using %d columns instead!\n", arrayLen );
dwNumColumns = arrayLen;
}
}
// Wait a second before we handle this query, in case user is flicking through options
m_fQueryDelayTime = Plat_FloatTime() + QUERY_DELAY_TIME;
// Sanity check the board we are reading from
Assert( dwViewId >= STATS_VIEW_WINS_ONLINE_CASUAL && dwViewId <= STATS_VIEW_GP_ONLINE_GG_BOMB );
// Clear the query, and copy over our search settings
ZeroMemory( &m_statsSpec, sizeof(m_statsSpec) );
m_statsSpec.dwViewId = dwViewId;
m_statsSpec.dwNumColumnIds = clamp( dwNumColumns, (DWORD)0, (DWORD)XUSER_STATS_ATTRS_IN_SPEC - 1 );
for (DWORD columnIdx = 0; columnIdx < m_statsSpec.dwNumColumnIds; ++columnIdx )
{
SFVALUE element = pui->Value_GetArrayElement( columnIdArray, columnIdx );
m_statsSpec.rgwColumnIds[columnIdx] = (WORD)(pui->Value_GetNumber( element ));
}
#endif
#if !defined( NO_STEAM )
// As soon as we change any parameters, cancel any previous queries
m_bCheckForQueryResults = false;
int nIdx = 0;
int filterType = (int)( pui->Params_GetArgAsNumber( obj, nIdx++ ) );
m_currentFilterType = (eLeaderboardFiltersType) clamp( filterType, (int)eLBFilter_Overall, (int)eLBFilter_Friends );
m_startingRowIndex = (int)( pui->Params_GetArgAsNumber( obj, nIdx++ ) );
m_rowsPerPage = (int)( pui->Params_GetArgAsNumber( obj, nIdx++ ) );
m_currentLeaderboardName = ( pui->Params_GetArgAsString( obj, nIdx++ ) );
// DevMsg(" Querying Steam board \"%s\" starting at row %d, %d total rows..\n\n", m_currentLeaderboardName, m_startingRowIndex, m_rowsPerPage );
// Wait a second before we handle this query, in case user is flicking through options
m_fQueryDelayTime = Plat_FloatTime() + QUERY_DELAY_TIME;
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Determine how many results we have obtained from our previous query
// Returns -1 while the query is still pending.
//-----------------------------------------------------------------------------
void CCreateLeaderboardsDialogScaleform::Query_NumResults( SCALEFORM_CALLBACK_ARGS_DECL )
{
int numResults = 0;
#if defined (_X360)
if ( m_fQueryDelayTime > 0.f )
numResults = -1; // Query is still in progress; display the "Searching..." msg
else
numResults = m_pResults.Count();
#endif // _X360
#if !defined( NO_STEAM )
if ( m_fQueryDelayTime > 0.f )
numResults = -1; // Query is still in progress; display the "Searching..." msg
else if ( m_bCheckForQueryResults )
numResults = ( m_cachedLeaderboardScores.m_cEntryCount );
#endif
m_pScaleformUI->Params_SetResult( obj, numResults );
}
//-----------------------------------------------------------------------------
// Purpose: Retrieve the row that contains information about the current player
//-----------------------------------------------------------------------------
void CCreateLeaderboardsDialogScaleform::Query_GetCurrentPlayerRow( SCALEFORM_CALLBACK_ARGS_DECL )
{
int playerRow = 0;
#if defined (_X360)
for ( int Idx = 0; Idx < m_pResults.Count(); Idx ++ )
{
if ( m_pResults[Idx]->xuid == m_PlayerXUID )
{
playerRow = Idx;
break;
}
}
#endif // _X360
#if !defined (NO_STEAM)
if ( m_currentLeaderboardHandle != 0 && m_cachedLeaderboardScores.m_hSteamLeaderboardEntries != 0 )
{
for ( int Idx = 0; Idx < m_cachedLeaderboardScores.m_cEntryCount; Idx++ )
{
LeaderboardEntry_t leaderboardEntry;
if ( steamapicontext->SteamUserStats()->GetDownloadedLeaderboardEntry( m_cachedLeaderboardScores.m_hSteamLeaderboardEntries, Idx, &leaderboardEntry, NULL, 0 ) )
{
if ( leaderboardEntry.m_steamIDUser.ConvertToUint64() == m_PlayerXUID )
{
playerRow = Idx;
break;
}
}
}
}
#endif // !NO_STEAM
m_pScaleformUI->Params_SetResult( obj, playerRow );
}
//-----------------------------------------------------------------------------
// Purpose: Get the name of the user in our results list at the row specified
//-----------------------------------------------------------------------------
void CCreateLeaderboardsDialogScaleform::QueryRow_GamerTag( SCALEFORM_CALLBACK_ARGS_DECL )
{
int rowNumber = (int)( pui->Params_GetArgAsNumber( obj, 0 ) );
// We retrieve all friend info as one big list, so offset into that list by the current row we're filling in Flash
if ( m_currentFilterType == eLBFilter_Friends )
rowNumber += m_startingRowIndex;
const char *gamerTag = NULL;
#if defined( _X360 )
if ( rowNumber >= 0 && rowNumber < m_pResults.Count() )
{
gamerTag = m_pResults[rowNumber]->szGamertag;
}
#endif // _X360
#if !defined( NO_STEAM )
LeaderboardEntry_t leaderboardEntry;
if ( steamapicontext->SteamUserStats()->GetDownloadedLeaderboardEntry( m_cachedLeaderboardScores.m_hSteamLeaderboardEntries, rowNumber, &leaderboardEntry, NULL, 0 ) )
{
gamerTag = steamapicontext->SteamFriends()->GetFriendPersonaName( leaderboardEntry.m_steamIDUser );
}
#endif // !NO_STEAM
if ( !gamerTag )
gamerTag = "ERROR";
wchar_t unicodeName[MAX_NETWORKID_LENGTH];
g_pVGuiLocalize->ConvertANSIToUnicode( gamerTag, unicodeName, sizeof(unicodeName) );
wchar_t safe_wide_name[MAX_NETWORKID_LENGTH * 10 ]; // add enough room to safely escape all 64 name characters
safe_wide_name[0] = L'\0';
g_pScaleformUI->MakeStringSafe( unicodeName, safe_wide_name, sizeof( safe_wide_name ) );
SFVALUE sfGamertag = CreateFlashString( safe_wide_name );
m_pScaleformUI->Params_SetResult( obj, sfGamertag );
SafeReleaseSFVALUE( sfGamertag );
}
//-----------------------------------------------------------------------------
// Purpose: Get the column value in our results list at the row specified
//-----------------------------------------------------------------------------
void CCreateLeaderboardsDialogScaleform::QueryRow_ColumnValue( SCALEFORM_CALLBACK_ARGS_DECL )
{
int numArgs = pui->Params_GetNumArgs( obj );
if ( numArgs < 2 )
{
Warning( "QueryRow_ColumnValue: Invalid number of arguments in call to function: %d\n", numArgs );
return;
}
int rowNumber = (int)( pui->Params_GetArgAsNumber( obj, 0 ) );
// We retrieve all friend info as one big list, so offset into that list by the current row we're filling in Flash
if ( m_currentFilterType == eLBFilter_Friends )
rowNumber += m_startingRowIndex;
int columnId = (int)( pui->Params_GetArgAsNumber( obj, 1 ) );
int columnValue = -1;
char largeNumberString[64] = {0}; // if the field is a 64-bit value, we have to retrieve it as a string
#if defined( _X360 )
if ( rowNumber >= 0 && rowNumber < m_pResults.Count() )
{
XUSER_STATS_ROW *pRow = m_pResults[rowNumber];
if ( columnId == 0 )
{
// 0 retrieves just the player's Ranking (1st place player is 1, 2nd place is 2, etc)
columnValue = pRow->dwRank;
}
else if ( columnId == -1 )
{
// -1 gets the Rating column, used to Rank the player
V_snprintf( largeNumberString, sizeof(largeNumberString), "%lld", pRow->i64Rating );
}
else if ( columnId == -2 )
{
// -2 gets the row's overall board "Ranking / TotalRankedUsers"
DWORD totalViewRows = 0;
// Try to find the total view rows for this board
if ( m_pResultsBuffer && m_pResultsBuffer->dwNumViews > 0 )
{
totalViewRows = m_pResultsBuffer->pViews[0].dwTotalViewRows;
}
else if ( m_pFriendsResult[0] && m_pFriendsResult[0]->dwNumViews > 0 )
{
totalViewRows = m_pFriendsResult[0]->pViews[0].dwTotalViewRows;
}
if ( totalViewRows > 0 )
{
V_snprintf( largeNumberString, sizeof(largeNumberString), "%d / %d", pRow->dwRank, totalViewRows );
}
else
{
// Couldn't locate valid totalViewRows, so just return this row's rank
columnValue = pRow->dwRank;
}
}
else if ( columnId == -3 )
{
// -3 retrieves the total number of users ranked on this view
if ( m_pResultsBuffer && m_pResultsBuffer->dwNumViews > 0 )
{
columnValue = m_pResultsBuffer->pViews[0].dwTotalViewRows;
}
}
else
{
for ( DWORD colIdx = 0; colIdx < pRow->dwNumColumns; ++colIdx )
{
if ( pRow->pColumns[colIdx].wColumnId == columnId )
{
switch ( pRow->pColumns[colIdx].Value.type )
{
case XUSER_DATA_TYPE_INT64:
V_snprintf( largeNumberString, sizeof(largeNumberString), "%lld", pRow->pColumns[colIdx].Value.i64Data );
break;
case XUSER_DATA_TYPE_INT32:
columnValue = pRow->pColumns[colIdx].Value.nData;
break;
default:
Warning( "CCreateLeaderboardsDialogScaleform::QueryRow_ColumnValue - the type for columnId %d is not currently support: %d\n", columnId, pRow->pColumns[colIdx].Value.type );
break;
}
}
}
}
}
#endif // _X360
#if !defined( NO_STEAM )
LeaderboardEntry_t leaderboardEntry;
int lbDetails[kMaxPayloadEntries] = { 0 };
int numDetails = kMaxPayloadEntries;
if ( columnId == -3 )
{
// -3 retrieves the total number of users ranked on this view
columnValue = steamapicontext->SteamUserStats()->GetLeaderboardEntryCount( m_currentLeaderboardHandle );
}
else if ( columnId == -4 )
{
columnValue = ( steamapicontext->SteamUser()->BLoggedOn() ? 1 : 0 );
}
else
if ( m_currentLeaderboardHandle != 0 &&
m_cachedLeaderboardScores.m_hSteamLeaderboardEntries != 0 &&
steamapicontext->SteamUserStats()->GetDownloadedLeaderboardEntry( m_cachedLeaderboardScores.m_hSteamLeaderboardEntries, rowNumber, &leaderboardEntry, lbDetails, numDetails ) )
{
// DevMsg( "Reading from row %d columnId: %d, extra details count = %d.\n", rowNumber, columnId, numDetails );
if ( columnId == 0 )
{
int totalViewRows = steamapicontext->SteamUserStats()->GetLeaderboardEntryCount( m_currentLeaderboardHandle );
if ( totalViewRows > 0 )
{
if ( leaderboardEntry.m_nGlobalRank <= LEADERBOARD_SHOW_RANK_UNDER )
V_snprintf( largeNumberString, sizeof(largeNumberString), "%d", leaderboardEntry.m_nGlobalRank );
else
V_snprintf( largeNumberString, sizeof(largeNumberString), "%.1f%%", MAX( 0.1f, ((float)leaderboardEntry.m_nGlobalRank / (float)totalViewRows) * 100 ));
}
else
{
// Couldn't locate valid totalViewRows, so just return this row's rank
if ( leaderboardEntry.m_nGlobalRank <= LEADERBOARD_SHOW_RANK_UNDER )
columnValue = leaderboardEntry.m_nGlobalRank;
else
V_snprintf( largeNumberString, sizeof(largeNumberString), "%s", "--" );
}
}
else if ( columnId == -1 )
{
columnValue = leaderboardEntry.m_nScore;
}
else if ( columnId == -2 )
{
// -2 gets the row's overall board "Ranking / TotalRankedUsers"
int totalViewRows = steamapicontext->SteamUserStats()->GetLeaderboardEntryCount( m_currentLeaderboardHandle );
if ( totalViewRows > 0 )
{
if ( leaderboardEntry.m_nGlobalRank <= LEADERBOARD_SHOW_RANK_UNDER )
V_snprintf( largeNumberString, sizeof(largeNumberString), "%d", leaderboardEntry.m_nGlobalRank );
else
V_snprintf( largeNumberString, sizeof(largeNumberString), "%.1f%%", MAX( 0.1f, ((float)leaderboardEntry.m_nGlobalRank / (float)totalViewRows) * 100 ));
}
else
{
// Couldn't locate valid totalViewRows, so just return this row's rank
if ( leaderboardEntry.m_nGlobalRank <= LEADERBOARD_SHOW_RANK_UNDER )
columnValue = leaderboardEntry.m_nGlobalRank;
else
V_snprintf( largeNumberString, sizeof(largeNumberString), "%s", "--" );
}
}
else if ( columnId == -3 )
{
// -3 retrieves the total number of users ranked on this view
columnValue = steamapicontext->SteamUserStats()->GetLeaderboardEntryCount( m_currentLeaderboardHandle );
}
else
{
V_snprintf( largeNumberString, sizeof(largeNumberString), "%lld", ExtractPayloadDataByColumnID( lbDetails, columnId-1 ) );
}
}
#endif // !NO_STEAM
if ( largeNumberString[0] != 0 )
{
SFVALUE sfNumberString = CreateFlashString( largeNumberString );
m_pScaleformUI->Params_SetResult( obj, sfNumberString );
SafeReleaseSFVALUE( sfNumberString );
}
else
{
m_pScaleformUI->Params_SetResult( obj, columnValue );
}
}
//-----------------------------------------------------------------------------
// Purpose: Get the ratio of 2 column values in our results list at the row specified
// (for example, to retrieve the ratio of Kills to Deaths by querying
// those two columns in unison and returning their ratio).
//-----------------------------------------------------------------------------
void CCreateLeaderboardsDialogScaleform::QueryRow_ColumnRatio( SCALEFORM_CALLBACK_ARGS_DECL )
{
int numArgs = pui->Params_GetNumArgs( obj );
if ( numArgs < 3 )
{
Warning( "QueryRow_ColumnRatio: Invalid number of arguments in call to function: %d\n", numArgs );
return;
}
int rowNumber = (int)( pui->Params_GetArgAsNumber( obj, 0 ) );
// We retrieve all friend info as one big list, so offset into that list by the current row we're filling in Flash
if ( m_currentFilterType == eLBFilter_Friends )
rowNumber += m_startingRowIndex;
int columnIdA = (int)( pui->Params_GetArgAsNumber( obj, 1 ) );
int columnIdB = (int)( pui->Params_GetArgAsNumber( obj, 2 ) );
// Optional param: specify formatting string for result
const char *formatStr = "%3.3f";
if ( numArgs > 3 )
{
formatStr = pui->Params_GetArgAsString( obj, 3 );
}
// Optional param: If true, return the value scaled up by 100 to be a percentage
bool bPercentage = false;
if ( numArgs > 4 )
{
bPercentage = pui->Params_GetArgAsBool( obj, 4 );
}
// Optional param: If true, we want the ratio of columnA / (columnA+columnB) - useful for calculating win percentage
bool bRatioSumAB = false;
if ( numArgs > 5 )
{
bRatioSumAB = pui->Params_GetArgAsBool( obj, 5 );
}
#if defined( _X360 )
// Our resulting ratio will be "columnA / columnB" or "column A / (columnA + columnB)"
LONGLONG columnValueA = 0;
LONGLONG columnValueB = 0;
if ( rowNumber >= 0 && rowNumber < m_pResults.Count() )
{
XUSER_STATS_ROW *pRow = m_pResults[rowNumber];
if ( columnIdA == -1 )
{
columnValueA = pRow->i64Rating;
}
if ( columnIdB == -1 )
{
columnValueB = pRow->i64Rating;
}
if ( columnIdA == -2 )
{
columnValueA = pRow->dwRank;
}
if ( columnIdB == -2 )
{
columnValueB = pRow->dwRank;
}
for ( DWORD colIdx = 0; colIdx < pRow->dwNumColumns; ++colIdx )
{
bool bIsColumnA = pRow->pColumns[colIdx].wColumnId == columnIdA;
bool bIsColumnB = pRow->pColumns[colIdx].wColumnId == columnIdB;
if ( bIsColumnA || bIsColumnB )
{
switch ( pRow->pColumns[colIdx].Value.type )
{
case XUSER_DATA_TYPE_INT64:
if ( bIsColumnA )
columnValueA = pRow->pColumns[colIdx].Value.i64Data;
if ( bIsColumnB )
columnValueB = pRow->pColumns[colIdx].Value.i64Data;
break;
case XUSER_DATA_TYPE_INT32:
if ( bIsColumnA )
columnValueA = pRow->pColumns[colIdx].Value.nData;
if ( bIsColumnB )
columnValueB = pRow->pColumns[colIdx].Value.nData;
break;
default:
Warning( "CCreateLeaderboardsDialogScaleform::QueryRow_ColumnValue - the type for columnId %d is not currently support: %d\n", pRow->pColumns[colIdx].wColumnId, pRow->pColumns[colIdx].Value.type );
break;
}
}
}
}
#endif // _X360
#if !defined( NO_STEAM )
// Our resulting ratio will be "columnA / columnB" or "column A / (columnA + columnB)"
uint64 columnValueA = 0;
uint64 columnValueB = 0;
LeaderboardEntry_t leaderboardEntry;
int lbDetails[kMaxPayloadEntries] = { 0 };
int numDetails = kMaxPayloadEntries;
if ( m_currentLeaderboardHandle != 0 &&
m_cachedLeaderboardScores.m_hSteamLeaderboardEntries != 0 &&
steamapicontext->SteamUserStats()->GetDownloadedLeaderboardEntry( m_cachedLeaderboardScores.m_hSteamLeaderboardEntries, rowNumber, &leaderboardEntry, lbDetails, numDetails ) )
{
if ( columnIdA == -1 )
{
columnValueA = leaderboardEntry.m_nScore;
}
if ( columnIdB == -1 )
{
columnValueB = leaderboardEntry.m_nScore;
}
if ( columnIdA == -2 )
{
columnValueA = leaderboardEntry.m_nGlobalRank;
}
if ( columnIdB == -2 )
{
columnValueB = leaderboardEntry.m_nGlobalRank;
}
if ( columnIdA > 0 )
{
// 1+ are the details of the entry, subtract 1 to lookup in the array
columnValueA = ExtractPayloadDataByColumnID( lbDetails, columnIdA-1 );
}
if ( columnIdB > 0 )
{
// 1+ are the details of the entry, subtract 1 to lookup in the array
columnValueB = ExtractPayloadDataByColumnID( lbDetails, columnIdB-1 );
}
}
#endif // !NO_STEAM
#if !defined( NO_STEAM ) || defined( _X360 )
float fResult = (float)columnValueA;
float fDivisor = (float)columnValueB;
if ( bRatioSumAB )
{
// When this flag is set, we want to divide by the sum of the two columns, so we return the ratio of A to the sum of A and B
fDivisor = (float)columnValueA + (float)columnValueB;
}
if ( fDivisor != 0 )
{
fResult = (float)columnValueA / fDivisor;
}
if ( bPercentage )
{
fResult *= 100.f;
}
char ratioString[64];
V_snprintf( ratioString, sizeof(ratioString), formatStr, fResult );
SFVALUE sfRatioString = CreateFlashString( ratioString );
m_pScaleformUI->Params_SetResult( obj, sfRatioString );
SafeReleaseSFVALUE( sfRatioString );
#endif // !defined( NO_STEAM ) || defined( _X360 )
}
//-----------------------------------------------------------------------------
// Purpose: Trigger the display of additional info about a user in the specified
// row of our query results. i.e. On XBox this brings up the Gamer Card
//-----------------------------------------------------------------------------
void CCreateLeaderboardsDialogScaleform::DisplayUserInfo( SCALEFORM_CALLBACK_ARGS_DECL )
{
int rowNumber = (int)( pui->Params_GetArgAsNumber( obj, 0 ) );
// We retrieve all friend info as one big list, so offset into that list by the current row we're filling in Flash
if ( m_currentFilterType == eLBFilter_Friends )
rowNumber += m_startingRowIndex;
#if defined( _X360 )
if ( rowNumber >= 0 && rowNumber < m_pResults.Count() )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD( GET_ACTIVE_SPLITSCREEN_SLOT() );
XShowGamerCardUI( XBX_GetActiveUserId(), m_pResults[rowNumber]->xuid );
}
#endif // _X360
// Steam overlay not available on console (PS3)
#if !defined( _GAMECONSOLE ) && !defined( NO_STEAM )
// Show the steam user id in the overlay
LeaderboardEntry_t leaderboardEntry;
if ( m_currentLeaderboardHandle != 0 &&
m_cachedLeaderboardScores.m_hSteamLeaderboardEntries != 0 &&
steamapicontext->SteamUserStats()->GetDownloadedLeaderboardEntry( m_cachedLeaderboardScores.m_hSteamLeaderboardEntries, rowNumber, &leaderboardEntry, NULL, 0 ) )
{
steamapicontext->SteamFriends()->ActivateGameOverlayToUser( "steamid", leaderboardEntry.m_steamIDUser );
}
#endif // !_GAMECONSOLE && !NO_STEAM
}
//-----------------------------------------------------------------------------
// Purpose: Cancels any existing queries and issues a new query.
//-----------------------------------------------------------------------------
void CCreateLeaderboardsDialogScaleform::QueryUpdate( void )
{
// If we have no new query, early out
if ( m_fQueryDelayTime <= 0.f )
return;
// Don't actually update the query until our delay has passed
if ( Plat_FloatTime() < m_fQueryDelayTime )
return;
#if defined (_X360)
// Cancel any existing queries
if ( m_hAsyncQuery != 0 )
{
Warning( "Leaderboard: QueryUpdate: Triggering a new update with an AsynchHandle still in flight!\n" );
xboxsystem->CancelOverlappedOperation( m_hAsyncQuery );
xboxsystem->ReleaseAsyncHandle( m_hAsyncQuery );
m_hAsyncQuery = 0;
}
#ifdef DIAGNOSE_ASYNCH_PROBLEMS
printf( "Leaderboard: QueryUpdate: Starting a new network query; allocating an AsyncHandle.\n" );
#endif
// Create a new query handle
m_hAsyncQuery = xboxsystem->CreateAsyncHandle();
m_bCheckForQueryResults = false;
// Wipe out any previous results
if ( m_pResultsBuffer != NULL )
{
delete [] m_pResultsBuffer;
m_pResultsBuffer = NULL;
}
if ( m_currentFilterType != eLBFilter_Friends )
{
m_pResults.RemoveAll();
}
// Invalidate any results
m_bResultsValid = false;
m_fQueryDelayTime = 0.f;
// Write any XBox API results into this value
int asynchResult = ERROR_SUCCESS;
switch ( m_currentFilterType )
{
case eLBFilter_Me:
{
asynchResult = xboxsystem->EnumerateStatsByXuid( m_PlayerXUID, m_rowsPerPage, 1, &m_statsSpec, (void**)&m_pResultsBuffer, true, &m_hAsyncQuery );
}
break;
case eLBFilter_Overall:
{
asynchResult = xboxsystem->EnumerateStatsByRank( m_startingRowIndex, m_rowsPerPage, 1, &m_statsSpec, (void**)&m_pResultsBuffer, true, &m_hAsyncQuery );
}
break;
case eLBFilter_Friends:
{
// If we haven't retrieved our friends list yet, do that first
if ( m_pFriends == NULL )
{
// Reset our friend tracking members
m_iNextFriend = -1;
m_bEnumeratingFriends = true;
asynchResult = xboxsystem->EnumerateFriends( m_iPlayerSlot, (void**)&m_pFriends, true, &m_hAsyncQuery );
if ( asynchResult != ERROR_SUCCESS && asynchResult != ERROR_IO_PENDING )
{
// Free the buffer, and error out now!
delete [] m_pFriends;
m_pFriends = NULL;
Warning( "LEADERBOARDS: QueryUpdate - Failed to enumerate our friends!" );
}
}
else
{
// Once we have a friends list, start querying each user individually
if ( m_iNextFriend < 0 )
{
// Reset the results list now - from here on out, we're writing to this incrementally for each friend in our list
m_pResults.RemoveAll();
m_iNextFriend = 0;
// Local user comes first, first entry in friends result list
asynchResult = xboxsystem->EnumerateStatsByXuid( m_PlayerXUID, 1, 1, &m_statsSpec, (void**)&(m_pFriendsResult[m_iNextFriend]), true, &m_hAsyncQuery );
}
else
{
// Now, once for each friend in the list
// NOTE! m_pFriends has exactly NumFriends entries, but m_pFriendsResult has an extra leading entry for the local user!
asynchResult = xboxsystem->EnumerateStatsByXuid( m_pFriends[m_iNextFriend - 1].xuid, 1, 1, &m_statsSpec, (void**)&(m_pFriendsResult[m_iNextFriend]), true, &m_hAsyncQuery );
}
}
}
break;
}
// Check return value
if ( asynchResult != ERROR_SUCCESS && asynchResult != ERROR_IO_PENDING )
{
// Free the buffer, and error out now!
delete [] m_pResultsBuffer;
m_pResultsBuffer = NULL;
Warning( "LEADERBOARDS: QueryUpdate - Failed to enumerate leaderboard results!" );
return;
}
// Begin waiting for results to come back
m_bCheckForQueryResults = true;
#endif // _X360
#if !defined( NO_STEAM )
if ( !steamapicontext || !steamapicontext->SteamUserStats() )
return;
// Invalidate any results
m_bResultsValid = false;
V_memset( &m_cachedLeaderboardScores, 0, sizeof(LeaderboardScoresDownloaded_t) );
m_fQueryDelayTime = 0.f;
// Read out the leaderboard format description from matchmaking
if ( !m_pLeaderboardDescription )
m_pLeaderboardDescription->deleteThis();
m_pLeaderboardDescription = g_pMatchFramework->GetMatchTitle()->DescribeTitleLeaderboard( m_currentLeaderboardName );
// Extract payload data size info
V_memset( m_payloadSizes, 0, sizeof(int)*kMaxPayloadEntries );
KeyValues *pPayloadFormat = m_pLeaderboardDescription ? m_pLeaderboardDescription->FindKey( ":payloadformat" ) : NULL;
if ( pPayloadFormat )
{
for ( int payloadIndex=0; payloadIndex < kMaxPayloadEntries; ++payloadIndex )
{
KeyValues *pPayload = pPayloadFormat->FindKey( CFmtStr( "payload%d", payloadIndex ) );
if ( !pPayload )
{
// No more payload entries specified.
break;
}
const char* pszFormat = pPayload->GetString( ":format", NULL );
if ( V_stricmp( pszFormat, "int" ) == 0 )
{
m_payloadSizes[payloadIndex] += sizeof( uint32 );
}
else if ( V_stricmp( pszFormat, "uint64" ) == 0 )
{
m_payloadSizes[payloadIndex] += sizeof( uint64 );
}
else
{
Warning( " LEADERBOARDS: WARNING! Unsupported data type in leaderboard payload data - assuming 32 bit\n\n" );
m_payloadSizes[payloadIndex] += sizeof( uint32 );
}
}
}
m_currentLeaderboardHandle = GetLeaderboardHandle( m_currentLeaderboardName );
// If we haven't loaded this leaderboard yet, look up its handle first
if ( m_currentLeaderboardHandle == 0 )
{
SteamAPICall_t hSteamAPICall = steamapicontext->SteamUserStats()->FindLeaderboard( m_currentLeaderboardName );
if ( hSteamAPICall != 0 )
{
m_SteamCallResultFindLeaderboard.Set( hSteamAPICall, this, &CCreateLeaderboardsDialogScaleform::Steam_OnFindLeaderboard );
}
}
else
{
// We can perform our query for this leaderboard immediately
QueryLeaderboard( );
}
#endif // !NO_STEAM
}
#if !defined ( NO_STEAM )
uint64 CCreateLeaderboardsDialogScaleform::ExtractPayloadDataByColumnID( int *pData, int columnId )
{
char* pPtr = (char*)pData;
int curColumnId = 0;
if ( !pPtr )
return 0ull;
while ( curColumnId < columnId && curColumnId < kMaxPayloadEntries )
{
pPtr += m_payloadSizes[curColumnId++];
}
if ( curColumnId >= kMaxPayloadEntries )
return 0ull;
#if defined( PLAT_BIG_ENDIAN )
// On big-endian platforms, we need to byteswap the values written to Steam since we always write them little-endian
// and Steam doesn't swap them for us
return ( m_payloadSizes[curColumnId] == sizeof(uint32) ? DWordSwap(*(uint32*)pPtr) : QWordSwap(*(uint64*)pPtr) );
#else
return ( m_payloadSizes[curColumnId] == sizeof(uint32) ? (*(uint32*)pPtr) : (*(uint64*)pPtr) );
#endif
}
SteamLeaderboard_t CCreateLeaderboardsDialogScaleform::GetLeaderboardHandle( const char* szLeaderboardName )
{
// make a mapping of map contexts to leaderboard handles
unsigned short index = m_LeaderboardHandles.Find( szLeaderboardName );
if ( index != m_LeaderboardHandles.InvalidIndex() )
{
return m_LeaderboardHandles.Element(index);
}
return (SteamLeaderboard_t)0;
}
void CCreateLeaderboardsDialogScaleform::SetLeaderboardHandle( const char* szLeaderboardName, SteamLeaderboard_t hLeaderboard )
{
m_LeaderboardHandles.InsertOrReplace( szLeaderboardName, hLeaderboard );
}
//=============================================================================
// Callback for FindLeaderboard
//=============================================================================
void CCreateLeaderboardsDialogScaleform::Steam_OnFindLeaderboard( LeaderboardFindResult_t *pFindLeaderboardResult, bool bIOFailure )
{
// see if we encountered an error during the call
if ( !pFindLeaderboardResult->m_bLeaderboardFound || bIOFailure )
{
Warning( " Leaderboards: Steam error trying to retrieve leaderboard \"%s\"\n\n", m_currentLeaderboardName );
// Report the error now
m_bCheckForQueryResults = true;
return;
}
// check to see which leaderboard handle we just retrieved
const char *pszReturnedName = steamapicontext->SteamUserStats()->GetLeaderboardName( pFindLeaderboardResult->m_hSteamLeaderboard );
Assert( StringHasPrefix( pszReturnedName, m_currentLeaderboardName ) );
SetLeaderboardHandle( pszReturnedName, pFindLeaderboardResult->m_hSteamLeaderboard );
m_currentLeaderboardHandle = pFindLeaderboardResult->m_hSteamLeaderboard;
// Now we can perform our query for this leaderboard
QueryLeaderboard( );
}
//=============================================================================
// Callback for DownloadLeaderboardEntries
//=============================================================================
void CCreateLeaderboardsDialogScaleform::Steam_OnLeaderboardScoresDownloaded( LeaderboardScoresDownloaded_t *p, bool bError )
{
if ( bError )
Warning( " Leaderboard \"%s\": Steam_OnLeaderboardScoresDownloaded received an error.\n", m_currentLeaderboardName );
// Fetch the data if found and no error
if ( !bError )
{
// DevMsg( " Leaderboard \"%s\": %d Entries found.\n", m_currentLeaderboardName, p->m_cEntryCount );
V_memcpy( &m_cachedLeaderboardScores, p, sizeof( LeaderboardScoresDownloaded_t ) );
}
m_bCheckForQueryResults = true;
}
void CCreateLeaderboardsDialogScaleform::QueryLeaderboard( void )
{
SteamAPICall_t hSteamAPICall = (SteamAPICall_t)0;
if ( m_currentLeaderboardHandle == 0 )
{
Warning( " CCreateLeaderboardsDialogScaleform::QueryLeaderboard - leaderboard not found: \"%s\"\n", m_currentLeaderboardName );
// Report the error now
m_bCheckForQueryResults = true;
return;
}
switch ( m_currentFilterType )
{
case eLBFilter_Me:
{
hSteamAPICall = steamapicontext->SteamUserStats()->DownloadLeaderboardEntries( m_currentLeaderboardHandle, k_ELeaderboardDataRequestGlobalAroundUser, -(m_rowsPerPage/2), (m_rowsPerPage/2) );
}
break;
case eLBFilter_Overall:
{
hSteamAPICall = steamapicontext->SteamUserStats()->DownloadLeaderboardEntries( m_currentLeaderboardHandle, k_ELeaderboardDataRequestGlobal, m_startingRowIndex, m_startingRowIndex + m_rowsPerPage - 1 );
}
break;
case eLBFilter_Friends:
{
hSteamAPICall = steamapicontext->SteamUserStats()->DownloadLeaderboardEntries( m_currentLeaderboardHandle, k_ELeaderboardDataRequestFriends, 0, 0 );
}
break;
}
if ( hSteamAPICall )
{
// Register for the async callback
m_SteamCallbackOnLeaderboardScoresDownloaded.Set( hSteamAPICall, this, &CCreateLeaderboardsDialogScaleform::Steam_OnLeaderboardScoresDownloaded );
}
else
{
// Report the error now
m_bCheckForQueryResults = true;
}
}
#endif // !NO_STEAM
#if defined (_X360)
//=============================================================================
// Purpose: Sorts a vector of rank/indexes in to the results buffer so we can
// sort friend lists
//=============================================================================
int FriendsSortFunc( XUSER_STATS_ROW *const *a, XUSER_STATS_ROW *const *b )
{
if ( (*a)->dwRank < (*b)->dwRank )
return -1;
if ( (*a)->dwRank > (*b)->dwRank )
return 1;
return 0;
}
#endif // _X360
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCreateLeaderboardsDialogScaleform::CheckForQueryResults( void )
{
#if defined (_X360)
// No new query to check on
if ( !m_bCheckForQueryResults )
return;
// Check our async handle to see if it's done
uint iResultCode = 0;
int result = xboxsystem->GetOverlappedResult( m_hAsyncQuery, &iResultCode, false );
// Abort on non-recoverable error codes
if ( result == ERROR_INVALID_HANDLE ||
result == ERROR_FUNCTION_FAILED )
{
Warning( "LEADERBOARDS: CheckForQueryResults got error code: %s. Aborting query.", result == ERROR_INVALID_HANDLE ? "ERROR_INVALID_HANDLE" : "ERROR_FUNCTION_FAILED ");
if ( m_hAsyncQuery != 0 )
{
xboxsystem->ReleaseAsyncHandle( m_hAsyncQuery );
m_hAsyncQuery = 0;
}
// Signal flash to terminate
WITH_SLOT_LOCKED
{
ScaleformUI()->Value_InvokeWithoutReturn( m_FlashAPI, "NotifyResults", 0, NULL );
}
m_bCheckForQueryResults = false;
return;
}
#ifdef DIAGNOSE_ASYNCH_PROBLEMS
printf( "Leaderboard: CheckForQueryResults - GetOverlappedResult returns %d, (result code %d)\n", result, iResultCode );
#endif
// If we are still retrieving friends info, check on that operation first
if ( m_bEnumeratingFriends )
{
if ( result == ERROR_SUCCESS )
{
m_iNumFriends = iResultCode;
m_bEnumeratingFriends = false;
m_bCheckForQueryResults = false;
// Queue up the next query
m_fQueryDelayTime = Plat_FloatTime() + QUERY_SHORT_DELAY_TIME;
}
return;
}
// Our query is complete, now we need to see if the query ran into any errors
if ( result == ERROR_SUCCESS )
{
// Filter: FRIENDS
// Handle friends differently, by pushing multiple queries until we've read out everyone
if ( m_currentFilterType == eLBFilter_Friends )
{
// Check that the friend result is valid, and add it to our vector
if ( m_pFriendsResult[m_iNextFriend] &&
m_pFriendsResult[m_iNextFriend]->dwNumViews > 0 &&
m_pFriendsResult[m_iNextFriend]->pViews[0].dwNumRows > 0 )
{
#ifdef DIAGNOSE_ASYNCH_PROBLEMS
printf( "Found FRIEND result user = %s: xuid: %d columns: %d (rank: %d with rating: %lld) \n",
m_pFriendsResult[m_iNextFriend]->pViews[0].pRows[0].szGamertag, m_pFriendsResult[m_iNextFriend]->pViews[0].pRows[0].xuid,
m_pFriendsResult[m_iNextFriend]->pViews[0].pRows[0].dwNumColumns, m_pFriendsResult[m_iNextFriend]->pViews[0].pRows[0].dwRank,
m_pFriendsResult[m_iNextFriend]->pViews[0].pRows[0].i64Rating );
#endif
if ( m_pFriendsResult[m_iNextFriend]->pViews[0].pRows[0].dwRank > 0 )
{
m_pResults.AddToTail( &m_pFriendsResult[m_iNextFriend]->pViews[0].pRows[0] );
}
}
m_iNextFriend++;
if ( m_iNextFriend < m_iNumFriends + 1 )
{
m_bCheckForQueryResults = false;
// Queue up the next query
m_fQueryDelayTime = Plat_FloatTime() + QUERY_SHORT_DELAY_TIME;
return;
}
else
{
// Now sort the results list by the ranking column
m_pResults.Sort( FriendsSortFunc );
// we have all results, return now!
m_bResultsValid = true;
}
}
// Filter: Overall/Me
// Non-friends query - all results come back in one batch
else
{
// We assume the results are valid now, and push only ranked values into our m_pResults list
m_bResultsValid = true;
// Reset the list, fill it with current data
m_pResults.RemoveAll();
// Make sure to update the starting index based on the actual starting index we get back from the results
if ( m_pResultsBuffer )
{
if ( m_pResultsBuffer->dwNumViews > 0 &&
m_pResultsBuffer->pViews[0].dwNumRows > 0 )
{
// Copy pointers to our results buffer into a vector so we can sort and handle friends properly
for ( uint i=0; i<m_pResultsBuffer->pViews[0].dwNumRows; i++ )
{
// Only add players that are ranked
if ( m_pResultsBuffer->pViews[0].pRows[i].dwRank > 0 )
{
m_pResults.AddToTail( &m_pResultsBuffer->pViews[0].pRows[i] );
#ifdef DIAGNOSE_ASYNCH_PROBLEMS
printf( "Found result user = %s: xuid: %d columns: %d (rank: %d with rating: %lld) \n",
m_pResultsBuffer->pViews[0].pRows[i].szGamertag, m_pResultsBuffer->pViews[0].pRows[i].xuid,
m_pResultsBuffer->pViews[0].pRows[i].dwNumColumns, m_pResultsBuffer->pViews[0].pRows[i].dwRank,
m_pResultsBuffer->pViews[0].pRows[i].i64Rating );
for ( DWORD col = 0; col < m_pResultsBuffer->pViews[0].pRows[i].dwNumColumns; col++ )
{
printf( " column[%d] (type %d) = %d \n", col,
m_pResultsBuffer->pViews[0].pRows[i].pColumns[col].wColumnId,
m_pResultsBuffer->pViews[0].pRows[i].pColumns[col].Value.nData );
}
#endif
}
}
}
}
}
// Signal Flash that we are ready to show results
WITH_SLOT_LOCKED
{
ScaleformUI()->Value_InvokeWithoutReturn( m_FlashAPI, "NotifyResults", 0, NULL );
}
m_bCheckForQueryResults = false;
}
#endif // _X360
#if !defined( NO_STEAM )
// No new query to check on
if ( !m_bCheckForQueryResults )
return;
// Signal Flash that we are ready to show results
WITH_SLOT_LOCKED
{
ScaleformUI()->Value_InvokeWithoutReturn( m_FlashAPI, "NotifyResults", 0, NULL );
}
m_bCheckForQueryResults = false;
#endif // !NO_STEAM
}
#endif // INCLUDE_SCALEFORM