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.

641 lines
18 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: baseclientstate.cpp: implementation of the CBaseClientState class.
  4. //
  5. //===========================================================================//
  6. #include "client_pch.h"
  7. #include "limits.h"
  8. #include "cl_pluginhelpers.h"
  9. #include <inetchannel.h>
  10. #include <vgui/ISurface.h>
  11. #include <vgui/IScheme.h>
  12. #include <vgui/ILocalize.h>
  13. #include <vgui/IVGui.h>
  14. #include <vgui/IPanel.h>
  15. #include <vgui_controls/Controls.h>
  16. #include <vgui_controls/Frame.h>
  17. #include <vgui_controls/EditablePanel.h>
  18. #include <vgui_controls/Button.h>
  19. #include <vgui_controls/RichText.h>
  20. #include <vgui_controls/Label.h>
  21. #include <vgui_controls/TextEntry.h>
  22. #include <vgui_controls/ImagePanel.h>
  23. #include <vgui_controls/AnimationController.h>
  24. #include "vgui_baseui_interface.h"
  25. #include "vgui_askconnectpanel.h"
  26. #include "cmd.h"
  27. #include "tier1/convar.h"
  28. // NOTE: This has to be the last file included!
  29. #include "tier0/memdbgon.h"
  30. // FIXME: Seems like we just extern this everywhere. Maybe it should be in a header file somewhere?
  31. extern IVEngineClient *engineClient;
  32. //-----------------------------------------------------------------------------
  33. // Purpose: Displays the options menu
  34. //-----------------------------------------------------------------------------
  35. class CPluginMenu : public vgui::EditablePanel
  36. {
  37. private:
  38. DECLARE_CLASS_SIMPLE( CPluginMenu, vgui::EditablePanel );
  39. public:
  40. CPluginMenu( vgui::Panel *parent );
  41. virtual ~CPluginMenu();
  42. void Show( KeyValues *kv );
  43. void OnCommand(const char *command);
  44. };
  45. //-----------------------------------------------------------------------------
  46. // Purpose: Constructor
  47. //-----------------------------------------------------------------------------
  48. CPluginMenu::CPluginMenu( vgui::Panel *parent ) : EditablePanel(parent, "PluginMenu" )
  49. {
  50. LoadControlSettings("Resource/UI/PluginMenu.res");
  51. }
  52. //-----------------------------------------------------------------------------
  53. // Purpose: Destructor
  54. //-----------------------------------------------------------------------------
  55. CPluginMenu::~CPluginMenu()
  56. {
  57. }
  58. //-----------------------------------------------------------------------------
  59. // Purpose: Show the options menu after using key values to configure it
  60. //-----------------------------------------------------------------------------
  61. void CPluginMenu::Show( KeyValues *kv )
  62. {
  63. vgui::Label *control = dynamic_cast<vgui::Label *>(FindChildByName("Text"));
  64. if (control)
  65. {
  66. control->SetText( kv->GetWString( "msg" ) );
  67. }
  68. int i = 0;
  69. // hide all the buttons
  70. for ( i = 0; i < GetChildCount(); i++ )
  71. {
  72. vgui::Button *button = dynamic_cast<vgui::Button *>(GetChild(i));
  73. if ( button )
  74. {
  75. button->SetVisible( false );
  76. }
  77. }
  78. i = 1;
  79. // now work out what buttons to display
  80. for ( KeyValues *pCur=kv->GetFirstTrueSubKey(); pCur; pCur=pCur->GetNextTrueSubKey(), i++ )
  81. {
  82. char controlName[64];
  83. Q_snprintf( controlName, sizeof(controlName), "option%i", i );
  84. vgui::Button *button = dynamic_cast<vgui::Button *>(FindChildByName(controlName,true));
  85. Assert( button );
  86. if ( button )
  87. {
  88. button->SetText( pCur->GetWString( "msg" ));
  89. button->SetCommand( pCur->GetString( "command" ));
  90. button->SetVisible( true );
  91. }
  92. }
  93. }
  94. //-----------------------------------------------------------------------------
  95. // Purpose: when a button is pressed send that command back to the engine
  96. //-----------------------------------------------------------------------------
  97. void CPluginMenu::OnCommand( const char *command )
  98. {
  99. Cbuf_AddText( Cbuf_GetCurrentPlayer(), command );
  100. CallParentFunction( new KeyValues( "Command", "command", "close" ) );
  101. }
  102. //-----------------------------------------------------------------------------
  103. // Purpose: Displays the gameui portion of plugin menus
  104. //-----------------------------------------------------------------------------
  105. class CPluginGameUIDialog : public vgui::Frame
  106. {
  107. private:
  108. DECLARE_CLASS_SIMPLE( CPluginGameUIDialog, vgui::Frame );
  109. public:
  110. CPluginGameUIDialog();
  111. virtual ~CPluginGameUIDialog();
  112. virtual void Show( DIALOG_TYPE type, KeyValues *kv );
  113. protected:
  114. void OnCommand( const char *cmd );
  115. private:
  116. CPluginMenu *m_Menu;
  117. vgui::RichText *m_RichText;
  118. vgui::Label *m_Message;
  119. vgui::TextEntry *m_Entry;
  120. vgui::Label *m_EntryLabel;
  121. vgui::Button *m_CloseButton;
  122. char m_szEntryCommand[ 255 ];
  123. };
  124. //-----------------------------------------------------------------------------
  125. // Purpose: constructor
  126. //-----------------------------------------------------------------------------
  127. CPluginGameUIDialog::CPluginGameUIDialog() : vgui::Frame( NULL, "Plugins" )
  128. {
  129. // initialize dialog
  130. SetTitle( "Plugins", true );
  131. SetAlpha( 255 );
  132. SetScheme( "Tracker" );
  133. m_szEntryCommand[ 0 ] = 0;
  134. m_Menu = new CPluginMenu( this );
  135. m_RichText = new vgui::RichText( this, "Rich" );
  136. m_Message = new vgui::Label( this, "Label", "" );
  137. m_Entry = new vgui::TextEntry( this, "Entry" );
  138. m_EntryLabel = new vgui::Label( this, "EntryLabel", "" );
  139. m_CloseButton = new vgui::Button( this, "Close", "");
  140. LoadControlSettings("Resource/UI/Plugin.res");
  141. InvalidateLayout();
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Purpose: destructor
  145. //-----------------------------------------------------------------------------
  146. CPluginGameUIDialog::~CPluginGameUIDialog()
  147. {
  148. }
  149. //-----------------------------------------------------------------------------
  150. // Purpose: called when the close button is pressed
  151. //-----------------------------------------------------------------------------
  152. void CPluginGameUIDialog::OnCommand( const char *cmd )
  153. {
  154. if ( !Q_stricmp( cmd, "close" ) )
  155. {
  156. if ( Q_strlen(m_szEntryCommand) > 0 )
  157. {
  158. char userCMD[ 512 ];
  159. char entryText[ 255 ];
  160. m_Entry->GetText( entryText, sizeof(entryText) );
  161. Q_snprintf( userCMD, sizeof(userCMD), "%s %s\n", m_szEntryCommand, entryText );
  162. // Only let them run commands marked with FCVAR_CLIENTCMD_CAN_EXECUTE.
  163. engineClient->ClientCmd( userCMD );
  164. }
  165. Close();
  166. g_PluginManager->OnPanelClosed();
  167. }
  168. else
  169. {
  170. BaseClass::OnCommand( cmd );
  171. }
  172. }
  173. //-----------------------------------------------------------------------------
  174. // Purpose: shows a precanned style of message in the GameUI
  175. //-----------------------------------------------------------------------------
  176. void CPluginGameUIDialog::Show( DIALOG_TYPE type, KeyValues *kv )
  177. {
  178. m_Menu->SetVisible(false);
  179. m_RichText->SetVisible(false);
  180. m_Message->SetVisible(false);
  181. m_Entry->SetVisible(false);
  182. m_EntryLabel->SetVisible(false);
  183. m_szEntryCommand[ 0 ] = 0;
  184. SetTitle( kv->GetWString( "title" ), true );
  185. switch ( type )
  186. {
  187. case DIALOG_MENU: // a options menu
  188. m_Menu->Show( kv );
  189. m_Menu->SetVisible( true );
  190. break;
  191. case DIALOG_TEXT: // a richtext dialog
  192. m_RichText->SetText( kv->GetWString( "msg" ) );
  193. m_RichText->SetVisible( true );
  194. break;
  195. case DIALOG_MSG: // just a msg to the screen, don't display in the gameui
  196. SetVisible( false );
  197. return;
  198. break;
  199. case DIALOG_ENTRY:
  200. m_Entry->SetVisible( true );
  201. m_EntryLabel->SetVisible( true );
  202. m_EntryLabel->SetText( kv->GetWString( "msg" ) );
  203. Q_strncpy( m_szEntryCommand, kv->GetString( "command" ), sizeof(m_szEntryCommand) );
  204. m_CloseButton->SetText( "#GameUI_OK" );
  205. break;
  206. default:
  207. Msg( "Invalid menu type (%i)\n", type );
  208. break;
  209. }
  210. Activate();
  211. }
  212. //-----------------------------------------------------------------------------
  213. // Purpose: the individual message snippets
  214. //-----------------------------------------------------------------------------
  215. class CMessage : public vgui::Label
  216. {
  217. private:
  218. DECLARE_CLASS_SIMPLE( CMessage, vgui::Label );
  219. public:
  220. CMessage(vgui::Panel *parent, const char *panelName, const char *text);
  221. ~CMessage();
  222. bool HasExtraPanel() { return m_bHasExtraPanel; }
  223. protected:
  224. void ApplySchemeSettings( vgui::IScheme *pScheme );
  225. private:
  226. bool m_bHasExtraPanel;
  227. };
  228. CMessage::CMessage( vgui::Panel *parent, const char *panelName, const char *text ) : vgui::Label( parent, panelName, text )
  229. {
  230. m_bHasExtraPanel = false;
  231. }
  232. CMessage::~CMessage()
  233. {
  234. }
  235. void CMessage::ApplySchemeSettings( vgui::IScheme *pScheme )
  236. {
  237. vgui::HFont font = pScheme->GetFont( "PluginText", false );
  238. if ( font == vgui::INVALID_FONT )
  239. {
  240. font = pScheme->GetFont( "HudHintText", false );
  241. }
  242. SetFont(font);
  243. BaseClass::ApplySchemeSettings( pScheme );
  244. }
  245. //-----------------------------------------------------------------------------
  246. // Purpose: the hud plugin message panel
  247. //-----------------------------------------------------------------------------
  248. class CPluginHudMessage : public vgui::Frame
  249. {
  250. private:
  251. DECLARE_CLASS_SIMPLE( CPluginHudMessage, vgui::Frame );
  252. public:
  253. CPluginHudMessage( vgui::VPANEL parent );
  254. ~CPluginHudMessage();
  255. void ShowMessage( const wchar_t *message, int time, Color clr, bool bHasExtraPanel );
  256. void StartHiding();
  257. void Hide();
  258. protected:
  259. void ApplySchemeSettings( vgui::IScheme *pScheme );
  260. void OnTick();
  261. void OnSizeChanged( int newWide, int newTall );
  262. private:
  263. enum { MESSAGE_X_INSET = 40, MAX_TEXT_LEN_PIXELS = 400 };
  264. CMessage *m_Message;
  265. vgui::ImagePanel *m_pExtraPanelIcon;
  266. bool m_bHidingControl;
  267. int m_iTargetH, m_iTargetW;
  268. Color m_fgColor;
  269. vgui::AnimationController *m_pAnimationController;
  270. };
  271. //-----------------------------------------------------------------------------
  272. // Purpose: constructor
  273. //-----------------------------------------------------------------------------
  274. CPluginHudMessage::CPluginHudMessage( vgui::VPANEL parent ) : vgui::Frame( NULL, "PluginHudMessage" )
  275. {
  276. SetParent( parent );
  277. SetVisible( false );
  278. SetAlpha( 255 );
  279. SetMinimumSize( 10 , 10 );
  280. SetScheme( "ClientScheme" );
  281. SetMoveable(false);
  282. SetSizeable(false);
  283. SetKeyBoardInputEnabled( false );
  284. SetMouseInputEnabled( false );
  285. SetTitleBarVisible( false );
  286. m_pExtraPanelIcon = new vgui::ImagePanel( this, "ExtraPanelIcon" );
  287. m_pExtraPanelIcon->SetVisible( false );
  288. m_Message = new CMessage( this, "Msg", "");
  289. m_Message->SetVisible( false );
  290. m_pAnimationController = new vgui::AnimationController( NULL );
  291. m_pAnimationController->SetParent( parent );
  292. m_pAnimationController->SetScriptFile( parent, "scripts/plugin_animations.txt" );
  293. m_pAnimationController->SetProportional( false );
  294. vgui::ivgui()->AddTickSignal(GetVPanel());
  295. LoadControlSettings("Resource/UI/PluginHud.res");
  296. InvalidateLayout();
  297. GetSize( m_iTargetW, m_iTargetH );
  298. }
  299. //-----------------------------------------------------------------------------
  300. // Purpose: destructor
  301. //-----------------------------------------------------------------------------
  302. CPluginHudMessage::~CPluginHudMessage()
  303. {
  304. }
  305. //-----------------------------------------------------------------------------
  306. // Purpose: set the see through color and rounded corners
  307. //-----------------------------------------------------------------------------
  308. void CPluginHudMessage::ApplySchemeSettings( vgui::IScheme *pScheme )
  309. {
  310. m_pExtraPanelIcon->SetImage( vgui::scheme()->GetImage( "plugin/message_waiting", true ) );
  311. BaseClass::ApplySchemeSettings( pScheme );
  312. SetBgColor( pScheme->GetColor( "Plugins.BgColor", pScheme->GetColor( "TransparentBlack", Color( 0, 0, 0, 192 ))) );
  313. SetPaintBackgroundType( 2 );
  314. m_Message->SetFgColor( m_fgColor );
  315. m_pExtraPanelIcon->SetVisible( !m_bHidingControl );
  316. }
  317. //-----------------------------------------------------------------------------
  318. // Purpose: run the anim controller and hide the message label if the anim var says to
  319. //-----------------------------------------------------------------------------
  320. void CPluginHudMessage::OnTick()
  321. {
  322. m_pAnimationController->UpdateAnimations( Sys_FloatTime() );
  323. BaseClass::OnTick();
  324. }
  325. //-----------------------------------------------------------------------------
  326. // Purpose: get the label size to track
  327. //-----------------------------------------------------------------------------
  328. void CPluginHudMessage::OnSizeChanged( int newWide, int newTall )
  329. {
  330. BaseClass::OnSizeChanged( newWide, newTall );
  331. int w, h;
  332. GetSize( w, h );
  333. m_Message->SetBounds( MESSAGE_X_INSET, 5, w - MESSAGE_X_INSET - 10, h - 10 );
  334. }
  335. //-----------------------------------------------------------------------------
  336. // Purpose: start the shrinking anim for the control if it should be showed, the hide anim otherwsise
  337. //-----------------------------------------------------------------------------
  338. void CPluginHudMessage::StartHiding()
  339. {
  340. if ( m_pExtraPanelIcon->IsVisible() )
  341. {
  342. m_pAnimationController->StartAnimationSequence( "PluginMessageSmall" );
  343. }
  344. else
  345. {
  346. Hide();
  347. }
  348. }
  349. //-----------------------------------------------------------------------------
  350. // Purpose: starts the hide anim for the control
  351. //-----------------------------------------------------------------------------
  352. void CPluginHudMessage::Hide()
  353. {
  354. m_pAnimationController->StartAnimationSequence( "PluginMessageHide" );
  355. m_pExtraPanelIcon->SetVisible( false );
  356. }
  357. //-----------------------------------------------------------------------------
  358. // Purpose: shows a text message on the hud
  359. //-----------------------------------------------------------------------------
  360. void CPluginHudMessage::ShowMessage( const wchar_t *text, int time, Color clr, bool bHasExtraPanel )
  361. {
  362. m_Message->SetVisible( true );
  363. m_Message->SetBounds( MESSAGE_X_INSET, 5, m_iTargetW - MESSAGE_X_INSET - 10, m_iTargetH - 10 );
  364. m_Message->SetText( text );
  365. m_Message->SetFgColor( clr );
  366. m_fgColor = clr;
  367. m_bHidingControl = !bHasExtraPanel;
  368. if ( bHasExtraPanel )
  369. {
  370. m_pExtraPanelIcon->SetVisible( true );
  371. }
  372. m_pAnimationController->StartAnimationSequence( "PluginMessageShow" );
  373. SetVisible( true );
  374. InvalidateLayout();
  375. int textW, textH;
  376. m_Message->GetContentSize( textW, textH );
  377. textW = MIN( textW + MESSAGE_X_INSET + 10, MAX_TEXT_LEN_PIXELS );
  378. SetSize( textW, m_iTargetH ); // the "small" animation event changes our size
  379. }
  380. //-----------------------------------------------------------------------------
  381. // Purpose: constructor
  382. //-----------------------------------------------------------------------------
  383. CPluginUIManager::CPluginUIManager() : vgui::Panel( NULL, "PluginManager" )
  384. {
  385. m_iCurPriority = INT_MAX;
  386. m_iMessageDisplayUntil = 0;
  387. m_iHudDisplayUntil = 0;
  388. m_bShutdown = false;
  389. m_pGameUIDialog = new CPluginGameUIDialog();
  390. Assert( m_pGameUIDialog );
  391. m_pGameUIDialog->SetParent( EngineVGui()->GetPanel( PANEL_GAMEUIDLL ) );
  392. m_pHudMessage = new CPluginHudMessage(EngineVGui()->GetPanel( PANEL_CLIENTDLL ));
  393. Assert( m_pHudMessage );
  394. vgui::ivgui()->AddTickSignal(GetVPanel());
  395. }
  396. //-----------------------------------------------------------------------------
  397. // Purpose: destructor
  398. //-----------------------------------------------------------------------------
  399. CPluginUIManager::~CPluginUIManager()
  400. {
  401. }
  402. //-----------------------------------------------------------------------------
  403. // Purpose: hides the two plugin dialogs at the appropriate times
  404. //-----------------------------------------------------------------------------
  405. void CPluginUIManager::OnTick()
  406. {
  407. if ( m_bShutdown )
  408. {
  409. return;
  410. }
  411. if ( m_iMessageDisplayUntil != 0 && !EngineVGui()->IsGameUIVisible() && m_iMessageDisplayUntil < Sys_FloatTime() ) // check the GameUI large message
  412. {
  413. m_pGameUIDialog->SetVisible( false );
  414. m_pHudMessage->Hide();
  415. m_iMessageDisplayUntil = 0;
  416. m_iCurPriority = INT_MAX;
  417. }
  418. if ( m_iHudDisplayUntil != 0 && m_iHudDisplayUntil < Sys_FloatTime() ) // check the hud panel
  419. {
  420. m_pHudMessage->StartHiding();
  421. m_iHudDisplayUntil = 0;
  422. }
  423. BaseClass::OnTick();
  424. }
  425. //-----------------------------------------------------------------------------
  426. // Purpose: shuts down the plugin UI
  427. //-----------------------------------------------------------------------------
  428. void CPluginUIManager::Shutdown()
  429. {
  430. vgui::ivgui()->RemoveTickSignal(GetVPanel());
  431. m_pHudMessage->Hide();
  432. m_pGameUIDialog->SetVisible( false );
  433. MarkForDeletion();
  434. m_bShutdown = true;
  435. }
  436. //-----------------------------------------------------------------------------
  437. // Purpose: shows a particular ui type and queues their lifetime
  438. //-----------------------------------------------------------------------------
  439. void CPluginUIManager::Show( DIALOG_TYPE type, KeyValues *kv )
  440. {
  441. // Check for the special DIALOG_ASKCONNECT command.
  442. if ( type == DIALOG_ASKCONNECT )
  443. {
  444. // Do the askconnect dialog.
  445. float flDuration = kv->GetFloat( "time", 4.0f );
  446. const char *pIP = kv->GetString( "title", NULL );
  447. if ( !pIP )
  448. {
  449. DevMsg( "Ignoring DIALOG_ASKCONNECT message. No IP specified." );
  450. return;
  451. }
  452. ShowAskConnectPanel( pIP, flDuration );
  453. return;
  454. }
  455. int level = kv->GetInt( "level", INT_MAX );
  456. if ( level < m_iCurPriority )
  457. {
  458. m_iCurPriority = level;
  459. }
  460. else
  461. {
  462. DevMsg( "Ignoring message %s, %i < %i\n", kv->GetName(), level, m_iCurPriority );
  463. return;
  464. }
  465. if ( type != DIALOG_MSG )
  466. {
  467. m_iMessageDisplayUntil = Sys_FloatTime() + MIN(MAX( kv->GetInt( "time", 10 ),10),200);
  468. }
  469. else
  470. {
  471. m_iMessageDisplayUntil = Sys_FloatTime() + 10;
  472. }
  473. m_iHudDisplayUntil = Sys_FloatTime() + 10; // hud messages only get 10 seconds
  474. m_pGameUIDialog->Show( type, kv );
  475. Color clr( 255, 255, 255, 255 );
  476. if ( !kv->IsEmpty( "color" ) )
  477. {
  478. clr = kv->GetColor( "color" );
  479. }
  480. m_pHudMessage->ShowMessage( kv->GetWString( "title" ), 10, clr, type != DIALOG_MSG );
  481. }
  482. //-----------------------------------------------------------------------------
  483. // Purpose: called when the gameui panel is closed
  484. //-----------------------------------------------------------------------------
  485. void CPluginUIManager::OnPanelClosed()
  486. {
  487. m_iCurPriority = INT_MAX;
  488. m_iHudDisplayUntil = 0;
  489. m_iMessageDisplayUntil = 0;
  490. m_pGameUIDialog->SetVisible( false );
  491. m_pHudMessage->Hide();
  492. }
  493. void CPluginUIManager::GetHudMessagePosition( int &x, int &y, int &wide, int &tall )
  494. {
  495. if ( m_pHudMessage )
  496. {
  497. m_pHudMessage->GetBounds( x, y, wide, tall );
  498. }
  499. else
  500. {
  501. x = y = wide = tall = 0;
  502. }
  503. }
  504. CPluginUIManager *g_PluginManager = NULL;
  505. //=============================================================================
  506. //
  507. // external interfaces
  508. //
  509. //=============================================================================
  510. ConVar cl_showpluginmessages ( "cl_showpluginmessages", "1", FCVAR_ARCHIVE, "Allow plugins to display messages to you" );
  511. void PluginHelpers_Menu( const CSVCMsg_Menu& msg )
  512. {
  513. if ( !msg.menu_key_values().size() )
  514. {
  515. return;
  516. }
  517. if ( !cl_showpluginmessages.GetBool() )
  518. {
  519. return;
  520. }
  521. if ( !g_PluginManager )
  522. {
  523. g_PluginManager = new CPluginUIManager();
  524. }
  525. KeyValues *keyvalues = new KeyValues( "menu" );
  526. CUtlBuffer buf( &msg.menu_key_values()[0], msg.menu_key_values().size() );
  527. bool bRet = keyvalues->ReadAsBinary( buf );
  528. Assert( bRet );
  529. if( bRet )
  530. {
  531. g_PluginManager->Show( ( DIALOG_TYPE )msg.dialog_type(), keyvalues );
  532. }
  533. keyvalues->deleteThis();
  534. }