|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Manager for handling UGC file information requests
//
//========================================================================//
#include "cbase.h"
#include "ugc_file_info_manager.h"
#if !defined (NO_STEAM) && !defined ( _PS3 )
CWorkshopFileInfoManager::CWorkshopFileInfoManager( IWorkshopFileInfoManagerCallbackInterface *pCallbackInterface ) : m_bActiveVotingRequest( false ), m_pActivePublishedFileRequest( NULL ), m_pCallbackInterface( pCallbackInterface ) { m_mapPublishedFileInfoDepot.SetLessFunc( DefLessFunc( PublishedFileId_t ) ); }
CWorkshopFileInfoManager::~CWorkshopFileInfoManager( void ) { }
//-----------------------------------------------------------------------------
// Purpose: Drive our requests forward
//-----------------------------------------------------------------------------
void CWorkshopFileInfoManager::Update( void ) { UpdatePublishedFileInfoQueries(); UpdatePublishedFileVotingInfoQueries(); }
//-----------------------------------------------------------------------------
// Purpose: Adds a published file to the query
// Return: If true, the published file already exists and the data can be immediately queried for. Otherwise, the caller will need to wait
//-----------------------------------------------------------------------------
bool CWorkshopFileInfoManager::AddFileInfoQuery( CBasePublishedFileRequest *pRequest, bool bAllowUpdate /*= false*/ ) { #ifndef NO_STEAM
Log_Msg( LOG_WORKSHOP, "[BaseModPanel] Added query for published file %llu\n", pRequest->GetTargetID() );
// If they don't want redundant calls in the hopper, early out
if ( bAllowUpdate == false && m_mapPublishedFileInfoDepot.Find( pRequest->GetTargetID() ) != m_mapPublishedFileInfoDepot.InvalidIndex() ) { // FIXME: ICK!
delete pRequest; return true; }
// FIXME: How do we ensure we're not colliding with data already present?
m_vecPublishedFileInfoQueryList.Insert( pRequest ); #endif
return false; }
#if !defined( _GAMECONSOLE )
//-----------------------------------------------------------------------------
// Purpose: Callbacks for retrieving information about a published file
//-----------------------------------------------------------------------------
void CWorkshopFileInfoManager::Steam_OnGetPublishedFileDetails( RemoteStorageGetPublishedFileDetailsResult_t *pResult, bool bError ) { if ( bError || pResult->m_eResult != k_EResultOK ) { // This file may have been revoked from the network, don't display it
if ( pResult->m_eResult == k_EResultFileNotFound ) { // FIXME: Do file clean-up at this point!
Log_Msg( LOG_WORKSHOP, "[BaseModPanel] Error: Failed to retrieve data for %llu (File Not Found)\n", m_pActivePublishedFileRequest->GetTargetID() ); } else { Log_Msg( LOG_WORKSHOP, "[BaseModPanel] Error: Failed to retrieve data for %llu (Error: %d)\n", m_pActivePublishedFileRequest->GetTargetID(), pResult->m_eResult ); }
// Clean up and move forward
m_pActivePublishedFileRequest->OnError( pResult->m_eResult ); if ( m_pCallbackInterface ) { m_pCallbackInterface->OnFileRequestError( pResult->m_nPublishedFileId ); }
delete m_pActivePublishedFileRequest; m_pActivePublishedFileRequest = NULL; return; }
// If this happens, it means that the request was nuked mid-flight!
Assert( m_pActivePublishedFileRequest != NULL ); if ( m_pActivePublishedFileRequest == NULL ) return;
// We're going to either update a current copy of this information, or create a new entry
int nIndex = m_mapPublishedFileInfoDepot.Find( pResult->m_nPublishedFileId ); if ( nIndex != m_mapPublishedFileInfoDepot.InvalidIndex() ) { Log_Msg( LOG_WORKSHOP, "[BaseModPanel] Updated file information for %llu\n", pResult->m_nPublishedFileId );
m_mapPublishedFileInfoDepot[nIndex].m_eVisibility = pResult->m_eVisibility; m_mapPublishedFileInfoDepot[nIndex].m_hFile = pResult->m_hFile; m_mapPublishedFileInfoDepot[nIndex].m_hPreviewFile = pResult->m_hPreviewFile; m_mapPublishedFileInfoDepot[nIndex].m_rtimeCreated = pResult->m_rtimeCreated; m_mapPublishedFileInfoDepot[nIndex].m_rtimeUpdated = pResult->m_rtimeUpdated; m_mapPublishedFileInfoDepot[nIndex].m_ulSteamIDOwner = pResult->m_ulSteamIDOwner; m_mapPublishedFileInfoDepot[nIndex].m_bTagsTruncated = pResult->m_bTagsTruncated; memcpy( m_mapPublishedFileInfoDepot[nIndex].m_rgchTitle, pResult->m_rgchTitle, ARRAYSIZE( m_mapPublishedFileInfoDepot[nIndex].m_rgchTitle ) ); memcpy( m_mapPublishedFileInfoDepot[nIndex].m_rgchDescription, pResult->m_rgchDescription, ARRAYSIZE( m_mapPublishedFileInfoDepot[nIndex].m_rgchDescription ) ); memcpy( m_mapPublishedFileInfoDepot[nIndex].m_pchFileName, pResult->m_pchFileName, ARRAYSIZE( m_mapPublishedFileInfoDepot[nIndex].m_pchFileName ) ); memcpy( m_mapPublishedFileInfoDepot[nIndex].m_rgchTags, pResult->m_rgchTags, ARRAYSIZE( m_mapPublishedFileInfoDepot[nIndex].m_rgchTags ) ); } else { Log_Msg( LOG_WORKSHOP, "[BaseModPanel] Added file information for %llu\n", pResult->m_nPublishedFileId );
// Package up the info block for insertion into our master depot
PublishedFileInfo_t info( pResult->m_nPublishedFileId ); info.m_eVisibility = pResult->m_eVisibility; info.m_hFile = pResult->m_hFile; info.m_hPreviewFile = pResult->m_hPreviewFile; info.m_rtimeCreated = pResult->m_rtimeCreated; info.m_rtimeUpdated = pResult->m_rtimeUpdated; info.m_ulSteamIDOwner = pResult->m_ulSteamIDOwner; info.m_bTagsTruncated = pResult->m_bTagsTruncated; memcpy( info.m_rgchTitle, pResult->m_rgchTitle, ARRAYSIZE( info.m_rgchTitle ) ); memcpy( info.m_rgchDescription, pResult->m_rgchDescription, ARRAYSIZE( info.m_rgchDescription ) ); memcpy( info.m_pchFileName, pResult->m_pchFileName, ARRAYSIZE( info.m_pchFileName ) ); memcpy( info.m_rgchTags, pResult->m_rgchTags, ARRAYSIZE( info.m_rgchTags ) );
// Add it into our master list
nIndex = m_mapPublishedFileInfoDepot.Insert( pResult->m_nPublishedFileId, info ); }
//Store all the tags
m_mapPublishedFileInfoDepot[nIndex].m_vTags.PurgeAndDeleteElements(); V_SplitString( m_mapPublishedFileInfoDepot[nIndex].m_rgchTags, ",", m_mapPublishedFileInfoDepot[nIndex].m_vTags );
// Call our post-load operation
m_pActivePublishedFileRequest->OnLoaded( m_mapPublishedFileInfoDepot[nIndex] );
if ( m_pCallbackInterface ) { m_pCallbackInterface->OnFileRequestFinished( pResult->m_nPublishedFileId ); }
// FIXME: Can we assure that the request is done at this point?
delete m_pActivePublishedFileRequest; m_pActivePublishedFileRequest = NULL; }
//-----------------------------------------------------------------------------
// Purpose: Update our voting info queries
//-----------------------------------------------------------------------------
void CWorkshopFileInfoManager::Steam_OnGetPublishedItemVoteDetails( RemoteStorageGetPublishedItemVoteDetailsResult_t *pResult, bool bError ) { // Make sure this callback was successful
if ( bError || pResult->m_eResult != k_EResultOK ) { Assert(0); return; }
// Take this information into the published file info (if present)
PublishedFileInfo_t *pInfo = (PublishedFileInfo_t *) GetPublishedFileInfoByID( pResult->m_unPublishedFileId ); if ( pInfo == NULL ) { // This means that you've requested voting data for a piece of information we no longer hold
// The info is going to leak at this point
Assert( pInfo != NULL ); return; }
// Update the data
pInfo->m_bVotingDataValid = true; pInfo->m_flVotingScore = pResult->m_fScore; pInfo->m_unUpVotes = pResult->m_nVotesFor; pInfo->m_unDownVotes = pResult->m_nVotesAgainst; pInfo->m_unDownVotes = pResult->m_nReports;
// Clear our mutex for more requests
m_bActiveVotingRequest = false; }
#endif // !_GAMECONSOLE
//-----------------------------------------------------------------------------
// Purpose: Move our information requests forward
//-----------------------------------------------------------------------------
void CWorkshopFileInfoManager::UpdatePublishedFileInfoQueries( void ) { #ifndef NO_STEAM
#if !defined( _GAMECONSOLE )
// If we have queries to service and none are in flight, start a new query
if ( m_vecPublishedFileInfoQueryList.Count() && m_pActivePublishedFileRequest == NULL ) { // Iterate over all our files until we hit one that's valid
while ( 1 ) { CBasePublishedFileRequest *pRequest = m_vecPublishedFileInfoQueryList.RemoveAtHead();
SteamAPICall_t hSteamAPICall = GetISteamRemoteStorage()->GetPublishedFileDetails( pRequest->GetTargetID(), 0 ); if ( hSteamAPICall == k_uAPICallInvalid ) { //TODO: Handle the error case
Log_Msg( LOG_WORKSHOP, "[BaseModPanel] Failed to query for details on published file: %llu\n", pRequest->GetTargetID() ); continue; }
Log_Msg( LOG_WORKSHOP, "[BaseModPanel] Querying for details of published file: %llu\n", pRequest->GetTargetID() );
// Query for the details of this file and mark it as the active query
// NOTE: Only only query may be active at any given time, so these requests are done serially
m_callbackGetPublishedFileDetails.Set( hSteamAPICall, this, &CWorkshopFileInfoManager::Steam_OnGetPublishedFileDetails ); m_pActivePublishedFileRequest = pRequest; break; } } #endif // !_GAMECONSOLE
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Update our voting info queries
//-----------------------------------------------------------------------------
void CWorkshopFileInfoManager::UpdatePublishedFileVotingInfoQueries( void ) { // We must have work to do...
if ( m_vecVotingInfoRequests.Count() == 0 ) return;
#if !defined( _GAMECONSOLE )
// If we have queries to service and none are in flight, start a new query
if ( m_bActiveVotingRequest == false ) // FIXME: Need to only let one be active at a time
{ // Iterate over all our files until we hit one that's valid
while ( 1 ) { PublishedFileId_t nTargetID = m_vecVotingInfoRequests.RemoveAtHead();
SteamAPICall_t hSteamAPICall = GetISteamRemoteStorage()->GetPublishedItemVoteDetails( nTargetID ); if ( hSteamAPICall == k_uAPICallInvalid ) { //TODO: Handle the error case
Log_Msg( LOG_WORKSHOP, "[CWorkshopFileInfoManager] Failed to query for voting details on published file: %llu\n", nTargetID ); continue; }
Log_Msg( LOG_WORKSHOP, "[CWorkshopFileInfoManager] Querying for voting details of published file: %llu\n", nTargetID );
// Query for the details of this file and mark it as the active query
// NOTE: Only only query may be active at any given time, so these requests are done serially
m_callbackGetPublishedItemVoteDetails.Set( hSteamAPICall, this, &CWorkshopFileInfoManager::Steam_OnGetPublishedItemVoteDetails ); m_bActiveVotingRequest = true; break; } }
#endif // !_GAMECONSOLE
}
//-----------------------------------------------------------------------------
// Purpose: Get published file information by its ID number
//-----------------------------------------------------------------------------
const PublishedFileInfo_t *CWorkshopFileInfoManager::GetPublishedFileInfoByID( PublishedFileId_t nID ) const { int nIndex = m_mapPublishedFileInfoDepot.Find( nID ); if ( nIndex == m_mapPublishedFileInfoDepot.InvalidIndex() ) return NULL;
return &(m_mapPublishedFileInfoDepot[nIndex]); }
//-----------------------------------------------------------------------------
// Purpose: Requests voting information for a published file
// Return: If true, the voting data already exists and can be immediately accessed. Otherwise, the caller will need to wait
//-----------------------------------------------------------------------------
bool CWorkshopFileInfoManager::AddFileVoteInfoRequest( const PublishedFileInfo_t *pInfo, bool bForceUpdate /*=false*/ ) { Assert( pInfo ); if ( pInfo == NULL ) return false;
// If we're not forcing the update, check our current data first
if ( bForceUpdate == false ) { // We've already got this data
if ( pInfo->HasVoteData() ) return true; }
#if !defined( _GAMECONSOLE )
m_vecVotingInfoRequests.Insert( pInfo->m_nPublishedFileId ); #endif
Log_Msg( LOG_WORKSHOP, "[BaseModPanel] Added voting info query for %llu\n", pInfo->m_nPublishedFileId ); return false; }
//-----------------------------------------------------------------------------
// Purpose: Remove a published file's information from our depot
//-----------------------------------------------------------------------------
bool CWorkshopFileInfoManager::RemovePublishedFileInfo( PublishedFileId_t nID ) { // Nuke this from our mapping
bool bFound = m_mapPublishedFileInfoDepot.Remove( nID );
// Delete it from our pending queries
if ( m_vecPublishedFileInfoQueryList.Count() ) { // FIXME: This is an abomination -- JDW
// Move through the queue looking for our ID to delete
CUtlQueue< CBasePublishedFileRequest * > tempQueue; CBasePublishedFileRequest *pRequest = NULL; while ( ( pRequest = m_vecPublishedFileInfoQueryList.RemoveAtHead() ) != NULL ) { if ( pRequest->GetTargetID() == nID ) { // Nuke our target
delete pRequest; bFound = true; continue; } tempQueue.Insert( pRequest ); }
// Clear our current queue (should be done already)
m_vecPublishedFileInfoQueryList.RemoveAll(); // Now add them all back -- and we cry
pRequest = NULL; while ( ( pRequest = tempQueue.RemoveAtHead() ) != NULL ) { m_vecPublishedFileInfoQueryList.Insert( pRequest ); } }
return bFound; }
// Check if the given id is in the list of info queries we haven't yet sent off
bool CWorkshopFileInfoManager::IsInfoRequestStillPending( PublishedFileId_t id ) const { // currently sent?
if ( m_pActivePublishedFileRequest && m_pActivePublishedFileRequest->GetTargetID() == id ) return true;
// not yet sent?
for ( int i = 0; i < m_vecPublishedFileInfoQueryList.Count(); ++i ) { CBasePublishedFileRequest* pReq = m_vecPublishedFileInfoQueryList[i]; if ( pReq && pReq->GetTargetID() == id ) { return true; } }
return false; }
#endif // !NO_STEAM
|