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.

230 lines
6.6 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. //=======================================================================================//
  4. #include "errorsystem.h"
  5. #include "replay/ienginereplay.h"
  6. #include "vgui/ILocalize.h"
  7. #include "shared_replaycontext.h"
  8. #if !defined( DEDICATED )
  9. #include "cl_downloader.h"
  10. #include "cl_sessionblockdownloader.h"
  11. #include "cl_recordingsessionblock.h"
  12. #include "replay/iclientreplay.h"
  13. extern IClientReplay *g_pClient;
  14. #endif // !defined( DEDICATED )
  15. // memdbgon must be the last include file in a .cpp file!!!
  16. #include "tier0/memdbgon.h"
  17. //----------------------------------------------------------------------------------------
  18. extern IEngineReplay *g_pEngine;
  19. extern vgui::ILocalize *g_pVGuiLocalize;
  20. //----------------------------------------------------------------------------------------
  21. CErrorSystem::CErrorSystem( IErrorReporter *pErrorReporter )
  22. : m_pErrorReporter( pErrorReporter )
  23. {
  24. }
  25. CErrorSystem::~CErrorSystem()
  26. {
  27. Clear();
  28. }
  29. void CErrorSystem::Clear()
  30. {
  31. FOR_EACH_LL( m_lstErrors, i )
  32. {
  33. wchar_t *pText = m_lstErrors[ i ];
  34. delete [] pText;
  35. }
  36. m_lstErrors.RemoveAll();
  37. }
  38. void CErrorSystem::AddError( const wchar_t *pError )
  39. {
  40. if ( !pError || !pError[0] )
  41. return;
  42. // Cache a copied version of the string
  43. const int nLen = wcslen( pError ) + 1;
  44. wchar_t *pNewError = new wchar_t[ nLen ];
  45. const int nSize = nLen * sizeof( wchar_t );
  46. V_wcsncpy( pNewError, pError, nSize );
  47. m_lstErrors.AddToTail( pNewError );
  48. }
  49. void CErrorSystem::AddError( const char *pError )
  50. {
  51. if ( !pError || !pError[0] )
  52. return;
  53. wchar_t wszError[1024];
  54. V_UTF8ToUnicode( pError, wszError, sizeof( wszError ) );
  55. AddError( wszError );
  56. }
  57. void CErrorSystem::AddErrorFromTokenName( const char *pToken )
  58. {
  59. if ( g_pVGuiLocalize )
  60. {
  61. AddError( g_pVGuiLocalize->Find( pToken ) );
  62. }
  63. else
  64. {
  65. AddError( pToken );
  66. }
  67. }
  68. void CErrorSystem::AddFormattedErrorFromTokenName( const char *pFormatToken/*=NULL*/, KeyValues *pFormatArgs/*=NULL*/ )
  69. {
  70. if ( !pFormatToken )
  71. {
  72. AssertMsg( 0, "Error token should always be valid." );
  73. return;
  74. }
  75. wchar_t wszErrorStr[1024];
  76. if ( g_pVGuiLocalize )
  77. {
  78. g_pVGuiLocalize->ConstructString( wszErrorStr, sizeof( wszErrorStr ), pFormatToken, pFormatArgs );
  79. }
  80. else
  81. {
  82. V_UTF8ToUnicode( pFormatToken, wszErrorStr, sizeof( wszErrorStr ) );
  83. }
  84. // Add the error
  85. AddError( wszErrorStr );
  86. // Delete args
  87. pFormatArgs->deleteThis();
  88. }
  89. #if !defined( DEDICATED )
  90. int g_nGenericErrorCounter = 0;
  91. void CErrorSystem::OGS_ReportSessionBlockDownloadError( const CHttpDownloader *pDownloader, const CClientRecordingSessionBlock *pBlock,
  92. int nLocalFileSize, int nMaxBlock, const bool *pSizesDiffer,
  93. const bool *pHashFail, uint8 *pLocalHash )
  94. {
  95. // Create a download error and queue for upload
  96. KeyValues *pDownloadError = pDownloader->GetOgsRow( g_nGenericErrorCounter );
  97. g_pClient->UploadOgsData( pDownloadError, false );
  98. // Create block download error
  99. KeyValues *pBlockDownloadError = new KeyValues( "TF2ReplayBlockDownloadErrors" );
  100. pBlockDownloadError->SetInt( "ErrorCounter", g_nGenericErrorCounter );
  101. pBlockDownloadError->SetInt( "NumCurrentDownloads", CSessionBlockDownloader::sm_nNumCurrentDownloads );
  102. pBlockDownloadError->SetInt( "MaxBlock", nMaxBlock );
  103. pBlockDownloadError->SetInt( "RemoteStatus", (int)pBlock->m_nRemoteStatus );
  104. pBlockDownloadError->SetInt( "ReconstructionIndex", pBlock->m_iReconstruction );
  105. pBlockDownloadError->SetInt( "RemoteFileSize", (int)pBlock->m_uFileSize );
  106. pBlockDownloadError->SetInt( "LocalFileSize", nLocalFileSize );
  107. pBlockDownloadError->SetInt( "NumDownloadAttempts", pBlock->GetNumDownloadAttempts() );
  108. // Only include these if appropriate - otherwise, let them be NULL for the given row
  109. if ( pSizesDiffer )
  110. {
  111. pBlockDownloadError->SetInt( "SizesDiffer", (int)*pSizesDiffer );
  112. }
  113. if ( pHashFail )
  114. {
  115. pBlockDownloadError->SetInt( "HashFail", (int)*pHashFail );
  116. // Include hashes
  117. char szRemoteHash[64], szLocalHash[64];
  118. V_binarytohex( pBlock->m_aHash, sizeof( pBlock->m_aHash ), szRemoteHash, sizeof( szRemoteHash ) );
  119. V_binarytohex( pLocalHash, sizeof( pBlock->m_aHash ), szLocalHash, sizeof( szLocalHash ) );
  120. pBlockDownloadError->SetString( "RemoteHash", szRemoteHash );
  121. pBlockDownloadError->SetString( "LocalHash", szLocalHash );
  122. }
  123. // Upload block download error
  124. g_pClient->UploadOgsData( pBlockDownloadError, false );
  125. // Upload generic error and link to this specific block error.
  126. OGS_ReportGenericError( "Block download failed" );
  127. }
  128. void CErrorSystem::OGS_ReportSessioInfoDownloadError( const CHttpDownloader *pDownloader, const char *pErrorToken )
  129. {
  130. // Create a download error and queue for upload
  131. KeyValues *pDownloadError = pDownloader->GetOgsRow( g_nGenericErrorCounter );
  132. g_pClient->UploadOgsData( pDownloadError, false );
  133. // Create session info download error
  134. KeyValues *pSessionInfoDownloadError = new KeyValues( "TF2ReplaySessionInfoDownloadErrors" );
  135. pSessionInfoDownloadError->SetInt( "ErrorCounter", g_nGenericErrorCounter++ );
  136. pSessionInfoDownloadError->SetString( "SessionInfoDownloadErrorID", pErrorToken );
  137. g_pClient->UploadOgsData( pSessionInfoDownloadError, false );
  138. // Upload generic error and link to this specific block error.
  139. OGS_ReportGenericError( "Session info download failed" );
  140. }
  141. // Note: we use the ErrorCounter as part of the key and so it must be unique. This means that all
  142. // special error tables (ie., session info download errors) must call back into this base function
  143. // to write out the base error and increment the counter.
  144. void CErrorSystem::OGS_ReportGenericError( const char *pGenericErrorToken )
  145. {
  146. KeyValues *pGenericError = new KeyValues( "TF2ReplayErrors" );
  147. pGenericError->SetInt( "ErrorCounter", g_nGenericErrorCounter++ );
  148. pGenericError->SetString( "ReplayErrorID", pGenericErrorToken );
  149. // Upload the generic error row now
  150. g_pClient->UploadOgsData( pGenericError, true );
  151. // Next error!
  152. ++g_nGenericErrorCounter;
  153. }
  154. #endif // !defined( DEDICATED )
  155. float CErrorSystem::GetNextThinkTime() const
  156. {
  157. return g_pEngine->GetHostTime() + 5.0f;
  158. }
  159. void CErrorSystem::Think()
  160. {
  161. CBaseThinker::Think();
  162. if ( m_lstErrors.Count() == 0 )
  163. return;
  164. const int nMaxLen = 4096;
  165. wchar_t wszErrorText[ nMaxLen ] = L"";
  166. FOR_EACH_LL( m_lstErrors, i )
  167. {
  168. const wchar_t *pError = m_lstErrors[ i ];
  169. if ( wcslen( wszErrorText ) + wcslen( pError ) + 1 >= nMaxLen )
  170. break;
  171. wcscat( wszErrorText, pError );
  172. wcscat( wszErrorText, L"\n" );
  173. }
  174. // Report now
  175. m_pErrorReporter->ReportErrorsToUser( wszErrorText );
  176. // Clear
  177. Clear();
  178. }
  179. //----------------------------------------------------------------------------------------