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

//========= 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