This commit is contained in:
Riley Labrecque
2014-01-29 12:59:35 +02:00
parent 84141487ef
commit c089bcacfa
76 changed files with 956 additions and 376 deletions
+321
View File
@@ -0,0 +1,321 @@
//========= Copyright © 1996-2009, Valve LLC, All rights reserved. ============
//
// Purpose: Class for tracking leaderboards
//
//=============================================================================
#include "stdafx.h"
#include "leaderboards.h"
#include <math.h>
#include "steam/isteamuserstats.h"
//-----------------------------------------------------------------------------
// Purpose: Menu that shows a leaderboard
//-----------------------------------------------------------------------------
class CLeaderboardMenu : public CBaseMenu<LeaderboardMenuItem_t>
{
static const int k_nMaxLeaderboardEntries = 10; // maximum number of leaderboard entries we can display
LeaderboardEntry_t m_leaderboardEntries[k_nMaxLeaderboardEntries]; // leaderboard entries we received from DownloadLeaderboardEntries
int m_nLeaderboardEntries; // number of leaderboard entries we received
SteamLeaderboard_t m_hSteamLeaderboard; // handle to the leaderboard we are displaying
ELeaderboardDataRequest m_eLeaderboardData; // type of data we are displaying
bool m_bLoading; // waiting to receive leaderboard results
bool m_bIOFailure; // last attempt to retrieve the leaderboard failed
CCallResult<CLeaderboardMenu, LeaderboardScoresDownloaded_t> m_callResultDownloadEntries;
public:
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CLeaderboardMenu( CGameEngine *pGameEngine ) : CBaseMenu<LeaderboardMenuItem_t>( pGameEngine )
{
m_hSteamLeaderboard = 0;
m_nLeaderboardEntries = 0;
m_bLoading = false;
m_bIOFailure = false;
}
//-----------------------------------------------------------------------------
// Purpose: Menu that shows a leaderboard
//-----------------------------------------------------------------------------
void ShowLeaderboard( SteamLeaderboard_t hLeaderboard, ELeaderboardDataRequest eLeaderboardData, int offset )
{
m_hSteamLeaderboard = hLeaderboard;
m_eLeaderboardData = eLeaderboardData;
m_bLoading = true;
m_bIOFailure = false;
if ( hLeaderboard )
{
// load the specified leaderboard data. We only display k_nMaxLeaderboardEntries entries at a time
SteamAPICall_t hSteamAPICall = SteamUserStats()->DownloadLeaderboardEntries( hLeaderboard, eLeaderboardData,
offset, offset + k_nMaxLeaderboardEntries );
// Register for the async callback
m_callResultDownloadEntries.Set( hSteamAPICall, this, &CLeaderboardMenu::OnLeaderboardDownloadedEntries );
}
Rebuild();
}
//-----------------------------------------------------------------------------
// Purpose: Creates leaderboard menu
//-----------------------------------------------------------------------------
void Rebuild()
{
PushSelectedItem();
ClearMenuItems();
LeaderboardMenuItem_t menuItemEmpty = { 0 };
LeaderboardMenuItem_t menuItemBack = { true, false };
LeaderboardMenuItem_t menuItemNextLeaderboard = { false, true };
if ( m_hSteamLeaderboard )
{
// create a header for the leaderboard
std::string strName = "Leaderboard: ";
strName += SteamUserStats()->GetLeaderboardName( m_hSteamLeaderboard );
if ( m_eLeaderboardData == k_ELeaderboardDataRequestGlobal )
strName += ", Top 10";
else if ( m_eLeaderboardData == k_ELeaderboardDataRequestGlobalAroundUser )
strName += ", Around User";
else if ( m_eLeaderboardData == k_ELeaderboardDataRequestFriends )
strName += ", Friends of User";
AddMenuItem( CLeaderboardMenu::MenuItem_t( strName, menuItemEmpty ) );
}
// create leaderboard
if ( !m_hSteamLeaderboard || m_bLoading )
{
AddMenuItem( CLeaderboardMenu::MenuItem_t( "Loading...", menuItemEmpty ) );
}
else if ( m_bIOFailure )
{
AddMenuItem( CLeaderboardMenu::MenuItem_t( "Network failure!", menuItemEmpty ) );
}
else
{
if ( m_nLeaderboardEntries == 0 )
{
// Requesting for global scores around the user will return successfully with 0 results if the
// user does not have an entry on the leaderboard
std::string strText;
if ( m_eLeaderboardData != k_ELeaderboardDataRequestGlobalAroundUser )
{
strText = "No scores for this leaderboard";
}
else
{
strText = SteamFriends()->GetPersonaName();
strText += " does not have a score for this leaderboard";
}
AddMenuItem( CLeaderboardMenu::MenuItem_t( strText, menuItemEmpty ) );
}
for ( int index = 0; index < m_nLeaderboardEntries; index++ )
{
char rgchMenuText[256];
const char *pchName = SteamFriends()->GetFriendPersonaName( m_leaderboardEntries[index].m_steamIDUser );
_snprintf( rgchMenuText, sizeof( rgchMenuText ), "(%d) %s - %d", m_leaderboardEntries[index].m_nGlobalRank,
pchName, m_leaderboardEntries[index].m_nScore );
AddMenuItem( MenuItem_t( std::string( rgchMenuText ), menuItemEmpty ) );
}
}
// navigation buttons
AddMenuItem( CLeaderboardMenu::MenuItem_t( "Next leaderboard", menuItemNextLeaderboard ) );
AddMenuItem( CLeaderboardMenu::MenuItem_t( "Return to main menu", menuItemBack ) );
PopSelectedItem();
}
//-----------------------------------------------------------------------------
// Purpose: Called when SteamUserStats()->DownloadLeaderboardEntries() returns asynchronously
//-----------------------------------------------------------------------------
void OnLeaderboardDownloadedEntries( LeaderboardScoresDownloaded_t *pLeaderboardScoresDownloaded, bool bIOFailure )
{
m_bLoading = false;
m_bIOFailure = bIOFailure;
// leaderboard entries handle will be invalid once we return from this function. Copy all data now.
m_nLeaderboardEntries = min( pLeaderboardScoresDownloaded->m_cEntryCount, k_nMaxLeaderboardEntries );
for ( int index = 0; index < m_nLeaderboardEntries; index++ )
{
SteamUserStats()->GetDownloadedLeaderboardEntry( pLeaderboardScoresDownloaded->m_hSteamLeaderboardEntries,
index, &m_leaderboardEntries[ index ], NULL, 0 );
}
// show our new data
Rebuild();
}
};
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CLeaderboards::CLeaderboards( CGameEngine *pGameEngine ) : m_pGameEngine( pGameEngine )
{
m_hQuickestWinLeaderboard = 0;
m_hFeetTraveledLeaderboard = 0;
m_nCurrentLeaderboard = 0;
m_pLeaderboardMenu = new CLeaderboardMenu( pGameEngine );
m_bLoading = false;
FindLeaderboards();
}
//-----------------------------------------------------------------------------
// Purpose: Run a frame for the CLeaderboards
//-----------------------------------------------------------------------------
void CLeaderboards::RunFrame()
{
m_pLeaderboardMenu->RunFrame();
}
//-----------------------------------------------------------------------------
// Purpose: Handles menu actions when viewing a leaderboard
//-----------------------------------------------------------------------------
void CLeaderboards::OnMenuSelection( LeaderboardMenuItem_t selection )
{
if ( selection.m_bBack )
{
SpaceWarClient()->SetGameState( k_EClientGameMenu );
}
else if ( selection.m_bNextLeaderboard )
{
m_nCurrentLeaderboard = ++m_nCurrentLeaderboard % 2;
Show();
}
}
//-----------------------------------------------------------------------------
// Purpose: Shows / Refreshes the leaderboard
//-----------------------------------------------------------------------------
void CLeaderboards::Show()
{
if ( m_nCurrentLeaderboard == 0 )
{
// we want to show the top 10. To do so, we request global score data beginning at 0
m_pLeaderboardMenu->ShowLeaderboard( m_hQuickestWinLeaderboard, k_ELeaderboardDataRequestGlobal, 0 );
}
else if ( m_nCurrentLeaderboard == 1 )
{
// we want to show the 10 users around us
m_pLeaderboardMenu->ShowLeaderboard( m_hFeetTraveledLeaderboard, k_ELeaderboardDataRequestGlobalAroundUser, -5 );
}
}
//-----------------------------------------------------------------------------
// Purpose: Gets handles for our leaderboards. If the leaderboards don't exist, creates them.
// Each time this is called, we look up another leaderboard.
//-----------------------------------------------------------------------------
void CLeaderboards::FindLeaderboards()
{
if ( m_bLoading )
return;
SteamAPICall_t hSteamAPICall = 0;
if ( !m_hQuickestWinLeaderboard )
{
// find/create a leaderboard for the quickest win
hSteamAPICall = SteamUserStats()->FindOrCreateLeaderboard( LEADERBOARD_QUICKEST_WIN,
k_ELeaderboardSortMethodAscending, k_ELeaderboardDisplayTypeTimeSeconds );
}
else if ( !m_hFeetTraveledLeaderboard )
{
// find/create a leaderboard for the most feet traveled in 1 round
hSteamAPICall = SteamUserStats()->FindOrCreateLeaderboard( LEADERBOARD_FEET_TRAVELED,
k_ELeaderboardSortMethodDescending, k_ELeaderboardDisplayTypeNumeric );
}
if ( hSteamAPICall != 0 )
{
// set the function to call when this API call has completed
m_SteamCallResultCreateLeaderboard.Set( hSteamAPICall, this, &CLeaderboards::OnFindLeaderboard );
m_bLoading = true;
}
}
//-----------------------------------------------------------------------------
// Purpose: Called when SteamUserStats()->FindOrCreateLeaderboard() returns asynchronously
//-----------------------------------------------------------------------------
void CLeaderboards::OnFindLeaderboard( LeaderboardFindResult_t *pFindLeaderboardResult, bool bIOFailure )
{
m_bLoading = false;
// see if we encountered an error during the call
if ( !pFindLeaderboardResult->m_bLeaderboardFound || bIOFailure )
return;
// check to see which leaderboard handle we just retrieved
const char *pchName = SteamUserStats()->GetLeaderboardName( pFindLeaderboardResult->m_hSteamLeaderboard );
if ( strcmp( pchName, LEADERBOARD_QUICKEST_WIN ) == 0 )
m_hQuickestWinLeaderboard = pFindLeaderboardResult->m_hSteamLeaderboard;
else if ( strcmp( pchName, LEADERBOARD_FEET_TRAVELED ) == 0 )
m_hFeetTraveledLeaderboard = pFindLeaderboardResult->m_hSteamLeaderboard;
// look up any other leaderboards
FindLeaderboards();
// if the user is currently looking at a leaderboard, it might be one we didn't have a handle for yet. Update the leaderboard.
if ( SpaceWarClient()->GetGameState() == k_EClientLeaderboards )
Show();
}
//-----------------------------------------------------------------------------
// Purpose: Updates leaderboards with stats from our just finished game
//-----------------------------------------------------------------------------
void CLeaderboards::UpdateLeaderboards( CStatsAndAchievements *pStats )
{
// if the user won, update the leaderboard with the time it took. If the user's previous time was faster, this time will be thrown out.
if ( m_hQuickestWinLeaderboard && SpaceWarClient()->BLocalPlayerWonLastGame() )
{
SteamAPICall_t hSteamAPICall = SteamUserStats()->UploadLeaderboardScore( m_hQuickestWinLeaderboard, (int)pStats->GetGameDurationSeconds(), NULL, 0 );
m_SteamCallResultUploadScore.Set( hSteamAPICall, this, &CLeaderboards::OnUploadScore );
}
// update the leaderboard for the most feet traveled in 1 round. If the user previously traveled farther in a round than this one,
// this value will be thrown out
if ( m_hFeetTraveledLeaderboard )
{
SteamUserStats()->UploadLeaderboardScore( m_hFeetTraveledLeaderboard, (int)pStats->GetGameFeetTraveled(), NULL, 0 );
}
}
//-----------------------------------------------------------------------------
// Purpose: Called when SteamUserStats()->UploadLeaderboardScore() returns asynchronously
//-----------------------------------------------------------------------------
void CLeaderboards::OnUploadScore( LeaderboardScoreUploaded_t *pScoreUploadedResult, bool bIOFailure )
{
if ( !pScoreUploadedResult->m_bSuccess )
{
// error
}
if ( pScoreUploadedResult->m_bScoreChanged )
{
// could display new rank
}
}
+64
View File
@@ -0,0 +1,64 @@
//========= Copyright © 1996-2009, Valve LLC, All rights reserved. ============
//
// Purpose: Class for tracking leaderboards
//
//=============================================================================
#ifndef LEADERBOARDS_H
#define LEADERBOARDS_H
#include "SpaceWar.h"
#include "GameEngine.h"
#include "steam/isteamuserstats.h"
#include "StatsAndAchievements.h"
#include "SpaceWarClient.h"
class ISteamUser;
class CSpaceWarClient;
class CLeaderboardMenu;
class CLeaderboards
{
public:
// Constructor
CLeaderboards( CGameEngine *pGameEngine );
// Run a frame
void RunFrame();
// shows / refreshes leaderboard
void Show();
// Updates leaderboards with stats from our just finished game
void UpdateLeaderboards( CStatsAndAchievements *pStats );
// handles input from leaderboard menu
void OnMenuSelection( LeaderboardMenuItem_t selection );
private:
void FindLeaderboards();
// Engine
CGameEngine *m_pGameEngine;
// Called when SteamUserStats()->FindOrCreateLeaderboard() returns asynchronously
void OnFindLeaderboard( LeaderboardFindResult_t *pFindLearderboardResult, bool bIOFailure );
CCallResult<CLeaderboards, LeaderboardFindResult_t> m_SteamCallResultCreateLeaderboard;
// Called when SteamUserStats()->UploadLeaderboardScore() returns asynchronously
void OnUploadScore( LeaderboardScoreUploaded_t *pFindLearderboardResult, bool bIOFailure );
CCallResult<CLeaderboards, LeaderboardScoreUploaded_t> m_SteamCallResultUploadScore;
// handles to our leaderboards
SteamLeaderboard_t m_hQuickestWinLeaderboard;
SteamLeaderboard_t m_hFeetTraveledLeaderboard;
int m_bLoading; // true if we looking up a leaderboard handle
CLeaderboardMenu *m_pLeaderboardMenu; // Displays the current leaderboard
int m_nCurrentLeaderboard; // Index for leaderboard the user is currently viewing
};
#endif // LEADERBOARDS_H
+6 -2
View File
@@ -56,8 +56,12 @@ public:
AddMenuItem( CLobbyMenu::MenuItem_t( "Set myself as Ready", menuItem ) );
}
// bugbug taylor make it so we can find out who the lobby owner is
bool bLobbyOwner = true;
// see if the local user is the owner of this lobby
bool bLobbyOwner = false;
if ( SteamUser()->GetSteamID() == SteamMatchmaking()->GetLobbyOwner( steamIDLobby ) )
{
bLobbyOwner = true;
}
// start game
if ( bLobbyOwner )
+1
View File
@@ -22,6 +22,7 @@ CMainMenu::CMainMenu( CGameEngine *pGameEngine ) : CBaseMenu<EClientGameState>(
AddMenuItem( MenuItem_t( "Find Lobby", k_EClientFindLobby ) );
AddMenuItem( MenuItem_t( "Instructions", k_EClientGameInstructions ) );
AddMenuItem( MenuItem_t( "Stats and Achievements", k_EClientStatsAchievements ) );
AddMenuItem( MenuItem_t( "Leaderboards", k_EClientLeaderboards ) );
AddMenuItem( MenuItem_t( "Remote Storage", k_EClientRemoteStorage ) );
AddMenuItem( MenuItem_t( "Exit Game", k_EClientGameExiting ) );
}
+6
View File
@@ -77,6 +77,11 @@
#define MAX_CLIENT_AND_SERVER_FPS 86
// Leaderboard names
#define LEADERBOARD_QUICKEST_WIN "Quickest Win"
#define LEADERBOARD_FEET_TRAVELED "Feet Traveled"
// Player colors
DWORD const g_rgPlayerColors[ MAX_PLAYERS_PER_SERVER ] =
{
@@ -109,6 +114,7 @@ enum EClientGameState
k_EClientJoiningLobby,
k_EClientFindLANServers,
k_EClientRemoteStorage,
k_EClientLeaderboards,
};
+48 -1
View File
@@ -13,6 +13,7 @@
#include "stdlib.h"
#include "time.h"
#include "ServerBrowser.h"
#include "Leaderboards.h"
#include "Lobby.h"
CSpaceWarClient *g_pSpaceWarClient = NULL;
@@ -24,7 +25,9 @@ CSpaceWarClient* SpaceWarClient() { return g_pSpaceWarClient; }
CSpaceWarClient::CSpaceWarClient( CGameEngine *pGameEngine, CSteamID steamIDUser ) :
m_SocketStatusCallback( this, &CSpaceWarClient::OnSocketStatusCallback ),
m_LobbyGameCreated( this, &CSpaceWarClient::OnLobbyGameCreated ),
m_IPCFailureCallback( this, &CSpaceWarClient::OnIPCFailure )
m_IPCFailureCallback( this, &CSpaceWarClient::OnIPCFailure ),
m_SteamShutdownCallback( this, &CSpaceWarClient::OnSteamShutdown )
{
g_pSpaceWarClient = this;
m_pGameEngine = pGameEngine;
@@ -78,6 +81,7 @@ CSpaceWarClient::CSpaceWarClient( CGameEngine *pGameEngine, CSteamID steamIDUser
// Init stats
m_pStatsAndAchievements = new CStatsAndAchievements( pGameEngine );
m_pLeaderboards = new CLeaderboards( pGameEngine );
// Remote Storage page
m_pRemoteStorage = new CRemoteStorage( pGameEngine );
@@ -668,6 +672,15 @@ void CSpaceWarClient::OnMenuSelection( LobbyMenuItem_t selection )
}
//-----------------------------------------------------------------------------
// Purpose: Handles menu actions when viewing a leaderboard
//-----------------------------------------------------------------------------
void CSpaceWarClient::OnMenuSelection( LeaderboardMenuItem_t selection )
{
m_pLeaderboards->OnMenuSelection( selection );
}
//-----------------------------------------------------------------------------
// Purpose: does work on transitioning from one game state to another
//-----------------------------------------------------------------------------
@@ -711,6 +724,16 @@ void CSpaceWarClient::OnGameStateChanged( EClientGameState eGameStateNew )
m_pServer = NULL;
}
}
else if ( m_eGameState == k_EClientGameWinner || m_eGameState == k_EClientGameDraw )
{
// game over.. update the leaderboard
m_pLeaderboards->UpdateLeaderboards( m_pStatsAndAchievements );
}
else if ( m_eGameState == k_EClientLeaderboards )
{
// we've switched to the leaderboard menu
m_pLeaderboards->Show();
}
}
//-----------------------------------------------------------------------------
@@ -730,6 +753,22 @@ void CSpaceWarClient::OnIPCFailure( IPCFailure_t *failure )
}
}
//-----------------------------------------------------------------------------
// Purpose: Handles notification of a Steam shutdown request since a Windows
// user in a second concurrent session requests to play this game. Shutdown
// this process immediately if possible.
//-----------------------------------------------------------------------------
void CSpaceWarClient::OnSteamShutdown( SteamShutdown_t *callback )
{
static bool bExiting = false;
if ( !bExiting )
{
OutputDebugString( "Steam shutdown request, shutting down\n" );
m_pGameEngine->Shutdown();
bExiting = true;
}
}
//-----------------------------------------------------------------------------
// Purpose: Main frame function, updates the state of the world and performs rendering
@@ -881,6 +920,14 @@ void CSpaceWarClient::RunFrame()
if ( bEscapePressed )
SetGameState( k_EClientGameMenu );
break;
case k_EClientLeaderboards:
m_pStarField->Render();
m_pLeaderboards->RunFrame();
if ( bEscapePressed )
SetGameState( k_EClientGameMenu );
break;
case k_EClientRemoteStorage:
m_pStarField->Render();
m_pRemoteStorage->Render();
+14
View File
@@ -27,6 +27,7 @@ class CSpaceWarServer;
class CServerBrowser;
class CLobbyBrowser;
class CLobby;
class CLeaderboards;
// Height of the HUD font
#define HUD_FONT_HEIGHT 18
@@ -66,6 +67,13 @@ struct LobbyMenuItem_t
bool m_bLeaveLobby;
};
// a leaderboard item
struct LeaderboardMenuItem_t
{
bool m_bBack;
bool m_bNextLeaderboard;
};
class CSpaceWarClient
@@ -120,6 +128,7 @@ public:
}
void OnMenuSelection( LobbyMenuItem_t selection );
void OnMenuSelection( LeaderboardMenuItem_t selection );
// Set game state
void SetGameState( EClientGameState eState );
@@ -256,6 +265,8 @@ private:
CStatsAndAchievements *m_pStatsAndAchievements;
CLeaderboards *m_pLeaderboards;
CServerBrowser *m_pServerBrowser;
CRemoteStorage *m_pRemoteStorage;
@@ -284,6 +295,9 @@ private:
// ipc failure handler
STEAM_CALLBACK( CSpaceWarClient, OnIPCFailure, IPCFailure_t, m_IPCFailureCallback );
// Steam wants to shut down, Game for Windows applications should shutdown too
STEAM_CALLBACK( CSpaceWarClient, OnSteamShutdown, SteamShutdown_t, m_SteamShutdownCallback );
};
extern CSpaceWarClient *g_pSpaceWarClient;
+5
View File
@@ -0,0 +1,5 @@
/////////////////////////////////////////////////////////////////////////////
// Header File for : SpaceWar
#define ID_ICON 101
/////////////////////////////////////////////////////////////////////////////
+4
View File
@@ -52,6 +52,10 @@ public:
// Accumulators
void AddDistanceTraveled( float flDistance );
// accessors
float GetGameFeetTraveled() { return m_flGameFeetTraveled; }
double GetGameDurationSeconds() { return m_flGameDurationSeconds; }
STEAM_CALLBACK( CStatsAndAchievements, OnUserStatsReceived, UserStatsReceived_t, m_CallbackUserStatsReceived );
STEAM_CALLBACK( CStatsAndAchievements, OnUserStatsStored, UserStatsStored_t, m_CallbackUserStatsStored );
STEAM_CALLBACK( CStatsAndAchievements, OnAchievementStored, UserAchievementStored_t, m_CallbackAchievementStored );
@@ -214,6 +214,10 @@
RelativePath=".\BaseMenu.cpp"
>
</File>
<File
RelativePath=".\Leaderboards.cpp"
>
</File>
<File
RelativePath=".\Lobby.cpp"
>
@@ -296,6 +300,10 @@
RelativePath=".\BaseMenu.h"
>
</File>
<File
RelativePath=".\Leaderboards.h"
>
</File>
<File
RelativePath=".\Lobby.h"
>