Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

849 lines
28 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================
  7. #include "cbase.h"
  8. #include "tf_mapinfo.h"
  9. #include <filesystem.h>
  10. #include "GameEventListener.h"
  11. #include "econ_item_system.h"
  12. #include "tf_item_inventory.h"
  13. #include "econ_contribution.h"
  14. #include "tf_duel_summary.h"
  15. #include "gc_clientsystem.h"
  16. #include "tf_duckleaderboard.h"
  17. #include "tf_gamerules.h"
  18. #include "tf_matchmaking_shared.h"
  19. #ifdef CLIENT_DLL
  20. #include "hud_macros.h"
  21. #endif // CLIENT_DLL
  22. // memdbgon must be the last include file in a .cpp file!!!
  23. #include <tier0/memdbgon.h>
  24. #ifdef CLIENT_DLL
  25. ConVar tf_duck_upload_rate( "tf_duck_upload_rate", "2400", FCVAR_DEVELOPMENTONLY ); // Make this DevOnly At ship and 60 seconds
  26. #endif
  27. const char *g_szLadderLeaderboardNames[] =
  28. {
  29. "tf2_ladder_6v6",
  30. "tf2_ladder_public",
  31. "tf2_ladder_9v9",
  32. "tf2_ladder_12v12",
  33. };
  34. COMPILE_TIME_ASSERT( ARRAYSIZE( g_szLadderLeaderboardNames ) == LADDER_LEADERBOARDS_MAX );
  35. void __MsgFunc_EOTLDuckEvent( bf_read &msg );
  36. //-----------------------------------------------------------------------------
  37. int SortLeaderboardVec( LeaderboardEntry_t * const *p1, LeaderboardEntry_t * const *p2 )
  38. {
  39. return ( *p2 )->m_nScore - ( *p1 )->m_nScore;
  40. }
  41. //-----------------------------------------------------------------------------
  42. static void RetrieveLeaderboardEntries( LeaderboardScoresDownloaded_t &scores, CUtlVector< LeaderboardEntry_t* > &entries )
  43. {
  44. entries.PurgeAndDeleteElements();
  45. entries.EnsureCapacity( scores.m_cEntryCount );
  46. for ( int i = 0; i < scores.m_cEntryCount; ++i )
  47. {
  48. LeaderboardEntry_t *leaderboardEntry = new LeaderboardEntry_t;
  49. if ( steamapicontext->SteamUserStats()->GetDownloadedLeaderboardEntry( scores.m_hSteamLeaderboardEntries, i, leaderboardEntry, NULL, 0 ) )
  50. {
  51. entries.AddToTail( leaderboardEntry );
  52. }
  53. }
  54. }
  55. CLeaderboardInfo::CLeaderboardInfo( const char *pLeaderboardName )
  56. {
  57. m_pLeaderboardName = pLeaderboardName ? V_strdup( pLeaderboardName ) : NULL;
  58. memset( &findLeaderboardResults, 0, sizeof( findLeaderboardResults ) );
  59. iNumLeaderboardEntries = 0;
  60. m_kLeaderboardType = kMapLeaderboard;
  61. m_iMyScore = 0;
  62. m_bHasPendingUpdate = false;
  63. m_bLeaderboardFound = false;
  64. }
  65. CLeaderboardInfo::~CLeaderboardInfo()
  66. {
  67. downloadedLeaderboardScoresGlobal.PurgeAndDeleteElements();
  68. downloadedLeaderboardScoresGlobalAroundUser.PurgeAndDeleteElements();
  69. downloadedLeaderboardScoresFriends.PurgeAndDeleteElements();
  70. delete m_pLeaderboardName;
  71. }
  72. void CLeaderboardInfo::RetrieveLeaderboardData()
  73. {
  74. if ( steamapicontext && steamapicontext->SteamUserStats() )
  75. {
  76. if ( m_kLeaderboardType == kMapLeaderboard )
  77. {
  78. SteamAPICall_t apicall = steamapicontext->SteamUserStats()->FindLeaderboard( CFmtStr( "contributions_%s", m_pLeaderboardName ) );
  79. findLeaderboardCallback.Set( apicall, this, &CLeaderboardInfo::OnFindLeaderboard );
  80. }
  81. else if ( m_kLeaderboardType == kDuckLeaderboard || m_kLeaderboardType == kDuckStat )
  82. {
  83. SteamAPICall_t apicall = steamapicontext->SteamUserStats()->FindLeaderboard( m_pLeaderboardName );
  84. findLeaderboardCallback.Set( apicall, this, &CLeaderboardInfo::OnFindLeaderboard );
  85. }
  86. else if ( m_kLeaderboardType == kLadderLeaderboard )
  87. {
  88. SteamAPICall_t apicall = steamapicontext->SteamUserStats()->FindLeaderboard( m_pLeaderboardName );
  89. findLeaderboardCallback.Set( apicall, this, &CLeaderboardInfo::OnFindLeaderboard );
  90. }
  91. }
  92. }
  93. bool CLeaderboardInfo::DownloadLeaderboardData()
  94. {
  95. if ( !findLeaderboardResults.m_bLeaderboardFound )
  96. return false;
  97. if ( m_kLeaderboardType == kMapLeaderboard )
  98. {
  99. SteamAPICall_t apicall = steamapicontext->SteamUserStats()->DownloadLeaderboardEntries( findLeaderboardResults.m_hSteamLeaderboard, k_ELeaderboardDataRequestGlobal, 1, 5 );
  100. downloadLeaderboardCallbackGlobal.Set( apicall, this, &CLeaderboardInfo::OnLeaderboardScoresDownloadedGlobal );
  101. apicall = steamapicontext->SteamUserStats()->DownloadLeaderboardEntries( findLeaderboardResults.m_hSteamLeaderboard, k_ELeaderboardDataRequestGlobalAroundUser, -2, 2 );
  102. downloadLeaderboardCallbackGlobalAroundUser.Set( apicall, this, &CLeaderboardInfo::OnLeaderboardScoresDownloadedGlobalAroundUser );
  103. apicall = steamapicontext->SteamUserStats()->DownloadLeaderboardEntries( findLeaderboardResults.m_hSteamLeaderboard, k_ELeaderboardDataRequestFriends, 1, 5 );
  104. downloadLeaderboardCallbackFriends.Set( apicall, this, &CLeaderboardInfo::OnLeaderboardScoresDownloadedFriends );
  105. return true;
  106. }
  107. if ( m_kLeaderboardType == kDuckLeaderboard )
  108. {
  109. SteamAPICall_t apicall = steamapicontext->SteamUserStats()->DownloadLeaderboardEntries( findLeaderboardResults.m_hSteamLeaderboard, k_ELeaderboardDataRequestFriends, -6, 6 );
  110. downloadLeaderboardCallbackFriends.Set( apicall, this, &CLeaderboardInfo::OnLeaderboardScoresDownloadedFriends );
  111. return true;
  112. }
  113. if ( m_kLeaderboardType == kDuckStat )
  114. {
  115. SteamAPICall_t apicall = steamapicontext->SteamUserStats()->DownloadLeaderboardEntries( findLeaderboardResults.m_hSteamLeaderboard, k_ELeaderboardDataRequestFriends, 0, 0 );
  116. downloadLeaderboardCallbackFriends.Set( apicall, this, &CLeaderboardInfo::OnLeaderboardScoresDownloadedFriends );
  117. return true;
  118. }
  119. if ( m_kLeaderboardType == kLadderLeaderboard )
  120. {
  121. SteamAPICall_t apicall = steamapicontext->SteamUserStats()->DownloadLeaderboardEntries( findLeaderboardResults.m_hSteamLeaderboard, k_ELeaderboardDataRequestGlobal, 1, 100 );
  122. downloadLeaderboardCallbackGlobal.Set( apicall, this, &CLeaderboardInfo::OnLeaderboardScoresDownloadedGlobal );
  123. apicall = steamapicontext->SteamUserStats()->DownloadLeaderboardEntries( findLeaderboardResults.m_hSteamLeaderboard, k_ELeaderboardDataRequestFriends, -45, 45 );
  124. downloadLeaderboardCallbackFriends.Set( apicall, this, &CLeaderboardInfo::OnLeaderboardScoresDownloadedFriends );
  125. return true;
  126. }
  127. return false;
  128. }
  129. void CLeaderboardInfo::OnFindLeaderboard( LeaderboardFindResult_t *pResult, bool bIOFailure )
  130. {
  131. findLeaderboardResults = *pResult;
  132. }
  133. void CLeaderboardInfo::OnLeaderboardScoresDownloadedGlobal( LeaderboardScoresDownloaded_t *pResult, bool bIOFailure )
  134. {
  135. RetrieveLeaderboardEntries( *pResult, downloadedLeaderboardScoresGlobal );
  136. iNumLeaderboardEntries = steamapicontext->SteamUserStats()->GetLeaderboardEntryCount( findLeaderboardResults.m_hSteamLeaderboard );
  137. }
  138. void CLeaderboardInfo::OnLeaderboardScoresDownloadedGlobalAroundUser( LeaderboardScoresDownloaded_t *pResult, bool bIOFailure )
  139. {
  140. RetrieveLeaderboardEntries( *pResult, downloadedLeaderboardScoresGlobalAroundUser );
  141. }
  142. void CLeaderboardInfo::OnLeaderboardScoresDownloadedFriends( LeaderboardScoresDownloaded_t *pResult, bool bIOFailure )
  143. {
  144. RetrieveLeaderboardEntries( *pResult, downloadedLeaderboardScoresFriends );
  145. iNumLeaderboardEntries = steamapicontext->SteamUserStats()->GetLeaderboardEntryCount( findLeaderboardResults.m_hSteamLeaderboard );
  146. CSteamID localID;
  147. if ( steamapicontext && steamapicontext->SteamUser() )
  148. {
  149. localID = steamapicontext->SteamUser()->GetSteamID();
  150. }
  151. FOR_EACH_VEC( downloadedLeaderboardScoresFriends, i )
  152. {
  153. if ( downloadedLeaderboardScoresFriends[i]->m_steamIDUser == localID )
  154. {
  155. if ( m_iMyScore < downloadedLeaderboardScoresFriends[i]->m_nScore )
  156. {
  157. // First update on finding the leaderboard, any gotten kills need to add to accumulate
  158. if ( m_bLeaderboardFound == false )
  159. {
  160. if ( m_iMyScore > 0 )
  161. {
  162. m_bHasPendingUpdate = true;
  163. }
  164. m_iMyScore += downloadedLeaderboardScoresFriends[i]->m_nScore;
  165. }
  166. else
  167. {
  168. m_iMyScore = downloadedLeaderboardScoresFriends[i]->m_nScore;
  169. }
  170. }
  171. // Use My Saved Score
  172. downloadedLeaderboardScoresFriends[i]->m_nScore = m_iMyScore;
  173. }
  174. }
  175. downloadedLeaderboardScoresFriends.Sort( &SortLeaderboardVec );
  176. m_bLeaderboardFound = true;
  177. }
  178. void CLeaderboardInfo::SetMyScore( int score )
  179. {
  180. m_iMyScore = score;
  181. if ( !m_bLeaderboardFound )
  182. return;
  183. // Update my leaderboard and resort
  184. iNumLeaderboardEntries = steamapicontext->SteamUserStats()->GetLeaderboardEntryCount( findLeaderboardResults.m_hSteamLeaderboard );
  185. CSteamID localID;
  186. if ( steamapicontext && steamapicontext->SteamUser() )
  187. {
  188. localID = steamapicontext->SteamUser()->GetSteamID();
  189. }
  190. FOR_EACH_VEC( downloadedLeaderboardScoresFriends, i )
  191. {
  192. if ( downloadedLeaderboardScoresFriends[i]->m_steamIDUser == localID )
  193. {
  194. if ( m_iMyScore > downloadedLeaderboardScoresFriends[i]->m_nScore )
  195. {
  196. // Use My Saved Score
  197. downloadedLeaderboardScoresFriends[i]->m_nScore = m_iMyScore;
  198. downloadedLeaderboardScoresFriends.Sort( &SortLeaderboardVec );
  199. break;
  200. }
  201. }
  202. }
  203. }
  204. //-----------------------------------------------------------------------------
  205. class CMapInfoContainer : public CAutoGameSystemPerFrame, public CGameEventListener
  206. {
  207. public:
  208. CMapInfoContainer()
  209. {
  210. memset( &m_findDuelLeaderboardResults, 0, sizeof( m_findDuelLeaderboardResults ) );
  211. m_flNextUpdateDuckScoreTime = Plat_FloatTime() + 10.0f;
  212. #ifdef CLIENT_DLL
  213. m_flNextDuckScoresUploadTime = Plat_FloatTime() + tf_duck_upload_rate.GetFloat();
  214. #endif
  215. m_flNextLadderUpdateTime = Plat_FloatTime() + 10.f;
  216. }
  217. virtual char const *Name()
  218. {
  219. return "CMapInfoContainer";
  220. }
  221. ~CMapInfoContainer()
  222. {
  223. m_vecMapInfos.PurgeAndDeleteElements();
  224. m_downloadedDuelLeaderboardScores_GlobalAroundUser.PurgeAndDeleteElements();
  225. m_downloadedDuelLeaderboardScores_Friends.PurgeAndDeleteElements();
  226. // For ducks
  227. m_vecDuckInfo.PurgeAndDeleteElements();
  228. // Ladders
  229. m_vecLadderLeaderboards.PurgeAndDeleteElements();
  230. }
  231. #ifdef CLIENT_DLL
  232. virtual void LevelShutdownPreEntity()
  233. {
  234. // upload scores on level leave
  235. //DuckUploadPendingScores();
  236. }
  237. // Gets called each frame
  238. virtual void Update( float frametime )
  239. {
  240. if ( m_flNextUpdateDuckScoreTime > 0 && m_flNextUpdateDuckScoreTime < Plat_FloatTime() )
  241. {
  242. if ( DownloadDuckLeaderboard() )
  243. {
  244. m_flNextUpdateDuckScoreTime = -1.0f;
  245. }
  246. }
  247. if ( m_flNextLadderUpdateTime > 0.f && m_flNextLadderUpdateTime < Plat_FloatTime() )
  248. {
  249. if ( DownloadLadderLeaderboard() )
  250. {
  251. m_flNextLadderUpdateTime = -1.f;
  252. }
  253. }
  254. // Duck Journal is off, no longer uploading
  255. //if ( m_flNextDuckScoresUploadTime < Plat_FloatTime() )
  256. //{
  257. // // Hard limit the rate players can update scores
  258. // float flNextUpdateTime = tf_duck_upload_rate.GetFloat();
  259. // if ( DuckUploadPendingScores() )
  260. // {
  261. // // Request new score
  262. // m_flNextUpdateDuckScoreTime = Plat_FloatTime() + 10.0f;
  263. // }
  264. // // 4x as long if you don't have a Duck Journal
  265. // C_TFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer();
  266. // if ( pPlayer )
  267. // {
  268. // static CSchemaAttributeDefHandle pAttr_DuckLevelBadge( "duck badge level" );
  269. // if ( pAttr_DuckLevelBadge )
  270. // {
  271. // CTFWearable *pActionItem = pPlayer->GetEquippedWearableForLoadoutSlot( LOADOUT_POSITION_ACTION );
  272. // // Don't care about the level, just if the attribute is found
  273. // if ( pActionItem && FindAttribute( pActionItem->GetAttributeContainer()->GetItem(), pAttr_DuckLevelBadge ) )
  274. // {
  275. // flNextUpdateTime *= 0.5f;
  276. // }
  277. // }
  278. // }
  279. // m_flNextDuckScoresUploadTime = Plat_FloatTime() + flNextUpdateTime;
  280. //}
  281. }
  282. #endif // CLIENT_DLL
  283. //-----------------------------------------------------------------------------
  284. // for duels
  285. void DownloadDuelLeaderboard()
  286. {
  287. if ( m_findDuelLeaderboardResults.m_bLeaderboardFound )
  288. {
  289. // and start downloading the leaderboards
  290. // friends
  291. SteamAPICall_t apicall = steamapicontext->SteamUserStats()->DownloadLeaderboardEntries( m_findDuelLeaderboardResults.m_hSteamLeaderboard, k_ELeaderboardDataRequestFriends, 1, 10 );
  292. m_downloadLeaderboardCallback_Friends.Set( apicall, this, &CMapInfoContainer::OnDuelLeaderboardScoresDownloaded_Friends );
  293. // global around user
  294. apicall = steamapicontext->SteamUserStats()->DownloadLeaderboardEntries( m_findDuelLeaderboardResults.m_hSteamLeaderboard, k_ELeaderboardDataRequestGlobalAroundUser, -4, 5 );
  295. m_downloadLeaderboardCallback_GlobalAroundUser.Set( apicall, this, &CMapInfoContainer::OnDuelLeaderboardScoresDownloaded_GlobalAroundUser );
  296. }
  297. }
  298. void OnFindDuelLeaderboard( LeaderboardFindResult_t *pResult, bool bIOFailure )
  299. {
  300. m_findDuelLeaderboardResults = *pResult;
  301. DownloadDuelLeaderboard();
  302. }
  303. void OnDuelLeaderboardScoresDownloaded_GlobalAroundUser( LeaderboardScoresDownloaded_t *pResult, bool bIOFailure )
  304. {
  305. RetrieveLeaderboardEntries( *pResult, m_downloadedDuelLeaderboardScores_GlobalAroundUser );
  306. }
  307. void OnDuelLeaderboardScoresDownloaded_Friends( LeaderboardScoresDownloaded_t *pResult, bool bIOFailure )
  308. {
  309. RetrieveLeaderboardEntries( *pResult, m_downloadedDuelLeaderboardScores_Friends );
  310. }
  311. // **************************************************************************************************************************
  312. bool DownloadLadderLeaderboard()
  313. {
  314. bool bDownloading = false;
  315. FOR_EACH_VEC( m_vecLadderLeaderboards, i )
  316. {
  317. bDownloading |= m_vecLadderLeaderboards[i]->DownloadLeaderboardData();
  318. }
  319. return bDownloading;
  320. }
  321. CLeaderboardInfo *GetLadderLeaderboard( const char *pszName )
  322. {
  323. FOR_EACH_VEC( m_vecLadderLeaderboards, i )
  324. {
  325. CLeaderboardInfo *pInfo = m_vecLadderLeaderboards[i];
  326. if ( pszName && pInfo && !V_strcmp( pszName, pInfo->GetLeaderboardName() ) )
  327. {
  328. return pInfo;
  329. }
  330. }
  331. return NULL;
  332. }
  333. // **************************************************************************************************************************
  334. bool DownloadDuckLeaderboard()
  335. {
  336. bool bDownloading = false;
  337. FOR_EACH_VEC( m_vecDuckInfo, i )
  338. {
  339. bDownloading |= m_vecDuckInfo[i]->DownloadLeaderboardData();
  340. }
  341. return bDownloading;
  342. }
  343. CLeaderboardInfo *GetDuckLeaderboard( const char* kName )
  344. {
  345. FOR_EACH_VEC( m_vecDuckInfo, i )
  346. {
  347. CLeaderboardInfo *pInfo = m_vecDuckInfo[i];
  348. if ( strstr( kName, pInfo->GetLeaderboardName() ) != NULL )
  349. {
  350. return pInfo;
  351. }
  352. }
  353. return NULL;
  354. }
  355. bool DuckUploadPendingScores()
  356. {
  357. return false;
  358. //CSteamID localID;
  359. //if ( !steamapicontext || !steamapicontext->SteamUser() )
  360. // return false;
  361. //localID = steamapicontext->SteamUser()->GetSteamID();
  362. //bool bUpdatedScores = false;
  363. //for ( int i = 0; i < DUCK_NUM_LEADERBOARDS; ++i )
  364. //{
  365. // CLeaderboardInfo *pLeaderboard = GetDuckLeaderboard( g_szDuckLeaderboardNames[i] );
  366. //
  367. // if ( pLeaderboard && pLeaderboard->IsLeaderboardFound() && pLeaderboard->HasPendingUpdate() )
  368. // {
  369. // pLeaderboard->SetHasPendingUpdate( false );
  370. // bUpdatedScores = true;
  371. // int iScoreCheck = RandomInt( INT_MAX / 2, INT_MAX );
  372. // // Tell the GC to update our duck contribution
  373. // GCSDK::CProtoBufMsg<CGCMsgGC_PlayerDuckLeaderboard_IndividualUpdate> msg( k_EMsgGC_DuckLeaderboard_IndividualUpdate );
  374. // msg.Body().set_score( pLeaderboard->GetMyScore() );
  375. // msg.Body().set_type( i );
  376. // MD5Context_t md5Context;
  377. // MD5Init( &md5Context );
  378. //
  379. // AccountID_t unAccountId = localID.GetAccountID();
  380. // int nScore = pLeaderboard->GetMyScore();
  381. // MD5Update( &md5Context, static_cast<const uint8 *>( (void *)&unAccountId ), sizeof( unAccountId ) );
  382. // MD5Update( &md5Context, static_cast<const uint8 *>( (void *)&nScore ), sizeof( nScore ) );
  383. // MD5Update( &md5Context, static_cast<const uint8 *>( (void *)&i ), sizeof( i ) );
  384. // MD5Update( &md5Context, static_cast<const uint8 *>( (void *)&TF_DUCK_ID ), sizeof( TF_DUCK_ID ) );
  385. // MD5Update( &md5Context, static_cast<const uint8 *>( (void *)&iScoreCheck ), sizeof( iScoreCheck ) );
  386. //
  387. // MD5Value_t md5Result;
  388. // MD5Final( &md5Result.bits[0], &md5Context );
  389. // msg.Body().set_score_id( &md5Result.bits[0], MD5_DIGEST_LENGTH );
  390. // msg.Body().set_score_check( iScoreCheck );
  391. // GCClientSystem()->BSendMessage( msg );
  392. // }
  393. //}
  394. //return bUpdatedScores;
  395. }
  396. void DuckUpdateScore( int iIncrement, EDuckLeaderboardTypes kLeaderboard )
  397. {
  398. // Get Current Score
  399. CLeaderboardInfo *pLeaderboard = GetDuckLeaderboard( g_szDuckLeaderboardNames[kLeaderboard] );
  400. int iCurrentScore = pLeaderboard->GetMyScore();
  401. int iNewScore = iCurrentScore + iIncrement;
  402. #ifdef CLIENT_DLL
  403. int iOldLevel = iCurrentScore / DUCK_XP_SCALE;
  404. int iNewLevel = iNewScore / DUCK_XP_SCALE;
  405. if ( iNewLevel > iOldLevel )
  406. {
  407. IGameEvent *event = gameeventmanager->CreateEvent( "duck_xp_level_up" );
  408. if ( event )
  409. {
  410. event->SetInt( "level", iNewLevel );
  411. gameeventmanager->FireEventClientSide( event );
  412. }
  413. }
  414. #endif
  415. // Set my new score
  416. pLeaderboard->SetMyScore( iNewScore );
  417. pLeaderboard->SetHasPendingUpdate( true );
  418. }
  419. //-----------------------------------------------------------------------------
  420. virtual bool Init()
  421. {
  422. ListenForGameEvent( "item_schema_initialized" );
  423. #ifdef CLIENT_DLL
  424. HOOK_MESSAGE( EOTLDuckEvent );
  425. #endif // CLIENT_DLL
  426. return true;
  427. }
  428. virtual void FireGameEvent( IGameEvent *event )
  429. {
  430. if ( Q_strcmp( event->GetName(), "item_schema_initialized" ) != 0 )
  431. return;
  432. for ( int i = 0; i < GetItemSchema()->GetMapCount(); i++ )
  433. {
  434. CLeaderboardInfo *pInfo = new CLeaderboardInfo( GetItemSchema()->GetMasterMapDefByIndex( i )->pszMapName );
  435. pInfo->m_kLeaderboardType = kMapLeaderboard;
  436. m_vecMapInfos.AddToTail( pInfo );
  437. const MapDef_t *pMapDef = GetItemSchema()->GetMasterMapDefByName( pInfo->GetLeaderboardName() );
  438. if ( pMapDef && pMapDef->IsCommunityMap() )
  439. {
  440. // retrieve leaderboard info
  441. pInfo->RetrieveLeaderboardData();
  442. }
  443. }
  444. // find duel leaderboards
  445. if ( steamapicontext && steamapicontext->SteamUserStats() )
  446. {
  447. SteamAPICall_t apicall = steamapicontext->SteamUserStats()->FindLeaderboard( "duel_wins" );
  448. m_findLeaderboardCallback.Set( apicall, this, &CMapInfoContainer::OnFindDuelLeaderboard );
  449. }
  450. // find duck leaderboards
  451. for ( int i = 0; i < DUCK_NUM_LEADERBOARDS; i++ )
  452. {
  453. CLeaderboardInfo *pInfo = new CLeaderboardInfo( g_szDuckLeaderboardNames[ i ] );
  454. pInfo->m_kLeaderboardType = i == 0 ? kDuckLeaderboard : kDuckStat;
  455. m_vecDuckInfo.AddToTail( pInfo );
  456. // retrieve leaderboard info
  457. pInfo->RetrieveLeaderboardData();
  458. }
  459. // Ladder
  460. for ( int i = 0; i < LADDER_LEADERBOARDS_MAX; i++ )
  461. {
  462. CLeaderboardInfo *pInfo = new CLeaderboardInfo( g_szLadderLeaderboardNames[i] );
  463. pInfo->m_kLeaderboardType = kLadderLeaderboard;
  464. m_vecLadderLeaderboards.AddToTail( pInfo );
  465. // retrieve leaderboard info
  466. pInfo->RetrieveLeaderboardData();
  467. }
  468. }
  469. public:
  470. CUtlVector< CLeaderboardInfo* > m_vecMapInfos;
  471. // for duels
  472. CCallResult< CMapInfoContainer, LeaderboardFindResult_t > m_findLeaderboardCallback;
  473. CCallResult< CMapInfoContainer, LeaderboardScoresDownloaded_t > m_downloadLeaderboardCallback_GlobalAroundUser;
  474. CCallResult< CMapInfoContainer, LeaderboardScoresDownloaded_t > m_downloadLeaderboardCallback_Friends;
  475. LeaderboardFindResult_t m_findDuelLeaderboardResults;
  476. CUtlVector< LeaderboardEntry_t* > m_downloadedDuelLeaderboardScores_GlobalAroundUser;
  477. CUtlVector< LeaderboardEntry_t* > m_downloadedDuelLeaderboardScores_Friends;
  478. // For ducks
  479. CUtlVector< CLeaderboardInfo* > m_vecDuckInfo;
  480. float m_flNextUpdateDuckScoreTime;
  481. float m_flNextDuckScoresUploadTime;
  482. // Ladders
  483. CUtlVector< CLeaderboardInfo* > m_vecLadderLeaderboards;
  484. float m_flNextLadderUpdateTime;
  485. };
  486. CMapInfoContainer gMapInfoContainer;
  487. static CLeaderboardInfo *FindMapInfo( const char *pMapName )
  488. {
  489. FOR_EACH_VEC( gMapInfoContainer.m_vecMapInfos, i )
  490. {
  491. CLeaderboardInfo *pInfo = gMapInfoContainer.m_vecMapInfos[i];
  492. if ( strstr( pMapName, pInfo->GetLeaderboardName() ) != NULL )
  493. return pInfo;
  494. }
  495. return NULL;
  496. }
  497. //-----------------------------------------------------------------------------
  498. bool Leaderboards_GetDuelWins( CUtlVector< LeaderboardEntry_t* > &scores, bool bGlobal )
  499. {
  500. if ( gMapInfoContainer.m_findDuelLeaderboardResults.m_bLeaderboardFound )
  501. {
  502. if ( bGlobal )
  503. {
  504. scores = gMapInfoContainer.m_downloadedDuelLeaderboardScores_GlobalAroundUser;
  505. }
  506. else
  507. {
  508. scores = gMapInfoContainer.m_downloadedDuelLeaderboardScores_Friends;
  509. }
  510. return true;
  511. }
  512. return false;
  513. }
  514. //-----------------------------------------------------------------------------
  515. // DUCKS
  516. void Leaderboards_GetDuckLeaderboardSteamIDs( CUtlVector< AccountID_t > &vecIds )
  517. {
  518. vecIds.RemoveAll();
  519. FOR_EACH_VEC( gMapInfoContainer.m_vecDuckInfo, i )
  520. {
  521. FOR_EACH_VEC( gMapInfoContainer.m_vecDuckInfo[i]->downloadedLeaderboardScoresFriends, iEntry )
  522. {
  523. vecIds.AddToHead( gMapInfoContainer.m_vecDuckInfo[i]->downloadedLeaderboardScoresFriends[iEntry]->m_steamIDUser.GetAccountID() );
  524. }
  525. }
  526. }
  527. bool Leaderboards_GetDuckLeaderboard( CUtlVector< LeaderboardEntry_t* > &scores, const char* kName )
  528. {
  529. CLeaderboardInfo *pLeaderboard = gMapInfoContainer.GetDuckLeaderboard( kName );
  530. if ( pLeaderboard && pLeaderboard->IsLeaderboardFound() )
  531. {
  532. scores = pLeaderboard->downloadedLeaderboardScoresFriends;
  533. return true;
  534. }
  535. return false;
  536. }
  537. int Leaderboards_GetDuckLeaderboardTotalEntryCount( const char* kName )
  538. {
  539. CLeaderboardInfo *pLeaderboard = gMapInfoContainer.GetDuckLeaderboard( kName );
  540. if ( pLeaderboard )
  541. {
  542. return pLeaderboard->iNumLeaderboardEntries;
  543. }
  544. return 0;
  545. }
  546. //-----------------------------------------------------------------------------
  547. // DUCK Collected Message from Server
  548. void __MsgFunc_EOTLDuckEvent( bf_read &msg )
  549. {
  550. #ifdef CLIENT_DLL
  551. CBasePlayer *pLocalPlayer = CBasePlayer::GetLocalPlayer();
  552. if ( !pLocalPlayer )
  553. return;
  554. if ( TFGameRules() && TFGameRules()->HaveCheatsBeenEnabledDuringLevel() )
  555. return;
  556. // IsCreated, ID of Creator, ID of Victim, Count, IsGolden
  557. int iIsCreated = (int)msg.ReadByte();
  558. int iCreatorId = (int)msg.ReadByte();
  559. int iVictimId = (int)msg.ReadByte();
  560. int iToucherId = (int)msg.ReadByte();
  561. int iDuckTeam = (int)msg.ReadByte();
  562. int iCount = (int)msg.ReadByte();
  563. int iDuckFlags = (int)msg.ReadByte();
  564. iDuckTeam = 0;
  565. iVictimId = 0;
  566. //iDuckFlags = 0;
  567. CBasePlayer *pCreator = UTIL_PlayerByIndex( iCreatorId );
  568. //CBasePlayer *pVictim = UTIL_PlayerByIndex( iVictimId );
  569. CBasePlayer *pToucher = UTIL_PlayerByIndex( iToucherId );
  570. if ( !pCreator )
  571. {
  572. iDuckFlags |= DUCK_FLAG_OBJECTIVE;
  573. }
  574. // If you were picked up, you need a toucher
  575. if ( iIsCreated == 0 && pToucher )
  576. {
  577. // if I picked them up
  578. if ( pToucher == pLocalPlayer )
  579. {
  580. // Offense
  581. if ( pCreator && pCreator->GetTeamNumber() == pLocalPlayer->GetTeamNumber() )
  582. {
  583. gMapInfoContainer.DuckUpdateScore( iCount, TF_DUCK_SCORING_PERSONAL_PICKUP_OFFENSE );
  584. gMapInfoContainer.DuckUpdateScore( iCount * DUCK_XP_WEIGHT_OFFENSE, TF_DUCK_SCORING_OVERALL_RATING );
  585. }
  586. //defense
  587. else if ( pCreator && pCreator->GetTeamNumber() != pLocalPlayer->GetTeamNumber() )
  588. {
  589. gMapInfoContainer.DuckUpdateScore( iCount, TF_DUCK_SCORING_PERSONAL_PICKUP_DEFENDED );
  590. gMapInfoContainer.DuckUpdateScore( iCount * DUCK_XP_WEIGHT_DEFENSE, TF_DUCK_SCORING_OVERALL_RATING );
  591. }
  592. // objective
  593. if ( iDuckFlags & DUCK_FLAG_OBJECTIVE )
  594. {
  595. gMapInfoContainer.DuckUpdateScore( iCount, TF_DUCK_SCORING_PERSONAL_PICKUP_OBJECTIVE );
  596. gMapInfoContainer.DuckUpdateScore( iCount* DUCK_XP_WEIGHT_OBJECTIVE, TF_DUCK_SCORING_OVERALL_RATING );
  597. }
  598. // bonus
  599. if ( iDuckFlags & DUCK_FLAG_BONUS )
  600. {
  601. gMapInfoContainer.DuckUpdateScore( iCount, TF_DUCK_SCORING_PERSONAL_BONUS_PICKUP );
  602. gMapInfoContainer.DuckUpdateScore( iCount* DUCK_XP_WEIGHT_BONUS, TF_DUCK_SCORING_OVERALL_RATING );
  603. }
  604. }
  605. // Teammate picks up a duck I made
  606. else if ( pCreator && pCreator == pLocalPlayer && pCreator->GetTeamNumber() == pToucher->GetTeamNumber() )
  607. {
  608. gMapInfoContainer.DuckUpdateScore( iCount, TF_DUCK_SCORING_TEAM_PICKUP_MY_DUCKS );
  609. gMapInfoContainer.DuckUpdateScore( iCount * DUCK_XP_WEIGHT_TEAMMATE, TF_DUCK_SCORING_OVERALL_RATING );
  610. }
  611. }
  612. // Duck Created
  613. else if ( iIsCreated != 0 )
  614. {
  615. // If this is the same as local player
  616. if ( pLocalPlayer == pCreator )
  617. {
  618. gMapInfoContainer.DuckUpdateScore( iCount, TF_DUCK_SCORING_PERSONAL_GENERATION );
  619. gMapInfoContainer.DuckUpdateScore( iCount * DUCK_XP_WEIGHT_GENERATION, TF_DUCK_SCORING_OVERALL_RATING );
  620. }
  621. }
  622. #endif
  623. }
  624. //-----------------------------------------------------------------------------
  625. void Leaderboards_Refresh()
  626. {
  627. gMapInfoContainer.DownloadDuelLeaderboard();
  628. gMapInfoContainer.DownloadDuckLeaderboard();
  629. gMapInfoContainer.DownloadLadderLeaderboard();
  630. }
  631. void MapInfo_RefreshLeaderboard( const char *pMapName )
  632. {
  633. CLeaderboardInfo *pInfo = FindMapInfo( pMapName );
  634. if ( pInfo )
  635. {
  636. pInfo->DownloadLeaderboardData();
  637. }
  638. }
  639. bool MapInfo_GetLeaderboardInfo( const char *pMapName, CUtlVector< LeaderboardEntry_t* > &scores, int &iNumLeaderboardEntries, uint32 unMinScores )
  640. {
  641. CLeaderboardInfo *pInfo = FindMapInfo( pMapName );
  642. if ( pInfo && pInfo->findLeaderboardResults.m_bLeaderboardFound )
  643. {
  644. if ( (uint32)pInfo->downloadedLeaderboardScoresFriends.Count() >= unMinScores )
  645. {
  646. scores = pInfo->downloadedLeaderboardScoresFriends;
  647. }
  648. else if ( (uint32)pInfo->downloadedLeaderboardScoresGlobalAroundUser.Count() >= unMinScores )
  649. {
  650. scores = pInfo->downloadedLeaderboardScoresGlobalAroundUser;
  651. }
  652. else
  653. {
  654. scores = pInfo->downloadedLeaderboardScoresGlobal;
  655. }
  656. iNumLeaderboardEntries = pInfo->iNumLeaderboardEntries;
  657. return true;
  658. }
  659. return false;
  660. }
  661. static const char *FindMapNameForContributionDefinitionIndex( item_definition_index_t unContribDefIndex )
  662. {
  663. for ( int i = 0; i < GetItemSchema()->GetMapCount(); i++ )
  664. {
  665. const MapDef_t* pMapDef = GetItemSchema()->GetMasterMapDefByIndex( i );
  666. if ( pMapDef->mapStampDef && pMapDef->mapStampDef->GetDefinitionIndex() == unContribDefIndex )
  667. return pMapDef->pszMapName;
  668. }
  669. return NULL;
  670. }
  671. bool MapInfo_DidPlayerDonate( uint32 unAccountID, const char *pLevelName )
  672. {
  673. if ( steamapicontext == NULL || steamapicontext->SteamUser() == NULL )
  674. return false;
  675. CSteamID localSteamID = steamapicontext->SteamUser()->GetSteamID();
  676. CSteamID steamID = localSteamID;
  677. steamID.SetAccountID( unAccountID );
  678. GCSDK::CGCClientSharedObjectCache *pSOCache = GCClientSystem()->GetSOCache( steamID );
  679. if ( pSOCache == NULL )
  680. return false;
  681. GCSDK::CGCClientSharedObjectTypeCache *pTypeCache = pSOCache->FindTypeCache( CTFMapContribution::k_nTypeID );
  682. if ( pTypeCache == NULL )
  683. return false;
  684. char pchBaseMapName[ MAX_PATH ];
  685. Q_FileBase( pLevelName, pchBaseMapName, sizeof(pchBaseMapName) );
  686. for ( uint32 i = 0; i < pTypeCache->GetCount(); ++i )
  687. {
  688. CTFMapContribution *pMapContribution = (CTFMapContribution*)( pTypeCache->GetObject( i ) );
  689. const char *pszMapName = FindMapNameForContributionDefinitionIndex( pMapContribution->Obj().def_index() );
  690. if ( pszMapName && FStrEq( pszMapName, pchBaseMapName ) )
  691. return true;
  692. }
  693. return false;
  694. }
  695. int MapInfo_GetDonationAmount( uint32 unAccountID, const char *pLevelName )
  696. {
  697. if ( steamapicontext == NULL || steamapicontext->SteamUser() == NULL )
  698. return 0;
  699. CSteamID localSteamID = steamapicontext->SteamUser()->GetSteamID();
  700. CSteamID steamID = localSteamID;
  701. steamID.SetAccountID( unAccountID );
  702. GCSDK::CGCClientSharedObjectCache *pSOCache = GCClientSystem()->GetSOCache( steamID );
  703. if ( pSOCache == NULL )
  704. return 0;
  705. GCSDK::CGCClientSharedObjectTypeCache *pTypeCache = pSOCache->FindTypeCache( CTFMapContribution::k_nTypeID );
  706. if ( pTypeCache == NULL )
  707. return 0;
  708. char pchBaseMapName[ MAX_PATH ];
  709. Q_FileBase( pLevelName, pchBaseMapName, sizeof(pchBaseMapName) );
  710. for ( uint32 i = 0; i < pTypeCache->GetCount(); ++i )
  711. {
  712. CTFMapContribution *pMapContribution = (CTFMapContribution*)( pTypeCache->GetObject( i ) );
  713. const char *pszMapName = FindMapNameForContributionDefinitionIndex( pMapContribution->Obj().def_index() );
  714. if ( pszMapName && FStrEq( pszMapName, pchBaseMapName ) )
  715. return pMapContribution->Obj().contribution_level();
  716. }
  717. return 0;
  718. }
  719. //-----------------------------------------------------------------------------
  720. // Ladders
  721. //-----------------------------------------------------------------------------
  722. bool Leaderboards_GetLadderLeaderboard( CUtlVector< LeaderboardEntry_t* > &scores, const char *pszName, bool bGlobal )
  723. {
  724. CLeaderboardInfo *pLeaderboard = gMapInfoContainer.GetLadderLeaderboard( pszName );
  725. if ( pLeaderboard && pLeaderboard->IsLeaderboardFound() )
  726. {
  727. scores = bGlobal ? pLeaderboard->downloadedLeaderboardScoresGlobal : pLeaderboard->downloadedLeaderboardScoresFriends;
  728. return true;
  729. }
  730. return false;
  731. }
  732. //-----------------------------------------------------------------------------
  733. //
  734. //-----------------------------------------------------------------------------
  735. void Leaderboards_LadderRefresh( void )
  736. {
  737. gMapInfoContainer.DownloadLadderLeaderboard();
  738. }