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.

1655 lines
41 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=====================================================================================//
  6. #include "client_pch.h"
  7. #include <time.h>
  8. #include "console.h"
  9. #include "ivideomode.h"
  10. #include "zone.h"
  11. #include "sv_main.h"
  12. #include "server.h"
  13. #include "MapReslistGenerator.h"
  14. #include "tier2/socketcreator.h"
  15. #if defined( _X360 )
  16. #include "xbox/xbox_console.h"
  17. #endif
  18. #include "toolframework/itoolframework.h"
  19. #include "netconsole.h"
  20. #include "host_cmd.h"
  21. // memdbgon must be the last include file in a .cpp file!!!
  22. #include "tier0/memdbgon.h"
  23. #if !defined( _X360 )
  24. #define MAXPRINTMSG 4096
  25. #else
  26. #define MAXPRINTMSG 1024
  27. #endif
  28. DEFINE_LOGGING_CHANNEL_NO_TAGS( LOG_CONSOLE, "Console" );
  29. bool con_debuglog = false;
  30. bool con_initialized = false;
  31. bool con_debuglogmapprefixed = false;
  32. static ConVar con_timestamp( "con_timestamp", "0", 0, "Prefix console.log entries with timestamps" );
  33. extern ConVar cl_hideserverip;
  34. // In order to avoid excessive opening and closing of the console log file
  35. // we wrap it in an object and keep the handle open. This is necessary
  36. // because of the sometimes considerable cost of opening and closing files
  37. // on Windows. Opening and closing files on Windows is always moderately
  38. // expensive, but profiling may dramatically underestimate the true cost
  39. // because some anti-virus software can make closing a file handle take
  40. // 20-90 ms!
  41. class ConsoleLogManager
  42. {
  43. public:
  44. ConsoleLogManager();
  45. ~ConsoleLogManager();
  46. void RemoveConsoleLogFile();
  47. bool ReadConsoleLogFile( CUtlBuffer& buf );
  48. FileHandle_t GetConsoleLogFileHandleForAppend();
  49. void CloseFileIfOpen();
  50. private:
  51. FileHandle_t m_fh;
  52. const char *GetConsoleLogFilename() const;
  53. };
  54. // Wrap the ConsoleLogManager in a function to ensure that the object is always
  55. // constructed before it is used.
  56. ConsoleLogManager& GetConsoleLogManager()
  57. {
  58. static ConsoleLogManager object;
  59. return object;
  60. }
  61. void ConsoleLogFileCallback(IConVar *var, const char *pOldValue, float flOldValue )
  62. {
  63. ConVarRef ref( var->GetName() );
  64. const char *logFile = ref.GetString();
  65. // close any existing file, because we have changed the name
  66. GetConsoleLogManager().CloseFileIfOpen();
  67. if ( !COM_IsValidPath( logFile ) )
  68. {
  69. con_debuglog = CommandLine()->FindParm( "-condebug" ) != 0;
  70. }
  71. else
  72. {
  73. con_debuglog = true;
  74. }
  75. }
  76. ConVar con_logfile( "con_logfile", "", FCVAR_RELEASE, "Console output gets written to this file", false, 0.0f, false, 0.0f, ConsoleLogFileCallback );
  77. static const char *GetTimestampString( void )
  78. {
  79. static char string[128];
  80. tm today;
  81. Plat_GetLocalTime( &today );
  82. Q_snprintf( string, sizeof( string ), "%02i/%02i/%04i - %02i:%02i:%02i",
  83. today.tm_mon+1, today.tm_mday, 1900 + today.tm_year,
  84. today.tm_hour, today.tm_min, today.tm_sec );
  85. return string;
  86. }
  87. #ifndef DEDICATED
  88. static ConVar con_trace( "con_trace", "0", FCVAR_MATERIAL_SYSTEM_THREAD, "Print console text to low level printout." );
  89. static ConVar con_notifytime( "con_notifytime","8", FCVAR_MATERIAL_SYSTEM_THREAD, "How long to display recent console text to the upper part of the game window" );
  90. static ConVar con_times("contimes", "8", FCVAR_MATERIAL_SYSTEM_THREAD, "Number of console lines to overlay for debugging." );
  91. static ConVar con_drawnotify( "con_drawnotify", IsGameConsole() ? "0" : "1", 0, "Disables drawing of notification area (for taking screenshots)." );
  92. static ConVar con_enable("con_enable", "0", FCVAR_ARCHIVE, "Allows the console to be activated.");
  93. static ConVar con_filter_enable ( "con_filter_enable","0", FCVAR_MATERIAL_SYSTEM_THREAD | FCVAR_RELEASE, "Filters console output based on the setting of con_filter_text. 1 filters completely, 2 displays filtered text brighter than other text." );
  94. static ConVar con_filter_text ( "con_filter_text","", FCVAR_MATERIAL_SYSTEM_THREAD | FCVAR_RELEASE, "Text with which to filter console spew. Set con_filter_enable 1 or 2 to activate." );
  95. static ConVar con_filter_text_out ( "con_filter_text_out","", FCVAR_MATERIAL_SYSTEM_THREAD | FCVAR_RELEASE, "Text with which to filter OUT of console spew. Set con_filter_enable 1 or 2 to activate." );
  96. //-----------------------------------------------------------------------------
  97. // Purpose: Implements the console using VGUI
  98. //-----------------------------------------------------------------------------
  99. class CConPanel : public CBasePanel
  100. {
  101. typedef CBasePanel BaseClass;
  102. public:
  103. enum
  104. {
  105. MAX_NOTIFY_TEXT_LINE = 256
  106. };
  107. CConPanel( vgui::Panel *parent );
  108. virtual ~CConPanel( void );
  109. virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
  110. // Draws the text
  111. virtual void Paint();
  112. // Draws the background image
  113. virtual void PaintBackground();
  114. // Draw notify area
  115. virtual void DrawNotify( void );
  116. // Draws debug ( Con_NXPrintf ) areas
  117. virtual void DrawDebugAreas( void );
  118. int ProcessNotifyLines( int &left, int &top, int &right, int &bottom, bool bDraw );
  119. // Draw helpers
  120. void DrawText( vgui::HFont font, int x, int y, wchar_t *data );
  121. virtual bool ShouldDraw( void );
  122. void Con_NPrintf( int idx, const char *msg );
  123. void Con_NXPrintf( const struct con_nprint_s *info, const char *msg );
  124. void AddToNotify( const Color& clr, char const *msg );
  125. void ClearNofify();
  126. private:
  127. // Console font
  128. vgui::HFont m_hFont;
  129. vgui::HFont m_hFontFixed;
  130. struct CNotifyText
  131. {
  132. Color clr;
  133. float liferemaining;
  134. wchar_t text[MAX_NOTIFY_TEXT_LINE];
  135. };
  136. CUtlVector< CNotifyText > m_NotifyText;
  137. enum
  138. {
  139. MAX_DBG_NOTIFY = 128,
  140. DBG_NOTIFY_TIMEOUT = 4,
  141. };
  142. float da_default_color[3];
  143. typedef struct
  144. {
  145. wchar_t szNotify[MAX_NOTIFY_TEXT_LINE];
  146. float expire;
  147. float color[3];
  148. bool fixed_width_font;
  149. } da_notify_t;
  150. da_notify_t da_notify[MAX_DBG_NOTIFY];
  151. bool m_bDrawDebugAreas;
  152. };
  153. static CConPanel *g_pConPanel = NULL;
  154. /*
  155. ================
  156. Con_HideConsole_f
  157. ================
  158. */
  159. void Con_HideConsole_f( void )
  160. {
  161. if ( IsX360() )
  162. return;
  163. if ( EngineVGui()->IsConsoleVisible() )
  164. {
  165. // hide the console
  166. EngineVGui()->HideConsole();
  167. }
  168. }
  169. static bool Con_ConsoleAllowed( void )
  170. {
  171. static bool s_bAllowed = !CommandLine()->CheckParm( "-noconsole" ) && !CommandLine()->FindParm( "-perfectworld" ); // disallow for perfect world
  172. return s_bAllowed;
  173. }
  174. /*
  175. ================
  176. Con_ShowConsole_f
  177. ================
  178. */
  179. void Con_ShowConsole_f( void )
  180. {
  181. if ( IsX360() )
  182. return;
  183. if ( vgui::input()->GetAppModalSurface() )
  184. {
  185. return;
  186. }
  187. // Allow the app to disable the console from the command-line, for demos.
  188. if ( !Con_ConsoleAllowed() )
  189. return;
  190. // make sure we're allowed to see the console
  191. if ( con_enable.GetBool() || developer.GetInt() || CommandLine()->CheckParm("-console") || CommandLine()->CheckParm("-rpt") )
  192. {
  193. // show the console
  194. EngineVGui()->ShowConsole();
  195. // [jason] Do not call this for CS:GO, since our loading screen is in Scaleform. Additionally, this can
  196. // cause a hang us during the load process since it prematurely fires OnEngineLevelLoadingFinished
  197. #if !defined( CSTRIKE15 )
  198. // remove any loading screen
  199. SCR_EndLoadingPlaque();
  200. #endif
  201. }
  202. }
  203. //-----------------------------------------------------------------------------
  204. // Purpose: toggles the console
  205. //-----------------------------------------------------------------------------
  206. void Con_ToggleConsole_f( void )
  207. {
  208. if ( IsX360() )
  209. return;
  210. if (EngineVGui()->IsConsoleVisible())
  211. {
  212. Con_HideConsole_f();
  213. }
  214. else
  215. {
  216. Con_ShowConsole_f();
  217. }
  218. }
  219. //-----------------------------------------------------------------------------
  220. // Purpose: Clears the console
  221. //-----------------------------------------------------------------------------
  222. void Con_Clear_f( void )
  223. {
  224. if ( IsX360() )
  225. return;
  226. EngineVGui()->ClearConsole();
  227. Con_ClearNotify();
  228. }
  229. static void LogFunction_PrintUsage()
  230. {
  231. Log_Msg( LOG_CONSOLE,
  232. "Log Function Help: \n"
  233. " log_level <channel specifiers> <level>\n"
  234. " log_color <channel specifiers> <hex color>\n"
  235. " log_flags <channel specifiers> <+/-flag>\n"
  236. "All functions are case insensitive.\n"
  237. "\n"
  238. "A channel specifier is either:\n"
  239. "1) tag specifiers: +/-tag1 +/-tag2 ... // Narrows down to channels with & without given tags.\n"
  240. "2) channel names: name1 name2 ... // Lists channels by name.\n"
  241. "\n"
  242. "level: all, warning, error, off // Spews anything at or above the specified level.\n"
  243. " // 'off' turns all spew off, 'all' turns all spew on.\n"
  244. "hex color: RRGGBBAA // A hexadecimal color value in the order RGBA.\n"
  245. "flag: <+/->DoNotEcho // Enable/disable a flag to turn off echoing to the console.\n"
  246. " <+/->ConsoleOnly // Enable/disable a flag to send text only to the console.\n"
  247. "e.g.\n"
  248. " log_level +console -developer warning // Sets minimum spew level of channels with the tag\n"
  249. " // 'console' but without the tag 'developer' to 'warning'.\n"
  250. "\n"
  251. " log_color renderdebug bsp FFC08040 // Sets the 'renderdebug' and 'bsp' channels to the RGBA color (64, 128, 192, 255).\n"
  252. "\n"
  253. " log_flags +developer +donotecho // Turns on the LCF_DO_NOT_ECHO flag for all channels with the 'developer' tag.\n"
  254. "\n" );
  255. };
  256. typedef bool (*LogFunctionActionFunc)( const CLoggingSystem::LoggingChannel_t *pChannel, const char *pParameter );
  257. static void Con_LogFunctionHelper( const CCommand &args, LogFunctionActionFunc callbackFunction )
  258. {
  259. int nArgs = args.ArgC();
  260. if ( nArgs < 3 )
  261. {
  262. LogFunction_PrintUsage();
  263. return;
  264. }
  265. const char *pParameter = args.ArgV()[nArgs - 1];
  266. struct ChannelSpecifier_t
  267. {
  268. const char *m_pSpecifier; // Points to tag or channel name
  269. bool m_bIsTag; // True for a tag specifier, false for a channel name
  270. bool m_bInclude; // If bIsTag is true, then bInclude is true for '+' and false for '-'.
  271. };
  272. const int nMaxSpecifiers = 16;
  273. int nSpecifierCount = nArgs - 2;
  274. if ( nSpecifierCount > nMaxSpecifiers )
  275. {
  276. Log_Warning( LOG_CONSOLE, "Too many channel specifiers (max: %d).\n", nMaxSpecifiers );
  277. LogFunction_PrintUsage();
  278. return;
  279. }
  280. ChannelSpecifier_t channelSpecifier[nMaxSpecifiers];
  281. for ( int nArg = 1; nArg < ( nArgs - 1 ); ++ nArg )
  282. {
  283. const char *pSpecifier = args.ArgV()[nArg];
  284. Assert( pSpecifier[0] != '\0' );
  285. if ( pSpecifier[0] == '+' )
  286. {
  287. channelSpecifier[nArg - 1].m_pSpecifier = pSpecifier + 1;
  288. channelSpecifier[nArg - 1].m_bIsTag = true;
  289. channelSpecifier[nArg - 1].m_bInclude = true;
  290. }
  291. else if ( pSpecifier[0] == '-' )
  292. {
  293. channelSpecifier[nArg - 1].m_pSpecifier = pSpecifier + 1;
  294. channelSpecifier[nArg - 1].m_bIsTag = true;
  295. channelSpecifier[nArg - 1].m_bInclude = false;
  296. }
  297. else
  298. {
  299. channelSpecifier[nArg - 1].m_pSpecifier = pSpecifier;
  300. channelSpecifier[nArg - 1].m_bIsTag = false;
  301. }
  302. if ( nArg > 1 )
  303. {
  304. if ( channelSpecifier[nArg - 1].m_bIsTag != channelSpecifier[nArg - 2].m_bIsTag )
  305. {
  306. Log_Warning( LOG_CONSOLE, "Cannot mix and match tag specifiers with channel name specifiers.\n" );
  307. LogFunction_PrintUsage();
  308. return;
  309. }
  310. }
  311. }
  312. bool bUsingTags = channelSpecifier[0].m_bIsTag;
  313. for ( LoggingChannelID_t channelID = LoggingSystem_GetFirstChannelID(); channelID != INVALID_LOGGING_CHANNEL_ID; channelID = LoggingSystem_GetNextChannelID( channelID ) )
  314. {
  315. const CLoggingSystem::LoggingChannel_t *pLoggingChannel = LoggingSystem_GetChannel( channelID );
  316. int nSpecifier;
  317. for ( nSpecifier = 0; nSpecifier < nSpecifierCount; ++ nSpecifier )
  318. {
  319. if ( bUsingTags )
  320. {
  321. bool bHasTag = pLoggingChannel->HasTag( channelSpecifier[nSpecifier].m_pSpecifier );
  322. if ( channelSpecifier[nSpecifier].m_bInclude != bHasTag )
  323. {
  324. // Channel has a prohibited tag or channel lacks a required tag
  325. break;
  326. }
  327. }
  328. else
  329. {
  330. if ( Q_stricmp( channelSpecifier[nSpecifier].m_pSpecifier, pLoggingChannel->m_Name ) == 0 )
  331. {
  332. // Found the channel
  333. break;
  334. }
  335. }
  336. }
  337. bool bReachedEnd = ( nSpecifier == nSpecifierCount );
  338. // If using tags, reaching the end means to include this channel.
  339. // If using channel names, reaching the end means no match was found.
  340. if ( bReachedEnd == bUsingTags )
  341. {
  342. if ( !callbackFunction( pLoggingChannel, pParameter ) )
  343. {
  344. LogFunction_PrintUsage();
  345. return;
  346. }
  347. }
  348. }
  349. }
  350. static bool Con_LogLevelCallback( const CLoggingSystem::LoggingChannel_t *pChannel, const char *pParameter )
  351. {
  352. LoggingSeverity_t minSeverity;
  353. if ( Q_stricmp( pParameter, "all" ) == 0 )
  354. {
  355. minSeverity = LS_MESSAGE;
  356. }
  357. else if ( Q_stricmp( pParameter, "warning" ) == 0 )
  358. {
  359. minSeverity = LS_WARNING;
  360. }
  361. else if ( Q_stricmp( pParameter, "error" ) == 0 )
  362. {
  363. minSeverity = LS_ERROR;
  364. }
  365. else if ( Q_stricmp( pParameter, "off" ) == 0 )
  366. {
  367. minSeverity = LS_HIGHEST_SEVERITY;
  368. }
  369. else
  370. {
  371. Log_Warning( LOG_CONSOLE, "Unrecognized severity: %s.\n", pParameter );
  372. return false;
  373. }
  374. Log_Msg( LOG_CONSOLE, "Setting channel '%s' minimum spew level to '%s'.\n", pChannel->m_Name, pParameter );
  375. LoggingSystem_SetChannelSpewLevel( pChannel->m_ID, minSeverity );
  376. return true;
  377. }
  378. static bool Con_LogColorCallback( const CLoggingSystem::LoggingChannel_t *pChannel, const char *pParameter )
  379. {
  380. int color;
  381. Q_hextobinary( pParameter, 8, ( byte * )&color, sizeof( color ) );
  382. Log_Msg( LOG_CONSOLE, "Setting channel '%s' color to %08X.\n", pChannel->m_Name, SwapDWord( color ) );
  383. LoggingSystem_SetChannelColor( pChannel->m_ID, color );
  384. return true;
  385. }
  386. static bool Con_LogFlagsCallback( const CLoggingSystem::LoggingChannel_t *pChannel, const char *pParameter )
  387. {
  388. bool bEnable;
  389. if ( pParameter[0] == '+' )
  390. {
  391. bEnable = true;
  392. }
  393. else if ( pParameter[0] == '-' )
  394. {
  395. bEnable = false;
  396. }
  397. else
  398. {
  399. Log_Warning( LOG_CONSOLE, "First character of flag specifier must be + or -.\n" );
  400. return false;
  401. }
  402. const char *pFlag = pParameter + 1;
  403. LoggingChannelFlags_t flag;
  404. if ( Q_stricmp( pFlag, "donotecho" ) == 0 )
  405. {
  406. flag = LCF_DO_NOT_ECHO;
  407. }
  408. else if ( Q_stricmp( pFlag, "consoleonly" ) == 0 )
  409. {
  410. flag = LCF_CONSOLE_ONLY;
  411. }
  412. else
  413. {
  414. Log_Warning( LOG_CONSOLE, "Unrecognized flag: %s.\n", pFlag );
  415. return false;
  416. }
  417. LoggingChannelFlags_t currentFlags = LoggingSystem_GetChannelFlags( pChannel->m_ID );
  418. if ( bEnable )
  419. {
  420. currentFlags = ( LoggingChannelFlags_t )( ( int )currentFlags | flag );
  421. }
  422. else
  423. {
  424. currentFlags = ( LoggingChannelFlags_t )( ( int )currentFlags & ( ~flag ) );
  425. }
  426. Log_Msg( LOG_CONSOLE, "Enabling flag '%s' on channel '%s'.\n", pFlag, pChannel->m_Name );
  427. LoggingSystem_SetChannelFlags( pChannel->m_ID, currentFlags );
  428. return true;
  429. }
  430. void Con_LogLevel_f( const CCommand &args )
  431. {
  432. Con_LogFunctionHelper( args, Con_LogLevelCallback );
  433. }
  434. void Con_LogColor_f( const CCommand &args )
  435. {
  436. Con_LogFunctionHelper( args, Con_LogColorCallback );
  437. }
  438. void Con_LogFlags_f( const CCommand &args )
  439. {
  440. Con_LogFunctionHelper( args, Con_LogFlagsCallback );
  441. }
  442. void Con_LogDumpChannels_f()
  443. {
  444. Log_Msg( LOG_CONSOLE, "%-4s %-32s %-10s %-10s %-32s %-32s\n", "ID", "Channel Name", "Severity", "Color", "Flags", "Tags" );
  445. Log_Msg( LOG_CONSOLE, "----------------------------------------------------------------------------------------------------------------------------------------------------\n" );
  446. int nChannelCount = LoggingSystem_GetChannelCount();
  447. for ( int i = 0; i < nChannelCount; ++ i )
  448. {
  449. const CLoggingSystem::LoggingChannel_t *pChannel = LoggingSystem_GetChannel( i );
  450. const char *pSeverity;
  451. if ( pChannel->m_MinimumSeverity >= LS_HIGHEST_SEVERITY ) pSeverity = "off";
  452. else if ( pChannel->m_MinimumSeverity >= LS_ERROR ) pSeverity = "error";
  453. else if ( pChannel->m_MinimumSeverity >= LS_WARNING ) pSeverity = "warning";
  454. else pSeverity = "all";
  455. Log_Msg( LOG_CONSOLE, "%-4d %-32s %-10s 0x%08X ", i, pChannel->m_Name, pSeverity, SwapDWord( *( int *)&pChannel->m_SpewColor ) );
  456. const int nMaxLen = 2048;
  457. char buf[nMaxLen];
  458. buf[0] = '\0';
  459. if ( pChannel->m_Flags & LCF_CONSOLE_ONLY )
  460. {
  461. Q_strncat( buf, "[ConsoleOnly]", nMaxLen );
  462. }
  463. if ( pChannel->m_Flags & LCF_DO_NOT_ECHO )
  464. {
  465. Q_strncat( buf, "[DoNotEcho]", nMaxLen );
  466. }
  467. Log_Msg( LOG_CONSOLE, "%-32s ", buf );
  468. buf[0] = '\0';
  469. CLoggingSystem::LoggingTag_t *pTag = pChannel->m_pFirstTag;
  470. while ( pTag != NULL )
  471. {
  472. Q_strncat( buf, "[", nMaxLen );
  473. Q_strncat( buf, pTag->m_pTagName, nMaxLen );
  474. Q_strncat( buf, "]", nMaxLen );
  475. pTag = pTag->m_pNextTag;
  476. }
  477. Log_Msg( LOG_CONSOLE, "%-32s\n", buf );
  478. }
  479. }
  480. /*
  481. ================
  482. Con_ClearNotify
  483. ================
  484. */
  485. void Con_ClearNotify (void)
  486. {
  487. if ( g_pConPanel )
  488. {
  489. g_pConPanel->ClearNofify();
  490. }
  491. }
  492. #endif // DEDICATED
  493. //--------------------------------------------------------------------------------
  494. // Purpose: handle any console stuff that needs to run frequently such as accepting on sockets
  495. //--------------------------------------------------------------------------------
  496. void Con_RunFrame( void )
  497. {
  498. #if SUPPORT_NET_CONSOLE
  499. if ( g_pNetConsoleMgr )
  500. g_pNetConsoleMgr->RunFrame();
  501. #endif
  502. }
  503. ConsoleLogManager::ConsoleLogManager()
  504. {
  505. m_fh = FILESYSTEM_INVALID_HANDLE;
  506. }
  507. ConsoleLogManager::~ConsoleLogManager()
  508. {
  509. // This fails because of destructor order problems. The file
  510. // system has already been shut down by the time this runs.
  511. // We'll have to count on the OS to close the file for us.
  512. //CloseFileIfOpen();
  513. }
  514. void ConsoleLogManager::RemoveConsoleLogFile()
  515. {
  516. // Make sure the log file is closed before we try deleting it.
  517. CloseFileIfOpen();
  518. g_pFileSystem->RemoveFile( GetConsoleLogFilename(), "GAME" );
  519. }
  520. bool ConsoleLogManager::ReadConsoleLogFile( CUtlBuffer& buf )
  521. {
  522. // Make sure the log file is closed before we try reading it.
  523. CloseFileIfOpen();
  524. const char *pLogFile = GetConsoleLogFilename();
  525. if ( g_pFullFileSystem->ReadFile( pLogFile, "GAME", buf ) )
  526. return true;
  527. return false;
  528. }
  529. FileHandle_t ConsoleLogManager::GetConsoleLogFileHandleForAppend()
  530. {
  531. if ( m_fh == FILESYSTEM_INVALID_HANDLE )
  532. {
  533. const char* file = GetConsoleLogFilename();
  534. m_fh = g_pFileSystem->Open( file, "a" );
  535. }
  536. return m_fh;
  537. }
  538. void ConsoleLogManager::CloseFileIfOpen()
  539. {
  540. if ( m_fh != FILESYSTEM_INVALID_HANDLE )
  541. {
  542. g_pFileSystem->Close( m_fh );
  543. m_fh = FILESYSTEM_INVALID_HANDLE;
  544. }
  545. }
  546. const char *ConsoleLogManager::GetConsoleLogFilename() const
  547. {
  548. const char *logFile = con_logfile.GetString();
  549. if ( !COM_IsValidPath( logFile ) )
  550. {
  551. return "console.log";
  552. }
  553. return logFile;
  554. }
  555. /*
  556. ================
  557. Con_Init
  558. ================
  559. */
  560. void Con_Init (void)
  561. {
  562. #ifdef DEDICATED
  563. con_debuglog = false; // the dedicated server's console will handle this
  564. con_debuglogmapprefixed = false;
  565. #else
  566. bool bRPTClient = ( CommandLine()->FindParm( "-rpt" ) != 0 );
  567. con_debuglog = bRPTClient || ( CommandLine()->FindParm( "-condebug" ) != 0 );
  568. con_debuglogmapprefixed = CommandLine()->FindParm( "-makereslists" ) != 0 || CommandLine()->FindParm( "-mapname" ) != 0;
  569. if ( con_debuglog )
  570. {
  571. con_logfile.SetValue( "console.log" );
  572. if ( bRPTClient || ( CommandLine()->FindParm( "-conclearlog" ) ) )
  573. {
  574. GetConsoleLogManager().RemoveConsoleLogFile();
  575. }
  576. }
  577. #endif // !DEDICATED
  578. con_initialized = true;
  579. }
  580. /*
  581. ================
  582. Con_Shutdown
  583. ================
  584. */
  585. void Con_Shutdown (void)
  586. {
  587. #if SUPPORT_NET_CONSOLE
  588. if ( g_pNetConsoleMgr )
  589. delete g_pNetConsoleMgr;
  590. #endif
  591. con_initialized = false;
  592. }
  593. /*
  594. ================
  595. Read the console log from disk and return it in 'buf'. Buf should come
  596. in as an empty TEXT_BUFFER CUtlBuffer.
  597. Returns true if the log file is successfully read.
  598. ================
  599. */
  600. bool GetConsoleLogFileData( CUtlBuffer& buf )
  601. {
  602. return GetConsoleLogManager().ReadConsoleLogFile( buf );
  603. }
  604. /*
  605. ================
  606. Con_DebugLog
  607. ================
  608. */
  609. void Con_DebugLog( const char *fmt, ...)
  610. {
  611. va_list argptr;
  612. char data[MAXPRINTMSG];
  613. va_start(argptr, fmt);
  614. Q_vsnprintf(data, sizeof(data), fmt, argptr);
  615. va_end(argptr);
  616. FileHandle_t fh = GetConsoleLogManager().GetConsoleLogFileHandleForAppend();
  617. if (fh != FILESYSTEM_INVALID_HANDLE )
  618. {
  619. if ( con_debuglogmapprefixed )
  620. {
  621. char const *prefix = MapReslistGenerator().LogPrefix();
  622. if ( prefix )
  623. {
  624. g_pFileSystem->Write( prefix, strlen(prefix), fh );
  625. }
  626. }
  627. if ( con_timestamp.GetBool() )
  628. {
  629. static bool needTimestamp = true; // Start the first line with a timestamp
  630. if ( needTimestamp )
  631. {
  632. const char *timestamp = GetTimestampString();
  633. g_pFileSystem->Write( timestamp, strlen( timestamp ), fh );
  634. g_pFileSystem->Write( ": ", 2, fh );
  635. }
  636. needTimestamp = V_stristr( data, "\n" ) ? true : false;
  637. }
  638. g_pFileSystem->Write( data, strlen(data), fh );
  639. // Now that we don't close the file we need to flush it in order
  640. // to make sure that the data makes it to the file system.
  641. g_pFileSystem->Flush( fh );
  642. }
  643. }
  644. static bool g_fIsDebugPrint = false;
  645. #ifndef DEDICATED
  646. /*
  647. ================
  648. Con_Printf
  649. Handles cursor positioning, line wrapping, etc
  650. ================
  651. */
  652. static bool g_fColorPrintf = false;
  653. static bool g_bInColorPrint = false;
  654. #ifdef _PS3
  655. #include "tls_ps3.h"
  656. #define g_bInSpew GetTLSGlobals()->bEngineConsoleIsInSpew
  657. #else
  658. extern CTHREADLOCALINT g_bInSpew;
  659. #endif
  660. void Con_Printf( const char *fmt, ... );
  661. void Con_ColorPrint( const Color& clr, char const *msg )
  662. {
  663. bool convisible = Con_IsVisible();
  664. bool indeveloper = ( developer.GetInt() > 0 );
  665. bool debugprint = g_fIsDebugPrint;
  666. SendStringToNetConsoles( msg );
  667. if ( IsPC() )
  668. {
  669. if ( g_bInColorPrint )
  670. return;
  671. int nCon_Filter_Enable = con_filter_enable.GetInt();
  672. if ( nCon_Filter_Enable > 0 )
  673. {
  674. const char *pszText = con_filter_text.GetString();
  675. const char *pszIgnoreText = con_filter_text_out.GetString();
  676. switch( nCon_Filter_Enable )
  677. {
  678. case 1:
  679. // if line does not contain keyword do not print the line
  680. if ( pszText && ( *pszText != '\0' ) && ( Q_stristr( msg, pszText ) == NULL ))
  681. return;
  682. if ( pszIgnoreText && *pszIgnoreText && ( Q_stristr( msg, pszIgnoreText ) != NULL ) )
  683. return;
  684. break;
  685. case 2:
  686. if ( pszIgnoreText && *pszIgnoreText && ( Q_stristr( msg, pszIgnoreText ) != NULL ) )
  687. return;
  688. // if line does not contain keyword print it in a darker color
  689. if ( pszText && ( *pszText != '\0' ) && ( Q_stristr( msg, pszText ) == NULL ))
  690. {
  691. Color mycolor(200, 200, 200, 150 );
  692. g_pCVar->ConsoleColorPrintf( mycolor, "%s", msg );
  693. return;
  694. }
  695. break;
  696. default:
  697. // by default do no filtering
  698. break;
  699. }
  700. }
  701. g_bInColorPrint = true;
  702. // also echo to debugging console
  703. if ( Plat_IsInDebugSession() && !con_trace.GetInt() )
  704. {
  705. Sys_OutputDebugString(msg);
  706. }
  707. if ( sv.IsDedicated() )
  708. {
  709. g_bInColorPrint = false;
  710. return; // no graphics mode
  711. }
  712. if ( g_fColorPrintf )
  713. {
  714. g_pCVar->ConsoleColorPrintf( clr, "%s", msg );
  715. }
  716. else
  717. {
  718. // write it out to the vgui console no matter what
  719. if ( g_fIsDebugPrint )
  720. {
  721. // Don't spew debug stuff to actual console once in game, unless console isn't up
  722. if ( !GetBaseLocalClient().IsActive() || !convisible )
  723. {
  724. g_pCVar->ConsoleDPrintf( "%s", msg );
  725. }
  726. }
  727. else
  728. {
  729. g_pCVar->ConsolePrintf( "%s", msg );
  730. }
  731. }
  732. // Make sure we "spew" if this wan't generated from the spew system
  733. if ( !g_bInSpew )
  734. {
  735. Msg( "%s", msg );
  736. }
  737. g_bInColorPrint = false;
  738. }
  739. // Only write to notify if it's non-debug or we are running with developer set > 0
  740. // Buf it it's debug then make sure we don't have the console down
  741. if ( ( !debugprint || indeveloper ) && !( debugprint && convisible ) )
  742. {
  743. if ( g_pConPanel )
  744. {
  745. g_pConPanel->AddToNotify( clr, msg );
  746. }
  747. }
  748. #if defined( _X360 )
  749. int r,g,b,a;
  750. char buffer[MAXPRINTMSG];
  751. const char *pFrom;
  752. char *pTo;
  753. clr.GetColor(r, g, b, a);
  754. // fixup percent printers
  755. pFrom = msg;
  756. pTo = buffer;
  757. while ( *pFrom && pTo < buffer+sizeof(buffer)-1 )
  758. {
  759. *pTo = *pFrom++;
  760. if ( *pTo++ == '%' )
  761. *pTo++ = '%';
  762. }
  763. *pTo = '\0';
  764. XBX_DebugString( XMAKECOLOR(r,g,b), buffer );
  765. #endif
  766. #if defined( _PS3 )
  767. Sys_OutputDebugString( msg );
  768. #endif
  769. }
  770. #endif
  771. // returns false if the print function shouldn't continue
  772. bool HandleRedirectAndDebugLog( const char *msg )
  773. {
  774. // Add to redirected message
  775. if ( SV_RedirectActive() )
  776. {
  777. SV_RedirectAddText( msg );
  778. return false;
  779. }
  780. // log all messages to file
  781. if ( con_debuglog )
  782. Con_DebugLog( "%s", msg );
  783. if (!con_initialized)
  784. {
  785. return false;
  786. }
  787. return true;
  788. }
  789. void Con_Print( const char *msg )
  790. {
  791. if ( !msg || !msg[0] )
  792. return;
  793. if ( !HandleRedirectAndDebugLog( msg ) )
  794. {
  795. return;
  796. }
  797. #ifdef DEDICATED
  798. Msg( "%s", msg );
  799. #else
  800. if ( sv.IsDedicated() )
  801. {
  802. Msg( "%s", msg );
  803. }
  804. else
  805. {
  806. #if !defined( _X360 )
  807. Color clr( 255, 255, 255, 255 );
  808. #else
  809. Color clr( 0, 0, 0, 255 );
  810. #endif
  811. Con_ColorPrint( clr, msg );
  812. }
  813. #endif
  814. }
  815. void Con_Printf( const char *fmt, ... )
  816. {
  817. va_list argptr;
  818. char msg[MAXPRINTMSG];
  819. static bool inupdate;
  820. va_start( argptr, fmt );
  821. Q_vsnprintf( msg, sizeof( msg ), fmt, argptr );
  822. va_end( argptr );
  823. if ( !HandleRedirectAndDebugLog( msg ) )
  824. {
  825. return;
  826. }
  827. #ifdef DEDICATED
  828. Msg( "%s", msg );
  829. #else
  830. if ( sv.IsDedicated() )
  831. {
  832. Msg( "%s", msg );
  833. }
  834. else
  835. {
  836. #if !defined( _X360 )
  837. Color clr( 255, 255, 255, 255 );
  838. #else
  839. Color clr( 0, 0, 0, 255 );
  840. #endif
  841. Con_ColorPrint( clr, msg );
  842. }
  843. #endif
  844. }
  845. #ifndef DEDICATED
  846. //-----------------------------------------------------------------------------
  847. // Purpose:
  848. // Input : clr -
  849. // *fmt -
  850. // ... -
  851. //-----------------------------------------------------------------------------
  852. void Con_ColorPrintf( const Color& clr, const char *fmt, ... )
  853. {
  854. va_list argptr;
  855. char msg[MAXPRINTMSG];
  856. static bool inupdate;
  857. va_start (argptr,fmt);
  858. Q_vsnprintf (msg,sizeof( msg ), fmt,argptr);
  859. va_end (argptr);
  860. LOCAL_THREAD_LOCK();
  861. if ( !HandleRedirectAndDebugLog( msg ) )
  862. {
  863. return;
  864. }
  865. g_fColorPrintf = true;
  866. Con_ColorPrint( clr, msg );
  867. g_fColorPrintf = false;
  868. }
  869. #endif
  870. /*
  871. ================
  872. Con_DPrintf
  873. A Con_Printf that only shows up if the "developer" cvar is set
  874. ================
  875. */
  876. void Con_DPrintf (const char *fmt, ...)
  877. {
  878. va_list argptr;
  879. char msg[MAXPRINTMSG];
  880. va_start (argptr,fmt);
  881. Q_vsnprintf(msg,sizeof( msg ), fmt,argptr);
  882. va_end (argptr);
  883. g_fIsDebugPrint = true;
  884. #ifdef DEDICATED
  885. DevMsg( "%s", msg );
  886. #else
  887. if ( sv.IsDedicated() )
  888. {
  889. DevMsg( "%s", msg );
  890. }
  891. else
  892. {
  893. Color clr( 196, 181, 80, 255 );
  894. Con_ColorPrint ( clr, msg );
  895. }
  896. #endif
  897. g_fIsDebugPrint = false;
  898. }
  899. /*
  900. ==================
  901. Con_SafePrintf
  902. Okay to call even when the screen can't be updated
  903. ==================
  904. */
  905. void Con_SafePrintf (const char *fmt, ...)
  906. {
  907. va_list argptr;
  908. char msg[MAXPRINTMSG];
  909. va_start (argptr,fmt);
  910. Q_vsnprintf(msg,sizeof( msg ), fmt,argptr);
  911. va_end (argptr);
  912. #ifndef DEDICATED
  913. bool temp;
  914. temp = scr_disabled_for_loading;
  915. scr_disabled_for_loading = true;
  916. #endif
  917. g_fIsDebugPrint = true;
  918. Con_Printf ("%s", msg);
  919. g_fIsDebugPrint = false;
  920. #ifndef DEDICATED
  921. scr_disabled_for_loading = temp;
  922. #endif
  923. }
  924. #ifndef DEDICATED
  925. bool Con_IsVisible()
  926. {
  927. return (EngineVGui()->IsConsoleVisible());
  928. }
  929. void Con_NPrintf( int idx, const char *fmt, ... )
  930. {
  931. va_list argptr;
  932. char outtext[MAXPRINTMSG];
  933. va_start(argptr, fmt);
  934. Q_vsnprintf( outtext, sizeof( outtext ), fmt, argptr);
  935. va_end(argptr);
  936. if ( IsPC()
  937. #ifndef _CERT
  938. || IsGameConsole()
  939. #endif // !_CERT
  940. )
  941. {
  942. g_pConPanel->Con_NPrintf( idx, outtext );
  943. }
  944. else
  945. {
  946. Con_Printf( outtext );
  947. }
  948. }
  949. void Con_NXPrintf( const struct con_nprint_s *info, const char *fmt, ... )
  950. {
  951. va_list argptr;
  952. char outtext[MAXPRINTMSG];
  953. va_start(argptr, fmt);
  954. Q_vsnprintf( outtext, sizeof( outtext ), fmt, argptr);
  955. va_end(argptr);
  956. if ( IsPC()
  957. #ifndef _CERT
  958. || IsGameConsole()
  959. #endif // !_CERT
  960. )
  961. {
  962. g_pConPanel->Con_NXPrintf( info, outtext );
  963. }
  964. else
  965. {
  966. // xbox doesn't use notify printing
  967. Con_Printf( outtext );
  968. // enforce a terminal CR, which PC callers don't specify
  969. // ensure vxconsole ouptut is formatted as expected (more often than not)
  970. Con_Printf( "\n" );
  971. }
  972. }
  973. //-----------------------------------------------------------------------------
  974. // Purpose: Creates the console panel
  975. // Input : *parent -
  976. //-----------------------------------------------------------------------------
  977. CConPanel::CConPanel( vgui::Panel *parent ) : CBasePanel( parent, "CConPanel" )
  978. {
  979. // Full screen assumed
  980. SetSize( videomode->GetModeWidth(), videomode->GetModeHeight() );
  981. SetPos( 0, 0 );
  982. SetVisible( true );
  983. SetCursor( 0 );
  984. da_default_color[0] = 1.0;
  985. da_default_color[1] = 1.0;
  986. da_default_color[2] = 1.0;
  987. m_bDrawDebugAreas = false;
  988. g_pConPanel = this;
  989. memset( da_notify, 0, sizeof(da_notify) );
  990. }
  991. //-----------------------------------------------------------------------------
  992. // Purpose:
  993. //-----------------------------------------------------------------------------
  994. CConPanel::~CConPanel( void )
  995. {
  996. }
  997. void CConPanel::Con_NPrintf( int idx, const char *msg )
  998. {
  999. if ( idx < 0 || idx >= MAX_DBG_NOTIFY )
  1000. return;
  1001. #ifdef WIN32
  1002. Q_snwprintf( da_notify[idx].szNotify, sizeof( da_notify[idx].szNotify ) / sizeof( wchar_t ) - 1, L"%S", msg );
  1003. #else
  1004. Q_snwprintf( da_notify[idx].szNotify, sizeof( da_notify[idx].szNotify ) / sizeof( wchar_t ) - 1, L"%s", msg );
  1005. #endif
  1006. da_notify[idx].szNotify[ sizeof( da_notify[idx].szNotify ) / sizeof( wchar_t ) - 1 ] = L'\0';
  1007. // Reset values
  1008. da_notify[idx].expire = realtime + DBG_NOTIFY_TIMEOUT;
  1009. VectorCopy( da_default_color, da_notify[idx].color );
  1010. da_notify[idx].fixed_width_font = false;
  1011. m_bDrawDebugAreas = true;
  1012. }
  1013. void CConPanel::Con_NXPrintf( const struct con_nprint_s *info, const char *msg )
  1014. {
  1015. if ( !info )
  1016. return;
  1017. if ( info->index < 0 || info->index >= MAX_DBG_NOTIFY )
  1018. return;
  1019. #ifdef WIN32
  1020. Q_snwprintf( da_notify[info->index].szNotify, sizeof( da_notify[info->index].szNotify ) / sizeof( wchar_t ) - 1, L"%S", msg );
  1021. #else
  1022. Q_snwprintf( da_notify[info->index].szNotify, sizeof( da_notify[info->index].szNotify ) / sizeof( wchar_t ) - 1, L"%s", msg );
  1023. #endif
  1024. da_notify[info->index].szNotify[ sizeof( da_notify[info->index].szNotify ) / sizeof( wchar_t ) - 1 ] = L'\0';
  1025. // Reset values
  1026. if ( info->time_to_live == -1 )
  1027. da_notify[ info->index ].expire = -1; // special marker means to just draw it once
  1028. else
  1029. da_notify[ info->index ].expire = realtime + info->time_to_live;
  1030. VectorCopy( info->color, da_notify[ info->index ].color );
  1031. da_notify[ info->index ].fixed_width_font = info->fixed_width_font;
  1032. m_bDrawDebugAreas = true;
  1033. }
  1034. static void safestrncat( wchar_t *text, int maxCharactersWithNullTerminator, wchar_t const *add, int addchars )
  1035. {
  1036. int maxCharactersWithoutTerminator = maxCharactersWithNullTerminator - 1;
  1037. int curlen = wcslen( text );
  1038. if ( curlen >= maxCharactersWithoutTerminator )
  1039. return;
  1040. wchar_t *p = text + curlen;
  1041. while ( curlen++ < maxCharactersWithoutTerminator &&
  1042. --addchars >= 0 )
  1043. {
  1044. *p++ = *add++;
  1045. }
  1046. *p = 0;
  1047. }
  1048. void CConPanel::AddToNotify( const Color& clr, char const *msg )
  1049. {
  1050. if ( !host_initialized )
  1051. return;
  1052. // notify area only ever draws in developer mode - it should never be used for game messages
  1053. if ( !developer.GetBool() )
  1054. return;
  1055. // If console is not allowed, then don't do the notify area
  1056. if ( !Con_ConsoleAllowed() )
  1057. return;
  1058. // skip any special characters
  1059. if ( msg[0] == 1 ||
  1060. msg[0] == 2 )
  1061. {
  1062. msg++;
  1063. }
  1064. // Nothing left
  1065. if ( !msg[0] )
  1066. return;
  1067. CNotifyText *current = NULL;
  1068. int slot = m_NotifyText.Count() - 1;
  1069. if ( slot < 0 )
  1070. {
  1071. slot = m_NotifyText.AddToTail();
  1072. current = &m_NotifyText[ slot ];
  1073. current->clr = clr;
  1074. current->text[ 0 ] = 0;
  1075. current->liferemaining = con_notifytime.GetFloat();;
  1076. }
  1077. else
  1078. {
  1079. current = &m_NotifyText[ slot ];
  1080. current->clr = clr;
  1081. }
  1082. Assert( current );
  1083. wchar_t unicode[ 1024 ];
  1084. g_pVGuiLocalize->ConvertANSIToUnicode( msg, unicode, sizeof( unicode ) );
  1085. wchar_t const *p = unicode;
  1086. while ( *p )
  1087. {
  1088. const wchar_t *nextreturn = wcsstr( p, L"\n" );
  1089. if ( nextreturn != NULL )
  1090. {
  1091. int copysize = nextreturn - p + 1;
  1092. safestrncat( current->text, MAX_NOTIFY_TEXT_LINE, p, copysize );
  1093. // Add a new notify, but don't add a new one if the previous one was empty...
  1094. if ( current->text[0] && current->text[0] != L'\n' )
  1095. {
  1096. slot = m_NotifyText.AddToTail();
  1097. current = &m_NotifyText[ slot ];
  1098. }
  1099. // Clear it
  1100. current->clr = clr;
  1101. current->text[ 0 ] = 0;
  1102. current->liferemaining = con_notifytime.GetFloat();
  1103. // Skip return character
  1104. p += copysize;
  1105. continue;
  1106. }
  1107. // Append it
  1108. safestrncat( current->text, MAX_NOTIFY_TEXT_LINE, p, wcslen( p ) );
  1109. current->clr = clr;
  1110. current->liferemaining = con_notifytime.GetFloat();
  1111. break;
  1112. }
  1113. while ( m_NotifyText.Count() > 0 &&
  1114. ( m_NotifyText.Count() >= con_times.GetInt() ) )
  1115. {
  1116. m_NotifyText.Remove( 0 );
  1117. }
  1118. }
  1119. //-----------------------------------------------------------------------------
  1120. // Purpose:
  1121. //-----------------------------------------------------------------------------
  1122. void CConPanel::ClearNofify()
  1123. {
  1124. m_NotifyText.RemoveAll();
  1125. }
  1126. void CConPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
  1127. {
  1128. BaseClass::ApplySchemeSettings( pScheme );
  1129. if ( IsGameConsole() )
  1130. {
  1131. // This is one of the few fonts we have loaded in shipping console builds
  1132. m_hFont = pScheme->GetFont( "DebugFixed", false );
  1133. m_hFontFixed = pScheme->GetFont( "DebugFixed", false );
  1134. }
  1135. else
  1136. {
  1137. m_hFont = pScheme->GetFont( "DefaultSmallDropShadow", false );
  1138. m_hFontFixed = pScheme->GetFont( "DefaultFixedDropShadow", false );
  1139. }
  1140. }
  1141. void CConPanel::DrawText( vgui::HFont font, int x, int y, wchar_t *data )
  1142. {
  1143. DrawColoredText( font,
  1144. x,
  1145. y,
  1146. 255,
  1147. 255,
  1148. 255,
  1149. 255,
  1150. data );
  1151. }
  1152. //-----------------------------------------------------------------------------
  1153. // called when we're ticked...
  1154. //-----------------------------------------------------------------------------
  1155. bool CConPanel::ShouldDraw()
  1156. {
  1157. bool bVisible = false;
  1158. if ( m_bDrawDebugAreas )
  1159. {
  1160. bVisible = true;
  1161. }
  1162. // Should be invisible if there's no notifys and the console is up.
  1163. // and if the launcher isn't active
  1164. if ( !Con_IsVisible() )
  1165. {
  1166. // [jason-HPE] This block is thread unsafe: modifications to the size
  1167. // of m_NotifyText can cause invalid vector accesses because we cache
  1168. // the size of the vector at the start of the loop.
  1169. LOCAL_THREAD_LOCK();
  1170. int i;
  1171. int c = m_NotifyText.Count();
  1172. for ( i = c - 1; i >= 0; i-- )
  1173. {
  1174. CNotifyText *notify = &m_NotifyText[ i ];
  1175. notify->liferemaining -= host_frametime;
  1176. if ( notify->liferemaining <= 0.0f )
  1177. {
  1178. m_NotifyText.Remove( i );
  1179. continue;
  1180. }
  1181. bVisible = true;
  1182. }
  1183. }
  1184. else
  1185. {
  1186. bVisible = true;
  1187. }
  1188. return bVisible;
  1189. }
  1190. //-----------------------------------------------------------------------------
  1191. // Purpose:
  1192. //-----------------------------------------------------------------------------
  1193. void CConPanel::DrawNotify( void )
  1194. {
  1195. int x = 8;
  1196. int y = 5;
  1197. if ( IsGameConsole() )
  1198. {
  1199. x += videomode->GetModeWidth() / 20;
  1200. y += videomode->GetModeHeight() / 20;
  1201. }
  1202. if ( !m_hFontFixed )
  1203. return;
  1204. // notify area only draws in developer mode
  1205. if ( !developer.GetBool() )
  1206. return;
  1207. // don't render notify area into movies, either
  1208. if ( cl_movieinfo.IsRecording( ) )
  1209. {
  1210. return;
  1211. }
  1212. if ( toolframework->InToolMode() && !toolframework->ShouldGameRenderView() )
  1213. {
  1214. return;
  1215. }
  1216. if ( !con_drawnotify.GetBool() )
  1217. {
  1218. return;
  1219. }
  1220. vgui::surface()->DrawSetTextFont( m_hFontFixed );
  1221. int fontTall = vgui::surface()->GetFontTall( m_hFontFixed ) + 1;
  1222. Color clr;
  1223. int c = m_NotifyText.Count();
  1224. for ( int i = 0; i < c; i++ )
  1225. {
  1226. CNotifyText *notify = &m_NotifyText[ i ];
  1227. float timeleft = notify->liferemaining;
  1228. clr = notify->clr;
  1229. if ( timeleft < .5f )
  1230. {
  1231. float f = clamp( timeleft, 0.0f, .5f ) / .5f;
  1232. clr[3] = (int)( f * 255.0f );
  1233. if ( i == 0 && f < 0.2f )
  1234. {
  1235. y -= fontTall * ( 1.0f - f / 0.2f );
  1236. }
  1237. }
  1238. else
  1239. {
  1240. clr[3] = 255;
  1241. }
  1242. DrawColoredText( m_hFontFixed, x, y, clr[0], clr[1], clr[2], clr[3], notify->text );
  1243. if ( IsX360() )
  1244. {
  1245. // For some reason the fontTall value on 360 is about twice as high as it should be
  1246. y += 12;
  1247. }
  1248. else
  1249. {
  1250. y += fontTall;
  1251. }
  1252. }
  1253. }
  1254. //-----------------------------------------------------------------------------
  1255. // Purpose:
  1256. //-----------------------------------------------------------------------------
  1257. ConVar con_nprint_bgalpha( "con_nprint_bgalpha", "50", 0, "Con_NPrint background alpha." );
  1258. ConVar con_nprint_bgborder( "con_nprint_bgborder", "5", 0, "Con_NPrint border size." );
  1259. void CConPanel::DrawDebugAreas( void )
  1260. {
  1261. if ( !m_bDrawDebugAreas )
  1262. return;
  1263. // Find the top and bottom of all the nprint text so we can draw a box behind it.
  1264. int left=99999, top=99999, right=-99999, bottom=-99999;
  1265. if ( con_nprint_bgalpha.GetInt() )
  1266. {
  1267. // First, figure out the bounds of all the con_nprint text.
  1268. if ( ProcessNotifyLines( left, top, right, bottom, false ) )
  1269. {
  1270. int b = con_nprint_bgborder.GetInt();
  1271. // Now draw a box behind it.
  1272. vgui::surface()->DrawSetColor( 0, 0, 0, con_nprint_bgalpha.GetInt() );
  1273. vgui::surface()->DrawFilledRect( left-b, top-b, right+b, bottom+b );
  1274. }
  1275. }
  1276. // Now draw the text.
  1277. if ( ProcessNotifyLines( left, top, right, bottom, true ) == 0 )
  1278. {
  1279. // Have all notifies expired?
  1280. m_bDrawDebugAreas = false;
  1281. }
  1282. }
  1283. int CConPanel::ProcessNotifyLines( int &left, int &top, int &right, int &bottom, bool bDraw )
  1284. {
  1285. int count = 0;
  1286. int y = 20;
  1287. int nXMargin = IsGameConsole() ? videomode->GetModeWidth() / 20 : 10;
  1288. int nYMargin = IsGameConsole() ? videomode->GetModeHeight() / 20 : 20;
  1289. int nFontTall;
  1290. if ( IsX360() )
  1291. {
  1292. // For some reason the fontTall value on 360 is about twice as high as it should be
  1293. nFontTall = 12;
  1294. }
  1295. else
  1296. {
  1297. nFontTall = vgui::surface()->GetFontTall( m_hFontFixed ) + 1;
  1298. }
  1299. for ( int i = 0; i < MAX_DBG_NOTIFY; i++ )
  1300. {
  1301. if ( realtime < da_notify[i].expire || da_notify[i].expire == -1 )
  1302. {
  1303. // If it's marked this way, only draw it once.
  1304. if ( da_notify[i].expire == -1 && bDraw )
  1305. {
  1306. da_notify[i].expire = realtime - 1;
  1307. }
  1308. int len;
  1309. int x;
  1310. vgui::HFont font = da_notify[i].fixed_width_font ? m_hFontFixed : m_hFont ;
  1311. len = DrawTextLen( font, da_notify[i].szNotify );
  1312. x = videomode->GetModeWidth() - nXMargin - len;
  1313. if ( y + nFontTall > videomode->GetModeHeight() - nYMargin )
  1314. return count;
  1315. count++;
  1316. int y = nYMargin + nFontTall * i;
  1317. if ( bDraw )
  1318. {
  1319. DrawColoredText( font, x, y,
  1320. da_notify[i].color[0] * 255,
  1321. da_notify[i].color[1] * 255,
  1322. da_notify[i].color[2] * 255,
  1323. 255,
  1324. da_notify[i].szNotify );
  1325. }
  1326. if ( da_notify[i].szNotify[0] )
  1327. {
  1328. // Extend the bounds.
  1329. left = MIN( left, x );
  1330. top = MIN( top, y );
  1331. right = MAX( right, x+len );
  1332. bottom = MAX( bottom, y+nFontTall );
  1333. }
  1334. y += nFontTall;
  1335. }
  1336. }
  1337. return count;
  1338. }
  1339. //-----------------------------------------------------------------------------
  1340. // Purpose:
  1341. //-----------------------------------------------------------------------------
  1342. void CConPanel::Paint()
  1343. {
  1344. VPROF( "CConPanel::Paint" );
  1345. DrawDebugAreas();
  1346. DrawNotify(); // only draw notify in game
  1347. }
  1348. //-----------------------------------------------------------------------------
  1349. // Purpose:
  1350. //-----------------------------------------------------------------------------
  1351. void CConPanel::PaintBackground()
  1352. {
  1353. // Rendering this information is not interesting and gives away server IP when streaming
  1354. #if 0
  1355. if ( !Con_IsVisible() )
  1356. return;
  1357. int wide = GetWide();
  1358. char ver[ 100 ];
  1359. Q_snprintf(ver, sizeof( ver ), "Source Engine %i (build %d)", GetHostVersion(), build_number() );
  1360. wchar_t unicode[ 200 ];
  1361. g_pVGuiLocalize->ConvertANSIToUnicode( ver, unicode, sizeof( unicode ) );
  1362. vgui::surface()->DrawSetTextColor( Color( 255, 255, 255, 255 ) );
  1363. int x = wide - DrawTextLen( m_hFont, unicode ) - 2;
  1364. DrawText( m_hFont, x, 0, unicode );
  1365. if ( GetBaseLocalClient().IsActive() )
  1366. {
  1367. if ( GetBaseLocalClient().m_NetChannel->IsLoopback() || cl_hideserverip.GetInt()>0 )
  1368. {
  1369. Q_snprintf(ver, sizeof( ver ), "Map '%s'", GetBaseLocalClient().m_szLevelNameShort );
  1370. }
  1371. else
  1372. {
  1373. Q_snprintf(ver, sizeof( ver ), "Server '%s' Map '%s'", GetBaseLocalClient().m_NetChannel->GetAddress(), GetBaseLocalClient().m_szLevelNameShort );
  1374. }
  1375. wchar_t unicode[ 200 ];
  1376. g_pVGuiLocalize->ConvertANSIToUnicode( ver, unicode, sizeof( unicode ) );
  1377. int tall = vgui::surface()->GetFontTall( m_hFont );
  1378. int x = wide - DrawTextLen( m_hFont, unicode ) - 2;
  1379. DrawText( m_hFont, x, tall + 1, unicode );
  1380. }
  1381. #endif
  1382. }
  1383. //-----------------------------------------------------------------------------
  1384. // Purpose: Creates the Console VGUI object
  1385. //-----------------------------------------------------------------------------
  1386. static CConPanel *conPanel = NULL;
  1387. void Con_CreateConsolePanel( vgui::Panel *parent )
  1388. {
  1389. conPanel = new CConPanel( parent );
  1390. if (conPanel)
  1391. {
  1392. conPanel->SetVisible(false);
  1393. }
  1394. }
  1395. vgui::Panel* Con_GetConsolePanel()
  1396. {
  1397. return conPanel;
  1398. }
  1399. static ConCommand toggleconsole("toggleconsole", Con_ToggleConsole_f, "Show/hide the console.", FCVAR_DONTRECORD );
  1400. static ConCommand hideconsole("hideconsole", Con_HideConsole_f, "Hide the console.", FCVAR_DONTRECORD );
  1401. static ConCommand showconsole("showconsole", Con_ShowConsole_f, "Show the console.", FCVAR_DONTRECORD );
  1402. static ConCommand clear("clear", Con_Clear_f, "Clear all console output.", FCVAR_DONTRECORD );
  1403. static ConCommand log_dumpchannels( "log_dumpchannels", Con_LogDumpChannels_f, "Dumps information about all logging channels.", FCVAR_DONTRECORD );
  1404. static ConCommand log_level( "log_level", Con_LogLevel_f, "Set the spew level of a logging channel.", FCVAR_DONTRECORD );
  1405. static ConCommand log_color( "log_color", Con_LogColor_f, "Set the color of a logging channel.", FCVAR_DONTRECORD );
  1406. static ConCommand log_flags( "log_flags", Con_LogFlags_f, "Set the flags on a logging channel.", FCVAR_DONTRECORD );
  1407. #endif // DEDICATED