diff options
Diffstat (limited to 'game/shared/motd.cpp')
| -rw-r--r-- | game/shared/motd.cpp | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/game/shared/motd.cpp b/game/shared/motd.cpp new file mode 100644 index 0000000..d9a245b --- /dev/null +++ b/game/shared/motd.cpp @@ -0,0 +1,281 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: motd: Handles a list of message of the day entries +// +//============================================================================= + +#include "cbase.h" +#include "motd.h" +#include "schemainitutils.h" +#include "rtime.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +using namespace GCSDK; + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +CMOTDEntryDefinition::CMOTDEntryDefinition( void ) +{ + m_pKVMOTD = NULL; + m_PostTime = 0; + m_ChangedTime = 0; +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +bool CMOTDEntryDefinition::BInitFromKV( KeyValues *pKVMOTD, CUtlVector<CUtlString> *pVecErrors ) +{ + m_pKVMOTD = pKVMOTD->MakeCopy(); + + const char *pszTime = m_pKVMOTD->GetString( "post_time", NULL ); + m_PostTime = (pszTime && pszTime[0]) ? CRTime::RTime32FromString(pszTime) : 0; + + pszTime = m_pKVMOTD->GetString( "last_changed_time", NULL ); + m_ChangedTime = (pszTime && pszTime[0]) ? CRTime::RTime32FromString(pszTime) : 0; + + return SCHEMA_INIT_SUCCESS(); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +const char *CMOTDEntryDefinition::GetTitle( ELanguage eLang ) +{ + if ( m_pKVMOTD ) + { + // See if we have a localised block for the specified language. + const char *pszLanguage = GetLanguageShortName( eLang ); + if ( pszLanguage && pszLanguage[0] ) + { + const char *pszText = m_pKVMOTD->GetString( CFmtStr( "title_%s", pszLanguage ), NULL ); + if ( pszText && pszText[0] ) + return pszText; + } + + // Fall back to english + return m_pKVMOTD->GetString( "title_english", "No Title" ); + } + + return "No Title"; +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +const char *CMOTDEntryDefinition::GetText( ELanguage eLang ) +{ + if ( m_pKVMOTD ) + { + // See if we have a localised block for the specified language. + const char *pszLanguage = GetLanguageShortName( eLang ); + if ( pszLanguage && pszLanguage[0] ) + { + const char *pszText = m_pKVMOTD->GetString( CFmtStr( "text_%s", pszLanguage ), NULL ); + if ( pszText && pszText[0] ) + return pszText; + } + + // Fall back to english + return m_pKVMOTD->GetString( "text_english", "No text" ); + } + + return "No text"; +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +const char *CMOTDEntryDefinition::GetHeaderTitle( ELanguage eLang ) +{ + if ( m_pKVMOTD ) + { + // See if we have a localised block for the specified language. + const char *pszLanguage = GetLanguageShortName( eLang ); + if ( pszLanguage && pszLanguage[0] ) + { + const char *pszText = m_pKVMOTD->GetString( CFmtStr( "header_%s", pszLanguage ), NULL ); + if ( pszText && pszText[0] ) + return pszText; + } + + // Fall back to english + return m_pKVMOTD->GetString( "header_english", "News" ); + } + + return "News"; +} + +// Sort by ID +int MOTDEntriesListLess( const CMOTDEntryDefinition *pLhs, const CMOTDEntryDefinition *pRhs ) +{ + // This is stupid, sort by the KeyID instead + return ( pLhs->GetNameInt() > pRhs->GetNameInt() ); +} + +//----------------------------------------------------------------------------- +// Purpose: Initializes the loot lists section of the schema +//----------------------------------------------------------------------------- +bool CMOTDManager::BInitMOTDEntries( KeyValues *pKVMOTDEntries, CUtlVector<CUtlString> *pVecErrors ) +{ + m_vecMOTDEntries.RemoveAll(); + + RTime32 iPrevTime = 0; + + if ( NULL != pKVMOTDEntries ) + { + FOR_EACH_TRUE_SUBKEY( pKVMOTDEntries, pKVEntry ) + { + const char *listName = pKVEntry->GetName(); + + SCHEMA_INIT_CHECK( listName != NULL, "All MOTD entries must have titles." ); + + int idx = m_vecMOTDEntries.AddToTail(); + SCHEMA_INIT_SUBSTEP( m_vecMOTDEntries[idx].BInitFromKV( pKVEntry, pVecErrors ) ); + + // Make sure the dates all move forward + SCHEMA_INIT_CHECK( m_vecMOTDEntries[idx].GetPostTime() > iPrevTime , "MOTD entry '%s' occurs prior to the previous entry.", m_vecMOTDEntries[idx].GetName() ); + iPrevTime = m_vecMOTDEntries[idx].GetPostTime(); + } + } + + // Then sort all the MOTDs in order of their changed times, so we can easily send them + m_vecMOTDEntries.Sort( MOTDEntriesListLess ); + + return SCHEMA_INIT_SUCCESS(); +} + +//----------------------------------------------------------------------------- +// Purpose: Returns the number of MOTD entries we've got after the specified time +//----------------------------------------------------------------------------- +int CMOTDManager::GetNumMOTDAfter( RTime32 iTime ) +{ + FOR_EACH_VEC( m_vecMOTDEntries, i ) + { + if ( m_vecMOTDEntries[i].GetChangedTime() > iTime ) + { + // We've hit the first MOTD entry after this time. All following posts are assumed after. + return (m_vecMOTDEntries.Count() - i); + } + } + + return 0; +} + +//----------------------------------------------------------------------------- +// Remove all unused MOTD: Save memory and whatever +//----------------------------------------------------------------------------- +void CMOTDManager::PurgeUnusedMOTDEntries( KeyValues *pKVMOTDEntries ) +{ + // Find the latest entry name and remove all others + int iLargest = -1; + FOR_EACH_VEC_BACK( m_vecMOTDEntries, i ) + { + int iMOTDindex = m_vecMOTDEntries[i].GetNameInt(); + if ( iMOTDindex > iLargest ) + { + iLargest = iMOTDindex; + } + } + + FOR_EACH_VEC_BACK( m_vecMOTDEntries, i ) + { + int iMOTDindex = m_vecMOTDEntries[i].GetNameInt(); + if ( iMOTDindex < iLargest ) + { + if ( pKVMOTDEntries ) + { + KeyValues *pKey = pKVMOTDEntries->FindKey( m_vecMOTDEntries[i].GetName() ); + if ( pKey ) + { + pKVMOTDEntries->RemoveSubKey( pKey ); + } + } + m_vecMOTDEntries.Remove( i ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Returns the definition for the next blog post after the specified time +//----------------------------------------------------------------------------- +CMOTDEntryDefinition *CMOTDManager::GetNextMOTDAfter( RTime32 iTime ) +{ + FOR_EACH_VEC( m_vecMOTDEntries, i ) + { + if ( m_vecMOTDEntries[i].GetChangedTime() > iTime ) + return &m_vecMOTDEntries[i]; + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CMOTDEntryDefinition *CMOTDManager::GetMOTDByIndex( int iIndex ) +{ + if ( iIndex < 0 || iIndex > m_vecMOTDEntries.Count() ) + return NULL; + return &m_vecMOTDEntries[iIndex]; +} + + +#ifdef GC_DLL + +//----------------------------------------------------------------------------- +// Handle MOTD requests job. +//----------------------------------------------------------------------------- +class CGCMOTDRequest : public CGCGameBaseJob +{ +public: + CGCMOTDRequest( CGCGameBase *pGC ) : CGCGameBaseJob( pGC ) { } + bool BYieldingRunJobFromMsg( GCSDK::IMsgNetPacket *pNetPacket ); +}; + + +//----------------------------------------------------------------------------- +// Purpose: Responds to requests from the client for the current MOTD list +//----------------------------------------------------------------------------- +bool CGCMOTDRequest::BYieldingRunJobFromMsg( IMsgNetPacket *pNetPacket ) +{ + CGCMsg< MsgGCMOTDRequest_t > msg( pNetPacket ); + ELanguage eLang = (ELanguage)msg.Body().m_eLanguage; + RTime32 iMOTDTime = msg.Body().m_nLastMOTDRequest; + + // Send the response to the client + GCSDK::CGCMsg<MsgGCMOTDRequestResponse_t> msg_response( k_EMsgGCMOTDRequestResponse ); + + int iEntries = 0; + CMOTDEntryDefinition *pMOTD = m_pGCGameBase->GetMOTDManager().GetNextMOTDAfter( iMOTDTime ); + while ( pMOTD ) + { + // Stuff this MOTD into the message. + msg_response.AddStrData( pMOTD->GetName() ); + msg_response.AddUintData( pMOTD->GetPostTime() ); + msg_response.AddStrData( pMOTD->GetTitle( eLang ) ); + msg_response.AddStrData( pMOTD->GetText( eLang ) ); + msg_response.AddStrData( pMOTD->GetURL() ); + msg_response.AddStrData( pMOTD->GetImage() ); + msg_response.AddIntData( pMOTD->GetHeaderType() ); + msg_response.AddStrData( pMOTD->GetHeaderTitle( eLang ) ); + msg_response.AddStrData( pMOTD->GetHeaderIcon() ); + iEntries++; + + // Move on to the next message. + iMOTDTime = pMOTD->GetChangedTime(); + pMOTD = m_pGCGameBase->GetMOTDManager().GetNextMOTDAfter( iMOTDTime ); + } + msg_response.Body().m_nEntries = iEntries; + + GGCEcon()->BSendGCMsgToClient( msg.Hdr().m_ulSteamID, msg_response ); + + return true; +} + +GC_REG_JOB( CGCGameBase, CGCMOTDRequest, "CGCMOTDRequest", k_EMsgGCMOTDRequest, k_EServerTypeGC ); + +#endif // GC_DLL |