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.

281 lines
8.8 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: motd: Handles a list of message of the day entries
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "motd.h"
  8. #include "schemainitutils.h"
  9. #include "rtime.h"
  10. // memdbgon must be the last include file in a .cpp file!!!
  11. #include "tier0/memdbgon.h"
  12. using namespace GCSDK;
  13. //-----------------------------------------------------------------------------
  14. //
  15. //-----------------------------------------------------------------------------
  16. CMOTDEntryDefinition::CMOTDEntryDefinition( void )
  17. {
  18. m_pKVMOTD = NULL;
  19. m_PostTime = 0;
  20. m_ChangedTime = 0;
  21. }
  22. //-----------------------------------------------------------------------------
  23. //
  24. //-----------------------------------------------------------------------------
  25. bool CMOTDEntryDefinition::BInitFromKV( KeyValues *pKVMOTD, CUtlVector<CUtlString> *pVecErrors )
  26. {
  27. m_pKVMOTD = pKVMOTD->MakeCopy();
  28. const char *pszTime = m_pKVMOTD->GetString( "post_time", NULL );
  29. m_PostTime = (pszTime && pszTime[0]) ? CRTime::RTime32FromString(pszTime) : 0;
  30. pszTime = m_pKVMOTD->GetString( "last_changed_time", NULL );
  31. m_ChangedTime = (pszTime && pszTime[0]) ? CRTime::RTime32FromString(pszTime) : 0;
  32. return SCHEMA_INIT_SUCCESS();
  33. }
  34. //-----------------------------------------------------------------------------
  35. //
  36. //-----------------------------------------------------------------------------
  37. const char *CMOTDEntryDefinition::GetTitle( ELanguage eLang )
  38. {
  39. if ( m_pKVMOTD )
  40. {
  41. // See if we have a localised block for the specified language.
  42. const char *pszLanguage = GetLanguageShortName( eLang );
  43. if ( pszLanguage && pszLanguage[0] )
  44. {
  45. const char *pszText = m_pKVMOTD->GetString( CFmtStr( "title_%s", pszLanguage ), NULL );
  46. if ( pszText && pszText[0] )
  47. return pszText;
  48. }
  49. // Fall back to english
  50. return m_pKVMOTD->GetString( "title_english", "No Title" );
  51. }
  52. return "No Title";
  53. }
  54. //-----------------------------------------------------------------------------
  55. //
  56. //-----------------------------------------------------------------------------
  57. const char *CMOTDEntryDefinition::GetText( ELanguage eLang )
  58. {
  59. if ( m_pKVMOTD )
  60. {
  61. // See if we have a localised block for the specified language.
  62. const char *pszLanguage = GetLanguageShortName( eLang );
  63. if ( pszLanguage && pszLanguage[0] )
  64. {
  65. const char *pszText = m_pKVMOTD->GetString( CFmtStr( "text_%s", pszLanguage ), NULL );
  66. if ( pszText && pszText[0] )
  67. return pszText;
  68. }
  69. // Fall back to english
  70. return m_pKVMOTD->GetString( "text_english", "No text" );
  71. }
  72. return "No text";
  73. }
  74. //-----------------------------------------------------------------------------
  75. //
  76. //-----------------------------------------------------------------------------
  77. const char *CMOTDEntryDefinition::GetHeaderTitle( ELanguage eLang )
  78. {
  79. if ( m_pKVMOTD )
  80. {
  81. // See if we have a localised block for the specified language.
  82. const char *pszLanguage = GetLanguageShortName( eLang );
  83. if ( pszLanguage && pszLanguage[0] )
  84. {
  85. const char *pszText = m_pKVMOTD->GetString( CFmtStr( "header_%s", pszLanguage ), NULL );
  86. if ( pszText && pszText[0] )
  87. return pszText;
  88. }
  89. // Fall back to english
  90. return m_pKVMOTD->GetString( "header_english", "News" );
  91. }
  92. return "News";
  93. }
  94. // Sort by ID
  95. int MOTDEntriesListLess( const CMOTDEntryDefinition *pLhs, const CMOTDEntryDefinition *pRhs )
  96. {
  97. // This is stupid, sort by the KeyID instead
  98. return ( pLhs->GetNameInt() > pRhs->GetNameInt() );
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Purpose: Initializes the loot lists section of the schema
  102. //-----------------------------------------------------------------------------
  103. bool CMOTDManager::BInitMOTDEntries( KeyValues *pKVMOTDEntries, CUtlVector<CUtlString> *pVecErrors )
  104. {
  105. m_vecMOTDEntries.RemoveAll();
  106. RTime32 iPrevTime = 0;
  107. if ( NULL != pKVMOTDEntries )
  108. {
  109. FOR_EACH_TRUE_SUBKEY( pKVMOTDEntries, pKVEntry )
  110. {
  111. const char *listName = pKVEntry->GetName();
  112. SCHEMA_INIT_CHECK( listName != NULL, "All MOTD entries must have titles." );
  113. int idx = m_vecMOTDEntries.AddToTail();
  114. SCHEMA_INIT_SUBSTEP( m_vecMOTDEntries[idx].BInitFromKV( pKVEntry, pVecErrors ) );
  115. // Make sure the dates all move forward
  116. SCHEMA_INIT_CHECK( m_vecMOTDEntries[idx].GetPostTime() > iPrevTime , "MOTD entry '%s' occurs prior to the previous entry.", m_vecMOTDEntries[idx].GetName() );
  117. iPrevTime = m_vecMOTDEntries[idx].GetPostTime();
  118. }
  119. }
  120. // Then sort all the MOTDs in order of their changed times, so we can easily send them
  121. m_vecMOTDEntries.Sort( MOTDEntriesListLess );
  122. return SCHEMA_INIT_SUCCESS();
  123. }
  124. //-----------------------------------------------------------------------------
  125. // Purpose: Returns the number of MOTD entries we've got after the specified time
  126. //-----------------------------------------------------------------------------
  127. int CMOTDManager::GetNumMOTDAfter( RTime32 iTime )
  128. {
  129. FOR_EACH_VEC( m_vecMOTDEntries, i )
  130. {
  131. if ( m_vecMOTDEntries[i].GetChangedTime() > iTime )
  132. {
  133. // We've hit the first MOTD entry after this time. All following posts are assumed after.
  134. return (m_vecMOTDEntries.Count() - i);
  135. }
  136. }
  137. return 0;
  138. }
  139. //-----------------------------------------------------------------------------
  140. // Remove all unused MOTD: Save memory and whatever
  141. //-----------------------------------------------------------------------------
  142. void CMOTDManager::PurgeUnusedMOTDEntries( KeyValues *pKVMOTDEntries )
  143. {
  144. // Find the latest entry name and remove all others
  145. int iLargest = -1;
  146. FOR_EACH_VEC_BACK( m_vecMOTDEntries, i )
  147. {
  148. int iMOTDindex = m_vecMOTDEntries[i].GetNameInt();
  149. if ( iMOTDindex > iLargest )
  150. {
  151. iLargest = iMOTDindex;
  152. }
  153. }
  154. FOR_EACH_VEC_BACK( m_vecMOTDEntries, i )
  155. {
  156. int iMOTDindex = m_vecMOTDEntries[i].GetNameInt();
  157. if ( iMOTDindex < iLargest )
  158. {
  159. if ( pKVMOTDEntries )
  160. {
  161. KeyValues *pKey = pKVMOTDEntries->FindKey( m_vecMOTDEntries[i].GetName() );
  162. if ( pKey )
  163. {
  164. pKVMOTDEntries->RemoveSubKey( pKey );
  165. }
  166. }
  167. m_vecMOTDEntries.Remove( i );
  168. }
  169. }
  170. }
  171. //-----------------------------------------------------------------------------
  172. // Purpose: Returns the definition for the next blog post after the specified time
  173. //-----------------------------------------------------------------------------
  174. CMOTDEntryDefinition *CMOTDManager::GetNextMOTDAfter( RTime32 iTime )
  175. {
  176. FOR_EACH_VEC( m_vecMOTDEntries, i )
  177. {
  178. if ( m_vecMOTDEntries[i].GetChangedTime() > iTime )
  179. return &m_vecMOTDEntries[i];
  180. }
  181. return NULL;
  182. }
  183. //-----------------------------------------------------------------------------
  184. // Purpose:
  185. //-----------------------------------------------------------------------------
  186. CMOTDEntryDefinition *CMOTDManager::GetMOTDByIndex( int iIndex )
  187. {
  188. if ( iIndex < 0 || iIndex > m_vecMOTDEntries.Count() )
  189. return NULL;
  190. return &m_vecMOTDEntries[iIndex];
  191. }
  192. #ifdef GC_DLL
  193. //-----------------------------------------------------------------------------
  194. // Handle MOTD requests job.
  195. //-----------------------------------------------------------------------------
  196. class CGCMOTDRequest : public CGCGameBaseJob
  197. {
  198. public:
  199. CGCMOTDRequest( CGCGameBase *pGC ) : CGCGameBaseJob( pGC ) { }
  200. bool BYieldingRunJobFromMsg( GCSDK::IMsgNetPacket *pNetPacket );
  201. };
  202. //-----------------------------------------------------------------------------
  203. // Purpose: Responds to requests from the client for the current MOTD list
  204. //-----------------------------------------------------------------------------
  205. bool CGCMOTDRequest::BYieldingRunJobFromMsg( IMsgNetPacket *pNetPacket )
  206. {
  207. CGCMsg< MsgGCMOTDRequest_t > msg( pNetPacket );
  208. ELanguage eLang = (ELanguage)msg.Body().m_eLanguage;
  209. RTime32 iMOTDTime = msg.Body().m_nLastMOTDRequest;
  210. // Send the response to the client
  211. GCSDK::CGCMsg<MsgGCMOTDRequestResponse_t> msg_response( k_EMsgGCMOTDRequestResponse );
  212. int iEntries = 0;
  213. CMOTDEntryDefinition *pMOTD = m_pGCGameBase->GetMOTDManager().GetNextMOTDAfter( iMOTDTime );
  214. while ( pMOTD )
  215. {
  216. // Stuff this MOTD into the message.
  217. msg_response.AddStrData( pMOTD->GetName() );
  218. msg_response.AddUintData( pMOTD->GetPostTime() );
  219. msg_response.AddStrData( pMOTD->GetTitle( eLang ) );
  220. msg_response.AddStrData( pMOTD->GetText( eLang ) );
  221. msg_response.AddStrData( pMOTD->GetURL() );
  222. msg_response.AddStrData( pMOTD->GetImage() );
  223. msg_response.AddIntData( pMOTD->GetHeaderType() );
  224. msg_response.AddStrData( pMOTD->GetHeaderTitle( eLang ) );
  225. msg_response.AddStrData( pMOTD->GetHeaderIcon() );
  226. iEntries++;
  227. // Move on to the next message.
  228. iMOTDTime = pMOTD->GetChangedTime();
  229. pMOTD = m_pGCGameBase->GetMOTDManager().GetNextMOTDAfter( iMOTDTime );
  230. }
  231. msg_response.Body().m_nEntries = iEntries;
  232. GGCEcon()->BSendGCMsgToClient( msg.Hdr().m_ulSteamID, msg_response );
  233. return true;
  234. }
  235. GC_REG_JOB( CGCGameBase, CGCMOTDRequest, "CGCMOTDRequest", k_EMsgGCMOTDRequest, k_EServerTypeGC );
  236. #endif // GC_DLL