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.

575 lines
14 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "hud_pdump.h"
  8. #include "iclientmode.h"
  9. #include "predictioncopy.h"
  10. #include "vgui/ISurface.h"
  11. #include "vgui/ILocalize.h"
  12. #include "vgui_int.h"
  13. #include "in_buttons.h"
  14. // memdbgon must be the last include file in a .cpp file!!!
  15. #include "tier0/memdbgon.h"
  16. using namespace vgui;
  17. CPDumpPanel *GetPDumpPanel()
  18. {
  19. return GET_FULLSCREEN_HUDELEMENT( CPDumpPanel );
  20. }
  21. DECLARE_HUDELEMENT_FLAGS( CPDumpPanel, HUDELEMENT_SS_FULLSCREEN_ONLY );
  22. CPDumpPanel::CPDumpPanel( const char *pElementName ) :
  23. CHudElement( pElementName ), BaseClass( NULL, "HudPredictionDump" ), m_nCurrentIndex( 0 )
  24. {
  25. vgui::Panel *pParent = GetFullscreenClientMode()->GetViewport();
  26. SetParent( pParent );
  27. SetProportional( false );
  28. SetKeyBoardInputEnabled( false );
  29. SetMouseInputEnabled( false );
  30. }
  31. CPDumpPanel::~CPDumpPanel()
  32. {
  33. }
  34. void CPDumpPanel::ApplySettings( KeyValues *inResourceData )
  35. {
  36. SetProportional( false );
  37. BaseClass::ApplySettings( inResourceData );
  38. }
  39. void CPDumpPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
  40. {
  41. SetProportional( false );
  42. BaseClass::ApplySchemeSettings( pScheme );
  43. SetPaintBackgroundEnabled( false );
  44. int screenWide, screenTall;
  45. VGui_GetTrueScreenSize(screenWide, screenTall);
  46. SetBounds(0, 0, screenWide, screenTall);
  47. // Make sure we sort above everyone else
  48. SetZPos( 100 );
  49. }
  50. //-----------------------------------------------------------------------------
  51. // Purpose:
  52. // Output : Returns true on success, false on failure.
  53. //-----------------------------------------------------------------------------
  54. bool CPDumpPanel::ShouldDraw()
  55. {
  56. if ( m_DumpEntityInfo.Count() == 0 )
  57. return false;
  58. return CHudElement::ShouldDraw();
  59. }
  60. static char const *pchButtonFields[]=
  61. {
  62. "m_nOldButtons",
  63. "m_nButtons",
  64. "m_afButtonLast",
  65. "m_afButtonPressed",
  66. "m_afButtonReleased",
  67. "m_afButtonForced",
  68. };
  69. static bool IsButtonField( char const *fieldname )
  70. {
  71. for ( int i =0 ; i < ARRAYSIZE( pchButtonFields ); ++i )
  72. {
  73. if ( !Q_stricmp( fieldname, pchButtonFields[ i ] ) )
  74. return true;
  75. }
  76. return false;
  77. }
  78. struct buttonname_t
  79. {
  80. int nBit;
  81. char const *pchName;
  82. };
  83. #define DECLARE_BUTTON_NAME( x ) { IN_##x, #x }
  84. static buttonname_t g_ButtonNames[] =
  85. {
  86. DECLARE_BUTTON_NAME( ATTACK ),
  87. DECLARE_BUTTON_NAME( JUMP ),
  88. DECLARE_BUTTON_NAME( DUCK ),
  89. DECLARE_BUTTON_NAME( FORWARD ),
  90. DECLARE_BUTTON_NAME( BACK ),
  91. DECLARE_BUTTON_NAME( USE ),
  92. DECLARE_BUTTON_NAME( CANCEL ),
  93. DECLARE_BUTTON_NAME( LEFT ),
  94. DECLARE_BUTTON_NAME( RIGHT ),
  95. DECLARE_BUTTON_NAME( MOVELEFT ),
  96. DECLARE_BUTTON_NAME( MOVERIGHT ),
  97. DECLARE_BUTTON_NAME( ATTACK2 ),
  98. DECLARE_BUTTON_NAME( RUN ),
  99. DECLARE_BUTTON_NAME( RELOAD ),
  100. DECLARE_BUTTON_NAME( ALT1 ),
  101. DECLARE_BUTTON_NAME( ALT2 ),
  102. DECLARE_BUTTON_NAME( SCORE ),
  103. DECLARE_BUTTON_NAME( SPEED),
  104. DECLARE_BUTTON_NAME( WALK ),
  105. DECLARE_BUTTON_NAME( ZOOM ),
  106. DECLARE_BUTTON_NAME( WEAPON1 ),
  107. DECLARE_BUTTON_NAME( WEAPON2 ),
  108. DECLARE_BUTTON_NAME( BULLRUSH ),
  109. DECLARE_BUTTON_NAME( GRENADE1 ),
  110. DECLARE_BUTTON_NAME( GRENADE2 ),
  111. DECLARE_BUTTON_NAME( LOOKSPIN ),
  112. };
  113. static char const *GetButtonFieldValue( char const *value, char *buf, size_t bufsize )
  114. {
  115. buf[ 0 ] = 0;
  116. char *pchDataStart = Q_strstr( value, "(" );
  117. if ( !pchDataStart )
  118. return value;
  119. int bits = Q_atoi( pchDataStart + 1 );
  120. // Assign button bits
  121. bool first = true;
  122. for ( int i = 0; i < ARRAYSIZE( g_ButtonNames ); ++i )
  123. {
  124. int mask = (1<<i);
  125. if ( bits & mask )
  126. {
  127. if ( !first )
  128. {
  129. Q_strncat( buf, ",", bufsize, COPY_ALL_CHARACTERS );
  130. }
  131. Q_strncat( buf, g_ButtonNames[ i ].pchName, bufsize, COPY_ALL_CHARACTERS );
  132. first = false;
  133. }
  134. }
  135. Q_strlower( buf );
  136. return buf;
  137. }
  138. static char const *CleanupZeros( char const *value, char *buf, size_t bufsize )
  139. {
  140. char *out = buf;
  141. while ( *value )
  142. {
  143. if ( *value != '.' )
  144. {
  145. *out++ = *value++;
  146. continue;
  147. }
  148. // Found a . now see if next run of characters until space or ')' is all zeroes
  149. char const *next = value + 1;
  150. while ( *next && *next == '0' )
  151. ++next;
  152. if ( *next == ' ' || *next == ')' )
  153. {
  154. // Don't write the . or the zeroes, just put value at the terminator
  155. value = next;
  156. }
  157. else
  158. {
  159. *out++ = *value++;
  160. }
  161. }
  162. *out = 0;
  163. return buf;
  164. }
  165. void CPDumpPanel::DumpComparision( const char *classname, const char *fieldname, const char *fieldtype,
  166. bool networked, bool noterrorchecked, bool differs, bool withintolerance, const char *value )
  167. {
  168. if ( fieldname == NULL )
  169. return;
  170. DumpInfo slot;
  171. slot.index = m_nCurrentIndex++;
  172. Q_snprintf( slot.classname, sizeof( slot.classname ), "%s", classname );
  173. slot.networked = networked;
  174. char bv[ DUMP_STRING_SIZE ];
  175. if ( IsButtonField( fieldname ) )
  176. {
  177. value = GetButtonFieldValue( value, bv, sizeof( bv ) );
  178. }
  179. else
  180. {
  181. value = CleanupZeros( value, bv, sizeof( bv ) );
  182. }
  183. Q_snprintf( slot.fieldstring, sizeof( slot.fieldstring ), "%s %s",
  184. fieldname,
  185. value );
  186. slot.differs = differs;
  187. slot.withintolerance = withintolerance;
  188. slot.noterrorchecked = noterrorchecked;
  189. m_DumpEntityInfo.InsertNoSort( slot );
  190. }
  191. //-----------------------------------------------------------------------------
  192. // Purpose: Callback function for dumping entity info to screen
  193. // Input : *classname -
  194. // *fieldname -
  195. // *fieldtype -
  196. // networked -
  197. // noterrorchecked -
  198. // differs -
  199. // withintolerance -
  200. // *value -
  201. // Output : static void
  202. //-----------------------------------------------------------------------------
  203. static void DumpComparision( const char *classname, const char *fieldname, const char *fieldtype,
  204. bool networked, bool noterrorchecked, bool differs, bool withintolerance, const char *value )
  205. {
  206. CPDumpPanel *pPanel = GetPDumpPanel();
  207. if ( !pPanel )
  208. return;
  209. pPanel->DumpComparision( classname, fieldname, fieldtype, networked, noterrorchecked, differs, withintolerance, value );
  210. }
  211. //-----------------------------------------------------------------------------
  212. // Purpose: Lookup color to use for data
  213. // Input : networked -
  214. // errorchecked -
  215. // differs -
  216. // withintolerance -
  217. // r -
  218. // g -
  219. // b -
  220. // a -
  221. // Output : static void
  222. //-----------------------------------------------------------------------------
  223. void CPDumpPanel::PredictionDumpColor( bool legend, bool predictable, bool networked, bool errorchecked, bool differs, bool withintolerance,
  224. int& r, int& g, int& b, int& a )
  225. {
  226. if ( !legend && !predictable )
  227. {
  228. r = 150;
  229. g = 180;
  230. b = 150;
  231. a = 255;
  232. return;
  233. }
  234. r = 255;
  235. g = 255;
  236. b = 255;
  237. a = 255;
  238. if ( networked )
  239. {
  240. if ( errorchecked )
  241. {
  242. r = 180;
  243. g = 180;
  244. b = 225;
  245. }
  246. else
  247. {
  248. r = 150;
  249. g = 180;
  250. b = 150;
  251. }
  252. }
  253. if ( differs )
  254. {
  255. if ( withintolerance )
  256. {
  257. r = 255;
  258. g = 255;
  259. b = 0;
  260. a = 255;
  261. }
  262. else
  263. {
  264. if ( !networked )
  265. {
  266. r = 180;
  267. g = 180;
  268. b = 100;
  269. a = 255;
  270. }
  271. else
  272. {
  273. r = 255;
  274. g = 0;
  275. b = 0;
  276. a = 255;
  277. }
  278. }
  279. }
  280. }
  281. //-----------------------------------------------------------------------------
  282. // Purpose: Dump entity data to screen
  283. // Input : *ent -
  284. // last_predicted -
  285. //-----------------------------------------------------------------------------
  286. void CPDumpPanel::DumpEntity( C_BaseEntity *ent, int commands_acknowledged )
  287. {
  288. #ifdef NO_ENTITY_PREDICTION
  289. return;
  290. #else
  291. Assert( ent );
  292. const byte *original_state_data = NULL;
  293. const byte *predicted_state_data = NULL;
  294. bool data_type_original = TD_OFFSET_PACKED;
  295. bool data_type_predicted = TD_OFFSET_PACKED;
  296. if ( ent->GetPredictable() )
  297. {
  298. original_state_data = (const byte *)ent->GetOriginalNetworkDataObject();
  299. predicted_state_data = (const byte *)ent->GetPredictedFrame( commands_acknowledged - 1 );
  300. }
  301. else
  302. {
  303. // Compare against self so that we're just dumping data to screen
  304. original_state_data = ( const byte * )ent;
  305. data_type_original = TD_OFFSET_NORMAL;
  306. predicted_state_data = original_state_data;
  307. data_type_predicted = data_type_original;
  308. }
  309. Assert( original_state_data );
  310. Assert( predicted_state_data );
  311. Clear();
  312. CPredictionCopy datacompare( PC_EVERYTHING,
  313. (byte *)original_state_data, data_type_original,
  314. predicted_state_data, data_type_predicted,
  315. CPredictionCopy::TRANSFERDATA_ERRORCHECK_DESCRIBE,
  316. ::DumpComparision );
  317. // Don't spew debugging info
  318. m_nCurrentIndex = 0;
  319. datacompare.TransferData( "", ent->entindex(), ent->GetPredDescMap() );
  320. m_hDumpEntity = ent;
  321. m_DumpEntityInfo.RedoSort();
  322. #endif
  323. }
  324. void CPDumpPanel::Clear()
  325. {
  326. m_DumpEntityInfo.RemoveAll();
  327. }
  328. void CPDumpPanel::Paint()
  329. {
  330. C_BaseEntity *ent = m_hDumpEntity;
  331. if ( !ent )
  332. {
  333. Clear();
  334. return;
  335. }
  336. bool bPredictable = ent->GetPredictable();
  337. // Now output the strings
  338. int x[5];
  339. x[0] = 20;
  340. int columnwidth = 375;
  341. int numcols = GetWide() / columnwidth;
  342. int i;
  343. numcols = clamp( numcols, 1, 5 );
  344. for ( i = 0; i < numcols; i++ )
  345. {
  346. if ( i == 0 )
  347. {
  348. x[i] = 20;
  349. }
  350. else
  351. {
  352. x[i] = x[ i-1 ] + columnwidth - 20;
  353. }
  354. }
  355. int nFontTweak = -7;
  356. int c = m_DumpEntityInfo.Count();
  357. int fonttall = vgui::surface()->GetFontTall( m_FontSmall ) + nFontTweak;
  358. int fonttallMedium = vgui::surface()->GetFontTall( m_FontMedium ) + nFontTweak;
  359. int fonttallBig = vgui::surface()->GetFontTall( m_FontBig ) + nFontTweak;
  360. char currentclass[ 128 ];
  361. currentclass[ 0 ] = 0;
  362. int starty = 15;
  363. int y = starty;
  364. int col = 0;
  365. int r = 255;
  366. int g = 255;
  367. int b = 255;
  368. int a = 255;
  369. char classextra[ 32 ];
  370. classextra[ 0 ] = 0;
  371. char classprefix[ 32 ];
  372. Q_strncpy( classprefix, "class ", sizeof( classprefix ) );
  373. const char *classname = ent->GetClassname();
  374. if ( !classname[ 0 ] )
  375. {
  376. classname = typeid( *ent ).name();
  377. Q_strncpy( classextra, " (classmap missing)", sizeof( classextra ) );
  378. classprefix[ 0 ] = 0;
  379. }
  380. char sz[ 512 ];
  381. wchar_t szconverted[ 1024 ];
  382. surface()->DrawSetTextFont( m_FontBig );
  383. surface()->DrawSetTextColor( Color( 255, 255, 255, 255 ) );
  384. surface()->DrawSetTextPos( x[ col ] - 10, y - fonttallBig - 2 );
  385. Q_snprintf( sz, sizeof( sz ), "entity # %i: %s%s%s", ent->entindex(), classprefix, classname, classextra );
  386. g_pVGuiLocalize->ConvertANSIToUnicode( sz, szconverted, sizeof(szconverted) );
  387. surface()->DrawPrintText( szconverted, wcslen( szconverted ) );
  388. for ( i = 0; i < c; i++ )
  389. {
  390. DumpInfo *slot = &m_DumpEntityInfo[ i ];
  391. if ( stricmp( slot->classname, currentclass ) )
  392. {
  393. y += 2;
  394. surface()->DrawSetTextFont( m_FontMedium );
  395. surface()->DrawSetTextColor( Color( 0, 255, 100, 255 ) );
  396. surface()->DrawSetTextPos( x[ col ] - 10, y );
  397. Q_snprintf( sz, sizeof( sz ), "%s", slot->classname );
  398. g_pVGuiLocalize->ConvertANSIToUnicode( sz, szconverted, sizeof(szconverted) );
  399. surface()->DrawPrintText( szconverted, wcslen( szconverted ) );
  400. y += fonttallMedium;
  401. Q_strncpy( currentclass, slot->classname, sizeof( currentclass ) );
  402. }
  403. PredictionDumpColor( false, bPredictable, slot->networked, !slot->noterrorchecked, slot->differs, slot->withintolerance,
  404. r, g, b, a );
  405. surface()->DrawSetTextFont( m_FontSmall );
  406. surface()->DrawSetTextColor( Color( r, g, b, a ) );
  407. surface()->DrawSetTextPos( x[ col ], y );
  408. Q_snprintf( sz, sizeof( sz ), "%s", slot->fieldstring );
  409. g_pVGuiLocalize->ConvertANSIToUnicode( sz, szconverted, sizeof(szconverted) );
  410. surface()->DrawPrintText( szconverted, wcslen( szconverted ) );
  411. y += fonttall;
  412. if ( y >= GetTall() - fonttall - starty )
  413. {
  414. y = starty;
  415. col++;
  416. if ( col >= numcols )
  417. break;
  418. }
  419. }
  420. surface()->DrawSetTextFont( m_FontSmall );
  421. // Figure how far over the legend needs to be.
  422. const char *pFirstAndLongestString = "Not networked, no differences";
  423. g_pVGuiLocalize->ConvertANSIToUnicode( pFirstAndLongestString, szconverted, sizeof(szconverted) );
  424. int textSizeWide, textSizeTall;
  425. surface()->GetTextSize( m_FontSmall, szconverted, textSizeWide, textSizeTall );
  426. // Draw a legend now
  427. int xpos = ScreenWidth() - textSizeWide - 5;
  428. y = ScreenHeight() - 7 * fonttall - 80;
  429. // Not networked, no differences
  430. PredictionDumpColor( true, bPredictable, false, false, false, false, r, g, b, a );
  431. surface()->DrawSetTextColor( Color( r, g, b, a ) );
  432. surface()->DrawSetTextPos( xpos, y );
  433. Q_strncpy( sz, pFirstAndLongestString, sizeof( sz ) );
  434. g_pVGuiLocalize->ConvertANSIToUnicode( sz, szconverted, sizeof(szconverted) );
  435. surface()->DrawPrintText( szconverted, wcslen( szconverted ) );
  436. y += fonttall;
  437. // Networked, no error check
  438. PredictionDumpColor( true, bPredictable, true, false, false, false, r, g, b, a );
  439. surface()->DrawSetTextColor( Color( r, g, b, a ) );
  440. surface()->DrawSetTextPos( xpos, y );
  441. Q_strncpy( sz, "Networked, not checked", sizeof( sz ) );
  442. g_pVGuiLocalize->ConvertANSIToUnicode( sz, szconverted, sizeof(szconverted) );
  443. surface()->DrawPrintText( szconverted, wcslen( szconverted ) );
  444. y += fonttall;
  445. // Networked, with error check
  446. PredictionDumpColor( true, bPredictable, true, true, false, false, r, g, b, a );
  447. surface()->DrawSetTextColor( Color( r, g, b, a ) );
  448. surface()->DrawSetTextPos( xpos, y );
  449. Q_strncpy( sz, "Networked, error checked", sizeof( sz ) );
  450. g_pVGuiLocalize->ConvertANSIToUnicode( sz, szconverted, sizeof(szconverted) );
  451. surface()->DrawPrintText( szconverted, wcslen( szconverted ) );
  452. y += fonttall;
  453. // Differs, but within tolerance
  454. PredictionDumpColor( true, bPredictable, true, true, true, true, r, g, b, a );
  455. surface()->DrawSetTextColor( Color( r, g, b, a ) );
  456. surface()->DrawSetTextPos( xpos, y );
  457. Q_strncpy( sz, "Differs, but within tolerance", sizeof( sz ) );
  458. g_pVGuiLocalize->ConvertANSIToUnicode( sz, szconverted, sizeof(szconverted) );
  459. surface()->DrawPrintText( szconverted, wcslen( szconverted ) );
  460. y += fonttall;
  461. // Differs, not within tolerance, but not networked
  462. PredictionDumpColor( true, bPredictable, false, true, true, false, r, g, b, a );
  463. surface()->DrawSetTextColor( Color( r, g, b, a ) );
  464. surface()->DrawSetTextPos( xpos, y );
  465. Q_strncpy( sz, "Differs, but not networked", sizeof( sz ) );
  466. g_pVGuiLocalize->ConvertANSIToUnicode( sz, szconverted, sizeof(szconverted) );
  467. surface()->DrawPrintText( szconverted, wcslen( szconverted ) );
  468. y += fonttall;
  469. // Differs, networked, not within tolerance
  470. PredictionDumpColor( true, bPredictable, true, true, true, false, r, g, b, a );
  471. surface()->DrawSetTextColor( Color( r, g, b, a ) );
  472. surface()->DrawSetTextPos( xpos, y );
  473. Q_strncpy( sz, "Differs, networked", sizeof( sz ) );
  474. g_pVGuiLocalize->ConvertANSIToUnicode( sz, szconverted, sizeof(szconverted) );
  475. surface()->DrawPrintText( szconverted, wcslen( szconverted ) );
  476. y += fonttall;
  477. }