Counter Strike : Global Offensive Source Code
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.

365 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Manager for handling UGC file information requests
  4. //
  5. //========================================================================//
  6. #include "cbase.h"
  7. #include "ugc_file_info_manager.h"
  8. #if !defined (NO_STEAM) && !defined ( _PS3 )
  9. CWorkshopFileInfoManager::CWorkshopFileInfoManager( IWorkshopFileInfoManagerCallbackInterface *pCallbackInterface ) :
  10. m_bActiveVotingRequest( false ),
  11. m_pActivePublishedFileRequest( NULL ),
  12. m_pCallbackInterface( pCallbackInterface )
  13. {
  14. m_mapPublishedFileInfoDepot.SetLessFunc( DefLessFunc( PublishedFileId_t ) );
  15. }
  16. CWorkshopFileInfoManager::~CWorkshopFileInfoManager( void )
  17. {
  18. }
  19. //-----------------------------------------------------------------------------
  20. // Purpose: Drive our requests forward
  21. //-----------------------------------------------------------------------------
  22. void CWorkshopFileInfoManager::Update( void )
  23. {
  24. UpdatePublishedFileInfoQueries();
  25. UpdatePublishedFileVotingInfoQueries();
  26. }
  27. //-----------------------------------------------------------------------------
  28. // Purpose: Adds a published file to the query
  29. // Return: If true, the published file already exists and the data can be immediately queried for. Otherwise, the caller will need to wait
  30. //-----------------------------------------------------------------------------
  31. bool CWorkshopFileInfoManager::AddFileInfoQuery( CBasePublishedFileRequest *pRequest, bool bAllowUpdate /*= false*/ )
  32. {
  33. #ifndef NO_STEAM
  34. Log_Msg( LOG_WORKSHOP, "[BaseModPanel] Added query for published file %llu\n", pRequest->GetTargetID() );
  35. // If they don't want redundant calls in the hopper, early out
  36. if ( bAllowUpdate == false && m_mapPublishedFileInfoDepot.Find( pRequest->GetTargetID() ) != m_mapPublishedFileInfoDepot.InvalidIndex() )
  37. {
  38. // FIXME: ICK!
  39. delete pRequest;
  40. return true;
  41. }
  42. // FIXME: How do we ensure we're not colliding with data already present?
  43. m_vecPublishedFileInfoQueryList.Insert( pRequest );
  44. #endif
  45. return false;
  46. }
  47. #if !defined( _GAMECONSOLE )
  48. //-----------------------------------------------------------------------------
  49. // Purpose: Callbacks for retrieving information about a published file
  50. //-----------------------------------------------------------------------------
  51. void CWorkshopFileInfoManager::Steam_OnGetPublishedFileDetails( RemoteStorageGetPublishedFileDetailsResult_t *pResult, bool bError )
  52. {
  53. if ( bError || pResult->m_eResult != k_EResultOK )
  54. {
  55. // This file may have been revoked from the network, don't display it
  56. if ( pResult->m_eResult == k_EResultFileNotFound )
  57. {
  58. // FIXME: Do file clean-up at this point!
  59. Log_Msg( LOG_WORKSHOP, "[BaseModPanel] Error: Failed to retrieve data for %llu (File Not Found)\n", m_pActivePublishedFileRequest->GetTargetID() );
  60. }
  61. else
  62. {
  63. Log_Msg( LOG_WORKSHOP, "[BaseModPanel] Error: Failed to retrieve data for %llu (Error: %d)\n", m_pActivePublishedFileRequest->GetTargetID(), pResult->m_eResult );
  64. }
  65. // Clean up and move forward
  66. m_pActivePublishedFileRequest->OnError( pResult->m_eResult );
  67. if ( m_pCallbackInterface )
  68. {
  69. m_pCallbackInterface->OnFileRequestError( pResult->m_nPublishedFileId );
  70. }
  71. delete m_pActivePublishedFileRequest;
  72. m_pActivePublishedFileRequest = NULL;
  73. return;
  74. }
  75. // If this happens, it means that the request was nuked mid-flight!
  76. Assert( m_pActivePublishedFileRequest != NULL );
  77. if ( m_pActivePublishedFileRequest == NULL )
  78. return;
  79. // We're going to either update a current copy of this information, or create a new entry
  80. int nIndex = m_mapPublishedFileInfoDepot.Find( pResult->m_nPublishedFileId );
  81. if ( nIndex != m_mapPublishedFileInfoDepot.InvalidIndex() )
  82. {
  83. Log_Msg( LOG_WORKSHOP, "[BaseModPanel] Updated file information for %llu\n", pResult->m_nPublishedFileId );
  84. m_mapPublishedFileInfoDepot[nIndex].m_eVisibility = pResult->m_eVisibility;
  85. m_mapPublishedFileInfoDepot[nIndex].m_hFile = pResult->m_hFile;
  86. m_mapPublishedFileInfoDepot[nIndex].m_hPreviewFile = pResult->m_hPreviewFile;
  87. m_mapPublishedFileInfoDepot[nIndex].m_rtimeCreated = pResult->m_rtimeCreated;
  88. m_mapPublishedFileInfoDepot[nIndex].m_rtimeUpdated = pResult->m_rtimeUpdated;
  89. m_mapPublishedFileInfoDepot[nIndex].m_ulSteamIDOwner = pResult->m_ulSteamIDOwner;
  90. m_mapPublishedFileInfoDepot[nIndex].m_bTagsTruncated = pResult->m_bTagsTruncated;
  91. memcpy( m_mapPublishedFileInfoDepot[nIndex].m_rgchTitle, pResult->m_rgchTitle, ARRAYSIZE( m_mapPublishedFileInfoDepot[nIndex].m_rgchTitle ) );
  92. memcpy( m_mapPublishedFileInfoDepot[nIndex].m_rgchDescription, pResult->m_rgchDescription, ARRAYSIZE( m_mapPublishedFileInfoDepot[nIndex].m_rgchDescription ) );
  93. memcpy( m_mapPublishedFileInfoDepot[nIndex].m_pchFileName, pResult->m_pchFileName, ARRAYSIZE( m_mapPublishedFileInfoDepot[nIndex].m_pchFileName ) );
  94. memcpy( m_mapPublishedFileInfoDepot[nIndex].m_rgchTags, pResult->m_rgchTags, ARRAYSIZE( m_mapPublishedFileInfoDepot[nIndex].m_rgchTags ) );
  95. }
  96. else
  97. {
  98. Log_Msg( LOG_WORKSHOP, "[BaseModPanel] Added file information for %llu\n", pResult->m_nPublishedFileId );
  99. // Package up the info block for insertion into our master depot
  100. PublishedFileInfo_t info( pResult->m_nPublishedFileId );
  101. info.m_eVisibility = pResult->m_eVisibility;
  102. info.m_hFile = pResult->m_hFile;
  103. info.m_hPreviewFile = pResult->m_hPreviewFile;
  104. info.m_rtimeCreated = pResult->m_rtimeCreated;
  105. info.m_rtimeUpdated = pResult->m_rtimeUpdated;
  106. info.m_ulSteamIDOwner = pResult->m_ulSteamIDOwner;
  107. info.m_bTagsTruncated = pResult->m_bTagsTruncated;
  108. memcpy( info.m_rgchTitle, pResult->m_rgchTitle, ARRAYSIZE( info.m_rgchTitle ) );
  109. memcpy( info.m_rgchDescription, pResult->m_rgchDescription, ARRAYSIZE( info.m_rgchDescription ) );
  110. memcpy( info.m_pchFileName, pResult->m_pchFileName, ARRAYSIZE( info.m_pchFileName ) );
  111. memcpy( info.m_rgchTags, pResult->m_rgchTags, ARRAYSIZE( info.m_rgchTags ) );
  112. // Add it into our master list
  113. nIndex = m_mapPublishedFileInfoDepot.Insert( pResult->m_nPublishedFileId, info );
  114. }
  115. //Store all the tags
  116. m_mapPublishedFileInfoDepot[nIndex].m_vTags.PurgeAndDeleteElements();
  117. V_SplitString( m_mapPublishedFileInfoDepot[nIndex].m_rgchTags, ",", m_mapPublishedFileInfoDepot[nIndex].m_vTags );
  118. // Call our post-load operation
  119. m_pActivePublishedFileRequest->OnLoaded( m_mapPublishedFileInfoDepot[nIndex] );
  120. if ( m_pCallbackInterface )
  121. {
  122. m_pCallbackInterface->OnFileRequestFinished( pResult->m_nPublishedFileId );
  123. }
  124. // FIXME: Can we assure that the request is done at this point?
  125. delete m_pActivePublishedFileRequest;
  126. m_pActivePublishedFileRequest = NULL;
  127. }
  128. //-----------------------------------------------------------------------------
  129. // Purpose: Update our voting info queries
  130. //-----------------------------------------------------------------------------
  131. void CWorkshopFileInfoManager::Steam_OnGetPublishedItemVoteDetails( RemoteStorageGetPublishedItemVoteDetailsResult_t *pResult, bool bError )
  132. {
  133. // Make sure this callback was successful
  134. if ( bError || pResult->m_eResult != k_EResultOK )
  135. {
  136. Assert(0);
  137. return;
  138. }
  139. // Take this information into the published file info (if present)
  140. PublishedFileInfo_t *pInfo = (PublishedFileInfo_t *) GetPublishedFileInfoByID( pResult->m_unPublishedFileId );
  141. if ( pInfo == NULL )
  142. {
  143. // This means that you've requested voting data for a piece of information we no longer hold
  144. // The info is going to leak at this point
  145. Assert( pInfo != NULL );
  146. return;
  147. }
  148. // Update the data
  149. pInfo->m_bVotingDataValid = true;
  150. pInfo->m_flVotingScore = pResult->m_fScore;
  151. pInfo->m_unUpVotes = pResult->m_nVotesFor;
  152. pInfo->m_unDownVotes = pResult->m_nVotesAgainst;
  153. pInfo->m_unDownVotes = pResult->m_nReports;
  154. // Clear our mutex for more requests
  155. m_bActiveVotingRequest = false;
  156. }
  157. #endif // !_GAMECONSOLE
  158. //-----------------------------------------------------------------------------
  159. // Purpose: Move our information requests forward
  160. //-----------------------------------------------------------------------------
  161. void CWorkshopFileInfoManager::UpdatePublishedFileInfoQueries( void )
  162. {
  163. #ifndef NO_STEAM
  164. #if !defined( _GAMECONSOLE )
  165. // If we have queries to service and none are in flight, start a new query
  166. if ( m_vecPublishedFileInfoQueryList.Count() && m_pActivePublishedFileRequest == NULL )
  167. {
  168. // Iterate over all our files until we hit one that's valid
  169. while ( 1 )
  170. {
  171. CBasePublishedFileRequest *pRequest = m_vecPublishedFileInfoQueryList.RemoveAtHead();
  172. SteamAPICall_t hSteamAPICall = GetISteamRemoteStorage()->GetPublishedFileDetails( pRequest->GetTargetID(), 0 );
  173. if ( hSteamAPICall == k_uAPICallInvalid )
  174. {
  175. //TODO: Handle the error case
  176. Log_Msg( LOG_WORKSHOP, "[BaseModPanel] Failed to query for details on published file: %llu\n", pRequest->GetTargetID() );
  177. continue;
  178. }
  179. Log_Msg( LOG_WORKSHOP, "[BaseModPanel] Querying for details of published file: %llu\n", pRequest->GetTargetID() );
  180. // Query for the details of this file and mark it as the active query
  181. // NOTE: Only only query may be active at any given time, so these requests are done serially
  182. m_callbackGetPublishedFileDetails.Set( hSteamAPICall, this, &CWorkshopFileInfoManager::Steam_OnGetPublishedFileDetails );
  183. m_pActivePublishedFileRequest = pRequest;
  184. break;
  185. }
  186. }
  187. #endif // !_GAMECONSOLE
  188. #endif
  189. }
  190. //-----------------------------------------------------------------------------
  191. // Purpose: Update our voting info queries
  192. //-----------------------------------------------------------------------------
  193. void CWorkshopFileInfoManager::UpdatePublishedFileVotingInfoQueries( void )
  194. {
  195. // We must have work to do...
  196. if ( m_vecVotingInfoRequests.Count() == 0 )
  197. return;
  198. #if !defined( _GAMECONSOLE )
  199. // If we have queries to service and none are in flight, start a new query
  200. if ( m_bActiveVotingRequest == false ) // FIXME: Need to only let one be active at a time
  201. {
  202. // Iterate over all our files until we hit one that's valid
  203. while ( 1 )
  204. {
  205. PublishedFileId_t nTargetID = m_vecVotingInfoRequests.RemoveAtHead();
  206. SteamAPICall_t hSteamAPICall = GetISteamRemoteStorage()->GetPublishedItemVoteDetails( nTargetID );
  207. if ( hSteamAPICall == k_uAPICallInvalid )
  208. {
  209. //TODO: Handle the error case
  210. Log_Msg( LOG_WORKSHOP, "[CWorkshopFileInfoManager] Failed to query for voting details on published file: %llu\n", nTargetID );
  211. continue;
  212. }
  213. Log_Msg( LOG_WORKSHOP, "[CWorkshopFileInfoManager] Querying for voting details of published file: %llu\n", nTargetID );
  214. // Query for the details of this file and mark it as the active query
  215. // NOTE: Only only query may be active at any given time, so these requests are done serially
  216. m_callbackGetPublishedItemVoteDetails.Set( hSteamAPICall, this, &CWorkshopFileInfoManager::Steam_OnGetPublishedItemVoteDetails );
  217. m_bActiveVotingRequest = true;
  218. break;
  219. }
  220. }
  221. #endif // !_GAMECONSOLE
  222. }
  223. //-----------------------------------------------------------------------------
  224. // Purpose: Get published file information by its ID number
  225. //-----------------------------------------------------------------------------
  226. const PublishedFileInfo_t *CWorkshopFileInfoManager::GetPublishedFileInfoByID( PublishedFileId_t nID ) const
  227. {
  228. int nIndex = m_mapPublishedFileInfoDepot.Find( nID );
  229. if ( nIndex == m_mapPublishedFileInfoDepot.InvalidIndex() )
  230. return NULL;
  231. return &(m_mapPublishedFileInfoDepot[nIndex]);
  232. }
  233. //-----------------------------------------------------------------------------
  234. // Purpose: Requests voting information for a published file
  235. // Return: If true, the voting data already exists and can be immediately accessed. Otherwise, the caller will need to wait
  236. //-----------------------------------------------------------------------------
  237. bool CWorkshopFileInfoManager::AddFileVoteInfoRequest( const PublishedFileInfo_t *pInfo, bool bForceUpdate /*=false*/ )
  238. {
  239. Assert( pInfo );
  240. if ( pInfo == NULL )
  241. return false;
  242. // If we're not forcing the update, check our current data first
  243. if ( bForceUpdate == false )
  244. {
  245. // We've already got this data
  246. if ( pInfo->HasVoteData() )
  247. return true;
  248. }
  249. #if !defined( _GAMECONSOLE )
  250. m_vecVotingInfoRequests.Insert( pInfo->m_nPublishedFileId );
  251. #endif
  252. Log_Msg( LOG_WORKSHOP, "[BaseModPanel] Added voting info query for %llu\n", pInfo->m_nPublishedFileId );
  253. return false;
  254. }
  255. //-----------------------------------------------------------------------------
  256. // Purpose: Remove a published file's information from our depot
  257. //-----------------------------------------------------------------------------
  258. bool CWorkshopFileInfoManager::RemovePublishedFileInfo( PublishedFileId_t nID )
  259. {
  260. // Nuke this from our mapping
  261. bool bFound = m_mapPublishedFileInfoDepot.Remove( nID );
  262. // Delete it from our pending queries
  263. if ( m_vecPublishedFileInfoQueryList.Count() )
  264. {
  265. // FIXME: This is an abomination -- JDW
  266. // Move through the queue looking for our ID to delete
  267. CUtlQueue< CBasePublishedFileRequest * > tempQueue;
  268. CBasePublishedFileRequest *pRequest = NULL;
  269. while ( ( pRequest = m_vecPublishedFileInfoQueryList.RemoveAtHead() ) != NULL )
  270. {
  271. if ( pRequest->GetTargetID() == nID )
  272. {
  273. // Nuke our target
  274. delete pRequest;
  275. bFound = true;
  276. continue;
  277. }
  278. tempQueue.Insert( pRequest );
  279. }
  280. // Clear our current queue (should be done already)
  281. m_vecPublishedFileInfoQueryList.RemoveAll();
  282. // Now add them all back -- and we cry
  283. pRequest = NULL;
  284. while ( ( pRequest = tempQueue.RemoveAtHead() ) != NULL )
  285. {
  286. m_vecPublishedFileInfoQueryList.Insert( pRequest );
  287. }
  288. }
  289. return bFound;
  290. }
  291. // Check if the given id is in the list of info queries we haven't yet sent off
  292. bool CWorkshopFileInfoManager::IsInfoRequestStillPending( PublishedFileId_t id ) const
  293. {
  294. // currently sent?
  295. if ( m_pActivePublishedFileRequest && m_pActivePublishedFileRequest->GetTargetID() == id )
  296. return true;
  297. // not yet sent?
  298. for ( int i = 0; i < m_vecPublishedFileInfoQueryList.Count(); ++i )
  299. {
  300. CBasePublishedFileRequest* pReq = m_vecPublishedFileInfoQueryList[i];
  301. if ( pReq && pReq->GetTargetID() == id )
  302. {
  303. return true;
  304. }
  305. }
  306. return false;
  307. }
  308. #endif // !NO_STEAM